commit 6bf67b0b2b2ddbc56b07a77572ae7ea369784c92
parent d2a0e99e3d1d9665952f489a2fdd82caf326d660
Author: triesap <tyson@radroots.org>
Date: Tue, 14 Jul 2026 11:05:10 +0000
sdk: align runtime with sealed event DTOs
- migrate SDK runtime and tests to sealed drafts, envelopes, and signed events
- publish source-owned event DTO package shapes without legacy envelope aliases
- send radrootsd publish requests as raw signed event JSON
- harden WASM and source-boundary tests against retired wire aliases
Diffstat:
48 files changed, 945 insertions(+), 688 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -1777,6 +1777,7 @@ dependencies = [
"dto_bindgen",
"hex",
"radroots_core",
+ "secp256k1",
"serde",
"serde_json",
"sha2",
diff --git a/contracts/packages/go.toml b/contracts/packages/go.toml
@@ -33,10 +33,12 @@ order = 3
"trade_validation.validate_listing_event" = "tradevalidation.ValidateListingEvent"
[shared_types]
-"WireEventParts" = "WireEventParts"
+"RadrootsNip01EventWireParts" = "RadrootsNip01EventWireParts"
+"RadrootsNip01EventWireDto" = "RadrootsNip01EventWireDto"
"RadrootsEventDraft" = "RadrootsEventDraft"
-"RadrootsSignedEvent" = "RadrootsSignedEvent"
-"RadrootsEventEnvelope" = "RadrootsEventEnvelope"
+"RadrootsSignedEventDto" = "RadrootsSignedEventDto"
+"RadrootsVerifiedSignedEventDto" = "RadrootsVerifiedSignedEventDto"
+"RadrootsEventEnvelopeDto" = "RadrootsEventEnvelopeDto"
"RadrootsEventRef" = "RadrootsEventRef"
"RadrootsEventPtr" = "RadrootsEventPtr"
"RadrootsListingAddress" = "ListingAddress"
diff --git a/contracts/packages/kotlin.toml b/contracts/packages/kotlin.toml
@@ -33,10 +33,12 @@ order = 2
"trade_validation.validate_listing_event" = "tradeValidation.validateListingEvent"
[shared_types]
-"WireEventParts" = "WireEventParts"
+"RadrootsNip01EventWireParts" = "RadrootsNip01EventWireParts"
+"RadrootsNip01EventWireDto" = "RadrootsNip01EventWireDto"
"RadrootsEventDraft" = "RadrootsEventDraft"
-"RadrootsSignedEvent" = "RadrootsSignedEvent"
-"RadrootsEventEnvelope" = "RadrootsEventEnvelope"
+"RadrootsSignedEventDto" = "RadrootsSignedEventDto"
+"RadrootsVerifiedSignedEventDto" = "RadrootsVerifiedSignedEventDto"
+"RadrootsEventEnvelopeDto" = "RadrootsEventEnvelopeDto"
"RadrootsEventRef" = "RadrootsEventRef"
"RadrootsEventPtr" = "RadrootsEventPtr"
"RadrootsListingAddress" = "ListingAddress"
diff --git a/contracts/packages/py.toml b/contracts/packages/py.toml
@@ -33,10 +33,12 @@ order = 3
"trade_validation.validate_listing_event" = "trade_validation_validate_listing_event"
[shared_types]
-"WireEventParts" = "WireEventParts"
+"RadrootsNip01EventWireParts" = "RadrootsNip01EventWireParts"
+"RadrootsNip01EventWireDto" = "RadrootsNip01EventWireDto"
"RadrootsEventDraft" = "RadrootsEventDraft"
-"RadrootsSignedEvent" = "RadrootsSignedEvent"
-"RadrootsEventEnvelope" = "RadrootsEventEnvelope"
+"RadrootsSignedEventDto" = "RadrootsSignedEventDto"
+"RadrootsVerifiedSignedEventDto" = "RadrootsVerifiedSignedEventDto"
+"RadrootsEventEnvelopeDto" = "RadrootsEventEnvelopeDto"
"RadrootsEventRef" = "RadrootsEventRef"
"RadrootsEventPtr" = "RadrootsEventPtr"
"RadrootsListingAddress" = "ListingAddress"
diff --git a/contracts/packages/swift.toml b/contracts/packages/swift.toml
@@ -33,10 +33,12 @@ order = 2
"trade_validation.validate_listing_event" = "tradeValidation.validateListingEvent"
[shared_types]
-"WireEventParts" = "WireEventParts"
+"RadrootsNip01EventWireParts" = "RadrootsNip01EventWireParts"
+"RadrootsNip01EventWireDto" = "RadrootsNip01EventWireDto"
"RadrootsEventDraft" = "RadrootsEventDraft"
-"RadrootsSignedEvent" = "RadrootsSignedEvent"
-"RadrootsEventEnvelope" = "RadrootsEventEnvelope"
+"RadrootsSignedEventDto" = "RadrootsSignedEventDto"
+"RadrootsVerifiedSignedEventDto" = "RadrootsVerifiedSignedEventDto"
+"RadrootsEventEnvelopeDto" = "RadrootsEventEnvelopeDto"
"RadrootsEventRef" = "RadrootsEventRef"
"RadrootsEventPtr" = "RadrootsEventPtr"
"RadrootsListingAddress" = "ListingAddress"
diff --git a/contracts/packages/ts.toml b/contracts/packages/ts.toml
@@ -103,10 +103,12 @@ order = 1
"trade_validation.validate_listing_event" = "tradeValidation.validateListingEvent"
[shared_types]
-"WireEventParts" = "WireEventParts"
+"RadrootsNip01EventWireParts" = "RadrootsNip01EventWireParts"
+"RadrootsNip01EventWireDto" = "RadrootsNip01EventWireDto"
"RadrootsEventDraft" = "RadrootsEventDraft"
-"RadrootsSignedEvent" = "RadrootsSignedEvent"
-"RadrootsEventEnvelope" = "RadrootsEventEnvelope"
+"RadrootsSignedEventDto" = "RadrootsSignedEventDto"
+"RadrootsVerifiedSignedEventDto" = "RadrootsVerifiedSignedEventDto"
+"RadrootsEventEnvelopeDto" = "RadrootsEventEnvelopeDto"
"RadrootsEventRef" = "RadrootsEventRef"
"RadrootsEventPtr" = "RadrootsEventPtr"
"RadrootsListingAddress" = "ListingAddress"
diff --git a/crates/event_codec_wasm/src/lib.rs b/crates/event_codec_wasm/src/lib.rs
@@ -607,6 +607,7 @@ mod tests {
RadrootsSocialFarmAnchor, RadrootsSocialLocation, RadrootsSocialMediaDimensions,
RadrootsSocialMediaMetadata, RadrootsSocialTarget,
};
+ use radroots_event::{RadrootsEventEnvelope, RadrootsEventEnvelopeParts};
fn sample_listing() -> RadrootsListing {
let quantity =
@@ -888,10 +889,10 @@ mod tests {
.custom_created_at(nostr::Timestamp::from_secs(1_800_000_000))
.sign_with_keys(&keys)
.expect("signed event");
- serde_json::to_string(&radroots_event::RadrootsEventEnvelope {
+ let envelope = RadrootsEventEnvelope::new(RadrootsEventEnvelopeParts {
id: event.id.to_hex(),
author: event.pubkey.to_hex(),
- created_at: event.created_at.as_secs() as u32,
+ created_at: event.created_at.as_secs(),
kind: u32::from(event.kind.as_u16()),
tags: event
.tags
@@ -902,7 +903,8 @@ mod tests {
content: event.content,
sig: event.sig.to_string(),
})
- .expect("event json")
+ .expect("event envelope");
+ serde_json::to_string(&envelope).expect("event json")
}
fn social_location() -> RadrootsSocialLocation {
diff --git a/crates/replica_sync_wasm/src/lib.rs b/crates/replica_sync_wasm/src/lib.rs
@@ -4,7 +4,7 @@
use base64::Engine;
#[cfg(target_arch = "wasm32")]
use base64::engine::general_purpose::URL_SAFE_NO_PAD;
-use radroots_event::RadrootsEventEnvelope;
+use radroots_event::{RadrootsEventEnvelope, RadrootsEventEnvelopeParts};
use radroots_replica_sync::RadrootsReplicaSyncRequest;
#[cfg(target_arch = "wasm32")]
use radroots_replica_sync::{
@@ -36,13 +36,11 @@ impl RadrootsReplicaIdFactory for WasmIdFactory {
}
#[derive(Deserialize)]
-struct NostrEventEnvelope {
+#[serde(deny_unknown_fields)]
+struct EventEnvelopeInput {
id: String,
- #[serde(default)]
- author: Option<String>,
- #[serde(default)]
- pubkey: Option<String>,
- created_at: u32,
+ author: String,
+ created_at: u64,
kind: u32,
tags: Vec<Vec<String>>,
content: String,
@@ -54,25 +52,18 @@ pub fn parse_request_model(request_json: &str) -> Result<RadrootsReplicaSyncRequ
}
pub fn parse_event_model(event_json: &str) -> Result<RadrootsEventEnvelope, String> {
- let envelope: NostrEventEnvelope =
+ let envelope: EventEnvelopeInput =
serde_json::from_str(event_json).map_err(|error| error.to_string())?;
- let author = match (envelope.author, envelope.pubkey) {
- (Some(author), Some(pubkey)) if author != pubkey => {
- return Err("author/pubkey mismatch".to_owned());
- }
- (Some(author), _) => author,
- (None, Some(pubkey)) => pubkey,
- (None, None) => return Err("missing author/pubkey".to_owned()),
- };
- Ok(RadrootsEventEnvelope {
+ RadrootsEventEnvelope::new(RadrootsEventEnvelopeParts {
id: envelope.id,
- author,
+ author: envelope.author,
created_at: envelope.created_at,
kind: envelope.kind,
tags: envelope.tags,
content: envelope.content,
sig: envelope.sig,
})
+ .map_err(|error| error.to_string())
}
#[cfg(target_arch = "wasm32")]
@@ -105,12 +96,12 @@ mod tests {
fn event_json(author: Option<&str>, pubkey: Option<&str>) -> String {
let mut fields = vec![
- r#""id":"event-id""#.to_owned(),
+ format!(r#""id":"{}""#, "0".repeat(64)),
r#""created_at":123"#.to_owned(),
r#""kind":30023"#.to_owned(),
r#""tags":[["d","one"]]"#.to_owned(),
r#""content":"content""#.to_owned(),
- r#""sig":"sig""#.to_owned(),
+ format!(r#""sig":"{}""#, "f".repeat(128)),
];
if let Some(author) = author {
fields.push(format!(r#""author":"{author}""#));
@@ -122,35 +113,28 @@ mod tests {
}
#[test]
- fn parse_event_accepts_matching_author_and_pubkey() {
- let event = parse_event_model(&event_json(Some("author"), Some("author"))).expect("event");
- assert_eq!(event.author, "author");
- assert_eq!(event.tags, vec![vec!["d".to_owned(), "one".to_owned()]]);
- }
-
- #[test]
- fn parse_event_accepts_author_without_pubkey() {
- let event = parse_event_model(&event_json(Some("author"), None)).expect("event");
- assert_eq!(event.author, "author");
- }
-
- #[test]
- fn parse_event_accepts_pubkey_without_author() {
- let event = parse_event_model(&event_json(None, Some("pubkey"))).expect("event");
- assert_eq!(event.author, "pubkey");
+ fn parse_event_accepts_author_domain_envelope() {
+ let author = "a".repeat(64);
+ let event = parse_event_model(&event_json(Some(author.as_str()), None)).expect("event");
+ assert_eq!(event.author_str(), author);
+ assert_eq!(
+ event.tags_as_vec(),
+ vec![vec!["d".to_owned(), "one".to_owned()]]
+ );
}
#[test]
- fn parse_event_rejects_author_pubkey_mismatch() {
- let error =
- parse_event_model(&event_json(Some("author"), Some("pubkey"))).expect_err("error");
- assert_eq!(error, "author/pubkey mismatch");
+ fn parse_event_rejects_pubkey_wire_alias() {
+ let author = "a".repeat(64);
+ let error = parse_event_model(&event_json(Some(author.as_str()), Some(author.as_str())))
+ .expect_err("error");
+ assert!(error.contains("unknown field `pubkey`"));
}
#[test]
- fn parse_event_rejects_missing_author_and_pubkey() {
+ fn parse_event_rejects_missing_author() {
let error = parse_event_model(&event_json(None, None)).expect_err("error");
- assert_eq!(error, "missing author/pubkey");
+ assert!(error.contains("missing field `author`"));
}
#[test]
diff --git a/crates/sdk/Cargo.toml b/crates/sdk/Cargo.toml
@@ -59,6 +59,7 @@ signer-adapters = [
"dep:radroots_nostr_connect",
"dep:radroots_nostr_signer",
"dep:tokio",
+ "radroots_event/signature",
"radroots_nostr/events",
]
runtime = [
diff --git a/crates/sdk/examples/sdk_v1_knowledge_prepare.rs b/crates/sdk/examples/sdk_v1_knowledge_prepare.rs
@@ -1,4 +1,5 @@
use nostr::{EventBuilder, Keys, Kind, Tag, Timestamp};
+use radroots_event::RadrootsEventEnvelopeParts;
use radroots_sdk::knowledge::prelude::*;
const SECRET_KEY_HEX: &str = "0101010101010101010101010101010101010101010101010101010101010101";
@@ -14,7 +15,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let manifest = contract_manifest();
let manifest_hash = contract_manifest_sha256()?;
- assert_eq!(draft.contract_id, KNOWLEDGE_CLAIM_CONTRACT_ID);
+ assert_eq!(draft.contract_id(), KNOWLEDGE_CLAIM_CONTRACT_ID);
assert_eq!(manifest.contract_count, 11);
assert_eq!(manifest_hash.len(), 64);
@@ -27,13 +28,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!(
"prepared knowledge claim draft: {}",
- draft.expected_event_id
+ draft.expected_event_id_str()
);
println!("knowledge manifest sha256: {manifest_hash}");
Ok(())
}
-fn sign_parts(parts: WireEventParts) -> Result<RadrootsEventEnvelope, Box<dyn std::error::Error>> {
+fn sign_parts(
+ parts: RadrootsNip01EventWireParts,
+) -> Result<RadrootsEventEnvelope, Box<dyn std::error::Error>> {
let tags = parts
.tags
.into_iter()
@@ -44,10 +47,10 @@ fn sign_parts(parts: WireEventParts) -> Result<RadrootsEventEnvelope, Box<dyn st
.tags(tags)
.custom_created_at(Timestamp::from_secs(u64::from(CREATED_AT)))
.sign_with_keys(&keys)?;
- Ok(RadrootsEventEnvelope {
+ Ok(RadrootsEventEnvelope::new(RadrootsEventEnvelopeParts {
id: event.id.to_hex(),
author: event.pubkey.to_hex(),
- created_at: event.created_at.as_secs() as u32,
+ created_at: event.created_at.as_secs(),
kind: u32::from(event.kind.as_u16()),
tags: event
.tags
@@ -57,7 +60,7 @@ fn sign_parts(parts: WireEventParts) -> Result<RadrootsEventEnvelope, Box<dyn st
.collect(),
content: event.content,
sig: event.sig.to_string(),
- })
+ })?)
}
fn public_key_hex() -> String {
diff --git a/crates/sdk/src/adapters/nostr.rs b/crates/sdk/src/adapters/nostr.rs
@@ -1,10 +1,9 @@
use core::time::Duration;
-use crate::adapters::signing::SignedEvent;
use crate::identity::RadrootsIdentity;
use radroots_nostr::prelude::{
- RadrootsNostrClient, RadrootsNostrClientOptions, RadrootsNostrError, RadrootsNostrEventId,
- RadrootsNostrOutput,
+ RadrootsNostrClient, RadrootsNostrClientOptions, RadrootsNostrError, RadrootsNostrEvent,
+ RadrootsNostrEventId, RadrootsNostrOutput,
};
pub fn signerless_client() -> RadrootsNostrClient {
@@ -58,7 +57,7 @@ pub async fn connected_relay_urls(client: &RadrootsNostrClient) -> Vec<String> {
pub async fn publish_signed_event(
client: &RadrootsNostrClient,
- event: &SignedEvent,
+ event: &RadrootsNostrEvent,
) -> Result<RadrootsNostrOutput<RadrootsNostrEventId>, RadrootsNostrError> {
client.send_event(event).await
}
diff --git a/crates/sdk/src/adapters/radrootsd.rs b/crates/sdk/src/adapters/radrootsd.rs
@@ -3,7 +3,7 @@ use core::time::Duration;
use radroots_event::draft::RadrootsSignedEvent;
use radroots_transport_publish_protocol::{
- METHOD_EVENT, SignedEventWire, TransportPublishDeliveryPolicy, TransportPublishEventRequest,
+ METHOD_EVENT, TransportPublishDeliveryPolicy, TransportPublishEventRequest,
TransportPublishEventResponse, TransportPublishProtocolError, TransportPublishTargetPolicy,
};
use reqwest::header::{AUTHORIZATION, CONTENT_TYPE, HeaderMap, HeaderValue};
@@ -81,6 +81,8 @@ impl RadrootsdProxyPublishAdapter {
&self,
request: RadrootsdProxyPublishRequest,
) -> Result<TransportPublishEventResponse, RadrootsdError> {
+ let event_identity =
+ RadrootsdProxyPublishEventIdentity::from_signed_event(&request.signed_event);
let request = request.into_protocol_request();
request
.validate(SDK_RADROOTSD_PROXY_MAX_TARGETS)
@@ -92,7 +94,7 @@ impl RadrootsdProxyPublishAdapter {
self.config.timeout,
)
.await?;
- validate_transport_publish_response_for_request(&request, &response)?;
+ validate_transport_publish_response_for_request(&request, &event_identity, &response)?;
Ok(response)
}
}
@@ -109,7 +111,7 @@ pub struct RadrootsdProxyPublishRequest {
impl RadrootsdProxyPublishRequest {
fn into_protocol_request(self) -> TransportPublishEventRequest {
TransportPublishEventRequest {
- event: signed_event_wire(&self.signed_event),
+ raw_event_json: self.signed_event.raw_json().to_owned(),
target_policy: self.target_policy,
delivery_policy: self.delivery_policy,
idempotency_key: self.idempotency_key,
@@ -118,6 +120,23 @@ impl RadrootsdProxyPublishRequest {
}
}
+#[derive(Clone, Debug, PartialEq, Eq)]
+struct RadrootsdProxyPublishEventIdentity {
+ event_id: String,
+ pubkey: String,
+ kind: u32,
+}
+
+impl RadrootsdProxyPublishEventIdentity {
+ fn from_signed_event(event: &RadrootsSignedEvent) -> Self {
+ Self {
+ event_id: event.id_str().to_owned(),
+ pubkey: event.pubkey_str().to_owned(),
+ kind: event.kind(),
+ }
+ }
+}
+
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RadrootsdError {
InvalidAuthHeader(String),
@@ -298,20 +317,9 @@ where
decode_jsonrpc_response(method, request_id, body.as_str())
}
-fn signed_event_wire(event: &RadrootsSignedEvent) -> SignedEventWire {
- SignedEventWire {
- id: event.id.clone(),
- pubkey: event.pubkey.clone(),
- created_at: event.created_at as u64,
- kind: event.kind,
- tags: event.tags.clone(),
- content: event.content.clone(),
- sig: event.sig.clone(),
- }
-}
-
fn validate_transport_publish_response_for_request(
request: &TransportPublishEventRequest,
+ event_identity: &RadrootsdProxyPublishEventIdentity,
response: &TransportPublishEventResponse,
) -> Result<(), RadrootsdError> {
response.job.validate().map_err(|error| {
@@ -319,13 +327,13 @@ fn validate_transport_publish_response_for_request(
"radrootsd transport publish response invalid: {error}"
))
})?;
- if response.job.event_id != request.event.id {
+ if response.job.event_id != event_identity.event_id {
return Err(response_mismatch("event_id"));
}
- if response.job.pubkey != request.event.pubkey {
+ if response.job.pubkey != event_identity.pubkey {
return Err(response_mismatch("pubkey"));
}
- if response.job.event_kind != request.event.kind {
+ if response.job.event_kind != event_identity.kind {
return Err(response_mismatch("event_kind"));
}
if response.job.delivery_policy != request.delivery_policy {
diff --git a/crates/sdk/src/adapters/signing.rs b/crates/sdk/src/adapters/signing.rs
@@ -1,27 +1,29 @@
use crate::identity::RadrootsIdentity;
-use radroots_event_codec::wire::WireEventParts;
-use radroots_nostr::prelude::{RadrootsNostrError, radroots_nostr_build_event};
+use radroots_event::wire::RadrootsNip01EventWireParts;
+use radroots_nostr::prelude::{
+ RadrootsNostrError, RadrootsNostrEvent, RadrootsNostrEventBuilder, radroots_nostr_build_event,
+};
-pub type SignedEvent = radroots_nostr::prelude::RadrootsNostrEvent;
-pub type NostrEventBuilder = radroots_nostr::prelude::RadrootsNostrEventBuilder;
pub type SigningError = RadrootsNostrError;
-pub fn event_builder_from_parts(parts: WireEventParts) -> Result<NostrEventBuilder, SigningError> {
+pub fn event_builder_from_parts(
+ parts: RadrootsNip01EventWireParts,
+) -> Result<RadrootsNostrEventBuilder, SigningError> {
radroots_nostr_build_event(parts.kind, parts.content, parts.tags)
}
pub fn sign_parts_with_identity(
identity: &RadrootsIdentity,
- parts: WireEventParts,
-) -> Result<SignedEvent, SigningError> {
+ parts: RadrootsNip01EventWireParts,
+) -> Result<RadrootsNostrEvent, SigningError> {
let builder = event_builder_from_parts(parts)?;
sign_builder_with_identity(identity, builder)
}
pub fn sign_builder_with_identity(
identity: &RadrootsIdentity,
- builder: NostrEventBuilder,
-) -> Result<SignedEvent, SigningError> {
+ builder: RadrootsNostrEventBuilder,
+) -> Result<RadrootsNostrEvent, SigningError> {
builder.sign_with_keys(identity.keys()).map_err(Into::into)
}
diff --git a/crates/sdk/src/dvm_runtime.rs b/crates/sdk/src/dvm_runtime.rs
@@ -11,15 +11,14 @@ use crate::{
};
#[cfg(feature = "runtime")]
use radroots_authority::{RadrootsActorContext, RadrootsEventSigner, authorize_actor_for_draft};
+use radroots_event::wire::RadrootsNip01EventWireParts;
#[cfg(feature = "runtime")]
use radroots_event::{
- RadrootsEventEnvelope,
- draft::RadrootsEventDraft,
+ draft::{RadrootsEventDraft, RadrootsSignedEvent},
ids::{RadrootsEventId, RadrootsListingAddress, RadrootsOrderId, RadrootsPublicKey},
kinds::KIND_TRADE_TRANSITION_PROOF_REQUEST,
};
-#[cfg(feature = "runtime")]
-use radroots_event_codec::wire::{WireEventParts, canonicalize_tags, to_frozen_draft};
+use radroots_event_codec::wire::canonicalize_tags;
#[cfg(feature = "runtime")]
use radroots_event_store::RadrootsEventIngest;
#[cfg(feature = "runtime")]
@@ -329,7 +328,7 @@ pub struct DvmTradeTransitionProofReceipt {
#[derive(Clone, Debug, serde::Serialize)]
#[non_exhaustive]
pub struct DvmValidationReceiptIngestRequest {
- pub event: RadrootsEventEnvelope,
+ pub event: RadrootsSignedEvent,
pub observed_at: Option<RadrootsSdkTimestamp>,
pub expected_order_id: Option<RadrootsOrderId>,
pub expected_listing_event_id: Option<RadrootsEventId>,
@@ -340,7 +339,7 @@ pub struct DvmValidationReceiptIngestRequest {
#[cfg(feature = "runtime")]
impl DvmValidationReceiptIngestRequest {
- pub fn new(event: RadrootsEventEnvelope) -> Self {
+ pub fn new(event: RadrootsSignedEvent) -> Self {
Self {
event,
observed_at: None,
@@ -468,7 +467,7 @@ impl<'sdk> DvmClient<'sdk> {
request: DvmValidationReceiptIngestRequest,
) -> Result<DvmValidationReceiptIngestReceipt, RadrootsSdkError> {
let verified = verify_validation_receipt_event(
- &request.event,
+ request.event.envelope(),
RadrootsValidationReceiptExpectedBinding {
order_id: request
.expected_order_id
@@ -490,7 +489,7 @@ impl<'sdk> DvmClient<'sdk> {
},
)
.map_err(validation_receipt_sdk_error)?;
- let receipt_event_id = parse_event_id(request.event.id.as_str(), "receipt event id")?;
+ let receipt_event_id = parse_event_id(request.event.id_str(), "receipt event id")?;
let order_id =
RadrootsOrderId::parse(verified.tags.order_id.as_str()).map_err(|error| {
RadrootsSdkError::InvalidRequest {
@@ -576,19 +575,22 @@ fn dvm_trade_transition_proof_plan(
],
];
canonicalize_tags(&mut tags);
- let frozen_draft = to_frozen_draft(
- WireEventParts {
- kind: KIND_TRADE_TRANSITION_PROOF_REQUEST,
- content,
- tags,
- },
+ let parts = RadrootsNip01EventWireParts {
+ kind: KIND_TRADE_TRANSITION_PROOF_REQUEST,
+ content,
+ tags,
+ };
+ let frozen_draft = RadrootsEventDraft::new(
DVM_TRADE_TRANSITION_PROOF_REQUEST_CONTRACT_ID,
+ parts.kind,
+ u64::from(created_at.try_into_nostr_created_at()?),
+ parts.tags,
+ parts.content,
request.actor.pubkey().as_str(),
- created_at.try_into_nostr_created_at()?,
)
.expect("DVM proof request draft is valid");
authorize_actor_for_draft(&request.actor, &frozen_draft)?;
- let expected_event_id = RadrootsEventId::parse(frozen_draft.expected_event_id.as_str())
+ let expected_event_id = RadrootsEventId::parse(frozen_draft.expected_event_id_str())
.expect("frozen DVM proof request draft produces a valid event id");
Ok(DvmTradeTransitionProofPlan {
worker_pubkey: request.worker_pubkey,
diff --git a/crates/sdk/src/farm.rs b/crates/sdk/src/farm.rs
@@ -2,8 +2,8 @@ pub use radroots_event::farm::*;
pub use radroots_event_codec::error::EventEncodeError;
-use radroots_event_codec::wire::WireEventParts;
+use radroots_event::wire::RadrootsNip01EventWireParts;
-pub fn build_draft(farm: &RadrootsFarm) -> Result<WireEventParts, EventEncodeError> {
+pub fn build_draft(farm: &RadrootsFarm) -> Result<RadrootsNip01EventWireParts, EventEncodeError> {
radroots_event_codec::farm::encode::to_wire_parts(farm)
}
diff --git a/crates/sdk/src/farms_runtime.rs b/crates/sdk/src/farms_runtime.rs
@@ -23,7 +23,6 @@ use radroots_event::{
listing::RadrootsListingPublicLocation,
};
#[cfg(feature = "runtime")]
-use radroots_event_codec::wire::to_frozen_draft;
#[cfg(feature = "runtime")]
pub const FARM_PUBLISH_OPERATION_KIND: &str = "farm.publish.v1";
@@ -740,14 +739,16 @@ fn farm_publish_plan(
})?;
let farm_addr = farm_addr(actor, farm_value.d_tag.as_str())
.expect("validated farm d tag forms a farm address");
- let frozen_draft = to_frozen_draft(
- parts,
+ let frozen_draft = RadrootsEventDraft::new(
FARM_PROFILE_CONTRACT_ID,
+ parts.kind,
+ created_at_nostr.into(),
+ parts.tags,
+ parts.content,
actor.pubkey().as_str(),
- created_at_nostr,
)
.expect("validated farm publish draft freezes");
- let expected_event_id = RadrootsEventId::parse(frozen_draft.expected_event_id.as_str())
+ let expected_event_id = RadrootsEventId::parse(frozen_draft.expected_event_id_str())
.expect("frozen farm draft produces a valid event id");
Ok(FarmPublishPlan {
farm_addr,
diff --git a/crates/sdk/src/knowledge.rs b/crates/sdk/src/knowledge.rs
@@ -11,6 +11,7 @@ use std::{
use core::fmt;
+pub use radroots_event::wire::RadrootsNip01EventWireParts;
pub use radroots_event::{
RadrootsEventEnvelope, RadrootsEventRef,
draft::{RadrootsDraftError, RadrootsEventDraft},
@@ -49,7 +50,6 @@ pub use radroots_event_codec::{
RadrootsContractValidatedEvent, RadrootsDecodeError, RadrootsDecodedEvent,
RadrootsIdVerifiedEvent, RadrootsNip01VerificationError, RadrootsSignatureVerifiedEvent,
},
- wire::WireEventParts,
};
use radroots_event::knowledge::{
@@ -66,7 +66,6 @@ use radroots_event_codec::{
wiki_merge_request_to_wire_parts, wiki_redirect_to_wire_parts,
},
knowledge_contract_manifest, verify_and_decode_radroots_event as codec_verify_and_decode,
- wire::to_frozen_draft,
};
pub const WIKI_ARTICLE_CONTRACT_ID: &str = "radroots.wiki.article.v1";
@@ -273,7 +272,7 @@ impl RadrootsWikiArticleBuilder {
builder_validated(article, validate_wiki_article)
}
- pub fn build_event(self) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+ pub fn build_event(self) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
Ok(build_wiki_article_event(&self.build()?)?)
}
@@ -317,7 +316,7 @@ impl RadrootsWikiRedirectBuilder {
builder_validated(redirect, validate_wiki_redirect)
}
- pub fn build_event(self) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+ pub fn build_event(self) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
Ok(build_wiki_redirect_event(&self.build()?)?)
}
@@ -396,7 +395,7 @@ impl RadrootsWikiMergeRequestBuilder {
builder_validated(request, validate_wiki_merge_request)
}
- pub fn build_event(self) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+ pub fn build_event(self) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
Ok(build_wiki_merge_request_event(&self.build()?)?)
}
@@ -512,7 +511,7 @@ impl RadrootsKnowledgeSourceBuilder {
builder_validated(source, validate_knowledge_source)
}
- pub fn build_event(self) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+ pub fn build_event(self) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
Ok(build_knowledge_source_event(&self.build()?)?)
}
@@ -606,7 +605,7 @@ impl RadrootsKnowledgeClaimBuilder {
builder_validated(claim, validate_knowledge_claim)
}
- pub fn build_event(self) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+ pub fn build_event(self) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
Ok(build_knowledge_claim_event(&self.build()?)?)
}
@@ -692,7 +691,7 @@ impl RadrootsKnowledgeRelationBuilder {
builder_validated(relation, validate_knowledge_relation)
}
- pub fn build_event(self) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+ pub fn build_event(self) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
Ok(build_knowledge_relation_event(&self.build()?)?)
}
@@ -775,7 +774,7 @@ impl RadrootsKnowledgeReviewBuilder {
builder_validated(review, validate_knowledge_review)
}
- pub fn build_event(self) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+ pub fn build_event(self) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
Ok(build_knowledge_review_event(&self.build()?)?)
}
@@ -874,7 +873,7 @@ impl RadrootsKnowledgeFieldReportBuilder {
builder_validated(report, validate_knowledge_field_report)
}
- pub fn build_event(self) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+ pub fn build_event(self) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
Ok(build_knowledge_field_report_event(&self.build()?)?)
}
@@ -902,56 +901,56 @@ impl KnowledgeEventBuilder {
pub fn wiki_article(
&self,
article: &RadrootsWikiArticle,
- ) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+ ) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
build_wiki_article_event(article)
}
pub fn wiki_redirect(
&self,
redirect: &RadrootsWikiRedirect,
- ) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+ ) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
build_wiki_redirect_event(redirect)
}
pub fn wiki_merge_request(
&self,
request: &RadrootsWikiMergeRequest,
- ) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+ ) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
build_wiki_merge_request_event(request)
}
pub fn knowledge_source(
&self,
source: &RadrootsKnowledgeSource,
- ) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+ ) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
build_knowledge_source_event(source)
}
pub fn knowledge_claim(
&self,
claim: &RadrootsKnowledgeClaim,
- ) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+ ) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
build_knowledge_claim_event(claim)
}
pub fn knowledge_relation(
&self,
relation: &RadrootsKnowledgeRelation,
- ) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+ ) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
build_knowledge_relation_event(relation)
}
pub fn knowledge_review(
&self,
review: &RadrootsKnowledgeReview,
- ) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+ ) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
build_knowledge_review_event(review)
}
pub fn knowledge_field_report(
&self,
report: &RadrootsKnowledgeFieldReport,
- ) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+ ) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
build_knowledge_field_report_event(report)
}
}
@@ -1065,49 +1064,49 @@ impl KnowledgeCodec {
pub fn build_wiki_article_event(
article: &RadrootsWikiArticle,
-) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
Ok(wiki_article_to_wire_parts(article)?)
}
pub fn build_wiki_redirect_event(
redirect: &RadrootsWikiRedirect,
-) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
Ok(wiki_redirect_to_wire_parts(redirect)?)
}
pub fn build_wiki_merge_request_event(
request: &RadrootsWikiMergeRequest,
-) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
Ok(wiki_merge_request_to_wire_parts(request)?)
}
pub fn build_knowledge_source_event(
source: &RadrootsKnowledgeSource,
-) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
Ok(knowledge_source_to_wire_parts(source)?)
}
pub fn build_knowledge_claim_event(
claim: &RadrootsKnowledgeClaim,
-) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
Ok(knowledge_claim_to_wire_parts(claim)?)
}
pub fn build_knowledge_relation_event(
relation: &RadrootsKnowledgeRelation,
-) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
Ok(knowledge_relation_to_wire_parts(relation)?)
}
pub fn build_knowledge_review_event(
review: &RadrootsKnowledgeReview,
-) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
Ok(knowledge_review_to_wire_parts(review)?)
}
pub fn build_knowledge_field_report_event(
report: &RadrootsKnowledgeFieldReport,
-) -> Result<WireEventParts, RadrootsSdkKnowledgeError> {
+) -> Result<RadrootsNip01EventWireParts, RadrootsSdkKnowledgeError> {
Ok(knowledge_field_report_to_wire_parts(report)?)
}
@@ -1234,16 +1233,18 @@ pub fn contract_manifest_sha256() -> Result<String, RadrootsSdkKnowledgeError> {
}
fn prepare_draft(
- parts: WireEventParts,
+ parts: RadrootsNip01EventWireParts,
contract_id: &'static str,
expected_pubkey: impl AsRef<str>,
created_at: u32,
) -> Result<RadrootsEventDraft, RadrootsSdkKnowledgeError> {
- Ok(to_frozen_draft(
- parts,
+ Ok(RadrootsEventDraft::new(
contract_id,
- expected_pubkey,
- created_at,
+ parts.kind,
+ u64::from(created_at),
+ parts.tags,
+ parts.content,
+ expected_pubkey.as_ref(),
)?)
}
@@ -1264,7 +1265,9 @@ fn draft_error_code(error: &RadrootsDraftError) -> &'static str {
"signed_event_computed_id_mismatch"
}
RadrootsDraftError::IdParse(_) => "id_parse",
- RadrootsDraftError::JsonString(_) => "json_string",
+ RadrootsDraftError::CanonicalEventId(_) => "canonical_event_id",
+ RadrootsDraftError::Envelope(_) => "event_envelope",
+ RadrootsDraftError::SignedEvent(_) => "signed_event",
}
}
@@ -1341,12 +1344,12 @@ pub mod prelude {
RadrootsKnowledgeRelationBuilder, RadrootsKnowledgeReview, RadrootsKnowledgeReviewBuilder,
RadrootsKnowledgeReviewScope, RadrootsKnowledgeReviewScore, RadrootsKnowledgeReviewTarget,
RadrootsKnowledgeSource, RadrootsKnowledgeSourceBuilder, RadrootsKnowledgeValidationError,
- RadrootsNip01VerificationError, RadrootsRightsAssertion, RadrootsSdkKnowledgeError,
- RadrootsSignatureVerifiedEvent, RadrootsWikiArticle, RadrootsWikiArticleBuilder,
- RadrootsWikiArticleVersionRef, RadrootsWikiDTagError, RadrootsWikiMergeRequest,
- RadrootsWikiMergeRequestBuilder, RadrootsWikiRedirect, RadrootsWikiRedirectBuilder,
- WIKI_ARTICLE_CONTRACT_ID, WIKI_MERGE_REQUEST_CONTRACT_ID, WIKI_REDIRECT_CONTRACT_ID,
- WireEventParts, build_knowledge_claim_event, build_knowledge_field_report_event,
+ RadrootsNip01EventWireParts, RadrootsNip01VerificationError, RadrootsRightsAssertion,
+ RadrootsSdkKnowledgeError, RadrootsSignatureVerifiedEvent, RadrootsWikiArticle,
+ RadrootsWikiArticleBuilder, RadrootsWikiArticleVersionRef, RadrootsWikiDTagError,
+ RadrootsWikiMergeRequest, RadrootsWikiMergeRequestBuilder, RadrootsWikiRedirect,
+ RadrootsWikiRedirectBuilder, WIKI_ARTICLE_CONTRACT_ID, WIKI_MERGE_REQUEST_CONTRACT_ID,
+ WIKI_REDIRECT_CONTRACT_ID, build_knowledge_claim_event, build_knowledge_field_report_event,
build_knowledge_relation_event, build_knowledge_review_event, build_knowledge_source_event,
build_wiki_article_event, build_wiki_merge_request_event, build_wiki_redirect_event,
contract_manifest, contract_manifest_json, contract_manifest_sha256, normalize_wiki_d_tag,
diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs
@@ -118,12 +118,12 @@ pub use crate::knowledge::{
RadrootsKnowledgeRelation, RadrootsKnowledgeRelationBuilder, RadrootsKnowledgeReview,
RadrootsKnowledgeReviewBuilder, RadrootsKnowledgeReviewScope, RadrootsKnowledgeReviewScore,
RadrootsKnowledgeReviewTarget, RadrootsKnowledgeSource, RadrootsKnowledgeSourceBuilder,
- RadrootsNip01VerificationError, RadrootsRightsAssertion, RadrootsSdkKnowledgeError,
- RadrootsSignatureVerifiedEvent, RadrootsWikiArticle, RadrootsWikiArticleBuilder,
- RadrootsWikiArticleVersionRef, RadrootsWikiDTagError, RadrootsWikiMergeRequest,
- RadrootsWikiMergeRequestBuilder, RadrootsWikiRedirect, RadrootsWikiRedirectBuilder,
- WIKI_ARTICLE_CONTRACT_ID, WIKI_MERGE_REQUEST_CONTRACT_ID, WIKI_REDIRECT_CONTRACT_ID,
- WireEventParts, build_knowledge_claim_event, build_knowledge_field_report_event,
+ RadrootsNip01EventWireParts, RadrootsNip01VerificationError, RadrootsRightsAssertion,
+ RadrootsSdkKnowledgeError, RadrootsSignatureVerifiedEvent, RadrootsWikiArticle,
+ RadrootsWikiArticleBuilder, RadrootsWikiArticleVersionRef, RadrootsWikiDTagError,
+ RadrootsWikiMergeRequest, RadrootsWikiMergeRequestBuilder, RadrootsWikiRedirect,
+ RadrootsWikiRedirectBuilder, WIKI_ARTICLE_CONTRACT_ID, WIKI_MERGE_REQUEST_CONTRACT_ID,
+ WIKI_REDIRECT_CONTRACT_ID, build_knowledge_claim_event, build_knowledge_field_report_event,
build_knowledge_relation_event, build_knowledge_review_event, build_knowledge_source_event,
build_wiki_article_event, build_wiki_merge_request_event, build_wiki_redirect_event,
contract_manifest, contract_manifest_json, contract_manifest_sha256, normalize_wiki_d_tag,
diff --git a/crates/sdk/src/listings_runtime.rs b/crates/sdk/src/listings_runtime.rs
@@ -331,8 +331,8 @@ fn listing_publish_plan(
let public_listing_addr = canonical.public_listing_addr().clone();
let draft_listing_addr = canonical.draft_listing_addr().clone();
let mutation = RadrootsListingMutation::publish(canonical);
- let frozen_draft = build_listing_mutation_draft(&mutation, created_at_nostr)?;
- let expected_event_id = RadrootsEventId::parse(frozen_draft.expected_event_id.as_str())
+ let frozen_draft = build_listing_mutation_draft(&mutation, u64::from(created_at_nostr))?;
+ let expected_event_id = RadrootsEventId::parse(frozen_draft.expected_event_id_str())
.expect("frozen listing draft produces a valid event id");
Ok(ListingPublishPlan {
public_listing_addr,
diff --git a/crates/sdk/src/order.rs b/crates/sdk/src/order.rs
@@ -5,80 +5,80 @@ pub use radroots_event_codec::order::RadrootsOrderEnvelopeParseError;
use radroots_event::RadrootsEventEnvelope;
#[cfg(any(feature = "signer-adapters", test))]
-use radroots_event::{RadrootsEventPtr, ids::RadrootsEventId, tags::TAG_E};
+use radroots_event::wire::RadrootsNip01EventWireParts;
#[cfg(any(feature = "signer-adapters", test))]
-use radroots_event_codec::wire::WireEventParts;
+use radroots_event::{RadrootsEventPtr, ids::RadrootsEventId, tags::TAG_E};
#[cfg(any(feature = "signer-adapters", test))]
#[derive(Debug, Clone)]
pub struct RadrootsOrderRequestDraft {
- parts: WireEventParts,
+ parts: RadrootsNip01EventWireParts,
}
#[cfg(any(feature = "signer-adapters", test))]
#[derive(Debug, Clone)]
pub struct RadrootsOrderDecisionDraft {
- parts: WireEventParts,
+ parts: RadrootsNip01EventWireParts,
}
#[cfg(any(feature = "signer-adapters", test))]
#[derive(Debug, Clone)]
pub struct RadrootsOrderRevisionProposalDraft {
- parts: WireEventParts,
+ parts: RadrootsNip01EventWireParts,
}
#[cfg(any(feature = "signer-adapters", test))]
#[derive(Debug, Clone)]
pub struct RadrootsOrderRevisionDecisionDraft {
- parts: WireEventParts,
+ parts: RadrootsNip01EventWireParts,
}
#[cfg(any(feature = "signer-adapters", test))]
#[derive(Debug, Clone)]
pub struct RadrootsOrderCancellationDraft {
- parts: WireEventParts,
+ parts: RadrootsNip01EventWireParts,
}
#[cfg(any(feature = "signer-adapters", test))]
impl RadrootsOrderRequestDraft {
- pub fn into_wire_parts(self) -> WireEventParts {
+ pub fn into_wire_parts(self) -> RadrootsNip01EventWireParts {
self.parts
}
}
#[cfg(any(feature = "signer-adapters", test))]
impl RadrootsOrderDecisionDraft {
- pub fn into_wire_parts(self) -> WireEventParts {
+ pub fn into_wire_parts(self) -> RadrootsNip01EventWireParts {
self.parts
}
}
#[cfg(any(feature = "signer-adapters", test))]
impl RadrootsOrderRevisionProposalDraft {
- pub fn into_wire_parts(self) -> WireEventParts {
+ pub fn into_wire_parts(self) -> RadrootsNip01EventWireParts {
self.parts
}
}
#[cfg(any(feature = "signer-adapters", test))]
impl RadrootsOrderRevisionDecisionDraft {
- pub fn into_wire_parts(self) -> WireEventParts {
+ pub fn into_wire_parts(self) -> RadrootsNip01EventWireParts {
self.parts
}
}
#[cfg(any(feature = "signer-adapters", test))]
impl RadrootsOrderCancellationDraft {
- pub fn into_wire_parts(self) -> WireEventParts {
+ pub fn into_wire_parts(self) -> RadrootsNip01EventWireParts {
self.parts
}
}
#[cfg(any(feature = "signer-adapters", test))]
fn with_contract_root_event_tag(
- mut parts: WireEventParts,
+ mut parts: RadrootsNip01EventWireParts,
root_event_id: &RadrootsEventId,
-) -> WireEventParts {
+) -> RadrootsNip01EventWireParts {
parts
.tags
.push(vec![TAG_E.to_owned(), root_event_id.as_str().to_owned()]);
diff --git a/crates/sdk/src/orders_runtime.rs b/crates/sdk/src/orders_runtime.rs
@@ -25,10 +25,12 @@ use crate::{
use radroots_authority::RadrootsActorContext;
#[cfg(all(feature = "runtime", test))]
use radroots_authority::RadrootsEventSigner;
+use radroots_event::wire::RadrootsNip01EventWireParts;
#[cfg(feature = "runtime")]
use radroots_event::{
- RadrootsEventEnvelope,
+ RadrootsEventEnvelope, RadrootsEventEnvelopeParts,
contract::RadrootsActorRole,
+ draft::RadrootsSignedEvent,
ids::RadrootsEventId,
kinds::{
KIND_ORDER_CANCELLATION, KIND_ORDER_DECISION, KIND_ORDER_REQUEST,
@@ -63,8 +65,6 @@ use radroots_event_codec::order::{
order_cancellation_from_event, order_decision_from_event, order_request_from_event,
order_revision_decision_from_event, order_revision_proposal_from_event,
};
-#[cfg(any(feature = "signer-adapters", test))]
-use radroots_event_codec::wire::{WireEventParts, to_frozen_draft};
#[cfg(all(feature = "runtime", feature = "transport-nostr-runtime"))]
use radroots_event_store::RadrootsStoredEventTag;
#[cfg(feature = "runtime")]
@@ -379,13 +379,13 @@ pub struct TradeSubmitReceipt {
#[derive(Clone, Debug, serde::Serialize)]
#[non_exhaustive]
pub struct TradeRequestEvidenceIngestRequest {
- pub event: RadrootsEventEnvelope,
+ pub event: RadrootsSignedEvent,
pub observed_at: Option<RadrootsSdkTimestamp>,
}
#[cfg(feature = "runtime")]
impl TradeRequestEvidenceIngestRequest {
- pub fn new(event: RadrootsEventEnvelope) -> Self {
+ pub fn new(event: RadrootsSignedEvent) -> Self {
Self {
event,
observed_at: None,
@@ -414,13 +414,13 @@ pub struct TradeRequestEvidenceIngestReceipt {
#[derive(Clone, Debug, serde::Serialize)]
#[non_exhaustive]
pub struct TradeEvidenceIngestRequest {
- pub event: RadrootsEventEnvelope,
+ pub event: RadrootsSignedEvent,
pub observed_at: Option<RadrootsSdkTimestamp>,
}
#[cfg(feature = "runtime")]
impl TradeEvidenceIngestRequest {
- pub fn new(event: RadrootsEventEnvelope) -> Self {
+ pub fn new(event: RadrootsSignedEvent) -> Self {
Self {
event,
observed_at: None,
@@ -2573,7 +2573,7 @@ impl<'sdk> TradesClient<'sdk> {
&self,
request: TradeEvidenceIngestRequest,
) -> Result<TradeEvidenceIngestReceipt, RadrootsSdkError> {
- let evidence = parse_order_evidence(&request.event)?;
+ let evidence = parse_order_evidence(request.event.envelope())?;
let observed_at = self.resolved_created_at(request.observed_at)?;
let observed_at_ms = sdk_timestamp_ms(observed_at)?;
let receipt = self
@@ -2598,7 +2598,7 @@ impl<'sdk> TradesClient<'sdk> {
&self,
request: TradeRequestEvidenceIngestRequest,
) -> Result<TradeRequestEvidenceIngestReceipt, RadrootsSdkError> {
- let evidence = parse_order_request_evidence(&request.event)?;
+ let evidence = parse_order_request_evidence(request.event.envelope())?;
let observed_at = self.resolved_created_at(request.observed_at)?;
let observed_at_ms = sdk_timestamp_ms(observed_at)?;
let receipt = self
@@ -4348,8 +4348,8 @@ where
)
.await?;
let (mut receipts, mut invalid_receipts) = classify_validation_receipts(events, None)?;
- receipts.retain(|receipt| receipt.event.id == receipt_event_id.as_str());
- invalid_receipts.retain(|receipt| receipt.event.id == receipt_event_id.as_str());
+ receipts.retain(|receipt| receipt.event.id_str() == receipt_event_id.as_str());
+ invalid_receipts.retain(|receipt| receipt.event.id_str() == receipt_event_id.as_str());
attach_worker_evidence(
sdk,
adapter,
@@ -4560,7 +4560,7 @@ where
let mut selections = worker_evidence_for_receipts(trusted_worker_pubkeys, receipts, events)?;
for receipt in receipts {
receipt.worker_evidence = selections
- .remove(receipt.event.id.as_str())
+ .remove(receipt.event.id_str())
.unwrap_or_default();
}
Ok(())
@@ -4578,14 +4578,14 @@ fn worker_evidence_for_receipts(
.collect::<BTreeSet<_>>();
let binding_by_receipt_id = receipts
.iter()
- .map(|receipt| (receipt.event.id.as_str(), receipt))
+ .map(|receipt| (receipt.event.id_str(), receipt))
.collect::<BTreeMap<_, _>>();
let mut by_receipt =
- BTreeMap::<String, Vec<(u32, String, bool, TradeValidationReceiptWorkerEvidence)>>::new();
+ BTreeMap::<String, Vec<(u64, String, bool, TradeValidationReceiptWorkerEvidence)>>::new();
for event in events {
let payload =
- match serde_json::from_str::<RawTradeValidationReceiptWorkerResult>(&event.content) {
+ match serde_json::from_str::<RawTradeValidationReceiptWorkerResult>(event.content()) {
Ok(payload) => payload,
Err(_) => continue,
};
@@ -4595,12 +4595,12 @@ fn worker_evidence_for_receipts(
if !worker_payload_binds_receipt(&payload, binding) {
continue;
}
- let author = RadrootsPublicKey::parse(event.author.as_str()).map_err(|error| {
+ let author = RadrootsPublicKey::parse(event.author_str()).map_err(|error| {
RadrootsSdkError::InvalidRequest {
message: format!("validation receipt worker evidence author is invalid: {error}"),
}
})?;
- let result_event_id = RadrootsEventId::parse(event.id.as_str()).map_err(|error| {
+ let result_event_id = RadrootsEventId::parse(event.id_str()).map_err(|error| {
RadrootsSdkError::InvalidRequest {
message: format!("validation receipt worker evidence event id is invalid: {error}"),
}
@@ -4629,8 +4629,8 @@ fn worker_evidence_for_receipts(
.and_then(RadrootsTradeCommitmentConfidence::from_label),
};
by_receipt.entry(receipt_event_id).or_default().push((
- event.created_at,
- event.id,
+ event.created_at_u64(),
+ event.id_str().to_owned(),
trusted,
view,
));
@@ -4669,7 +4669,7 @@ fn worker_payload_binds_receipt(
payload.status == "succeeded"
&& payload.worker_role.as_deref() == Some("non_authoritative_prover")
&& payload.receipt_kind == Some(KIND_TRADE_VALIDATION_RECEIPT)
- && payload.receipt_event_id == receipt.event.id
+ && payload.receipt_event_id == receipt.event.id_str()
&& payload.order_id.as_deref() == Some(receipt.tags.order_id.as_str())
&& payload.listing_event_id.as_deref() == Some(receipt.tags.listing_event_id.as_str())
&& payload.event_set_root.as_deref() == Some(receipt.tags.event_set_root.as_str())
@@ -4776,7 +4776,7 @@ async fn trade_status_validation_trust_decision(
));
}
let event = stored_event_to_nostr_event(&stored_event)?;
- let receipt_author = match RadrootsPublicKey::parse(event.author.as_str()) {
+ let receipt_author = match RadrootsPublicKey::parse(event.author_str()) {
Ok(author) => author,
Err(_) => {
return Ok(trade_validation_trust_decision(
@@ -5270,7 +5270,7 @@ fn stored_event_to_nostr_event(
),
}
})?;
- Ok(RadrootsEventEnvelope {
+ RadrootsEventEnvelope::new(RadrootsEventEnvelopeParts {
id: stored_event.event_id.clone(),
author: stored_event.pubkey.clone(),
created_at: stored_event.created_at,
@@ -5279,6 +5279,12 @@ fn stored_event_to_nostr_event(
content: stored_event.content.clone(),
sig: stored_event.sig.clone(),
})
+ .map_err(|error| RadrootsSdkError::EventStore {
+ message: format!(
+ "stored event {} contains invalid envelope: {error}",
+ stored_event.event_id
+ ),
+ })
}
#[cfg(all(feature = "runtime", feature = "transport-nostr-runtime"))]
@@ -5287,9 +5293,9 @@ fn validation_receipt_event_order(
right: &TradeValidationReceiptEvent,
) -> core::cmp::Ordering {
left.event
- .created_at
- .cmp(&right.event.created_at)
- .then_with(|| left.event.id.cmp(&right.event.id))
+ .created_at()
+ .cmp(&right.event.created_at())
+ .then_with(|| left.event.id().cmp(right.event.id()))
}
#[cfg(all(feature = "runtime", feature = "transport-nostr-runtime"))]
@@ -5298,9 +5304,9 @@ fn validation_receipt_invalid_order(
right: &TradeValidationReceiptInvalidCandidate,
) -> core::cmp::Ordering {
left.event
- .created_at
- .cmp(&right.event.created_at)
- .then_with(|| left.event.id.cmp(&right.event.id))
+ .created_at()
+ .cmp(&right.event.created_at())
+ .then_with(|| left.event.id().cmp(right.event.id()))
}
#[cfg(all(feature = "runtime", feature = "transport-nostr-runtime"))]
@@ -5625,7 +5631,7 @@ impl<'sdk> TradeSellerClient<'sdk> {
),
}
})?;
- let nostr_event = RadrootsEventEnvelope {
+ let nostr_event = RadrootsEventEnvelope::new(RadrootsEventEnvelopeParts {
id: event.event_id,
author: event.pubkey,
created_at: event.created_at,
@@ -5633,7 +5639,10 @@ impl<'sdk> TradeSellerClient<'sdk> {
tags,
content: event.content,
sig: event.sig,
- };
+ })
+ .map_err(|error| RadrootsSdkError::Projection {
+ message: format!("stored trade inbox event envelope is invalid: {error}"),
+ })?;
if let Ok(RadrootsOrderEventRecord::Request(record)) =
order_event_record_from_event(&nostr_event)
{
@@ -6387,12 +6396,12 @@ struct ParsedOrderEvidence {
fn parse_order_evidence(
event: &RadrootsEventEnvelope,
) -> Result<ParsedOrderEvidence, RadrootsSdkError> {
- let event_id = RadrootsEventId::parse(event.id.as_str()).map_err(|error| {
+ let event_id = RadrootsEventId::parse(event.id_str()).map_err(|error| {
RadrootsSdkError::InvalidRequest {
message: format!("order evidence event id is invalid: {error}"),
}
})?;
- let (order_id, listing_addr) = match event.kind {
+ let (order_id, listing_addr) = match event.kind_u32() {
KIND_ORDER_REQUEST => {
let payload = order_request_from_event(event)
.map_err(order_evidence_parse_error)?
@@ -6434,7 +6443,7 @@ fn parse_order_evidence(
order_id,
listing_addr,
event_id,
- event_kind: event.kind,
+ event_kind: event.kind_u32(),
})
}
@@ -6680,15 +6689,13 @@ fn order_submit_plan(
message: format!("order submit draft encode failed: {error}"),
}
})?;
- let frozen_draft = to_frozen_draft(
+ let (frozen_draft, expected_event_id) = freeze_order_workflow_draft(
draft.into_wire_parts(),
TRADE_SUBMIT_CONTRACT_ID,
order_request.buyer_pubkey.as_str(),
created_at_nostr,
- )
- .expect("validated order submit draft freezes");
- let expected_event_id = RadrootsEventId::parse(frozen_draft.expected_event_id.as_str())
- .expect("frozen order submit draft produces a valid event id");
+ "trade.prepare_submit",
+ );
Ok(TradeSubmitPlan {
workflow: order_workflow_plan(
TradeWorkflowKind::Submit,
@@ -6732,15 +6739,13 @@ fn order_decision_plan(
.expect("canonical order decision payload validates");
let draft = order::build_order_decision_draft(&request_event_id, &request_event_id, &decision)
.expect("validated order decision draft encodes");
- let frozen_draft = to_frozen_draft(
+ let (frozen_draft, expected_event_id) = freeze_order_workflow_draft(
draft.into_wire_parts(),
TRADE_DECISION_CONTRACT_ID,
decision.seller_pubkey.as_str(),
created_at_nostr,
- )
- .expect("validated order decision draft freezes");
- let expected_event_id = RadrootsEventId::parse(frozen_draft.expected_event_id.as_str())
- .expect("frozen order decision draft produces a valid event id");
+ "trade.prepare_decision",
+ );
Ok(TradeDecisionPlan {
workflow: order_workflow_plan(
TradeWorkflowKind::Decision,
@@ -7138,15 +7143,22 @@ fn order_workflow_enqueue_receipt(
#[cfg(any(feature = "signer-adapters", test))]
fn freeze_order_workflow_draft(
- parts: WireEventParts,
+ parts: RadrootsNip01EventWireParts,
contract_id: &str,
expected_pubkey: &str,
created_at: u32,
_operation: &'static str,
) -> (RadrootsEventDraft, RadrootsEventId) {
- let frozen_draft = to_frozen_draft(parts, contract_id, expected_pubkey, created_at)
- .expect("validated order workflow draft freezes");
- let expected_event_id = RadrootsEventId::parse(frozen_draft.expected_event_id.as_str())
+ let frozen_draft = RadrootsEventDraft::new(
+ contract_id,
+ parts.kind,
+ u64::from(created_at),
+ parts.tags,
+ parts.content,
+ expected_pubkey,
+ )
+ .expect("validated order workflow draft freezes");
+ let expected_event_id = RadrootsEventId::parse(frozen_draft.expected_event_id_str())
.expect("frozen order workflow draft produces a valid event id");
(frozen_draft, expected_event_id)
}
@@ -7219,7 +7231,7 @@ struct TradeRequestEvidence {
fn parse_order_request_evidence(
event: &RadrootsEventEnvelope,
) -> Result<TradeRequestEvidence, RadrootsSdkError> {
- let request_event_id = RadrootsEventId::parse(event.id.as_str()).map_err(|error| {
+ let request_event_id = RadrootsEventId::parse(event.id_str()).map_err(|error| {
RadrootsSdkError::InvalidRequest {
message: format!("order request evidence event id is invalid: {error}"),
}
@@ -7983,6 +7995,9 @@ fn projection_error(error: RadrootsOrderStoreQueryError) -> RadrootsSdkError {
RadrootsOrderStoreQueryError::Decode { .. } => {
"stored order event could not decode as order record"
}
+ RadrootsOrderStoreQueryError::InvalidStoredEnvelope { .. } => {
+ "stored order event envelope is invalid"
+ }
RadrootsOrderStoreQueryError::Projection(error) => return error.into(),
};
RadrootsSdkError::Projection {
diff --git a/crates/sdk/src/signer_provider.rs b/crates/sdk/src/signer_provider.rs
@@ -12,7 +12,8 @@ use radroots_event::kinds::{
KIND_FARM, KIND_LISTING, KIND_ORDER_CANCELLATION, KIND_ORDER_DECISION, KIND_ORDER_REQUEST,
KIND_ORDER_REVISION_DECISION, KIND_ORDER_REVISION_PROPOSAL,
};
-use radroots_nostr::prelude::{RadrootsNostrEvent, RadrootsNostrKeys, radroots_event_from_nostr};
+use radroots_event::wire::RadrootsNip01EventWire;
+use radroots_nostr::prelude::{RadrootsNostrEvent, RadrootsNostrKeys};
use radroots_nostr_connect::prelude::{
RadrootsNostrConnectClientRequest, RadrootsNostrConnectClientTarget,
RadrootsNostrConnectClientTransport, RadrootsNostrConnectClientTransportFuture,
@@ -552,16 +553,16 @@ fn sign_event_request_from_frozen_draft(
let unsigned_event = UnsignedEvent {
id: None,
pubkey: public_key,
- created_at: Timestamp::from_secs(u64::from(draft.created_at)),
+ created_at: Timestamp::from_secs(draft.created_at_u64()),
kind,
tags: Tags::from_list(tags),
- content: draft.content.clone(),
+ content: draft.content().to_owned(),
};
Ok(RadrootsNostrConnectRequest::SignEvent(unsigned_event))
}
fn nip46_unsigned_event_pubkey(draft: &RadrootsEventDraft) -> Result<PublicKey, RadrootsSdkError> {
- PublicKey::parse(draft.expected_pubkey.as_str()).map_err(|error| {
+ PublicKey::parse(draft.expected_pubkey_str()).map_err(|error| {
nip46_sign_event_protocol_error(format!(
"failed to parse frozen draft pubkey for NIP-46 unsigned event: {error}"
))
@@ -569,7 +570,7 @@ fn nip46_unsigned_event_pubkey(draft: &RadrootsEventDraft) -> Result<PublicKey,
}
fn nip46_unsigned_event_kind(draft: &RadrootsEventDraft) -> Result<Kind, RadrootsSdkError> {
- let kind = u16::try_from(draft.kind).map_err(|error| {
+ let kind = u16::try_from(draft.kind_u32()).map_err(|error| {
nip46_sign_event_protocol_error(format!(
"failed to convert frozen draft kind to NIP-46 unsigned event: {error}"
))
@@ -578,9 +579,10 @@ fn nip46_unsigned_event_kind(draft: &RadrootsEventDraft) -> Result<Kind, Radroot
}
fn nip46_unsigned_event_tags(draft: &RadrootsEventDraft) -> Result<Vec<Tag>, RadrootsSdkError> {
- let mut tags = Vec::with_capacity(draft.tags.len());
- for raw_tag in &draft.tags {
- let tag = Tag::parse(raw_tag.clone()).map_err(|error| {
+ let raw_tags = draft.tags_as_vec();
+ let mut tags = Vec::with_capacity(raw_tags.len());
+ for raw_tag in raw_tags {
+ let tag = Tag::parse(raw_tag).map_err(|error| {
nip46_sign_event_protocol_error(format!(
"failed to convert frozen draft tags to NIP-46 unsigned event: {error}"
))
@@ -604,12 +606,26 @@ fn signed_event_from_nip46_response(
match response {
RadrootsNostrConnectResponse::SignedEvent(event) => {
let raw_json = event.as_json();
- RadrootsSignedEvent::from_event(radroots_event_from_nostr(&event), raw_json).map_err(
- |error| RadrootsSdkError::SignerProtocol {
+ let wire = RadrootsNip01EventWire::parse_json(raw_json.as_str()).map_err(|error| {
+ RadrootsSdkError::SignerProtocol {
mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(),
- reason: format!("remote signed event is invalid: {error}"),
- },
- )
+ reason: format!("remote signed event wire is invalid: {error}"),
+ }
+ })?;
+ let signed_event =
+ RadrootsSignedEvent::from_wire_verified_id(wire, raw_json).map_err(|error| {
+ RadrootsSdkError::SignerProtocol {
+ mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(),
+ reason: format!("remote signed event is invalid: {error}"),
+ }
+ })?;
+ signed_event
+ .verify_signature()
+ .map(|verified| verified.into_signed_event())
+ .map_err(|error| RadrootsSdkError::SignerProtocol {
+ mode: RadrootsSdkSignerMode::MycNip46.as_str().to_owned(),
+ reason: format!("remote signed event signature is invalid: {error}"),
+ })
}
RadrootsNostrConnectResponse::Error { error, .. } => {
Err(RadrootsSdkError::SignerRequestRejected {
@@ -669,7 +685,7 @@ fn sign_receipt(
mode,
signer_pubkey,
remote_signer_pubkey,
- signed_event_id: signed_event.id.clone(),
+ signed_event_id: signed_event.id_str().to_owned(),
signed_event,
}
}
diff --git a/crates/sdk/src/sync_runtime.rs b/crates/sdk/src/sync_runtime.rs
@@ -1128,7 +1128,7 @@ async fn push_proxy_claimed_outbox_event(
idempotency_key: Some(proxy_outbox_idempotency_key(
claimed.outbox_event_id,
claimed.attempt_count,
- signed_event.id.as_str(),
+ signed_event.id_str(),
active_delivery_plan_id(claimed, "radrootsd proxy publish")?,
)),
timeout_ms: adapter.config().request_timeout_ms,
@@ -1686,7 +1686,7 @@ fn proxy_transport_error_receipt(
.filter(|target| target.status.is_ready_for_attempt())
.collect::<Vec<_>>();
let target_count = ready_targets.len();
- let event_id = push_receipt_event_id(event.id.as_str(), "proxy transport failure event id")?;
+ let event_id = push_receipt_event_id(event.id_str(), "proxy transport failure event id")?;
Ok(PushOutboxEventReceipt {
event_id,
outbox_event_id: claimed.outbox_event_id,
diff --git a/crates/sdk/src/workflow_runtime.rs b/crates/sdk/src/workflow_runtime.rs
@@ -6,7 +6,6 @@ use crate::{
};
use radroots_authority::{RadrootsActorContext, RadrootsEventSigner, sign_authorized_draft};
use radroots_event::{
- RadrootsEventEnvelope,
draft::{RadrootsEventDraft, RadrootsSignedEvent},
ids::RadrootsEventId,
};
@@ -78,12 +77,12 @@ async fn enqueue_signed_workflow_event(
Some(idempotency_key) => idempotency_key,
None => SdkIdempotencyKey::derive(
request.operation_kind,
- request.frozen_draft.expected_event_id.as_str(),
- request.frozen_draft.expected_pubkey.as_str(),
+ request.frozen_draft.expected_event_id_str(),
+ request.frozen_draft.expected_pubkey_str(),
),
};
let observed_at_ms = sdk_now_ms(sdk)?;
- let signed_event_id = RadrootsEventId::parse(request.frozen_draft.expected_event_id.as_str())
+ let signed_event_id = RadrootsEventId::parse(request.frozen_draft.expected_event_id_str())
.expect("frozen workflow draft has a valid expected event id");
let delivery_plan_value = delivery_plan.delivery_plan;
let idempotency_key_for_enqueue = idempotency_key.clone();
@@ -102,15 +101,13 @@ async fn enqueue_signed_workflow_event(
.await?;
let partial_failure_digest_prefix =
digest_prefix(preflight.operation_idempotency_digest.as_str());
- let event = event_from_signed(&signed_event);
let local_import_observation = RadrootsTransportObservation::new(
RadrootsTransportKind::Local,
SDK_LOCAL_EVENT_ENDPOINT_URI,
RadrootsTransportObservationType::LocalImport,
observed_at_ms,
)?;
- let ingest = RadrootsEventIngest::new(event, observed_at_ms)
- .with_raw_json(signed_event.raw_json.clone())
+ let ingest = RadrootsEventIngest::new(signed_event.clone(), observed_at_ms)
.with_observation(local_import_observation);
let ingest_receipt = sdk._event_store.ingest_event(ingest).await?;
let outbox_input = signed_outbox_input(
@@ -319,18 +316,6 @@ fn signed_outbox_input(
.with_idempotency_key(idempotency_key.into_string())
}
-fn event_from_signed(signed_event: &RadrootsSignedEvent) -> RadrootsEventEnvelope {
- RadrootsEventEnvelope {
- id: signed_event.id.clone(),
- author: signed_event.pubkey.clone(),
- created_at: signed_event.created_at,
- kind: signed_event.kind,
- tags: signed_event.tags.clone(),
- content: signed_event.content.clone(),
- sig: signed_event.sig.clone(),
- }
-}
-
#[cfg(test)]
#[path = "../tests/unit/workflow_runtime_tests.rs"]
mod tests;
diff --git a/crates/sdk/tests/dvm_runtime.rs b/crates/sdk/tests/dvm_runtime.rs
@@ -20,6 +20,7 @@ use radroots_event::{
RadrootsOrderEconomicLine, RadrootsOrderEconomics, RadrootsOrderInventoryCommitment,
RadrootsOrderItem, RadrootsOrderPricingBasis, RadrootsOrderRequest,
},
+ wire::RadrootsNip01EventWireParts,
};
use radroots_event_store::{RadrootsEventIngest, RadrootsEventStore};
use radroots_nostr::prelude::{
@@ -91,6 +92,12 @@ impl RadrootsEventSigner for FixtureSigner {
}
}
+fn signed_event_from_envelope(event: RadrootsEventEnvelope) -> RadrootsSignedEvent {
+ let wire = event.to_nip01_wire();
+ let raw_json = serde_json::to_string(&wire).expect("raw event json");
+ RadrootsSignedEvent::from_wire_verified_id(wire, raw_json).expect("signed event")
+}
+
#[tokio::test]
async fn dvm_trade_transition_proof_request_enqueues_signed_job() {
let (_tempdir, sdk, store) = directory_sdk_and_store().await;
@@ -260,16 +267,18 @@ async fn dvm_configured_enqueue_reports_prepare_and_target_errors_without_mutati
async fn dvm_validation_receipt_ingest_commits_pending_trade_status() {
let (_tempdir, sdk, store) = directory_sdk_and_store().await;
let request_event = signed_order_request_event("order-dvm-ingest", 10);
- let request_event_id = RadrootsEventId::parse(request_event.id.as_str()).expect("request id");
+ let request_event_id = RadrootsEventId::parse(request_event.id_str()).expect("request id");
let decision_event = signed_order_decision_event("order-dvm-ingest", &request_event_id, 11);
- let decision_event_id =
- RadrootsEventId::parse(decision_event.id.as_str()).expect("decision id");
+ let decision_event_id = RadrootsEventId::parse(decision_event.id_str()).expect("decision id");
for (event, observed_at_ms) in [
(request_event.clone(), 1_000),
(decision_event.clone(), 1_100),
] {
store
- .ingest_event(RadrootsEventIngest::new(event, observed_at_ms))
+ .ingest_event(RadrootsEventIngest::new(
+ signed_event_from_envelope(event),
+ observed_at_ms,
+ ))
.await
.expect("ingest order event");
}
@@ -289,11 +298,11 @@ async fn dvm_validation_receipt_ingest_commits_pending_trade_status() {
&decision_event_id,
12,
);
- let receipt_event_id = RadrootsEventId::parse(receipt_event.id.as_str()).expect("receipt id");
+ let receipt_event_id = RadrootsEventId::parse(receipt_event.id_str()).expect("receipt id");
let ingest = sdk
.dvm()
.ingest_validation_receipt(
- DvmValidationReceiptIngestRequest::new(receipt_event)
+ DvmValidationReceiptIngestRequest::new(signed_event_from_envelope(receipt_event))
.with_expected_order_id(order_id("order-dvm-ingest"))
.with_expected_listing_event_id(listing_event_id.clone())
.with_expected_root_event_id(request_event_id.clone())
@@ -367,7 +376,7 @@ async fn dvm_validation_receipt_ingest_rejects_binding_mismatch_without_mutation
let error = sdk
.dvm()
.ingest_validation_receipt(
- DvmValidationReceiptIngestRequest::new(receipt_event)
+ DvmValidationReceiptIngestRequest::new(signed_event_from_envelope(receipt_event))
.with_expected_order_id(order_id("other-order")),
)
.await
@@ -448,7 +457,7 @@ async fn dvm_validation_receipt_ingest_reports_timestamp_and_refresh_errors() {
let error = sdk
.dvm()
.ingest_validation_receipt(
- DvmValidationReceiptIngestRequest::new(overflow_observed)
+ DvmValidationReceiptIngestRequest::new(signed_event_from_envelope(overflow_observed))
.with_observed_at(RadrootsSdkTimestamp::from_unix_seconds(u64::MAX)),
)
.await
@@ -477,7 +486,9 @@ async fn dvm_validation_receipt_ingest_reports_timestamp_and_refresh_errors() {
);
let error = sdk
.dvm()
- .ingest_validation_receipt(DvmValidationReceiptIngestRequest::new(default_observed))
+ .ingest_validation_receipt(DvmValidationReceiptIngestRequest::new(
+ signed_event_from_envelope(default_observed),
+ ))
.await
.expect_err("default observed overflow");
assert!(matches!(
@@ -505,7 +516,7 @@ async fn dvm_validation_receipt_ingest_reports_timestamp_and_refresh_errors() {
let error = sdk
.dvm()
.ingest_validation_receipt(
- DvmValidationReceiptIngestRequest::new(refresh_overflow)
+ DvmValidationReceiptIngestRequest::new(signed_event_from_envelope(refresh_overflow))
.with_observed_at(RadrootsSdkTimestamp::from_unix_seconds(1_700_000_000)),
)
.await
@@ -554,7 +565,9 @@ async fn dvm_prepare_and_ingest_use_sdk_clock_defaults() {
);
let ingest = sdk
.dvm()
- .ingest_validation_receipt(DvmValidationReceiptIngestRequest::new(receipt_event))
+ .ingest_validation_receipt(DvmValidationReceiptIngestRequest::new(
+ signed_event_from_envelope(receipt_event),
+ ))
.await
.expect("default observed timestamp ingest");
@@ -574,7 +587,9 @@ async fn dvm_validation_receipt_ingest_rejects_invalid_verified_order_id() {
let error = sdk
.dvm()
- .ingest_validation_receipt(DvmValidationReceiptIngestRequest::new(receipt_event))
+ .ingest_validation_receipt(DvmValidationReceiptIngestRequest::new(
+ signed_event_from_envelope(receipt_event),
+ ))
.await
.expect_err("invalid order id");
@@ -591,23 +606,21 @@ async fn dvm_validation_receipt_ingest_rejects_invalid_verified_order_id() {
#[tokio::test]
async fn dvm_validation_receipt_ingest_rejects_invalid_receipt_event_id() {
- let (_tempdir, sdk, store) = directory_sdk_and_store().await;
- let mut receipt_event = signed_validation_receipt_event(
+ let (_tempdir, _sdk, store) = directory_sdk_and_store().await;
+ let receipt_event = signed_validation_receipt_event(
"order-dvm-bad-receipt-id",
&deterministic_event_id("listing-event"),
&deterministic_event_id("request-event"),
&deterministic_event_id("decision-event"),
12,
);
- receipt_event.id = "bad id".to_owned();
-
- let error = sdk
- .dvm()
- .ingest_validation_receipt(DvmValidationReceiptIngestRequest::new(receipt_event))
- .await
+ let mut wire = receipt_event.to_nip01_wire();
+ wire.id = "bad id".to_owned();
+ let raw_json = serde_json::to_string(&wire).expect("raw event json");
+ let error = RadrootsSignedEvent::from_wire_unchecked(wire, raw_json)
.expect_err("invalid receipt event id");
- assert!(matches!(error, RadrootsSdkError::InvalidRequest { .. }));
+ assert!(error.to_string().contains("event envelope id is invalid"));
assert_eq!(
store
.status_summary()
@@ -845,7 +858,7 @@ fn signed_validation_receipt_event(
fn signed_event(
secret_key_hex: &str,
created_at: u32,
- parts: radroots_event_codec::wire::WireEventParts,
+ parts: RadrootsNip01EventWireParts,
) -> RadrootsEventEnvelope {
let secret_key = RadrootsNostrSecretKey::from_hex(secret_key_hex).expect("secret key");
let keys = RadrootsNostrKeys::new(secret_key);
diff --git a/crates/sdk/tests/farms_runtime.rs b/crates/sdk/tests/farms_runtime.rs
@@ -68,29 +68,29 @@ impl RadrootsEventSigner for FixtureSigner {
&self,
draft: &RadrootsEventDraft,
) -> Result<RadrootsSignedEvent, RadrootsSignerError> {
- if self.pubkey().as_str() != draft.expected_pubkey.as_str() {
+ if self.pubkey().as_str() != draft.expected_pubkey_str() {
return Err(RadrootsSignerError::SigningFailed {
message: "wrong fixture signer".to_owned(),
});
}
let sig = "f".repeat(128);
let raw_json = serde_json::json!({
- "id": draft.expected_event_id,
+ "id": draft.expected_event_id_str(),
"pubkey": self.pubkey().as_str(),
- "created_at": draft.created_at,
- "kind": draft.kind,
- "tags": draft.tags,
- "content": draft.content,
+ "created_at": draft.created_at_u64(),
+ "kind": draft.kind_u32(),
+ "tags": draft.tags_as_vec(),
+ "content": draft.content(),
"sig": sig,
})
.to_string();
RadrootsSignedEvent::new(RadrootsSignedEventParts {
- id: draft.expected_event_id.clone(),
+ id: draft.expected_event_id_str().to_owned(),
pubkey: self.pubkey().as_str().to_owned(),
- created_at: draft.created_at,
- kind: draft.kind,
- tags: draft.tags.clone(),
- content: draft.content.clone(),
+ created_at: draft.created_at_u64(),
+ kind: draft.kind_u32(),
+ tags: draft.tags_as_vec(),
+ content: draft.content().to_owned(),
sig,
raw_json,
})
@@ -252,11 +252,11 @@ async fn farm_prepare_publish_is_side_effect_free() {
let request = FarmPreparePublishRequest::new(farmer_actor(), farm(FARM_A_D_TAG, "North Farm"));
let prepared = sdk.farms().prepare_publish(request).expect("prepared");
- assert_eq!(prepared.frozen_draft.kind, KIND_FARM);
+ assert_eq!(prepared.frozen_draft.kind_u32(), KIND_FARM);
assert_eq!(prepared.created_at.unix_seconds(), 1_700_000_000);
assert_eq!(
prepared.expected_event_id,
- prepared.frozen_draft.expected_event_id
+ prepared.frozen_draft.expected_event_id_str()
);
assert_eq!(
prepared.farm_addr.as_str(),
@@ -684,7 +684,7 @@ async fn farm_enqueue_publish_stores_event_and_queues_signed_outbox_without_prof
.expect("outbox event")
.expect("outbox event");
assert_eq!(outbox_event.state, RadrootsOutboxEventState::Signed);
- assert_eq!(outbox_event.draft.kind, KIND_FARM);
+ assert_eq!(outbox_event.draft.kind_u32(), KIND_FARM);
assert!(outbox_event.signed_event.is_some());
}
diff --git a/crates/sdk/tests/knowledge_public_api.rs b/crates/sdk/tests/knowledge_public_api.rs
@@ -1,6 +1,7 @@
#![cfg(feature = "knowledge")]
use nostr::{EventBuilder, Keys, Kind, Tag, Timestamp};
+use radroots_event::RadrootsEventEnvelopeParts;
use radroots_sdk::knowledge::prelude::*;
const SECRET_KEY_HEX: &str = "0101010101010101010101010101010101010101010101010101010101010101";
@@ -60,8 +61,8 @@ fn fluent_builders_auto_fill_schema_and_prepare_drafts() {
let claim_draft = claim_builder()
.build_draft(public_key_hex(), CREATED_AT)
.expect("claim draft");
- assert_eq!(article_draft.contract_id, WIKI_ARTICLE_CONTRACT_ID);
- assert_eq!(claim_draft.contract_id, KNOWLEDGE_CLAIM_CONTRACT_ID);
+ assert_eq!(article_draft.contract_id(), WIKI_ARTICLE_CONTRACT_ID);
+ assert_eq!(claim_draft.contract_id(), KNOWLEDGE_CLAIM_CONTRACT_ID);
}
#[test]
@@ -329,17 +330,20 @@ fn knowledge_draft_builder_freezes_mvp_drafts_without_runtime() {
.knowledge_field_report(&knowledge_field_report())
.expect("field report draft");
- assert_eq!(article.contract_id, WIKI_ARTICLE_CONTRACT_ID);
- assert_eq!(redirect.contract_id, WIKI_REDIRECT_CONTRACT_ID);
- assert_eq!(merge_request.contract_id, WIKI_MERGE_REQUEST_CONTRACT_ID);
- assert_eq!(source.contract_id, KNOWLEDGE_SOURCE_CONTRACT_ID);
- assert_eq!(claim.contract_id, KNOWLEDGE_CLAIM_CONTRACT_ID);
- assert_eq!(relation.contract_id, KNOWLEDGE_RELATION_CONTRACT_ID);
- assert_eq!(review.contract_id, KNOWLEDGE_REVIEW_CONTRACT_ID);
- assert_eq!(field_report.contract_id, KNOWLEDGE_FIELD_REPORT_CONTRACT_ID);
- assert_eq!(claim.expected_pubkey, public_key_hex());
- assert_eq!(claim.created_at, CREATED_AT);
- assert_eq!(claim.kind, KIND_KNOWLEDGE_CLAIM);
+ assert_eq!(article.contract_id(), WIKI_ARTICLE_CONTRACT_ID);
+ assert_eq!(redirect.contract_id(), WIKI_REDIRECT_CONTRACT_ID);
+ assert_eq!(merge_request.contract_id(), WIKI_MERGE_REQUEST_CONTRACT_ID);
+ assert_eq!(source.contract_id(), KNOWLEDGE_SOURCE_CONTRACT_ID);
+ assert_eq!(claim.contract_id(), KNOWLEDGE_CLAIM_CONTRACT_ID);
+ assert_eq!(relation.contract_id(), KNOWLEDGE_RELATION_CONTRACT_ID);
+ assert_eq!(review.contract_id(), KNOWLEDGE_REVIEW_CONTRACT_ID);
+ assert_eq!(
+ field_report.contract_id(),
+ KNOWLEDGE_FIELD_REPORT_CONTRACT_ID
+ );
+ assert_eq!(claim.expected_pubkey_str(), public_key_hex());
+ assert_eq!(claim.created_at_u64(), u64::from(CREATED_AT));
+ assert_eq!(claim.kind_u32(), KIND_KNOWLEDGE_CLAIM);
}
#[test]
@@ -397,7 +401,7 @@ fn knowledge_errors_expose_stable_codes() {
let draft_error: RadrootsSdkKnowledgeError = RadrootsEventDraft::new(
KNOWLEDGE_CLAIM_CONTRACT_ID,
KIND_KNOWLEDGE_CLAIM,
- CREATED_AT,
+ u64::from(CREATED_AT),
Vec::new(),
r#"{"schema":"radroots.knowledge.claim.v1","schema_version":1}"#,
public_key_hex(),
@@ -408,7 +412,7 @@ fn knowledge_errors_expose_stable_codes() {
assert_eq!(draft_error.inner_code(), "missing_tag");
}
-fn sign_parts(parts: WireEventParts) -> RadrootsEventEnvelope {
+fn sign_parts(parts: RadrootsNip01EventWireParts) -> RadrootsEventEnvelope {
let tags = parts
.tags
.into_iter()
@@ -421,10 +425,10 @@ fn sign_parts(parts: WireEventParts) -> RadrootsEventEnvelope {
.custom_created_at(Timestamp::from_secs(u64::from(CREATED_AT)))
.sign_with_keys(&keys)
.expect("signed event");
- RadrootsEventEnvelope {
+ RadrootsEventEnvelope::new(RadrootsEventEnvelopeParts {
id: event.id.to_hex(),
author: event.pubkey.to_hex(),
- created_at: event.created_at.as_secs() as u32,
+ created_at: event.created_at.as_secs(),
kind: u32::from(event.kind.as_u16()),
tags: event
.tags
@@ -434,7 +438,8 @@ fn sign_parts(parts: WireEventParts) -> RadrootsEventEnvelope {
.collect(),
content: event.content,
sig: event.sig.to_string(),
- }
+ })
+ .expect("event envelope")
}
fn public_key_hex() -> String {
diff --git a/crates/sdk/tests/listings_runtime.rs b/crates/sdk/tests/listings_runtime.rs
@@ -74,29 +74,29 @@ impl RadrootsEventSigner for FixtureSigner {
&self,
draft: &RadrootsEventDraft,
) -> Result<RadrootsSignedEvent, RadrootsSignerError> {
- if self.pubkey().as_str() != draft.expected_pubkey.as_str() {
+ if self.pubkey().as_str() != draft.expected_pubkey_str() {
return Err(RadrootsSignerError::SigningFailed {
message: "wrong fixture signer".to_owned(),
});
}
let sig = "f".repeat(128);
let raw_json = serde_json::json!({
- "id": draft.expected_event_id,
+ "id": draft.expected_event_id_str(),
"pubkey": self.pubkey().as_str(),
- "created_at": draft.created_at,
- "kind": draft.kind,
- "tags": draft.tags,
- "content": draft.content,
+ "created_at": draft.created_at_u64(),
+ "kind": draft.kind_u32(),
+ "tags": draft.tags_as_vec(),
+ "content": draft.content(),
"sig": sig,
})
.to_string();
RadrootsSignedEvent::new(RadrootsSignedEventParts {
- id: draft.expected_event_id.clone(),
+ id: draft.expected_event_id_str().to_owned(),
pubkey: self.pubkey().as_str().to_owned(),
- created_at: draft.created_at,
- kind: draft.kind,
- tags: draft.tags.clone(),
- content: draft.content.clone(),
+ created_at: draft.created_at_u64(),
+ kind: draft.kind_u32(),
+ tags: draft.tags_as_vec(),
+ content: draft.content().to_owned(),
sig,
raw_json,
})
@@ -207,11 +207,11 @@ async fn prepare_publish_is_side_effect_free() {
let request = ListingPreparePublishRequest::new(actor(), listing(LISTING_A_D_TAG, "Coffee"));
let prepared = sdk.listings().prepare_publish(request).expect("prepared");
- assert_eq!(prepared.frozen_draft.kind, KIND_LISTING);
+ assert_eq!(prepared.frozen_draft.kind_u32(), KIND_LISTING);
assert_eq!(prepared.created_at.unix_seconds(), 1_700_000_000);
assert_eq!(
prepared.expected_event_id,
- prepared.frozen_draft.expected_event_id
+ prepared.frozen_draft.expected_event_id_str()
);
assert_eq!(
prepared.public_listing_addr.as_str(),
@@ -648,7 +648,7 @@ async fn explicit_historical_created_at_does_not_backdate_observed_at_ms() {
.await
.expect("outbox event")
.expect("outbox event");
- assert_eq!(outbox_event.draft.created_at, 1_600_000_000);
+ assert_eq!(outbox_event.draft.created_at_u64(), 1_600_000_000);
assert_eq!(
outbox_event.event_store_ingested_at_ms,
Some(observed_at_ms)
diff --git a/crates/sdk/tests/orders_runtime.rs b/crates/sdk/tests/orders_runtime.rs
@@ -16,9 +16,11 @@ use radroots_core::{
};
#[cfg(feature = "transport-nostr-runtime")]
use radroots_event::ids::RadrootsPublicKey;
+use radroots_event::wire::RadrootsNip01EventWireParts;
use radroots_event::{
RadrootsEventEnvelope, RadrootsEventPtr,
contract::RadrootsActorRole,
+ draft::RadrootsSignedEvent,
ids::{RadrootsEventId, RadrootsListingAddress, RadrootsOrderId, RadrootsOrderRevisionId},
kinds::{
KIND_LISTING, KIND_ORDER_DECISION, KIND_ORDER_REQUEST, KIND_POST,
@@ -31,7 +33,6 @@ use radroots_event::{
RadrootsOrderRevisionOutcome,
},
};
-use radroots_event_codec::wire::WireEventParts;
use radroots_event_store::{RadrootsEventIngest, RadrootsEventStore};
use radroots_nostr::prelude::{
RadrootsNostrKeys, RadrootsNostrSecretKey, RadrootsNostrTimestamp, radroots_event_from_nostr,
@@ -88,6 +89,12 @@ const SELLER_PUBLIC_KEY_HEX: &str =
const SERVICE_SECRET_KEY_HEX: &str =
"48314941f2c9c01ef99f531df7b1d59a8de23dbeb45a498e5aa5f671e921931f";
const RELAY: &str = "wss://relay.radroots.test";
+
+fn signed_event_from_envelope(event: RadrootsEventEnvelope) -> RadrootsSignedEvent {
+ let wire = event.to_nip01_wire();
+ let raw_json = serde_json::to_string(&wire).expect("raw event json");
+ RadrootsSignedEvent::from_wire_verified_id(wire, raw_json).expect("signed event")
+}
#[cfg(any())]
const OTHER_PUBLIC_KEY_HEX: &str =
"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc";
@@ -689,11 +696,11 @@ async fn order_submit_prepare_is_side_effect_free() {
prepared.listing_event_id.as_str(),
listing_event.id.as_str()
);
- assert_eq!(prepared.frozen_draft.kind, KIND_ORDER_REQUEST);
+ assert_eq!(prepared.frozen_draft.kind_u32(), KIND_ORDER_REQUEST);
assert_eq!(prepared.created_at.unix_seconds(), 1_700_000_000);
assert_eq!(
prepared.expected_event_id,
- prepared.frozen_draft.expected_event_id
+ prepared.frozen_draft.expected_event_id_str()
);
assert_eq!(
store
@@ -939,7 +946,7 @@ async fn order_submit_enqueue_stores_event_queues_outbox_and_status_sees_request
.expect("outbox event")
.expect("outbox event");
assert_eq!(outbox_event.state, RadrootsOutboxEventState::Signed);
- assert_eq!(outbox_event.draft.kind, KIND_ORDER_REQUEST);
+ assert_eq!(outbox_event.draft.kind_u32(), KIND_ORDER_REQUEST);
assert!(outbox_event.signed_event.is_some());
let status = sdk
@@ -1221,7 +1228,7 @@ async fn trade_product_clients_resync_committed_after_rhi_validation_receipt() {
let ingest = seller_sdk
.dvm()
.ingest_validation_receipt(
- DvmValidationReceiptIngestRequest::new(receipt_event)
+ DvmValidationReceiptIngestRequest::new(signed_event_from_envelope(receipt_event))
.with_expected_order_id(propose_receipt.order_id.clone())
.with_expected_listing_event_id(propose_receipt.listing_event_id.clone())
.with_expected_root_event_id(propose_receipt.signed_event_id.clone())
@@ -1233,7 +1240,7 @@ async fn trade_product_clients_resync_committed_after_rhi_validation_receipt() {
assert_eq!(ingest.receipt_event_id, receipt_event_id);
seller_store
.ingest_event(RadrootsEventIngest::new(
- radroots_event_from_nostr(&worker_raw_event),
+ signed_event_from_envelope(radroots_event_from_nostr(&worker_raw_event)),
4_050,
))
.await
@@ -1331,10 +1338,9 @@ async fn trade_status_trust_policy_requires_trusted_cryptographic_receipt_for_co
let (_tempdir, sdk, store) = directory_sdk_and_store().await;
let order_id = "trade-status-trusted-crypto";
let request_event = signed_order_request_event(order_id, 70);
- let request_event_id = RadrootsEventId::parse(request_event.id.as_str()).expect("request id");
+ let request_event_id = RadrootsEventId::parse(request_event.id_str()).expect("request id");
let decision_event = signed_order_decision_event(order_id, &request_event_id, 71);
- let decision_event_id =
- RadrootsEventId::parse(decision_event.id.as_str()).expect("decision id");
+ let decision_event_id = RadrootsEventId::parse(decision_event.id_str()).expect("decision id");
let listing_event_id = deterministic_event_id("listing-event");
let receipt_raw_event = signed_raw_sp1_validation_receipt_event(
order_id,
@@ -1361,7 +1367,10 @@ async fn trade_status_trust_policy_requires_trusted_cryptographic_receipt_for_co
(radroots_event_from_nostr(&worker_raw_event), 7_300),
] {
store
- .ingest_event(RadrootsEventIngest::new(event, observed_at_ms))
+ .ingest_event(RadrootsEventIngest::new(
+ signed_event_from_envelope(event),
+ observed_at_ms,
+ ))
.await
.expect("ingest trade status trust event");
}
@@ -1792,7 +1801,7 @@ async fn trade_product_accept_require_explicit_evidence_ingests_supplied_request
PublishMode::EnqueueOnly,
SatisfactionPolicy::NoWait,
TradeEvidenceMode::require_explicit_evidence([
- TradeEvidenceIngestRequest::new(request_event),
+ TradeEvidenceIngestRequest::new(signed_event_from_envelope(request_event)),
]),
)
.try_with_idempotency_key("trade-product-explicit-accept")
@@ -1943,10 +1952,7 @@ async fn trade_validation_receipts_fetch_from_relays_and_select_worker_evidence(
assert_eq!(list.receipts.len(), 1);
assert!(list.invalid_receipts.is_empty());
assert_eq!(list.nostr_evidence.out_of_filter_count, 2);
- assert_eq!(
- list.receipts[0].event.id.as_str(),
- receipt_event_id.as_str()
- );
+ assert_eq!(list.receipts[0].event.id_str(), receipt_event_id.as_str());
let trusted = list.receipts[0]
.worker_evidence
.trusted
@@ -3300,7 +3306,7 @@ async fn trade_product_propose_dry_run_returns_plan_without_local_side_effects()
};
assert_eq!(plan.order_id.as_str(), "trade-product-dry-run");
- assert_eq!(plan.frozen_draft.kind, KIND_ORDER_REQUEST);
+ assert_eq!(plan.frozen_draft.kind_u32(), KIND_ORDER_REQUEST);
assert_eq!(plan.expected_event_id, plan.workflow.expected_event_id);
assert_eq!(
store
@@ -3904,7 +3910,7 @@ fn validation_receipt_wire_parts(
listing_event_id: &RadrootsEventId,
root_event_id: &RadrootsEventId,
target_event_id: &RadrootsEventId,
-) -> WireEventParts {
+) -> RadrootsNip01EventWireParts {
validation_receipt_wire_parts_with_proof(
raw_order_id,
listing_event_id,
@@ -3920,7 +3926,7 @@ fn validation_receipt_wire_parts_with_proof(
root_event_id: &RadrootsEventId,
target_event_id: &RadrootsEventId,
proof_system: RadrootsValidationReceiptProofSystem,
-) -> WireEventParts {
+) -> RadrootsNip01EventWireParts {
let proof = match proof_system {
RadrootsValidationReceiptProofSystem::None => RadrootsValidationReceiptProof {
inline_proof_base64: None,
@@ -4022,7 +4028,7 @@ fn signed_raw_sp1_worker_result_event(
signed_raw_event(
SERVICE_SECRET_KEY_HEX,
created_at,
- WireEventParts {
+ RadrootsNip01EventWireParts {
kind: KIND_TRADE_TRANSITION_PROOF_RESULT,
content,
tags: vec![
@@ -4074,7 +4080,7 @@ fn signed_raw_worker_result_event(
signed_raw_event(
SERVICE_SECRET_KEY_HEX,
created_at,
- WireEventParts {
+ RadrootsNip01EventWireParts {
kind: KIND_TRADE_TRANSITION_PROOF_RESULT,
content,
tags: vec![
@@ -4155,7 +4161,10 @@ async fn ingest_status_noise_events(
for index in 0..non_trade_count {
store
.ingest_event(RadrootsEventIngest::new(
- signed_status_noise_post_event(index, 32_000 + index as u32),
+ signed_event_from_envelope(signed_status_noise_post_event(
+ index,
+ 32_000 + index as u32,
+ )),
1_700_200_000_000 + index,
))
.await
@@ -4166,7 +4175,10 @@ async fn ingest_status_noise_events(
let order_id = format!("status-noise-background-{index:03}");
store
.ingest_event(RadrootsEventIngest::new(
- signed_order_request_event(&order_id, 33_000 + index as u32),
+ signed_event_from_envelope(signed_order_request_event(
+ &order_id,
+ 33_000 + index as u32,
+ )),
1_700_200_100_000 + index,
))
.await
@@ -4185,13 +4197,17 @@ fn hash32(ch: char) -> String {
fn signed_event(
secret_key_hex: &str,
created_at: u32,
- parts: WireEventParts,
+ parts: RadrootsNip01EventWireParts,
) -> RadrootsEventEnvelope {
let event = signed_raw_event(secret_key_hex, created_at, parts);
radroots_event_from_nostr(&event)
}
-fn signed_raw_event(secret_key_hex: &str, created_at: u32, parts: WireEventParts) -> nostr::Event {
+fn signed_raw_event(
+ secret_key_hex: &str,
+ created_at: u32,
+ parts: RadrootsNip01EventWireParts,
+) -> nostr::Event {
let secret_key = RadrootsNostrSecretKey::from_hex(secret_key_hex).expect("secret key");
let keys = RadrootsNostrKeys::new(secret_key);
radroots_nostr_build_event(parts.kind, parts.content, parts.tags)
@@ -4223,7 +4239,7 @@ fn signed_raw_order_request_event(raw_order_id: &str, created_at: u32) -> nostr:
#[cfg(any())]
fn request_event_ptr(event: &RadrootsEventEnvelope) -> RadrootsEventPtr {
RadrootsEventPtr {
- id: event.id.clone(),
+ id: event.id_str().to_owned(),
relays: Some(RELAY.to_owned()),
}
}
@@ -4268,7 +4284,7 @@ fn signed_status_noise_post_event(index: i64, created_at: u32) -> RadrootsEventE
signed_event(
SELLER_SECRET_KEY_HEX,
created_at,
- WireEventParts {
+ RadrootsNip01EventWireParts {
kind: KIND_POST,
content: format!("local status noise {index}"),
tags: Vec::new(),
@@ -4280,7 +4296,7 @@ fn signed_non_order_event(created_at: u32) -> RadrootsEventEnvelope {
signed_event(
SELLER_SECRET_KEY_HEX,
created_at,
- WireEventParts {
+ RadrootsNip01EventWireParts {
kind: KIND_LISTING,
content: "{}".to_owned(),
tags: vec![vec!["d".to_owned(), "not-an-order".to_owned()]],
@@ -4293,9 +4309,10 @@ fn signed_non_order_event(created_at: u32) -> RadrootsEventEnvelope {
async fn order_request_evidence_ingest_stores_request_and_enables_decision_enqueue() {
let (_tempdir, sdk, store) = directory_sdk_and_store().await;
let request_event = signed_order_request_event("order-decision-ingested", 39);
- let request_event_id = RadrootsEventId::parse(request_event.id.as_str()).expect("request id");
- let ingest_request = TradeRequestEvidenceIngestRequest::new(request_event.clone())
- .with_observed_at(RadrootsSdkTimestamp::from_unix_seconds(1_700_000_039));
+ let request_event_id = RadrootsEventId::parse(request_event.id_str()).expect("request id");
+ let ingest_request =
+ TradeRequestEvidenceIngestRequest::new(signed_event_from_envelope(request_event.clone()))
+ .with_observed_at(RadrootsSdkTimestamp::from_unix_seconds(1_700_000_039));
let ingest_receipt = sdk
.trades()
@@ -4359,13 +4376,15 @@ async fn order_request_evidence_ingest_stores_request_and_enables_decision_enque
async fn order_evidence_ingest_stores_lifecycle_evidence_for_projection() {
let (_tempdir, sdk, store) = directory_sdk_and_store().await;
let request_event = signed_order_request_event("order-evidence-ingest", 39);
- let request_event_id = RadrootsEventId::parse(request_event.id.as_str()).expect("request id");
+ let request_event_id = RadrootsEventId::parse(request_event.id_str()).expect("request id");
let decision_event =
signed_order_decision_event("order-evidence-ingest", &request_event_id, 40);
let request_receipt = sdk
.trades()
- .ingest_evidence(TradeEvidenceIngestRequest::new(request_event.clone()))
+ .ingest_evidence(TradeEvidenceIngestRequest::new(signed_event_from_envelope(
+ request_event.clone(),
+ )))
.await
.expect("request evidence");
assert_eq!(request_receipt.order_id.as_str(), "order-evidence-ingest");
@@ -4375,7 +4394,9 @@ async fn order_evidence_ingest_stores_lifecycle_evidence_for_projection() {
let decision_receipt = sdk
.trades()
- .ingest_evidence(TradeEvidenceIngestRequest::new(decision_event.clone()))
+ .ingest_evidence(TradeEvidenceIngestRequest::new(signed_event_from_envelope(
+ decision_event.clone(),
+ )))
.await
.expect("decision evidence");
assert_eq!(decision_receipt.order_id.as_str(), "order-evidence-ingest");
@@ -4385,7 +4406,9 @@ async fn order_evidence_ingest_stores_lifecycle_evidence_for_projection() {
let duplicate_receipt = sdk
.trades()
- .ingest_evidence(TradeEvidenceIngestRequest::new(decision_event))
+ .ingest_evidence(TradeEvidenceIngestRequest::new(signed_event_from_envelope(
+ decision_event,
+ )))
.await
.expect("duplicate decision evidence");
assert_eq!(duplicate_receipt.local_event_seq, 2);
@@ -4420,7 +4443,9 @@ async fn order_evidence_ingest_rejects_non_order_events() {
let (_tempdir, sdk, store) = directory_sdk_and_store().await;
let error = sdk
.trades()
- .ingest_evidence(TradeEvidenceIngestRequest::new(signed_non_order_event(41)))
+ .ingest_evidence(TradeEvidenceIngestRequest::new(signed_event_from_envelope(
+ signed_non_order_event(41),
+ )))
.await
.expect_err("non order event");
@@ -4443,7 +4468,9 @@ async fn order_request_evidence_ingest_rejects_non_request_events() {
let error = sdk
.trades()
- .ingest_request_evidence(TradeRequestEvidenceIngestRequest::new(decision_event))
+ .ingest_request_evidence(TradeRequestEvidenceIngestRequest::new(
+ signed_event_from_envelope(decision_event),
+ ))
.await
.expect_err("non request event");
@@ -4483,11 +4510,11 @@ async fn order_decision_prepare_accept_and_decline_are_side_effect_free() {
assert_eq!(accepted.buyer_pubkey.as_str(), BUYER_PUBLIC_KEY_HEX);
assert_eq!(accepted.seller_pubkey.as_str(), SELLER_PUBLIC_KEY_HEX);
assert_eq!(accepted.request_event_id, request_event_id);
- assert_eq!(accepted.frozen_draft.kind, KIND_ORDER_DECISION);
+ assert_eq!(accepted.frozen_draft.kind_u32(), KIND_ORDER_DECISION);
assert_eq!(accepted.created_at.unix_seconds(), 1_700_000_000);
assert_eq!(
accepted.expected_event_id,
- accepted.frozen_draft.expected_event_id
+ accepted.frozen_draft.expected_event_id_str()
);
let mut declined_payload = order_decision("order-decision-prepare-decline");
@@ -4504,7 +4531,7 @@ async fn order_decision_prepare_accept_and_decline_are_side_effect_free() {
.expect("declined plan");
assert_eq!(declined.order_id.as_str(), "order-decision-prepare-decline");
- assert_eq!(declined.frozen_draft.kind, KIND_ORDER_DECISION);
+ assert_eq!(declined.frozen_draft.kind_u32(), KIND_ORDER_DECISION);
assert_eq!(
store
.status_summary()
@@ -4661,7 +4688,10 @@ async fn order_decision_runtime_dtos_serialize_deterministically() {
let request_event = signed_order_request_event("order-decision-serialized-enqueue", 45);
store
- .ingest_event(RadrootsEventIngest::new(request_event.clone(), 4_500))
+ .ingest_event(RadrootsEventIngest::new(
+ signed_event_from_envelope(request_event.clone()),
+ 4_500,
+ ))
.await
.expect("ingest request");
let enqueue_request = TradeDecisionEnqueueRequest::new(
@@ -4799,7 +4829,7 @@ async fn order_decision_runtime_dtos_serialize_deterministically() {
"order_id": receipt.order_id.as_str(),
"locator": {
"trade_id": receipt.order_id.as_str(),
- "root_event_id": request_event.id.as_str(),
+ "root_event_id": request_event.id_str(),
"listing_addr": receipt.listing_addr.as_str(),
"buyer_pubkey": BUYER_PUBLIC_KEY_HEX,
"seller_pubkey": SELLER_PUBLIC_KEY_HEX
@@ -4807,7 +4837,7 @@ async fn order_decision_runtime_dtos_serialize_deterministically() {
"listing_addr": receipt.listing_addr.as_str(),
"buyer_pubkey": BUYER_PUBLIC_KEY_HEX,
"seller_pubkey": SELLER_PUBLIC_KEY_HEX,
- "request_event_id": request_event.id.as_str(),
+ "request_event_id": request_event.id_str(),
"expected_event_id": receipt.expected_event_id.as_str(),
"signed_event_id": receipt.signed_event_id.as_str(),
"local_event_seq": 2,
@@ -5069,18 +5099,19 @@ async fn order_revision_and_cancellation_dtos_serialize_deterministically() {
let event = signed_order_request_event("order-evidence-dto", 77);
let request_evidence =
- TradeRequestEvidenceIngestRequest::new(event.clone()).with_observed_at(created_at);
+ TradeRequestEvidenceIngestRequest::new(signed_event_from_envelope(event.clone()))
+ .with_observed_at(created_at);
let request_evidence_json =
serde_json::to_value(&request_evidence).expect("request evidence json");
assert_struct_serialize_error_paths(&request_evidence, 2);
- assert_eq!(request_evidence_json["event"]["id"], event.id.as_str());
+ assert_eq!(request_evidence_json["event"]["id"], event.id_str());
assert_eq!(request_evidence_json["observed_at"], 1_700_000_654);
- let order_evidence =
- TradeEvidenceIngestRequest::new(event.clone()).with_observed_at(created_at);
+ let order_evidence = TradeEvidenceIngestRequest::new(signed_event_from_envelope(event.clone()))
+ .with_observed_at(created_at);
let order_evidence_json = serde_json::to_value(&order_evidence).expect("order evidence json");
assert_struct_serialize_error_paths(&order_evidence, 2);
- assert_eq!(order_evidence_json["event"]["id"], event.id.as_str());
+ assert_eq!(order_evidence_json["event"]["id"], event.id_str());
assert_eq!(order_evidence_json["observed_at"], 1_700_000_654);
}
@@ -5089,9 +5120,12 @@ async fn order_revision_and_cancellation_dtos_serialize_deterministically() {
async fn order_decision_enqueue_accept_stores_event_queues_outbox_and_updates_status() {
let (_tempdir, sdk, store) = directory_sdk_and_store().await;
let request_event = signed_order_request_event("order-decision-accept", 40);
- let request_event_id = RadrootsEventId::parse(request_event.id.as_str()).expect("request id");
+ let request_event_id = RadrootsEventId::parse(request_event.id_str()).expect("request id");
store
- .ingest_event(RadrootsEventIngest::new(request_event.clone(), 4_000))
+ .ingest_event(RadrootsEventIngest::new(
+ signed_event_from_envelope(request_event.clone()),
+ 4_000,
+ ))
.await
.expect("ingest request");
let request = TradeDecisionEnqueueRequest::new(
@@ -5152,7 +5186,7 @@ async fn order_decision_enqueue_accept_stores_event_queues_outbox_and_updates_st
.expect("outbox event")
.expect("outbox event");
assert_eq!(outbox_event.state, RadrootsOutboxEventState::Signed);
- assert_eq!(outbox_event.draft.kind, KIND_ORDER_DECISION);
+ assert_eq!(outbox_event.draft.kind_u32(), KIND_ORDER_DECISION);
assert!(outbox_event.signed_event.is_some());
let status = sdk
@@ -5168,7 +5202,7 @@ async fn order_decision_enqueue_accept_stores_event_queues_outbox_and_updates_st
.request_event_id
.as_ref()
.map(RadrootsEventId::as_str),
- Some(request_event.id.as_str())
+ Some(request_event.id_str())
);
assert_eq!(
status
@@ -5194,7 +5228,10 @@ async fn order_decision_enqueue_decline_stores_event_and_status_sees_declined()
let (_tempdir, sdk, store) = directory_sdk_and_store().await;
let request_event = signed_order_request_event("order-decision-decline", 41);
store
- .ingest_event(RadrootsEventIngest::new(request_event.clone(), 4_100))
+ .ingest_event(RadrootsEventIngest::new(
+ signed_event_from_envelope(request_event.clone()),
+ 4_100,
+ ))
.await
.expect("ingest request");
let mut decision = order_decision("order-decision-decline");
@@ -5290,7 +5327,10 @@ async fn order_decision_enqueue_returns_sanitized_signer_errors_before_decision_
let (_tempdir, sdk, store) = directory_sdk_and_store().await;
let request_event = signed_order_request_event("order-decision-wrong-signer", 42);
store
- .ingest_event(RadrootsEventIngest::new(request_event.clone(), 4_200))
+ .ingest_event(RadrootsEventIngest::new(
+ signed_event_from_envelope(request_event.clone()),
+ 4_200,
+ ))
.await
.expect("ingest request");
let request = TradeDecisionEnqueueRequest::new(
@@ -5332,7 +5372,7 @@ async fn order_decision_enqueue_returns_sanitized_signer_errors_before_decision_
async fn order_decision_enqueue_rejects_existing_decision_state_before_mutation() {
let (_tempdir, sdk, store) = directory_sdk_and_store().await;
let request_event = signed_order_request_event("order-decision-conflict", 43);
- let request_event_id = RadrootsEventId::parse(request_event.id.as_str()).expect("request id");
+ let request_event_id = RadrootsEventId::parse(request_event.id_str()).expect("request id");
let decision_event =
signed_order_decision_event("order-decision-conflict", &request_event_id, 44);
for (event, observed_at_ms) in [
@@ -5340,7 +5380,10 @@ async fn order_decision_enqueue_rejects_existing_decision_state_before_mutation(
(decision_event.clone(), 4_400),
] {
store
- .ingest_event(RadrootsEventIngest::new(event, observed_at_ms))
+ .ingest_event(RadrootsEventIngest::new(
+ signed_event_from_envelope(event),
+ observed_at_ms,
+ ))
.await
.expect("ingest");
}
@@ -5385,7 +5428,7 @@ async fn order_decision_enqueue_rejects_existing_decision_state_before_mutation(
.decision_event_id
.as_ref()
.map(RadrootsEventId::as_str),
- Some(decision_event.id.as_str())
+ Some(decision_event.id_str())
);
}
@@ -5394,9 +5437,12 @@ async fn order_decision_enqueue_rejects_existing_decision_state_before_mutation(
async fn order_revision_lifecycle_accepts_proposal_and_waits_for_rhi() {
let (_tempdir, sdk, store) = directory_sdk_and_store().await;
let request_event = signed_order_request_event("order-lifecycle-agreement", 50);
- let request_event_id = RadrootsEventId::parse(request_event.id.as_str()).expect("request id");
+ let request_event_id = RadrootsEventId::parse(request_event.id_str()).expect("request id");
store
- .ingest_event(RadrootsEventIngest::new(request_event.clone(), 5_000))
+ .ingest_event(RadrootsEventIngest::new(
+ signed_event_from_envelope(request_event.clone()),
+ 5_000,
+ ))
.await
.expect("ingest request");
@@ -5544,9 +5590,12 @@ async fn order_revision_lifecycle_accepts_proposal_and_waits_for_rhi() {
async fn order_revision_proposal_status_exposes_pending_and_blocks_follow_on_lifecycle() {
let (_tempdir, sdk, store) = directory_sdk_and_store().await;
let request_event = signed_order_request_event("order-lifecycle-pending-revision", 55);
- let request_event_id = RadrootsEventId::parse(request_event.id.as_str()).expect("request id");
+ let request_event_id = RadrootsEventId::parse(request_event.id_str()).expect("request id");
store
- .ingest_event(RadrootsEventIngest::new(request_event.clone(), 5_500))
+ .ingest_event(RadrootsEventIngest::new(
+ signed_event_from_envelope(request_event.clone()),
+ 5_500,
+ ))
.await
.expect("ingest request");
let proposal = order_revision_proposal(
@@ -5662,9 +5711,12 @@ async fn order_revision_proposal_status_exposes_pending_and_blocks_follow_on_lif
async fn order_declined_revision_finalizes_declined_negotiation() {
let (_tempdir, sdk, store) = directory_sdk_and_store().await;
let request_event = signed_order_request_event("order-lifecycle-declined-revision", 56);
- let request_event_id = RadrootsEventId::parse(request_event.id.as_str()).expect("request id");
+ let request_event_id = RadrootsEventId::parse(request_event.id_str()).expect("request id");
store
- .ingest_event(RadrootsEventIngest::new(request_event.clone(), 5_600))
+ .ingest_event(RadrootsEventIngest::new(
+ signed_event_from_envelope(request_event.clone()),
+ 5_600,
+ ))
.await
.expect("ingest request");
let proposal = order_revision_proposal(
@@ -5784,9 +5836,12 @@ async fn order_declined_revision_finalizes_declined_negotiation() {
async fn order_cancel_lifecycle_enqueue_updates_status() {
let (_tempdir, sdk, store) = directory_sdk_and_store().await;
let request_event = signed_order_request_event("order-lifecycle-cancel", 60);
- let request_event_id = RadrootsEventId::parse(request_event.id.as_str()).expect("request id");
+ let request_event_id = RadrootsEventId::parse(request_event.id_str()).expect("request id");
store
- .ingest_event(RadrootsEventIngest::new(request_event.clone(), 6_000))
+ .ingest_event(RadrootsEventIngest::new(
+ signed_event_from_envelope(request_event.clone()),
+ 6_000,
+ ))
.await
.expect("ingest request");
let cancellation_actor = buyer_actor();
@@ -5882,7 +5937,7 @@ async fn order_cancel_lifecycle_enqueue_updates_status() {
async fn order_lifecycle_enqueue_rejects_invalid_state_before_mutation() {
let (_tempdir, sdk, store) = directory_sdk_and_store().await;
let request_event = signed_order_request_event("order-lifecycle-invalid", 70);
- let request_event_id = RadrootsEventId::parse(request_event.id.as_str()).expect("request id");
+ let request_event_id = RadrootsEventId::parse(request_event.id_str()).expect("request id");
let missing = sdk
.trades()
.enqueue_revision_proposal_with_explicit_signer(
@@ -5916,7 +5971,10 @@ async fn order_lifecycle_enqueue_rejects_invalid_state_before_mutation() {
);
store
- .ingest_event(RadrootsEventIngest::new(request_event.clone(), 7_000))
+ .ingest_event(RadrootsEventIngest::new(
+ signed_event_from_envelope(request_event.clone()),
+ 7_000,
+ ))
.await
.expect("ingest request");
let decision_receipt = sdk
@@ -6043,9 +6101,12 @@ async fn order_status_query_uses_indexed_order_id_under_background_event_noise()
.await;
let request_event = signed_order_request_event("order-status-noise-active", 31_000);
- let request_event_id = request_event.id.clone();
+ let request_event_id = request_event.id().clone();
store
- .ingest_event(RadrootsEventIngest::new(request_event, 1_700_200_000_000))
+ .ingest_event(RadrootsEventIngest::new(
+ signed_event_from_envelope(request_event),
+ 1_700_200_000_000,
+ ))
.await
.expect("active order ingest");
@@ -6588,7 +6649,7 @@ fn order_status_issue_mapping_preserves_kind_codes_and_event_ids() {
async fn order_status_projects_local_request_and_decision_events() {
let (_tempdir, sdk, store) = directory_sdk_and_store().await;
let request_event = signed_order_request_event("order-1", 20);
- let request_event_id = RadrootsEventId::parse(request_event.id.as_str()).expect("request id");
+ let request_event_id = RadrootsEventId::parse(request_event.id_str()).expect("request id");
let decision_event = signed_order_decision_event("order-1", &request_event_id, 21);
for (event, observed_at_ms) in [
@@ -6596,7 +6657,10 @@ async fn order_status_projects_local_request_and_decision_events() {
(decision_event.clone(), 2_100),
] {
store
- .ingest_event(RadrootsEventIngest::new(event, observed_at_ms))
+ .ingest_event(RadrootsEventIngest::new(
+ signed_event_from_envelope(event),
+ observed_at_ms,
+ ))
.await
.expect("ingest");
}
@@ -6618,7 +6682,7 @@ async fn order_status_projects_local_request_and_decision_events() {
.iter()
.map(RadrootsEventId::as_str)
.collect::<Vec<_>>(),
- vec![request_event.id.as_str(), decision_event.id.as_str()]
+ vec![request_event.id_str(), decision_event.id_str()]
);
assert_eq!(receipt.status, TradeStatusKind::AgreedPendingRhi);
assert_eq!(
@@ -6626,18 +6690,18 @@ async fn order_status_projects_local_request_and_decision_events() {
.request_event_id
.as_ref()
.map(RadrootsEventId::as_str),
- Some(request_event.id.as_str())
+ Some(request_event.id_str())
);
assert_eq!(
receipt
.decision_event_id
.as_ref()
.map(RadrootsEventId::as_str),
- Some(decision_event.id.as_str())
+ Some(decision_event.id_str())
);
assert_eq!(
receipt.last_event_id.as_ref().map(RadrootsEventId::as_str),
- Some(decision_event.id.as_str())
+ Some(decision_event.id_str())
);
assert_eq!(receipt.listing_addr, Some(listing_address()));
assert_eq!(
@@ -6671,12 +6735,15 @@ async fn order_status_projects_local_request_and_decision_events() {
async fn order_status_reports_limited_local_results() {
let (_tempdir, sdk, store) = directory_sdk_and_store().await;
let request_event = signed_order_request_event("order-1", 25);
- let request_event_id = RadrootsEventId::parse(request_event.id.as_str()).expect("request id");
+ let request_event_id = RadrootsEventId::parse(request_event.id_str()).expect("request id");
let decision_event = signed_order_decision_event("order-1", &request_event_id, 26);
for (event, observed_at_ms) in [(request_event.clone(), 2_500), (decision_event, 2_600)] {
store
- .ingest_event(RadrootsEventIngest::new(event, observed_at_ms))
+ .ingest_event(RadrootsEventIngest::new(
+ signed_event_from_envelope(event),
+ observed_at_ms,
+ ))
.await
.expect("ingest");
}
@@ -6697,19 +6764,19 @@ async fn order_status_reports_limited_local_results() {
.iter()
.map(RadrootsEventId::as_str)
.collect::<Vec<_>>(),
- vec![request_event.id.as_str()]
+ vec![request_event.id_str()]
);
assert_eq!(
receipt
.request_event_id
.as_ref()
.map(RadrootsEventId::as_str),
- Some(request_event.id.as_str())
+ Some(request_event.id_str())
);
assert!(receipt.decision_event_id.is_none());
assert_eq!(
receipt.last_event_id.as_ref().map(RadrootsEventId::as_str),
- Some(request_event.id.as_str())
+ Some(request_event.id_str())
);
assert!(receipt.issues.is_empty());
}
@@ -6725,7 +6792,10 @@ async fn order_status_reports_root_ambiguity_for_reused_trade_ids() {
(second_request_event.clone(), 2_800),
] {
store
- .ingest_event(RadrootsEventIngest::new(event, observed_at_ms))
+ .ingest_event(RadrootsEventIngest::new(
+ signed_event_from_envelope(event),
+ observed_at_ms,
+ ))
.await
.expect("ingest");
}
@@ -6745,10 +6815,7 @@ async fn order_status_reports_root_ambiguity_for_reused_trade_ids() {
.iter()
.map(RadrootsEventId::as_str)
.collect::<Vec<_>>(),
- vec![
- first_request_event.id.as_str(),
- second_request_event.id.as_str()
- ]
+ vec![first_request_event.id_str(), second_request_event.id_str()]
);
assert!(receipt.issues.is_empty());
let candidate_roots = receipt
@@ -6765,10 +6832,7 @@ async fn order_status_reports_root_ambiguity_for_reused_trade_ids() {
.collect::<Vec<_>>();
assert_eq!(
candidate_roots,
- vec![
- first_request_event.id.as_str(),
- second_request_event.id.as_str()
- ]
+ vec![first_request_event.id_str(), second_request_event.id_str()]
);
assert_eq!(
receipt
@@ -6777,15 +6841,15 @@ async fn order_status_reports_root_ambiguity_for_reused_trade_ids() {
.map(|candidate| TradeStatusRequest::locator_selector(&candidate.locator))
.collect::<Vec<_>>(),
vec![
- format!("order-1@{}", first_request_event.id.as_str()),
- format!("order-1@{}", second_request_event.id.as_str())
+ format!("order-1@{}", first_request_event.id_str()),
+ format!("order-1@{}", second_request_event.id_str())
]
);
let root_specific = sdk
.trades()
.status(
- TradeStatusRequest::parse(&format!("order-1@{}", second_request_event.id.as_str()))
+ TradeStatusRequest::parse(&format!("order-1@{}", second_request_event.id_str()))
.expect("root status request"),
)
.await
@@ -6798,7 +6862,7 @@ async fn order_status_reports_root_ambiguity_for_reused_trade_ids() {
.request_event_id
.as_ref()
.map(RadrootsEventId::as_str),
- Some(second_request_event.id.as_str())
+ Some(second_request_event.id_str())
);
assert!(root_specific.ambiguity_candidates.is_empty());
}
@@ -6815,7 +6879,10 @@ async fn trade_product_mutation_returns_structured_ambiguity() {
(second_request_event.clone(), 2_800),
] {
store
- .ingest_event(RadrootsEventIngest::new(event, observed_at_ms))
+ .ingest_event(RadrootsEventIngest::new(
+ signed_event_from_envelope(event),
+ observed_at_ms,
+ ))
.await
.expect("ingest");
}
@@ -6860,10 +6927,7 @@ async fn trade_product_mutation_returns_structured_ambiguity() {
.expect("root event id")
})
.collect::<Vec<_>>(),
- vec![
- first_request_event.id.as_str(),
- second_request_event.id.as_str()
- ]
+ vec![first_request_event.id_str(), second_request_event.id_str()]
);
assert_eq!(
error.recovery_actions(),
@@ -6887,11 +6951,14 @@ async fn order_status_maps_malformed_local_data_to_sanitized_error() {
let request_event = signed_order_request_event("order-1", 30);
let raw_event_json = serde_json::to_string(&request_event).expect("raw event json");
store
- .ingest_event(RadrootsEventIngest::new(request_event.clone(), 3_000))
+ .ingest_event(RadrootsEventIngest::new(
+ signed_event_from_envelope(request_event.clone()),
+ 3_000,
+ ))
.await
.expect("ingest");
sqlx::query("UPDATE event_envelopes SET tags_json = '[' WHERE event_id = ?")
- .bind(request_event.id.as_str())
+ .bind(request_event.id_str())
.execute(store.pool())
.await
.expect("corrupt tags");
@@ -6906,7 +6973,7 @@ async fn order_status_maps_malformed_local_data_to_sanitized_error() {
assert!(matches!(error, RadrootsSdkError::Projection { .. }));
assert!(message.contains("contains invalid tags_json"));
assert!(!message.contains(raw_event_json.as_str()));
- assert!(!message.contains(request_event.sig.as_str()));
+ assert!(!message.contains(request_event.sig_str()));
assert!(!message.contains("\"tags\""));
assert!(!message.contains("\"content\""));
}
@@ -6917,7 +6984,10 @@ async fn trade_status_watch_emits_finite_refresh_window() {
let order_id = "watch-finite-refresh-window";
let request_event = signed_order_request_event(order_id, 820);
store
- .ingest_event(RadrootsEventIngest::new(request_event, 1_700_400_000_000))
+ .ingest_event(RadrootsEventIngest::new(
+ signed_event_from_envelope(request_event),
+ 1_700_400_000_000,
+ ))
.await
.expect("request ingest");
@@ -7056,7 +7126,7 @@ async fn manual_local_status_perf_gate_measures_100k_events() {
let event = signed_order_request_event(&order_id, 20_000 + index as u32);
store
.ingest_event(RadrootsEventIngest::new(
- event,
+ signed_event_from_envelope(event),
1_700_100_000_000 + index as i64,
))
.await
diff --git a/crates/sdk/tests/replica_ingest.rs b/crates/sdk/tests/replica_ingest.rs
@@ -1,4 +1,4 @@
-use radroots_event::{RadrootsEventEnvelope, farm::RadrootsFarm};
+use radroots_event::{RadrootsEventEnvelope, RadrootsEventEnvelopeParts, farm::RadrootsFarm};
use radroots_replica_schema::farm::IFarmFindMany;
use radroots_replica_store::ReplicaSql;
use radroots_replica_sync::{RadrootsReplicaIngestOutcome, radroots_replica_ingest_event};
@@ -17,15 +17,16 @@ fn sdk_event(
content: String,
tags: Vec<Vec<String>>,
) -> RadrootsEventEnvelope {
- RadrootsEventEnvelope {
+ RadrootsEventEnvelope::new(RadrootsEventEnvelopeParts {
id: format!("{id:064x}"),
author: author.to_owned(),
- created_at,
+ created_at: u64::from(created_at),
kind,
tags,
content,
sig: "f".repeat(128),
- }
+ })
+ .expect("sdk event envelope")
}
fn sample_farm() -> RadrootsFarm {
@@ -81,5 +82,5 @@ fn sdk_farm_draft_ingests_into_replica_projection() {
assert_eq!(farms.len(), 1);
assert_eq!(farms[0].d_tag, sample_farm().d_tag);
assert_eq!(farms[0].name, sample_farm().name);
- assert_eq!(farms[0].pubkey, event.author);
+ assert_eq!(farms[0].pubkey, event.author_str());
}
diff --git a/crates/sdk/tests/runtime_foundation.rs b/crates/sdk/tests/runtime_foundation.rs
@@ -1045,7 +1045,11 @@ fn sdk_examples_stay_on_product_api_boundary() {
];
for (name, example) in examples {
- assert!(!example.contains("WireEventParts"), "{name}");
+ assert!(!example.contains(concat!("Wire", "EventParts")), "{name}");
+ assert!(
+ !example.contains(concat!("Radroots", "Frozen", "EventDraft")),
+ "{name}"
+ );
assert!(!example.contains("protocol::wire"), "{name}");
assert!(!example.contains("event_codec::wire"), "{name}");
assert!(!example.contains(".as_wire_parts("), "{name}");
diff --git a/crates/sdk/tests/source_boundary.rs b/crates/sdk/tests/source_boundary.rs
@@ -104,6 +104,22 @@ const FORBIDDEN_SDK_README_CONCEPTS: &[ForbiddenSdkConcept] = &[
const FORBIDDEN_FOUNDATION_HARDENING_RETIRED_CONCEPTS: &[ForbiddenSdkConcept] = &[
ForbiddenSdkConcept {
+ pattern: "WireEventParts",
+ reason: "event construction must use current Radroots NIP-01 wire part names",
+ },
+ ForbiddenSdkConcept {
+ pattern: "RadrootsFrozenEventDraft",
+ reason: "event draft surfaces must use the current RadrootsEventDraft name",
+ },
+ ForbiddenSdkConcept {
+ pattern: "pub type SignedEvent",
+ reason: "SDK signing adapters must not expose compatibility aliases for signed events",
+ },
+ ForbiddenSdkConcept {
+ pattern: "pub type NostrEventBuilder",
+ reason: "SDK signing adapters must not expose compatibility aliases for event builders",
+ },
+ ForbiddenSdkConcept {
pattern: "SignedNostrEvent",
reason: "generic signed-event surfaces must use product-neutral signed-event names",
},
diff --git a/crates/sdk/tests/support/fixture_signer.rs b/crates/sdk/tests/support/fixture_signer.rs
@@ -23,29 +23,29 @@ impl RadrootsEventSigner for FixtureSigner {
&self,
draft: &RadrootsEventDraft,
) -> Result<RadrootsSignedEvent, RadrootsSignerError> {
- if self.pubkey().as_str() != draft.expected_pubkey.as_str() {
+ if self.pubkey().as_str() != draft.expected_pubkey_str() {
return Err(RadrootsSignerError::SigningFailed {
message: "wrong fixture signer".to_owned(),
});
}
let sig = "f".repeat(128);
let raw_json = serde_json::json!({
- "id": draft.expected_event_id,
+ "id": draft.expected_event_id_str(),
"pubkey": self.pubkey().as_str(),
- "created_at": draft.created_at,
- "kind": draft.kind,
- "tags": draft.tags,
- "content": draft.content,
+ "created_at": draft.created_at_u64(),
+ "kind": draft.kind_u32(),
+ "tags": draft.tags_as_vec(),
+ "content": draft.content(),
"sig": sig,
})
.to_string();
RadrootsSignedEvent::new(RadrootsSignedEventParts {
- id: draft.expected_event_id.clone(),
+ id: draft.expected_event_id_str().to_owned(),
pubkey: self.pubkey().as_str().to_owned(),
- created_at: draft.created_at,
- kind: draft.kind,
- tags: draft.tags.clone(),
- content: draft.content.clone(),
+ created_at: draft.created_at_u64(),
+ kind: draft.kind_u32(),
+ tags: draft.tags_as_vec(),
+ content: draft.content().to_owned(),
sig,
raw_json,
})
diff --git a/crates/sdk/tests/sync_runtime.rs b/crates/sdk/tests/sync_runtime.rs
@@ -338,7 +338,7 @@ impl RadrootsRelayPublishAdapter for RecordingPublishAdapter {
self.raw_events
.lock()
.expect("raw event lock")
- .push(request.signed_event.raw_json.clone());
+ .push(request.signed_event.raw_json().to_owned());
self.request_times_ms
.lock()
.expect("request time lock")
@@ -383,29 +383,29 @@ impl RadrootsEventSigner for FixtureSigner {
&self,
draft: &RadrootsEventDraft,
) -> Result<RadrootsSignedEvent, RadrootsSignerError> {
- if self.pubkey().as_str() != draft.expected_pubkey.as_str() {
+ if self.pubkey().as_str() != draft.expected_pubkey_str() {
return Err(RadrootsSignerError::SigningFailed {
message: "wrong fixture signer".to_owned(),
});
}
let sig = "f".repeat(128);
let raw_json = serde_json::json!({
- "id": draft.expected_event_id,
+ "id": draft.expected_event_id_str(),
"pubkey": self.pubkey().as_str(),
- "created_at": draft.created_at,
- "kind": draft.kind,
- "tags": draft.tags,
- "content": draft.content,
+ "created_at": draft.created_at_u64(),
+ "kind": draft.kind_u32(),
+ "tags": draft.tags_as_vec(),
+ "content": draft.content(),
"sig": sig,
})
.to_string();
RadrootsSignedEvent::new(RadrootsSignedEventParts {
- id: draft.expected_event_id.clone(),
+ id: draft.expected_event_id_str().to_owned(),
pubkey: self.pubkey().as_str().to_owned(),
- created_at: draft.created_at,
- kind: draft.kind,
- tags: draft.tags.clone(),
- content: draft.content.clone(),
+ created_at: draft.created_at_u64(),
+ kind: draft.kind_u32(),
+ tags: draft.tags_as_vec(),
+ content: draft.content().to_owned(),
sig,
raw_json,
})
diff --git a/crates/sdk/tests/unit/adapters_nostr_tests.rs b/crates/sdk/tests/unit/adapters_nostr_tests.rs
@@ -5,7 +5,7 @@ use super::{
use crate::adapters::signing::sign_parts_with_identity;
use crate::identity::RadrootsIdentity;
use core::time::Duration;
-use radroots_event_codec::wire::WireEventParts;
+use radroots_event::wire::RadrootsNip01EventWireParts;
use radroots_nostr::prelude::RadrootsNostrClientOptions;
use tokio::runtime::Runtime;
@@ -74,7 +74,7 @@ fn relay_helpers_accept_empty_relay_sets_without_network_endpoints() {
let signed = sign_parts_with_identity(
&identity,
- WireEventParts {
+ RadrootsNip01EventWireParts {
kind: 1,
content: "hello".to_owned(),
tags: Vec::new(),
diff --git a/crates/sdk/tests/unit/adapters_radrootsd_tests.rs b/crates/sdk/tests/unit/adapters_radrootsd_tests.rs
@@ -1,4 +1,5 @@
use super::*;
+use radroots_event::wire::RadrootsNip01EventWire;
use radroots_transport::RADROOTS_RETICULUM_PREVIEW_ENDPOINT_URI;
use radroots_transport_publish_protocol::{
NostrPublishTargetSourcePolicy, TransportPublishDeliveryPolicy, TransportPublishEventRequest,
@@ -86,7 +87,7 @@ fn spawn_http_server(
}
fn signed_event() -> RadrootsSignedEvent {
- RadrootsSignedEvent {
+ let wire = RadrootsNip01EventWire {
id: "a".repeat(64),
pubkey: "b".repeat(64),
created_at: 1_700_000_000,
@@ -94,22 +95,24 @@ fn signed_event() -> RadrootsSignedEvent {
tags: vec![vec!["d".to_owned(), "listing-1".to_owned()]],
content: "{\"name\":\"carrots\"}".to_owned(),
sig: "c".repeat(128),
- raw_json: serde_json::json!({
- "id": "a".repeat(64),
- "pubkey": "b".repeat(64),
- "created_at": 1_700_000_000u32,
- "kind": 30402u32,
- "tags": [["d", "listing-1"]],
- "content": "{\"name\":\"carrots\"}",
- "sig": "c".repeat(128)
- })
- .to_string(),
- }
+ extra: Default::default(),
+ };
+ let raw_json = serde_json::json!({
+ "id": "a".repeat(64),
+ "pubkey": "b".repeat(64),
+ "created_at": 1_700_000_000u32,
+ "kind": 30402u32,
+ "tags": [["d", "listing-1"]],
+ "content": "{\"name\":\"carrots\"}",
+ "sig": "c".repeat(128)
+ })
+ .to_string();
+ RadrootsSignedEvent::from_wire_unchecked(wire, raw_json).expect("signed event")
}
fn publish_request() -> TransportPublishEventRequest {
TransportPublishEventRequest {
- event: signed_event_wire(&signed_event()),
+ raw_event_json: signed_event().raw_json().to_owned(),
target_policy: TransportPublishTargetPolicy::nostr(
NostrPublishTargetSourcePolicy::RequestThenAuthorWriteThenDaemonDefault,
vec!["wss://relay.example.com".to_owned()],
@@ -358,9 +361,11 @@ fn proxy_config_builders_preserve_typed_runtime_options() {
fn publish_event_request_json_uses_signed_event_contract() {
let value = publish_event_request_json(&publish_request()).expect("request json");
- assert_eq!(value["event"]["id"], "a".repeat(64));
- assert_eq!(value["event"]["pubkey"], "b".repeat(64));
- assert_eq!(value["event"]["kind"], 30_402);
+ let raw_event_json = value["raw_event_json"].as_str().expect("raw event json");
+ let raw_event: serde_json::Value = serde_json::from_str(raw_event_json).expect("raw event");
+ assert_eq!(raw_event["id"], "a".repeat(64));
+ assert_eq!(raw_event["pubkey"], "b".repeat(64));
+ assert_eq!(raw_event["kind"], 30_402);
assert_eq!(value["target_policy"]["kind"], "nostr");
assert_eq!(
value["target_policy"]["source_policy"],
@@ -462,7 +467,11 @@ async fn publish_event_posts_transport_publish_jsonrpc() {
let body: serde_json::Value = serde_json::from_str(recorded.body.as_str()).expect("body");
assert_eq!(body["method"], METHOD_EVENT);
assert_eq!(body["id"], SDK_RADROOTSD_PROXY_REQUEST_ID);
- assert_eq!(body["params"]["event"]["content"], "{\"name\":\"carrots\"}");
+ let raw_event_json = body["params"]["raw_event_json"]
+ .as_str()
+ .expect("raw event json");
+ let raw_event: serde_json::Value = serde_json::from_str(raw_event_json).expect("raw event");
+ assert_eq!(raw_event["content"], "{\"name\":\"carrots\"}");
assert_eq!(body["params"]["target_policy"]["kind"], "nostr");
assert_eq!(
body["params"]["target_policy"]["relay_urls"][0],
@@ -833,7 +842,7 @@ async fn publish_event_empty_http_error_reports_empty_body() {
}
#[tokio::test]
-async fn publish_signed_event_rejects_invalid_protocol_requests_before_http() {
+async fn publish_signed_event_rejects_invalid_target_requests_before_http() {
let adapter =
RadrootsdProxyPublishAdapter::new(RadrootsdProxyConfig::new("http://127.0.0.1:9/rpc"));
let base = RadrootsdProxyPublishRequest {
@@ -847,10 +856,6 @@ async fn publish_signed_event_rejects_invalid_protocol_requests_before_http() {
timeout_ms: Some(1_000),
};
- let mut invalid_event_kind = base.clone();
- invalid_event_kind.signed_event.kind = 70_000;
- let mut empty_event_tag = base.clone();
- empty_event_tag.signed_event.tags = vec![Vec::new()];
let mut invalid_quorum = base.clone();
invalid_quorum.delivery_policy = TransportPublishDeliveryPolicy::Quorum { quorum: 0 };
let mut too_many_targets = base.clone();
@@ -896,8 +901,6 @@ async fn publish_signed_event_rejects_invalid_protocol_requests_before_http() {
empty_idempotency.idempotency_key = Some(" ".to_owned());
for request in [
- invalid_event_kind,
- empty_event_tag,
invalid_quorum,
too_many_targets,
empty_endpoint_uri,
@@ -915,7 +918,7 @@ async fn publish_signed_event_rejects_invalid_protocol_requests_before_http() {
async fn adapter_rejects_invalid_request_before_transport() {
let adapter =
RadrootsdProxyPublishAdapter::new(RadrootsdProxyConfig::new("http://127.0.0.1:9/rpc"));
- let mut request = RadrootsdProxyPublishRequest {
+ let request = RadrootsdProxyPublishRequest {
signed_event: signed_event(),
target_policy: TransportPublishTargetPolicy::nostr(
NostrPublishTargetSourcePolicy::RequestThenAuthorWriteThenDaemonDefault,
@@ -925,7 +928,6 @@ async fn adapter_rejects_invalid_request_before_transport() {
idempotency_key: None,
timeout_ms: None,
};
- request.signed_event.id = "A".repeat(64);
let error = adapter
.publish_signed_event(request)
diff --git a/crates/sdk/tests/unit/adapters_signing_tests.rs b/crates/sdk/tests/unit/adapters_signing_tests.rs
@@ -1,10 +1,10 @@
use super::{event_builder_from_parts, sign_parts_with_identity};
use crate::identity::RadrootsIdentity;
-use radroots_event_codec::wire::WireEventParts;
+use radroots_event::wire::RadrootsNip01EventWireParts;
#[test]
fn event_builder_from_parts_preserves_kind_and_content() {
- let builder = event_builder_from_parts(WireEventParts {
+ let builder = event_builder_from_parts(RadrootsNip01EventWireParts {
kind: 30402,
content: "hello".into(),
tags: vec![vec!["x".into(), "y".into()]],
@@ -22,7 +22,7 @@ fn sign_parts_with_identity_signs_event() {
let identity = RadrootsIdentity::generate();
let event = sign_parts_with_identity(
&identity,
- WireEventParts {
+ RadrootsNip01EventWireParts {
kind: 30402,
content: "hello".into(),
tags: vec![],
diff --git a/crates/sdk/tests/unit/dvm_runtime_tests.rs b/crates/sdk/tests/unit/dvm_runtime_tests.rs
@@ -9,10 +9,11 @@ use crate::{
};
use radroots_authority::RadrootsActorContext;
use radroots_event::{
- RadrootsEventEnvelope,
contract::RadrootsActorRole,
+ draft::RadrootsSignedEvent,
ids::{RadrootsEventId, RadrootsInventoryBinId, RadrootsListingAddress, RadrootsPublicKey},
kinds::KIND_TRADE_TRANSITION_PROOF_REQUEST,
+ wire::RadrootsNip01EventWire,
};
use radroots_trade::validation_receipt::RadrootsValidationReceiptProofSystem;
@@ -33,14 +34,17 @@ fn trade_transition_proof_plan_builds_microstandard_wire_payload() {
)
.expect("plan");
let payload: serde_json::Value =
- serde_json::from_str(&plan.frozen_draft.content).expect("payload json");
+ serde_json::from_str(plan.frozen_draft.content()).expect("payload json");
assert_eq!(
- plan.frozen_draft.contract_id,
+ plan.frozen_draft.contract_id(),
super::DVM_TRADE_TRANSITION_PROOF_REQUEST_CONTRACT_ID
);
- assert_eq!(plan.frozen_draft.kind, KIND_TRADE_TRANSITION_PROOF_REQUEST);
- assert_eq!(plan.frozen_draft.expected_pubkey, SERVICE);
+ assert_eq!(
+ plan.frozen_draft.kind_u32(),
+ KIND_TRADE_TRANSITION_PROOF_REQUEST
+ );
+ assert_eq!(plan.frozen_draft.expected_pubkey_str(), SERVICE);
assert_eq!(plan.worker_pubkey.as_str(), WORKER);
assert_eq!(plan.proof_mode, DvmProofMode::None);
assert_eq!(
@@ -54,12 +58,10 @@ fn trade_transition_proof_plan_builds_microstandard_wire_payload() {
assert_eq!(payload["inventory_sequence"], 7);
assert_eq!(payload["previous_state_root"], hash32('3'));
assert_eq!(payload["listing_event_id"], event_id('1').as_str());
+ let tags = plan.frozen_draft.tags_as_vec();
+ assert_eq!(tags[0], vec!["a", listing_addr().as_str()]);
assert_eq!(
- plan.frozen_draft.tags[0],
- vec!["a", listing_addr().as_str()]
- );
- assert_eq!(
- plan.frozen_draft.tags[1],
+ tags[1],
vec![
"i",
event_id('3').as_str(),
@@ -67,7 +69,7 @@ fn trade_transition_proof_plan_builds_microstandard_wire_payload() {
"radroots:order_decision_event"
]
);
- assert_eq!(plan.frozen_draft.tags[2], vec!["p", WORKER]);
+ assert_eq!(tags[2], vec!["p", WORKER]);
}
#[test]
@@ -371,14 +373,26 @@ fn hash32(ch: char) -> String {
format!("0x{}", ch.to_string().repeat(64))
}
-fn dummy_event() -> RadrootsEventEnvelope {
- RadrootsEventEnvelope {
+fn dummy_event() -> RadrootsSignedEvent {
+ let wire = RadrootsNip01EventWire {
id: event_id('9').into_string(),
- author: event_id('a').into_string(),
+ pubkey: event_id('a').into_string(),
created_at: 1,
kind: 3440,
tags: Vec::new(),
content: "{}".to_owned(),
- sig: event_id('b').into_string(),
- }
+ sig: "b".repeat(128),
+ extra: Default::default(),
+ };
+ let raw_json = serde_json::json!({
+ "id": wire.id.clone(),
+ "pubkey": wire.pubkey.clone(),
+ "created_at": wire.created_at,
+ "kind": wire.kind,
+ "tags": wire.tags.clone(),
+ "content": wire.content.clone(),
+ "sig": wire.sig.clone()
+ })
+ .to_string();
+ RadrootsSignedEvent::from_wire_unchecked(wire, raw_json).expect("signed event")
}
diff --git a/crates/sdk/tests/unit/orders_runtime_tests.rs b/crates/sdk/tests/unit/orders_runtime_tests.rs
@@ -6,6 +6,7 @@ use radroots_core::{
};
use radroots_event::{
draft::RadrootsSignedEvent,
+ envelope::RadrootsEventEnvelopeParts,
kinds::KIND_LISTING,
order::{
RadrootsOrderDecisionOutcome, RadrootsOrderEconomicItem, RadrootsOrderEconomicLine,
@@ -120,7 +121,7 @@ fn ptr(id: String) -> RadrootsEventPtr {
}
fn nostr_event(id: String, kind: u32) -> RadrootsEventEnvelope {
- RadrootsEventEnvelope {
+ RadrootsEventEnvelope::new(RadrootsEventEnvelopeParts {
id,
author: hex_64('c'),
created_at: 1_700_000_000,
@@ -128,7 +129,8 @@ fn nostr_event(id: String, kind: u32) -> RadrootsEventEnvelope {
tags: Vec::new(),
content: "{}".to_owned(),
sig: hex_128('f'),
- }
+ })
+ .expect("event envelope")
}
fn actor(pubkey: &RadrootsPublicKey, role: RadrootsActorRole) -> RadrootsActorContext {
@@ -594,21 +596,29 @@ async fn enqueue_fixture_submit(sdk: &RadrootsClient, raw_order_id: &str) -> Tra
}
fn event_from_parts(
- parts: WireEventParts,
+ parts: RadrootsNip01EventWireParts,
contract_id: &str,
expected_pubkey: &RadrootsPublicKey,
) -> RadrootsEventEnvelope {
- let frozen = to_frozen_draft(parts, contract_id, expected_pubkey.as_str(), 1_700_000_000)
- .expect("frozen draft");
- RadrootsEventEnvelope {
- id: frozen.expected_event_id,
+ let frozen = RadrootsEventDraft::new(
+ contract_id,
+ parts.kind,
+ 1_700_000_000,
+ parts.tags,
+ parts.content,
+ expected_pubkey.as_str(),
+ )
+ .expect("frozen draft");
+ RadrootsEventEnvelope::new(RadrootsEventEnvelopeParts {
+ id: frozen.expected_event_id_str().to_owned(),
author: expected_pubkey.as_str().to_owned(),
- created_at: frozen.created_at,
- kind: frozen.kind,
- tags: frozen.tags,
- content: frozen.content,
+ created_at: frozen.created_at_u64(),
+ kind: frozen.kind_u32(),
+ tags: frozen.tags_as_vec(),
+ content: frozen.content().to_owned(),
sig: hex_128('f'),
- }
+ })
+ .expect("event envelope")
}
fn request_event() -> RadrootsEventEnvelope {
@@ -623,6 +633,36 @@ fn request_event() -> RadrootsEventEnvelope {
)
}
+fn event_parts_from(event: &RadrootsEventEnvelope) -> RadrootsEventEnvelopeParts {
+ RadrootsEventEnvelopeParts {
+ id: event.id_str().to_owned(),
+ author: event.author_str().to_owned(),
+ created_at: event.created_at_u64(),
+ kind: event.kind_u32(),
+ tags: event.tags_as_vec(),
+ content: event.content().to_owned(),
+ sig: event.sig_str().to_owned(),
+ }
+}
+
+fn event_with_content(event: &RadrootsEventEnvelope, content: String) -> RadrootsEventEnvelope {
+ RadrootsEventEnvelope::new(RadrootsEventEnvelopeParts {
+ content,
+ ..event_parts_from(event)
+ })
+ .expect("event envelope")
+}
+
+fn signed_event_from(event: RadrootsEventEnvelope) -> RadrootsSignedEvent {
+ let wire = event.to_nip01_wire();
+ let raw_json = serde_json::to_string(&wire).expect("raw event json");
+ RadrootsSignedEvent::from_wire_unchecked(wire, raw_json).expect("signed event")
+}
+
+fn request_signed_event() -> RadrootsSignedEvent {
+ signed_event_from(request_event())
+}
+
fn order_request_evidence_error(
result: Result<TradeRequestEvidence, RadrootsSdkError>,
) -> RadrootsSdkError {
@@ -1008,7 +1048,7 @@ fn workflow_plan_builders_cover_success_and_actor_mismatch_paths() {
1_700_000_000,
"order test",
);
- assert_eq!(expected_event_id, frozen_draft.expected_event_id);
+ assert_eq!(expected_event_id, frozen_draft.expected_event_id_str());
}
#[test]
@@ -1161,7 +1201,7 @@ fn order_evidence_parses_all_lifecycle_event_kinds() {
);
let decision_event_id =
- RadrootsEventId::parse(decision_event.id.as_str()).expect("decision event id");
+ RadrootsEventId::parse(decision_event.id_str()).expect("decision event id");
let proposal = revision_proposal_payload(&root_event_id, &decision_event_id);
let proposal_event = event_from_parts(
order::build_order_revision_proposal_draft(&root_event_id, &decision_event_id, &proposal)
@@ -1178,7 +1218,7 @@ fn order_evidence_parses_all_lifecycle_event_kinds() {
);
let proposal_event_id =
- RadrootsEventId::parse(proposal_event.id.as_str()).expect("proposal event id");
+ RadrootsEventId::parse(proposal_event.id_str()).expect("proposal event id");
let revision_decision = revision_decision_payload(
&proposal,
&proposal_event_id,
@@ -1226,22 +1266,26 @@ fn order_request_evidence_parses_and_rejects_malformed_envelopes() {
assert_eq!(evidence.buyer_pubkey, pubkey('c'));
assert_eq!(evidence.seller_pubkey, pubkey('d'));
- let mut invalid_id = event.clone();
- invalid_id.id = "not-hex".to_owned();
+ let invalid_id = RadrootsEventEnvelope::new(RadrootsEventEnvelopeParts {
+ id: "not-hex".to_owned(),
+ ..event_parts_from(&event)
+ })
+ .expect_err("invalid id");
assert!(
- invalid_request_message(order_request_evidence_error(parse_order_request_evidence(
- &invalid_id,
- )))
- .contains("event id is invalid")
+ invalid_id
+ .to_string()
+ .contains("event envelope id is invalid")
);
- let mut invalid_author = event.clone();
- invalid_author.author = "not-hex".to_owned();
+ let invalid_author = RadrootsEventEnvelope::new(RadrootsEventEnvelopeParts {
+ author: "not-hex".to_owned(),
+ ..event_parts_from(&event)
+ })
+ .expect_err("invalid author");
assert!(
- invalid_request_message(order_request_evidence_error(parse_order_request_evidence(
- &invalid_author,
- )))
- .contains("decode failed")
+ invalid_author
+ .to_string()
+ .contains("event envelope author is invalid")
);
let request = order_request_payload();
@@ -1259,8 +1303,7 @@ fn order_request_evidence_parses_and_rejects_malformed_envelopes() {
.contains("decode failed")
);
- let mut decode_failure = event.clone();
- decode_failure.content = "{}".to_owned();
+ let decode_failure = event_with_content(&event, "{}".to_owned());
assert!(
invalid_request_message(order_request_evidence_error(parse_order_request_evidence(
&decode_failure,
@@ -1268,11 +1311,13 @@ fn order_request_evidence_parses_and_rejects_malformed_envelopes() {
.contains("decode failed")
);
- let mut envelope = serde_json::from_str::<serde_json::Value>(event.content.as_str())
- .expect("request envelope");
+ let mut envelope =
+ serde_json::from_str::<serde_json::Value>(event.content()).expect("request envelope");
envelope["order_id"] = serde_json::Value::String("other-order".to_owned());
- let mut order_mismatch = event.clone();
- order_mismatch.content = serde_json::to_string(&envelope).expect("mismatched envelope");
+ let order_mismatch = event_with_content(
+ &event,
+ serde_json::to_string(&envelope).expect("mismatched envelope"),
+ );
assert!(
invalid_request_message(order_request_evidence_error(parse_order_request_evidence(
&order_mismatch,
@@ -1280,11 +1325,13 @@ fn order_request_evidence_parses_and_rejects_malformed_envelopes() {
.contains("decode failed")
);
- let mut envelope = serde_json::from_str::<serde_json::Value>(event.content.as_str())
- .expect("request envelope");
+ let mut envelope =
+ serde_json::from_str::<serde_json::Value>(event.content()).expect("request envelope");
envelope["listing_addr"] = serde_json::Value::String(format!("30402:{}:other", hex_64('d')));
- let mut listing_mismatch = event;
- listing_mismatch.content = serde_json::to_string(&envelope).expect("mismatched envelope");
+ let listing_mismatch = event_with_content(
+ &event,
+ serde_json::to_string(&envelope).expect("mismatched envelope"),
+ );
assert!(
invalid_request_message(order_request_evidence_error(parse_order_request_evidence(
&listing_mismatch,
@@ -3817,7 +3864,8 @@ async fn order_ingest_and_enqueue_wrappers_report_prepare_timestamp_errors() {
assert!(matches!(
sdk.trades()
.ingest_evidence(
- TradeEvidenceIngestRequest::new(request_event()).with_observed_at(out_of_range,)
+ TradeEvidenceIngestRequest::new(request_signed_event())
+ .with_observed_at(out_of_range,)
)
.await,
Err(RadrootsSdkError::TimestampOutOfRange { .. })
@@ -3825,7 +3873,7 @@ async fn order_ingest_and_enqueue_wrappers_report_prepare_timestamp_errors() {
assert!(matches!(
sdk.trades()
.ingest_request_evidence(
- TradeRequestEvidenceIngestRequest::new(request_event())
+ TradeRequestEvidenceIngestRequest::new(request_signed_event())
.with_observed_at(out_of_range,),
)
.await,
@@ -3945,14 +3993,16 @@ async fn order_default_timestamp_paths_report_clock_errors() {
assert!(matches!(
clock_error_sdk
.trades()
- .ingest_evidence(TradeEvidenceIngestRequest::new(request_event()))
+ .ingest_evidence(TradeEvidenceIngestRequest::new(request_signed_event()))
.await,
Err(RadrootsSdkError::ClockBeforeUnixEpoch)
));
assert!(matches!(
clock_error_sdk
.trades()
- .ingest_request_evidence(TradeRequestEvidenceIngestRequest::new(request_event()))
+ .ingest_request_evidence(TradeRequestEvidenceIngestRequest::new(
+ request_signed_event()
+ ))
.await,
Err(RadrootsSdkError::ClockBeforeUnixEpoch)
));
@@ -4056,10 +4106,10 @@ fn order_runtime_request_builders_and_serializers_cover_source_attached_paths()
assert_struct_serialize_error_paths(&submit_enqueue, 6);
let request_ingest =
- TradeRequestEvidenceIngestRequest::new(request_event()).with_observed_at(created_at);
+ TradeRequestEvidenceIngestRequest::new(request_signed_event()).with_observed_at(created_at);
assert_struct_serialize_error_paths(&request_ingest, 2);
let evidence_ingest =
- TradeEvidenceIngestRequest::new(request_event()).with_observed_at(created_at);
+ TradeEvidenceIngestRequest::new(request_signed_event()).with_observed_at(created_at);
assert_struct_serialize_error_paths(&evidence_ingest, 2);
let decision_prepare = TradeDecisionPrepareRequest::new(
@@ -4342,7 +4392,7 @@ async fn closed_event_store_errors_are_mapped_for_ingest_and_prepared_lookup() {
sdk._event_store.pool().close().await;
let ingest_error = sdk
.trades()
- .ingest_evidence(TradeEvidenceIngestRequest::new(request_event()))
+ .ingest_evidence(TradeEvidenceIngestRequest::new(request_signed_event()))
.await
.expect_err("closed ingest evidence");
assert!(matches!(ingest_error, RadrootsSdkError::EventStore { .. }));
@@ -4351,7 +4401,9 @@ async fn closed_event_store_errors_are_mapped_for_ingest_and_prepared_lookup() {
sdk._event_store.pool().close().await;
let request_ingest_error = sdk
.trades()
- .ingest_request_evidence(TradeRequestEvidenceIngestRequest::new(request_event()))
+ .ingest_request_evidence(TradeRequestEvidenceIngestRequest::new(
+ request_signed_event(),
+ ))
.await
.expect_err("closed request evidence ingest");
assert!(matches!(
@@ -4372,7 +4424,7 @@ async fn closed_event_store_errors_are_mapped_for_ingest_and_prepared_lookup() {
#[tokio::test]
async fn order_status_and_evidence_ingest_cover_source_attached_success_paths() {
let sdk = prepared_order_sdk().await;
- let request_event = request_event();
+ let request_event = request_signed_event();
let request_receipt = sdk
.trades()
.ingest_request_evidence(TradeRequestEvidenceIngestRequest::new(
diff --git a/crates/sdk/tests/unit/runtime_tests.rs b/crates/sdk/tests/unit/runtime_tests.rs
@@ -1604,19 +1604,38 @@ async fn restore_archive_private_failures_cover_staging_and_verification_edges()
.build()
.await
.expect("populated sdk");
+ let populated_event_pubkey = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
+ let populated_event_tags = Vec::<Vec<String>>::new();
+ let populated_event_content = "{}".to_owned();
+ let populated_event_id = radroots_event::wire::compute_canonical_nip01_event_id(
+ populated_event_pubkey,
+ 1_700_000_002,
+ 1,
+ &populated_event_tags,
+ &populated_event_content,
+ )
+ .expect("canonical event id");
+ let populated_event_wire = radroots_event::wire::RadrootsNip01EventWire {
+ id: populated_event_id.into_string(),
+ pubkey: populated_event_pubkey.to_owned(),
+ created_at: 1_700_000_002,
+ kind: 1,
+ tags: populated_event_tags,
+ content: populated_event_content,
+ sig: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".to_owned(),
+ extra: Default::default(),
+ };
+ let populated_event_raw_json =
+ serde_json::to_string(&populated_event_wire).expect("raw event json");
+ let populated_event = radroots_event::draft::RadrootsSignedEvent::from_wire_verified_id(
+ populated_event_wire,
+ populated_event_raw_json,
+ )
+ .expect("signed event");
populated_sdk
._event_store
.ingest_event(radroots_event_store::RadrootsEventIngest::new(
- radroots_event::RadrootsEventEnvelope {
- id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".to_owned(),
- author: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
- .to_owned(),
- created_at: 1_700_000_002,
- kind: 1,
- tags: Vec::new(),
- content: "{}".to_owned(),
- sig: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".to_owned(),
- },
+ populated_event,
1_700_000_002_000,
))
.await
diff --git a/crates/sdk/tests/unit/signer_provider_tests.rs b/crates/sdk/tests/unit/signer_provider_tests.rs
@@ -2,8 +2,8 @@ use super::*;
use nostr::nips::nip44::{self, Version};
use nostr::{EventBuilder, JsonUtil, Kind, Tag};
use radroots_event::contract::RadrootsActorRole;
+use radroots_event::draft::RadrootsEventDraft;
use radroots_event::kinds::{KIND_COOP, KIND_FARM};
-use radroots_event_codec::wire::{WireEventParts, to_frozen_draft};
use radroots_nostr::prelude::{RadrootsNostrEvent, RadrootsNostrSecretKey};
use radroots_nostr_connect::prelude::{
RADROOTS_NOSTR_CONNECT_RPC_KIND, RadrootsNostrConnectClientTarget, RadrootsNostrConnectError,
@@ -64,15 +64,13 @@ fn frozen_draft_with(
tags: Vec<Vec<String>>,
content: &str,
) -> RadrootsEventDraft {
- to_frozen_draft(
- WireEventParts {
- kind,
- content: content.to_owned(),
- tags,
- },
+ RadrootsEventDraft::new(
contract_id,
+ kind,
+ u64::from(created_at),
+ tags,
+ content,
pubkey,
- created_at,
)
.expect("frozen draft")
}
@@ -80,7 +78,7 @@ fn frozen_draft_with(
fn sign_event(keys: &RadrootsNostrKeys, draft: &RadrootsEventDraft) -> RadrootsNostrEvent {
let signed =
radroots_nostr::prelude::radroots_nostr_sign_frozen_draft(keys, draft).expect("signed");
- RadrootsNostrEvent::from_json(signed.raw_json.as_str()).expect("event")
+ RadrootsNostrEvent::from_json(signed.raw_json()).expect("event")
}
fn response_event(
@@ -255,7 +253,7 @@ async fn local_key_provider_signs_authorized_frozen_draft() {
assert!(provider.capability().nip46_permissions.is_empty());
assert_eq!(receipt.mode, RadrootsSdkSignerMode::LocalKey);
assert_eq!(receipt.signer_pubkey, USER_PUBLIC_KEY_HEX);
- assert_eq!(receipt.signed_event_id, draft.expected_event_id);
+ assert_eq!(receipt.signed_event_id, draft.expected_event_id_str());
assert_eq!(
progress,
vec![
@@ -530,7 +528,7 @@ async fn myc_nip46_provider_signs_and_validates_remote_event() {
let draft = frozen_draft();
let signed = radroots_nostr::prelude::radroots_nostr_sign_frozen_draft(&user_keys, &draft)
.expect("signed");
- let signed_event = RadrootsNostrEvent::from_json(signed.raw_json.as_str()).expect("event");
+ let signed_event = RadrootsNostrEvent::from_json(signed.raw_json()).expect("event");
let transport = Arc::new(MockNip46Transport::new(
remote_keys.clone(),
vec![MockNip46Response::Respond(
@@ -584,14 +582,17 @@ async fn myc_nip46_provider_signs_and_validates_remote_event() {
.into_iter()
.map(Tag::to_vec)
.collect::<Vec<_>>();
- assert_eq!(sign_event_request.pubkey.to_hex(), draft.expected_pubkey);
+ assert_eq!(
+ sign_event_request.pubkey.to_hex(),
+ draft.expected_pubkey_str()
+ );
assert_eq!(
sign_event_request.created_at.as_secs(),
- u64::from(draft.created_at)
+ draft.created_at_u64()
);
- assert_eq!(sign_event_request.kind.as_u16(), draft.kind as u16);
- assert_eq!(request_tags, draft.tags);
- assert_eq!(sign_event_request.content, draft.content);
+ assert_eq!(sign_event_request.kind.as_u16(), draft.kind_u32() as u16);
+ assert_eq!(request_tags, draft.tags_as_vec());
+ assert_eq!(sign_event_request.content, draft.content());
let request_id = request_messages[0]
.id
.strip_prefix("radroots-sdk-myc-nip46-sign-")
@@ -610,48 +611,6 @@ async fn myc_nip46_provider_signs_and_validates_remote_event() {
);
}
-#[test]
-fn myc_nip46_sign_event_request_reports_invalid_frozen_drafts() {
- let mut invalid_pubkey = frozen_draft();
- invalid_pubkey.expected_pubkey = "not-a-public-key".to_owned();
- let error = sign_event_request_from_frozen_draft(&invalid_pubkey)
- .expect_err("invalid NIP-46 pubkey error");
- assert!(matches!(
- error,
- RadrootsSdkError::SignerProtocol {
- mode,
- ref reason
- } if mode == RadrootsSdkSignerMode::MycNip46.as_str()
- && reason.contains("failed to parse frozen draft pubkey")
- ));
-
- let mut oversized_kind = frozen_draft();
- oversized_kind.kind = u32::from(u16::MAX) + 1;
- let error = sign_event_request_from_frozen_draft(&oversized_kind)
- .expect_err("oversized NIP-46 event kind error");
- assert!(matches!(
- error,
- RadrootsSdkError::SignerProtocol {
- mode,
- ref reason
- } if mode == RadrootsSdkSignerMode::MycNip46.as_str()
- && reason.contains("failed to convert frozen draft kind")
- ));
-
- let mut empty_tag = frozen_draft();
- empty_tag.tags = vec![Vec::new()];
- let error =
- sign_event_request_from_frozen_draft(&empty_tag).expect_err("invalid NIP-46 tag error");
- assert!(matches!(
- error,
- RadrootsSdkError::SignerProtocol {
- mode,
- ref reason
- } if mode == RadrootsSdkSignerMode::MycNip46.as_str()
- && reason.contains("failed to convert frozen draft tags")
- ));
-}
-
#[tokio::test]
async fn myc_nip46_provider_reports_preflight_and_progress_sink_edges() {
let draft = frozen_draft();
@@ -727,7 +686,7 @@ async fn myc_nip46_provider_returns_completion_progress_errors_after_remote_sign
let draft = frozen_draft();
let signed = radroots_nostr::prelude::radroots_nostr_sign_frozen_draft(&user_keys, &draft)
.expect("signed");
- let signed_event = RadrootsNostrEvent::from_json(signed.raw_json.as_str()).expect("event");
+ let signed_event = RadrootsNostrEvent::from_json(signed.raw_json()).expect("event");
let (signer, transport) = myc_signer_with_responses(vec![MockNip46Response::Respond(
RadrootsNostrConnectResponse::SignedEvent(signed_event),
)]);
@@ -1086,5 +1045,5 @@ async fn sdk_builder_installs_configured_signer_provider() {
))
.await
.expect("receipt");
- assert_eq!(receipt.signed_event_id, draft.expected_event_id);
+ assert_eq!(receipt.signed_event_id, draft.expected_event_id_str());
}
diff --git a/crates/sdk/tests/unit/sync_runtime_tests.rs b/crates/sdk/tests/unit/sync_runtime_tests.rs
@@ -29,8 +29,6 @@ use radroots_event::draft::{RadrootsEventDraft, RadrootsSignedEvent};
use radroots_event::ids::RadrootsEventId;
#[cfg(feature = "radrootsd-proxy")]
use radroots_event::kinds::KIND_FARM;
-#[cfg(feature = "radrootsd-proxy")]
-use radroots_event_codec::wire::{WireEventParts, to_frozen_draft};
use radroots_event_store::RadrootsEventStoreStatusSummary;
#[cfg(feature = "radrootsd-proxy")]
use radroots_nostr::prelude::{
@@ -134,15 +132,13 @@ fn proxy_actor() -> RadrootsActorContext {
#[cfg(feature = "radrootsd-proxy")]
fn proxy_frozen_draft(d_tag: &str) -> RadrootsEventDraft {
- to_frozen_draft(
- WireEventParts {
- kind: KIND_FARM,
- content: "{}".to_owned(),
- tags: vec![vec!["d".to_owned(), d_tag.to_owned()]],
- },
+ RadrootsEventDraft::new(
"radroots.farm.profile.v1",
- PROXY_SIGNER_PUBLIC_KEY_HEX,
+ KIND_FARM,
1_700_000_000,
+ vec![vec!["d".to_owned(), d_tag.to_owned()]],
+ "{}",
+ PROXY_SIGNER_PUBLIC_KEY_HEX,
)
.expect("frozen draft")
}
@@ -903,7 +899,7 @@ async fn proxy_push_empty_queue_and_private_helpers_are_deterministic() {
message.clone(),
)
.expect("proxy transport error receipt");
- assert_eq!(receipt.event_id, signed_event.id);
+ assert_eq!(receipt.event_id, signed_event.id_str());
assert_eq!(receipt.final_state, PushOutboxEventState::PublishRetryable);
assert_eq!(receipt.retryable_count, 1);
assert!(!receipt.quorum_met);
@@ -1115,16 +1111,15 @@ async fn proxy_push_reports_missing_signed_claim_before_daemon_publish() {
state: RadrootsOutboxEventState::Signed,
claim_token: "claim-token".to_owned(),
active_delivery_plan_id: Some(1),
- draft: RadrootsEventDraft {
- contract_id: "radroots.test".to_owned(),
- contract_registry_version: 1,
- kind: 1,
- created_at: 1_700_000_000,
- tags: Vec::new(),
- content: "{}".to_owned(),
- expected_pubkey: "a".repeat(64),
- expected_event_id: "b".repeat(64),
- },
+ draft: RadrootsEventDraft::new(
+ "radroots.farm.profile.v1",
+ KIND_FARM,
+ 1_700_000_000,
+ vec![vec!["d".to_owned(), "missing-signed-event".to_owned()]],
+ "{}",
+ PROXY_SIGNER_PUBLIC_KEY_HEX,
+ )
+ .expect("draft"),
signed_event: None,
delivery_targets: Vec::new(),
};
@@ -1457,8 +1452,7 @@ async fn proxy_completion_updates_outbox_for_success_retryable_and_terminal_rece
.signed_event
.as_ref()
.expect("signed event")
- .id
- .as_str(),
+ .id_str(),
outcome_kind,
);
assert_eq!(
@@ -1467,16 +1461,19 @@ async fn proxy_completion_updates_outbox_for_success_retryable_and_terminal_rece
.signed_event
.as_ref()
.expect("signed event")
- .id
- .clone()
+ .id_str()
);
assert_eq!(
publish.pubkey,
- claimed.signed_event.as_ref().expect("signed event").pubkey
+ claimed
+ .signed_event
+ .as_ref()
+ .expect("signed event")
+ .pubkey_str()
);
assert_eq!(
publish.event_kind,
- claimed.signed_event.as_ref().expect("signed event").kind
+ claimed.signed_event.as_ref().expect("signed event").kind()
);
let proxy_receipt =
push_proxy_event_receipt(claimed.outbox_event_id, publish.clone()).expect("receipt");
@@ -1564,10 +1561,7 @@ async fn proxy_completion_matches_duplicate_endpoint_targets_by_scope() {
.expect("claim")
.expect("claim");
assert_eq!(claimed.outbox_event_id, enqueue.outbox_event_id);
- let mut publish = proxy_job(
- signed_event.id.as_str(),
- TransportPublishOutcomeKind::Accepted,
- );
+ let mut publish = proxy_job(signed_event.id_str(), TransportPublishOutcomeKind::Accepted);
publish.target_policy = TransportPublishTargetPolicy::explicit_targets(vec![
TransportPublishTarget::nostr("wss://relay.example.com")
.with_scope("farm.a")
@@ -1631,8 +1625,7 @@ async fn proxy_completion_rejects_duplicate_daemon_outcome_before_local_mutation
.signed_event
.as_ref()
.expect("signed event")
- .id
- .as_str(),
+ .id_str(),
TransportPublishOutcomeKind::Accepted,
);
publish.targets.push(publish.targets[0].clone());
diff --git a/crates/sdk/tests/unit/workflow_runtime_tests.rs b/crates/sdk/tests/unit/workflow_runtime_tests.rs
@@ -3,9 +3,8 @@ use super::*;
use crate::{RadrootsSdkLocalKeySigner, RadrootsSdkSignerProvider};
use radroots_authority::{RadrootsSignerError, RadrootsSignerIdentity};
use radroots_event::contract::RadrootsActorRole;
-use radroots_event::draft::RadrootsSignedEvent;
+use radroots_event::draft::{RadrootsEventDraft, RadrootsSignedEvent, RadrootsSignedEventParts};
use radroots_event::kinds::KIND_FARM;
-use radroots_event_codec::wire::{WireEventParts, to_frozen_draft};
use radroots_nostr::prelude::{
RadrootsNostrKeys, RadrootsNostrSecretKey, radroots_nostr_sign_frozen_draft,
};
@@ -54,15 +53,13 @@ fn frozen_draft_for(pubkey: &str) -> RadrootsEventDraft {
}
fn frozen_draft_for_d_tag(pubkey: &str, d_tag: &str) -> RadrootsEventDraft {
- to_frozen_draft(
- WireEventParts {
- kind: KIND_FARM,
- content: "{}".to_owned(),
- tags: vec![vec!["d".to_owned(), d_tag.to_owned()]],
- },
+ RadrootsEventDraft::new(
"radroots.farm.profile.v1",
- pubkey,
+ KIND_FARM,
1_700_000_000,
+ vec![vec!["d".to_owned(), d_tag.to_owned()]],
+ "{}",
+ pubkey,
)
.expect("frozen draft")
}
@@ -72,16 +69,29 @@ fn frozen_draft() -> RadrootsEventDraft {
}
fn signed_event() -> RadrootsSignedEvent {
- RadrootsSignedEvent {
- id: "b".repeat(64),
- pubkey: "a".repeat(64),
- created_at: 1_700_000_000,
- kind: 1,
- tags: vec![vec!["d".to_owned(), "test".to_owned()]],
- content: "{}".to_owned(),
- sig: "c".repeat(128),
- raw_json: "{}".to_owned(),
- }
+ let draft = frozen_draft();
+ let sig = "c".repeat(128);
+ let raw_json = serde_json::json!({
+ "id": draft.expected_event_id_str(),
+ "pubkey": draft.expected_pubkey_str(),
+ "created_at": draft.created_at_u64(),
+ "kind": draft.kind_u32(),
+ "tags": draft.tags_as_vec(),
+ "content": draft.content(),
+ "sig": sig,
+ })
+ .to_string();
+ RadrootsSignedEvent::new(RadrootsSignedEventParts {
+ id: draft.expected_event_id_str().to_owned(),
+ pubkey: draft.expected_pubkey_str().to_owned(),
+ created_at: draft.created_at_u64(),
+ kind: draft.kind_u32(),
+ tags: draft.tags_as_vec(),
+ content: draft.content().to_owned(),
+ sig,
+ raw_json,
+ })
+ .expect("signed event")
}
fn nostr_profile(relay: &'static str) -> crate::TransportProfile {
@@ -121,9 +131,9 @@ fn workflow_digest_and_event_helpers_cover_error_and_input_paths() {
let draft = frozen_draft();
let signed = signed_event();
- let event = event_from_signed(&signed);
- assert_eq!(event.id, signed.id);
- assert_eq!(event.author, signed.pubkey);
+ let event = signed.envelope();
+ assert_eq!(event.id(), signed.id());
+ assert_eq!(event.author(), signed.pubkey());
let idempotency_key = SdkIdempotencyKey::new("workflow-idempotency").expect("idempotency");
let input = signed_outbox_input(
@@ -344,7 +354,7 @@ async fn enqueue_signed_workflow_stores_signed_event_and_reports_idempotency_con
assert_eq!(
receipt.signed_event_id.as_str(),
- first_draft.expected_event_id
+ first_draft.expected_event_id_str()
);
assert!(receipt.local_event_seq > 0);
assert!(receipt.outbox_operation_id > 0);
@@ -445,7 +455,10 @@ async fn enqueue_configured_signed_workflow_uses_sdk_signer_provider() {
.await
.expect("configured enqueue");
- assert_eq!(receipt.signed_event_id.as_str(), draft.expected_event_id);
+ assert_eq!(
+ receipt.signed_event_id.as_str(),
+ draft.expected_event_id_str()
+ );
assert_eq!(receipt.idempotency_digest_prefix.len(), 12);
}
diff --git a/packages/event-bindings/src/generated/types.ts b/packages/event-bindings/src/generated/types.ts
@@ -30,7 +30,7 @@ export type RadrootsDocument = { d_tag: string, doc_type: string, title: string,
export type RadrootsDocumentSubject = { pubkey: string, address?: string | null, };
-export type RadrootsEventEnvelope = { id: string, author: string, created_at: number, kind: number, tags: Array<Array<string>>, content: string, sig: string, };
+export type RadrootsEventEnvelopeDto = { id: string, author: string, created_at: number, kind: number, tags: Array<Array<string>>, content: string, sig: string, };
export type RadrootsEventPtr = { id: string, relays?: string | null, };
@@ -138,6 +138,8 @@ export type RadrootsMessageFileDimensions = { w: number, h: number, };
export type RadrootsMessageRecipient = { public_key: string, relay_url?: string | null, };
+export type RadrootsNip01EventWireDto = { id: string, pubkey: string, created_at: number, kind: number, tags: Array<Array<string>>, content: string, sig: string, extra: { [key: string]: unknown }, };
+
export type RadrootsOrderCancellation = { order_id: string, listing_addr: string, buyer_pubkey: string, seller_pubkey: string, reason: string, };
export type RadrootsOrderDecision = { order_id: string, listing_addr: string, buyer_pubkey: string, seller_pubkey: string, decision: RadrootsOrderDecisionOutcome, };
@@ -204,6 +206,10 @@ export type RadrootsRightsAssertion = { assertion: string, holder?: string | nul
export type RadrootsSeal = { content: string, };
+export type RadrootsSignedEventDto = { state: RadrootsSignedEventVerificationStateDto, envelope: RadrootsEventEnvelopeDto, wire: RadrootsNip01EventWireDto, raw_json: string, };
+
+export type RadrootsSignedEventVerificationStateDto = "id_verified";
+
export type RadrootsSocialFarmAnchor = { farm: RadrootsFarmRef, relays?: Array<string> | null, };
export type RadrootsSocialLocation = { name?: string | null, geohash?: string | null, };
@@ -222,6 +228,10 @@ export type RadrootsTradeListingValidateResult = { valid: boolean, errors: Array
export type RadrootsTradeValidationListingError = { kind: "invalid_kind", amount: { kind: number, }, } | { kind: "missing_listing_id", } | { kind: "listing_event_not_found", amount: { listing_addr: string, }, } | { kind: "listing_event_fetch_failed", amount: { listing_addr: string, }, } | { kind: "parse_error", amount: { error: RadrootsListingParseError, }, } | { kind: "invalid_seller", } | { kind: "missing_farm_profile", } | { kind: "missing_farm_record", } | { kind: "missing_title", } | { kind: "missing_description", } | { kind: "missing_product_type", } | { kind: "missing_bins", } | { kind: "missing_primary_bin", } | { kind: "invalid_bin", } | { kind: "missing_price", } | { kind: "invalid_price", } | { kind: "missing_inventory", } | { kind: "invalid_inventory", } | { kind: "missing_availability", } | { kind: "missing_location", } | { kind: "missing_location_locality", } | { kind: "missing_location_geohash", } | { kind: "invalid_location_geohash", } | { kind: "missing_delivery_method", };
+export type RadrootsVerifiedSignedEventDto = { state: RadrootsVerifiedSignedEventVerificationStateDto, signed_event: RadrootsSignedEventDto, };
+
+export type RadrootsVerifiedSignedEventVerificationStateDto = "signature_verified";
+
export type RadrootsWikiArticle = { d_tag: string, title?: string | null, content_djot: string, summary?: string | null, topics: Array<string>, references: Array<RadrootsEventRef>, forked_from: Array<RadrootsWikiArticleVersionRef>, deferred_to?: RadrootsWikiArticleVersionRef | null, };
export type RadrootsWikiArticleVersionRef = { event_id: string, address_ref: RadrootsAddressableRef, };
diff --git a/packages/event-bindings/src/index.ts b/packages/event-bindings/src/index.ts
@@ -1,3 +1,22 @@
export * from "./generated/types.js";
export * from "./generated/constants.js";
export * from "./generated/kinds.js";
+
+export const RADROOTS_EVENT_TIMESTAMP_MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER;
+
+export function radrootsEventTimestampFromJsonNumber(value: number): number {
+ return radrootsEventTimestampJsonNumber(value);
+}
+
+export function radrootsEventTimestampToJsonNumber(value: number): number {
+ return radrootsEventTimestampJsonNumber(value);
+}
+
+function radrootsEventTimestampJsonNumber(value: number): number {
+ if (!Number.isSafeInteger(value) || value < 0) {
+ throw new RangeError(
+ `Radroots event timestamp must be a non-negative safe integer no greater than Number.MAX_SAFE_INTEGER (${Number.MAX_SAFE_INTEGER})`,
+ );
+ }
+ return value;
+}
diff --git a/tools/xtask/src/contracts.rs b/tools/xtask/src/contracts.rs
@@ -684,7 +684,12 @@ order = 1
"profile.build_draft" = "profile.buildDraft"
[shared_types]
-"WireEventParts" = "WireEventParts"
+"RadrootsNip01EventWireParts" = "RadrootsNip01EventWireParts"
+"RadrootsNip01EventWireDto" = "RadrootsNip01EventWireDto"
+"RadrootsEventDraft" = "RadrootsEventDraft"
+"RadrootsSignedEventDto" = "RadrootsSignedEventDto"
+"RadrootsVerifiedSignedEventDto" = "RadrootsVerifiedSignedEventDto"
+"RadrootsEventEnvelopeDto" = "RadrootsEventEnvelopeDto"
[artifacts]
models_dir = "src/generated"
diff --git a/tools/xtask/src/dto_roots.rs b/tools/xtask/src/dto_roots.rs
@@ -572,7 +572,7 @@ mod tests {
"RadrootsCoopRef",
"RadrootsDocument",
"RadrootsDocumentSubject",
- "RadrootsEventEnvelope",
+ "RadrootsEventEnvelopeDto",
"RadrootsEventPtr",
"RadrootsEventRef",
"RadrootsEvidenceBounty",
@@ -626,6 +626,7 @@ mod tests {
"RadrootsMessageFile",
"RadrootsMessageFileDimensions",
"RadrootsMessageRecipient",
+ "RadrootsNip01EventWireDto",
"RadrootsOrderCancellation",
"RadrootsOrderDecision",
"RadrootsOrderDecisionOutcome",
@@ -659,6 +660,8 @@ mod tests {
"RadrootsResourceHarvestProduct",
"RadrootsRightsAssertion",
"RadrootsSeal",
+ "RadrootsSignedEventDto",
+ "RadrootsSignedEventVerificationStateDto",
"RadrootsSocialFarmAnchor",
"RadrootsSocialLocation",
"RadrootsSocialMediaDimensions",
@@ -668,6 +671,8 @@ mod tests {
"RadrootsTradeListingValidateRequest",
"RadrootsTradeListingValidateResult",
"RadrootsTradeValidationListingError",
+ "RadrootsVerifiedSignedEventDto",
+ "RadrootsVerifiedSignedEventVerificationStateDto",
"RadrootsWikiArticle",
"RadrootsWikiArticleVersionRef",
"RadrootsWikiMergeRequest",
@@ -896,6 +901,30 @@ mod tests {
}
#[test]
+ fn event_generated_types_expose_current_signed_event_dto_shapes() {
+ let wire = type_declaration(EVENT_BINDINGS_TYPES_TS, "RadrootsNip01EventWireDto");
+ let envelope = type_declaration(EVENT_BINDINGS_TYPES_TS, "RadrootsEventEnvelopeDto");
+ let signed = type_declaration(EVENT_BINDINGS_TYPES_TS, "RadrootsSignedEventDto");
+ let verified = type_declaration(EVENT_BINDINGS_TYPES_TS, "RadrootsVerifiedSignedEventDto");
+
+ assert!(wire.contains("pubkey: string"));
+ assert!(wire.contains("extra: { [key: string]: unknown }"));
+ assert!(envelope.contains("author: string"));
+ assert!(!envelope.contains("pubkey"));
+ assert!(!envelope.contains("extra"));
+ assert!(signed.contains("state: RadrootsSignedEventVerificationStateDto"));
+ assert!(signed.contains("envelope: RadrootsEventEnvelopeDto"));
+ assert!(signed.contains("wire: RadrootsNip01EventWireDto"));
+ assert!(signed.contains("raw_json: string"));
+ assert!(verified.contains("state: RadrootsVerifiedSignedEventVerificationStateDto"));
+ assert!(verified.contains("signed_event: RadrootsSignedEventDto"));
+ assert!(
+ !EVENT_BINDINGS_TYPES_TS.contains("export type RadrootsEventEnvelope ="),
+ "event package must not export the retired raw envelope type name"
+ );
+ }
+
+ #[test]
fn event_index_type_inventory_matches_current_package_surface() {
let actual = type_inventory(EVENT_INDEX_BINDINGS_TYPES_TS);
diff --git a/tools/xtask/src/smoke.rs b/tools/xtask/src/smoke.rs
@@ -120,6 +120,7 @@ fn is_exact_crates_version(version: &str) -> bool {
}
const CONSUMER_MAIN: &str = r#"use nostr::{EventBuilder, Keys, Kind, Tag, Timestamp};
+use radroots_event::RadrootsEventEnvelopeParts;
use radroots_sdk::knowledge::prelude::*;
const SECRET_KEY_HEX: &str = "0101010101010101010101010101010101010101010101010101010101010101";
@@ -141,7 +142,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
-fn sign_parts(parts: WireEventParts) -> Result<RadrootsEventEnvelope, Box<dyn std::error::Error>> {
+fn sign_parts(parts: RadrootsNip01EventWireParts) -> Result<RadrootsEventEnvelope, Box<dyn std::error::Error>> {
let tags = parts
.tags
.into_iter()
@@ -152,10 +153,10 @@ fn sign_parts(parts: WireEventParts) -> Result<RadrootsEventEnvelope, Box<dyn st
.tags(tags)
.custom_created_at(Timestamp::from_secs(u64::from(CREATED_AT)))
.sign_with_keys(&keys)?;
- Ok(RadrootsEventEnvelope {
+ Ok(RadrootsEventEnvelope::new(RadrootsEventEnvelopeParts {
id: event.id.to_hex(),
author: event.pubkey.to_hex(),
- created_at: event.created_at.as_secs() as u32,
+ created_at: event.created_at.as_secs(),
kind: u32::from(event.kind.as_u16()),
tags: event
.tags
@@ -165,7 +166,7 @@ fn sign_parts(parts: WireEventParts) -> Result<RadrootsEventEnvelope, Box<dyn st
.collect(),
content: event.content,
sig: event.sig.to_string(),
- })
+ })?)
}
fn public_key_hex() -> String {