feat: validate blob_gas_used in header (#4676)

This commit is contained in:
Dan Cline
2023-09-20 02:58:48 -04:00
committed by GitHub
parent ec4b302079
commit 24a8590e69
3 changed files with 79 additions and 5 deletions

View File

@ -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(())
}
@ -491,9 +506,9 @@ mod tests {
use mockall::mock;
use reth_interfaces::{Error::Consensus, Result};
use reth_primitives::{
hex_literal::hex, proofs, Account, Address, BlockHash, BlockHashOrNumber, Bytes,
ChainSpecBuilder, Header, Signature, TransactionKind, TransactionSigned, Withdrawal,
MAINNET, U256,
constants::eip4844::DATA_GAS_PER_BLOB, hex_literal::hex, proofs, Account, Address,
BlockBody, BlockHash, BlockHashOrNumber, Bytes, ChainSpecBuilder, Header, Signature,
TransactionKind, TransactionSigned, Withdrawal, H256, MAINNET, U256,
};
use std::ops::RangeBounds;
@ -615,6 +630,26 @@ mod tests {
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
fn mock_block() -> (SealedBlock, Header) {
// 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(()));
}
#[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
})
);
}
}

View File

@ -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}"
)]
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}.")]
ExcessBlobGasDiff {
expected: u64,

View File

@ -330,10 +330,10 @@ pub enum PayloadError {
/// Invalid payload base fee.
#[error("Invalid payload base fee: {0}")]
BaseFee(U256),
/// Invalid payload base fee.
/// Invalid payload blob gas used.
#[error("Invalid payload blob gas used: {0}")]
BlobGasUsed(U256),
/// Invalid payload base fee.
/// Invalid payload excess blob gas.
#[error("Invalid payload excess blob gas: {0}")]
ExcessBlobGas(U256),
/// Invalid payload block hash.