consensus: add unit tests for StorageInner (#10776)

This commit is contained in:
Thomas Coratger
2024-09-09 06:27:40 -07:00
committed by GitHub
parent 8296fcc295
commit 4cbdc7c125

View File

@ -425,3 +425,257 @@ impl StorageInner {
Ok((new_header, execution_outcome))
}
}
#[cfg(test)]
mod tests {
use reth_chainspec::{ChainHardforks, EthereumHardfork, ForkCondition};
use reth_primitives::Transaction;
use super::*;
#[test]
fn test_block_hash() {
let mut storage = StorageInner::default();
// Define two block hashes and their corresponding block numbers.
let block_hash_1: BlockHash = B256::random();
let block_number_1: BlockNumber = 1;
let block_hash_2: BlockHash = B256::random();
let block_number_2: BlockNumber = 2;
// Insert the block number and hash pairs into the `hash_to_number` map.
storage.hash_to_number.insert(block_hash_1, block_number_1);
storage.hash_to_number.insert(block_hash_2, block_number_2);
// Verify that `block_hash` returns the correct block hash for the given block number.
assert_eq!(storage.block_hash(block_number_1), Some(block_hash_1));
assert_eq!(storage.block_hash(block_number_2), Some(block_hash_2));
// Test that `block_hash` returns `None` for a non-existent block number.
let block_number_3: BlockNumber = 3;
assert_eq!(storage.block_hash(block_number_3), None);
}
#[test]
fn test_header_by_hash_or_number() {
let mut storage = StorageInner::default();
// Define block numbers, headers, and hashes.
let block_number_1: u64 = 1;
let block_number_2: u64 = 2;
let header_1 = Header { number: block_number_1, ..Default::default() };
let header_2 = Header { number: block_number_2, ..Default::default() };
let block_hash_1: BlockHash = B256::random();
let block_hash_2: BlockHash = B256::random();
// Insert headers and hash-to-number mappings.
storage.headers.insert(block_number_1, header_1.clone());
storage.headers.insert(block_number_2, header_2.clone());
storage.hash_to_number.insert(block_hash_1, block_number_1);
storage.hash_to_number.insert(block_hash_2, block_number_2);
// Test header retrieval by block number.
assert_eq!(
storage.header_by_hash_or_number(BlockHashOrNumber::Number(block_number_1)),
Some(header_1.clone())
);
assert_eq!(
storage.header_by_hash_or_number(BlockHashOrNumber::Number(block_number_2)),
Some(header_2.clone())
);
// Test header retrieval by block hash.
assert_eq!(
storage.header_by_hash_or_number(BlockHashOrNumber::Hash(block_hash_1)),
Some(header_1)
);
assert_eq!(
storage.header_by_hash_or_number(BlockHashOrNumber::Hash(block_hash_2)),
Some(header_2)
);
// Test non-existent block number and hash.
assert_eq!(storage.header_by_hash_or_number(BlockHashOrNumber::Number(999)), None);
let non_existent_hash: BlockHash = B256::random();
assert_eq!(
storage.header_by_hash_or_number(BlockHashOrNumber::Hash(non_existent_hash)),
None
);
}
#[test]
fn test_insert_new_block() {
let mut storage = StorageInner::default();
// Define headers and block bodies.
let header_1 = Header { difficulty: U256::from(100), ..Default::default() };
let body_1 = BlockBody::default();
let header_2 = Header { difficulty: U256::from(200), ..Default::default() };
let body_2 = BlockBody::default();
// Insert the first block.
storage.insert_new_block(header_1.clone(), body_1.clone());
let best_block_1 = storage.best_block;
let best_hash_1 = storage.best_hash;
// Verify the block was inserted correctly.
assert_eq!(
storage.headers.get(&best_block_1),
Some(&Header { number: 1, ..header_1.clone() })
);
assert_eq!(storage.bodies.get(&best_hash_1), Some(&body_1));
assert_eq!(storage.hash_to_number.get(&best_hash_1), Some(&best_block_1));
// Insert the second block.
storage.insert_new_block(header_2.clone(), body_2.clone());
let best_block_2 = storage.best_block;
let best_hash_2 = storage.best_hash;
// Verify the second block was inserted correctly.
assert_eq!(
storage.headers.get(&best_block_2),
Some(&Header {
number: 2,
parent_hash: Header { number: 1, ..header_1 }.hash_slow(),
..header_2
})
);
assert_eq!(storage.bodies.get(&best_hash_2), Some(&body_2));
assert_eq!(storage.hash_to_number.get(&best_hash_2), Some(&best_block_2));
// Check that the total difficulty was updated.
assert_eq!(storage.total_difficulty, header_1.difficulty + header_2.difficulty);
}
#[test]
fn test_build_basic_header_template() {
let mut storage = StorageInner::default();
let chain_spec = ChainSpec::default();
let best_block_number = 1;
let best_block_hash = B256::random();
let timestamp = 1_600_000_000;
// Set up best block information
storage.best_block = best_block_number;
storage.best_hash = best_block_hash;
// Build header template
let header = storage.build_header_template(
timestamp,
&[], // no transactions
&[], // no ommers
None, // no withdrawals
None, // no requests
&chain_spec,
);
// Verify basic fields
assert_eq!(header.parent_hash, best_block_hash);
assert_eq!(header.number, best_block_number + 1);
assert_eq!(header.timestamp, timestamp);
assert_eq!(header.gas_limit, chain_spec.max_gas_limit);
}
#[test]
fn test_ommers_and_transactions_roots() {
let storage = StorageInner::default();
let chain_spec = ChainSpec::default();
let timestamp = 1_600_000_000;
// Setup ommers and transactions
let ommers = vec![Header::default()];
let transactions = vec![TransactionSigned::default()];
// Build header template
let header = storage.build_header_template(
timestamp,
&transactions,
&ommers,
None, // no withdrawals
None, // no requests
&chain_spec,
);
// Verify ommers and transactions roots
assert_eq!(header.ommers_hash, proofs::calculate_ommers_root(&ommers));
assert_eq!(header.transactions_root, proofs::calculate_transaction_root(&transactions));
}
// Test base fee calculation from the parent block
#[test]
fn test_base_fee_calculation() {
let mut storage = StorageInner::default();
let chain_spec = ChainSpec::default();
let timestamp = 1_600_000_000;
// Set up the parent header with base fee
let base_fee = Some(100);
let parent_header = Header { base_fee_per_gas: base_fee, ..Default::default() };
storage.headers.insert(storage.best_block, parent_header);
// Build header template
let header = storage.build_header_template(
timestamp,
&[], // no transactions
&[], // no ommers
None, // no withdrawals
None, // no requests
&chain_spec,
);
// Verify base fee is correctly propagated
assert_eq!(header.base_fee_per_gas, base_fee);
}
// Test blob gas and excess blob gas calculation when Cancun is active
#[test]
fn test_blob_gas_calculation_cancun() {
let storage = StorageInner::default();
let chain_spec = ChainSpec {
hardforks: ChainHardforks::new(vec![(
EthereumHardfork::Cancun.boxed(),
ForkCondition::Timestamp(25),
)]),
..Default::default()
};
let timestamp = 26;
// Set up a transaction with blob gas
let blob_tx = TransactionSigned {
transaction: Transaction::Eip4844(Default::default()),
..Default::default()
};
let transactions = vec![blob_tx];
// Build header template
let header = storage.build_header_template(
timestamp,
&transactions,
&[], // no ommers
None, // no withdrawals
None, // no requests
&chain_spec,
);
// Verify that the header has the correct fields including blob gas
assert_eq!(
header,
Header {
parent_hash: B256::ZERO,
ommers_hash: proofs::calculate_ommers_root(&[]),
transactions_root: proofs::calculate_transaction_root(&transactions),
withdrawals_root: None,
difficulty: U256::from(2),
number: 1,
gas_limit: chain_spec.max_gas_limit,
timestamp,
base_fee_per_gas: None,
blob_gas_used: Some(0),
requests_root: None,
excess_blob_gas: Some(0),
..Default::default()
}
);
}
}