github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/evm/handler/precompiles.go (about)

     1  package handler
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  
     7  	"github.com/onflow/cadence"
     8  	"github.com/onflow/cadence/runtime/sema"
     9  
    10  	"github.com/onflow/flow-go/fvm/environment"
    11  	"github.com/onflow/flow-go/fvm/evm/precompiles"
    12  	"github.com/onflow/flow-go/fvm/evm/types"
    13  	"github.com/onflow/flow-go/model/flow"
    14  )
    15  
    16  func preparePrecompiles(
    17  	evmContractAddress flow.Address,
    18  	randomBeaconAddress flow.Address,
    19  	addressAllocator types.AddressAllocator,
    20  	backend types.Backend,
    21  ) []types.Precompile {
    22  	archAddress := addressAllocator.AllocatePrecompileAddress(1)
    23  	archContract := precompiles.ArchContract(
    24  		archAddress,
    25  		blockHeightProvider(backend),
    26  		coaOwnershipProofValidator(evmContractAddress, backend),
    27  		randomSourceProvider(randomBeaconAddress, backend),
    28  		revertibleRandomGenerator(backend),
    29  	)
    30  	return []types.Precompile{archContract}
    31  }
    32  
    33  func blockHeightProvider(backend types.Backend) func() (uint64, error) {
    34  	return func() (uint64, error) {
    35  		h, err := backend.GetCurrentBlockHeight()
    36  		if types.IsAFatalError(err) || types.IsABackendError(err) {
    37  			panic(err)
    38  		}
    39  		return h, err
    40  	}
    41  }
    42  
    43  const RandomSourceTypeValueFieldName = "value"
    44  
    45  func randomSourceProvider(contractAddress flow.Address, backend types.Backend) func(uint64) (uint64, error) {
    46  	return func(blockHeight uint64) (uint64, error) {
    47  		value, err := backend.Invoke(
    48  			environment.ContractFunctionSpec{
    49  				AddressFromChain: func(_ flow.Chain) flow.Address {
    50  					return contractAddress
    51  				},
    52  				LocationName: "RandomBeaconHistory",
    53  				FunctionName: "sourceOfRandomness",
    54  				ArgumentTypes: []sema.Type{
    55  					sema.UInt64Type,
    56  				},
    57  			},
    58  			[]cadence.Value{
    59  				cadence.NewUInt64(blockHeight),
    60  			},
    61  		)
    62  		if err != nil {
    63  			if types.IsAFatalError(err) || types.IsABackendError(err) {
    64  				panic(err)
    65  			}
    66  			return 0, err
    67  		}
    68  
    69  		data, ok := value.(cadence.Struct)
    70  		if !ok {
    71  			return 0, fmt.Errorf("invalid output data received from getRandomSource")
    72  		}
    73  
    74  		cadenceArray := cadence.SearchFieldByName(data, RandomSourceTypeValueFieldName).(cadence.Array)
    75  		source := make([]byte, 8)
    76  		for i := range source {
    77  			source[i] = byte(cadenceArray.Values[i].(cadence.UInt8))
    78  		}
    79  
    80  		return binary.BigEndian.Uint64(source), nil
    81  	}
    82  }
    83  
    84  func revertibleRandomGenerator(backend types.Backend) func() (uint64, error) {
    85  	return func() (uint64, error) {
    86  		rand := make([]byte, 8)
    87  		err := backend.ReadRandom(rand)
    88  		if err != nil {
    89  			return 0, err
    90  		}
    91  
    92  		return binary.BigEndian.Uint64(rand), nil
    93  	}
    94  }
    95  
    96  const ValidationResultTypeIsValidFieldName = "isValid"
    97  
    98  func coaOwnershipProofValidator(contractAddress flow.Address, backend types.Backend) func(proof *types.COAOwnershipProofInContext) (bool, error) {
    99  	return func(proof *types.COAOwnershipProofInContext) (bool, error) {
   100  		value, err := backend.Invoke(
   101  			environment.ContractFunctionSpec{
   102  				AddressFromChain: func(_ flow.Chain) flow.Address {
   103  					return contractAddress
   104  				},
   105  				LocationName: "EVM",
   106  				FunctionName: "validateCOAOwnershipProof",
   107  				ArgumentTypes: []sema.Type{
   108  					types.FlowAddressSemaType,
   109  					types.PublicPathSemaType,
   110  					types.SignedDataSemaType,
   111  					types.KeyIndicesSemaType,
   112  					types.SignaturesSemaType,
   113  					types.AddressBytesSemaType,
   114  				},
   115  			},
   116  			proof.ToCadenceValues(),
   117  		)
   118  		if err != nil {
   119  			if types.IsAFatalError(err) || types.IsABackendError(err) {
   120  				panic(err)
   121  			}
   122  			return false, err
   123  		}
   124  		data, ok := value.(cadence.Struct)
   125  		if !ok {
   126  			return false, fmt.Errorf("invalid output data received from validateCOAOwnershipProof")
   127  		}
   128  
   129  		isValidValue := cadence.SearchFieldByName(data, ValidationResultTypeIsValidFieldName)
   130  		if isValidValue == nil {
   131  			return false, fmt.Errorf("invalid output data received from validateCOAOwnershipProof")
   132  		}
   133  
   134  		return bool(isValidValue.(cadence.Bool)), nil
   135  	}
   136  }