feat: add 4844 header fields and consensus checks (#3972)

This commit is contained in:
Dan Cline
2023-07-29 08:51:16 -04:00
committed by GitHub
parent 15bb1c90b8
commit 334d6068ad
12 changed files with 368 additions and 7 deletions

View File

@@ -269,6 +269,8 @@ impl StorageInner {
nonce: 0,
base_fee_per_gas,
extra_data: Default::default(),
blob_gas_used: None,
excess_blob_gas: None,
};
header.transactions_root = if transactions.is_empty() {

View File

@@ -1,8 +1,13 @@
//! Collection of methods for block validation.
use reth_interfaces::{consensus::ConsensusError, Result as RethResult};
use reth_primitives::{
constants, BlockNumber, ChainSpec, Hardfork, Header, InvalidTransactionError, SealedBlock,
SealedHeader, Transaction, TransactionSignedEcRecovered, TxEip1559, TxEip2930, TxLegacy,
blobfee::calculate_excess_blob_gas,
constants::{
self,
eip4844::{DATA_GAS_PER_BLOB, MAX_DATA_GAS_PER_BLOCK},
},
BlockNumber, ChainSpec, Hardfork, Header, InvalidTransactionError, SealedBlock, SealedHeader,
Transaction, TransactionSignedEcRecovered, TxEip1559, TxEip2930, TxLegacy,
};
use reth_provider::{AccountReader, HeaderProvider, WithdrawalsProvider};
use std::collections::{hash_map::Entry, HashMap};
@@ -38,6 +43,15 @@ pub fn validate_header_standalone(
return Err(ConsensusError::WithdrawalsRootUnexpected)
}
// Ensures that EIP-4844 fields are valid once cancun is active.
if chain_spec.fork(Hardfork::Cancun).active_at_timestamp(header.timestamp) {
validate_4844_header_standalone(header)?;
} else if header.blob_gas_used.is_some() {
return Err(ConsensusError::BlobGasUsedUnexpected)
} else if header.excess_blob_gas.is_some() {
return Err(ConsensusError::ExcessBlobGasUnexpected)
}
Ok(())
}
@@ -291,6 +305,11 @@ pub fn validate_header_regarding_parent(
}
}
// ensure that the blob gas fields for this block
if chain_spec.fork(Hardfork::Cancun).active_at_timestamp(child.timestamp) {
validate_4844_header_with_parent(parent, child)?;
}
Ok(())
}
@@ -376,6 +395,72 @@ pub fn full_validation<Provider: HeaderProvider + AccountReader + WithdrawalsPro
Ok(())
}
/// Validates that the EIP-4844 header fields are correct with respect to the parent block. This
/// ensures that the `blob_gas_used` and `excess_blob_gas` fields exist in the child header, and
/// that the `excess_blob_gas` field matches the expected `excess_blob_gas` calculated from the
/// parent header fields.
pub fn validate_4844_header_with_parent(
parent: &SealedHeader,
child: &SealedHeader,
) -> Result<(), ConsensusError> {
// From [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844#header-extension):
//
// > For the first post-fork block, both parent.blob_gas_used and parent.excess_blob_gas
// > are evaluated as 0.
//
// This means in the first post-fork block, calculate_excess_blob_gas will return 0.
let parent_blob_gas_used = parent.blob_gas_used.unwrap_or(0);
let parent_excess_blob_gas = parent.excess_blob_gas.unwrap_or(0);
if child.blob_gas_used.is_none() {
return Err(ConsensusError::BlobGasUsedMissing)
}
let excess_blob_gas = child.excess_blob_gas.ok_or(ConsensusError::ExcessBlobGasMissing)?;
let expected_excess_blob_gas =
calculate_excess_blob_gas(parent_excess_blob_gas, parent_blob_gas_used);
if expected_excess_blob_gas != excess_blob_gas {
return Err(ConsensusError::ExcessBlobGasDiff {
expected: expected_excess_blob_gas,
got: excess_blob_gas,
parent_excess_blob_gas,
parent_blob_gas_used,
})
}
Ok(())
}
/// Validates that the EIP-4844 header fields exist and conform to the spec. This ensures that:
///
/// * `blob_gas_used` exists as a header field
/// * `excess_blob_gas` exists as a header field
/// * `blob_gas_used` is less than or equal to `MAX_DATA_GAS_PER_BLOCK`
/// * `blob_gas_used` is a multiple of `DATA_GAS_PER_BLOB`
pub fn validate_4844_header_standalone(header: &SealedHeader) -> Result<(), ConsensusError> {
let blob_gas_used = header.blob_gas_used.ok_or(ConsensusError::BlobGasUsedMissing)?;
if header.excess_blob_gas.is_none() {
return Err(ConsensusError::ExcessBlobGasMissing)
}
if blob_gas_used > MAX_DATA_GAS_PER_BLOCK {
return Err(ConsensusError::BlobGasUsedExceedsMaxBlobGasPerBlock {
blob_gas_used,
max_blob_gas_per_block: MAX_DATA_GAS_PER_BLOCK,
})
}
if blob_gas_used % DATA_GAS_PER_BLOB != 0 {
return Err(ConsensusError::BlobGasUsedNotMultipleOfBlobGasPerBlob {
blob_gas_used,
blob_gas_per_blob: DATA_GAS_PER_BLOB,
})
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
@@ -530,6 +615,8 @@ mod tests {
nonce: 0x0000000000000000,
base_fee_per_gas: 0x28f0001df.into(),
withdrawals_root: None,
blob_gas_used: None,
excess_blob_gas: None,
};
// size: 0x9b5

View File

@@ -113,6 +113,27 @@ pub enum ConsensusError {
WithdrawalIndexInvalid { got: u64, expected: u64 },
#[error("Missing withdrawals")]
BodyWithdrawalsMissing,
#[error("Missing blob gas used")]
BlobGasUsedMissing,
#[error("Unexpected blob gas used")]
BlobGasUsedUnexpected,
#[error("Missing excess blob gas")]
ExcessBlobGasMissing,
#[error("Unexpected excess blob gas")]
ExcessBlobGasUnexpected,
#[error("Blob gas used {blob_gas_used} exceeds maximum allowance {max_blob_gas_per_block}")]
BlobGasUsedExceedsMaxBlobGasPerBlock { blob_gas_used: u64, max_blob_gas_per_block: u64 },
#[error(
"Blob gas used {blob_gas_used} is not a multiple of blob gas per blob {blob_gas_per_blob}"
)]
BlobGasUsedNotMultipleOfBlobGasPerBlob { blob_gas_used: u64, blob_gas_per_blob: u64 },
#[error("Invalid excess blob gas. Expected: {expected}, got: {got}. Parent excess blob gas: {parent_excess_blob_gas}, parent blob gas used: {parent_blob_gas_used}.")]
ExcessBlobGasDiff {
expected: u64,
got: u64,
parent_excess_blob_gas: u64,
parent_blob_gas_used: u64,
},
/// Error for a transaction that violates consensus.
#[error(transparent)]
InvalidTransaction(#[from] InvalidTransactionError),

View File

@@ -258,6 +258,8 @@ mod test {
nonce: 0x0000000000000000u64,
base_fee_per_gas: None,
withdrawals_root: None,
blob_gas_used: None,
excess_blob_gas: None,
},
]),
}.encode(&mut data);
@@ -289,6 +291,8 @@ mod test {
nonce: 0x0000000000000000u64,
base_fee_per_gas: None,
withdrawals_root: None,
blob_gas_used: None,
excess_blob_gas: None,
},
]),
};
@@ -401,6 +405,8 @@ mod test {
nonce: 0x0000000000000000u64,
base_fee_per_gas: None,
withdrawals_root: None,
blob_gas_used: None,
excess_blob_gas: None,
},
],
withdrawals: None,
@@ -485,6 +491,8 @@ mod test {
nonce: 0x0000000000000000u64,
base_fee_per_gas: None,
withdrawals_root: None,
blob_gas_used: None,
excess_blob_gas: None,
},
],
withdrawals: None,

