17
17
package vm
18
18
19
19
import (
20
+ "errors"
20
21
"math/big"
21
22
"sync/atomic"
22
23
"time"
@@ -59,6 +60,24 @@ func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
59
60
return p , ok
60
61
}
61
62
63
+ // run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter.
64
+ func run (evm * EVM , contract * Contract , input []byte , readOnly bool ) ([]byte , error ) {
65
+ for _ , interpreter := range evm .interpreters {
66
+ if interpreter .CanRun (contract .Code ) {
67
+ if evm .interpreter != interpreter {
68
+ // Ensure that the interpreter pointer is set back
69
+ // to its current value upon return.
70
+ defer func (i Interpreter ) {
71
+ evm .interpreter = i
72
+ }(evm .interpreter )
73
+ evm .interpreter = interpreter
74
+ }
75
+ return interpreter .Run (contract , input , readOnly )
76
+ }
77
+ }
78
+ return nil , errors .New ("no compatible interpreter" )
79
+ }
80
+
62
81
// BlockContext provides the EVM with auxiliary information. Once provided
63
82
// it shouldn't be modified.
64
83
type BlockContext struct {
@@ -112,7 +131,8 @@ type EVM struct {
112
131
Config Config
113
132
// global (to this context) ethereum virtual machine
114
133
// used throughout the execution of the tx.
115
- interpreter * EVMInterpreter
134
+ interpreters []Interpreter
135
+ interpreter Interpreter
116
136
// abort is used to abort the EVM calling operations
117
137
// NOTE: must be set atomically
118
138
abort int32
@@ -129,13 +149,35 @@ type EVM struct {
129
149
// only ever be used *once*.
130
150
func NewEVM (blockCtx BlockContext , txCtx TxContext , statedb StateDB , chainConfig ctypes.ChainConfigurator , config Config ) * EVM {
131
151
evm := & EVM {
132
- Context : blockCtx ,
133
- TxContext : txCtx ,
134
- StateDB : statedb ,
135
- Config : config ,
136
- chainConfig : chainConfig ,
137
- }
138
- evm .interpreter = NewEVMInterpreter (evm , config )
152
+ Context : blockCtx ,
153
+ TxContext : txCtx ,
154
+ StateDB : statedb ,
155
+ Config : config ,
156
+ chainConfig : chainConfig ,
157
+ interpreters : make ([]Interpreter , 0 , 1 ),
158
+ }
159
+
160
+ if chainConfig .IsEWASM (blockCtx .BlockNumber ) {
161
+ // to be implemented by EVM-C and Wagon PRs.
162
+ // if vmConfig.EWASMInterpreter != "" {
163
+ // extIntOpts := strings.Split(vmConfig.EWASMInterpreter, ":")
164
+ // path := extIntOpts[0]
165
+ // options := []string{}
166
+ // if len(extIntOpts) > 1 {
167
+ // options = extIntOpts[1..]
168
+ // }
169
+ // evm.interpreters = append(evm.interpreters, NewEVMVCInterpreter(evm, vmConfig, options))
170
+ // } else {
171
+ // evm.interpreters = append(evm.interpreters, NewEWASMInterpreter(evm, vmConfig))
172
+ // }
173
+ panic ("No supported ewasm interpreter yet." )
174
+ }
175
+
176
+ // vmConfig.EVMInterpreter will be used by EVM-C, it won't be checked here
177
+ // as we always want to have the built-in EVM as the failover option.
178
+ evm .interpreters = append (evm .interpreters , NewEVMInterpreter (evm , config ))
179
+ evm .interpreter = evm .interpreters [0 ]
180
+
139
181
return evm
140
182
}
141
183
@@ -158,7 +200,7 @@ func (evm *EVM) Cancelled() bool {
158
200
}
159
201
160
202
// Interpreter returns the current interpreter
161
- func (evm * EVM ) Interpreter () * EVMInterpreter {
203
+ func (evm * EVM ) Interpreter () Interpreter {
162
204
return evm .interpreter
163
205
}
164
206
@@ -216,7 +258,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
216
258
// The depth-check is already done, and precompiles handled above
217
259
contract := NewContract (caller , AccountRef (addrCopy ), value , gas )
218
260
contract .SetCallCode (& addrCopy , evm .StateDB .GetCodeHash (addrCopy ), code )
219
- ret , err = evm . interpreter . Run ( contract , input , false )
261
+ ret , err = run ( evm , contract , input , false )
220
262
gas = contract .Gas
221
263
}
222
264
}
@@ -268,7 +310,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
268
310
// The contract is a scoped environment for this execution context only.
269
311
contract := NewContract (caller , AccountRef (caller .Address ()), value , gas )
270
312
contract .SetCallCode (& addrCopy , evm .StateDB .GetCodeHash (addrCopy ), evm .StateDB .GetCode (addrCopy ))
271
- ret , err = evm . interpreter . Run ( contract , input , false )
313
+ ret , err = run ( evm , contract , input , false )
272
314
gas = contract .Gas
273
315
}
274
316
if err != nil {
@@ -303,7 +345,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
303
345
// Initialise a new contract and make initialise the delegate values
304
346
contract := NewContract (caller , AccountRef (caller .Address ()), nil , gas ).AsDelegate ()
305
347
contract .SetCallCode (& addrCopy , evm .StateDB .GetCodeHash (addrCopy ), evm .StateDB .GetCode (addrCopy ))
306
- ret , err = evm . interpreter . Run ( contract , input , false )
348
+ ret , err = run ( evm , contract , input , false )
307
349
gas = contract .Gas
308
350
}
309
351
if err != nil {
@@ -354,7 +396,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
354
396
// When an error was returned by the EVM or when setting the creation code
355
397
// above we revert to the snapshot and consume any gas remaining. Additionally
356
398
// when we're in Homestead this also counts for code storage gas errors.
357
- ret , err = evm . interpreter . Run ( contract , input , true )
399
+ ret , err = run ( evm , contract , input , true )
358
400
gas = contract .Gas
359
401
}
360
402
if err != nil {
@@ -424,7 +466,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
424
466
}
425
467
start := time .Now ()
426
468
427
- ret , err := evm . interpreter . Run ( contract , nil , false )
469
+ ret , err := run ( evm , contract , nil , false )
428
470
429
471
// Check whether the max code size has been exceeded, assign err if the case.
430
472
if err == nil && evm .ChainConfig ().IsEnabled (evm .chainConfig .GetEIP170Transition , evm .Context .BlockNumber ) && uint64 (len (ret )) > vars .MaxCodeSize {
0 commit comments