Skip to content

Commit

Permalink
mempool+rpcserver: add interface TxMempool
Browse files Browse the repository at this point in the history
This commit adds a new interface `TxMempool` which defines how other
subsystems interact with `TxPool`.
  • Loading branch information
yyforyongyu authored and kcalvinalvin committed Nov 5, 2024
1 parent 9afb3df commit 32404c3
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 31 deletions.
2 changes: 1 addition & 1 deletion electrum/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ func handleTransactionBroadcast(s *ElectrumServer, cmd *btcjson.Request, conn ne
// Also, since an error is being returned to the caller, ensure the
// transaction is removed from the memory pool.
if len(acceptedTxs) == 0 || !acceptedTxs[0].Tx.Hash().IsEqual(tx.Hash()) {
s.cfg.Mempool.RemoveTransaction(tx, true, true)
s.cfg.Mempool.RemoveTransaction(tx, true)

errStr := fmt.Errorf("transaction %v is not in accepted list",
tx.Hash())
Expand Down
71 changes: 71 additions & 0 deletions mempool/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package mempool

import (
"time"

"github.com/utreexo/utreexod/btcjson"
"github.com/utreexo/utreexod/btcutil"
"github.com/utreexo/utreexod/chaincfg/chainhash"
"github.com/utreexo/utreexod/wire"
)

// TxMempool defines an interface that's used by other subsystems to interact
// with the mempool.
type TxMempool interface {
// LastUpdated returns the last time a transaction was added to or
// removed from the source pool.
LastUpdated() time.Time

// TxDescs returns a slice of descriptors for all the transactions in
// the pool.
TxDescs() []*TxDesc

// RawMempoolVerbose returns all the entries in the mempool as a fully
// populated btcjson result.
RawMempoolVerbose() map[string]*btcjson.GetRawMempoolVerboseResult

// Count returns the number of transactions in the main pool. It does
// not include the orphan pool.
Count() int

// FetchTransaction returns the requested transaction from the
// transaction pool. This only fetches from the main transaction pool
// and does not include orphans.
FetchTransaction(txHash *chainhash.Hash) (*btcutil.Tx, error)

// HaveTransaction returns whether or not the passed transaction
// already exists in the main pool or in the orphan pool.
HaveTransaction(hash *chainhash.Hash) bool

// 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.
//
// It returns a slice of transactions added to the mempool. When the
// error is nil, the list will include the passed transaction itself
// along with any additional orphan transactions that were added as a
// result of the passed one being accepted.
ProcessTransaction(tx *btcutil.Tx, allowOrphan,
rateLimit bool, tag Tag) ([]*TxDesc, error)

// RemoveTransaction removes the passed transaction from the mempool.
// When the removeRedeemers flag is set, any transactions that redeem
// outputs from the removed transaction will also be removed
// recursively from the mempool, as they would otherwise become
// orphans.
RemoveTransaction(tx *btcutil.Tx, removeRedeemers bool)

// CheckMempoolAcceptance behaves similarly to bitcoind's
// `testmempoolaccept` RPC method. It will perform a series of checks
// to decide whether this transaction can be accepted to the mempool.
// If not, the specific error is returned and the caller needs to take
// actions based on it.
CheckMempoolAcceptance(tx *btcutil.Tx) (*MempoolAcceptResult, error)

// CheckSpend checks whether the passed outpoint is already spent by
// a transaction in the mempool. If that's the case the spending
// transaction will be returned, if not nil will be returned.
CheckSpend(op wire.OutPoint) *btcutil.Tx
}
34 changes: 9 additions & 25 deletions mempool/mempool.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ type TxPool struct {
// Ensure the TxPool type implements the mining.TxSource interface.
var _ mining.TxSource = (*TxPool)(nil)

// Ensure the TxPool type implements the TxMemPool interface.
var _ TxMempool = (*TxPool)(nil)

// removeOrphan is the internal function which implements the public
// RemoveOrphan. See the comment for RemoveOrphan for more details.
//
Expand Down Expand Up @@ -481,14 +484,14 @@ func (mp *TxPool) HaveTransaction(hash *chainhash.Hash) bool {
// RemoveTransaction. See the comment for RemoveTransaction for more details.
//
// This function MUST be called with the mempool lock held (for writes).
func (mp *TxPool) removeTransaction(tx *btcutil.Tx, removeRedeemers, uncacheUtreexo bool) {
func (mp *TxPool) removeTransaction(tx *btcutil.Tx, removeRedeemers bool) {
txHash := tx.Hash()
if removeRedeemers {
// Remove any transactions which rely on this one.
for i := uint32(0); i < uint32(len(tx.MsgTx().TxOut)); i++ {
prevOut := wire.OutPoint{Hash: *txHash, Index: i}
if txRedeemer, exists := mp.outpoints[prevOut]; exists {
mp.removeTransaction(txRedeemer, true, uncacheUtreexo)
mp.removeTransaction(txRedeemer, true)
}
}
}
Expand All @@ -501,25 +504,6 @@ func (mp *TxPool) removeTransaction(tx *btcutil.Tx, removeRedeemers, uncacheUtre
mp.cfg.AddrIndex.RemoveUnconfirmedTx(txHash)
}

// If the utreexo view is active, then remove the cached hashes from the
// accumulator.
if mp.cfg.IsUtreexoViewActive != nil && mp.cfg.IsUtreexoViewActive() && uncacheUtreexo {
leaves, found := mp.poolLeaves[*txHash]
if !found {
log.Debugf("missing the leaf hashes for tx %s from while "+
"removing it from the pool",
tx.MsgTx().TxHash().String())
} else {
delete(mp.poolLeaves, *txHash)

err := mp.cfg.PruneFromAccumulator(leaves)
if err != nil {
log.Infof("err while pruning proof for inputs of tx %s: ",
err, tx.MsgTx().TxHash().String())
}
}
}

// Mark the referenced outpoints as unspent by the pool.
for _, txIn := range txDesc.Tx.MsgTx().TxIn {
delete(mp.outpoints, txIn.PreviousOutPoint)
Expand All @@ -536,10 +520,10 @@ func (mp *TxPool) removeTransaction(tx *btcutil.Tx, removeRedeemers, uncacheUtre
// it'll uncache the utreexo proof for the given tx if it's cached.
//
// This function is safe for concurrent access.
func (mp *TxPool) RemoveTransaction(tx *btcutil.Tx, removeRedeemers, uncacheUtreexo bool) {
func (mp *TxPool) RemoveTransaction(tx *btcutil.Tx, removeRedeemers bool) {
// Protect concurrent access.
mp.mtx.Lock()
mp.removeTransaction(tx, removeRedeemers, uncacheUtreexo)
mp.removeTransaction(tx, removeRedeemers)
mp.mtx.Unlock()
}

Expand All @@ -556,7 +540,7 @@ func (mp *TxPool) RemoveDoubleSpends(tx *btcutil.Tx) {
for _, txIn := range tx.MsgTx().TxIn {
if txRedeemer, ok := mp.outpoints[txIn.PreviousOutPoint]; ok {
if !txRedeemer.Hash().IsEqual(tx.Hash()) {
mp.removeTransaction(txRedeemer, true, true)
mp.removeTransaction(txRedeemer, true)
}
}
}
Expand Down Expand Up @@ -1052,7 +1036,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit,
//
// Don't remove the cached utreexo proof either because we'll need
// it for the ingestion.
mp.removeTransaction(conflict, false, false)
mp.removeTransaction(conflict, false)
}
txD := mp.addTransaction(r.utxoView, tx, r.bestHeight, int64(r.TxFee))

Expand Down
4 changes: 2 additions & 2 deletions netsync/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -1717,7 +1717,7 @@ func (sm *SyncManager) handleBlockchainNotification(notification *blockchain.Not
// transaction are NOT removed recursively because they are still
// valid.
for _, tx := range block.Transactions()[1:] {
sm.txMemPool.RemoveTransaction(tx, false, true)
sm.txMemPool.RemoveTransaction(tx, false)
sm.txMemPool.RemoveDoubleSpends(tx)
sm.txMemPool.RemoveOrphan(tx)
sm.peerNotifier.TransactionConfirmed(tx)
Expand Down Expand Up @@ -1756,7 +1756,7 @@ func (sm *SyncManager) handleBlockchainNotification(notification *blockchain.Not
// Remove the transaction and all transactions
// that depend on it if it wasn't accepted into
// the transaction pool.
sm.txMemPool.RemoveTransaction(tx, true, true)
sm.txMemPool.RemoveTransaction(tx, true)
}
}

Expand Down
6 changes: 3 additions & 3 deletions rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -3933,7 +3933,7 @@ func handleRebroadcastUnconfirmedBDKTxs(s *rpcServer, cmd interface{}, closeChan
tx := unconfirmedTx.Tx

// If it's already in the mempool, then we've already broadcasted it.
if s.cfg.TxMemPool.IsTransactionInPool(tx.Hash()) {
if s.cfg.TxMemPool.HaveTransaction(tx.Hash()) {
continue
}

Expand Down Expand Up @@ -4322,7 +4322,7 @@ func (s *rpcServer) rpcProcessTx(tx *btcutil.Tx, allowOrphan, rateLimit bool) er
// Also, since an error is being returned to the caller, ensure the
// transaction is removed from the memory pool.
if len(acceptedTxs) == 0 || !acceptedTxs[0].Tx.Hash().IsEqual(tx.Hash()) {
s.cfg.TxMemPool.RemoveTransaction(tx, true, true)
s.cfg.TxMemPool.RemoveTransaction(tx, true)

errStr := fmt.Sprintf("transaction %v is not in accepted list",
tx.Hash())
Expand Down Expand Up @@ -5633,7 +5633,7 @@ type rpcserverConfig struct {
DB database.DB

// TxMemPool defines the transaction memory pool to interact with.
TxMemPool *mempool.TxPool
TxMemPool mempool.TxMempool

// These fields allow the RPC server to interface with mining.
//
Expand Down

0 comments on commit 32404c3

Please sign in to comment.