// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. package main import ( "container/list" "crypto/rand" "fmt" "math" "math/big" "sync" "time" "github.com/btcsuite/btcd/blockchain" "github.com/btcsuite/btcd/database" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" ) const ( // mempoolHeight is the height used for the "block" height field of the // contextual transaction information provided in a transaction store. mempoolHeight = 0x7fffffff // maxOrphanTransactions is the maximum number of orphan transactions // that can be queued. At the time this comment was written, this // equates to 10,000 transactions, but will increase if the max allowed // block payload increases. maxOrphanTransactions = wire.MaxBlockPayload / 100 // maxOrphanTxSize is the maximum size allowed for orphan transactions. // This helps prevent memory exhaustion attacks from sending a lot of // of big orphans. maxOrphanTxSize = 5000 // maxSigOpsPerTx is the maximum number of signature operations // in a single transaction we will relay or mine. It is a fraction // of the max signature operations for a block. maxSigOpsPerTx = blockchain.MaxSigOpsPerBlock / 5 // maxStandardTxSize is the maximum size allowed for transactions that // are considered standard and will therefore be relayed and considered // for mining. maxStandardTxSize = 100000 // maxStandardSigScriptSize is the maximum size allowed for a // transaction input signature script to be considered standard. This // value allows for a 15-of-15 CHECKMULTISIG pay-to-script-hash with // compressed keys. // // The form of the overall script is: OP_0 <15 signatures> OP_PUSHDATA2 // <2 bytes len> [OP_15 <15 pubkeys> OP_15 OP_CHECKMULTISIG] // // For the p2sh script portion, each of the 15 compressed pubkeys are // 33 bytes (plus one for the OP_DATA_33 opcode), and the thus it totals // to (15*34)+3 = 513 bytes. Next, each of the 15 signatures is a max // of 73 bytes (plus one for the OP_DATA_73 opcode). Also, there is one // extra byte for the initial extra OP_0 push and 3 bytes for the // OP_PUSHDATA2 needed to specify the 513 bytes for the script push. // That brings the total to 1+(15*74)+3+513 = 1627. This value also // adds a few extra bytes to provide a little buffer. // (1 + 15*74 + 3) + (15*34 + 3) + 23 = 1650 maxStandardSigScriptSize = 1650 // maxStandardMultiSigKeys is the maximum number of public keys allowed // in a multi-signature transaction output script for it to be // considered standard. maxStandardMultiSigKeys = 3 // minTxRelayFee is the minimum fee in satoshi that is required for a // transaction to be treated as free for relay and mining purposes. It // is also used to help determine if a transaction is considered dust // and as a base for calculating minimum required fees for larger // transactions. This value is in Satoshi/1000 bytes. minTxRelayFee = 1000 ) // TxDesc is a descriptor containing a transaction in the mempool and the // metadata we store about it. type TxDesc struct { Tx *btcutil.Tx // Transaction. Added time.Time // Time when added to pool. Height int64 // Blockheight when added to pool. Fee int64 // Transaction fees. startingPriority float64 // Priority when added to the pool. } // txMemPool is used as a source of transactions that need to be mined into // blocks and relayed to other peers. It is safe for concurrent access from // multiple peers. type txMemPool struct { sync.RWMutex server *server pool map[wire.ShaHash]*TxDesc orphans map[wire.ShaHash]*btcutil.Tx orphansByPrev map[wire.ShaHash]*list.List addrindex map[string]map[*btcutil.Tx]struct{} // maps address to txs outpoints map[wire.OutPoint]*btcutil.Tx lastUpdated time.Time // last time pool was updated pennyTotal float64 // exponentially decaying total for penny spends. lastPennyUnix int64 // unix time of last ``penny spend'' } // isDust returns whether or not the passed transaction output amount is // considered dust or not. Dust is defined in terms of the minimum transaction // relay fee. In particular, if the cost to the network to spend coins is more // than 1/3 of the minimum transaction relay fee, it is considered dust. func isDust(txOut *wire.TxOut) bool { // The total serialized size consists of the output and the associated // input script to redeem it. Since there is no input script // to redeem it yet, use the minimum size of a typical input script. // // Pay-to-pubkey-hash bytes breakdown: // // Output to hash (34 bytes): // 8 value, 1 script len, 25 script [1 OP_DUP, 1 OP_HASH_160, // 1 OP_DATA_20, 20 hash, 1 OP_EQUALVERIFY, 1 OP_CHECKSIG] // // Input with compressed pubkey (148 bytes): // 36 prev outpoint, 1 script len, 107 script [1 OP_DATA_72, 72 sig, // 1 OP_DATA_33, 33 compressed pubkey], 4 sequence // // Input with uncompressed pubkey (180 bytes): // 36 prev outpoint, 1 script len, 139 script [1 OP_DATA_72, 72 sig, // 1 OP_DATA_65, 65 compressed pubkey], 4 sequence // // Pay-to-pubkey bytes breakdown: // // Output to compressed pubkey (44 bytes): // 8 value, 1 script len, 35 script [1 OP_DATA_33, // 33 compressed pubkey, 1 OP_CHECKSIG] // // Output to uncompressed pubkey (76 bytes): // 8 value, 1 script len, 67 script [1 OP_DATA_65, 65 pubkey, // 1 OP_CHECKSIG] // // Input (114 bytes): // 36 prev outpoint, 1 script len, 73 script [1 OP_DATA_72, // 72 sig], 4 sequence // // Theoretically this could examine the script type of the output script // and use a different size for the typical input script size for // pay-to-pubkey vs pay-to-pubkey-hash inputs per the above breakdowns, // but the only combinination which is less than the value chosen is // a pay-to-pubkey script with a compressed pubkey, which is not very // common. // // The most common scripts are pay-to-pubkey-hash, and as per the above // breakdown, the minimum size of a p2pkh input script is 148 bytes. So // that figure is used. totalSize := txOut.SerializeSize() + 148 // The output is considered dust if the cost to the network to spend the // coins is more than 1/3 of the minimum free transaction relay fee. // minFreeTxRelayFee is in Satoshi/KB, so multiply by 1000 to // convert to bytes. // // Using the typical values for a pay-to-pubkey-hash transaction from // the breakdown above and the default minimum free transaction relay // fee of 1000, this equates to values less than 546 satoshi being // considered dust. // // The following is equivalent to (value/totalSize) * (1/3) * 1000 // without needing to do floating point math. return txOut.Value*1000/(3*int64(totalSize)) < minTxRelayFee } // checkPkScriptStandard performs a series of checks on a transaction ouput // script (public key script) to ensure it is a "standard" public key script. // A standard public key script is one that is a recognized form, and for // multi-signature scripts, only contains from 1 to maxStandardMultiSigKeys // public keys. func checkPkScriptStandard(pkScript []byte, scriptClass txscript.ScriptClass) error { switch scriptClass { case txscript.MultiSigTy: numPubKeys, numSigs, err := txscript.CalcMultiSigStats(pkScript) if err != nil { str := fmt.Sprintf("multi-signature script parse "+ "failure: %v", err) return txRuleError(wire.RejectNonstandard, str) } // A standard multi-signature public key script must contain // from 1 to maxStandardMultiSigKeys public keys. if numPubKeys < 1 { str := "multi-signature script with no pubkeys" return txRuleError(wire.RejectNonstandard, str) } if numPubKeys > maxStandardMultiSigKeys { str := fmt.Sprintf("multi-signature script with %d "+ "public keys which is more than the allowed "+ "max of %d", numPubKeys, maxStandardMultiSigKeys) return txRuleError(wire.RejectNonstandard, str) } // A standard multi-signature public key script must have at // least 1 signature and no more signatures than available // public keys. if numSigs < 1 { return txRuleError(wire.RejectNonstandard, "multi-signature script with no signatures") } if numSigs > numPubKeys { str := fmt.Sprintf("multi-signature script with %d "+ "signatures which is more than the available "+ "%d public keys", numSigs, numPubKeys) return txRuleError(wire.RejectNonstandard, str) } case txscript.NonStandardTy: return txRuleError(wire.RejectNonstandard, "non-standard script form") } return 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 (mp *txMemPool) checkTransactionStandard(tx *btcutil.Tx, height int64) error { msgTx := tx.MsgTx() // The transaction must be a currently supported version. if msgTx.Version > wire.TxVersion || msgTx.Version < 1 { str := fmt.Sprintf("transaction version %d is not in the "+ "valid range of %d-%d", msgTx.Version, 1, wire.TxVersion) return txRuleError(wire.RejectNonstandard, str) } // The transaction must be finalized to be standard and therefore // considered for inclusion in a block. adjustedTime := mp.server.timeSource.AdjustedTime() if !blockchain.IsFinalizedTransaction(tx, height, adjustedTime) { return txRuleError(wire.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(wire.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(wire.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(wire.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 = wire.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(wire.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(wire.RejectNonstandard, str) } return nil } // 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(wire.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(wire.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(wire.RejectNonstandard, str) } } return nil } // calcMinRequiredTxRelayFee returns the minimum transaction fee required for a // transaction with the passed serialized size to be accepted into the memory // pool and relayed. func calcMinRequiredTxRelayFee(serializedSize int64) int64 { // Calculate the minimum fee for a transaction to be allowed into the // mempool and relayed by scaling the base fee (which is the minimum // free transaction relay fee). minTxRelayFee is in Satoshi/KB, so // divide the transaction size by 1000 to convert to kilobytes. Also, // integer division is used so fees only increase on full kilobyte // boundaries. minFee := (1 + serializedSize/1000) * minTxRelayFee // Set the minimum fee to the maximum possible value if the calculated // fee is not in the valid range for monetary amounts. if minFee < 0 || minFee > btcutil.MaxSatoshi { minFee = btcutil.MaxSatoshi } return minFee } // removeOrphan is the internal function which implements the public // RemoveOrphan. See the comment for RemoveOrphan for more details. // This function MUST be called with the mempool lock held (for writes). func (mp *txMemPool) removeOrphan(txHash *wire.ShaHash) { // Nothing to do if passed tx is not an orphan. tx, exists := mp.orphans[*txHash] if !exists { return } // Remove the reference from the previous orphan index. for _, txIn := range tx.MsgTx().TxIn { originTxHash := txIn.PreviousOutPoint.Hash if orphans, exists := mp.orphansByPrev[originTxHash]; exists { for e := orphans.Front(); e != nil; e = e.Next() { if e.Value.(*btcutil.Tx) == tx { orphans.Remove(e) break } } // Remove the map entry altogether if there are no // longer any orphans which depend on it. if orphans.Len() == 0 { delete(mp.orphansByPrev, originTxHash) } } } // Remove the transaction from the orphan pool. delete(mp.orphans, *txHash) } // RemoveOrphan removes the passed orphan transaction from the orphan pool and // previous orphan index. // This function is safe for concurrent access. func (mp *txMemPool) RemoveOrphan(txHash *wire.ShaHash) { mp.Lock() mp.removeOrphan(txHash) mp.Unlock() } // limitNumOrphans limits the number of orphan transactions by evicting a random // orphan if adding a new one would cause it to overflow the max allowed. // // This function MUST be called with the mempool lock held (for writes). func (mp *txMemPool) limitNumOrphans() error { if len(mp.orphans)+1 > maxOrphanTransactions { // Generate a cryptographically random hash. randHashBytes := make([]byte, wire.HashSize) _, err := rand.Read(randHashBytes) if err != nil { return err } randHashNum := new(big.Int).SetBytes(randHashBytes) // Try to find the first entry that is greater than the random // hash. Use the first entry (which is already pseudorandom due // to Go's range statement over maps) as a fallback if none of // the hashes in the orphan pool are larger than the random // hash. var foundHash *wire.ShaHash for txHash := range mp.orphans { if foundHash == nil { foundHash = &txHash } txHashNum := blockchain.ShaHashToBig(&txHash) if txHashNum.Cmp(randHashNum) > 0 { foundHash = &txHash break } } mp.removeOrphan(foundHash) } return 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)) } // 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(wire.RejectNonstandard, str) } // Add the orphan if the none of the above disqualified it. mp.addOrphan(tx) return nil } // isTransactionInPool returns whether or not the passed transaction already // exists in the main pool. // // This function MUST be called with the mempool lock held (for reads). func (mp *txMemPool) isTransactionInPool(hash *wire.ShaHash) bool { if _, exists := mp.pool[*hash]; exists { return true } return false } // IsTransactionInPool returns whether or not the passed transaction already // exists in the main pool. // // This function is safe for concurrent access. func (mp *txMemPool) IsTransactionInPool(hash *wire.ShaHash) bool { // Protect concurrent access. mp.RLock() defer mp.RUnlock() return mp.isTransactionInPool(hash) } // isOrphanInPool returns whether or not the passed transaction already exists // in the orphan pool. // // This function MUST be called with the mempool lock held (for reads). func (mp *txMemPool) isOrphanInPool(hash *wire.ShaHash) bool { if _, exists := mp.orphans[*hash]; exists { return true } return false } // IsOrphanInPool returns whether or not the passed transaction already exists // in the orphan pool. // // This function is safe for concurrent access. func (mp *txMemPool) IsOrphanInPool(hash *wire.ShaHash) bool { // Protect concurrent access. mp.RLock() defer mp.RUnlock() return mp.isOrphanInPool(hash) } // haveTransaction returns whether or not the passed transaction already exists // in the main pool or in the orphan pool. // // This function MUST be called with the mempool lock held (for reads). func (mp *txMemPool) haveTransaction(hash *wire.ShaHash) bool { return mp.isTransactionInPool(hash) || mp.isOrphanInPool(hash) } // HaveTransaction returns whether or not the passed transaction already exists // in the main pool or in the orphan pool. // // This function is safe for concurrent access. func (mp *txMemPool) HaveTransaction(hash *wire.ShaHash) bool { // Protect concurrent access. mp.RLock() defer mp.RUnlock() return mp.haveTransaction(hash) } // 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 := wire.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 { if cfg.AddrIndex { mp.removeTransactionFromAddrIndex(tx) } for _, txIn := range txDesc.Tx.MsgTx().TxIn { delete(mp.outpoints, txIn.PreviousOutPoint) } delete(mp.pool, *txHash) mp.lastUpdated = time.Now() } } // removeTransactionFromAddrIndex removes the passed transaction from our // address based index. // // This function MUST be called with the mempool lock held (for writes). func (mp *txMemPool) removeTransactionFromAddrIndex(tx *btcutil.Tx) error { previousOutputScripts, err := mp.fetchReferencedOutputScripts(tx) if err != nil { txmpLog.Errorf("Unable to obtain referenced output scripts for "+ "the passed tx (addrindex): %v", err) return err } for _, pkScript := range previousOutputScripts { mp.removeScriptFromAddrIndex(pkScript, tx) } for _, txOut := range tx.MsgTx().TxOut { mp.removeScriptFromAddrIndex(txOut.PkScript, tx) } return nil } // removeScriptFromAddrIndex dissociates the address encoded by the // passed pkScript from the passed tx in our address based tx index. // // This function MUST be called with the mempool lock held (for writes). func (mp *txMemPool) removeScriptFromAddrIndex(pkScript []byte, tx *btcutil.Tx) error { _, addresses, _, err := txscript.ExtractPkScriptAddrs(pkScript, activeNetParams.Params) if err != nil { txmpLog.Errorf("Unable to extract encoded addresses from script "+ "for addrindex (addrindex): %v", err) return err } for _, addr := range addresses { delete(mp.addrindex[addr.EncodeAddress()], tx) } return nil } // RemoveTransaction removes the passed transaction and any transactions which // depend on it from the memory pool. // // This function is safe for concurrent access. func (mp *txMemPool) RemoveTransaction(tx *btcutil.Tx) { // Protect concurrent access. mp.Lock() defer mp.Unlock() mp.removeTransaction(tx) } // 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() if cfg.AddrIndex { mp.addTransactionToAddrIndex(tx) } } // addTransactionToAddrIndex adds all addresses related to the transaction to // our in-memory address index. Note that this address is only populated when // we're running with the optional address index activated. // // This function MUST be called with the mempool lock held (for writes). func (mp *txMemPool) addTransactionToAddrIndex(tx *btcutil.Tx) error { previousOutScripts, err := mp.fetchReferencedOutputScripts(tx) if err != nil { txmpLog.Errorf("Unable to obtain referenced output scripts for "+ "the passed tx (addrindex): %v", err) return err } // Index addresses of all referenced previous output tx's. for _, pkScript := range previousOutScripts { mp.indexScriptAddressToTx(pkScript, tx) } // Index addresses of all created outputs. for _, txOut := range tx.MsgTx().TxOut { mp.indexScriptAddressToTx(txOut.PkScript, tx) } return nil } // fetchReferencedOutputScripts looks up and returns all the scriptPubKeys // referenced by inputs of the passed transaction. // // This function MUST be called with the mempool lock held (for reads). func (mp *txMemPool) fetchReferencedOutputScripts(tx *btcutil.Tx) ([][]byte, error) { txStore, err := mp.fetchInputTransactions(tx) if err != nil || len(txStore) == 0 { return nil, err } previousOutScripts := make([][]byte, 0, len(tx.MsgTx().TxIn)) for _, txIn := range tx.MsgTx().TxIn { outPoint := txIn.PreviousOutPoint if txStore[outPoint.Hash].Err == nil { referencedOutPoint := txStore[outPoint.Hash].Tx.MsgTx().TxOut[outPoint.Index] previousOutScripts = append(previousOutScripts, referencedOutPoint.PkScript) } } return previousOutScripts, nil } // indexScriptByAddress alters our address index by indexing the payment address // encoded by the passed scriptPubKey to the passed transaction. // // This function MUST be called with the mempool lock held (for writes). func (mp *txMemPool) indexScriptAddressToTx(pkScript []byte, tx *btcutil.Tx) error { _, addresses, _, err := txscript.ExtractPkScriptAddrs(pkScript, activeNetParams.Params) if err != nil { txmpLog.Errorf("Unable to extract encoded addresses from script "+ "for addrindex: %v", err) return err } for _, addr := range addresses { if mp.addrindex[addr.EncodeAddress()] == nil { mp.addrindex[addr.EncodeAddress()] = make(map[*btcutil.Tx]struct{}) } mp.addrindex[addr.EncodeAddress()][tx] = struct{}{} } return nil } // calcInputValueAge is a helper function used to calculate the input age of // a transaction. The input age for a txin is the number of confirmations // since the referenced txout multiplied by its output value. The total input // age is the sum of this value for each txin. Any inputs to the transaction // which are currently in the mempool and hence not mined into a block yet, // contribute no additional input age to the transaction. func calcInputValueAge(txDesc *TxDesc, txStore blockchain.TxStore, nextBlockHeight int64) float64 { var totalInputAge float64 for _, txIn := range txDesc.Tx.MsgTx().TxIn { originHash := &txIn.PreviousOutPoint.Hash originIndex := txIn.PreviousOutPoint.Index // Don't attempt to accumulate the total input age if the txIn // in question doesn't exist. if txData, exists := txStore[*originHash]; exists && txData.Tx != nil { // Inputs with dependencies currently in the mempool // have their block height set to a special constant. // Their input age should computed as zero since their // parent hasn't made it into a block yet. var inputAge int64 if txData.BlockHeight == mempoolHeight { inputAge = 0 } else { inputAge = nextBlockHeight - txData.BlockHeight } // Sum the input value times age. originTxOut := txData.Tx.MsgTx().TxOut[originIndex] inputValue := originTxOut.Value totalInputAge += float64(inputValue * inputAge) } } return totalInputAge } // minInt is a helper function to return the minimum of two ints. This avoids // a math import and the need to cast to floats. func minInt(a, b int) int { if a < b { return a } return b } // 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) } // StartingPriority calculates the priority of this tx descriptor's underlying // transaction relative to when it was first added to the mempool. The result // is lazily computed and then cached for subsequent function calls. func (txD *TxDesc) StartingPriority(txStore blockchain.TxStore) float64 { // Return our cached result. if txD.startingPriority != float64(0) { return txD.startingPriority } // Compute our starting priority caching the result. inputAge := calcInputValueAge(txD, txStore, txD.Height) txSize := txD.Tx.MsgTx().SerializeSize() txD.startingPriority = calcPriority(txD.Tx, txSize, inputAge) return txD.startingPriority } // CurrentPriority calculates the current priority of this tx descriptor's // underlying transaction relative to the next block height. func (txD *TxDesc) CurrentPriority(txStore blockchain.TxStore, nextBlockHeight int64) float64 { inputAge := calcInputValueAge(txD, txStore, nextBlockHeight) txSize := txD.Tx.MsgTx().SerializeSize() return calcPriority(txD.Tx, txSize, inputAge) } // 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(wire.RejectDuplicate, str) } } return nil } // fetchInputTransactions fetches the input transactions referenced by the // passed transaction. First, it fetches from the main chain, then it tries to // fetch any missing inputs from the transaction pool. // // This function MUST be called with the mempool lock held (for reads). func (mp *txMemPool) fetchInputTransactions(tx *btcutil.Tx) (blockchain.TxStore, error) { txStore, err := mp.server.blockManager.blockChain.FetchTransactionStore(tx) if err != nil { return nil, err } // Attempt to populate any missing inputs from the transaction pool. for _, txD := range txStore { if txD.Err == database.ErrTxShaMissing || txD.Tx == nil { if poolTxDesc, exists := mp.pool[*txD.Hash]; exists { poolTx := poolTxDesc.Tx txD.Tx = poolTx txD.BlockHeight = mempoolHeight txD.Spent = make([]bool, len(poolTx.MsgTx().TxOut)) txD.Err = nil } } } return txStore, nil } // FetchTransaction returns the requested transaction from the transaction pool. // This only fetches from the main transaction pool and does not include // orphans. // // This function is safe for concurrent access. func (mp *txMemPool) FetchTransaction(txHash *wire.ShaHash) (*btcutil.Tx, error) { // Protect concurrent access. mp.RLock() defer mp.RUnlock() if txDesc, exists := mp.pool[*txHash]; exists { return txDesc.Tx, nil } return nil, fmt.Errorf("transaction is not in the pool") } // FilterTransactionsByAddress returns all transactions currently in the // mempool that either create an output to the passed address or spend a // previously created ouput to the address. func (mp *txMemPool) FilterTransactionsByAddress(addr btcutil.Address) ([]*btcutil.Tx, error) { // Protect concurrent access. mp.RLock() defer mp.RUnlock() if txs, exists := mp.addrindex[addr.EncodeAddress()]; exists { addressTxs := make([]*btcutil.Tx, 0, len(txs)) for tx := range txs { addressTxs = append(addressTxs, tx) } return addressTxs, nil } return nil, fmt.Errorf("address does not have any transactions in the pool") } // 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) ([]*wire.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(wire.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(wire.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(wire.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 := mp.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 = wire.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(wire.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 []*wire.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 = wire.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(wire.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(wire.RejectInsufficientFee, str) } // Require that free transactions have sufficient priority to be mined // in the next block. Transactions which are being added back to the // memory pool from blocks that have been disconnected during a reorg // are exempted. if isNew && !cfg.NoRelayPriority && txFee < minFee { txD := &TxDesc{ Tx: tx, Added: time.Now(), Height: curHeight, Fee: txFee, } currentPriority := txD.CurrentPriority(txStore, nextBlockHeight) if currentPriority <= minHighPriority { str := fmt.Sprintf("transaction %v has insufficient "+ "priority (%g <= %g)", txHash, currentPriority, minHighPriority) return nil, txRuleError(wire.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(wire.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, txscript.StandardVerifyFlags) 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 } // MaybeAcceptTransaction is the main workhorse for handling insertion of new // free-standing transactions into a memory pool. It includes functionality // such as rejecting duplicate transactions, ensuring transactions follow all // rules, detecting orphan transactions, and insertion into the memory pool. // // If the transaction is an orphan (missing parent transactions), the // transaction is NOT added to the orphan pool, but each unknown referenced // parent is returned. Use ProcessTransaction instead if new orphans should // be added to the orphan pool. // // This function is safe for concurrent access. func (mp *txMemPool) MaybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit bool) ([]*wire.ShaHash, error) { // Protect concurrent access. mp.Lock() defer mp.Unlock() return mp.maybeAcceptTransaction(tx, isNew, rateLimit) } // processOrphans determines if there are any orphans which depend on the passed // transaction hash (it is possible that they are no longer orphans) and // potentially accepts them to the memory pool. It repeats the process for the // newly accepted transactions (to detect further orphans which may no longer be // orphans) until there are no more. // // This function MUST be called with the mempool lock held (for writes). func (mp *txMemPool) processOrphans(hash *wire.ShaHash) error { // Start with processing at least the passed hash. processHashes := list.New() processHashes.PushBack(hash) for processHashes.Len() > 0 { // Pop the first hash to process. firstElement := processHashes.Remove(processHashes.Front()) processHash := firstElement.(*wire.ShaHash) // Look up all orphans that are referenced by the transaction we // just accepted. This will typically only be one, but it could // be multiple if the referenced transaction contains multiple // outputs. Skip to the next item on the list of hashes to // process if there are none. orphans, exists := mp.orphansByPrev[*processHash] if !exists || orphans == nil { continue } var enext *list.Element for e := orphans.Front(); e != nil; e = enext { enext = e.Next() tx := e.Value.(*btcutil.Tx) // Remove the orphan from the orphan pool. Current // behavior requires that all saved orphans with // a newly accepted parent are removed from the orphan // pool and potentially added to the memory pool, but // transactions which cannot be added to memory pool // (including due to still being orphans) are expunged // from the orphan pool. // // TODO(jrick): The above described behavior sounds // like a bug, and I think we should investigate // potentially moving orphans to the memory pool, but // leaving them in the orphan pool if not all parent // transactions are known yet. orphanHash := tx.Sha() mp.removeOrphan(orphanHash) // Potentially accept the transaction into the // transaction pool. missingParents, err := mp.maybeAcceptTransaction(tx, true, true) if err != nil { return err } if len(missingParents) == 0 { // Generate and relay the inventory vector for the // newly accepted transaction. iv := wire.NewInvVect(wire.InvTypeTx, tx.Sha()) mp.server.RelayInventory(iv, tx) } else { // Transaction is still an orphan. // TODO(jrick): This removeOrphan call is // likely unnecessary as it was unconditionally // removed above and maybeAcceptTransaction won't // add it back. mp.removeOrphan(orphanHash) } // Add this transaction to the list of transactions to // process so any orphans that depend on this one are // handled too. // // TODO(jrick): In the case that this is still an orphan, // we know that any other transactions in the orphan // pool with this orphan as their parent are still // orphans as well, and should be removed. While // recursively calling removeOrphan and // maybeAcceptTransaction on these transactions is not // wrong per se, it is overkill if all we care about is // recursively removing child transactions of this // orphan. processHashes.PushBack(orphanHash) } } return nil } // ProcessTransaction is the main workhorse for handling insertion of new // free-standing transactions into the memory pool. It includes functionality // such as rejecting duplicate transactions, ensuring transactions follow all // rules, orphan transaction handling, and insertion into the memory pool. // // This function is safe for concurrent access. func (mp *txMemPool) ProcessTransaction(tx *btcutil.Tx, allowOrphan, rateLimit bool) error { // Protect concurrent access. mp.Lock() defer mp.Unlock() txmpLog.Tracef("Processing transaction %v", tx.Sha()) // Potentially accept the transaction to the memory pool. missingParents, err := mp.maybeAcceptTransaction(tx, true, rateLimit) if err != nil { return err } if len(missingParents) == 0 { // Generate the inventory vector and relay it. iv := wire.NewInvVect(wire.InvTypeTx, tx.Sha()) mp.server.RelayInventory(iv, tx) // Accept any orphan transactions that depend on this // transaction (they may no longer be orphans if all inputs // are now available) and repeat for those accepted // transactions until there are no more. err := mp.processOrphans(tx.Sha()) if err != nil { return err } } else { // The transaction is an orphan (has inputs missing). Reject // it if the flag to allow orphans is not set. if !allowOrphan { // Only use the first missing parent transaction in // the error message. // // NOTE: RejectDuplicate is really not an accurate // reject code here, but it matches the reference // implementation and there isn't a better choice due // to the limited number of reject codes. Missing // inputs is assumed to mean they are already spent // which is not really always the case. str := fmt.Sprintf("orphan transaction %v references "+ "outputs of unknown or fully-spent "+ "transaction %v", tx.Sha(), missingParents[0]) return txRuleError(wire.RejectDuplicate, str) } // Potentially add the orphan transaction to the orphan pool. err := mp.maybeAddOrphan(tx) if err != nil { return err } } return nil } // Count returns the number of transactions in the main pool. It does not // include the orphan pool. // // This function is safe for concurrent access. func (mp *txMemPool) Count() int { mp.RLock() defer mp.RUnlock() return len(mp.pool) } // TxShas returns a slice of hashes for all of the transactions in the memory // pool. // // This function is safe for concurrent access. func (mp *txMemPool) TxShas() []*wire.ShaHash { mp.RLock() defer mp.RUnlock() hashes := make([]*wire.ShaHash, len(mp.pool)) i := 0 for hash := range mp.pool { hashCopy := hash hashes[i] = &hashCopy i++ } return hashes } // TxDescs returns a slice of descriptors for all the transactions in the pool. // The descriptors are to be treated as read only. // // This function is safe for concurrent access. func (mp *txMemPool) TxDescs() []*TxDesc { mp.RLock() defer mp.RUnlock() descs := make([]*TxDesc, len(mp.pool)) i := 0 for _, desc := range mp.pool { descs[i] = desc i++ } return descs } // LastUpdated returns the last time a transaction was added to or removed from // the main pool. It does not include the orphan pool. // // This function is safe for concurrent access. func (mp *txMemPool) LastUpdated() time.Time { mp.RLock() defer mp.RUnlock() return mp.lastUpdated } // newTxMemPool returns a new memory pool for validating and storing standalone // transactions until they are mined into a block. func newTxMemPool(server *server) *txMemPool { memPool := &txMemPool{ server: server, pool: make(map[wire.ShaHash]*TxDesc), orphans: make(map[wire.ShaHash]*btcutil.Tx), orphansByPrev: make(map[wire.ShaHash]*list.List), outpoints: make(map[wire.OutPoint]*btcutil.Tx), } if cfg.AddrIndex { memPool.addrindex = make(map[string]map[*btcutil.Tx]struct{}) } return memPool }