diff options
author | Martin Holst Swende <martin@swende.se> | 2019-03-12 17:40:05 +0800 |
---|---|---|
committer | Péter Szilágyi <peterke@gmail.com> | 2019-03-12 17:40:05 +0800 |
commit | 7504dbd6eb3f62371f86b06b03ffd665690951f2 (patch) | |
tree | d16b8f9989a4f994966d1325de791b698432f8e3 /core/vm/interpreter.go | |
parent | da5de012c35c677e2e7a43373951ba18b6749e9b (diff) | |
download | go-tangerine-7504dbd6eb3f62371f86b06b03ffd665690951f2.tar go-tangerine-7504dbd6eb3f62371f86b06b03ffd665690951f2.tar.gz go-tangerine-7504dbd6eb3f62371f86b06b03ffd665690951f2.tar.bz2 go-tangerine-7504dbd6eb3f62371f86b06b03ffd665690951f2.tar.lz go-tangerine-7504dbd6eb3f62371f86b06b03ffd665690951f2.tar.xz go-tangerine-7504dbd6eb3f62371f86b06b03ffd665690951f2.tar.zst go-tangerine-7504dbd6eb3f62371f86b06b03ffd665690951f2.zip |
core/vm: 64 bit memory and gas calculations (#19210)
* core/vm: remove function call for stack validation from evm runloop
* core/vm: separate gas calc into static + dynamic
* core/vm: optimize push1
* core/vm: reuse pooled bigints for ADDRESS, ORIGIN and CALLER
* core/vm: use generic error message for jump/jumpi, to avoid string interpolation
* testdata: fix tests for new error message
* core/vm: use 64-bit memory calculations
* core/vm: fix error in memory calculation
* core/vm: address review concerns
* core/vm: avoid unnecessary use of big.Int:BitLen()
Diffstat (limited to 'core/vm/interpreter.go')
-rw-r--r-- | core/vm/interpreter.go | 51 |
1 files changed, 27 insertions, 24 deletions
diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index c9dc3c00c..417665370 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -118,22 +118,6 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { } } -func (in *EVMInterpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error { - if in.evm.chainRules.IsByzantium { - if in.readOnly { - // If the interpreter is operating in readonly mode, make sure no - // state-modifying operation is performed. The 3rd stack item - // for a call operation is the value. Transferring value from one - // account to the others means the state is modified and should also - // return with an error. - if operation.writes || (op == CALL && stack.Back(2).BitLen() > 0) { - return errWriteProtection - } - } - } - return nil -} - // Run loops and evaluates the contract's code with the given input data and returns // the return byte-slice and an error if one occurred. // @@ -217,19 +201,35 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( if !operation.valid { return nil, fmt.Errorf("invalid opcode 0x%x", int(op)) } - if err = operation.validateStack(stack); err != nil { - return nil, err + // Validate stack + if sLen := stack.len(); sLen < operation.minStack { + return nil, fmt.Errorf("stack underflow (%d <=> %d)", sLen, operation.minStack) + } else if sLen > operation.maxStack { + return nil, fmt.Errorf("stack limit reached %d (%d)", sLen, operation.maxStack) } // If the operation is valid, enforce and write restrictions - if err = in.enforceRestrictions(op, operation, stack); err != nil { - return nil, err + if in.readOnly && in.evm.chainRules.IsByzantium { + // If the interpreter is operating in readonly mode, make sure no + // state-modifying operation is performed. The 3rd stack item + // for a call operation is the value. Transferring value from one + // account to the others means the state is modified and should also + // return with an error. + if operation.writes || (op == CALL && stack.Back(2).Sign() != 0) { + return nil, errWriteProtection + } + } + // Static portion of gas + if !contract.UseGas(operation.constantGas) { + return nil, ErrOutOfGas } var memorySize uint64 // calculate the new memory size and expand the memory to fit // the operation + // Memory check needs to be done prior to evaluating the dynamic gas portion, + // to detect calculation overflows if operation.memorySize != nil { - memSize, overflow := bigUint64(operation.memorySize(stack)) + memSize, overflow := operation.memorySize(stack) if overflow { return nil, errGasUintOverflow } @@ -239,11 +239,14 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( return nil, errGasUintOverflow } } + // Dynamic portion of gas // consume the gas and return an error if not enough gas is available. // cost is explicitly set so that the capture state defer method can get the proper cost - cost, err = operation.gasCost(in.gasTable, in.evm, contract, stack, mem, memorySize) - if err != nil || !contract.UseGas(cost) { - return nil, ErrOutOfGas + if operation.dynamicGas != nil { + cost, err = operation.dynamicGas(in.gasTable, in.evm, contract, stack, mem, memorySize) + if err != nil || !contract.UseGas(cost) { + return nil, ErrOutOfGas + } } if memorySize > 0 { mem.Resize(memorySize) |