pub struct ChainManager { /* private fields */ }Expand description
Thread-safe chain manager.
Wraps a local chain with mutex protection for concurrent access from multiple kernel subsystems. Optionally holds an Ed25519 signing key for cryptographic chain signing.
Implementations§
Source§impl ChainManager
impl ChainManager
Sourcepub fn new(chain_id: u32, checkpoint_interval: u64) -> Self
pub fn new(chain_id: u32, checkpoint_interval: u64) -> Self
Create a new chain manager with genesis event.
Sourcepub fn default_local() -> Self
pub fn default_local() -> Self
Create with default settings.
Sourcepub fn from_events(
events: Vec<ChainEvent>,
checkpoint_interval: u64,
) -> Result<Self, Box<dyn Error + Send + Sync>>
pub fn from_events( events: Vec<ChainEvent>, checkpoint_interval: u64, ) -> Result<Self, Box<dyn Error + Send + Sync>>
Restore a chain manager from a verified event prefix (WEFT-105).
Used when a joining node already shares a common genesis / prefix with a peer (same cluster identity). Events must be non-empty and pass integrity verification.
Sourcepub fn with_signing_key(self, key: SigningKey) -> Self
pub fn with_signing_key(self, key: SigningKey) -> Self
Attach an Ed25519 signing key for RVF segment signing.
Sourcepub fn verifying_key(&self) -> Option<VerifyingKey>
pub fn verifying_key(&self) -> Option<VerifyingKey>
Get the verifying (public) key, if a signing key is set.
Sourcepub fn set_signing_key(&mut self, key: SigningKey)
pub fn set_signing_key(&mut self, key: SigningKey)
Set the signing key (mutable borrow — use with Arc::get_mut()
before sharing the manager across tasks).
Sourcepub fn has_signing_key(&self) -> bool
pub fn has_signing_key(&self) -> bool
Whether this chain manager has a signing key attached.
Sourcepub fn signing_key_clone(&self) -> Option<SigningKey>
pub fn signing_key_clone(&self) -> Option<SigningKey>
Clone the Ed25519 signing key (for key rotation, WEFT-107).
Sourcepub fn set_ml_dsa_key(&mut self, key: MlDsa65Key)
pub fn set_ml_dsa_key(&mut self, key: MlDsa65Key)
Set the ML-DSA-65 key for post-quantum dual signing.
Sourcepub fn has_dual_signing(&self) -> bool
pub fn has_dual_signing(&self) -> bool
Whether dual signing (Ed25519 + ML-DSA-65) is enabled.
Sourcepub fn load_or_create_key(
path: &Path,
) -> Result<SigningKey, Box<dyn Error + Send + Sync>>
pub fn load_or_create_key( path: &Path, ) -> Result<SigningKey, Box<dyn Error + Send + Sync>>
Load an Ed25519 signing key from file, or generate and persist a new one.
Sourcepub fn append(
&self,
source: &str,
kind: &str,
payload: Option<Value>,
) -> ChainEvent
pub fn append( &self, source: &str, kind: &str, payload: Option<Value>, ) -> ChainEvent
Append an event to the chain.
Sourcepub fn append_idempotent(
&self,
source: &str,
kind: &str,
payload: Option<Value>,
idempotency_key: Option<[u8; 32]>,
) -> ChainEvent
pub fn append_idempotent( &self, source: &str, kind: &str, payload: Option<Value>, idempotency_key: Option<[u8; 32]>, ) -> ChainEvent
Append an event with an optional idempotency key (WEFT-103).
When idempotency_key is Some, the chain is scanned for the
most recent IDEMPOTENCY_LOOKBACK events. If an event with
the same key is found, no append occurs and the prior
event is returned. This protects the chain against:
- Retried mesh writes that crossed the network twice.
- HTTP-handler retries on connection drops.
- Sync-sweep loops that re-emit the same logical operation.
When idempotency_key is None, behaves exactly like
Self::append.
Concurrency: the lookback scan and the append happen under the same inner mutex, so concurrent callers cannot race past each other to insert duplicates.
Sourcepub fn checkpoint(&self) -> ChainCheckpoint
pub fn checkpoint(&self) -> ChainCheckpoint
Create a checkpoint.
Sourcepub fn tail(&self, n: usize) -> Vec<ChainEvent>
pub fn tail(&self, n: usize) -> Vec<ChainEvent>
Get recent events (last n, or all if n=0).
Sourcepub fn set_rule_hash_provider(&self, provider: RuleHashProvider)
pub fn set_rule_hash_provider(&self, provider: RuleHashProvider)
Install the provider that stamps rule_hash on every append
(ADR-103 A7).
Lock order: the chain lock is taken first, then the provider
runs. The provider must therefore never block and never call back
into this manager: read lock-free state (an atomic, see
crate::chain_rule_hash::RuleHashCell) or use try_read.
A provider that takes a lock another thread holds while appending
would deadlock. In dev/test builds (panic = unwind) a panicking
provider is caught: the event is appended without rule_hash and a
warning is logged. Release builds use panic = "abort", so there a
provider panic aborts the process; it must not panic.
Sourcepub fn set_max_replay_window(&self, events: u64)
pub fn set_max_replay_window(&self, events: u64)
Bound how far back Self::subscribe may replay, in events.
Sourcepub fn subscribe(
self: &Arc<Self>,
filter: ChainFilter,
) -> Result<ChainSubscription, SubscribeError>
pub fn subscribe( self: &Arc<Self>, filter: ChainFilter, ) -> Result<ChainSubscription, SubscribeError>
Subscribe to chain events: optional replay from filter.from_seq,
then live events, with no gap and no duplicate between the two.
See crate::chain_subscribe.
Under the chain lock this only subscribes to the live feed and
records the snapshot end; the replay is paged later in short lock
holds by the subscription, so a deep from_seq cannot stall
appends or pin memory.
§Errors
[SubscribeError::ReplayWindowExceeded] when from_seq is older
than the configured replay window.
Sourcepub fn tail_from(&self, after: u64) -> Vec<ChainEvent>
pub fn tail_from(&self, after: u64) -> Vec<ChainEvent>
Return events with sequence strictly greater than after.
Used for incremental replication in K6.4 chain sync.
Sourcepub fn append_signed(
&self,
event: ChainEvent,
) -> Result<ChainEvent, AppendSignedError>
pub fn append_signed( &self, event: ChainEvent, ) -> Result<ChainEvent, AppendSignedError>
Append a remote (pre-built) chain event after verifying hash linkage (WEFT-105 / K6.4 chain replay).
Unlike Self::append, this does not re-hash or re-timestamp the
event — the remote node’s event is accepted as-is when:
event.chain_idmatches the local chainevent.sequenceequals the next expected sequenceevent.prev_hashequals the local tip hashevent.payload_hashmatches a recomputation of the payloadevent.hashmatches a recomputation of the event commitment
Idempotent: if an event with the same sequence and hash already
exists, returns AppendSignedError::AlreadyPresent.
Fork policy (ADR-089): same sequence with a different hash returns
AppendSignedError::Fork — tips are retained by rejecting silent
overwrite; higher-level merge commits are out of scope for linear
catch-up replay.
Sourcepub fn head_sequence(&self) -> u64
pub fn head_sequence(&self) -> u64
Get the current head sequence number (sequence of the last event). Returns 0 when the chain is empty.
Sourcepub fn head_hash(&self) -> [u8; 32]
pub fn head_hash(&self) -> [u8; 32]
Get the current head hash (hash of the last event). Returns the all-zero hash when the chain is empty.
Sourcepub fn checkpoints(&self) -> Vec<ChainCheckpoint>
pub fn checkpoints(&self) -> Vec<ChainCheckpoint>
Get all checkpoints.
Sourcepub fn witness_count(&self) -> usize
pub fn witness_count(&self) -> usize
Get the number of witness entries.
Sourcepub fn verify_witness(&self) -> Result<usize, Box<dyn Error + Send + Sync>>
pub fn verify_witness(&self) -> Result<usize, Box<dyn Error + Send + Sync>>
Serialize the witness chain and verify it.
Returns Ok(entry_count) if the witness chain is valid, or
Err if verification fails.
Sourcepub fn generate_attestation(
&self,
vector_count: u64,
epoch: u64,
content_hash: &str,
) -> Option<CustodyAttestation>
pub fn generate_attestation( &self, vector_count: u64, epoch: u64, content_hash: &str, ) -> Option<CustodyAttestation>
Generate a custody attestation document.
Assembles the current chain state, vector count and content hash, and signs the result with the kernel’s Ed25519 key.
Returns None if no signing key is configured.
Sourcepub fn verify_integrity(&self) -> ChainVerifyResult
pub fn verify_integrity(&self) -> ChainVerifyResult
Verify the integrity of the entire chain.
Walks all events and verifies:
- Each event’s
prev_hashmatches the prior event’shash - Each event’s
payload_hashmatches the recomputed payload hash - Each event’s
hashmatches the recomputed event hash
Sourcepub fn save_to_file(
&self,
path: &Path,
) -> Result<(), Box<dyn Error + Send + Sync>>
pub fn save_to_file( &self, path: &Path, ) -> Result<(), Box<dyn Error + Send + Sync>>
Save the chain to a file (line-delimited JSON).
Writes all events as newline-delimited JSON to the given path. Creates parent directories if they don’t exist.
Sourcepub fn load_from_file(
path: &Path,
checkpoint_interval: u64,
) -> Result<Self, Box<dyn Error + Send + Sync>>
pub fn load_from_file( path: &Path, checkpoint_interval: u64, ) -> Result<Self, Box<dyn Error + Send + Sync>>
Load a chain from a file (line-delimited JSON).
Reads events, verifies integrity, and restores state so that new events continue from the last sequence number.
Sourcepub fn save_to_rvf(
&self,
path: &Path,
) -> Result<(), Box<dyn Error + Send + Sync>>
pub fn save_to_rvf( &self, path: &Path, ) -> Result<(), Box<dyn Error + Send + Sync>>
Save the chain as a concatenation of RVF segments.
Each event is serialized as an ExochainEvent segment (subtype 0x40) containing a 64-byte ExoChainHeader + CBOR payload. A trailing ExochainCheckpoint segment (subtype 0x41) records the final chain state for external verification.
Sourcepub fn load_from_rvf(
path: &Path,
checkpoint_interval: u64,
) -> Result<Self, Box<dyn Error + Send + Sync>>
pub fn load_from_rvf( path: &Path, checkpoint_interval: u64, ) -> Result<Self, Box<dyn Error + Send + Sync>>
Load a chain from an RVF segment file.
Reads concatenated RVF segments, validates each segment’s content hash, decodes ExoChainHeader + CBOR payload, and reconstructs the chain events. Checkpoint segments (subtype 0x41) are skipped.
Sourcepub fn record_lineage(
&self,
child_id: [u8; 16],
parent_id: [u8; 16],
parent_hash: [u8; 32],
derivation_type: DerivationType,
mutation_count: u32,
description: &str,
) -> ChainEvent
pub fn record_lineage( &self, child_id: [u8; 16], parent_id: [u8; 16], parent_hash: [u8; 32], derivation_type: DerivationType, mutation_count: u32, description: &str, ) -> ChainEvent
Record a lineage derivation event in the chain.
Creates a LineageRecord from the given parameters, serializes it,
adds a lineage witness entry, and appends a lineage.derivation
chain event with the full record in the payload.
child_id: UUID of the derived entity (agent, resource)parent_id: UUID of the parent entity (zero for root)parent_hash: hash of the parent’s state at derivation timederivation_type: how the child was producedmutation_count: number of mutations/changes applieddescription: human-readable description (max 47 chars)
Sourcepub fn verify_lineage(&self) -> Result<usize, Box<dyn Error + Send + Sync>>
pub fn verify_lineage(&self) -> Result<usize, Box<dyn Error + Send + Sync>>
Extract lineage records from chain events and verify the chain.
Returns Ok(count) if all lineage records form a valid chain,
or Err describing the verification failure.
Sourcepub fn record_witness_bundle(
&self,
bundle_bytes: &[u8],
header: &WitnessHeader,
policy_violations: u32,
rollback_count: u32,
) -> ChainEvent
pub fn record_witness_bundle( &self, bundle_bytes: &[u8], header: &WitnessHeader, policy_violations: u32, rollback_count: u32, ) -> ChainEvent
Record a completed witness bundle as a chain event.
Takes the raw bundle bytes and parsed header produced by
WitnessBuilder::build(), stores them as a witness.bundle
chain event with the bundle hex-encoded in the payload.
Sourcepub fn aggregate_scorecard(&self, n: usize) -> Scorecard
pub fn aggregate_scorecard(&self, n: usize) -> Scorecard
Aggregate witness bundles from recent chain events into a scorecard.
Scans the last n events (0 = all) for witness.bundle events,
parses each bundle, and produces an aggregate Scorecard.
Sourcepub fn last_tree_root_hash(&self) -> Option<String>
pub fn last_tree_root_hash(&self) -> Option<String>
Find the most recent tree root hash recorded in chain events.
Scans backwards through the event log looking for payloads
that contain tree_root_hash (shutdown, boot.ready, boot.manifest)
or root_hash on tree-sourced events (tree.checkpoint, checkpoint).
Returns the hash as a hex string if found.
Sourcepub fn status(&self) -> ChainStatus
pub fn status(&self) -> ChainStatus
Get a status summary.
Sourcepub fn verify_rvf_signature(
path: &Path,
verifying_key: &VerifyingKey,
) -> Result<bool, Box<dyn Error + Send + Sync>>
pub fn verify_rvf_signature( path: &Path, verifying_key: &VerifyingKey, ) -> Result<bool, Box<dyn Error + Send + Sync>>
Verify the Ed25519 signature on an RVF chain file.
Reads the file, locates the checkpoint segment and trailing signature footer, and verifies the signature against the provided public key.
Returns Ok(true) if signature is valid, Ok(false) if
invalid, and Err if the file has no signature or can’t be read.
Sourcepub fn verify_rvf_dual_signature(
path: &Path,
ed_key: &VerifyingKey,
ml_key: &MlDsa65VerifyKey,
) -> Result<bool, Box<dyn Error + Send + Sync>>
pub fn verify_rvf_dual_signature( path: &Path, ed_key: &VerifyingKey, ml_key: &MlDsa65VerifyKey, ) -> Result<bool, Box<dyn Error + Send + Sync>>
Verify dual (Ed25519 + ML-DSA-65) signatures on an RVF chain file.
Returns Ok(true) if both signatures are valid, Ok(false) if
either is invalid, and Err if the file has no dual signature.
Sourcepub fn dual_sign(&self, data: &[u8]) -> Option<DualSignature>
pub fn dual_sign(&self, data: &[u8]) -> Option<DualSignature>
Sign data with both Ed25519 and ML-DSA-65 (if configured).
Returns Some(DualSignature) when at least the Ed25519 key is
present. The ML-DSA-65 half is populated only when the ML-DSA key
has been set via [set_ml_dsa_key].
Sourcepub fn verify_dual_signature(
data: &[u8],
sig: &DualSignature,
ed25519_pubkey: &VerifyingKey,
ml_dsa_pubkey: Option<&MlDsa65VerifyKey>,
) -> bool
pub fn verify_dual_signature( data: &[u8], sig: &DualSignature, ed25519_pubkey: &VerifyingKey, ml_dsa_pubkey: Option<&MlDsa65VerifyKey>, ) -> bool
Verify a dual signature against the given data and public keys.
Ed25519 verification is mandatory. ML-DSA-65 verification is
performed only when both the signature and verification key are
present. Returns false if any present signature is invalid.
Source§impl ChainManager
impl ChainManager
Sourcepub fn append_loggable(&self, event: &dyn ChainLoggable) -> ChainEvent
pub fn append_loggable(&self, event: &dyn ChainLoggable) -> ChainEvent
Append an event from any ChainLoggable implementor.
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for ChainManager
impl RefUnwindSafe for ChainManager
impl Send for ChainManager
impl Sync for ChainManager
impl Unpin for ChainManager
impl UnsafeUnpin for ChainManager
impl UnwindSafe for ChainManager
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> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§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