diff --git a/blockchain-tests-skip.yml b/blockchain-tests-skip.yml index 43f149c5b..ba0ab5009 100644 --- a/blockchain-tests-skip.yml +++ b/blockchain-tests-skip.yml @@ -1877,72 +1877,6 @@ testname: - eoaEmpty_d1g0v1_Shanghai - eoaEmpty_d1g1v0_Shanghai - sha3_deja_d0g0v0_Shanghai - stStackTests: - - stackOverflowM1DUP_d0g0v0_Shanghai - - stackOverflowM1DUP_d10g0v0_Shanghai - - stackOverflowM1DUP_d11g0v0_Shanghai - - stackOverflowM1DUP_d12g0v0_Shanghai - - stackOverflowM1DUP_d13g0v0_Shanghai - - stackOverflowM1DUP_d14g0v0_Shanghai - - stackOverflowM1DUP_d15g0v0_Shanghai - - stackOverflowM1DUP_d1g0v0_Shanghai - - stackOverflowM1DUP_d2g0v0_Shanghai - - stackOverflowM1DUP_d3g0v0_Shanghai - - stackOverflowM1DUP_d4g0v0_Shanghai - - stackOverflowM1DUP_d5g0v0_Shanghai - - stackOverflowM1DUP_d6g0v0_Shanghai - - stackOverflowM1DUP_d7g0v0_Shanghai - - stackOverflowM1DUP_d8g0v0_Shanghai - - stackOverflowM1DUP_d9g0v0_Shanghai - - stackOverflowM1PUSH_d0g0v0_Shanghai - - stackOverflowM1PUSH_d10g0v0_Shanghai - - stackOverflowM1PUSH_d11g0v0_Shanghai - - stackOverflowM1PUSH_d12g0v0_Shanghai - - stackOverflowM1PUSH_d13g0v0_Shanghai - - stackOverflowM1PUSH_d14g0v0_Shanghai - - stackOverflowM1PUSH_d15g0v0_Shanghai - - stackOverflowM1PUSH_d16g0v0_Shanghai - - stackOverflowM1PUSH_d17g0v0_Shanghai - - stackOverflowM1PUSH_d18g0v0_Shanghai - - stackOverflowM1PUSH_d19g0v0_Shanghai - - stackOverflowM1PUSH_d1g0v0_Shanghai - - stackOverflowM1PUSH_d20g0v0_Shanghai - - stackOverflowM1PUSH_d21g0v0_Shanghai - - stackOverflowM1PUSH_d22g0v0_Shanghai - - stackOverflowM1PUSH_d23g0v0_Shanghai - - stackOverflowM1PUSH_d24g0v0_Shanghai - - stackOverflowM1PUSH_d25g0v0_Shanghai - - stackOverflowM1PUSH_d26g0v0_Shanghai - - stackOverflowM1PUSH_d27g0v0_Shanghai - - stackOverflowM1PUSH_d28g0v0_Shanghai - - stackOverflowM1PUSH_d29g0v0_Shanghai - - stackOverflowM1PUSH_d2g0v0_Shanghai - - stackOverflowM1PUSH_d30g0v0_Shanghai - - stackOverflowM1PUSH_d3g0v0_Shanghai - - stackOverflowM1PUSH_d4g0v0_Shanghai - - stackOverflowM1PUSH_d5g0v0_Shanghai - - stackOverflowM1PUSH_d6g0v0_Shanghai - - stackOverflowM1PUSH_d7g0v0_Shanghai - - stackOverflowM1PUSH_d8g0v0_Shanghai - - stackOverflowM1PUSH_d9g0v0_Shanghai - - stackOverflowM1_d0g0v0_Shanghai - - stackOverflowM1_d10g0v0_Shanghai - - stackOverflowM1_d11g0v0_Shanghai - - stackOverflowM1_d12g0v0_Shanghai - - stackOverflowM1_d13g0v0_Shanghai - - stackOverflowM1_d14g0v0_Shanghai - - stackOverflowM1_d15g0v0_Shanghai - - stackOverflowM1_d1g0v0_Shanghai - - stackOverflowM1_d2g0v0_Shanghai - - stackOverflowM1_d3g0v0_Shanghai - - stackOverflowM1_d4g0v0_Shanghai - - stackOverflowM1_d5g0v0_Shanghai - - stackOverflowM1_d6g0v0_Shanghai - - stackOverflowM1_d7g0v0_Shanghai - - stackOverflowM1_d8g0v0_Shanghai - - stackOverflowM1_d9g0v0_Shanghai - - stackOverflowSWAP_d0g0v0_Shanghai - - stacksanitySWAP_d0g0v0_Shanghai stStaticCall: - StaticcallToPrecompileFromCalledContract_d0g0v0_Shanghai - StaticcallToPrecompileFromContractInitialization_d0g0v0_Shanghai diff --git a/scripts/utils/kakarot.py b/scripts/utils/kakarot.py index c6782f8f3..8cd64352a 100644 --- a/scripts/utils/kakarot.py +++ b/scripts/utils/kakarot.py @@ -219,7 +219,10 @@ async def _wrapper(self, *args, **kwargs): ) result = await kakarot_contract.functions["eth_call"].call( origin=origin, - to=int(self.address, 16), + to={ + "is_some": 1, + "value": int(self.address, 16), + }, gas_limit=gas_limit, gas_price=gas_price, value=value, diff --git a/src/kakarot/interfaces/interfaces.cairo b/src/kakarot/interfaces/interfaces.cairo index 3570f1608..8c4396143 100644 --- a/src/kakarot/interfaces/interfaces.cairo +++ b/src/kakarot/interfaces/interfaces.cairo @@ -1,6 +1,7 @@ %lang starknet from starkware.cairo.common.uint256 import Uint256 +from kakarot.model import model @contract_interface namespace IERC20 { @@ -102,7 +103,7 @@ namespace IKakarot { func eth_call( origin: felt, - to: felt, + to: model.Option, gas_limit: felt, gas_price: felt, value: Uint256, @@ -112,7 +113,7 @@ namespace IKakarot { } func eth_send_transaction( - to: felt, + to: model.Option, gas_limit: felt, gas_price: felt, value: Uint256, diff --git a/src/kakarot/interpreter.cairo b/src/kakarot/interpreter.cairo index 3ebe84017..50e9ca6f5 100644 --- a/src/kakarot/interpreter.cairo +++ b/src/kakarot/interpreter.cairo @@ -98,7 +98,7 @@ namespace Interpreter { return evm; } let stack_overflow = is_le( - Constants.STACK_MAX_DEPTH, stack.size + opcode.stack_size_diff + 1 + Constants.STACK_MAX_DEPTH + 1, stack.size + opcode.stack_size_diff ); if (stack_overflow != 0) { let (revert_reason_len, revert_reason) = Errors.stackOverflow(); diff --git a/src/kakarot/kakarot.cairo b/src/kakarot/kakarot.cairo index 4b986a710..81f378f10 100644 --- a/src/kakarot/kakarot.cairo +++ b/src/kakarot/kakarot.cairo @@ -14,6 +14,7 @@ from starkware.cairo.common.registers import get_fp_and_pc // Local dependencies from backend.starknet import Starknet from kakarot.account import Account +from kakarot.model import model from kakarot.library import Kakarot from utils.utils import Helpers @@ -145,7 +146,7 @@ func eth_call{ syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* }( origin: felt, - to: felt, + to: model.Option, gas_limit: felt, gas_price: felt, value: Uint256, @@ -183,7 +184,7 @@ func eth_call{ func eth_send_transaction{ syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* }( - to: felt, + to: model.Option, gas_limit: felt, gas_price: felt, value: Uint256, diff --git a/src/kakarot/library.cairo b/src/kakarot/library.cairo index 761d5580c..b83e0bcac 100644 --- a/src/kakarot/library.cairo +++ b/src/kakarot/library.cairo @@ -24,7 +24,6 @@ from kakarot.interpreter import Interpreter from kakarot.instructions.system_operations import CreateHelper from kakarot.interfaces.interfaces import IAccount, IERC20 from kakarot.model import model -from utils.utils import Helpers // @title Kakarot main library file. // @notice This file contains the core EVM execution logic. @@ -75,7 +74,7 @@ namespace Kakarot { bitwise_ptr: BitwiseBuiltin*, }( origin: felt, - to: felt, + to: model.Option, gas_limit: felt, gas_price: felt, value: Uint256*, @@ -85,14 +84,14 @@ namespace Kakarot { access_list: felt*, ) -> (model.EVM*, model.State*, felt) { alloc_locals; + let is_regular_tx = is_not_zero(to.is_some); + let is_deploy_tx = 1 - is_regular_tx; let evm_contract_address = resolve_to(to, origin); let starknet_contract_address = Account.compute_starknet_address(evm_contract_address); tempvar address = new model.Address( starknet=starknet_contract_address, evm=evm_contract_address ); - let is_regular_tx = is_not_zero(to); - let is_deploy_tx = 1 - is_regular_tx; let (bytecode_len, bytecode) = Starknet.get_bytecode(address.evm); let env = Starknet.get_env(origin, gas_price); @@ -187,7 +186,7 @@ namespace Kakarot { } // @notice Get the EVM address from the transaction - // @dev When to=0, it's a deploy tx so we first compute the target address + // @dev When to=None, it's a deploy tx so we first compute the target address // @param to The transaction to parameter // @param origin The transaction origin parameter // @return the target evm address @@ -196,10 +195,10 @@ namespace Kakarot { pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*, - }(to: felt, origin: felt) -> felt { + }(to: model.Option, origin: felt) -> felt { alloc_locals; - if (to != 0) { - return to; + if (to.is_some != 0) { + return to.value; } // TODO: read the nonce from the provided origin address, otherwise in view mode this will // TODO: always use a 0 nonce diff --git a/src/kakarot/model.cairo b/src/kakarot/model.cairo index 4e0d00f20..e84249197 100644 --- a/src/kakarot/model.cairo +++ b/src/kakarot/model.cairo @@ -3,6 +3,14 @@ from starkware.cairo.common.dict import DictAccess from starkware.cairo.common.uint256 import Uint256 namespace model { + // @notice: Represents an optional value. + // @param is_some A boolean indicating whether the value is present. + // @param value The value (if applicable). + struct Option { + is_some: felt, + value: felt, + } + // @notice Info: https://www.evm.codes/about#stack // @notice Stack with a 1024 items maximum size. Each item is a 256 bits word. The stack is used by most // @notice opcodes to consume their parameters from. @@ -187,7 +195,7 @@ namespace model { gas_limit: felt, max_priority_fee_per_gas: felt, max_fee_per_gas: felt, - destination: felt, + destination: Option, amount: Uint256, payload_len: felt, payload: felt*, diff --git a/src/utils/eth_transaction.cairo b/src/utils/eth_transaction.cairo index a6b151e95..bccdecdd6 100644 --- a/src/utils/eth_transaction.cairo +++ b/src/utils/eth_transaction.cairo @@ -44,7 +44,9 @@ namespace EthTransaction { let nonce = Helpers.bytes_to_felt(sub_items[0].data_len, sub_items[0].data); let gas_price = Helpers.bytes_to_felt(sub_items[1].data_len, sub_items[1].data); let gas_limit = Helpers.bytes_to_felt(sub_items[2].data_len, sub_items[2].data); - let destination = Helpers.bytes_to_felt(sub_items[3].data_len, sub_items[3].data); + let destination = Helpers.try_parse_destination_from_bytes( + sub_items[3].data_len, sub_items[3].data + ); let amount = Helpers.bytes_i_to_uint256(sub_items[4].data, sub_items[4].data_len); let payload_len = sub_items[5].data_len; let payload = sub_items[5].data; @@ -84,7 +86,9 @@ namespace EthTransaction { let nonce = Helpers.bytes_to_felt(sub_items[1].data_len, sub_items[1].data); let gas_price = Helpers.bytes_to_felt(sub_items[2].data_len, sub_items[2].data); let gas_limit = Helpers.bytes_to_felt(sub_items[3].data_len, sub_items[3].data); - let destination = Helpers.bytes_to_felt(sub_items[4].data_len, sub_items[4].data); + let destination = Helpers.try_parse_destination_from_bytes( + sub_items[4].data_len, sub_items[4].data + ); let amount = Helpers.bytes_i_to_uint256(sub_items[5].data, sub_items[5].data_len); let payload_len = sub_items[6].data_len; let payload = sub_items[6].data; @@ -133,7 +137,9 @@ namespace EthTransaction { ); let max_fee_per_gas = Helpers.bytes_to_felt(sub_items[3].data_len, sub_items[3].data); let gas_limit = Helpers.bytes_to_felt(sub_items[4].data_len, sub_items[4].data); - let destination = Helpers.bytes_to_felt(sub_items[5].data_len, sub_items[5].data); + let destination = Helpers.try_parse_destination_from_bytes( + sub_items[5].data_len, sub_items[5].data + ); let amount = Helpers.bytes_i_to_uint256(sub_items[6].data, sub_items[6].data_len); let payload_len = sub_items[7].data_len; let payload = sub_items[7].data; diff --git a/src/utils/utils.cairo b/src/utils/utils.cairo index d1404392d..9c97569c0 100644 --- a/src/utils/utils.cairo +++ b/src/utils/utils.cairo @@ -13,6 +13,7 @@ from starkware.cairo.common.bool import FALSE from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin from starkware.cairo.common.hash_state import hash_finalize, hash_init, hash_update +from kakarot.model import model from utils.bytes import uint256_to_bytes32 // @title Helper Functions @@ -210,6 +211,16 @@ namespace Helpers { return current; } + func try_parse_destination_from_bytes(bytes_len: felt, bytes: felt*) -> model.Option { + if (bytes_len != 20) { + let res = model.Option(is_some=0, value=0); + return res; + } + let address = bytes20_to_felt(bytes); + let res = model.Option(is_some=1, value=address); + return res; + } + // @notice This function is used to convert a sequence of 20 bytes big-endian // to felt. // @param val: pointer to the first byte of the 20. diff --git a/tests/end_to_end/test_kakarot.py b/tests/end_to_end/test_kakarot.py index 134ff60a9..df928a8fe 100644 --- a/tests/end_to_end/test_kakarot.py +++ b/tests/end_to_end/test_kakarot.py @@ -169,7 +169,10 @@ async def test_eth_call_should_succeed( result = await kakarot.functions["eth_call"].call( origin=int(evm_address, 16), - to=int(generate_random_evm_address(seed=3), 16), + to={ + "is_some": 1, + "value": int(generate_random_evm_address(seed=3), 16), + }, gas_limit=1_000_000_000, gas_price=1_000, value=1_000, diff --git a/tests/src/utils/test_eth_transaction.py b/tests/src/utils/test_eth_transaction.py index 37cfe7708..1e757c52a 100644 --- a/tests/src/utils/test_eth_transaction.py +++ b/tests/src/utils/test_eth_transaction.py @@ -151,7 +151,7 @@ async def test_should_decode_all_transactions_types( == decoded_tx["max_fee_per_gas"] ) assert transaction["gas"] == decoded_tx["gas_limit"] - assert transaction["to"] == decoded_tx["destination"] + assert transaction["to"] == decoded_tx["destination"]["value"] assert transaction["value"] == int(decoded_tx["amount"], 16) assert transaction["chainId"] == decoded_tx["chain_id"] assert expected_data == decoded_tx["payload"] diff --git a/tests/src/utils/test_utils.cairo b/tests/src/utils/test_utils.cairo index 00de2fdd7..33aaa9ae8 100644 --- a/tests/src/utils/test_utils.cairo +++ b/tests/src/utils/test_utils.cairo @@ -100,3 +100,21 @@ func test__bytes_used_128{range_check_ptr}(output_ptr: felt*) { assert [output_ptr] = bytes_used; return (); } + +func test__try_parse_destination_from_bytes{range_check_ptr}(output_ptr: felt*) { + let (bytes) = alloc(); + tempvar bytes_len; + %{ + segments.write_arg(ids.bytes, program_input["bytes"]) + ids.bytes_len = len(program_input["bytes"]) + %} + + // When + let maybe_address = Helpers.try_parse_destination_from_bytes(bytes_len, bytes); + + // Then + assert [output_ptr] = maybe_address.is_some; + assert [output_ptr + 1] = maybe_address.value; + + return (); +} diff --git a/tests/src/utils/test_utils.py b/tests/src/utils/test_utils.py index 5a54f0908..e90762634 100644 --- a/tests/src/utils/test_utils.py +++ b/tests/src/utils/test_utils.py @@ -66,3 +66,19 @@ def test_should_return_bytes_used_in_128_word(cairo_run, word): word=word, ) assert bytes_length == output[0] + + +@pytest.mark.parametrize( + "bytes,expected", + [ + (b"", [0, 0]), # An empty field + ( + b"\x01" * 20, + [1, 0x0101010101010101010101010101010101010101], + ), # An address of 20 bytes + (b"\x01" * 40, [0, 0]), # and invalid address + ], +) +def test_should_parse_destination_from_bytes(cairo_run, bytes, expected): + result = cairo_run("test__try_parse_destination_from_bytes", bytes=list(bytes)) + assert result == expected diff --git a/tests/utils/serde.py b/tests/utils/serde.py index 0378e06ee..d86f33178 100644 --- a/tests/utils/serde.py +++ b/tests/utils/serde.py @@ -169,9 +169,14 @@ def serialize_eth_transaction(self, tx_ptr): "max_fee_per_gas": self.memory.get( tx_ptr + tx_scope.members["max_fee_per_gas"].offset ), - "destination": to_checksum_address( - f'0x{self.memory.get(tx_ptr + tx_scope.members["destination"].offset):040x}' - ), + "destination": { + "is_some": self.memory.get( + tx_ptr + tx_scope.members["destination"].offset + ), + "value": to_checksum_address( + f'0x{self.memory.get(tx_ptr + tx_scope.members["destination"].offset + 1):040x}' + ), + }, "amount": self.serialize_uint256( tx_ptr + tx_scope.members["amount"].offset ),