refactor(all): rework EVM constructor #30745 (#2065)

This commit is contained in:
Daniel Liu 2026-02-17 17:05:18 +08:00 committed by GitHub
parent 373037032f
commit cfca45a7eb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 241 additions and 137 deletions

View file

@ -777,9 +777,10 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
evmContext := core.NewEVMBlockContext(block, b.blockchain, nil) evmContext := core.NewEVMBlockContext(block, b.blockchain, nil)
// Create a new environment which holds all relevant information // Create a new environment which holds all relevant information
// about the transaction and calling mechanisms. // about the transaction and calling mechanisms.
vmenv := vm.NewEVM(evmContext, txContext, stateDB, nil, b.config, vm.Config{NoBaseFee: true}) evm := vm.NewEVM(evmContext, stateDB, nil, b.config, vm.Config{NoBaseFee: true})
evm.SetTxContext(txContext)
gaspool := new(core.GasPool).AddGas(gomath.MaxUint64) gaspool := new(core.GasPool).AddGas(gomath.MaxUint64)
return core.NewStateTransition(vmenv, msg, gaspool).TransitionDb(common.Address{}) return core.NewStateTransition(evm, msg, gaspool).TransitionDb(common.Address{})
} }
// SendTransaction updates the pending block to include the given transaction. // SendTransaction updates the pending block to include the given transaction.

View file

