core, all: split vm.Context into BlockContext and TxContext (#21672)

* all: core: split vm.Config into BlockConfig and TxConfig

* core: core/vm: reset EVM between tx in block instead of creating new

* core/vm: added docs
pull/21860/head
Marius van der Wijden 4 years ago committed by GitHub
parent 6f4cccf8d2
commit 2045a2bba3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      accounts/abi/bind/backends/simulated.go
  2. 10
      cmd/evm/internal/t8ntool/execution.go
  3. 10
      cmd/geth/retesteth.go
  4. 16
      core/evm.go
  5. 5
      core/state_prefetcher.go
  6. 48
      core/state_processor.go
  7. 8
      core/state_transition.go
  8. 41
      core/vm/evm.go
  9. 4
      core/vm/gas_table_test.go
  10. 16
      core/vm/instructions.go
  11. 14
      core/vm/instructions_test.go
  12. 2
      core/vm/logger_test.go
  13. 10
      core/vm/runtime/env.go
  14. 6
      core/vm/runtime/runtime.go
  15. 5
      eth/api_backend.go
  16. 60
      eth/api_tracer.go
  17. 2
      eth/tracers/tracer.go
  18. 4
      eth/tracers/tracer_test.go
  19. 21
      eth/tracers/tracers_test.go
  20. 5
      les/api_backend.go
  21. 10
      les/odr_test.go
  22. 5
      light/odr_test.go
  23. 5
      tests/state_test_util.go
  24. 10
      tests/vm_test_util.go

@ -542,10 +542,11 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
// Execute the call. // Execute the call.
msg := callMsg{call} msg := callMsg{call}
evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain, nil) txContext := core.NewEVMTxContext(msg)
evmContext := core.NewEVMBlockContext(block.Header(), 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, stateDB, b.config, vm.Config{}) vmEnv := vm.NewEVM(evmContext, txContext, stateDB, b.config, vm.Config{})
gasPool := new(core.GasPool).AddGas(math.MaxUint64) gasPool := new(core.GasPool).AddGas(math.MaxUint64)
return core.NewStateTransition(vmEnv, msg, gasPool).TransitionDb() return core.NewStateTransition(vmEnv, msg, gasPool).TransitionDb()

@ -110,7 +110,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
txIndex = 0 txIndex = 0
) )
gaspool.AddGas(pre.Env.GasLimit) gaspool.AddGas(pre.Env.GasLimit)
vmContext := vm.Context{ vmContext := vm.BlockContext{
CanTransfer: core.CanTransfer, CanTransfer: core.CanTransfer,
Transfer: core.Transfer, Transfer: core.Transfer,
Coinbase: pre.Env.Coinbase, Coinbase: pre.Env.Coinbase,
@ -119,7 +119,6 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
Difficulty: pre.Env.Difficulty, Difficulty: pre.Env.Difficulty,
GasLimit: pre.Env.GasLimit, GasLimit: pre.Env.GasLimit,
GetHash: getHash, GetHash: getHash,
// GasPrice and Origin needs to be set per transaction
} }
// If DAO is supported/enabled, we need to handle it here. In geth 'proper', it's // If DAO is supported/enabled, we need to handle it here. In geth 'proper', it's
// done in StateProcessor.Process(block, ...), right before transactions are applied. // done in StateProcessor.Process(block, ...), right before transactions are applied.
@ -143,10 +142,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
vmConfig.Tracer = tracer vmConfig.Tracer = tracer
vmConfig.Debug = (tracer != nil) vmConfig.Debug = (tracer != nil)
statedb.Prepare(tx.Hash(), blockHash, txIndex) statedb.Prepare(tx.Hash(), blockHash, txIndex)
vmContext.GasPrice = msg.GasPrice() txContext := core.NewEVMTxContext(msg)
vmContext.Origin = msg.From()
evm := vm.NewEVM(vmContext, statedb, chainConfig, vmConfig) evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig)
if chainConfig.IsYoloV2(vmContext.BlockNumber) { if chainConfig.IsYoloV2(vmContext.BlockNumber) {
statedb.AddAddressToAccessList(msg.From()) statedb.AddAddressToAccessList(msg.From())
if dst := msg.To(); dst != nil { if dst := msg.To(); dst != nil {
@ -185,7 +183,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
receipt.GasUsed = msgResult.UsedGas receipt.GasUsed = msgResult.UsedGas
// if the transaction created a contract, store the creation address in the receipt. // if the transaction created a contract, store the creation address in the receipt.
if msg.To() == nil { if msg.To() == nil {
receipt.ContractAddress = crypto.CreateAddress(evm.Context.Origin, tx.Nonce()) receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
} }
// Set the receipt logs and create a bloom for filtering // Set the receipt logs and create a bloom for filtering
receipt.Logs = statedb.GetLogs(tx.Hash()) receipt.Logs = statedb.GetLogs(tx.Hash())

@ -671,12 +671,13 @@ func (api *RetestethAPI) AccountRange(ctx context.Context,
} }
// Recompute transactions up to the target index. // Recompute transactions up to the target index.
signer := types.MakeSigner(api.blockchain.Config(), block.Number()) signer := types.MakeSigner(api.blockchain.Config(), block.Number())
context := core.NewEVMBlockContext(block.Header(), api.blockchain, nil)
for idx, tx := range block.Transactions() { for idx, tx := range block.Transactions() {
// Assemble the transaction call message and return if the requested offset // Assemble the transaction call message and return if the requested offset
msg, _ := tx.AsMessage(signer) msg, _ := tx.AsMessage(signer)
context := core.NewEVMContext(msg, block.Header(), api.blockchain, nil) txContext := core.NewEVMTxContext(msg)
// 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, statedb, api.blockchain.Config(), vm.Config{}) vmenv := vm.NewEVM(context, txContext, statedb, api.blockchain.Config(), vm.Config{})
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
return AccountRangeResult{}, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) return AccountRangeResult{}, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
} }
@ -781,12 +782,13 @@ func (api *RetestethAPI) StorageRangeAt(ctx context.Context,
} }
// Recompute transactions up to the target index. // Recompute transactions up to the target index.
signer := types.MakeSigner(api.blockchain.Config(), block.Number()) signer := types.MakeSigner(api.blockchain.Config(), block.Number())
context := core.NewEVMBlockContext(block.Header(), api.blockchain, nil)
for idx, tx := range block.Transactions() { for idx, tx := range block.Transactions() {
// Assemble the transaction call message and return if the requested offset // Assemble the transaction call message and return if the requested offset
msg, _ := tx.AsMessage(signer) msg, _ := tx.AsMessage(signer)
context := core.NewEVMContext(msg, block.Header(), api.blockchain, nil) txContext := core.NewEVMTxContext(msg)
// 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, statedb, api.blockchain.Config(), vm.Config{}) vmenv := vm.NewEVM(context, txContext, statedb, api.blockchain.Config(), vm.Config{})
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
return StorageRangeResult{}, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) return StorageRangeResult{}, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
} }

