Skip to content

Commit 754e68b

Browse files
mergify[bot]fedekunzefacs95
authored
imp(vm): Interpreter interface (backport ethereum#2) (ethereum#12)
Co-authored-by: Federico Kunze Küllmer <[email protected]> Co-authored-by: Freddy Caceres <[email protected]>
1 parent 485d066 commit 754e68b

File tree

5 files changed

+90
-21
lines changed

5 files changed

+90
-21
lines changed

CHANGELOG.md

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
2+
<!--
3+
Guiding Principles:
4+
5+
Changelogs are for humans, not machines.
6+
There should be an entry for every single version.
7+
The same types of changes should be grouped.
8+
Versions and sections should be linkable.
9+
The latest version comes first.
10+
The release date of each version is displayed.
11+
Mention whether you follow Semantic Versioning.
12+
13+
Usage:
14+
15+
Change log entries are to be added to the Unreleased section under the
16+
appropriate stanza (see below). Each entry should ideally include a tag and
17+
the Github issue reference in the following format:
18+
19+
* (<tag>) \#<issue-number> message
20+
21+
The issue numbers will later be link-ified during the release process so you do
22+
not have to worry about including a link manually, but you can if you wish.
23+
24+
Types of changes (Stanzas):
25+
26+
"Features" for new features.
27+
"Improvements" for changes in existing functionality.
28+
"Deprecated" for soon-to-be removed features.
29+
"Bug Fixes" for any bug fixes.
30+
"Client Breaking" for breaking CLI commands and REST routes used by end-users.
31+
"API Breaking" for breaking exported APIs used by developers building on SDK.
32+
"State Machine Breaking" for any changes that result in a different AppState given same genesisState and txList.
33+
34+
Ref: https://keepachangelog.com/en/1.0.0/
35+
-->
36+
37+
# Changelog
38+
39+
## Unreleased
40+
41+
### Improvements
42+
43+
* [#2](https://github.com/evmos/go-ethereum/pull/2) Define `Interpreter` interface for the EVM.

core/vm/evm.go

+11-5
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ type EVM struct {
113113
Config Config
114114
// global (to this context) ethereum virtual machine
115115
// used throughout the execution of the tx.
116-
interpreter *EVMInterpreter
116+
interpreter Interpreter
117117
// abort is used to abort the EVM calling operations
118118
// NOTE: must be set atomically
119119
abort int32
@@ -134,6 +134,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig
134134
chainConfig: chainConfig,
135135
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil),
136136
}
137+
137138
evm.interpreter = NewEVMInterpreter(evm, config)
138139
return evm
139140
}
@@ -157,10 +158,15 @@ func (evm *EVM) Cancelled() bool {
157158
}
158159

159160
// Interpreter returns the current interpreter
160-
func (evm *EVM) Interpreter() *EVMInterpreter {
161+
func (evm *EVM) Interpreter() Interpreter {
161162
return evm.interpreter
162163
}
163164

165+
// WithInterpreter sets the interpreter to the EVM instance
166+
func (evm *EVM) WithInterpreter(interpreter Interpreter) {
167+
evm.interpreter = interpreter
168+
}
169+
164170
// Call executes the contract associated with the addr with the given input as
165171
// parameters. It also handles any necessary value transfer required and takes
166172
// the necessary steps to create accounts and reverses the state in case of an
@@ -263,7 +269,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
263269
if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
264270
return nil, gas, ErrInsufficientBalance
265271
}
266-
var snapshot = evm.StateDB.Snapshot()
272+
snapshot := evm.StateDB.Snapshot()
267273

