Skip to content

Commit 454b3e0

Browse files
authored
feat: implement rlp::Encodable::length for Header (#1541)
1 parent 0866446 commit 454b3e0

File tree

1 file changed

+107
-81
lines changed

1 file changed

+107
-81
lines changed

ethportal-api/src/types/execution/header.rs

+107-81
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use alloy::{
22
primitives::{keccak256, Address, Bloom, Bytes, B256, B64, U256, U64},
3-
rlp::{Decodable, Encodable, Header as RlpHeader},
3+
rlp::{self, Decodable, Encodable},
44
rpc::types::Header as RpcHeader,
55
};
6+
use bytes::Buf;
67
use serde::{Deserialize, Deserializer, Serialize, Serializer};
78

89
use crate::utils::bytes::{hex_decode, hex_encode};
@@ -87,113 +88,138 @@ where
8788
impl Header {
8889
/// Returns the Keccak-256 hash of the header.
8990
pub fn hash(&self) -> B256 {
90-
keccak256(alloy::rlp::encode(self))
91+
keccak256(rlp::encode(self))
92+
}
93+
94+
/// Calculates the byte length of the RLP encoding without RLP header.
95+
fn rlp_payload_length(&self) -> usize {
96+
self.parent_hash.length()
97+
+ self.uncles_hash.length()
98+
+ self.author.length()
99+
+ self.state_root.length()
100+
+ self.transactions_root.length()
101+
+ self.receipts_root.length()
102+
+ self.logs_bloom.length()
103+
+ self.difficulty.length()
104+
+ self.number.length()
105+
+ self.gas_limit.length()
106+
+ self.gas_used.length()
107+
+ self.timestamp.length()
108+
+ self.extra_data.as_slice().length()
109+
+ self.mix_hash.as_ref().map_or(0, Encodable::length)
110+
+ self.nonce.as_ref().map_or(0, Encodable::length)
111+
+ self.base_fee_per_gas.as_ref().map_or(0, Encodable::length)
112+
+ self.withdrawals_root.as_ref().map_or(0, Encodable::length)
113+
+ self.blob_gas_used.as_ref().map_or(0, Encodable::length)
114+
+ self.excess_blob_gas.as_ref().map_or(0, Encodable::length)
115+
+ self
116+
.parent_beacon_block_root
117+
.as_ref()
118+
.map_or(0, Encodable::length)
91119
}
92120
}
93121

94122
impl Encodable for Header {
95123
fn encode(&self, out: &mut dyn bytes::BufMut) {
96-
let mut list = vec![];
97-
self.parent_hash.encode(&mut list);
98-
self.uncles_hash.encode(&mut list);
99-
self.author.encode(&mut list);
100-
self.state_root.encode(&mut list);
101-
self.transactions_root.encode(&mut list);
102-
self.receipts_root.encode(&mut list);
103-
self.logs_bloom.encode(&mut list);
104-
self.difficulty.encode(&mut list);
105-
self.number.encode(&mut list);
106-
self.gas_limit.encode(&mut list);
107-
self.gas_used.encode(&mut list);
108-
self.timestamp.encode(&mut list);
109-
self.extra_data.as_slice().encode(&mut list);
110-
111-
if let Some(val) = self.mix_hash {
112-
val.encode(&mut list);
124+
rlp::Header {
125+
list: true,
126+
payload_length: self.rlp_payload_length(),
113127
}
114-
115-
if let Some(val) = self.nonce {
116-
val.encode(&mut list);
128+
.encode(out);
129+
130+
self.parent_hash.encode(out);
131+
self.uncles_hash.encode(out);
132+
self.author.encode(out);
133+
self.state_root.encode(out);
134+
self.transactions_root.encode(out);
135+
self.receipts_root.encode(out);
136+
self.logs_bloom.encode(out);
137+
self.difficulty.encode(out);
138+
self.number.encode(out);
139+
self.gas_limit.encode(out);
140+
self.gas_used.encode(out);
141+
self.timestamp.encode(out);
142+
self.extra_data.as_slice().encode(out);
143+
144+
if let Some(val) = &self.mix_hash {
145+
val.encode(out);
117146
}
118-
119-
if let Some(val) = self.base_fee_per_gas {
120-
val.encode(&mut list);
147+
if let Some(val) = &self.nonce {
148+
val.encode(out);
121149
}
122-
123-
if let Some(val) = self.withdrawals_root {
124-
val.encode(&mut list);
150+
if let Some(val) = &self.base_fee_per_gas {
151+
val.encode(out);
125152
}
126-
127-
if let Some(val) = self.blob_gas_used {
128-
val.encode(&mut list);
153+
if let Some(val) = &self.withdrawals_root {
154+
val.encode(out);
129155
}
130-
131-
if let Some(val) = self.excess_blob_gas {
132-
val.encode(&mut list);
156+
if let Some(val) = &self.blob_gas_used {
157+
val.encode(out);
133158
}
134-
135-
if let Some(val) = self.parent_beacon_block_root {
136-
val.encode(&mut list);
159+
if let Some(val) = &self.excess_blob_gas {
160+
val.encode(out);
161+
}
162+
if let Some(val) = &self.parent_beacon_block_root {
163+
val.encode(out);
137164
}
165+
}
138166

139-
let header = RlpHeader {
140-
list: true,
141-
payload_length: list.len(),
142-
};
143-
header.encode(out);
144-
out.put_slice(list.as_slice());
167+
fn length(&self) -> usize {
168+
let payload_length = self.rlp_payload_length();
169+
payload_length + rlp::length_of_length(payload_length)
145170
}
146171
}
147172

148173
impl Decodable for Header {
149-
/// Attempt to decode a header from RLP bytes.
150-
fn decode(buf: &mut &[u8]) -> alloy::rlp::Result<Self> {
151-
let rlp_head = alloy::rlp::Header::decode(buf)?;
152-
if !rlp_head.list {
153-
return Err(alloy::rlp::Error::UnexpectedString);
154-
}
155-
let started_len = buf.len();
174+
fn decode(buf: &mut &[u8]) -> rlp::Result<Self> {
175+
let mut payload_view = rlp::Header::decode_bytes(buf, /* is_list= */ true)?;
176+
let payload_size = payload_view.remaining();
177+
156178
let mut header = Header {
157-
parent_hash: Decodable::decode(buf)?,
158-
uncles_hash: Decodable::decode(buf)?,
159-
author: Decodable::decode(buf)?,
160-
state_root: Decodable::decode(buf)?,
161-
transactions_root: Decodable::decode(buf)?,
162-
receipts_root: Decodable::decode(buf)?,
163-
logs_bloom: Decodable::decode(buf)?,
164-
difficulty: Decodable::decode(buf)?,
165-
number: Decodable::decode(buf)?,
166-
gas_limit: Decodable::decode(buf)?,
167-
gas_used: Decodable::decode(buf)?,
168-
timestamp: Decodable::decode(buf)?,
169-
extra_data: Bytes::decode(buf)?.to_vec(),
170-
mix_hash: Some(Decodable::decode(buf)?),
171-
nonce: Some(Decodable::decode(buf)?),
179+
parent_hash: Decodable::decode(&mut payload_view)?,
180+
uncles_hash: Decodable::decode(&mut payload_view)?,
181+
author: Decodable::decode(&mut payload_view)?,
182+
state_root: Decodable::decode(&mut payload_view)?,
183+
transactions_root: Decodable::decode(&mut payload_view)?,
184+
receipts_root: Decodable::decode(&mut payload_view)?,
185+
logs_bloom: Decodable::decode(&mut payload_view)?,
186+
difficulty: Decodable::decode(&mut payload_view)?,
187+
number: Decodable::decode(&mut payload_view)?,
188+
gas_limit: Decodable::decode(&mut payload_view)?,
189+
gas_used: Decodable::decode(&mut payload_view)?,
190+
timestamp: Decodable::decode(&mut payload_view)?,
191+
extra_data: Bytes::decode(&mut payload_view)?.to_vec(),
192+
mix_hash: Some(Decodable::decode(&mut payload_view)?),
193+
nonce: Some(Decodable::decode(&mut payload_view)?),
172194
base_fee_per_gas: None,
173195
withdrawals_root: None,
174196
blob_gas_used: None,
175197
excess_blob_gas: None,
176198
parent_beacon_block_root: None,
177199
};
178200

179-
if started_len - buf.len() < rlp_head.payload_length {
180-
header.base_fee_per_gas = Some(Decodable::decode(buf)?)
201+
if payload_view.has_remaining() {
202+
header.base_fee_per_gas = Some(Decodable::decode(&mut payload_view)?)
181203
}
182-
183-
if started_len - buf.len() < rlp_head.payload_length {
184-
header.withdrawals_root = Some(Decodable::decode(buf)?)
204+
if payload_view.has_remaining() {
205+
header.withdrawals_root = Some(Decodable::decode(&mut payload_view)?)
185206
}
186-
187-
if started_len - buf.len() < rlp_head.payload_length {
188-
header.blob_gas_used = Some(Decodable::decode(buf)?)
207+
if payload_view.has_remaining() {
208+
header.blob_gas_used = Some(Decodable::decode(&mut payload_view)?)
189209
}
190-
191-
if started_len - buf.len() < rlp_head.payload_length {
192-
header.excess_blob_gas = Some(Decodable::decode(buf)?)
210+
if payload_view.has_remaining() {
211+
header.excess_blob_gas = Some(Decodable::decode(&mut payload_view)?)
212+
}
213+
if payload_view.has_remaining() {
214+
header.parent_beacon_block_root = Some(Decodable::decode(&mut payload_view)?)
193215
}
194216

195-
if started_len - buf.len() < rlp_head.payload_length {
196-
header.parent_beacon_block_root = Some(Decodable::decode(buf)?)
217+
if payload_view.has_remaining() {
218+
let consumed = payload_size - payload_view.remaining();
219+
return Err(rlp::Error::ListLengthMismatch {
220+
expected: payload_size,
221+
got: consumed,
222+
});
197223
}
198224

199225
Ok(header)
@@ -333,7 +359,7 @@ mod tests {
333359
)
334360
);
335361

336-
let encoded_header = alloy::rlp::encode(header);
362+
let encoded_header = rlp::encode(header);
337363
assert_eq!(header_rlp, encoded_header);
338364
}
339365

@@ -353,7 +379,7 @@ mod tests {
353379
.unwrap()
354380
)
355381
);
356-
let encoded_header = alloy::rlp::encode(header);
382+
let encoded_header = rlp::encode(header);
357383
assert_eq!(header_rlp, encoded_header);
358384
}
359385

@@ -466,7 +492,7 @@ mod tests {
466492
B256::from_str("0x10aca3ebb4cf6ddd9e945a5db19385f9c105ede7374380c50d56384c3d233785")
467493
.unwrap();
468494
assert_eq!(decoded.hash(), expected_hash);
469-
let expected_header = alloy::rlp::encode(expected);
495+
let expected_header = rlp::encode(expected);
470496
assert_eq!(data, expected_header);
471497
}
472498

0 commit comments

Comments
 (0)