lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

commit 6d5823cbb6da79f9490414be91881cf9181729d8
parent 311fac6626bfdfb14f49d50f1cd4c78b82f51e49
Author: triesap <tyson@radroots.org>
Date:   Sun, 14 Jun 2026 01:30:38 -0700

outbox: remove concrete key signing orchestration

- remove the public claimed-event signing helper from outbox
- keep complete_signing as the state-machine boundary for signed events
- update outbox and relay transport tests to pre-sign drafts directly
- validate outbox, relay transport, and authority check and test lanes

Diffstat:
Mcrates/outbox/Cargo.toml | 8++++----
Mcrates/outbox/src/error.rs | 3---
Mcrates/outbox/src/store.rs | 71++++++++++++++++++++++++++++++-----------------------------------------
Mcrates/relay_transport/tests/transport.rs | 45+++++++++++++++++++++++++++------------------
4 files changed, 61 insertions(+), 66 deletions(-)

diff --git a/crates/outbox/Cargo.toml b/crates/outbox/Cargo.toml @@ -26,10 +26,6 @@ radroots_event_store = { workspace = true, default-features = false, features = "sqlite", "runtime-tokio", ] } -radroots_nostr = { workspace = true, default-features = false, features = [ - "std", - "events", -] } hex = { workspace = true } serde = { workspace = true, features = ["std"] } serde_json = { workspace = true, features = ["std"] } @@ -38,4 +34,8 @@ sqlx = { workspace = true, optional = true, features = ["derive"] } thiserror = { workspace = true } [dev-dependencies] +radroots_nostr = { workspace = true, default-features = false, features = [ + "std", + "events", +] } tokio = { workspace = true, features = ["macros", "rt"] } diff --git a/crates/outbox/src/error.rs b/crates/outbox/src/error.rs @@ -10,9 +10,6 @@ pub enum RadrootsOutboxError { #[error("JSON error: {0}")] Json(#[from] serde_json::Error), - #[error("Nostr error: {0}")] - Nostr(#[from] radroots_nostr::prelude::RadrootsNostrError), - #[error("Event store error: {0}")] EventStore(#[from] radroots_event_store::RadrootsEventStoreError), diff --git a/crates/outbox/src/store.rs b/crates/outbox/src/store.rs @@ -11,7 +11,6 @@ use crate::model::{ use radroots_event_store::{RadrootsEventIngest, RadrootsEventStore}; use radroots_events::RadrootsNostrEvent; use radroots_events::draft::{RadrootsFrozenEventDraft, RadrootsSignedNostrEvent}; -use radroots_nostr::prelude::{RadrootsNostrKeys, radroots_nostr_sign_frozen_draft}; use serde::Serialize; use sha2::{Digest, Sha256}; use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions, SqliteQueryResult}; @@ -290,25 +289,6 @@ impl RadrootsOutbox { Ok(signed_event) } - pub async fn sign_claimed_event( - &self, - claimed: &RadrootsOutboxClaimedEvent, - keys: &RadrootsNostrKeys, - now_ms: i64, - ) -> Result<RadrootsSignedNostrEvent, RadrootsOutboxError> { - if let Some(signed_event) = claimed.signed_event.clone() { - return Ok(signed_event); - } - let signed_event = radroots_nostr_sign_frozen_draft(keys, &claimed.draft)?; - self.complete_signing( - claimed.outbox_event_id, - claimed.claim_token.as_str(), - signed_event, - now_ms, - ) - .await - } - pub async fn mark_sign_retryable( &self, outbox_event_id: i64, @@ -992,7 +972,9 @@ fn bool_i64(value: bool) -> i64 { mod tests { use super::*; use radroots_events::kinds::KIND_POST; - use radroots_nostr::prelude::RadrootsNostrSecretKey; + use radroots_nostr::prelude::{ + RadrootsNostrKeys, RadrootsNostrSecretKey, radroots_nostr_sign_frozen_draft, + }; const FIXTURE_ALICE_SECRET_KEY_HEX: &str = "10c5304d6c9ae3a1a16f7860f1cc8f5e3a76225a2663b3a989a0d775919b7df5"; @@ -1055,6 +1037,28 @@ mod tests { (receipt, claimed) } + async fn complete_claimed_signing( + outbox: &RadrootsOutbox, + claimed: &RadrootsOutboxClaimedEvent, + keys: &RadrootsNostrKeys, + now_ms: i64, + ) -> RadrootsSignedNostrEvent { + if let Some(signed_event) = claimed.signed_event.clone() { + return signed_event; + } + let signed_event = + radroots_nostr_sign_frozen_draft(keys, &claimed.draft).expect("signed event"); + outbox + .complete_signing( + claimed.outbox_event_id, + claimed.claim_token.as_str(), + signed_event, + now_ms, + ) + .await + .expect("complete signing") + } + async fn table_count(outbox: &RadrootsOutbox, table_name: &str) -> i64 { let sql = format!("SELECT COUNT(*) FROM {table_name}"); sqlx::query_scalar(sql.as_str()) @@ -1363,10 +1367,7 @@ mod tests { .await .expect("claim") .expect("claim"); - let signed = outbox - .sign_claimed_event(&first_claim, &fixture_keys(), 1_050) - .await - .expect("sign"); + let signed = complete_claimed_signing(&outbox, &first_claim, &fixture_keys(), 1_050).await; outbox.recover_expired_claims(1_101).await.expect("recover"); let second_claim = outbox .claim_next_ready_event("worker-b", "claim-b", 1_500, 1_200) @@ -1430,10 +1431,7 @@ mod tests { let (receipt, claimed) = enqueue_signed_fixture(&outbox).await; let keys = fixture_keys(); - let signed = outbox - .sign_claimed_event(&claimed, &keys, 1_100) - .await - .expect("sign"); + let signed = complete_claimed_signing(&outbox, &claimed, &keys, 1_100).await; assert_eq!(signed.id, receipt.expected_event_id); let recovered = outbox.recover_expired_claims(2_001).await.expect("recover"); @@ -1447,10 +1445,7 @@ mod tests { assert_eq!(publish_claim.state, RadrootsOutboxEventState::Publishing); assert_eq!(publish_claim.signed_event.as_ref(), Some(&signed)); - let reused = outbox - .sign_claimed_event(&publish_claim, &keys, 2_200) - .await - .expect("reuse signed event"); + let reused = complete_claimed_signing(&outbox, &publish_claim, &keys, 2_200).await; assert_eq!(reused, signed); let event = outbox @@ -1470,10 +1465,7 @@ mod tests { .expect("event store"); let (receipt, claimed) = enqueue_signed_fixture(&outbox).await; let keys = fixture_keys(); - let signed = outbox - .sign_claimed_event(&claimed, &keys, 1_100) - .await - .expect("sign"); + let signed = complete_claimed_signing(&outbox, &claimed, &keys, 1_100).await; let first = outbox .ingest_signed_event_local(&event_store, receipt.outbox_event_id, "claim-a", 1_200) @@ -1646,10 +1638,7 @@ mod tests { .await .expect("claim") .expect("claim"); - outbox - .sign_claimed_event(&sign_claim, &fixture_keys(), 1_100) - .await - .expect("sign"); + complete_claimed_signing(&outbox, &sign_claim, &fixture_keys(), 1_100).await; outbox.recover_expired_claims(2_001).await.expect("recover"); outbox .claim_next_ready_event("publisher", "publish-a", 3_000, 2_100) diff --git a/crates/relay_transport/tests/transport.rs b/crates/relay_transport/tests/transport.rs @@ -7,8 +7,8 @@ use radroots_nostr::prelude::{ radroots_nostr_sign_frozen_draft, }; use radroots_outbox::{ - RadrootsOutbox, RadrootsOutboxEventState, RadrootsOutboxOperationInput, - RadrootsOutboxOperationStatus, RadrootsOutboxRelayStatus, + RadrootsOutbox, RadrootsOutboxClaimedEvent, RadrootsOutboxEventState, + RadrootsOutboxOperationInput, RadrootsOutboxOperationStatus, RadrootsOutboxRelayStatus, }; use radroots_relay_transport::{ RadrootsMockRelayFetchAdapter, RadrootsMockRelayPublishAdapter, RadrootsOutboxPublishPolicy, @@ -45,6 +45,27 @@ fn signed_post(content: &str) -> RadrootsSignedNostrEvent { radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed event") } +async fn complete_claimed_signing( + outbox: &RadrootsOutbox, + claimed: &RadrootsOutboxClaimedEvent, + now_ms: i64, +) -> RadrootsSignedNostrEvent { + if let Some(signed_event) = claimed.signed_event.clone() { + return signed_event; + } + let signed_event = + radroots_nostr_sign_frozen_draft(&fixture_keys(), &claimed.draft).expect("signed event"); + outbox + .complete_signing( + claimed.outbox_event_id, + claimed.claim_token.as_str(), + signed_event, + now_ms, + ) + .await + .expect("complete signing") +} + fn unsupported_raw_event() -> String { let event = radroots_nostr_build_event(999, "unsupported", Vec::new()) .expect("event builder") @@ -413,10 +434,7 @@ async fn outbox_publish_persists_partial_success_and_skips_accepted_retry() { .await .expect("claim") .expect("claim"); - let signed = outbox - .sign_claimed_event(&claimed, &fixture_keys(), 1_100) - .await - .expect("sign"); + let signed = complete_claimed_signing(&outbox, &claimed, 1_100).await; outbox.recover_expired_claims(2_001).await.expect("recover"); let publish_claim = outbox .claim_next_ready_event("publisher", "publish-a", 3_000, 2_100) @@ -557,10 +575,7 @@ async fn outbox_publish_marks_published_without_adapter_when_all_relays_already_ .await .expect("claim") .expect("claim"); - let signed = outbox - .sign_claimed_event(&claimed, &fixture_keys(), 1_100) - .await - .expect("sign"); + let signed = complete_claimed_signing(&outbox, &claimed, 1_100).await; outbox.recover_expired_claims(2_001).await.expect("recover"); let publish_claim = outbox .claim_next_ready_event("publisher", "publish-a", 3_000, 2_100) @@ -655,10 +670,7 @@ async fn outbox_publish_uses_persisted_accepted_count_for_explicit_quorum() { .await .expect("claim") .expect("claim"); - outbox - .sign_claimed_event(&claimed, &fixture_keys(), 1_100) - .await - .expect("sign"); + complete_claimed_signing(&outbox, &claimed, 1_100).await; outbox.recover_expired_claims(2_001).await.expect("recover"); let publish_claim = outbox .claim_next_ready_event("publisher", "publish-a", 3_000, 2_100) @@ -755,10 +767,7 @@ async fn outbox_publish_marks_published_when_policy_quorum_is_met_with_failure_d .await .expect("claim") .expect("claim"); - let signed = outbox - .sign_claimed_event(&claimed, &fixture_keys(), 1_100) - .await - .expect("sign"); + let signed = complete_claimed_signing(&outbox, &claimed, 1_100).await; outbox.recover_expired_claims(2_001).await.expect("recover"); let publish_claim = outbox .claim_next_ready_event("publisher", "publish-a", 3_000, 2_100)