Revalidate transactions before rebroadcast

This commit is contained in:
Mike Zak 2021-05-30 16:49:51 +03:00
parent 4f4a8934e7
commit 903fa58957
6 changed files with 64 additions and 13 deletions

View File

@ -80,7 +80,11 @@ func (f *FlowContext) broadcastTransactionsAfterBlockAdded(
var txIDsToRebroadcast []*externalapi.DomainTransactionID
if f.shouldRebroadcastTransactions() {
txIDsToRebroadcast = f.txIDsToRebroadcast()
var err error
txIDsToRebroadcast, err = f.txIDsToRebroadcast()
if err != nil {
return err
}
}
txIDsToBroadcast := make([]*externalapi.DomainTransactionID, len(transactionsAcceptedToMempool)+len(txIDsToRebroadcast))

View File

@ -44,17 +44,25 @@ func (f *FlowContext) shouldRebroadcastTransactions() bool {
return time.Since(f.lastRebroadcastTime) > rebroadcastInterval
}
func (f *FlowContext) txIDsToRebroadcast() []*externalapi.DomainTransactionID {
func (f *FlowContext) txIDsToRebroadcast() ([]*externalapi.DomainTransactionID, error) {
f.transactionsToRebroadcastLock.Lock()
defer f.transactionsToRebroadcastLock.Unlock()
txIDs := make([]*externalapi.DomainTransactionID, len(f.transactionsToRebroadcast))
txIDs := make([]*externalapi.DomainTransactionID, 0, len(f.transactionsToRebroadcast))
i := 0
for _, tx := range f.transactionsToRebroadcast {
txIDs[i] = consensushashing.TransactionID(tx)
isValid, err := f.Domain().MiningManager().RevalidateTransaction(tx)
if err != nil {
return nil, err
}
if !isValid {
continue
}
txIDs = append(txIDs, consensushashing.TransactionID(tx))
i++
}
return txIDs
return txIDs, nil
}
// SharedRequestedTransactions returns a *transactionrelay.SharedRequestedTransactions for sharing

View File

@ -0,0 +1 @@
package mempool

View File

@ -7,22 +7,19 @@ package mempool
import (
"container/list"
"fmt"
"github.com/kaspanet/kaspad/domain/dagconfig"
"sort"
"sync"
"time"
"github.com/kaspanet/kaspad/infrastructure/logger"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize"
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
"github.com/kaspanet/kaspad/domain/dagconfig"
miningmanagermodel "github.com/kaspanet/kaspad/domain/miningmanager/model"
"github.com/kaspanet/kaspad/infrastructure/logger"
"github.com/kaspanet/kaspad/util"
"github.com/kaspanet/kaspad/util/mstime"
"github.com/pkg/errors"
@ -164,6 +161,10 @@ type txDescriptor struct {
// one that is accepted to pool, but cannot be mined in next block because it
// depends on outputs of accepted, but still not mined transaction
depCount int
// expirationDAAScore is the virtual DAA score at which this transaction is expired
// if expirationDAAScore == 0 - the transaction never expires.
expirationDAAScore uint64
}
// orphanTx is normal transaction that references an ancestor transaction
@ -411,6 +412,13 @@ type transactionAndOutpoint struct {
outpoint *consensusexternalapi.DomainOutpoint
}
func (mp *mempool) removeTransactionAndItsChainedTransactionsWithLock(transaction *consensusexternalapi.DomainTransaction) error {
mp.mtx.Lock()
defer mp.mtx.Unlock()
return mp.removeTransactionAndItsChainedTransactions(transaction)
}
// removeTransactionAndItsChainedTransactions removes a transaction and all of its chained transaction from the mempool.
// This function MUST be called with the mempool lock held (for writes).
func (mp *mempool) removeTransactionAndItsChainedTransactions(transaction *consensusexternalapi.DomainTransaction) error {
@ -899,7 +907,9 @@ func (mp *mempool) processOrphans(acceptedTx *consensusexternalapi.DomainTransac
// the passed one being accepted.
//
// This function is safe for concurrent access.
func (mp *mempool) ValidateAndInsertTransaction(tx *consensusexternalapi.DomainTransaction, allowOrphan bool) error {
func (mp *mempool) ValidateAndInsertTransaction(
tx *consensusexternalapi.DomainTransaction, expirationDAAScore uint64, allowOrphan bool) error {
log.Tracef("Processing transaction %s", consensushashing.TransactionID(tx))
// Protect concurrent access.
@ -1042,3 +1052,25 @@ func (mp *mempool) RemoveTransactions(txs []*consensusexternalapi.DomainTransact
return mp.removeTransactionsFromPool(txs)
}
// RevalidateTransaction revalidates given transaction, and removes from mempool if it isn't valid
func (mp *mempool) RevalidateTransaction(tx *consensusexternalapi.DomainTransaction) (isValid bool, err error) {
tx = tx.Clone()
_ = mp.mempoolUTXOSet.populateUTXOEntries(tx)
err = mp.consensus.ValidateTransactionAndPopulateWithConsensusData(tx)
if err != nil {
if errors.As(err, &ruleerrors.RuleError{}) {
log.Debugf("Transaction %s was found invalid during revalidate and therefore is being removed from mempool",
consensushashing.TransactionID(tx))
err := mp.removeTransactionAndItsChainedTransactionsWithLock(tx)
if err != nil {
return false, err
}
return false, nil
}
return false, err
}
return true, nil
}

View File

@ -14,6 +14,7 @@ type MiningManager interface {
TransactionCount() int
HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) ([]*consensusexternalapi.DomainTransaction, error)
ValidateAndInsertTransaction(transaction *consensusexternalapi.DomainTransaction, allowOrphan bool) error
RevalidateTransaction(tx *consensusexternalapi.DomainTransaction) (isValid bool, err error)
}
type miningManager struct {
@ -51,3 +52,7 @@ func (mm *miningManager) AllTransactions() []*consensusexternalapi.DomainTransac
func (mm *miningManager) TransactionCount() int {
return mm.mempool.TransactionCount()
}
func (mm *miningManager) RevalidateTransaction(tx *consensusexternalapi.DomainTransaction) (isValid bool, err error) {
return mm.mempool.RevalidateTransaction(tx)
}

View File

@ -14,4 +14,5 @@ type Mempool interface {
GetTransaction(transactionID *consensusexternalapi.DomainTransactionID) (*consensusexternalapi.DomainTransaction, bool)
AllTransactions() []*consensusexternalapi.DomainTransaction
TransactionCount() int
RevalidateTransaction(tx *consensusexternalapi.DomainTransaction) (isValid bool, err error)
}