#![forbid(unsafe_code)]
use std::path::{Path, PathBuf};
pub mod admission_operation_store;
pub mod approval_store;
pub mod authority;
pub mod batch_approval_store;
pub mod budget_store;
pub mod capability_lineage;
pub mod channel_lifecycle_store;
pub mod channel_release_publisher_store;
pub mod clearing_lifecycle_store;
pub mod dead_letters;
pub mod economic_state_cache;
pub mod encrypted_blob;
pub mod evidence_export;
pub mod execution_nonce_store;
pub mod fiscal_store;
pub mod frost_store;
pub mod iou_store;
#[cfg(feature = "lineage")]
pub mod lineage_cte;
pub mod memory_provenance_store;
pub mod receipt_query;
pub mod receipt_store;
pub mod revocation_store;
pub mod schema_version;
pub mod serving_owner;
pub mod settle_attempts;
pub mod tool_outcome_store;
pub use chio_core::crypto::SharedCanonicalBytes;
pub use chio_core::{CanonicalBytes, CanonicalJsonWitness};
pub use chio_kernel::{EvidenceChildReceiptScope, EvidenceExportQuery};
pub const DEFAULT_READER_POOL_MAX_SIZE: u32 = 8;
pub const DEFAULT_WRITER_POOL_MAX_SIZE: u32 = 1;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SqlitePoolConfig {
pub reader_pool_max_size: u32,
pub writer_pool_max_size: u32,
pub max_page_count: Option<u32>,
}
impl Default for SqlitePoolConfig {
fn default() -> Self {
Self {
reader_pool_max_size: DEFAULT_READER_POOL_MAX_SIZE,
writer_pool_max_size: DEFAULT_WRITER_POOL_MAX_SIZE,
max_page_count: None,
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SqliteStoreOptions {
pub pool: SqlitePoolConfig,
pub incremental_verification: bool,
}
impl Default for SqliteStoreOptions {
fn default() -> Self {
Self {
pool: SqlitePoolConfig::default(),
incremental_verification: true,
}
}
}
#[must_use]
pub fn is_in_memory_sqlite_path(path: &str) -> bool {
if path.eq_ignore_ascii_case(":memory:") {
return true;
}
let Some(rest) = path.strip_prefix("file:") else {
return false;
};
let (name, query) = match rest.split_once('?') {
Some((name, query)) => (name, Some(query)),
None => (rest, None),
};
if name.eq_ignore_ascii_case(":memory:") {
return true;
}
query.is_some_and(|query| {
query
.split('&')
.any(|param| param.eq_ignore_ascii_case("mode=memory"))
})
}
#[must_use]
pub(crate) fn sqlite_parent_dir_to_create(path: &Path) -> Option<PathBuf> {
let Some(text) = path.to_str() else {
return non_empty_parent(path);
};
if is_in_memory_sqlite_path(text) {
return None;
}
non_empty_parent(&sqlite_filesystem_path(text))
}
fn non_empty_parent(path: &Path) -> Option<PathBuf> {
path.parent()
.filter(|parent| !parent.as_os_str().is_empty())
.map(Path::to_path_buf)
}
#[must_use]
pub fn sqlite_filesystem_path(text: &str) -> PathBuf {
let Some(rest) = text.strip_prefix("file:") else {
return PathBuf::from(text);
};
let without_query = rest.split_once('?').map_or(rest, |(name, _query)| name);
let filesystem = match without_query.strip_prefix("//") {
Some(after_authority_marker) => match after_authority_marker.find('/') {
Some(path_start) => &after_authority_marker[path_start..],
None => "",
},
None => without_query,
};
PathBuf::from(filesystem)
}
pub use admission_operation_store::{
CreditExposureAccountSnapshot, DurableObligationV1, SqliteAdmissionOperationStore,
};
pub use approval_store::SqliteApprovalStore;
pub use authority::SqliteCapabilityAuthority;
pub use batch_approval_store::SqliteBatchApprovalStore;
pub use budget_store::{BudgetStoreSnapshot, SqliteBudgetStore};
pub use channel_lifecycle_store::{
ChannelLifecycleStoreError, ChannelPreparedAdmissionRecordV1, ChannelPreparedBeginResult,
ChannelReservationDispositionV1, ChannelReservationStageRecordV1, SqliteChannelLifecycleStore,
};
pub use channel_release_publisher_store::{
ChannelReleasePublicationRecordV1, ChannelReleasePublicationStatusV1,
ChannelReleasePublisherError, ChannelReleaseSubmissionOutcomeV1,
SqliteChannelReleasePublisherStore, VerifiedChannelReleasePublicationV1,
};
pub use clearing_lifecycle_store::{ClearingLifecycleStoreError, SqliteClearingLifecycleStore};
pub use economic_state_cache::{
admission_terminal_projection_effect_result, EconomicOperationStageBinding,
EconomicOperationStageContext, EconomicStateCacheError, EconomicStateStageDescriptor,
EconomicStateStageRecord, EconomicStateStageStatus, SqliteEconomicStateCache,
};
pub use encrypted_blob::{
decrypt_blob, encrypt_blob, BlobHandle, BlobStoreError, DecryptError, EncryptError,
EncryptedBlob, SqliteEncryptedBlobStore, TenantId, TenantKey,
};
pub use execution_nonce_store::{SqliteExecutionNonceStore, SqliteExecutionNonceStoreError};
pub use frost_store::{
FrostActiveRosterRecord, FrostCeremonyRecord, FrostCeremonyRound1Record,
FrostCeremonyRound2Record, FrostCeremonyState, FrostCoordinatorCancellation,
FrostCoordinatorCommitment, FrostCoordinatorLease, FrostCoordinatorSessionRecord,
FrostCoordinatorSessionRequest, FrostCoordinatorSessionState, FrostCoordinatorShare,
FrostCoordinatorSigningPackage, FrostCustodyKey, FrostRotationRecord, FrostRotationState,
FrostSignerCommitment, FrostSignerSessionRecord, FrostSignerSessionRequest,
FrostSignerSessionState, FrostSignerShare, FrostStoreError, SqliteFrostStore,
StagedFrostRotation, StoredFrostCeremonyCompletion,
};
pub use iou_store::{SqliteIouEnvelopeStore, IOU_ENVELOPE_MIGRATION};
pub use memory_provenance_store::{SqliteMemoryProvenanceStore, SqliteMemoryProvenanceStoreError};
pub use receipt_store::{BackgroundCheckpointSigner, SqliteReceiptStore};
pub use revocation_store::SqliteRevocationStore;
pub use schema_version::{
check_schema_version, stamp_schema_version, SchemaVersionError, CHIO_SQLITE_APPLICATION_ID,
};
pub use serving_owner::{
scope_fixed_authority_ids_for_current_thread, FixedAuthorityIdScope, SqliteAuthorityStore,
SqliteServingOwnerError,
};
impl chio_kernel::QualifiedAdmissionProjectionStore
for admission_operation_store::SqliteAdmissionOperationStore
{
fn load_payment_journal(
&self,
operation_id: &str,
active_fence: &chio_kernel::admission_operation::StoreMutationFence,
) -> Result<
Option<chio_kernel::payment::PaymentJournalRecord>,
chio_kernel::AdmissionPaymentJournalError,
> {
admission_operation_store::SqliteAdmissionOperationStore::load_payment_journal(
self,
operation_id,
active_fence,
)
}
fn advance_payment_journal(
&self,
advance: chio_kernel::AdmissionPaymentJournalAdvance<'_>,
) -> Result<chio_kernel::payment::PaymentJournalRecord, chio_kernel::AdmissionPaymentJournalError>
{
admission_operation_store::SqliteAdmissionOperationStore::advance_payment_journal(
self, advance,
)
}
fn begin_payment_settlement(
&self,
begin: chio_kernel::AdmissionPaymentSettlementBegin<'_>,
) -> Result<chio_kernel::AdmissionPaymentSettlement, chio_kernel::AdmissionPaymentJournalError>
{
admission_operation_store::SqliteAdmissionOperationStore::begin_payment_settlement(
self, begin,
)
}
fn authorize_budget_and_commit_admission(
&self,
operation: &chio_kernel::admission_operation::AdmissionOperationV1,
recovery_lease: &chio_kernel::admission_operation::AdmissionRecoveryLease,
request: chio_kernel::budget_store::BudgetAuthorizeHoldRequest,
payment_journal: Option<chio_kernel::payment::PaymentJournalRecord>,
credit_exposure: Option<chio_kernel::CreditExposureReservationRequest>,
active_fence: &chio_kernel::admission_operation::StoreMutationFence,
trusted_now_unix_ms: u64,
) -> Result<
chio_kernel::AdmissionBudgetAuthorization,
chio_kernel::AdmissionBudgetAuthorizationError,
> {
admission_operation_store::SqliteAdmissionOperationStore::authorize_budget_and_commit_admission(
self,
operation,
recovery_lease,
request,
payment_journal,
credit_exposure,
active_fence,
trusted_now_unix_ms,
)
.map(|(decision, operation)| chio_kernel::AdmissionBudgetAuthorization {
decision,
operation,
})
.map_err(|error| match error {
chio_kernel::admission_operation::AdmissionCaptureError::Unavailable(detail) => {
chio_kernel::AdmissionBudgetAuthorizationError::Unavailable(detail)
}
chio_kernel::admission_operation::AdmissionCaptureError::Fenced => {
chio_kernel::AdmissionBudgetAuthorizationError::Fenced
}
chio_kernel::admission_operation::AdmissionCaptureError::OutcomeUnknown(detail) => {
chio_kernel::AdmissionBudgetAuthorizationError::OutcomeUnknown(detail)
}
chio_kernel::admission_operation::AdmissionCaptureError::Invariant(detail) => {
chio_kernel::AdmissionBudgetAuthorizationError::Invariant(detail)
}
chio_kernel::admission_operation::AdmissionCaptureError::Operation(error) => {
chio_kernel::AdmissionBudgetAuthorizationError::Operation(error)
}
})
}
fn capture_invocation_and_commit_dispatch(
&self,
operation: &chio_kernel::admission_operation::AdmissionOperationV1,
recovery_lease: &chio_kernel::admission_operation::AdmissionRecoveryLease,
request: chio_kernel::budget_store::BudgetCaptureInvocationRequest,
active_fence: &chio_kernel::admission_operation::StoreMutationFence,
trusted_now_unix_ms: u64,
) -> Result<
chio_kernel::AdmissionBudgetCapture,
chio_kernel::admission_operation::AdmissionCaptureError,
> {
admission_operation_store::SqliteAdmissionOperationStore::capture_invocation_and_commit_dispatch(
self,
operation,
recovery_lease,
request,
active_fence,
trusted_now_unix_ms,
)
.map(|(decision, operation)| chio_kernel::AdmissionBudgetCapture {
decision,
operation,
})
}
fn reserve_threshold_approval_and_commit_admission(
&self,
command: &chio_kernel::admission_operation::AdmissionOperationCommand,
reservation: &chio_kernel::ThresholdApprovalReplayReservationV1,
trusted_now_unix_ms: u64,
) -> Result<
chio_kernel::admission_operation::AdmissionCommandResult,
chio_kernel::admission_operation::AdmissionOperationStoreError,
> {
admission_operation_store::SqliteAdmissionOperationStore::reserve_threshold_approval_and_commit_admission(
self,
command,
reservation,
trusted_now_unix_ms,
)
}
fn list_admission_receipts_after(
&self,
after_receipt_id: Option<&str>,
limit: usize,
) -> Result<Vec<chio_core::receipt::body::ChioReceipt>, chio_kernel::ReceiptStoreError> {
self.list_terminal_receipts_after(after_receipt_id, limit)
}
}
impl chio_credit::obligation::CreditAdmissionStore
for admission_operation_store::SqliteAdmissionOperationStore
{
fn lookup_record_by_operation(
&self,
operation_id: &str,
) -> Result<
Option<chio_credit::obligation::CreditExposureReservationRecordV1>,
chio_credit::obligation::CreditAdmissionError,
> {
self.load_credit_exposure_reservation(operation_id)
.map_err(|error| {
chio_credit::obligation::CreditAdmissionError::Store(error.to_string())
})
}
}
impl chio_kernel::receipt_store::AnchoredAdmissionProjectionStore
for admission_operation_store::SqliteAdmissionOperationStore
{
fn stage_anchored_terminal_projection(
&self,
advance: &chio_core::economic_continuity::VerifiedEconomicStateBatchAdvance,
recovery_lease: &chio_kernel::admission_operation::AdmissionRecoveryLease,
envelope: &chio_kernel::admission_operation::SignedAdmissionTerminalProjectionV1,
active_fence: &chio_kernel::admission_operation::StoreMutationFence,
trusted_now_unix_ms: u64,
) -> Result<(), chio_kernel::ReceiptStoreError> {
admission_operation_store::SqliteAdmissionOperationStore::stage_anchored_terminal_projection(
self,
advance,
recovery_lease,
envelope,
active_fence,
trusted_now_unix_ms,
)
.map_err(admission_operation_store::receipt_projection_error)
}
fn qualify_anchored_terminal_projection(
&self,
batch_id: &str,
active_fence: &chio_kernel::admission_operation::StoreMutationFence,
trusted_now_unix_ms: u64,
) -> Result<(), chio_kernel::ReceiptStoreError> {
admission_operation_store::SqliteAdmissionOperationStore::qualify_anchored_terminal_projection(
self,
batch_id,
active_fence,
trusted_now_unix_ms,
)
.map_err(admission_operation_store::receipt_projection_error)
}
fn record_anchored_terminal_projection(
&self,
advance: &chio_core::economic_continuity::VerifiedEconomicStateBatchAdvance,
committed: &chio_core::economic_continuity::VerifiedEconomicStateView,
pins: &chio_core::economic_continuity::EconomicStateAnchorPins,
active_fence: &chio_kernel::admission_operation::StoreMutationFence,
trusted_now_unix_ms: u64,
) -> Result<(), chio_kernel::ReceiptStoreError> {
admission_operation_store::SqliteAdmissionOperationStore::record_anchored_terminal_projection(
self,
advance,
committed,
pins,
active_fence,
trusted_now_unix_ms,
)
.map_err(admission_operation_store::receipt_projection_error)
}
fn commit_anchored_terminal_projection(
&self,
batch_id: &str,
active_fence: &chio_kernel::admission_operation::StoreMutationFence,
trusted_now_unix_ms: u64,
) -> Result<chio_kernel::admission_operation::AdmissionTerminal, chio_kernel::ReceiptStoreError>
{
admission_operation_store::SqliteAdmissionOperationStore::commit_anchored_terminal_projection(
self,
batch_id,
active_fence,
trusted_now_unix_ms,
)
.map_err(admission_operation_store::receipt_projection_error)
}
}
pub use settle_attempts::{SqliteSettlementOutcomeStore, SETTLE_ATTEMPTS_MIGRATION};
pub use tool_outcome_store::SqliteToolOutcomeStore;
#[cfg(test)]
mod tests {
use super::{is_in_memory_sqlite_path, sqlite_parent_dir_to_create};
use std::path::{Path, PathBuf};
#[test]
fn resolves_parent_dir_from_file_uris_and_plain_paths() {
assert_eq!(
sqlite_parent_dir_to_create(Path::new(
"file:/var/lib/chio/receipts.db.revocations?mode=rwc"
)),
Some(PathBuf::from("/var/lib/chio"))
);
assert_eq!(
sqlite_parent_dir_to_create(Path::new("file:///var/lib/chio/db?cache=shared")),
Some(PathBuf::from("/var/lib/chio"))
);
assert_eq!(
sqlite_parent_dir_to_create(Path::new("/var/lib/chio/receipts.db")),
Some(PathBuf::from("/var/lib/chio"))
);
assert_eq!(sqlite_parent_dir_to_create(Path::new("receipts.db")), None);
assert_eq!(
sqlite_parent_dir_to_create(Path::new("file:receipts.db?mode=rwc")),
None
);
assert_eq!(sqlite_parent_dir_to_create(Path::new(":memory:")), None);
assert_eq!(
sqlite_parent_dir_to_create(Path::new("file:receipts.db?mode=memory")),
None
);
}
#[test]
fn classifies_in_memory_sqlite_paths() {
for path in [
":memory:",
":MEMORY:",
"file::memory:",
"file:receipts.db?mode=memory",
"file:receipts.db?cache=shared&mode=memory",
] {
assert!(
is_in_memory_sqlite_path(path),
"{path} must classify as in-memory"
);
}
}
#[test]
fn classifies_durable_sqlite_paths() {
for path in [
"receipts.db",
"/var/lib/chio/receipts.db",
"file:/var/lib/chio/receipts.db?mode=rwc",
"file:receipts.db",
"memory-notes.db",
] {
assert!(
!is_in_memory_sqlite_path(path),
"{path} must classify as durable"
);
}
}
}