penumbra_sdk_tct/
block.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::block::*;
10use crate::{prelude::*, Witness};
11
12#[derive(Derivative, Debug, Clone, Serialize, Deserialize)]
16pub struct Builder {
17 index: HashedMap<StateCommitment, index::within::Block>,
18 inner: Arc<frontier::Top<Item>>,
19}
20
21impl Default for Builder {
22 fn default() -> Self {
23 Self {
24 index: HashedMap::default(),
25 inner: Arc::new(frontier::Top::new(frontier::TrackForgotten::No)),
26 }
27 }
28}
29
30#[derive(Derivative, Debug, Clone, Serialize, Deserialize)]
33pub struct Finalized {
34 pub(in super::super) index: HashedMap<StateCommitment, index::within::Block>,
35 pub(in super::super) inner: Insert<complete::Top<complete::Item>>,
36}
37
38impl Default for Finalized {
39 fn default() -> Self {
40 Builder::default().finalize()
41 }
42}
43
44impl Finalized {
45 pub fn root(&self) -> Root {
54 Root(self.inner.hash())
55 }
56}
57
58impl From<Root> for Finalized {
59 fn from(root: Root) -> Self {
60 Self {
61 index: HashedMap::default(),
62 inner: Insert::Hash(root.0),
63 }
64 }
65}
66
67impl From<Builder> for Finalized {
68 fn from(mut builder: Builder) -> Self {
69 builder.finalize()
70 }
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
75#[serde(try_from = "pb::MerkleRoot", into = "pb::MerkleRoot")]
76#[cfg_attr(any(test, feature = "arbitrary"), derive(proptest_derive::Arbitrary))]
77pub struct Root(pub Hash);
78
79impl Root {
80 pub fn is_empty_finalized(&self) -> bool {
82 self.0 == Hash::one()
83 }
84
85 pub fn is_empty_unfinalized(&self) -> bool {
87 self.0 == Hash::zero()
88 }
89}
90
91impl From<Root> for Fq {
92 fn from(root: Root) -> Self {
93 root.0.into()
94 }
95}
96
97impl TryFrom<pb::MerkleRoot> for Root {
98 type Error = RootDecodeError;
99
100 fn try_from(root: pb::MerkleRoot) -> Result<Root, Self::Error> {
101 let bytes: [u8; 32] = (&root.inner[..]).try_into().map_err(|_| RootDecodeError)?;
102 let inner = Fq::from_bytes_checked(&bytes).map_err(|_| RootDecodeError)?;
103 Ok(Root(Hash::new(inner)))
104 }
105}
106
107impl From<Root> for pb::MerkleRoot {
108 fn from(root: Root) -> Self {
109 Self {
110 inner: Fq::from(root.0).to_bytes().to_vec(),
111 }
112 }
113}
114
115impl DomainType for Root {
116 type Proto = pb::MerkleRoot;
117}
118
119impl Display for Root {
120 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
121 write!(f, "{}", hex::encode(Fq::from(self.0).to_bytes()))
122 }
123}
124
125impl Builder {
126 pub fn new() -> Self {
128 Self::default()
129 }
130
131 pub fn insert(
137 &mut self,
138 witness: Witness,
139 commitment: StateCommitment,
140 ) -> Result<(), InsertError> {
141 let item = match witness {
142 Witness::Keep => commitment.into(),
143 Witness::Forget => Hash::of(commitment).into(),
144 };
145
146 let position = u16::try_from(self.inner.position().ok_or(InsertError)?)
148 .expect("position of block is never greater than `u16::MAX`")
149 .into();
150
151 Arc::make_mut(&mut self.inner)
153 .insert(item)
154 .expect("inserting a commitment must succeed when block has a position");
155
156 if let Witness::Keep = witness {
159 if let Some(replaced) = self.index.insert(commitment, position) {
160 let forgotten = Arc::make_mut(&mut self.inner).forget(replaced);
163 debug_assert!(forgotten);
164 }
165 }
166
167 Ok(())
168 }
169
170 pub fn root(&self) -> Root {
174 Root(self.inner.hash())
175 }
176
177 pub fn finalize(&mut self) -> Finalized {
180 let this = std::mem::take(self);
181
182 let inner = Arc::try_unwrap(this.inner).unwrap_or_else(|arc| (*arc).clone());
184
185 let inner = inner.finalize();
186 let index = this.index;
187 Finalized { index, inner }
188 }
189}
190
191#[cfg(test)]
192mod test {
193 use super::*;
194
195 #[test]
196 fn insert_error_sync_send() {
197 static_assertions::assert_impl_all!(InsertError: Sync, Send);
198 }
199}