aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm/interpreter.go
diff options
context:
space:
mode:
authorMartin Holst Swende <martin@swende.se>2019-03-12 17:40:05 +0800
committerPéter Szilágyi <peterke@gmail.com>2019-03-12 17:40:05 +0800
commit7504dbd6eb3f62371f86b06b03ffd665690951f2 (patch)
treed16b8f9989a4f994966d1325de791b698432f8e3 /core/vm/interpreter.go
parentda5de012c35c677e2e7a43373951ba18b6749e9b (diff)
downloadgo-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.go51
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)