Skip to main content

LocalLedger

Struct LocalLedger 

Source
pub struct LocalLedger { /* private fields */ }
Expand description

File-based ledger backed by an append-only JSON-lines file.

Implementations§

Source§

impl LocalLedger

Source

pub const BACKEND_KIND: &'static str = "local-file"

Backend identifier.

Source

pub fn open<P: AsRef<Path>>(path: P) -> Result<Self>

Open an existing ledger file or create a new one.

On open: replays the file, verifies the hash chain, and reconstructs LCT state. Errors if the chain is broken (tamper detected) or if any entry’s stored hash doesn’t match its canonical hash.

On create: writes a genesis entry to the file.

Examples found in repository?
examples/cross_language_verify/verify.rs (line 97)
71fn main() -> ExitCode {
72    let (ledger_path, sidecar_path) = parse_args();
73
74    println!("[rust] Reading sidecar at {}", sidecar_path.display());
75    let sidecar_text = match fs::read_to_string(&sidecar_path) {
76        Ok(s) => s,
77        Err(e) => {
78            eprintln!("[rust] Could not read sidecar {}: {}", sidecar_path.display(), e);
79            eprintln!("[rust] Did you run `python mint.py` first?");
80            return ExitCode::from(2);
81        }
82    };
83    let sidecar: LctSidecar = match serde_json::from_str(&sidecar_text) {
84        Ok(s) => s,
85        Err(e) => {
86            eprintln!("[rust] Sidecar parse error: {}", e);
87            return ExitCode::from(2);
88        }
89    };
90    println!("[rust]   lct_id      = {}", sidecar.lct_id);
91    println!("[rust]   fingerprint = {}", sidecar.fingerprint);
92
93    println!(
94        "[rust] Opening LocalLedger at {} (this replays + verifies the chain)",
95        ledger_path.display()
96    );
97    let ledger = match LocalLedger::open(&ledger_path) {
98        Ok(l) => l,
99        Err(e) => {
100            eprintln!("[rust] Ledger open failed: {}", e);
101            eprintln!("[rust] If this is a chain-integrity failure, the ledger was tampered.");
102            return ExitCode::from(3);
103        }
104    };
105    println!("[rust] Chain intact. {} entries replayed.", ledger.len());
106
107    let lct_uuid = match uuid::Uuid::parse_str(&sidecar.lct_id) {
108        Ok(u) => u,
109        Err(e) => {
110            eprintln!("[rust] Sidecar lct_id is not a UUID: {}", e);
111            return ExitCode::from(2);
112        }
113    };
114
115    let lookup = match ledger.lookup(lct_uuid) {
116        Ok(l) => l,
117        Err(e) => {
118            eprintln!("[rust] Ledger lookup failed: {}", e);
119            return ExitCode::from(3);
120        }
121    };
122    let lct = match lookup {
123        Some(lct) => lct,
124        None => {
125            eprintln!("[rust] LCT {} not present in ledger.", sidecar.lct_id);
126            return ExitCode::from(3);
127        }
128    };
129    println!("[rust] LCT present in ledger.");
130
131    if lct.fingerprint() != sidecar.fingerprint {
132        eprintln!(
133            "[rust] FINGERPRINT MISMATCH:\n  sidecar:  {}\n  on-chain: {}",
134            sidecar.fingerprint,
135            lct.fingerprint()
136        );
137        return ExitCode::from(3);
138    }
139    println!("[rust] Fingerprint matches sidecar.");
140
141    let proof = match ledger.anchor(lct.id) {
142        Ok(p) => p,
143        Err(e) => {
144            eprintln!("[rust] anchor() failed: {}", e);
145            return ExitCode::from(3);
146        }
147    };
148    let verified = match ledger.verify_proof(&proof) {
149        Ok(v) => v,
150        Err(e) => {
151            eprintln!("[rust] verify_proof error: {}", e);
152            return ExitCode::from(3);
153        }
154    };
155    if !verified {
156        eprintln!("[rust] Anchor proof DID NOT verify under the Rust implementation.");
157        return ExitCode::from(3);
158    }
159    println!("[rust] Anchor proof verifies under the Rust implementation. ✓");
160    println!();
161    println!("[rust] Cross-language verification succeeded.");
162    println!(
163        "[rust] Python wrote a hash-chained ledger; Rust read the same file, replayed the chain, \
164         looked up the LCT by id, matched its fingerprint, and verified the inclusion proof — \
165         with zero shared runtime. The on-disk format is the contract."
166    );
167    ExitCode::SUCCESS
168}
Source

pub fn path(&self) -> &Path

Path of the ledger file.

Source

pub fn entries(&self) -> &[LedgerEntry]

Iterate over all entries (replayed from file).

Trait Implementations§

Source§

impl Debug for LocalLedger

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Ledger for LocalLedger

Source§

fn mint(&mut self, lct: &Lct) -> Result<MintReceipt>

Mint a new LCT, anchoring it to the ledger. Read more
Source§

fn lookup(&self, id: Uuid) -> Result<Option<Lct>>

Look up an LCT by ID. Read more
Source§

fn update_status(&mut self, id: Uuid, status: LctStatus) -> Result<LedgerEntry>

Update an LCT’s status (Active → Dormant → Void → Slashed). Read more
Source§

fn anchor(&self, id: Uuid) -> Result<LedgerProof>

Generate proof that an LCT exists in the ledger.
Source§

fn verify_proof(&self, proof: &LedgerProof) -> Result<bool>

Verify a proof against the current ledger state. Read more
Source§

fn backend_kind(&self) -> &'static str

Backend identifier (used in receipts and proofs).
Source§

fn len(&self) -> u64

Total number of entries in the ledger (including genesis).
Source§

fn is_empty(&self) -> bool

Whether the ledger has any entries beyond genesis.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V