Skip to content

Commit

Permalink
feat: enable txs to address 0 (#951)
Browse files Browse the repository at this point in the history
<!--- 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.2

## 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. -->

- add an "option" struct to pass an optional destination address 
- 
-

<!-- 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/951)
<!-- Reviewable:end -->
  • Loading branch information
enitrat authored Feb 6, 2024
1 parent b6b1283 commit ab68ac1
Show file tree
Hide file tree
Showing 14 changed files with 94 additions and 89 deletions.
66 changes: 0 additions & 66 deletions blockchain-tests-skip.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion scripts/utils/kakarot.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 3 additions & 2 deletions src/kakarot/interfaces/interfaces.cairo
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
%lang starknet

from starkware.cairo.common.uint256 import Uint256
from kakarot.model import model

@contract_interface
namespace IERC20 {
Expand Down Expand Up @@ -102,7 +103,7 @@ namespace IKakarot {

func eth_call(
origin: felt,
to: felt,
to: model.Option,
gas_limit: felt,
gas_price: felt,
value: Uint256,
Expand All @@ -112,7 +113,7 @@ namespace IKakarot {
}

func eth_send_transaction(
to: felt,
to: model.Option,
gas_limit: felt,
gas_price: felt,
value: Uint256,
Expand Down
2 changes: 1 addition & 1 deletion src/kakarot/interpreter.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
5 changes: 3 additions & 2 deletions src/kakarot/kakarot.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
15 changes: 7 additions & 8 deletions src/kakarot/library.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -75,7 +74,7 @@ namespace Kakarot {
bitwise_ptr: BitwiseBuiltin*,
}(
origin: felt,
to: felt,
to: model.Option,
gas_limit: felt,
gas_price: felt,
value: Uint256*,
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
10 changes: 9 additions & 1 deletion src/kakarot/model.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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*,
Expand Down
12 changes: 9 additions & 3 deletions src/utils/eth_transaction.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
11 changes: 11 additions & 0 deletions src/utils/utils.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
5 changes: 4 additions & 1 deletion tests/end_to_end/test_kakarot.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion tests/src/utils/test_eth_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down
18 changes: 18 additions & 0 deletions tests/src/utils/test_utils.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -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 ();
}
16 changes: 16 additions & 0 deletions tests/src/utils/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
11 changes: 8 additions & 3 deletions tests/utils/serde.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
),
Expand Down

0 comments on commit ab68ac1

Please sign in to comment.