@ -35,8 +35,8 @@ type ChainContext interface {
GetHeader(common.Hash, uint64) *types.Header GetHeader(common.Hash, uint64) *types.Header
} }
// NewEVMContext creates a new context for use in the EVM. // NewEVMBlockContext creates a new context for use in the EVM.
func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author *common.Address) vm.Context { func NewEVMBlockContext(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 // If we don't have an explicit author (i.e. not mining), extract from the header
var beneficiary common.Address var beneficiary common.Address
if author == nil { if author == nil {
@ -44,17 +44,23 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author
} else { } else {
beneficiary = *author beneficiary = *author
} }
return vm.Context{ return vm.BlockContext{
CanTransfer: CanTransfer, CanTransfer: CanTransfer,
Transfer: Transfer, Transfer: Transfer,
GetHash: GetHashFn(header, chain), GetHash: GetHashFn(header, chain),
Origin: msg.From(),
Coinbase: beneficiary, Coinbase: beneficiary,
BlockNumber: new(big.Int).Set(header.Number), BlockNumber: new(big.Int).Set(header.Number),
Time: new(big.Int).SetUint64(header.Time), Time: new(big.Int).SetUint64(header.Time),
Difficulty: new(big.Int).Set(header.Difficulty), Difficulty: new(big.Int).Set(header.Difficulty),
GasLimit: header.GasLimit, GasLimit: header.GasLimit,
GasPrice: new(big.Int).Set(msg.GasPrice()), }
}
// NewEVMTxContext creates a new transaction context for a single transaction.
func NewEVMTxContext(msg Message) vm.TxContext {
return vm.TxContext{
Origin: msg.From(),
GasPrice: new(big.Int).Set(msg.GasPrice()),
} }
} }

@ -86,8 +86,9 @@ func precacheTransaction(config *params.ChainConfig, bc ChainContext, author *co
return err return err
} }
// Create the EVM and execute the transaction // Create the EVM and execute the transaction
context := NewEVMContext(msg, header, bc, author) context := NewEVMBlockContext(header, bc, author)
vm := vm.NewEVM(context, statedb, config, cfg) txContext := NewEVMTxContext(msg)
vm := vm.NewEVM(context, txContext, statedb, config, cfg)
_, err = ApplyMessage(vm, msg, gaspool) _, err = ApplyMessage(vm, msg, gaspool)
return err return err

@ -65,10 +65,16 @@ 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 { if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
misc.ApplyDAOHardFork(statedb) misc.ApplyDAOHardFork(statedb)
} }
blockContext := NewEVMBlockContext(header, p.bc, nil)
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)
// Iterate over and process the individual transactions // Iterate over and process the individual transactions
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number))
if err != nil {
return nil, nil, 0, err
}
statedb.Prepare(tx.Hash(), block.Hash(), i) statedb.Prepare(tx.Hash(), block.Hash(), i)
receipt, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, usedGas, cfg) receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, header, tx, usedGas, vmenv)
if err != nil { if err != nil {
return nil, nil, 0, err return nil, nil, 0, err
} }
@ -81,34 +87,25 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
return receipts, allLogs, *usedGas, nil return receipts, allLogs, *usedGas, nil
} }
// ApplyTransaction attempts to apply a transaction to the given state database func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) {
// 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, error) {
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))
if err != nil {
return nil, err
}
// Create a new context to be used in the EVM environment // Create a new context to be used in the EVM environment
context := NewEVMContext(msg, header, bc, author) txContext := NewEVMTxContext(msg)
// Create a new environment which holds all relevant information // Add addresses to access list if applicable
// about the transaction and calling mechanisms.
vmenv := vm.NewEVM(context, statedb, config, cfg)
if config.IsYoloV2(header.Number) { if config.IsYoloV2(header.Number) {
statedb.AddAddressToAccessList(msg.From()) statedb.AddAddressToAccessList(msg.From())
if dst := msg.To(); dst != nil { if dst := msg.To(); dst != nil {
statedb.AddAddressToAccessList(*dst) statedb.AddAddressToAccessList(*dst)
// If it's a create-tx, the destination will be added inside evm.create // If it's a create-tx, the destination will be added inside evm.create
} }
for _, addr := range vmenv.ActivePrecompiles() { for _, addr := range evm.ActivePrecompiles() {
statedb.AddAddressToAccessList(addr) statedb.AddAddressToAccessList(addr)
} }
} }
// Update the evm with the new transaction context.
evm.Reset(txContext, statedb)
// Apply the transaction to the current state (included in the env) // Apply the transaction to the current state (included in the env)
result, err := ApplyMessage(vmenv, msg, gp) result, err := ApplyMessage(evm, msg, gp)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -128,7 +125,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
receipt.GasUsed = result.UsedGas receipt.GasUsed = result.UsedGas
// if the transaction created a contract, store the creation address in the receipt. // if the transaction created a contract, store the creation address in the receipt.
if msg.To() == nil { if msg.To() == nil {
receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce()) receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
} }
// Set the receipt logs and create a bloom for filtering // Set the receipt logs and create a bloom for filtering
receipt.Logs = statedb.GetLogs(tx.Hash()) receipt.Logs = statedb.GetLogs(tx.Hash())
@ -139,3 +136,18 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
return receipt, err return receipt, 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 ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) {
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))
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)
return applyTransaction(msg, config, bc, author, gp, statedb, header, tx, usedGas, vmenv)
}

