github.com/ethereum/go-ethereum@v1.16.1/core/vm/errors.go (about)

     1  // Copyright 2014 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package vm
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"math"
    23  )
    24  
    25  // List evm execution errors
    26  var (
    27  	ErrOutOfGas                 = errors.New("out of gas")
    28  	ErrCodeStoreOutOfGas        = errors.New("contract creation code storage out of gas")
    29  	ErrDepth                    = errors.New("max call depth exceeded")
    30  	ErrInsufficientBalance      = errors.New("insufficient balance for transfer")
    31  	ErrContractAddressCollision = errors.New("contract address collision")
    32  	ErrExecutionReverted        = errors.New("execution reverted")
    33  	ErrMaxCodeSizeExceeded      = errors.New("max code size exceeded")
    34  	ErrMaxInitCodeSizeExceeded  = errors.New("max initcode size exceeded")
    35  	ErrInvalidJump              = errors.New("invalid jump destination")
    36  	ErrWriteProtection          = errors.New("write protection")
    37  	ErrReturnDataOutOfBounds    = errors.New("return data out of bounds")
    38  	ErrGasUintOverflow          = errors.New("gas uint64 overflow")
    39  	ErrInvalidCode              = errors.New("invalid code: must not begin with 0xef")
    40  	ErrNonceUintOverflow        = errors.New("nonce uint64 overflow")
    41  
    42  	// errStopToken is an internal token indicating interpreter loop termination,
    43  	// never returned to outside callers.
    44  	errStopToken = errors.New("stop token")
    45  )
    46  
    47  // ErrStackUnderflow wraps an evm error when the items on the stack less
    48  // than the minimal requirement.
    49  type ErrStackUnderflow struct {
    50  	stackLen int
    51  	required int
    52  }
    53  
    54  func (e ErrStackUnderflow) Error() string {
    55  	return fmt.Sprintf("stack underflow (%d <=> %d)", e.stackLen, e.required)
    56  }
    57  
    58  func (e ErrStackUnderflow) Unwrap() error {
    59  	return errors.New("stack underflow")
    60  }
    61  
    62  // ErrStackOverflow wraps an evm error when the items on the stack exceeds
    63  // the maximum allowance.
    64  type ErrStackOverflow struct {
    65  	stackLen int
    66  	limit    int
    67  }
    68  
    69  func (e ErrStackOverflow) Error() string {
    70  	return fmt.Sprintf("stack limit reached %d (%d)", e.stackLen, e.limit)
    71  }
    72  
    73  func (e ErrStackOverflow) Unwrap() error {
    74  	return errors.New("stack overflow")
    75  }
    76  
    77  // ErrInvalidOpCode wraps an evm error when an invalid opcode is encountered.
    78  type ErrInvalidOpCode struct {
    79  	opcode OpCode
    80  }
    81  
    82  func (e *ErrInvalidOpCode) Error() string { return fmt.Sprintf("invalid opcode: %s", e.opcode) }
    83  
    84  // rpcError is the same interface as the one defined in rpc/errors.go
    85  // but we do not want to depend on rpc package here so we redefine it.
    86  //
    87  // It's used to ensure that the VMError implements the RPC error interface.
    88  type rpcError interface {
    89  	Error() string  // returns the message
    90  	ErrorCode() int // returns the code
    91  }
    92  
    93  var _ rpcError = (*VMError)(nil)
    94  
    95  // VMError wraps a VM error with an additional stable error code. The error
    96  // field is the original error that caused the VM error and must be one of the
    97  // VM error defined at the top of this file.
    98  //
    99  // If the error is not one of the known error above, the error code will be
   100  // set to VMErrorCodeUnknown.
   101  type VMError struct {
   102  	error
   103  	code int
   104  }
   105  
   106  func VMErrorFromErr(err error) error {
   107  	if err == nil {
   108  		return nil
   109  	}
   110  
   111  	return &VMError{
   112  		error: err,
   113  		code:  vmErrorCodeFromErr(err),
   114  	}
   115  }
   116  
   117  func (e *VMError) Error() string {
   118  	return e.error.Error()
   119  }
   120  
   121  func (e *VMError) Unwrap() error {
   122  	return e.error
   123  }
   124  
   125  func (e *VMError) ErrorCode() int {
   126  	return e.code
   127  }
   128  
   129  const (
   130  	// We start the error code at 1 so that we can use 0 later for some possible extension. There
   131  	// is no unspecified value for the code today because it should always be set to a valid value
   132  	// that could be VMErrorCodeUnknown if the error is not mapped to a known error code.
   133  
   134  	VMErrorCodeOutOfGas = 1 + iota
   135  	VMErrorCodeCodeStoreOutOfGas
   136  	VMErrorCodeDepth
   137  	VMErrorCodeInsufficientBalance
   138  	VMErrorCodeContractAddressCollision
   139  	VMErrorCodeExecutionReverted
   140  	VMErrorCodeMaxCodeSizeExceeded
   141  	VMErrorCodeInvalidJump
   142  	VMErrorCodeWriteProtection
   143  	VMErrorCodeReturnDataOutOfBounds
   144  	VMErrorCodeGasUintOverflow
   145  	VMErrorCodeInvalidCode
   146  	VMErrorCodeNonceUintOverflow
   147  	VMErrorCodeStackUnderflow
   148  	VMErrorCodeStackOverflow
   149  	VMErrorCodeInvalidOpCode
   150  
   151  	// VMErrorCodeUnknown explicitly marks an error as unknown, this is useful when error is converted
   152  	// from an actual `error` in which case if the mapping is not known, we can use this value to indicate that.
   153  	VMErrorCodeUnknown = math.MaxInt - 1
   154  )
   155  
   156  func vmErrorCodeFromErr(err error) int {
   157  	switch {
   158  	case errors.Is(err, ErrOutOfGas):
   159  		return VMErrorCodeOutOfGas
   160  	case errors.Is(err, ErrCodeStoreOutOfGas):
   161  		return VMErrorCodeCodeStoreOutOfGas
   162  	case errors.Is(err, ErrDepth):
   163  		return VMErrorCodeDepth
   164  	case errors.Is(err, ErrInsufficientBalance):
   165  		return VMErrorCodeInsufficientBalance
   166  	case errors.Is(err, ErrContractAddressCollision):
   167  		return VMErrorCodeContractAddressCollision
   168  	case errors.Is(err, ErrExecutionReverted):
   169  		return VMErrorCodeExecutionReverted
   170  	case errors.Is(err, ErrMaxCodeSizeExceeded):
   171  		return VMErrorCodeMaxCodeSizeExceeded
   172  	case errors.Is(err, ErrInvalidJump):
   173  		return VMErrorCodeInvalidJump
   174  	case errors.Is(err, ErrWriteProtection):
   175  		return VMErrorCodeWriteProtection
   176  	case errors.Is(err, ErrReturnDataOutOfBounds):
   177  		return VMErrorCodeReturnDataOutOfBounds
   178  	case errors.Is(err, ErrGasUintOverflow):
   179  		return VMErrorCodeGasUintOverflow
   180  	case errors.Is(err, ErrInvalidCode):
   181  		return VMErrorCodeInvalidCode
   182  	case errors.Is(err, ErrNonceUintOverflow):
   183  		return VMErrorCodeNonceUintOverflow
   184  
   185  	default:
   186  		// Dynamic errors
   187  		if v := (*ErrStackUnderflow)(nil); errors.As(err, &v) {
   188  			return VMErrorCodeStackUnderflow
   189  		}
   190  
   191  		if v := (*ErrStackOverflow)(nil); errors.As(err, &v) {
   192  			return VMErrorCodeStackOverflow
   193  		}
   194  
   195  		if v := (*ErrInvalidOpCode)(nil); errors.As(err, &v) {
   196  			return VMErrorCodeInvalidOpCode
   197  		}
   198  
   199  		return VMErrorCodeUnknown
   200  	}
   201  }