View File

@@ -714,6 +714,8 @@ fn build_payload<Pool, Client>(
difficulty: U256::ZERO,
gas_used: cumulative_gas_used,
extra_data: extra_data.into(),
blob_gas_used: None,
excess_blob_gas: None,
};
// seal the block
@@ -785,6 +787,8 @@ where
difficulty: U256::ZERO,
gas_used: 0,
extra_data: extra_data.into(),
blob_gas_used: None,
excess_blob_gas: None,
};
let block = Block { header, body: vec![], ommers: vec![], withdrawals };

View File

@@ -0,0 +1,12 @@
//! Helpers for working with EIP-4844 blob fee
use crate::constants::eip4844::TARGET_DATA_GAS_PER_BLOCK;
/// Calculates the excess data gas for the next block, after applying the current set of blobs on
/// top of the excess data gas.
///
/// Specified in [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844#header-extension)
pub fn calculate_excess_blob_gas(parent_excess_blob_gas: u64, parent_blob_gas_used: u64) -> u64 {
let excess_blob_gas = parent_excess_blob_gas + parent_blob_gas_used;
excess_blob_gas.saturating_sub(TARGET_DATA_GAS_PER_BLOCK)
}

View File

@@ -1,5 +1,6 @@
use crate::{
basefee::calculate_next_block_base_fee,
blobfee::calculate_excess_blob_gas,
keccak256,
proofs::{EMPTY_LIST_HASH, EMPTY_ROOT},
BlockBodyRoots, BlockHash, BlockNumHash, BlockNumber, Bloom, Bytes, H160, H256, H64, U256,
@@ -7,7 +8,7 @@ use crate::{
use bytes::{Buf, BufMut, BytesMut};
use reth_codecs::{add_arbitrary_tests, derive_arbitrary, main_codec, Compact};
use reth_rlp::{length_of_length, Decodable, Encodable, EMPTY_STRING_CODE};
use reth_rlp::{length_of_length, Decodable, Encodable, EMPTY_LIST_CODE, EMPTY_STRING_CODE};
use serde::{Deserialize, Serialize};
use std::{
mem,
@@ -91,6 +92,13 @@ pub struct Header {
/// above the gas target, and decreasing when blocks are below the gas target. The base fee per
/// gas is burned.
pub base_fee_per_gas: Option<u64>,
/// The total amount of blob gas consumed by the transactions within the block, added in
/// EIP-4844.
pub blob_gas_used: Option<u64>,
/// A running total of blob gas consumed in excess of the target, prior to the block. Blocks
/// 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>,
/// An arbitrary byte array containing data relevant to this block. This must be 32 bytes or
/// fewer; formally Hx.
pub extra_data: Bytes,
@@ -116,6 +124,8 @@ impl Default for Header {
nonce: 0,
base_fee_per_gas: None,
withdrawals_root: None,
blob_gas_used: None,
excess_blob_gas: None,
}
}
}
@@ -170,6 +180,13 @@ impl Header {
Some(calculate_next_block_base_fee(self.gas_used, self.gas_limit, self.base_fee_per_gas?))
}
/// Calculate excess blob gas for the next block according to the EIP-4844 spec.
///
/// Returns a `None` if no excess blob gas is set, no EIP-4844 support
pub fn next_block_excess_blob_gas(&self) -> Option<u64> {
Some(calculate_excess_blob_gas(self.excess_blob_gas?, self.blob_gas_used?))
}
/// Seal the header with a known hash.
///
/// WARNING: This method does not perform validation whether the hash is correct.
@@ -202,6 +219,8 @@ impl Header {
mem::size_of::<H256>() + // mix hash
mem::size_of::<u64>() + // nonce
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
self.extra_data.len() // extra data
}
@@ -225,11 +244,34 @@ impl Header {
if let Some(base_fee) = self.base_fee_per_gas {
length += U256::from(base_fee).length();
} else if self.withdrawals_root.is_some() {
length += 1; // EMTY STRING CODE
} else if self.withdrawals_root.is_some() ||
self.blob_gas_used.is_some() ||
self.excess_blob_gas.is_some()
{
length += 1; // EMPTY STRING 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() {
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
}
// 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:
// * 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();
}
length
@@ -261,12 +303,38 @@ impl Encodable for Header {
// 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() {
} else if self.withdrawals_root.is_some() ||
self.blob_gas_used.is_some() ||
self.excess_blob_gas.is_some()
{
out.put_u8(EMPTY_STRING_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() {
out.put_u8(EMPTY_STRING_CODE);
}
// Encode blob gas used. Put empty string 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() {
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:
// * 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);
}
}
@@ -303,7 +371,10 @@ impl Decodable for Header {
nonce: H64::decode(buf)?.to_low_u64_be(),
base_fee_per_gas: None,
withdrawals_root: None,
blob_gas_used: None,
excess_blob_gas: None,
};
if started_len - buf.len() < rlp_head.payload_length {
if buf.first().map(|b| *b == EMPTY_STRING_CODE).unwrap_or_default() {
buf.advance(1)
@@ -311,9 +382,36 @@ impl Decodable for Header {
this.base_fee_per_gas = Some(U256::decode(buf)?.to::<u64>());
}
}
// Withdrawals root for post-shanghai headers
if started_len - buf.len() < rlp_head.payload_length {
this.withdrawals_root = Some(Decodable::decode(buf)?);
if buf.first().map(|b| *b == EMPTY_STRING_CODE).unwrap_or_default() {
buf.advance(1)
} else {
this.withdrawals_root = Some(Decodable::decode(buf)?);
}
}
// Blob gas used and excess blob gas for post-cancun headers
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.blob_gas_used = Some(U256::decode(buf)?.to::<u64>());
}
}
// 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:
// * 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>());
}
let consumed = started_len - buf.len();
if consumed != rlp_head.payload_length {
return Err(reth_rlp::DecodeError::ListLengthMismatch {
@@ -536,6 +634,8 @@ mod ethers_compat {
gas_used: block.gas_used.as_u64(),
withdrawals_root: None,
logs_bloom: block.logs_bloom.unwrap_or_default().0.into(),
blob_gas_used: None,
excess_blob_gas: None,
}
}
}
@@ -605,6 +705,8 @@ mod tests {
nonce: 0,
base_fee_per_gas: Some(0x036b_u64),
withdrawals_root: None,
blob_gas_used: None,
excess_blob_gas: None,
};
assert_eq!(header.hash_slow(), expected_hash);
}
@@ -683,6 +785,120 @@ mod tests {
assert_eq!(header.hash_slow(), expected_hash);
}
// Test vector from: https://github.com/ethereum/tests/blob/7e9e0940c0fcdbead8af3078ede70f969109bd85/BlockchainTests/ValidBlocks/bcExample/cancunExample.json
#[test]
fn test_decode_block_header_with_blob_fields_ef_tests() {
let data = hex::decode("f90221a03a9b485972e7353edd9152712492f0c58d89ef80623686b6bf947a4a6dce6cb6a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa03c837fc158e3e93eafcaf2e658a02f5d8f99abc9f1c4c66cdea96c0ca26406aea04409cc4b699384ba5f8248d92b784713610c5ff9c1de51e9239da0dac76de9cea046cab26abf1047b5b119ecc2dda1296b071766c8b1307e1381fcecc90d513d86b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008001887fffffffffffffff8302a86582079e42a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b42188000000000000000009a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218302000080").unwrap();
let expected = Header {
parent_hash: H256::from_str(
"3a9b485972e7353edd9152712492f0c58d89ef80623686b6bf947a4a6dce6cb6",
)
.unwrap(),
ommers_hash: H256::from_str(
"1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
)
.unwrap(),
beneficiary: Address::from_str("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba").unwrap(),
state_root: H256::from_str(
"3c837fc158e3e93eafcaf2e658a02f5d8f99abc9f1c4c66cdea96c0ca26406ae",
)
.unwrap(),
transactions_root: H256::from_str(
"4409cc4b699384ba5f8248d92b784713610c5ff9c1de51e9239da0dac76de9ce",
)
.unwrap(),
receipts_root: H256::from_str(
"46cab26abf1047b5b119ecc2dda1296b071766c8b1307e1381fcecc90d513d86",
)
.unwrap(),
logs_bloom: Default::default(),
difficulty: U256::from(0),
number: 0x1,
gas_limit: 0x7fffffffffffffff,
gas_used: 0x02a865,
timestamp: 0x079e,
extra_data: Bytes::from(vec![0x42]),
mix_hash: H256::from_str(
"56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
)
.unwrap(),
nonce: 0,
base_fee_per_gas: Some(9),
withdrawals_root: Some(
H256::from_str("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
.unwrap(),
),
blob_gas_used: Some(0x020000),
excess_blob_gas: Some(0),
};
let header = Header::decode(&mut data.as_slice()).unwrap();
assert_eq!(header, expected);
let expected_hash =
H256::from_str("0x10aca3ebb4cf6ddd9e945a5db19385f9c105ede7374380c50d56384c3d233785")
.unwrap();
assert_eq!(header.hash_slow(), expected_hash);
}
#[test]
fn test_decode_block_header_with_blob_fields() {
// Block from devnet-7
let data = hex::decode("f90239a013a7ec98912f917b3e804654e37c9866092043c13eb8eab94eb64818e886cff5a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794f97e180c050e5ab072211ad2c213eb5aee4df134a0ec229dbe85b0d3643ad0f471e6ec1a36bbc87deffbbd970762d22a53b35d068aa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080830305988401c9c380808464c40d5499d883010c01846765746888676f312e32302e35856c696e7578a070ccadc40b16e2094954b1064749cc6fbac783c1712f1b271a8aac3eda2f232588000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421808401600000").unwrap();
let expected = Header {
parent_hash: H256::from_str(
"13a7ec98912f917b3e804654e37c9866092043c13eb8eab94eb64818e886cff5",
)
.unwrap(),
ommers_hash: H256::from_str(
"1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
)
.unwrap(),
beneficiary: Address::from_str("f97e180c050e5ab072211ad2c213eb5aee4df134").unwrap(),
state_root: H256::from_str(
"ec229dbe85b0d3643ad0f471e6ec1a36bbc87deffbbd970762d22a53b35d068a",
)
.unwrap(),
transactions_root: H256::from_str(
"56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
)
.unwrap(),
receipts_root: H256::from_str(
"56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
)
.unwrap(),
logs_bloom: Default::default(),
difficulty: U256::from(0),
number: 0x30598,
gas_limit: 0x1c9c380,
gas_used: 0,
timestamp: 0x64c40d54,
extra_data: Bytes::from(
hex::decode("d883010c01846765746888676f312e32302e35856c696e7578").unwrap(),
),
mix_hash: H256::from_str(
"70ccadc40b16e2094954b1064749cc6fbac783c1712f1b271a8aac3eda2f2325",
)
.unwrap(),
nonce: 0,
base_fee_per_gas: Some(7),
withdrawals_root: Some(
H256::from_str("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
.unwrap(),
),
blob_gas_used: Some(0),
excess_blob_gas: Some(0x1600000),
};
let header = Header::decode(&mut data.as_slice()).unwrap();
assert_eq!(header, expected);
let expected_hash =
H256::from_str("0x539c9ea0a3ca49808799d3964b8b6607037227de26bc51073c6926963127087b")
.unwrap();
assert_eq!(header.hash_slow(), expected_hash);
}
#[test]
fn sanity_direction() {
let reverse = true;

View File

@@ -23,6 +23,7 @@ pub mod abi;
mod account;
pub mod basefee;
mod bits;
pub mod blobfee;
mod block;
pub mod bloom;
mod chain;

View File

@@ -267,6 +267,9 @@ impl Header {
base_fee_per_gas,
extra_data,
withdrawals_root,
// TODO: add header fields to the rpc header
blob_gas_used: _,
excess_blob_gas: _,
},
hash,
} = primitive_header;

View File

@@ -172,6 +172,9 @@ impl TryFrom<ExecutionPayload> for SealedBlock {
ommers_hash: EMPTY_LIST_HASH,
difficulty: Default::default(),
nonce: Default::default(),
// TODO: add conversion once ExecutionPayload has 4844 fields
blob_gas_used: None,
excess_blob_gas: None,
}
.seal_slow();

View File

@@ -143,6 +143,8 @@ impl PendingBlockEnv {
difficulty: U256::ZERO,
gas_used: cumulative_gas_used,
extra_data: Default::default(),
blob_gas_used: None,
excess_blob_gas: None,
};
// seal the block

View File

@@ -100,6 +100,8 @@ impl From<Header> for SealedHeader {
parent_hash: value.parent_hash,
logs_bloom: value.bloom,
withdrawals_root: value.withdrawals_root,
blob_gas_used: None,
excess_blob_gas: None,
};
header.seal(value.hash)
}