mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: add EIP-4788 parent_beacon_block_root to Header (#4299)
This commit is contained in:
@ -100,6 +100,9 @@ pub struct Header {
|
||||
/// with above-target blob gas consumption increase this value, blocks with below-target blob
|
||||
/// gas consumption decrease it (bounded at 0). This was added in EIP-4844.
|
||||
pub excess_blob_gas: Option<u64>,
|
||||
/// TODO: Docs
|
||||
/// This was added in EIP-4788.
|
||||
pub parent_beacon_block_root: Option<H256>,
|
||||
/// An arbitrary byte array containing data relevant to this block. This must be 32 bytes or
|
||||
/// fewer; formally Hx.
|
||||
pub extra_data: Bytes,
|
||||
@ -127,6 +130,7 @@ impl Default for Header {
|
||||
withdrawals_root: None,
|
||||
blob_gas_used: None,
|
||||
excess_blob_gas: None,
|
||||
parent_beacon_block_root: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -227,6 +231,7 @@ impl Header {
|
||||
mem::size_of::<Option<u64>>() + // base fee per gas
|
||||
mem::size_of::<Option<u64>>() + // blob gas used
|
||||
mem::size_of::<Option<u64>>() + // excess blob gas
|
||||
mem::size_of::<Option<H256>>() + // parent beacon block root
|
||||
self.extra_data.len() // extra data
|
||||
}
|
||||
|
||||
@ -252,32 +257,42 @@ impl Header {
|
||||
length += U256::from(base_fee).length();
|
||||
} else if self.withdrawals_root.is_some() ||
|
||||
self.blob_gas_used.is_some() ||
|
||||
self.excess_blob_gas.is_some()
|
||||
self.excess_blob_gas.is_some() ||
|
||||
self.parent_beacon_block_root.is_some()
|
||||
{
|
||||
length += 1; // EMPTY STRING CODE
|
||||
length += 1; // EMPTY LIST CODE
|
||||
}
|
||||
|
||||
if let Some(root) = self.withdrawals_root {
|
||||
length += root.length();
|
||||
} else if self.blob_gas_used.is_some() || self.excess_blob_gas.is_some() {
|
||||
} else if self.blob_gas_used.is_some() ||
|
||||
self.excess_blob_gas.is_some() ||
|
||||
self.parent_beacon_block_root.is_some()
|
||||
{
|
||||
length += 1; // EMPTY STRING CODE
|
||||
}
|
||||
|
||||
if let Some(blob_gas_used) = self.blob_gas_used {
|
||||
length += U256::from(blob_gas_used).length();
|
||||
} else if self.excess_blob_gas.is_some() {
|
||||
length += 1; // EMPTY STRING CODE
|
||||
} else if self.excess_blob_gas.is_some() || self.parent_beacon_block_root.is_some() {
|
||||
length += 1; // EMPTY LIST CODE
|
||||
}
|
||||
|
||||
// Encode excess blob gas length. If new fields are added, the above pattern will need to
|
||||
// be repeated and placeholder length added. Otherwise, it's impossible to tell _which_
|
||||
// fields are missing. This is mainly relevant for contrived cases where a header is
|
||||
// created at random, for example:
|
||||
if let Some(excess_blob_gas) = self.excess_blob_gas {
|
||||
length += U256::from(excess_blob_gas).length();
|
||||
} else if self.parent_beacon_block_root.is_some() {
|
||||
length += 1; // EMPTY LIST CODE
|
||||
}
|
||||
|
||||
// Encode parent beacon block root length. If new fields are added, the above pattern will
|
||||
// need to be repeated and placeholder length added. Otherwise, it's impossible to
|
||||
// tell _which_ fields are missing. This is mainly relevant for contrived cases
|
||||
// where a header is created at random, for example:
|
||||
// * A header is created with a withdrawals root, but no base fee. Shanghai blocks are
|
||||
// post-London, so this is technically not valid. However, a tool like proptest would
|
||||
// generate a block like this.
|
||||
if let Some(excess_blob_gas) = self.excess_blob_gas {
|
||||
length += U256::from(excess_blob_gas).length();
|
||||
if let Some(parent_beacon_block_root) = self.parent_beacon_block_root {
|
||||
length += parent_beacon_block_root.length();
|
||||
}
|
||||
|
||||
length
|
||||
@ -305,42 +320,54 @@ impl Encodable for Header {
|
||||
self.mix_hash.encode(out);
|
||||
H64::from_low_u64_be(self.nonce).encode(out);
|
||||
|
||||
// Encode base fee. Put empty string if base fee is missing,
|
||||
// Encode base fee. Put empty list if base fee is missing,
|
||||
// but withdrawals root is present.
|
||||
if let Some(ref base_fee) = self.base_fee_per_gas {
|
||||
U256::from(*base_fee).encode(out);
|
||||
} else if self.withdrawals_root.is_some() ||
|
||||
self.blob_gas_used.is_some() ||
|
||||
self.excess_blob_gas.is_some()
|
||||
self.excess_blob_gas.is_some() ||
|
||||
self.parent_beacon_block_root.is_some()
|
||||
{
|
||||
out.put_u8(EMPTY_STRING_CODE);
|
||||
out.put_u8(EMPTY_LIST_CODE);
|
||||
}
|
||||
|
||||
// Encode withdrawals root. Put empty string if withdrawals root is missing,
|
||||
// but blob gas used is present.
|
||||
if let Some(ref root) = self.withdrawals_root {
|
||||
root.encode(out);
|
||||
} else if self.blob_gas_used.is_some() || self.excess_blob_gas.is_some() {
|
||||
} else if self.blob_gas_used.is_some() ||
|
||||
self.excess_blob_gas.is_some() ||
|
||||
self.parent_beacon_block_root.is_some()
|
||||
{
|
||||
out.put_u8(EMPTY_STRING_CODE);
|
||||
}
|
||||
|
||||
// Encode blob gas used. Put empty string if blob gas used is missing,
|
||||
// Encode blob gas used. Put empty list if blob gas used is missing,
|
||||
// but excess blob gas is present.
|
||||
if let Some(ref blob_gas_used) = self.blob_gas_used {
|
||||
U256::from(*blob_gas_used).encode(out);
|
||||
} else if self.excess_blob_gas.is_some() {
|
||||
} else if self.excess_blob_gas.is_some() || self.parent_beacon_block_root.is_some() {
|
||||
out.put_u8(EMPTY_LIST_CODE);
|
||||
}
|
||||
|
||||
// Encode excess blob gas. If new fields are added, the above pattern will need to be
|
||||
// repeated and placeholders added. Otherwise, it's impossible to tell _which_ fields
|
||||
// are missing. This is mainly relevant for contrived cases where a header is created
|
||||
// at random, for example:
|
||||
// Encode excess blob gas. Put empty list if excess blob gas is missing,
|
||||
// but parent beacon block root is present.
|
||||
if let Some(ref excess_blob_gas) = self.excess_blob_gas {
|
||||
U256::from(*excess_blob_gas).encode(out);
|
||||
} else if self.parent_beacon_block_root.is_some() {
|
||||
out.put_u8(EMPTY_LIST_CODE);
|
||||
}
|
||||
|
||||
// Encode parent beacon block root. If new fields are added, the above pattern will need to
|
||||
// be repeated and placeholders added. Otherwise, it's impossible to tell _which_
|
||||
// fields are missing. This is mainly relevant for contrived cases where a header is
|
||||
// created at random, for example:
|
||||
// * A header is created with a withdrawals root, but no base fee. Shanghai blocks are
|
||||
// post-London, so this is technically not valid. However, a tool like proptest would
|
||||
// generate a block like this.
|
||||
if let Some(ref excess_blob_gas) = self.excess_blob_gas {
|
||||
U256::from(*excess_blob_gas).encode(out);
|
||||
if let Some(ref parent_beacon_block_root) = self.parent_beacon_block_root {
|
||||
parent_beacon_block_root.encode(out);
|
||||
}
|
||||
}
|
||||
|
||||
@ -379,10 +406,11 @@ impl Decodable for Header {
|
||||
withdrawals_root: None,
|
||||
blob_gas_used: None,
|
||||
excess_blob_gas: None,
|
||||
parent_beacon_block_root: None,
|
||||
};
|
||||
|
||||
if started_len - buf.len() < rlp_head.payload_length {
|
||||
if buf.first().map(|b| *b == EMPTY_STRING_CODE).unwrap_or_default() {
|
||||
if buf.first().map(|b| *b == EMPTY_LIST_CODE).unwrap_or_default() {
|
||||
buf.advance(1)
|
||||
} else {
|
||||
this.base_fee_per_gas = Some(U256::decode(buf)?.to::<u64>());
|
||||
@ -407,15 +435,23 @@ impl Decodable for Header {
|
||||
}
|
||||
}
|
||||
|
||||
// Decode excess blob gas. If new fields are added, the above pattern will need to be
|
||||
// repeated and placeholders decoded. Otherwise, it's impossible to tell _which_ fields are
|
||||
// missing. This is mainly relevant for contrived cases where a header is created at
|
||||
// random, for example:
|
||||
if started_len - buf.len() < rlp_head.payload_length {
|
||||
if buf.first().map(|b| *b == EMPTY_LIST_CODE).unwrap_or_default() {
|
||||
buf.advance(1)
|
||||
} else {
|
||||
this.excess_blob_gas = Some(U256::decode(buf)?.to::<u64>());
|
||||
}
|
||||
}
|
||||
|
||||
// Decode parent beacon block root. If new fields are added, the above pattern will need to
|
||||
// be repeated and placeholders decoded. Otherwise, it's impossible to tell _which_
|
||||
// fields are missing. This is mainly relevant for contrived cases where a header is
|
||||
// created at random, for example:
|
||||
// * A header is created with a withdrawals root, but no base fee. Shanghai blocks are
|
||||
// post-London, so this is technically not valid. However, a tool like proptest would
|
||||
// generate a block like this.
|
||||
if started_len - buf.len() < rlp_head.payload_length {
|
||||
this.excess_blob_gas = Some(U256::decode(buf)?.to::<u64>());
|
||||
this.parent_beacon_block_root = Some(H256::decode(buf)?);
|
||||
}
|
||||
|
||||
let consumed = started_len - buf.len();
|
||||
@ -642,6 +678,7 @@ mod ethers_compat {
|
||||
logs_bloom: block.logs_bloom.unwrap_or_default().0.into(),
|
||||
blob_gas_used: None,
|
||||
excess_blob_gas: None,
|
||||
parent_beacon_block_root: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -713,6 +750,7 @@ mod tests {
|
||||
withdrawals_root: None,
|
||||
blob_gas_used: None,
|
||||
excess_blob_gas: None,
|
||||
parent_beacon_block_root: None,
|
||||
};
|
||||
assert_eq!(header.hash_slow(), expected_hash);
|
||||
}
|
||||
@ -836,6 +874,7 @@ mod tests {
|
||||
),
|
||||
blob_gas_used: Some(0x020000),
|
||||
excess_blob_gas: Some(0),
|
||||
parent_beacon_block_root: None,
|
||||
};
|
||||
|
||||
let header = Header::decode(&mut data.as_slice()).unwrap();
|
||||
@ -892,6 +931,7 @@ mod tests {
|
||||
H256::from_str("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
.unwrap(),
|
||||
),
|
||||
parent_beacon_block_root: None,
|
||||
blob_gas_used: Some(0),
|
||||
excess_blob_gas: Some(0x1600000),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user