github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/evm/types/address.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "encoding/hex" 6 "fmt" 7 8 "github.com/onflow/cadence" 9 "github.com/onflow/cadence/encoding/ccf" 10 "github.com/onflow/cadence/runtime/sema" 11 gethCommon "github.com/onflow/go-ethereum/common" 12 13 "github.com/onflow/flow-go/model/flow" 14 ) 15 16 // FlowEVMSpecialAddressPrefixLen captures the number of prefix bytes with constant values for special accounts (extended precompiles and COAs). 17 // 18 // The prefix length should insure a high-enough level of security against finding a preimage using the hash 19 // function used for EVM addresses generation (Keccak256). This is required to avoid finding an EVM address 20 // that is also a valid FlowEVM address. 21 // The target (minimal) security in this case is the security level provided by EVM addresses. 22 // Since EVM addresses are 160-bits long, they offer only 80 bits of security (collision resistance 23 // offers the lowest level). 24 // A preimage resistance of 80 bits requires the prefix to be at least 80-bits long (i.e 10 bytes). 25 // When used as a prefix in EVM addresses (20-bytes long), a prefix length of 12 bytes 26 // leaves a variable part of 8 bytes (64 bits). 27 const FlowEVMSpecialAddressPrefixLen = 12 28 29 const COAAddressTemplate = "A.%v.EVM.CadenceOwnedAccountCreated" 30 31 var ( 32 // Using leading zeros for prefix helps with the storage compactness. 33 // 34 // Prefix for the built-in EVM precompiles 35 FlowEVMNativePrecompileAddressPrefix = [FlowEVMSpecialAddressPrefixLen]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 36 // Prefix for the extended precompiles 37 FlowEVMExtendedPrecompileAddressPrefix = [FlowEVMSpecialAddressPrefixLen]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} 38 // Prefix for the COA addresses 39 FlowEVMCOAAddressPrefix = [FlowEVMSpecialAddressPrefixLen]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2} 40 ) 41 42 // Address is an EVM-compatible address 43 type Address gethCommon.Address 44 45 // AddressLength holds the number of bytes used for each EVM address 46 const AddressLength = gethCommon.AddressLength 47 48 // NewAddress constructs a new Address 49 func NewAddress(addr gethCommon.Address) Address { 50 return Address(addr) 51 } 52 53 // EmptyAddress is an empty evm address 54 var EmptyAddress = Address(gethCommon.Address{}) 55 56 // Bytes returns a byte slice for the address 57 func (fa Address) Bytes() []byte { 58 return fa[:] 59 } 60 61 // String returns the hex encoding of the address 62 // it returns empty string if address is empty 63 func (fa Address) String() string { 64 if fa == EmptyAddress { 65 return "" 66 } 67 return fa.ToCommon().Hex() 68 } 69 70 // ToCommon returns the geth address 71 func (fa Address) ToCommon() gethCommon.Address { 72 return gethCommon.Address(fa) 73 } 74 75 // NewAddressFromBytes constructs a new address from bytes 76 func NewAddressFromBytes(inp []byte) Address { 77 return Address(gethCommon.BytesToAddress(inp)) 78 } 79 80 const CadenceOwnedAccountCreatedTypeAddressFieldName = "address" 81 82 func COAAddressFromFlowCOACreatedEvent(evmContractAddress flow.Address, event flow.Event) (Address, error) { 83 // check the type first 84 if string(event.Type) != fmt.Sprintf(COAAddressTemplate, evmContractAddress.Hex()) { 85 return Address{}, fmt.Errorf("wrong event type is passed") 86 } 87 88 // then decode 89 eventData, err := ccf.Decode(nil, event.Payload) 90 if err != nil { 91 return Address{}, err 92 } 93 94 cadenceEvent, ok := eventData.(cadence.Event) 95 if !ok { 96 return Address{}, fmt.Errorf("event data is not a cadence event") 97 } 98 99 addressValue := cadence.SearchFieldByName( 100 cadenceEvent, 101 CadenceOwnedAccountCreatedTypeAddressFieldName, 102 ) 103 104 addressString, ok := addressValue.(cadence.String) 105 if !ok { 106 return Address{}, fmt.Errorf("address is not a string") 107 } 108 109 addressBytes, err := hex.DecodeString(string(addressString)) 110 if err != nil { 111 return Address{}, err 112 } 113 114 return NewAddressFromBytes(addressBytes), nil 115 } 116 117 // NewAddressFromString constructs a new address from an string 118 func NewAddressFromString(str string) Address { 119 return NewAddressFromBytes([]byte(str)) 120 } 121 122 var AddressBytesCadenceType = cadence.NewConstantSizedArrayType(AddressLength, cadence.UInt8Type) 123 var AddressBytesSemaType = sema.ByteArrayType 124 125 func (a Address) ToCadenceValue() cadence.Array { 126 values := make([]cadence.Value, len(a)) 127 for i, v := range a { 128 values[i] = cadence.NewUInt8(v) 129 } 130 return cadence.NewArray(values). 131 WithType(AddressBytesCadenceType) 132 } 133 134 // IsACOAAddress returns true if the address is a COA address 135 // 136 // This test insures `addr` has been generated as a COA address with high probability. 137 // Brute forcing an EVM address `addr` to pass the `IsACOAAddress` test is as hard as the bit-length 138 // of `FlowEVMCOAAddressPrefix` (here 96 bits). 139 // Although this is lower than the protocol-wide security level in Flow (128 bits), it remains 140 // higher than the EVM addresses security (80 bits when considering collision attacks) 141 func IsACOAAddress(addr Address) bool { 142 return bytes.HasPrefix(addr[:], FlowEVMCOAAddressPrefix[:]) 143 } 144 145 // IsAnExtendedPrecompileAddress returns true if the address is a extended precompile address 146 func IsAnExtendedPrecompileAddress(addr Address) bool { 147 return bytes.HasPrefix(addr[:], FlowEVMExtendedPrecompileAddressPrefix[:]) 148 }