Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EVM] Contract deploy change return value #5606

Merged
merged 35 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
fc3e408
update contract deploy to return result
Mar 29, 2024
a5c5217
update account type
Mar 29, 2024
794de19
update comments
Mar 29, 2024
0aa5fa7
return result on deploy
Mar 29, 2024
0ffb4d6
update deploy handler to return address as result
Mar 29, 2024
b7a5bfa
account fix comment
Mar 29, 2024
9e81add
update the test with new result type
Mar 29, 2024
dc70221
handler tests fix
Mar 29, 2024
5db7042
panic on error only
Apr 2, 2024
9745641
assign result in emulator
Apr 2, 2024
5ddbfb2
overwrite deployed address for call
Apr 2, 2024
9d3d855
update evm test
Apr 2, 2024
8819c86
handler test update
Apr 2, 2024
2c3a9ae
fix evm test assertion
Apr 2, 2024
04cf4c8
fix contract test
Apr 2, 2024
82520ec
update comment
Apr 2, 2024
a1e51e9
add contract address field
Apr 11, 2024
48445ed
update name
Apr 11, 2024
5bfcb86
add deployed contract address
Apr 11, 2024
d5f9a84
use deployed contract address field
Apr 11, 2024
1269e91
add init contract address
Apr 11, 2024
3fb8536
result to evm result
Apr 11, 2024
611156d
test the evm deploy result
Apr 11, 2024
bc60205
specify deployment contract
Apr 11, 2024
e0ff8fa
add empty address check for non-deploy
Apr 11, 2024
46bef61
fix deploy address test
Apr 11, 2024
403b9af
change result to be optional
Apr 22, 2024
904ee8c
fix name change
Apr 23, 2024
167bee1
change the result type for deployed contract to be pointer, so it can…
Apr 23, 2024
4a7b100
make the result deployed address pointer and optional
Apr 23, 2024
49b7f43
set optional if contract address not present
Apr 23, 2024
cc1e6a2
test changes with optional
Apr 23, 2024
0a0b559
additional check for contract addr
Apr 23, 2024
7be61a9
Merge branch 'master' into gregor/evm/deploy-result
devbugging Apr 23, 2024
7458cfe
Merge branch 'master' into gregor/evm/deploy-result
devbugging Apr 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions fvm/evm/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -558,10 +558,10 @@ func (a *Account) transfer(to types.Address, balance types.Balance) (*types.Resu
// Deploy deploys a contract to the EVM environment
// the new deployed contract would be at the returned address and
// the contract data is not controlled by the caller accounts
func (a *Account) Deploy(code types.Code, gaslimit types.GasLimit, balance types.Balance) types.Address {
func (a *Account) Deploy(code types.Code, gaslimit types.GasLimit, balance types.Balance) *types.ResultSummary {
res, err := a.deploy(code, gaslimit, balance)
panicOnErrorOrInvalidOrFailedState(res, err)
return types.Address(res.DeployedContractAddress)
return res.ResultSummary()
}

func (a *Account) deploy(code types.Code, gaslimit types.GasLimit, balance types.Balance) (*types.Result, error) {
Expand Down
8 changes: 6 additions & 2 deletions fvm/evm/handler/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,8 @@ func TestHandler_COA(t *testing.T) {
require.Equal(t, bal, foa.Balance())

testContract := testutils.GetStorageTestContract(t)
addr := foa.Deploy(testContract.ByteCode, math.MaxUint64, types.NewBalanceFromUFix64(0))
result := foa.Deploy(testContract.ByteCode, math.MaxUint64, types.NewBalanceFromUFix64(0))
addr := result.DeployedContractAddress
require.NotNil(t, addr)

num := big.NewInt(22)
Expand Down Expand Up @@ -655,8 +656,11 @@ func TestHandler_COA(t *testing.T) {
foa.Deposit(vault)

testContract := testutils.GetStorageTestContract(t)
addr := foa.Deploy(testContract.ByteCode, math.MaxUint64, types.EmptyBalance)
result := foa.Deploy(testContract.ByteCode, math.MaxUint64, types.EmptyBalance)
addr := result.DeployedContractAddress
require.NotNil(t, addr)
require.Equal(t, types.StatusSuccessful, result.Status)
require.Equal(t, types.ErrCodeNoError, result.ErrorCode)

ret := foa.Call(
addr,
Expand Down
10 changes: 5 additions & 5 deletions fvm/evm/stdlib/contract.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -255,20 +255,20 @@ contract EVM {
}

/// Deploys a contract to the EVM environment.
/// Returns the address of the newly deployed contract
/// Returns the result which contains address of
/// the newly deployed contract
access(all)
fun deploy(
code: [UInt8],
gasLimit: UInt64,
value: Balance
): EVMAddress {
let addressBytes = InternalEVM.deploy(
): Result {
return InternalEVM.deploy(
from: self.addressBytes,
code: code,
gasLimit: gasLimit,
value: value.attoflow
)
return EVMAddress(bytes: addressBytes)
) as! Result
}

/// Calls a function with the given data.
Expand Down
32 changes: 29 additions & 3 deletions fvm/evm/stdlib/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,29 @@ func ContractCode(flowTokenAddress flow.Address, evmAbiOnly bool) []byte {
}

const ContractName = "EVM"

const evmAddressTypeBytesFieldName = "bytes"

const evmAddressTypeQualifiedIdentifier = "EVM.EVMAddress"

const evmBalanceTypeQualifiedIdentifier = "EVM.Balance"

const evmResultTypeQualifiedIdentifier = "EVM.Result"

const evmStatusTypeQualifiedIdentifier = "EVM.Status"

const evmBlockTypeQualifiedIdentifier = "EVM.EVMBlock"

const abiEncodingByteSize = 32

var EVMTransactionBytesCadenceType = cadence.NewVariableSizedArrayType(cadence.TheUInt8Type)

var evmTransactionBytesType = sema.NewVariableSizedType(nil, sema.UInt8Type)

var evmAddressBytesType = sema.NewConstantSizedType(nil, sema.UInt8Type, types.AddressLength)

var evmAddressBytesStaticType = interpreter.ConvertSemaArrayTypeToStaticArrayType(nil, evmAddressBytesType)

var EVMAddressBytesCadenceType = cadence.NewConstantSizedArrayType(types.AddressLength, cadence.TheUInt8Type)

// abiEncodingError
Expand Down Expand Up @@ -264,19 +273,33 @@ func newInternalEVMTypeEncodeABIFunction(
}

var gethTypeString = gethABI.Type{T: gethABI.StringTy}

var gethTypeBool = gethABI.Type{T: gethABI.BoolTy}

var gethTypeUint8 = gethABI.Type{T: gethABI.UintTy, Size: 8}

var gethTypeUint16 = gethABI.Type{T: gethABI.UintTy, Size: 16}

var gethTypeUint32 = gethABI.Type{T: gethABI.UintTy, Size: 32}

var gethTypeUint64 = gethABI.Type{T: gethABI.UintTy, Size: 64}

var gethTypeUint128 = gethABI.Type{T: gethABI.UintTy, Size: 128}

var gethTypeUint256 = gethABI.Type{T: gethABI.UintTy, Size: 256}

var gethTypeInt8 = gethABI.Type{T: gethABI.IntTy, Size: 8}

var gethTypeInt16 = gethABI.Type{T: gethABI.IntTy, Size: 16}

var gethTypeInt32 = gethABI.Type{T: gethABI.IntTy, Size: 32}

var gethTypeInt64 = gethABI.Type{T: gethABI.IntTy, Size: 64}

var gethTypeInt128 = gethABI.Type{T: gethABI.IntTy, Size: 128}

var gethTypeInt256 = gethABI.Type{T: gethABI.IntTy, Size: 256}

var gethTypeAddress = gethABI.Type{Size: 20, T: gethABI.AddressTy}

func gethABIType(staticType interpreter.StaticType, evmAddressTypeID common.TypeID) (gethABI.Type, bool) {
Expand Down Expand Up @@ -1579,7 +1602,8 @@ var internalEVMTypeDeployFunctionType = &sema.FunctionType{
TypeAnnotation: sema.NewTypeAnnotation(sema.UIntType),
},
},
ReturnTypeAnnotation: sema.NewTypeAnnotation(evmAddressBytesType),
// Actually EVM.Result, but cannot refer to it here
ReturnTypeAnnotation: sema.NewTypeAnnotation(sema.AnyStructType),
}

func newInternalEVMTypeDeployFunction(
Expand Down Expand Up @@ -1639,9 +1663,11 @@ func newInternalEVMTypeDeployFunction(

const isAuthorized = true
account := handler.AccountByAddress(fromAddress, isAuthorized)
address := account.Deploy(code, gasLimit, amount)
result := account.Deploy(code, gasLimit, amount)

return EVMAddressToAddressBytesArrayValue(inter, address)
// assign deployed contract address to return value since it's the only result of the deploy
result.ReturnedValue = result.DeployedContractAddress[:]
return NewResultValue(handler, gauge, inter, locationRange, result)
},
)
}
Expand Down
25 changes: 12 additions & 13 deletions fvm/evm/stdlib/contract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ type testFlowAccount struct {
transfer func(address types.Address, balance types.Balance)
deposit func(vault *types.FLOWTokenVault)
withdraw func(balance types.Balance) *types.FLOWTokenVault
deploy func(code types.Code, limit types.GasLimit, balance types.Balance) types.Address
deploy func(code types.Code, limit types.GasLimit, balance types.Balance) *types.ResultSummary
call func(address types.Address, data types.Data, limit types.GasLimit, balance types.Balance) *types.ResultSummary
}

Expand Down Expand Up @@ -150,7 +150,7 @@ func (t *testFlowAccount) Withdraw(balance types.Balance) *types.FLOWTokenVault
return t.withdraw(balance)
}

func (t *testFlowAccount) Deploy(code types.Code, limit types.GasLimit, balance types.Balance) types.Address {
func (t *testFlowAccount) Deploy(code types.Code, limit types.GasLimit, balance types.Balance) *types.ResultSummary {
if t.deploy == nil {
panic("unexpected Deploy")
}
Expand Down Expand Up @@ -3589,20 +3589,23 @@ func TestCadenceOwnedAccountDeploy(t *testing.T) {
require.NoError(t, err)

handler := &testContractHandler{
flowTokenAddress: common.Address(contractsAddress),
evmContractAddress: common.Address(contractsAddress),
accountByAddress: func(fromAddress types.Address, isAuthorized bool) types.Account {
assert.Equal(t, types.Address{3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, fromAddress)
assert.True(t, isAuthorized)

return &testFlowAccount{
address: fromAddress,
deploy: func(code types.Code, limit types.GasLimit, balance types.Balance) types.Address {
deploy: func(code types.Code, limit types.GasLimit, balance types.Balance) *types.ResultSummary {
deployed = true
assert.Equal(t, types.Code{4, 5, 6}, code)
assert.Equal(t, types.GasLimit(9999), limit)
assert.Equal(t, types.NewBalanceFromUFix64(expectedBalance), balance)

return types.Address{4}
return &types.ResultSummary{
Status: types.StatusSuccessful,
DeployedContractAddress: types.Address{4},
}
},
}
},
Expand All @@ -3615,18 +3618,17 @@ func TestCadenceOwnedAccountDeploy(t *testing.T) {

script := []byte(`
import EVM from 0x1
import FlowToken from 0x1

access(all)
fun main(): [UInt8; 20] {
fun main(): [UInt8] {
let cadenceOwnedAccount <- EVM.createCadenceOwnedAccount()
let address = cadenceOwnedAccount.deploy(
let res = cadenceOwnedAccount.deploy(
code: [4, 5, 6],
gasLimit: 9999,
value: EVM.Balance(flow: 1230000000000000000)
)
destroy cadenceOwnedAccount
return address.bytes
return res.data
}
`)

Expand Down Expand Up @@ -3696,10 +3698,7 @@ func TestCadenceOwnedAccountDeploy(t *testing.T) {
cadence.UInt8(0), cadence.UInt8(0),
cadence.UInt8(0), cadence.UInt8(0),
cadence.UInt8(0), cadence.UInt8(0),
}).WithType(cadence.NewConstantSizedArrayType(
types.AddressLength,
cadence.UInt8Type{},
))
}).WithType(cadence.NewVariableSizedArrayType(cadence.UInt8Type{}))

require.Equal(t, expected, actual)

Expand Down
16 changes: 8 additions & 8 deletions fvm/evm/types/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ package types
// deploy contracts to the environment,
// or call methods on contracts without the need to sign a transaction.
type Account interface {
// Returns the address of this account
// Address returns the address of this account
Address() Address

// Returns the balance of this account
// Balance returns the balance of this account
Balance() Balance

// Returns the code of this account
// Code returns the code of this account
Code() Code

// Returns the code hash of this account
// CodeHash returns the code hash of this account
CodeHash() []byte

// Returns the nonce of this account
// Nonce returns the nonce of this account
Nonce() uint64

// Deposit deposits the token from the given vault into this account
Expand All @@ -39,10 +39,10 @@ type Account interface {
Transfer(to Address, balance Balance)

// Deploy deploys a contract to the environment
// the new deployed contract would be at the returned address and
// the contract data is not controlled by the COA
// the new deployed contract would be at the returned
// result address and the contract data is not controlled by the COA
// works only for COAs
Deploy(Code, GasLimit, Balance) Address
Deploy(Code, GasLimit, Balance) *ResultSummary

// Call calls a smart contract function with the given data.
// The gas usage is limited by the given gas limit,
Expand Down
Loading