diff --git a/domain/miningmanager/mempool/mempool.go b/domain/miningmanager/mempool/mempool.go index 6566719cb..cabdae0b3 100644 --- a/domain/miningmanager/mempool/mempool.go +++ b/domain/miningmanager/mempool/mempool.go @@ -3,6 +3,7 @@ package mempool import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/kaspanet/kaspad/domain/miningmanager/mempool/model" ) type mempool struct { @@ -60,7 +61,7 @@ func (mp *mempool) validateTransactionInContext(transaction *externalapi.DomainT } func (mp *mempool) fillInputsAndGetMissingParents(transaction *externalapi.DomainTransaction) ( - parents []*mempoolTransaction, missingParents []externalapi.DomainTransactionID, err error) { + parents []*model.MempoolTransaction, missingParents []externalapi.DomainTransactionID, err error) { panic("mempool.fillInputsAndGetMissingParents not implemented") // TODO (Mike) } diff --git a/domain/miningmanager/mempool/mempool_utxo_set.go b/domain/miningmanager/mempool/mempool_utxo_set.go index fcb02da54..bbd2e5f97 100644 --- a/domain/miningmanager/mempool/mempool_utxo_set.go +++ b/domain/miningmanager/mempool/mempool_utxo_set.go @@ -1,29 +1,51 @@ package mempool -import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - -type outpointToUTXOEntry map[externalapi.DomainOutpoint]externalapi.UTXOEntry +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/miningmanager/mempool/model" +) type mempoolUTXOSet struct { - mempool *mempool - poolUnspentOutputs outpointToUTXOEntry + mempool *mempool + poolUnspentOutputs model.OutpointToUTXOEntry + transactionsByPreviousOutpoint model.OutpointToTransaction } func newMempoolUTXOSet(mp *mempool) *mempoolUTXOSet { return &mempoolUTXOSet{ - mempool: mp, - poolUnspentOutputs: outpointToUTXOEntry{}, + mempool: mp, + poolUnspentOutputs: model.OutpointToUTXOEntry{}, + transactionsByPreviousOutpoint: model.OutpointToTransaction{}, } } -func (mpus *mempoolUTXOSet) getParentsInPool(transaction *mempoolTransaction) ([]*mempoolTransaction, error) { +func (mpus *mempoolUTXOSet) getParentsInPool(transaction *model.MempoolTransaction) (model.ParentUTXOsInPool, error) { + //parents := model.ParentUTXOsInPool{} + + //outpoint := &externalapi.DomainOutpoint{ + // TransactionID: *transaction.TransactionID(), + //} + //for i, input := transaction.Transaction.Inputs{ + // outpoint.Index = i + // utxo, ok := mpus.getOutpoint(outpoint) + //} + panic("mempoolUTXOSet.getParentsInPool not implemented") // TODO (Mike) } -func (mpus *mempoolUTXOSet) addTransaction(transaction *mempoolTransaction) error { +func (mpus *mempoolUTXOSet) addTransaction(transaction *model.MempoolTransaction) error { panic("mempoolUTXOSet.addTransaction not implemented") // TODO (Mike) } -func (mpus *mempoolUTXOSet) checkDoubleSpends(transaction *mempoolTransaction) error { +func (mpus *mempoolUTXOSet) removeTransaction(transactionID *externalapi.DomainTransactionID) error { + panic("mempoolUTXOSet.removeTransaction not implemented") // TODO (Mike) +} + +func (mpus *mempoolUTXOSet) checkDoubleSpends(transaction *model.MempoolTransaction) error { panic("mempoolUTXOSet.checkDoubleSpends not implemented") // TODO (Mike) } + +func (mpus *mempoolUTXOSet) getOutpoint(outpoint *externalapi.DomainOutpoint) (externalapi.UTXOEntry, bool) { + utxo, ok := mpus.poolUnspentOutputs[*outpoint] + return utxo, ok +} diff --git a/domain/miningmanager/mempool/model.go b/domain/miningmanager/mempool/model.go deleted file mode 100644 index 2c4c058ab..000000000 --- a/domain/miningmanager/mempool/model.go +++ /dev/null @@ -1,29 +0,0 @@ -package mempool - -import ( - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" -) - -type idToTransaction map[externalapi.DomainTransactionID]*mempoolTransaction - -type mempoolTransaction struct { - transaction *externalapi.DomainTransaction - parentsInPool idToTransaction - isHighPriority bool - addedAtDAAScore uint64 -} - -func (mt *mempoolTransaction) transactionID() *externalapi.DomainTransactionID { - return consensushashing.TransactionID(mt.transaction) -} - -type orphanTransaction struct { - transaction *externalapi.DomainTransaction - isHighPriority bool - addedAtDAAScore uint64 -} - -func (ot *orphanTransaction) transactionID() *externalapi.DomainTransactionID { - return consensushashing.TransactionID(ot.transaction) -} diff --git a/domain/miningmanager/mempool/model/map_types.go b/domain/miningmanager/mempool/model/map_types.go new file mode 100644 index 000000000..4f6fe126c --- /dev/null +++ b/domain/miningmanager/mempool/model/map_types.go @@ -0,0 +1,14 @@ +package model + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +// IDToTransaction maps transactionID to a MempoolTransaction +type IDToTransaction map[externalapi.DomainTransactionID]*MempoolTransaction + +// OutpointToUTXOEntry maps an outpoint to a UTXOEntry +type OutpointToUTXOEntry map[externalapi.DomainOutpoint]externalapi.UTXOEntry + +// OutpointToTransaction maps an outpoint to a MempoolTransaction +type OutpointToTransaction map[externalapi.DomainOutpoint]*MempoolTransaction diff --git a/domain/miningmanager/mempool/model/mempool_transaction.go b/domain/miningmanager/mempool/model/mempool_transaction.go new file mode 100644 index 000000000..172603faf --- /dev/null +++ b/domain/miningmanager/mempool/model/mempool_transaction.go @@ -0,0 +1,19 @@ +package model + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" +) + +// MempoolTransaction represents a transaction inside the main TransactionPool +type MempoolTransaction struct { + Transaction *externalapi.DomainTransaction + ParentsInPool IDToTransaction + IsHighPriority bool + AddedAtDAAScore uint64 +} + +// TransactionID returns the ID of this MempoolTransaction +func (mt *MempoolTransaction) TransactionID() *externalapi.DomainTransactionID { + return consensushashing.TransactionID(mt.Transaction) +} diff --git a/domain/miningmanager/mempool/model/ordered_transactions_by_fee_rate.go b/domain/miningmanager/mempool/model/ordered_transactions_by_fee_rate.go new file mode 100644 index 000000000..7550e0ea5 --- /dev/null +++ b/domain/miningmanager/mempool/model/ordered_transactions_by_fee_rate.go @@ -0,0 +1,76 @@ +package model + +import ( + "sort" + + "github.com/pkg/errors" +) + +// TransactionsOrderedByFeeRate represents a set of MempoolTransactions ordered by their fee / mass rate +type TransactionsOrderedByFeeRate struct { + slice []*MempoolTransaction +} + +// Push inserts a transaction into the set, placing it in the correct place to preserve order +func (tobf *TransactionsOrderedByFeeRate) Push(transaction *MempoolTransaction) error { + index, err := tobf.findTransactionIndex(transaction) + if err != nil { + return err + } + + tobf.slice = append(tobf.slice[:index], + append([]*MempoolTransaction{transaction}, tobf.slice[index:]...)...) + + return nil +} + +// Remove removes the given transaction from the set. +// Returns an error if transaction does not exist in the set, or if the given transaction does not have mass +// and fee filled in. +func (tobf *TransactionsOrderedByFeeRate) Remove(transaction *MempoolTransaction) error { + index, err := tobf.findTransactionIndex(transaction) + if err != nil { + return err + } + + txID := transaction.TransactionID() + if !tobf.slice[index].TransactionID().Equal(txID) { + return errors.Errorf("Couldn't find %s in mp.orderedTransactionsByFeeRate", txID) + } + + tobf.RemoveAtIndex(index) + return nil +} + +// RemoveAtIndex removes the transaction at the given index. +// Returns an error in case of out-of-bounds index. +func (tobf *TransactionsOrderedByFeeRate) RemoveAtIndex(index int) error { + if index < 0 || index > len(tobf.slice)-1 { + return errors.Errorf("Index %d is out of bound of this TransactionsOrderedByFeeRate", index) + } + tobf.slice = append(tobf.slice[:index], tobf.slice[index+1:]...) + return nil +} + +func (tobf *TransactionsOrderedByFeeRate) findTransactionIndex(transaction *MempoolTransaction) (int, error) { + if transaction.Transaction.Fee == 0 || transaction.Transaction.Mass == 0 { + return 0, errors.Errorf("findTxIndexInOrderedTransactionsByFeeRate expects a transaction with " + + "populated fee and mass") + } + txID := transaction.TransactionID() + txFeeRate := float64(transaction.Transaction.Fee) / float64(transaction.Transaction.Mass) + + return sort.Search(len(tobf.slice), func(i int) bool { + iElement := tobf.slice[i] + elementFeeRate := float64(iElement.Transaction.Fee) / float64(iElement.Transaction.Mass) + if elementFeeRate > txFeeRate { + return true + } + + if elementFeeRate == txFeeRate && txID.LessOrEqual(iElement.TransactionID()) { + return true + } + + return false + }), nil +} diff --git a/domain/miningmanager/mempool/model/orphan_transaction.go b/domain/miningmanager/mempool/model/orphan_transaction.go new file mode 100644 index 000000000..5169c09e7 --- /dev/null +++ b/domain/miningmanager/mempool/model/orphan_transaction.go @@ -0,0 +1,18 @@ +package model + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" +) + +// OrphanTransaction represents a transaction in the OrphanPool +type OrphanTransaction struct { + transaction *externalapi.DomainTransaction + IsHighPriority bool + AddedAtDAAScore uint64 +} + +// TransactionID returns the ID of this OrphanTransaction +func (ot *OrphanTransaction) TransactionID() *externalapi.DomainTransactionID { + return consensushashing.TransactionID(ot.transaction) +} diff --git a/domain/miningmanager/mempool/model/parent_utxos_in_pool.go b/domain/miningmanager/mempool/model/parent_utxos_in_pool.go new file mode 100644 index 000000000..b451503f3 --- /dev/null +++ b/domain/miningmanager/mempool/model/parent_utxos_in_pool.go @@ -0,0 +1,16 @@ +package model + +import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + +// ParentUTXOsInPool represent the utxos a transaction spends out of the mempool. +// The utxos are indexed by transaction output index, for convenient access. +type ParentUTXOsInPool map[int]externalapi.UTXOEntry + +func (pip ParentUTXOsInPool) GetForIndex(index int) (externalapi.UTXOEntry, bool) { + utxoEntry, ok := pip[index] + return utxoEntry, ok +} + +func (pip ParentUTXOsInPool) SetIndex(index int, utxoEntry externalapi.UTXOEntry) { + pip[index] = utxoEntry +} diff --git a/domain/miningmanager/mempool/ordered_transactions_by_fee_rate.go b/domain/miningmanager/mempool/ordered_transactions_by_fee_rate.go deleted file mode 100644 index bfcb46f3f..000000000 --- a/domain/miningmanager/mempool/ordered_transactions_by_fee_rate.go +++ /dev/null @@ -1,65 +0,0 @@ -package mempool - -import ( - "sort" - - "github.com/pkg/errors" -) - -type transactionsOrderedByFee struct { - slice []*mempoolTransaction -} - -func (tobf *transactionsOrderedByFee) findTransactionIndex(transaction *mempoolTransaction) (int, error) { - if transaction.transaction.Fee == 0 || transaction.transaction.Mass == 0 { - return 0, errors.Errorf("findTxIndexInOrderedTransactionsByFeeRate expects a transaction with " + - "populated fee and mass") - } - txID := transaction.transactionID() - txFeeRate := float64(transaction.transaction.Fee) / float64(transaction.transaction.Mass) - - return sort.Search(len(tobf.slice), func(i int) bool { - iElement := tobf.slice[i] - elementFeeRate := float64(iElement.transaction.Fee) / float64(iElement.transaction.Mass) - if elementFeeRate > txFeeRate { - return true - } - - if elementFeeRate == txFeeRate && txID.LessOrEqual(iElement.transactionID()) { - return true - } - - return false - }), nil -} - -func (tobf *transactionsOrderedByFee) push(transaction *mempoolTransaction) error { - index, err := tobf.findTransactionIndex(transaction) - if err != nil { - return err - } - - tobf.slice = append(tobf.slice[:index], - append([]*mempoolTransaction{transaction}, tobf.slice[index:]...)...) - - return nil -} - -func (tobf *transactionsOrderedByFee) remove(transaction *mempoolTransaction) error { - index, err := tobf.findTransactionIndex(transaction) - if err != nil { - return err - } - - txID := transaction.transactionID() - if !tobf.slice[index].transactionID().Equal(txID) { - return errors.Errorf("Couldn't find %s in mp.orderedTransactionsByFeeRate", txID) - } - - tobf.removeAtIndex(index) - return nil -} - -func (tobf *transactionsOrderedByFee) removeAtIndex(index int) { - tobf.slice = append(tobf.slice[:index], tobf.slice[index+1:]...) -} diff --git a/domain/miningmanager/mempool/orphan_pool.go b/domain/miningmanager/mempool/orphan_pool.go index 999a66ea2..a8d68ad3a 100644 --- a/domain/miningmanager/mempool/orphan_pool.go +++ b/domain/miningmanager/mempool/orphan_pool.go @@ -1,8 +1,11 @@ package mempool -import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/miningmanager/mempool/model" +) -type idToOrphan map[externalapi.DomainTransactionID]*orphanTransaction +type idToOrphan map[externalapi.DomainTransactionID]*model.OrphanTransaction type previousOutpointToOrphans map[externalapi.DomainOutpoint]idToOrphan type orphansPool struct { @@ -27,13 +30,13 @@ func (op *orphansPool) maybeAddOrphan(transaction *externalapi.DomainTransaction panic("orphansPool.maybeAddOrphan not implemented") // TODO (Mike) } -func (op *orphansPool) processOrphansAfterAcceptedTransaction(acceptedTransaction *mempoolTransaction) ( - acceptedOrphans []*mempoolTransaction, err error) { +func (op *orphansPool) processOrphansAfterAcceptedTransaction(acceptedTransaction *model.MempoolTransaction) ( + acceptedOrphans []*model.MempoolTransaction, err error) { panic("orphansPool.processOrphansAfterAcceptedTransaction not implemented") // TODO (Mike) } -func (op *orphansPool) unorphanTransaction(orphanTransactionID *externalapi.DomainTransactionID) (mempoolTransaction, error) { +func (op *orphansPool) unorphanTransaction(orphanTransactionID *externalapi.DomainTransactionID) (model.MempoolTransaction, error) { panic("orphansPool.unorphanTransaction not implemented") // TODO (Mike) } @@ -53,13 +56,13 @@ func (op *orphansPool) expireOrphanTransactions() error { for _, orphanTransaction := range op.allOrphans { // Never expire high priority transactions - if orphanTransaction.isHighPriority { + if orphanTransaction.IsHighPriority { continue } // Remove all transactions whose addedAtDAAScore is older then transactionExpireIntervalDAAScore - if virtualDAAScore-orphanTransaction.addedAtDAAScore > op.mempool.config.orphanExpireIntervalDAAScore { - err = op.removeOrphan(orphanTransaction.transactionID()) + if virtualDAAScore-orphanTransaction.AddedAtDAAScore > op.mempool.config.orphanExpireIntervalDAAScore { + err = op.removeOrphan(orphanTransaction.TransactionID()) if err != nil { return err } diff --git a/domain/miningmanager/mempool/transactions_pool.go b/domain/miningmanager/mempool/transactions_pool.go index aeea1f320..f38443dc1 100644 --- a/domain/miningmanager/mempool/transactions_pool.go +++ b/domain/miningmanager/mempool/transactions_pool.go @@ -2,35 +2,34 @@ package mempool import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/miningmanager/mempool/model" ) -type outpointToTransaction map[externalapi.DomainOutpoint]*mempoolTransaction - type transactionsPool struct { mempool *mempool - allTransactions idToTransaction - highPriorityTransactions idToTransaction - chainedTransactionsByPreviousOutpoint outpointToTransaction - transactionsByFeeRate transactionsOrderedByFee + allTransactions model.IDToTransaction + highPriorityTransactions model.IDToTransaction + chainedTransactionsByPreviousOutpoint model.OutpointToTransaction + transactionsByFeeRate model.TransactionsOrderedByFeeRate lastExpireScan uint64 } func newTransactionsPool(mp *mempool) *transactionsPool { return &transactionsPool{ mempool: mp, - allTransactions: idToTransaction{}, - highPriorityTransactions: idToTransaction{}, - chainedTransactionsByPreviousOutpoint: outpointToTransaction{}, - transactionsByFeeRate: transactionsOrderedByFee{}, + allTransactions: model.IDToTransaction{}, + highPriorityTransactions: model.IDToTransaction{}, + chainedTransactionsByPreviousOutpoint: model.OutpointToTransaction{}, + transactionsByFeeRate: model.TransactionsOrderedByFeeRate{}, lastExpireScan: 0, } } -func (tp *transactionsPool) addTransaction(transaction *externalapi.DomainTransaction, parentsInPool []*mempoolTransaction) error { +func (tp *transactionsPool) addTransaction(transaction *externalapi.DomainTransaction, parentsInPool []*model.MempoolTransaction) error { panic("transactionsPool.addTransaction not implemented") // TODO (Mike) } -func (tp *transactionsPool) addMempoolTransaction(transaction mempoolTransaction) error { +func (tp *transactionsPool) addMempoolTransaction(transaction model.MempoolTransaction) error { panic("transactionsPool.addMempoolTransaction not implemented") // TODO (Mike) } @@ -46,13 +45,13 @@ func (tp *transactionsPool) expireOldTransactions() error { for _, mempoolTransaction := range tp.allTransactions { // Never expire high priority transactions - if mempoolTransaction.isHighPriority { + if mempoolTransaction.IsHighPriority { continue } // Remove all transactions whose addedAtDAAScore is older then transactionExpireIntervalDAAScore - if virtualDAAScore-mempoolTransaction.addedAtDAAScore > tp.mempool.config.transactionExpireIntervalDAAScore { - err = tp.mempool.RemoveTransaction(mempoolTransaction.transactionID()) + if virtualDAAScore-mempoolTransaction.AddedAtDAAScore > tp.mempool.config.transactionExpireIntervalDAAScore { + err = tp.mempool.RemoveTransaction(mempoolTransaction.TransactionID()) if err != nil { return err } @@ -67,8 +66,8 @@ func (tp *transactionsPool) allReadyTransactions() []*externalapi.DomainTransact result := []*externalapi.DomainTransaction{} for _, mempoolTransaction := range tp.allTransactions { - if len(mempoolTransaction.parentsInPool) == 0 { - result = append(result, mempoolTransaction.transaction) + if len(mempoolTransaction.ParentsInPool) == 0 { + result = append(result, mempoolTransaction.Transaction) } }