Skip to content

Commit 73dbfba

Browse files
authored
refactor(protocol/protocol): switch to nested structs (op-rs/kona#3058)
The `L1BlockInfo___` structs contains overlapping fields. This branch factors out the non-deprecated fields e.g. `L1BlockInfoBedrockBase` and embeds this as a field in `L1BlockInfoBedrock`: ``` pub struct L1BlockInfoBedrock { #[serde(flatten)] base: L1BlockInfoBedrockBase, /// The fee overhead for L1 data. Deprecated in ecotone. pub l1_fee_overhead: U256, /// The fee scalar for L1 data. Deprecated in ecotone. pub l1_fee_scalar: U256, } ``` The purpose is reuse (think OOP inheritance) instead of repetition. As a side-effect this increases encapsulation. It establishes a partial order and a chain of fully embedded structs: L1BlockInfoBedrockBase < L1BlockInfoEcotoneBase < L1BlockInfoIsthmus < L1BlockInfoJovian Further L1BlockInfoBedrockBase < L1BlockInfoBedrock and L1BlockInfoEcotoneBase < L1BlockInfoEcotone This is deemed necessary to get around deprecated fields in `L1BlockInfoBedrock` and `L1BlockInfoEcotone`. To hide the implementation details, constructors have been added and destructuring is discouraged. There is no single way to do this in Rust, but this is one way. A similar way is used [`op-alloy`](https://github.com/alloy-rs/op-alloy/blob/main/crates/rpc-types/src/transaction.rs).
1 parent 088fac6 commit 73dbfba

17 files changed

Lines changed: 1167 additions & 839 deletions

File tree

Cargo.lock

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/protocol/derive/src/stages/batch/batch_queue.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -987,16 +987,16 @@ mod tests {
987987
batch_vec.push(Ok(batch));
988988
}
989989
// Insert a deposit transaction in the front of the second batch txs
990-
let expected = L1BlockInfoBedrock {
991-
number: 16988980031808077784,
992-
time: 1697121143,
993-
base_fee: 10419034451,
994-
block_hash: b256!("392012032675be9f94aae5ab442de73c5f4fb1bf30fa7dd0d2442239899a40fc"),
995-
sequence_number: 4,
996-
batcher_address: address!("6887246668a3b87f54deb3b94ba47a6f63f32985"),
997-
l1_fee_overhead: U256::from(0xbc),
998-
l1_fee_scalar: U256::from(0xa6fe0),
999-
};
990+
let expected = L1BlockInfoBedrock::new(
991+
16988980031808077784,
992+
1697121143,
993+
10419034451,
994+
b256!("392012032675be9f94aae5ab442de73c5f4fb1bf30fa7dd0d2442239899a40fc"),
995+
4,
996+
address!("6887246668a3b87f54deb3b94ba47a6f63f32985"),
997+
U256::from(0xbc),
998+
U256::from(0xa6fe0),
999+
);
10001000
let deposit_tx_calldata: Bytes = L1BlockInfoTx::Bedrock(expected).encode_calldata();
10011001
let tx = TxDeposit {
10021002
source_hash: B256::left_padding_from(&[0xde, 0xad]),

crates/protocol/protocol/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ alloy-serde = { workspace = true, optional = true }
5454
# `test-utils` feature
5555
spin = { workspace = true, optional = true }
5656
tracing-subscriber = { workspace = true, features = ["fmt"], optional = true }
57+
ambassador = "0.4.2"
5758

5859
[dev-dependencies]
5960
brotli = { workspace = true, features = ["std"] }

crates/protocol/protocol/src/batch/span.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use crate::{
4343
/// SpanBatch {
4444
/// prefix: {
4545
/// rel_timestamp, // Relative to genesis
46-
/// l1_origin_num, // Final L1 block number
46+
/// l1_origin_num, // Final L1 block number
4747
/// parent_check, // First 20 bytes of parent hash
4848
/// l1_origin_check, // First 20 bytes of L1 origin hash
4949
/// },
@@ -751,7 +751,7 @@ impl SpanBatch {
751751
mod tests {
752752
use super::*;
753753
use crate::test_utils::{CollectingLayer, TestBatchValidator, TraceStorage};
754-
use alloc::{string::ToString, vec};
754+
use alloc::vec;
755755
use alloy_consensus::{Header, constants::EIP1559_TX_TYPE_ID};
756756
use alloy_eips::BlockNumHash;
757757
use alloy_primitives::{B256, Bytes, b256};
@@ -1503,6 +1503,7 @@ mod tests {
15031503

15041504
#[tokio::test]
15051505
async fn test_check_batch_epoch_hash_mismatch() {
1506+
use crate::alloc::string::ToString;
15061507
let trace_store: TraceStorage = Default::default();
15071508
let layer = CollectingLayer::new(trace_store.clone());
15081509
let subscriber = tracing_subscriber::Registry::default().with(layer);

crates/protocol/protocol/src/block.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ mod tests {
274274
#[test]
275275
fn test_from_block_and_genesis() {
276276
use crate::test_utils::RAW_BEDROCK_INFO_TX;
277+
use alloc::vec;
277278
let genesis = ChainGenesis {
278279
l1: BlockNumHash { hash: B256::from([4; 32]), number: 2 },
279280
l2: BlockNumHash { hash: B256::from([5; 32]), number: 1 },

crates/protocol/protocol/src/info/bedrock.rs

Lines changed: 122 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
//! Contains bedrock-specific L1 block info types.
22
3+
use ambassador::Delegate;
4+
5+
use crate::info::bedrock_base::ambassador_impl_L1BlockInfoBedrockBaseFields;
36
use alloc::vec::Vec;
47
use alloy_primitives::{Address, B256, Bytes, U256};
58

6-
use crate::DecodeError;
7-
9+
use crate::{
10+
DecodeError,
11+
info::{L1BlockInfoBedrockBaseFields, bedrock_base::L1BlockInfoBedrockBase},
12+
};
813
/// Represents the fields within a Bedrock L1 block info transaction.
914
///
1015
/// Bedrock Binary Format
@@ -21,27 +26,45 @@ use crate::DecodeError;
2126
// | 32 | L1FeeOverhead |
2227
// | 32 | L1FeeScalar |
2328
// +---------+--------------------------+
24-
#[derive(Debug, Clone, Hash, Eq, PartialEq, Default, Copy)]
29+
#[derive(Debug, Clone, Hash, Eq, PartialEq, Default, Copy, Delegate)]
30+
#[delegate(L1BlockInfoBedrockBaseFields, target = "base")]
2531
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2632
pub struct L1BlockInfoBedrock {
27-
/// The current L1 origin block number
28-
pub number: u64,
29-
/// The current L1 origin block's timestamp
30-
pub time: u64,
31-
/// The current L1 origin block's basefee
32-
pub base_fee: u64,
33-
/// The current L1 origin block's hash
34-
pub block_hash: B256,
35-
/// The current sequence number
36-
pub sequence_number: u64,
37-
/// The address of the batch submitter
38-
pub batcher_address: Address,
39-
/// The fee overhead for L1 data
33+
#[cfg_attr(feature = "serde", serde(flatten))]
34+
base: L1BlockInfoBedrockBase,
35+
/// The fee overhead for L1 data. Deprecated in Ecotone.
4036
pub l1_fee_overhead: U256,
41-
/// The fee scalar for L1 data
37+
/// The fee scalar for L1 data. Deprecated in Ecotone.
4238
pub l1_fee_scalar: U256,
4339
}
4440

41+
/// Accessors for fields deprecated after Bedrock.
42+
pub trait L1BlockInfoBedrockOnlyFields {
43+
/// The fee overhead for L1 data. Deprecated in Ecotone.
44+
fn l1_fee_overhead(&self) -> U256;
45+
46+
/// The fee scalar for L1 data. Deprecated in Ecotone.
47+
fn l1_fee_scalar(&self) -> U256;
48+
}
49+
50+
impl L1BlockInfoBedrockOnlyFields for L1BlockInfoBedrock {
51+
fn l1_fee_overhead(&self) -> U256 {
52+
self.l1_fee_overhead
53+
}
54+
55+
fn l1_fee_scalar(&self) -> U256 {
56+
self.l1_fee_scalar
57+
}
58+
}
59+
60+
/// Accessors trait for all fields on [`L1BlockInfoBedrock`].
61+
pub trait L1BlockInfoBedrockFields:
62+
L1BlockInfoBedrockBaseFields + L1BlockInfoBedrockOnlyFields
63+
{
64+
}
65+
66+
impl L1BlockInfoBedrockFields for L1BlockInfoBedrock {}
67+
4568
impl L1BlockInfoBedrock {
4669
/// The length of an L1 info transaction in Bedrock.
4770
pub const L1_INFO_TX_LEN: usize = 4 + 32 * 8;
@@ -54,14 +77,14 @@ impl L1BlockInfoBedrock {
5477
pub fn encode_calldata(&self) -> Bytes {
5578
let mut buf = Vec::with_capacity(Self::L1_INFO_TX_LEN);
5679
buf.extend_from_slice(Self::L1_INFO_TX_SELECTOR.as_ref());
57-
buf.extend_from_slice(U256::from(self.number).to_be_bytes::<32>().as_slice());
58-
buf.extend_from_slice(U256::from(self.time).to_be_bytes::<32>().as_slice());
59-
buf.extend_from_slice(U256::from(self.base_fee).to_be_bytes::<32>().as_slice());
60-
buf.extend_from_slice(self.block_hash.as_slice());
61-
buf.extend_from_slice(U256::from(self.sequence_number).to_be_bytes::<32>().as_slice());
62-
buf.extend_from_slice(self.batcher_address.into_word().as_slice());
63-
buf.extend_from_slice(self.l1_fee_overhead.to_be_bytes::<32>().as_slice());
64-
buf.extend_from_slice(self.l1_fee_scalar.to_be_bytes::<32>().as_slice());
80+
buf.extend_from_slice(U256::from(self.number()).to_be_bytes::<32>().as_slice());
81+
buf.extend_from_slice(U256::from(self.time()).to_be_bytes::<32>().as_slice());
82+
buf.extend_from_slice(U256::from(self.base_fee()).to_be_bytes::<32>().as_slice());
83+
buf.extend_from_slice(self.block_hash().as_slice());
84+
buf.extend_from_slice(U256::from(self.sequence_number()).to_be_bytes::<32>().as_slice());
85+
buf.extend_from_slice(self.batcher_address().into_word().as_slice());
86+
buf.extend_from_slice(self.l1_fee_overhead().to_be_bytes::<32>().as_slice());
87+
buf.extend_from_slice(self.l1_fee_scalar().to_be_bytes::<32>().as_slice());
6588
buf.into()
6689
}
6790

@@ -100,7 +123,7 @@ impl L1BlockInfoBedrock {
100123
let l1_fee_overhead = U256::from_be_slice(r[196..228].as_ref());
101124
let l1_fee_scalar = U256::from_be_slice(r[228..260].as_ref());
102125

103-
Ok(Self {
126+
Ok(Self::new(
104127
number,
105128
time,
106129
base_fee,
@@ -109,7 +132,69 @@ impl L1BlockInfoBedrock {
109132
batcher_address,
110133
l1_fee_overhead,
111134
l1_fee_scalar,
112-
})
135+
))
136+
}
137+
/// Construct from all values.
138+
#[allow(clippy::too_many_arguments)]
139+
pub const fn new(
140+
number: u64,
141+
time: u64,
142+
base_fee: u64,
143+
block_hash: B256,
144+
sequence_number: u64,
145+
batcher_address: Address,
146+
l1_fee_overhead: U256,
147+
l1_fee_scalar: U256,
148+
) -> Self {
149+
Self {
150+
base: L1BlockInfoBedrockBase::new(
151+
number,
152+
time,
153+
base_fee,
154+
block_hash,
155+
sequence_number,
156+
batcher_address,
157+
),
158+
l1_fee_overhead,
159+
l1_fee_scalar,
160+
}
161+
}
162+
/// Construct from default values and `base_fee`.
163+
pub fn new_from_base_fee(base_fee: u64) -> Self {
164+
Self { base: L1BlockInfoBedrockBase::new_from_base_fee(base_fee), ..Default::default() }
165+
}
166+
/// Construct from default values and `block_hash`.
167+
pub fn new_from_block_hash(block_hash: B256) -> Self {
168+
Self { base: L1BlockInfoBedrockBase::new_from_block_hash(block_hash), ..Default::default() }
169+
}
170+
/// Construct from default values and `sequence_number`.
171+
pub fn new_from_sequence_number(sequence_number: u64) -> Self {
172+
Self {
173+
base: L1BlockInfoBedrockBase::new_from_sequence_number(sequence_number),
174+
..Default::default()
175+
}
176+
}
177+
/// Construct from default values and `batcher_address`.
178+
pub fn new_from_batcher_address(batcher_address: Address) -> Self {
179+
Self {
180+
base: L1BlockInfoBedrockBase::new_from_batcher_address(batcher_address),
181+
..Default::default()
182+
}
183+
}
184+
/// Construct from default values and `l1_fee_scalar`.
185+
pub fn new_from_l1_fee_scalar(l1_fee_scalar: U256) -> Self {
186+
Self { l1_fee_scalar, ..Default::default() }
187+
}
188+
/// Construct from default values and `l1_fee_overhead`.
189+
pub fn new_from_l1_fee_overhead(l1_fee_overhead: U256) -> Self {
190+
Self { l1_fee_overhead, ..Default::default() }
191+
}
192+
/// Construct from default values, `number` and `block_hash`.
193+
pub fn new_from_number_and_block_hash(number: u64, block_hash: B256) -> Self {
194+
Self {
195+
base: L1BlockInfoBedrockBase::new_from_number_and_block_hash(number, block_hash),
196+
..Default::default()
197+
}
113198
}
114199
}
115200

@@ -129,16 +214,16 @@ mod tests {
129214

130215
#[test]
131216
fn test_l1_block_info_bedrock_roundtrip_calldata_encoding() {
132-
let info = L1BlockInfoBedrock {
133-
number: 1,
134-
time: 2,
135-
base_fee: 3,
136-
block_hash: B256::from([4u8; 32]),
137-
sequence_number: 5,
138-
batcher_address: Address::from([6u8; 20]),
139-
l1_fee_overhead: U256::from(7),
140-
l1_fee_scalar: U256::from(8),
141-
};
217+
let info = L1BlockInfoBedrock::new(
218+
1,
219+
2,
220+
3,
221+
B256::from([4u8; 32]),
222+
5,
223+
Address::from([6u8; 20]),
224+
U256::from(7),
225+
U256::from(8),
226+
);
142227

143228
let calldata = info.encode_calldata();
144229
let decoded_info = L1BlockInfoBedrock::decode_calldata(&calldata).unwrap();

0 commit comments

Comments
 (0)