268274
// Invoke tracer hooks that signal entering/exiting a call frame
269275
if evm.Config.Debug {
@@ -304,7 +310,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
304310
if evm.depth > int(params.CallCreateDepth) {
305311
return nil, gas, ErrDepth
306312
}
307-
var snapshot = evm.StateDB.Snapshot()
313+
snapshot := evm.StateDB.Snapshot()
308314

309315
// Invoke tracer hooks that signal entering/exiting a call frame
310316
if evm.Config.Debug {
@@ -348,7 +354,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
348354
// after all empty accounts were deleted, so this is not required. However, if we omit this,
349355
// then certain tests start failing; stRevertTest/RevertPrecompiledTouchExactOOG.json.
350356
// We could change this, but for now it's left for legacy reasons
351-
var snapshot = evm.StateDB.Snapshot()
357+
snapshot := evm.StateDB.Snapshot()
352358

353359
// We do an AddBalance of zero here, just in order to trigger a touch.
354360
// This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium,

core/vm/instructions_test.go

+24-16
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@ type twoOperandParams struct {
4141
y string
4242
}
4343

44-
var alphabetSoup = "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
45-
var commonParams []*twoOperandParams
46-
var twoOpMethods map[string]executionFunc
44+
var (
45+
alphabetSoup = "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
46+
commonParams []*twoOperandParams
47+
twoOpMethods map[string]executionFunc
48+
)
4749

4850
func init() {
4951
// Params is a list of common edgecases that should be used for some common tests
@@ -92,10 +94,10 @@ func init() {
9294

9395
func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFunc, name string) {
9496
var (
95-
env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{})
96-
stack = newstack()
97-
pc = uint64(0)
98-
evmInterpreter = env.interpreter
97+
env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{})
98+
stack = newstack()
99+
pc = uint64(0)
100+
interpreter = env.interpreter
99101
)
100102

101103
for i, test := range tests {
@@ -104,7 +106,7 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu
104106
expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Expected))
105107
stack.push(x)
106108
stack.push(y)
107-
opFn(&pc, evmInterpreter, &ScopeContext{nil, stack, nil})
109+
opFn(&pc, interpreter.(*EVMInterpreter), &ScopeContext{nil, stack, nil})
108110
if len(stack.data) != 1 {
109111
t.Errorf("Expected one item on stack after %v, got %d: ", name, len(stack.data))
110112
}
@@ -202,7 +204,8 @@ func TestAddMod(t *testing.T) {
202204
z string
203205
expected string
204206
}{
205-
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
207+
{
208+
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
206209
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
207210
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
208211
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
@@ -246,7 +249,7 @@ func TestWriteExpectedValues(t *testing.T) {
246249
y := new(uint256.Int).SetBytes(common.Hex2Bytes(param.y))
247250
stack.push(x)
248251
stack.push(y)
249-
opFn(&pc, interpreter, &ScopeContext{nil, stack, nil})
252+
opFn(&pc, interpreter.(*EVMInterpreter), &ScopeContext{nil, stack, nil})
250253
actual := stack.pop()
251254
result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)}
252255
}
@@ -258,7 +261,7 @@ func TestWriteExpectedValues(t *testing.T) {
258261
if err != nil {
259262
t.Fatal(err)
260263
}
261-
_ = os.WriteFile(fmt.Sprintf("testdata/testcases_%v.json", name), data, 0644)
264+
_ = os.WriteFile(fmt.Sprintf("testdata/testcases_%v.json", name), data, 0o644)
262265
if err != nil {
263266
t.Fatal(err)
264267
}
@@ -447,11 +450,13 @@ func BenchmarkOpEq(b *testing.B) {
447450

448451
opBenchmark(b, opEq, x, y)
449452
}
453+
450454
func BenchmarkOpEq2(b *testing.B) {
451455
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
452456
y := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201fffffffe"
453457
opBenchmark(b, opEq, x, y)
454458
}
459+
455460
func BenchmarkOpAnd(b *testing.B) {
456461
x := alphabetSoup
457462
y := alphabetSoup
@@ -502,18 +507,21 @@ func BenchmarkOpSHL(b *testing.B) {
502507

503508
opBenchmark(b, opSHL, x, y)
504509
}
510+
505511
func BenchmarkOpSHR(b *testing.B) {
506512
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
507513
y := "ff"
508514

509515
opBenchmark(b, opSHR, x, y)
510516
}
517+
511518
func BenchmarkOpSAR(b *testing.B) {
512519
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
513520
y := "ff"
514521

515522
opBenchmark(b, opSAR, x, y)
516523
}
524+
517525
func BenchmarkOpIsZero(b *testing.B) {
518526
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
519527
opBenchmark(b, opIszero, x)
@@ -673,12 +681,12 @@ func TestRandom(t *testing.T) {
673681
{name: "hash(0x010203)", random: crypto.Keccak256Hash([]byte{0x01, 0x02, 0x03})},
674682
} {
675683
var (
676-
env = NewEVM(BlockContext{Random: &tt.random}, TxContext{}, nil, params.TestChainConfig, Config{})
677-
stack = newstack()
678-
pc = uint64(0)
679-
evmInterpreter = env.interpreter
684+
env = NewEVM(BlockContext{Random: &tt.random}, TxContext{}, nil, params.TestChainConfig, Config{})
685+
stack = newstack()
686+
pc = uint64(0)
687+
interpreter = env.interpreter
680688
)
681-
opRandom(&pc, evmInterpreter, &ScopeContext{nil, stack, nil})
689+
opRandom(&pc, interpreter.(*EVMInterpreter), &ScopeContext{nil, stack, nil})
682690
if len(stack.data) != 1 {
683691
t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data))
684692
}

core/vm/interface.go

+10
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,13 @@ type CallContext interface {
8888
// Create a new contract
8989
Create(env *EVM, me ContractRef, data []byte, gas, value *big.Int) ([]byte, common.Address, error)
9090
}
91+
92+
// Interpreter is used to run Ethereum based contracts and will utilize the
93+
// passed environment to query external sources for state information.
94+
// The Interpreter will run the byte code VM based on the passed
95+
// configuration.
96+
type Interpreter interface {
97+
// Run loops and evaluates the contract's code with the given input data and returns
98+
// the return byte-slice and an error if one occurred.
99+
Run(contract *Contract, input []byte, static bool) ([]byte, error)
100+
}

core/vm/interpreter.go

+2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ type keccakState interface {
5252
Read([]byte) (int, error)
5353
}
5454

55+
var _ Interpreter = &EVMInterpreter{}
56+
5557
// EVMInterpreter represents an EVM interpreter
5658
type EVMInterpreter struct {
5759
evm *EVM

0 commit comments

Comments
 (0)