From c24c9e2c5dec4882b1ae0db4ce8f6c71de510e78 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 28 Jan 2021 14:38:15 +0100 Subject: [PATCH 1/4] core: properly reset the statedb on sethead --- core/tx_pool.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/tx_pool.go b/core/tx_pool.go index 4a17c31ca881..a09dc3fb521f 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -1115,6 +1115,7 @@ func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirt // reset retrieves the current state of the blockchain and ensures the content // of the transaction pool is valid with regard to the chain state. func (pool *TxPool) reset(oldHead, newHead *types.Header) { + log.Warn("Reseting txpool") // If we're reorging an old state, reinject all dropped transactions var reinject types.Transactions @@ -1141,6 +1142,15 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { // If the reorg ended up on a lower number, it's indicative of setHead being the cause log.Debug("Skipping transaction reset caused by setHead", "old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum) + // We still need to update the current state s.th. the lost transactions can be readded by the user + statedb, err := pool.chain.StateAt(newHead.Root) + if err != nil { + log.Error("Failed to reset txpool state", "err", err) + return + } + pool.currentState = statedb + pool.pendingNonces = newTxNoncer(statedb) + pool.currentMaxGas = newHead.GasLimit } else { // If we reorged to a same or higher number, then it's not a case of setHead log.Warn("Transaction pool reset with missing oldhead", From 83002a7d2b3e745ac4ae5896d882612fd4ddfab8 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 28 Jan 2021 14:40:07 +0100 Subject: [PATCH 2/4] core: remove debug output --- core/tx_pool.go | 1 - 1 file changed, 1 deletion(-) diff --git a/core/tx_pool.go b/core/tx_pool.go index a09dc3fb521f..1808a1a3e907 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -1115,7 +1115,6 @@ func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirt // reset retrieves the current state of the blockchain and ensures the content // of the transaction pool is valid with regard to the chain state. func (pool *TxPool) reset(oldHead, newHead *types.Header) { - log.Warn("Reseting txpool") // If we're reorging an old state, reinject all dropped transactions var reinject types.Transactions From a03638d61e1b1255434aea55d962ebebfc093833 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 2 Feb 2021 12:24:50 +0100 Subject: [PATCH 3/4] core: refactored logic --- core/tx_pool.go | 67 ++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 37 deletions(-) diff --git a/core/tx_pool.go b/core/tx_pool.go index 1808a1a3e907..75b4ad58c556 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -1137,53 +1137,46 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { // head from the chain. // If that is the case, we don't have the lost transactions any more, and // there's nothing to add - if newNum < oldNum { + if newNum >= oldNum { + // If we reorged to a same or higher number, then it's not a case of setHead + log.Warn("Transaction pool reset with missing oldhead", + "old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum) + return + } else { // If the reorg ended up on a lower number, it's indicative of setHead being the cause log.Debug("Skipping transaction reset caused by setHead", "old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum) // We still need to update the current state s.th. the lost transactions can be readded by the user - statedb, err := pool.chain.StateAt(newHead.Root) - if err != nil { - log.Error("Failed to reset txpool state", "err", err) + } + } else { + for rem.NumberU64() > add.NumberU64() { + discarded = append(discarded, rem.Transactions()...) + if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { + log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash()) return } - pool.currentState = statedb - pool.pendingNonces = newTxNoncer(statedb) - pool.currentMaxGas = newHead.GasLimit - } else { - // If we reorged to a same or higher number, then it's not a case of setHead - log.Warn("Transaction pool reset with missing oldhead", - "old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum) } - return - } - for rem.NumberU64() > add.NumberU64() { - discarded = append(discarded, rem.Transactions()...) - if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { - log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash()) - return - } - } - for add.NumberU64() > rem.NumberU64() { - included = append(included, add.Transactions()...) - if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil { - log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash()) - return - } - } - for rem.Hash() != add.Hash() { - discarded = append(discarded, rem.Transactions()...) - if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { - log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash()) - return + for add.NumberU64() > rem.NumberU64() { + included = append(included, add.Transactions()...) + if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil { + log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash()) + return + } } - included = append(included, add.Transactions()...) - if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil { - log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash()) - return + for rem.Hash() != add.Hash() { + discarded = append(discarded, rem.Transactions()...) + if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { + log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash()) + return + } + included = append(included, add.Transactions()...) + if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil { + log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash()) + return + } } + reinject = types.TxDifference(discarded, included) } - reinject = types.TxDifference(discarded, included) } } // Initialize the internal state to the current head From 4bb9be4d91398270089b10d438c5439f3e65b685 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 2 Feb 2021 12:52:34 +0100 Subject: [PATCH 4/4] core: dropped else after return --- core/tx_pool.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/tx_pool.go b/core/tx_pool.go index 75b4ad58c556..36546cde7549 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -1142,12 +1142,11 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { log.Warn("Transaction pool reset with missing oldhead", "old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum) return - } else { - // If the reorg ended up on a lower number, it's indicative of setHead being the cause - log.Debug("Skipping transaction reset caused by setHead", - "old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum) - // We still need to update the current state s.th. the lost transactions can be readded by the user } + // If the reorg ended up on a lower number, it's indicative of setHead being the cause + log.Debug("Skipping transaction reset caused by setHead", + "old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum) + // We still need to update the current state s.th. the lost transactions can be readded by the user } else { for rem.NumberU64() > add.NumberU64() { discarded = append(discarded, rem.Transactions()...)