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 }