From 93e6c0244e65d6994e60c08a309219bacff83fa5 Mon Sep 17 00:00:00 2001 From: shinhagunn Date: Tue, 25 Jan 2022 20:56:01 -0300 Subject: [PATCH] Ensure pending state is ready for tx execution (#1858) * Enusre pending state is ready for tx execution This commit ensures that StateDB.Prepare is called on the pending state before it is returned from the miner/worker. This prevents access logs from previous transaction executions from interfering with the gas cost calculations of the subsequently executed transaction. The problem this solves was introdued by this upstream PR https://github.com/ethereum/go-ethereum/pull/21509 which added an access list to the state which was used to reduce gas costs for repeated access of the same state locations, this resulted in the pending block having the access list of the last executed transaction, which could cause gas estimates to be wrong when the estimated transaction accessed some of the same state as the prior transaction. * Add more in depth comment on call to Prepare --- miner/worker.go | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/miner/worker.go b/miner/worker.go index aebad34b9b..1a7180140e 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -168,7 +168,24 @@ func (w *worker) pending() (*types.Block, *state.StateDB) { if w.snapshotState == nil { return nil, nil } - return w.snapshotBlock, w.snapshotState.Copy() + stateCopy := w.snapshotState.Copy() + // Call Prepare to ensure that any access logs from the last executed + // transaction have been erased. + // + // Prior to the upstream PR + // https://github.com/ethereum/go-ethereum/pull/21509 the state returned + // from pending was ready to use for transaction execution, that PR + // essentially changed the contract of the pendng method, in that the + // returned state was not ready for transaction execution and required + // Prepare to be called on it first, but notably the PR did not update any + // of the callers of pending to ensure that Prepare was called. I think + // this broke some of the eth rpc apis. Calling Prepare here essentially + // restores the previous contract for this method which was that the + // returned state is ready to use for transaction execution. + // + // See https://github.com/celo-org/celo-blockchain/pull/1858#issuecomment-1054159493 for more details. + stateCopy.Prepare(common.Hash{}, 0) + return w.snapshotBlock, stateCopy } // pendingBlock returns pending block.