the Position type is exclusively used with leaves, propose a readability rename to LeafPosition
This commit is contained in:
parent
67111e2940
commit
c30825df64
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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())
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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(),
|
||||
&[
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue