github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/evm/precompiles/precompile.go (about) 1 package precompiles 2 3 import ( 4 "errors" 5 6 "github.com/onflow/flow-go/fvm/evm/types" 7 ) 8 9 // InvalidMethodCallGasUsage captures how much gas we charge for invalid method call 10 const InvalidMethodCallGasUsage = uint64(1) 11 12 // ErrInvalidMethodCall is returned when the method is not available on the contract 13 var ErrInvalidMethodCall = errors.New("invalid method call") 14 15 // Function is an interface for a function in a multi-function precompile contract 16 type Function interface { 17 // FunctionSelector returns the function selector bytes for this function 18 FunctionSelector() FunctionSelector 19 20 // ComputeGas computes the gas needed for the given input 21 ComputeGas(input []byte) uint64 22 23 // Run runs the function on the given data 24 Run(input []byte) ([]byte, error) 25 } 26 27 // MultiFunctionPrecompileContract constructs a multi-function precompile smart contract 28 func MultiFunctionPrecompileContract( 29 address types.Address, 30 functions []Function, 31 ) types.Precompile { 32 pc := &precompile{ 33 functions: make(map[FunctionSelector]Function), 34 address: address, 35 } 36 for _, f := range functions { 37 pc.functions[f.FunctionSelector()] = f 38 } 39 return pc 40 } 41 42 type precompile struct { 43 address types.Address 44 functions map[FunctionSelector]Function 45 } 46 47 func (p *precompile) Address() types.Address { 48 return p.address 49 } 50 51 // RequiredGas calculates the contract gas use 52 func (p *precompile) RequiredGas(input []byte) uint64 { 53 if len(input) < FunctionSelectorLength { 54 return InvalidMethodCallGasUsage 55 } 56 sig, data := SplitFunctionSelector(input) 57 callable, found := p.functions[sig] 58 if !found { 59 return InvalidMethodCallGasUsage 60 } 61 return callable.ComputeGas(data) 62 } 63 64 // Run runs the precompiled contract 65 func (p *precompile) Run(input []byte) ([]byte, error) { 66 if len(input) < FunctionSelectorLength { 67 return nil, ErrInvalidMethodCall 68 } 69 sig, data := SplitFunctionSelector(input) 70 callable, found := p.functions[sig] 71 if !found { 72 return nil, ErrInvalidMethodCall 73 } 74 return callable.Run(data) 75 }