Skip to content

Commit

Permalink
feat: partial pollard
Browse files Browse the repository at this point in the history
Partial pollards allow you to hold only a subset of utxos in the forest,
effectively caching them and not requiring to download or validate extra
proofs for it.

This commit implements it using a very similar approach as the main
forest, but with the possibility to prune leaves that you don't want to
hold anymore.
  • Loading branch information
Davidson-Souza committed Dec 3, 2024
1 parent d8d795e commit ce1f4e6
Show file tree
Hide file tree
Showing 8 changed files with 1,141 additions and 20 deletions.
6 changes: 4 additions & 2 deletions examples/custom-hash-type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
//! use your custom hashes, just tweak the implementation of
//! [NodeHash](crate::accumulator::node_hash::NodeHash) for your hash type.
use rustreexo::accumulator::node_hash::AccumulatorHash;
use rustreexo::accumulator::mem_forest::MemForest;
use rustreexo::accumulator::node_hash::AccumulatorHash;
use starknet_crypto::poseidon_hash_many;
use starknet_crypto::Felt;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
/// We need a stateful wrapper around the actual hash, this is because we use those different
/// values inside our accumulator. Here we use an enum to represent the different states, you
/// may want to use a struct with more data, depending on your needs.
Expand All @@ -34,6 +34,8 @@ enum PoseidonHash {
/// returns sane values (that is, if we call [NodeHash::placeholder] calling [NodeHash::is_placeholder]
/// on the result should return true).
Placeholder,

#[default]
/// This is an empty value, it represents a node that was deleted from the accumulator.
///
/// Same as the placeholder, you can implement this the way you want, just make sure that
Expand Down
2 changes: 1 addition & 1 deletion examples/full-accumulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
use std::str::FromStr;

use rustreexo::accumulator::node_hash::BitcoinNodeHash;
use rustreexo::accumulator::mem_forest::MemForest;
use rustreexo::accumulator::node_hash::BitcoinNodeHash;
use rustreexo::accumulator::proof::Proof;
use rustreexo::accumulator::stump::Stump;

Expand Down
26 changes: 14 additions & 12 deletions src/accumulator/mem_forest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
//!
//! # Example
//! ```
//! use rustreexo::accumulator::mem_forest::MemForest;
//! use rustreexo::accumulator::node_hash::AccumulatorHash;
//! use rustreexo::accumulator::node_hash::BitcoinNodeHash;
//! use rustreexo::accumulator::mem_forest::MemForest;
//!
//! let values = vec![0, 1, 2, 3, 4, 5, 6, 7];
//! let hashes: Vec<BitcoinNodeHash> = values
Expand Down Expand Up @@ -225,8 +225,8 @@ impl<Hash: AccumulatorHash> MemForest<Hash> {
/// Creates a new empty [MemForest] with a custom hash function.
/// # Example
/// ```
/// use rustreexo::accumulator::node_hash::BitcoinNodeHash;
/// use rustreexo::accumulator::mem_forest::MemForest;
/// use rustreexo::accumulator::node_hash::BitcoinNodeHash;
/// let mut MemForest = MemForest::<BitcoinNodeHash>::new();
/// ```
pub fn new_with_hash() -> MemForest<Hash> {
Expand All @@ -241,8 +241,8 @@ impl<Hash: AccumulatorHash> MemForest<Hash> {
/// or to disk.
/// # Example
/// ```
/// use rustreexo::accumulator::node_hash::BitcoinNodeHash;
/// use rustreexo::accumulator::mem_forest::MemForest;
/// use rustreexo::accumulator::node_hash::BitcoinNodeHash;
///
/// let mut mem_forest = MemForest::<BitcoinNodeHash>::new();
/// let mut serialized = Vec::new();
Expand All @@ -269,8 +269,8 @@ impl<Hash: AccumulatorHash> MemForest<Hash> {
/// ```
/// use std::io::Cursor;
///
/// use rustreexo::accumulator::node_hash::BitcoinNodeHash;
/// use rustreexo::accumulator::mem_forest::MemForest;
/// use rustreexo::accumulator::node_hash::BitcoinNodeHash;
/// let mut serialized = Cursor::new(vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
/// let MemForest = MemForest::<BitcoinNodeHash>::deserialize(&mut serialized).unwrap();
/// assert_eq!(MemForest.leaves, 0);
Expand Down Expand Up @@ -304,8 +304,8 @@ impl<Hash: AccumulatorHash> MemForest<Hash> {
/// and the hashes that we what to prove, but sorted by position in the tree.
/// # Example
/// ```
/// use rustreexo::accumulator::node_hash::BitcoinNodeHash;
/// use rustreexo::accumulator::mem_forest::MemForest;
/// use rustreexo::accumulator::node_hash::BitcoinNodeHash;
/// let mut mem_forest = MemForest::<BitcoinNodeHash>::new();
/// let hashes = vec![0, 1, 2, 3, 4, 5, 6, 7]
/// .iter()
Expand Down Expand Up @@ -349,8 +349,9 @@ impl<Hash: AccumulatorHash> MemForest<Hash> {
/// use bitcoin_hashes::sha256::Hash as Data;
/// use bitcoin_hashes::Hash;
/// use bitcoin_hashes::HashEngine;
/// use rustreexo::accumulator::node_hash::BitcoinNodeHash;
/// use rustreexo::accumulator::mem_forest::MemForest;
/// use rustreexo::accumulator::node_hash::BitcoinNodeHash;
/// use rustreexo::accumulator::node_hash::NodeHash;
/// let values = vec![0, 1, 2, 3, 4, 5, 6, 7];
/// let hashes = values
/// .into_iter()
Expand Down Expand Up @@ -690,9 +691,9 @@ mod test {
use serde::Deserialize;

use super::MemForest;
use crate::accumulator::mem_forest::Node;
use crate::accumulator::node_hash::AccumulatorHash;
use crate::accumulator::node_hash::BitcoinNodeHash;
use crate::accumulator::mem_forest::Node;
use crate::accumulator::proof::Proof;

fn hash_from_u8(value: u8) -> BitcoinNodeHash {
Expand Down Expand Up @@ -1007,9 +1008,10 @@ mod test {
p.modify(&[], &[hashes[0]]).expect("can remove 0");
let mut writer = std::io::Cursor::new(Vec::new());
p.serialize(&mut writer).unwrap();
let deserialized =
MemForest::<BitcoinNodeHash>::deserialize(&mut std::io::Cursor::new(writer.into_inner()))
.unwrap();
let deserialized = MemForest::<BitcoinNodeHash>::deserialize(&mut std::io::Cursor::new(
writer.into_inner(),
))
.unwrap();
assert_eq!(
deserialized.get_roots()[0].get_data(),
p.get_roots()[0].get_data()
Expand Down Expand Up @@ -1077,8 +1079,8 @@ mod test {
assert_eq!(p.leaves, 16);
let mut serialized = Vec::<u8>::new();
p.serialize(&mut serialized).expect("serialize should work");
let deserialized =
MemForest::<BitcoinNodeHash>::deserialize(&*serialized).expect("deserialize should work");
let deserialized = MemForest::<BitcoinNodeHash>::deserialize(&*serialized)
.expect("deserialize should work");
assert_eq!(deserialized.get_roots().len(), 1);
assert!(deserialized.get_roots()[0].get_data().is_empty());
assert_eq!(deserialized.leaves, 16);
Expand Down
3 changes: 2 additions & 1 deletion src/accumulator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
//! a lightweight implementation of utreexo that only stores roots. Although the [stump::Stump]
//! only keeps the accumulator's roots, it still trustlessly update this state, not requiring
//! a trusted third party to learn about the current state.
pub mod node_hash;
pub mod mem_forest;
pub mod node_hash;
pub mod pollard;
pub mod proof;
pub mod stump;
pub(super) mod util;
2 changes: 1 addition & 1 deletion src/accumulator/node_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ use serde::Deserialize;
use serde::Serialize;

pub trait AccumulatorHash:
Copy + Clone + Ord + Debug + Display + std::hash::Hash + 'static
Copy + Clone + Ord + Debug + Display + std::hash::Hash + Default + 'static
{
fn is_empty(&self) -> bool;
fn empty() -> Self;
Expand Down
Loading

0 comments on commit ce1f4e6

Please sign in to comment.