1use super::*;
17
18impl<N: Network, C: ConsensusStorage<N>> Ledger<N, C> {
19 pub fn get_committee(&self, block_height: u32) -> Result<Option<Committee<N>>> {
21 self.vm.finalize_store().committee_store().get_committee(block_height)
22 }
23
24 pub fn get_committee_for_round(&self, round: u64) -> Result<Option<Committee<N>>> {
26 if let Some(committee) = self.committee_cache.lock().get(&round) {
28 return Ok(Some(committee.clone()));
29 }
30
31 match self.vm.finalize_store().committee_store().get_committee_for_round(round)? {
32 Some(committee) => {
34 self.committee_cache.lock().push(round, committee.clone());
36 Ok(Some(committee))
38 }
39 None => {
41 let current_committee = self.latest_committee()?;
43 match current_committee.starting_round() == round {
45 true => Ok(Some(current_committee)),
46 false => Ok(None),
47 }
48 }
49 }
50 }
51
52 pub fn get_committee_lookback_for_round(&self, round: u64) -> Result<Option<Committee<N>>> {
54 let previous_round = match round % 2 == 0 {
57 true => round.saturating_sub(1),
58 false => round.saturating_sub(2),
59 };
60
61 let committee_lookback_round = previous_round.saturating_sub(Committee::<N>::COMMITTEE_LOOKBACK_RANGE);
63
64 self.get_committee_for_round(committee_lookback_round)
66 }
67
68 pub fn get_state_root(&self, block_height: u32) -> Result<Option<N::StateRoot>> {
70 self.vm.block_store().get_state_root(block_height)
71 }
72
73 pub fn get_state_path_for_commitment(&self, commitment: &Field<N>) -> Result<StatePath<N>> {
75 self.vm.block_store().get_state_path_for_commitment(commitment)
76 }
77
78 pub fn get_state_paths_for_commitments(&self, commitments: &[Field<N>]) -> Result<Vec<StatePath<N>>> {
80 self.vm.block_store().get_state_paths_for_commitments(commitments)
81 }
82
83 pub fn get_epoch_hash(&self, block_height: u32) -> Result<N::BlockHash> {
85 let epoch_number = block_height.saturating_div(N::NUM_BLOCKS_PER_EPOCH);
87 let epoch_starting_height = epoch_number.saturating_mul(N::NUM_BLOCKS_PER_EPOCH);
89 let epoch_hash = self.get_previous_hash(epoch_starting_height)?;
91 Ok(epoch_hash)
93 }
94
95 pub fn get_block(&self, height: u32) -> Result<Block<N>> {
97 match self.try_get_block(height)? {
98 Some(block) => Ok(block),
99 None => bail!("Block {height} does not exist in storage"),
100 }
101 }
102
103 pub fn try_get_block(&self, height: u32) -> Result<Option<Block<N>>> {
108 if height == 0 {
109 return Ok(Some(self.genesis_block.clone()));
110 }
111
112 match self.vm.block_store().get_block_hash(height)? {
113 Some(hash) => self.vm.block_store().get_block(&hash),
114 None => Ok(None),
115 }
116 }
117
118 pub fn get_blocks(&self, heights: Range<u32>) -> Result<Vec<Block<N>>> {
121 cfg_into_iter!(heights).map(|height| self.get_block(height)).collect()
122 }
123
124 pub fn get_block_by_hash(&self, block_hash: &N::BlockHash) -> Result<Block<N>> {
126 match self.try_get_block_by_hash(block_hash)? {
127 Some(block) => Ok(block),
128 None => bail!("Block '{block_hash}' does not exist in storage"),
129 }
130 }
131
132 pub fn try_get_block_by_hash(&self, block_hash: &N::BlockHash) -> Result<Option<Block<N>>> {
137 self.vm.block_store().get_block(block_hash)
138 }
139
140 pub fn get_height(&self, block_hash: &N::BlockHash) -> Result<u32> {
142 match self.vm.block_store().get_block_height(block_hash)? {
143 Some(height) => Ok(height),
144 None => bail!("Missing block height for block '{block_hash}'"),
145 }
146 }
147
148 pub fn get_hash(&self, height: u32) -> Result<N::BlockHash> {
150 if height == 0 {
152 return Ok(self.genesis_block.hash());
153 }
154 match self.vm.block_store().get_block_hash(height)? {
155 Some(block_hash) => Ok(block_hash),
156 None => bail!("Missing block hash for block {height}"),
157 }
158 }
159
160 pub fn get_previous_hash(&self, height: u32) -> Result<N::BlockHash> {
162 if height == 0 {
164 return Ok(N::BlockHash::default());
165 }
166 match self.vm.block_store().get_previous_block_hash(height)? {
167 Some(previous_hash) => Ok(previous_hash),
168 None => bail!("Missing previous block hash for block {height}"),
169 }
170 }
171
172 pub fn get_header(&self, height: u32) -> Result<Header<N>> {
174 if height == 0 {
176 return Ok(*self.genesis_block.header());
177 }
178 let block_hash = match self.vm.block_store().get_block_hash(height)? {
180 Some(block_hash) => block_hash,
181 None => bail!("Block {height} does not exist in storage"),
182 };
183 match self.vm.block_store().get_block_header(&block_hash)? {
185 Some(header) => Ok(header),
186 None => bail!("Missing block header for block {height}"),
187 }
188 }
189
190 pub fn get_transactions(&self, height: u32) -> Result<Transactions<N>> {
192 if height == 0 {
194 return Ok(self.genesis_block.transactions().clone());
195 }
196 let Some(block_hash) = self.vm.block_store().get_block_hash(height)? else {
198 bail!("Block {height} does not exist in storage");
199 };
200 match self.vm.block_store().get_block_transactions(&block_hash)? {
202 Some(transactions) => Ok(transactions),
203 None => bail!("Missing block transactions for block {height}"),
204 }
205 }
206
207 pub fn get_aborted_transaction_ids(&self, height: u32) -> Result<Vec<N::TransactionID>> {
209 if height == 0 {
211 return Ok(self.genesis_block.aborted_transaction_ids().clone());
212 }
213 let Some(block_hash) = self.vm.block_store().get_block_hash(height)? else {
215 bail!("Block {height} does not exist in storage");
216 };
217 match self.vm.block_store().get_block_aborted_transaction_ids(&block_hash)? {
219 Some(aborted_transaction_ids) => Ok(aborted_transaction_ids),
220 None => bail!("Missing aborted transaction IDs for block {height}"),
221 }
222 }
223
224 pub fn get_transaction(&self, transaction_id: N::TransactionID) -> Result<Transaction<N>> {
226 match self.vm.block_store().get_transaction(&transaction_id)? {
228 Some(transaction) => Ok(transaction),
229 None => bail!("Missing transaction for ID {transaction_id}"),
230 }
231 }
232
233 pub fn get_confirmed_transaction(&self, transaction_id: N::TransactionID) -> Result<ConfirmedTransaction<N>> {
235 match self.vm.block_store().get_confirmed_transaction(&transaction_id)? {
237 Some(confirmed_transaction) => Ok(confirmed_transaction),
238 None => bail!("Missing confirmed transaction for ID {transaction_id}"),
239 }
240 }
241
242 pub fn get_unconfirmed_transaction(&self, transaction_id: &N::TransactionID) -> Result<Transaction<N>> {
244 match self.vm.block_store().get_unconfirmed_transaction(transaction_id)? {
246 Some(unconfirmed_transaction) => Ok(unconfirmed_transaction),
247 None => bail!("Missing unconfirmed transaction for ID {transaction_id}"),
248 }
249 }
250
251 pub fn get_latest_edition_for_program(&self, program_id: &ProgramID<N>) -> Result<u16> {
253 match self.vm.block_store().get_latest_edition_for_program(program_id)? {
254 Some(edition) => Ok(edition),
255 None => bail!("Missing latest edition for program ID {program_id}"),
256 }
257 }
258
259 pub fn get_program(&self, program_id: ProgramID<N>) -> Result<Program<N>> {
261 match self.vm.block_store().get_latest_program(&program_id)? {
262 Some(program) => Ok(program),
263 None => bail!("Missing program for ID {program_id}"),
264 }
265 }
266
267 pub fn get_program_for_edition(&self, program_id: ProgramID<N>, edition: u16) -> Result<Program<N>> {
269 match self.try_get_program_for_edition(&program_id, edition)? {
270 Some(program) => Ok(program),
271 None => bail!("Missing program for ID {program_id} and edition {edition}"),
272 }
273 }
274
275 pub fn try_get_program_for_edition(&self, program_id: &ProgramID<N>, edition: u16) -> Result<Option<Program<N>>> {
278 self.vm.block_store().get_program_for_edition(program_id, edition)
279 }
280
281 pub fn get_solutions(&self, height: u32) -> Result<Solutions<N>> {
283 if height == 0 {
285 return Ok(self.genesis_block.solutions().clone());
286 }
287 let block_hash = match self.vm.block_store().get_block_hash(height)? {
289 Some(block_hash) => block_hash,
290 None => bail!("Block {height} does not exist in storage"),
291 };
292 self.vm.block_store().get_block_solutions(&block_hash)
294 }
295
296 pub fn get_solution(&self, solution_id: &SolutionID<N>) -> Result<Solution<N>> {
298 self.vm.block_store().get_solution(solution_id)
299 }
300
301 pub fn get_authority(&self, height: u32) -> Result<Authority<N>> {
303 if height == 0 {
305 return Ok(self.genesis_block.authority().clone());
306 }
307 let block_hash = match self.vm.block_store().get_block_hash(height)? {
309 Some(block_hash) => block_hash,
310 None => bail!("Block {height} does not exist in storage"),
311 };
312 match self.vm.block_store().get_block_authority(&block_hash)? {
314 Some(authority) => Ok(authority),
315 None => bail!("Missing authority for block {height}"),
316 }
317 }
318
319 pub fn get_batch_certificate(&self, certificate_id: &Field<N>) -> Result<Option<BatchCertificate<N>>> {
321 self.vm.block_store().get_batch_certificate(certificate_id)
322 }
323
324 pub fn get_delegators_for_validator(&self, validator: &Address<N>) -> Result<Vec<Address<N>>> {
326 let credits_program_id = ProgramID::from_str("credits.aleo")?;
328 let bonded_mapping = Identifier::from_str("bonded")?;
330 let bonded_mapping_key = Identifier::from_str("validator")?;
332 let bonded = self.vm.finalize_store().get_mapping_confirmed(credits_program_id, bonded_mapping)?;
334 cfg_into_iter!(bonded)
336 .filter_map(|(bonded_address, bond_state)| {
337 let Plaintext::Literal(Literal::Address(bonded_address), _) = bonded_address else {
338 return Some(Err(anyhow!("Invalid delegator in finalize storage.")));
339 };
340 let Value::Plaintext(Plaintext::Struct(bond_state, _)) = bond_state else {
341 return Some(Err(anyhow!("Invalid bond_state in finalize storage.")));
342 };
343 let Some(mapping_validator) = bond_state.get(&bonded_mapping_key) else {
344 return Some(Err(anyhow!("Invalid bond_state validator in finalize storage.")));
345 };
346 let Plaintext::Literal(Literal::Address(mapping_validator), _) = mapping_validator else {
347 return Some(Err(anyhow!("Invalid validator in finalize storage.")));
348 };
349 (mapping_validator == validator && bonded_address != *validator).then_some(Ok(bonded_address))
353 })
354 .collect::<Result<_>>()
355 }
356
357 pub fn get_bonded_amount(&self, address: &Address<N>) -> Result<u64> {
359 let credits_program_id = ProgramID::from_str("credits.aleo")?;
361 let bonded_mapping = Identifier::from_str("bonded")?;
363 let bonded_mapping_key = Plaintext::from(Literal::Address(*address));
365 let microcredits_key = Identifier::from_str("microcredits")?;
367 let bond_state =
369 self.vm.finalize_store().get_value_confirmed(credits_program_id, bonded_mapping, &bonded_mapping_key)?;
370 match bond_state {
372 Some(Value::Plaintext(Plaintext::Struct(bond_state, _))) => match bond_state.get(µcredits_key) {
373 Some(Plaintext::Literal(Literal::U64(amount), _)) => Ok(**amount),
374 _ => bail!("Expected 'microcredits' as a u64 in bond_state struct."),
375 },
376 None => Ok(0),
378 _ => bail!("Invalid bond_state in finalize storage."),
379 }
380 }
381}