github.com/MetalBlockchain/subnet-evm@v0.4.9/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/MetalBlockchain/metalgo/snow" 11 "github.com/MetalBlockchain/subnet-evm/commontype" 12 "github.com/ethereum/go-ethereum/common" 13 ) 14 15 const ( 16 selectorLen = 4 17 ) 18 19 type RunStatefulPrecompileFunc func(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) 20 21 // PrecompileAccessibleState defines the interface exposed to stateful precompile contracts 22 type PrecompileAccessibleState interface { 23 GetStateDB() StateDB 24 GetBlockContext() BlockContext 25 GetSnowContext() *snow.Context 26 CallFromPrecompile(caller common.Address, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) 27 } 28 29 // BlockContext defines an interface that provides information to a stateful precompile 30 // about the block that activates the upgrade. The precompile can access this information 31 // to initialize its state. 32 type BlockContext interface { 33 Number() *big.Int 34 Timestamp() *big.Int 35 } 36 37 // ChainContext defines an interface that provides information to a stateful precompile 38 // about the chain configuration. The precompile can access this information to initialize 39 // its state. 40 type ChainConfig interface { 41 // GetFeeConfig returns the original FeeConfig that was set in the genesis. 42 GetFeeConfig() commontype.FeeConfig 43 // AllowedFeeRecipients returns true if fee recipients are allowed in the genesis. 44 AllowedFeeRecipients() bool 45 } 46 47 // StateDB is the interface for accessing EVM state 48 type StateDB interface { 49 GetState(common.Address, common.Hash) common.Hash 50 SetState(common.Address, common.Hash, common.Hash) 51 52 SetCode(common.Address, []byte) 53 54 SetNonce(common.Address, uint64) 55 GetNonce(common.Address) uint64 56 57 GetBalance(common.Address) *big.Int 58 AddBalance(common.Address, *big.Int) 59 SubBalance(common.Address, *big.Int) 60 61 CreateAccount(common.Address) 62 Exist(common.Address) bool 63 64 AddLog(addr common.Address, topics []common.Hash, data []byte, blockNumber uint64) 65 66 Suicide(common.Address) bool 67 Finalise(deleteEmptyObjects bool) 68 } 69 70 // StatefulPrecompiledContract is the interface for executing a precompiled contract 71 type StatefulPrecompiledContract interface { 72 // Run executes the precompiled contract. 73 Run(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) 74 } 75 76 // statefulPrecompileFunction defines a function implemented by a stateful precompile 77 type statefulPrecompileFunction struct { 78 // selector is the 4 byte function selector for this function 79 // This should be calculated from the function signature using CalculateFunctionSelector 80 selector []byte 81 // execute is performed when this function is selected 82 execute RunStatefulPrecompileFunc 83 } 84 85 // newStatefulPrecompileFunction creates a stateful precompile function with the given arguments 86 func newStatefulPrecompileFunction(selector []byte, execute RunStatefulPrecompileFunc) *statefulPrecompileFunction { 87 return &statefulPrecompileFunction{ 88 selector: selector, 89 execute: execute, 90 } 91 } 92 93 // statefulPrecompileWithFunctionSelectors implements StatefulPrecompiledContract by using 4 byte function selectors to pass 94 // off responsibilities to internal execution functions. 95 // Note: because we only ever read from [functions] there no lock is required to make it thread-safe. 96 type statefulPrecompileWithFunctionSelectors struct { 97 fallback RunStatefulPrecompileFunc 98 functions map[string]*statefulPrecompileFunction 99 } 100 101 // newStatefulPrecompileWithFunctionSelectors generates new StatefulPrecompile using [functions] as the available functions and [fallback] 102 // 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. 103 func newStatefulPrecompileWithFunctionSelectors(fallback RunStatefulPrecompileFunc, functions []*statefulPrecompileFunction) StatefulPrecompiledContract { 104 // Construct the contract and populate [functions]. 105 contract := &statefulPrecompileWithFunctionSelectors{ 106 fallback: fallback, 107 functions: make(map[string]*statefulPrecompileFunction), 108 } 109 for _, function := range functions { 110 _, exists := contract.functions[string(function.selector)] 111 if exists { 112 panic(fmt.Errorf("cannot create stateful precompile with duplicated function selector: %q", function.selector)) 113 } 114 contract.functions[string(function.selector)] = function 115 } 116 117 return contract 118 } 119 120 // Run selects the function using the 4 byte function selector at the start of the input and executes the underlying function on the 121 // given arguments. 122 func (s *statefulPrecompileWithFunctionSelectors) Run(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { 123 // If there is no input data present, call the fallback function if present. 124 if len(input) == 0 && s.fallback != nil { 125 return s.fallback(accessibleState, caller, addr, nil, suppliedGas, readOnly) 126 } 127 128 // Otherwise, an unexpected input size will result in an error. 129 if len(input) < selectorLen { 130 return nil, suppliedGas, fmt.Errorf("missing function selector to precompile - input length (%d)", len(input)) 131 } 132 133 // Use the function selector to grab the correct function 134 selector := input[:selectorLen] 135 functionInput := input[selectorLen:] 136 function, ok := s.functions[string(selector)] 137 if !ok { 138 return nil, suppliedGas, fmt.Errorf("invalid function selector %#x", selector) 139 } 140 141 return function.execute(accessibleState, caller, addr, functionInput, suppliedGas, readOnly) 142 }