Skip to content

Commit e0f0992

Browse files
cchudantantiyro
andauthored
fix: l2-to-l1 messaging (#371)
Co-authored-by: antiyro <[email protected]>
1 parent e8b71ff commit e0f0992

File tree

4 files changed

+74
-57
lines changed

4 files changed

+74
-57
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Next release
44

5+
- fix(block_production): get l2-to-l1 messages recursively from the call tree
56
- refactor: replace starknet-rs BlockId with types-rs BlockId and remove redundant mp_block::BlockId
67
- feat(fgw): added `add_transaction` for gateway client
78
- fix(fgw): include `l1_to_l2_consumed_message` in L1 handler receipt

crates/client/devnet/src/lib.rs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -551,22 +551,46 @@ mod tests {
551551
tracing::info!("receipt: {:?}", block.inner.receipts[0]);
552552

553553
let TransactionReceipt::Invoke(receipt) = block.inner.receipts[0].clone() else { unreachable!() };
554+
let fees_fri = block.inner.receipts[0].actual_fee().amount;
554555

555556
if !expect_reverted {
556557
assert_eq!(
557558
receipt,
558559
InvokeTransactionReceipt {
559560
transaction_hash: result.transaction_hash,
560561
messages_sent: vec![],
561-
events: vec![Event {
562-
from_address: ERC20_STRK_CONTRACT_ADDRESS,
563-
// TODO: do not match keys and data yet (unsure)
564-
keys: receipt.events[0].keys.clone(),
565-
data: receipt.events[0].data.clone(),
566-
}],
562+
events: vec![
563+
Event {
564+
from_address: ERC20_STRK_CONTRACT_ADDRESS,
565+
keys: vec![
566+
// Transfer
567+
Felt::from_hex_unchecked(
568+
"0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"
569+
),
570+
// From
571+
contract_0.address,
572+
// To
573+
contract_1.address,
574+
],
575+
// U256 of the amount
576+
data: vec![transfer_amount.into(), Felt::ZERO],
577+
},
578+
Event {
579+
from_address: ERC20_STRK_CONTRACT_ADDRESS,
580+
keys: vec![
581+
Felt::from_hex_unchecked(
582+
"0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"
583+
),
584+
contract_0.address,
585+
sequencer_address,
586+
],
587+
// This is the fees transfer to the sequencer.
588+
data: vec![fees_fri, Felt::ZERO],
589+
},
590+
],
567591
// TODO: resources and fees are not tested because they consistent accross runs, we have to figure out why
568592
execution_resources: receipt.execution_resources.clone(),
569-
actual_fee: FeePayment { amount: receipt.actual_fee.amount, unit: PriceUnit::Fri },
593+
actual_fee: FeePayment { amount: fees_fri, unit: PriceUnit::Fri },
570594
execution_result: receipt.execution_result.clone(), // matched below
571595
}
572596
);

crates/primitives/receipt/src/from_blockifier.rs

Lines changed: 40 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ fn get_l1_handler_message_hash(tx: &L1HandlerTransaction) -> Result<Felt, L1Hand
5959
Ok(Felt::from_bytes_le(message.hash().as_bytes()))
6060
}
6161

62+
fn recursive_call_info_iter(res: &TransactionExecutionInfo) -> impl Iterator<Item = &CallInfo> {
63+
res
64+
.non_optional_call_infos() // all root callinfos
65+
.flat_map(|call_info| call_info.iter()) // flatmap over the roots' recursive inner call infos
66+
}
67+
6268
pub fn from_blockifier_execution_info(res: &TransactionExecutionInfo, tx: &Transaction) -> TransactionReceipt {
6369
let price_unit = match blockifier_tx_fee_type(tx) {
6470
FeeType::Eth => PriceUnit::Wei,
@@ -68,9 +74,6 @@ pub fn from_blockifier_execution_info(res: &TransactionExecutionInfo, tx: &Trans
6874
let actual_fee = FeePayment { amount: res.transaction_receipt.fee.into(), unit: price_unit };
6975
let transaction_hash = blockifier_tx_hash(tx);
7076

71-
let mut events: Vec<Event> = Vec::new();
72-
get_events_from_call_info(res.execute_call_info.as_ref(), 0, &mut events);
73-
7477
let message_hash = match tx {
7578
Transaction::L1HandlerTransaction(tx) => match get_l1_handler_message_hash(tx) {
7679
Ok(hash) => Some(hash),
@@ -82,16 +85,29 @@ pub fn from_blockifier_execution_info(res: &TransactionExecutionInfo, tx: &Trans
8285
_ => None,
8386
};
8487

85-
let messages_sent = res
86-
.non_optional_call_infos()
88+
let messages_sent = recursive_call_info_iter(res)
8789
.flat_map(|call| {
8890
call.execution.l2_to_l1_messages.iter().map(|message| MsgToL1 {
91+
// Note: storage address here to identify the contract. Not caller address nor code address, because of delegate (library) calls.
8992
from_address: call.call.storage_address.into(),
9093
to_address: message.message.to_address.into(),
9194
payload: message.message.payload.0.clone(),
9295
})
9396
})
9497
.collect();
98+
let events = recursive_call_info_iter(res)
99+
.flat_map(|call| {
100+
call.execution.events.iter().map(|event| Event {
101+
// See above for why we use storage address.
102+
from_address: call.call.storage_address.into(),
103+
keys: event.event.keys.iter().map(|k| k.0).collect(),
104+
data: event.event.data.0.clone(),
105+
})
106+
})
107+
.collect();
108+
109+
// Note: these should not be iterated over recursively because they include the inner calls
110+
// We only add up the root calls here without recursing into the inner calls.
95111

96112
let get_applications = |resource| {
97113
res.non_optional_call_infos()
@@ -172,49 +188,9 @@ impl From<GasVector> for L1Gas {
172188
}
173189
}
174190

175-
/// To get all the events from the CallInfo including the inner call events.
176-
fn get_events_from_call_info(call_info: Option<&CallInfo>, next_order: usize, events_vec: &mut Vec<Event>) -> usize {
177-
let mut event_idx = 0;
178-
let mut inner_call_idx = 0;
179-
let mut next_order = next_order;
180-
181-
let call_info = match call_info {
182-
Some(call) => call,
183-
None => return 0,
184-
};
185-
186-
loop {
187-
if event_idx < call_info.execution.events.len() {
188-
let ordered_event = &call_info.execution.events[event_idx];
189-
if ordered_event.order == next_order {
190-
let event = Event {
191-
from_address: call_info.call.storage_address.into(),
192-
keys: ordered_event.event.keys.iter().map(|k| k.0).collect(),
193-
data: ordered_event.event.data.0.clone(),
194-
};
195-
events_vec.push(event);
196-
next_order += 1;
197-
event_idx += 1;
198-
continue;
199-
}
200-
}
201-
202-
if inner_call_idx < call_info.inner_calls.len() {
203-
next_order =
204-
get_events_from_call_info(Some(&call_info.inner_calls[inner_call_idx]), next_order, events_vec);
205-
inner_call_idx += 1;
206-
continue;
207-
}
208-
209-
break;
210-
}
211-
212-
next_order
213-
}
214-
215191
#[cfg(test)]
216192
mod events_logic_tests {
217-
use crate::from_blockifier::get_events_from_call_info;
193+
use super::*;
218194
use crate::Event;
219195
use blockifier::execution::call_info::{CallExecution, CallInfo, OrderedEvent};
220196
use rstest::rstest;
@@ -223,17 +199,31 @@ mod events_logic_tests {
223199

224200
#[rstest]
225201
fn test_event_ordering() {
226-
let mut events = Vec::new();
227202
let nested_calls = create_call_info(
228203
0,
229204
vec![create_call_info(
230205
1,
231206
vec![create_call_info(2, vec![create_call_info(3, vec![create_call_info(4, vec![])])])],
232207
)],
233208
);
234-
get_events_from_call_info(Some(&nested_calls), 0, &mut events);
235-
236-
let expected_events_ordering = vec![event(0), event(1), event(2), event(3), event(4)];
209+
let call_2 = create_call_info(5, vec![]);
210+
let events: Vec<_> = recursive_call_info_iter(&TransactionExecutionInfo {
211+
validate_call_info: Some(nested_calls),
212+
execute_call_info: None,
213+
fee_transfer_call_info: Some(call_2),
214+
revert_error: None,
215+
transaction_receipt: Default::default(),
216+
})
217+
.flat_map(|call| {
218+
call.execution.events.iter().map(|event| Event {
219+
// See above for why we use storage address.
220+
from_address: call.call.storage_address.into(),
221+
keys: event.event.keys.iter().map(|k| k.0).collect(),
222+
data: event.event.data.0.clone(),
223+
})
224+
})
225+
.collect();
226+
let expected_events_ordering = vec![event(0), event(1), event(2), event(3), event(4), event(5)];
237227

238228
assert_eq!(expected_events_ordering, events);
239229
}

scripts/e2e-tests.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ set -e
66

77
# will also launch anvil and automatically close it down on error or success
88

9+
export PROPTEST_CASES=10
10+
911
anvil --fork-url https://eth.merkle.io --fork-block-number 20395662 &
1012

1113
subshell() {

0 commit comments

Comments
 (0)