commit acf95826e5f5c919b4633bcfc7f52c55b88c4198
parent c180b47d48b1e8efc16ff340be76491588452792
Author: triesap <tyson@radroots.org>
Date: Thu, 7 May 2026 15:54:31 +0000
listing: preserve direct relay signed event
- add the signed Nostr event to direct relay publish receipts
- share signing through one helper before relay connection and publish
- assert receipt parity for event id, signature, timestamp, content, and tags
- update listing and order receipt consumers for the expanded receipt shape
Diffstat:
3 files changed, 66 insertions(+), 7 deletions(-)
diff --git a/src/runtime/direct_relay.rs b/src/runtime/direct_relay.rs
@@ -18,6 +18,7 @@ pub struct DirectRelayFailure {
#[derive(Debug, Clone)]
pub struct DirectRelayPublishReceipt {
+ pub event: RadrootsNostrEvent,
pub event_id: String,
pub created_at: u32,
pub signature: String,
@@ -187,11 +188,7 @@ async fn publish_parts_with_identity_async(
relay_urls: &[String],
parts: WireEventParts,
) -> Result<DirectRelayPublishReceipt, DirectRelayPublishError> {
- let builder = radroots_nostr_build_event(parts.kind, parts.content, parts.tags)
- .map_err(DirectRelayPublishError::Build)?;
- let event = builder
- .sign_with_keys(identity.keys())
- .map_err(|error| DirectRelayPublishError::Sign(error.into()))?;
+ let event = sign_parts_with_identity(identity, parts)?;
let event_id = event.id.to_hex();
let created_at = event_created_at_u32(&event);
let signature = event.sig.to_string();
@@ -245,6 +242,7 @@ async fn publish_parts_with_identity_async(
}
Ok(DirectRelayPublishReceipt {
+ event,
event_id,
created_at,
signature,
@@ -259,6 +257,17 @@ async fn publish_parts_with_identity_async(
})
}
+fn sign_parts_with_identity(
+ identity: &RadrootsIdentity,
+ parts: WireEventParts,
+) -> Result<RadrootsNostrEvent, DirectRelayPublishError> {
+ let builder = radroots_nostr_build_event(parts.kind, parts.content, parts.tags)
+ .map_err(DirectRelayPublishError::Build)?;
+ builder
+ .sign_with_keys(identity.keys())
+ .map_err(|error| DirectRelayPublishError::Sign(error.into()))
+}
+
fn relay_failures_from_output<T: std::fmt::Debug>(
output: &RadrootsNostrOutput<T>,
) -> Vec<DirectRelayFailure> {
@@ -297,8 +306,9 @@ mod tests {
use radroots_nostr::prelude::RadrootsNostrFilter;
use super::{
- DirectRelayFetchError, DirectRelayPublishError, fetch_events_from_relays_async,
- fetch_events_from_relays_with_timeout, publish_parts_with_identity,
+ DirectRelayFetchError, DirectRelayPublishError, event_created_at_u32,
+ fetch_events_from_relays_async, fetch_events_from_relays_with_timeout,
+ publish_parts_with_identity, sign_parts_with_identity,
};
#[test]
@@ -319,6 +329,43 @@ mod tests {
}
#[test]
+ fn direct_relay_signed_event_preserves_publish_receipt_parity() {
+ let identity = RadrootsIdentity::generate();
+ let parts = WireEventParts {
+ kind: 30402,
+ content: "listing".to_owned(),
+ tags: vec![
+ vec!["d".to_owned(), "listing-1".to_owned()],
+ vec!["title".to_owned(), "eggs".to_owned()],
+ ],
+ };
+ let event = sign_parts_with_identity(&identity, parts.clone()).expect("signed event");
+ let receipt = super::DirectRelayPublishReceipt {
+ event: event.clone(),
+ event_id: event.id.to_hex(),
+ created_at: event_created_at_u32(&event),
+ signature: event.sig.to_string(),
+ target_relays: vec!["ws://127.0.0.1:1234".to_owned()],
+ connected_relays: vec!["ws://127.0.0.1:1234".to_owned()],
+ acknowledged_relays: vec!["ws://127.0.0.1:1234".to_owned()],
+ failed_relays: Vec::new(),
+ };
+ let tags = receipt
+ .event
+ .tags
+ .iter()
+ .map(|tag| tag.as_slice().to_vec())
+ .collect::<Vec<_>>();
+
+ assert_eq!(receipt.event_id, receipt.event.id.to_hex());
+ assert_eq!(receipt.signature, receipt.event.sig.to_string());
+ assert_eq!(receipt.created_at, event_created_at_u32(&receipt.event));
+ assert_eq!(receipt.event.kind.as_u16() as u32, parts.kind);
+ assert_eq!(receipt.event.content, parts.content);
+ assert_eq!(tags, parts.tags);
+ }
+
+ #[test]
fn fetch_events_requires_relays_before_runtime_work() {
let err = fetch_events_from_relays_with_timeout(
&[],
diff --git a/src/runtime/listing.rs b/src/runtime/listing.rs
@@ -2009,6 +2009,7 @@ fn published_mutation_view(
receipt: DirectRelayPublishReceipt,
) -> ListingMutationView {
let DirectRelayPublishReceipt {
+ event: published_event,
event_id,
created_at,
signature,
@@ -2017,6 +2018,8 @@ fn published_mutation_view(
acknowledged_relays,
failed_relays,
} = receipt;
+ debug_assert_eq!(event_id, published_event.id.to_hex());
+ debug_assert_eq!(signature, published_event.sig.to_string());
event.event_id = Some(event_id.clone());
event.created_at = Some(created_at);
event.signature = Some(signature);
diff --git a/src/runtime/order.rs b/src/runtime/order.rs
@@ -7422,6 +7422,7 @@ fn published_order_revision_view(
receipt: DirectRelayPublishReceipt,
) -> OrderRevisionProposalView {
let DirectRelayPublishReceipt {
+ event: _,
event_id,
created_at: _,
signature: _,
@@ -7452,6 +7453,7 @@ fn published_order_revision_decision_view(
receipt: DirectRelayPublishReceipt,
) -> OrderRevisionDecisionView {
let DirectRelayPublishReceipt {
+ event: _,
event_id,
created_at: _,
signature: _,
@@ -7578,6 +7580,7 @@ fn published_order_fulfillment_view(
receipt: DirectRelayPublishReceipt,
) -> OrderFulfillmentView {
let DirectRelayPublishReceipt {
+ event: _,
event_id,
created_at: _,
signature: _,
@@ -7606,6 +7609,7 @@ fn published_order_cancellation_view(
receipt: DirectRelayPublishReceipt,
) -> OrderCancellationView {
let DirectRelayPublishReceipt {
+ event: _,
event_id,
created_at: _,
signature: _,
@@ -7633,6 +7637,7 @@ fn published_order_receipt_view(
receipt: DirectRelayPublishReceipt,
) -> OrderReceiptView {
let DirectRelayPublishReceipt {
+ event: _,
event_id,
created_at: _,
signature: _,
@@ -7668,6 +7673,7 @@ fn published_order_payment_view(
receipt: DirectRelayPublishReceipt,
) -> OrderPaymentView {
let DirectRelayPublishReceipt {
+ event: _,
event_id,
created_at: _,
signature: _,
@@ -7696,6 +7702,7 @@ fn published_order_settlement_view(
receipt: DirectRelayPublishReceipt,
) -> OrderSettlementView {
let DirectRelayPublishReceipt {
+ event: _,
event_id,
created_at: _,
signature: _,
@@ -8055,6 +8062,7 @@ fn published_order_decision_view(
inventory: Option<OrderInventoryView>,
) -> OrderDecisionView {
let DirectRelayPublishReceipt {
+ event: _,
event_id,
created_at: _,
signature: _,
@@ -9716,6 +9724,7 @@ fn published_order_submit_view(
receipt: DirectRelayPublishReceipt,
) -> OrderSubmitView {
let DirectRelayPublishReceipt {
+ event: _,
event_id,
created_at: _,
signature: _,