Skip to content

Commit 7dd3b09

Browse files
authored
feat: add missing nonce to L1 messages serialization (#341)
Signed-off-by: Gregory Edison <[email protected]>
1 parent aac8ed3 commit 7dd3b09

File tree

2 files changed

+74
-6
lines changed

2 files changed

+74
-6
lines changed

crates/scroll/alloy/consensus/src/transaction/l1_message.rs

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,18 @@ pub const L1_MESSAGE_TRANSACTION_TYPE: u8 = 126;
2929
/// contain optionally serializable fields, no `bincode` compatible bridge implementation is
3030
/// required.
3131
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
32-
#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
33-
#[cfg_attr(any(test, feature = "serde"), serde(rename_all = "camelCase"))]
32+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
33+
#[cfg_attr(
34+
any(test, feature = "serde"),
35+
serde(from = "msg_serde::L1MsgSerdeHelper", into = "msg_serde::L1MsgSerdeHelper")
36+
)]
3437
#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
3538
#[cfg_attr(any(test, feature = "reth-codec"), derive(Compact))]
3639
#[cfg_attr(any(test, feature = "reth-codec"), add_arbitrary_tests(compact, rlp))]
3740
pub struct TxL1Message {
3841
/// The queue index of the message in the L1 contract queue.
39-
#[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
4042
pub queue_index: u64,
4143
/// The gas limit for the transaction. Gas is paid for when message is sent from the L1.
42-
#[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity", rename = "gas"))]
4344
pub gas_limit: u64,
4445
/// The destination for the transaction. `Address` is used in place of `TxKind` since contract
4546
/// creations aren't allowed via L1 message transactions.
@@ -300,6 +301,55 @@ impl Sealable for TxL1Message {
300301
}
301302
}
302303

304+
#[cfg(any(test, feature = "serde"))]
305+
mod msg_serde {
306+
use super::*;
307+
use serde::{Deserialize, Serialize};
308+
309+
/// Helper struct to serialize/deserialize the `TxL1Message` with a `nonce` field.
310+
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
311+
#[serde(rename_all = "camelCase")]
312+
pub struct L1MsgSerdeHelper {
313+
#[serde(with = "alloy_serde::quantity")]
314+
queue_index: u64,
315+
#[serde(with = "alloy_serde::quantity", rename = "gas")]
316+
gas_limit: u64,
317+
to: Address,
318+
value: U256,
319+
sender: Address,
320+
input: Bytes,
321+
#[serde(default, with = "alloy_serde::quantity")]
322+
nonce: u64,
323+
}
324+
325+
impl From<L1MsgSerdeHelper> for TxL1Message {
326+
fn from(helper: L1MsgSerdeHelper) -> Self {
327+
Self {
328+
queue_index: helper.queue_index,
329+
gas_limit: helper.gas_limit,
330+
to: helper.to,
331+
value: helper.value,
332+
sender: helper.sender,
333+
input: helper.input,
334+
}
335+
}
336+
}
337+
338+
impl From<TxL1Message> for L1MsgSerdeHelper {
339+
fn from(helper: TxL1Message) -> Self {
340+
Self {
341+
queue_index: helper.queue_index,
342+
gas_limit: helper.gas_limit,
343+
to: helper.to,
344+
value: helper.value,
345+
sender: helper.sender,
346+
input: helper.input,
347+
nonce: 0,
348+
}
349+
}
350+
}
351+
}
352+
303353
/// Scroll specific transaction fields
304354
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
305355
#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
@@ -347,6 +397,24 @@ mod tests {
347397
use rand::Rng;
348398
use reth_codecs::{test_utils::UnusedBits, validate_bitflag_backwards_compat};
349399

400+
#[test]
401+
fn test_serde_roundtrip() {
402+
let original = TxL1Message {
403+
queue_index: 100,
404+
gas_limit: 1234,
405+
to: Address::random(),
406+
value: U256::random(),
407+
sender: Address::random(),
408+
input: bytes!("deadbeef"),
409+
};
410+
let json = serde_json::to_value(&original).expect("Failed to serialize");
411+
assert_eq!(json.get("nonce"), Some(&serde_json::Value::String("0x0".to_string())));
412+
413+
let deserialized: TxL1Message =
414+
serde_json::from_value(json).expect("Failed to deserialize");
415+
assert_eq!(original, deserialized);
416+
}
417+
350418
#[test]
351419
fn test_rlp_roundtrip() {
352420
// <https://scrollscan.com/tx/0xace7103cc22a372c81cda04e15442a721cd3d5d64eda2e1578ba310d91597d97>

crates/scroll/alloy/rpc-types/src/transaction.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,10 +296,10 @@ mod tests {
296296
use alloy_primitives::address;
297297

298298
#[test]
299-
fn can_deserialize_deposit() {
299+
fn can_deserialize_l1_messages() {
300300
// cast rpc eth_getTransactionByHash
301301
// 0x5c1c3785c8bf5d7f1cb714abd1d22e32642887215602c3a14a5e9ee105bad6aa --rpc-url https://rpc.scroll.io
302-
let rpc_tx = r#"{"blockHash":"0x018ed80ea8340984a1f4841490284d6e51d71f9e9411feeca41e007a89fbfdff","blockNumber":"0xb81121","from":"0x7885bcbd5cecef1336b5300fb5186a12ddd8c478","gas":"0x1e8480","gasPrice":"0x0","hash":"0x5c1c3785c8bf5d7f1cb714abd1d22e32642887215602c3a14a5e9ee105bad6aa","input":"0x8ef1332e000000000000000000000000c186fa914353c44b2e33ebe05f21846f1048beda0000000000000000000000003bad7ad0728f9917d1bf08af5782dcbd516cdd96000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e7ba000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000044493a4f846ffc1507cbfe98a2b0ba1f06ea7e4eb749c001f78f6cb5540daa556a0566322a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","to":"0x781e90f1c8fc4611c9b7497c3b47f99ef6969cbc","transactionIndex":"0x0","value":"0x0","type":"0x7e","v":"0x0","r":"0x0","s":"0x0","sender":"0x7885bcbd5cecef1336b5300fb5186a12ddd8c478","queueIndex":"0xe7ba0", "yParity":"0x0"}"#;
302+
let rpc_tx = r#"{"blockHash":"0x018ed80ea8340984a1f4841490284d6e51d71f9e9411feeca41e007a89fbfdff","blockNumber":"0xb81121","from":"0x7885bcbd5cecef1336b5300fb5186a12ddd8c478","gas":"0x1e8480","gasPrice":"0x0","hash":"0x5c1c3785c8bf5d7f1cb714abd1d22e32642887215602c3a14a5e9ee105bad6aa","input":"0x8ef1332e000000000000000000000000c186fa914353c44b2e33ebe05f21846f1048beda0000000000000000000000003bad7ad0728f9917d1bf08af5782dcbd516cdd96000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e7ba000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000044493a4f846ffc1507cbfe98a2b0ba1f06ea7e4eb749c001f78f6cb5540daa556a0566322a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","to":"0x781e90f1c8fc4611c9b7497c3b47f99ef6969cbc","transactionIndex":"0x0","value":"0x0","type":"0x7e","v":"0x0","r":"0x0","s":"0x0","sender":"0x7885bcbd5cecef1336b5300fb5186a12ddd8c478","queueIndex":"0xe7ba0", "yParity":"0x0"}"#;
303303

304304
let tx = serde_json::from_str::<Transaction>(rpc_tx).unwrap();
305305

0 commit comments

Comments
 (0)