the Position type is exclusively used with leaves, propose a readability rename to LeafPosition

This commit is contained in:
zancas 2023-07-06 11:17:00 -06:00
parent 67111e2940
commit c30825df64
No known key found for this signature in database
GPG Key ID: E4BCAA0A9B09F559
9 changed files with 286 additions and 253 deletions

View File

@ -32,7 +32,7 @@
//! In this module, the term "ommer" is used as for the sibling of a parent node in a binary tree.
pub use incrementalmerkletree::{
frontier::{Frontier, NonEmptyFrontier},
Address, Hashable, Level, Position, Retention, Source,
Address, Hashable, LeafPosition, Level, Retention, Source,
};
use std::collections::{BTreeMap, BTreeSet, VecDeque};
use std::fmt::Debug;
@ -45,7 +45,7 @@ pub enum ContinuityError {
PriorPositionNotFound,
/// Returned when the subsequent bridge's prior position does not match the position of the
/// prior bridge's frontier.
PositionMismatch(Position, Position),
PositionMismatch(LeafPosition, LeafPosition),
}
/// Errors that can be discovered during the process of attempting to create
@ -55,7 +55,7 @@ pub enum WitnessingError {
AuthBaseNotFound,
CheckpointInvalid,
CheckpointTooDeep(usize),
PositionNotMarked(Position),
PositionNotMarked(LeafPosition),
BridgeFusionError(ContinuityError),
BridgeAddressInvalid(Address),
}
@ -78,7 +78,7 @@ pub enum WitnessingError {
pub struct MerkleBridge<H> {
/// The position of the final leaf in the frontier of the bridge that this bridge is the
/// successor of, or None if this is the first bridge in a tree.
prior_position: Option<Position>,
prior_position: Option<LeafPosition>,
/// The set of addresses for which we are waiting to discover the ommers. The values of this
/// set and the keys of the `need` map should always be disjoint. Also, this set should
/// never contain an address for which the sibling value has been discovered; at that point,
@ -112,7 +112,7 @@ impl<H> MerkleBridge<H> {
/// Construct a new Merkle bridge from its constituent parts.
pub fn from_parts(
prior_position: Option<Position>,
prior_position: Option<LeafPosition>,
tracking: BTreeSet<Address>,
ommers: BTreeMap<Address, H>,
frontier: NonEmptyFrontier<H>,
@ -128,12 +128,12 @@ impl<H> MerkleBridge<H> {
/// Returns the position of the final leaf in the frontier of the
/// bridge that this bridge is the successor of, or None
/// if this is the first bridge in a tree.
pub fn prior_position(&self) -> Option<Position> {
pub fn prior_position(&self) -> Option<LeafPosition> {
self.prior_position
}
/// Returns the position of the most recently appended leaf.
pub fn position(&self) -> Position {
pub fn position(&self) -> LeafPosition {
self.frontier.position()
}
@ -177,9 +177,9 @@ impl<H> MerkleBridge<H> {
}
/// Returns the range of positions observed by this bridge.
pub fn position_range(&self) -> Range<Position> {
pub fn position_range(&self) -> Range<LeafPosition> {
Range {
start: self.prior_position.unwrap_or_else(|| Position::from(0)),
start: self.prior_position.unwrap_or_else(|| LeafPosition::from(0)),
end: self.position() + 1,
}
}
@ -330,11 +330,11 @@ pub struct Checkpoint<C> {
bridges_len: usize,
/// A set of the positions that have been marked during the period that this
/// checkpoint is the current checkpoint.
marked: BTreeSet<Position>,
marked: BTreeSet<LeafPosition>,
/// When a mark is forgotten, we add it to the checkpoint's forgotten set but
/// don't immediately remove it from the `saved` map; that removal occurs when
/// the checkpoint is eventually dropped.
forgotten: BTreeSet<Position>,
forgotten: BTreeSet<LeafPosition>,
}
impl<C> Checkpoint<C> {
@ -342,8 +342,8 @@ impl<C> Checkpoint<C> {
pub fn from_parts(
id: C,
bridges_len: usize,
marked: BTreeSet<Position>,
forgotten: BTreeSet<Position>,
marked: BTreeSet<LeafPosition>,
forgotten: BTreeSet<LeafPosition>,
) -> Self {
Self {
id,
@ -379,13 +379,13 @@ impl<C> Checkpoint<C> {
/// Returns a set of the positions that have been marked during the period that this
/// checkpoint is the current checkpoint.
pub fn marked(&self) -> &BTreeSet<Position> {
pub fn marked(&self) -> &BTreeSet<LeafPosition> {
&self.marked
}
/// Returns the set of previously-marked positions that have had their marks removed
/// during the period that this checkpoint is the current checkpoint.
pub fn forgotten(&self) -> &BTreeSet<Position> {
pub fn forgotten(&self) -> &BTreeSet<LeafPosition> {
&self.forgotten
}
@ -405,7 +405,7 @@ impl<C> Checkpoint<C> {
// A private convenience method that returns the position of the bridge corresponding
// to this checkpoint, if the checkpoint is not for the empty bridge.
fn position<H: Ord>(&self, bridges: &[MerkleBridge<H>]) -> Option<Position> {
fn position<H: Ord>(&self, bridges: &[MerkleBridge<H>]) -> Option<LeafPosition> {
if self.bridges_len == 0 {
None
} else {
@ -431,7 +431,7 @@ pub struct BridgeTree<H, C, const DEPTH: u8> {
current_bridge: Option<MerkleBridge<H>>,
/// A map from positions for which we wish to be able to compute a
/// witness to index in the bridges vector.
saved: BTreeMap<Position, usize>,
saved: BTreeMap<LeafPosition, usize>,
/// A deque of bridge indices to which it's possible to rewind directly.
/// This deque must be maintained to have a minimum size of 1 and a maximum
/// size of `max_checkpoints` in order to correctly maintain mark & rewind
@ -459,7 +459,10 @@ impl<H: Debug, C: Debug, const DEPTH: u8> Debug for BridgeTree<H, C, DEPTH> {
pub enum BridgeTreeError {
IncorrectIncompleteIndex,
InvalidMarkIndex(usize),
PositionMismatch { expected: Position, found: Position },
PositionMismatch {
expected: LeafPosition,
found: LeafPosition,
},
InvalidSavePoints,
Discontinuity(ContinuityError),
CheckpointMismatch,
@ -510,7 +513,7 @@ impl<H, C, const DEPTH: u8> BridgeTree<H, C, DEPTH> {
/// Returns the map from leaf positions that have been marked to the index of
/// the bridge whose tip is at that position in this tree's list of bridges.
pub fn marked_indices(&self) -> &BTreeMap<Position, usize> {
pub fn marked_indices(&self) -> &BTreeMap<LeafPosition, usize> {
&self.saved
}
@ -555,7 +558,7 @@ impl<H: Hashable + Clone + Ord, C: Clone + Ord, const DEPTH: u8> BridgeTree<H, C
pub fn from_parts(
prior_bridges: Vec<MerkleBridge<H>>,
current_bridge: Option<MerkleBridge<H>>,
saved: BTreeMap<Position, usize>,
saved: BTreeMap<LeafPosition, usize>,
checkpoints: VecDeque<Checkpoint<C>>,
max_checkpoints: usize,
) -> Result<Self, BridgeTreeError> {
@ -588,7 +591,7 @@ impl<H: Hashable + Clone + Ord, C: Clone + Ord, const DEPTH: u8> BridgeTree<H, C
fn check_consistency_internal(
prior_bridges: &[MerkleBridge<H>],
current_bridge: &Option<MerkleBridge<H>>,
saved: &BTreeMap<Position, usize>,
saved: &BTreeMap<LeafPosition, usize>,
checkpoints: &VecDeque<Checkpoint<C>>,
max_checkpoints: usize,
) -> Result<(), BridgeTreeError> {
@ -673,7 +676,7 @@ impl<H: Hashable + Clone + Ord, C: Clone + Ord, const DEPTH: u8> BridgeTree<H, C
}
/// Returns the most recently appended leaf value.
pub fn current_position(&self) -> Option<Position> {
pub fn current_position(&self) -> Option<LeafPosition> {
self.current_bridge.as_ref().map(|b| b.position())
}
@ -686,7 +689,7 @@ impl<H: Hashable + Clone + Ord, C: Clone + Ord, const DEPTH: u8> BridgeTree<H, C
///
/// Returns an optional value containing the current position if successful or if the current
/// value was already marked, or None if the tree is empty.
pub fn mark(&mut self) -> Option<Position> {
pub fn mark(&mut self) -> Option<LeafPosition> {
match self.current_bridge.take() {
Some(mut cur_b) => {
let pos = cur_b.position();
@ -724,13 +727,13 @@ impl<H: Hashable + Clone + Ord, C: Clone + Ord, const DEPTH: u8> BridgeTree<H, C
}
/// Return a set of all the positions for which we have marked.
pub fn marked_positions(&self) -> BTreeSet<Position> {
pub fn marked_positions(&self) -> BTreeSet<LeafPosition> {
self.saved.keys().cloned().collect()
}
/// Returns the leaf at the specified position if the tree can produce
/// a witness for it.
pub fn get_marked_leaf(&self, position: Position) -> Option<&H> {
pub fn get_marked_leaf(&self, position: LeafPosition) -> Option<&H> {
self.saved
.get(&position)
.and_then(|idx| self.prior_bridges.get(*idx).map(|b| b.current_leaf()))
@ -739,7 +742,7 @@ impl<H: Hashable + Clone + Ord, C: Clone + Ord, const DEPTH: u8> BridgeTree<H, C
/// Marks the value at the specified position as a value we're no longer
/// interested in maintaining a mark for. Returns true if successful and
/// false if we were already not maintaining a mark at this position.
pub fn remove_mark(&mut self, position: Position) -> bool {
pub fn remove_mark(&mut self, position: LeafPosition) -> bool {
if self.saved.contains_key(&position) {
if let Some(c) = self.checkpoints.back_mut() {
c.forgotten.insert(position);
@ -819,7 +822,7 @@ impl<H: Hashable + Clone + Ord, C: Clone + Ord, const DEPTH: u8> BridgeTree<H, C
/// position or if no checkpoint is available at the specified depth.
pub fn witness(
&self,
position: Position,
position: LeafPosition,
checkpoint_depth: usize,
) -> Result<Vec<H>, WitnessingError> {
#[derive(Debug)]
@ -1015,15 +1018,15 @@ mod tests {
DEPTH
}
fn current_position(&self) -> Option<Position> {
fn current_position(&self) -> Option<LeafPosition> {
BridgeTree::current_position(self)
}
fn get_marked_leaf(&self, position: Position) -> Option<H> {
fn get_marked_leaf(&self, position: LeafPosition) -> Option<H> {
BridgeTree::get_marked_leaf(self, position).cloned()
}
fn marked_positions(&self) -> BTreeSet<Position> {
fn marked_positions(&self) -> BTreeSet<LeafPosition> {
BridgeTree::marked_positions(self)
}
@ -1031,11 +1034,11 @@ mod tests {
BridgeTree::root(self, checkpoint_depth)
}
fn witness(&self, position: Position, checkpoint_depth: usize) -> Option<Vec<H>> {
fn witness(&self, position: LeafPosition, checkpoint_depth: usize) -> Option<Vec<H>> {
BridgeTree::witness(self, position, checkpoint_depth).ok()
}
fn remove_mark(&mut self, position: Position) -> bool {
fn remove_mark(&mut self, position: LeafPosition) -> bool {
BridgeTree::remove_mark(self, position)
}
@ -1080,7 +1083,7 @@ mod tests {
where
G::Value: Hashable + Clone + Ord + Debug + 'static,
{
let pos_gen = (0..max_count).prop_map(|p| Position::try_from(p).unwrap());
let pos_gen = (0..max_count).prop_map(|p| LeafPosition::try_from(p).unwrap());
proptest::collection::vec(arb_operation(item_gen, pos_gen), 0..max_count).prop_map(|ops| {
let mut tree: BridgeTree<G::Value, usize, 8> = BridgeTree::new(10);
for (i, op) in ops.into_iter().enumerate() {
@ -1164,9 +1167,9 @@ mod tests {
if i % 7 == 0 {
t.mark();
if i > 0 && i % 2 == 0 {
to_unmark.push(Position::from(i));
to_unmark.push(LeafPosition::from(i));
} else {
has_witness.push(Position::from(i));
has_witness.push(LeafPosition::from(i));
}
}
if i % 11 == 0 && !to_unmark.is_empty() {
@ -1221,7 +1224,7 @@ mod tests {
ops in proptest::collection::vec(
arb_operation(
(0..32u64).prop_map(SipHashable),
(0u64..100).prop_map(Position::from)
(0u64..100).prop_map(LeafPosition::from)
),
1..100
)
@ -1236,7 +1239,7 @@ mod tests {
ops in proptest::collection::vec(
arb_operation(
(97u8..123).prop_map(|c| char::from(c).to_string()),
(0u64..100).prop_map(Position::from)
(0u64..100).prop_map(LeafPosition::from)
),
1..100
)

View File

@ -1,7 +1,7 @@
use std::convert::TryFrom;
use std::mem::size_of;
use crate::{Address, Hashable, Level, MerklePath, Position, Source};
use crate::{Address, Hashable, LeafPosition, Level, MerklePath, Source};
#[cfg(feature = "legacy-api")]
use {std::collections::VecDeque, std::iter::repeat};
@ -25,7 +25,7 @@ pub enum FrontierError {
/// values that will be required when producing a witness for the current leaf.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NonEmptyFrontier<H> {
position: Position,
position: LeafPosition,
leaf: H,
ommers: Vec<H>,
}
@ -41,7 +41,11 @@ impl<H> NonEmptyFrontier<H> {
}
/// Constructs a new frontier from its constituent parts.
pub fn from_parts(position: Position, leaf: H, ommers: Vec<H>) -> Result<Self, FrontierError> {
pub fn from_parts(
position: LeafPosition,
leaf: H,
ommers: Vec<H>,
) -> Result<Self, FrontierError> {
let expected_ommers = position.past_ommer_count();
if ommers.len() == expected_ommers.into() {
Ok(Self {
@ -55,12 +59,12 @@ impl<H> NonEmptyFrontier<H> {
}
/// Decomposes the frontier into its constituent parts
pub fn into_parts(self) -> (Position, H, Vec<H>) {
pub fn into_parts(self) -> (LeafPosition, H, Vec<H>) {
(self.position, self.leaf, self.ommers)
}
/// Returns the position of the most recently appended leaf.
pub fn position(&self) -> Position {
pub fn position(&self) -> LeafPosition {
self.position
}
@ -205,7 +209,11 @@ impl<H, const DEPTH: u8> Frontier<H, DEPTH> {
///
/// Returns an error if the new frontier would exceed the maximum allowed depth or if the list
/// of ommers provided is not consistent with the position of the leaf.
pub fn from_parts(position: Position, leaf: H, ommers: Vec<H>) -> Result<Self, FrontierError> {
pub fn from_parts(
position: LeafPosition,
leaf: H,
ommers: Vec<H>,
) -> Result<Self, FrontierError> {
NonEmptyFrontier::from_parts(position, leaf, ommers).and_then(Self::try_from)
}

View File

@ -135,9 +135,9 @@ impl Iterator for WitnessAddrsIter {
/// A type representing the position of a leaf in a Merkle tree.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Position(u64);
pub struct LeafPosition(u64);
impl Position {
impl LeafPosition {
/// Return whether the position refers to the right-hand child of a subtree with
/// its root at level 1.
pub fn is_right_child(&self) -> bool {
@ -180,51 +180,51 @@ impl Position {
}
}
impl From<Position> for u64 {
fn from(p: Position) -> Self {
impl From<LeafPosition> for u64 {
fn from(p: LeafPosition) -> Self {
p.0
}
}
impl From<u64> for Position {
impl From<u64> for LeafPosition {
fn from(sz: u64) -> Self {
Self(sz)
}
}
impl Add<u64> for Position {
type Output = Position;
impl Add<u64> for LeafPosition {
type Output = LeafPosition;
fn add(self, other: u64) -> Self {
Position(self.0 + other)
LeafPosition(self.0 + other)
}
}
impl AddAssign<u64> for Position {
impl AddAssign<u64> for LeafPosition {
fn add_assign(&mut self, other: u64) {
self.0 += other
}
}
impl Sub<u64> for Position {
type Output = Position;
impl Sub<u64> for LeafPosition {
type Output = LeafPosition;
fn sub(self, other: u64) -> Self {
if self.0 < other {
panic!("position underflow");
}
Position(self.0 - other)
LeafPosition(self.0 - other)
}
}
impl TryFrom<usize> for Position {
impl TryFrom<usize> for LeafPosition {
type Error = TryFromIntError;
fn try_from(sz: usize) -> Result<Self, Self::Error> {
<u64>::try_from(sz).map(Self)
}
}
impl TryFrom<Position> for usize {
impl TryFrom<LeafPosition> for usize {
type Error = TryFromIntError;
fn try_from(p: Position) -> Result<Self, Self::Error> {
fn try_from(p: LeafPosition) -> Result<Self, Self::Error> {
<usize>::try_from(p.0)
}
}
@ -320,7 +320,7 @@ impl Address {
}
/// Returns the address at the given level that contains the specified leaf position.
pub fn above_position(level: Level, position: Position) -> Self {
pub fn above_position(level: Level, position: LeafPosition) -> Self {
Address {
level,
index: position.0 >> level.0,
@ -412,25 +412,25 @@ impl Address {
/// Returns the minimum value among the range of leaf positions that are contained within the
/// tree with its root at this address.
pub fn position_range_start(&self) -> Position {
pub fn position_range_start(&self) -> LeafPosition {
(self.index << self.level.0).try_into().unwrap()
}
/// Returns the (exclusive) end of the range of leaf positions that are contained within the
/// tree with its root at this address.
pub fn position_range_end(&self) -> Position {
pub fn position_range_end(&self) -> LeafPosition {
((self.index + 1) << self.level.0).try_into().unwrap()
}
/// Returns the maximum value among the range of leaf positions that are contained within the
/// tree with its root at this address.
pub fn max_position(&self) -> Position {
pub fn max_position(&self) -> LeafPosition {
self.position_range_end() - 1
}
/// Returns the end-exclusive range of leaf positions that are contained within the tree with
/// its root at this address.
pub fn position_range(&self) -> Range<Position> {
pub fn position_range(&self) -> Range<LeafPosition> {
Range {
start: self.position_range_start(),
end: self.position_range_end(),
@ -459,7 +459,7 @@ impl Address {
/// Returns whether the tree with this root address contains the given leaf position, or if not
/// whether an address at the same level with a greater or lesser index will contain the
/// specified leaf position.
pub fn position_cmp(&self, pos: Position) -> Ordering {
pub fn position_cmp(&self, pos: LeafPosition) -> Ordering {
let range = self.position_range();
if range.start > pos {
Ordering::Greater
@ -518,8 +518,8 @@ impl Address {
}
}
impl From<Position> for Address {
fn from(p: Position) -> Self {
impl From<LeafPosition> for Address {
fn from(p: LeafPosition) -> Self {
Address {
level: 0.into(),
index: p.into(),
@ -527,8 +527,8 @@ impl From<Position> for Address {
}
}
impl<'a> From<&'a Position> for Address {
fn from(p: &'a Position) -> Self {
impl<'a> From<&'a LeafPosition> for Address {
fn from(p: &'a LeafPosition) -> Self {
Address {
level: 0.into(),
index: (*p).into(),
@ -536,7 +536,7 @@ impl<'a> From<&'a Position> for Address {
}
}
impl From<Address> for Option<Position> {
impl From<Address> for Option<LeafPosition> {
fn from(addr: Address) -> Self {
if addr.level == 0.into() {
Some(addr.index.into())
@ -546,7 +546,7 @@ impl From<Address> for Option<Position> {
}
}
impl<'a> From<&'a Address> for Option<Position> {
impl<'a> From<&'a Address> for Option<LeafPosition> {
fn from(addr: &'a Address) -> Self {
if addr.level == 0.into() {
Some(addr.index.into())
@ -560,13 +560,13 @@ impl<'a> From<&'a Address> for Option<Position> {
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MerklePath<H, const DEPTH: u8> {
path_elems: Vec<H>,
position: Position,
position: LeafPosition,
}
impl<H, const DEPTH: u8> MerklePath<H, DEPTH> {
/// Constructs a Merkle path directly from a path and position.
#[allow(clippy::result_unit_err)]
pub fn from_parts(path_elems: Vec<H>, position: Position) -> Result<Self, ()> {
pub fn from_parts(path_elems: Vec<H>, position: LeafPosition) -> Result<Self, ()> {
if path_elems.len() == usize::from(DEPTH) {
Ok(MerklePath {
path_elems,
@ -581,7 +581,7 @@ impl<H, const DEPTH: u8> MerklePath<H, DEPTH> {
&self.path_elems
}
pub fn position(&self) -> Position {
pub fn position(&self) -> LeafPosition {
self.position
}
}
@ -623,42 +623,42 @@ pub trait Hashable: fmt::Debug {
pub(crate) mod tests {
use crate::MerklePath;
use super::{Address, Level, Position, Source};
use super::{Address, LeafPosition, Level, Source};
use core::ops::Range;
use either::Either;
#[test]
fn position_is_complete_subtree() {
assert!(Position(0).is_complete_subtree(Level(0)));
assert!(Position(1).is_complete_subtree(Level(1)));
assert!(!Position(2).is_complete_subtree(Level(1)));
assert!(!Position(2).is_complete_subtree(Level(2)));
assert!(Position(3).is_complete_subtree(Level(2)));
assert!(!Position(4).is_complete_subtree(Level(2)));
assert!(Position(7).is_complete_subtree(Level(3)));
assert!(Position(u32::MAX as u64).is_complete_subtree(Level(32)));
assert!(LeafPosition(0).is_complete_subtree(Level(0)));
assert!(LeafPosition(1).is_complete_subtree(Level(1)));
assert!(!LeafPosition(2).is_complete_subtree(Level(1)));
assert!(!LeafPosition(2).is_complete_subtree(Level(2)));
assert!(LeafPosition(3).is_complete_subtree(Level(2)));
assert!(!LeafPosition(4).is_complete_subtree(Level(2)));
assert!(LeafPosition(7).is_complete_subtree(Level(3)));
assert!(LeafPosition(u32::MAX as u64).is_complete_subtree(Level(32)));
}
#[test]
fn position_past_ommer_count() {
assert_eq!(0, Position(0).past_ommer_count());
assert_eq!(1, Position(1).past_ommer_count());
assert_eq!(1, Position(2).past_ommer_count());
assert_eq!(2, Position(3).past_ommer_count());
assert_eq!(1, Position(4).past_ommer_count());
assert_eq!(3, Position(7).past_ommer_count());
assert_eq!(1, Position(8).past_ommer_count());
assert_eq!(0, LeafPosition(0).past_ommer_count());
assert_eq!(1, LeafPosition(1).past_ommer_count());
assert_eq!(1, LeafPosition(2).past_ommer_count());
assert_eq!(2, LeafPosition(3).past_ommer_count());
assert_eq!(1, LeafPosition(4).past_ommer_count());
assert_eq!(3, LeafPosition(7).past_ommer_count());
assert_eq!(1, LeafPosition(8).past_ommer_count());
}
#[test]
fn position_root_level() {
assert_eq!(Level(0), Position(0).root_level());
assert_eq!(Level(1), Position(1).root_level());
assert_eq!(Level(2), Position(2).root_level());
assert_eq!(Level(2), Position(3).root_level());
assert_eq!(Level(3), Position(4).root_level());
assert_eq!(Level(3), Position(7).root_level());
assert_eq!(Level(4), Position(8).root_level());
assert_eq!(Level(0), LeafPosition(0).root_level());
assert_eq!(Level(1), LeafPosition(1).root_level());
assert_eq!(Level(2), LeafPosition(2).root_level());
assert_eq!(Level(2), LeafPosition(3).root_level());
assert_eq!(Level(3), LeafPosition(4).root_level());
assert_eq!(Level(3), LeafPosition(7).root_level());
assert_eq!(Level(4), LeafPosition(8).root_level());
}
#[test]
@ -667,13 +667,13 @@ pub(crate) mod tests {
let path_elem = |l, i, s| (Address::from_parts(Level::from(l), i), s);
assert_eq!(
vec![path_elem(0, 1, Future), path_elem(1, 1, Future)],
Position::from(0)
LeafPosition::from(0)
.witness_addrs(Level::from(2))
.collect::<Vec<_>>()
);
assert_eq!(
vec![path_elem(0, 3, Future), path_elem(1, 0, Past(0))],
Position::from(2)
LeafPosition::from(2)
.witness_addrs(Level::from(2))
.collect::<Vec<_>>()
);
@ -683,7 +683,7 @@ pub(crate) mod tests {
path_elem(1, 0, Past(1)),
path_elem(2, 1, Future)
],
Position::from(3)
LeafPosition::from(3)
.witness_addrs(Level::from(3))
.collect::<Vec<_>>()
);
@ -694,7 +694,7 @@ pub(crate) mod tests {
path_elem(2, 0, Past(0)),
path_elem(3, 1, Future)
],
Position::from(4)
LeafPosition::from(4)
.witness_addrs(Level::from(4))
.collect::<Vec<_>>()
);
@ -705,7 +705,7 @@ pub(crate) mod tests {
path_elem(2, 0, Past(1)),
path_elem(3, 1, Future)
],
Position::from(6)
LeafPosition::from(6)
.witness_addrs(Level::from(4))
.collect::<Vec<_>>()
);
@ -746,22 +746,22 @@ pub(crate) mod tests {
assert_eq!(
Address::from_parts(Level(0), 0).position_range(),
Range {
start: Position(0),
end: Position(1)
start: LeafPosition(0),
end: LeafPosition(1)
}
);
assert_eq!(
Address::from_parts(Level(1), 0).position_range(),
Range {
start: Position(0),
end: Position(2)
start: LeafPosition(0),
end: LeafPosition(2)
}
);
assert_eq!(
Address::from_parts(Level(2), 1).position_range(),
Range {
start: Position(4),
end: Position(8)
start: LeafPosition(4),
end: LeafPosition(8)
}
);
}
@ -769,7 +769,7 @@ pub(crate) mod tests {
#[test]
fn addr_above_position() {
assert_eq!(
Address::above_position(Level(3), Position(9)),
Address::above_position(Level(3), LeafPosition(9)),
Address::from_parts(Level(3), 1)
);
}
@ -811,7 +811,7 @@ pub(crate) mod tests {
fn merkle_path_root() {
let path: MerklePath<String, 3> = MerklePath::from_parts(
vec!["a".to_string(), "cd".to_string(), "efgh".to_string()],
Position(1),
LeafPosition(1),
)
.unwrap();
@ -819,7 +819,7 @@ pub(crate) mod tests {
let path: MerklePath<String, 3> = MerklePath::from_parts(
vec!["d".to_string(), "ab".to_string(), "efgh".to_string()],
Position(2),
LeafPosition(2),
)
.unwrap();

View File

@ -5,7 +5,7 @@ use core::marker::PhantomData;
use proptest::prelude::*;
use std::collections::BTreeSet;
use crate::{Hashable, Level, Position, Retention};
use crate::{Hashable, LeafPosition, Level, Retention};
pub mod complete_tree;
@ -38,14 +38,14 @@ pub trait Tree<H, C> {
fn append(&mut self, value: H, retention: Retention<C>) -> bool;
/// Returns the most recently appended leaf value.
fn current_position(&self) -> Option<Position>;
fn current_position(&self) -> Option<LeafPosition>;
/// Returns the leaf at the specified position if the tree can produce
/// a witness for it.
fn get_marked_leaf(&self, position: Position) -> Option<H>;
fn get_marked_leaf(&self, position: LeafPosition) -> Option<H>;
/// Return a set of all the positions for which we have marked.
fn marked_positions(&self) -> BTreeSet<Position>;
fn marked_positions(&self) -> BTreeSet<LeafPosition>;
/// Obtains the root of the Merkle tree at the specified checkpoint depth
/// by hashing against empty nodes up to the maximum height of the tree.
@ -56,12 +56,12 @@ pub trait Tree<H, C> {
/// Obtains a witness for the value at the specified leaf position, as of the tree state at the
/// given checkpoint depth. Returns `None` if there is no witness information for the requested
/// position or if no checkpoint is available at the specified depth.
fn witness(&self, position: Position, checkpoint_depth: usize) -> Option<Vec<H>>;
fn witness(&self, position: LeafPosition, checkpoint_depth: usize) -> Option<Vec<H>>;
/// Marks the value at the specified position as a value we're no longer
/// interested in maintaining a mark for. Returns true if successful and
/// false if we were already not maintaining a mark at this position.
fn remove_mark(&mut self, position: Position) -> bool;
fn remove_mark(&mut self, position: LeafPosition) -> bool;
/// Creates a new checkpoint for the current tree state.
///
@ -132,12 +132,12 @@ impl<H: Hashable> Hashable for Option<H> {
pub enum Operation<A, C> {
Append(A, Retention<C>),
CurrentPosition,
MarkedLeaf(Position),
MarkedLeaf(LeafPosition),
MarkedPositions,
Unmark(Position),
Unmark(LeafPosition),
Checkpoint(C),
Rewind,
Witness(Position, usize),
Witness(LeafPosition, usize),
GarbageCollect,
}
@ -148,15 +148,15 @@ pub fn append_str<C>(x: &str, retention: Retention<C>) -> Operation<String, C> {
}
pub fn unmark<H, C>(pos: u64) -> Operation<H, C> {
Operation::Unmark(Position::from(pos))
Operation::Unmark(LeafPosition::from(pos))
}
pub fn witness<H, C>(pos: u64, depth: usize) -> Operation<H, C> {
Operation::Witness(Position::from(pos), depth)
Operation::Witness(LeafPosition::from(pos), depth)
}
impl<H: Hashable + Clone, C: Clone> Operation<H, C> {
pub fn apply<T: Tree<H, C>>(&self, tree: &mut T) -> Option<(Position, Vec<H>)> {
pub fn apply<T: Tree<H, C>>(&self, tree: &mut T) -> Option<(LeafPosition, Vec<H>)> {
match self {
Append(a, r) => {
assert!(tree.append(a.clone(), r.clone()), "append failed");
@ -185,7 +185,7 @@ impl<H: Hashable + Clone, C: Clone> Operation<H, C> {
pub fn apply_all<T: Tree<H, C>>(
ops: &[Operation<H, C>],
tree: &mut T,
) -> Option<(Position, Vec<H>)> {
) -> Option<(LeafPosition, Vec<H>)> {
let mut result = None;
for op in ops {
result = op.apply(tree);
@ -218,7 +218,7 @@ pub fn arb_retention() -> impl Strategy<Value = Retention<()>> {
pub fn arb_operation<G: Strategy + Clone>(
item_gen: G,
pos_gen: impl Strategy<Value = Position> + Clone,
pos_gen: impl Strategy<Value = LeafPosition> + Clone,
) -> impl Strategy<Value = Operation<G::Value, ()>>
where
G::Value: Clone + 'static,
@ -350,7 +350,7 @@ pub fn check_operations<H: Hashable + Ord + Clone + Debug, C: Clone, T: Tree<H,
Ok(())
}
pub fn compute_root_from_witness<H: Hashable>(value: H, position: Position, path: &[H]) -> H {
pub fn compute_root_from_witness<H: Hashable>(value: H, position: LeafPosition, path: &[H]) -> H {
let mut cur = value;
let mut lvl = 0.into();
for (i, v) in path
@ -413,35 +413,35 @@ impl<H: Hashable + Ord + Clone + Debug, C: Clone, I: Tree<H, C>, E: Tree<H, C>>
a
}
fn current_position(&self) -> Option<Position> {
fn current_position(&self) -> Option<LeafPosition> {
let a = self.inefficient.current_position();
let b = self.efficient.current_position();
assert_eq!(a, b);
a
}
fn get_marked_leaf(&self, position: Position) -> Option<H> {
fn get_marked_leaf(&self, position: LeafPosition) -> Option<H> {
let a = self.inefficient.get_marked_leaf(position);
let b = self.efficient.get_marked_leaf(position);
assert_eq!(a, b);
a
}
fn marked_positions(&self) -> BTreeSet<Position> {
fn marked_positions(&self) -> BTreeSet<LeafPosition> {
let a = self.inefficient.marked_positions();
let b = self.efficient.marked_positions();
assert_eq!(a, b);
a
}
fn witness(&self, position: Position, checkpoint_depth: usize) -> Option<Vec<H>> {
fn witness(&self, position: LeafPosition, checkpoint_depth: usize) -> Option<Vec<H>> {
let a = self.inefficient.witness(position, checkpoint_depth);
let b = self.efficient.witness(position, checkpoint_depth);
assert_eq!(a, b);
a
}
fn remove_mark(&mut self, position: Position) -> bool {
fn remove_mark(&mut self, position: LeafPosition) -> bool {
let a = self.inefficient.remove_mark(position);
let b = self.efficient.remove_mark(position);
assert_eq!(a, b);
@ -581,7 +581,7 @@ pub fn check_append<H: TestHashable, C: TestCheckpoint, T: Tree<H, C>, F: Fn(usi
// 16 appends should succeed
for i in 0..16 {
tree.assert_append(i, Ephemeral);
assert_eq!(tree.current_position(), Some(Position::from(i)));
assert_eq!(tree.current_position(), Some(LeafPosition::from(i)));
}
// 17th append should fail
@ -608,14 +608,14 @@ pub fn check_witnesses<H: TestHashable, C: TestCheckpoint, T: Tree<H, C>, F: Fn(
let mut tree = new_tree(100);
tree.assert_append(0, Ephemeral);
tree.assert_append(1, Marked);
assert_eq!(tree.witness(Position::from(0), 0), None);
assert_eq!(tree.witness(LeafPosition::from(0), 0), None);
}
{
let mut tree = new_tree(100);
tree.assert_append(0, Marked);
assert_eq!(
tree.witness(Position::from(0), 0),
tree.witness(LeafPosition::from(0), 0),
Some(vec![
H::empty_root(0.into()),
H::empty_root(1.into()),
@ -637,7 +637,7 @@ pub fn check_witnesses<H: TestHashable, C: TestCheckpoint, T: Tree<H, C>, F: Fn(
tree.assert_append(2, Marked);
assert_eq!(
tree.witness(Position::from(2), 0),
tree.witness(LeafPosition::from(2), 0),
Some(vec![
H::empty_root(0.into()),
H::combine_all(1, &[0, 1]),
@ -648,7 +648,7 @@ pub fn check_witnesses<H: TestHashable, C: TestCheckpoint, T: Tree<H, C>, F: Fn(
tree.assert_append(3, Ephemeral);
assert_eq!(
tree.witness(Position::from(2), 0),
tree.witness(LeafPosition::from(2), 0),
Some(vec![
H::from_u64(3),
H::combine_all(1, &[0, 1]),
@ -659,7 +659,7 @@ pub fn check_witnesses<H: TestHashable, C: TestCheckpoint, T: Tree<H, C>, F: Fn(
tree.assert_append(4, Ephemeral);
assert_eq!(
tree.witness(Position::from(2), 0),
tree.witness(LeafPosition::from(2), 0),
Some(vec![
H::from_u64(3),
H::combine_all(1, &[0, 1]),
@ -700,7 +700,7 @@ pub fn check_witnesses<H: TestHashable, C: TestCheckpoint, T: Tree<H, C>, F: Fn(
tree.assert_append(6, Ephemeral);
assert_eq!(
tree.witness(Position::from(5), 0),
tree.witness(LeafPosition::from(5), 0),
Some(vec![
H::from_u64(4),
H::combine_all(1, &[6]),
@ -719,7 +719,7 @@ pub fn check_witnesses<H: TestHashable, C: TestCheckpoint, T: Tree<H, C>, F: Fn(
tree.assert_append(11, Ephemeral);
assert_eq!(
tree.witness(Position::from(10), 0),
tree.witness(LeafPosition::from(10), 0),
Some(vec![
H::from_u64(11),
H::combine_all(1, &[8, 9]),
@ -775,7 +775,7 @@ pub fn check_witnesses<H: TestHashable, C: TestCheckpoint, T: Tree<H, C>, F: Fn(
tree.assert_append(7, Ephemeral);
assert!(tree.rewind());
assert_eq!(
tree.witness(Position::from(2), 0),
tree.witness(LeafPosition::from(2), 0),
Some(vec![
H::from_u64(3),
H::combine_all(1, &[0, 1]),
@ -796,7 +796,7 @@ pub fn check_witnesses<H: TestHashable, C: TestCheckpoint, T: Tree<H, C>, F: Fn(
tree.assert_append(15, Ephemeral);
assert_eq!(
tree.witness(Position::from(12), 0),
tree.witness(LeafPosition::from(12), 0),
Some(vec![
H::from_u64(13),
H::combine_all(1, &[14, 15]),
@ -818,7 +818,7 @@ pub fn check_witnesses<H: TestHashable, C: TestCheckpoint, T: Tree<H, C>, F: Fn(
assert_eq!(
Operation::apply_all(&ops, &mut tree),
Some((
Position::from(11),
LeafPosition::from(11),
vec![
H::from_u64(10),
H::combine_all(1, &[8, 9]),
@ -870,7 +870,7 @@ pub fn check_witnesses<H: TestHashable, C: TestCheckpoint, T: Tree<H, C>, F: Fn(
assert_eq!(
Operation::apply_all(&ops, &mut tree),
Some((
Position::from(3),
LeafPosition::from(3),
vec![
H::from_u64(2),
H::combine_all(1, &[0, 1]),
@ -905,13 +905,13 @@ pub fn check_witnesses<H: TestHashable, C: TestCheckpoint, T: Tree<H, C>, F: Fn(
),
Append(H::from_u64(0), Ephemeral),
Append(H::from_u64(0), Ephemeral),
Witness(Position(3), 1),
Witness(LeafPosition(3), 1),
];
let mut tree = new_tree(100);
assert_eq!(
Operation::apply_all(&ops, &mut tree),
Some((
Position::from(3),
LeafPosition::from(3),
vec![
H::from_u64(0),
H::combine_all(1, &[0, 0]),
@ -944,7 +944,7 @@ pub fn check_witnesses<H: TestHashable, C: TestCheckpoint, T: Tree<H, C>, F: Fn(
),
Rewind,
Rewind,
Witness(Position(7), 2),
Witness(LeafPosition(7), 2),
];
let mut tree = new_tree(100);
assert_eq!(Operation::apply_all(&ops, &mut tree), None);
@ -968,13 +968,13 @@ pub fn check_witnesses<H: TestHashable, C: TestCheckpoint, T: Tree<H, C>, F: Fn(
is_marked: false,
},
),
Witness(Position(2), 2),
Witness(LeafPosition(2), 2),
];
let mut tree = new_tree(100);
assert_eq!(
Operation::apply_all(&ops, &mut tree),
Some((
Position::from(2),
LeafPosition::from(2),
vec![
H::empty_leaf(),
H::combine_all(1, &[0, 0]),
@ -1001,7 +1001,7 @@ pub fn check_checkpoint_rewind<C: TestCheckpoint, T: Tree<String, C>, F: Fn(usiz
t.assert_checkpoint(1);
t.append("b".to_string(), Retention::Marked);
assert!(t.rewind());
assert_eq!(Some(Position::from(0)), t.current_position());
assert_eq!(Some(LeafPosition::from(0)), t.current_position());
let mut t = new_tree(100);
t.append("a".to_string(), Retention::Marked);
@ -1013,7 +1013,7 @@ pub fn check_checkpoint_rewind<C: TestCheckpoint, T: Tree<String, C>, F: Fn(usiz
t.assert_checkpoint(1);
t.append("a".to_string(), Retention::Ephemeral);
assert!(t.rewind());
assert_eq!(Some(Position::from(0)), t.current_position());
assert_eq!(Some(LeafPosition::from(0)), t.current_position());
let mut t = new_tree(100);
t.append("a".to_string(), Retention::Ephemeral);
@ -1277,7 +1277,7 @@ pub fn check_witness_consistency<C: TestCheckpoint, T: Tree<String, C>, F: Fn(us
pub(crate) mod tests {
use crate::{
testing::{compute_root_from_witness, SipHashable},
Hashable, Level, Position,
Hashable, LeafPosition, Level,
};
#[test]
@ -1316,7 +1316,7 @@ pub(crate) mod tests {
assert_eq!(
compute_root_from_witness(
SipHashable(4),
Position::from(4),
LeafPosition::from(4),
&[
SipHashable(5),
SipHashable::combine(0.into(), &SipHashable(6), &SipHashable(7)),

View File

@ -2,7 +2,7 @@
use std::cmp::min;
use std::collections::{BTreeMap, BTreeSet};
use crate::{testing::Tree, Hashable, Level, Position, Retention};
use crate::{testing::Tree, Hashable, LeafPosition, Level, Retention};
const MAX_COMPLETE_SIZE_ERROR: &str = "Positions of a `CompleteTree` must fit into the platform word size, because larger complete trees are not representable.";
@ -44,11 +44,11 @@ pub struct Checkpoint {
leaves_len: usize,
/// A set of the positions that have been marked during the period that this
/// checkpoint is the current checkpoint.
marked: BTreeSet<Position>,
marked: BTreeSet<LeafPosition>,
/// When a mark is forgotten, we add it to the checkpoint's forgotten set but
/// don't immediately remove it from the `marked` set; that removal occurs when
/// the checkpoint is eventually dropped.
forgotten: BTreeSet<Position>,
forgotten: BTreeSet<LeafPosition>,
}
impl Checkpoint {
@ -64,7 +64,7 @@ impl Checkpoint {
#[derive(Clone, Debug)]
pub struct CompleteTree<H, C: Ord, const DEPTH: u8> {
leaves: Vec<Option<H>>,
marks: BTreeSet<Position>,
marks: BTreeSet<LeafPosition>,
checkpoints: BTreeMap<C, Checkpoint>,
max_checkpoints: usize,
}
@ -127,7 +127,7 @@ impl<H: Hashable, C: Clone + Ord + core::fmt::Debug, const DEPTH: u8> CompleteTr
Ok(())
}
fn current_position(&self) -> Option<Position> {
fn current_position(&self) -> Option<LeafPosition> {
if self.leaves.is_empty() {
None
} else {
@ -139,7 +139,7 @@ impl<H: Hashable, C: Clone + Ord + core::fmt::Debug, const DEPTH: u8> CompleteTr
/// Marks the current tree state leaf as a value that we're interested in
/// marking. Returns the current position if the tree is non-empty.
fn mark(&mut self) -> Option<Position> {
fn mark(&mut self) -> Option<LeafPosition> {
if let Some(pos) = self.current_position() {
if !self.marks.contains(&pos) {
self.marks.insert(pos);
@ -155,7 +155,7 @@ impl<H: Hashable, C: Clone + Ord + core::fmt::Debug, const DEPTH: u8> CompleteTr
}
}
fn checkpoint(&mut self, id: C, pos: Option<Position>) {
fn checkpoint(&mut self, id: C, pos: Option<LeafPosition>) {
self.checkpoints.insert(
id,
Checkpoint::at_length(pos.map_or_else(
@ -218,15 +218,15 @@ impl<H: Hashable + PartialEq + Clone, C: Ord + Clone + core::fmt::Debug, const D
Self::append(self, value, retention).is_ok()
}
fn current_position(&self) -> Option<Position> {
fn current_position(&self) -> Option<LeafPosition> {
Self::current_position(self)
}
fn marked_positions(&self) -> BTreeSet<Position> {
fn marked_positions(&self) -> BTreeSet<LeafPosition> {
self.marks.clone()
}
fn get_marked_leaf(&self, position: Position) -> Option<H> {
fn get_marked_leaf(&self, position: LeafPosition) -> Option<H> {
if self.marks.contains(&position) {
self.leaves
.get(usize::try_from(position).expect(MAX_COMPLETE_SIZE_ERROR))
@ -241,7 +241,7 @@ impl<H: Hashable + PartialEq + Clone, C: Ord + Clone + core::fmt::Debug, const D
.and_then(|len| root(&self.leaves[0..len], DEPTH))
}
fn witness(&self, position: Position, checkpoint_depth: usize) -> Option<Vec<H>> {
fn witness(&self, position: LeafPosition, checkpoint_depth: usize) -> Option<Vec<H>> {
if self.marks.contains(&position) && checkpoint_depth <= self.checkpoints.len() {
let leaves_len = self.leaves_at_checkpoint_depth(checkpoint_depth)?;
let c_idx = self.checkpoints.len() - checkpoint_depth;
@ -276,7 +276,7 @@ impl<H: Hashable + PartialEq + Clone, C: Ord + Clone + core::fmt::Debug, const D
}
}
fn remove_mark(&mut self, position: Position) -> bool {
fn remove_mark(&mut self, position: LeafPosition) -> bool {
if self.marks.contains(&position) {
if let Some(c) = self.checkpoints.values_mut().rev().next() {
c.forgotten.insert(position);
@ -323,7 +323,7 @@ mod tests {
check_append, check_checkpoint_rewind, check_rewind_remove_mark, check_root_hashes,
check_witnesses, compute_root_from_witness, SipHashable, Tree,
},
Hashable, Level, Position, Retention,
Hashable, LeafPosition, Level, Retention,
};
#[test]
@ -411,7 +411,7 @@ mod tests {
assert_eq!(tree.root(0).unwrap(), expected);
for i in 0u64..(1 << DEPTH) {
let position = Position::try_from(i).unwrap();
let position = LeafPosition::try_from(i).unwrap();
let path = tree.witness(position, 0).unwrap();
assert_eq!(
compute_root_from_witness(SipHashable(i), position, &path),

View File

@ -5,7 +5,7 @@ use std::rc::Rc;
use tracing::trace;
use incrementalmerkletree::{
frontier::NonEmptyFrontier, Address, Hashable, Level, MerklePath, Position, Retention,
frontier::NonEmptyFrontier, Address, Hashable, LeafPosition, Level, MerklePath, Retention,
};
#[cfg(feature = "legacy-api")]
@ -34,13 +34,13 @@ pub enum TreeState {
Empty,
/// Checkpoint at a (possibly pruned) leaf state corresponding to the
/// wrapped leaf position.
AtPosition(Position),
AtPosition(LeafPosition),
}
#[derive(Clone, Debug)]
pub struct Checkpoint {
tree_state: TreeState,
marks_removed: BTreeSet<Position>,
marks_removed: BTreeSet<LeafPosition>,
}
impl Checkpoint {
@ -51,14 +51,14 @@ impl Checkpoint {
}
}
pub fn at_position(position: Position) -> Self {
pub fn at_position(position: LeafPosition) -> Self {
Checkpoint {
tree_state: TreeState::AtPosition(position),
marks_removed: BTreeSet::new(),
}
}
pub fn from_parts(tree_state: TreeState, marks_removed: BTreeSet<Position>) -> Self {
pub fn from_parts(tree_state: TreeState, marks_removed: BTreeSet<LeafPosition>) -> Self {
Checkpoint {
tree_state,
marks_removed,
@ -69,7 +69,7 @@ impl Checkpoint {
self.tree_state
}
pub fn marks_removed(&self) -> &BTreeSet<Position> {
pub fn marks_removed(&self) -> &BTreeSet<LeafPosition> {
&self.marks_removed
}
@ -77,7 +77,7 @@ impl Checkpoint {
matches!(self.tree_state, TreeState::Empty)
}
pub fn position(&self) -> Option<Position> {
pub fn position(&self) -> Option<LeafPosition> {
match self.tree_state {
TreeState::Empty => None,
TreeState::AtPosition(pos) => Some(pos),
@ -376,7 +376,7 @@ impl<
}
/// Returns the root address of the subtree that contains the specified position.
pub fn subtree_addr(pos: Position) -> Address {
pub fn subtree_addr(pos: LeafPosition) -> Address {
Address::above_position(Self::subtree_level(), pos)
}
@ -387,7 +387,7 @@ impl<
/// Returns the leaf value at the specified position, if it is a marked leaf.
pub fn get_marked_leaf(
&self,
position: Position,
position: LeafPosition,
) -> Result<Option<H>, ShardTreeError<S::Error>> {
Ok(self
.store
@ -398,7 +398,7 @@ impl<
}
/// Returns the positions of marked leaves in the tree.
pub fn marked_positions(&self) -> Result<BTreeSet<Position>, ShardTreeError<S::Error>> {
pub fn marked_positions(&self) -> Result<BTreeSet<LeafPosition>, ShardTreeError<S::Error>> {
let mut result = BTreeSet::new();
for subtree_addr in &self
.store
@ -646,9 +646,9 @@ impl<
#[allow(clippy::type_complexity)]
pub fn batch_insert<I: Iterator<Item = (H, Retention<C>)>>(
&mut self,
mut start: Position,
mut start: LeafPosition,
values: I,
) -> Result<Option<(Position, Vec<IncompleteAt>)>, ShardTreeError<S::Error>> {
) -> Result<Option<(LeafPosition, Vec<IncompleteAt>)>, ShardTreeError<S::Error>> {
trace!("Batch inserting from {:?}", start);
let mut values = values.peekable();
let mut subtree_root_addr = Self::subtree_addr(start);
@ -717,7 +717,7 @@ impl<
fn go<H: Hashable + Clone + PartialEq>(
root_addr: Address,
root: &PrunableTree<H>,
) -> Option<(PrunableTree<H>, Position)> {
) -> Option<(PrunableTree<H>, LeafPosition)> {
match root {
Tree(Node::Parent { ann, left, right }) => {
let (l_addr, r_addr) = root_addr.children().unwrap();
@ -815,7 +815,7 @@ impl<
// will be removed from the checkpoints map.
let remove_count = checkpoint_count - self.max_checkpoints;
let mut checkpoints_to_delete = vec![];
let mut clear_positions: BTreeMap<Address, BTreeMap<Position, RetentionFlags>> =
let mut clear_positions: BTreeMap<Address, BTreeMap<LeafPosition, RetentionFlags>> =
BTreeMap::new();
self.store
.with_checkpoints(checkpoint_count, |cid, checkpoint| {
@ -1013,7 +1013,7 @@ impl<
pub fn root(
&self,
address: Address,
truncate_at: Position,
truncate_at: LeafPosition,
) -> Result<H, ShardTreeError<S::Error>> {
assert!(Self::root_addr().contains(&address));
@ -1033,7 +1033,7 @@ impl<
pub fn root_caching(
&mut self,
address: Address,
truncate_at: Position,
truncate_at: LeafPosition,
) -> Result<H, ShardTreeError<S::Error>> {
let (root, updated_cap) = self.root_internal(
&LocatedPrunableTree {
@ -1060,7 +1060,7 @@ impl<
target_addr: Address,
// An inclusive lower bound for positions whose leaf values will be replaced by empty
// roots.
truncate_at: Position,
truncate_at: LeafPosition,
) -> Result<(H, Option<PrunableTree<H>>), ShardTreeError<S::Error>> {
match &cap.root {
Tree(Node::Parent { ann, left, right }) => {
@ -1199,7 +1199,7 @@ impl<
fn root_from_shards(
&self,
address: Address,
truncate_at: Position,
truncate_at: LeafPosition,
) -> Result<H, ShardTreeError<S::Error>> {
match address.context(Self::subtree_level()) {
Either::Left(subtree_addr) => {
@ -1312,7 +1312,7 @@ impl<
pub fn max_leaf_position(
&self,
checkpoint_depth: usize,
) -> Result<Option<Position>, ShardTreeError<S::Error>> {
) -> Result<Option<LeafPosition>, ShardTreeError<S::Error>> {
Ok(if checkpoint_depth == 0 {
// TODO: This relies on the invariant that the last shard in the subtrees vector is
// never created without a leaf then being added to it. However, this may be a
@ -1370,7 +1370,7 @@ impl<
/// result as `checkpoint_depth == 1`.
pub fn witness(
&self,
position: Position,
position: LeafPosition,
checkpoint_depth: usize,
) -> Result<MerklePath<H, DEPTH>, ShardTreeError<S::Error>> {
let max_leaf_position = self.max_leaf_position(checkpoint_depth).and_then(|v| {
@ -1414,7 +1414,7 @@ impl<
/// those values from potentially large numbers of subtree roots in the future.
pub fn witness_caching(
&mut self,
position: Position,
position: LeafPosition,
checkpoint_depth: usize,
) -> Result<MerklePath<H, DEPTH>, ShardTreeError<S::Error>> {
let max_leaf_position = self.max_leaf_position(checkpoint_depth).and_then(|v| {
@ -1463,7 +1463,7 @@ impl<
/// not marked, or an error if one is produced by the underlying data store.
pub fn remove_mark(
&mut self,
position: Position,
position: LeafPosition,
as_of_checkpoint: Option<&C>,
) -> Result<bool, ShardTreeError<S::Error>> {
match self
@ -1526,7 +1526,7 @@ mod tests {
check_witness_consistency, check_witnesses, complete_tree::CompleteTree, CombinedTree,
SipHashable,
},
Address, Hashable, Level, Position, Retention,
Address, Hashable, LeafPosition, Level, Retention,
};
use crate::{
@ -1674,7 +1674,7 @@ mod tests {
ops in proptest::collection::vec(
arb_operation(
(0..32u64).prop_map(SipHashable),
(0u64..100).prop_map(Position::from)
(0u64..100).prop_map(LeafPosition::from)
),
1..100
)
@ -1689,7 +1689,7 @@ mod tests {
ops in proptest::collection::vec(
arb_operation(
(97u8..123).prop_map(|c| char::from(c).to_string()),
(0u64..100).prop_map(Position::from)
(0u64..100).prop_map(LeafPosition::from)
),
1..100
)
@ -1776,7 +1776,7 @@ mod tests {
if let Ok((t, None)) = result {
// verify that the leaf at the tip is included
assert_eq!(
t.root.root_hash(root_addr, Position::from(3)),
t.root.root_hash(root_addr, LeafPosition::from(3)),
Ok("abc_____".to_string())
);
}
@ -1802,7 +1802,7 @@ mod tests {
if let Ok((t, Some(c), Some(r))) = result {
// verify that we can find the "marked" leaf
assert_eq!(
t.root.root_hash(root_addr, Position::from(7)),
t.root.root_hash(root_addr, LeafPosition::from(7)),
Ok("abcdefg_".to_string())
);
@ -1824,8 +1824,10 @@ mod tests {
);
assert_eq!(
r.root
.root_hash(Address::from_parts(Level::from(3), 3), Position::from(25)),
r.root.root_hash(
Address::from_parts(Level::from(3), 3),
LeafPosition::from(25)
),
Ok("y_______".to_string())
);
}
@ -1849,7 +1851,7 @@ mod tests {
if let Ok((t, None, None)) = result {
// verify that we can find the "marked" leaf
assert_eq!(
t.root.root_hash(root_addr, Position::from(3)),
t.root.root_hash(root_addr, LeafPosition::from(3)),
Ok("abc_____".to_string())
);
}

View File

@ -5,7 +5,7 @@ use std::rc::Rc;
use bitflags::bitflags;
use incrementalmerkletree::{
frontier::NonEmptyFrontier, Address, Hashable, Level, Position, Retention,
frontier::NonEmptyFrontier, Address, Hashable, LeafPosition, Level, Retention,
};
use tracing::trace;
@ -105,7 +105,11 @@ impl<H: Hashable + Clone + PartialEq> PrunableTree<H> {
/// ### Parameters:
/// * `truncate_at` An inclusive lower bound on positions in the tree beyond which all leaf
/// values will be treated as `Nil`.
pub fn root_hash(&self, root_addr: Address, truncate_at: Position) -> Result<H, Vec<Address>> {
pub fn root_hash(
&self,
root_addr: Address,
truncate_at: LeafPosition,
) -> Result<H, Vec<Address>> {
if truncate_at <= root_addr.position_range_start() {
// we are in the part of the tree where we're generating empty roots,
// so no need to inspect the tree
@ -156,7 +160,7 @@ impl<H: Hashable + Clone + PartialEq> PrunableTree<H> {
///
/// Computing the set of marked positions requires a full traversal of the tree, and so should
/// be considered to be a somewhat expensive operation.
pub fn marked_positions(&self, root_addr: Address) -> BTreeSet<Position> {
pub fn marked_positions(&self, root_addr: Address) -> BTreeSet<LeafPosition> {
match &self.0 {
Node::Parent { left, right, .. } => {
// We should never construct parent nodes where both children are Nil.
@ -177,7 +181,7 @@ impl<H: Hashable + Clone + PartialEq> PrunableTree<H> {
} => {
let mut result = BTreeSet::new();
if root_addr.level() == 0.into() && retention.is_marked() {
result.insert(Position::from(root_addr.index()));
result.insert(LeafPosition::from(root_addr.index()));
}
result
}
@ -344,9 +348,9 @@ pub struct BatchInsertionResult<H, C: Ord, I: Iterator<Item = (H, Retention<C>)>
/// each inserted leaf with [`Retention::Marked`] retention.
pub incomplete: Vec<IncompleteAt>,
/// The maximum position at which a leaf was inserted.
pub max_insert_position: Option<Position>,
pub max_insert_position: Option<LeafPosition>,
/// The positions of all leaves with [`Retention::Checkpoint`] retention that were inserted.
pub checkpoints: BTreeMap<C, Position>,
pub checkpoints: BTreeMap<C, LeafPosition>,
/// The unconsumed remainder of the iterator from which leaves were inserted, if the tree
/// was completely filled before the iterator was fully consumed.
pub remainder: I,
@ -360,7 +364,7 @@ pub enum InsertionError {
NotContained(Address),
/// The start of the range of positions provided for insertion is not included
/// in the range of positions within this subtree.
OutOfRange(Position, Range<Position>),
OutOfRange(LeafPosition, Range<LeafPosition>),
/// An existing root hash conflicts with the root hash of a node being inserted.
Conflict(Address),
/// An out-of-order checkpoint was detected
@ -451,7 +455,7 @@ impl<H: Hashable + Clone + PartialEq> LocatedPrunableTree<H> {
/// If the tree contains any [`Node::Nil`] nodes corresponding to positions less than
/// `truncate_at`, this will return an error containing the addresses of those nodes within the
/// tree.
pub fn root_hash(&self, truncate_at: Position) -> Result<H, Vec<Address>> {
pub fn root_hash(&self, truncate_at: LeafPosition) -> Result<H, Vec<Address>> {
self.root.root_hash(self.root_addr, truncate_at)
}
@ -471,11 +475,11 @@ impl<H: Hashable + Clone + PartialEq> LocatedPrunableTree<H> {
}
/// Returns the positions of marked leaves in the tree.
pub fn marked_positions(&self) -> BTreeSet<Position> {
pub fn marked_positions(&self) -> BTreeSet<LeafPosition> {
fn go<H: Hashable + Clone + PartialEq>(
root_addr: Address,
root: &PrunableTree<H>,
acc: &mut BTreeSet<Position>,
acc: &mut BTreeSet<LeafPosition>,
) {
match &root.0 {
Node::Parent { left, right, .. } => {
@ -485,7 +489,7 @@ impl<H: Hashable + Clone + PartialEq> LocatedPrunableTree<H> {
}
Node::Leaf { value } => {
if value.1.is_marked() && root_addr.level() == 0.into() {
acc.insert(Position::from(root_addr.index()));
acc.insert(LeafPosition::from(root_addr.index()));
}
}
_ => {}
@ -505,14 +509,18 @@ impl<H: Hashable + Clone + PartialEq> LocatedPrunableTree<H> {
///
/// Returns either the witness for the leaf at the specified position, or an error that
/// describes the causes of failure.
pub fn witness(&self, position: Position, truncate_at: Position) -> Result<Vec<H>, QueryError> {
pub fn witness(
&self,
position: LeafPosition,
truncate_at: LeafPosition,
) -> Result<Vec<H>, QueryError> {
// traverse down to the desired leaf position, and then construct
// the authentication path on the way back up.
fn go<H: Hashable + Clone + PartialEq>(
root: &PrunableTree<H>,
root_addr: Address,
position: Position,
truncate_at: Position,
position: LeafPosition,
truncate_at: LeafPosition,
) -> Result<Vec<H>, Vec<Address>> {
match &root.0 {
Node::Parent { left, right, .. } => {
@ -590,9 +598,9 @@ impl<H: Hashable + Clone + PartialEq> LocatedPrunableTree<H> {
/// The leaf at the specified position is retained. Returns the truncated tree if a leaf or
/// subtree root with the specified position as its maximum position exists, or `None`
/// otherwise.
pub fn truncate_to_position(&self, position: Position) -> Option<Self> {
pub fn truncate_to_position(&self, position: LeafPosition) -> Option<Self> {
fn go<H: Hashable + Clone + PartialEq>(
position: Position,
position: LeafPosition,
root_addr: Address,
root: &PrunableTree<H>,
) -> Option<PrunableTree<H>> {
@ -818,7 +826,7 @@ impl<H: Hashable + Clone + PartialEq> LocatedPrunableTree<H> {
&self,
value: H,
retention: Retention<C>,
) -> Result<(Self, Position, Option<C>), InsertionError> {
) -> Result<(Self, LeafPosition, Option<C>), InsertionError> {
let checkpoint_id = if let Retention::Checkpoint { id, .. } = &retention {
Some(id.clone())
} else {
@ -870,7 +878,7 @@ impl<H: Hashable + Clone + PartialEq> LocatedPrunableTree<H> {
/// level.
/// * `values` The iterator of `(H, [`Retention`])` pairs from which to construct the tree.
pub fn from_iter<C: Clone + Ord, I: Iterator<Item = (H, Retention<C>)>>(
position_range: Range<Position>,
position_range: Range<LeafPosition>,
prune_below: Level,
mut values: I,
) -> Option<BatchInsertionResult<H, C, I>> {
@ -1031,7 +1039,7 @@ impl<H: Hashable + Clone + PartialEq> LocatedPrunableTree<H> {
// with the addresses at which they will be inserted, along with their root hashes.
let mut fragments: Vec<(Self, bool)> = vec![];
let mut position = position_range.start;
let mut checkpoints: BTreeMap<C, Position> = BTreeMap::new();
let mut checkpoints: BTreeMap<C, LeafPosition> = BTreeMap::new();
while position < position_range.end {
if let Some((value, retention)) = values.next() {
if let Retention::Checkpoint { id, .. } = &retention {
@ -1101,7 +1109,7 @@ impl<H: Hashable + Clone + PartialEq> LocatedPrunableTree<H> {
/// of this tree's position range or if a conflict with an existing subtree root is detected.
pub fn batch_insert<C: Clone + Ord, I: Iterator<Item = (H, Retention<C>)>>(
&self,
start: Position,
start: LeafPosition,
values: I,
) -> Result<Option<BatchInsertionResult<H, C, I>>, InsertionError> {
trace!("Batch inserting into {:?} from {:?}", self.root_addr, start);
@ -1144,7 +1152,7 @@ impl<H: Hashable + Clone + PartialEq> LocatedPrunableTree<H> {
// have inaccurate position information (e.g. in the case that the tree is the
// cursor for an `IncrementalWitness`).
fn from_frontier_parts<C>(
position: Position,
position: LeafPosition,
leaf: H,
mut ommers: impl Iterator<Item = H>,
leaf_retention: &Retention<C>,
@ -1386,9 +1394,9 @@ impl<H: Hashable + Clone + PartialEq> LocatedPrunableTree<H> {
/// Clears the specified retention flags at all positions specified, pruning any branches
/// that no longer need to be retained.
pub fn clear_flags(&self, to_clear: BTreeMap<Position, RetentionFlags>) -> Self {
pub fn clear_flags(&self, to_clear: BTreeMap<LeafPosition, RetentionFlags>) -> Self {
fn go<H: Hashable + Clone + PartialEq>(
to_clear: &[(Position, RetentionFlags)],
to_clear: &[(LeafPosition, RetentionFlags)],
root_addr: Address,
root: &PrunableTree<H>,
) -> PrunableTree<H> {
@ -1468,7 +1476,7 @@ fn accumulate_result_with<A, B, C>(
mod tests {
use std::collections::BTreeSet;
use incrementalmerkletree::{Address, Level, Position, Retention};
use incrementalmerkletree::{Address, LeafPosition, Level, Retention};
use super::{LocatedPrunableTree, PrunableTree, QueryError, RetentionFlags};
use crate::tree::{
@ -1484,24 +1492,36 @@ mod tests {
);
assert_eq!(
t.root_hash(Address::from_parts(Level::from(1), 0), Position::from(2)),
t.root_hash(
Address::from_parts(Level::from(1), 0),
LeafPosition::from(2)
),
Ok("ab".to_string())
);
let t0 = parent(nil(), t.clone());
assert_eq!(
t0.root_hash(Address::from_parts(Level::from(2), 0), Position::from(4)),
t0.root_hash(
Address::from_parts(Level::from(2), 0),
LeafPosition::from(4)
),
Err(vec![Address::from_parts(Level::from(1), 0)])
);
// Check root computation with truncation
let t1 = parent(t, nil());
assert_eq!(
t1.root_hash(Address::from_parts(Level::from(2), 0), Position::from(2)),
t1.root_hash(
Address::from_parts(Level::from(2), 0),
LeafPosition::from(2)
),
Ok("ab__".to_string())
);
assert_eq!(
t1.root_hash(Address::from_parts(Level::from(2), 0), Position::from(3)),
t1.root_hash(
Address::from_parts(Level::from(2), 0),
LeafPosition::from(3)
),
Err(vec![Address::from_parts(Level::from(1), 1)])
);
}
@ -1514,13 +1534,13 @@ mod tests {
);
assert_eq!(
t.marked_positions(Address::from_parts(Level::from(1), 0)),
BTreeSet::from([Position::from(1)])
BTreeSet::from([LeafPosition::from(1)])
);
let t0 = parent(t.clone(), t);
assert_eq!(
t0.marked_positions(Address::from_parts(Level::from(2), 1)),
BTreeSet::from([Position::from(5), Position::from(7)])
BTreeSet::from([LeafPosition::from(5), LeafPosition::from(7)])
);
}
@ -1698,7 +1718,7 @@ mod tests {
#[test]
fn located_from_iter_non_sibling_adjacent() {
let res = LocatedPrunableTree::from_iter::<(), _>(
Position::from(3)..Position::from(5),
LeafPosition::from(3)..LeafPosition::from(5),
Level::new(0),
vec![
("d".to_string(), Retention::Ephemeral),
@ -1743,7 +1763,7 @@ mod tests {
// On the same tree, perform an out-of-order insertion.
let out_of_order = base
.batch_insert::<(), _>(
Position::from(3),
LeafPosition::from(3),
vec![("d".to_string(), Retention::Ephemeral)].into_iter(),
)
.unwrap()
@ -1762,7 +1782,7 @@ mod tests {
let complete = out_of_order
.subtree
.batch_insert::<(), _>(
Position::from(1),
LeafPosition::from(1),
vec![
("b".to_string(), Retention::Ephemeral),
("c".to_string(), Retention::Ephemeral),

View File

@ -71,8 +71,8 @@ pub fn arb_shardtree<H: Strategy + Clone>(
) -> impl Strategy<
Value = (
ShardTree<MemoryShardStore<H::Value, usize>, 6, 3>,
Vec<Position>,
Vec<Position>,
Vec<LeafPosition>,
Vec<LeafPosition>,
),
>
where
@ -87,7 +87,7 @@ where
let mut checkpoint_positions = vec![];
let mut marked_positions = vec![];
tree.batch_insert(
Position::from(0),
LeafPosition::from(0),
leaves
.into_iter()
.enumerate()
@ -97,7 +97,7 @@ where
match (is_checkpoint, is_marked) {
(false, false) => Retention::Ephemeral,
(true, is_marked) => {
let pos = Position::try_from(id).unwrap();
let pos = LeafPosition::try_from(id).unwrap();
checkpoint_positions.push(pos);
if is_marked {
marked_positions.push(pos);
@ -105,7 +105,7 @@ where
Retention::Checkpoint { id, is_marked }
}
(false, true) => {
marked_positions.push(Position::try_from(id).unwrap());
marked_positions.push(LeafPosition::try_from(id).unwrap());
Retention::Marked
}
},
@ -144,21 +144,21 @@ where
}
}
fn current_position(&self) -> Option<Position> {
fn current_position(&self) -> Option<LeafPosition> {
match ShardTree::max_leaf_position(self, 0) {
Ok(v) => v,
Err(err) => panic!("current position query failed: {:?}", err),
}
}
fn get_marked_leaf(&self, position: Position) -> Option<H> {
fn get_marked_leaf(&self, position: LeafPosition) -> Option<H> {
match ShardTree::get_marked_leaf(self, position) {
Ok(v) => v,
Err(err) => panic!("marked leaf query failed: {:?}", err),
}
}
fn marked_positions(&self) -> BTreeSet<Position> {
fn marked_positions(&self) -> BTreeSet<LeafPosition> {
match ShardTree::marked_positions(self) {
Ok(v) => v,
Err(err) => panic!("marked positions query failed: {:?}", err),
@ -172,7 +172,7 @@ where
}
}
fn witness(&self, position: Position, checkpoint_depth: usize) -> Option<Vec<H>> {
fn witness(&self, position: LeafPosition, checkpoint_depth: usize) -> Option<Vec<H>> {
match ShardTree::witness(self, position, checkpoint_depth) {
Ok(p) => Some(p.path_elems().to_vec()),
Err(ShardTreeError::Query(
@ -184,7 +184,7 @@ where
}
}
fn remove_mark(&mut self, position: Position) -> bool {
fn remove_mark(&mut self, position: LeafPosition) -> bool {
let max_checkpoint = self
.store
.max_checkpoint_id()
@ -213,7 +213,7 @@ pub fn check_shardtree_insertion<
) {
assert_matches!(
tree.batch_insert(
Position::from(1),
LeafPosition::from(1),
vec![
("b".to_string(), Retention::Checkpoint { id: 1, is_marked: false }),
("c".to_string(), Retention::Ephemeral),
@ -221,7 +221,7 @@ pub fn check_shardtree_insertion<
].into_iter()
),
Ok(Some((pos, incomplete))) if
pos == Position::from(3) &&
pos == LeafPosition::from(3) &&
incomplete == vec![
IncompleteAt {
address: Address::from_parts(Level::from(0), 0),
@ -241,13 +241,13 @@ pub fn check_shardtree_insertion<
assert_matches!(
tree.batch_insert(
Position::from(0),
LeafPosition::from(0),
vec![
("a".to_string(), Retention::Ephemeral),
].into_iter()
),
Ok(Some((pos, incomplete))) if
pos == Position::from(0) &&
pos == LeafPosition::from(0) &&
incomplete == vec![]
);
@ -263,7 +263,7 @@ pub fn check_shardtree_insertion<
assert_matches!(
tree.batch_insert(
Position::from(10),
LeafPosition::from(10),
vec![
("k".to_string(), Retention::Ephemeral),
("l".to_string(), Retention::Checkpoint { id: 2, is_marked: false }),
@ -271,7 +271,7 @@ pub fn check_shardtree_insertion<
].into_iter()
),
Ok(Some((pos, incomplete))) if
pos == Position::from(12) &&
pos == LeafPosition::from(12) &&
incomplete == vec![
IncompleteAt {
address: Address::from_parts(Level::from(0), 13),
@ -303,7 +303,7 @@ pub fn check_shardtree_insertion<
assert_matches!(
tree.batch_insert(
Position::from(4),
LeafPosition::from(4),
('e'..'k')
.into_iter()
.map(|c| (c.to_string(), Retention::Ephemeral))
@ -335,7 +335,7 @@ pub fn check_shard_sizes<E: Debug, S: ShardStore<H = String, CheckpointId = u32,
.get_shard(Address::from_parts(Level::from(2), 3))
.unwrap()
.and_then(|t| t.max_position()),
Some(Position::from(14))
Some(LeafPosition::from(14))
);
}
@ -359,7 +359,7 @@ pub fn check_witness_with_pruned_subtrees<
// simulate discovery of a note
tree.batch_insert(
Position::from(24),
LeafPosition::from(24),
('a'..='h').into_iter().map(|c| {
(
c.to_string(),
@ -377,7 +377,7 @@ pub fn check_witness_with_pruned_subtrees<
.unwrap();
// construct a witness for the note
let witness = tree.witness(Position::from(26), 0).unwrap();
let witness = tree.witness(LeafPosition::from(26), 0).unwrap();
assert_eq!(
witness.path_elems(),
&[

View File

@ -1,7 +1,7 @@
use std::ops::Deref;
use std::rc::Rc;
use incrementalmerkletree::{Address, Level, Position};
use incrementalmerkletree::{Address, LeafPosition, Level};
/// A "pattern functor" for a single layer of a binary tree.
#[derive(Clone, Debug, PartialEq, Eq)]
@ -193,8 +193,8 @@ impl<A, V> LocatedTree<A, V> {
///
/// Note that no actual leaf value may exist at this position, as it may have previously been
/// pruned.
pub fn max_position(&self) -> Option<Position> {
fn go<A, V>(addr: Address, root: &Tree<A, V>) -> Option<Position> {
pub fn max_position(&self) -> Option<LeafPosition> {
fn go<A, V>(addr: Address, root: &Tree<A, V>) -> Option<LeafPosition> {
match &root.0 {
Node::Nil => None,
Node::Leaf { .. } => Some(addr.position_range_end() - 1),
@ -209,8 +209,8 @@ impl<A, V> LocatedTree<A, V> {
}
/// Returns the value at the specified position, if any.
pub fn value_at_position(&self, position: Position) -> Option<&V> {
fn go<A, V>(pos: Position, addr: Address, root: &Tree<A, V>) -> Option<&V> {
pub fn value_at_position(&self, position: LeafPosition) -> Option<&V> {
fn go<A, V>(pos: LeafPosition, addr: Address, root: &Tree<A, V>) -> Option<&V> {
match &root.0 {
Node::Parent { left, right, .. } => {
let (l_addr, r_addr) = addr.children().unwrap();