urma-core 0.3.0

Canonical URMA V0 codecs, crypto and proof validation without I/O
Documentation
use super::{Geometry, LeafManifest, RootManifest};
use crate::error::{Error, ensure};
use bitcoin::Txid;
use std::collections::HashSet;

pub struct ManifestInventory {
    geometry: Geometry,
    next_leaf: u16,
    seen: HashSet<Txid>,
}

impl ManifestInventory {
    pub fn new(root_txid: Txid, manifest: &RootManifest) -> Result<Self, Error> {
        let geometry = manifest.geometry()?;
        let mut seen = HashSet::new();
        seen.try_reserve(usize::try_from(geometry.nodes())?)?;
        seen.insert(root_txid);
        for reference in &manifest.entries {
            ensure!(
                seen.insert(reference.txid),
                "duplicate or cyclic root reference"
            );
        }
        Ok(Self {
            geometry,
            next_leaf: 0,
            seen,
        })
    }

    pub fn accept_leaf(&mut self, leaf: &LeafManifest) -> Result<(), Error> {
        leaf.validate()?;
        ensure!(leaf.index == self.next_leaf, "leaf order mismatch");
        ensure!(
            leaf.entries.len() == usize::from(self.geometry.leaf_entries(self.next_leaf)?),
            "leaf count disagrees with root"
        );
        let mut additions = HashSet::new();
        additions.try_reserve(leaf.entries.len())?;
        for reference in &leaf.entries {
            ensure!(
                !self.seen.contains(&reference.txid) && additions.insert(reference.txid),
                "duplicate or cyclic data reference"
            );
        }
        self.seen.extend(additions);
        self.next_leaf += 1;
        Ok(())
    }

    pub fn is_complete(&self) -> bool {
        self.next_leaf == self.geometry.leaves()
    }
}