Trusty: provenance library workspace (initial import)

This commit is contained in:
2026-09-09 18:31:00 -04:00
commit 693f3bef1e
73 changed files with 26295 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
[package]
name = "trusty-memory"
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
description = "In-memory Store backend for Trusty. Reference implementation and test harness."
[dependencies]
trusty-store = { workspace = true }
[dev-dependencies]
trusty-store = { workspace = true, features = ["testing"] }

View File

@@ -0,0 +1,135 @@
//! In-memory [`Store`](trusty_store::Store) backend for Trusty.
//!
//! Reference implementation of the `Store` trait. Intended for tests, fuzzing,
//! and conformance checks. Not suitable for persistent production use -- all data
//! is lost when the process exits.
#![deny(clippy::all)]
use std::collections::{BTreeMap, HashMap};
use trusty_store::{
KvCrossCheckReport, LastRow, RowInsert, Store, StoreResult, StoredRow, TipRow, TipUpsert,
};
#[derive(Clone, Default)]
pub struct MemoryStore {
rows: BTreeMap<i64, StoredRow>,
next_id: i64,
tips_by_chain: HashMap<String, TipRow>,
tips_by_entity: HashMap<String, TipRow>,
}
impl MemoryStore {
pub fn new() -> Self {
Self::default()
}
}
impl Store for MemoryStore {
fn last_row(&self, entity_id: &str) -> StoreResult<Option<LastRow>> {
let last = self
.rows
.values()
.rev()
.find(|r| r.entity_id == entity_id && r.event_type != "BREAK" && r.row_hash.is_some())
.map(|r| LastRow {
row_hash: r.row_hash.clone().unwrap(),
sequence: r.sequence,
});
Ok(last)
}
fn insert_row(&mut self, row: &RowInsert) -> StoreResult<i64> {
self.next_id += 1;
let id = self.next_id;
let stored = StoredRow {
id,
entity_id: row.entity_id.clone(),
chain_id: row.chain_id.clone(),
event_type: row.event_type.clone(),
sequence: row.sequence,
prev_hash: row.prev_hash.clone(),
row_hash: row.row_hash.clone(),
anchor_hash: row.anchor_hash.clone(),
raw_payload: row.raw_payload.clone(),
detected_at: row.detected_at.clone(),
received_at: row.received_at.clone(),
source_url: row.source_url.clone(),
extraction_method: row.extraction_method.clone(),
};
self.rows.insert(id, stored);
Ok(id)
}
fn iter_chain<'a>(
&'a self,
entity_id: &str,
) -> StoreResult<Box<dyn Iterator<Item = StoreResult<StoredRow>> + 'a>> {
let entity = entity_id.to_string();
let iter = self
.rows
.values()
.filter(move |r| r.entity_id == entity)
.cloned()
.map(Ok);
Ok(Box::new(iter))
}
fn get_tip(&self, chain_id: &str) -> StoreResult<Option<TipRow>> {
Ok(self.tips_by_chain.get(chain_id).cloned())
}
fn get_tip_for_entity(&self, entity_id: &str) -> StoreResult<Option<TipRow>> {
Ok(self.tips_by_entity.get(entity_id).cloned())
}
fn set_tip(&mut self, tip: &TipUpsert) -> StoreResult<()> {
let row = TipRow {
entity_id: tip.entity_id.clone(),
chain_id: tip.chain_id.clone(),
current_tip_hash: tip.current_tip_hash.clone(),
updated_at: String::new(),
};
self.tips_by_chain.insert(tip.chain_id.clone(), row.clone());
self.tips_by_entity.insert(tip.entity_id.clone(), row);
Ok(())
}
fn kv_cross_check(&self) -> StoreResult<KvCrossCheckReport> {
let kv1 = self.rows.values().filter(|r| r.row_hash.is_some()).count();
let kv2 = self.tips_by_entity.len();
let mut mismatches: Vec<String> = Vec::new();
for (entity, tip) in &self.tips_by_entity {
if let Some(hash) = &tip.current_tip_hash {
let found = self.rows.values().any(|r| {
r.row_hash.as_deref() == Some(hash.as_str()) && r.chain_id == tip.chain_id
});
if !found {
mismatches.push(format!("tip_hash_not_in_rows: {}", entity));
}
}
}
Ok(KvCrossCheckReport {
ok: mismatches.is_empty(),
kv1_total_hashes: kv1,
kv2_total_entities: kv2,
entities_checked: kv2,
mismatches,
})
}
fn with_txn(
&mut self,
f: &mut dyn FnMut(&mut dyn Store) -> StoreResult<()>,
) -> StoreResult<()> {
let snap = self.clone();
match f(self) {
Ok(()) => Ok(()),
Err(e) => {
*self = snap;
Err(e)
}
}
}
}

View File

@@ -0,0 +1,8 @@
use trusty_memory::MemoryStore;
use trusty_store::testing::run_conformance;
#[test]
fn memory_store_passes_conformance() {
let mut store = MemoryStore::new();
run_conformance(&mut store);
}