Skip to content

Commit

Permalink
Merge pull request onflow#5460 from onflow/ramtin/5458-expose-evm-cod…
Browse files Browse the repository at this point in the history
…e-codehash-nonce

[Flow EVM] make EVM address' code/codeHash/nonce accessible
  • Loading branch information
ramtinms authored Feb 27, 2024
2 parents c912767 + f9c5cbf commit 6908b7e
Show file tree
Hide file tree
Showing 4 changed files with 358 additions and 51 deletions.
34 changes: 23 additions & 11 deletions fvm/evm/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,25 +366,32 @@ func (a *Account) Address() types.Address {

// Nonce returns the nonce of this account
//
// TODO: we might need to meter computation for read only operations as well
// currently the storage limits is enforced
// Note: we don't meter any extra computation given reading data
// from the storage already transalates into computation
func (a *Account) Nonce() uint64 {
ctx, err := a.fch.getBlockContext()
nonce, err := a.nonce()
panicOnAnyError(err)
return nonce
}

blk, err := a.fch.emulator.NewReadOnlyBlockView(ctx)
panicOnAnyError(err)
func (a *Account) nonce() (uint64, error) {
ctx, err := a.fch.getBlockContext()
if err != nil {
return 0, err
}

nonce, err := blk.NonceOf(a.address)
panicOnAnyError(err)
blk, err := a.fch.emulator.NewReadOnlyBlockView(ctx)
if err != nil {
return 0, err
}

return nonce
return blk.NonceOf(a.address)
}

// Balance returns the balance of this account
//
// TODO: we might need to meter computation for read only operations as well
// currently the storage limits is enforced
// Note: we don't meter any extra computation given reading data
// from the storage already transalates into computation
func (a *Account) Balance() types.Balance {
bal, err := a.balance()
panicOnAnyError(err)
Expand All @@ -407,6 +414,9 @@ func (a *Account) balance() (types.Balance, error) {
}

// Code returns the code of this account
//
// Note: we don't meter any extra computation given reading data
// from the storage already transalates into computation
func (a *Account) Code() types.Code {
code, err := a.code()
panicOnAnyError(err)
Expand All @@ -427,13 +437,15 @@ func (a *Account) code() (types.Code, error) {
}

// CodeHash returns the code hash of this account
//
// Note: we don't meter any extra computation given reading data
// from the storage already transalates into computation
func (a *Account) CodeHash() []byte {
codeHash, err := a.codeHash()
panicOnAnyError(err)
return codeHash
}

// CodeHash returns the code hash of this account
func (a *Account) codeHash() ([]byte, error) {
ctx, err := a.fch.getBlockContext()
if err != nil {
Expand Down
24 changes: 24 additions & 0 deletions fvm/evm/stdlib/contract.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,30 @@ contract EVM {
)
return Balance(attoflow: balance)
}

/// Nonce of the address
access(all)
fun nonce(): UInt64 {
return InternalEVM.nonce(
address: self.bytes
)
}

/// Code of the address
access(all)
fun code(): [UInt8] {
return InternalEVM.code(
address: self.bytes
)
}

/// CodeHash of the address
access(all)
fun codeHash(): [UInt8] {
return InternalEVM.codeHash(
address: self.bytes
)
}
}

access(all)
Expand Down
147 changes: 147 additions & 0 deletions fvm/evm/stdlib/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -1342,6 +1342,132 @@ func newInternalEVMTypeBalanceFunction(
)
}

const internalEVMTypeNonceFunctionName = "nonce"

var internalEVMTypeNonceFunctionType = &sema.FunctionType{
Parameters: []sema.Parameter{
{
Label: "address",
TypeAnnotation: sema.NewTypeAnnotation(evmAddressBytesType),
},
},
ReturnTypeAnnotation: sema.NewTypeAnnotation(sema.UInt64Type),
}

// newInternalEVMTypeNonceFunction returns the nonce of the account
func newInternalEVMTypeNonceFunction(
gauge common.MemoryGauge,
handler types.ContractHandler,
) *interpreter.HostFunctionValue {
return interpreter.NewHostFunctionValue(
gauge,
internalEVMTypeCallFunctionType,
func(invocation interpreter.Invocation) interpreter.Value {
inter := invocation.Interpreter
locationRange := invocation.LocationRange

addressValue, ok := invocation.Arguments[0].(*interpreter.ArrayValue)
if !ok {
panic(errors.NewUnreachableError())
}

address, err := AddressBytesArrayValueToEVMAddress(inter, locationRange, addressValue)
if err != nil {
panic(err)
}

const isAuthorized = false
account := handler.AccountByAddress(address, isAuthorized)

return interpreter.UInt64Value(account.Nonce())
},
)
}

const internalEVMTypeCodeFunctionName = "code"

var internalEVMTypeCodeFunctionType = &sema.FunctionType{
Parameters: []sema.Parameter{
{
Label: "address",
TypeAnnotation: sema.NewTypeAnnotation(evmAddressBytesType),
},
},
ReturnTypeAnnotation: sema.NewTypeAnnotation(sema.ByteArrayType),
}

// newInternalEVMTypeCodeFunction returns the code of the account
func newInternalEVMTypeCodeFunction(
gauge common.MemoryGauge,
handler types.ContractHandler,
) *interpreter.HostFunctionValue {
return interpreter.NewHostFunctionValue(
gauge,
internalEVMTypeCallFunctionType,
func(invocation interpreter.Invocation) interpreter.Value {
inter := invocation.Interpreter
locationRange := invocation.LocationRange

addressValue, ok := invocation.Arguments[0].(*interpreter.ArrayValue)
if !ok {
panic(errors.NewUnreachableError())
}

address, err := AddressBytesArrayValueToEVMAddress(inter, locationRange, addressValue)
if err != nil {
panic(err)
}

const isAuthorized = false
account := handler.AccountByAddress(address, isAuthorized)

return interpreter.ByteSliceToByteArrayValue(inter, account.Code())
},
)
}

const internalEVMTypeCodeHashFunctionName = "codeHash"

var internalEVMTypeCodeHashFunctionType = &sema.FunctionType{
Parameters: []sema.Parameter{
{
Label: "address",
TypeAnnotation: sema.NewTypeAnnotation(evmAddressBytesType),
},
},
ReturnTypeAnnotation: sema.NewTypeAnnotation(sema.ByteArrayType),
}

// newInternalEVMTypeCodeHashFunction returns the code hash of the account
func newInternalEVMTypeCodeHashFunction(
gauge common.MemoryGauge,
handler types.ContractHandler,
) *interpreter.HostFunctionValue {
return interpreter.NewHostFunctionValue(
gauge,
internalEVMTypeCallFunctionType,
func(invocation interpreter.Invocation) interpreter.Value {
inter := invocation.Interpreter
locationRange := invocation.LocationRange

addressValue, ok := invocation.Arguments[0].(*interpreter.ArrayValue)
if !ok {
panic(errors.NewUnreachableError())
}

address, err := AddressBytesArrayValueToEVMAddress(inter, locationRange, addressValue)
if err != nil {
panic(err)
}

const isAuthorized = false
account := handler.AccountByAddress(address, isAuthorized)

return interpreter.ByteSliceToByteArrayValue(inter, account.CodeHash())
},
)
}

const internalEVMTypeWithdrawFunctionName = "withdraw"

var internalEVMTypeWithdrawFunctionType = &sema.FunctionType{
Expand Down Expand Up @@ -1596,6 +1722,9 @@ func NewInternalEVMContractValue(
internalEVMTypeWithdrawFunctionName: newInternalEVMTypeWithdrawFunction(gauge, handler),
internalEVMTypeDeployFunctionName: newInternalEVMTypeDeployFunction(gauge, handler),
internalEVMTypeBalanceFunctionName: newInternalEVMTypeBalanceFunction(gauge, handler),
internalEVMTypeNonceFunctionName: newInternalEVMTypeNonceFunction(gauge, handler),
internalEVMTypeCodeFunctionName: newInternalEVMTypeCodeFunction(gauge, handler),
internalEVMTypeCodeHashFunctionName: newInternalEVMTypeCodeHashFunction(gauge, handler),
internalEVMTypeEncodeABIFunctionName: newInternalEVMTypeEncodeABIFunction(gauge, location),
internalEVMTypeDecodeABIFunctionName: newInternalEVMTypeDecodeABIFunction(gauge, location),
internalEVMTypeCastToAttoFLOWFunctionName: newInternalEVMTypeCastToAttoFLOWFunction(gauge, handler),
Expand Down Expand Up @@ -1670,6 +1799,24 @@ var InternalEVMContractType = func() *sema.CompositeType {
internalEVMTypeBalanceFunctionType,
"",
),
sema.NewUnmeteredPublicFunctionMember(
ty,
internalEVMTypeNonceFunctionName,
internalEVMTypeNonceFunctionType,
"",
),
sema.NewUnmeteredPublicFunctionMember(
ty,
internalEVMTypeCodeFunctionName,
internalEVMTypeCodeFunctionType,
"",
),
sema.NewUnmeteredPublicFunctionMember(
ty,
internalEVMTypeCodeHashFunctionName,
internalEVMTypeCodeHashFunctionType,
"",
),
sema.NewUnmeteredPublicFunctionMember(
ty,
internalEVMTypeEncodeABIFunctionName,
Expand Down
Loading

0 comments on commit 6908b7e

Please sign in to comment.