snarkvm_ledger_debug/
get.rs

1// Copyright (C) 2019-2023 Aleo Systems Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7// http://www.apache.org/licenses/LICENSE-2.0
8
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use super::*;
16
17impl<N: Network, C: ConsensusStorage<N>> Ledger<N, C> {
18    /// Returns the committee for the given `block height`.
19    pub fn get_committee(&self, block_height: u32) -> Result<Option<Committee<N>>> {
20        self.vm.finalize_store().committee_store().get_committee(block_height)
21    }
22
23    /// Returns the committee for the given `round`.
24    pub fn get_committee_for_round(&self, round: u64) -> Result<Option<Committee<N>>> {
25        self.vm.finalize_store().committee_store().get_committee_for_round(round)
26    }
27
28    /// Returns the state root that contains the given `block height`.
29    pub fn get_state_root(&self, block_height: u32) -> Result<Option<N::StateRoot>> {
30        self.vm.block_store().get_state_root(block_height)
31    }
32
33    /// Returns a state path for the given commitment.
34    pub fn get_state_path_for_commitment(&self, commitment: &Field<N>) -> Result<StatePath<N>> {
35        self.vm.block_store().get_state_path_for_commitment(commitment)
36    }
37
38    /// Returns the epoch challenge for the given block height.
39    pub fn get_epoch_challenge(&self, block_height: u32) -> Result<EpochChallenge<N>> {
40        // Compute the epoch number from the current block height.
41        let epoch_number = block_height / N::NUM_BLOCKS_PER_EPOCH;
42        // Compute the epoch starting height (a multiple of `NUM_BLOCKS_PER_EPOCH`).
43        let epoch_starting_height = epoch_number * N::NUM_BLOCKS_PER_EPOCH;
44        // Retrieve the epoch block hash, defined as the 'previous block hash' from the epoch starting height.
45        let epoch_block_hash = self.get_previous_hash(epoch_starting_height)?;
46        // Construct the epoch challenge.
47        EpochChallenge::new(epoch_number, epoch_block_hash, N::COINBASE_PUZZLE_DEGREE)
48    }
49
50    /// Returns the block for the given block height.
51    pub fn get_block(&self, height: u32) -> Result<Block<N>> {
52        // If the height is 0, return the genesis block.
53        if height == 0 {
54            return Ok(self.genesis_block.clone());
55        }
56        // Retrieve the block hash.
57        let block_hash = match self.vm.block_store().get_block_hash(height)? {
58            Some(block_hash) => block_hash,
59            None => bail!("Block {height} does not exist in storage"),
60        };
61        // Retrieve the block.
62        match self.vm.block_store().get_block(&block_hash)? {
63            Some(block) => Ok(block),
64            None => bail!("Block {height} ('{block_hash}') does not exist in storage"),
65        }
66    }
67
68    /// Returns the blocks in the given block range.
69    /// The range is inclusive of the start and exclusive of the end.
70    pub fn get_blocks(&self, heights: Range<u32>) -> Result<Vec<Block<N>>> {
71        cfg_into_iter!(heights).map(|height| self.get_block(height)).collect()
72    }
73
74    /// Returns the block for the given block hash.
75    pub fn get_block_by_hash(&self, block_hash: &N::BlockHash) -> Result<Block<N>> {
76        // Retrieve the block.
77        match self.vm.block_store().get_block(block_hash)? {
78            Some(block) => Ok(block),
79            None => bail!("Block '{block_hash}' does not exist in storage"),
80        }
81    }
82
83    /// Returns the block height for the given block hash.
84    pub fn get_height(&self, block_hash: &N::BlockHash) -> Result<u32> {
85        match self.vm.block_store().get_block_height(block_hash)? {
86            Some(height) => Ok(height),
87            None => bail!("Missing block height for block '{block_hash}'"),
88        }
89    }
90
91    /// Returns the block hash for the given block height.
92    pub fn get_hash(&self, height: u32) -> Result<N::BlockHash> {
93        // If the height is 0, return the genesis block hash.
94        if height == 0 {
95            return Ok(self.genesis_block.hash());
96        }
97        match self.vm.block_store().get_block_hash(height)? {
98            Some(block_hash) => Ok(block_hash),
99            None => bail!("Missing block hash for block {height}"),
100        }
101    }
102
103    /// Returns the previous block hash for the given block height.
104    pub fn get_previous_hash(&self, height: u32) -> Result<N::BlockHash> {
105        // If the height is 0, return the default block hash.
106        if height == 0 {
107            return Ok(N::BlockHash::default());
108        }
109        match self.vm.block_store().get_previous_block_hash(height)? {
110            Some(previous_hash) => Ok(previous_hash),
111            None => bail!("Missing previous block hash for block {height}"),
112        }
113    }
114
115    /// Returns the block header for the given block height.
116    pub fn get_header(&self, height: u32) -> Result<Header<N>> {
117        // If the height is 0, return the genesis block header.
118        if height == 0 {
119            return Ok(*self.genesis_block.header());
120        }
121        // Retrieve the block hash.
122        let block_hash = match self.vm.block_store().get_block_hash(height)? {
123            Some(block_hash) => block_hash,
124            None => bail!("Block {height} does not exist in storage"),
125        };
126        // Retrieve the block header.
127        match self.vm.block_store().get_block_header(&block_hash)? {
128            Some(header) => Ok(header),
129            None => bail!("Missing block header for block {height}"),
130        }
131    }
132
133    /// Returns the block transactions for the given block height.
134    pub fn get_transactions(&self, height: u32) -> Result<Transactions<N>> {
135        // If the height is 0, return the genesis block transactions.
136        if height == 0 {
137            return Ok(self.genesis_block.transactions().clone());
138        }
139        // Retrieve the block hash.
140        let Some(block_hash) = self.vm.block_store().get_block_hash(height)? else {
141            bail!("Block {height} does not exist in storage");
142        };
143        // Retrieve the block transaction.
144        match self.vm.block_store().get_block_transactions(&block_hash)? {
145            Some(transactions) => Ok(transactions),
146            None => bail!("Missing block transactions for block {height}"),
147        }
148    }
149
150    /// Returns the aborted transaction IDs for the given block height.
151    pub fn get_aborted_transaction_ids(&self, height: u32) -> Result<Vec<N::TransactionID>> {
152        // If the height is 0, return the genesis block aborted transaction IDs.
153        if height == 0 {
154            return Ok(self.genesis_block.aborted_transaction_ids().clone());
155        }
156        // Retrieve the block hash.
157        let Some(block_hash) = self.vm.block_store().get_block_hash(height)? else {
158            bail!("Block {height} does not exist in storage");
159        };
160        // Retrieve the aborted transaction IDs.
161        match self.vm.block_store().get_block_aborted_transaction_ids(&block_hash)? {
162            Some(aborted_transaction_ids) => Ok(aborted_transaction_ids),
163            None => bail!("Missing aborted transaction IDs for block {height}"),
164        }
165    }
166
167    /// Returns the transaction for the given transaction ID.
168    pub fn get_transaction(&self, transaction_id: N::TransactionID) -> Result<Transaction<N>> {
169        // Retrieve the transaction.
170        match self.vm.block_store().get_transaction(&transaction_id)? {
171            Some(transaction) => Ok(transaction),
172            None => bail!("Missing transaction for ID {transaction_id}"),
173        }
174    }
175
176    /// Returns the confirmed transaction for the given transaction ID.
177    pub fn get_confirmed_transaction(&self, transaction_id: N::TransactionID) -> Result<ConfirmedTransaction<N>> {
178        // Retrieve the confirmed transaction.
179        match self.vm.block_store().get_confirmed_transaction(&transaction_id)? {
180            Some(confirmed_transaction) => Ok(confirmed_transaction),
181            None => bail!("Missing confirmed transaction for ID {transaction_id}"),
182        }
183    }
184
185    /// Returns the unconfirmed transaction for the given `transaction ID`.
186    pub fn get_unconfirmed_transaction(&self, transaction_id: &N::TransactionID) -> Result<Transaction<N>> {
187        // Retrieve the unconfirmed transaction.
188        match self.vm.block_store().get_unconfirmed_transaction(transaction_id)? {
189            Some(unconfirmed_transaction) => Ok(unconfirmed_transaction),
190            None => bail!("Missing unconfirmed transaction for ID {transaction_id}"),
191        }
192    }
193
194    /// Returns the program for the given program ID.
195    pub fn get_program(&self, program_id: ProgramID<N>) -> Result<Program<N>> {
196        match self.vm.block_store().get_program(&program_id)? {
197            Some(program) => Ok(program),
198            None => bail!("Missing program for ID {program_id}"),
199        }
200    }
201
202    /// Returns the block solutions for the given block height.
203    pub fn get_solutions(&self, height: u32) -> Result<Option<CoinbaseSolution<N>>> {
204        // If the height is 0, return the genesis block solutions.
205        if height == 0 {
206            return Ok(self.genesis_block.solutions().cloned());
207        }
208        // Retrieve the block hash.
209        let block_hash = match self.vm.block_store().get_block_hash(height)? {
210            Some(block_hash) => block_hash,
211            None => bail!("Block {height} does not exist in storage"),
212        };
213        // Retrieve the block solutions.
214        self.vm.block_store().get_block_solutions(&block_hash)
215    }
216
217    /// Returns the solution for the given solution ID.
218    pub fn get_solution(&self, solution_id: &PuzzleCommitment<N>) -> Result<ProverSolution<N>> {
219        self.vm.block_store().get_solution(solution_id)
220    }
221
222    /// Returns the block authority for the given block height.
223    pub fn get_authority(&self, height: u32) -> Result<Authority<N>> {
224        // If the height is 0, return the genesis block authority.
225        if height == 0 {
226            return Ok(self.genesis_block.authority().clone());
227        }
228        // Retrieve the block hash.
229        let block_hash = match self.vm.block_store().get_block_hash(height)? {
230            Some(block_hash) => block_hash,
231            None => bail!("Block {height} does not exist in storage"),
232        };
233        // Retrieve the block authority.
234        match self.vm.block_store().get_block_authority(&block_hash)? {
235            Some(authority) => Ok(authority),
236            None => bail!("Missing authority for block {height}"),
237        }
238    }
239
240    /// Returns the batch certificate for the given `certificate ID`.
241    pub fn get_batch_certificate(&self, certificate_id: &Field<N>) -> Result<Option<BatchCertificate<N>>> {
242        self.vm.block_store().get_batch_certificate(certificate_id)
243    }
244}
245
246#[cfg(test)]
247mod tests {
248    use super::*;
249    use crate::test_helpers::CurrentLedger;
250    use console::network::Testnet3;
251
252    type CurrentNetwork = Testnet3;
253
254    #[test]
255    fn test_get_block() {
256        // Load the genesis block.
257        let genesis = Block::from_bytes_le(CurrentNetwork::genesis_bytes()).unwrap();
258
259        // Initialize a new ledger.
260        let ledger = CurrentLedger::load(genesis.clone(), None).unwrap();
261        // Retrieve the genesis block.
262        let candidate = ledger.get_block(0).unwrap();
263        // Ensure the genesis block matches.
264        assert_eq!(genesis, candidate);
265    }
266}