#![warn(missing_docs)]
pub mod base;
pub mod checkpoint;
pub mod context;
#[cfg(feature = "persist")]
pub mod log;
pub mod propose;
pub mod receipt;
pub mod record;
pub mod state;
pub mod verify;
pub use base::canonical::{canonical_json, canonical_json_string};
pub use base::hash::{
hex_decode, hex_encode, sha256, sha256_canonical, sha256_concat_ids, sha256_utf8, Hash256,
};
pub use base::schema::{
default_space, schema_id, schema_name_for_id, SchemaId, DEFAULT_SPACE_NAME, SCHEMA_ACTION,
SCHEMA_APPROVAL, SCHEMA_CAPABILITY, SCHEMA_PLAN, SCHEMA_REFUSAL, SCHEMA_REQUEST,
SCHEMA_RESPONSE, SCHEMA_RESULT, SCHEMA_RESULT_EFFECT_CONFIRMATION, SCHEMA_RESULT_EXTERNAL,
SCHEMA_RETRACTION, SCHEMA_SUMMARY, SCHEMA_USAGE, SCHEMA_VERDICT, SPEC_VERSION,
};
pub use base::time::{Time, TimeSource};
pub use record::author::{ActorId, Author, Signature};
pub use record::evidence::{base_evidence, derive_evidence, weakest, Evidence};
pub use record::kind::{
AuthorType, CapabilityMode, ExecMode, Kind, ReasonCode, RefType, RefusalTarget, ResultStatus,
SummaryType, UsageOutcome, VerdictResult,
};
pub use record::payloads::{
ActionData, ApprovalData, Attachment, CapabilityData, FailurePolicy, PlanData, PlanStatus,
PlanTask, PlanTaskKind, RefusalData, RequestData, ResponseData, ResultData, RetractionData,
SummaryData, TaskDoneWhen, TaskStatus, UsageData, UsageOutcomeCounts, VerdictData,
};
pub use record::record::{
decode, encode, Proposal, Record, ScopeId, SpaceId, ThreadId, RECORD_SIGNATURE_DOMAIN,
};
pub use record::refs::{sort_and_dedup_refs, RecordId, Ref};
pub use record::sign::{signature_verifies, verified_key, Ed25519Signer, PublicKeyBytes};
pub use checkpoint::{
create_checkpoint, head_attestation, CanonicalUtcTimestamp, Checkpoint, HeadAttestation,
InvalidTimestamp, TrustedCheckpoint,
};
#[cfg(feature = "persist")]
pub use log::writer::{BatchAppend, LogWriter, DEFAULT_MAX_LOG_BYTES, EMPTY_HEAD};
pub use receipt::{
validate, validate_with_limits, Receipt, Report, ValidationLimits, ValidationStatus,
};
pub use verify::rules::VerifierRules;
pub use verify::verifier::{verify_log, verify_record, LogVerdict};
pub use state::build::{build_state_unchecked, verify_and_build_state};
pub use state::incremental::{apply_record, find_replace_ref};
pub use state::state::State;
pub use context::context::{build_context, build_context_with, Context, ContextPolicy};
pub use propose::proposer::Proposer;
#[derive(Debug)]
pub enum LogError {
AlreadyLocked,
Io(std::io::Error),
CorruptedRecovery,
RecoveryRequired,
TimeExhausted,
HeadConflict {
expected: crate::record::refs::RecordId,
actual: crate::record::refs::RecordId,
},
RecordTooLarge {
bytes: usize,
},
LogSizeLimitExceeded {
bytes: u64,
max_bytes: u64,
},
InvalidExistingLog {
reason: Option<crate::record::kind::ReasonCode>,
},
StateMismatch,
RulesMismatch,
SerdeJson(serde_json::Error),
}
impl std::fmt::Display for LogError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
LogError::AlreadyLocked => write!(f, "log is already locked by another writer"),
LogError::Io(e) => write!(f, "I/O error: {}", e),
LogError::CorruptedRecovery => write!(f, "corrupted commit intent during recovery"),
LogError::RecoveryRequired => write!(
f,
"a commit entered its durable phase but did not finish; drop and reopen the writer"
),
LogError::TimeExhausted => {
write!(
f,
"logical time counter exhausted; log accepts no further commits"
)
}
LogError::HeadConflict { expected, actual } => write!(
f,
"head conflict: expected {}, log is at {}",
base::hash::hex_encode(expected),
base::hash::hex_encode(actual)
),
LogError::RecordTooLarge { bytes } => write!(
f,
"record frame of {} bytes exceeds the u32 length prefix; refusing to corrupt the log",
bytes
),
LogError::LogSizeLimitExceeded { bytes, max_bytes } => write!(
f,
"log size of {bytes} bytes exceeds configured limit of {max_bytes} bytes"
),
LogError::InvalidExistingLog { reason } => {
write!(f, "existing log failed replay verification")?;
if let Some(reason) = reason {
write!(f, ": {reason:?}")?;
}
Ok(())
}
LogError::StateMismatch => write!(
f,
"derived state does not match the current log; rebuild it before committing"
),
LogError::RulesMismatch => write!(
f,
"commit rules differ from the rules used to open this writer"
),
LogError::SerdeJson(e) => write!(f, "JSON error: {}", e),
}
}
}
impl std::error::Error for LogError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
LogError::Io(e) => Some(e),
LogError::SerdeJson(e) => Some(e),
_ => None,
}
}
}
impl From<serde_json::Error> for LogError {
fn from(e: serde_json::Error) -> Self {
LogError::SerdeJson(e)
}
}
impl From<std::io::Error> for LogError {
fn from(e: std::io::Error) -> Self {
LogError::Io(e)
}
}