// CountP2SHSigOps returns the number of signature operations for all input // transactions which are of the pay-to-script-hash type. This uses the // precise, signature operation counting mechanism from the script engine which // requires access to the input transaction scripts. func CountP2SHSigOps(tx *btcutil.Tx, isCoinBaseTx bool, txStore TxStore) (int, error) { // Coinbase transactions have no interesting inputs. if isCoinBaseTx { return 0, nil } // 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. txInHash := &txIn.PreviousOutPoint.Hash originTx, exists := txStore[*txInHash] if !exists || originTx.Err != nil || originTx.Tx == nil { str := fmt.Sprintf("unable to find input transaction "+ "%v referenced from transaction %v", txInHash, tx.Sha()) return 0, ruleError(ErrMissingTx, str) } originMsgTx := originTx.Tx.MsgTx() // Ensure the output index in the referenced transaction is // available. originTxIndex := txIn.PreviousOutPoint.Index if originTxIndex >= uint32(len(originMsgTx.TxOut)) { str := fmt.Sprintf("out of bounds input index %d in "+ "transaction %v referenced from transaction %v", originTxIndex, txInHash, tx.Sha()) return 0, ruleError(ErrBadTxInput, str) } // We're only interested in pay-to-script-hash types, so skip // this input if it's not one. pkScript := originMsgTx.TxOut[originTxIndex].PkScript if !txscript.IsPayToScriptHash(pkScript) { continue } // Count the precise number of signature operations in the // referenced public key script. sigScript := txIn.SignatureScript numSigOps := txscript.GetPreciseSigOpCount(sigScript, pkScript, true) // We could potentially overflow the accumulator so check for // overflow. lastSigOps := totalSigOps totalSigOps += numSigOps if totalSigOps < lastSigOps { str := fmt.Sprintf("the public key script from "+ "output index %d in transaction %v contains "+ "too many signature operations - overflow", originTxIndex, txInHash) return 0, ruleError(ErrTooManySigOps, str) } } return totalSigOps, nil }
// calcPriority returns a transaction priority given a transaction and the sum // of each of its input values multiplied by their age (# of confirmations). // Thus, the final formula for the priority is: // sum(inputValue * inputAge) / adjustedTxSize func calcPriority(tx *btcutil.Tx, serializedTxSize int, inputValueAge float64) float64 { // In order to encourage spending multiple old unspent transaction // outputs thereby reducing the total set, don't count the constant // overhead for each input as well as enough bytes of the signature // script to cover a pay-to-script-hash redemption with a compressed // pubkey. This makes additional inputs free by boosting the priority // of the transaction accordingly. No more incentive is given to avoid // encouraging gaming future transactions through the use of junk // outputs. This is the same logic used in the reference // implementation. // // The constant overhead for a txin is 41 bytes since the previous // outpoint is 36 bytes + 4 bytes for the sequence + 1 byte the // signature script length. // // A compressed pubkey pay-to-script-hash redemption with a maximum len // signature is of the form: // [OP_DATA_73 <73-byte sig> + OP_DATA_35 + {OP_DATA_33 // <33 byte compresed pubkey> + OP_CHECKSIG}] // // Thus 1 + 73 + 1 + 1 + 33 + 1 = 110 overhead := 0 for _, txIn := range tx.MsgTx().TxIn { // Max inputs + size can't possibly overflow here. overhead += 41 + minInt(110, len(txIn.SignatureScript)) } if overhead >= serializedTxSize { return 0.0 } return inputValueAge / float64(serializedTxSize-overhead) }
// checkSerializedHeight checks if the signature script in the passed // transaction starts with the serialized block height of wantHeight. 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 " + "length of the serialized block height" str = fmt.Sprintf(str, serializedHeightVersion) return ruleError(ErrMissingCoinbaseHeight, str) } serializedLen := int(sigScript[0]) if len(sigScript[1:]) < serializedLen { str := "the coinbase signature script for blocks of " + "version %d or greater must start with the " + "serialized block height" str = fmt.Sprintf(str, serializedLen) return ruleError(ErrMissingCoinbaseHeight, str) } serializedHeightBytes := make([]byte, 8, 8) copy(serializedHeightBytes, sigScript[1:serializedLen+1]) serializedHeight := binary.LittleEndian.Uint64(serializedHeightBytes) if int64(serializedHeight) != wantHeight { str := fmt.Sprintf("the coinbase signature script serialized "+ "block height is %d when %d was expected", serializedHeight, wantHeight) return ruleError(ErrBadCoinbaseHeight, str) } return nil }
// IsFinalizedTransaction determines whether or not a transaction is finalized. 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 { return true } // The lock time field of a transaction is either a block height at // which the transaction is finalized or a timestamp depending on if the // value is before the lockTimeThreshold. When it is under the // threshold it is a block height. blockTimeOrHeight := int64(0) if lockTime < lockTimeThreshold { blockTimeOrHeight = blockHeight } else { blockTimeOrHeight = blockTime.Unix() } if int64(lockTime) < blockTimeOrHeight { return true } // At this point, the transaction's lock time hasn't occured yet, but // the transaction might still be finalized if the sequence number // for all transaction inputs is maxed out. for _, txIn := range msgTx.TxIn { if txIn.Sequence != math.MaxUint32 { return false } } return true }
// ValidateTransactionScripts validates the scripts for the passed transaction // using multiple goroutines. func ValidateTransactionScripts(tx *btcutil.Tx, txStore TxStore, flags txscript.ScriptFlags) error { // Collect all of the transaction inputs and required information for // validation. txIns := tx.MsgTx().TxIn txValItems := make([]*txValidateItem, 0, len(txIns)) for txInIdx, txIn := range txIns { // Skip coinbases. if txIn.PreviousOutPoint.Index == math.MaxUint32 { continue } txVI := &txValidateItem{ txInIndex: txInIdx, txIn: txIn, tx: tx, } txValItems = append(txValItems, txVI) } // Validate all of the inputs. validator := newTxValidator(txStore, flags) if err := validator.Validate(txValItems); err != nil { return err } return nil }
// isNonstandardTransaction determines whether a transaction contains any // scripts which are not one of the standard types. 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.MsgTx().TxOut { scriptClass := txscript.GetScriptClass(txOut.PkScript) if scriptClass == txscript.NonStandardTy { return true } } return false }
// checkPoolDoubleSpend checks whether or not the passed transaction is // attempting to spend coins already spent by other transactions in the pool. // Note it does not check for double spends against transactions already in the // main chain. // // This function MUST be called with the mempool lock held (for reads). func (mp *txMemPool) checkPoolDoubleSpend(tx *btcutil.Tx) error { for _, txIn := range tx.MsgTx().TxIn { if txR, exists := mp.outpoints[txIn.PreviousOutPoint]; exists { str := fmt.Sprintf("output %v already spent by "+ "transaction %v in the memory pool", txIn.PreviousOutPoint, txR.Sha()) return txRuleError(btcwire.RejectDuplicate, str) } } return nil }
// RemoveDoubleSpends removes all transactions which spend outputs spent by the // passed transaction from the memory pool. Removing those transactions then // leads to removing all transactions which rely on them, recursively. This is // necessary when a block is connected to the main chain because the block may // contain transactions which were previously unknown to the memory pool // // This function is safe for concurrent access. func (mp *txMemPool) RemoveDoubleSpends(tx *btcutil.Tx) { // Protect concurrent access. mp.Lock() defer mp.Unlock() for _, txIn := range tx.MsgTx().TxIn { if txRedeemer, ok := mp.outpoints[txIn.PreviousOutPoint]; ok { if !txRedeemer.Sha().IsEqual(tx.Sha()) { mp.removeTransaction(txRedeemer) } } } }
// addTransaction adds the passed transaction to the memory pool. It should // not be called directly as it doesn't perform any validation. This is a // helper for maybeAcceptTransaction. // // This function MUST be called with the mempool lock held (for writes). func (mp *txMemPool) addTransaction(tx *btcutil.Tx, height, fee int64) { // Add the transaction to the pool and mark the referenced outpoints // as spent by the pool. mp.pool[*tx.Sha()] = &TxDesc{ Tx: tx, Added: time.Now(), Height: height, Fee: fee, } for _, txIn := range tx.MsgTx().TxIn { mp.outpoints[txIn.PreviousOutPoint] = tx } mp.lastUpdated = time.Now() }
// FetchTransactionStore fetches the input transactions referenced by the // 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 *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]struct{}) txNeededSet[*tx.Sha()] = struct{}{} for _, txIn := range tx.MsgTx().TxIn { txNeededSet[txIn.PreviousOutPoint.Hash] = struct{}{} } // Request the input transactions from the point of view of the end of // the main chain without including fully spent trasactions in the // results. Fully spent transactions are only needed for chain // reorganization which does not apply here. txStore := fetchTxStoreMain(b.db, txNeededSet, false) return txStore, nil }
// addOrphan adds an orphan transaction to the orphan pool. // // This function MUST be called with the mempool lock held (for writes). func (mp *txMemPool) addOrphan(tx *btcutil.Tx) { // Limit the number orphan transactions to prevent memory exhaustion. A // random orphan is evicted to make room if needed. mp.limitNumOrphans() mp.orphans[*tx.Sha()] = tx for _, txIn := range tx.MsgTx().TxIn { originTxHash := txIn.PreviousOutPoint.Hash if mp.orphansByPrev[originTxHash] == nil { mp.orphansByPrev[originTxHash] = list.New() } mp.orphansByPrev[originTxHash].PushBack(tx) } txmpLog.Debugf("Stored orphan transaction %v (total: %d)", tx.Sha(), len(mp.orphans)) }
// IsCoinBase determines whether or not a transaction is a coinbase. A coinbase // is a special transaction created by miners that has no inputs. This is // 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(tx *btcutil.Tx) bool { msgTx := tx.MsgTx() // A coin base must only have one transaction input. if len(msgTx.TxIn) != 1 { return false } // The previous output of a coin base must have a max value index and // a zero hash. prevOut := msgTx.TxIn[0].PreviousOutPoint if prevOut.Index != math.MaxUint32 || !prevOut.Hash.IsEqual(zeroHash) { return false } return true }
// checkInputsStandard performs a series of checks on a transaction's inputs // to ensure they are "standard". A standard transaction input is one that // that consumes the expected number of elements from the stack and that number // is the same as the output script pushes. This help prevent resource // exhaustion attacks by "creative" use of scripts that are super expensive to // process like OP_DUP OP_CHECKSIG OP_DROP repeated a large number of times // followed by a final OP_TRUE. func checkInputsStandard(tx *btcutil.Tx, txStore blockchain.TxStore) error { // NOTE: The reference implementation also does a coinbase check here, // but coinbases have already been rejected prior to calling this // function so no need to recheck. for i, txIn := range tx.MsgTx().TxIn { // It is safe to elide existence and index checks here since // they have already been checked prior to calling this // function. prevOut := txIn.PreviousOutPoint originTx := txStore[prevOut.Hash].Tx.MsgTx() originPkScript := originTx.TxOut[prevOut.Index].PkScript // Calculate stats for the script pair. scriptInfo, err := txscript.CalcScriptInfo(txIn.SignatureScript, originPkScript, true) if err != nil { str := fmt.Sprintf("transaction input #%d script parse "+ "failure: %v", i, err) return txRuleError(btcwire.RejectNonstandard, str) } // A negative value for expected inputs indicates the script is // non-standard in some way. if scriptInfo.ExpectedInputs < 0 { str := fmt.Sprintf("transaction input #%d expects %d "+ "inputs", i, scriptInfo.ExpectedInputs) return txRuleError(btcwire.RejectNonstandard, str) } // The script pair is non-standard if the number of available // inputs does not match the number of expected inputs. if scriptInfo.NumInputs != scriptInfo.ExpectedInputs { str := fmt.Sprintf("transaction input #%d expects %d "+ "inputs, but referenced output script provides "+ "%d", i, scriptInfo.ExpectedInputs, scriptInfo.NumInputs) return txRuleError(btcwire.RejectNonstandard, str) } } return nil }
// spendTransaction updates the passed transaction store by marking the inputs // to the passed transaction as spent. It also adds the passed transaction to // the store at the provided height. func spendTransaction(txStore blockchain.TxStore, tx *btcutil.Tx, height int64) error { for _, txIn := range tx.MsgTx().TxIn { originHash := &txIn.PreviousOutPoint.Hash originIndex := txIn.PreviousOutPoint.Index if originTx, exists := txStore[*originHash]; exists { originTx.Spent[originIndex] = true } } txStore[*tx.Sha()] = &blockchain.TxData{ Tx: tx, Hash: tx.Sha(), BlockHeight: height, Spent: make([]bool, len(tx.MsgTx().TxOut)), Err: nil, } return nil }
// removeTransaction is the internal function which implements the public // RemoveTransaction. See the comment for RemoveTransaction for more details. // // This function MUST be called with the mempool lock held (for writes). func (mp *txMemPool) removeTransaction(tx *btcutil.Tx) { // Remove any transactions which rely on this one. txHash := tx.Sha() for i := uint32(0); i < uint32(len(tx.MsgTx().TxOut)); i++ { outpoint := btcwire.NewOutPoint(txHash, i) if txRedeemer, exists := mp.outpoints[*outpoint]; exists { mp.removeTransaction(txRedeemer) } } // Remove the transaction and mark the referenced outpoints as unspent // by the pool. if txDesc, exists := mp.pool[*txHash]; exists { for _, txIn := range txDesc.Tx.MsgTx().TxIn { delete(mp.outpoints, txIn.PreviousOutPoint) } delete(mp.pool, *txHash) mp.lastUpdated = time.Now() } }
// CountSigOps returns the number of signature operations for all transaction // input and output scripts in the provided transaction. This uses the // quicker, but imprecise, signature operation counting mechanism from // txscript. func CountSigOps(tx *btcutil.Tx) int { msgTx := tx.MsgTx() // Accumulate the number of signature operations in all transaction // inputs. totalSigOps := 0 for _, txIn := range msgTx.TxIn { numSigOps := txscript.GetSigOpCount(txIn.SignatureScript) totalSigOps += numSigOps } // Accumulate the number of signature operations in all transaction // outputs. for _, txOut := range msgTx.TxOut { numSigOps := txscript.GetSigOpCount(txOut.PkScript) totalSigOps += numSigOps } return totalSigOps }
// maybeAddOrphan potentially adds an orphan to the orphan pool. // // This function MUST be called with the mempool lock held (for writes). func (mp *txMemPool) maybeAddOrphan(tx *btcutil.Tx) error { // Ignore orphan transactions that are too large. This helps avoid // a memory exhaustion attack based on sending a lot of really large // orphans. In the case there is a valid transaction larger than this, // it will ultimtely be rebroadcast after the parent transactions // have been mined or otherwise received. // // Note that the number of orphan transactions in the orphan pool is // also limited, so this equates to a maximum memory used of // maxOrphanTxSize * maxOrphanTransactions (which is 500MB as of the // time this comment was written). serializedLen := tx.MsgTx().SerializeSize() if serializedLen > maxOrphanTxSize { str := fmt.Sprintf("orphan transaction size of %d bytes is "+ "larger than max allowed size of %d bytes", serializedLen, maxOrphanTxSize) return txRuleError(btcwire.RejectNonstandard, str) } // Add the orphan if the none of the above disqualified it. mp.addOrphan(tx) return nil }
// maybeAcceptTransaction is the internal function which implements the public // MaybeAcceptTransaction. See the comment for MaybeAcceptTransaction for // more details. // // This function MUST be called with the mempool lock held (for writes). func (mp *txMemPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit bool) ([]*btcwire.ShaHash, error) { txHash := tx.Sha() // Don't accept the transaction if it already exists in the pool. This // applies to orphan transactions as well. This check is intended to // be a quick check to weed out duplicates. if mp.haveTransaction(txHash) { str := fmt.Sprintf("already have transaction %v", txHash) return nil, txRuleError(btcwire.RejectDuplicate, str) } // Perform preliminary sanity checks on the transaction. This makes // use of btcchain which contains the invariant rules for what // transactions are allowed into blocks. err := blockchain.CheckTransactionSanity(tx) if err != nil { if cerr, ok := err.(blockchain.RuleError); ok { return nil, chainRuleError(cerr) } return nil, err } // A standalone transaction must not be a coinbase transaction. if blockchain.IsCoinBase(tx) { str := fmt.Sprintf("transaction %v is an individual coinbase", txHash) return nil, txRuleError(btcwire.RejectInvalid, str) } // Don't accept transactions with a lock time after the maximum int32 // value for now. This is an artifact of older bitcoind clients which // treated this field as an int32 and would treat anything larger // incorrectly (as negative). if tx.MsgTx().LockTime > math.MaxInt32 { str := fmt.Sprintf("transaction %v has a lock time after "+ "2038 which is not accepted yet", txHash) return nil, txRuleError(btcwire.RejectNonstandard, str) } // Get the current height of the main chain. A standalone transaction // will be mined into the next block at best, so it's height is at least // one more than the current height. _, curHeight, err := mp.server.db.NewestSha() if err != nil { // This is an unexpected error so don't turn it into a rule // error. return nil, err } nextBlockHeight := curHeight + 1 // Don't allow non-standard transactions if the network parameters // forbid their relaying. if !activeNetParams.RelayNonStdTxs { err := checkTransactionStandard(tx, nextBlockHeight) if err != nil { // Attempt to extract a reject code from the error so // it can be retained. When not possible, fall back to // a non standard error. rejectCode, found := extractRejectCode(err) if !found { rejectCode = btcwire.RejectNonstandard } str := fmt.Sprintf("transaction %v is not standard: %v", txHash, err) return nil, txRuleError(rejectCode, str) } } // The transaction may not use any of the same outputs as other // transactions already in the pool as that would ultimately result in a // double spend. This check is intended to be quick and therefore only // detects double spends within the transaction pool itself. The // transaction could still be double spending coins from the main chain // at this point. There is a more in-depth check that happens later // after fetching the referenced transaction inputs from the main chain // which examines the actual spend data and prevents double spends. err = mp.checkPoolDoubleSpend(tx) if err != nil { return nil, err } // Fetch all of the transactions referenced by the inputs to this // transaction. This function also attempts to fetch the transaction // itself to be used for detecting a duplicate transaction without // needing to do a separate lookup. txStore, err := mp.fetchInputTransactions(tx) if err != nil { if cerr, ok := err.(blockchain.RuleError); ok { return nil, chainRuleError(cerr) } return nil, err } // Don't allow the transaction if it exists in the main chain and is not // not already fully spent. if txD, exists := txStore[*txHash]; exists && txD.Err == nil { for _, isOutputSpent := range txD.Spent { if !isOutputSpent { return nil, txRuleError(btcwire.RejectDuplicate, "transaction already exists") } } } delete(txStore, *txHash) // Transaction is an orphan if any of the referenced input transactions // don't exist. Adding orphans to the orphan pool is not handled by // this function, and the caller should use maybeAddOrphan if this // behavior is desired. var missingParents []*btcwire.ShaHash for _, txD := range txStore { if txD.Err == database.ErrTxShaMissing { missingParents = append(missingParents, txD.Hash) } } if len(missingParents) != 0 { return missingParents, nil } // Perform several checks on the transaction inputs using the invariant // rules in btcchain for what transactions are allowed into blocks. // Also returns the fees associated with the transaction which will be // used later. txFee, err := blockchain.CheckTransactionInputs(tx, nextBlockHeight, txStore) if err != nil { if cerr, ok := err.(blockchain.RuleError); ok { return nil, chainRuleError(cerr) } return nil, err } // Don't allow transactions with non-standard inputs if the network // parameters forbid their relaying. if !activeNetParams.RelayNonStdTxs { err := checkInputsStandard(tx, txStore) if err != nil { // Attempt to extract a reject code from the error so // it can be retained. When not possible, fall back to // a non standard error. rejectCode, found := extractRejectCode(err) if !found { rejectCode = btcwire.RejectNonstandard } str := fmt.Sprintf("transaction %v has a non-standard "+ "input: %v", txHash, err) return nil, txRuleError(rejectCode, str) } } // NOTE: if you modify this code to accept non-standard transactions, // you should add code here to check that the transaction does a // reasonable number of ECDSA signature verifications. // Don't allow transactions with an excessive number of signature // operations which would result in making it impossible to mine. Since // the coinbase address itself can contain signature operations, the // maximum allowed signature operations per transaction is less than // the maximum allowed signature operations per block. numSigOps, err := blockchain.CountP2SHSigOps(tx, false, txStore) if err != nil { if cerr, ok := err.(blockchain.RuleError); ok { return nil, chainRuleError(cerr) } return nil, err } numSigOps += blockchain.CountSigOps(tx) if numSigOps > maxSigOpsPerTx { str := fmt.Sprintf("transaction %v has too many sigops: %d > %d", txHash, numSigOps, maxSigOpsPerTx) return nil, txRuleError(btcwire.RejectNonstandard, str) } // Don't allow transactions with fees too low to get into a mined block. // // Most miners allow a free transaction area in blocks they mine to go // alongside the area used for high-priority transactions as well as // transactions with fees. A transaction size of up to 1000 bytes is // considered safe to go into this section. Further, the minimum fee // calculated below on its own would encourage several small // transactions to avoid fees rather than one single larger transaction // which is more desirable. Therefore, as long as the size of the // transaction does not exceeed 1000 less than the reserved space for // high-priority transactions, don't require a fee for it. serializedSize := int64(tx.MsgTx().SerializeSize()) minFee := calcMinRequiredTxRelayFee(serializedSize) if serializedSize >= (defaultBlockPrioritySize-1000) && txFee < minFee { str := fmt.Sprintf("transaction %v has %d fees which is under "+ "the required amount of %d", txHash, txFee, minFee) return nil, txRuleError(btcwire.RejectInsufficientFee, str) } // Free-to-relay transactions are rate limited here to prevent // penny-flooding with tiny transactions as a form of attack. if rateLimit && txFee < minFee { nowUnix := time.Now().Unix() // we decay passed data with an exponentially decaying ~10 // minutes window - matches bitcoind handling. mp.pennyTotal *= math.Pow(1.0-1.0/600.0, float64(nowUnix-mp.lastPennyUnix)) mp.lastPennyUnix = nowUnix // Are we still over the limit? if mp.pennyTotal >= cfg.FreeTxRelayLimit*10*1000 { str := fmt.Sprintf("transaction %v has been rejected "+ "by the rate limiter due to low fees", txHash) return nil, txRuleError(btcwire.RejectInsufficientFee, str) } oldTotal := mp.pennyTotal mp.pennyTotal += float64(serializedSize) txmpLog.Tracef("rate limit: curTotal %v, nextTotal: %v, "+ "limit %v", oldTotal, mp.pennyTotal, cfg.FreeTxRelayLimit*10*1000) } // Verify crypto signatures for each input and reject the transaction if // any don't verify. err = blockchain.ValidateTransactionScripts(tx, txStore, standardScriptVerifyFlags) if err != nil { if cerr, ok := err.(blockchain.RuleError); ok { return nil, chainRuleError(cerr) } return nil, err } // Add to transaction pool. mp.addTransaction(tx, curHeight, txFee) txmpLog.Debugf("Accepted transaction %v (pool size: %v)", txHash, len(mp.pool)) if mp.server.rpcServer != nil { // Notify websocket clients about mempool transactions. mp.server.rpcServer.ntfnMgr.NotifyMempoolTx(tx, isNew) // Potentially notify any getblocktemplate long poll clients // about stale block templates due to the new transaction. mp.server.rpcServer.gbtWorkState.NotifyMempoolTx(mp.lastUpdated) } return nil, nil }
// checkTransactionStandard performs a series of checks on a transaction to // ensure it is a "standard" transaction. A standard transaction is one that // conforms to several additional limiting cases over what is considered a // "sane" transaction such as having a version in the supported range, being // finalized, conforming to more stringent size constraints, having scripts // of recognized forms, and not containing "dust" outputs (those that are // so small it costs more to process them than they are worth). func checkTransactionStandard(tx *btcutil.Tx, height int64) error { msgTx := tx.MsgTx() // The transaction must be a currently supported version. if msgTx.Version > btcwire.TxVersion || msgTx.Version < 1 { str := fmt.Sprintf("transaction version %d is not in the "+ "valid range of %d-%d", msgTx.Version, 1, btcwire.TxVersion) return txRuleError(btcwire.RejectNonstandard, str) } // The transaction must be finalized to be standard and therefore // considered for inclusion in a block. if !blockchain.IsFinalizedTransaction(tx, height, time.Now()) { return txRuleError(btcwire.RejectNonstandard, "transaction is not finalized") } // Since extremely large transactions with a lot of inputs can cost // almost as much to process as the sender fees, limit the maximum // size of a transaction. This also helps mitigate CPU exhaustion // attacks. serializedLen := msgTx.SerializeSize() if serializedLen > maxStandardTxSize { str := fmt.Sprintf("transaction size of %v is larger than max "+ "allowed size of %v", serializedLen, maxStandardTxSize) return txRuleError(btcwire.RejectNonstandard, str) } for i, txIn := range msgTx.TxIn { // Each transaction input signature script must not exceed the // maximum size allowed for a standard transaction. See // the comment on maxStandardSigScriptSize for more details. sigScriptLen := len(txIn.SignatureScript) if sigScriptLen > maxStandardSigScriptSize { str := fmt.Sprintf("transaction input %d: signature "+ "script size of %d bytes is large than max "+ "allowed size of %d bytes", i, sigScriptLen, maxStandardSigScriptSize) return txRuleError(btcwire.RejectNonstandard, str) } // Each transaction input signature script must only contain // opcodes which push data onto the stack. if !txscript.IsPushOnlyScript(txIn.SignatureScript) { str := fmt.Sprintf("transaction input %d: signature "+ "script is not push only", i) return txRuleError(btcwire.RejectNonstandard, str) } // Each transaction input signature script must only contain // canonical data pushes. A canonical data push is one where // the minimum possible number of bytes is used to represent // the data push as possible. if !txscript.HasCanonicalPushes(txIn.SignatureScript) { str := fmt.Sprintf("transaction input %d: signature "+ "script has a non-canonical data push", i) return txRuleError(btcwire.RejectNonstandard, str) } } // None of the output public key scripts can be a non-standard script or // be "dust" (except when the script is a null data script). numNullDataOutputs := 0 for i, txOut := range msgTx.TxOut { scriptClass := txscript.GetScriptClass(txOut.PkScript) err := checkPkScriptStandard(txOut.PkScript, scriptClass) if err != nil { // Attempt to extract a reject code from the error so // it can be retained. When not possible, fall back to // a non standard error. rejectCode, found := extractRejectCode(err) if !found { rejectCode = btcwire.RejectNonstandard } str := fmt.Sprintf("transaction output %d: %v", i, err) return txRuleError(rejectCode, str) } // Accumulate the number of outputs which only carry data. For // all other script types, ensure the output value is not // "dust". if scriptClass == txscript.NullDataTy { numNullDataOutputs++ } else if isDust(txOut) { str := fmt.Sprintf("transaction output %d: payment "+ "of %d is dust", i, txOut.Value) return txRuleError(btcwire.RejectDust, str) } } // A standard transaction must not have more than one output script that // only carries data. if numNullDataOutputs > 1 { str := "more than one transaction output in a nulldata script" return txRuleError(btcwire.RejectNonstandard, str) } return nil }
// CheckTransactionSanity performs some preliminary checks on a transaction to // ensure it is sane. These checks are context free. func CheckTransactionSanity(tx *btcutil.Tx) error { // A transaction must have at least one input. msgTx := tx.MsgTx() if len(msgTx.TxIn) == 0 { return ruleError(ErrNoTxInputs, "transaction has no inputs") } // A transaction must have at least one output. if len(msgTx.TxOut) == 0 { return ruleError(ErrNoTxOutputs, "transaction has no outputs") } // A transaction must not exceed the maximum allowed block payload when // serialized. serializedTxSize := tx.MsgTx().SerializeSize() if serializedTxSize > btcwire.MaxBlockPayload { str := fmt.Sprintf("serialized transaction is too big - got "+ "%d, max %d", serializedTxSize, btcwire.MaxBlockPayload) return ruleError(ErrTxTooBig, str) } // Ensure the transaction amounts are in range. Each transaction // output must not be negative or more than the max allowed per // transaction. Also, the total of all outputs must abide by the same // restrictions. All amounts in a transaction are in a unit value known // as a satoshi. One bitcoin is a quantity of satoshi as defined by the // SatoshiPerBitcoin constant. var totalSatoshi int64 for _, txOut := range msgTx.TxOut { satoshi := txOut.Value if satoshi < 0 { str := fmt.Sprintf("transaction output has negative "+ "value of %v", satoshi) return ruleError(ErrBadTxOutValue, str) } if satoshi > btcutil.MaxSatoshi { str := fmt.Sprintf("transaction output value of %v is "+ "higher than max allowed value of %v", satoshi, btcutil.MaxSatoshi) return ruleError(ErrBadTxOutValue, str) } // TODO(davec): No need to check < 0 here as satoshi is // guaranteed to be positive per the above check. Also need // to add overflow checks. totalSatoshi += satoshi if totalSatoshi < 0 { str := fmt.Sprintf("total value of all transaction "+ "outputs has negative value of %v", totalSatoshi) return ruleError(ErrBadTxOutValue, str) } if totalSatoshi > btcutil.MaxSatoshi { str := fmt.Sprintf("total value of all transaction "+ "outputs is %v which is higher than max "+ "allowed value of %v", totalSatoshi, btcutil.MaxSatoshi) return ruleError(ErrBadTxOutValue, str) } } // Check for duplicate transaction inputs. existingTxOut := make(map[btcwire.OutPoint]struct{}) for _, txIn := range msgTx.TxIn { if _, exists := existingTxOut[txIn.PreviousOutPoint]; exists { return ruleError(ErrDuplicateTxInputs, "transaction "+ "contains duplicate inputs") } existingTxOut[txIn.PreviousOutPoint] = struct{}{} } // Coinbase script length must be between min and max length. if IsCoinBase(tx) { 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)", slen, MinCoinbaseScriptLen, MaxCoinbaseScriptLen) return ruleError(ErrBadCoinbaseScriptLen, str) } } else { // Previous transaction outputs referenced by the inputs to this // transaction must not be null. for _, txIn := range msgTx.TxIn { prevOut := &txIn.PreviousOutPoint if isNullOutpoint(prevOut) { return ruleError(ErrBadTxInput, "transaction "+ "input refers to previous output that "+ "is null") } } } return nil }
// CheckTransactionInputs performs a series of checks on the inputs to a // transaction to ensure they are valid. An example of some of the checks // include verifying all inputs exist, ensuring the coinbase seasoning // requirements are met, detecting double spends, validating all values and fees // are in the legal range and the total output amount doesn't exceed the input // 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 *btcutil.Tx, txHeight int64, txStore TxStore) (int64, error) { // Coinbase transactions have no inputs. if IsCoinBase(tx) { return 0, nil } txHash := tx.Sha() var totalSatoshiIn int64 for _, txIn := range tx.MsgTx().TxIn { // Ensure the input is available. txInHash := &txIn.PreviousOutPoint.Hash originTx, exists := txStore[*txInHash] if !exists || originTx.Err != nil || originTx.Tx == nil { str := fmt.Sprintf("unable to find input transaction "+ "%v for transaction %v", txInHash, txHash) return 0, ruleError(ErrMissingTx, str) } // Ensure the transaction is not spending coins which have not // yet reached the required coinbase maturity. if IsCoinBase(originTx.Tx) { originHeight := originTx.BlockHeight blocksSincePrev := txHeight - originHeight if blocksSincePrev < coinbaseMaturity { str := fmt.Sprintf("tried to spend coinbase "+ "transaction %v from height %v at "+ "height %v before required maturity "+ "of %v blocks", txInHash, originHeight, txHeight, coinbaseMaturity) return 0, ruleError(ErrImmatureSpend, str) } } // Ensure the transaction is not double spending coins. originTxIndex := txIn.PreviousOutPoint.Index if originTxIndex >= uint32(len(originTx.Spent)) { str := fmt.Sprintf("out of bounds input index %d in "+ "transaction %v referenced from transaction %v", originTxIndex, txInHash, txHash) return 0, ruleError(ErrBadTxInput, str) } if originTx.Spent[originTxIndex] { str := fmt.Sprintf("transaction %v tried to double "+ "spend output %v", txHash, txIn.PreviousOutPoint) return 0, ruleError(ErrDoubleSpend, str) } // Ensure the transaction amounts are in range. Each of the // output values of the input transactions must not be negative // or more than the max allowed per transaction. All amounts in // 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.MsgTx().TxOut[originTxIndex].Value if originTxSatoshi < 0 { str := fmt.Sprintf("transaction output has negative "+ "value of %v", originTxSatoshi) return 0, ruleError(ErrBadTxOutValue, str) } if originTxSatoshi > btcutil.MaxSatoshi { str := fmt.Sprintf("transaction output value of %v is "+ "higher than max allowed value of %v", originTxSatoshi, btcutil.MaxSatoshi) return 0, ruleError(ErrBadTxOutValue, str) } // The total of all outputs must not be more than the max // allowed per transaction. Also, we could potentially overflow // the accumulator so check for overflow. lastSatoshiIn := totalSatoshiIn totalSatoshiIn += originTxSatoshi if totalSatoshiIn < lastSatoshiIn || totalSatoshiIn > btcutil.MaxSatoshi { str := fmt.Sprintf("total value of all transaction "+ "inputs is %v which is higher than max "+ "allowed value of %v", totalSatoshiIn, btcutil.MaxSatoshi) return 0, ruleError(ErrBadTxOutValue, str) } // Mark the referenced output as spent. originTx.Spent[originTxIndex] = true } // Calculate the total output amount for this transaction. It is safe // 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.MsgTx().TxOut { totalSatoshiOut += txOut.Value } // Ensure the transaction does not spend more than its inputs. if totalSatoshiIn < totalSatoshiOut { str := fmt.Sprintf("total value of all transaction inputs for "+ "transaction %v is %v which is less than the amount "+ "spent of %v", txHash, totalSatoshiIn, totalSatoshiOut) return 0, ruleError(ErrSpendTooHigh, str) } // NOTE: bitcoind checks if the transaction fees are < 0 here, but that // is an impossible condition because of the check above that ensures // the inputs are >= the outputs. txFeeInSatoshi := totalSatoshiIn - totalSatoshiOut return txFeeInSatoshi, nil }