Skip to content

Commit 51afb30

Browse files
committed
refactor(core,eth,internal): switch EVM tx context in ApplyMessage ethereum#30809
Move EVM tx context switching into ApplyMessage and remove the redundant caller-side setup. Keep the execution gas price visible to tracers in XDPoS, because TransactionToMessage can rewrite msg.GasPrice for TRC21 and fixed-price fee paths before execution. Seed the tx context before OnTxStart and restore VMContext.GasPrice so tracers observe the execution-time pricing instead of the raw transaction price. Update tracer tests to cover the execution gas price path.
1 parent f5fe86c commit 51afb30

18 files changed

Lines changed: 82 additions & 100 deletions

File tree

core/state_prefetcher.go

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package core
1919
import (
2020
"sync/atomic"
2121

22-
"github.com/XinFinOrg/XDPoSChain/common"
2322
"github.com/XinFinOrg/XDPoSChain/consensus"
2423
"github.com/XinFinOrg/XDPoSChain/core/state"
2524
"github.com/XinFinOrg/XDPoSChain/core/types"
@@ -69,7 +68,11 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
6968
return // Also invalid block, bail out
7069
}
7170
statedb.SetTxContext(tx.Hash(), i)
72-
if err := precacheTransaction(msg, gaspool, evm); err != nil {
71+
coinbaseOwner := statedb.GetOwner(evm.Context.Coinbase)
72+
73+
// We attempt to apply a transaction. The goal is not to execute
74+
// the transaction successfully, rather to warm up touched data slots.
75+
if _, err := ApplyMessage(evm, msg, gaspool, coinbaseOwner); err != nil {
7376
return // Ugh, something went horribly wrong, bail out
7477
}
7578
// If we're pre-byzantium, pre-load trie nodes for the intermediate root
@@ -82,14 +85,3 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
8285
statedb.IntermediateRoot(true)
8386
}
8487
}
85-
86-
// precacheTransaction attempts to apply a transaction to the given state database
87-
// and uses the input parameters for its environment. The goal is not to execute
88-
// the transaction successfully, rather to warm up touched data slots.
89-
func precacheTransaction(msg *Message, gaspool *GasPool, evm *vm.EVM) error {
90-
// Update the evm with the new transaction context.
91-
evm.SetTxContext(NewEVMTxContext(msg))
92-
// Add addresses to access list if applicable
93-
_, err := ApplyMessage(evm, msg, gaspool, common.Address{})
94-
return err
95-
}

