Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

L1handler refactor #2097

Merged
merged 16 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- New required flag `--type` to `account add` command

### Forge

#### Changed

- `L1HandlerTrait::execute()` takes source address and payloads as arguments [Read more here](https://foundry-rs.github.io/starknet-foundry/appendix/cheatcodes/l1_handler.html)


## [0.23.0] - 2024-05-08

### Forge


#### Removed
- `event_name_hash` removal, in favour of `selector!` usage

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,5 @@ fn test_l1_handler() {

let mut l1_handler = L1HandlerTrait::new(checker_address, selector!("handle_l1_message"));

l1_handler.from_address = 123;
l1_handler.payload = array![proxy_address.into(), empty_hash.into(), 2].span();

l1_handler.execute().unwrap();
l1_handler.execute(123, array![proxy_address.into(), empty_hash.into(), 2].span()).unwrap();
}
5 changes: 1 addition & 4 deletions crates/forge/tests/integration/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -675,10 +675,7 @@ fn l1_handler_cost() {

let mut l1_handler = L1HandlerTrait::new(contract_address, selector!("handle_l1_message"));

l1_handler.from_address = 123;
l1_handler.payload = array![].span();

l1_handler.execute().unwrap();
l1_handler.execute(123, array![].span()).unwrap();
}
"#
),
Expand Down
31 changes: 24 additions & 7 deletions crates/forge/tests/integration/l1_handler_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ fn l1_handler_execute() {
use array::{ArrayTrait, SpanTrait};
use core::result::ResultTrait;
use snforge_std::{declare, ContractClassTrait, L1Handler, L1HandlerTrait};
use snforge_std::errors::{ SyscallResultStringErrorTrait, PanicDataOrString };

#[test]
fn l1_handler_execute() {
Expand All @@ -46,10 +47,7 @@ fn l1_handler_execute() {
selector!("process_l1_message")
);

l1_handler.from_address = 0x123;
l1_handler.payload = payload.span();

l1_handler.execute().unwrap();
l1_handler.execute(0x123, payload.span()).unwrap();

let dispatcher = IBalanceTokenDispatcher { contract_address };
assert(dispatcher.get_balance() == 42, dispatcher.get_balance());
Expand All @@ -69,16 +67,35 @@ fn l1_handler_execute() {
selector!("panicking_l1_handler")
);

l1_handler.from_address = 0x123;
l1_handler.payload = array![].span();
match l1_handler.execute() {
match l1_handler.execute(0x123, array![].span()) {
Result::Ok(_) => panic_with_felt252('should have panicked'),
Result::Err(panic_data) => {
assert(*panic_data.at(0) == 'custom', 'Wrong 1st panic datum');
assert(*panic_data.at(1) == 'panic', 'Wrong 2nd panic datum');
},
}
}

#[test]
fn l1_handler_function_missing() {
let calldata = array![0x123];

let contract = declare("l1_handler_executor").unwrap();
let (contract_address, _) = contract.deploy(@calldata).unwrap();


let mut l1_handler = L1HandlerTrait::new(
contract_address,
selector!("this_does_not_exist")
);

match l1_handler.execute(0x123, array![].span()){
Result::Ok(_) => panic_with_felt252('should have panicked'),
Result::Err(_) => {
// Would be nice to assert the error here once it is be possible in cairo
MaksymilianDemitraszek marked this conversation as resolved.
Show resolved Hide resolved
},
}
}
"#
),
Contract::from_code_path(
Expand Down
5 changes: 1 addition & 4 deletions crates/forge/tests/integration/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -896,10 +896,7 @@ fn trace_l1_handler() {

let mut l1_handler = L1HandlerTrait::new(checker_address, selector!("handle_l1_message"));

l1_handler.from_address = 123;
l1_handler.payload = array![proxy_address.into()].span();

l1_handler.execute().unwrap();
l1_handler.execute(123, array![proxy_address.into()].span()).unwrap();
assert_trace(get_call_trace(), proxy_address, checker_address);
}

Expand Down
2 changes: 1 addition & 1 deletion docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
* [sequencer_address](appendix/cheatcodes/sequencer_address.md)
* [get_class_hash](appendix/cheatcodes/get_class_hash.md)
* [replace_bytecode](appendix/cheatcodes/replace_bytecode.md)
* [l1_handler_execute](appendix/cheatcodes/l1_handler_execute.md)
* [l1_handler](appendix/cheatcodes/l1_handler.md)
* [spy_events](appendix/cheatcodes/spy_events.md)
* [store](appendix/cheatcodes/store.md)
* [load](appendix/cheatcodes/load.md)
Expand Down
2 changes: 1 addition & 1 deletion docs/src/appendix/cheatcodes.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
- [`stop_mock_call`](cheatcodes/mock_call.md#stop_mock_call) - cancels the `mock_call` / `start_mock_call` for an entry point
- [`get_class_hash`](cheatcodes/get_class_hash.md) - retrieves a class hash of a contract
- [`replace_bytecode`](cheatcodes/replace_bytecode.md) - replace the class hash of a contract
- [`l1_handler_execute`](cheatcodes/l1_handler_execute.md) - executes a `#[l1_handler]` function to mock a message arriving from Ethereum
- [`l1_handler`](cheatcodes/l1_handler.md) - executes a `#[l1_handler]` function to mock a message arriving from Ethereum
- [`spy_events`](cheatcodes/spy_events.md) - creates `EventSpy` instance which spies on events emitted by contracts
- [`store`](cheatcodes/store.md) - stores values in targeted contact's storage
- [`load`](cheatcodes/load.md) - loads values directly from targeted contact's storage
Expand Down
2 changes: 1 addition & 1 deletion docs/src/appendix/cheatcodes/block_number.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ Changes the block number for the given target.
# `stop_roll`
> `fn stop_roll(target: CheatTarget)`

Cancels the `roll` / `start_roll` for the given target.
Cancels the `roll` / `start_roll` for the given target.
7 changes: 7 additions & 0 deletions docs/src/appendix/cheatcodes/l1_handler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# `l1_handler`

> `fn new(target: ContractAddress, selector: felt252) -> L1Handler`
Returns a structure referring to a L1 handler function.

> `fn execute(self: L1Handler) -> SyscallResult<()>`
Mocks a L1 -> L2 message from Ethereum handled by the given L1 handler function.
81 changes: 0 additions & 81 deletions docs/src/appendix/cheatcodes/l1_handler_execute.md

This file was deleted.

34 changes: 21 additions & 13 deletions snforge_std/src/cheatcodes/l1_handler.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,37 @@ use super::super::_cheatcode::handle_cheatcode;

#[derive(Drop, Clone)]
struct L1Handler {
contract_address: ContractAddress,
function_selector: felt252,
from_address: felt252,
payload: Span::<felt252>,
target: ContractAddress,
selector: felt252,
}

trait L1HandlerTrait {
fn new(contract_address: ContractAddress, function_selector: felt252) -> L1Handler;
fn execute(self: L1Handler) -> SyscallResult<()>;
fn new(target: ContractAddress, selector: felt252) -> L1Handler;
fn execute(
self: L1Handler, from_address: felt252, payload: Span::<felt252>
) -> SyscallResult<()>;
}

impl L1HandlerImpl of L1HandlerTrait {
fn new(contract_address: ContractAddress, function_selector: felt252) -> L1Handler {
L1Handler {
contract_address, function_selector, from_address: 0, payload: array![].span(),
}
/// `target` - The target starknet contract address
/// `selector` - Selector of a `#[l1_handler]` function. Can be acquired with `selector!("function_handler_name")` macro
/// Returns a structure referring to a L1 handler function
fn new(target: ContractAddress, selector: felt252) -> L1Handler {
L1Handler { target, selector, }
}

fn execute(self: L1Handler) -> SyscallResult<()> {
/// Mocks L1 -> L2 message from Ethereum handled by the given L1 handler function
/// `self` - `L1Handler` structure referring to a L1 handler function
/// `from_address` - Ethereum address of the contract that you want to be the message sender
/// `payload` - The handlers' function arguments serialized with `Serde`
/// Returns () or panic data if it failed
fn execute(
self: L1Handler, from_address: felt252, payload: Span::<felt252>
) -> SyscallResult<()> {
let mut inputs: Array::<felt252> = array![
self.contract_address.into(), self.function_selector, self.from_address,
self.target.into(), self.selector, from_address.into(),
];
self.payload.serialize(ref inputs);
payload.serialize(ref inputs);

let mut outputs = handle_cheatcode(cheatcode::<'l1_handler_execute'>(inputs.span()));
let exit_code = *outputs.pop_front().unwrap();
Expand Down
Loading