Skip to content

Commit

Permalink
[KGA-71][KGA-69][KGA-66][KGA-115][KGA-123] fix: remove messaging (#1623)
Browse files Browse the repository at this point in the history
Feature needs rework. Will not be used until further notice.

code-423n4/2024-09-kakarot-findings#111
code-423n4/2024-09-kakarot-findings#105
  • Loading branch information
obatirou authored Nov 20, 2024
1 parent df0f345 commit bdfa507
Show file tree
Hide file tree
Showing 25 changed files with 16 additions and 959 deletions.
4 changes: 0 additions & 4 deletions cairo_zero/kakarot/constants.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,12 @@ namespace Constants {

// Kakarot precompiles
const CAIRO_WHITELISTED_CALL_PRECOMPILE = 0x75001;
const CAIRO_MESSAGING_PRECOMPILE = 0x75002;
const CAIRO_MULTICALL_PRECOMPILE = 0x75003;
const CAIRO_CALL_PRECOMPILE = 0x75004;

// FIELD PRIME
const FELT252_PRIME_HIGH = 0x8000000000000110000000000000000;
const FELT252_PRIME_LOW = 0x1;

// Infinite gas handle_l1_message
const INFINITE_GAS = 2 ** 64 - 1;
}

// See model.Opcode:
Expand Down
6 changes: 0 additions & 6 deletions cairo_zero/kakarot/interfaces/interfaces.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -178,12 +178,6 @@ namespace IKakarot {
func set_authorized_pre_eip155_tx(sender_address: felt, msg_hash: felt) {
}

func set_l1_messaging_contract_address(l1_messaging_contract_address: felt) {
}

func get_l1_messaging_contract_address() -> (l1_messaging_contract_address: felt) {
}

func eth_call(
nonce: felt,
origin: felt,
Expand Down
45 changes: 0 additions & 45 deletions cairo_zero/kakarot/kakarot.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -325,48 +325,3 @@ func set_authorized_pre_eip155_tx{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*
IAccount.set_authorized_pre_eip155_tx(sender_starknet_address, msg_hash);
return ();
}

// @notice Sets the L1 messaging contract address
// @param l1_messaging_contract_address The address of the L1 messaging contract
@external
func set_l1_messaging_contract_address{
syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr
}(l1_messaging_contract_address: felt) {
Ownable.assert_only_owner();
return Kakarot.set_l1_messaging_contract_address(l1_messaging_contract_address);
}

// @notice Gets the L1 messaging contract address
// @return l1_messaging_contract_address The address of the L1 messaging contract
@external
func get_l1_messaging_contract_address{
syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr
}() -> (l1_messaging_contract_address: felt) {
let l1_messaging_contract_address = Kakarot.get_l1_messaging_contract_address();
return (l1_messaging_contract_address=l1_messaging_contract_address);
}

// @notice Handles messages from L1
// @param from_address The address of the L1 contract sending the message
// @param l1_sender The address of the L1 account that initiated the message
// @param to_address The target address on L2
// @param value The amount of native tokens to be transferred
// @param data_len The length of the EVM calldata
// @param data The EVM calldata
@l1_handler
func handle_l1_message{
syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*
}(from_address: felt, l1_sender: felt, to_address: felt, value: felt, data_len: felt, data: felt*) {
alloc_locals;
Pausable.assert_not_paused();
let l1_messaging_contract_address = Kakarot.get_l1_messaging_contract_address();
if (from_address != l1_messaging_contract_address) {
return ();
}

let (_, state, _, _) = Kakarot.handle_l1_message(l1_sender, to_address, value, data_len, data);

// Reverted or not - commit the state change. If reverted, the state was cleared to only contain gas-related changes.
Starknet.commit(state);
return ();
}
39 changes: 0 additions & 39 deletions cairo_zero/kakarot/library.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ from kakarot.storages import (
Kakarot_chain_id,
Kakarot_evm_to_starknet_address,
Kakarot_authorized_cairo_precompiles_callers,
Kakarot_l1_messaging_contract_address,
)
from kakarot.events import evm_contract_deployed
from kakarot.interpreter import Interpreter
Expand Down Expand Up @@ -404,44 +403,6 @@ namespace Kakarot {
return (evm_address=evm_address);
}

func set_l1_messaging_contract_address{
syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr
}(l1_messaging_contract_address: felt) {
Kakarot_l1_messaging_contract_address.write(l1_messaging_contract_address);
return ();
}

func get_l1_messaging_contract_address{
syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr
}() -> felt {
let (l1_messaging_contract_address) = Kakarot_l1_messaging_contract_address.read();
return l1_messaging_contract_address;
}

// @notice Handle an L1 message
// Gas is paid on L1 through the starknet messaging system hence this should not
// revert due to OOG.
// The gas limit is set to Constants.INFINITE_GAS.
// The gas price is set to 0 so no gas is paid and no refund is given.
func handle_l1_message{
syscall_ptr: felt*,
pedersen_ptr: HashBuiltin*,
range_check_ptr,
bitwise_ptr: BitwiseBuiltin*,
}(l1_sender: felt, to_address: felt, value: felt, data_len: felt, data: felt*) -> (
model.EVM*, model.State*, felt, felt
) {
// TODO: ensure fair gas limits and prices
let (val_high, val_low) = split_felt(value);
tempvar value_u256 = new Uint256(low=val_low, high=val_high);
let to = model.Option(is_some=1, value=to_address);
let (access_list) = alloc();

return eth_call(
0, l1_sender, to, Constants.INFINITE_GAS, 0, value_u256, data_len, data, 0, access_list
);
}

// @notice Initialize the chain ID
// @param chain_id The chain ID
func initialize_chain_id{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
Expand Down
33 changes: 0 additions & 33 deletions cairo_zero/kakarot/precompiles/kakarot_precompiles.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ from kakarot.errors import Errors
from kakarot.interfaces.interfaces import IAccount
from kakarot.account import Account
from kakarot.constants import Constants
from kakarot.storages import Kakarot_l1_messaging_contract_address
from utils.utils import Helpers
from backend.starknet import Starknet

Expand All @@ -28,7 +27,6 @@ const NUMBER_OF_CALLS_BYTES = 32;

// TODO: compute acceptable EVM gas values for Cairo execution
const CAIRO_PRECOMPILE_GAS = 10000;
const CAIRO_MESSAGE_GAS = 5000;

// ! Contains precompiles that are specific to Kakarot.
// !
Expand All @@ -47,11 +45,6 @@ const CAIRO_MESSAGE_GAS = 5000;
// ! A contract should never be whitelisted for usage without extensive review and
// ! auditing.
// !
// ! - 0x75002: Whitelisted Cairo Message Precompile. Allows the whitelisted caller to send messages to
// ! L1. This can only be used by the L2KakarotMessaging contract. The message sent to L1 must be
// ! formatted in a specific way, and only allowing L2KakarotMessaging to send messages to L1
// ! ensures this format is respected.
// !
// ! - 0x75003: Multicall Precompile. Allows the caller to execute `n` Cairo calls in a single
// ! precompile call. This precompile cannot be called with DELEGATECALL / CALLCODE. As such, it can
// ! be used permissionlessly by any contract.
Expand Down Expand Up @@ -153,32 +146,6 @@ namespace KakarotPrecompiles {
);
return (output_len, output, gas_cost, reverted);
}

// @notice Sends a message to L1.
// @dev Only the L2KakarotMessaging contract is allowed to send messages to L1. The caller must
// be whitelisted, and this whitelist _mut_ be enforced upstream.
// @param input_len The length of the input in bytes.
// @param input The input data.
// @param caller_address unused
func cairo_message{
syscall_ptr: felt*,
pedersen_ptr: HashBuiltin*,
range_check_ptr,
bitwise_ptr: BitwiseBuiltin*,
}(input_len: felt, input: felt*, caller_address: felt) -> (
output_len: felt, output: felt*, gas_used: felt, reverted: felt
) {
alloc_locals;

// TODO: implement packing mechanism that doesn't truncate 32-byte values
// let (data_len, data) = Helpers.load_256_bits_array(data_bytes_len, data_ptr);

let (target_address) = Kakarot_l1_messaging_contract_address.read();

send_message_to_l1(target_address, input_len, input);
let (output) = alloc();
return (0, output, CAIRO_MESSAGE_GAS, FALSE);
}
}

namespace Internals {
Expand Down
2 changes: 1 addition & 1 deletion cairo_zero/kakarot/precompiles/precompiles.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ namespace Precompiles {
jmp rel offset;
call KakarotPrecompiles.cairo_call_precompile; // offset 0x0c: precompile 0x75001
ret;
call KakarotPrecompiles.cairo_message; // offset 0x0d: precompile 0x75002
call not_implemented_precompile; // offset 0x0d
ret;
call KakarotPrecompiles.cairo_multicall_precompile; // offset 0x0e: precompile 0x75003
ret;
Expand Down
4 changes: 0 additions & 4 deletions cairo_zero/kakarot/precompiles/precompiles_helpers.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,12 @@ namespace PrecompilesHelpers {
// @notice Return whether the precompile address requires a whitelist.
// @dev The Cairo Call precompile must be whitelisted, as we can use it with DELEGATECALL / CALLCODE
// to preserve the msg.sender of the contract that calls this precompile. Use case: DualVM tokens.
// @dev The Cairo Messaging precompile must be whitelisted, as we format the message payload in a specific Solidity contract.
// @param precompile_address The address of the precompile.
// @return Whether the precompile address requires a whitelist.
func requires_whitelist(precompile_address: felt) -> felt {
if (precompile_address == Constants.CAIRO_WHITELISTED_CALL_PRECOMPILE) {
return TRUE;
}
if (precompile_address == Constants.CAIRO_MESSAGING_PRECOMPILE) {
return TRUE;
}
return FALSE;
}

Expand Down
4 changes: 0 additions & 4 deletions cairo_zero/kakarot/storages.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,3 @@ func Kakarot_chain_id() -> (res: felt) {
@storage_var
func Kakarot_authorized_cairo_precompiles_callers(address: felt) -> (res: felt) {
}

@storage_var
func Kakarot_l1_messaging_contract_address() -> (res: felt) {
}
75 changes: 0 additions & 75 deletions cairo_zero/tests/src/kakarot/precompiles/test_precompiles.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import pytest
from eth_abi import encode
from starkware.starknet.public.abi import get_selector_from_name

from tests.utils.constants import (
CAIRO_MESSAGE_GAS,
CAIRO_PRECOMPILE_GAS,
FIRST_KAKAROT_PRECOMPILE_ADDRESS,
FIRST_ROLLUP_PRECOMPILE_ADDRESS,
Expand Down Expand Up @@ -208,79 +206,6 @@ def test__cairo_precompiles(
)
return

class TestKakarotMessaging:
@SyscallHandler.patch(
"Kakarot_authorized_cairo_precompiles_callers",
AUTHORIZED_CALLER_ADDRESS,
1,
)
@SyscallHandler.patch(
"Kakarot_l1_messaging_contract_address",
0xC0DE,
)
@pytest.mark.parametrize(
"address, caller_address, input_data, to_address, expected_reverted_return_data, expected_reverted",
[
(
0x75002,
AUTHORIZED_CALLER_ADDRESS,
encode(
["uint160", "bytes"], [0xC0DE, encode(["uint128"], [0x2A])]
),
0xC0DE,
b"",
False,
),
(
0x75002,
AUTHORIZED_CALLER_ADDRESS,
encode(["uint160", "bytes"], [0xC0DE, 0x2A.to_bytes(1, "big")]),
0xC0DE,
b"",
False,
),
(
0x75002,
UNAUTHORIZED_CALLER_ADDRESS,
bytes.fromhex("0abcdef0"),
0xC0DE,
b"Kakarot: unauthorizedPrecompile",
True,
),
],
ids=[
"ok_32_bytes_data",
"ok_1_bytes_data",
"ko_unauthorized_caller",
],
)
def test__cairo_message(
self,
caller_address,
cairo_run,
address,
input_data,
to_address,
expected_reverted_return_data,
expected_reverted,
):
address = 0x75002
return_data, reverted, gas_used = cairo_run(
"test__precompiles_run",
address=address,
input=input_data,
caller_address=caller_address,
message_address=address,
)
if expected_reverted:
assert reverted
assert bytes(return_data) == expected_reverted_return_data
return
SyscallHandler.mock_send_message_to_l1.assert_any_call(
to_address=to_address, payload=list(input_data)
)
assert gas_used == CAIRO_MESSAGE_GAS

class TestIsPrecompile:
@pytest.mark.parametrize(
"address", range(0, LAST_ETHEREUM_PRECOMPILE_ADDRESS + 2)
Expand Down
25 changes: 0 additions & 25 deletions cairo_zero/tests/src/kakarot/test_kakarot.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ from kakarot.kakarot import (
transfer_ownership,
upgrade_account,
deploy_externally_owned_account,
handle_l1_message,
pause,
unpause,
initialize_chain_id,
Expand Down Expand Up @@ -253,30 +252,6 @@ func test__upgrade_account{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range
return ();
}

func test__handle_l1_message{
syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*
}() {
tempvar from_address;
tempvar l1_sender;
tempvar to_address;
tempvar value;
tempvar data_len;
let (data) = alloc();

%{
ids.from_address = program_input["from_address"]
ids.l1_sender = program_input["l1_sender"]
ids.to_address = program_input["to_address"]
ids.value = program_input["value"]
ids.data_len = len(program_input["data"])
segments.write_arg(ids.data, list(program_input["data"]))
%}

handle_l1_message(from_address, l1_sender, to_address, value, data_len, data);

return ();
}

func test__pause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
pause();
return ();
Expand Down
31 changes: 0 additions & 31 deletions cairo_zero/tests/src/kakarot/test_kakarot.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,37 +510,6 @@ def test_upgrade_account_should_replace_class(self, cairo_run):
calldata=[0x1234],
)

class TestL1Handler:
@SyscallHandler.patch("Pausable_paused", 1)
def test_should_assert_unpaused(self, cairo_run):
with cairo_error(message="Pausable: paused"):
cairo_run(
"test__handle_l1_message",
from_address=0xABC,
l1_sender=0xABC,
to_address=0xABC,
value=0xABC,
data=[],
)

def test_should_not_handle_message_from_non_l1_messaging_contract(
self, cairo_run
):
"""
Test that the L1 handler does not handle messages when from_address is not the L1
messaging contract address (default is address 0).
If the message were handled, this would fail because no patches are set (e.g. balanceOf,
deploy, all the IAccount interface methods).
"""
cairo_run(
"test__handle_l1_message",
from_address=0xDEAD,
l1_sender=0xABDE1,
to_address=0xABDE1,
value=0x1234,
data=[],
)

class TestEthCall:
@pytest.mark.slow
@pytest.mark.SolmateERC20
Expand Down
Loading

0 comments on commit bdfa507

Please sign in to comment.