From 40a10edbb7bec74d23c0faa0a0173c3452a8c9b0 Mon Sep 17 00:00:00 2001 From: D-Stacks Date: Sat, 2 Jul 2022 11:28:22 +0200 Subject: [PATCH] fix mempool accessing, rewrite get_mempool_entries_by_addresses --- .../get_mempool_entries_by_addresses.go | 170 ++++++------------ domain/miningmanager/factory.go | 2 +- .../check_transaction_standard_test.go | 6 +- .../mempool/handle_new_block_transactions.go | 4 +- domain/miningmanager/mempool/mempool.go | 47 +++-- .../miningmanager/mempool/mempool_utxo_set.go | 2 +- domain/miningmanager/mempool/orphan_pool.go | 68 ++++++- .../revalidate_high_priority_transactions.go | 31 +++- .../mempool/transactions_pool.go | 64 ++++++- .../validate_and_insert_transaction.go | 10 +- domain/miningmanager/miningmanager.go | 23 +++ .../miningmanager/model/interface_mempool.go | 9 + 12 files changed, 282 insertions(+), 154 deletions(-) diff --git a/app/rpc/rpchandlers/get_mempool_entries_by_addresses.go b/app/rpc/rpchandlers/get_mempool_entries_by_addresses.go index d40d42332..aedd433b1 100644 --- a/app/rpc/rpchandlers/get_mempool_entries_by_addresses.go +++ b/app/rpc/rpchandlers/get_mempool_entries_by_addresses.go @@ -1,14 +1,9 @@ package rpchandlers import ( - "errors" - "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/rpc/rpccontext" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" - "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" "github.com/kaspanet/kaspad/util" ) @@ -20,128 +15,77 @@ func HandleGetMempoolEntriesByAddresses(context *rpccontext.Context, _ *router.R mempoolEntriesByAddresses := make([]*appmessage.MempoolEntryByAddress, 0) - if !getMempoolEntriesByAddressesRequest.FilterTransactionPool { - transactionPoolTransactions := context.Domain.MiningManager().AllTransactions() - transactionPoolEntriesByAddresses, err := extractMempoolEntriesByAddressesFromTransactions( - context, - getMempoolEntriesByAddressesRequest.Addresses, - transactionPoolTransactions, - false, - ) + for _, addressString := range getMempoolEntriesByAddressesRequest.Addresses { + + address, err := util.DecodeAddress(addressString, context.Config.NetParams().Prefix) if err != nil { - rpcError := &appmessage.RPCError{} - if !errors.As(err, &rpcError) { - return nil, err - } - errorMessage := &appmessage.GetUTXOsByAddressesResponseMessage{} - errorMessage.Error = rpcError + errorMessage := &appmessage.GetMempoolEntriesByAddressesResponseMessage{} + errorMessage.Error = appmessage.RPCErrorf("Could not decode address '%s': %s", addressString, err) return errorMessage, nil } - mempoolEntriesByAddresses = append(mempoolEntriesByAddresses, transactionPoolEntriesByAddresses...) - } - - if getMempoolEntriesByAddressesRequest.IncludeOrphanPool { - - orphanPoolTransactions := context.Domain.MiningManager().AllOrphanTransactions() - orphanPoolEntriesByAddresse, err := extractMempoolEntriesByAddressesFromTransactions( - context, - getMempoolEntriesByAddressesRequest.Addresses, - orphanPoolTransactions, - true, - ) - if err != nil { - rpcError := &appmessage.RPCError{} - if !errors.As(err, &rpcError) { - return nil, err - } - errorMessage := &appmessage.GetUTXOsByAddressesResponseMessage{} - errorMessage.Error = rpcError - return errorMessage, nil - } - - mempoolEntriesByAddresses = append(mempoolEntriesByAddresses, orphanPoolEntriesByAddresse...) - } - - return appmessage.NewGetMempoolEntriesByAddressesResponseMessage(mempoolEntriesByAddresses), nil -} - -//TO DO: optimize extractMempoolEntriesByAddressesFromTransactions -func extractMempoolEntriesByAddressesFromTransactions(context *rpccontext.Context, addresses []string, transactions []*externalapi.DomainTransaction, areOrphans bool) ([]*appmessage.MempoolEntryByAddress, error) { - mempoolEntriesByAddresses := make([]*appmessage.MempoolEntryByAddress, 0) - for _, addressString := range addresses { - _, err := util.DecodeAddress(addressString, context.Config.ActiveNetParams.Prefix) - if err != nil { - return nil, appmessage.RPCErrorf("Could not decode address '%s': %s", addressString, err) - } sending := make([]*appmessage.MempoolEntry, 0) receiving := make([]*appmessage.MempoolEntry, 0) - for _, transaction := range transactions { + if !getMempoolEntriesByAddressesRequest.FilterTransactionPool { - for i, input := range transaction.Inputs { - // TODO: Fix this - if input.UTXOEntry == nil { - log.Errorf("Couldn't find UTXO entry for input %d in mempool transaction %s. This is a bug and should be fixed.", i, consensushashing.TransactionID(transaction)) - continue - } - - _, transactionSendingAddress, err := txscript.ExtractScriptPubKeyAddress( - input.UTXOEntry.ScriptPublicKey(), - context.Config.ActiveNetParams) - if err != nil { - return nil, err - } - if addressString == transactionSendingAddress.String() { - rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction) - sending = append( - sending, - &appmessage.MempoolEntry{ - Fee: transaction.Fee, - Transaction: rpcTransaction, - IsOrphan: areOrphans, - }, - ) - break //one input is enough - } + sendingInMempool, receivingInMempool, err := context.Domain.MiningManager().GetTransactionsByAddresses() + if err != nil { + return nil, err } - for _, output := range transaction.Outputs { - _, transactionReceivingAddress, err := txscript.ExtractScriptPubKeyAddress( - output.ScriptPublicKey, - context.Config.ActiveNetParams, - ) - if err != nil { - return nil, err - } - if addressString == transactionReceivingAddress.String() { - rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction) - receiving = append( - receiving, - &appmessage.MempoolEntry{ - Fee: transaction.Fee, - Transaction: rpcTransaction, - IsOrphan: areOrphans, - }, - ) - break //one output is enough - } + if transaction, found := sendingInMempool[address]; found { + rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction) + sending = append(sending, &appmessage.MempoolEntry{ + Fee: transaction.Fee, + Transaction: rpcTransaction, + IsOrphan: false}) } - //Only append mempoolEntriesByAddress, if at least 1 mempoolEntry for the address is found. - //This mimics the behaviour of GetUtxosByAddresses RPC call. - if len(sending) > 0 || len(receiving) > 0 { - mempoolEntriesByAddresses = append( - mempoolEntriesByAddresses, - &appmessage.MempoolEntryByAddress{ - Address: addressString, - Sending: sending, - Receiving: receiving, - }, - ) + if transaction, found := receivingInMempool[address]; found { + rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction) + receiving = append(receiving, &appmessage.MempoolEntry{ + Fee: transaction.Fee, + Transaction: rpcTransaction, + IsOrphan: false}) } } + if getMempoolEntriesByAddressesRequest.IncludeOrphanPool { + sendingInOrphanPool, receivingInOrphanPool, err := context.Domain.MiningManager().GetOrphanTransactionsByAddresses() + if err != nil { + return nil, err + } + + if transaction, found := sendingInOrphanPool[address]; found { + rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction) + sending = append(sending, &appmessage.MempoolEntry{ + Fee: transaction.Fee, + Transaction: rpcTransaction, + IsOrphan: true}) + } + + if transaction, found := receivingInOrphanPool[address]; found { + rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction) + receiving = append(receiving, &appmessage.MempoolEntry{ + Fee: transaction.Fee, + Transaction: rpcTransaction, + IsOrphan: true}) + } + + } + + if len(sending) > 0 || len(receiving) > 0 { + mempoolEntriesByAddresses = append( + mempoolEntriesByAddresses, + &appmessage.MempoolEntryByAddress{ + Address: address.String(), + Sending: sending, + Receiving: receiving, + }, + ) + } } - return mempoolEntriesByAddresses, nil + + return appmessage.NewGetMempoolEntriesByAddressesResponseMessage(mempoolEntriesByAddresses), nil } diff --git a/domain/miningmanager/factory.go b/domain/miningmanager/factory.go index 16b50fb29..26ad5faaf 100644 --- a/domain/miningmanager/factory.go +++ b/domain/miningmanager/factory.go @@ -20,7 +20,7 @@ type factory struct{} func (f *factory) NewMiningManager(consensusReference consensusreference.ConsensusReference, params *dagconfig.Params, mempoolConfig *mempoolpkg.Config) MiningManager { - mempool := mempoolpkg.New(mempoolConfig, consensusReference) + mempool := mempoolpkg.New(mempoolConfig, params, consensusReference) blockTemplateBuilder := blocktemplatebuilder.New(consensusReference, mempool, params.MaxBlockMass, params.CoinbasePayloadScriptPublicKeyMaxLength) return &miningManager{ diff --git a/domain/miningmanager/mempool/check_transaction_standard_test.go b/domain/miningmanager/mempool/check_transaction_standard_test.go index 1482c2b8c..ba5a05192 100644 --- a/domain/miningmanager/mempool/check_transaction_standard_test.go +++ b/domain/miningmanager/mempool/check_transaction_standard_test.go @@ -95,7 +95,7 @@ func TestCalcMinRequiredTxRelayFee(t *testing.T) { mempoolConfig.MinimumRelayTransactionFee = test.minimumRelayTransactionFee tcAsConsensus := tc.(externalapi.Consensus) tcAsConsensusPointer := &tcAsConsensus - mempool := New(mempoolConfig, consensusreference.NewConsensusReference(&tcAsConsensusPointer)).(*mempool) + mempool := New(mempoolConfig, tc.DAGParams(), consensusreference.NewConsensusReference(&tcAsConsensusPointer)).(*mempool) got := mempool.minimumRequiredTransactionRelayFee(test.size) if got != test.want { @@ -184,7 +184,7 @@ func TestIsTransactionOutputDust(t *testing.T) { mempoolConfig.MinimumRelayTransactionFee = test.minimumRelayTransactionFee tcAsConsensus := tc.(externalapi.Consensus) tcAsConsensusPointer := &tcAsConsensus - mempool := New(mempoolConfig, consensusreference.NewConsensusReference(&tcAsConsensusPointer)).(*mempool) + mempool := New(mempoolConfig, tc.DAGParams(), consensusreference.NewConsensusReference(&tcAsConsensusPointer)).(*mempool) res := mempool.IsTransactionOutputDust(&test.txOut) if res != test.isDust { @@ -306,7 +306,7 @@ func TestCheckTransactionStandardInIsolation(t *testing.T) { tcAsConsensus := tc.(externalapi.Consensus) tcAsConsensusPointer := &tcAsConsensus consensusReference := consensusreference.NewConsensusReference(&tcAsConsensusPointer) - mempool := New(mempoolConfig, consensusReference).(*mempool) + mempool := New(mempoolConfig, tc.DAGParams(), consensusReference).(*mempool) // Ensure standardness is as expected. err := mempool.checkTransactionStandardInIsolation(test.tx) diff --git a/domain/miningmanager/mempool/handle_new_block_transactions.go b/domain/miningmanager/mempool/handle_new_block_transactions.go index 344043138..77ed98b4e 100644 --- a/domain/miningmanager/mempool/handle_new_block_transactions.go +++ b/domain/miningmanager/mempool/handle_new_block_transactions.go @@ -6,7 +6,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" ) -func (mp *mempool) handleNewBlockTransactions(blockTransactions []*externalapi.DomainTransaction) ( +func (mp *mempool) handleNewBlockTransactions(blockTransactions []*externalapi.DomainTransaction, clone bool) ( []*externalapi.DomainTransaction, error) { // Skip the coinbase transaction @@ -30,7 +30,7 @@ func (mp *mempool) handleNewBlockTransactions(blockTransactions []*externalapi.D return nil, err } - acceptedOrphansFromThisTransaction, err := mp.orphansPool.processOrphansAfterAcceptedTransaction(transaction) + acceptedOrphansFromThisTransaction, err := mp.orphansPool.processOrphansAfterAcceptedTransaction(transaction, clone) if err != nil { return nil, err } diff --git a/domain/miningmanager/mempool/mempool.go b/domain/miningmanager/mempool/mempool.go index c6eb41fe4..70e47a773 100644 --- a/domain/miningmanager/mempool/mempool.go +++ b/domain/miningmanager/mempool/mempool.go @@ -1,9 +1,12 @@ package mempool import ( - "github.com/kaspanet/kaspad/domain/consensusreference" "sync" + "github.com/kaspanet/kaspad/domain/consensusreference" + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/kaspanet/kaspad/util" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" miningmanagermodel "github.com/kaspanet/kaspad/domain/miningmanager/model" ) @@ -12,6 +15,7 @@ type mempool struct { mtx sync.RWMutex config *Config + params *dagconfig.Params consensusReference consensusreference.ConsensusReference mempoolUTXOSet *mempoolUTXOSet @@ -20,9 +24,10 @@ type mempool struct { } // New constructs a new mempool -func New(config *Config, consensusReference consensusreference.ConsensusReference) miningmanagermodel.Mempool { +func New(config *Config, params *dagconfig.Params, consensusReference consensusreference.ConsensusReference) miningmanagermodel.Mempool { mp := &mempool{ config: config, + params: params, consensusReference: consensusReference, } @@ -39,35 +44,57 @@ func (mp *mempool) ValidateAndInsertTransaction(transaction *externalapi.DomainT mp.mtx.Lock() defer mp.mtx.Unlock() - return mp.validateAndInsertTransaction(transaction, isHighPriority, allowOrphan) + return mp.validateAndInsertTransaction(transaction, isHighPriority, allowOrphan, true) } func (mp *mempool) GetTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) { mp.mtx.RLock() defer mp.mtx.RUnlock() - return mp.transactionsPool.getTransaction(transactionID) + return mp.transactionsPool.getTransaction(transactionID, true) +} + +func (mp *mempool) GetTransactionsByAddresses() ( + sending map[util.Address]*externalapi.DomainTransaction, + receiving map[util.Address]*externalapi.DomainTransaction, + err error, +) { + mp.mtx.RLock() + defer mp.mtx.RUnlock() + + return mp.transactionsPool.getTransactionsByAddresses(true) } func (mp *mempool) AllTransactions() []*externalapi.DomainTransaction { mp.mtx.RLock() defer mp.mtx.RUnlock() - return mp.transactionsPool.getAllTransactions() + return mp.transactionsPool.getAllTransactions(true) } func (mp *mempool) GetOrphanTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) { mp.mtx.RLock() defer mp.mtx.RUnlock() - return mp.orphansPool.getOrphanTransaction(transactionID) + return mp.orphansPool.getOrphanTransaction(transactionID, true) +} + +func (mp *mempool) GetOrphanTransactionsByAddresses() ( + sending map[util.Address]*externalapi.DomainTransaction, + receiving map[util.Address]*externalapi.DomainTransaction, + err error, +) { + mp.mtx.RLock() + defer mp.mtx.RUnlock() + + return mp.orphansPool.getOrphanTransactionsByAddresses(true) } func (mp *mempool) AllOrphanTransactions() []*externalapi.DomainTransaction { mp.mtx.RLock() defer mp.mtx.RUnlock() - return mp.orphansPool.getAllOrphanTransactions() + return mp.orphansPool.getAllOrphanTransactions(true) } func (mp *mempool) TransactionCount() int { @@ -83,21 +110,21 @@ func (mp *mempool) HandleNewBlockTransactions(transactions []*externalapi.Domain mp.mtx.Lock() defer mp.mtx.Unlock() - return mp.handleNewBlockTransactions(transactions) + return mp.handleNewBlockTransactions(transactions, true) } func (mp *mempool) BlockCandidateTransactions() []*externalapi.DomainTransaction { mp.mtx.RLock() defer mp.mtx.RUnlock() - return mp.transactionsPool.allReadyTransactions() + return mp.transactionsPool.allReadyTransactions(true) } func (mp *mempool) RevalidateHighPriorityTransactions() (validTransactions []*externalapi.DomainTransaction, err error) { mp.mtx.Lock() defer mp.mtx.Unlock() - return mp.revalidateHighPriorityTransactions() + return mp.revalidateHighPriorityTransactions(true) } func (mp *mempool) RemoveTransactions(transactions []*externalapi.DomainTransaction, removeRedeemers bool) error { diff --git a/domain/miningmanager/mempool/mempool_utxo_set.go b/domain/miningmanager/mempool/mempool_utxo_set.go index aa20d05d5..bbe555258 100644 --- a/domain/miningmanager/mempool/mempool_utxo_set.go +++ b/domain/miningmanager/mempool/mempool_utxo_set.go @@ -51,7 +51,7 @@ func (mpus *mempoolUTXOSet) addTransaction(transaction *model.MempoolTransaction func (mpus *mempoolUTXOSet) removeTransaction(transaction *model.MempoolTransaction) { for _, input := range transaction.Transaction().Inputs { // If the transaction creating the output spent by this input is in the mempool - restore it's UTXO - if _, ok := mpus.mempool.transactionsPool.getTransaction(&input.PreviousOutpoint.TransactionID); ok { + if _, ok := mpus.mempool.transactionsPool.getTransaction(&input.PreviousOutpoint.TransactionID, false); ok { mpus.poolUnspentOutputs[input.PreviousOutpoint] = input.UTXOEntry } delete(mpus.transactionByPreviousOutpoint, input.PreviousOutpoint) diff --git a/domain/miningmanager/mempool/orphan_pool.go b/domain/miningmanager/mempool/orphan_pool.go index d053ecd28..65fc8d8ae 100644 --- a/domain/miningmanager/mempool/orphan_pool.go +++ b/domain/miningmanager/mempool/orphan_pool.go @@ -4,6 +4,8 @@ import ( "fmt" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" + "github.com/kaspanet/kaspad/util" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" @@ -134,7 +136,7 @@ func (op *orphansPool) addOrphan(transaction *externalapi.DomainTransaction, isH return nil } -func (op *orphansPool) processOrphansAfterAcceptedTransaction(acceptedTransaction *externalapi.DomainTransaction) ( +func (op *orphansPool) processOrphansAfterAcceptedTransaction(acceptedTransaction *externalapi.DomainTransaction, clone bool) ( acceptedOrphans []*externalapi.DomainTransaction, err error) { acceptedOrphans = []*externalapi.DomainTransaction{} @@ -169,7 +171,11 @@ func (op *orphansPool) processOrphansAfterAcceptedTransaction(acceptedTransactio } return nil, err } - acceptedOrphans = append(acceptedOrphans, orphan.Transaction()) + if clone { + acceptedOrphans = append(acceptedOrphans, orphan.Transaction().Clone()) + } else { + acceptedOrphans = append(acceptedOrphans, orphan.Transaction()) + } } } } @@ -329,17 +335,67 @@ func (op *orphansPool) randomNonHighPriorityOrphan() *model.OrphanTransaction { return nil } -func (op *orphansPool) getOrphanTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) { +func (op *orphansPool) getOrphanTransaction(transactionID *externalapi.DomainTransactionID, clone bool) (*externalapi.DomainTransaction, bool) { if orphanTransaction, ok := op.allOrphans[*transactionID]; ok { + if clone { + return orphanTransaction.Transaction().Clone(), true + } return orphanTransaction.Transaction(), true } return nil, false } -func (op *orphansPool) getAllOrphanTransactions() []*externalapi.DomainTransaction { - allOrphanTransactions := make([]*externalapi.DomainTransaction, 0, len(op.allOrphans)) +func (op *orphansPool) getOrphanTransactionsByAddresses(clone bool) ( + sending map[util.Address]*externalapi.DomainTransaction, + receiving map[util.Address]*externalapi.DomainTransaction, + err error) { + sending = make(map[util.Address]*externalapi.DomainTransaction) + receiving = make(map[util.Address]*externalapi.DomainTransaction) + var transaction *externalapi.DomainTransaction for _, mempoolTransaction := range op.allOrphans { - allOrphanTransactions = append(allOrphanTransactions, mempoolTransaction.Transaction()) + if clone { + transaction = mempoolTransaction.Transaction().Clone() + } else { + transaction = mempoolTransaction.Transaction() + } + for _, input := range transaction.Inputs { + if input.UTXOEntry == nil { //this is not a bug, but a valid state of orphan transactions with missing outpoints. + continue + } + _, address, err := txscript.ExtractScriptPubKeyAddress(input.UTXOEntry.ScriptPublicKey(), op.mempool.params) + if err != nil { + return nil, nil, err + } + if address == nil { //none standard tx + continue + } + sending[address] = transaction + for _, output := range transaction.Outputs { + _, address, err := txscript.ExtractScriptPubKeyAddress(output.ScriptPublicKey, op.mempool.params) + if err != nil { + return nil, nil, err + } + if address == nil { //none standard tx + continue + } + receiving[address] = transaction + + } + } + } + + return sending, receiving, nil +} + +func (op *orphansPool) getAllOrphanTransactions(clone bool) []*externalapi.DomainTransaction { + allOrphanTransactions := make([]*externalapi.DomainTransaction, len(op.allOrphans)) + i := 0 + for _, mempoolTransaction := range op.allOrphans { + if clone { + allOrphanTransactions[i] = mempoolTransaction.Transaction().Clone() + } else { + allOrphanTransactions[i] = mempoolTransaction.Transaction() + } } return allOrphanTransactions } diff --git a/domain/miningmanager/mempool/revalidate_high_priority_transactions.go b/domain/miningmanager/mempool/revalidate_high_priority_transactions.go index 6cb876875..a006c8503 100644 --- a/domain/miningmanager/mempool/revalidate_high_priority_transactions.go +++ b/domain/miningmanager/mempool/revalidate_high_priority_transactions.go @@ -6,22 +6,35 @@ import ( "github.com/kaspanet/kaspad/infrastructure/logger" ) -func (mp *mempool) revalidateHighPriorityTransactions() ([]*externalapi.DomainTransaction, error) { +func (mp *mempool) revalidateHighPriorityTransactions(clone bool) ([]*externalapi.DomainTransaction, error) { onEnd := logger.LogAndMeasureExecutionTime(log, "revalidateHighPriorityTransactions") defer onEnd() validTransactions := []*externalapi.DomainTransaction{} + if !clone { + for _, transaction := range mp.transactionsPool.highPriorityTransactions { + isValid, err := mp.revalidateTransaction(transaction) + if err != nil { + return nil, err + } + if !isValid { + continue + } - for _, transaction := range mp.transactionsPool.highPriorityTransactions { - isValid, err := mp.revalidateTransaction(transaction) - if err != nil { - return nil, err - } - if !isValid { - continue + validTransactions = append(validTransactions, transaction.Transaction()) } + } else { + for _, transaction := range mp.transactionsPool.highPriorityTransactions { + isValid, err := mp.revalidateTransaction(transaction) + if err != nil { + return nil, err + } + if !isValid { + continue + } - validTransactions = append(validTransactions, transaction.Transaction()) + validTransactions = append(validTransactions, transaction.Transaction().Clone()) + } } return validTransactions, nil diff --git a/domain/miningmanager/mempool/transactions_pool.go b/domain/miningmanager/mempool/transactions_pool.go index bad4e7f7c..bfc0af311 100644 --- a/domain/miningmanager/mempool/transactions_pool.go +++ b/domain/miningmanager/mempool/transactions_pool.go @@ -6,7 +6,9 @@ import ( "github.com/pkg/errors" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" "github.com/kaspanet/kaspad/domain/miningmanager/mempool/model" + "github.com/kaspanet/kaspad/util" ) type transactionsPool struct { @@ -130,12 +132,16 @@ func (tp *transactionsPool) expireOldTransactions() error { return nil } -func (tp *transactionsPool) allReadyTransactions() []*externalapi.DomainTransaction { +func (tp *transactionsPool) allReadyTransactions(clone bool) []*externalapi.DomainTransaction { result := []*externalapi.DomainTransaction{} for _, mempoolTransaction := range tp.allTransactions { if len(mempoolTransaction.ParentTransactionsInPool()) == 0 { - result = append(result, mempoolTransaction.Transaction()) + if clone { + result = append(result, mempoolTransaction.Transaction().Clone()) + } else { + result = append(result, mempoolTransaction.Transaction()) + } } } @@ -204,17 +210,63 @@ func (tp *transactionsPool) limitTransactionCount() error { return nil } -func (tp *transactionsPool) getTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) { +func (tp *transactionsPool) getTransaction(transactionID *externalapi.DomainTransactionID, clone bool) (*externalapi.DomainTransaction, bool) { if mempoolTransaction, ok := tp.allTransactions[*transactionID]; ok { + if clone { + return mempoolTransaction.Transaction().Clone(), true + } return mempoolTransaction.Transaction(), true } return nil, false } -func (tp *transactionsPool) getAllTransactions() []*externalapi.DomainTransaction { - allTransactions := make([]*externalapi.DomainTransaction, 0, len(tp.allTransactions)) +func (tp *transactionsPool) getTransactionsByAddresses(clone bool) ( + sending map[util.Address]*externalapi.DomainTransaction, + receiving map[util.Address]*externalapi.DomainTransaction, + err error) { + sending = make(map[util.Address]*externalapi.DomainTransaction) + receiving = make(map[util.Address]*externalapi.DomainTransaction) + var transaction *externalapi.DomainTransaction for _, mempoolTransaction := range tp.allTransactions { - allTransactions = append(allTransactions, mempoolTransaction.Transaction()) + if clone { + transaction = mempoolTransaction.Transaction().Clone() + } else { + transaction = mempoolTransaction.Transaction() + } + for _, input := range transaction.Inputs { + _, address, err := txscript.ExtractScriptPubKeyAddress(input.UTXOEntry.ScriptPublicKey(), tp.mempool.params) + if err != nil { + return nil, nil, err + } + if address == nil { //ignore none-standard script + continue + } + sending[address] = transaction + for _, output := range transaction.Outputs { + _, address, err := txscript.ExtractScriptPubKeyAddress(output.ScriptPublicKey, tp.mempool.params) + if err != nil { + return nil, nil, err + } + if address == nil { //ignore none-standard script + continue + } + receiving[address] = transaction + } + } + } + return sending, receiving, nil +} + +func (tp *transactionsPool) getAllTransactions(clone bool) []*externalapi.DomainTransaction { + allTransactions := make([]*externalapi.DomainTransaction, len(tp.allTransactions)) + i := 0 + for _, mempoolTransaction := range tp.allTransactions { + if clone { + allTransactions[i] = mempoolTransaction.Transaction().Clone() + } else { + allTransactions[i] = mempoolTransaction.Transaction() + } + i++ } return allTransactions } diff --git a/domain/miningmanager/mempool/validate_and_insert_transaction.go b/domain/miningmanager/mempool/validate_and_insert_transaction.go index 3ccedc9bb..1ed6c9cce 100644 --- a/domain/miningmanager/mempool/validate_and_insert_transaction.go +++ b/domain/miningmanager/mempool/validate_and_insert_transaction.go @@ -10,7 +10,7 @@ import ( ) func (mp *mempool) validateAndInsertTransaction(transaction *externalapi.DomainTransaction, isHighPriority bool, - allowOrphan bool) (acceptedTransactions []*externalapi.DomainTransaction, err error) { + allowOrphan bool, clone bool) (acceptedTransactions []*externalapi.DomainTransaction, err error) { onEnd := logger.LogAndMeasureExecutionTime(log, fmt.Sprintf("validateAndInsertTransaction %s", consensushashing.TransactionID(transaction))) @@ -49,12 +49,16 @@ func (mp *mempool) validateAndInsertTransaction(transaction *externalapi.DomainT return nil, err } - acceptedOrphans, err := mp.orphansPool.processOrphansAfterAcceptedTransaction(mempoolTransaction.Transaction()) + acceptedOrphans, err := mp.orphansPool.processOrphansAfterAcceptedTransaction(mempoolTransaction.Transaction(), clone) if err != nil { return nil, err } - acceptedTransactions = append([]*externalapi.DomainTransaction{transaction}, acceptedOrphans...) + if clone { + acceptedTransactions = append([]*externalapi.DomainTransaction{transaction.Clone()}, acceptedOrphans...) + } else { + acceptedTransactions = append([]*externalapi.DomainTransaction{transaction}, acceptedOrphans...) + } err = mp.transactionsPool.limitTransactionCount() if err != nil { diff --git a/domain/miningmanager/miningmanager.go b/domain/miningmanager/miningmanager.go index 08e576f13..fc29dd59e 100644 --- a/domain/miningmanager/miningmanager.go +++ b/domain/miningmanager/miningmanager.go @@ -7,6 +7,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensusreference" miningmanagermodel "github.com/kaspanet/kaspad/domain/miningmanager/model" + "github.com/kaspanet/kaspad/util" ) // MiningManager creates block templates for mining as well as maintaining @@ -16,8 +17,16 @@ type MiningManager interface { ClearBlockTemplate() GetBlockTemplateBuilder() miningmanagermodel.BlockTemplateBuilder GetTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) + GetTransactionsByAddresses() ( + sending map[util.Address]*externalapi.DomainTransaction, + receiving map[util.Address]*externalapi.DomainTransaction, + err error) AllTransactions() []*externalapi.DomainTransaction GetOrphanTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) + GetOrphanTransactionsByAddresses() ( + sending map[util.Address]*externalapi.DomainTransaction, + receiving map[util.Address]*externalapi.DomainTransaction, + err error) AllOrphanTransactions() []*externalapi.DomainTransaction TransactionCount() int HandleNewBlockTransactions(txs []*externalapi.DomainTransaction) ([]*externalapi.DomainTransaction, error) @@ -118,12 +127,26 @@ func (mm *miningManager) AllTransactions() []*externalapi.DomainTransaction { return mm.mempool.AllTransactions() } +func (mm *miningManager) GetTransactionsByAddresses() ( + sending map[util.Address]*externalapi.DomainTransaction, + receiving map[util.Address]*externalapi.DomainTransaction, + err error) { + return mm.mempool.GetTransactionsByAddresses() +} + func (mm *miningManager) GetOrphanTransaction( transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) { return mm.mempool.GetOrphanTransaction(transactionID) } +func (mm *miningManager) GetOrphanTransactionsByAddresses() ( + sending map[util.Address]*externalapi.DomainTransaction, + receiving map[util.Address]*externalapi.DomainTransaction, + err error) { + return mm.mempool.GetTransactionsByAddresses() +} + func (mm *miningManager) AllOrphanTransactions() []*externalapi.DomainTransaction { return mm.mempool.AllOrphanTransactions() diff --git a/domain/miningmanager/model/interface_mempool.go b/domain/miningmanager/model/interface_mempool.go index caf6b5968..419ea6402 100644 --- a/domain/miningmanager/model/interface_mempool.go +++ b/domain/miningmanager/model/interface_mempool.go @@ -2,6 +2,7 @@ package model import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/util" ) // Mempool maintains a set of known transactions that @@ -13,8 +14,16 @@ type Mempool interface { acceptedTransactions []*externalapi.DomainTransaction, err error) RemoveTransactions(txs []*externalapi.DomainTransaction, removeRedeemers bool) error GetTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) + GetTransactionsByAddresses() ( + sending map[util.Address]*externalapi.DomainTransaction, + receiving map[util.Address]*externalapi.DomainTransaction, + err error) AllTransactions() []*externalapi.DomainTransaction GetOrphanTransaction(transactionID *externalapi.DomainTransactionID) (*externalapi.DomainTransaction, bool) + GetOrphanTransactionsByAddresses() ( + sending map[util.Address]*externalapi.DomainTransaction, + receiving map[util.Address]*externalapi.DomainTransaction, + err error) AllOrphanTransactions() []*externalapi.DomainTransaction TransactionCount() int RevalidateHighPriorityTransactions() (validTransactions []*externalapi.DomainTransaction, err error)