@ -371,7 +371,9 @@ func createBlockFromHeader(bc *core.BlockChain, customHeader *types.Header, txs
var receipts types.Receipts var receipts types.Receipts
for i, tx := range txs { for i, tx := range txs {
statedb.SetTxContext(tx.Hash(), i) statedb.SetTxContext(tx.Hash(), i)
receipt, _, _, err := core.ApplyTransaction(bc.Config(), nil, bc, &header.Coinbase, gp, statedb, nil, &header, tx, gasUsed, vm.Config{}) blockContext := core.NewEVMBlockContext(&header, bc, &header.Coinbase)
evm := vm.NewEVM(blockContext, statedb, nil, bc.Config(), vm.Config{})
receipt, _, _, err := core.ApplyTransaction(bc.Config(), nil, evm, gp, statedb, &header, tx, gasUsed)
if err != nil { if err != nil {
return nil, fmt.Errorf("%v when applying transaction", err) return nil, fmt.Errorf("%v when applying transaction", err)
} }

View file

@ -901,7 +901,9 @@ func createBlockFromHeader(bc *core.BlockChain, customHeader *types.Header, txs
var receipts types.Receipts var receipts types.Receipts
for i, tx := range txs { for i, tx := range txs {
statedb.SetTxContext(tx.Hash(), i) statedb.SetTxContext(tx.Hash(), i)
receipt, _, _, err := core.ApplyTransaction(bc.Config(), nil, bc, &header.Coinbase, gp, statedb, nil, &header, tx, gasUsed, vm.Config{}) blockContext := core.NewEVMBlockContext(&header, bc, &header.Coinbase)
evm := vm.NewEVM(blockContext, statedb, nil, bc.Config(), vm.Config{})
receipt, _, _, err := core.ApplyTransaction(bc.Config(), nil, evm, gp, statedb, &header, tx, gasUsed)
if err != nil { if err != nil {
return nil, fmt.Errorf("%v when applying transaction", err) return nil, fmt.Errorf("%v when applying transaction", err)
} }

View file

@ -87,7 +87,9 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti
} }
feeCapacity := b.statedb.GetTRC21FeeCapacityFromState() feeCapacity := b.statedb.GetTRC21FeeCapacityFromState()
b.statedb.SetTxContext(tx.Hash(), len(b.txs)) b.statedb.SetTxContext(tx.Hash(), len(b.txs))
receipt, gas, tokenFeeUsed, err := ApplyTransaction(b.config, feeCapacity, bc, &b.header.Coinbase, b.gasPool, b.statedb, nil, b.header, tx, &b.header.GasUsed, vmConfig) blockContext := NewEVMBlockContext(b.header, bc, &b.header.Coinbase)
evm := vm.NewEVM(blockContext, b.statedb, nil, b.config, vmConfig)
receipt, gas, tokenFeeUsed, err := ApplyTransaction(b.config, feeCapacity, evm, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -235,7 +237,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
if config.IsPrague(b.header.Number) { if config.IsPrague(b.header.Number) {
// EIP-2935 // EIP-2935
blockContext := NewEVMBlockContext(b.header, chainReader, &b.header.Coinbase) blockContext := NewEVMBlockContext(b.header, chainReader, &b.header.Coinbase)
evm := vm.NewEVM(blockContext, vm.TxContext{}, statedb, nil, config, vm.Config{}) evm := vm.NewEVM(blockContext, statedb, nil, config, vm.Config{})
ProcessParentBlockHash(b.header.ParentHash, evm, statedb) ProcessParentBlockHash(b.header.ParentHash, evm, statedb)
} }

View file

@ -53,7 +53,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
header = block.Header() header = block.Header()
gaspool = new(GasPool).AddGas(block.GasLimit()) gaspool = new(GasPool).AddGas(block.GasLimit())
blockContext = NewEVMBlockContext(header, p.bc, nil) blockContext = NewEVMBlockContext(header, p.bc, nil)
evm = vm.NewEVM(blockContext, vm.TxContext{}, statedb, nil, p.config, cfg) evm = vm.NewEVM(blockContext, statedb, nil, p.config, cfg)
signer = types.MakeSigner(p.config, header.Number) signer = types.MakeSigner(p.config, header.Number)
) )
// Iterate over and process the individual transactions // Iterate over and process the individual transactions
@ -69,7 +69,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
return // Also invalid block, bail out return // Also invalid block, bail out
} }
statedb.SetTxContext(tx.Hash(), i) statedb.SetTxContext(tx.Hash(), i)
if err := precacheTransaction(msg, p.config, gaspool, statedb, header, evm); err != nil { if err := precacheTransaction(msg, gaspool, evm); err != nil {
return // Ugh, something went horribly wrong, bail out return // Ugh, something went horribly wrong, bail out
} }
// If we're pre-byzantium, pre-load trie nodes for the intermediate root // If we're pre-byzantium, pre-load trie nodes for the intermediate root
@ -86,9 +86,9 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
// precacheTransaction attempts to apply a transaction to the given state database // precacheTransaction attempts to apply a transaction to the given state database
// and uses the input parameters for its environment. The goal is not to execute // and uses the input parameters for its environment. The goal is not to execute
// the transaction successfully, rather to warm up touched data slots. // the transaction successfully, rather to warm up touched data slots.
func precacheTransaction(msg *Message, config *params.ChainConfig, gaspool *GasPool, statedb *state.StateDB, header *types.Header, evm *vm.EVM) error { func precacheTransaction(msg *Message, gaspool *GasPool, evm *vm.EVM) error {
// Update the evm with the new transaction context. // Update the evm with the new transaction context.
evm.Reset(NewEVMTxContext(msg), statedb) evm.SetTxContext(NewEVMTxContext(msg))
// Add addresses to access list if applicable // Add addresses to access list if applicable
_, err := ApplyMessage(evm, msg, gaspool, common.Address{}) _, err := ApplyMessage(evm, msg, gaspool, common.Address{})
return err return err

View file

@ -97,13 +97,13 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, tra
totalFeeUsed := big.NewInt(0) totalFeeUsed := big.NewInt(0)
// Apply pre-execution system calls. // Apply pre-execution system calls.
blockContext := NewEVMBlockContext(header, p.bc, nil) context := NewEVMBlockContext(header, p.bc, nil)
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, tracingStateDB, tradingState, p.config, cfg) evm := vm.NewEVM(context, tracingStateDB, tradingState, p.config, cfg)
signer := types.MakeSigner(p.config, blockNumber) signer := types.MakeSigner(p.config, blockNumber)
coinbaseOwner := getCoinbaseOwner(p.bc, statedb, header, nil) coinbaseOwner := getCoinbaseOwner(p.bc, statedb, header, nil)
if p.config.IsPrague(block.Number()) { if p.config.IsPrague(block.Number()) {
ProcessParentBlockHash(block.ParentHash(), vmenv, tracingStateDB) ProcessParentBlockHash(block.ParentHash(), evm, tracingStateDB)
} }
// Iterate over and process the individual transactions // Iterate over and process the individual transactions
@ -146,7 +146,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, tra
} }
statedb.SetTxContext(tx.Hash(), i) statedb.SetTxContext(tx.Hash(), i)
receipt, gas, tokenFeeUsed, err := ApplyTransactionWithEVM(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv, balanceFee, coinbaseOwner) receipt, gas, tokenFeeUsed, err := ApplyTransactionWithEVM(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, evm, balanceFee, coinbaseOwner)
if err != nil { if err != nil {
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
} }
@ -204,13 +204,13 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated
} }
// Apply pre-execution system calls. // Apply pre-execution system calls.
blockContext := NewEVMBlockContext(header, p.bc, nil) context := NewEVMBlockContext(header, p.bc, nil)
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, tracingStateDB, tradingState, p.config, cfg) evm := vm.NewEVM(context, tracingStateDB, tradingState, p.config, cfg)
signer := types.MakeSigner(p.config, blockNumber) signer := types.MakeSigner(p.config, blockNumber)
coinbaseOwner := getCoinbaseOwner(p.bc, statedb, header, nil) coinbaseOwner := getCoinbaseOwner(p.bc, statedb, header, nil)
if p.config.IsPrague(block.Number()) { if p.config.IsPrague(block.Number()) {
ProcessParentBlockHash(block.ParentHash(), vmenv, tracingStateDB) ProcessParentBlockHash(block.ParentHash(), evm, tracingStateDB)
} }
// Iterate over and process the individual transactions // Iterate over and process the individual transactions
@ -253,7 +253,7 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated
} }
statedb.SetTxContext(tx.Hash(), i) statedb.SetTxContext(tx.Hash(), i)
receipt, gas, tokenFeeUsed, err := ApplyTransactionWithEVM(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv, balanceFee, coinbaseOwner) receipt, gas, tokenFeeUsed, err := ApplyTransactionWithEVM(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, evm, balanceFee, coinbaseOwner)
if err != nil { if err != nil {
return nil, nil, 0, err return nil, nil, 0, err
} }
@ -280,11 +280,7 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated
// and uses the input parameters for its environment similar to ApplyTransaction. However, // and uses the input parameters for its environment similar to ApplyTransaction. However,
// this method takes an already created EVM instance as input. // this method takes an already created EVM instance as input.
func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, 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) { func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, 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) {
// Initialize tracer at the beginning to ensure all transaction types
// (including non-EVM special transactions) are properly traced.
var tracingStateDB = vm.StateDB(statedb)
if hooks := evm.Config.Tracer; hooks != nil { if hooks := evm.Config.Tracer; hooks != nil {
tracingStateDB = state.NewHookedState(statedb, hooks)
if hooks.OnTxStart != nil { if hooks.OnTxStart != nil {
hooks.OnTxStart(evm.GetVMContext(), tx, msg.From) hooks.OnTxStart(evm.GetVMContext(), tx, msg.From)
} }
@ -314,7 +310,7 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo
// Create a new context to be used in the EVM environment // Create a new context to be used in the EVM environment
txContext := NewEVMTxContext(msg) txContext := NewEVMTxContext(msg)
evm.Reset(txContext, tracingStateDB) evm.SetTxContext(txContext)
// Bypass denylist address // Bypass denylist address
maxBlockNumber := new(big.Int).SetInt64(9147459) maxBlockNumber := new(big.Int).SetInt64(9147459)
@ -469,7 +465,7 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo
// Update the state with pending changes. // Update the state with pending changes.
var root []byte var root []byte
if config.IsByzantium(blockNumber) { if config.IsByzantium(blockNumber) {
tracingStateDB.Finalise(true) evm.StateDB.Finalise(true)
} else { } else {
root = statedb.IntermediateRoot(config.IsEIP158(blockNumber)).Bytes() root = statedb.IntermediateRoot(config.IsEIP158(blockNumber)).Bytes()
} }
@ -524,7 +520,7 @@ func getCoinbaseOwner(bc *BlockChain, statedb *state.StateDB, header *types.Head
// and uses the input parameters for its environment. It returns the receipt // and uses the input parameters for its environment. It returns the receipt
// for the transaction, gas used and an error if the transaction failed, // for the transaction, gas used and an error if the transaction failed,
// indicating the block was invalid. // indicating the block was invalid.
func ApplyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*big.Int, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, XDCxState *tradingstate.TradingStateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, uint64, bool, error) { func ApplyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*big.Int, evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64) (*types.Receipt, uint64, bool, error) {
var balanceFee *big.Int var balanceFee *big.Int
if tx.To() != nil { if tx.To() != nil {
if value, ok := tokensFee[*tx.To()]; ok { if value, ok := tokensFee[*tx.To()]; ok {
@ -532,16 +528,13 @@ func ApplyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*
} }
} }
// Create a new context to be used in the EVM environment
blockContext := NewEVMBlockContext(header, bc, author)
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, XDCxState, config, cfg)
signer := types.MakeSigner(config, header.Number) signer := types.MakeSigner(config, header.Number)
msg, err := TransactionToMessage(tx, signer, balanceFee, header.Number, header.BaseFee) msg, err := TransactionToMessage(tx, signer, balanceFee, header.Number, header.BaseFee)
if err != nil { if err != nil {
return nil, 0, false, err return nil, 0, false, err
} }
coinbaseOwner := getCoinbaseOwner(bc, statedb, header, author) coinbaseOwner := statedb.GetOwner(evm.Context.Coinbase)
return ApplyTransactionWithEVM(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv, balanceFee, coinbaseOwner) return ApplyTransactionWithEVM(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, evm, balanceFee, coinbaseOwner)
} }
func ApplySignTransaction(msg *Message, config *params.ChainConfig, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, gasUsed uint64, tokenFeeUsed bool, err error) { func ApplySignTransaction(msg *Message, config *params.ChainConfig, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, gasUsed uint64, tokenFeeUsed bool, err error) {
@ -726,7 +719,7 @@ func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb vm.Stat
To: &params.HistoryStorageAddress, To: &params.HistoryStorageAddress,
Data: prevHash.Bytes(), Data: prevHash.Bytes(),
} }
vmenv.Reset(NewEVMTxContext(msg), statedb) vmenv.SetTxContext(NewEVMTxContext(msg))
statedb.AddAddressToAccessList(params.HistoryStorageAddress) statedb.AddAddressToAccessList(params.HistoryStorageAddress)
_, _, err := vmenv.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560) _, _, err := vmenv.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560)
if err != nil { if err != nil {

View file

@ -467,7 +467,7 @@ func TestApplyTransactionWithEVMTracer(t *testing.T) {
blockHash := genesis.Hash() blockHash := genesis.Hash()
vmContext := NewEVMBlockContext(blockchain.CurrentBlock(), blockchain, nil) vmContext := NewEVMBlockContext(blockchain.CurrentBlock(), blockchain, nil)
evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, nil, blockchain.Config(), vmConfig) evm := vm.NewEVM(vmContext, statedb, nil, blockchain.Config(), vmConfig)
// Apply transaction // Apply transaction
var usedGas uint64 var usedGas uint64
@ -493,6 +493,81 @@ func TestApplyTransactionWithEVMTracer(t *testing.T) {
} }
} }
func TestApplyTransactionWithEVMStateChangeHooks(t *testing.T) {
var (
config = &params.ChainConfig{
ChainID: big.NewInt(1),
HomesteadBlock: big.NewInt(0),
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(0),
Eip1559Block: big.NewInt(0),
Ethash: new(params.EthashConfig),
}
signer = types.LatestSigner(config)
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
sender = crypto.PubkeyToAddress(testKey.PublicKey)
recipient = common.HexToAddress("0x1234567890123456789012345678901234567890")
hookInvoked bool
)
db := rawdb.NewMemoryDatabase()
gspec := &Genesis{
Config: config,
Alloc: types.GenesisAlloc{
sender: {
Balance: big.NewInt(1000000000000000000),
Nonce: 0,
},
},
}
genesis := gspec.MustCommit(db)
blockchain, _ := NewBlockChain(db, nil, gspec, ethash.NewFaker(), vm.Config{})
defer blockchain.Stop()
statedb, err := blockchain.State()
if err != nil {
t.Fatalf("Failed to get state: %v", err)
}
tx := types.NewTransaction(0, recipient, big.NewInt(1), 21000, big.NewInt(20000000000), nil)
signedTx, err := types.SignTx(tx, signer, testKey)
if err != nil {
t.Fatalf("Failed to sign tx: %v", err)
}
hooks := &tracing.Hooks{
OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
hookInvoked = true
},
}
hookedState := state.NewHookedState(statedb, hooks)
vmContext := NewEVMBlockContext(blockchain.CurrentBlock(), blockchain, nil)
evmenv := vm.NewEVM(vmContext, hookedState, nil, blockchain.Config(), vm.Config{Tracer: hooks})
msg, err := TransactionToMessage(signedTx, signer, nil, big.NewInt(1), nil)
if err != nil {
t.Fatalf("Failed to build message: %v", err)
}
gasPool := new(GasPool).AddGas(1000000)
var usedGas uint64
_, _, _, err = ApplyTransactionWithEVM(msg, config, gasPool, statedb, big.NewInt(1), genesis.Hash(), signedTx, &usedGas, evmenv, nil, common.Address{})
if err != nil {
t.Fatalf("ApplyTransactionWithEVM failed: %v", err)
}
if !hookInvoked {
t.Fatal("expected OnBalanceChange to be invoked, but it was not")
}
}
func TestProcessParentBlockHash(t *testing.T) { func TestProcessParentBlockHash(t *testing.T) {
var ( var (
chainConfig = params.MergedTestChainConfig chainConfig = params.MergedTestChainConfig
@ -508,11 +583,11 @@ func TestProcessParentBlockHash(t *testing.T) {
statedb.IntermediateRoot(true) statedb.IntermediateRoot(true)
vmContext := NewEVMBlockContext(header, nil, &coinbase) vmContext := NewEVMBlockContext(header, nil, &coinbase)
evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, nil, chainConfig, vm.Config{}) evm := vm.NewEVM(vmContext, statedb, nil, chainConfig, vm.Config{})
ProcessParentBlockHash(header.ParentHash, evm, statedb) ProcessParentBlockHash(header.ParentHash, evm, statedb)
vmContext = NewEVMBlockContext(parent, nil, &coinbase) vmContext = NewEVMBlockContext(parent, nil, &coinbase)
evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, nil, chainConfig, vm.Config{}) evm = vm.NewEVM(vmContext, statedb, nil, chainConfig, vm.Config{})
ProcessParentBlockHash(parent.ParentHash, evm, statedb) ProcessParentBlockHash(parent.ParentHash, evm, statedb)
// make sure that the state is correct // make sure that the state is correct
@ -548,8 +623,8 @@ func TestProcessParentBlockHashPragueGuard(t *testing.T) {
BaseFee: nil, BaseFee: nil,
Random: &random, Random: &random,
} }
evmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, nil, &config, vm.Config{}) evm := vm.NewEVM(blockContext, statedb, nil, &config, vm.Config{})
ProcessParentBlockHash(common.Hash{0x01}, evmenv, statedb) ProcessParentBlockHash(common.Hash{0x01}, evm, statedb)
if code := statedb.GetCode(params.HistoryStorageAddress); len(code) != 0 { if code := statedb.GetCode(params.HistoryStorageAddress); len(code) != 0 {
t.Fatalf("unexpected history contract code predeploy: %x", code) t.Fatalf("unexpected history contract code predeploy: %x", code)
@ -586,8 +661,8 @@ func TestProcessParentBlockHashBackfillMissingHistory(t *testing.T) {
BaseFee: nil, BaseFee: nil,
Random: &random, Random: &random,
} }
evmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, nil, &config, vm.Config{}) evm := vm.NewEVM(blockContext, statedb, nil, &config, vm.Config{})
ProcessParentBlockHash(common.Hash{0x01}, evmenv, statedb) ProcessParentBlockHash(common.Hash{0x01}, evm, statedb)
if have := getParentBlockHash(statedb, 1); have != available[1] { if have := getParentBlockHash(statedb, 1); have != available[1] {
t.Fatalf("expected hash at slot 1, have %v", have) t.Fatalf("expected hash at slot 1, have %v", have)
@ -619,14 +694,14 @@ func TestProcessParentBlockHashCodeMismatchPanics(t *testing.T) {
BaseFee: nil, BaseFee: nil,
Random: &random, Random: &random,
} }
evmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, nil, &config, vm.Config{}) evm := vm.NewEVM(blockContext, statedb, nil, &config, vm.Config{})
defer func() { defer func() {
if recover() == nil { if recover() == nil {
t.Fatal("expected panic on history storage code mismatch") t.Fatal("expected panic on history storage code mismatch")
} }
}() }()
ProcessParentBlockHash(common.Hash{0x01}, evmenv, statedb) ProcessParentBlockHash(common.Hash{0x01}, evm, statedb)
} }
func getParentBlockHash(statedb *state.StateDB, number uint64) common.Hash { func getParentBlockHash(statedb *state.StateDB, number uint64) common.Hash {

View file

@ -110,9 +110,10 @@ func CallContractWithState(call ethereum.CallMsg, chain consensus.ChainContext,
// about the transaction and calling mechanisms. // about the transaction and calling mechanisms.
txContext := NewEVMTxContext(msg) txContext := NewEVMTxContext(msg)
evmContext := NewEVMBlockContext(chain.CurrentHeader(), chain, nil) evmContext := NewEVMBlockContext(chain.CurrentHeader(), chain, nil)
vmenv := vm.NewEVM(evmContext, txContext, statedb, nil, chain.Config(), vm.Config{}) evm := vm.NewEVM(evmContext, statedb, nil, chain.Config(), vm.Config{})
evm.SetTxContext(txContext)
gaspool := new(GasPool).AddGas(1000000) gaspool := new(GasPool).AddGas(1000000)
result, err := NewStateTransition(vmenv, msg, gaspool).TransitionDb(common.Address{}) result, err := NewStateTransition(evm, msg, gaspool).TransitionDb(common.Address{})
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -132,12 +132,13 @@ type EVM struct {
returnData []byte // Last CALL's return data for subsequent reuse returnData []byte // Last CALL's return data for subsequent reuse
} }
// NewEVM returns a new EVM. The returned EVM is not thread safe and should // NewEVM constructs an EVM instance with the supplied block context, state
// only ever be used *once*. // database and several configs. It is meant to be used throughout the entire
func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, tradingStateDB *tradingstate.TradingStateDB, chainConfig *params.ChainConfig, config Config) *EVM { // state transition of a block, with the transaction context switched as
// needed by calling evm.SetTxContext.
func NewEVM(blockCtx BlockContext, statedb StateDB, tradingStateDB *tradingstate.TradingStateDB, chainConfig *params.ChainConfig, config Config) *EVM {
evm := &EVM{ evm := &EVM{
Context: blockCtx, Context: blockCtx,
TxContext: txCtx,
StateDB: statedb, StateDB: statedb,
tradingStateDB: tradingStateDB, tradingStateDB: tradingStateDB,
Config: config, Config: config,
@ -198,6 +199,11 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, tradingStat
return evm return evm
} }
// SetTracer sets the tracer for following state transition.
func (evm *EVM) SetTracer(tracer *tracing.Hooks) {
evm.Config.Tracer = tracer
}
// SetPrecompiles sets the precompiled contracts for the EVM. // SetPrecompiles sets the precompiled contracts for the EVM.
// This method is only used through RPC calls. // This method is only used through RPC calls.
// It is not thread-safe. // It is not thread-safe.
@ -205,11 +211,10 @@ func (evm *EVM) SetPrecompiles(precompiles PrecompiledContracts) {
evm.precompiles = precompiles evm.precompiles = precompiles
} }
// Reset resets the EVM with a new transaction context.Reset // SetTxContext updates the EVM with a new transaction context.
// This is not threadsafe and should only be done very cautiously. // This is not threadsafe and should only be done very cautiously.
func (evm *EVM) Reset(txCtx TxContext, statedb StateDB) { func (evm *EVM) SetTxContext(txCtx TxContext) {
evm.TxContext = txCtx evm.TxContext = txCtx
evm.StateDB = statedb
} }
// Cancel cancels any running EVM operation. This may be called concurrently and // Cancel cancels any running EVM operation. This may be called concurrently and

View file

@ -96,16 +96,16 @@ func TestEIP2200(t *testing.T) {
CanTransfer: func(StateDB, common.Address, *uint256.Int) bool { return true }, CanTransfer: func(StateDB, common.Address, *uint256.Int) bool { return true },
Transfer: func(StateDB, common.Address, common.Address, *uint256.Int) {}, Transfer: func(StateDB, common.Address, common.Address, *uint256.Int) {},
} }
vmenv := NewEVM(vmctx, TxContext{}, statedb, nil, params.AllEthashProtocolChanges, Config{ExtraEips: []int{2200}}) evm := NewEVM(vmctx, statedb, nil, params.AllEthashProtocolChanges, Config{ExtraEips: []int{2200}})
_, gas, err := vmenv.Call(common.Address{}, address, nil, tt.gaspool, new(uint256.Int)) _, gas, err := evm.Call(common.Address{}, address, nil, tt.gaspool, new(uint256.Int))
if !errors.Is(err, tt.failure) { if !errors.Is(err, tt.failure) {
t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure) t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure)
} }
if used := tt.gaspool - gas; used != tt.used { if used := tt.gaspool - gas; used != tt.used {
t.Errorf("test %d: gas used mismatch: have %v, want %v", i, used, tt.used) t.Errorf("test %d: gas used mismatch: have %v, want %v", i, used, tt.used)
} }
if refund := vmenv.StateDB.GetRefund(); refund != tt.refund { if refund := evm.StateDB.GetRefund(); refund != tt.refund {
t.Errorf("test %d: gas refund mismatch: have %v, want %v", i, refund, tt.refund) t.Errorf("test %d: gas refund mismatch: have %v, want %v", i, refund, tt.refund)
} }
} }
@ -151,9 +151,9 @@ func TestCreateGas(t *testing.T) {
config.ExtraEips = []int{3860} config.ExtraEips = []int{3860}
} }
vmenv := NewEVM(vmctx, TxContext{}, statedb, nil, params.AllEthashProtocolChanges, config) evm := NewEVM(vmctx, statedb, nil, params.AllEthashProtocolChanges, config)
var startGas = uint64(testGas) var startGas = uint64(testGas)
ret, gas, err := vmenv.Call(common.Address{}, address, nil, startGas, new(uint256.Int)) ret, gas, err := evm.Call(common.Address{}, address, nil, startGas, new(uint256.Int))
if err != nil { if err != nil {
return false return false
} }

