From d6c0088fc6cda2dcefdbae3053593f947f0be6fe Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Tue, 13 Jul 2021 13:14:31 -0600 Subject: [PATCH] Add construction of BridgeTree from parts. --- src/bridgetree.rs | 155 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 129 insertions(+), 26 deletions(-) diff --git a/src/bridgetree.rs b/src/bridgetree.rs index 84cd514..00cb160 100644 --- a/src/bridgetree.rs +++ b/src/bridgetree.rs @@ -191,9 +191,9 @@ impl NonEmptyFrontier { impl NonEmptyFrontier { /// Returns the value of the most recently appended leaf. - pub fn leaf_value(&self) -> H { + pub fn leaf_value(&self) -> &H { match &self.leaf { - Leaf::Left(v) | Leaf::Right(_, v) => v.clone(), + Leaf::Left(v) | Leaf::Right(_, v) => v, } } } @@ -478,6 +478,18 @@ impl AuthFragment { } } + pub fn position(&self) -> Position { + self.position + } + + pub fn altitudes_observed(&self) -> usize { + self.altitudes_observed + } + + pub fn values(&self) -> &Vec { + &self.values + } + pub fn is_complete(&self) -> bool { self.altitudes_observed >= self.position.altitudes_required().count() } @@ -530,6 +542,30 @@ pub struct MerkleBridge { frontier: NonEmptyFrontier, } +impl MerkleBridge { + pub fn prior_position(&self) -> Option { + self.prior_position.clone() + } + + pub fn auth_fragments(&self) -> &HashMap> { + &self.auth_fragments + } + + pub fn frontier(&self) -> &NonEmptyFrontier { + &self.frontier + } + + pub fn max_altitude(&self) -> Altitude { + self.frontier.max_altitude() + } + + pub fn can_follow(&self, prev: &Self) -> bool { + self.prior_position + .iter() + .all(|p| *p == prev.frontier.position()) + } +} + impl MerkleBridge { pub fn new(value: H) -> Self { MerkleBridge { @@ -562,24 +598,14 @@ impl MerkleBridge { } } - pub fn max_altitude(&self) -> Altitude { - self.frontier.max_altitude() - } - pub fn root(&self) -> H { self.frontier.root() } - pub fn leaf_value(&self) -> H { + pub fn leaf_value(&self) -> &H { self.frontier.leaf_value() } - pub fn can_follow(&self, prev: &Self) -> bool { - self.prior_position - .iter() - .all(|p| *p == prev.frontier.position()) - } - fn fuse(&self, next: &Self) -> Option> { if next.can_follow(&self) { let fused = MerkleBridge { @@ -620,23 +646,25 @@ impl MerkleBridge { #[derive(Clone, Debug, Serialize, Deserialize)] pub enum Checkpoint { - /// checpoint of the empty bridge + /// Checkpoint of the empty bridge Empty, - /// + /// Checkpoint of a particular bridge state to which it is + /// possible to rewind. AtIndex(usize, MerkleBridge), } +impl Checkpoint { + pub fn is_empty(&self) -> bool { + matches!(&self, Checkpoint::Empty) + } +} + #[derive(Clone, Serialize, Deserialize)] pub struct BridgeTree { - /// Version value for the serialized form - ser_version: u8, /// The ordered list of Merkle bridges representing the history /// of the tree. There will be one bridge for each saved leaf, plus /// the current bridge to the tip of the tree. bridges: Vec>, - /// The last index of bridges for which no additional elements need - /// to be added to the trailing edge - incomplete_from: usize, /// A map from leaf digests to indices within the `bridges` vector. saved: HashMap, /// A stack of bridge indices to which it's possible to rewind directly. @@ -651,24 +679,83 @@ impl Debug for BridgeTree) -> Result<(), std::fmt::Error> { write!( f, - "BridgeTree {{\n depth: {:?},\n bridges: {:?},\n incomplete_from: {:?},\n saved: {:?},\n checkpoints: {:?},\n max_checkpoints: {:?}\n}}", - DEPTH, self.bridges, self.incomplete_from, self.saved, self.checkpoints, self.max_checkpoints + "BridgeTree {{\n depth: {:?},\n bridges: {:?},\n saved: {:?},\n checkpoints: {:?},\n max_checkpoints: {:?}\n}}", + DEPTH, self.bridges, self.saved, self.checkpoints, self.max_checkpoints ) } } +#[derive(Debug, Clone)] +pub enum BridgeTreeError { + IncorrectIncompleteIndex, + InvalidWitnessIndex, + InvalidSavePoints, + ContinuityError, + CheckpointMismatch, +} + impl BridgeTree { pub fn new(max_checkpoints: usize) -> Self { BridgeTree { - ser_version: 0, bridges: vec![], - incomplete_from: 0, saved: HashMap::new(), checkpoints: vec![], max_checkpoints, } } + pub fn from_parts( + bridges: Vec>, + saved: HashMap, + checkpoints: Vec>, + max_checkpoints: usize, + ) -> Result { + // check that saved values correspond to bridges + if saved + .iter() + .any(|(a, i)| i >= &bridges.len() || bridges[*i].frontier().leaf_value() != a) + { + Err(BridgeTreeError::InvalidWitnessIndex) + } else if bridges.is_empty() { + // it's okay to return the empty bridge, but only if there are no saved points + // and no non-empty checkpoints + if saved.is_empty() && checkpoints.iter().all(|c| c.is_empty()) { + let mut result = Self::new(max_checkpoints); + for _ in checkpoints.iter() { + // restore the correct number of empty checkpoints. + result.checkpoint() + } + Ok(result) + } else { + Err(BridgeTreeError::InvalidSavePoints) + } + // check continuity of bridge order + } else if bridges + .iter() + .zip(bridges.iter().skip(1)) + .any(|(prev, next)| !next.can_follow(prev)) + { + Err(BridgeTreeError::ContinuityError) + // verify checkpoints to ensure continuity from bridge locations + } else if checkpoints.len() > max_checkpoints + || checkpoints.iter().any(|c| match c { + Checkpoint::Empty => false, + Checkpoint::AtIndex(i, b) => { + i == &0 || i >= &bridges.len() || !b.can_follow(&bridges[i - 1]) + } + }) + { + Err(BridgeTreeError::CheckpointMismatch) + } else { + Ok(BridgeTree { + bridges, + saved, + checkpoints, + max_checkpoints, + }) + } + } + /// Removes the oldest checkpoint. Returns true if successful and false if /// there are no checkpoints. fn drop_oldest_checkpoint(&mut self) -> bool { @@ -679,6 +766,22 @@ impl BridgeTree { true } } + + pub fn bridges(&self) -> &Vec> { + &self.bridges + } + + pub fn witnessable_leaves(&self) -> &HashMap { + &self.saved + } + + pub fn checkpoints(&self) -> &Vec> { + &self.checkpoints + } + + pub fn max_checkpoints(&self) -> usize { + self.max_checkpoints + } } impl crate::Frontier for BridgeTree { @@ -720,7 +823,7 @@ impl Tree for BridgeTree bool { let next = self.bridges.last().map(|current| { ( - current.leaf_value(), + current.leaf_value().clone(), current.successor(self.bridges.len() - 1), ) }); @@ -867,7 +970,7 @@ impl Tree for BridgeTree 0 && bridge.frontier == self.bridges[i - 1].frontier;