kona_protocol/info/
bedrock.rs1use alloc::vec::Vec;
4use alloy_primitives::{Address, B256, Bytes, U256};
5
6use crate::DecodeError;
7
8#[derive(Debug, Clone, Hash, Eq, PartialEq, Default, Copy)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26pub struct L1BlockInfoBedrock {
27 pub number: u64,
29 pub time: u64,
31 pub base_fee: u64,
33 pub block_hash: B256,
35 pub sequence_number: u64,
37 pub batcher_address: Address,
39 pub l1_fee_overhead: U256,
41 pub l1_fee_scalar: U256,
43}
44
45impl L1BlockInfoBedrock {
46 pub const L1_INFO_TX_LEN: usize = 4 + 32 * 8;
48
49 pub const L1_INFO_TX_SELECTOR: [u8; 4] = [0x01, 0x5d, 0x8e, 0xb9];
52
53 pub fn encode_calldata(&self) -> Bytes {
55 let mut buf = Vec::with_capacity(Self::L1_INFO_TX_LEN);
56 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());
65 buf.into()
66 }
67
68 pub fn decode_calldata(r: &[u8]) -> Result<Self, DecodeError> {
70 if r.len() != Self::L1_INFO_TX_LEN {
71 return Err(DecodeError::InvalidBedrockLength(Self::L1_INFO_TX_LEN, r.len()));
72 }
73
74 let mut number = [0u8; 8];
79 number.copy_from_slice(&r[28..36]);
80 let number = u64::from_be_bytes(number);
81
82 let mut time = [0u8; 8];
84 time.copy_from_slice(&r[60..68]);
85 let time = u64::from_be_bytes(time);
86
87 let mut base_fee = [0u8; 8];
89 base_fee.copy_from_slice(&r[92..100]);
90 let base_fee = u64::from_be_bytes(base_fee);
91
92 let block_hash = B256::from_slice(r[100..132].as_ref());
93
94 let mut sequence_number = [0u8; 8];
96 sequence_number.copy_from_slice(&r[156..164]);
97 let sequence_number = u64::from_be_bytes(sequence_number);
98
99 let batcher_address = Address::from_slice(r[176..196].as_ref());
100 let l1_fee_overhead = U256::from_be_slice(r[196..228].as_ref());
101 let l1_fee_scalar = U256::from_be_slice(r[228..260].as_ref());
102
103 Ok(Self {
104 number,
105 time,
106 base_fee,
107 block_hash,
108 sequence_number,
109 batcher_address,
110 l1_fee_overhead,
111 l1_fee_scalar,
112 })
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119 use alloc::vec;
120
121 #[test]
122 fn test_decode_calldata_bedrock_invalid_length() {
123 let r = vec![0u8; 1];
124 assert_eq!(
125 L1BlockInfoBedrock::decode_calldata(&r),
126 Err(DecodeError::InvalidBedrockLength(L1BlockInfoBedrock::L1_INFO_TX_LEN, r.len(),))
127 );
128 }
129
130 #[test]
131 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 };
142
143 let calldata = info.encode_calldata();
144 let decoded_info = L1BlockInfoBedrock::decode_calldata(&calldata).unwrap();
145 assert_eq!(info, decoded_info);
146 }
147}