Skip to content

Commit

Permalink
Merge pull request #1998 from sjnam/evm-loop-err
Browse files Browse the repository at this point in the history
Simplify error handling in interpreter loop
  • Loading branch information
sjnam committed Oct 16, 2023
2 parents 4062013 + 1385fbd commit ff04efd
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 41 deletions.
4 changes: 4 additions & 0 deletions blockchain/vm/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,8 @@ var (
ErrMaxCodeSizeExceeded = errors.New("evm: max code size exceeded")
ErrInvalidJump = errors.New("evm: invalid jump destination")
ErrInvalidCode = errors.New("invalid code: must not begin with 0xef")

// errStopToken is an internal token indicating interpreter loop termination,
// never returned to outside callers.
errStopToken = errors.New("stop token")
)
25 changes: 16 additions & 9 deletions blockchain/vm/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@ func opJump(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
if !scope.Contract.validJumpdest(pos) {
return nil, ErrInvalidJump
}
*pc = pos.Uint64()
*pc = pos.Uint64() - 1 // pc will be increased by the interpreter loop

evm.interpreter.intPool.put(pos)
return nil, nil
Expand All @@ -665,9 +665,7 @@ func opJumpi(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
if !scope.Contract.validJumpdest(pos) {
return nil, ErrInvalidJump
}
*pc = pos.Uint64()
} else {
*pc++
*pc = pos.Uint64() - 1 // pc will be increased by the interpreter loop
}

evm.interpreter.intPool.put(pos, cond)
Expand Down Expand Up @@ -719,8 +717,10 @@ func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
evm.interpreter.intPool.put(value, offset, size)

if suberr == ErrExecutionReverted {
evm.interpreter.returnData = res // set REVERT data to return data buffer
return res, nil
}
evm.interpreter.returnData = nil // clear dirty return data buffer
return nil, nil
}

Expand All @@ -747,8 +747,10 @@ func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
evm.interpreter.intPool.put(endowment, offset, size, salt)

if suberr == ErrExecutionReverted {
evm.interpreter.returnData = res // set REVERT data to return data buffer
return res, nil
}
evm.interpreter.returnData = nil // clear dirty return data buffer
return nil, nil
}

Expand Down Expand Up @@ -779,6 +781,7 @@ func opCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
scope.Contract.Gas += returnGas

evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize)
evm.interpreter.returnData = ret
return ret, nil
}

Expand Down Expand Up @@ -809,6 +812,7 @@ func opCallCode(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
scope.Contract.Gas += returnGas

evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize)
evm.interpreter.returnData = ret
return ret, nil
}

Expand All @@ -835,6 +839,7 @@ func opDelegateCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
scope.Contract.Gas += returnGas

evm.interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize)
evm.interpreter.returnData = ret
return ret, nil
}

Expand All @@ -861,6 +866,7 @@ func opStaticCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
scope.Contract.Gas += returnGas

evm.interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize)
evm.interpreter.returnData = ret
return ret, nil
}

Expand All @@ -869,19 +875,20 @@ func opReturn(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
ret := scope.Memory.GetPtr(offset.Int64(), size.Int64())

evm.interpreter.intPool.put(offset, size)
return ret, nil
return ret, errStopToken
}

func opRevert(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
offset, size := scope.Stack.pop(), scope.Stack.pop()
ret := scope.Memory.GetPtr(offset.Int64(), size.Int64())

evm.interpreter.intPool.put(offset, size)
return ret, nil
evm.interpreter.returnData = ret
return ret, ErrExecutionReverted
}

func opStop(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
return nil, nil
return nil, errStopToken
}

