diff --git a/core/state_transition.go b/core/state_transition.go index b6925f258ad3..2b8e6d9ee9d2 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -381,7 +381,6 @@ func (st *StateTransition) TransitionDb(owner common.Address) (*ExecutionResult, var ( msg = st.msg - sender = vm.AccountRef(st.from()) rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber) contractCreation = msg.To == nil ) @@ -423,7 +422,7 @@ func (st *StateTransition) TransitionDb(owner common.Address) (*ExecutionResult, vmerr error // vm errors do not effect consensus and are therefore not assigned to err ) if contractCreation { - ret, _, st.gasRemaining, vmerr = st.evm.Create(sender, msg.Data, st.gasRemaining, value) + ret, _, st.gasRemaining, vmerr = st.evm.Create(msg.From, msg.Data, st.gasRemaining, value) } else { // Increment the nonce for the next transaction st.state.SetNonce(msg.From, st.state.GetNonce(msg.From)+1) @@ -446,7 +445,7 @@ func (st *StateTransition) TransitionDb(owner common.Address) (*ExecutionResult, } // Execute the transaction's call. - ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, value) + ret, st.gasRemaining, vmerr = st.evm.Call(msg.From, st.to(), msg.Data, st.gasRemaining, value) } if !rules.IsEIP1559 { diff --git a/core/vm/contract.go b/core/vm/contract.go index ee8ae604966e..410f116e3594 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -22,40 +22,21 @@ import ( "github.com/holiman/uint256" ) -// ContractRef is a reference to the contract's backing object -type ContractRef interface { - Address() common.Address -} - -// AccountRef implements ContractRef. -// -// Account references are used during EVM initialisation and -// its primary use is to fetch addresses. Removing this object -// proves difficult because of the cached jump destinations which -// are fetched from the parent contract (i.e. the caller), which -// is a ContractRef. -type AccountRef common.Address - -// Address casts AccountRef to an Address -func (ar AccountRef) Address() common.Address { return (common.Address)(ar) } - // Contract represents an ethereum contract in the state database. It contains // the contract code, calling arguments. Contract stores the caller and // contract address directly. type Contract struct { - // CallerAddress is the result of the caller which initialised this - // contract. However when the "call method" is delegated this value - // needs to be initialised to that of the caller's caller. - CallerAddress common.Address - caller ContractRef - self ContractRef + // caller is the result of the caller which initialised this + // contract. However, when the "call method" is delegated this + // value needs to be initialised to that of the caller's caller. + caller common.Address + address common.Address jumpdests map[common.Hash]bitvec // Aggregated result of JUMPDEST analysis. analysis bitvec // Locally cached result of JUMPDEST analysis Code []byte CodeHash common.Hash - CodeAddr *common.Address Input []byte Gas uint64 @@ -63,23 +44,18 @@ type Contract struct { } // NewContract returns a new contract environment for the execution of EVM. -func NewContract(caller ContractRef, object ContractRef, value *uint256.Int, gas uint64) *Contract { - c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object} - - if parent, ok := caller.(*Contract); ok { - // Reuse JUMPDEST analysis from parent context if available. - c.jumpdests = parent.jumpdests - } else { - c.jumpdests = make(map[common.Hash]bitvec) +func NewContract(caller common.Address, address common.Address, value *uint256.Int, gas uint64, jumpDests map[common.Hash]bitvec) *Contract { + // Initialize the jump analysis map if it's nil, mostly for tests + if jumpDests == nil { + jumpDests = make(map[common.Hash]bitvec) + } + return &Contract{ + caller: caller, + address: address, + jumpdests: jumpDests, + Gas: gas, + value: value, } - - // Gas should be a pointer so it can safely be reduced through the run - // This pointer will be off the state transition - c.Gas = gas - // ensures a value is set - c.value = value - - return c } func (c *Contract) validJumpdest(dest *uint256.Int) bool { @@ -129,18 +105,6 @@ func (c *Contract) isCode(udest uint64) bool { return c.analysis.codeSegment(udest) } -// AsDelegate sets the contract to be a delegate call and returns the current -// contract (for chaining calls) -func (c *Contract) AsDelegate() *Contract { - // NOTE: caller must, at all times be a contract. It should never happen - // that caller is something other than a Contract. - parent := c.caller.(*Contract) - c.CallerAddress = parent.CallerAddress - c.value = parent.value - - return c -} - // GetOp returns the n'th element in the contract's byte array func (c *Contract) GetOp(n uint64) OpCode { if n < uint64(len(c.Code)) { @@ -155,7 +119,7 @@ func (c *Contract) GetOp(n uint64) OpCode { // Caller will recursively call caller when the contract is a delegate // call, including that of caller's caller. func (c *Contract) Caller() common.Address { - return c.CallerAddress + return c.caller } // UseGas attempts the use gas and subtracts it and returns true on success @@ -183,7 +147,7 @@ func (c *Contract) RefundGas(gas uint64, logger *tracing.Hooks, reason tracing.G // Address returns the contracts address func (c *Contract) Address() common.Address { - return c.self.Address() + return c.address } // Value returns the contract's value (sent to it from it's caller) @@ -193,16 +157,7 @@ func (c *Contract) Value() *uint256.Int { // SetCallCode sets the code of the contract and address of the backing data // object -func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) { +func (c *Contract) SetCallCode(hash common.Hash, code []byte) { c.Code = code c.CodeHash = hash - c.CodeAddr = addr -} - -// SetCodeOptionalHash can be used to provide code, but it's optional to provide hash. -// In case hash is not provided, the jumpdest analysis will not be saved to the parent context -func (c *Contract) SetCodeOptionalHash(addr *common.Address, codeAndHash *codeAndHash) { - c.Code = codeAndHash.code - c.CodeHash = codeAndHash.hash - c.CodeAddr = addr } diff --git a/core/vm/evm.go b/core/vm/evm.go index 47429396f593..08fc43503454 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -89,6 +89,7 @@ type EVM struct { // BlockContext provides auxiliary blockchain related information Context BlockContext TxContext + // StateDB gives access to the underlying state StateDB StateDB @@ -97,15 +98,16 @@ type EVM struct { // table holds the opcode specific handlers table *JumpTable - // Depth is the current call stack + // depth is the current call stack depth int // chainConfig contains information about the current chain chainConfig *params.ChainConfig + // chain rules contains the chain rules for the current epoch chainRules params.Rules - // virtual machine configuration options used to initialise the - // evm. + + // virtual machine configuration options used to initialise the evm Config Config // abort is used to abort the EVM calling operations @@ -119,6 +121,10 @@ type EVM struct { // precompiles holds the precompiled contracts for the current epoch precompiles map[common.Address]PrecompiledContract + // jumpDests is the aggregated result of JUMPDEST analysis made through + // the life cycle of EVM. + jumpDests map[common.Hash]bitvec + hasher crypto.KeccakState // Keccak256 hasher instance shared across opcodes hasherBuf common.Hash // Keccak256 hasher result array shared across opcodes @@ -137,6 +143,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, tradingStat Config: config, chainConfig: chainConfig, chainRules: chainConfig.Rules(blockCtx.BlockNumber), + jumpDests: make(map[common.Hash]bitvec), hasher: crypto.NewKeccakState(), } evm.precompiles = activePrecompiledContracts(evm.chainRules) @@ -218,10 +225,10 @@ func (evm *EVM) Cancelled() bool { // parameters. It also handles any necessary value transfer required and takes // the necessary steps to create accounts and reverses the state in case of an // execution error or failed value transfer. -func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) { +func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) { // Capture the tracer start/end events in debug mode if evm.Config.Tracer != nil { - evm.captureBegin(evm.depth, CALL, caller.Address(), addr, input, gas, value.ToBig()) + evm.captureBegin(evm.depth, CALL, caller, addr, input, gas, value.ToBig()) defer func(startGas uint64) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) @@ -231,7 +238,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 value.Sign() != 0 && !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { + if value.Sign() != 0 && !evm.Context.CanTransfer(evm.StateDB, caller, value) { return nil, gas, ErrInsufficientBalance } snapshot := evm.StateDB.Snapshot() @@ -244,22 +251,19 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } evm.StateDB.CreateAccount(addr) } - evm.Context.Transfer(evm.StateDB, caller.Address(), addr, value) + evm.Context.Transfer(evm.StateDB, caller, addr, value) if isPrecompile { ret, gas, err = RunPrecompiledContract(evm, p, input, gas, evm.Config.Tracer) } else { // 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. code := evm.resolveCode(addr) if len(code) == 0 { ret, err = nil, nil // gas is unchanged } else { - addrCopy := addr - // If the account has no code, we can abort here - // The depth-check is already done, and precompiles handled above - contract := NewContract(caller, AccountRef(addrCopy), value, gas) - contract.SetCallCode(&addrCopy, evm.resolveCodeHash(addrCopy), code) + // The contract is a scoped environment for this execution context only. + contract := NewContract(caller, addr, value, gas, evm.jumpDests) + contract.SetCallCode(evm.resolveCodeHash(addr), code) ret, err = evm.Run(contract, input, false) gas = contract.Gas } @@ -290,10 +294,10 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // // CallCode differs from Call in the sense that it executes the given address' // code with the caller as context. -func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) { +func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) { // Invoke tracer hooks that signal entering/exiting a call frame if evm.Config.Tracer != nil { - evm.captureBegin(evm.depth, CALLCODE, caller.Address(), addr, input, gas, value.ToBig()) + evm.captureBegin(evm.depth, CALLCODE, caller, addr, input, gas, value.ToBig()) defer func(startGas uint64) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) @@ -306,7 +310,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // Note although it's noop to transfer X ether to caller itself. But // if caller doesn't have enough balance, it would be an error to allow // over-charging itself. So the check here is necessary. - if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { + if !evm.Context.CanTransfer(evm.StateDB, caller, value) { return nil, gas, ErrInsufficientBalance } var snapshot = evm.StateDB.Snapshot() @@ -315,11 +319,10 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, if p, isPrecompile := evm.precompile(addr); isPrecompile { ret, gas, err = RunPrecompiledContract(evm, p, input, gas, evm.Config.Tracer) } else { - addrCopy := addr // 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, AccountRef(caller.Address()), value, gas) - contract.SetCallCode(&addrCopy, evm.resolveCodeHash(addrCopy), evm.resolveCode(addrCopy)) + contract := NewContract(caller, caller, value, gas, evm.jumpDests) + contract.SetCallCode(evm.resolveCodeHash(addr), evm.resolveCode(addr)) ret, err = evm.Run(contract, input, false) gas = contract.Gas } @@ -341,14 +344,11 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // // DelegateCall differs from CallCode in the sense that it executes the given address' // code with the caller as context and the caller is set to the caller of the caller. -func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { +func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) { // Invoke tracer hooks that signal entering/exiting a call frame if evm.Config.Tracer != nil { - // NOTE: caller must, at all times be a contract. It should never happen - // that caller is something other than a Contract. - parent := caller.(*Contract) // DELEGATECALL inherits value from parent call - evm.captureBegin(evm.depth, DELEGATECALL, caller.Address(), addr, input, gas, parent.value.ToBig()) + evm.captureBegin(evm.depth, DELEGATECALL, caller, addr, input, gas, value.ToBig()) defer func(startGas uint64) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) @@ -363,10 +363,11 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by if p, isPrecompile := evm.precompile(addr); isPrecompile { ret, gas, err = RunPrecompiledContract(evm, p, input, gas, evm.Config.Tracer) } else { - addrCopy := addr // Initialise a new contract and make initialise the delegate values - contract := NewContract(caller, AccountRef(caller.Address()), nil, gas).AsDelegate() - contract.SetCallCode(&addrCopy, evm.resolveCodeHash(addrCopy), evm.resolveCode(addrCopy)) + // + // Note: The value refers to the original value from the parent call. + contract := NewContract(originCaller, caller, value, gas, evm.jumpDests) + contract.SetCallCode(evm.resolveCodeHash(addr), evm.resolveCode(addr)) ret, err = evm.Run(contract, input, false) gas = contract.Gas } @@ -386,10 +387,10 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by // as parameters while disallowing any modifications to the state during the call. // Opcodes that attempt to perform such modifications will result in exceptions // instead of performing the modifications. -func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { +func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { // Invoke tracer hooks that signal entering/exiting a call frame if evm.Config.Tracer != nil { - evm.captureBegin(evm.depth, STATICCALL, caller.Address(), addr, input, gas, nil) + evm.captureBegin(evm.depth, STATICCALL, caller, addr, input, gas, nil) defer func(startGas uint64) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) @@ -416,14 +417,10 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte if p, isPrecompile := evm.precompile(addr); isPrecompile { ret, gas, err = RunPrecompiledContract(evm, p, input, gas, evm.Config.Tracer) } else { - // At this point, we use a copy of address. If we don't, the go compiler will - // leak the 'contract' to the outer scope, and make allocation for 'contract' - // even if the actual execution ends on RunPrecompiled above. - addrCopy := addr // 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, AccountRef(addrCopy), new(uint256.Int), gas) - contract.SetCallCode(&addrCopy, evm.resolveCodeHash(addrCopy), evm.resolveCode(addrCopy)) + contract := NewContract(caller, addr, new(uint256.Int), gas, evm.jumpDests) + contract.SetCallCode(evm.resolveCodeHash(addr), evm.resolveCode(addr)) // 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. @@ -444,22 +441,10 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte return ret, gas, err } -type codeAndHash struct { - code []byte - hash common.Hash -} - -func (c *codeAndHash) Hash() common.Hash { - if c.hash == (common.Hash{}) { - c.hash = crypto.Keccak256Hash(c.code) - } - return c.hash -} - // create creates a new contract using code as deployment code. -func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *uint256.Int, address common.Address, typ OpCode) (ret []byte, createAddress common.Address, leftOverGas uint64, err error) { +func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *uint256.Int, address common.Address, typ OpCode) (ret []byte, createAddress common.Address, leftOverGas uint64, err error) { if evm.Config.Tracer != nil { - evm.captureBegin(evm.depth, typ, caller.Address(), address, codeAndHash.code, gas, value.ToBig()) + evm.captureBegin(evm.depth, typ, caller, address, code, gas, value.ToBig()) defer func(startGas uint64) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) @@ -469,14 +454,14 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, if evm.depth > int(params.CallCreateDepth) { return nil, common.Address{}, gas, ErrDepth } - if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { + if !evm.Context.CanTransfer(evm.StateDB, caller, value) { return nil, common.Address{}, gas, ErrInsufficientBalance } - nonce := evm.StateDB.GetNonce(caller.Address()) + nonce := evm.StateDB.GetNonce(caller) if nonce+1 < nonce { return nil, common.Address{}, gas, ErrNonceUintOverflow } - evm.StateDB.SetNonce(caller.Address(), nonce+1) + evm.StateDB.SetNonce(caller, nonce+1) // We add this to the access list _before_ taking a snapshot. Even if the creation fails, // the access-list change should not be rolled back if evm.chainRules.IsEIP1559 { @@ -503,12 +488,15 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, if evm.chainRules.IsEIP158 { evm.StateDB.SetNonce(address, 1) } - evm.Context.Transfer(evm.StateDB, caller.Address(), address, value) + evm.Context.Transfer(evm.StateDB, caller, 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, AccountRef(address), value, gas) - contract.SetCodeOptionalHash(&address, codeAndHash) + contract := NewContract(caller, address, value, gas, evm.jumpDests) + + // Explicitly set the code to a null hash to prevent caching of jump analysis + // for the initialization code. + contract.SetCallCode(common.Hash{}, code) ret, err = evm.initNewContract(contract, address) if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) { @@ -551,19 +539,18 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]b } // Create creates a new contract using code as deployment code. -func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { - contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address())) - return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr, CREATE) +func (evm *EVM) Create(caller common.Address, code []byte, gas uint64, value *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { + contractAddr = crypto.CreateAddress(caller, evm.StateDB.GetNonce(caller)) + return evm.create(caller, code, gas, value, contractAddr, CREATE) } // Create2 creates a new contract using code as deployment code. // // The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:] // instead of the usual sender-and-nonce-hash as the address where the contract is initialized at. -func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { - codeAndHash := &codeAndHash{code: code} - contractAddr = crypto.CreateAddress2(caller.Address(), salt.Bytes32(), codeAndHash.Hash().Bytes()) - return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2) +func (evm *EVM) Create2(caller common.Address, code []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { + contractAddr = crypto.CreateAddress2(caller, salt.Bytes32(), crypto.Keccak256(code)) + return evm.create(caller, code, gas, endowment, contractAddr, CREATE2) } // resolveCode returns the code associated with the provided account. After diff --git a/core/vm/gas_table_test.go b/core/vm/gas_table_test.go index e48b704ad583..becf0822872b 100644 --- a/core/vm/gas_table_test.go +++ b/core/vm/gas_table_test.go @@ -98,7 +98,7 @@ func TestEIP2200(t *testing.T) { } vmenv := NewEVM(vmctx, TxContext{}, statedb, nil, params.AllEthashProtocolChanges, Config{ExtraEips: []int{2200}}) - _, gas, err := vmenv.Call(AccountRef(common.Address{}), address, nil, tt.gaspool, new(uint256.Int)) + _, gas, err := vmenv.Call(common.Address{}, address, nil, tt.gaspool, new(uint256.Int)) if !errors.Is(err, tt.failure) { t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure) } @@ -153,7 +153,7 @@ func TestCreateGas(t *testing.T) { vmenv := NewEVM(vmctx, TxContext{}, statedb, nil, params.AllEthashProtocolChanges, config) var startGas = uint64(testGas) - ret, gas, err := vmenv.Call(AccountRef(common.Address{}), address, nil, startGas, new(uint256.Int)) + ret, gas, err := vmenv.Call(common.Address{}, address, nil, startGas, new(uint256.Int)) if err != nil { return false } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index b55b26557a40..ef12a444af08 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -677,7 +677,7 @@ func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Contract.UseGas(gas, evm.Config.Tracer, tracing.GasChangeCallContractCreation) - res, addr, returnGas, suberr := evm.Create(scope.Contract, input, gas, &value) + res, addr, returnGas, suberr := evm.Create(scope.Contract.Address(), input, gas, &value) // Push item on the stack based on the returned error. If the ruleset is // homestead we must check for CodeStoreOutOfGasError (homestead only // rule) and treat as an error, if the ruleset is frontier we must @@ -717,7 +717,7 @@ func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Contract.UseGas(gas, evm.Config.Tracer, tracing.GasChangeCallContractCreation2) // reuse size int for stackvalue stackvalue := size - res, addr, returnGas, suberr := evm.Create2(scope.Contract, input, gas, + res, addr, returnGas, suberr := evm.Create2(scope.Contract.Address(), input, gas, &endowment, &salt) // Push item on the stack based on the returned error. if suberr != nil { @@ -755,7 +755,7 @@ func opCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { if !value.IsZero() { gas += params.CallStipend } - ret, returnGas, err := evm.Call(scope.Contract, toAddr, args, gas, &value) + ret, returnGas, err := evm.Call(scope.Contract.Address(), toAddr, args, gas, &value) if err != nil { temp.Clear() @@ -789,7 +789,7 @@ func opCallCode(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { gas += params.CallStipend } - ret, returnGas, err := evm.CallCode(scope.Contract, toAddr, args, gas, &value) + ret, returnGas, err := evm.CallCode(scope.Contract.Address(), toAddr, args, gas, &value) if err != nil { temp.Clear() } else { @@ -818,7 +818,7 @@ func opDelegateCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { // Get arguments from the memory. args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) - ret, returnGas, err := evm.DelegateCall(scope.Contract, toAddr, args, gas) + ret, returnGas, err := evm.DelegateCall(scope.Contract.Caller(), scope.Contract.Address(), toAddr, args, gas, scope.Contract.value) if err != nil { temp.Clear() } else { @@ -847,7 +847,7 @@ func opStaticCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { // Get arguments from the memory. args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) - ret, returnGas, err := evm.StaticCall(scope.Contract, toAddr, args, gas) + ret, returnGas, err := evm.StaticCall(scope.Contract.Address(), toAddr, args, gas) if err != nil { temp.Clear() } else { diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index 04234ab88aa5..18bb33338405 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -51,14 +51,6 @@ var alphabetSoup = "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffff var commonParams []*twoOperandParams var twoOpMethods map[string]executionFunc -type contractRef struct { - addr common.Address -} - -func (c contractRef) Address() common.Address { - return c.addr -} - func init() { // Params is a list of common edgecases that should be used for some common tests params := []string{ @@ -583,8 +575,7 @@ func TestOpTstore(t *testing.T) { mem = NewMemory() caller = common.Address{} to = common.Address{1} - contractRef = contractRef{caller} - contract = NewContract(contractRef, AccountRef(to), new(uint256.Int), 0) + contract = NewContract(caller, to, new(uint256.Int), 0, nil) scopeContext = ScopeContext{mem, stack, contract} value = common.Hex2Bytes("abcdef00000000000000abba000000000deaf000000c0de00100000000133700") ) diff --git a/core/vm/interface.go b/core/vm/interface.go index 65d268f2fb03..bdb55efe021e 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -108,16 +108,3 @@ type StateDB interface { IncrementMintedRecordNonce() } - -// CallContext provides a basic interface for the EVM calling conventions. The EVM -// depends on this context being implemented for doing subcalls and initialising new EVM contracts. -type CallContext interface { - // Call calls another contract. - Call(env *EVM, me ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) - // CallCode takes another contracts code and execute within our own context - CallCode(env *EVM, me ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) - // DelegateCall is same as CallCode except sender and value is propagated from parent to child scope - DelegateCall(env *EVM, me ContractRef, addr common.Address, data []byte, gas *big.Int) ([]byte, error) - // Create creates a new contract - Create(env *EVM, me ContractRef, data []byte, gas, value *big.Int) ([]byte, common.Address, error) -} diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 8c091cbf18b7..f21ef9552942 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -117,7 +117,6 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { var ( address = common.BytesToAddress([]byte("contract")) vmenv = NewEnv(cfg) - sender = vm.AccountRef(cfg.Origin) rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber) ) if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil { @@ -133,7 +132,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { cfg.State.SetCode(address, code) // Call the code with the given configuration. ret, _, err := vmenv.Call( - sender, + cfg.Origin, common.BytesToAddress([]byte("contract")), input, cfg.GasLimit, @@ -154,9 +153,8 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabase(db)) } var ( - vmenv = NewEnv(cfg) - sender = vm.AccountRef(cfg.Origin) - rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber) + vmenv = NewEnv(cfg) + rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber) ) if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil { cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) @@ -168,7 +166,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { // Call the code with the given configuration. code, address, leftOverGas, err := vmenv.Create( - sender, + cfg.Origin, input, cfg.GasLimit, uint256.MustFromBig(cfg.Value), @@ -186,7 +184,6 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er var ( vmenv = NewEnv(cfg) - sender = cfg.State.GetOrNewStateObject(cfg.Origin) statedb = cfg.State rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber) ) @@ -200,7 +197,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er // Call the code with the given configuration. ret, leftOverGas, err := vmenv.Call( - sender, + cfg.Origin, address, input, cfg.GasLimit, diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 9cf524fec620..2d35f8282697 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -33,19 +33,6 @@ import ( "github.com/holiman/uint256" ) -type account struct{} - -func (account) SubBalance(amount *big.Int) {} -func (account) AddBalance(amount *big.Int) {} -func (account) SetAddress(common.Address) {} -func (account) Value() *big.Int { return nil } -func (account) SetBalance(*big.Int) {} -func (account) SetNonce(uint64) {} -func (account) Balance() *big.Int { return nil } -func (account) Address() common.Address { return common.Address{} } -func (account) SetCode(common.Hash, []byte) {} -func (account) ForEachStorage(cb func(key, value common.Hash) bool) {} - type dummyStatedb struct { state.StateDB } @@ -68,7 +55,7 @@ func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCo gasLimit uint64 = 31000 startGas uint64 = 10000 value = new(uint256.Int) - contract = vm.NewContract(account{}, account{}, value, startGas) + contract = vm.NewContract(common.Address{}, common.Address{}, value, startGas, nil) ) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0} if contractCode != nil { @@ -189,7 +176,7 @@ func TestHaltBetweenSteps(t *testing.T) { t.Fatal(err) } scope := &vm.ScopeContext{ - Contract: vm.NewContract(&account{}, &account{}, new(uint256.Int), 0), + Contract: vm.NewContract(common.Address{}, common.Address{}, new(uint256.Int), 0, nil), } env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, nil, chainConfig, vm.Config{Tracer: tracer.Hooks}) tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{}) @@ -302,7 +289,7 @@ func TestEnterExit(t *testing.T) { t.Fatal(err) } scope := &vm.ScopeContext{ - Contract: vm.NewContract(&account{}, &account{}, new(uint256.Int), 0), + Contract: vm.NewContract(common.Address{}, common.Address{}, new(uint256.Int), 0, nil), } tracer.OnEnter(1, byte(vm.CALL), scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int)) tracer.OnExit(1, []byte{}, 400, nil, false) diff --git a/eth/tracers/logger/logger_test.go b/eth/tracers/logger/logger_test.go index 77c67b415703..5b2c75e60627 100644 --- a/eth/tracers/logger/logger_test.go +++ b/eth/tracers/logger/logger_test.go @@ -29,22 +29,6 @@ import ( "github.com/holiman/uint256" ) -type dummyContractRef struct { - calledForEach bool -} - -func (dummyContractRef) Address() common.Address { return common.Address{} } -func (dummyContractRef) Value() *big.Int { return new(big.Int) } -func (dummyContractRef) SetCode(common.Hash, []byte) {} -func (d *dummyContractRef) ForEachStorage(callback func(key, value common.Hash) bool) { - d.calledForEach = true -} -func (d *dummyContractRef) SubBalance(amount *big.Int) {} -func (d *dummyContractRef) AddBalance(amount *big.Int) {} -func (d *dummyContractRef) SetBalance(*big.Int) {} -func (d *dummyContractRef) SetNonce(uint64) {} -func (d *dummyContractRef) Balance() *big.Int { return new(big.Int) } - type dummyStatedb struct { state.StateDB } @@ -59,7 +43,7 @@ func TestStoreCapture(t *testing.T) { var ( logger = NewStructLogger(nil) evm = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, nil, params.TestChainConfig, vm.Config{Tracer: logger.Hooks()}) - contract = vm.NewContract(&dummyContractRef{}, &dummyContractRef{}, new(uint256.Int), 100000) + contract = vm.NewContract(common.Address{}, common.Address{}, new(uint256.Int), 100000, nil) ) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)} var index common.Hash diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go index 181a4a49863b..2209fb5629d5 100644 --- a/tests/vm_test_util.go +++ b/tests/vm_test_util.go @@ -121,7 +121,7 @@ func (t *VMTest) Run(vmconfig vm.Config) error { func (t *VMTest) exec(statedb *state.StateDB, vmconfig vm.Config) ([]byte, uint64, error) { evm := t.newEVM(statedb, vmconfig) e := t.json.Exec - return evm.Call(vm.AccountRef(e.Caller), e.Address, e.Data, e.GasLimit, uint256.MustFromBig(e.Value)) + return evm.Call(e.Caller, e.Address, e.Data, e.GasLimit, uint256.MustFromBig(e.Value)) } func (t *VMTest) newEVM(statedb *state.StateDB, vmconfig vm.Config) *vm.EVM {