WeaveDocs
Strand

Merkle and Bitfield

Merkle tree and bitfield internals for Strand — sparse replication, proof generation, and gap repair across partial replicas.

Purpose

Append-only log with Merkle proofs, bitfields, storage backends, policies, and replication streams.

This page follows the real source shape for Strand and explains the workflow a developer is likely to use first.

Developer workflow

Start from the smallest constructor or builder, perform one meaningful operation, inspect the returned state, then add the relevant policy, storage, or network integration. The examples below should be expanded whenever the crate API changes.

Primary types to know

  • AllowAllPolicy — models/strand/src/policy.rs
  • Bitfield — models/strand/src/bitfield.rs
  • BitfieldIterator — models/strand/src/bitfield.rs
  • FileStorage — models/strand/src/storage.rs
  • Header — models/strand/src/lib.rs
  • Info — models/strand/src/storage.rs
  • MemoryStorage — models/strand/src/storage.rs
  • MerkleTree — models/strand/src/merkle_tree.rs
  • Node — models/strand/src/merkle_tree.rs
  • Proof — models/strand/src/merkle_tree.rs
  • RangeHandle — models/strand/src/replication_api.rs
  • RangeSpec — models/strand/src/replication_api.rs

Example shape

use strand::{Bitfield, MerkleTree, Node, Strand, StrandConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Build a local strand and request a Merkle proof for an interior block.
    let dir = tempfile::tempdir()?;
    let mut strand = Strand::new(StrandConfig::new().with_storage(dir.path())).await?;
    for payload in [b"alpha".as_slice(), b"beta", b"gamma", b"delta"] {
        strand.append(payload).await?;
    }
    let target_seq: u64 = 2;
    let proof = strand.proof(target_seq).await?;
    let ok = strand.verify_proof(&proof, b"gamma").await?;
    assert!(ok, "proof must verify for the original payload");

    // Reconstruct a MerkleTree directly from leaf nodes to confirm the public surface.
    let mut tree = MerkleTree::new();
    for (i, leaf_hash) in [[1u8; 32], [2u8; 32], [3u8; 32], [4u8; 32]].into_iter().enumerate() {
        tree.add(Node { index: i as u64, size: 1, hash: leaf_hash });
    }
    let root = tree.root_hash();

    // Bitfield tracks which sequence numbers a peer has. Mark the first three present
    // and ask for the next missing slot — replication uses this to schedule fetches.
    let mut have = Bitfield::with_capacity(8);
    have.set_range(0, 3, true);
    let next_missing = have.first_unset();

    println!(
        "verified seq={} proof_nodes={} tree_root={} peer_have_count={} next_missing={:?}",
        target_seq,
        proof.nodes.len(),
        hex::encode(root),
        have.count(),
        next_missing,
    );
    Ok(())
}