View file

@ -98,7 +98,7 @@ func init() {
func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFunc, name string) { func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFunc, name string) {
var ( var (
evm = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{}) evm = NewEVM(BlockContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack() stack = newstack()
pc = uint64(0) pc = uint64(0)
) )
@ -196,7 +196,7 @@ func TestSAR(t *testing.T) {
func TestAddMod(t *testing.T) { func TestAddMod(t *testing.T) {
var ( var (
evm = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{}) evm = NewEVM(BlockContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack() stack = newstack()
pc = uint64(0) pc = uint64(0)
) )
@ -239,7 +239,7 @@ func TestWriteExpectedValues(t *testing.T) {
// getResult is a convenience function to generate the expected values // getResult is a convenience function to generate the expected values
getResult := func(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase { getResult := func(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase {
var ( var (
evm = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{}) evm = NewEVM(BlockContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack() stack = newstack()
pc = uint64(0) pc = uint64(0)
) )
@ -289,7 +289,7 @@ func TestJsonTestcases(t *testing.T) {
func opBenchmark(bench *testing.B, op executionFunc, args ...string) { func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
var ( var (
evm = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{}) evm = NewEVM(BlockContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack() stack = newstack()
scope = &ScopeContext{nil, stack, nil} scope = &ScopeContext{nil, stack, nil}
) )
@ -526,7 +526,7 @@ func BenchmarkOpIsZero(b *testing.B) {
func TestOpMstore(t *testing.T) { func TestOpMstore(t *testing.T) {
var ( var (
evm = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{}) evm = NewEVM(BlockContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack() stack = newstack()
mem = NewMemory() mem = NewMemory()
) )
@ -550,7 +550,7 @@ func TestOpMstore(t *testing.T) {
func BenchmarkOpMstore(bench *testing.B) { func BenchmarkOpMstore(bench *testing.B) {
var ( var (
evm = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{}) evm = NewEVM(BlockContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack() stack = newstack()
mem = NewMemory() mem = NewMemory()
) )
@ -570,7 +570,7 @@ func BenchmarkOpMstore(bench *testing.B) {
func TestOpTstore(t *testing.T) { func TestOpTstore(t *testing.T) {
var ( var (
statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase())) statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()))
evm = NewEVM(BlockContext{}, TxContext{}, statedb, nil, params.TestChainConfig, Config{}) evm = NewEVM(BlockContext{}, statedb, nil, params.TestChainConfig, Config{})
stack = newstack() stack = newstack()
mem = NewMemory() mem = NewMemory()
caller = common.Address{} caller = common.Address{}
@ -609,7 +609,7 @@ func TestOpTstore(t *testing.T) {
func BenchmarkOpKeccak256(bench *testing.B) { func BenchmarkOpKeccak256(bench *testing.B) {
var ( var (
evm = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{}) evm = NewEVM(BlockContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack() stack = newstack()
mem = NewMemory() mem = NewMemory()
) )
@ -710,7 +710,7 @@ func TestRandom(t *testing.T) {
{name: "hash(0x010203)", random: crypto.Keccak256Hash([]byte{0x01, 0x02, 0x03})}, {name: "hash(0x010203)", random: crypto.Keccak256Hash([]byte{0x01, 0x02, 0x03})},
} { } {
var ( var (
evm = NewEVM(BlockContext{Random: &tt.random}, TxContext{}, nil, nil, params.TestChainConfig, Config{}) evm = NewEVM(BlockContext{Random: &tt.random}, nil, nil, params.TestChainConfig, Config{})
stack = newstack() stack = newstack()
pc = uint64(0) pc = uint64(0)
) )
@ -750,7 +750,7 @@ func TestBlobHash(t *testing.T) {
{name: "out-of-bounds (nil)", idx: 25, expect: zero, hashes: nil}, {name: "out-of-bounds (nil)", idx: 25, expect: zero, hashes: nil},
} { } {
var ( var (
evm = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{}) evm = NewEVM(BlockContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack() stack = newstack()
pc = uint64(0) pc = uint64(0)
) )
@ -853,7 +853,7 @@ func TestOpMCopy(t *testing.T) {
}, },
} { } {
var ( var (
evm = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{}) evm = NewEVM(BlockContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack() stack = newstack()
pc = uint64(0) pc = uint64(0)
) )
@ -909,7 +909,7 @@ func TestOpMCopy(t *testing.T) {
} }
func TestOpCLZ(t *testing.T) { func TestOpCLZ(t *testing.T) {
evm := NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{}) evm := NewEVM(BlockContext{}, nil, nil, params.TestChainConfig, Config{})
tests := []struct { tests := []struct {
inputHex string inputHex string

View file

@ -39,5 +39,7 @@ func NewEnv(cfg *Config) *vm.EVM {
Random: cfg.Random, Random: cfg.Random,
} }
return vm.NewEVM(blockContext, txContext, cfg.State, nil, cfg.ChainConfig, cfg.EVMConfig) evm := vm.NewEVM(blockContext, cfg.State, nil, cfg.ChainConfig, cfg.EVMConfig)
evm.SetTxContext(txContext)
return evm
} }

View file

@ -32,7 +32,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/accounts" "github.com/XinFinOrg/XDPoSChain/accounts"
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind" "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/math"
"github.com/XinFinOrg/XDPoSChain/consensus" "github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS" "github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
"github.com/XinFinOrg/XDPoSChain/contracts" "github.com/XinFinOrg/XDPoSChain/contracts"
@ -40,7 +39,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/core/bloombits" "github.com/XinFinOrg/XDPoSChain/core/bloombits"
"github.com/XinFinOrg/XDPoSChain/core/rawdb" "github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/tracing"
"github.com/XinFinOrg/XDPoSChain/core/txpool" "github.com/XinFinOrg/XDPoSChain/core/txpool"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/core/vm" "github.com/XinFinOrg/XDPoSChain/core/vm"
@ -264,20 +262,18 @@ func (b *EthAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
return b.eth.blockchain.GetTdByHash(hash) return b.eth.blockchain.GetTdByHash(hash)
} }
func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, XDCxState *tradingstate.TradingStateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error) { func (b *EthAPIBackend) GetEVM(ctx context.Context, state *state.StateDB, XDCxState *tradingstate.TradingStateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error) {
vmError := func() error { return nil } vmError := func() error { return nil }
if vmConfig == nil { if vmConfig == nil {
vmConfig = b.eth.blockchain.GetVMConfig() vmConfig = b.eth.blockchain.GetVMConfig()
} }
state.SetBalance(msg.From, math.MaxBig256, tracing.BalanceChangeUnspecified)
txContext := core.NewEVMTxContext(msg)
var context vm.BlockContext var context vm.BlockContext
if blockCtx != nil { if blockCtx != nil {
context = *blockCtx context = *blockCtx
} else { } else {
context = core.NewEVMBlockContext(header, b.eth.BlockChain(), nil) context = core.NewEVMBlockContext(header, b.eth.BlockChain(), nil)
} }
return vm.NewEVM(context, txContext, state, XDCxState, b.eth.chainConfig, *vmConfig), vmError, nil return vm.NewEVM(context, state, XDCxState, b.eth.chainConfig, *vmConfig), vmError, nil
} }
func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {

View file

@ -176,7 +176,8 @@ func run(ctx context.Context, call *core.Message, opts *Options) (*core.Executio
if msgContext.GasPrice.Sign() == 0 { if msgContext.GasPrice.Sign() == 0 {
evmContext.BaseFee = new(big.Int) evmContext.BaseFee = new(big.Int)
} }
evm := vm.NewEVM(evmContext, msgContext, dirtyState, nil, opts.Config, vm.Config{NoBaseFee: true}) evm := vm.NewEVM(evmContext, dirtyState, nil, opts.Config, vm.Config{NoBaseFee: true})
evm.SetTxContext(msgContext)
// Monitor the outer context and interrupt the EVM upon cancellation. To avoid // Monitor the outer context and interrupt the EVM upon cancellation. To avoid
// a dangling goroutine until the outer estimation finishes, create an internal // a dangling goroutine until the outer estimation finishes, create an internal
// context for the lifetime of this method call. // context for the lifetime of this method call.

View file

@ -206,11 +206,11 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
if err != nil { if err != nil {
return nil, vm.BlockContext{}, nil, nil, err return nil, vm.BlockContext{}, nil, nil, err
} }
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil)
evm := vm.NewEVM(context, statedb, nil, eth.blockchain.Config(), vm.Config{})
// If prague hardfork, insert parent block hash in the state as per EIP-2935. // If prague hardfork, insert parent block hash in the state as per EIP-2935.
if eth.blockchain.Config().IsPrague(block.Number()) { if eth.blockchain.Config().IsPrague(block.Number()) {
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) core.ProcessParentBlockHash(block.ParentHash(), evm, statedb)
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, nil, eth.blockchain.Config(), vm.Config{})
core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb)
} }
if txIndex == 0 && len(block.Transactions()) == 0 { if txIndex == 0 && len(block.Transactions()) == 0 {
return nil, vm.BlockContext{}, statedb, release, nil return nil, vm.BlockContext{}, statedb, release, nil
@ -219,6 +219,9 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
signer := types.MakeSigner(eth.blockchain.Config(), block.Number()) signer := types.MakeSigner(eth.blockchain.Config(), block.Number())
feeCapacity := statedb.GetTRC21FeeCapacityFromState() feeCapacity := statedb.GetTRC21FeeCapacityFromState()
for idx, tx := range block.Transactions() { for idx, tx := range block.Transactions() {
if idx == txIndex {
return tx, context, statedb, release, nil
}
var balance *big.Int var balance *big.Int
if tx.To() != nil { if tx.To() != nil {
if value, ok := feeCapacity[*tx.To()]; ok { if value, ok := feeCapacity[*tx.To()]; ok {
@ -228,19 +231,16 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
// Assemble the transaction call message and return if the requested offset // Assemble the transaction call message and return if the requested offset
msg, _ := core.TransactionToMessage(tx, signer, balance, block.Number(), block.BaseFee()) msg, _ := core.TransactionToMessage(tx, signer, balance, block.Number(), block.BaseFee())
txContext := core.NewEVMTxContext(msg) txContext := core.NewEVMTxContext(msg)
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) evm.SetTxContext(txContext)
if idx == txIndex {
return tx, context, statedb, release, nil
}
// Not yet the searched for transaction, execute on top of the current state // Not yet the searched for transaction, execute on top of the current state
vmenv := vm.NewEVM(context, txContext, statedb, nil, eth.blockchain.Config(), vm.Config{})
statedb.SetTxContext(tx.Hash(), idx) statedb.SetTxContext(tx.Hash(), idx)
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()), common.Address{}); err != nil { if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()), common.Address{}); err != nil {
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
} }
// Ensure any modifications are committed to the state // Ensure any modifications are committed to the state
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number()))
} }
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
} }

View file

@ -382,8 +382,8 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
// Insert parent hash in history contract. // Insert parent hash in history contract.
if api.backend.ChainConfig().IsPrague(next.Number()) { if api.backend.ChainConfig().IsPrague(next.Number()) {
context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil) context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil)
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, nil, api.backend.ChainConfig(), vm.Config{}) evm := vm.NewEVM(context, statedb, nil, api.backend.ChainConfig(), vm.Config{})
core.ProcessParentBlockHash(next.ParentHash(), vmenv, statedb) core.ProcessParentBlockHash(next.ParentHash(), evm, statedb)
} }
// Clean out any pending release functions of trace state. Note this // Clean out any pending release functions of trace state. Note this
// step must be done after constructing tracing state, because the // step must be done after constructing tracing state, because the
@ -519,8 +519,9 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
deleteEmptyObjects = chainConfig.IsEIP158(block.Number()) deleteEmptyObjects = chainConfig.IsEIP158(block.Number())
) )
evm := vm.NewEVM(vmctx, statedb, nil, chainConfig, vm.Config{})
if chainConfig.IsPrague(block.Number()) { if chainConfig.IsPrague(block.Number()) {
core.ProcessParentBlockHash(block.ParentHash(), vm.NewEVM(vmctx, vm.TxContext{}, statedb, nil, chainConfig, vm.Config{}), statedb) core.ProcessParentBlockHash(block.ParentHash(), evm, statedb)
} }
feeCapacity := statedb.GetTRC21FeeCapacityFromState() feeCapacity := statedb.GetTRC21FeeCapacityFromState()
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
@ -540,10 +541,10 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
var ( var (
msg, _ = core.TransactionToMessage(tx, signer, balance, block.Number(), block.BaseFee()) msg, _ = core.TransactionToMessage(tx, signer, balance, block.Number(), block.BaseFee())
txContext = core.NewEVMTxContext(msg) txContext = core.NewEVMTxContext(msg)
vmenv = vm.NewEVM(vmctx, txContext, statedb, nil, chainConfig, vm.Config{})
) )
evm.SetTxContext(txContext)
statedb.SetTxContext(tx.Hash(), i) statedb.SetTxContext(tx.Hash(), i)
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit), common.Address{}); err != nil { if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit), common.Address{}); err != nil {
log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err) log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
// We intentionally don't return the error here: if we do, then the RPC server will not // We intentionally don't return the error here: if we do, then the RPC server will not
// return the roots. Most likely, the caller already knows that a certain transaction fails to // return the roots. Most likely, the caller already knows that a certain transaction fails to
@ -587,9 +588,9 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
defer release() defer release()
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
evm := vm.NewEVM(blockCtx, statedb, nil, api.backend.ChainConfig(), vm.Config{})
if api.backend.ChainConfig().IsPrague(block.Number()) { if api.backend.ChainConfig().IsPrague(block.Number()) {
vmenv := vm.NewEVM(blockCtx, vm.TxContext{}, statedb, nil, api.backend.ChainConfig(), vm.Config{}) core.ProcessParentBlockHash(block.ParentHash(), evm, statedb)
core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb)
} }
// JS tracers have high overhead. In this case run a parallel // JS tracers have high overhead. In this case run a parallel
@ -692,6 +693,8 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
feeCapacity := statedb.GetTRC21FeeCapacityFromState() feeCapacity := statedb.GetTRC21FeeCapacityFromState()
var failed error var failed error
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
evm := vm.NewEVM(blockCtx, statedb, nil, api.backend.ChainConfig(), vm.Config{})
txloop: txloop:
for i, tx := range txs { for i, tx := range txs {
// Send the trace task over for execution // Send the trace task over for execution
@ -717,14 +720,14 @@ txloop:
header := block.Header() header := block.Header()
msg, _ := core.TransactionToMessage(tx, signer, balance, header.Number, header.BaseFee) msg, _ := core.TransactionToMessage(tx, signer, balance, header.Number, header.BaseFee)
statedb.SetTxContext(tx.Hash(), i) statedb.SetTxContext(tx.Hash(), i)
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, nil, api.backend.ChainConfig(), vm.Config{}) evm.SetTxContext(core.NewEVMTxContext(msg))
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit), common.Address{}); err != nil { if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit), common.Address{}); err != nil {
failed = err failed = err
break txloop break txloop
} }
// Finalize the state so any modifications are written to the trie // Finalize the state so any modifications are written to the trie
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number()))
} }
close(jobs) close(jobs)
@ -894,7 +897,8 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor
} }
} }
// The actual TxContext will be created as part of ApplyTransactionWithEVM. // The actual TxContext will be created as part of ApplyTransactionWithEVM.
vmenv := vm.NewEVM(vmctx, vm.TxContext{GasPrice: message.GasPrice}, statedb, nil, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true}) evm := vm.NewEVM(vmctx, statedb, nil, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true})
evm.SetTxContext(vm.TxContext{GasPrice: message.GasPrice})
// Define a meaningful timeout of a single transaction trace // Define a meaningful timeout of a single transaction trace
if config.Timeout != nil { if config.Timeout != nil {
@ -908,7 +912,7 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor
if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) { if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) {
tracer.Stop(errors.New("execution timeout")) tracer.Stop(errors.New("execution timeout"))
// Stop evm execution. Note cancellation is not necessarily immediate. // Stop evm execution. Note cancellation is not necessarily immediate.
vmenv.Cancel() evm.Cancel()
} }
}() }()
defer cancel() defer cancel()
@ -923,7 +927,7 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor
// Call SetTxContext to clear out the statedb access list // Call SetTxContext to clear out the statedb access list
statedb.SetTxContext(txctx.TxHash, txctx.TxIndex) statedb.SetTxContext(txctx.TxHash, txctx.TxIndex)
_, _, _, err = core.ApplyTransactionWithEVM(message, api.backend.ChainConfig(), new(core.GasPool).AddGas(message.GasLimit), statedb, vmctx.BlockNumber, txctx.BlockHash, tx, &usedGas, vmenv, balance, common.Address{}) _, _, _, err = core.ApplyTransactionWithEVM(message, api.backend.ChainConfig(), new(core.GasPool).AddGas(message.GasLimit), statedb, vmctx.BlockNumber, txctx.BlockHash, tx, &usedGas, evm, balance, common.Address{})
if err != nil { if err != nil {
return nil, fmt.Errorf("tracing failed: %w", err) return nil, fmt.Errorf("tracing failed: %w", err)
} }

