mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: validate blob_gas_used in header (#4676)
This commit is contained in:
@ -247,6 +247,21 @@ pub fn validate_block_standalone(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EIP-4844: Shard Blob Transactions
|
||||||
|
if chain_spec.is_cancun_activated_at_timestamp(block.timestamp) {
|
||||||
|
// Check that the blob gas used in the header matches the sum of the blob gas used by each
|
||||||
|
// blob tx
|
||||||
|
let header_blob_gas_used = block.blob_gas_used.ok_or(ConsensusError::BlobGasUsedMissing)?;
|
||||||
|
let total_blob_gas =
|
||||||
|
block.blob_transactions().iter().filter_map(|tx| tx.blob_gas_used()).sum();
|
||||||
|
if total_blob_gas != header_blob_gas_used {
|
||||||
|
return Err(ConsensusError::BlobGasUsedDiff {
|
||||||
|
header_blob_gas_used,
|
||||||
|
expected_blob_gas_used: total_blob_gas,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,9 +506,9 @@ mod tests {
|
|||||||
use mockall::mock;
|
use mockall::mock;
|
||||||
use reth_interfaces::{Error::Consensus, Result};
|
use reth_interfaces::{Error::Consensus, Result};
|
||||||
use reth_primitives::{
|
use reth_primitives::{
|
||||||
hex_literal::hex, proofs, Account, Address, BlockHash, BlockHashOrNumber, Bytes,
|
constants::eip4844::DATA_GAS_PER_BLOB, hex_literal::hex, proofs, Account, Address,
|
||||||
ChainSpecBuilder, Header, Signature, TransactionKind, TransactionSigned, Withdrawal,
|
BlockBody, BlockHash, BlockHashOrNumber, Bytes, ChainSpecBuilder, Header, Signature,
|
||||||
MAINNET, U256,
|
TransactionKind, TransactionSigned, Withdrawal, H256, MAINNET, U256,
|
||||||
};
|
};
|
||||||
use std::ops::RangeBounds;
|
use std::ops::RangeBounds;
|
||||||
|
|
||||||
@ -615,6 +630,26 @@ mod tests {
|
|||||||
TransactionSignedEcRecovered::from_signed_transaction(tx, signer)
|
TransactionSignedEcRecovered::from_signed_transaction(tx, signer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mock_blob_tx(nonce: u64, num_blobs: usize) -> TransactionSigned {
|
||||||
|
let request = Transaction::Eip4844(TxEip4844 {
|
||||||
|
chain_id: 1u64,
|
||||||
|
nonce,
|
||||||
|
max_fee_per_gas: 0x28f000fff,
|
||||||
|
max_priority_fee_per_gas: 0x28f000fff,
|
||||||
|
max_fee_per_blob_gas: 0x7,
|
||||||
|
gas_limit: 10,
|
||||||
|
to: TransactionKind::Call(Address::default()),
|
||||||
|
value: 3,
|
||||||
|
input: Bytes::from(vec![1, 2]),
|
||||||
|
access_list: Default::default(),
|
||||||
|
blob_versioned_hashes: vec![H256::random(); num_blobs],
|
||||||
|
});
|
||||||
|
|
||||||
|
let signature = Signature { odd_y_parity: true, r: U256::default(), s: U256::default() };
|
||||||
|
|
||||||
|
TransactionSigned::from_transaction_and_signature(request, signature)
|
||||||
|
}
|
||||||
|
|
||||||
/// got test block
|
/// got test block
|
||||||
fn mock_block() -> (SealedBlock, Header) {
|
fn mock_block() -> (SealedBlock, Header) {
|
||||||
// https://etherscan.io/block/15867168 where transaction root and receipts root are cleared
|
// https://etherscan.io/block/15867168 where transaction root and receipts root are cleared
|
||||||
@ -822,4 +857,41 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(validate_header_standalone(&header, &chain_spec), Ok(()));
|
assert_eq!(validate_header_standalone(&header, &chain_spec), Ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cancun_block_incorrect_blob_gas_used() {
|
||||||
|
let chain_spec = ChainSpecBuilder::mainnet().cancun_activated().build();
|
||||||
|
|
||||||
|
// create a tx with 10 blobs
|
||||||
|
let transaction = mock_blob_tx(1, 10);
|
||||||
|
|
||||||
|
let header = Header {
|
||||||
|
base_fee_per_gas: Some(1337u64),
|
||||||
|
withdrawals_root: Some(proofs::calculate_withdrawals_root(&[])),
|
||||||
|
blob_gas_used: Some(1),
|
||||||
|
transactions_root: proofs::calculate_transaction_root(&[transaction.clone()]),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
.seal_slow();
|
||||||
|
|
||||||
|
let body = BlockBody {
|
||||||
|
transactions: vec![transaction],
|
||||||
|
ommers: vec![],
|
||||||
|
withdrawals: Some(vec![]),
|
||||||
|
};
|
||||||
|
|
||||||
|
let block = SealedBlock::new(header, body);
|
||||||
|
|
||||||
|
// 10 blobs times the blob gas per blob
|
||||||
|
let expected_blob_gas_used = 10 * DATA_GAS_PER_BLOB;
|
||||||
|
|
||||||
|
// validate blob, it should fail blob gas used validation
|
||||||
|
assert_eq!(
|
||||||
|
validate_block_standalone(&block, &chain_spec),
|
||||||
|
Err(ConsensusError::BlobGasUsedDiff {
|
||||||
|
header_blob_gas_used: 1,
|
||||||
|
expected_blob_gas_used
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -153,6 +153,8 @@ pub enum ConsensusError {
|
|||||||
"Blob gas used {blob_gas_used} is not a multiple of blob gas per blob {blob_gas_per_blob}"
|
"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 },
|
BlobGasUsedNotMultipleOfBlobGasPerBlob { blob_gas_used: u64, blob_gas_per_blob: u64 },
|
||||||
|
#[error("Blob gas used in the header {header_blob_gas_used} does not match the expected blob gas used {expected_blob_gas_used}")]
|
||||||
|
BlobGasUsedDiff { header_blob_gas_used: u64, expected_blob_gas_used: 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}.")]
|
#[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 {
|
ExcessBlobGasDiff {
|
||||||
expected: u64,
|
expected: u64,
|
||||||
|
|||||||
@ -330,10 +330,10 @@ pub enum PayloadError {
|
|||||||
/// Invalid payload base fee.
|
/// Invalid payload base fee.
|
||||||
#[error("Invalid payload base fee: {0}")]
|
#[error("Invalid payload base fee: {0}")]
|
||||||
BaseFee(U256),
|
BaseFee(U256),
|
||||||
/// Invalid payload base fee.
|
/// Invalid payload blob gas used.
|
||||||
#[error("Invalid payload blob gas used: {0}")]
|
#[error("Invalid payload blob gas used: {0}")]
|
||||||
BlobGasUsed(U256),
|
BlobGasUsed(U256),
|
||||||
/// Invalid payload base fee.
|
/// Invalid payload excess blob gas.
|
||||||
#[error("Invalid payload excess blob gas: {0}")]
|
#[error("Invalid payload excess blob gas: {0}")]
|
||||||
ExcessBlobGas(U256),
|
ExcessBlobGas(U256),
|
||||||
/// Invalid payload block hash.
|
/// Invalid payload block hash.
|
||||||
|
|||||||
Reference in New Issue
Block a user