core/state_processor.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,9 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated
280280
// and uses the input parameters for its environment similar to ApplyTransaction. However,
281281
// this method takes an already created EVM instance as input.
282282
func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM, balanceFee *big.Int, coinbaseOwner common.Address) (receipt *types.Receipt, gasUsed uint64, tokenFeeUsed bool, err error) {
283+
// OnTxStart runs before ApplyMessage, so the execution tx context must be visible
284+
// here too. This is XDPoS-specific because msg.GasPrice can differ from the raw tx.
285+
evm.SetTxContext(NewEVMTxContext(msg))
283286
if hooks := evm.Config.Tracer; hooks != nil {
284287
if hooks.OnTxStart != nil {
285288
hooks.OnTxStart(evm.GetVMContext(), tx, msg.From)
@@ -309,10 +312,6 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB,
309312
return ApplyEmptyTransaction(msg, config, statedb, blockNumber, blockHash, tx, usedGas, evm)
310313
}
311314

312-
// Create a new context to be used in the EVM environment
313-
txContext := NewEVMTxContext(msg)
314-
evm.SetTxContext(txContext)
315-
316315
// Bypass denylist address
317316
maxBlockNumber := new(big.Int).SetInt64(9147459)
318317
if blockNumber.Cmp(maxBlockNumber) <= 0 {

core/state_transition.go

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -206,10 +206,11 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, balanceFee, blo
206206
// indicates a core error meaning that the message would always fail for that particular
207207
// state and would never be accepted within a block.
208208
func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool, owner common.Address) (*ExecutionResult, error) {
209-
return NewStateTransition(evm, msg, gp).TransitionDb(owner)
209+
evm.SetTxContext(NewEVMTxContext(msg))
210+
return newStateTransition(evm, msg, gp).execute(owner)
210211
}
211212

212-
// StateTransition represents a state transition.
213+
// stateTransition represents a state transition.
213214
//
214215
// == The State Transitioning Model
215216
//
@@ -231,7 +232,7 @@ func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool, owner common.Address)
231232
//
232233
// 5. Run Script section
233234
// 6. Derive new state root
234-
type StateTransition struct {
235+
type stateTransition struct {
235236
gp *GasPool
236237
msg *Message
237238
gasRemaining uint64
@@ -240,25 +241,25 @@ type StateTransition struct {
240241
evm *vm.EVM
241242
}
242243

243-
// NewStateTransition initialises and returns a new state transition object.
244-
func NewStateTransition(evm *vm.EVM, msg *Message, gp *GasPool) *StateTransition {
245-
return &StateTransition{
244+
// newStateTransition initialises and returns a new state transition object.
245+
func newStateTransition(evm *vm.EVM, msg *Message, gp *GasPool) *stateTransition {
246+
return &stateTransition{
246247
gp: gp,
247248
evm: evm,
248249
msg: msg,
249250
state: evm.StateDB,
250251
}
251252
}
252253

253-
func (st *StateTransition) from() common.Address {
254+
func (st *stateTransition) from() common.Address {
254255
f := st.msg.From
255256
if !st.state.Exist(f) {
256257
st.state.CreateAccount(f)
257258
}
258259
return f
259260
}
260261

261-
func (st *StateTransition) to() common.Address {
262+
func (st *stateTransition) to() common.Address {
262263
if st.msg == nil {
263264
return common.Address{}
264265
}
@@ -272,7 +273,7 @@ func (st *StateTransition) to() common.Address {
272273
return *to
273274
}
274275

275-
func (st *StateTransition) buyGas() error {
276+
func (st *stateTransition) buyGas() error {
276277
mgval := new(big.Int).SetUint64(st.msg.GasLimit)
277278
mgval = mgval.Mul(mgval, st.msg.GasPrice)
278279
if st.msg.BalanceTokenFee == nil {
@@ -304,7 +305,7 @@ func (st *StateTransition) buyGas() error {
304305
return nil
305306
}
306307

307-
func (st *StateTransition) preCheck() error {
308+
func (st *stateTransition) preCheck() error {
308309
// Only check transactions that are not fake
309310
msg := st.msg
310311
if !msg.SkipNonceChecks {
@@ -371,20 +372,17 @@ func (st *StateTransition) preCheck() error {
371372
return st.buyGas()
372373
}
373374

374-
// TransitionDb will transition the state by applying the current message and
375+
// execute will transition the state by applying the current message and
375376
// returning the evm execution result with following fields.
376377
//
377-
// - used gas:
378-
// total gas used (including gas being refunded)
379-
// - returndata:
380-
// the returned data from evm
381-
// - concrete execution error:
382-
// various **EVM** error which aborts the execution,
383-
// e.g. ErrOutOfGas, ErrExecutionReverted
378+
// - used gas: total gas used (including gas being refunded)
379+
// - returndata: the returned data from evm
380+
// - concrete execution error: various EVM errors which abort the execution, e.g.
381+
// ErrOutOfGas, ErrExecutionReverted
384382
//
385383
// However if any consensus issue encountered, return the error directly with
386384
// nil evm execution result.
387-
func (st *StateTransition) TransitionDb(owner common.Address) (*ExecutionResult, error) {
385+
func (st *stateTransition) execute(owner common.Address) (*ExecutionResult, error) {
388386
// First check this message satisfies all consensus rules before
389387
// applying the message. The rules include these clauses
390388
//
@@ -523,7 +521,7 @@ func (st *StateTransition) TransitionDb(owner common.Address) (*ExecutionResult,
523521
}
524522

525523
// validateAuthorization validates an EIP-7702 authorization against the state.
526-
func (st *StateTransition) validateAuthorization(auth *types.SetCodeAuthorization) (authority common.Address, err error) {
524+
func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorization) (authority common.Address, err error) {
527525
// Verify chain ID is null or equal to current chain ID.
528526
if !auth.ChainID.IsZero() && auth.ChainID.CmpBig(st.evm.ChainConfig().ChainID) != 0 {
529527
return authority, ErrAuthorizationWrongChainID
@@ -554,7 +552,7 @@ func (st *StateTransition) validateAuthorization(auth *types.SetCodeAuthorizatio
554552
}
555553

556554
// applyAuthorization applies an EIP-7702 code delegation to the state.
557-
func (st *StateTransition) applyAuthorization(msg *Message, auth *types.SetCodeAuthorization) error {
555+
func (st *stateTransition) applyAuthorization(msg *Message, auth *types.SetCodeAuthorization) error {
558556
authority, err := st.validateAuthorization(auth)
559557
if err != nil {
560558
return err
@@ -581,7 +579,7 @@ func (st *StateTransition) applyAuthorization(msg *Message, auth *types.SetCodeA
581579
}
582580

583581
// calcRefund computes refund counter, capped to a refund quotient.
584-
func (st *StateTransition) calcRefund() uint64 {
582+
func (st *stateTransition) calcRefund() uint64 {
585583
var refund uint64
586584
if !st.evm.ChainConfig().IsEIP1559(st.evm.Context.BlockNumber) {
587585
// Before EIP-3529: refunds were capped to gasUsed / 2
@@ -601,7 +599,7 @@ func (st *StateTransition) calcRefund() uint64 {
601599

602600
// returnGas returns ETH for remaining gas,
603601
// exchanged at the original rate.
604-
func (st *StateTransition) returnGas() {
602+
func (st *stateTransition) returnGas() {
605603
if st.msg.BalanceTokenFee == nil {
606604
remaining := new(big.Int).SetUint64(st.gasRemaining)
607605
remaining.Mul(remaining, st.msg.GasPrice)
@@ -618,6 +616,6 @@ func (st *StateTransition) returnGas() {
618616
}
619617

620618
// gasUsed returns the amount of gas used up by the state transition.
621-
func (st *StateTransition) gasUsed() uint64 {
619+
func (st *stateTransition) gasUsed() uint64 {
622620
return st.initialGas - st.gasRemaining
623621
}

core/token_validator.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,10 @@ func CallContractWithState(call ethereum.CallMsg, chain consensus.ChainContext,
108108

109109
// Create a new environment which holds all relevant information
110110
// about the transaction and calling mechanisms.
111-
txContext := NewEVMTxContext(msg)
112111
evmContext := NewEVMBlockContext(chain.CurrentHeader(), chain, nil)
113112
evm := vm.NewEVM(evmContext, statedb, nil, chain.Config(), vm.Config{})
114-
evm.SetTxContext(txContext)
115113
gaspool := new(GasPool).AddGas(1000000)
116-
result, err := NewStateTransition(evm, msg, gaspool).TransitionDb(common.Address{})
114+
result, err := ApplyMessage(evm, msg, gaspool, common.Address{})
117115
if err != nil {
118116
return nil, err
119117
}

core/tracing/hooks.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,12 @@ type VMContext struct {
5353
BlockNumber *big.Int
5454
Time uint64
5555
Random *common.Hash
56-
// Effective tx gas price
56+
BaseFee *big.Int
57+
StateDB StateDB
58+
59+
// XDPoS tracers need the execution-time gas price because TransactionToMessage
60+
// may rewrite it for TRC21 and fixed-price fee paths.
5761
GasPrice *big.Int
58-
StateDB StateDB
5962
}
6063

6164
// BlockEvent is emitted upon tracing an incoming block.

core/vm/evm.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,10 @@ func (evm *EVM) GetVMContext() *tracing.VMContext {
638638
BlockNumber: evm.Context.BlockNumber,
639639
Time: evm.Context.Time,
640640
Random: evm.Context.Random,
641-
GasPrice: evm.TxContext.GasPrice,
641+
BaseFee: evm.Context.BaseFee,
642642
StateDB: evm.StateDB,
643+
644+
// Keep GasPrice in the tracer context for XDPoS-specific execution pricing.
645+
GasPrice: evm.TxContext.GasPrice,
643646
}
644647
}

eth/gasestimator/gasestimator.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,17 +174,15 @@ func execute(ctx context.Context, call *core.Message, opts *Options, gasLimit ui
174174
func run(ctx context.Context, call *core.Message, opts *Options) (*core.ExecutionResult, error) {
175175
// Assemble the call and the call context
176176
var (
177-
msgContext = core.NewEVMTxContext(call)
178177
evmContext = core.NewEVMBlockContext(opts.Header, opts.Chain, nil)
179178
dirtyState = opts.State.Copy()
180179
)
181180
// Lower the basefee to 0 to avoid breaking EVM
182181
// invariants (basefee < feecap).
183-
if msgContext.GasPrice.Sign() == 0 {
182+
if call.GasPrice.Sign() == 0 {
184183
evmContext.BaseFee = new(big.Int)
185184
}
186185
evm := vm.NewEVM(evmContext, dirtyState, nil, opts.Config, vm.Config{NoBaseFee: true})
187-
evm.SetTxContext(msgContext)
188186

189187
// Monitor the outer context and interrupt the EVM upon cancellation. To avoid
190188
// a dangling goroutine until the outer estimation finishes, create an internal

eth/state_accessor.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,6 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
230230
}
231231
// Assemble the transaction call message and return if the requested offset
232232
msg, _ := core.TransactionToMessage(tx, signer, balance, block.Number(), block.BaseFee())
233-
txContext := core.NewEVMTxContext(msg)
234-
evm.SetTxContext(txContext)
235233

236234
// Not yet the searched for transaction, execute on top of the current state
237235
statedb.SetTxContext(tx.Hash(), idx)

eth/tracers/api.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -539,11 +539,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
539539
balance = value
540540
}
541541
}
542-
var (
543-
msg, _ = core.TransactionToMessage(tx, signer, balance, block.Number(), block.BaseFee())
544-
txContext = core.NewEVMTxContext(msg)
545-
)
546-
evm.SetTxContext(txContext)
542+
msg, _ := core.TransactionToMessage(tx, signer, balance, block.Number(), block.BaseFee())
547543
statedb.SetTxContext(tx.Hash(), i)
548544
if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit), common.Address{}); err != nil {
549545
log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
@@ -724,7 +720,6 @@ txloop:
724720
header := block.Header()
725721
msg, _ := core.TransactionToMessage(tx, signer, balance, header.Number, header.BaseFee)
726722
statedb.SetTxContext(tx.Hash(), i)
727-
evm.SetTxContext(core.NewEVMTxContext(msg))
728723
if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit), common.Address{}); err != nil {
729724
failed = err
730725
break txloop
@@ -902,7 +897,6 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor
902897
}
903898
tracingStateDB := state.NewHookedState(statedb, tracer.Hooks)
904899
evm := vm.NewEVM(vmctx, tracingStateDB, nil, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true})
905-
evm.SetTxContext(vm.TxContext{GasPrice: message.GasPrice})
906900

907901
// Define a meaningful timeout of a single transaction trace
908902
if config.Timeout != nil {

eth/tracers/api_test.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,6 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
183183
return tx, context, statedb, release, nil
184184
}
185185
msg, _ := core.TransactionToMessage(tx, signer, nil, block.Number(), block.BaseFee())
186-
txContext := core.NewEVMTxContext(msg)
187-
evm.SetTxContext(txContext)
188186
if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()), common.Address{}); err != nil {
189187
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
190188
}

0 commit comments

Comments
 (0)