View file

@ -174,18 +174,19 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
} }
// Recompute transactions up to the target index. // Recompute transactions up to the target index.
signer := types.MakeSigner(b.chainConfig, block.Number()) signer := types.MakeSigner(b.chainConfig, block.Number())
context := core.NewEVMBlockContext(block.Header(), b.chain, nil)
evm := vm.NewEVM(context, statedb, nil, b.chainConfig, vm.Config{})
for idx, tx := range block.Transactions() { for idx, tx := range block.Transactions() {
msg, _ := core.TransactionToMessage(tx, signer, nil, block.Number(), block.BaseFee())
txContext := core.NewEVMTxContext(msg)
context := core.NewEVMBlockContext(block.Header(), b.chain, nil)
if idx == txIndex { if idx == txIndex {
return tx, context, statedb, release, nil return tx, context, statedb, release, nil
} }
vmenv := vm.NewEVM(context, txContext, statedb, nil, b.chainConfig, vm.Config{}) msg, _ := core.TransactionToMessage(tx, signer, nil, block.Number(), block.BaseFee())
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()), common.Address{}); err != nil { txContext := core.NewEVMTxContext(msg)
evm.SetTxContext(txContext)
if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()), common.Address{}); err != nil {
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
} }
statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number()))
} }
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
} }

