WeaveDocs
Strand

Append and Read

Append and read entries on a single-writer signed log: ordered writes, sealed Merkle proofs, bitfield-tracked replication.

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.

Note

A Strand is single-writer per instance. The instance holds the signing key and serialises appends; do not call append concurrently from multiple Strand handles to the same on-disk strand.

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::{Strand, StrandConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let dir = tempfile::tempdir()?;
    let cfg = StrandConfig::new().with_storage(dir.path());
    let mut strand = Strand::new(cfg).await?;

    // Append a batch of blocks; the returned seq is the new tail index.
    for (i, payload) in ["genesis", "block-one", "block-two"].iter().enumerate() {
        let seq = strand.append(payload.as_bytes()).await?;
        assert_eq!(seq, i as u64);
    }

    // Random-access read returns the exact bytes that were appended.
    let block_one = strand.get(1).await?;
    assert_eq!(block_one, b"block-one");

    // Read the per-block Header to inspect signature + tree hash without the payload.
    let header = strand.get_header(2).await?;
    println!(
        "strand len={} latest_seq={} discovery_key={}",
        strand.len(),
        2,
        hex::encode(strand.discovery_key()),
    );
    println!(
        "header seq={} length={} writer={}",
        header.seq,
        header.length,
        hex::encode(header.writer_public_key),
    );
    Ok(())
}