commit ede93b05499af38054f92f827207a37a2d190cdc
parent 52be745797061ad23fe82f77470dcd58cbb5bcf0
Author: triesap <tyson@radroots.org>
Date: Sun, 5 Jul 2026 05:13:51 +0000
status: expose storage checkpoint evidence
- add WAL checkpoint metrics to SDK storage status receipts
- surface checkpoint completeness through public runtime DTOs
- cover memory and directory storage status assertions
- gate relay-only helpers out of narrow performance builds
Diffstat:
6 files changed, 276 insertions(+), 63 deletions(-)
diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs
@@ -162,7 +162,8 @@ pub use crate::runtime::{
RadrootsSdkTimestamp, RestoreArchive, RestoreReceipt, RestoreRequest, SdkBackupManifest,
SdkBackupManifestKind, SdkBackupState, SdkBackupVerification, SdkEventStoreStorageStatus,
SdkOutboxStorageStatus, SdkPrivateStoreStorageStatus, SdkPublishTransport, SdkRestoreState,
- SdkSqliteStoreStatus, SdkStorageKind, StorageStatusReceipt, StorageStatusRequest,
+ SdkSqliteStoreStatus, SdkSqliteWalCheckpointStatus, SdkStorageKind, StorageStatusReceipt,
+ StorageStatusRequest,
};
#[cfg(all(feature = "runtime", feature = "signer-adapters"))]
pub use crate::signer_provider::{
diff --git a/crates/sdk/src/orders_runtime.rs b/crates/sdk/src/orders_runtime.rs
@@ -1,11 +1,11 @@
#[cfg(feature = "signer-adapters")]
use crate::TradeBuyerClient;
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
use crate::runtime::sdk_now_ms;
#[cfg(feature = "runtime")]
-use crate::sync_runtime::{
- SyncProjectionRefreshReceipt, SyncProjectionRefreshRequest, refresh_product_projections_for_sdk,
-};
+use crate::sync_runtime::SyncProjectionRefreshReceipt;
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
+use crate::sync_runtime::{SyncProjectionRefreshRequest, refresh_product_projections_for_sdk};
#[cfg(feature = "signer-adapters")]
use crate::workflow_runtime::enqueue_configured_signed_workflow;
#[cfg(any(feature = "signer-adapters", test))]
@@ -26,19 +26,21 @@ use crate::{SdkRelayUrlPolicy, workflow_runtime::enqueue_signed_workflow};
use radroots_authority::RadrootsActorContext;
#[cfg(all(feature = "runtime", test))]
use radroots_authority::RadrootsEventSigner;
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
+use radroots_event_store::RadrootsStoredEventTag;
#[cfg(feature = "runtime")]
-use radroots_event_store::{RadrootsEventIngest, RadrootsStoredEvent, RadrootsStoredEventTag};
+use radroots_event_store::{RadrootsEventIngest, RadrootsStoredEvent};
#[cfg(feature = "runtime")]
use radroots_events::{
RadrootsNostrEvent,
contract::RadrootsActorRole,
ids::RadrootsEventId,
kinds::{
- KIND_LISTING, KIND_ORDER_CANCELLATION, KIND_ORDER_DECISION, KIND_ORDER_REQUEST,
+ KIND_ORDER_CANCELLATION, KIND_ORDER_DECISION, KIND_ORDER_REQUEST,
KIND_ORDER_REVISION_DECISION, KIND_ORDER_REVISION_PROPOSAL,
KIND_TRADE_TRANSITION_PROOF_RESULT, KIND_TRADE_VALIDATION_RECEIPT,
},
- tags::{TAG_D, TAG_E, TAG_P},
+ tags::TAG_P,
};
#[cfg(any(feature = "signer-adapters", test))]
use radroots_events::{
@@ -56,6 +58,11 @@ use radroots_events::{
ids::{RadrootsListingAddress, RadrootsOrderId, RadrootsPublicKey},
order::RadrootsOrderEconomics,
};
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
+use radroots_events::{
+ kinds::KIND_LISTING,
+ tags::{TAG_D, TAG_E},
+};
#[cfg(feature = "runtime")]
use radroots_events_codec::order::{
order_cancellation_from_event, order_decision_from_event, order_request_from_event,
@@ -68,7 +75,7 @@ use radroots_nostr::prelude::{
RadrootsNostrEventId, RadrootsNostrFilter, RadrootsNostrKind, RadrootsNostrPublicKey,
radroots_nostr_filter_tag,
};
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
use radroots_relay_transport::{
RadrootsNostrClientFetchAdapter, RadrootsRelayFetchAdapter, RadrootsRelayFetchEventReceipt,
RadrootsRelayFetchOutcomeKind, RadrootsRelayFetchReceipt, RadrootsRelayFetchRelayOutcome,
@@ -78,7 +85,7 @@ use radroots_relay_transport::{
use radroots_trade::dvm::RADROOTS_DVM_TAG_VALIDATION_RECEIPT;
#[cfg(feature = "runtime")]
use radroots_trade::identity::{RadrootsTradeLocator, RadrootsTradeLocatorCandidate};
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
use radroots_trade::listing::parse_listing_address;
#[cfg(any(feature = "signer-adapters", test))]
use radroots_trade::order::{
@@ -93,14 +100,15 @@ use radroots_trade::order::{
RadrootsTradeLocatorProjectionResolution, order_event_record_from_event,
order_projection_query_for_trade_locator,
};
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
+use radroots_trade::validation_receipt::RadrootsValidationReceiptError;
#[cfg(feature = "runtime")]
use radroots_trade::validation_receipt::{
RadrootsTradeCommitmentConfidence, RadrootsTradeValidationAuthority,
RadrootsTradeValidationReceipt, RadrootsTradeValidationTrustPolicy,
- RadrootsTradeValidationTrustState, RadrootsValidationReceiptError,
- RadrootsValidationReceiptExpectedBinding, RadrootsValidationReceiptProofSystem,
- RadrootsValidationReceiptResult, RadrootsValidationReceiptTags,
- verify_validation_receipt_event,
+ RadrootsTradeValidationTrustState, RadrootsValidationReceiptExpectedBinding,
+ RadrootsValidationReceiptProofSystem, RadrootsValidationReceiptResult,
+ RadrootsValidationReceiptTags, verify_validation_receipt_event,
};
#[cfg(feature = "runtime")]
use radroots_trade::workflow::RadrootsTradeWorkflowState;
@@ -1540,6 +1548,7 @@ impl TradeResyncRequest {
Ok(self)
}
+ #[cfg(feature = "relay-runtime")]
fn validate(&self) -> Result<(), RadrootsSdkError> {
if self.limit == 0 || self.limit > TRADE_STATUS_MAX_LIMIT {
return Err(RadrootsSdkError::trade_status_limit_invalid(
@@ -1742,6 +1751,7 @@ impl TradeValidationReceiptListRequest {
Ok(self)
}
+ #[cfg(feature = "relay-runtime")]
fn validate(&self) -> Result<(), RadrootsSdkError> {
validate_validation_receipt_limit(self.limit)
}
@@ -3525,6 +3535,7 @@ impl<'sdk> TradeResyncClient<'sdk> {
}
#[cfg(not(feature = "relay-runtime"))]
{
+ let _ = self.sdk;
let _ = request;
Err(RadrootsSdkError::ProductSyncUnsupported {
operation: "trade.resync",
@@ -3647,7 +3658,7 @@ fn trade_evidence_fetch_request(
)
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
fn trade_evidence_query_plan(
locator: RadrootsTradeLocator,
limit: u32,
@@ -3720,7 +3731,7 @@ fn trade_evidence_query_plan(
})
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
fn trade_evidence_branch(
kind: TradeEvidenceQueryBranchKind,
event_kinds: Vec<u32>,
@@ -3788,13 +3799,13 @@ fn trade_evidence_branch_filter(
}
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
struct ListingSnapshotFilterParts {
seller_pubkey: String,
listing_id: String,
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
fn listing_snapshot_filter_parts(
listing_addr: &str,
) -> Result<ListingSnapshotFilterParts, RadrootsSdkError> {
@@ -3808,7 +3819,7 @@ fn listing_snapshot_filter_parts(
})
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
fn trade_resync_total_relay_failure(
receipt: &RadrootsRelayFetchReceipt,
relay_count: usize,
@@ -3816,7 +3827,7 @@ fn trade_resync_total_relay_failure(
relay_count > 0 && receipt.eose_count == 0 && receipt.closed_count >= relay_count
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
fn trade_resync_total_failure_message(
operation: &str,
receipt: &RadrootsRelayFetchReceipt,
@@ -3827,7 +3838,7 @@ fn trade_resync_total_failure_message(
)
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
impl TradeResyncEvidenceReceipt {
async fn from_fetch(
sdk: &crate::RadrootsClient,
@@ -3865,7 +3876,7 @@ impl TradeResyncEvidenceReceipt {
}
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
async fn trade_evidence_branch_receipts(
sdk: &crate::RadrootsClient,
query_plan: &TradeEvidenceQueryPlan,
@@ -3902,7 +3913,7 @@ async fn trade_evidence_branch_receipts(
.collect())
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
async fn trade_evidence_event_branch(
sdk: &crate::RadrootsClient,
query_plan: &TradeEvidenceQueryPlan,
@@ -3940,7 +3951,7 @@ async fn trade_evidence_event_branch(
.unwrap_or(TradeEvidenceQueryBranchKind::RejectedEvidence))
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
fn trade_evidence_branch_matches_event(
branch: &TradeEvidenceQueryBranch,
stored_event: &RadrootsStoredEvent,
@@ -3966,7 +3977,7 @@ fn trade_evidence_branch_matches_event(
}
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
impl TradeEvidenceBranchReceipt {
fn from_parts(
branch: TradeEvidenceQueryBranchKind,
@@ -4016,7 +4027,7 @@ impl TradeEvidenceBranchReceipt {
}
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
impl From<RadrootsRelayFetchEventReceipt> for TradeResyncEventImportReceipt {
fn from(receipt: RadrootsRelayFetchEventReceipt) -> Self {
Self {
@@ -4035,7 +4046,7 @@ impl From<RadrootsRelayFetchEventReceipt> for TradeResyncEventImportReceipt {
}
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
impl From<RadrootsRelayFetchRelayOutcome> for TradeResyncRelayOutcomeReceipt {
fn from(receipt: RadrootsRelayFetchRelayOutcome) -> Self {
Self {
@@ -4047,7 +4058,7 @@ impl From<RadrootsRelayFetchRelayOutcome> for TradeResyncRelayOutcomeReceipt {
}
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
impl From<RadrootsRelayFetchOutcomeKind> for TradeResyncRelayOutcomeKind {
fn from(kind: RadrootsRelayFetchOutcomeKind) -> Self {
match kind {
@@ -4058,7 +4069,7 @@ impl From<RadrootsRelayFetchOutcomeKind> for TradeResyncRelayOutcomeKind {
}
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
impl From<RadrootsRelayOutcomeKind> for TradeResyncRelayTransportOutcomeKind {
fn from(kind: RadrootsRelayOutcomeKind) -> Self {
match kind {
@@ -4096,6 +4107,7 @@ impl<'sdk> TradeValidationReceiptsClient<'sdk> {
}
#[cfg(not(feature = "relay-runtime"))]
{
+ let _ = self.sdk;
let _ = request;
Err(RadrootsSdkError::ProductSyncUnsupported {
operation: "trade.validation_receipts.list",
@@ -4159,6 +4171,7 @@ impl<'sdk> TradeValidationReceiptsClient<'sdk> {
}
#[cfg(not(feature = "relay-runtime"))]
{
+ let _ = self.sdk;
let _ = request;
Err(RadrootsSdkError::ProductSyncUnsupported {
operation: "trade.validation_receipts.inspect",
@@ -4197,6 +4210,7 @@ impl<'sdk> TradeValidationReceiptsClient<'sdk> {
}
#[cfg(not(feature = "relay-runtime"))]
{
+ let _ = self.sdk;
let _ = request;
Err(RadrootsSdkError::ProductSyncUnsupported {
operation: "trade.validation_receipts.verify",
@@ -4270,7 +4284,7 @@ where
})
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
fn validation_receipt_relay_targets(
sdk: &crate::RadrootsClient,
operation: impl Into<String>,
@@ -4361,7 +4375,7 @@ fn validation_receipt_worker_fetch_request(
))
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
async fn validation_receipt_events_from_fetch(
sdk: &crate::RadrootsClient,
events: &[TradeResyncEventImportReceipt],
@@ -4395,7 +4409,7 @@ async fn validation_receipt_events_from_fetch(
Ok(fetched)
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
fn classify_validation_receipts(
events: Vec<RadrootsNostrEvent>,
expected_order_id: Option<&str>,
@@ -5075,7 +5089,7 @@ struct RawTradeValidationReceiptWorkerResult {
worker_role: Option<String>,
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
impl TradeValidationReceiptRelayEvidenceReceipt {
fn from_fetch(receipt: RadrootsRelayFetchReceipt) -> Self {
Self {
@@ -5094,7 +5108,7 @@ impl TradeValidationReceiptRelayEvidenceReceipt {
}
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
impl From<RadrootsRelayFetchRelayOutcome> for TradeValidationReceiptRelayOutcomeReceipt {
fn from(receipt: RadrootsRelayFetchRelayOutcome) -> Self {
Self {
@@ -5106,7 +5120,7 @@ impl From<RadrootsRelayFetchRelayOutcome> for TradeValidationReceiptRelayOutcome
}
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
impl From<RadrootsRelayFetchOutcomeKind> for TradeValidationReceiptRelayOutcomeKind {
fn from(kind: RadrootsRelayFetchOutcomeKind) -> Self {
match kind {
@@ -5117,7 +5131,7 @@ impl From<RadrootsRelayFetchOutcomeKind> for TradeValidationReceiptRelayOutcomeK
}
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
impl From<RadrootsRelayOutcomeKind> for TradeValidationReceiptRelayTransportOutcomeKind {
fn from(kind: RadrootsRelayOutcomeKind) -> Self {
match kind {
@@ -5182,7 +5196,7 @@ fn stored_event_to_nostr_event(
})
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
fn validation_receipt_event_order(
left: &TradeValidationReceiptEvent,
right: &TradeValidationReceiptEvent,
@@ -5193,7 +5207,7 @@ fn validation_receipt_event_order(
.then_with(|| left.event.id.cmp(&right.event.id))
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
fn validation_receipt_invalid_order(
left: &TradeValidationReceiptInvalidCandidate,
right: &TradeValidationReceiptInvalidCandidate,
@@ -5204,7 +5218,7 @@ fn validation_receipt_invalid_order(
.then_with(|| left.event.id.cmp(&right.event.id))
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
fn validate_validation_receipt_limit(limit: u32) -> Result<(), RadrootsSdkError> {
if limit == 0 || limit > TRADE_STATUS_MAX_LIMIT {
return Err(RadrootsSdkError::trade_status_limit_invalid(
@@ -5233,7 +5247,7 @@ where
.collect()
}
-#[cfg(feature = "runtime")]
+#[cfg(all(feature = "runtime", feature = "relay-runtime"))]
fn validation_receipt_invalid_reason_code(error: &RadrootsValidationReceiptError) -> &'static str {
match error {
RadrootsValidationReceiptError::InvalidProofMetadata("proof.material")
@@ -6055,7 +6069,7 @@ async fn ingest_explicit_trade_mutation_evidence(
Ok(())
}
-#[cfg(feature = "signer-adapters")]
+#[cfg(all(feature = "signer-adapters", feature = "relay-runtime"))]
fn require_trade_mutation_online_evidence_clean(
operation: &'static str,
status: &TradeStatusReceipt,
diff --git a/crates/sdk/src/runtime.rs b/crates/sdk/src/runtime.rs
@@ -15,7 +15,7 @@ use radroots_event_store::RadrootsEventStore;
#[cfg(feature = "runtime")]
use radroots_outbox::RadrootsOutbox;
#[cfg(feature = "runtime")]
-use sqlx::SqlitePool;
+use sqlx::{Row, SqlitePool};
#[cfg(feature = "runtime")]
use std::{
fs,
@@ -166,12 +166,23 @@ pub struct SdkSqliteStoreStatus {
pub journal_mode: String,
pub foreign_keys_enabled: bool,
pub busy_timeout_ms: i64,
+ pub wal_checkpoint: SdkSqliteWalCheckpointStatus,
pub integrity_ok: bool,
pub integrity_result: String,
}
#[cfg(feature = "runtime")]
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
+pub struct SdkSqliteWalCheckpointStatus {
+ pub wal_enabled: bool,
+ pub busy: i64,
+ pub log_frame_count: i64,
+ pub checkpointed_frame_count: i64,
+ pub checkpoint_complete: bool,
+}
+
+#[cfg(feature = "runtime")]
+#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct SdkEventStoreStorageStatus {
pub store: SdkSqliteStoreStatus,
pub total_events: i64,
@@ -1400,12 +1411,14 @@ async fn sqlite_store_status(
foreign_keys_enabled: bool,
busy_timeout_ms: i64,
) -> Result<SdkSqliteStoreStatus, RadrootsSdkError> {
+ let wal_checkpoint = sqlite_wal_checkpoint_status(pool, &journal_mode).await?;
let integrity = sqlite_integrity_result(pool).await?;
Ok(SdkSqliteStoreStatus {
schema_version,
journal_mode,
foreign_keys_enabled,
busy_timeout_ms,
+ wal_checkpoint,
integrity_ok: integrity.ok,
integrity_result: integrity.result,
})
@@ -1419,18 +1432,107 @@ async fn private_sqlite_store_status(
foreign_keys_enabled: bool,
busy_timeout_ms: i64,
) -> Result<SdkSqliteStoreStatus, RadrootsSdkError> {
+ let wal_checkpoint = private_store_sqlite_wal_checkpoint_status(pool, &journal_mode).await?;
let integrity = private_store_sqlite_integrity_result(pool).await?;
Ok(SdkSqliteStoreStatus {
schema_version,
journal_mode,
foreign_keys_enabled,
busy_timeout_ms,
+ wal_checkpoint,
integrity_ok: integrity.ok,
integrity_result: integrity.result,
})
}
#[cfg(feature = "runtime")]
+async fn sqlite_wal_checkpoint_status(
+ pool: &SqlitePool,
+ journal_mode: &str,
+) -> Result<SdkSqliteWalCheckpointStatus, RadrootsSdkError> {
+ let row = sqlx::query("PRAGMA wal_checkpoint(PASSIVE)")
+ .fetch_one(pool)
+ .await
+ .map_err(|error| RadrootsSdkError::EventStore {
+ message: error.to_string(),
+ })?;
+ let busy = row
+ .try_get(0)
+ .map_err(|error| RadrootsSdkError::EventStore {
+ message: error.to_string(),
+ })?;
+ let log_frame_count = row
+ .try_get(1)
+ .map_err(|error| RadrootsSdkError::EventStore {
+ message: error.to_string(),
+ })?;
+ let checkpointed_frame_count =
+ row.try_get(2)
+ .map_err(|error| RadrootsSdkError::EventStore {
+ message: error.to_string(),
+ })?;
+ Ok(sqlite_wal_checkpoint_status_from_values(
+ journal_mode,
+ busy,
+ log_frame_count,
+ checkpointed_frame_count,
+ ))
+}
+
+#[cfg(feature = "runtime")]
+async fn private_store_sqlite_wal_checkpoint_status(
+ pool: &SqlitePool,
+ journal_mode: &str,
+) -> Result<SdkSqliteWalCheckpointStatus, RadrootsSdkError> {
+ let row = sqlx::query("PRAGMA wal_checkpoint(PASSIVE)")
+ .fetch_one(pool)
+ .await
+ .map_err(|error| RadrootsSdkError::PrivateStore {
+ message: error.to_string(),
+ })?;
+ let busy = row
+ .try_get(0)
+ .map_err(|error| RadrootsSdkError::PrivateStore {
+ message: error.to_string(),
+ })?;
+ let log_frame_count = row
+ .try_get(1)
+ .map_err(|error| RadrootsSdkError::PrivateStore {
+ message: error.to_string(),
+ })?;
+ let checkpointed_frame_count =
+ row.try_get(2)
+ .map_err(|error| RadrootsSdkError::PrivateStore {
+ message: error.to_string(),
+ })?;
+ Ok(sqlite_wal_checkpoint_status_from_values(
+ journal_mode,
+ busy,
+ log_frame_count,
+ checkpointed_frame_count,
+ ))
+}
+
+#[cfg(feature = "runtime")]
+fn sqlite_wal_checkpoint_status_from_values(
+ journal_mode: &str,
+ busy: i64,
+ log_frame_count: i64,
+ checkpointed_frame_count: i64,
+) -> SdkSqliteWalCheckpointStatus {
+ let wal_enabled = journal_mode.eq_ignore_ascii_case("wal");
+ let checkpoint_complete = busy == 0
+ && (!wal_enabled || (log_frame_count >= 0 && log_frame_count == checkpointed_frame_count));
+ SdkSqliteWalCheckpointStatus {
+ wal_enabled,
+ busy,
+ log_frame_count,
+ checkpointed_frame_count,
+ checkpoint_complete,
+ }
+}
+
+#[cfg(feature = "runtime")]
async fn sqlite_integrity_result(
pool: &SqlitePool,
) -> Result<SqliteIntegrityResult, RadrootsSdkError> {
diff --git a/crates/sdk/tests/orders_runtime.rs b/crates/sdk/tests/orders_runtime.rs
@@ -8,19 +8,19 @@ use std::time::{Duration, Instant};
#[cfg(feature = "relay-runtime")]
use futures::future::BoxFuture;
+#[cfg(feature = "relay-runtime")]
use nostr::JsonUtil;
use radroots_authority::RadrootsActorContext;
use radroots_core::{
RadrootsCoreCurrency, RadrootsCoreDecimal, RadrootsCoreMoney, RadrootsCoreUnit,
};
use radroots_event_store::{RadrootsEventIngest, RadrootsEventStore};
+#[cfg(feature = "relay-runtime")]
+use radroots_events::ids::RadrootsPublicKey;
use radroots_events::{
RadrootsNostrEvent, RadrootsNostrEventPtr,
contract::RadrootsActorRole,
- ids::{
- RadrootsEventId, RadrootsListingAddress, RadrootsOrderId, RadrootsOrderRevisionId,
- RadrootsPublicKey,
- },
+ ids::{RadrootsEventId, RadrootsListingAddress, RadrootsOrderId, RadrootsOrderRevisionId},
kinds::{
KIND_LISTING, KIND_ORDER_DECISION, KIND_ORDER_REQUEST, KIND_POST,
KIND_TRADE_TRANSITION_PROOF_RESULT, KIND_TRADE_VALIDATION_RECEIPT,
@@ -38,36 +38,42 @@ use radroots_nostr::prelude::{
radroots_nostr_build_event,
};
use radroots_outbox::RadrootsOutbox;
-use radroots_relay_transport::{RadrootsMockRelayFetchAdapter, RadrootsRelayFetchItem};
#[cfg(feature = "relay-runtime")]
use radroots_relay_transport::{
- RadrootsRelayFetchAdapter, RadrootsRelayFetchRequest, RadrootsRelayTransportError,
+ RadrootsMockRelayFetchAdapter, RadrootsRelayFetchAdapter, RadrootsRelayFetchItem,
+ RadrootsRelayFetchRequest, RadrootsRelayTransportError,
};
use radroots_sdk::{
- AckPolicy, DvmValidationReceiptIngestRequest, PublishMode, RadrootsClient, RadrootsSdkError,
- RadrootsSdkRecoveryAction, RadrootsSdkTimestamp, RadrootsTradeValidationTrustPolicy,
- RadrootsTradeValidationTrustState, RelayResolutionPolicy, SdkMutationState, SdkRelayTargetSet,
- SdkRelayUrlPolicy, SdkTradeStatusIssue, SdkTradeStatusIssueKind, SdkTradeStatusSource,
- TRADE_STATUS_DEFAULT_LIMIT, TRADE_STATUS_MAX_LIMIT, TRADE_STATUS_WATCH_MAX_CAPACITY,
- TRADE_SUBMIT_OPERATION_KIND, TradeAcceptRequest, TradeCancelRequest, TradeDeclineRequest,
- TradeEvidenceIngestRequest, TradeEvidenceMode, TradeEvidenceQueryBranchKind,
- TradeMutationOutcome, TradeProposeRequest, TradeRequestEvidenceIngestRequest,
- TradeResyncRelayOutcomeKind, TradeResyncRelayTransportOutcomeKind, TradeResyncRequest,
- TradeRevisionDecisionRequest, TradeRevisionProposalRequest, TradeSellerInboxRequest,
+ AckPolicy, PublishMode, RadrootsClient, RadrootsSdkError, RadrootsSdkRecoveryAction,
+ RadrootsSdkTimestamp, RadrootsTradeValidationTrustPolicy, RadrootsTradeValidationTrustState,
+ RelayResolutionPolicy, SdkMutationState, SdkRelayTargetSet, SdkRelayUrlPolicy,
+ SdkTradeStatusIssue, SdkTradeStatusIssueKind, SdkTradeStatusSource, TRADE_STATUS_DEFAULT_LIMIT,
+ TRADE_STATUS_MAX_LIMIT, TRADE_STATUS_WATCH_MAX_CAPACITY, TRADE_SUBMIT_OPERATION_KIND,
+ TradeAcceptRequest, TradeCancelRequest, TradeDeclineRequest, TradeEvidenceIngestRequest,
+ TradeEvidenceMode, TradeMutationOutcome, TradeProposeRequest,
+ TradeRequestEvidenceIngestRequest, TradeRevisionDecisionRequest, TradeRevisionProposalRequest,
TradeStatusKind, TradeStatusNextActionKind, TradeStatusRequest, TradeStatusWatchCancelState,
- TradeStatusWatchRequest, TradeValidationReceiptInspectRequest,
- TradeValidationReceiptListRequest, TradeValidationReceiptVerifyRequest,
+ TradeStatusWatchRequest,
+};
+#[cfg(feature = "relay-runtime")]
+use radroots_sdk::{
+ DvmValidationReceiptIngestRequest, TradeEvidenceQueryBranchKind, TradeResyncRelayOutcomeKind,
+ TradeResyncRelayTransportOutcomeKind, TradeResyncRequest, TradeSellerInboxRequest,
+ TradeValidationReceiptInspectRequest, TradeValidationReceiptListRequest,
+ TradeValidationReceiptVerifyRequest,
};
use radroots_sdk::{PrivacyPreflightConfirmation, PrivacyPreflightStatus, ProductSensitivityField};
#[cfg(all(feature = "signer-adapters", feature = "local-signer"))]
use radroots_sdk::{RadrootsSdkLocalKeySigner, RadrootsSdkSignerProvider};
+#[cfg(feature = "relay-runtime")]
+use radroots_trade::identity::RadrootsTradeLocator;
+use radroots_trade::order::RadrootsOrderIssue;
use radroots_trade::validation_receipt::{
RadrootsTradeValidationReceipt, RadrootsValidationReceiptProof,
RadrootsValidationReceiptProofSystem, RadrootsValidationReceiptResult,
RadrootsValidationReceiptStatement, RadrootsValidationReceiptType,
validation_receipt_event_build, validation_receipt_public_values_hash_hex,
};
-use radroots_trade::{identity::RadrootsTradeLocator, order::RadrootsOrderIssue};
use serde::Serialize;
use serde::ser::{self, SerializeStruct};
@@ -85,6 +91,7 @@ const RELAY: &str = "wss://relay.radroots.test";
#[cfg(any())]
const OTHER_PUBLIC_KEY_HEX: &str =
"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc";
+#[cfg(feature = "relay-runtime")]
const RELAY_B: &str = "wss://relay-b.radroots.test";
const PERF_TOTAL_LOCAL_EVENTS: i64 = 100_000;
const PERF_TRADE_RELEVANT_EVENTS: i64 = 25_000;
@@ -455,6 +462,7 @@ async fn directory_sdk_and_store() -> (tempfile::TempDir, RadrootsClient, Radroo
(tempdir, sdk, store)
}
+#[cfg(feature = "relay-runtime")]
async fn directory_sdk_and_store_with_relays(
relays: &[&str],
) -> (tempfile::TempDir, RadrootsClient, RadrootsEventStore) {
@@ -2613,6 +2621,7 @@ async fn trade_resync_reports_partial_relay_failure() {
);
}
+#[cfg(feature = "relay-runtime")]
async fn relay_event_item_from_store(
source: &RadrootsEventStore,
event_id: &RadrootsEventId,
@@ -2645,6 +2654,7 @@ async fn event_from_store(
radroots_event_from_nostr(&event)
}
+#[cfg(feature = "relay-runtime")]
fn relay_raw_event_item(
event: &nostr::Event,
relay_url: &str,
@@ -2657,12 +2667,14 @@ fn relay_raw_event_item(
}
}
+#[cfg(feature = "relay-runtime")]
fn relay_eose(relay_url: &str) -> RadrootsRelayFetchItem {
RadrootsRelayFetchItem::Eose {
relay_url: relay_url.to_owned(),
}
}
+#[cfg(feature = "relay-runtime")]
fn relay_closed(relay_url: &str, message: &str) -> RadrootsRelayFetchItem {
RadrootsRelayFetchItem::Closed {
relay_url: relay_url.to_owned(),
@@ -2670,6 +2682,7 @@ fn relay_closed(relay_url: &str, message: &str) -> RadrootsRelayFetchItem {
}
}
+#[cfg(feature = "relay-runtime")]
fn relay_malformed(relay_url: &str) -> RadrootsRelayFetchItem {
RadrootsRelayFetchItem::Event {
relay_url: relay_url.to_owned(),
@@ -3820,6 +3833,7 @@ fn revision_economics() -> RadrootsOrderEconomics {
}
}
+#[cfg(feature = "relay-runtime")]
fn signed_raw_validation_receipt_event(
raw_order_id: &str,
listing_event_id: &RadrootsEventId,
@@ -3859,6 +3873,7 @@ fn signed_raw_sp1_validation_receipt_event(
)
}
+#[cfg(feature = "relay-runtime")]
fn validation_receipt_wire_parts(
raw_order_id: &str,
listing_event_id: &RadrootsEventId,
@@ -3996,6 +4011,7 @@ fn signed_raw_sp1_worker_result_event(
)
}
+#[cfg(feature = "relay-runtime")]
fn signed_raw_worker_result_event(
raw_order_id: &str,
receipt_event_id: &RadrootsEventId,
@@ -4169,6 +4185,7 @@ fn signed_order_request_event(raw_order_id: &str, created_at: u32) -> RadrootsNo
signed_event(BUYER_SECRET_KEY_HEX, created_at, draft)
}
+#[cfg(feature = "relay-runtime")]
fn signed_raw_order_request_event(raw_order_id: &str, created_at: u32) -> nostr::Event {
let draft = radroots_events_codec::order::order_request_event_build(
&listing_event_ptr(),
diff --git a/crates/sdk/tests/runtime_foundation.rs b/crates/sdk/tests/runtime_foundation.rs
@@ -8,8 +8,8 @@ use radroots_sdk::{
SDK_IDEMPOTENCY_KEY_MAX_LEN, SDK_RELAY_TARGET_MAX_COUNT, SdkBackupState, SdkBackupVerification,
SdkEventStoreStorageStatus, SdkIdempotencyKey, SdkOutboxStorageStatus,
SdkPrivateStoreStorageStatus, SdkRelayTargetPolicy, SdkRelayTargetSet, SdkRelayUrlPolicy,
- SdkRestoreState, SdkSqliteStoreStatus, SdkStorageKind, StorageStatusReceipt,
- StorageStatusRequest,
+ SdkRestoreState, SdkSqliteStoreStatus, SdkSqliteWalCheckpointStatus, SdkStorageKind,
+ StorageStatusReceipt, StorageStatusRequest,
};
use radroots_trade::identity::RadrootsTradeLocator;
use sqlx::Row;
@@ -678,6 +678,13 @@ fn storage_backup_and_integrity_contract_dtos_serialize() {
journal_mode: "wal".to_owned(),
foreign_keys_enabled: true,
busy_timeout_ms: 5_000,
+ wal_checkpoint: SdkSqliteWalCheckpointStatus {
+ wal_enabled: true,
+ busy: 0,
+ log_frame_count: 8,
+ checkpointed_frame_count: 8,
+ checkpoint_complete: true,
+ },
integrity_ok: true,
integrity_result: "ok".to_owned(),
};
@@ -728,6 +735,13 @@ fn storage_backup_and_integrity_contract_dtos_serialize() {
"journal_mode": "wal",
"foreign_keys_enabled": true,
"busy_timeout_ms": 5000,
+ "wal_checkpoint": {
+ "wal_enabled": true,
+ "busy": 0,
+ "log_frame_count": 8,
+ "checkpointed_frame_count": 8,
+ "checkpoint_complete": true
+ },
"integrity_ok": true,
"integrity_result": "ok"
},
@@ -743,6 +757,13 @@ fn storage_backup_and_integrity_contract_dtos_serialize() {
"journal_mode": "wal",
"foreign_keys_enabled": true,
"busy_timeout_ms": 5000,
+ "wal_checkpoint": {
+ "wal_enabled": true,
+ "busy": 0,
+ "log_frame_count": 8,
+ "checkpointed_frame_count": 8,
+ "checkpoint_complete": true
+ },
"integrity_ok": true,
"integrity_result": "ok"
},
@@ -762,6 +783,13 @@ fn storage_backup_and_integrity_contract_dtos_serialize() {
"journal_mode": "wal",
"foreign_keys_enabled": true,
"busy_timeout_ms": 5000,
+ "wal_checkpoint": {
+ "wal_enabled": true,
+ "busy": 0,
+ "log_frame_count": 8,
+ "checkpointed_frame_count": 8,
+ "checkpoint_complete": true
+ },
"integrity_ok": true,
"integrity_result": "ok"
},
diff --git a/crates/sdk/tests/unit/runtime_tests.rs b/crates/sdk/tests/unit/runtime_tests.rs
@@ -45,6 +45,13 @@ fn sqlite_status() -> SdkSqliteStoreStatus {
journal_mode: "wal".to_owned(),
foreign_keys_enabled: true,
busy_timeout_ms: 5_000,
+ wal_checkpoint: SdkSqliteWalCheckpointStatus {
+ wal_enabled: true,
+ busy: 0,
+ log_frame_count: 0,
+ checkpointed_frame_count: 0,
+ checkpoint_complete: true,
+ },
integrity_ok: true,
integrity_result: "ok".to_owned(),
}
@@ -57,6 +64,18 @@ fn private_sqlite_status() -> SdkSqliteStoreStatus {
}
}
+fn assert_wal_checkpoint_ready(status: &SdkSqliteStoreStatus) {
+ assert_eq!(status.journal_mode, "wal");
+ assert!(status.wal_checkpoint.wal_enabled);
+ assert_eq!(status.wal_checkpoint.busy, 0);
+ assert!(status.wal_checkpoint.log_frame_count >= 0);
+ assert_eq!(
+ status.wal_checkpoint.log_frame_count,
+ status.wal_checkpoint.checkpointed_frame_count
+ );
+ assert!(status.wal_checkpoint.checkpoint_complete);
+}
+
fn storage_status() -> StorageStatusReceipt {
StorageStatusReceipt {
storage: SdkStorageKind::Memory,
@@ -360,6 +379,30 @@ async fn runtime_public_surface_covers_builders_status_integrity_backup_and_rest
.await
.expect("memory status");
assert_eq!(memory_status.storage, SdkStorageKind::Memory);
+ assert!(!memory_status.event_store.store.wal_checkpoint.wal_enabled);
+ assert!(!memory_status.outbox.store.wal_checkpoint.wal_enabled);
+ assert!(!memory_status.private_store.store.wal_checkpoint.wal_enabled);
+ assert!(
+ memory_status
+ .event_store
+ .store
+ .wal_checkpoint
+ .checkpoint_complete
+ );
+ assert!(
+ memory_status
+ .outbox
+ .store
+ .wal_checkpoint
+ .checkpoint_complete
+ );
+ assert!(
+ memory_status
+ .private_store
+ .store
+ .wal_checkpoint
+ .checkpoint_complete
+ );
let memory_integrity = memory_sdk
.integrity(IntegrityRequest::new())
.await
@@ -376,6 +419,14 @@ async fn runtime_public_surface_covers_builders_status_integrity_backup_and_rest
.await
.expect("directory sdk");
assert!(directory_sdk.storage_paths().is_some());
+ let directory_status = directory_sdk
+ .storage_status(StorageStatusRequest::new())
+ .await
+ .expect("directory status");
+ assert_eq!(directory_status.storage, SdkStorageKind::Directory);
+ assert_wal_checkpoint_ready(&directory_status.event_store.store);
+ assert_wal_checkpoint_ready(&directory_status.outbox.store);
+ assert_wal_checkpoint_ready(&directory_status.private_store.store);
let backup_destination = tempdir.path().join("backup");
let backup = directory_sdk