Skip to content

Commit 0939d88

Browse files
facs95GAtom22
authored andcommitted
feat(evm): OpCodesHooks for CREATE and CALL opcodes (ethereum#28)
Co-authored-by: Tom <54514587+GAtom22@users.noreply.github.com>
1 parent 1d2e117 commit 0939d88

File tree

2 files changed

+78
-33
lines changed

2 files changed

+78
-33
lines changed

core/vm/evm.go

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,10 @@ type EVM struct {
9595
// activePrecompiles defines the precompiles that are currently active
9696
activePrecompiles []common.Address
9797

98-
// preExecuteCallback is a callback function that is called before executing
99-
// CALL, CALLCODE, DELEGATECALL and STATICCALL opcodes.
100-
preExecuteCallback preExecuteCallbackType
101-
}
102-
103-
type preExecuteCallbackType func(evm *EVM, addr common.Address) error
104-
105-
func dummyCallback(evm *EVM, addr common.Address) error {
106-
return nil
98+
// hooks is a set of functions that can be used to intercept and modify the
99+
// behavior of the EVM when executing certain opcodes.
100+
// The hooks are called before the execution of the respective opcodes.
101+
hooks OpCodeHooks
107102
}
108103

109104
// NewEVM returns a new EVM. The returned EVM is not thread safe and should
@@ -121,13 +116,13 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig
121116
}
122117
}
123118
evm := &EVM{
124-
Context: blockCtx,
125-
TxContext: txCtx,
126-
StateDB: statedb,
127-
Config: config,
128-
chainConfig: chainConfig,
129-
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time),
130-
preExecuteCallback: dummyCallback,
119+
Context: blockCtx,
120+
TxContext: txCtx,
121+
StateDB: statedb,
122+
Config: config,
123+
chainConfig: chainConfig,
124+
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time),
125+
hooks: newNoopOpCodeHooks(),
131126
}
132127
// set the default precompiles
133128
evm.activePrecompiles = DefaultActivePrecompiles(evm.chainRules)
@@ -137,17 +132,17 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig
137132
return evm
138133
}
139134

140-
// NewEVMWithCallback returns a new EVM and takes a custom preExecuteCallback. The returned EVM is
135+
// NewEVMWithHooks returns a new EVM and takes a custom OpCodeHooks. The returned EVM is
141136
// not thread safe and should only ever be used *once*.
142-
func NewEVMWithCallback(callback preExecuteCallbackType, blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM {
137+
func NewEVMWithHooks(hooks OpCodeHooks, blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM {
143138
evm := &EVM{
144-
Context: blockCtx,
145-
TxContext: txCtx,
146-
StateDB: statedb,
147-
Config: config,
148-
chainConfig: chainConfig,
149-
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time),
150-
preExecuteCallback: callback,
139+
Context: blockCtx,
140+
TxContext: txCtx,
141+
StateDB: statedb,
142+
Config: config,
143+
chainConfig: chainConfig,
144+
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time),
145+
hooks: hooks,
151146
}
152147
// set the default precompiles
153148
evm.activePrecompiles = DefaultActivePrecompiles(evm.chainRules)
@@ -190,8 +185,7 @@ func (evm *EVM) WithInterpreter(interpreter Interpreter) {
190185
// the necessary steps to create accounts and reverses the state in case of an
191186
// execution error or failed value transfer.
192187
func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) {
193-
err = evm.preExecuteCallback(evm, addr)
194-
if err != nil {
188+
if err = evm.hooks.CallHook(evm, caller.Address(), addr); err != nil {
195189
return nil, gas, err
196190
}
197191

@@ -284,8 +278,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
284278
// CallCode differs from Call in the sense that it executes the given address'
285279
// code with the caller as context.
286280
func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) {
287-
err = evm.preExecuteCallback(evm, addr)
288-
if err != nil {
281+
if err = evm.hooks.CallHook(evm, caller.Address(), addr); err != nil {
289282
return nil, gas, err
290283
}
291284

@@ -337,8 +330,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
337330
// DelegateCall differs from CallCode in the sense that it executes the given address'
338331
// code with the caller as context and the caller is set to the caller of the caller.
339332
func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
340-
err = evm.preExecuteCallback(evm, addr)
341-
if err != nil {
333+
if err = evm.hooks.CallHook(evm, caller.Address(), addr); err != nil {
342334
return nil, gas, err
343335
}
344336

@@ -385,8 +377,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
385377
// Opcodes that attempt to perform such modifications will result in exceptions
386378
// instead of performing the modifications.
387379
func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
388-
err = evm.preExecuteCallback(evm, addr)
389-
if err != nil {
380+
if err = evm.hooks.CallHook(evm, caller.Address(), addr); err != nil {
390381
return nil, gas, err
391382
}
392383

@@ -547,6 +538,9 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
547538

548539
// Create creates a new contract using code as deployment code.
549540
func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
541+
if err = evm.hooks.CreateHook(evm, caller.Address()); err != nil {
542+
return nil, common.Address{}, gas, err
543+
}
550544
contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address()))
551545
return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr, CREATE)
552546
}
@@ -556,6 +550,9 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *uint2
556550
// The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:]
557551
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
558552
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) {
553+
if err = evm.hooks.CreateHook(evm, caller.Address()); err != nil {
554+
return nil, common.Address{}, gas, err
555+
}
559556
codeAndHash := &codeAndHash{code: code}
560557
contractAddr = crypto.CreateAddress2(caller.Address(), salt.Bytes32(), codeAndHash.Hash().Bytes())
561558
return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2)

core/vm/opcode_hooks.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright 2014 The go-ethereum Authors
2+
// This file is part of the go-ethereum library.
3+
//
4+
// The go-ethereum library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The go-ethereum library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package vm
18+
19+
import "github.com/ethereum/go-ethereum/common"
20+
21+
// OpCodeHooks is a set of hooks that can be used to intercept and modify the
22+
// behavior of the EVM when executing certain opcodes.
23+
// The hooks are called before the execution of the respective opcodes.
24+
type OpCodeHooks interface {
25+
// CallHook is called before executing a CALL, CALLCODE, DELEGATECALL and STATICCALL opcodes.
26+
CallHook(evm *EVM, caller common.Address, recipient common.Address) error
27+
// CreateHook is called before executing a CREATE and CREATE2 opcodes.
28+
CreateHook(evm *EVM, caller common.Address) error
29+
}
30+
31+
type NoopOpCodeHooks struct {
32+
}
33+
34+
func (NoopOpCodeHooks) CallHook(evm *EVM, caller common.Address, recipient common.Address) error {
35+
return nil
36+
}
37+
38+
func (NoopOpCodeHooks) CreateHook(evm *EVM, caller common.Address) error {
39+
return nil
40+
}
41+
42+
func newNoopOpCodeHooks() OpCodeHooks {
43+
return NoopOpCodeHooks{}
44+
}
45+
46+
func NewDefaultOpCodeHooks() OpCodeHooks {
47+
return newNoopOpCodeHooks()
48+
}

0 commit comments

Comments
 (0)