use super::*;
impl<N: Network, C: ConsensusStorage<N>> Ledger<N, C> {
pub fn get_committee(&self, block_height: u32) -> Result<Option<Committee<N>>> {
self.vm.finalize_store().committee_store().get_committee(block_height)
}
pub fn get_committee_for_round(&self, round: u64) -> Result<Option<Committee<N>>> {
self.vm.finalize_store().committee_store().get_committee_for_round(round)
}
pub fn get_committee_lookback_for_round(&self, round: u64) -> Result<Option<Committee<N>>> {
let previous_round = match round % 2 == 0 {
true => round.saturating_sub(1),
false => round.saturating_sub(2),
};
let committee_lookback_round = previous_round.saturating_sub(Committee::<N>::COMMITTEE_LOOKBACK_RANGE);
self.get_committee_for_round(committee_lookback_round)
}
pub fn get_state_root(&self, block_height: u32) -> Result<Option<N::StateRoot>> {
self.vm.block_store().get_state_root(block_height)
}
pub fn get_state_path_for_commitment(&self, commitment: &Field<N>) -> Result<StatePath<N>> {
self.vm.block_store().get_state_path_for_commitment(commitment)
}
pub fn get_epoch_hash(&self, block_height: u32) -> Result<N::BlockHash> {
let epoch_number = block_height.saturating_div(N::NUM_BLOCKS_PER_EPOCH);
let epoch_starting_height = epoch_number.saturating_mul(N::NUM_BLOCKS_PER_EPOCH);
let epoch_hash = self.get_previous_hash(epoch_starting_height)?;
Ok(epoch_hash)
}
pub fn get_block(&self, height: u32) -> Result<Block<N>> {
if height == 0 {
return Ok(self.genesis_block.clone());
}
let block_hash = match self.vm.block_store().get_block_hash(height)? {
Some(block_hash) => block_hash,
None => bail!("Block {height} does not exist in storage"),
};
match self.vm.block_store().get_block(&block_hash)? {
Some(block) => Ok(block),
None => bail!("Block {height} ('{block_hash}') does not exist in storage"),
}
}
pub fn get_blocks(&self, heights: Range<u32>) -> Result<Vec<Block<N>>> {
cfg_into_iter!(heights).map(|height| self.get_block(height)).collect()
}
pub fn get_block_by_hash(&self, block_hash: &N::BlockHash) -> Result<Block<N>> {
match self.vm.block_store().get_block(block_hash)? {
Some(block) => Ok(block),
None => bail!("Block '{block_hash}' does not exist in storage"),
}
}
pub fn get_height(&self, block_hash: &N::BlockHash) -> Result<u32> {
match self.vm.block_store().get_block_height(block_hash)? {
Some(height) => Ok(height),
None => bail!("Missing block height for block '{block_hash}'"),
}
}
pub fn get_hash(&self, height: u32) -> Result<N::BlockHash> {
if height == 0 {
return Ok(self.genesis_block.hash());
}
match self.vm.block_store().get_block_hash(height)? {
Some(block_hash) => Ok(block_hash),
None => bail!("Missing block hash for block {height}"),
}
}
pub fn get_previous_hash(&self, height: u32) -> Result<N::BlockHash> {
if height == 0 {
return Ok(N::BlockHash::default());
}
match self.vm.block_store().get_previous_block_hash(height)? {
Some(previous_hash) => Ok(previous_hash),
None => bail!("Missing previous block hash for block {height}"),
}
}
pub fn get_header(&self, height: u32) -> Result<Header<N>> {
if height == 0 {
return Ok(*self.genesis_block.header());
}
let block_hash = match self.vm.block_store().get_block_hash(height)? {
Some(block_hash) => block_hash,
None => bail!("Block {height} does not exist in storage"),
};
match self.vm.block_store().get_block_header(&block_hash)? {
Some(header) => Ok(header),
None => bail!("Missing block header for block {height}"),
}
}
pub fn get_transactions(&self, height: u32) -> Result<Transactions<N>> {
if height == 0 {
return Ok(self.genesis_block.transactions().clone());
}
let Some(block_hash) = self.vm.block_store().get_block_hash(height)? else {
bail!("Block {height} does not exist in storage");
};
match self.vm.block_store().get_block_transactions(&block_hash)? {
Some(transactions) => Ok(transactions),
None => bail!("Missing block transactions for block {height}"),
}
}
pub fn get_aborted_transaction_ids(&self, height: u32) -> Result<Vec<N::TransactionID>> {
if height == 0 {
return Ok(self.genesis_block.aborted_transaction_ids().clone());
}
let Some(block_hash) = self.vm.block_store().get_block_hash(height)? else {
bail!("Block {height} does not exist in storage");
};
match self.vm.block_store().get_block_aborted_transaction_ids(&block_hash)? {
Some(aborted_transaction_ids) => Ok(aborted_transaction_ids),
None => bail!("Missing aborted transaction IDs for block {height}"),
}
}
pub fn get_transaction(&self, transaction_id: N::TransactionID) -> Result<Transaction<N>> {
match self.vm.block_store().get_transaction(&transaction_id)? {
Some(transaction) => Ok(transaction),
None => bail!("Missing transaction for ID {transaction_id}"),
}
}
pub fn get_confirmed_transaction(&self, transaction_id: N::TransactionID) -> Result<ConfirmedTransaction<N>> {
match self.vm.block_store().get_confirmed_transaction(&transaction_id)? {
Some(confirmed_transaction) => Ok(confirmed_transaction),
None => bail!("Missing confirmed transaction for ID {transaction_id}"),
}
}
pub fn get_unconfirmed_transaction(&self, transaction_id: &N::TransactionID) -> Result<Transaction<N>> {
match self.vm.block_store().get_unconfirmed_transaction(transaction_id)? {
Some(unconfirmed_transaction) => Ok(unconfirmed_transaction),
None => bail!("Missing unconfirmed transaction for ID {transaction_id}"),
}
}
pub fn get_program(&self, program_id: ProgramID<N>) -> Result<Program<N>> {
match self.vm.block_store().get_program(&program_id)? {
Some(program) => Ok(program),
None => bail!("Missing program for ID {program_id}"),
}
}
pub fn get_solutions(&self, height: u32) -> Result<Solutions<N>> {
if height == 0 {
return Ok(self.genesis_block.solutions().clone());
}
let block_hash = match self.vm.block_store().get_block_hash(height)? {
Some(block_hash) => block_hash,
None => bail!("Block {height} does not exist in storage"),
};
self.vm.block_store().get_block_solutions(&block_hash)
}
pub fn get_solution(&self, solution_id: &SolutionID<N>) -> Result<Solution<N>> {
self.vm.block_store().get_solution(solution_id)
}
pub fn get_authority(&self, height: u32) -> Result<Authority<N>> {
if height == 0 {
return Ok(self.genesis_block.authority().clone());
}
let block_hash = match self.vm.block_store().get_block_hash(height)? {
Some(block_hash) => block_hash,
None => bail!("Block {height} does not exist in storage"),
};
match self.vm.block_store().get_block_authority(&block_hash)? {
Some(authority) => Ok(authority),
None => bail!("Missing authority for block {height}"),
}
}
pub fn get_batch_certificate(&self, certificate_id: &Field<N>) -> Result<Option<BatchCertificate<N>>> {
self.vm.block_store().get_batch_certificate(certificate_id)
}
pub fn get_delegators_for_validator(&self, validator: &Address<N>) -> Result<Vec<Address<N>>> {
let credits_program_id = ProgramID::from_str("credits.aleo")?;
let bonded_mapping = Identifier::from_str("bonded")?;
let bonded_mapping_key = Identifier::from_str("validator")?;
let bonded = self.vm.finalize_store().get_mapping_confirmed(credits_program_id, bonded_mapping)?;
cfg_into_iter!(bonded)
.filter_map(|(bonded_address, bond_state)| {
let Plaintext::Literal(Literal::Address(bonded_address), _) = bonded_address else {
return Some(Err(anyhow!("Invalid delegator in finalize storage.")));
};
let Value::Plaintext(Plaintext::Struct(bond_state, _)) = bond_state else {
return Some(Err(anyhow!("Invalid bond_state in finalize storage.")));
};
let Some(mapping_validator) = bond_state.get(&bonded_mapping_key) else {
return Some(Err(anyhow!("Invalid bond_state validator in finalize storage.")));
};
let Plaintext::Literal(Literal::Address(mapping_validator), _) = mapping_validator else {
return Some(Err(anyhow!("Invalid validator in finalize storage.")));
};
(mapping_validator == validator && bonded_address != *validator).then_some(Ok(bonded_address))
})
.collect::<Result<_>>()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_helpers::CurrentLedger;
use console::network::MainnetV0;
type CurrentNetwork = MainnetV0;
#[test]
fn test_get_block() {
let genesis = Block::from_bytes_le(CurrentNetwork::genesis_bytes()).unwrap();
let ledger = CurrentLedger::load(genesis.clone(), StorageMode::Production).unwrap();
let candidate = ledger.get_block(0).unwrap();
assert_eq!(genesis, candidate);
}
}