diff --git a/blockmanager.go b/blockmanager.go index 0e051eee6..b1f14f1af 100644 --- a/blockmanager.go +++ b/blockmanager.go @@ -1185,7 +1185,7 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) { // Reinsert all of the transactions (except the coinbase) into // the transaction pool. for _, tx := range block.Transactions()[1:] { - _, err := b.server.txMemPool.MaybeAcceptTransaction(tx, + _, _, err := b.server.txMemPool.MaybeAcceptTransaction(tx, false, false) if err != nil { // Remove the transaction and all transactions diff --git a/mempool/mempool.go b/mempool/mempool.go index f70d6447b..0cc757446 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -481,10 +481,10 @@ func (mp *TxPool) RemoveDoubleSpends(tx *btcutil.Tx) { // helper for maybeAcceptTransaction. // // This function MUST be called with the mempool lock held (for writes). -func (mp *TxPool) addTransaction(utxoView *blockchain.UtxoViewpoint, tx *btcutil.Tx, height int32, fee int64) { +func (mp *TxPool) addTransaction(utxoView *blockchain.UtxoViewpoint, tx *btcutil.Tx, height int32, fee int64) *TxDesc { // Add the transaction to the pool and mark the referenced outpoints // as spent by the pool. - mp.pool[*tx.Hash()] = &TxDesc{ + txD := &TxDesc{ TxDesc: mining.TxDesc{ Tx: tx, Added: time.Now(), @@ -493,6 +493,8 @@ func (mp *TxPool) addTransaction(utxoView *blockchain.UtxoViewpoint, tx *btcutil }, StartingPriority: mining.CalcPriority(tx.MsgTx(), utxoView, height), } + mp.pool[*tx.Hash()] = txD + for _, txIn := range tx.MsgTx().TxIn { mp.outpoints[txIn.PreviousOutPoint] = tx } @@ -503,6 +505,8 @@ func (mp *TxPool) addTransaction(utxoView *blockchain.UtxoViewpoint, tx *btcutil if mp.cfg.AddrIndex != nil { mp.cfg.AddrIndex.AddUnconfirmedTx(tx, utxoView) } + + return txD } // checkPoolDoubleSpend checks whether or not the passed transaction is @@ -572,7 +576,7 @@ func (mp *TxPool) FetchTransaction(txHash *chainhash.Hash) (*btcutil.Tx, error) // more details. // // This function MUST be called with the mempool lock held (for writes). -func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejectDupOrphans bool) ([]*chainhash.Hash, error) { +func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejectDupOrphans bool) ([]*chainhash.Hash, *TxDesc, error) { txHash := tx.Hash() // Don't accept the transaction if it already exists in the pool. This @@ -583,7 +587,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec mp.isOrphanInPool(txHash)) { str := fmt.Sprintf("already have transaction %v", txHash) - return nil, txRuleError(wire.RejectDuplicate, str) + return nil, nil, txRuleError(wire.RejectDuplicate, str) } // Perform preliminary sanity checks on the transaction. This makes @@ -592,16 +596,16 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec err := blockchain.CheckTransactionSanity(tx) if err != nil { if cerr, ok := err.(blockchain.RuleError); ok { - return nil, chainRuleError(cerr) + return nil, nil, chainRuleError(cerr) } - return nil, err + return nil, 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) + return nil, nil, txRuleError(wire.RejectInvalid, str) } // Don't accept transactions with a lock time after the maximum int32 @@ -611,7 +615,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec 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) + return nil, nil, txRuleError(wire.RejectNonstandard, str) } // Get the current height of the main chain. A standalone transaction @@ -638,7 +642,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec } str := fmt.Sprintf("transaction %v is not standard: %v", txHash, err) - return nil, txRuleError(rejectCode, str) + return nil, nil, txRuleError(rejectCode, str) } } @@ -652,7 +656,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec // which examines the actual spend data and prevents double spends. err = mp.checkPoolDoubleSpend(tx) if err != nil { - return nil, err + return nil, nil, err } // Fetch all of the unspent transaction outputs referenced by the inputs @@ -662,16 +666,16 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec utxoView, err := mp.fetchInputUtxos(tx) if err != nil { if cerr, ok := err.(blockchain.RuleError); ok { - return nil, chainRuleError(cerr) + return nil, nil, chainRuleError(cerr) } - return nil, err + return nil, nil, err } // Don't allow the transaction if it exists in the main chain and is not // not already fully spent. txEntry := utxoView.LookupEntry(txHash) if txEntry != nil && !txEntry.IsFullySpent() { - return nil, txRuleError(wire.RejectDuplicate, + return nil, nil, txRuleError(wire.RejectDuplicate, "transaction already exists") } delete(utxoView.Entries(), *txHash) @@ -692,7 +696,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec } } if len(missingParents) > 0 { - return missingParents, nil + return missingParents, nil, nil } // Don't allow the transaction into the mempool unless its sequence @@ -701,13 +705,13 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec sequenceLock, err := mp.cfg.CalcSequenceLock(tx, utxoView) if err != nil { if cerr, ok := err.(blockchain.RuleError); ok { - return nil, chainRuleError(cerr) + return nil, nil, chainRuleError(cerr) } - return nil, err + return nil, nil, err } if !blockchain.SequenceLockActive(sequenceLock, nextBlockHeight, medianTimePast) { - return nil, txRuleError(wire.RejectNonstandard, + return nil, nil, txRuleError(wire.RejectNonstandard, "transaction's sequence locks on inputs not met") } @@ -719,9 +723,9 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec utxoView, mp.cfg.ChainParams) if err != nil { if cerr, ok := err.(blockchain.RuleError); ok { - return nil, chainRuleError(cerr) + return nil, nil, chainRuleError(cerr) } - return nil, err + return nil, nil, err } // Don't allow transactions with non-standard inputs if the network @@ -738,7 +742,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec } str := fmt.Sprintf("transaction %v has a non-standard "+ "input: %v", txHash, err) - return nil, txRuleError(rejectCode, str) + return nil, nil, txRuleError(rejectCode, str) } } @@ -754,15 +758,15 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec numSigOps, err := blockchain.CountP2SHSigOps(tx, false, utxoView) if err != nil { if cerr, ok := err.(blockchain.RuleError); ok { - return nil, chainRuleError(cerr) + return nil, nil, chainRuleError(cerr) } - return nil, err + return nil, nil, err } numSigOps += blockchain.CountSigOps(tx) if numSigOps > mp.cfg.Policy.MaxSigOpsPerTx { str := fmt.Sprintf("transaction %v has too many sigops: %d > %d", txHash, numSigOps, mp.cfg.Policy.MaxSigOpsPerTx) - return nil, txRuleError(wire.RejectNonstandard, str) + return nil, nil, txRuleError(wire.RejectNonstandard, str) } // Don't allow transactions with fees too low to get into a mined block. @@ -783,7 +787,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec 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) + return nil, nil, txRuleError(wire.RejectInsufficientFee, str) } // Require that free transactions have sufficient priority to be mined @@ -797,7 +801,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec str := fmt.Sprintf("transaction %v has insufficient "+ "priority (%g <= %g)", txHash, currentPriority, mining.MinHighPriority) - return nil, txRuleError(wire.RejectInsufficientFee, str) + return nil, nil, txRuleError(wire.RejectInsufficientFee, str) } } @@ -815,7 +819,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec if mp.pennyTotal >= mp.cfg.Policy.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) + return nil, nil, txRuleError(wire.RejectInsufficientFee, str) } oldTotal := mp.pennyTotal @@ -831,18 +835,18 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec txscript.StandardVerifyFlags, mp.cfg.SigCache) if err != nil { if cerr, ok := err.(blockchain.RuleError); ok { - return nil, chainRuleError(cerr) + return nil, nil, chainRuleError(cerr) } - return nil, err + return nil, nil, err } // Add to transaction pool. - mp.addTransaction(utxoView, tx, bestHeight, txFee) + txD := mp.addTransaction(utxoView, tx, bestHeight, txFee) log.Debugf("Accepted transaction %v (pool size: %v)", txHash, len(mp.pool)) - return nil, nil + return nil, txD, nil } // MaybeAcceptTransaction is the main workhorse for handling insertion of new @@ -856,21 +860,21 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec // be added to the orphan pool. // // This function is safe for concurrent access. -func (mp *TxPool) MaybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit bool) ([]*chainhash.Hash, error) { +func (mp *TxPool) MaybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit bool) ([]*chainhash.Hash, *TxDesc, error) { // Protect concurrent access. mp.mtx.Lock() - hashes, err := mp.maybeAcceptTransaction(tx, isNew, rateLimit, true) + hashes, txD, err := mp.maybeAcceptTransaction(tx, isNew, rateLimit, true) mp.mtx.Unlock() - return hashes, err + return hashes, txD, err } // processOrphans is the internal function which implements the public // ProcessOrphans. See the comment for ProcessOrphans for more details. // // This function MUST be called with the mempool lock held (for writes). -func (mp *TxPool) processOrphans(acceptedTx *btcutil.Tx) []*btcutil.Tx { - var acceptedTxns []*btcutil.Tx +func (mp *TxPool) processOrphans(acceptedTx *btcutil.Tx) []*TxDesc { + var acceptedTxns []*TxDesc // Start with processing at least the passed transaction. processList := list.New() @@ -901,7 +905,7 @@ func (mp *TxPool) processOrphans(acceptedTx *btcutil.Tx) []*btcutil.Tx { // Potentially accept an orphan into the tx pool. for _, tx := range orphans { - missing, err := mp.maybeAcceptTransaction( + missing, txD, err := mp.maybeAcceptTransaction( tx, true, true, false) if err != nil { // The orphan is now invalid, so there @@ -925,7 +929,7 @@ func (mp *TxPool) processOrphans(acceptedTx *btcutil.Tx) []*btcutil.Tx { // the orphan pool, and add it to the list of // transactions to process so any orphans that // depend on it are handled too. - acceptedTxns = append(acceptedTxns, tx) + acceptedTxns = append(acceptedTxns, txD) mp.removeOrphan(tx, false) processList.PushBack(tx) @@ -941,8 +945,8 @@ func (mp *TxPool) processOrphans(acceptedTx *btcutil.Tx) []*btcutil.Tx { // by the accepted transactions since those are now definitive double // spends. mp.removeOrphanDoubleSpends(acceptedTx) - for _, tx := range acceptedTxns { - mp.removeOrphanDoubleSpends(tx) + for _, txD := range acceptedTxns { + mp.removeOrphanDoubleSpends(txD.Tx) } return acceptedTxns @@ -958,7 +962,7 @@ func (mp *TxPool) processOrphans(acceptedTx *btcutil.Tx) []*btcutil.Tx { // no transactions were moved from the orphan pool to the mempool. // // This function is safe for concurrent access. -func (mp *TxPool) ProcessOrphans(acceptedTx *btcutil.Tx) []*btcutil.Tx { +func (mp *TxPool) ProcessOrphans(acceptedTx *btcutil.Tx) []*TxDesc { mp.mtx.Lock() acceptedTxns := mp.processOrphans(acceptedTx) mp.mtx.Unlock() @@ -977,7 +981,7 @@ func (mp *TxPool) ProcessOrphans(acceptedTx *btcutil.Tx) []*btcutil.Tx { // the passed one being accepted. // // This function is safe for concurrent access. -func (mp *TxPool) ProcessTransaction(tx *btcutil.Tx, allowOrphan, rateLimit bool) ([]*btcutil.Tx, error) { +func (mp *TxPool) ProcessTransaction(tx *btcutil.Tx, allowOrphan, rateLimit bool) ([]*TxDesc, error) { log.Tracef("Processing transaction %v", tx.Hash()) // Protect concurrent access. @@ -985,7 +989,7 @@ func (mp *TxPool) ProcessTransaction(tx *btcutil.Tx, allowOrphan, rateLimit bool defer mp.mtx.Unlock() // Potentially accept the transaction to the memory pool. - missingParents, err := mp.maybeAcceptTransaction(tx, true, rateLimit, + missingParents, txD, err := mp.maybeAcceptTransaction(tx, true, rateLimit, true) if err != nil { return nil, err @@ -997,11 +1001,11 @@ func (mp *TxPool) ProcessTransaction(tx *btcutil.Tx, allowOrphan, rateLimit bool // are now available) and repeat for those accepted // transactions until there are no more. newTxs := mp.processOrphans(tx) - acceptedTxs := make([]*btcutil.Tx, len(newTxs)+1) + acceptedTxs := make([]*TxDesc, len(newTxs)+1) // Add the parent transaction first so remote nodes // do not add orphans. - acceptedTxs[0] = tx + acceptedTxs[0] = txD copy(acceptedTxs[1:], newTxs) return acceptedTxs, nil diff --git a/mempool/mempool_test.go b/mempool/mempool_test.go index 8a65abb87..a962842ab 100644 --- a/mempool/mempool_test.go +++ b/mempool/mempool_test.go @@ -442,10 +442,10 @@ func TestSimpleOrphanChain(t *testing.T) { "length does not match expected -- got %d, want %d", len(acceptedTxns), len(chainedTxns)) } - for _, tx := range acceptedTxns { + for _, txD := range acceptedTxns { // Ensure the transaction is no longer in the orphan pool, is // now in the transaction pool, and is reported as available. - testPoolMembership(tc, tx, false, true) + testPoolMembership(tc, txD.Tx, false, true) } } @@ -784,10 +784,10 @@ func TestMultiInputOrphanDoubleSpend(t *testing.T) { "length does not match expected -- got %d, want %d", len(acceptedTxns), maxOrphans) } - for _, tx := range acceptedTxns { + for _, txD := range acceptedTxns { // Ensure the transaction is no longer in the orphan pool, is // in the transaction pool, and is reported as available. - testPoolMembership(tc, tx, false, true) + testPoolMembership(tc, txD.Tx, false, true) } // Ensure the double spending orphan is no longer in the orphan pool and diff --git a/server.go b/server.go index 771e310f7..63a52fea2 100644 --- a/server.go +++ b/server.go @@ -972,18 +972,18 @@ func (s *server) RemoveRebroadcastInventory(iv *wire.InvVect) { // both websocket and getblocktemplate long poll clients of the passed // transactions. This function should be called whenever new transactions // are added to the mempool. -func (s *server) AnnounceNewTransactions(newTxs []*btcutil.Tx) { +func (s *server) AnnounceNewTransactions(newTxs []*mempool.TxDesc) { // Generate and relay inventory vectors for all newly accepted // transactions into the memory pool due to the original being // accepted. - for _, tx := range newTxs { + for _, txD := range newTxs { // Generate the inventory vector and relay it. - iv := wire.NewInvVect(wire.InvTypeTx, tx.Hash()) - s.RelayInventory(iv, tx) + iv := wire.NewInvVect(wire.InvTypeTx, txD.Tx.Hash()) + s.RelayInventory(iv, txD) if s.rpcServer != nil { // Notify websocket clients about mempool transactions. - s.rpcServer.ntfnMgr.NotifyMempoolTx(tx, true) + s.rpcServer.ntfnMgr.NotifyMempoolTx(txD.Tx, true) // Potentially notify any getblocktemplate long poll clients // about stale block templates due to the new transaction. @@ -1319,14 +1319,14 @@ func (s *server) handleRelayInvMsg(state *peerState, msg relayMsg) { // Don't relay the transaction if there is a bloom // filter loaded and the transaction doesn't match it. if sp.filter.IsLoaded() { - tx, ok := msg.data.(*btcutil.Tx) + txD, ok := msg.data.(*mempool.TxDesc) if !ok { peerLog.Warnf("Underlying data for tx" + - " inv relay is not a transaction") + " inv relay is not a *mempool.TxDesc") return } - if !sp.filter.MatchTxAndUpdate(tx) { + if !sp.filter.MatchTxAndUpdate(txD.Tx) { return } }