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  }