diff --git a/crates/stages/src/stages/bodies.rs b/crates/stages/src/stages/bodies.rs index f36efb7ee5..592e9f3da9 100644 --- a/crates/stages/src/stages/bodies.rs +++ b/crates/stages/src/stages/bodies.rs @@ -40,6 +40,7 @@ const BODIES: StageId = StageId("Bodies"); /// /// - [`BlockOmmers`][reth_interfaces::db::tables::BlockOmmers] /// - [`Transactions`][reth_interfaces::db::tables::Transactions] +/// - [`TransactionHashNumber`][reth_interfaces::db::tables::TransactionHashNumber] /// /// # Genesis /// @@ -49,6 +50,7 @@ const BODIES: StageId = StageId("Bodies"); /// - The [`BlockOmmers`][reth_interfaces::db::tables::BlockOmmers] table /// - The [`CumulativeTxCount`][reth_interfaces::db::tables::CumulativeTxCount] table /// - The [`Transactions`][reth_interfaces::db::tables::Transactions] table +/// - The [`TransactionHashNumber`][reth_interfaces::db::tables::TransactionHashNumber] table #[derive(Debug)] pub struct BodyStage { /// The body downloader. @@ -153,6 +155,9 @@ impl Stage for BodyStage(transaction.hash(), first_tx_id)?; + // Append the transaction tx_cursor.append(first_tx_id, transaction)?; first_tx_id += 1; } @@ -179,6 +184,7 @@ impl Stage for BodyStage()?; let mut block_ommers_cursor = db.cursor_mut::()?; let mut transaction_cursor = db.cursor_mut::()?; + let mut tx_hash_number_cursor = db.cursor_mut::()?; let mut entry = tx_count_cursor.last()?; while let Some((key, count)) = entry { @@ -200,8 +206,11 @@ impl Stage for BodyStage()?; - tx_cursor.last()?.expect("Could not read last transaction"); + let (_, transaction) = tx_cursor.last()?.expect("Could not read last transaction"); tx_cursor.delete_current()?; + tx.delete::(transaction.hash, None)?; Ok(()) }) .expect("Could not delete a transaction"); @@ -586,7 +596,9 @@ mod tests { tx.put::(key, tx_count)?; tx.put::(key, StoredBlockOmmers { ommers: vec![] })?; (last_count..tx_count).try_for_each(|idx| { - tx.put::(idx, random_signed_tx()) + let transaction = random_signed_tx(); + tx.put::(transaction.hash(), idx)?; + tx.put::(idx, transaction) }) })?; } @@ -619,6 +631,10 @@ mod tests { if let Some(last_tx_id) = self.last_count() { self.db .check_no_entry_above::(last_tx_id, |key| key)?; + self.db.check_no_entry_above_by_value::( + last_tx_id, + |value| value, + )?; } Ok(()) } @@ -660,6 +676,7 @@ mod tests { let mut ommers_cursor = tx.cursor::()?; let mut tx_count_cursor = tx.cursor::()?; let mut transaction_cursor = tx.cursor::()?; + let mut tx_hash_num_cursor = tx.cursor::()?; let first_tx_count_key = match tx_count_cursor.first()? { Some((key, _)) => key, @@ -692,12 +709,14 @@ mod tests { // Validate that block trasactions exist let first_tx_id = prev_entry.map(|(_, v)| v).unwrap_or_default(); // reduce by one for block_reward index - let tx_count = if count == 0 { 0} else {count-1}; + let tx_count = if count == 0 { 0 } else { count - 1 }; for tx_id in first_tx_id..tx_count { + let tx_entry = transaction_cursor.seek_exact(tx_id)?; + assert!(tx_entry.is_some(), "A transaction is missing."); assert_matches!( - transaction_cursor.seek_exact(tx_id), + tx_hash_num_cursor.seek_exact(tx_entry.unwrap().1.hash), Ok(Some(_)), - "A transaction is missing." + "A transaction hash to index mapping is missing." ); } diff --git a/crates/stages/src/test_utils/test_db.rs b/crates/stages/src/test_utils/test_db.rs index d3ec1424b1..7b1aae0a55 100644 --- a/crates/stages/src/test_utils/test_db.rs +++ b/crates/stages/src/test_utils/test_db.rs @@ -155,8 +155,10 @@ impl TestStageDB { { self.query(|tx| { let mut cursor = tx.cursor::()?; - if let Some((_, value)) = cursor.last()? { + let mut entry = cursor.last()?; + while let Some((_, value)) = entry { assert!(selector(value) <= num); + entry = cursor.prev()?; } Ok(()) }) diff --git a/crates/storage/db/src/tables/mod.rs b/crates/storage/db/src/tables/mod.rs index a7cfe54953..6a3ff12e6f 100644 --- a/crates/storage/db/src/tables/mod.rs +++ b/crates/storage/db/src/tables/mod.rs @@ -18,7 +18,7 @@ use crate::{ }; use reth_primitives::{ Account, Address, BlockHash, BlockNumber, Header, IntegerList, Receipt, StorageEntry, - TransactionSigned, TxNumber, H256, + TransactionSigned, TxHash, TxNumber, H256, }; /// Enum for the types of tables present in libmdbx. @@ -31,7 +31,7 @@ pub enum TableType { } /// Default tables that should be present inside database. -pub const TABLES: [(TableType, &str); 20] = [ +pub const TABLES: [(TableType, &str); 21] = [ (TableType::Table, CanonicalHeaders::const_name()), (TableType::Table, HeaderTD::const_name()), (TableType::Table, HeaderNumbers::const_name()), @@ -40,6 +40,7 @@ pub const TABLES: [(TableType, &str); 20] = [ (TableType::Table, CumulativeTxCount::const_name()), (TableType::Table, NonCanonicalTransactions::const_name()), (TableType::Table, Transactions::const_name()), + (TableType::Table, TxHashNumber::const_name()), (TableType::Table, Receipts::const_name()), (TableType::Table, Logs::const_name()), (TableType::Table, PlainAccountState::const_name()), @@ -145,6 +146,11 @@ table!( ( Transactions ) TxNumber | TransactionSigned ); +table!( + /// Stores the mapping of the transaction hash to the transaction number. + ( TxHashNumber ) TxHash | TxNumber +); + table!( /// (Canonical only) Stores transaction receipts. ( Receipts ) TxNumber | Receipt