View file

@ -142,7 +142,8 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err) t.Fatalf("failed to prepare transaction for tracing: %v", err)
} }
evm := vm.NewEVM(context, core.NewEVMTxContext(msg), logState, nil, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) evm := vm.NewEVM(context, logState, nil, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
evm.SetTxContext(core.NewEVMTxContext(msg))
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()), common.Address{}) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()), common.Address{})
if err != nil { if err != nil {
@ -228,13 +229,17 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
state := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc) state := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc)
b.ReportAllocs() b.ReportAllocs()
evm := vm.NewEVM(context, state, nil, test.Genesis.Config, vm.Config{})
evm.SetTxContext(txContext)
for b.Loop() { for b.Loop() {
snap := state.Snapshot()
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil, test.Genesis.Config) tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil, test.Genesis.Config)
if err != nil { if err != nil {
b.Fatalf("failed to create call tracer: %v", err) b.Fatalf("failed to create call tracer: %v", err)
} }
evm := vm.NewEVM(context, txContext, state, nil, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) evm.Config.Tracer = tracer.Hooks
snap := state.Snapshot()
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
if _, err = st.TransitionDb(common.Address{}); err != nil { if _, err = st.TransitionDb(common.Address{}); err != nil {
b.Fatalf("failed to execute transaction: %v", err) b.Fatalf("failed to execute transaction: %v", err)
@ -379,7 +384,8 @@ func TestInternals(t *testing.T) {
Origin: origin, Origin: origin,
GasPrice: tx.GasPrice(), GasPrice: tx.GasPrice(),
} }
evm := vm.NewEVM(context, txContext, logState, nil, config, vm.Config{Tracer: tc.tracer.Hooks}) evm := vm.NewEVM(context, logState, nil, config, vm.Config{Tracer: tc.tracer.Hooks})
evm.SetTxContext(txContext)
msg, err := core.TransactionToMessage(tx, signer, nil, nil, big.NewInt(0)) msg, err := core.TransactionToMessage(tx, signer, nil, nil, big.NewInt(0))
if err != nil { if err != nil {
t.Fatalf("test %v: failed to create message: %v", tc.name, err) t.Fatalf("test %v: failed to create message: %v", tc.name, err)
@ -459,7 +465,8 @@ func testContractTracer(tracerName string, dirPath string, t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to create call tracer: %v", err) t.Fatalf("failed to create call tracer: %v", err)
} }
evm := vm.NewEVM(context, txContext, state, nil, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) evm := vm.NewEVM(context, state, nil, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
evm.SetTxContext(txContext)
msg, err := core.TransactionToMessage(tx, signer, nil, nil, nil) msg, err := core.TransactionToMessage(tx, signer, nil, nil, nil)
if err != nil { if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err) t.Fatalf("failed to prepare transaction for tracing: %v", err)

View file

@ -105,7 +105,8 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
if err != nil { if err != nil {
return fmt.Errorf("failed to prepare transaction for tracing: %v", err) return fmt.Errorf("failed to prepare transaction for tracing: %v", err)
} }
evm := vm.NewEVM(context, core.NewEVMTxContext(msg), state, nil, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) evm := vm.NewEVM(context, state, nil, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
evm.SetTxContext(core.NewEVMTxContext(msg))
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()), common.Address{}) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()), common.Address{})
if err != nil { if err != nil {

View file

@ -114,7 +114,8 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err) t.Fatalf("failed to prepare transaction for tracing: %v", err)
} }
evm := vm.NewEVM(context, core.NewEVMTxContext(msg), state, nil, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) evm := vm.NewEVM(context, state, nil, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
evm.SetTxContext(core.NewEVMTxContext(msg))
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()), common.Address{}) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()), common.Address{})
if err != nil { if err != nil {

View file

@ -51,12 +51,13 @@ func testCtx() *vmContext {
func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) { func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) {
var ( var (
evm = vm.NewEVM(vmctx.ctx, vmctx.txContext, &dummyStatedb{}, nil, chaincfg, vm.Config{Tracer: tracer.Hooks}) evm = vm.NewEVM(vmctx.ctx, &dummyStatedb{}, nil, chaincfg, vm.Config{Tracer: tracer.Hooks})
gasLimit uint64 = 31000 gasLimit uint64 = 31000
startGas uint64 = 10000 startGas uint64 = 10000
value = new(uint256.Int) value = new(uint256.Int)
contract = vm.NewContract(common.Address{}, common.Address{}, value, startGas, nil) contract = vm.NewContract(common.Address{}, common.Address{}, value, startGas, nil)
) )
evm.SetTxContext(vmctx.txContext)
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0} contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0}
if contractCode != nil { if contractCode != nil {
contract.Code = contractCode contract.Code = contractCode
@ -178,8 +179,9 @@ func TestHaltBetweenSteps(t *testing.T) {
scope := &vm.ScopeContext{ scope := &vm.ScopeContext{
Contract: vm.NewContract(common.Address{}, common.Address{}, new(uint256.Int), 0, nil), Contract: vm.NewContract(common.Address{}, common.Address{}, new(uint256.Int), 0, nil),
} }
env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, nil, chainConfig, vm.Config{Tracer: tracer.Hooks}) evm := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, &dummyStatedb{}, nil, chainConfig, vm.Config{Tracer: tracer.Hooks})
tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{}) evm.SetTxContext(vm.TxContext{GasPrice: big.NewInt(1)})
tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{})
tracer.OnEnter(0, byte(vm.CALL), common.Address{}, common.Address{}, []byte{}, 0, big.NewInt(0)) tracer.OnEnter(0, byte(vm.CALL), common.Address{}, common.Address{}, []byte{}, 0, big.NewInt(0))
tracer.OnOpcode(0, 0, 0, 0, scope, nil, 0, nil) tracer.OnOpcode(0, 0, 0, 0, scope, nil, 0, nil)
timeout := errors.New("stahp") timeout := errors.New("stahp")
@ -201,8 +203,9 @@ func TestNoStepExec(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, nil, chainConfig, vm.Config{Tracer: tracer.Hooks}) evm := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, &dummyStatedb{}, nil, chainConfig, vm.Config{Tracer: tracer.Hooks})
tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{}) evm.SetTxContext(vm.TxContext{GasPrice: big.NewInt(100)})
tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{})
tracer.OnEnter(0, byte(vm.CALL), common.Address{}, common.Address{}, []byte{}, 1000, big.NewInt(0)) tracer.OnEnter(0, byte(vm.CALL), common.Address{}, common.Address{}, []byte{}, 1000, big.NewInt(0))
tracer.OnExit(0, nil, 0, nil, false) tracer.OnExit(0, nil, 0, nil, false)
ret, err := tracer.GetResult() ret, err := tracer.GetResult()

