github.com/dim4egster/coreth@v0.10.2/precompile/contract.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package precompile
     5  
     6  import (
     7  	"fmt"
     8  	"math/big"
     9  
    10  	"github.com/ethereum/go-ethereum/common"
    11  )
    12  
    13  const (
    14  	selectorLen = 4
    15  )
    16  
    17  type RunStatefulPrecompileFunc func(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error)
    18  
    19  // PrecompileAccessibleState defines the interface exposed to stateful precompile contracts
    20  type PrecompileAccessibleState interface {
    21  	GetStateDB() StateDB
    22  	GetBlockContext() BlockContext
    23  	NativeAssetCall(caller common.Address, input []byte, suppliedGas uint64, gasGost uint64, readOnly bool) (ret []byte, remainingGas uint64, err error)
    24  }
    25  
    26  // BlockContext defines an interface that provides information to a stateful precompile
    27  // about the block that activates the upgrade. The precompile can access this information
    28  // to initialize its state.
    29  type BlockContext interface {
    30  	Number() *big.Int
    31  	Timestamp() *big.Int
    32  }
    33  
    34  // ChainContext defines an interface that provides information to a stateful precompile
    35  // about the chain configuration. The precompile can access this information to initialize
    36  // its state.
    37  type ChainConfig interface {
    38  	// Note: None of the existing stateful precompiles currently access chain config information
    39  	// in Configure so this interface is empty.
    40  }
    41  
    42  // StateDB is the interface for accessing EVM state
    43  type StateDB interface {
    44  	GetState(common.Address, common.Hash) common.Hash
    45  	SetState(common.Address, common.Hash, common.Hash)
    46  
    47  	SetCode(common.Address, []byte)
    48  
    49  	SetNonce(common.Address, uint64)
    50  	GetNonce(common.Address) uint64
    51  
    52  	GetBalance(common.Address) *big.Int
    53  	AddBalance(common.Address, *big.Int)
    54  	SubBalance(common.Address, *big.Int)
    55  
    56  	SubBalanceMultiCoin(common.Address, common.Hash, *big.Int)
    57  	AddBalanceMultiCoin(common.Address, common.Hash, *big.Int)
    58  	GetBalanceMultiCoin(common.Address, common.Hash) *big.Int
    59  
    60  	CreateAccount(common.Address)
    61  	Exist(common.Address) bool
    62  }
    63  
    64  // StatefulPrecompiledContract is the interface for executing a precompiled contract
    65  type StatefulPrecompiledContract interface {
    66  	// Run executes the precompiled contract.
    67  	Run(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error)
    68  }
    69  
    70  // statefulPrecompileFunction defines a function implemented by a stateful precompile
    71  type statefulPrecompileFunction struct {
    72  	// selector is the 4 byte function selector for this function
    73  	// This should be calculated from the function signature using CalculateFunctionSelector
    74  	selector []byte
    75  	// execute is performed when this function is selected
    76  	execute RunStatefulPrecompileFunc
    77  }
    78  
    79  // newStatefulPrecompileFunction creates a stateful precompile function with the given arguments
    80  //nolint:unused,deadcode
    81  func newStatefulPrecompileFunction(selector []byte, execute RunStatefulPrecompileFunc) *statefulPrecompileFunction {
    82  	return &statefulPrecompileFunction{
    83  		selector: selector,
    84  		execute:  execute,
    85  	}
    86  }
    87  
    88  // statefulPrecompileWithFunctionSelectors implements StatefulPrecompiledContract by using 4 byte function selectors to pass
    89  // off responsibilities to internal execution functions.
    90  // Note: because we only ever read from [functions] there no lock is required to make it thread-safe.
    91  type statefulPrecompileWithFunctionSelectors struct {
    92  	fallback  *statefulPrecompileFunction
    93  	functions map[string]*statefulPrecompileFunction
    94  }
    95  
    96  // newStatefulPrecompileWithFunctionSelectors generates new StatefulPrecompile using [functions] as the available functions and [fallback]
    97  // as an optional fallback if there is no input data. Note: the selector of [fallback] will be ignored, so it is required to be left empty.
    98  //nolint:unused,deadcode
    99  func newStatefulPrecompileWithFunctionSelectors(fallback *statefulPrecompileFunction, functions []*statefulPrecompileFunction) StatefulPrecompiledContract {
   100  	// Ensure that if a fallback is present, it does not have a mistakenly populated function selector.
   101  	if fallback != nil && len(fallback.selector) != 0 {
   102  		panic(fmt.Errorf("fallback function cannot specify non-zero length function selector"))
   103  	}
   104  
   105  	// Construct the contract and populate [functions].
   106  	contract := &statefulPrecompileWithFunctionSelectors{
   107  		fallback:  fallback,
   108  		functions: make(map[string]*statefulPrecompileFunction),
   109  	}
   110  	for _, function := range functions {
   111  		_, exists := contract.functions[string(function.selector)]
   112  		if exists {
   113  			panic(fmt.Errorf("cannot create stateful precompile with duplicated function selector: %q", function.selector))
   114  		}
   115  		contract.functions[string(function.selector)] = function
   116  	}
   117  
   118  	return contract
   119  }
   120  
   121  // Run selects the function using the 4 byte function selector at the start of the input and executes the underlying function on the
   122  // given arguments.
   123  func (s *statefulPrecompileWithFunctionSelectors) Run(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) {
   124  	// If there is no input data present, call the fallback function if present.
   125  	if len(input) == 0 && s.fallback != nil {
   126  		return s.fallback.execute(accessibleState, caller, addr, nil, suppliedGas, readOnly)
   127  	}
   128  
   129  	// Otherwise, an unexpected input size will result in an error.
   130  	if len(input) < selectorLen {
   131  		return nil, suppliedGas, fmt.Errorf("missing function selector to precompile - input length (%d)", len(input))
   132  	}
   133  
   134  	// Use the function selector to grab the correct function
   135  	selector := input[:selectorLen]
   136  	functionInput := input[selectorLen:]
   137  	function, ok := s.functions[string(selector)]
   138  	if !ok {
   139  		return nil, suppliedGas, fmt.Errorf("invalid function selector %#x", selector)
   140  	}
   141  
   142  	return function.execute(accessibleState, caller, addr, functionInput, suppliedGas, readOnly)
   143  }