core/vm: simplify error handling in interpreter loop (#23952)
* core/vm: break loop on any error * core/vm: move ErrExecutionReverted to opRevert() * core/vm: use "stop token" to stop the loop * core/vm: unconditionally pc++ in the loop * core/vm: set return data in instruction impls
This commit is contained in:
		
							parent
							
								
									86fe359a56
								
							
						
					
					
						commit
						1fa91729f2
					
				| @ -36,6 +36,10 @@ var ( | ||||
| 	ErrGasUintOverflow          = errors.New("gas uint64 overflow") | ||||
| 	ErrInvalidCode              = errors.New("invalid code: must not begin with 0xef") | ||||
| 	ErrNonceUintOverflow        = errors.New("nonce uint64 overflow") | ||||
| 
 | ||||
| 	// errStopToken is an internal token indicating interpreter loop termination,
 | ||||
| 	// never returned to outside callers.
 | ||||
| 	errStopToken = errors.New("stop token") | ||||
| ) | ||||
| 
 | ||||
| // ErrStackUnderflow wraps an evm error when the items on the stack less
 | ||||
|  | ||||
| @ -526,7 +526,7 @@ func opJump(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt | ||||
| 	if !scope.Contract.validJumpdest(&pos) { | ||||
| 		return nil, ErrInvalidJump | ||||
| 	} | ||||
| 	*pc = pos.Uint64() | ||||
| 	*pc = pos.Uint64() - 1 // pc will be increased by the interpreter loop
 | ||||
| 	return nil, nil | ||||
| } | ||||
| 
 | ||||
| @ -536,9 +536,7 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by | ||||
| 		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
 | ||||
| 	} | ||||
| 	return nil, nil | ||||
| } | ||||
| @ -598,8 +596,10 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b | ||||
| 	scope.Contract.Gas += returnGas | ||||
| 
 | ||||
| 	if suberr == ErrExecutionReverted { | ||||
| 		interpreter.returnData = res // set REVERT data to return data buffer
 | ||||
| 		return res, nil | ||||
| 	} | ||||
| 	interpreter.returnData = nil // clear dirty return data buffer
 | ||||
| 	return nil, nil | ||||
| } | ||||
| 
 | ||||
| @ -634,8 +634,10 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] | ||||
| 	scope.Contract.Gas += returnGas | ||||
| 
 | ||||
| 	if suberr == ErrExecutionReverted { | ||||
| 		interpreter.returnData = res // set REVERT data to return data buffer
 | ||||
| 		return res, nil | ||||
| 	} | ||||
| 	interpreter.returnData = nil // clear dirty return data buffer
 | ||||
| 	return nil, nil | ||||
| } | ||||
| 
 | ||||
| @ -674,6 +676,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt | ||||
| 	} | ||||
| 	scope.Contract.Gas += returnGas | ||||
| 
 | ||||
| 	interpreter.returnData = ret | ||||
| 	return ret, nil | ||||
| } | ||||
| 
 | ||||
| @ -709,6 +712,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ | ||||
| 	} | ||||
| 	scope.Contract.Gas += returnGas | ||||
| 
 | ||||
| 	interpreter.returnData = ret | ||||
| 	return ret, nil | ||||
| } | ||||
| 
 | ||||
| @ -737,6 +741,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext | ||||
| 	} | ||||
| 	scope.Contract.Gas += returnGas | ||||
| 
 | ||||
| 	interpreter.returnData = ret | ||||
| 	return ret, nil | ||||
| } | ||||
| 
 | ||||
| @ -765,6 +770,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) | ||||
| 	} | ||||
| 	scope.Contract.Gas += returnGas | ||||
| 
 | ||||
| 	interpreter.returnData = ret | ||||
| 	return ret, nil | ||||
| } | ||||
| 
 | ||||
| @ -772,18 +778,19 @@ func opReturn(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b | ||||
| 	offset, size := scope.Stack.pop(), scope.Stack.pop() | ||||
| 	ret := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64())) | ||||
| 
 | ||||
| 	return ret, nil | ||||
| 	return ret, errStopToken | ||||
| } | ||||
| 
 | ||||
| func opRevert(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { | ||||
| 	offset, size := scope.Stack.pop(), scope.Stack.pop() | ||||
| 	ret := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64())) | ||||
| 
 | ||||
| 	return ret, nil | ||||
| 	interpreter.returnData = ret | ||||
| 	return ret, ErrExecutionReverted | ||||
| } | ||||
| 
 | ||||
| func opStop(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { | ||||
| 	return nil, nil | ||||
| 	return nil, errStopToken | ||||
| } | ||||
| 
 | ||||
| func opSuicide(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { | ||||
| @ -795,7 +802,7 @@ func opSuicide(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] | ||||
| 		interpreter.cfg.Tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) | ||||
| 		interpreter.cfg.Tracer.CaptureExit([]byte{}, 0, nil) | ||||
| 	} | ||||
| 	return nil, nil | ||||
| 	return nil, errStopToken | ||||
| } | ||||
| 
 | ||||
| // following functions are used by the instruction jump  table
 | ||||
