pub struct HashChain { /* private fields */ }Expand description
A live hash chain: holds the root key and current head hash.
Cloning is cheap (Arc’d). Thread-safe via parking_lot::Mutex on the
head and chain id (the latter so that Self::load_head_from_file
can adopt the persisted id from a previous process invocation).
Implementations§
Source§impl HashChain
impl HashChain
Sourcepub fn new(root_key: &[u8]) -> Self
pub fn new(root_key: &[u8]) -> Self
Construct a new chain with the given root key and all-zero head.
Call HashChain::load_head_from_file after construction to resume
from an existing chain head persisted in the audit log.
Sourcepub fn resume(root_key: &[u8], head: [u8; 32], id: ChainId) -> Self
pub fn resume(root_key: &[u8], head: [u8; 32], id: ChainId) -> Self
Resume from a known head hash. Use this when you have the head
computed by HashChain::head from a previous session.
Sourcepub fn load_head_from_file(&self, path: &Path) -> Result<(), ChainLoadError>
pub fn load_head_from_file(&self, path: &Path) -> Result<(), ChainLoadError>
Read the last record_hash (and the matching chain_id) from the
audit log and use them as the current state. This lets a fresh
process pick up where the last left off without breaking the
chain’s identity (both head and id are restored). Tolerates:
missing file, empty file, all-blank file. Corrupt JSON or a
wrong-length hash in the last line is reported as Err so the
caller can refuse to start (a silent reset would let the chain
appear to verify while being disconnected from prior records).
Sourcepub fn id(&self) -> ChainId
pub fn id(&self) -> ChainId
Returns the chain id. If Self::load_head_from_file has been
called and the file contained a chain_id, that id is returned;
otherwise a fresh id is generated lazily on first call and cached.
Sourcepub fn adopt_id(&self, id: ChainId)
pub fn adopt_id(&self, id: ChainId)
Adopt the chain id from an external source (e.g. a sidecar file
persisted by crate::decision::DecisionLog). Idempotent: if an
id has already been observed (loaded from the audit log or set
explicitly), this is a no-op.
pub fn head(&self) -> [u8; 32]
Sourcepub fn set_head(&self, head: [u8; 32])
pub fn set_head(&self, head: [u8; 32])
Set the current head. Use this to resume a chain from a previously serialized head hash (e.g. when starting a new process that wants to continue appending to an existing log).
Sourcepub fn append(&self, canonical_record: &[u8]) -> ([u8; 32], [u8; 32])
pub fn append(&self, canonical_record: &[u8]) -> ([u8; 32], [u8; 32])
Append a record: returns (prev_hash, new_hash).
The canonical record bytes should be the canonical JSON serialization
of the record (see crate::decision::canonical).
Thread-safe: the head read, HMAC computation, and head write happen inside a single critical section. Concurrent appenders serialize.
Note: this advances the in-memory head before the caller has
persisted anything. If the caller’s persistence step fails, the
chain is left one step ahead of the on-disk file. Callers that
need an atomic “compute hash + persist” should use
Self::try_append_with_io instead.
Sourcepub fn try_append_with_io<F, T>(
&self,
canonical_record: &[u8],
persist: F,
) -> Result<T>
pub fn try_append_with_io<F, T>( &self, canonical_record: &[u8], persist: F, ) -> Result<T>
Atomic “compute hash + persist” for callers that hold an external lock (typically a file lock). The chain head is only advanced if the closure succeeds — so a failed write leaves the chain unchanged and a retry will produce the same hash.
Lock order: caller must hold the outer (file) lock before entering this method; we then take the chain head lock. The file lock is released by the caller, the chain head lock by this method’s return.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for HashChain
impl !RefUnwindSafe for HashChain
impl Send for HashChain
impl Sync for HashChain
impl Unpin for HashChain
impl !UnwindSafe for HashChain
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more