From ab226e09a66a5f6066d0957d0af9b966377e54da Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 10 Nov 2022 20:31:29 -0600 Subject: [PATCH] mempool: Store transaction descs in pools. Currently, several places that interact with the maps that house the raw transactions and staged transactions need access to the additional description data for the transaction in addition to the transaction itself. This involves an additional lookup and the need to pass around the map that houses that associated description data to perform the lookup. In order to avoid that additional lookup, passing around the associated map, and to simplify the code, this modifies those maps to store the overall transaction descriptions directly instead of the raw transactions and updates the various consumers accordingly. --- internal/mempool/mempool.go | 71 ++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/internal/mempool/mempool.go b/internal/mempool/mempool.go index cbc8039819..6aeea1cca1 100644 --- a/internal/mempool/mempool.go +++ b/internal/mempool/mempool.go @@ -248,11 +248,11 @@ type TxPool struct { orphans map[chainhash.Hash]*orphanTx orphansByPrev map[wire.OutPoint]map[chainhash.Hash]*dcrutil.Tx - outpoints map[wire.OutPoint]*dcrutil.Tx + outpoints map[wire.OutPoint]*TxDesc miningView *mining.TxMiningView staged map[chainhash.Hash]*TxDesc - stagedOutpoints map[wire.OutPoint]*dcrutil.Tx + stagedOutpoints map[wire.OutPoint]*TxDesc transient map[chainhash.Hash]*dcrutil.Tx @@ -634,7 +634,7 @@ func (mp *TxPool) stageTransaction(txDesc *TxDesc) { tx := txDesc.Tx mp.staged[*tx.Hash()] = txDesc for _, txIn := range tx.MsgTx().TxIn { - mp.stagedOutpoints[txIn.PreviousOutPoint] = tx + mp.stagedOutpoints[txIn.PreviousOutPoint] = txDesc } } @@ -670,8 +670,8 @@ func (mp *TxPool) hasMempoolInput(tx *dcrutil.Tx) bool { // and invokes the function f for each transaction in the set. // // This function MUST be called with the mempool lock held (for reads). -func forEachRedeemer(tx *dcrutil.Tx, outpoints map[wire.OutPoint]*dcrutil.Tx, - pool map[chainhash.Hash]*TxDesc, f func(redeemerTxDesc *TxDesc)) { +func forEachRedeemer(tx *dcrutil.Tx, outpoints map[wire.OutPoint]*TxDesc, + f func(redeemerTxDesc *TxDesc)) { tree := wire.TxTreeRegular numOutputs := uint32(len(tx.MsgTx().TxOut)) @@ -679,20 +679,19 @@ func forEachRedeemer(tx *dcrutil.Tx, outpoints map[wire.OutPoint]*dcrutil.Tx, outpoint := wire.OutPoint{Hash: *tx.Hash(), Tree: tree} for i := uint32(0); i < numOutputs; i++ { outpoint.Index = i - redeemerTx, exists := outpoints[outpoint] + redeemerTxDesc, exists := outpoints[outpoint] if !exists { continue } - redeemerTxHash := redeemerTx.Hash() - if redeemerTxDesc, exist := pool[*redeemerTxHash]; exist { - // Skip previously seen redeemers. - if _, saw := seen[*redeemerTxHash]; saw { - continue - } - seen[*redeemerTxHash] = struct{}{} - f(redeemerTxDesc) + // Skip previously seen redeemers. + redeemerTxHash := redeemerTxDesc.Tx.Hash() + if _, saw := seen[*redeemerTxHash]; saw { + continue } + seen[*redeemerTxHash] = struct{}{} + + f(redeemerTxDesc) } } @@ -702,7 +701,7 @@ func forEachRedeemer(tx *dcrutil.Tx, outpoints map[wire.OutPoint]*dcrutil.Tx, // // This function MUST be called with the mempool lock held (for reads). func (mp *TxPool) forEachRedeemer(tx *dcrutil.Tx, f func(redeemer *TxDesc)) { - forEachRedeemer(tx, mp.outpoints, mp.pool, f) + forEachRedeemer(tx, mp.outpoints, f) } // forEachStagedRedeemer scans the stage pool for transactions that have an @@ -711,7 +710,7 @@ func (mp *TxPool) forEachRedeemer(tx *dcrutil.Tx, f func(redeemer *TxDesc)) { // // This function MUST be called with the mempool lock held (for reads). func (mp *TxPool) forEachStagedRedeemer(tx *dcrutil.Tx, f func(redeemer *TxDesc)) { - forEachRedeemer(tx, mp.stagedOutpoints, mp.staged, f) + forEachRedeemer(tx, mp.stagedOutpoints, f) } // haveTransaction returns whether or not the passed transaction already exists @@ -794,13 +793,13 @@ func (mp *TxPool) removeTransaction(tx *dcrutil.Tx, removeRedeemers bool) { outpoint := wire.OutPoint{Hash: *txHash, Tree: tree} for i := uint32(0); i < uint32(len(tx.MsgTx().TxOut)); i++ { outpoint.Index = i - if txRedeemer, exists := mp.outpoints[outpoint]; exists { - mp.removeTransaction(txRedeemer, true) + if txRedeemerDesc, exists := mp.outpoints[outpoint]; exists { + mp.removeTransaction(txRedeemerDesc.Tx, true) continue } - if txRedeemer, exists := mp.stagedOutpoints[outpoint]; exists { + if txRedeemerDesc, exists := mp.stagedOutpoints[outpoint]; exists { log.Tracef("Removing staged transaction %v", outpoint.Hash) - mp.removeStagedTransaction(txRedeemer) + mp.removeStagedTransaction(txRedeemerDesc.Tx) } } } @@ -859,16 +858,16 @@ func (mp *TxPool) RemoveDoubleSpends(tx *dcrutil.Tx) { // Protect concurrent access. mp.mtx.Lock() for _, txIn := range tx.MsgTx().TxIn { - if txRedeemer, ok := mp.outpoints[txIn.PreviousOutPoint]; ok { - if !txRedeemer.Hash().IsEqual(tx.Hash()) { - mp.removeTransaction(txRedeemer, true) + if txRedeemerDesc, ok := mp.outpoints[txIn.PreviousOutPoint]; ok { + if txRedeemerDesc.Tx.Hash() != tx.Hash() { + mp.removeTransaction(txRedeemerDesc.Tx, true) } } - if txRedeemer, ok := mp.stagedOutpoints[txIn.PreviousOutPoint]; ok { - if !txRedeemer.Hash().IsEqual(tx.Hash()) { - log.Debugf("Removing double spend transaction %v "+ - "from stage pool", tx.Hash()) - mp.removeStagedTransaction(txRedeemer) + if txRedeemerDesc, ok := mp.stagedOutpoints[txIn.PreviousOutPoint]; ok { + if txRedeemerDesc.Tx.Hash() != tx.Hash() { + log.Debugf("Removing double spend transaction %v from stage "+ + "pool", tx.Hash()) + mp.removeStagedTransaction(txRedeemerDesc.Tx) } } } @@ -908,7 +907,7 @@ func (mp *TxPool) addTransaction(utxoView *blockchain.UtxoViewpoint, txDesc *TxD msgTx := tx.MsgTx() for _, txIn := range msgTx.TxIn { - mp.outpoints[txIn.PreviousOutPoint] = tx + mp.outpoints[txIn.PreviousOutPoint] = txDesc } atomic.StoreInt64(&mp.lastUpdated, time.Now().Unix()) @@ -948,14 +947,14 @@ func (mp *TxPool) checkPoolDoubleSpend(tx *dcrutil.Tx, txType stake.TxType, isTr } if txR, exists := mp.outpoints[txIn.PreviousOutPoint]; exists { - str := fmt.Sprintf("transaction %v in the pool "+ - "already spends the same coins", txR.Hash()) + str := fmt.Sprintf("transaction %v in the pool already spends the "+ + "same coins", txR.Tx.Hash()) return txRuleError(ErrMempoolDoubleSpend, str) } if txR, exists := mp.stagedOutpoints[txIn.PreviousOutPoint]; exists { str := fmt.Sprintf("transaction %v in the stage pool "+ - "already spends the same coins", txR.Hash()) + "already spends the same coins", txR.Tx.Hash()) return txRuleError(ErrMempoolDoubleSpend, str) } } @@ -1736,8 +1735,8 @@ func (mp *TxPool) maybeAcceptTransaction(tx *dcrutil.Tx, isNew, allowHighFees, // mempool tickets that redeem it to move to the stage pool. if !isNew && txType == stake.TxTypeRegular { mp.forEachRedeemer(tx, func(redeemerTxDesc *TxDesc) { - redeemerTx := redeemerTxDesc.Tx if redeemerTxDesc.Type == stake.TxTypeSStx { + redeemerTx := redeemerTxDesc.Tx mp.removeTransaction(redeemerTx, true) mp.stageTransaction(redeemerTxDesc) log.Debugf("Moved ticket %v dependent on %v into stage pool", @@ -2306,12 +2305,12 @@ func New(cfg *Config) *TxPool { pool: make(map[chainhash.Hash]*TxDesc), orphans: make(map[chainhash.Hash]*orphanTx), orphansByPrev: make(map[wire.OutPoint]map[chainhash.Hash]*dcrutil.Tx), - outpoints: make(map[wire.OutPoint]*dcrutil.Tx), + outpoints: make(map[wire.OutPoint]*TxDesc), votes: make(map[chainhash.Hash][]mining.VoteDesc), tspends: make(map[chainhash.Hash]*dcrutil.Tx), nextExpireScan: time.Now().Add(orphanExpireScanInterval), staged: make(map[chainhash.Hash]*TxDesc), - stagedOutpoints: make(map[wire.OutPoint]*dcrutil.Tx), + stagedOutpoints: make(map[wire.OutPoint]*TxDesc), transient: make(map[chainhash.Hash]*dcrutil.Tx), } @@ -2323,7 +2322,7 @@ func New(cfg *Config) *TxPool { for i := uint32(0); i < txOutLen; i++ { outpoint.Index = i if txRedeemer, exists := mp.outpoints[outpoint]; exists { - f(&mp.pool[txRedeemer.MsgTx().TxHash()].TxDesc) + f(&txRedeemer.TxDesc) } } }