Add construction of BridgeTree from parts.
This commit is contained in:
parent
f705a68db8
commit
d6c0088fc6
|
@ -191,9 +191,9 @@ impl<H> NonEmptyFrontier<H> {
|
|||
|
||||
impl<H: Clone> NonEmptyFrontier<H> {
|
||||
/// 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<A> AuthFragment<A> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn position(&self) -> Position {
|
||||
self.position
|
||||
}
|
||||
|
||||
pub fn altitudes_observed(&self) -> usize {
|
||||
self.altitudes_observed
|
||||
}
|
||||
|
||||
pub fn values(&self) -> &Vec<A> {
|
||||
&self.values
|
||||
}
|
||||
|
||||
pub fn is_complete(&self) -> bool {
|
||||
self.altitudes_observed >= self.position.altitudes_required().count()
|
||||
}
|
||||
|
@ -530,6 +542,30 @@ pub struct MerkleBridge<H> {
|
|||
frontier: NonEmptyFrontier<H>,
|
||||
}
|
||||
|
||||
impl<H> MerkleBridge<H> {
|
||||
pub fn prior_position(&self) -> Option<Position> {
|
||||
self.prior_position.clone()
|
||||
}
|
||||
|
||||
pub fn auth_fragments(&self) -> &HashMap<usize, AuthFragment<H>> {
|
||||
&self.auth_fragments
|
||||
}
|
||||
|
||||
pub fn frontier(&self) -> &NonEmptyFrontier<H> {
|
||||
&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<H: Hashable + Clone + PartialEq> MerkleBridge<H> {
|
||||
pub fn new(value: H) -> Self {
|
||||
MerkleBridge {
|
||||
|
@ -562,24 +598,14 @@ impl<H: Hashable + Clone + PartialEq> MerkleBridge<H> {
|
|||
}
|
||||
}
|
||||
|
||||
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<MerkleBridge<H>> {
|
||||
if next.can_follow(&self) {
|
||||
let fused = MerkleBridge {
|
||||
|
@ -620,23 +646,25 @@ impl<H: Hashable + Clone + PartialEq> MerkleBridge<H> {
|
|||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum Checkpoint<H> {
|
||||
/// 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<H>),
|
||||
}
|
||||
|
||||
impl<H> Checkpoint<H> {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
matches!(&self, Checkpoint::Empty)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct BridgeTree<H: Hash + Eq, const DEPTH: u8> {
|
||||
/// 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<MerkleBridge<H>>,
|
||||
/// 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<H, usize>,
|
||||
/// A stack of bridge indices to which it's possible to rewind directly.
|
||||
|
@ -651,24 +679,83 @@ impl<H: Hashable + Hash + Eq + Debug, const DEPTH: u8> Debug for BridgeTree<H, D
|
|||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> 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<H: Hashable + Hash + Eq + Clone, const DEPTH: u8> BridgeTree<H, DEPTH> {
|
||||
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<MerkleBridge<H>>,
|
||||
saved: HashMap<H, usize>,
|
||||
checkpoints: Vec<Checkpoint<H>>,
|
||||
max_checkpoints: usize,
|
||||
) -> Result<Self, BridgeTreeError> {
|
||||
// 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<H: Hashable + Hash + Eq + Clone, const DEPTH: u8> BridgeTree<H, DEPTH> {
|
|||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bridges(&self) -> &Vec<MerkleBridge<H>> {
|
||||
&self.bridges
|
||||
}
|
||||
|
||||
pub fn witnessable_leaves(&self) -> &HashMap<H, usize> {
|
||||
&self.saved
|
||||
}
|
||||
|
||||
pub fn checkpoints(&self) -> &Vec<Checkpoint<H>> {
|
||||
&self.checkpoints
|
||||
}
|
||||
|
||||
pub fn max_checkpoints(&self) -> usize {
|
||||
self.max_checkpoints
|
||||
}
|
||||
}
|
||||
|
||||
impl<H: Hashable + Hash + Eq + Clone, const DEPTH: u8> crate::Frontier<H> for BridgeTree<H, DEPTH> {
|
||||
|
@ -720,7 +823,7 @@ impl<H: Hashable + Hash + Eq + Clone, const DEPTH: u8> Tree<H> for BridgeTree<H,
|
|||
fn witness(&mut self) -> 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<H: Hashable + Hash + Eq + Clone, const DEPTH: u8> Tree<H> for BridgeTree<H,
|
|||
} else {
|
||||
self.bridges.truncate(i + 1);
|
||||
self.saved.retain(|_, saved_idx| *saved_idx <= i);
|
||||
if self.saved.contains_key(&bridge.frontier.leaf_value()) {
|
||||
if self.saved.contains_key(bridge.frontier.leaf_value()) {
|
||||
// if we've rewound to a witnessed point, then "re-witness"
|
||||
let is_duplicate_frontier =
|
||||
i > 0 && bridge.frontier == self.bridges[i - 1].frontier;
|
||||
|
|
Loading…
Reference in New Issue