Skip to main content

ChainManager

Struct ChainManager 

Source
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

Source

pub fn new(chain_id: u32, checkpoint_interval: u64) -> Self

Create a new chain manager with genesis event.

Source

pub fn default_local() -> Self

Create with default settings.

Source

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.

Source

pub fn with_signing_key(self, key: SigningKey) -> Self

Attach an Ed25519 signing key for RVF segment signing.

Source

pub fn verifying_key(&self) -> Option<VerifyingKey>

Get the verifying (public) key, if a signing key is set.

Source

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).

Source

pub fn has_signing_key(&self) -> bool

Whether this chain manager has a signing key attached.

Source

pub fn signing_key_clone(&self) -> Option<SigningKey>

Clone the Ed25519 signing key (for key rotation, WEFT-107).

Source

pub fn set_ml_dsa_key(&mut self, key: MlDsa65Key)

Set the ML-DSA-65 key for post-quantum dual signing.

Source

pub fn has_dual_signing(&self) -> bool

Whether dual signing (Ed25519 + ML-DSA-65) is enabled.

Source

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.

Source

pub fn append( &self, source: &str, kind: &str, payload: Option<Value>, ) -> ChainEvent

Append an event to the chain.

Source

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.

Source

pub fn checkpoint(&self) -> ChainCheckpoint

Create a checkpoint.

Source

pub fn len(&self) -> usize

Get the current chain length.

Source

pub fn is_empty(&self) -> bool

Check if the chain is empty (should never be after genesis).

Source

pub fn sequence(&self) -> u64

Get the current sequence number.

Source

pub fn last_hash(&self) -> [u8; 32]

Get the last hash.

Source

pub fn chain_id(&self) -> u32

Get the chain ID.

Source

pub fn tail(&self, n: usize) -> Vec<ChainEvent>

Get recent events (last n, or all if n=0).

Source

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.

Source

pub fn set_max_replay_window(&self, events: u64)

Bound how far back Self::subscribe may replay, in events.

Source

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.

Source

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.

Source

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:

  1. event.chain_id matches the local chain
  2. event.sequence equals the next expected sequence
  3. event.prev_hash equals the local tip hash
  4. event.payload_hash matches a recomputation of the payload
  5. event.hash matches 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.

Source

pub fn head_sequence(&self) -> u64

Get the current head sequence number (sequence of the last event). Returns 0 when the chain is empty.

Source

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.

Source

pub fn checkpoints(&self) -> Vec<ChainCheckpoint>

Get all checkpoints.

Source

pub fn witness_count(&self) -> usize

Get the number of witness entries.

Source

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.

Source

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.

Source

pub fn verify_integrity(&self) -> ChainVerifyResult

Verify the integrity of the entire chain.

Walks all events and verifies:

  1. Each event’s prev_hash matches the prior event’s hash
  2. Each event’s payload_hash matches the recomputed payload hash
  3. Each event’s hash matches the recomputed event hash
Source

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.

Source

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.

Source

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.

Source

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.

Source

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 time
  • derivation_type: how the child was produced
  • mutation_count: number of mutations/changes applied
  • description: human-readable description (max 47 chars)
Source

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.

Source

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.

Source

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.

Source

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.

Source

pub fn status(&self) -> ChainStatus

Get a status summary.

Source

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.

Source

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.

Source

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].

Source

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

Source

pub fn append_loggable(&self, event: &dyn ChainLoggable) -> ChainEvent

Append an event from any ChainLoggable implementor.

Trait Implementations§

Source§

impl Debug for ChainManager

Source§

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

Formats the value using the given formatter. Read more

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> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Pointee for T

Source§

type Pointer = u32

Source§

fn debug( pointer: <T as Pointee>::Pointer, f: &mut Formatter<'_>, ) -> Result<(), Error>

Source§

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

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
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

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more