penumbra_sdk_tct/
epoch.rs1use std::fmt::Display;
2use std::sync::Arc;
3
4use decaf377::Fq;
5use hash_hasher::HashedMap;
6use penumbra_sdk_proto::{penumbra::crypto::tct::v1 as pb, DomainType};
7use serde::{Deserialize, Serialize};
8
9use crate::error::epoch::*;
10use crate::{prelude::*, Witness};
11
12#[path = "block.rs"]
13pub(crate) mod block;
14
15#[derive(Derivative, Debug, Clone, Serialize, Deserialize)]
20pub struct Builder {
21 index: HashedMap<StateCommitment, index::within::Epoch>,
22 inner: Arc<frontier::Top<frontier::Tier<frontier::Item>>>,
23}
24
25impl Default for Builder {
26 fn default() -> Self {
27 Self {
28 index: HashedMap::default(),
29 inner: Arc::new(frontier::Top::new(frontier::TrackForgotten::No)),
30 }
31 }
32}
33
34#[derive(Derivative, Debug, Clone, Serialize, Deserialize)]
36pub struct Finalized {
37 pub(super) index: HashedMap<StateCommitment, index::within::Epoch>,
38 pub(super) inner: Insert<complete::Top<complete::Tier<complete::Item>>>,
39}
40
41impl Default for Finalized {
42 fn default() -> Self {
43 Builder::default().finalize()
44 }
45}
46
47impl Finalized {
48 pub fn root(&self) -> Root {
57 Root(self.inner.hash())
58 }
59}
60
61impl From<Root> for Finalized {
62 fn from(root: Root) -> Self {
63 Self {
64 index: HashedMap::default(),
65 inner: Insert::Hash(root.0),
66 }
67 }
68}
69
70impl From<Builder> for Finalized {
71 fn from(mut builder: Builder) -> Self {
72 builder.finalize()
73 }
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
78#[serde(try_from = "pb::MerkleRoot", into = "pb::MerkleRoot")]
79#[cfg_attr(any(test, feature = "arbitrary"), derive(proptest_derive::Arbitrary))]
80pub struct Root(pub Hash);
81
82impl Root {
83 pub fn is_empty_finalized(&self) -> bool {
85 self.0 == Hash::one()
86 }
87
88 pub fn is_empty_unfinalized(&self) -> bool {
90 self.0 == Hash::zero()
91 }
92}
93
94impl From<Root> for Fq {
95 fn from(root: Root) -> Self {
96 root.0.into()
97 }
98}
99
100impl TryFrom<pb::MerkleRoot> for Root {
101 type Error = RootDecodeError;
102
103 fn try_from(root: pb::MerkleRoot) -> Result<Root, Self::Error> {
104 let bytes: [u8; 32] = (&root.inner[..]).try_into().map_err(|_| RootDecodeError)?;
105 let inner = Fq::from_bytes_checked(&bytes).map_err(|_| RootDecodeError)?;
106 Ok(Root(Hash::new(inner)))
107 }
108}
109
110impl From<Root> for pb::MerkleRoot {
111 fn from(root: Root) -> Self {
112 Self {
113 inner: Fq::from(root.0).to_bytes().to_vec(),
114 }
115 }
116}
117
118impl DomainType for Root {
119 type Proto = pb::MerkleRoot;
120}
121
122impl Display for Root {
123 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
124 write!(f, "{}", hex::encode(Fq::from(self.0).to_bytes()))
125 }
126}
127
128impl From<InsertBlockError> for block::Finalized {
129 fn from(error: InsertBlockError) -> Self {
130 error.0
131 }
132}
133
134impl Builder {
135 pub fn new() -> Self {
137 Self::default()
138 }
139
140 pub fn insert(
149 &mut self,
150 witness: Witness,
151 commitment: StateCommitment,
152 ) -> Result<(), InsertError> {
153 let item = match witness {
154 Witness::Keep => commitment.into(),
155 Witness::Forget => Hash::of(commitment).into(),
156 };
157
158 let position = u32::try_from(self.inner.position().ok_or(InsertError::Full)?)
160 .expect("position of epoch is never greater than `u32::MAX`")
161 .into();
162
163 Arc::make_mut(&mut self.inner)
165 .update(|block| {
166 if block.is_finalized() {
169 return None;
170 }
171
172 Some(block.insert(item).map_err(|_| InsertError::BlockFull))
173 })
174 .flatten()
175 .unwrap_or_else(|| {
178 Arc::make_mut(&mut self.inner)
179 .insert(frontier::Tier::new(item))
180 .map_err(|_| InsertError::Full)?;
181 Ok(())
182 })?;
183
184 if let Witness::Keep = witness {
187 if let Some(replaced) = self.index.insert(commitment, position) {
188 let forgotten = Arc::make_mut(&mut self.inner).forget(replaced);
191 debug_assert!(forgotten);
192 }
193 }
194
195 Ok(())
196 }
197
198 pub fn insert_block(
203 &mut self,
204 block: impl Into<block::Finalized>,
205 ) -> Result<block::Root, InsertBlockError> {
206 let block::Finalized { inner, index } = block.into();
207
208 if self.inner.is_full() {
210 return Err(InsertBlockError(block::Finalized { inner, index }));
211 }
212
213 let inner: frontier::Tier<frontier::Item> = match inner {
215 Insert::Keep(inner) => inner.into(),
216 Insert::Hash(hash) => hash.into(),
217 };
218
219 Arc::make_mut(&mut self.inner).update(|block| block.finalize());
222
223 let index::within::Epoch { block, .. } = u32::try_from(
225 self.inner
226 .position()
227 .expect("epoch must have a position because it is not full"),
228 )
229 .expect("position of epoch is never greater than `u32::MAX`")
230 .into();
231
232 let block_root = block::Root(inner.hash());
234
235 Arc::make_mut(&mut self.inner)
237 .insert(inner)
238 .expect("inserting a block must succeed because epoch is not full");
239
240 for (c, index::within::Block { commitment }) in index {
242 if let Some(replaced) = self
245 .index
246 .insert(c, index::within::Epoch { block, commitment })
247 {
248 let forgotten = Arc::make_mut(&mut self.inner).forget(replaced);
251 debug_assert!(forgotten);
252 }
253 }
254
255 Ok(block_root)
256 }
257
258 pub fn end_block(&mut self) -> Result<block::Root, InsertBlockError> {
261 let (already_finalized, finalized_root) = Arc::make_mut(&mut self.inner)
264 .update(|tier| {
265 let already_finalized = tier.finalize();
266 (already_finalized, block::Root(tier.hash()))
267 })
268 .unwrap_or((true, block::Finalized::default().root()));
270
271 if already_finalized {
274 self.insert_block(block::Finalized::default())?;
275 };
276
277 Ok(finalized_root)
278 }
279
280 pub fn root(&self) -> Root {
284 Root(self.inner.hash())
285 }
286
287 pub fn finalize(&mut self) -> Finalized {
290 let this = std::mem::take(self);
291
292 let inner = Arc::try_unwrap(this.inner).unwrap_or_else(|arc| (*arc).clone());
294
295 let inner = inner.finalize();
296 let index = this.index;
297 Finalized { index, inner }
298 }
299}