@ -230,8 +230,8 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
} }
msg := st.msg msg := st.msg
sender := vm.AccountRef(msg.From()) sender := vm.AccountRef(msg.From())
homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber) homestead := st.evm.ChainConfig().IsHomestead(st.evm.Context.BlockNumber)
istanbul := st.evm.ChainConfig().IsIstanbul(st.evm.BlockNumber) istanbul := st.evm.ChainConfig().IsIstanbul(st.evm.Context.BlockNumber)
contractCreation := msg.To() == nil contractCreation := msg.To() == nil
// Check clauses 4-5, subtract intrinsic gas if everything is correct // Check clauses 4-5, subtract intrinsic gas if everything is correct
@ -245,7 +245,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
st.gas -= gas st.gas -= gas
// Check clause 6 // Check clause 6
if msg.Value().Sign() > 0 && !st.evm.CanTransfer(st.state, msg.From(), msg.Value()) { if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From(), msg.Value()) {
return nil, ErrInsufficientFundsForTransfer return nil, ErrInsufficientFundsForTransfer
} }
var ( var (
@ -260,7 +260,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value) ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value)
} }
st.refundGas() 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.Context.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice))
return &ExecutionResult{ return &ExecutionResult{
UsedGas: st.gasUsed(), UsedGas: st.gasUsed(),

@ -91,9 +91,9 @@ func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, err
return nil, errors.New("no compatible interpreter") return nil, errors.New("no compatible interpreter")
} }
// Context provides the EVM with auxiliary information. Once provided // BlockContext provides the EVM with auxiliary information. Once provided
// it shouldn't be modified. // it shouldn't be modified.
type Context struct { type BlockContext struct {
// CanTransfer returns whether the account contains // CanTransfer returns whether the account contains
// sufficient ether to transfer the value // sufficient ether to transfer the value
CanTransfer CanTransferFunc CanTransfer CanTransferFunc
@ -102,10 +102,6 @@ type Context struct {
// GetHash returns the hash corresponding to n // GetHash returns the hash corresponding to n
GetHash GetHashFunc GetHash GetHashFunc
// Message information
Origin common.Address // Provides information for ORIGIN
GasPrice *big.Int // Provides information for GASPRICE
// Block information // Block information
Coinbase common.Address // Provides information for COINBASE Coinbase common.Address // Provides information for COINBASE
GasLimit uint64 // Provides information for GASLIMIT GasLimit uint64 // Provides information for GASLIMIT
@ -114,6 +110,14 @@ type Context struct {
Difficulty *big.Int // Provides information for DIFFICULTY Difficulty *big.Int // Provides information for DIFFICULTY
} }
// TxContext provides the EVM with information about a transaction.
// All fields can change between transactions.
type TxContext struct {
// Message information
Origin common.Address // Provides information for ORIGIN
GasPrice *big.Int // Provides information for GASPRICE
}
// EVM is the Ethereum Virtual Machine base object and provides // EVM is the Ethereum Virtual Machine base object and provides
// the necessary tools to run a contract on the given state with // the necessary tools to run a contract on the given state with
// the provided context. It should be noted that any error // the provided context. It should be noted that any error
@ -125,7 +129,8 @@ type Context struct {
// The EVM should never be reused and is not thread safe. // The EVM should never be reused and is not thread safe.
type EVM struct { type EVM struct {
// Context provides auxiliary blockchain related information // Context provides auxiliary blockchain related information
Context Context BlockContext
TxContext
// StateDB gives access to the underlying state // StateDB gives access to the underlying state
StateDB StateDB StateDB StateDB
// Depth is the current call stack // Depth is the current call stack
@ -153,17 +158,18 @@ type EVM struct {
// NewEVM returns a new EVM. The returned EVM is not thread safe and should // NewEVM returns a new EVM. The returned EVM is not thread safe and should
// only ever be used *once*. // only ever be used *once*.
func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM { func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM {
evm := &EVM{ evm := &EVM{
Context: ctx, Context: blockCtx,
TxContext: txCtx,
StateDB: statedb, StateDB: statedb,
vmConfig: vmConfig, vmConfig: vmConfig,
chainConfig: chainConfig, chainConfig: chainConfig,
chainRules: chainConfig.Rules(ctx.BlockNumber), chainRules: chainConfig.Rules(blockCtx.BlockNumber),
interpreters: make([]Interpreter, 0, 1), interpreters: make([]Interpreter, 0, 1),
} }
if chainConfig.IsEWASM(ctx.BlockNumber) { if chainConfig.IsEWASM(blockCtx.BlockNumber) {
// to be implemented by EVM-C and Wagon PRs. // to be implemented by EVM-C and Wagon PRs.
// if vmConfig.EWASMInterpreter != "" { // if vmConfig.EWASMInterpreter != "" {
// extIntOpts := strings.Split(vmConfig.EWASMInterpreter, ":") // extIntOpts := strings.Split(vmConfig.EWASMInterpreter, ":")
@ -187,6 +193,13 @@ func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmCon
return evm return evm
} }
// Reset resets the EVM with a new transaction context.Reset
// This is not threadsafe and should only be done very cautiously.
func (evm *EVM) Reset(txCtx TxContext, statedb StateDB) {
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
// it's safe to be called multiple times. // it's safe to be called multiple times.
func (evm *EVM) Cancel() { func (evm *EVM) Cancel() {
@ -233,7 +246,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
} }
evm.StateDB.CreateAccount(addr) evm.StateDB.CreateAccount(addr)
} }
evm.Transfer(evm.StateDB, caller.Address(), addr, value) evm.Context.Transfer(evm.StateDB, caller.Address(), addr, value)
// Capture the tracer start/end events in debug mode // Capture the tracer start/end events in debug mode
if evm.vmConfig.Debug && evm.depth == 0 { if evm.vmConfig.Debug && evm.depth == 0 {
@ -426,7 +439,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
if evm.depth > int(params.CallCreateDepth) { if evm.depth > int(params.CallCreateDepth) {
return nil, common.Address{}, gas, ErrDepth return nil, common.Address{}, gas, ErrDepth
} }
if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
return nil, common.Address{}, gas, ErrInsufficientBalance return nil, common.Address{}, gas, ErrInsufficientBalance
} }
nonce := evm.StateDB.GetNonce(caller.Address()) nonce := evm.StateDB.GetNonce(caller.Address())
@ -447,7 +460,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
if evm.chainRules.IsEIP158 { if evm.chainRules.IsEIP158 {
evm.StateDB.SetNonce(address, 1) evm.StateDB.SetNonce(address, 1)
} }
evm.Transfer(evm.StateDB, caller.Address(), address, value) evm.Context.Transfer(evm.StateDB, caller.Address(), address, value)
// Initialise a new contract and set the code that is to be used by the EVM. // 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. // The contract is a scoped environment for this execution context only.

@ -87,11 +87,11 @@ func TestEIP2200(t *testing.T) {
statedb.SetState(address, common.Hash{}, common.BytesToHash([]byte{tt.original})) statedb.SetState(address, common.Hash{}, common.BytesToHash([]byte{tt.original}))
statedb.Finalise(true) // Push the state into the "original" slot statedb.Finalise(true) // Push the state into the "original" slot
vmctx := Context{ vmctx := BlockContext{
CanTransfer: func(StateDB, common.Address, *big.Int) bool { return true }, CanTransfer: func(StateDB, common.Address, *big.Int) bool { return true },
Transfer: func(StateDB, common.Address, common.Address, *big.Int) {}, Transfer: func(StateDB, common.Address, common.Address, *big.Int) {},
} }
vmenv := NewEVM(vmctx, statedb, params.AllEthashProtocolChanges, Config{ExtraEips: []int{2200}}) vmenv := NewEVM(vmctx, TxContext{}, statedb, params.AllEthashProtocolChanges, Config{ExtraEips: []int{2200}})
_, gas, err := vmenv.Call(AccountRef(common.Address{}), address, nil, tt.gaspool, new(big.Int)) _, gas, err := vmenv.Call(AccountRef(common.Address{}), address, nil, tt.gaspool, new(big.Int))
if err != tt.failure { if err != tt.failure {

@ -438,14 +438,14 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx)
return nil, nil return nil, nil
} }
var upper, lower uint64 var upper, lower uint64
upper = interpreter.evm.BlockNumber.Uint64() upper = interpreter.evm.Context.BlockNumber.Uint64()
if upper < 257 { if upper < 257 {
lower = 0 lower = 0
} else { } else {
lower = upper - 256 lower = upper - 256
} }
if num64 >= lower && num64 < upper { if num64 >= lower && num64 < upper {
num.SetBytes(interpreter.evm.GetHash(num64).Bytes()) num.SetBytes(interpreter.evm.Context.GetHash(num64).Bytes())
} else { } else {
num.Clear() num.Clear()
} }
@ -453,30 +453,30 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx)
} }
func opCoinbase(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { func opCoinbase(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
callContext.stack.push(new(uint256.Int).SetBytes(interpreter.evm.Coinbase.Bytes())) callContext.stack.push(new(uint256.Int).SetBytes(interpreter.evm.Context.Coinbase.Bytes()))
return nil, nil return nil, nil
} }
func opTimestamp(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { func opTimestamp(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
v, _ := uint256.FromBig(interpreter.evm.Time) v, _ := uint256.FromBig(interpreter.evm.Context.Time)
callContext.stack.push(v) callContext.stack.push(v)
return nil, nil return nil, nil
} }
func opNumber(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { func opNumber(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
v, _ := uint256.FromBig(interpreter.evm.BlockNumber) v, _ := uint256.FromBig(interpreter.evm.Context.BlockNumber)
callContext.stack.push(v) callContext.stack.push(v)
return nil, nil return nil, nil
} }
func opDifficulty(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { func opDifficulty(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
v, _ := uint256.FromBig(interpreter.evm.Difficulty) v, _ := uint256.FromBig(interpreter.evm.Context.Difficulty)
callContext.stack.push(v) callContext.stack.push(v)
return nil, nil return nil, nil
} }
func opGasLimit(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { func opGasLimit(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
callContext.stack.push(new(uint256.Int).SetUint64(interpreter.evm.GasLimit)) callContext.stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.GasLimit))
return nil, nil return nil, nil
} }
@ -842,7 +842,7 @@ func makeLog(size int) executionFunc {
Data: d, Data: d,
// This is a non-consensus field, but assigned here because // This is a non-consensus field, but assigned here because
// core/state doesn't know the current block number. // core/state doesn't know the current block number.
BlockNumber: interpreter.evm.BlockNumber.Uint64(), BlockNumber: interpreter.evm.Context.BlockNumber.Uint64(),
}) })
return nil, nil return nil, nil

@ -92,7 +92,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 (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{})
stack = newstack() stack = newstack()
rstack = newReturnStack() rstack = newReturnStack()
pc = uint64(0) pc = uint64(0)
@ -192,7 +192,7 @@ func TestSAR(t *testing.T) {
func TestAddMod(t *testing.T) { func TestAddMod(t *testing.T) {
var ( var (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{})
stack = newstack() stack = newstack()
evmInterpreter = NewEVMInterpreter(env, env.vmConfig) evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
pc = uint64(0) pc = uint64(0)
@ -231,7 +231,7 @@ func TestAddMod(t *testing.T) {
// getResult is a convenience function to generate the expected values // getResult is a convenience function to generate the expected values
func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase { func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase {
var ( var (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{})
stack, rstack = newstack(), newReturnStack() stack, rstack = newstack(), newReturnStack()
pc = uint64(0) pc = uint64(0)
interpreter = env.interpreter.(*EVMInterpreter) interpreter = env.interpreter.(*EVMInterpreter)
@ -281,7 +281,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 (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{})
stack, rstack = newstack(), newReturnStack() stack, rstack = newstack(), newReturnStack()
evmInterpreter = NewEVMInterpreter(env, env.vmConfig) evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
) )
@ -515,7 +515,7 @@ func BenchmarkOpIsZero(b *testing.B) {
func TestOpMstore(t *testing.T) { func TestOpMstore(t *testing.T) {
var ( var (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{})
stack, rstack = newstack(), newReturnStack() stack, rstack = newstack(), newReturnStack()
mem = NewMemory() mem = NewMemory()
evmInterpreter = NewEVMInterpreter(env, env.vmConfig) evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
@ -539,7 +539,7 @@ func TestOpMstore(t *testing.T) {
func BenchmarkOpMstore(bench *testing.B) { func BenchmarkOpMstore(bench *testing.B) {
var ( var (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{})
stack, rstack = newstack(), newReturnStack() stack, rstack = newstack(), newReturnStack()
mem = NewMemory() mem = NewMemory()
evmInterpreter = NewEVMInterpreter(env, env.vmConfig) evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
@ -560,7 +560,7 @@ func BenchmarkOpMstore(bench *testing.B) {
func BenchmarkOpSHA3(bench *testing.B) { func BenchmarkOpSHA3(bench *testing.B) {
var ( var (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{})
stack, rstack = newstack(), newReturnStack() stack, rstack = newstack(), newReturnStack()
mem = NewMemory() mem = NewMemory()
evmInterpreter = NewEVMInterpreter(env, env.vmConfig) evmInterpreter = NewEVMInterpreter(env, env.vmConfig)

@ -51,7 +51,7 @@ func (*dummyStatedb) GetRefund() uint64 { return 1337 }
func TestStoreCapture(t *testing.T) { func TestStoreCapture(t *testing.T) {
var ( var (
env = NewEVM(Context{}, &dummyStatedb{}, params.TestChainConfig, Config{}) env = NewEVM(BlockContext{}, TxContext{}, &dummyStatedb{}, params.TestChainConfig, Config{})
logger = NewStructLogger(nil) logger = NewStructLogger(nil)
mem = NewMemory() mem = NewMemory()
stack = newstack() stack = newstack()

@ -22,18 +22,20 @@ import (
) )
func NewEnv(cfg *Config) *vm.EVM { func NewEnv(cfg *Config) *vm.EVM {
context := vm.Context{ txContext := vm.TxContext{
Origin: cfg.Origin,
GasPrice: cfg.GasPrice,
}
blockContext := vm.BlockContext{
CanTransfer: core.CanTransfer, CanTransfer: core.CanTransfer,
Transfer: core.Transfer, Transfer: core.Transfer,
GetHash: cfg.GetHashFn, GetHash: cfg.GetHashFn,
Origin: cfg.Origin,
Coinbase: cfg.Coinbase, Coinbase: cfg.Coinbase,
BlockNumber: cfg.BlockNumber, BlockNumber: cfg.BlockNumber,
Time: cfg.Time, Time: cfg.Time,
Difficulty: cfg.Difficulty, Difficulty: cfg.Difficulty,
GasLimit: cfg.GasLimit, GasLimit: cfg.GasLimit,
GasPrice: cfg.GasPrice,
} }
return vm.NewEVM(context, cfg.State, cfg.ChainConfig, cfg.EVMConfig) return vm.NewEVM(blockContext, txContext, cfg.State, cfg.ChainConfig, cfg.EVMConfig)
} }

@ -113,7 +113,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
vmenv = NewEnv(cfg) vmenv = NewEnv(cfg)
sender = vm.AccountRef(cfg.Origin) sender = vm.AccountRef(cfg.Origin)
) )
if cfg.ChainConfig.IsYoloV2(vmenv.BlockNumber) { if cfg.ChainConfig.IsYoloV2(vmenv.Context.BlockNumber) {
cfg.State.AddAddressToAccessList(cfg.Origin) cfg.State.AddAddressToAccessList(cfg.Origin)
cfg.State.AddAddressToAccessList(address) cfg.State.AddAddressToAccessList(address)
for _, addr := range vmenv.ActivePrecompiles() { for _, addr := range vmenv.ActivePrecompiles() {
@ -150,7 +150,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
vmenv = NewEnv(cfg) vmenv = NewEnv(cfg)
sender = vm.AccountRef(cfg.Origin) sender = vm.AccountRef(cfg.Origin)
) )
if cfg.ChainConfig.IsYoloV2(vmenv.BlockNumber) { if cfg.ChainConfig.IsYoloV2(vmenv.Context.BlockNumber) {
cfg.State.AddAddressToAccessList(cfg.Origin) cfg.State.AddAddressToAccessList(cfg.Origin)
for _, addr := range vmenv.ActivePrecompiles() { for _, addr := range vmenv.ActivePrecompiles() {
cfg.State.AddAddressToAccessList(addr) cfg.State.AddAddressToAccessList(addr)
@ -178,7 +178,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er
vmenv := NewEnv(cfg) vmenv := NewEnv(cfg)
sender := cfg.State.GetOrNewStateObject(cfg.Origin) sender := cfg.State.GetOrNewStateObject(cfg.Origin)
if cfg.ChainConfig.IsYoloV2(vmenv.BlockNumber) { if cfg.ChainConfig.IsYoloV2(vmenv.Context.BlockNumber) {
cfg.State.AddAddressToAccessList(cfg.Origin) cfg.State.AddAddressToAccessList(cfg.Origin)
cfg.State.AddAddressToAccessList(address) cfg.State.AddAddressToAccessList(address)
for _, addr := range vmenv.ActivePrecompiles() { for _, addr := range vmenv.ActivePrecompiles() {

@ -194,8 +194,9 @@ func (b *EthAPIBackend) GetTd(ctx context.Context, hash 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) { func (b *EthAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header) (*vm.EVM, func() error, error) {
vmError := func() error { return nil } vmError := func() error { return nil }
context := core.NewEVMContext(msg, header, b.eth.BlockChain(), nil) txContext := core.NewEVMTxContext(msg)
return vm.NewEVM(context, state, b.eth.blockchain.Config(), *b.eth.blockchain.GetVMConfig()), vmError, nil context := core.NewEVMBlockContext(header, b.eth.BlockChain(), nil)
return vm.NewEVM(context, txContext, state, b.eth.blockchain.Config(), *b.eth.blockchain.GetVMConfig()), vmError, nil
} }
func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {

@ -203,13 +203,11 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl
// Fetch and execute the next block trace tasks // Fetch and execute the next block trace tasks
for task := range tasks { for task := range tasks {
signer := types.MakeSigner(api.eth.blockchain.Config(), task.block.Number()) signer := types.MakeSigner(api.eth.blockchain.Config(), task.block.Number())
blockCtx := core.NewEVMBlockContext(task.block.Header(), api.eth.blockchain, nil)
// Trace all the transactions contained within // Trace all the transactions contained within
for i, tx := range task.block.Transactions() { for i, tx := range task.block.Transactions() {
msg, _ := tx.AsMessage(signer) msg, _ := tx.AsMessage(signer)
vmctx := core.NewEVMContext(msg, task.block.Header(), api.eth.blockchain, nil) res, err := api.traceTx(ctx, msg, blockCtx, task.statedb, config)
res, err := api.traceTx(ctx, msg, vmctx, task.statedb, config)
if err != nil { if err != nil {
task.results[i] = &txTraceResult{Error: err.Error()} task.results[i] = &txTraceResult{Error: err.Error()}
log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err) log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
@ -473,17 +471,15 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block,
if threads > len(txs) { if threads > len(txs) {
threads = len(txs) threads = len(txs)
} }
blockCtx := core.NewEVMBlockContext(block.Header(), api.eth.blockchain, nil)
for th := 0; th < threads; th++ { for th := 0; th < threads; th++ {
pend.Add(1) pend.Add(1)
go func() { go func() {
defer pend.Done() defer pend.Done()
// Fetch and execute the next transaction trace tasks // Fetch and execute the next transaction trace tasks
for task := range jobs { for task := range jobs {
msg, _ := txs[task.index].AsMessage(signer) msg, _ := txs[task.index].AsMessage(signer)
vmctx := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil) res, err := api.traceTx(ctx, msg, blockCtx, task.statedb, config)
res, err := api.traceTx(ctx, msg, vmctx, task.statedb, config)
if err != nil { if err != nil {
results[task.index] = &txTraceResult{Error: err.Error()} results[task.index] = &txTraceResult{Error: err.Error()}
continue continue
@ -500,9 +496,9 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block,
// Generate the next state snapshot fast without tracing // Generate the next state snapshot fast without tracing
msg, _ := tx.AsMessage(signer) msg, _ := tx.AsMessage(signer)
vmctx := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil) txContext := core.NewEVMTxContext(msg)
vmenv := vm.NewEVM(vmctx, statedb, api.eth.blockchain.Config(), vm.Config{}) vmenv := vm.NewEVM(blockCtx, txContext, statedb, api.eth.blockchain.Config(), vm.Config{})
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
failed = err failed = err
break break
@ -565,6 +561,7 @@ func (api *PrivateDebugAPI) standardTraceBlockToFile(ctx context.Context, block
signer = types.MakeSigner(api.eth.blockchain.Config(), block.Number()) signer = types.MakeSigner(api.eth.blockchain.Config(), block.Number())
dumps []string dumps []string
chainConfig = api.eth.blockchain.Config() chainConfig = api.eth.blockchain.Config()
vmctx = core.NewEVMBlockContext(block.Header(), api.eth.blockchain, nil)
canon = true canon = true
) )
// Check if there are any overrides: the caller may wish to enable a future // Check if there are any overrides: the caller may wish to enable a future
@ -587,13 +584,12 @@ func (api *PrivateDebugAPI) standardTraceBlockToFile(ctx context.Context, block
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
// Prepare the trasaction for un-traced execution // Prepare the trasaction for un-traced execution
var ( var (
msg, _ = tx.AsMessage(signer) msg, _ = tx.AsMessage(signer)
vmctx = core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil) txContext = core.NewEVMTxContext(msg)
vmConf vm.Config
vmConf vm.Config dump *os.File
dump *os.File writer *bufio.Writer
writer *bufio.Writer err error
err error
) )
// If the transaction needs tracing, swap out the configs // If the transaction needs tracing, swap out the configs
if tx.Hash() == txHash || txHash == (common.Hash{}) { if tx.Hash() == txHash || txHash == (common.Hash{}) {
@ -617,7 +613,7 @@ func (api *PrivateDebugAPI) standardTraceBlockToFile(ctx context.Context, block
} }
} }
// Execute the transaction and flush any traces to disk // Execute the transaction and flush any traces to disk
vmenv := vm.NewEVM(vmctx, statedb, chainConfig, vmConf) vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())) _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
if writer != nil { if writer != nil {
writer.Flush() writer.Flush()
@ -776,18 +772,19 @@ func (api *PrivateDebugAPI) TraceCall(ctx context.Context, args ethapi.CallArgs,
// Execute the trace // Execute the trace
msg := args.ToMessage(api.eth.APIBackend.RPCGasCap()) msg := args.ToMessage(api.eth.APIBackend.RPCGasCap())
vmctx := core.NewEVMContext(msg, header, api.eth.blockchain, nil) vmctx := core.NewEVMBlockContext(header, api.eth.blockchain, nil)
return api.traceTx(ctx, msg, vmctx, statedb, config) return api.traceTx(ctx, msg, vmctx, statedb, config)
} }
// traceTx configures a new tracer according to the provided configuration, and // traceTx configures a new tracer according to the provided configuration, and
// executes the given message in the provided environment. The return value will // executes the given message in the provided environment. The return value will
// be tracer dependent. // be tracer dependent.
func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, vmctx vm.Context, statedb *state.StateDB, config *TraceConfig) (interface{}, error) { func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
// Assemble the structured logger or the JavaScript tracer // Assemble the structured logger or the JavaScript tracer
var ( var (
tracer vm.Tracer tracer vm.Tracer
err error err error
txContext = core.NewEVMTxContext(message)
) )
switch { switch {
case config != nil && config.Tracer != nil: case config != nil && config.Tracer != nil:
@ -817,7 +814,7 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, v
tracer = vm.NewStructLogger(config.LogConfig) tracer = vm.NewStructLogger(config.LogConfig)
} }
// Run the transaction with tracing enabled. // Run the transaction with tracing enabled.
vmenv := vm.NewEVM(vmctx, statedb, api.eth.blockchain.Config(), vm.Config{Debug: true, Tracer: tracer}) vmenv := vm.NewEVM(vmctx, txContext, statedb, api.eth.blockchain.Config(), vm.Config{Debug: true, Tracer: tracer})
result, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())) result, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()))
if err != nil { if err != nil {
@ -847,19 +844,19 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, v
} }
// computeTxEnv returns the execution environment of a certain transaction. // computeTxEnv returns the execution environment of a certain transaction.
func (api *PrivateDebugAPI) computeTxEnv(block *types.Block, txIndex int, reexec uint64) (core.Message, vm.Context, *state.StateDB, error) { func (api *PrivateDebugAPI) computeTxEnv(block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, error) {
// Create the parent state database // Create the parent state database
parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1) parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1)
if parent == nil { if parent == nil {
return nil, vm.Context{}, nil, fmt.Errorf("parent %#x not found", block.ParentHash()) return nil, vm.BlockContext{}, nil, fmt.Errorf("parent %#x not found", block.ParentHash())
} }
statedb, err := api.computeStateDB(parent, reexec) statedb, err := api.computeStateDB(parent, reexec)
if err != nil { if err != nil {
return nil, vm.Context{}, nil, err return nil, vm.BlockContext{}, nil, err
} }
if txIndex == 0 && len(block.Transactions()) == 0 { if txIndex == 0 && len(block.Transactions()) == 0 {
return nil, vm.Context{}, statedb, nil return nil, vm.BlockContext{}, statedb, nil
} }
// Recompute transactions up to the target index. // Recompute transactions up to the target index.
@ -868,18 +865,19 @@ func (api *PrivateDebugAPI) computeTxEnv(block *types.Block, txIndex int, reexec
for idx, tx := range block.Transactions() { for idx, tx := range block.Transactions() {
// Assemble the transaction call message and return if the requested offset // Assemble the transaction call message and return if the requested offset
msg, _ := tx.AsMessage(signer) msg, _ := tx.AsMessage(signer)
context := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil) txContext := core.NewEVMTxContext(msg)
context := core.NewEVMBlockContext(block.Header(), api.eth.blockchain, nil)
if idx == txIndex { if idx == txIndex {
return msg, context, statedb, nil return msg, context, statedb, 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, statedb, api.eth.blockchain.Config(), vm.Config{}) vmenv := vm.NewEVM(context, txContext, statedb, api.eth.blockchain.Config(), vm.Config{})
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
return nil, vm.Context{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) return nil, vm.BlockContext{}, 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(vmenv.ChainConfig().IsEIP158(block.Number()))
} }
return nil, vm.Context{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
} }

@ -545,7 +545,7 @@ func (jst *Tracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost
if jst.err == nil { if jst.err == nil {
// Initialize the context if it wasn't done yet // Initialize the context if it wasn't done yet
if !jst.inited { if !jst.inited {
jst.ctx["block"] = env.BlockNumber.Uint64() jst.ctx["block"] = env.Context.BlockNumber.Uint64()
jst.inited = true jst.inited = true
} }
// If tracing was interrupted, set the error and stop // If tracing was interrupted, set the error and stop

@ -51,7 +51,7 @@ type dummyStatedb struct {
func (*dummyStatedb) GetRefund() uint64 { return 1337 } func (*dummyStatedb) GetRefund() uint64 { return 1337 }
func runTrace(tracer *Tracer) (json.RawMessage, error) { func runTrace(tracer *Tracer) (json.RawMessage, error) {
env := vm.NewEVM(vm.Context{BlockNumber: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}) env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer})
contract := vm.NewContract(account{}, account{}, big.NewInt(0), 10000) contract := vm.NewContract(account{}, account{}, big.NewInt(0), 10000)
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0} contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0}
@ -166,7 +166,7 @@ func TestHaltBetweenSteps(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
env := vm.NewEVM(vm.Context{BlockNumber: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}) env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer})
contract := vm.NewContract(&account{}, &account{}, big.NewInt(0), 0) contract := vm.NewContract(&account{}, &account{}, big.NewInt(0), 0)
tracer.CaptureState(env, 0, 0, 0, 0, nil, nil, nil, nil, contract, 0, nil) tracer.CaptureState(env, 0, 0, 0, 0, nil, nil, nil, nil, contract, 0, nil)

@ -143,16 +143,18 @@ func TestPrestateTracerCreate2(t *testing.T) {
result: 0x60f3f640a8508fC6a86d45DF051962668E1e8AC7 result: 0x60f3f640a8508fC6a86d45DF051962668E1e8AC7
*/ */
origin, _ := signer.Sender(tx) origin, _ := signer.Sender(tx)
context := vm.Context{ txContext := vm.TxContext{
Origin: origin,
GasPrice: big.NewInt(1),
}
context := vm.BlockContext{
CanTransfer: core.CanTransfer, CanTransfer: core.CanTransfer,
Transfer: core.Transfer, Transfer: core.Transfer,
Origin: origin,
Coinbase: common.Address{}, Coinbase: common.Address{},
BlockNumber: new(big.Int).SetUint64(8000000), BlockNumber: new(big.Int).SetUint64(8000000),
Time: new(big.Int).SetUint64(5), Time: new(big.Int).SetUint64(5),
Difficulty: big.NewInt(0x30000), Difficulty: big.NewInt(0x30000),
GasLimit: uint64(6000000), GasLimit: uint64(6000000),
GasPrice: big.NewInt(1),
} }
alloc := core.GenesisAlloc{} alloc := core.GenesisAlloc{}
@ -175,7 +177,7 @@ func TestPrestateTracerCreate2(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, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer}) evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer})
msg, err := tx.AsMessage(signer) msg, err := tx.AsMessage(signer)
if err != nil { if err != nil {
@ -230,17 +232,18 @@ func TestCallTracer(t *testing.T) {
} }
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number))) signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)))
origin, _ := signer.Sender(tx) origin, _ := signer.Sender(tx)
txContext := vm.TxContext{
context := vm.Context{ Origin: origin,
GasPrice: tx.GasPrice(),
}
context := vm.BlockContext{
CanTransfer: core.CanTransfer, CanTransfer: core.CanTransfer,
Transfer: core.Transfer, Transfer: core.Transfer,
Origin: origin,
Coinbase: test.Context.Miner, Coinbase: test.Context.Miner,
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
Time: new(big.Int).SetUint64(uint64(test.Context.Time)), Time: new(big.Int).SetUint64(uint64(test.Context.Time)),
Difficulty: (*big.Int)(test.Context.Difficulty), Difficulty: (*big.Int)(test.Context.Difficulty),
GasLimit: uint64(test.Context.GasLimit), GasLimit: uint64(test.Context.GasLimit),
GasPrice: tx.GasPrice(),
} }
_, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false) _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false)
@ -249,7 +252,7 @@ func TestCallTracer(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, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
msg, err := tx.AsMessage(signer) msg, err := tx.AsMessage(signer)
if err != nil { if err != nil {

@ -171,8 +171,9 @@ func (b *LesApiBackend) GetTd(ctx context.Context, 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) { func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header) (*vm.EVM, func() error, error) {
context := core.NewEVMContext(msg, header, b.eth.blockchain, nil) txContext := core.NewEVMTxContext(msg)
return vm.NewEVM(context, state, b.eth.chainConfig, vm.Config{}), state.Error, nil context := core.NewEVMBlockContext(header, b.eth.blockchain, nil)
return vm.NewEVM(context, txContext, state, b.eth.chainConfig, vm.Config{}), state.Error, nil
} }
func (b *LesApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { func (b *LesApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {

@ -130,8 +130,9 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false)} msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false)}
context := core.NewEVMContext(msg, header, bc, nil) context := core.NewEVMBlockContext(header, bc, nil)
vmenv := vm.NewEVM(context, statedb, config, vm.Config{}) txContext := core.NewEVMTxContext(msg)
vmenv := vm.NewEVM(context, txContext, statedb, config, vm.Config{})
//vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{}) //vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{})
gp := new(core.GasPool).AddGas(math.MaxUint64) gp := new(core.GasPool).AddGas(math.MaxUint64)
@ -143,8 +144,9 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
state := light.NewState(ctx, header, lc.Odr()) state := light.NewState(ctx, header, lc.Odr())
state.SetBalance(bankAddr, math.MaxBig256) state.SetBalance(bankAddr, math.MaxBig256)
msg := callmsg{types.NewMessage(bankAddr, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false)} msg := callmsg{types.NewMessage(bankAddr, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false)}
context := core.NewEVMContext(msg, header, lc, nil) context := core.NewEVMBlockContext(header, lc, nil)
vmenv := vm.NewEVM(context, state, config, vm.Config{}) txContext := core.NewEVMTxContext(msg)
vmenv := vm.NewEVM(context, txContext, state, config, vm.Config{})
gp := new(core.GasPool).AddGas(math.MaxUint64) gp := new(core.GasPool).AddGas(math.MaxUint64)
result, _ := core.ApplyMessage(vmenv, msg, gp) result, _ := core.ApplyMessage(vmenv, msg, gp)
if state.Error() == nil { if state.Error() == nil {

@ -195,8 +195,9 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
// Perform read-only call. // Perform read-only call.
st.SetBalance(testBankAddress, math.MaxBig256) st.SetBalance(testBankAddress, math.MaxBig256)
msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), data, false)} msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), data, false)}
context := core.NewEVMContext(msg, header, chain, nil) txContext := core.NewEVMTxContext(msg)
vmenv := vm.NewEVM(context, st, config, vm.Config{}) context := core.NewEVMBlockContext(header, chain, nil)
vmenv := vm.NewEVM(context, txContext, st, config, vm.Config{})
gp := new(core.GasPool).AddGas(math.MaxUint64) gp := new(core.GasPool).AddGas(math.MaxUint64)
result, _ := core.ApplyMessage(vmenv, msg, gp) result, _ := core.ApplyMessage(vmenv, msg, gp)
res = append(res, result.Return()...) res = append(res, result.Return()...)

@ -182,9 +182,10 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
if err != nil { if err != nil {
return nil, nil, common.Hash{}, err return nil, nil, common.Hash{}, err
} }
context := core.NewEVMContext(msg, block.Header(), nil, &t.json.Env.Coinbase) txContext := core.NewEVMTxContext(msg)
context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase)
context.GetHash = vmTestBlockHash context.GetHash = vmTestBlockHash
evm := vm.NewEVM(context, statedb, config, vmconfig) evm := vm.NewEVM(context, txContext, statedb, config, vmconfig)
if config.IsYoloV2(context.BlockNumber) { if config.IsYoloV2(context.BlockNumber) {
statedb.AddAddressToAccessList(msg.From()) statedb.AddAddressToAccessList(msg.From())

@ -138,20 +138,22 @@ func (t *VMTest) newEVM(statedb *state.StateDB, vmconfig vm.Config) *vm.EVM {
return core.CanTransfer(db, address, amount) return core.CanTransfer(db, address, amount)
} }
transfer := func(db vm.StateDB, sender, recipient common.Address, amount *big.Int) {} transfer := func(db vm.StateDB, sender, recipient common.Address, amount *big.Int) {}
context := vm.Context{ txContext := vm.TxContext{
Origin: t.json.Exec.Origin,
GasPrice: t.json.Exec.GasPrice,
}
context := vm.BlockContext{
CanTransfer: canTransfer, CanTransfer: canTransfer,
Transfer: transfer, Transfer: transfer,
GetHash: vmTestBlockHash, GetHash: vmTestBlockHash,
Origin: t.json.Exec.Origin,
Coinbase: t.json.Env.Coinbase, Coinbase: t.json.Env.Coinbase,
BlockNumber: new(big.Int).SetUint64(t.json.Env.Number), BlockNumber: new(big.Int).SetUint64(t.json.Env.Number),
Time: new(big.Int).SetUint64(t.json.Env.Timestamp), Time: new(big.Int).SetUint64(t.json.Env.Timestamp),
GasLimit: t.json.Env.GasLimit, GasLimit: t.json.Env.GasLimit,
Difficulty: t.json.Env.Difficulty, Difficulty: t.json.Env.Difficulty,
GasPrice: t.json.Exec.GasPrice,
} }
vmconfig.NoRecursion = true vmconfig.NoRecursion = true
return vm.NewEVM(context, statedb, params.MainnetChainConfig, vmconfig) return vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vmconfig)
} }
func vmTestBlockHash(n uint64) common.Hash { func vmTestBlockHash(n uint64) common.Hash {

Loading…
Cancel
Save