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
This commit is contained in:
committed by
GitHub
parent
6f4cccf8d2
commit
2045a2bba3
@ -91,9 +91,9 @@ func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, err
|
||||
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.
|
||||
type Context struct {
|
||||
type BlockContext struct {
|
||||
// CanTransfer returns whether the account contains
|
||||
// sufficient ether to transfer the value
|
||||
CanTransfer CanTransferFunc
|
||||
@ -102,10 +102,6 @@ type Context struct {
|
||||
// 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
|
||||
@ -114,6 +110,14 @@ type Context struct {
|
||||
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
|
||||
// the necessary tools to run a contract on the given state with
|
||||
// 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.
|
||||
type EVM struct {
|
||||
// Context provides auxiliary blockchain related information
|
||||
Context
|
||||
Context BlockContext
|
||||
TxContext
|
||||
// StateDB gives access to the underlying state
|
||||
StateDB StateDB
|
||||
// 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
|
||||
// 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{
|
||||
Context: ctx,
|
||||
Context: blockCtx,
|
||||
TxContext: txCtx,
|
||||
StateDB: statedb,
|
||||
vmConfig: vmConfig,
|
||||
chainConfig: chainConfig,
|
||||
chainRules: chainConfig.Rules(ctx.BlockNumber),
|
||||
chainRules: chainConfig.Rules(blockCtx.BlockNumber),
|
||||
interpreters: make([]Interpreter, 0, 1),
|
||||
}
|
||||
|
||||
if chainConfig.IsEWASM(ctx.BlockNumber) {
|
||||
if chainConfig.IsEWASM(blockCtx.BlockNumber) {
|
||||
// to be implemented by EVM-C and Wagon PRs.
|
||||
// if vmConfig.EWASMInterpreter != "" {
|
||||
// extIntOpts := strings.Split(vmConfig.EWASMInterpreter, ":")
|
||||
@ -187,6 +193,13 @@ func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmCon
|
||||
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
|
||||
// it's safe to be called multiple times.
|
||||
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.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
|
||||
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) {
|
||||
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
|
||||
}
|
||||
nonce := evm.StateDB.GetNonce(caller.Address())
|
||||
@ -447,7 +460,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||
if evm.chainRules.IsEIP158 {
|
||||
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.
|
||||
// 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.Finalise(true) // Push the state into the "original" slot
|
||||
|
||||
vmctx := Context{
|
||||
vmctx := BlockContext{
|
||||
CanTransfer: func(StateDB, common.Address, *big.Int) bool { return true },
|
||||
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))
|
||||
if err != tt.failure {
|
||||
|
@ -438,14 +438,14 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx)
|
||||
return nil, nil
|
||||
}
|
||||
var upper, lower uint64
|
||||
upper = interpreter.evm.BlockNumber.Uint64()
|
||||
upper = interpreter.evm.Context.BlockNumber.Uint64()
|
||||
if upper < 257 {
|
||||
lower = 0
|
||||
} else {
|
||||
lower = upper - 256
|
||||
}
|
||||
if num64 >= lower && num64 < upper {
|
||||
num.SetBytes(interpreter.evm.GetHash(num64).Bytes())
|
||||
num.SetBytes(interpreter.evm.Context.GetHash(num64).Bytes())
|
||||
} else {
|
||||
num.Clear()
|
||||
}
|
||||
@ -453,30 +453,30 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
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)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
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)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@ -842,7 +842,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.Context.BlockNumber.Uint64(),
|
||||
})
|
||||
|
||||
return nil, nil
|
||||
|
@ -92,7 +92,7 @@ func init() {
|
||||
func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFunc, name string) {
|
||||
|
||||
var (
|
||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
||||
env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{})
|
||||
stack = newstack()
|
||||
rstack = newReturnStack()
|
||||
pc = uint64(0)
|
||||
@ -192,7 +192,7 @@ func TestSAR(t *testing.T) {
|
||||
|
||||
func TestAddMod(t *testing.T) {
|
||||
var (
|
||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
||||
env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{})
|
||||
stack = newstack()
|
||||
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||
pc = uint64(0)
|
||||
@ -231,7 +231,7 @@ func TestAddMod(t *testing.T) {
|
||||
// getResult is a convenience function to generate the expected values
|
||||
func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase {
|
||||
var (
|
||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
||||
env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{})
|
||||
stack, rstack = newstack(), newReturnStack()
|
||||
pc = uint64(0)
|
||||
interpreter = env.interpreter.(*EVMInterpreter)
|
||||
@ -281,7 +281,7 @@ func TestJsonTestcases(t *testing.T) {
|
||||
|
||||
func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
|
||||
var (
|
||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
||||
env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{})
|
||||
stack, rstack = newstack(), newReturnStack()
|
||||
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||
)
|
||||
@ -515,7 +515,7 @@ func BenchmarkOpIsZero(b *testing.B) {
|
||||
|
||||
func TestOpMstore(t *testing.T) {
|
||||
var (
|
||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
||||
env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{})
|
||||
stack, rstack = newstack(), newReturnStack()
|
||||
mem = NewMemory()
|
||||
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||
@ -539,7 +539,7 @@ func TestOpMstore(t *testing.T) {
|
||||
|
||||
func BenchmarkOpMstore(bench *testing.B) {
|
||||
var (
|
||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
||||
env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{})
|
||||
stack, rstack = newstack(), newReturnStack()
|
||||
mem = NewMemory()
|
||||
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||
@ -560,7 +560,7 @@ func BenchmarkOpMstore(bench *testing.B) {
|
||||
|
||||
func BenchmarkOpSHA3(bench *testing.B) {
|
||||
var (
|
||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
||||
env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{})
|
||||
stack, rstack = newstack(), newReturnStack()
|
||||
mem = NewMemory()
|
||||
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||
|
@ -51,7 +51,7 @@ func (*dummyStatedb) GetRefund() uint64 { return 1337 }
|
||||
|
||||
func TestStoreCapture(t *testing.T) {
|
||||
var (
|
||||
env = NewEVM(Context{}, &dummyStatedb{}, params.TestChainConfig, Config{})
|
||||
env = NewEVM(BlockContext{}, TxContext{}, &dummyStatedb{}, params.TestChainConfig, Config{})
|
||||
logger = NewStructLogger(nil)
|
||||
mem = NewMemory()
|
||||
stack = newstack()
|
||||
|
@ -22,18 +22,20 @@ import (
|
||||
)
|
||||
|
||||
func NewEnv(cfg *Config) *vm.EVM {
|
||||
context := vm.Context{
|
||||
txContext := vm.TxContext{
|
||||
Origin: cfg.Origin,
|
||||
GasPrice: cfg.GasPrice,
|
||||
}
|
||||
blockContext := vm.BlockContext{
|
||||
CanTransfer: core.CanTransfer,
|
||||
Transfer: core.Transfer,
|
||||
GetHash: cfg.GetHashFn,
|
||||
Origin: cfg.Origin,
|
||||
Coinbase: cfg.Coinbase,
|
||||
BlockNumber: cfg.BlockNumber,
|
||||
Time: cfg.Time,
|
||||
Difficulty: cfg.Difficulty,
|
||||
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)
|
||||
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(address)
|
||||
for _, addr := range vmenv.ActivePrecompiles() {
|
||||
@ -150,7 +150,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
|
||||
vmenv = NewEnv(cfg)
|
||||
sender = vm.AccountRef(cfg.Origin)
|
||||
)
|
||||
if cfg.ChainConfig.IsYoloV2(vmenv.BlockNumber) {
|
||||
if cfg.ChainConfig.IsYoloV2(vmenv.Context.BlockNumber) {
|
||||
cfg.State.AddAddressToAccessList(cfg.Origin)
|
||||
for _, addr := range vmenv.ActivePrecompiles() {
|
||||
cfg.State.AddAddressToAccessList(addr)
|
||||
@ -178,7 +178,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er
|
||||
vmenv := NewEnv(cfg)
|
||||
|
||||
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(address)
|
||||
for _, addr := range vmenv.ActivePrecompiles() {
|
||||
|
Reference in New Issue
Block a user