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  }