penumbra_sdk_tct/storage/
deserialize.rs1use futures::StreamExt;
4
5use crate::prelude::*;
6
7pub async fn from_async_reader<R: AsyncRead>(reader: &mut R) -> Result<Tree, R::Error> {
9 let position = reader.position().await?;
10 let forgotten = reader.forgotten().await?;
11 let mut load_commitments = LoadCommitments::new(position, forgotten);
12 let mut commitments = reader.commitments();
13 while let Some((position, commitment)) = commitments.next().await.transpose()? {
14 load_commitments.insert(position, commitment);
15 }
16 drop(commitments);
17 let mut hashes = reader.hashes();
18 let mut load_hashes = load_commitments.load_hashes();
19 while let Some((position, height, hash)) = hashes.next().await.transpose()? {
20 load_hashes.insert(position, height, hash);
21 }
22 Ok(load_hashes.finish())
23}
24
25pub fn from_reader<R: Read>(reader: &mut R) -> Result<Tree, R::Error> {
27 let position = reader.position()?;
28 let forgotten = reader.forgotten()?;
29 let mut load_commitments = LoadCommitments::new(position, forgotten);
30 let mut commitments = reader.commitments();
31 while let Some((position, commitment)) = commitments.next().transpose()? {
32 load_commitments.insert(position, commitment);
33 }
34 drop(commitments);
35 let mut load_hashes = load_commitments.load_hashes();
36 let mut hashes = reader.hashes();
37 while let Some((position, height, hash)) = hashes.next().transpose()? {
38 load_hashes.insert(position, height, hash);
39 }
40 Ok(load_hashes.finish())
41}
42
43pub struct LoadCommitments {
48 inner: frontier::Top<frontier::Tier<frontier::Tier<frontier::Item>>>,
49 index: HashedMap<StateCommitment, index::within::Tree>,
50}
51
52impl LoadCommitments {
53 pub(crate) fn new(position: impl Into<StoredPosition>, forgotten: Forgotten) -> Self {
54 let position = match position.into() {
56 StoredPosition::Position(position) => Some(position.into()),
57 StoredPosition::Full => None,
58 };
59 Self {
60 inner: OutOfOrder::uninitialized(position, forgotten),
61 index: HashedMap::default(),
62 }
63 }
64
65 pub fn insert(&mut self, position: Position, commitment: StateCommitment) {
67 self.inner
68 .uninitialized_out_of_order_insert_commitment(position.into(), commitment);
69 self.index.insert(commitment, u64::from(position).into());
70 }
71
72 pub fn load_hashes(self) -> LoadHashes {
74 LoadHashes {
75 inner: self.inner,
76 index: self.index,
77 }
78 }
79}
80
81impl Extend<(Position, StateCommitment)> for LoadCommitments {
82 fn extend<T: IntoIterator<Item = (Position, StateCommitment)>>(&mut self, iter: T) {
83 for (position, commitment) in iter {
84 self.insert(position, commitment);
85 }
86 }
87}
88
89pub struct LoadHashes {
91 inner: frontier::Top<frontier::Tier<frontier::Tier<frontier::Item>>>,
92 index: HashedMap<StateCommitment, index::within::Tree>,
93}
94
95impl LoadHashes {
96 pub fn insert(&mut self, position: Position, height: u8, hash: Hash) {
98 self.inner.unchecked_set_hash(position.into(), height, hash);
99 }
100
101 pub fn finish(mut self) -> Tree {
103 self.inner.finish_initialize();
104 Tree::unchecked_from_parts(self.index, self.inner)
105 }
106}
107
108impl Extend<(Position, u8, Hash)> for LoadHashes {
109 fn extend<T: IntoIterator<Item = (Position, u8, Hash)>>(&mut self, iter: T) {
110 for (position, height, hash) in iter {
111 self.insert(position, height, hash);
112 }
113 }
114}
115
116#[cfg(test)]
117mod test {
118 use super::*;
119 use proptest::{arbitrary::*, prelude::*};
120
121 proptest::proptest! {
122 #[test]
123 fn uninitialized_produces_correct_position_and_forgotten(init_position in prop::option::of(any::<Position>()), init_forgotten in any::<Forgotten>()) {
124 let tree: frontier::Top<frontier::Tier<frontier::Tier<frontier::Item>>> =
125 OutOfOrder::uninitialized(init_position.map(Into::into), init_forgotten);
126 assert_eq!(init_position, tree.position().map(Into::into));
127 assert_eq!(init_forgotten, tree.forgotten().unwrap());
128 }
129 }
130}