View file

@ -42,7 +42,7 @@ func (*dummyStatedb) SetState(_ common.Address, _ common.Hash, _ common.Hash) co
func TestStoreCapture(t *testing.T) { func TestStoreCapture(t *testing.T) {
var ( var (
logger = NewStructLogger(nil) logger = NewStructLogger(nil)
evm = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, nil, params.TestChainConfig, vm.Config{Tracer: logger.Hooks()}) evm = vm.NewEVM(vm.BlockContext{}, &dummyStatedb{}, nil, params.TestChainConfig, vm.Config{Tracer: logger.Hooks()})
contract = vm.NewContract(common.Address{}, common.Address{}, new(uint256.Int), 100000, nil) contract = vm.NewContract(common.Address{}, common.Address{}, new(uint256.Int), 100000, nil)
) )
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)} contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)}

View file

@ -88,7 +88,8 @@ func BenchmarkTransactionTrace(b *testing.B) {
//EnableMemory: false, //EnableMemory: false,
//EnableReturnData: false, //EnableReturnData: false,
}) })
evm := vm.NewEVM(context, txContext, state, nil, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer.Hooks()}) evm := vm.NewEVM(context, state, nil, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer.Hooks()})
evm.SetTxContext(txContext)
msg, err := core.TransactionToMessage(tx, signer, nil, nil, context.BaseFee) msg, err := core.TransactionToMessage(tx, signer, nil, nil, context.BaseFee)
if err != nil { if err != nil {
b.Fatalf("failed to prepare transaction for tracing: %v", err) b.Fatalf("failed to prepare transaction for tracing: %v", err)

View file

@ -1274,7 +1274,8 @@ func applyMessage(ctx context.Context, b Backend, args TransactionArgs, state *s
if msg.GasPrice.Sign() == 0 { if msg.GasPrice.Sign() == 0 {
blockContext.BaseFee = new(big.Int) blockContext.BaseFee = new(big.Int)
} }
evm, vmError, err := b.GetEVM(ctx, msg, state, XDCxState, header, vmConfig, blockContext) state.SetBalance(msg.From, math.MaxBig256, tracing.BalanceChangeUnspecified)
evm, vmError, err := b.GetEVM(ctx, state, XDCxState, header, vmConfig, blockContext)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1284,7 +1285,7 @@ func applyMessage(ctx context.Context, b Backend, args TransactionArgs, state *s
if precompiles != nil { if precompiles != nil {
evm.SetPrecompiles(precompiles) evm.SetPrecompiles(precompiles)
} }
evm.SetTxContext(core.NewEVMTxContext(msg))
res, err := applyMessageWithEVM(ctx, evm, msg, timeout, gp) res, err := applyMessageWithEVM(ctx, evm, msg, timeout, gp)
// If an internal state error occurred, let that have precedence. Otherwise, // If an internal state error occurred, let that have precedence. Otherwise,
// a "trie root missing" type of error will masquerade as e.g. "insufficient gas" // a "trie root missing" type of error will masquerade as e.g. "insufficient gas"
@ -1888,16 +1889,18 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
// Apply the transaction with the access list tracer // Apply the transaction with the access list tracer
tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles) tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles)
config := vm.Config{Tracer: tracer.Hooks(), NoBaseFee: true} config := vm.Config{Tracer: tracer.Hooks(), NoBaseFee: true}
vmenv, _, err := b.GetEVM(ctx, msg, statedb, XDCxState, header, &config, nil) statedb.SetBalance(msg.From, math.MaxBig256, tracing.BalanceChangeUnspecified)
evm, _, err := b.GetEVM(ctx, statedb, XDCxState, header, &config, nil)
if err != nil { if err != nil {
return nil, 0, nil, err return nil, 0, nil, err
} }
// Lower the basefee to 0 to avoid breaking EVM // Lower the basefee to 0 to avoid breaking EVM
// invariants (basefee < feecap). // invariants (basefee < feecap).
if msg.GasPrice.Sign() == 0 { if msg.GasPrice.Sign() == 0 {
vmenv.Context.BaseFee = new(big.Int) evm.Context.BaseFee = new(big.Int)
} }
res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit), common.Address{}) evm.SetTxContext(core.NewEVMTxContext(msg))
res, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit), common.Address{})
if err != nil { if err != nil {
return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.ToTransaction(types.LegacyTxType).Hash(), err) return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.ToTransaction(types.LegacyTxType).Hash(), err)
} }

