Fix bookkeeping of chained transactions in mempool (#1946)

* Fix bookkeeping of chained transactions in mempool

* Fix golint error
This commit is contained in:
Svarog 2022-02-18 13:21:45 +02:00 committed by GitHub
parent 13a09da848
commit f452531df0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 50 additions and 38 deletions

View File

@ -9,7 +9,7 @@ import (
) )
func (mp *mempool) fillInputsAndGetMissingParents(transaction *externalapi.DomainTransaction) ( func (mp *mempool) fillInputsAndGetMissingParents(transaction *externalapi.DomainTransaction) (
parents model.OutpointToTransactionMap, missingOutpoints []*externalapi.DomainOutpoint, err error) { parents model.IDToTransactionMap, missingOutpoints []*externalapi.DomainOutpoint, err error) {
parentsInPool := mp.transactionsPool.getParentTransactionsInPool(transaction) parentsInPool := mp.transactionsPool.getParentTransactionsInPool(transaction)
@ -34,9 +34,9 @@ func (mp *mempool) fillInputsAndGetMissingParents(transaction *externalapi.Domai
return parentsInPool, nil, nil return parentsInPool, nil, nil
} }
func fillInputs(transaction *externalapi.DomainTransaction, parentsInPool model.OutpointToTransactionMap) { func fillInputs(transaction *externalapi.DomainTransaction, parentsInPool model.IDToTransactionMap) {
for _, input := range transaction.Inputs { for _, input := range transaction.Inputs {
parent, ok := parentsInPool[input.PreviousOutpoint] parent, ok := parentsInPool[input.PreviousOutpoint.TransactionID]
if !ok { if !ok {
continue continue
} }

View File

@ -7,6 +7,9 @@ import (
// IDToTransactionMap maps transactionID to a MempoolTransaction // IDToTransactionMap maps transactionID to a MempoolTransaction
type IDToTransactionMap map[externalapi.DomainTransactionID]*MempoolTransaction type IDToTransactionMap map[externalapi.DomainTransactionID]*MempoolTransaction
// IDToTransactionsSliceMap maps transactionID to a slice MempoolTransaction
type IDToTransactionsSliceMap map[externalapi.DomainTransactionID][]*MempoolTransaction
// OutpointToUTXOEntryMap maps an outpoint to a UTXOEntry // OutpointToUTXOEntryMap maps an outpoint to a UTXOEntry
type OutpointToUTXOEntryMap map[externalapi.DomainOutpoint]externalapi.UTXOEntry type OutpointToUTXOEntryMap map[externalapi.DomainOutpoint]externalapi.UTXOEntry

View File

@ -8,7 +8,7 @@ import (
// MempoolTransaction represents a transaction inside the main TransactionPool // MempoolTransaction represents a transaction inside the main TransactionPool
type MempoolTransaction struct { type MempoolTransaction struct {
transaction *externalapi.DomainTransaction transaction *externalapi.DomainTransaction
parentTransactionsInPool OutpointToTransactionMap parentTransactionsInPool IDToTransactionMap
isHighPriority bool isHighPriority bool
addedAtDAAScore uint64 addedAtDAAScore uint64
} }
@ -16,7 +16,7 @@ type MempoolTransaction struct {
// NewMempoolTransaction constructs a new MempoolTransaction // NewMempoolTransaction constructs a new MempoolTransaction
func NewMempoolTransaction( func NewMempoolTransaction(
transaction *externalapi.DomainTransaction, transaction *externalapi.DomainTransaction,
parentTransactionsInPool OutpointToTransactionMap, parentTransactionsInPool IDToTransactionMap,
isHighPriority bool, isHighPriority bool,
addedAtDAAScore uint64, addedAtDAAScore uint64,
) *MempoolTransaction { ) *MempoolTransaction {
@ -39,10 +39,15 @@ func (mt *MempoolTransaction) Transaction() *externalapi.DomainTransaction {
} }
// ParentTransactionsInPool a list of parent transactions that exist in the mempool, indexed by outpoint // ParentTransactionsInPool a list of parent transactions that exist in the mempool, indexed by outpoint
func (mt *MempoolTransaction) ParentTransactionsInPool() OutpointToTransactionMap { func (mt *MempoolTransaction) ParentTransactionsInPool() IDToTransactionMap {
return mt.parentTransactionsInPool return mt.parentTransactionsInPool
} }
// RemoveParentTransactionInPool deletes a transaction from the parentTransactionsInPool set
func (mt *MempoolTransaction) RemoveParentTransactionInPool(transactionID *externalapi.DomainTransactionID) {
delete(mt.parentTransactionsInPool, *transactionID)
}
// IsHighPriority returns whether this MempoolTransaction is a high-priority one // IsHighPriority returns whether this MempoolTransaction is a high-priority one
func (mt *MempoolTransaction) IsHighPriority() bool { func (mt *MempoolTransaction) IsHighPriority() bool {
return mt.isHighPriority return mt.isHighPriority

View File

@ -27,9 +27,13 @@ func (mp *mempool) removeTransaction(transactionID *externalapi.DomainTransactio
} }
transactionsToRemove := []*model.MempoolTransaction{mempoolTransaction} transactionsToRemove := []*model.MempoolTransaction{mempoolTransaction}
redeemers := mp.transactionsPool.getRedeemers(mempoolTransaction)
if removeRedeemers { if removeRedeemers {
redeemers := mp.transactionsPool.getRedeemers(mempoolTransaction)
transactionsToRemove = append(transactionsToRemove, redeemers...) transactionsToRemove = append(transactionsToRemove, redeemers...)
} else {
for _, redeemer := range redeemers {
redeemer.RemoveParentTransactionInPool(transactionID)
}
} }
for _, transactionToRemove := range transactionsToRemove { for _, transactionToRemove := range transactionsToRemove {

View File

@ -1,35 +1,36 @@
package mempool package mempool
import ( import (
"time"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/miningmanager/mempool/model" "github.com/kaspanet/kaspad/domain/miningmanager/mempool/model"
"time"
) )
type transactionsPool struct { type transactionsPool struct {
mempool *mempool mempool *mempool
allTransactions model.IDToTransactionMap allTransactions model.IDToTransactionMap
highPriorityTransactions model.IDToTransactionMap highPriorityTransactions model.IDToTransactionMap
chainedTransactionsByPreviousOutpoint model.OutpointToTransactionMap chainedTransactionsByParentID model.IDToTransactionsSliceMap
transactionsOrderedByFeeRate model.TransactionsOrderedByFeeRate transactionsOrderedByFeeRate model.TransactionsOrderedByFeeRate
lastExpireScanDAAScore uint64 lastExpireScanDAAScore uint64
lastExpireScanTime time.Time lastExpireScanTime time.Time
} }
func newTransactionsPool(mp *mempool) *transactionsPool { func newTransactionsPool(mp *mempool) *transactionsPool {
return &transactionsPool{ return &transactionsPool{
mempool: mp, mempool: mp,
allTransactions: model.IDToTransactionMap{}, allTransactions: model.IDToTransactionMap{},
highPriorityTransactions: model.IDToTransactionMap{}, highPriorityTransactions: model.IDToTransactionMap{},
chainedTransactionsByPreviousOutpoint: model.OutpointToTransactionMap{}, chainedTransactionsByParentID: model.IDToTransactionsSliceMap{},
transactionsOrderedByFeeRate: model.TransactionsOrderedByFeeRate{}, transactionsOrderedByFeeRate: model.TransactionsOrderedByFeeRate{},
lastExpireScanDAAScore: 0, lastExpireScanDAAScore: 0,
lastExpireScanTime: time.Now(), lastExpireScanTime: time.Now(),
} }
} }
func (tp *transactionsPool) addTransaction(transaction *externalapi.DomainTransaction, func (tp *transactionsPool) addTransaction(transaction *externalapi.DomainTransaction,
parentTransactionsInPool model.OutpointToTransactionMap, isHighPriority bool) (*model.MempoolTransaction, error) { parentTransactionsInPool model.IDToTransactionMap, isHighPriority bool) (*model.MempoolTransaction, error) {
virtualDAAScore, err := tp.mempool.consensusReference.Consensus().GetVirtualDAAScore() virtualDAAScore, err := tp.mempool.consensusReference.Consensus().GetVirtualDAAScore()
if err != nil { if err != nil {
@ -50,8 +51,13 @@ func (tp *transactionsPool) addTransaction(transaction *externalapi.DomainTransa
func (tp *transactionsPool) addMempoolTransaction(transaction *model.MempoolTransaction) error { func (tp *transactionsPool) addMempoolTransaction(transaction *model.MempoolTransaction) error {
tp.allTransactions[*transaction.TransactionID()] = transaction tp.allTransactions[*transaction.TransactionID()] = transaction
for outpoint, parentTransactionInPool := range transaction.ParentTransactionsInPool() { for _, parentTransactionInPool := range transaction.ParentTransactionsInPool() {
tp.chainedTransactionsByPreviousOutpoint[outpoint] = parentTransactionInPool parentTransactionID := *parentTransactionInPool.TransactionID()
if tp.chainedTransactionsByParentID[parentTransactionID] == nil {
tp.chainedTransactionsByParentID[parentTransactionID] = []*model.MempoolTransaction{}
}
tp.chainedTransactionsByParentID[parentTransactionID] =
append(tp.chainedTransactionsByParentID[parentTransactionID], transaction)
} }
tp.mempool.mempoolUTXOSet.addTransaction(transaction) tp.mempool.mempoolUTXOSet.addTransaction(transaction)
@ -78,9 +84,7 @@ func (tp *transactionsPool) removeTransaction(transaction *model.MempoolTransact
delete(tp.highPriorityTransactions, *transaction.TransactionID()) delete(tp.highPriorityTransactions, *transaction.TransactionID())
for outpoint := range transaction.ParentTransactionsInPool() { delete(tp.chainedTransactionsByParentID, *transaction.TransactionID())
delete(tp.chainedTransactionsByPreviousOutpoint, outpoint)
}
return nil return nil
} }
@ -132,13 +136,13 @@ func (tp *transactionsPool) allReadyTransactions() []*externalapi.DomainTransact
} }
func (tp *transactionsPool) getParentTransactionsInPool( func (tp *transactionsPool) getParentTransactionsInPool(
transaction *externalapi.DomainTransaction) model.OutpointToTransactionMap { transaction *externalapi.DomainTransaction) model.IDToTransactionMap {
parentsTransactionsInPool := model.OutpointToTransactionMap{} parentsTransactionsInPool := model.IDToTransactionMap{}
for _, input := range transaction.Inputs { for _, input := range transaction.Inputs {
if transaction, ok := tp.allTransactions[input.PreviousOutpoint.TransactionID]; ok { if transaction, ok := tp.allTransactions[input.PreviousOutpoint.TransactionID]; ok {
parentsTransactionsInPool[input.PreviousOutpoint] = transaction parentsTransactionsInPool[*transaction.TransactionID()] = transaction
} }
} }
@ -153,13 +157,9 @@ func (tp *transactionsPool) getRedeemers(transaction *model.MempoolTransaction)
last := len(stack) - 1 last := len(stack) - 1
current, stack = stack[last], stack[:last] current, stack = stack[last], stack[:last]
outpoint := externalapi.DomainOutpoint{TransactionID: *current.TransactionID()} for _, redeemerTransaction := range tp.chainedTransactionsByParentID[*current.TransactionID()] {
for i := range current.Transaction().Outputs { stack = append(stack, redeemerTransaction)
outpoint.Index = uint32(i) redeemers = append(redeemers, redeemerTransaction)
if redeemerTransaction, ok := tp.chainedTransactionsByPreviousOutpoint[outpoint]; ok {
stack = append(stack, redeemerTransaction)
redeemers = append(redeemers, redeemerTransaction)
}
} }
} }
return redeemers return redeemers