Convert API to use new btcutil.Tx.
This is part of the ongoing transaction hash optimization effort noted in conformal/btcd#25.
This commit is contained in:
parent
b6e4ae4441
commit
6165e9b95b
8 changed files with 83 additions and 129 deletions
12
accept.go
12
accept.go
|
@ -60,16 +60,10 @@ func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block) error {
|
|||
}
|
||||
|
||||
// Ensure all transactions in the block are finalized.
|
||||
for i, tx := range block.MsgBlock().Transactions {
|
||||
for _, tx := range block.Transactions() {
|
||||
if !IsFinalizedTransaction(tx, blockHeight, blockHeader.Timestamp) {
|
||||
// Use the TxSha function from the block rather
|
||||
// than the transaction itself since the block version
|
||||
// is cached. Also, it's safe to ignore the error here
|
||||
// since the only reason TxSha can fail is if the index
|
||||
// is out of range which is impossible here.
|
||||
txSha, _ := block.TxSha(i)
|
||||
str := fmt.Sprintf("block contains unfinalized "+
|
||||
"transaction %v", txSha)
|
||||
"transaction %v", tx.Sha())
|
||||
return RuleError(str)
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +123,7 @@ func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block) error {
|
|||
if prevNode != nil {
|
||||
expectedHeight = prevNode.height + 1
|
||||
}
|
||||
coinbaseTx := block.MsgBlock().Transactions[0]
|
||||
coinbaseTx := block.Transactions()[0]
|
||||
err := checkSerializedHeight(coinbaseTx, expectedHeight)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -154,11 +154,11 @@ func (b *BlockChain) findLatestKnownCheckpoint() (*btcutil.Block, error) {
|
|||
|
||||
// isNonstandardTransaction determines whether a transaction contains any
|
||||
// scripts which are not one of the standard types.
|
||||
func isNonstandardTransaction(tx *btcwire.MsgTx) bool {
|
||||
func isNonstandardTransaction(tx *btcutil.Tx) bool {
|
||||
// TODO(davec): Should there be checks for the input signature scripts?
|
||||
|
||||
// Check all of the output public key scripts for non-standard scripts.
|
||||
for _, txOut := range tx.TxOut {
|
||||
for _, txOut := range tx.MsgTx().TxOut {
|
||||
scriptClass := btcscript.GetScriptClass(txOut.PkScript)
|
||||
if scriptClass == btcscript.NonStandardTy {
|
||||
return true
|
||||
|
@ -235,7 +235,7 @@ func (b *BlockChain) IsCheckpointCandidate(block *btcutil.Block) (bool, error) {
|
|||
|
||||
// A checkpoint must have transactions that only contain standard
|
||||
// scripts.
|
||||
for _, tx := range block.MsgBlock().Transactions {
|
||||
for _, tx := range block.Transactions() {
|
||||
if isNonstandardTransaction(tx) {
|
||||
return false, nil
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ package btcchain
|
|||
|
||||
import (
|
||||
"github.com/conformal/btcutil"
|
||||
"github.com/conformal/btcwire"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -37,6 +36,6 @@ func TstTimeSorter(times []time.Time) timeSorter {
|
|||
|
||||
// TstCheckSerializedHeight makes the internal checkSerializedHeight function
|
||||
// available to the test package.
|
||||
func TstCheckSerializedHeight(coinbaseTx *btcwire.MsgTx, wantHeight int64) error {
|
||||
func TstCheckSerializedHeight(coinbaseTx *btcutil.Tx, wantHeight int64) error {
|
||||
return checkSerializedHeight(coinbaseTx, wantHeight)
|
||||
}
|
||||
|
|
12
merkle.go
12
merkle.go
|
@ -69,21 +69,15 @@ func hashMerkleBranches(left *btcwire.ShaHash, right *btcwire.ShaHash) *btcwire.
|
|||
// Since this function uses nodes that are pointers to the hashes, empty nodes
|
||||
// will be nil.
|
||||
func BuildMerkleTreeStore(block *btcutil.Block) []*btcwire.ShaHash {
|
||||
numTransactions := len(block.MsgBlock().Transactions)
|
||||
|
||||
// Calculate how many entries are required to hold the binary merkle
|
||||
// tree as a linear array and create an array of that size.
|
||||
nextPoT := nextPowerOfTwo(numTransactions)
|
||||
nextPoT := nextPowerOfTwo(len(block.Transactions()))
|
||||
arraySize := nextPoT*2 - 1
|
||||
merkles := make([]*btcwire.ShaHash, arraySize)
|
||||
|
||||
// Create the base transaction shas and populate the array with them.
|
||||
for i := 0; i < numTransactions; i++ {
|
||||
// Ignore the error since the only reason TxSha can fail is
|
||||
// if the index is out of range which is impossible here due
|
||||
// to using a loop over the existing transactions.
|
||||
sha, _ := block.TxSha(i)
|
||||
merkles[i] = sha
|
||||
for i, tx := range block.Transactions() {
|
||||
merkles[i] = tx.Sha()
|
||||
}
|
||||
|
||||
// Start the array offset after the last transaction and adjusted to the
|
||||
|
|
39
scriptval.go
39
scriptval.go
|
@ -19,16 +19,10 @@ type txValidate struct {
|
|||
err error
|
||||
}
|
||||
|
||||
// txProcessList
|
||||
type txProcessList struct {
|
||||
txsha btcwire.ShaHash
|
||||
tx *btcwire.MsgTx
|
||||
}
|
||||
|
||||
// validateTxIn validates a the script pair for the passed spending transaction
|
||||
// (along with the specific input index) and origin transaction (with the
|
||||
// specific output index).
|
||||
func validateTxIn(txInIdx int, txin *btcwire.TxIn, txSha *btcwire.ShaHash, tx *btcwire.MsgTx, originTx *btcwire.MsgTx, flags btcscript.ScriptFlags) error {
|
||||
func validateTxIn(txInIdx int, txin *btcwire.TxIn, tx *btcutil.Tx, originTx *btcutil.Tx, flags btcscript.ScriptFlags) error {
|
||||
// If the input transaction has no previous input, there is nothing
|
||||
// to check.
|
||||
originTxIdx := txin.PreviousOutpoint.Index
|
||||
|
@ -36,17 +30,17 @@ func validateTxIn(txInIdx int, txin *btcwire.TxIn, txSha *btcwire.ShaHash, tx *b
|
|||
return nil
|
||||
}
|
||||
|
||||
if originTxIdx >= uint32(len(originTx.TxOut)) {
|
||||
if originTxIdx >= uint32(len(originTx.MsgTx().TxOut)) {
|
||||
originTxSha := &txin.PreviousOutpoint.Hash
|
||||
log.Warnf("unable to locate source tx %v spending tx %v",
|
||||
originTxSha, &txSha)
|
||||
originTxSha, tx.Sha())
|
||||
return fmt.Errorf("invalid index %x", originTxIdx)
|
||||
}
|
||||
|
||||
sigScript := txin.SignatureScript
|
||||
pkScript := originTx.TxOut[originTxIdx].PkScript
|
||||
engine, err := btcscript.NewScript(sigScript, pkScript, txInIdx, tx,
|
||||
flags)
|
||||
pkScript := originTx.MsgTx().TxOut[originTxIdx].PkScript
|
||||
engine, err := btcscript.NewScript(sigScript, pkScript, txInIdx,
|
||||
tx.MsgTx(), flags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -62,9 +56,9 @@ func validateTxIn(txInIdx int, txin *btcwire.TxIn, txSha *btcwire.ShaHash, tx *b
|
|||
|
||||
// ValidateTransactionScripts validates the scripts for the passed transaction
|
||||
// using multiple goroutines.
|
||||
func ValidateTransactionScripts(tx *btcwire.MsgTx, txHash *btcwire.ShaHash, txStore TxStore, flags btcscript.ScriptFlags) (err error) {
|
||||
func ValidateTransactionScripts(tx *btcutil.Tx, txStore TxStore, flags btcscript.ScriptFlags) (err error) {
|
||||
c := make(chan txValidate)
|
||||
job := tx.TxIn
|
||||
job := tx.MsgTx().TxIn
|
||||
resultErrors := make([]error, len(job))
|
||||
|
||||
var currentItem int
|
||||
|
@ -72,12 +66,12 @@ func ValidateTransactionScripts(tx *btcwire.MsgTx, txHash *btcwire.ShaHash, txSt
|
|||
|
||||
processFunc := func(txInIdx int) {
|
||||
log.Tracef("validating tx %v input %v len %v",
|
||||
txHash, currentItem, len(job))
|
||||
tx.Sha(), currentItem, len(job))
|
||||
txin := job[txInIdx]
|
||||
originTxSha := &txin.PreviousOutpoint.Hash
|
||||
origintxidx := txin.PreviousOutpoint.Index
|
||||
|
||||
var originTx *btcwire.MsgTx
|
||||
var originTx *btcutil.Tx
|
||||
if origintxidx != math.MaxUint32 {
|
||||
txInfo, ok := txStore[*originTxSha]
|
||||
if !ok {
|
||||
|
@ -87,8 +81,7 @@ func ValidateTransactionScripts(tx *btcwire.MsgTx, txHash *btcwire.ShaHash, txSt
|
|||
}
|
||||
originTx = txInfo.Tx
|
||||
}
|
||||
err := validateTxIn(txInIdx, job[txInIdx], txHash, tx, originTx,
|
||||
flags)
|
||||
err := validateTxIn(txInIdx, txin, tx, originTx, flags)
|
||||
r := txValidate{txInIdx, err}
|
||||
c <- r
|
||||
}
|
||||
|
@ -114,7 +107,8 @@ func ValidateTransactionScripts(tx *btcwire.MsgTx, txHash *btcwire.ShaHash, txSt
|
|||
}
|
||||
for i := 0; i < len(job); i++ {
|
||||
if resultErrors[i] != nil {
|
||||
log.Warnf("tx %v failed input %v, err %v", txHash, i, resultErrors[i])
|
||||
log.Warnf("tx %v failed input %v, err %v", tx.Sha(), i,
|
||||
resultErrors[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
|
@ -130,17 +124,14 @@ func checkBlockScripts(block *btcutil.Block, txStore TxStore) error {
|
|||
flags |= btcscript.ScriptBip16
|
||||
}
|
||||
|
||||
txList := block.MsgBlock().Transactions
|
||||
txList := block.Transactions()
|
||||
c := make(chan txValidate)
|
||||
resultErrors := make([]error, len(txList))
|
||||
|
||||
var currentItem int
|
||||
var completedItems int
|
||||
processFunc := func(txIdx int) {
|
||||
tx := txList[txIdx]
|
||||
txHash, _ := block.TxSha(txIdx)
|
||||
|
||||
err := ValidateTransactionScripts(tx, txHash, txStore, flags)
|
||||
err := ValidateTransactionScripts(txList[txIdx], txStore, flags)
|
||||
r := txValidate{txIdx, err}
|
||||
c <- r
|
||||
}
|
||||
|
|
55
txlookup.go
55
txlookup.go
|
@ -14,7 +14,7 @@ import (
|
|||
// TxData contains contextual information about transactions such as which block
|
||||
// they were found in and whether or not the outputs are spent.
|
||||
type TxData struct {
|
||||
Tx *btcwire.MsgTx
|
||||
Tx *btcutil.Tx
|
||||
Hash *btcwire.ShaHash
|
||||
BlockHeight int64
|
||||
Spent []bool
|
||||
|
@ -33,23 +33,19 @@ type TxStore map[btcwire.ShaHash]*TxData
|
|||
func connectTransactions(txStore TxStore, block *btcutil.Block) error {
|
||||
// Loop through all of the transactions in the block to see if any of
|
||||
// them are ones we need to update and spend based on the results map.
|
||||
for i, tx := range block.MsgBlock().Transactions {
|
||||
txHash, err := block.TxSha(i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, tx := range block.Transactions() {
|
||||
// Update the transaction store with the transaction information
|
||||
// if it's one of the requested transactions.
|
||||
if txD, exists := txStore[*txHash]; exists {
|
||||
msgTx := tx.MsgTx()
|
||||
if txD, exists := txStore[*tx.Sha()]; exists {
|
||||
txD.Tx = tx
|
||||
txD.BlockHeight = block.Height()
|
||||
txD.Spent = make([]bool, len(tx.TxOut))
|
||||
txD.Spent = make([]bool, len(msgTx.TxOut))
|
||||
txD.Err = nil
|
||||
}
|
||||
|
||||
// Spend the origin transaction output.
|
||||
for _, txIn := range tx.TxIn {
|
||||
for _, txIn := range msgTx.TxIn {
|
||||
originHash := &txIn.PreviousOutpoint.Hash
|
||||
originIndex := txIn.PreviousOutpoint.Index
|
||||
if originTx, exists := txStore[*originHash]; exists {
|
||||
|
@ -67,18 +63,13 @@ func connectTransactions(txStore TxStore, block *btcutil.Block) error {
|
|||
func disconnectTransactions(txStore TxStore, block *btcutil.Block) error {
|
||||
// Loop through all of the transactions in the block to see if any of
|
||||
// them are ones that need to be undone based on the transaction store.
|
||||
for i, tx := range block.MsgBlock().Transactions {
|
||||
txHash, err := block.TxSha(i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, tx := range block.Transactions() {
|
||||
// Clear this transaction from the transaction store if needed.
|
||||
// Only clear it rather than deleting it because the transaction
|
||||
// connect code relies on its presence to decide whether or not
|
||||
// to update the store and any transactions which exist on both
|
||||
// sides of a fork would otherwise not be updated.
|
||||
if txD, exists := txStore[*txHash]; exists {
|
||||
if txD, exists := txStore[*tx.Sha()]; exists {
|
||||
txD.Tx = nil
|
||||
txD.BlockHeight = 0
|
||||
txD.Spent = nil
|
||||
|
@ -86,7 +77,7 @@ func disconnectTransactions(txStore TxStore, block *btcutil.Block) error {
|
|||
}
|
||||
|
||||
// Unspend the origin transaction output.
|
||||
for _, txIn := range tx.TxIn {
|
||||
for _, txIn := range tx.MsgTx().TxIn {
|
||||
originHash := &txIn.PreviousOutpoint.Hash
|
||||
originIndex := txIn.PreviousOutpoint.Index
|
||||
originTx, exists := txStore[*originHash]
|
||||
|
@ -146,7 +137,7 @@ func fetchTxStoreMain(db btcdb.Db, txSet map[btcwire.ShaHash]bool, includeSpent
|
|||
// cause subtle errors, so avoid the potential altogether.
|
||||
txD.Err = txReply.Err
|
||||
if txReply.Err == nil {
|
||||
txD.Tx = txReply.Tx
|
||||
txD.Tx = btcutil.NewTx(txReply.Tx)
|
||||
txD.BlockHeight = txReply.Height
|
||||
txD.Spent = make([]bool, len(txReply.TxSpent))
|
||||
copy(txD.Spent, txReply.TxSpent)
|
||||
|
@ -240,14 +231,9 @@ func (b *BlockChain) fetchInputTransactions(node *blockNode, block *btcutil.Bloc
|
|||
// this block could be referencing other transactions earlier in this
|
||||
// block which are not yet in the chain.
|
||||
txInFlight := map[btcwire.ShaHash]int{}
|
||||
transactions := block.MsgBlock().Transactions
|
||||
for i := range transactions {
|
||||
// Get transaction hash. It's safe to ignore the error since
|
||||
// it's already cached in the nominal code path and the only
|
||||
// way it can fail is if the index is out of range which is
|
||||
// impossible here.
|
||||
txHash, _ := block.TxSha(i)
|
||||
txInFlight[*txHash] = i
|
||||
transactions := block.Transactions()
|
||||
for i, tx := range transactions {
|
||||
txInFlight[*tx.Sha()] = i
|
||||
}
|
||||
|
||||
// Loop through all of the transaction inputs (except for the coinbase
|
||||
|
@ -256,7 +242,7 @@ func (b *BlockChain) fetchInputTransactions(node *blockNode, block *btcutil.Bloc
|
|||
txNeededSet := make(map[btcwire.ShaHash]bool)
|
||||
txStore := make(TxStore)
|
||||
for i, tx := range transactions[1:] {
|
||||
for _, txIn := range tx.TxIn {
|
||||
for _, txIn := range tx.MsgTx().TxIn {
|
||||
// Add an entry to the transaction store for the needed
|
||||
// transaction with it set to missing by default.
|
||||
originHash := &txIn.PreviousOutpoint.Hash
|
||||
|
@ -279,7 +265,7 @@ func (b *BlockChain) fetchInputTransactions(node *blockNode, block *btcutil.Bloc
|
|||
originTx := transactions[inFlightIndex]
|
||||
txD.Tx = originTx
|
||||
txD.BlockHeight = node.height
|
||||
txD.Spent = make([]bool, len(originTx.TxOut))
|
||||
txD.Spent = make([]bool, len(originTx.MsgTx().TxOut))
|
||||
txD.Err = nil
|
||||
} else {
|
||||
txNeededSet[*originHash] = true
|
||||
|
@ -306,18 +292,13 @@ func (b *BlockChain) fetchInputTransactions(node *blockNode, block *btcutil.Bloc
|
|||
// passed transaction from the point of view of the end of the main chain. It
|
||||
// also attempts to fetch the transaction itself so the returned TxStore can be
|
||||
// examined for duplicate transactions.
|
||||
func (b *BlockChain) FetchTransactionStore(tx *btcwire.MsgTx) (TxStore, error) {
|
||||
txHash, err := tx.TxSha()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (b *BlockChain) FetchTransactionStore(tx *btcutil.Tx) (TxStore, error) {
|
||||
// Create a set of needed transactions from the transactions referenced
|
||||
// by the inputs of the passed transaction. Also, add the passed
|
||||
// transaction itself as a way for the caller to detect duplicates.
|
||||
txNeededSet := make(map[btcwire.ShaHash]bool)
|
||||
txNeededSet[txHash] = true
|
||||
for _, txIn := range tx.TxIn {
|
||||
txNeededSet[*tx.Sha()] = true
|
||||
for _, txIn := range tx.MsgTx().TxIn {
|
||||
txNeededSet[txIn.PreviousOutpoint.Hash] = true
|
||||
}
|
||||
|
||||
|
|
80
validate.go
80
validate.go
|
@ -94,7 +94,9 @@ func isNullOutpoint(outpoint *btcwire.OutPoint) bool {
|
|||
// represented in the block chain by a transaction with a single input that has
|
||||
// a previous output transaction index set to the maximum value along with a
|
||||
// zero hash.
|
||||
func IsCoinBase(msgTx *btcwire.MsgTx) bool {
|
||||
func IsCoinBase(tx *btcutil.Tx) bool {
|
||||
msgTx := tx.MsgTx()
|
||||
|
||||
// A coin base must only have one transaction input.
|
||||
if len(msgTx.TxIn) != 1 {
|
||||
return false
|
||||
|
@ -111,7 +113,9 @@ func IsCoinBase(msgTx *btcwire.MsgTx) bool {
|
|||
}
|
||||
|
||||
// IsFinalizedTransaction determines whether or not a transaction is finalized.
|
||||
func IsFinalizedTransaction(msgTx *btcwire.MsgTx, blockHeight int64, blockTime time.Time) bool {
|
||||
func IsFinalizedTransaction(tx *btcutil.Tx, blockHeight int64, blockTime time.Time) bool {
|
||||
msgTx := tx.MsgTx()
|
||||
|
||||
// Lock time of zero means the transaction is finalized.
|
||||
lockTime := msgTx.LockTime
|
||||
if lockTime == 0 {
|
||||
|
@ -175,14 +179,15 @@ func calcBlockSubsidy(height int64) int64 {
|
|||
|
||||
// CheckTransactionSanity performs some preliminary checks on a transaction to
|
||||
// ensure it is sane. These checks are context free.
|
||||
func CheckTransactionSanity(tx *btcwire.MsgTx) error {
|
||||
func CheckTransactionSanity(tx *btcutil.Tx) error {
|
||||
// A transaction must have at least one input.
|
||||
if len(tx.TxIn) == 0 {
|
||||
msgTx := tx.MsgTx()
|
||||
if len(msgTx.TxIn) == 0 {
|
||||
return RuleError("transaction has no inputs")
|
||||
}
|
||||
|
||||
// A transaction must have at least one output.
|
||||
if len(tx.TxOut) == 0 {
|
||||
if len(msgTx.TxOut) == 0 {
|
||||
return RuleError("transaction has no outputs")
|
||||
}
|
||||
|
||||
|
@ -198,7 +203,7 @@ func CheckTransactionSanity(tx *btcwire.MsgTx) error {
|
|||
// as a satoshi. One bitcoin is a quantity of satoshi as defined by the
|
||||
// satoshiPerBitcoin constant.
|
||||
var totalSatoshi int64
|
||||
for _, txOut := range tx.TxOut {
|
||||
for _, txOut := range msgTx.TxOut {
|
||||
satoshi := txOut.Value
|
||||
if satoshi < 0 {
|
||||
str := fmt.Sprintf("transaction output has negative "+
|
||||
|
@ -231,7 +236,7 @@ func CheckTransactionSanity(tx *btcwire.MsgTx) error {
|
|||
|
||||
// Check for duplicate transaction inputs.
|
||||
existingTxOut := make(map[btcwire.OutPoint]bool)
|
||||
for _, txIn := range tx.TxIn {
|
||||
for _, txIn := range msgTx.TxIn {
|
||||
if _, exists := existingTxOut[txIn.PreviousOutpoint]; exists {
|
||||
return RuleError("transaction contains duplicate outpoint")
|
||||
}
|
||||
|
@ -240,7 +245,7 @@ func CheckTransactionSanity(tx *btcwire.MsgTx) error {
|
|||
|
||||
// Coinbase script length must be between min and max length.
|
||||
if IsCoinBase(tx) {
|
||||
slen := len(tx.TxIn[0].SignatureScript)
|
||||
slen := len(msgTx.TxIn[0].SignatureScript)
|
||||
if slen < minCoinbaseScriptLen || slen > maxCoinbaseScriptLen {
|
||||
str := fmt.Sprintf("coinbase transaction script length "+
|
||||
"of %d is out of range (min: %d, max: %d)",
|
||||
|
@ -250,7 +255,7 @@ func CheckTransactionSanity(tx *btcwire.MsgTx) error {
|
|||
} else {
|
||||
// Previous transaction outputs referenced by the inputs to this
|
||||
// transaction must not be null.
|
||||
for _, txIn := range tx.TxIn {
|
||||
for _, txIn := range msgTx.TxIn {
|
||||
prevOut := &txIn.PreviousOutpoint
|
||||
if isNullOutpoint(prevOut) {
|
||||
return RuleError("transaction input refers to " +
|
||||
|
@ -302,7 +307,9 @@ func (b *BlockChain) checkProofOfWork(block *btcutil.Block) error {
|
|||
// input and output scripts in the provided transaction. This uses the
|
||||
// quicker, but imprecise, signature operation counting mechanism from
|
||||
// btcscript.
|
||||
func countSigOps(msgTx *btcwire.MsgTx) int {
|
||||
func countSigOps(tx *btcutil.Tx) int {
|
||||
msgTx := tx.MsgTx()
|
||||
|
||||
// Accumulate the number of signature operations in all transaction
|
||||
// inputs.
|
||||
totalSigOps := 0
|
||||
|
@ -325,20 +332,15 @@ func countSigOps(msgTx *btcwire.MsgTx) int {
|
|||
// transactions which are of the pay-to-script-hash type. This uses the
|
||||
// precise, signature operation counting mechanism from btcscript which requires
|
||||
// access to the input transaction scripts.
|
||||
func countP2SHSigOps(msgTx *btcwire.MsgTx, isCoinBaseTx bool, txStore TxStore) (int, error) {
|
||||
func countP2SHSigOps(tx *btcutil.Tx, isCoinBaseTx bool, txStore TxStore) (int, error) {
|
||||
// Coinbase transactions have no interesting inputs.
|
||||
if isCoinBaseTx {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// TODO(davec): Need to pass the cached version in.
|
||||
txHash, err := msgTx.TxSha()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Accumulate the number of signature operations in all transaction
|
||||
// inputs.
|
||||
msgTx := tx.MsgTx()
|
||||
totalSigOps := 0
|
||||
for _, txIn := range msgTx.TxIn {
|
||||
// Ensure the referenced input transaction is available.
|
||||
|
@ -347,23 +349,24 @@ func countP2SHSigOps(msgTx *btcwire.MsgTx, isCoinBaseTx bool, txStore TxStore) (
|
|||
if !exists || originTx.Err != nil || originTx.Tx == nil {
|
||||
str := fmt.Sprintf("unable to find input transaction "+
|
||||
"%v referenced from transaction %v", txInHash,
|
||||
txHash)
|
||||
tx.Sha())
|
||||
return 0, RuleError(str)
|
||||
}
|
||||
originMsgTx := originTx.Tx.MsgTx()
|
||||
|
||||
// Ensure the output index in the referenced transaction is
|
||||
// available.
|
||||
originTxIndex := txIn.PreviousOutpoint.Index
|
||||
if originTxIndex >= uint32(len(originTx.Tx.TxOut)) {
|
||||
if originTxIndex >= uint32(len(originMsgTx.TxOut)) {
|
||||
str := fmt.Sprintf("out of bounds input index %d in "+
|
||||
"transaction %v referenced from transaction %v",
|
||||
originTxIndex, txInHash, txHash)
|
||||
originTxIndex, txInHash, tx.Sha())
|
||||
return 0, RuleError(str)
|
||||
}
|
||||
|
||||
// We're only interested in pay-to-script-hash types, so skip
|
||||
// this input if it's not one.
|
||||
pkScript := originTx.Tx.TxOut[originTxIndex].PkScript
|
||||
pkScript := originMsgTx.TxOut[originTxIndex].PkScript
|
||||
if !btcscript.IsPayToScriptHash(pkScript) {
|
||||
continue
|
||||
}
|
||||
|
@ -407,8 +410,7 @@ func (b *BlockChain) checkBlockSanity(block *btcutil.Block) error {
|
|||
}
|
||||
|
||||
// Ensure the block time is not more than 2 hours in the future.
|
||||
msgBlock := block.MsgBlock()
|
||||
header := &msgBlock.Header
|
||||
header := &block.MsgBlock().Header
|
||||
if header.Timestamp.After(time.Now().Add(time.Hour * 2)) {
|
||||
str := fmt.Sprintf("block timestamp of %v is too far in the "+
|
||||
"future", header.Timestamp)
|
||||
|
@ -416,7 +418,7 @@ func (b *BlockChain) checkBlockSanity(block *btcutil.Block) error {
|
|||
}
|
||||
|
||||
// A block must have at least one transaction.
|
||||
transactions := msgBlock.Transactions
|
||||
transactions := block.Transactions()
|
||||
if len(transactions) == 0 {
|
||||
return RuleError("block does not contain any transactions")
|
||||
}
|
||||
|
@ -463,11 +465,8 @@ func (b *BlockChain) checkBlockSanity(block *btcutil.Block) error {
|
|||
// since the transaction hashes are already cached due to building the
|
||||
// merkle tree above.
|
||||
existingTxHashes := make(map[btcwire.ShaHash]bool)
|
||||
txShas, err := block.TxShas()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, hash := range txShas {
|
||||
for _, tx := range transactions {
|
||||
hash := tx.Sha()
|
||||
if _, exists := existingTxHashes[*hash]; exists {
|
||||
str := fmt.Sprintf("block contains duplicate "+
|
||||
"transaction %v", hash)
|
||||
|
@ -497,8 +496,8 @@ func (b *BlockChain) checkBlockSanity(block *btcutil.Block) error {
|
|||
|
||||
// checkSerializedHeight checks if the signature script in the passed
|
||||
// transaction starts with the serialized block height of wantHeight.
|
||||
func checkSerializedHeight(coinbaseTx *btcwire.MsgTx, wantHeight int64) error {
|
||||
sigScript := coinbaseTx.TxIn[0].SignatureScript
|
||||
func checkSerializedHeight(coinbaseTx *btcutil.Tx, wantHeight int64) error {
|
||||
sigScript := coinbaseTx.MsgTx().TxIn[0].SignatureScript
|
||||
if len(sigScript) < 1 {
|
||||
str := "the coinbase signature script for blocks of " +
|
||||
"version %d or greater must start with the " +
|
||||
|
@ -601,20 +600,15 @@ func (b *BlockChain) checkBIP0030(node *blockNode, block *btcutil.Block) error {
|
|||
// amount, and verifying the signatures to prove the spender was the owner of
|
||||
// the bitcoins and therefore allowed to spend them. As it checks the inputs,
|
||||
// it also calculates the total fees for the transaction and returns that value.
|
||||
func CheckTransactionInputs(tx *btcwire.MsgTx, txHeight int64, txStore TxStore) (int64, error) {
|
||||
func CheckTransactionInputs(tx *btcutil.Tx, txHeight int64, txStore TxStore) (int64, error) {
|
||||
// Coinbase transactions have no inputs.
|
||||
if IsCoinBase(tx) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// TODO(davec): Need to pass the cached version in.
|
||||
txHash, err := tx.TxSha()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
txHash := tx.Sha()
|
||||
var totalSatoshiIn int64
|
||||
for _, txIn := range tx.TxIn {
|
||||
for _, txIn := range tx.MsgTx().TxIn {
|
||||
// Ensure the input is available.
|
||||
txInHash := &txIn.PreviousOutpoint.Hash
|
||||
originTx, exists := txStore[*txInHash]
|
||||
|
@ -659,7 +653,7 @@ func CheckTransactionInputs(tx *btcwire.MsgTx, txHeight int64, txStore TxStore)
|
|||
// a transaction are in a unit value known as a satoshi. One
|
||||
// bitcoin is a quantity of satoshi as defined by the
|
||||
// satoshiPerBitcoin constant.
|
||||
originTxSatoshi := originTx.Tx.TxOut[originTxIndex].Value
|
||||
originTxSatoshi := originTx.Tx.MsgTx().TxOut[originTxIndex].Value
|
||||
if originTxSatoshi < 0 {
|
||||
str := fmt.Sprintf("transaction output has negative "+
|
||||
"value of %v", originTxSatoshi)
|
||||
|
@ -693,7 +687,7 @@ func CheckTransactionInputs(tx *btcwire.MsgTx, txHeight int64, txStore TxStore)
|
|||
// to ignore overflow and out of range errors here because those error
|
||||
// conditions would have already been caught by checkTransactionSanity.
|
||||
var totalSatoshiOut int64
|
||||
for _, txOut := range tx.TxOut {
|
||||
for _, txOut := range tx.MsgTx().TxOut {
|
||||
totalSatoshiOut += txOut.Value
|
||||
}
|
||||
|
||||
|
@ -771,7 +765,7 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block) er
|
|||
// expands the count to include a precise count of pay-to-script-hash
|
||||
// signature operations in each of the input transaction public key
|
||||
// scripts.
|
||||
transactions := block.MsgBlock().Transactions
|
||||
transactions := block.Transactions()
|
||||
totalSigOps := 0
|
||||
for i, tx := range transactions {
|
||||
numsigOps := countSigOps(tx)
|
||||
|
@ -832,7 +826,7 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block) er
|
|||
// errors here because those error conditions would have already been
|
||||
// caught by checkTransactionSanity.
|
||||
var totalSatoshiOut int64
|
||||
for _, txOut := range transactions[0].TxOut {
|
||||
for _, txOut := range transactions[0].MsgTx().TxOut {
|
||||
totalSatoshiOut += txOut.Value
|
||||
}
|
||||
expectedSatoshiOut := calcBlockSubsidy(node.height) + totalFees
|
||||
|
|
|
@ -66,8 +66,9 @@ func TestCheckSerializedHeight(t *testing.T) {
|
|||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
tx := coinbaseTx.Copy()
|
||||
tx.TxIn[0].SignatureScript = test.sigScript
|
||||
msgTx := coinbaseTx.Copy()
|
||||
msgTx.TxIn[0].SignatureScript = test.sigScript
|
||||
tx := btcutil.NewTx(msgTx)
|
||||
|
||||
err := btcchain.TstCheckSerializedHeight(tx, test.wantHeight)
|
||||
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
|
||||
|
|
Loading…
Add table
Reference in a new issue