|  | ||||
| @ -259,22 +259,16 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( | ||||
| 
 | ||||
| 		// execute the operation
 | ||||
| 		res, err = operation.execute(&pc, in, callContext) | ||||
| 		// 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 | ||||
| 		case operation.reverts: | ||||
| 			return res, ErrExecutionReverted | ||||
| 		case operation.halts: | ||||
| 			return res, nil | ||||
| 		case !operation.jumps: | ||||
| 		if err != nil { | ||||
| 			break | ||||
| 		} | ||||
| 		pc++ | ||||
| 	} | ||||
| 
 | ||||
| 	if err == errStopToken { | ||||
| 		err = nil // clear stop token error
 | ||||
| 	} | ||||
| 	return nil, nil | ||||
| 
 | ||||
| 	return res, err | ||||
| } | ||||
|  | ||||
| @ -41,11 +41,7 @@ type operation struct { | ||||
| 	// memorySize returns the memory size required for the operation
 | ||||
| 	memorySize memorySizeFunc | ||||
| 
 | ||||
| 	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 ( | ||||
| @ -128,7 +124,6 @@ func newConstantinopleInstructionSet() JumpTable { | ||||
| 		maxStack:    maxStack(4, 1), | ||||
| 		memorySize:  memoryCreate2, | ||||
| 		writes:      true, | ||||
| 		returns:     true, | ||||
| 	} | ||||
| 	return instructionSet | ||||
| } | ||||
| @ -144,7 +139,6 @@ func newByzantiumInstructionSet() JumpTable { | ||||
| 		minStack:    minStack(6, 1), | ||||
| 		maxStack:    maxStack(6, 1), | ||||
| 		memorySize:  memoryStaticCall, | ||||
| 		returns:     true, | ||||
| 	} | ||||
| 	instructionSet[RETURNDATASIZE] = &operation{ | ||||
| 		execute:     opReturnDataSize, | ||||
| @ -166,8 +160,6 @@ func newByzantiumInstructionSet() JumpTable { | ||||
| 		minStack:   minStack(2, 0), | ||||
| 		maxStack:   maxStack(2, 0), | ||||
| 		memorySize: memoryRevert, | ||||
| 		reverts:    true, | ||||
| 		returns:    true, | ||||
| 	} | ||||
| 	return instructionSet | ||||
| } | ||||
| @ -204,7 +196,6 @@ func newHomesteadInstructionSet() JumpTable { | ||||
| 		minStack:    minStack(6, 1), | ||||
| 		maxStack:    maxStack(6, 1), | ||||
| 		memorySize:  memoryDelegateCall, | ||||
| 		returns:     true, | ||||
| 	} | ||||
| 	return instructionSet | ||||
| } | ||||
| @ -218,7 +209,6 @@ func newFrontierInstructionSet() JumpTable { | ||||
| 			constantGas: 0, | ||||
| 			minStack:    minStack(0, 0), | ||||
| 			maxStack:    maxStack(0, 0), | ||||
| 			halts:       true, | ||||
| 		}, | ||||
| 		ADD: { | ||||
| 			execute:     opAdd, | ||||
| @ -528,14 +518,12 @@ func newFrontierInstructionSet() JumpTable { | ||||
| 			constantGas: GasMidStep, | ||||
| 			minStack:    minStack(1, 0), | ||||
| 			maxStack:    maxStack(1, 0), | ||||
| 			jumps:       true, | ||||
| 		}, | ||||
| 		JUMPI: { | ||||
| 			execute:     opJumpi, | ||||
| 			constantGas: GasSlowStep, | ||||
| 			minStack:    minStack(2, 0), | ||||
| 			maxStack:    maxStack(2, 0), | ||||
| 			jumps:       true, | ||||
| 		}, | ||||
| 		PC: { | ||||
| 			execute:     opPc, | ||||
| @ -993,7 +981,6 @@ func newFrontierInstructionSet() JumpTable { | ||||
| 			maxStack:    maxStack(3, 1), | ||||
| 			memorySize:  memoryCreate, | ||||
| 			writes:      true, | ||||
| 			returns:     true, | ||||
| 		}, | ||||
| 		CALL: { | ||||
| 			execute:     opCall, | ||||
| @ -1002,7 +989,6 @@ func newFrontierInstructionSet() JumpTable { | ||||
| 			minStack:    minStack(7, 1), | ||||
| 			maxStack:    maxStack(7, 1), | ||||
| 			memorySize:  memoryCall, | ||||
| 			returns:     true, | ||||
| 		}, | ||||
| 		CALLCODE: { | ||||
| 			execute:     opCallCode, | ||||
| @ -1011,7 +997,6 @@ func newFrontierInstructionSet() JumpTable { | ||||
| 			minStack:    minStack(7, 1), | ||||
| 			maxStack:    maxStack(7, 1), | ||||
| 			memorySize:  memoryCall, | ||||
| 			returns:     true, | ||||
| 		}, | ||||
| 		RETURN: { | ||||
| 			execute:    opReturn, | ||||
| @ -1019,14 +1004,12 @@ func newFrontierInstructionSet() JumpTable { | ||||
| 			minStack:   minStack(2, 0), | ||||
| 			maxStack:   maxStack(2, 0), | ||||
| 			memorySize: memoryReturn, | ||||
| 			halts:      true, | ||||
| 		}, | ||||
| 		SELFDESTRUCT: { | ||||
| 			execute:    opSuicide, | ||||
| 			dynamicGas: gasSelfdestruct, | ||||
| 			minStack:   minStack(1, 0), | ||||
| 			maxStack:   maxStack(1, 0), | ||||
| 			halts:      true, | ||||
| 			writes:     true, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user