func opSelfdestruct(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
Expand All @@ -896,7 +903,7 @@ func opSelfdestruct(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
// evm.interpreter.cfg.Tracer.CaptureExit([]byte{}, 0, nil)
// }

return nil, nil
return nil, errStopToken
}

// opPush1 is a specialized version of pushN
Expand Down Expand Up @@ -930,7 +937,7 @@ func opSelfdestruct6780(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, erro
// tracer.CaptureExit([]byte{}, 0, nil)
// }

return nil, nil
return nil, errStopToken
}

// following functions are used by the instruction jump table
Expand Down
23 changes: 8 additions & 15 deletions blockchain/vm/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,27 +343,20 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte) (ret []byte, err
if verifyPool {
verifyIntegerPool(in.intPool)
}
// if the operation clears the return data (e.g. it has returning data)
// set the last return to the result of the operation.
if operation.returns {
in.returnData = res
}

switch {
case err != nil:
return nil, err // TODO-Klaytn-Issue615
case operation.reverts:
return res, ErrExecutionReverted // TODO-Klaytn-Issue615
case operation.halts:
return res, nil
case !operation.jumps:
pc++
if err != nil {
break
}
pc++
}

abort := atomic.LoadInt32(&in.evm.abort)
if (abort & CancelByTotalTimeLimit) != 0 {
return nil, ErrTotalTimeLimitReached // TODO-Klaytn-Issue615
}
return nil, nil
if err == errStopToken {
err = nil // clear stop token error
}

return res, err
}
17 changes: 0 additions & 17 deletions blockchain/vm/jump_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,7 @@ type operation struct {
// This value will be used to limit the execution time of a transaction on EVM.
computationCost uint64

halts bool // indicates whether the operation should halt further execution
jumps bool // indicates whether the program counter should not increment
writes bool // determines whether this a state modifying operation
reverts bool // determines whether the operation reverts state (implicitly halts)
returns bool // determines whether the operations sets the return data content
}

var (
Expand Down Expand Up @@ -153,7 +149,6 @@ func newConstantinopleInstructionSet() JumpTable {
maxStack: maxStack(4, 1),
memorySize: memoryCreate2,
writes: true,
returns: true,
computationCost: params.Create2ComputationCost,
}
return instructionSet
Expand All @@ -171,7 +166,6 @@ func newByzantiumInstructionSet() JumpTable {
minStack: minStack(6, 1),
maxStack: maxStack(6, 1),
memorySize: memoryStaticCall,
returns: true,
computationCost: params.StaticCallComputationCost,
}
instructionSet[RETURNDATASIZE] = &operation{
Expand All @@ -196,8 +190,6 @@ func newByzantiumInstructionSet() JumpTable {
minStack: minStack(2, 0),
maxStack: maxStack(2, 0),
memorySize: memoryRevert,
reverts: true,
returns: true,
computationCost: params.RevertComputationCost,
}
return instructionSet
Expand All @@ -214,7 +206,6 @@ func newHomesteadInstructionSet() JumpTable {
minStack: minStack(6, 1),
maxStack: maxStack(6, 1),
memorySize: memoryDelegateCall,
returns: true,
computationCost: params.DelegateCallComputationCost,
}
return instructionSet
Expand All @@ -229,7 +220,6 @@ func newFrontierInstructionSet() JumpTable {
constantGas: 0,
minStack: minStack(0, 0),
maxStack: maxStack(0, 0),
halts: true,
computationCost: params.StopComputationCost,
},
ADD: {
Expand Down Expand Up @@ -588,15 +578,13 @@ func newFrontierInstructionSet() JumpTable {
constantGas: GasMidStep,
minStack: minStack(1, 0),
maxStack: maxStack(1, 0),
jumps: true,
computationCost: params.JumpComputationCost,
},
JUMPI: {
execute: opJumpi,
constantGas: GasSlowStep,
minStack: minStack(2, 0),
maxStack: maxStack(2, 0),
jumps: true,
computationCost: params.JumpiComputationCost,
},
PC: {
Expand Down Expand Up @@ -1128,7 +1116,6 @@ func newFrontierInstructionSet() JumpTable {
maxStack: maxStack(3, 1),
memorySize: memoryCreate,
writes: true,
returns: true,
computationCost: params.CreateComputationCost,
},
CALL: {
Expand All @@ -1138,7 +1125,6 @@ func newFrontierInstructionSet() JumpTable {
minStack: minStack(7, 1),
maxStack: maxStack(7, 1),
memorySize: memoryCall,
returns: true,
computationCost: params.CallComputationCost,
},
CALLCODE: {
Expand All @@ -1148,7 +1134,6 @@ func newFrontierInstructionSet() JumpTable {
minStack: minStack(7, 1),
maxStack: maxStack(7, 1),
memorySize: memoryCall,
returns: true,
computationCost: params.CallCodeComputationCost,
},
RETURN: {
Expand All @@ -1157,15 +1142,13 @@ func newFrontierInstructionSet() JumpTable {
minStack: minStack(2, 0),
maxStack: maxStack(2, 0),
memorySize: memoryReturn,
halts: true,
computationCost: params.ReturnComputationCost,
},
SELFDESTRUCT: {
execute: opSelfdestruct,
dynamicGas: gasSelfdestruct,
minStack: minStack(1, 0),
maxStack: maxStack(1, 0),
halts: true,
writes: true,
computationCost: params.SelfDestructComputationCost,
},
Expand Down

0 comments on commit ff04efd

Please sign in to comment.