View file

@ -75,7 +75,7 @@ type Backend interface {
PendingBlockAndReceipts() (*types.Block, types.Receipts) PendingBlockAndReceipts() (*types.Block, types.Receipts)
GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error)
GetTd(ctx context.Context, hash common.Hash) *big.Int GetTd(ctx context.Context, hash common.Hash) *big.Int
GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, XDCxState *tradingstate.TradingStateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error) GetEVM(ctx context.Context, state *state.StateDB, XDCxState *tradingstate.TradingStateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error)
SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription

View file

@ -175,12 +175,12 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
NoBaseFee: !sim.validate, NoBaseFee: !sim.validate,
Tracer: tracer.Hooks(), Tracer: tracer.Hooks(),
} }
evm = vm.NewEVM(blockContext, vm.TxContext{GasPrice: new(big.Int)}, sim.state, nil, sim.chainConfig, *vmConfig)
) )
var tracingStateDB = vm.StateDB(sim.state) var tracingStateDB = vm.StateDB(sim.state)
if hooks := tracer.Hooks(); hooks != nil { if hooks := tracer.Hooks(); hooks != nil {
tracingStateDB = state.NewHookedState(sim.state, hooks) tracingStateDB = state.NewHookedState(sim.state, hooks)
} }
evm := vm.NewEVM(blockContext, tracingStateDB, nil, sim.chainConfig, *vmConfig)
// It is possible to override precompiles with EVM bytecode, or // It is possible to override precompiles with EVM bytecode, or
// move them to another address. // move them to another address.
if precompiles != nil { if precompiles != nil {
@ -198,7 +198,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
tracer.reset(tx.Hash(), uint(i)) tracer.reset(tx.Hash(), uint(i))
// EoA check is always skipped, even in validation mode. // EoA check is always skipped, even in validation mode.
msg := call.ToMessage(sim.b, header.BaseFee, !sim.validate, true) msg := call.ToMessage(sim.b, header.BaseFee, !sim.validate, true)
evm.Reset(core.NewEVMTxContext(msg), tracingStateDB) evm.SetTxContext(core.NewEVMTxContext(msg))
result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp) result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp)
if err != nil { if err != nil {
txErr := txValidationError(err) txErr := txValidationError(err)

View file

@ -349,7 +349,7 @@ func (b *backendMock) GetTd(ctx context.Context, hash common.Hash) *big.Int {
return nil return nil
} }
func (b *backendMock) GetEVM(context.Context, *core.Message, *state.StateDB, *tradingstate.TradingStateDB, *types.Header, *vm.Config, *vm.BlockContext) (*vm.EVM, func() error, error) { func (b *backendMock) GetEVM(context.Context, *state.StateDB, *tradingstate.TradingStateDB, *types.Header, *vm.Config, *vm.BlockContext) (*vm.EVM, func() error, error) {
return nil, nil, nil return nil, nil, nil
} }

View file

@ -86,14 +86,15 @@ type Agent interface {
type Work struct { type Work struct {
config *params.ChainConfig config *params.ChainConfig
signer types.Signer signer types.Signer
state *state.StateDB // apply state changes here
tcount int // tx count in cycle
evm *vm.EVM
state *state.StateDB // apply state changes here
parentState *state.StateDB parentState *state.StateDB
tradingState *tradingstate.TradingStateDB tradingState *tradingstate.TradingStateDB
lendingState *lendingstate.LendingStateDB lendingState *lendingstate.LendingStateDB
ancestors mapset.Set[common.Hash] // ancestor set (used for checking uncle parent validity) ancestors mapset.Set[common.Hash] // ancestor set (used for checking uncle parent validity)
family mapset.Set[common.Hash] // family set (used for checking uncle invalidity) family mapset.Set[common.Hash] // family set (used for checking uncle invalidity)
tcount int // tx count in cycle
Block *types.Block // the new block Block *types.Block // the new block
@ -636,6 +637,7 @@ func (w *worker) makeCurrent(parent *types.Block, header *types.Header) error {
ancestors: mapset.NewSet[common.Hash](), ancestors: mapset.NewSet[common.Hash](),
family: mapset.NewSet[common.Hash](), family: mapset.NewSet[common.Hash](),
header: header, header: header,
evm: vm.NewEVM(core.NewEVMBlockContext(header, w.chain, &header.Coinbase), state, XDCxState, w.config, vm.Config{}),
uncles: make(map[common.Hash]*types.Header), uncles: make(map[common.Hash]*types.Header),
createdAt: time.Now(), createdAt: time.Now(),
} }
@ -788,9 +790,7 @@ func (w *worker) commitNewWork() {
work.state.DeleteAddress(common.BlockSignersBinary) work.state.DeleteAddress(common.BlockSignersBinary)
} }
if w.config.IsPrague(header.Number) { if w.config.IsPrague(header.Number) {
context := core.NewEVMBlockContext(header, w.chain, nil) core.ProcessParentBlockHash(header.ParentHash, work.evm, work.state)
vmenv := vm.NewEVM(context, vm.TxContext{}, w.current.state, nil, w.config, vm.Config{})
core.ProcessParentBlockHash(header.ParentHash, vmenv, w.current.state)
} }
// won't grasp txs at checkpoint // won't grasp txs at checkpoint
var ( var (
@ -1049,7 +1049,7 @@ func (w *Work) commitTransactions(mux *event.TypeMux, balanceFee map[common.Addr
log.Trace("Skipping account with special transaction invalid nonce", "sender", from, "nonce", nonce, "tx nonce ", tx.Nonce(), "to", to) log.Trace("Skipping account with special transaction invalid nonce", "sender", from, "nonce", nonce, "tx nonce ", tx.Nonce(), "to", to)
continue continue
} }
logs, tokenFeeUsed, gas, err := w.commitTransaction(balanceFee, tx, bc, coinbase, gp) logs, tokenFeeUsed, gas, err := w.commitTransaction(balanceFee, tx, gp)
switch { switch {
case errors.Is(err, core.ErrNonceTooLow): case errors.Is(err, core.ErrNonceTooLow):
// New head notification data race between the transaction pool and miner, shift // New head notification data race between the transaction pool and miner, shift
@ -1159,7 +1159,7 @@ func (w *Work) commitTransactions(mux *event.TypeMux, balanceFee map[common.Addr
txs.Pop() txs.Pop()
continue continue
} }
logs, tokenFeeUsed, gas, err := w.commitTransaction(balanceFee, tx, bc, coinbase, gp) logs, tokenFeeUsed, gas, err := w.commitTransaction(balanceFee, tx, gp)
switch { switch {
case errors.Is(err, core.ErrGasLimitReached): case errors.Is(err, core.ErrGasLimitReached):
// Pop the current out-of-gas transaction without shifting in the next from the account // Pop the current out-of-gas transaction without shifting in the next from the account
@ -1222,10 +1222,10 @@ func (w *Work) commitTransactions(mux *event.TypeMux, balanceFee map[common.Addr
} }
} }
func (w *Work) commitTransaction(balanceFee map[common.Address]*big.Int, tx *types.Transaction, bc *core.BlockChain, coinbase common.Address, gp *core.GasPool) ([]*types.Log, bool, uint64, error) { func (w *Work) commitTransaction(balanceFee map[common.Address]*big.Int, tx *types.Transaction, gp *core.GasPool) ([]*types.Log, bool, uint64, error) {
snap := w.state.Snapshot() snap := w.state.Snapshot()
receipt, gas, tokenFeeUsed, err := core.ApplyTransaction(w.config, balanceFee, bc, &coinbase, gp, w.state, w.tradingState, w.header, tx, &w.header.GasUsed, vm.Config{}) receipt, gas, tokenFeeUsed, err := core.ApplyTransaction(w.config, balanceFee, w.evm, gp, w.state, w.header, tx, &w.header.GasUsed)
if err != nil { if err != nil {
w.state.RevertToSnapshot(snap) w.state.RevertToSnapshot(snap)
return nil, false, 0, err return nil, false, 0, err

View file

@ -182,7 +182,8 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) (*state.StateD
context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase) context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase)
context.GetHash = vmTestBlockHash context.GetHash = vmTestBlockHash
context.BaseFee = baseFee context.BaseFee = baseFee
evm := vm.NewEVM(context, txContext, statedb, nil, config, vmconfig) evm := vm.NewEVM(context, statedb, nil, config, vmconfig)
evm.SetTxContext(txContext)
// Execute the message. // Execute the message.
snapshot := statedb.Snapshot() snapshot := statedb.Snapshot()

View file

@ -148,7 +148,9 @@ func (t *VMTest) newEVM(statedb *state.StateDB, vmconfig vm.Config) *vm.EVM {
GasLimit: t.json.Env.GasLimit, GasLimit: t.json.Env.GasLimit,
Difficulty: t.json.Env.Difficulty, Difficulty: t.json.Env.Difficulty,
} }
return vm.NewEVM(context, txContext, statedb, nil, params.MainnetChainConfig, vmconfig) evm := vm.NewEVM(context, statedb, nil, params.MainnetChainConfig, vmconfig)
evm.SetTxContext(txContext)
return evm
} }
func vmTestBlockHash(n uint64) common.Hash { func vmTestBlockHash(n uint64) common.Hash {