hotstuff_rs/block_tree/accessors/app.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
//! Special, read-only interface for querying the Block Tree used only by `App`s.
use crate::{
hotstuff::types::PhaseCertificate,
types::{
block::Block,
data_types::{BlockHeight, CryptoHash, Data, DataLen, Datum},
update_sets::AppStateUpdates,
validator_set::ValidatorSet,
},
};
use super::super::pluggables::KVStore;
use super::internal::{BlockTreeError, BlockTreeSingleton};
/// View of the block tree made available to [method calls](crate::app::App#required-methods) on `App`s.
///
/// # Purpose
///
/// The view of the block tree that `AppBlockTreeView` provides is special in two important ways to the
/// correct implementation of the `App` trait:
/// 1. `AppBlockTreeView` presents the App State as it is at a specific "point in time", that is:
/// - Just after [`parent_block`](crate::app::App::produce_block) is executed in the case of
/// `produce_block`.
/// - Just before [`proposed_block`](crate::app::App::validate_block) is executed in the case of
/// `validate_block`.
/// 2. `AppBlockTreeView` does not implement all of the block tree getters available through, e.g.,
/// [`BlockTreeSnapshot`](super::block_tree_snapshot::BlockTreeSnapshot). Instead, `AppBlockTreeView`'s
/// getters are limited to those that get the fields of the block tree that should be consistent
/// across all replicas at a specific point in time. `App` methods can therefore safely depend on the
/// data in these fields without risking [non-determinism](crate::app::App#determinism-requirements).
///
/// # Constructor
///
/// To create an instance of `AppBlockTreeView`, use [`BlockTree::app_view`].
pub struct AppBlockTreeView<'a, K: KVStore> {
// Reference to the block tree.
pub(super) block_tree: &'a BlockTreeSingleton<K>,
// The pending `AppStateUpdates` in the chain preceding the block this `AppBlockTreeView` is supposed
// to see the block tree from the perspective of.
pub(super) pending_ancestors_app_state_updates: Vec<Option<AppStateUpdates>>,
}
impl<'a, K: KVStore> AppBlockTreeView<'a, K> {
/// Get `block`, if it is currently in the block tree.
pub fn block(&self, block: &CryptoHash) -> Result<Option<Block>, BlockTreeError> {
self.block_tree.block(block)
}
/// Get the height of `block`, if `block` is currently in the block tree.
pub fn block_height(&self, block: &CryptoHash) -> Result<Option<BlockHeight>, BlockTreeError> {
self.block_tree.block_height(block)
}
/// Get `block.justify`, if `block` is currently in the block tree.
pub fn block_justify(&self, block: &CryptoHash) -> Result<PhaseCertificate, BlockTreeError> {
self.block_tree.block_justify(block)
}
/// Get `block.data_hash`, if `block` is currently in the block tree.
pub fn block_data_hash(
&self,
block: &CryptoHash,
) -> Result<Option<CryptoHash>, BlockTreeError> {
self.block_tree.block_data_hash(block)
}
/// Get `block.data.len()`, if `block` is currently in the block tree.
pub fn block_data_len(&self, block: &CryptoHash) -> Result<Option<DataLen>, BlockTreeError> {
self.block_tree.block_data_len(block)
}
/// Get the whole of `block.data`, if `block` is currently in the block tree.
pub fn block_data(&self, block: &CryptoHash) -> Result<Option<Data>, BlockTreeError> {
self.block_tree.block_data(block)
}
/// Get one `block.data[datum_index]`, if `block` is currently in the block tree.
pub fn block_datum(&self, block: &CryptoHash, datum_index: u32) -> Option<Datum> {
self.block_tree.block_datum(block, datum_index)
}
/// Get the committed block at `height`, if it is currently in the block tree.
pub fn block_at_height(
&self,
height: BlockHeight,
) -> Result<Option<CryptoHash>, BlockTreeError> {
self.block_tree.block_at_height(height)
}
/// Get the value associated with `key` in the current app state.
pub fn app_state(&'a self, key: &[u8]) -> Option<Vec<u8>> {
let latest_key_update =
self.pending_ancestors_app_state_updates
.iter()
.find(|app_state_updates_opt| {
if let Some(app_state_updates) = app_state_updates_opt {
app_state_updates.contains_delete(&key.to_vec())
|| app_state_updates.get_insert(&key.to_vec()).is_some()
} else {
false
}
});
if let Some(Some(app_state_updates)) = latest_key_update {
if app_state_updates.contains_delete(&key.to_vec()) {
return None;
} else if let Some(value) = app_state_updates.get_insert(&key.to_vec()) {
return Some(value.clone());
}
}
self.block_tree.committed_app_state(key)
}
/// Get the current committed validator set.
pub fn validator_set(&self) -> Result<ValidatorSet, BlockTreeError> {
self.block_tree.committed_validator_set()
}
}