Skip to content

Commit

Permalink
feat: set account bytecode-nonce from kakarot (#1174)
Browse files Browse the repository at this point in the history
feat: set account bytecode-nonce from kakarot

<!--- Please provide a general summary of your changes in the title
above -->

<!-- Give an estimate of the time you spent on this PR in terms of work
days.
Did you spend 0.5 days on this PR or rather 2 days?  -->

Time spent on this PR: 0.1d

## Pull request type

<!-- Please try to limit your pull request to one type,
submit multiple pull requests if needed. -->

Please check the type of change your PR introduces:

- [ ] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no api changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [ ] Other (please describe):

## What is the current behavior?

<!-- Please describe the current behavior that you are modifying,
or link to a relevant issue. -->

Resolves #<Issue number>

## What is the new behavior?

<!-- Please describe the behavior or changes that are being added by
this PR. -->

-
-
-

<!-- Reviewable:start -->
- - -
This change is [<img src="https://reviewable.io/review_button.svg"
height="34" align="absmiddle"
alt="Reviewable"/>](https://reviewable.io/reviews/kkrt-labs/kakarot/1174)
<!-- Reviewable:end -->
  • Loading branch information
enitrat committed Jun 4, 2024
1 parent f7f263c commit 094a55c
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 0 deletions.
25 changes: 25 additions & 0 deletions src/kakarot/kakarot.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,31 @@ func register_account{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_chec
return Kakarot.register_account(evm_address);
}

// @notice Writes to an account's bytecode
// @dev Writes the bytecode to the account's storage.
// @param evm_address The evm address of the account.
// @param bytecode_len The length of the bytecode.
// @param bytecode The bytecode to write.
@external
func write_account_bytecode{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
evm_address: felt, bytecode_len: felt, bytecode: felt*
) {
Ownable.assert_only_owner();
return Kakarot.write_account_bytecode(evm_address, bytecode_len, bytecode);
}

// @notice Writes to an account's nonce
// @dev Writes the nonce to the account's storage.
// @param evm_address The evm address of the account.
// @param nonce The nonce to write.
@external
func write_account_nonce{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
evm_address: felt, nonce: felt
) {
Ownable.assert_only_owner();
return Kakarot.write_account_nonce(evm_address, nonce);
}

// @notice The eth_call function as described in the spec,
// see https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call
// This is a view only function, meaning that it doesn't make any state change.
Expand Down
25 changes: 25 additions & 0 deletions src/kakarot/library.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,31 @@ namespace Kakarot {
return ();
}

// @notice Writes to an account's bytecode
// @param evm_address The evm address of the account.
// @param bytecode_len The length of the bytecode.
// @param bytecode The bytecode to write.
func write_account_bytecode{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
evm_address: felt, bytecode_len: felt, bytecode: felt*
) {
alloc_locals;
let starknet_address = Account.compute_starknet_address(evm_address);
IAccount.write_bytecode(starknet_address, bytecode_len, bytecode);
return ();
}

// @notice Writes to an account's nonce
// @param evm_address The evm address of the account.
// @param nonce The nonce to write.
func write_account_nonce{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
evm_address: felt, nonce: felt
) {
alloc_locals;
let starknet_address = Account.compute_starknet_address(evm_address);
IAccount.set_nonce(starknet_address, nonce);
return ();
}

// @notice Get the EVM address from the transaction
// @dev When to=None, it's a deploy tx so we first compute the target address
// @param to The transaction to parameter
Expand Down
115 changes: 115 additions & 0 deletions tests/end_to_end/test_kakarot.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from starknet_py.contract import Contract
from starknet_py.net.full_node_client import FullNodeClient

from kakarot_scripts.utils.kakarot import get_solidity_artifacts
from kakarot_scripts.utils.starknet import wait_for_transaction
from tests.end_to_end.bytecodes import test_cases
from tests.utils.constants import PRE_FUND_AMOUNT, TRANSACTION_GAS_LIMIT
Expand Down Expand Up @@ -217,6 +218,120 @@ async def test_should_fail_when_account_is_already_registered(
assert receipt.execution_status.name == "REVERTED"
assert "Kakarot: account already registered" in receipt.revert_reason

class TestSetAccountStorage:
class TestWriteAccountBytecode:
async def test_should_set_account_bytecode(
self,
starknet: FullNodeClient,
deploy_externally_owned_account,
invoke,
compute_starknet_address,
get_contract,
random_seed,
):
counter_artifacts = get_solidity_artifacts("PlainOpcodes", "Counter")
evm_address = generate_random_evm_address(random_seed)
await deploy_externally_owned_account(evm_address)

bytecode = list(bytes.fromhex(counter_artifacts["bytecode"][2:]))
await invoke(
"kakarot",
"write_account_bytecode",
int(evm_address, 16),
bytecode,
)

eoa = get_contract(
"account_contract",
address=await compute_starknet_address(evm_address),
)
stored_code = (await eoa.functions["bytecode"].call()).bytecode
assert stored_code == bytecode

async def test_should_fail_not_owner(
self,
starknet: FullNodeClient,
deploy_externally_owned_account,
invoke,
compute_starknet_address,
get_contract,
random_seed,
other,
):
counter_artifacts = get_solidity_artifacts("PlainOpcodes", "Counter")
evm_address = generate_random_evm_address(random_seed)
await deploy_externally_owned_account(evm_address)

bytecode = list(bytes.fromhex(counter_artifacts["bytecode"][2:]))
tx_hash = await invoke(
"kakarot",
"write_account_bytecode",
int(evm_address, 16),
bytecode,
account=other,
)
receipt = await starknet.get_transaction_receipt(tx_hash)
assert receipt.execution_status.name == "REVERTED"
assert "Ownable: caller is not the owner" in receipt.revert_reason

class TestWriteAccountNonce:

async def test_should_set_account_nonce(
self,
starknet: FullNodeClient,
deploy_externally_owned_account,
invoke,
compute_starknet_address,
get_contract,
random_seed,
):
evm_address = generate_random_evm_address(random_seed)
await deploy_externally_owned_account(evm_address)
eoa = get_contract(
"account_contract",
address=await compute_starknet_address(evm_address),
)
prev_nonce = (await eoa.functions["get_nonce"].call()).nonce

await invoke(
"kakarot",
"write_account_nonce",
int(evm_address, 16),
prev_nonce + 1,
)

stored_nonce = (await eoa.functions["get_nonce"].call()).nonce
assert stored_nonce == prev_nonce + 1

async def test_should_fail_not_owner(
self,
starknet: FullNodeClient,
deploy_externally_owned_account,
invoke,
compute_starknet_address,
get_contract,
random_seed,
other,
):
evm_address = generate_random_evm_address(random_seed)
await deploy_externally_owned_account(evm_address)
eoa = get_contract(
"account_contract",
address=await compute_starknet_address(evm_address),
)
prev_nonce = (await eoa.functions["get_nonce"].call()).nonce

tx_hash = await invoke(
"kakarot",
"write_account_nonce",
int(evm_address, 16),
prev_nonce + 1,
account=other,
)
receipt = await starknet.get_transaction_receipt(tx_hash)
assert receipt.execution_status.name == "REVERTED"
assert "Ownable: caller is not the owner" in receipt.revert_reason

class TestEthCallNativeCoinTransfer:
async def test_eth_call_should_succeed(
self,
Expand Down

0 comments on commit 094a55c

Please sign in to comment.