From edacead03de92aa935c82cdd9ac6882122458807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Walter?= Date: Wed, 25 Oct 2023 17:03:23 +0200 Subject: [PATCH] Add account_type and set nonce to 1 for EOA --- src/kakarot/account.cairo | 41 ++++++++++++------- .../accounts/contract/contract_account.cairo | 8 ++++ .../eoa/externally_owned_account.cairo | 8 ++++ src/kakarot/interfaces/interfaces.cairo | 3 ++ src/kakarot/library.cairo | 8 ++-- .../ef_tests/test_ef_blockchain_tests.py | 2 +- 6 files changed, 51 insertions(+), 19 deletions(-) diff --git a/src/kakarot/account.cairo b/src/kakarot/account.cairo index b3bf60ee5..8531b5d91 100644 --- a/src/kakarot/account.cairo +++ b/src/kakarot/account.cairo @@ -116,8 +116,7 @@ namespace Account { ) { alloc_locals; - let (registered_starknet_account) = get_registered_starknet_address(self.address); - let starknet_account_exists = is_not_zero(registered_starknet_account); + let starknet_account_exists = is_registered(self.address); // Case new Account if (starknet_account_exists == 0) { @@ -150,10 +149,8 @@ namespace Account { return (); } - // Case EOA - // TODO: use supports interface instead of the bytecode_len proxy - let (bytecode_len) = IAccount.bytecode_len(contract_address=starknet_address); - if (bytecode_len == 0) { + let (account_type) = IAccount.account_type(contract_address=starknet_address); + if (account_type == 'EOA') { return (); } @@ -173,8 +170,7 @@ namespace Account { address: model.Address* ) -> model.Account* { alloc_locals; - let (local registered_starknet_account) = get_registered_starknet_address(address.evm); - let starknet_account_exists = is_not_zero(registered_starknet_account); + let starknet_account_exists = is_registered(address.evm); // Case touching a non deployed account if (starknet_account_exists == 0) { @@ -183,17 +179,21 @@ namespace Account { return account; } - // Case EOA - // TODO: use supports interface instead of the bytecode_len proxy - let (bytecode_len, bytecode) = IAccount.bytecode(contract_address=address.starknet); - if (bytecode_len == 0) { + let (account_type) = IAccount.account_type(contract_address=address.starknet); + + if (account_type == 'EOA') { + let (bytecode: felt*) = alloc(); let account = Account.init( - address=address.evm, code_len=bytecode_len, code=bytecode, nonce=0 + // There is no way to access the nonce of an EOA currently + // But putting 1 shouldn't have any impact and is safer than 0 + // since has_code_or_nonce is used in some places to trigger collision + address=address.evm, code_len=0, code=bytecode, nonce=1 ); return account; } // Case CA + let (bytecode_len, bytecode) = IAccount.bytecode(contract_address=address.starknet); let (nonce) = IContractAccount.get_nonce(contract_address=address.starknet); let account = Account.init( address=address.evm, code_len=bytecode_len, code=bytecode, nonce=nonce @@ -234,8 +234,7 @@ namespace Account { } // Case reading from Starknet storage - let (local registered_starknet_account) = get_registered_starknet_address(address.evm); - let starknet_account_exists = is_not_zero(registered_starknet_account); + let starknet_account_exists = is_registered(address.evm); if (starknet_account_exists != 0) { let (value) = IContractAccount.storage( contract_address=address.starknet, storage_addr=storage_addr @@ -427,6 +426,18 @@ namespace Account { } return FALSE; } + + // @notice Tell if an account is already registered + // @param address the address (EVM) as felt + // @return true if the account is already registered + func is_registered{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + address: felt + ) -> felt { + alloc_locals; + let (local registered_starknet_account) = get_registered_starknet_address(address); + let starknet_account_exists = is_not_zero(registered_starknet_account); + return starknet_account_exists; + } } namespace Internals { diff --git a/src/kakarot/accounts/contract/contract_account.cairo b/src/kakarot/accounts/contract/contract_account.cairo index cd21e4144..a4acd5ee0 100644 --- a/src/kakarot/accounts/contract/contract_account.cairo +++ b/src/kakarot/accounts/contract/contract_account.cairo @@ -101,3 +101,11 @@ func get_nonce{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( func set_nonce{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(nonce: felt) { return ContractAccount.set_nonce(nonce); } + +// @notice Returns the account type +@view +func account_type{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( + type: felt +) { + return ('CA',); +} diff --git a/src/kakarot/accounts/eoa/externally_owned_account.cairo b/src/kakarot/accounts/eoa/externally_owned_account.cairo index f30f7670a..b559f9b89 100644 --- a/src/kakarot/accounts/eoa/externally_owned_account.cairo +++ b/src/kakarot/accounts/eoa/externally_owned_account.cairo @@ -136,3 +136,11 @@ func bytecode_len{ }() -> (len: felt) { return (len=0); } + +// @notice Returns the account type +@view +func account_type{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( + type: felt +) { + return ('EOA',); +} diff --git a/src/kakarot/interfaces/interfaces.cairo b/src/kakarot/interfaces/interfaces.cairo index 237887d3e..4743d8542 100644 --- a/src/kakarot/interfaces/interfaces.cairo +++ b/src/kakarot/interfaces/interfaces.cairo @@ -56,6 +56,9 @@ namespace IAccount { func bytecode() -> (bytecode_len: felt, bytecode: felt*) { } + + func account_type() -> (type: felt) { + } } @contract_interface diff --git a/src/kakarot/library.cairo b/src/kakarot/library.cairo index 5140c577b..5aae82306 100644 --- a/src/kakarot/library.cairo +++ b/src/kakarot/library.cairo @@ -129,9 +129,11 @@ namespace Kakarot { let (state, success) = State.add_transfer(state, transfer); // Check collision - let (state, account) = State.get_account(state, address); - let has_code_or_nonce = Account.has_code_or_nonce(account); - let is_collision = has_code_or_nonce * is_deploy_tx; + let is_registered = Account.is_registered(address.evm); + let is_collision = is_registered * is_deploy_tx; + + // Nonce is set to 1 in case of deploy_tx + let account = Account.fetch_or_create(address); let nonce = account.nonce * (1 - is_deploy_tx) + is_deploy_tx; let account = Account.set_nonce(account, nonce); let state = State.set_account(state, address, account); diff --git a/tests/integration/ef_tests/test_ef_blockchain_tests.py b/tests/integration/ef_tests/test_ef_blockchain_tests.py index 77d7aad2d..1dd6dbe60 100644 --- a/tests/integration/ef_tests/test_ef_blockchain_tests.py +++ b/tests/integration/ef_tests/test_ef_blockchain_tests.py @@ -210,7 +210,7 @@ async def test_case( starknet_address = get_starknet_address(int(transaction["sender"], 16)) await kakarot.eth_send_transaction( - to=int(transaction["to"], 16), + to=int(transaction["to"] or "0", 16), gas_limit=int(transaction["gasLimit"], 16), gas_price=int(transaction["gasPrice"], 16), value=int(transaction["value"], 16),