diff --git a/evmcore/chain_makers.go b/evmcore/chain_makers.go index 5d34326d6..c6ac567e8 100644 --- a/evmcore/chain_makers.go +++ b/evmcore/chain_makers.go @@ -29,7 +29,6 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/Fantom-foundation/go-opera/inter" - "github.com/Fantom-foundation/go-opera/opera" ) // BlockGen creates blocks for testing. @@ -78,29 +77,22 @@ func (b *BlockGen) SetCoinbase(addr common.Address) { // added. Notably, contract code relying on the BLOCKHASH instruction // will panic during execution. func (b *BlockGen) AddTx(tx *types.Transaction) { - b.AddTxWithChain(nil, tx) + b.addTx(nil, vm.Config{}, tx) } -// AddTxWithChain adds a transaction to the generated block. If no coinbase has +// addTx adds a transaction to the generated block. If no coinbase has // been set, the block's coinbase is set to the zero address. // -// AddTxWithChain panics if the transaction cannot be executed. In addition to -// the protocol-imposed limitations (gas limit, etc.), there are some -// further limitations on the content of transactions that can be -// added. If contract code relies on the BLOCKHASH instruction, -// the block in chain will be returned. -func (b *BlockGen) AddTxWithChain(bc DummyChain, tx *types.Transaction) { +// There are a few options can be passed as well in order to run some +// customized rules. +// - bc: enables the ability to query historical block hashes for BLOCKHASH +// - vmConfig: extends the flexibility for customizing evm rules, e.g. enable extra EIPs +func (b *BlockGen) addTx(bc DummyChain, vmConfig vm.Config, tx *types.Transaction) { if b.gasPool == nil { b.SetCoinbase(common.Address{}) } - msg, err := TxAsMessage(tx, types.MakeSigner(b.config, b.header.Number), b.header.BaseFee) - if err != nil { - panic(err) - } - b.statedb.Prepare(tx.Hash(), len(b.txs)) - blockContext := NewEVMBlockContext(b.header, bc, nil) - vmenv := vm.NewEVM(blockContext, vm.TxContext{}, b.statedb, b.config, opera.DefaultVMConfig) - receipt, _, _, err := applyTransaction(msg, b.config, b.gasPool, b.statedb, b.header.Number, b.header.Hash, tx, &b.header.GasUsed, vmenv, func(log *types.Log, db *state.StateDB) {}) + b.statedb.SetTxContext(tx.Hash(), len(b.txs)) + receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vmConfig) if err != nil { panic(err) } @@ -108,6 +100,22 @@ func (b *BlockGen) AddTxWithChain(bc DummyChain, tx *types.Transaction) { b.receipts = append(b.receipts, receipt) } +// AddTxWithChain adds a transaction to the generated block. If no coinbase has +// been set, the block's coinbase is set to the zero address. +// +// AddTxWithChain panics if the transaction cannot be executed. In addition to +// the protocol-imposed limitations (gas limit, etc.), there are some +// further limitations on the content of transactions that can be +// added. If contract code relies on the BLOCKHASH instruction, +// the block in chain will be returned. +func (b *BlockGen) AddTxWithChain(bc DummyChain, tx *types.Transaction) { + b.addTx(bc, vm.Config{}, tx) +} + +func (b *BlockGen) AddTxWithVMConfig(tx *types.Transaction, config vm.Config) { + b.addTx(nil, config, tx) +} + // GetBalance returns the balance of the given address at the generated block. func (b *BlockGen) GetBalance(addr common.Address) *big.Int { return b.statedb.GetBalance(addr) diff --git a/evmcore/state_prefetcher.go b/evmcore/state_prefetcher.go index dac3d1e3c..b736b74bf 100644 --- a/evmcore/state_prefetcher.go +++ b/evmcore/state_prefetcher.go @@ -66,7 +66,7 @@ func (p *statePrefetcher) Prefetch(block *EvmBlock, statedb *state.StateDB, cfg if err != nil { return // Also invalid block, bail out } - statedb.Prepare(tx.Hash(), i) + statedb.SetTxContext(tx.Hash(), i) if err := precacheTransaction(msg, p.config, gaspool, statedb, header, evm); err != nil { return // Ugh, something went horribly wrong, bail out } diff --git a/evmcore/state_processor.go b/evmcore/state_processor.go index 931699588..fa9fbdb93 100644 --- a/evmcore/state_processor.go +++ b/evmcore/state_processor.go @@ -79,7 +79,7 @@ func (p *StateProcessor) Process( return nil, nil, nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } - statedb.Prepare(tx.Hash(), i) + statedb.SetTxContext(tx.Hash(), i) receipt, _, skip, err = applyTransaction(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv, onNewLog) if skip { skipped = append(skipped, uint32(i)) @@ -161,6 +161,22 @@ func applyTransaction( return receipt, result.UsedGas, false, err } +// ApplyTransaction attempts to apply a transaction to the given state database +// and uses the input parameters for its environment. It returns the receipt +// for the transaction, gas used and an error if the transaction failed, +// indicating the block was invalid. +func ApplyTransaction(config *params.ChainConfig, bc DummyChain, author *common.Address, gp *GasPool, statedb *state.StateDB, header *EvmHeader, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) { + msg, err := tx.AsMessage(types.MakeSigner(config, header.Number), header.BaseFee) + if err != nil { + return nil, err + } + // Create a new context to be used in the EVM environment + blockContext := NewEVMBlockContext(header, bc, author) + vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg) + receipt, _, _, err := applyTransaction(msg, config, gp, statedb, header.Number, header.Hash, tx, usedGas, vmenv, func(log *types.Log, db *state.StateDB) {}) + return receipt, err +} + func TxAsMessage(tx *types.Transaction, signer types.Signer, baseFee *big.Int) (types.Message, error) { if !internaltx.IsInternal(tx) { return tx.AsMessage(signer, baseFee) diff --git a/evmcore/state_transition.go b/evmcore/state_transition.go index 1fee3d1f4..aa0ecc4a2 100644 --- a/evmcore/state_transition.go +++ b/evmcore/state_transition.go @@ -42,8 +42,10 @@ The state transitioning model does all the necessary work to work out a valid ne 3) Create a new state object if the recipient is \0*32 4) Value transfer == If contract creation == - 4a) Attempt to run transaction data - 4b) If valid, use result as code for the new state object + + 4a) Attempt to run transaction data + 4b) If valid, use result as code for the new state object + == end == 5) Run Script section 6) Derive new state root @@ -232,13 +234,13 @@ func (st *StateTransition) internal() bool { // TransitionDb will transition the state by applying the current message and // returning the evm execution result with following fields. // -// - used gas: -// total gas used (including gas being refunded) -// - returndata: -// the returned data from evm -// - concrete execution error: -// various **EVM** error which aborts the execution, -// e.g. ErrOutOfGas, ErrExecutionReverted +// - used gas: +// total gas used (including gas being refunded) +// - returndata: +// the returned data from evm +// - concrete execution error: +// various **EVM** error which aborts the execution, +// e.g. ErrOutOfGas, ErrExecutionReverted // // However if any consensus issue encountered, return the error directly with // nil evm execution result. @@ -261,6 +263,8 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { } msg := st.msg sender := vm.AccountRef(msg.From()) + //rules := st.evm.ChainConfig().Rules(st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber)) + rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber) contractCreation := msg.To() == nil london := st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) @@ -275,10 +279,10 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { } st.gas -= gas - // Set up the initial access list. - if rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber); rules.IsBerlin { - st.state.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList()) - } + // Execute the preparatory steps for state transition which includes: + // - prepare accessList(post-berlin) + // - reset transient storage(eip 1153) + st.state.Prepare(rules, msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList()) var ( ret []byte