diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 7371dfb1f1..a6f2b082b8 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -300,8 +300,8 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM from.SetBalance(math.MaxBig256) // Execute the call. msg := callmsg{call} - - evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain, nil) + blockCtx := core.NewBlockContext(block.Header(), b.blockchain, nil) + evmContext := core.NewEVMContext(msg, blockCtx) // Create a new environment which holds all relevant information // about the transaction and calling mechanisms. vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{}) diff --git a/core/chain_makers.go b/core/chain_makers.go index 0b5a3d1843..d106f4e212 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -96,7 +96,9 @@ func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) { b.SetCoinbase(common.Address{}) } b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs)) - receipt, _, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{}) + blockContext := NewBlockContext(b.header, bc, nil) + signer := types.MakeSigner(b.config, b.header.Number) + receipt, _, err := ApplyTransaction(b.config, signer, blockContext, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{}) if err != nil { panic(err) } diff --git a/core/evm.go b/core/evm.go index e830847bd5..17a31f3d2f 100644 --- a/core/evm.go +++ b/core/evm.go @@ -35,8 +35,7 @@ type ChainContext interface { GetHeader(common.Hash, uint64) *types.Header } -// NewEVMContext creates a new context for use in the EVM. -func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author *common.Address) vm.Context { +func NewBlockContext(header *types.Header, chain ChainContext, author *common.Address) *vm.BlockContext { // If we don't have an explicit author (i.e. not mining), extract from the header var beneficiary common.Address if author == nil { @@ -44,17 +43,25 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author } else { beneficiary = *author } + return &vm.BlockContext{ + GetHash: GetHashFn(header, chain), + CanTransfer: CanTransfer, + Transfer: Transfer, + Coinbase: beneficiary, + BlockNumber: new(big.Int).Set(header.Number), + Time: new(big.Int).Set(header.Time), + Difficulty: new(big.Int).Set(header.Difficulty), + GasLimit: header.GasLimit, + + } +} + +// NewEVMContext creates a new context for use in the EVM. +func NewEVMContext(msg Message, blockContext *vm.BlockContext) vm.Context { return vm.Context{ - CanTransfer: CanTransfer, - Transfer: Transfer, - GetHash: GetHashFn(header, chain), - Origin: msg.From(), - Coinbase: beneficiary, - BlockNumber: new(big.Int).Set(header.Number), - Time: new(big.Int).Set(header.Time), - Difficulty: new(big.Int).Set(header.Difficulty), - GasLimit: header.GasLimit, - GasPrice: new(big.Int).Set(msg.GasPrice()), + BlockContext: blockContext, + Origin: msg.From(), + GasPrice: new(big.Int).Set(msg.GasPrice()), } } diff --git a/core/state_processor.go b/core/state_processor.go index 503a35d16a..ecb86b263d 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -17,7 +17,6 @@ package core import ( - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core/state" @@ -46,6 +45,8 @@ func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consen } } + + // Process processes the state changes according to the Ethereum rules by running // the transaction messages using the statedb and applying any rewards to both // the processor (coinbase) and any included uncles. @@ -65,10 +66,12 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(statedb) } + blockContext := NewBlockContext(header, p.bc, nil) + signer := types.MakeSigner(p.config, header.Number) // Iterate over and process the individual transactions for i, tx := range block.Transactions() { statedb.Prepare(tx.Hash(), block.Hash(), i) - receipt, _, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, usedGas, cfg) + receipt, _, err := ApplyTransaction(p.config, signer, blockContext, gp, statedb, header, tx, usedGas, cfg) if err != nil { return nil, nil, 0, err } @@ -85,13 +88,13 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // 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 ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, uint64, error) { - msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) +func ApplyTransaction(config *params.ChainConfig, signer types.Signer, blockContext *vm.BlockContext, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, uint64, error) { + msg, err := tx.AsMessage(signer) if err != nil { return nil, 0, err } // Create a new context to be used in the EVM environment - context := NewEVMContext(msg, header, bc, author) + context := NewEVMContext(msg, blockContext) // Create a new environment which holds all relevant information // about the transaction and calling mechanisms. vmenv := vm.NewEVM(context, statedb, config, cfg) diff --git a/core/state_transition.go b/core/state_transition.go index fda081b7d1..ad4c2ca024 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -186,7 +186,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo } msg := st.msg sender := vm.AccountRef(msg.From()) - homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber) + homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockContext.BlockNumber) contractCreation := msg.To() == nil // Pay intrinsic gas @@ -222,7 +222,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo } } st.refundGas() - st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice)) + st.state.AddBalance(st.evm.BlockContext.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice)) return ret, st.gasUsed(), vmerr != nil, err } diff --git a/core/vm/evm.go b/core/vm/evm.go index 70e1cd1b87..fc696e5173 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -44,7 +44,7 @@ type ( func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) { if contract.CodeAddr != nil { precompiles := PrecompiledContractsHomestead - if evm.ChainConfig().IsByzantium(evm.BlockNumber) { + if evm.ChainConfig().IsByzantium(evm.BlockContext.BlockNumber) { precompiles = PrecompiledContractsByzantium } if p := precompiles[*contract.CodeAddr]; p != nil { @@ -70,18 +70,25 @@ func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, err // Context provides the EVM with auxiliary information. Once provided // it shouldn't be modified. type Context struct { + BlockContext *BlockContext + // Message information + Origin common.Address // Provides information for ORIGIN + GasPrice *big.Int // Provides information for GASPRICE +} + +func (c *Context) GetHash(n uint64) common.Hash{ + return c.BlockContext.GetHash(n) +} + +// BlockContext provides the EVM with auxiliary +// info about things that can be reused across transactions in a block +type BlockContext struct { // CanTransfer returns whether the account contains // sufficient ether to transfer the value CanTransfer CanTransferFunc // Transfer transfers ether from one account to the other Transfer TransferFunc - // GetHash returns the hash corresponding to n GetHash GetHashFunc - - // Message information - Origin common.Address // Provides information for ORIGIN - GasPrice *big.Int // Provides information for GASPRICE - // Block information Coinbase common.Address // Provides information for COINBASE GasLimit uint64 // Provides information for GASLIMIT @@ -135,11 +142,11 @@ func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmCon StateDB: statedb, vmConfig: vmConfig, chainConfig: chainConfig, - chainRules: chainConfig.Rules(ctx.BlockNumber), + chainRules: chainConfig.Rules(ctx.BlockContext.BlockNumber), interpreters: make([]Interpreter, 0, 1), } - if chainConfig.IsEWASM(ctx.BlockNumber) { + if chainConfig.IsEWASM(ctx.BlockContext.BlockNumber) { // to be implemented by EVM-C and Wagon PRs. // if vmConfig.EWASMInterpreter != "" { // extIntOpts := strings.Split(vmConfig.EWASMInterpreter, ":") @@ -188,7 +195,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas return nil, gas, ErrDepth } // Fail if we're trying to transfer more than the available balance - if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { + if !evm.Context.BlockContext.CanTransfer(evm.StateDB, caller.Address(), value) { return nil, gas, ErrInsufficientBalance } @@ -198,10 +205,10 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas ) if !evm.StateDB.Exist(addr) { precompiles := PrecompiledContractsHomestead - if evm.ChainConfig().IsByzantium(evm.BlockNumber) { + if evm.ChainConfig().IsByzantium(evm.BlockContext.BlockNumber) { precompiles = PrecompiledContractsByzantium } - if precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 { + if precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockContext.BlockNumber) && value.Sign() == 0 { // Calling a non existing account, don't do anything, but ping the tracer if evm.vmConfig.Debug && evm.depth == 0 { evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) @@ -211,7 +218,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } evm.StateDB.CreateAccount(addr) } - evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value) + evm.BlockContext.Transfer(evm.StateDB, caller.Address(), to.Address(), value) // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. contract := NewContract(caller, to, value, gas) @@ -259,7 +266,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, return nil, gas, ErrDepth } // Fail if we're trying to transfer more than the available balance - if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { + if !evm.BlockContext.CanTransfer(evm.StateDB, caller.Address(), value) { return nil, gas, ErrInsufficientBalance } @@ -375,7 +382,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, if evm.depth > int(params.CallCreateDepth) { return nil, common.Address{}, gas, ErrDepth } - if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { + if !evm.BlockContext.CanTransfer(evm.StateDB, caller.Address(), value) { return nil, common.Address{}, gas, ErrInsufficientBalance } nonce := evm.StateDB.GetNonce(caller.Address()) @@ -389,10 +396,10 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // Create a new account on the state snapshot := evm.StateDB.Snapshot() evm.StateDB.CreateAccount(address) - if evm.ChainConfig().IsEIP158(evm.BlockNumber) { + if evm.ChainConfig().IsEIP158(evm.BlockContext.BlockNumber) { evm.StateDB.SetNonce(address, 1) } - evm.Transfer(evm.StateDB, caller.Address(), address, value) + evm.BlockContext.Transfer(evm.StateDB, caller.Address(), address, value) // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. @@ -411,7 +418,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, ret, err := run(evm, contract, nil, false) // check whether the max code size has been exceeded - maxCodeSizeExceeded := evm.ChainConfig().IsEIP158(evm.BlockNumber) && len(ret) > params.MaxCodeSize + maxCodeSizeExceeded := evm.ChainConfig().IsEIP158(evm.BlockContext.BlockNumber) && len(ret) > params.MaxCodeSize // if the contract creation ran successfully and no errors were returned // calculate the gas required to store the code. If the code could not // be stored due to not enough gas set an error and let it be handled @@ -428,7 +435,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally // when we're in homestead this also counts for code storage gas errors. - if maxCodeSizeExceeded || (err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) { + if maxCodeSizeExceeded || (err != nil && (evm.ChainConfig().IsHomestead(evm.BlockContext.BlockNumber) || err != ErrCodeStoreOutOfGas)) { evm.StateDB.RevertToSnapshot(snapshot) if err != errExecutionReverted { contract.UseGas(contract.Gas) diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 6400c1324f..12c37e4073 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -387,7 +387,7 @@ func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem gas = gt.Calls transfersValue = stack.Back(2).Sign() != 0 address = common.BigToAddress(stack.Back(1)) - eip158 = evm.ChainConfig().IsEIP158(evm.BlockNumber) + eip158 = evm.ChainConfig().IsEIP158(evm.BlockContext.BlockNumber) ) if eip158 { if transfersValue && evm.StateDB.Empty(address) { @@ -453,11 +453,11 @@ func gasRevert(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { var gas uint64 // EIP150 homestead gas reprice fork: - if evm.ChainConfig().IsEIP150(evm.BlockNumber) { + if evm.ChainConfig().IsEIP150(evm.BlockContext.BlockNumber) { gas = gt.Suicide var ( address = common.BigToAddress(stack.Back(0)) - eip158 = evm.ChainConfig().IsEIP158(evm.BlockNumber) + eip158 = evm.ChainConfig().IsEIP158(evm.BlockContext.BlockNumber) ) if eip158 { diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 2a062d7e77..21f1476bfe 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -559,40 +559,40 @@ func opGasprice(pc *uint64, interpreter *EVMInterpreter, contract *Contract, mem } func opBlockhash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - num := stack.pop() + num := stack.peek() - n := interpreter.intPool.get().Sub(interpreter.evm.BlockNumber, common.Big257) - if num.Cmp(n) > 0 && num.Cmp(interpreter.evm.BlockNumber) < 0 { - stack.push(interpreter.evm.GetHash(num.Uint64()).Big()) + n := interpreter.intPool.get().Sub(interpreter.evm.BlockContext.BlockNumber, common.Big257) + if num.Cmp(n) > 0 && num.Cmp(interpreter.evm.BlockContext.BlockNumber) < 0 { + h := interpreter.evm.GetHash(num.Uint64()) + num.SetBytes(h.Bytes()) } else { - stack.push(interpreter.intPool.getZero()) + num.SetUint64(0) } - interpreter.intPool.put(num, n) return nil, nil } func opCoinbase(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Coinbase.Bytes())) + stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.BlockContext.Coinbase.Bytes())) return nil, nil } func opTimestamp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Time))) + stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.BlockContext.Time))) return nil, nil } func opNumber(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.BlockNumber))) + stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.BlockContext.BlockNumber))) return nil, nil } func opDifficulty(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Difficulty))) + stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.BlockContext.Difficulty))) return nil, nil } func opGasLimit(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(math.U256(interpreter.intPool.get().SetUint64(interpreter.evm.GasLimit))) + stack.push(math.U256(interpreter.intPool.get().SetUint64(interpreter.evm.BlockContext.GasLimit))) return nil, nil } @@ -694,7 +694,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor input = memory.Get(offset.Int64(), size.Int64()) gas = contract.Gas ) - if interpreter.evm.ChainConfig().IsEIP150(interpreter.evm.BlockNumber) { + if interpreter.evm.ChainConfig().IsEIP150(interpreter.evm.BlockContext.BlockNumber) { gas -= gas / 64 } @@ -704,7 +704,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor // homestead we must check for CodeStoreOutOfGasError (homestead only // rule) and treat as an error, if the ruleset is frontier we must // ignore this error and pretend the operation was successful. - if interpreter.evm.ChainConfig().IsHomestead(interpreter.evm.BlockNumber) && suberr == ErrCodeStoreOutOfGas { + if interpreter.evm.ChainConfig().IsHomestead(interpreter.evm.BlockContext.BlockNumber) && suberr == ErrCodeStoreOutOfGas { stack.push(interpreter.intPool.getZero()) } else if suberr != nil && suberr != ErrCodeStoreOutOfGas { stack.push(interpreter.intPool.getZero()) @@ -902,7 +902,7 @@ func makeLog(size int) executionFunc { Data: d, // This is a non-consensus field, but assigned here because // core/state doesn't know the current block number. - BlockNumber: interpreter.evm.BlockNumber.Uint64(), + BlockNumber: interpreter.evm.BlockContext.BlockNumber.Uint64(), }) interpreter.intPool.put(mStart, mSize) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 4176653700..4716df79a0 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -100,11 +100,11 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { // we'll set the default jump table. if !cfg.JumpTable[STOP].valid { switch { - case evm.ChainConfig().IsConstantinople(evm.BlockNumber): + case evm.ChainConfig().IsConstantinople(evm.BlockContext.BlockNumber): cfg.JumpTable = constantinopleInstructionSet - case evm.ChainConfig().IsByzantium(evm.BlockNumber): + case evm.ChainConfig().IsByzantium(evm.BlockContext.BlockNumber): cfg.JumpTable = byzantiumInstructionSet - case evm.ChainConfig().IsHomestead(evm.BlockNumber): + case evm.ChainConfig().IsHomestead(evm.BlockContext.BlockNumber): cfg.JumpTable = homesteadInstructionSet default: cfg.JumpTable = frontierInstructionSet @@ -114,7 +114,7 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { return &EVMInterpreter{ evm: evm, cfg: cfg, - gasTable: evm.ChainConfig().GasTable(evm.BlockNumber), + gasTable: evm.ChainConfig().GasTable(evm.BlockContext.BlockNumber), } } diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go index 42a5b0f801..d7eac77500 100644 --- a/core/vm/runtime/env.go +++ b/core/vm/runtime/env.go @@ -23,22 +23,26 @@ import ( ) func NewEnv(cfg *Config) *vm.EVM { + getHash := cfg.GetHashFn if getHash == nil { getHash = func(uint64) common.Hash { return common.Hash{} } } - context := vm.Context{ + blockCtx := &vm.BlockContext{ CanTransfer: core.CanTransfer, Transfer: core.Transfer, GetHash: getHash, - Origin: cfg.Origin, Coinbase: cfg.Coinbase, BlockNumber: cfg.BlockNumber, Time: cfg.Time, Difficulty: cfg.Difficulty, GasLimit: cfg.GasLimit, - GasPrice: cfg.GasPrice, + } + context := vm.Context{ + BlockContext: blockCtx, + Origin: cfg.Origin, + GasPrice: cfg.GasPrice, } return vm.NewEVM(context, cfg.State, cfg.ChainConfig, cfg.EVMConfig) diff --git a/eth/api_backend.go b/eth/api_backend.go index a48815e0db..a3e604586c 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -128,8 +128,8 @@ func (b *EthAPIBackend) GetTd(blockHash common.Hash) *big.Int { func (b *EthAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header) (*vm.EVM, func() error, error) { state.SetBalance(msg.From(), math.MaxBig256) vmError := func() error { return nil } - - context := core.NewEVMContext(msg, header, b.eth.BlockChain(), nil) + blockCtx := core.NewBlockContext(header, b.eth.BlockChain(), nil) + context := core.NewEVMContext(msg, blockCtx) return vm.NewEVM(context, state, b.eth.chainConfig, *b.eth.blockchain.GetVMConfig()), vmError, nil } diff --git a/eth/api_tracer.go b/eth/api_tracer.go index a529ea118e..ba1f4222f5 100644 --- a/eth/api_tracer.go +++ b/eth/api_tracer.go @@ -203,10 +203,11 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl for task := range tasks { signer := types.MakeSigner(api.config, task.block.Number()) + blockCtx := core.NewBlockContext(task.block.Header(), api.eth.blockchain, nil) // Trace all the transactions contained within for i, tx := range task.block.Transactions() { msg, _ := tx.AsMessage(signer) - vmctx := core.NewEVMContext(msg, task.block.Header(), api.eth.blockchain, nil) + vmctx := core.NewEVMContext(msg, blockCtx) res, err := api.traceTx(ctx, msg, vmctx, task.statedb, config) if err != nil { @@ -440,7 +441,7 @@ func (api *PrivateDebugAPI) StandardTraceBadBlockToFile(ctx context.Context, has // traceBlock configures a new tracer according to the provided configuration, and // executes all the transactions contained within. The return value will be one item -// per transaction, dependent on the requestd tracer. +// per transaction, dependent on the requested tracer. func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) { // Create the parent state database if err := api.eth.engine.VerifyHeader(api.eth.blockchain, block.Header(), true); err != nil { @@ -476,11 +477,12 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, pend.Add(1) go func() { defer pend.Done() + blockCtx := core.NewBlockContext(block.Header(), api.eth.blockchain, nil) // Fetch and execute the next transaction trace tasks for task := range jobs { msg, _ := txs[task.index].AsMessage(signer) - vmctx := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil) + vmctx := core.NewEVMContext(msg,blockCtx) res, err := api.traceTx(ctx, msg, vmctx, task.statedb, config) if err != nil { @@ -496,10 +498,11 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, for i, tx := range txs { // Send the trace task over for execution jobs <- &txTraceTask{statedb: statedb.Copy(), index: i} + blockCtx := core.NewBlockContext(block.Header(), api.eth.blockchain, nil) // Generate the next state snapshot fast without tracing msg, _ := tx.AsMessage(signer) - vmctx := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil) + vmctx := core.NewEVMContext(msg,blockCtx) vmenv := vm.NewEVM(vmctx, statedb, api.config, vm.Config{}) if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { @@ -564,11 +567,12 @@ func (api *PrivateDebugAPI) standardTraceBlockToFile(ctx context.Context, block signer = types.MakeSigner(api.config, block.Number()) dumps []string ) + blockCtx := core.NewBlockContext(block.Header(), api.eth.blockchain, nil) for i, tx := range block.Transactions() { // Prepare the trasaction for un-traced execution var ( msg, _ = tx.AsMessage(signer) - vmctx = core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil) + vmctx = core.NewEVMContext(msg, blockCtx) vmConf vm.Config dump *os.File @@ -797,11 +801,11 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, ree } // Recompute transactions up to the target index. signer := types.MakeSigner(api.config, block.Number()) - + blockCtx := core.NewBlockContext(block.Header(), api.eth.blockchain, nil) for idx, tx := range block.Transactions() { // Assemble the transaction call message and return if the requested offset msg, _ := tx.AsMessage(signer) - context := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil) + context := core.NewEVMContext(msg, blockCtx) if idx == txIndex { return msg, context, statedb, nil } diff --git a/eth/tracers/tracer.go b/eth/tracers/tracer.go index 9d6701868c..6f31b8023f 100644 --- a/eth/tracers/tracer.go +++ b/eth/tracers/tracer.go @@ -536,7 +536,7 @@ func (jst *Tracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost if jst.err == nil { // Initialize the context if it wasn't done yet if !jst.inited { - jst.ctx["block"] = env.BlockNumber.Uint64() + jst.ctx["block"] = env.BlockContext.BlockNumber.Uint64() jst.inited = true } // If tracing was interrupted, set the error and stop diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 69eb80a5c5..b434f18a18 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -144,15 +144,17 @@ func TestPrestateTracerCreate2(t *testing.T) { */ origin, _ := signer.Sender(tx) context := vm.Context{ - CanTransfer: core.CanTransfer, - Transfer: core.Transfer, - Origin: origin, - Coinbase: common.Address{}, - BlockNumber: new(big.Int).SetUint64(8000000), - Time: new(big.Int).SetUint64(5), - Difficulty: big.NewInt(0x30000), - GasLimit: uint64(6000000), - GasPrice: big.NewInt(1), + BlockContext: &vm.BlockContext{ + CanTransfer: core.CanTransfer, + Transfer: core.Transfer, + Coinbase: common.Address{}, + BlockNumber: new(big.Int).SetUint64(8000000), + Time: new(big.Int).SetUint64(5), + Difficulty: big.NewInt(0x30000), + GasLimit: uint64(6000000), + }, + Origin: origin, + GasPrice: big.NewInt(1), } alloc := core.GenesisAlloc{} @@ -232,15 +234,17 @@ func TestCallTracer(t *testing.T) { origin, _ := signer.Sender(tx) context := vm.Context{ - CanTransfer: core.CanTransfer, - Transfer: core.Transfer, - Origin: origin, - Coinbase: test.Context.Miner, - BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), - Time: new(big.Int).SetUint64(uint64(test.Context.Time)), - Difficulty: (*big.Int)(test.Context.Difficulty), - GasLimit: uint64(test.Context.GasLimit), - GasPrice: tx.GasPrice(), + BlockContext: &vm.BlockContext{ + CanTransfer: core.CanTransfer, + Transfer: core.Transfer, + Coinbase: test.Context.Miner, + BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), + Time: new(big.Int).SetUint64(uint64(test.Context.Time)), + Difficulty: (*big.Int)(test.Context.Difficulty), + GasLimit: uint64(test.Context.GasLimit), + }, + Origin: origin, + GasPrice: tx.GasPrice(), } statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc) diff --git a/les/api_backend.go b/les/api_backend.go index 7531396235..d3b5096686 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -107,7 +107,8 @@ func (b *LesApiBackend) GetTd(hash common.Hash) *big.Int { func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header) (*vm.EVM, func() error, error) { state.SetBalance(msg.From(), math.MaxBig256) - context := core.NewEVMContext(msg, header, b.eth.blockchain, nil) + blockCtx := core.NewBlockContext(header, b.eth.blockchain, nil) + context := core.NewEVMContext(msg, blockCtx) return vm.NewEVM(context, state, b.eth.chainConfig, vm.Config{}), state.Error, nil } diff --git a/light/odr_test.go b/light/odr_test.go index c1762c43ec..a26804e937 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -195,7 +195,8 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain // Perform read-only call. st.SetBalance(testBankAddress, math.MaxBig256) msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), data, false)} - context := core.NewEVMContext(msg, header, chain, nil) + blockCtx := core.NewBlockContext(header, chain, nil) + context := core.NewEVMContext(msg, blockCtx) vmenv := vm.NewEVM(context, st, config, vm.Config{}) gp := new(core.GasPool).AddGas(math.MaxUint64) ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp) diff --git a/miner/worker.go b/miner/worker.go index 48473796bc..3a65571a6f 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -690,8 +690,9 @@ func (w *worker) updateSnapshot() { func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) { snap := w.current.state.Snapshot() - - receipt, _, err := core.ApplyTransaction(w.config, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, *w.chain.GetVMConfig()) + signer := types.MakeSigner(w.config, w.current.header.Number) + blockContext := core.NewBlockContext(w.current.header, w.chain, &coinbase) + receipt, _, err := core.ApplyTransaction(w.config, signer, blockContext, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, *w.chain.GetVMConfig()) if err != nil { w.current.state.RevertToSnapshot(snap) return nil, err diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 0b78f26ed1..cfd837583d 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -134,8 +134,9 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) (*state.StateD if err != nil { return nil, err } - context := core.NewEVMContext(msg, block.Header(), nil, &t.json.Env.Coinbase) - context.GetHash = vmTestBlockHash + blockCtx := core.NewBlockContext(block.Header(), nil, &t.json.Env.Coinbase) + context := core.NewEVMContext(msg, blockCtx) + blockCtx.GetHash = vmTestBlockHash evm := vm.NewEVM(context, statedb, config, vmconfig) gaspool := new(core.GasPool) diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go index 91566c47e3..4ae07f3b03 100644 --- a/tests/vm_test_util.go +++ b/tests/vm_test_util.go @@ -130,17 +130,20 @@ func (t *VMTest) newEVM(statedb *state.StateDB, vmconfig vm.Config) *vm.EVM { return core.CanTransfer(db, address, amount) } transfer := func(db vm.StateDB, sender, recipient common.Address, amount *big.Int) {} - context := vm.Context{ + blockCtx := &vm.BlockContext{ CanTransfer: canTransfer, Transfer: transfer, GetHash: vmTestBlockHash, - Origin: t.json.Exec.Origin, Coinbase: t.json.Env.Coinbase, BlockNumber: new(big.Int).SetUint64(t.json.Env.Number), Time: new(big.Int).SetUint64(t.json.Env.Timestamp), GasLimit: t.json.Env.GasLimit, Difficulty: t.json.Env.Difficulty, - GasPrice: t.json.Exec.GasPrice, + } + context := vm.Context{ + Origin: t.json.Exec.Origin, + BlockContext: blockCtx, + GasPrice: t.json.Exec.GasPrice, } vmconfig.NoRecursion = true return vm.NewEVM(context, statedb, params.MainnetChainConfig, vmconfig)