diff --git a/ledger/Cargo.toml b/ledger/Cargo.toml index a8b6017677..88ae4d6ff7 100644 --- a/ledger/Cargo.toml +++ b/ledger/Cargo.toml @@ -168,6 +168,9 @@ workspace = true [dependencies.rayon] workspace = true +[dependencies.serde] +workspace = true + [dependencies.time] workspace = true diff --git a/ledger/src/get.rs b/ledger/src/get.rs index 2e62a5fe14..efb04e8c16 100644 --- a/ledger/src/get.rs +++ b/ledger/src/get.rs @@ -15,6 +15,8 @@ use super::*; +use crate::store::TransactionType; + impl> Ledger { /// Returns the committee for the given `block height`. pub fn get_committee(&self, block_height: u32) -> Result>> { @@ -378,4 +380,96 @@ impl> Ledger { _ => bail!("Invalid bond_state in finalize storage."), } } + + /// Returns a tuple containing the number of all the input records and all the output records. + pub fn get_record_count(&self) -> RecordCount { + let transition_store = self.vm.block_store().transition_store(); + let num_input_records = transition_store.input_store().record_map().len_confirmed(); + let num_output_records = transition_store.output_store().record_map().len_confirmed(); + RecordCount { input: num_input_records, output: num_output_records } + } + + /// Returns the list of input and output records applicable to the given block height. + pub fn get_num_block_records(&self, height: u32) -> Result { + let block_store = self.vm.block_store(); + let block_hash = match block_store.get_block_hash(height)? { + Some(block_hash) => block_hash, + None => bail!("Block {height} does not exist in storage"), + }; + + let Some(block_transaction_ids) = block_store.transactions_map().get_confirmed(&block_hash)? else { + return Ok(Default::default()); + }; + + let transaction_store = block_store.transaction_store(); + let mut transaction_ids_with_type = Vec::with_capacity(block_transaction_ids.len()); + for tx_id in block_transaction_ids.iter() { + let Some(tx_ty) = transaction_store.id_map().get_confirmed(tx_id)? else { + bail!("Missing type for transaction {tx_id}"); + }; + transaction_ids_with_type.push((*tx_id, tx_ty)); + } + + let transition_store = transaction_store.transition_store(); + let execution_store = transaction_store.execution_store(); + let fee_store = transaction_store.fee_store(); + let input_store = transition_store.input_store(); + let output_store = transition_store.output_store(); + + let mut num_input_records = 0usize; + let mut num_output_records = 0usize; + + let mut process_transition_ids = |transition_ids: &[N::TransitionID]| -> Result<()> { + for transition_id in transition_ids { + let input_ids = transition_store.get_input_ids(transition_id)?; + let output_ids = transition_store.get_output_ids(transition_id)?; + + for id in input_ids { + if input_store.record_map().contains_key_confirmed(&id)? { + num_input_records += 1; + } + } + for id in output_ids { + if output_store.record_map().contains_key_confirmed(&id)? { + num_output_records += 1; + } + } + } + + Ok(()) + }; + + for (tx_id, tx_ty) in transaction_ids_with_type { + match *tx_ty { + TransactionType::Deploy => { + continue; + } + TransactionType::Execute => { + let Some(transition_ids_w_fee) = execution_store.id_map().get_confirmed(&tx_id)? else { + continue; + }; + let (transition_ids, _fee) = &*transition_ids_w_fee; + + process_transition_ids(transition_ids)?; + } + TransactionType::Fee => { + let Some(transition_id_w_root_and_proof) = fee_store.fee_map().get_confirmed(&tx_id)? else { + continue; + }; + let (transition_id, _root, _proof) = &*transition_id_w_root_and_proof; + + process_transition_ids(&[*transition_id])?; + } + } + } + + Ok(RecordCount { input: num_input_records, output: num_output_records }) + } +} + +/// An object representing the number of input and output records. +#[derive(Debug, Clone, Copy, Default, serde::Deserialize, serde::Serialize)] +pub struct RecordCount { + pub input: usize, + pub output: usize, } diff --git a/ledger/src/lib.rs b/ledger/src/lib.rs index a35cb87489..cd9db2ff4e 100644 --- a/ledger/src/lib.rs +++ b/ledger/src/lib.rs @@ -60,7 +60,7 @@ use snarkvm_ledger_committee::Committee; use snarkvm_ledger_narwhal::{BatchCertificate, Subdag, Transmission, TransmissionID}; use snarkvm_ledger_puzzle::{Puzzle, PuzzleSolutions, Solution, SolutionID}; use snarkvm_ledger_query::QueryTrait; -use snarkvm_ledger_store::{ConsensusStorage, ConsensusStore}; +use snarkvm_ledger_store::{ConsensusStorage, ConsensusStore, helpers::MapRead}; use snarkvm_synthesizer::{ program::{FinalizeGlobalState, Program}, vm::VM, diff --git a/ledger/store/src/block/mod.rs b/ledger/store/src/block/mod.rs index f7e4bff74d..7191442050 100644 --- a/ledger/store/src/block/mod.rs +++ b/ledger/store/src/block/mod.rs @@ -1204,6 +1204,11 @@ impl> BlockStore { pub fn backup_database>(&self, path: P) -> Result<(), String> { self.storage.backup_database(path) } + + /// Returns a reference to the transactions map. + pub fn transactions_map(&self) -> &B::TransactionsMap { + self.storage.transactions_map() + } } impl> BlockStore { diff --git a/ledger/store/src/transaction/deployment.rs b/ledger/store/src/transaction/deployment.rs index c7c28e9a35..2f0ceb33d1 100644 --- a/ledger/store/src/transaction/deployment.rs +++ b/ledger/store/src/transaction/deployment.rs @@ -736,6 +736,11 @@ impl> DeploymentStore { pub fn storage_mode(&self) -> &StorageMode { self.storage.storage_mode() } + + /// Returns a reference to the program map. + pub fn program_map(&self) -> &D::ProgramMap { + self.storage.program_map() + } } impl> DeploymentStore { diff --git a/ledger/store/src/transaction/execution.rs b/ledger/store/src/transaction/execution.rs index 23b4fa51f8..74d092855a 100644 --- a/ledger/store/src/transaction/execution.rs +++ b/ledger/store/src/transaction/execution.rs @@ -355,6 +355,11 @@ impl> ExecutionStore { pub fn storage_mode(&self) -> &StorageMode { self.storage.storage_mode() } + + /// Returns a reference to the ID map. + pub fn id_map(&self) -> &E::IDMap { + self.storage.id_map() + } } impl> ExecutionStore { diff --git a/ledger/store/src/transaction/fee.rs b/ledger/store/src/transaction/fee.rs index 3795fab002..3c455ace0b 100644 --- a/ledger/store/src/transaction/fee.rs +++ b/ledger/store/src/transaction/fee.rs @@ -236,6 +236,11 @@ impl> FeeStore { pub fn storage_mode(&self) -> &StorageMode { self.storage.storage_mode() } + + /// Returns a reference to the fee map. + pub fn fee_map(&self) -> &F::FeeMap { + self.storage.fee_map() + } } impl> FeeStore { diff --git a/ledger/store/src/transaction/mod.rs b/ledger/store/src/transaction/mod.rs index 9ddec8b772..6ab5005dd7 100644 --- a/ledger/store/src/transaction/mod.rs +++ b/ledger/store/src/transaction/mod.rs @@ -321,6 +321,21 @@ impl> TransactionStore { pub fn storage_mode(&self) -> &StorageMode { self.storage.storage_mode() } + + /// Returns a reference to the transaction ID map. + pub fn id_map(&self) -> &T::IDMap { + self.storage.id_map() + } + + /// Returns a reference to the execution store. + pub fn execution_store(&self) -> &ExecutionStore { + self.storage.execution_store() + } + + /// Returns a reference to the fee store. + pub fn fee_store(&self) -> &FeeStore { + self.storage.fee_store() + } } impl> TransactionStore { diff --git a/ledger/store/src/transition/input.rs b/ledger/store/src/transition/input.rs index dbbe3c3134..6708c603c7 100644 --- a/ledger/store/src/transition/input.rs +++ b/ledger/store/src/transition/input.rs @@ -384,6 +384,11 @@ impl> InputStore { pub fn storage_mode(&self) -> &StorageMode { self.storage.storage_mode() } + + /// Returns a reference to the map of the records. + pub fn record_map(&self) -> &I::RecordMap { + &self.record + } } impl> InputStore { diff --git a/ledger/store/src/transition/mod.rs b/ledger/store/src/transition/mod.rs index 328e48da0a..c5771c7360 100644 --- a/ledger/store/src/transition/mod.rs +++ b/ledger/store/src/transition/mod.rs @@ -370,6 +370,16 @@ impl> TransitionStore { pub fn storage_mode(&self) -> &StorageMode { self.storage.storage_mode() } + + /// Returns a reference to the input store. + pub fn input_store(&self) -> &InputStore { + &self.inputs + } + + /// Returns a reference to the output store. + pub fn output_store(&self) -> &OutputStore { + &self.outputs + } } impl> TransitionStore { diff --git a/ledger/store/src/transition/output.rs b/ledger/store/src/transition/output.rs index be72027717..f54b59f37b 100644 --- a/ledger/store/src/transition/output.rs +++ b/ledger/store/src/transition/output.rs @@ -439,6 +439,11 @@ impl> OutputStore { pub fn storage_mode(&self) -> &StorageMode { self.storage.storage_mode() } + + /// Returns a reference to the map of the records. + pub fn record_map(&self) -> &O::RecordMap { + &self.record + } } impl> OutputStore {