From ae8ce20c0b433f401f596fb7860b4e66a8657a61 Mon Sep 17 00:00:00 2001 From: greged93 <82421016+greged93@users.noreply.github.com> Date: Wed, 21 Aug 2024 05:27:06 -0700 Subject: [PATCH 1/3] fix: block_range (#10418) --- crates/storage/provider/src/providers/blockchain_provider.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/storage/provider/src/providers/blockchain_provider.rs b/crates/storage/provider/src/providers/blockchain_provider.rs index 3fae8b39e72d6..6592a2c19d1be 100644 --- a/crates/storage/provider/src/providers/blockchain_provider.rs +++ b/crates/storage/provider/src/providers/blockchain_provider.rs @@ -638,7 +638,7 @@ where blocks.append(&mut database_blocks); // Advance the range iterator by the number of blocks fetched from the database - range.nth(database_blocks.len() - 1); + range.nth(blocks.len() - 1); // Fetch the remaining blocks from the in-memory state for num in range { From f0197a55712cabcd33eaff01ab6b07c14e8d2def Mon Sep 17 00:00:00 2001 From: greged93 <82421016+greged93@users.noreply.github.com> Date: Wed, 21 Aug 2024 07:01:38 -0700 Subject: [PATCH 2/3] test: ReceiptProviderIdExt (#10420) --- .../src/providers/blockchain_provider.rs | 124 +++++++++++++++--- 1 file changed, 107 insertions(+), 17 deletions(-) diff --git a/crates/storage/provider/src/providers/blockchain_provider.rs b/crates/storage/provider/src/providers/blockchain_provider.rs index 6592a2c19d1be..ac5eaad8c3d74 100644 --- a/crates/storage/provider/src/providers/blockchain_provider.rs +++ b/crates/storage/provider/src/providers/blockchain_provider.rs @@ -1492,14 +1492,19 @@ mod tests { use reth_chain_state::{ExecutedBlock, NewCanonicalChain}; use reth_chainspec::ChainSpecProvider; use reth_db::{test_utils::TempDatabase, DatabaseEnv}; - use reth_primitives::{BlockHashOrNumber, BlockNumberOrTag, Header, SealedBlock, B256}; + use reth_execution_types::ExecutionOutcome; + use reth_primitives::{ + BlockHashOrNumber, BlockNumberOrTag, Header, Receipt, SealedBlock, StaticFileSegment, B256, + }; use reth_storage_api::{ - BlockHashReader, BlockNumReader, BlockReader, BlockReaderIdExt, BlockSource, HeaderProvider, + BlockHashReader, BlockNumReader, BlockReader, BlockReaderIdExt, BlockSource, + HeaderProvider, ReceiptProviderIdExt, }; - use reth_testing_utils::generators::{self, random_block, random_block_range}; + use reth_testing_utils::generators::{self, random_block, random_block_range, random_receipt}; use crate::{ - providers::BlockchainProvider2, test_utils::create_test_provider_factory, CanonChainTracker, + providers::BlockchainProvider2, test_utils::create_test_provider_factory, + CanonChainTracker, StaticFileWriter, }; const TEST_BLOCKS_COUNT: usize = 5; @@ -1512,35 +1517,53 @@ mod tests { BlockchainProvider2>>, Vec, Vec, + Vec>, )> { let mut rng = generators::rng(); let block_range = (database_blocks + in_memory_blocks - 1) as u64; let blocks = random_block_range(&mut rng, 0..=block_range, B256::ZERO, 0..1); + let receipts: Vec> = blocks + .iter() + .map(|block| block.body.iter()) + .map(|tx| tx.map(|tx| random_receipt(&mut rng, tx, Some(2))).collect()) + .collect(); let factory = create_test_provider_factory(); let provider_rw = factory.provider_rw()?; let mut blocks_iter = blocks.clone().into_iter(); - // Insert data blocks into the database + // Insert blocks and receipts into the database for block in (0..database_blocks).map_while(|_| blocks_iter.next()) { provider_rw.insert_historical_block( - block.seal_with_senders().expect("failed to seal block with senders"), + block.clone().seal_with_senders().expect("failed to seal block with senders"), )?; + + // Insert the receipts into the database using the writer from the provider_rw + let mut writer = + provider_rw.static_file_provider().latest_writer(StaticFileSegment::Receipts)?; + let block_number = block.number as usize; + for receipt in receipts.get(block_number).unwrap() { + writer.append_receipt(block.number, receipt)?; + } } provider_rw.commit()?; let provider = BlockchainProvider2::new(factory)?; - // Insert the rest of the blocks into the in-memory state + // Insert the rest of the blocks and receipts into the in-memory state let chain = NewCanonicalChain::Commit { new: blocks_iter .map(|block| { let senders = block.senders().expect("failed to recover senders"); + let block_receipts = receipts.get(block.number as usize).unwrap().clone(); + let execution_outcome = + ExecutionOutcome { receipts: block_receipts.into(), ..Default::default() }; + ExecutedBlock::new( Arc::new(block), Arc::new(senders), - Default::default(), + execution_outcome.into(), Default::default(), Default::default(), ) @@ -1561,7 +1584,7 @@ mod tests { provider.set_finalized(finalized_block.header); let (database_blocks, in_memory_blocks) = blocks.split_at(database_blocks); - Ok((provider, database_blocks.to_vec(), in_memory_blocks.to_vec())) + Ok((provider, database_blocks.to_vec(), in_memory_blocks.to_vec(), receipts)) } #[test] @@ -1728,7 +1751,7 @@ mod tests { #[test] fn test_block_reader_pending_block() -> eyre::Result<()> { - let (provider, _, _) = + let (provider, _, _, _) = provider_with_random_blocks(TEST_BLOCKS_COUNT, TEST_BLOCKS_COUNT).unwrap(); // Generate a random block @@ -1828,7 +1851,7 @@ mod tests { #[test] fn test_block_hash_reader() -> eyre::Result<()> { - let (provider, database_blocks, in_memory_blocks) = + let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(TEST_BLOCKS_COUNT, TEST_BLOCKS_COUNT)?; let database_block = database_blocks.first().unwrap().clone(); @@ -1851,7 +1874,7 @@ mod tests { #[test] fn test_header_provider() -> eyre::Result<()> { - let (provider, database_blocks, in_memory_blocks) = + let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(TEST_BLOCKS_COUNT, TEST_BLOCKS_COUNT).unwrap(); let database_block = database_blocks.first().unwrap().clone(); @@ -1915,7 +1938,7 @@ mod tests { #[test] fn test_block_num_reader() -> eyre::Result<()> { - let (provider, database_blocks, in_memory_blocks) = + let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(TEST_BLOCKS_COUNT, TEST_BLOCKS_COUNT).unwrap(); assert_eq!(provider.best_block_number()?, in_memory_blocks.last().unwrap().number); @@ -1931,7 +1954,7 @@ mod tests { #[test] fn test_block_reader_id_ext_block_by_id() { - let (provider, database_blocks, in_memory_blocks) = + let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(TEST_BLOCKS_COUNT, TEST_BLOCKS_COUNT).unwrap(); let database_block = database_blocks.first().unwrap().clone(); @@ -1959,7 +1982,7 @@ mod tests { #[test] fn test_block_reader_id_ext_header_by_number_or_tag() { - let (provider, database_blocks, in_memory_blocks) = + let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(TEST_BLOCKS_COUNT, TEST_BLOCKS_COUNT).unwrap(); let database_block = database_blocks.first().unwrap().clone(); @@ -2009,7 +2032,7 @@ mod tests { #[test] fn test_block_reader_id_ext_header_by_id() { - let (provider, database_blocks, in_memory_blocks) = + let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(TEST_BLOCKS_COUNT, TEST_BLOCKS_COUNT).unwrap(); let database_block = database_blocks.first().unwrap().clone(); @@ -2060,7 +2083,7 @@ mod tests { #[test] fn test_block_reader_id_ext_ommers_by_id() { - let (provider, database_blocks, in_memory_blocks) = + let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(TEST_BLOCKS_COUNT, TEST_BLOCKS_COUNT).unwrap(); let database_block = database_blocks.first().unwrap().clone(); @@ -2090,4 +2113,71 @@ mod tests { in_memory_block.ommers ); } + + #[test] + fn test_receipt_provider_id_ext_receipts_by_block_id() -> eyre::Result<()> { + let (provider, database_blocks, in_memory_blocks, receipts) = + provider_with_random_blocks(TEST_BLOCKS_COUNT, TEST_BLOCKS_COUNT)?; + + let database_block = database_blocks.first().unwrap().clone(); + let in_memory_block = in_memory_blocks.last().unwrap().clone(); + + let block_number = database_block.number; + let block_hash = database_block.header.hash(); + + assert_eq!( + provider.receipts_by_block_id(block_number.into())?.unwrap_or_default(), + receipts.get(block_number as usize).unwrap().clone() + ); + assert_eq!( + provider.receipts_by_block_id(block_hash.into())?.unwrap_or_default(), + receipts.get(block_number as usize).unwrap().clone() + ); + + let block_number = in_memory_block.number; + let block_hash = in_memory_block.header.hash(); + + assert_eq!( + provider.receipts_by_block_id(block_number.into())?.unwrap_or_default(), + receipts.get(block_number as usize).unwrap().clone() + ); + assert_eq!( + provider.receipts_by_block_id(block_hash.into())?.unwrap_or_default(), + receipts.get(block_number as usize).unwrap().clone() + ); + + Ok(()) + } + + #[test] + fn test_receipt_provider_id_ext_receipts_by_block_number_or_tag() -> eyre::Result<()> { + let (provider, database_blocks, in_memory_blocks, receipts) = + provider_with_random_blocks(TEST_BLOCKS_COUNT, TEST_BLOCKS_COUNT)?; + + let database_block = database_blocks.first().unwrap().clone(); + + let in_memory_block_count = in_memory_blocks.len(); + let canonical_block = in_memory_blocks.get(in_memory_block_count - 1).unwrap().clone(); + let safe_block = in_memory_blocks.get(in_memory_block_count - 2).unwrap().clone(); + let finalized_block = in_memory_blocks.get(in_memory_block_count - 3).unwrap().clone(); + + assert_eq!( + provider.receipts_by_number_or_tag(database_block.number.into())?.unwrap_or_default(), + receipts.get(database_block.number as usize).unwrap().clone() + ); + assert_eq!( + provider.receipts_by_number_or_tag(BlockNumberOrTag::Latest)?.unwrap_or_default(), + receipts.get(canonical_block.number as usize).unwrap().clone() + ); + assert_eq!( + provider.receipts_by_number_or_tag(BlockNumberOrTag::Safe)?.unwrap_or_default(), + receipts.get(safe_block.number as usize).unwrap().clone() + ); + assert_eq!( + provider.receipts_by_number_or_tag(BlockNumberOrTag::Finalized)?.unwrap_or_default(), + receipts.get(finalized_block.number as usize).unwrap().clone() + ); + + Ok(()) + } } From 1f6993d770a27db0f82735864623e4a285ae4765 Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Wed, 21 Aug 2024 07:21:01 -0700 Subject: [PATCH 3/3] test(trie): fuzz in-memory storage nodes (#10413) --- crates/trie/db/tests/fuzz_in_memory_nodes.rs | 59 ++++++++++++++++++-- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/crates/trie/db/tests/fuzz_in_memory_nodes.rs b/crates/trie/db/tests/fuzz_in_memory_nodes.rs index a8ebea9415e96..32737c1980145 100644 --- a/crates/trie/db/tests/fuzz_in_memory_nodes.rs +++ b/crates/trie/db/tests/fuzz_in_memory_nodes.rs @@ -1,15 +1,16 @@ use proptest::prelude::*; use reth_db::{cursor::DbCursorRW, tables, transaction::DbTxMut}; -use reth_primitives::{Account, B256, U256}; +use reth_primitives::{Account, StorageEntry, B256, U256}; use reth_provider::test_utils::create_test_provider_factory; use reth_trie::{ prefix_set::{PrefixSetMut, TriePrefixSets}, - test_utils::state_root_prehashed, + test_utils::{state_root_prehashed, storage_root_prehashed}, trie_cursor::InMemoryTrieCursorFactory, - StateRoot, + updates::TrieUpdates, + StateRoot, StorageRoot, }; use reth_trie_common::Nibbles; -use reth_trie_db::{DatabaseStateRoot, DatabaseTrieCursorFactory}; +use reth_trie_db::{DatabaseStateRoot, DatabaseStorageRoot, DatabaseTrieCursorFactory}; use std::collections::BTreeMap; proptest! { @@ -60,7 +61,57 @@ proptest! { ); assert_eq!(expected_root, state_root); } + } + + #[test] + fn fuzz_in_memory_storage_nodes(mut init_storage: BTreeMap, storage_updates: [BTreeMap; 10]) { + let hashed_address = B256::random(); + let factory = create_test_provider_factory(); + let provider = factory.provider_rw().unwrap(); + let mut hashed_storage_cursor = + provider.tx_ref().cursor_write::().unwrap(); + + // Insert init state into database + for (hashed_slot, value) in init_storage.clone() { + hashed_storage_cursor + .upsert(hashed_address, StorageEntry { key: hashed_slot, value }) + .unwrap(); + } + // Compute initial storage root and updates + let (_, _, mut storage_trie_nodes) = + StorageRoot::from_tx_hashed(provider.tx_ref(), hashed_address).root_with_updates().unwrap(); + let mut storage = init_storage; + for mut storage_update in storage_updates { + // Insert state updates into database + let mut changes = PrefixSetMut::default(); + for (hashed_slot, value) in storage_update.clone() { + hashed_storage_cursor + .upsert(hashed_address, StorageEntry { key: hashed_slot, value }) + .unwrap(); + changes.insert(Nibbles::unpack(hashed_slot)); + } + + // Compute root with in-memory trie nodes overlay + let mut trie_nodes = TrieUpdates::default(); + trie_nodes.insert_storage_updates(hashed_address, storage_trie_nodes.clone()); + let (storage_root, _, trie_updates) = + StorageRoot::from_tx_hashed(provider.tx_ref(), hashed_address) + .with_prefix_set(changes.freeze()) + .with_trie_cursor_factory(InMemoryTrieCursorFactory::new( + DatabaseTrieCursorFactory::new(provider.tx_ref()), + &trie_nodes.into_sorted(), + )) + .root_with_updates() + .unwrap(); + + storage_trie_nodes.extend(trie_updates); + + // Verify the result + storage.append(&mut storage_update); + let expected_root = storage_root_prehashed(storage.clone()); + assert_eq!(expected_root, storage_root); + } } }