mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-11-24 06:25:55 +00:00
Use removeRedeemers correctly
This commit is contained in:
parent
387fade044
commit
659260f4eb
@ -147,16 +147,12 @@ func (btb *blockTemplateBuilder) BuildBlockTemplate(
|
|||||||
invalidTxsErr := ruleerrors.ErrInvalidTransactionsInNewBlock{}
|
invalidTxsErr := ruleerrors.ErrInvalidTransactionsInNewBlock{}
|
||||||
if errors.As(err, &invalidTxsErr) {
|
if errors.As(err, &invalidTxsErr) {
|
||||||
log.Criticalf("consensusReference.Consensus().BuildBlock returned invalid txs in BuildBlockTemplate")
|
log.Criticalf("consensusReference.Consensus().BuildBlock returned invalid txs in BuildBlockTemplate")
|
||||||
invalidTxs := make([]*consensusexternalapi.DomainTransaction, 0, len(invalidTxsErr.InvalidTransactions))
|
err = btb.mempool.RemoveInvalidTransactions(&invalidTxsErr)
|
||||||
for _, tx := range invalidTxsErr.InvalidTransactions {
|
|
||||||
invalidTxs = append(invalidTxs, tx.Transaction)
|
|
||||||
}
|
|
||||||
err = btb.mempool.RemoveTransactions(invalidTxs, true)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// mempool.RemoveTransactions might return errors in situations that are perfectly fine in this context.
|
// mempool.RemoveInvalidTransactions might return errors in situations that are perfectly fine in this context.
|
||||||
// TODO: Once the mempool invariants are clear, this should be converted back `return nil, err`:
|
// TODO: Once the mempool invariants are clear, this should be converted back `return nil, err`:
|
||||||
// https://github.com/kaspanet/kaspad/issues/1553
|
// https://github.com/kaspanet/kaspad/issues/1553
|
||||||
log.Criticalf("Error from mempool.RemoveTransactions: %+v", err)
|
log.Criticalf("Error from mempool.RemoveInvalidTransactions: %+v", err)
|
||||||
}
|
}
|
||||||
// We can call this recursively without worry because this should almost never happen
|
// We can call this recursively without worry because this should almost never happen
|
||||||
return btb.BuildBlockTemplate(coinbaseData)
|
return btb.BuildBlockTemplate(coinbaseData)
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
package mempool
|
package mempool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensusreference"
|
"github.com/kaspanet/kaspad/domain/consensusreference"
|
||||||
@ -151,11 +153,29 @@ func (mp *mempool) RevalidateHighPriorityTransactions() (validTransactions []*ex
|
|||||||
return mp.revalidateHighPriorityTransactions()
|
return mp.revalidateHighPriorityTransactions()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *mempool) RemoveTransactions(transactions []*externalapi.DomainTransaction, removeRedeemers bool) error {
|
func (mp *mempool) RemoveInvalidTransactions(err *ruleerrors.ErrInvalidTransactionsInNewBlock) error {
|
||||||
mp.mtx.Lock()
|
mp.mtx.Lock()
|
||||||
defer mp.mtx.Unlock()
|
defer mp.mtx.Unlock()
|
||||||
|
|
||||||
return mp.removeTransactions(transactions, removeRedeemers)
|
for _, tx := range err.InvalidTransactions {
|
||||||
|
ruleErr, success := tx.Error.(ruleerrors.RuleError)
|
||||||
|
if !success {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
inner := ruleErr.Unwrap()
|
||||||
|
removeRedeemers := true
|
||||||
|
if _, ok := inner.(ruleerrors.ErrMissingTxOut); ok {
|
||||||
|
removeRedeemers = false
|
||||||
|
}
|
||||||
|
|
||||||
|
err := mp.removeTransaction(consensushashing.TransactionID(tx.Transaction), removeRedeemers)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *mempool) RemoveTransaction(transactionID *externalapi.DomainTransactionID, removeRedeemers bool) error {
|
func (mp *mempool) RemoveTransaction(transactionID *externalapi.DomainTransactionID, removeRedeemers bool) error {
|
||||||
|
|||||||
@ -2,20 +2,9 @@ package mempool
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
|
||||||
"github.com/kaspanet/kaspad/domain/miningmanager/mempool/model"
|
"github.com/kaspanet/kaspad/domain/miningmanager/mempool/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (mp *mempool) removeTransactions(transactions []*externalapi.DomainTransaction, removeRedeemers bool) error {
|
|
||||||
for _, transaction := range transactions {
|
|
||||||
err := mp.removeTransaction(consensushashing.TransactionID(transaction), removeRedeemers)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mp *mempool) removeTransaction(transactionID *externalapi.DomainTransactionID, removeRedeemers bool) error {
|
func (mp *mempool) removeTransaction(transactionID *externalapi.DomainTransactionID, removeRedeemers bool) error {
|
||||||
if _, ok := mp.orphansPool.allOrphans[*transactionID]; ok {
|
if _, ok := mp.orphansPool.allOrphans[*transactionID]; ok {
|
||||||
return mp.orphansPool.removeOrphan(transactionID, true)
|
return mp.orphansPool.removeOrphan(transactionID, true)
|
||||||
|
|||||||
@ -10,16 +10,83 @@ func (mp *mempool) revalidateHighPriorityTransactions() ([]*externalapi.DomainTr
|
|||||||
onEnd := logger.LogAndMeasureExecutionTime(log, "revalidateHighPriorityTransactions")
|
onEnd := logger.LogAndMeasureExecutionTime(log, "revalidateHighPriorityTransactions")
|
||||||
defer onEnd()
|
defer onEnd()
|
||||||
|
|
||||||
|
// We revalidate transactions in topological order in case there are dependencies between them
|
||||||
|
|
||||||
|
// Naturally transactions points to their dependencies, but since we want to start processing the dependencies
|
||||||
|
// first, we build the opposite DAG. We initially fill `queue` with transactions with no dependencies.
|
||||||
|
childrenByID := make(map[externalapi.DomainTransactionID]map[externalapi.DomainTransactionID]struct{})
|
||||||
|
queue := make([]externalapi.DomainTransactionID, 0, len(mp.transactionsPool.highPriorityTransactions))
|
||||||
|
for id, transaction := range mp.transactionsPool.highPriorityTransactions {
|
||||||
|
hasParents := false
|
||||||
|
for _, input := range transaction.Transaction().Inputs {
|
||||||
|
if _, ok := mp.transactionsPool.highPriorityTransactions[input.PreviousOutpoint.TransactionID]; !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
hasParents = true
|
||||||
|
if _, ok := childrenByID[input.PreviousOutpoint.TransactionID]; !ok {
|
||||||
|
childrenByID[input.PreviousOutpoint.TransactionID] = make(map[externalapi.DomainTransactionID]struct{})
|
||||||
|
}
|
||||||
|
|
||||||
|
childrenByID[input.PreviousOutpoint.TransactionID][id] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasParents {
|
||||||
|
queue = append(queue, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidTransactions := make(map[externalapi.DomainTransactionID]struct{})
|
||||||
|
visited := make(map[externalapi.DomainTransactionID]struct{})
|
||||||
validTransactions := []*externalapi.DomainTransaction{}
|
validTransactions := []*externalapi.DomainTransaction{}
|
||||||
for _, transaction := range mp.transactionsPool.highPriorityTransactions {
|
|
||||||
|
// Now we iterate the DAG in topological order using BFS
|
||||||
|
for len(queue) > 0 {
|
||||||
|
var txID externalapi.DomainTransactionID
|
||||||
|
txID, queue = queue[0], queue[1:]
|
||||||
|
|
||||||
|
if _, ok := visited[txID]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
visited[txID] = struct{}{}
|
||||||
|
|
||||||
|
if _, ok := invalidTransactions[txID]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction := mp.transactionsPool.highPriorityTransactions[txID]
|
||||||
isValid, err := mp.revalidateTransaction(transaction)
|
isValid, err := mp.revalidateTransaction(transaction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isValid {
|
if !isValid {
|
||||||
|
// Invalidate the offspring of this transaction
|
||||||
|
invalidateQueue := []externalapi.DomainTransactionID{txID}
|
||||||
|
for len(invalidateQueue) > 0 {
|
||||||
|
var current externalapi.DomainTransactionID
|
||||||
|
current, invalidateQueue = invalidateQueue[0], invalidateQueue[1:]
|
||||||
|
|
||||||
|
if _, ok := invalidTransactions[current]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidTransactions[current] = struct{}{}
|
||||||
|
if children, ok := childrenByID[current]; ok {
|
||||||
|
for child := range children {
|
||||||
|
invalidateQueue = append(invalidateQueue, child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if children, ok := childrenByID[txID]; ok {
|
||||||
|
for child := range children {
|
||||||
|
queue = append(queue, child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
validTransactions = append(validTransactions, transaction.Transaction().Clone())
|
validTransactions = append(validTransactions, transaction.Transaction().Clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package model
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Mempool maintains a set of known transactions that
|
// Mempool maintains a set of known transactions that
|
||||||
@ -11,7 +12,7 @@ type Mempool interface {
|
|||||||
BlockCandidateTransactions() []*externalapi.DomainTransaction
|
BlockCandidateTransactions() []*externalapi.DomainTransaction
|
||||||
ValidateAndInsertTransaction(transaction *externalapi.DomainTransaction, isHighPriority bool, allowOrphan bool) (
|
ValidateAndInsertTransaction(transaction *externalapi.DomainTransaction, isHighPriority bool, allowOrphan bool) (
|
||||||
acceptedTransactions []*externalapi.DomainTransaction, err error)
|
acceptedTransactions []*externalapi.DomainTransaction, err error)
|
||||||
RemoveTransactions(txs []*externalapi.DomainTransaction, removeRedeemers bool) error
|
RemoveInvalidTransactions(err *ruleerrors.ErrInvalidTransactionsInNewBlock) error
|
||||||
GetTransaction(
|
GetTransaction(
|
||||||
transactionID *externalapi.DomainTransactionID,
|
transactionID *externalapi.DomainTransactionID,
|
||||||
includeTransactionPool bool,
|
includeTransactionPool bool,
|
||||||
|
|||||||
@ -52,6 +52,8 @@ func (ui *UTXOIndex) Reset() error {
|
|||||||
ui.mutex.Lock()
|
ui.mutex.Lock()
|
||||||
defer ui.mutex.Unlock()
|
defer ui.mutex.Unlock()
|
||||||
|
|
||||||
|
log.Infof("Starting UTXO index reset")
|
||||||
|
|
||||||
err := ui.store.deleteAll()
|
err := ui.store.deleteAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -88,7 +90,13 @@ func (ui *UTXOIndex) Reset() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This has to be done last to mark that the reset went smoothly and no reset has to be called next time.
|
// This has to be done last to mark that the reset went smoothly and no reset has to be called next time.
|
||||||
return ui.store.updateAndCommitVirtualParentsWithoutTransaction(virtualInfo.ParentHashes)
|
err = ui.store.updateAndCommitVirtualParentsWithoutTransaction(virtualInfo.ParentHashes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("Finished UTXO index reset")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ui *UTXOIndex) isSynced() (bool, error) {
|
func (ui *UTXOIndex) isSynced() (bool, error) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user