cli

Command-line interface for Radroots
git clone https://radroots.dev/git/cli.git
Log | Files | Refs | README | LICENSE

commit 94abe59df22261896c4eea882d405965bd6a77cf
parent be7a2541f6391da355a9bc258a8197f192adf54e
Author: triesap <tyson@radroots.org>
Date:   Sat, 13 Jun 2026 00:44:17 -0700

cli: align typed protocol ids

- Refresh the lockfile for the shared SQLite binding graph
- Parse rr-rs order and listing protocol IDs at event boundaries
- Update local replica tests for the event-head contract
- Validate the no-default locked CLI check and test lanes

Diffstat:
MCargo.lock | 57+++++++++++++++++++--------------------------------------
Msrc/ops/exec/basket.rs | 2+-
Msrc/runtime/listing.rs | 47++++++++++++++++++++++++++++++++++++++++++-----
Msrc/runtime/order.rs | 443+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/runtime/sync.rs | 9++-------
Mtests/support/mod.rs | 2+-
Mtests/target_cli.rs | 25+++++++++++++++++++------
7 files changed, 362 insertions(+), 223 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -1422,12 +1422,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] -name = "foldhash" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" - -[[package]] name = "foreign-types" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1691,7 +1685,7 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", - "foldhash 0.1.5", + "foldhash", ] [[package]] @@ -1699,9 +1693,6 @@ name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" -dependencies = [ - "foldhash 0.2.0", -] [[package]] name = "hashlink" @@ -1713,6 +1704,15 @@ dependencies = [ ] [[package]] +name = "hashlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2225,9 +2225,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.37.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f111c8c41e7c61a49cd34e44c7619462967221a6443b0ec299e0ac30cfb9b1" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ "cc", "pkg-config", @@ -3567,8 +3567,11 @@ dependencies = [ name = "radroots_events" version = "0.1.0-alpha.2" dependencies = [ + "hex", "radroots_core", "serde", + "serde_json", + "sha2", ] [[package]] @@ -4089,27 +4092,17 @@ dependencies = [ ] [[package]] -name = "rsqlite-vfs" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a1f2315036ef6b1fbacd1972e8ee7688030b0a2121edfc2a6550febd41574d" -dependencies = [ - "hashbrown 0.16.1", - "thiserror 2.0.18", -] - -[[package]] name = "rusqlite" -version = "0.39.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d2b0146dd9661bf67bb107c0bb2a55064d556eeb3fc314151b957f313bcd4e" +checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" dependencies = [ "bitflags", "fallible-iterator", "fallible-streaming-iterator", + "hashlink 0.9.1", "libsqlite3-sys", "smallvec", - "sqlite-wasm-rs", ] [[package]] @@ -5617,18 +5610,6 @@ dependencies = [ ] [[package]] -name = "sqlite-wasm-rs" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4206ed3a67690b9c29b77d728f6acc3ce78f16bf846d83c94f76400320181b" -dependencies = [ - "cc", - "js-sys", - "rsqlite-vfs", - "wasm-bindgen", -] - -[[package]] name = "stable_deref_trait" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -7159,7 +7140,7 @@ checksum = "8902160c4e6f2fb145dbe9d6760a75e3c9522d8bf796ed7047c85919ac7115f8" dependencies = [ "arraydeque", "encoding_rs", - "hashlink", + "hashlink 0.8.4", ] [[package]] diff --git a/src/ops/exec/basket.rs b/src/ops/exec/basket.rs @@ -536,7 +536,7 @@ impl OperationService<BasketQuoteCreateRequest> for BasketOperationService<'_> { let quote = BasketQuote { quote_id: quote_economics .as_ref() - .map(|economics| economics.quote_id.clone()) + .map(|economics| economics.quote_id.to_string()) .unwrap_or_else(|| format!("quote_{}", loaded.document.basket.basket_id)), quote_version: quote_economics .as_ref() diff --git a/src/runtime/listing.rs b/src/runtime/listing.rs @@ -11,6 +11,7 @@ use radroots_core::{ }; use radroots_events::RadrootsNostrEvent; use radroots_events::farm::RadrootsFarmRef; +use radroots_events::ids::{RadrootsDTag, RadrootsInventoryBinId}; use radroots_events::kinds::{KIND_LISTING, KIND_LISTING_DRAFT}; use radroots_events::listing::{ RadrootsListing, RadrootsListingAvailability, RadrootsListingBin, @@ -77,6 +78,21 @@ const APP_RECORD_LIST_LIMIT: u32 = 500; static D_TAG_COUNTER: AtomicU64 = AtomicU64::new(0); +fn protocol_d_tag(value: &str, field: &str) -> Result<RadrootsDTag, RuntimeError> { + value + .parse() + .map_err(|error| RuntimeError::Config(format!("{field} is not a valid d tag: {error}"))) +} + +fn protocol_inventory_bin_id( + value: &str, + field: &str, +) -> Result<RadrootsInventoryBinId, RuntimeError> { + value.parse().map_err(|error| { + RuntimeError::Config(format!("{field} is not a valid inventory bin id: {error}")) + }) +} + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields)] struct ListingDraftDocument { @@ -2206,9 +2222,25 @@ fn canonicalize_draft( draft.primary_bin.bin_id.trim(), price_currency, )?; + let primary_bin_id = + protocol_inventory_bin_id(draft.primary_bin.bin_id.trim(), "primary_bin.bin_id").map_err( + |error| { + issue_for_field( + contents, + "primary_bin.bin_id", + format!("invalid primary_bin bin id: {error}"), + ) + }, + )?; let listing = RadrootsListing { - d_tag: listing_id.clone(), + d_tag: protocol_d_tag(listing_id.as_str(), "listing d_tag").map_err(|error| { + issue_for_field( + contents, + "listing.d_tag", + format!("invalid listing d_tag: {error}"), + ) + })?, published_at: None, farm: RadrootsFarmRef { pubkey: seller_pubkey.clone(), @@ -2225,9 +2257,9 @@ fn canonicalize_draft( profile: None, year: None, }, - primary_bin_id: draft.primary_bin.bin_id.trim().to_owned(), + primary_bin_id: primary_bin_id.clone(), bins: vec![RadrootsListingBin { - bin_id: draft.primary_bin.bin_id.trim().to_owned(), + bin_id: primary_bin_id, quantity, price_per_canonical_unit: price, display_amount: None, @@ -3410,7 +3442,7 @@ mod tests { use radroots_events_codec::d_tag::is_d_tag_base64url; use radroots_events_codec::wire::WireEventParts; use radroots_identity::RadrootsIdentity; - use radroots_nostr::prelude::radroots_nostr_build_event; + use radroots_nostr::prelude::{RadrootsNostrTimestamp, radroots_nostr_build_event}; #[test] fn generated_listing_d_tag_is_valid_base64url() { @@ -3513,6 +3545,7 @@ mod tests { let active = signed_test_listing_event_with_identity( &identity, test_listing_wire_parts(&seller_pubkey, listing_d_tag, "active", "Pasture Eggs"), + 1_700_000_001, ); let active_view = ingest_listing_event_into_local_replica(&replica, &active, Some(listing_addr.clone())); @@ -3534,6 +3567,7 @@ mod tests { let updated = signed_test_listing_event_with_identity( &identity, test_listing_wire_parts(&seller_pubkey, listing_d_tag, "active", "Market Eggs"), + 1_700_000_002, ); let updated_view = ingest_listing_event_into_local_replica(&replica, &updated, Some(listing_addr.clone())); @@ -3548,6 +3582,7 @@ mod tests { let archived = signed_test_listing_event_with_identity( &identity, test_listing_wire_parts(&seller_pubkey, listing_d_tag, "archived", "Market Eggs"), + 1_700_000_003, ); let archived_view = ingest_listing_event_into_local_replica(&replica, &archived, Some(listing_addr)); @@ -3697,15 +3732,17 @@ mod tests { parts: WireEventParts, ) -> radroots_nostr::prelude::RadrootsNostrEvent { let identity = RadrootsIdentity::generate(); - signed_test_listing_event_with_identity(&identity, parts) + signed_test_listing_event_with_identity(&identity, parts, 1_700_000_001) } fn signed_test_listing_event_with_identity( identity: &RadrootsIdentity, parts: WireEventParts, + created_at: u64, ) -> radroots_nostr::prelude::RadrootsNostrEvent { radroots_nostr_build_event(parts.kind, parts.content, parts.tags) .expect("event builder") + .custom_created_at(RadrootsNostrTimestamp::from_secs(created_at)) .sign_with_keys(identity.keys()) .expect("signed event") } diff --git a/src/runtime/order.rs b/src/runtime/order.rs @@ -12,6 +12,10 @@ use radroots_core::{ convert_unit_decimal, }; use radroots_events::RadrootsNostrEventPtr; +use radroots_events::ids::{ + RadrootsEconomicsDigest, RadrootsInventoryBinId, RadrootsListingAddress, RadrootsOrderId, + RadrootsOrderQuoteId, RadrootsOrderRevisionId, +}; use radroots_events::kinds::{ KIND_LISTING, KIND_ORDER_CANCELLATION, KIND_ORDER_DECISION, KIND_ORDER_FULFILLMENT_UPDATE, KIND_ORDER_PAYMENT_RECORD, KIND_ORDER_RECEIPT, KIND_ORDER_REQUEST, @@ -53,10 +57,10 @@ use radroots_nostr::prelude::{ radroots_nostr_kind, }; use radroots_replica_db::{ - ReplicaSql, ReplicaTradeProductSummaryRow, nostr_event_state, trade_product, + ReplicaSql, ReplicaTradeProductSummaryRow, nostr_event_head, trade_product, }; -use radroots_replica_db_schema::nostr_event_state::{ - INostrEventStateFindOne, INostrEventStateFindOneArgs, NostrEventStateQueryBindValues, +use radroots_replica_db_schema::nostr_event_head::{ + INostrEventHeadFindOne, INostrEventHeadFindOneArgs, NostrEventHeadQueryBindValues, }; use radroots_replica_db_schema::trade_product::{ ITradeProductFieldsFilter, ITradeProductFindMany, TradeProduct, @@ -144,6 +148,48 @@ const APP_ORDER_SIGNED_EVIDENCE_CONFLICT_ISSUE: &str = "app_order_signed_evidenc static ORDER_COUNTER: AtomicU64 = AtomicU64::new(0); +fn protocol_order_id(value: &str, field: &str) -> Result<RadrootsOrderId, RuntimeError> { + value + .parse() + .map_err(|error| RuntimeError::Config(format!("{field} is not a valid order id: {error}"))) +} + +fn protocol_listing_addr(value: &str, field: &str) -> Result<RadrootsListingAddress, RuntimeError> { + value.parse().map_err(|error| { + RuntimeError::Config(format!("{field} is not a valid listing address: {error}")) + }) +} + +fn protocol_revision_id(value: &str, field: &str) -> Result<RadrootsOrderRevisionId, RuntimeError> { + value.parse().map_err(|error| { + RuntimeError::Config(format!("{field} is not a valid order revision id: {error}")) + }) +} + +fn protocol_quote_id(value: &str, field: &str) -> Result<RadrootsOrderQuoteId, RuntimeError> { + value.parse().map_err(|error| { + RuntimeError::Config(format!("{field} is not a valid order quote id: {error}")) + }) +} + +fn protocol_inventory_bin_id( + value: &str, + field: &str, +) -> Result<RadrootsInventoryBinId, RuntimeError> { + value.parse().map_err(|error| { + RuntimeError::Config(format!("{field} is not a valid inventory bin id: {error}")) + }) +} + +fn protocol_economics_digest( + value: &str, + field: &str, +) -> Result<RadrootsEconomicsDigest, RuntimeError> { + value.parse().map_err(|error| { + RuntimeError::Config(format!("{field} is not a valid economics digest: {error}")) + }) +} + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields)] struct OrderDraftDocument { @@ -272,8 +318,8 @@ struct ResolvedTradeProductNotes { struct ResolvedSellerOrderRequest { request_event_id: String, listing_event_id: Option<String>, - order_id: String, - listing_addr: String, + order_id: RadrootsOrderId, + listing_addr: RadrootsListingAddress, buyer_pubkey: String, seller_pubkey: String, items: Vec<RadrootsOrderItem>, @@ -1107,7 +1153,8 @@ fn rebind_inner( document.buyer_actor.pubkey = target_pubkey.clone(); document.buyer_actor.source = ORDER_BUYER_ACTOR_SOURCE_REBIND.to_owned(); if order_id_changed && let Some(economics) = document.order.economics.as_mut() { - economics.quote_id = format!("quote_{to_order_id}"); + economics.quote_id = + protocol_quote_id(format!("quote_{to_order_id}").as_str(), "quote_id")?; } let output_file = if order_id_changed { @@ -3564,7 +3611,7 @@ fn order_status_revision_view( { return Some(OrderStatusRevisionView { state: "pending".to_owned(), - revision_id: Some(proposal.payload.revision_id.clone()), + revision_id: Some(proposal.payload.revision_id.to_string()), proposal_event_id: Some(proposal.event_id.clone()), decision_event_id: None, root_event_id: Some(proposal.root_event_id.clone()), @@ -3598,7 +3645,7 @@ fn order_status_revision_view_from_decision( }; OrderStatusRevisionView { state: state.to_owned(), - revision_id: Some(decision.payload.revision_id.clone()), + revision_id: Some(decision.payload.revision_id.to_string()), proposal_event_id: Some(decision.prev_event_id.clone()), decision_event_id: Some(decision.event_id.clone()), root_event_id: Some(decision.root_event_id.clone()), @@ -3663,7 +3710,7 @@ fn inventory_bins_from_decision( let mut bins = inventory_commitments .iter() .map(|commitment| OrderInventoryBinView { - bin_id: commitment.bin_id.clone(), + bin_id: commitment.bin_id.to_string(), committed_count: u64::from(commitment.bin_count), available_count: None, remaining_count: None, @@ -4929,7 +4976,7 @@ fn apply_order_payment_status(view: &mut OrderPaymentView, status: &OrderStatusV view.root_event_id = status.request_event_id.clone(); view.prev_event_id = order_payment_prev_event_id(status); if let Some(economics) = status.economics.as_ref() { - view.quote_id = Some(economics.quote_id.clone()); + view.quote_id = Some(economics.quote_id.to_string()); view.quote_version = Some(economics.quote_version); view.economics_digest = radroots_order_economics_digest(economics).ok(); view.amount = Some(economics.total.amount); @@ -5808,8 +5855,8 @@ fn apply_order_decision_request( view: &mut OrderDecisionView, request: &ResolvedSellerOrderRequest, ) { - view.order_id = request.order_id.clone(); - view.listing_addr = Some(request.listing_addr.clone()); + view.order_id = request.order_id.to_string(); + view.listing_addr = Some(request.listing_addr.to_string()); view.buyer_pubkey = Some(request.buyer_pubkey.clone()); view.seller_pubkey = Some(request.seller_pubkey.clone()); view.request_event_id = Some(request.request_event_id.clone()); @@ -6082,7 +6129,7 @@ fn order_revision_preflight_view_from_status( if let Some(record) = pending_revision { view.event_id = Some(record.event_id.clone()); view.event_kind = Some(KIND_ORDER_REVISION_PROPOSAL); - view.revision_id = Some(record.payload.revision_id.clone()); + view.revision_id = Some(record.payload.revision_id.to_string()); } view.reason = Some(match state { "missing" => format!("no active order events matched `{}`", args.key), @@ -6464,7 +6511,7 @@ fn order_inventory_view_from_listing_projection( .bins .iter() .map(|bin| OrderInventoryBinView { - bin_id: bin.bin_id.clone(), + bin_id: bin.bin_id.to_string(), committed_count: bin.accepted_reserved_count, available_count: Some(bin.available_count), remaining_count: Some(bin.remaining_count), @@ -6618,7 +6665,7 @@ fn listing_inventory_bins( ) })?; Ok(vec![RadrootsListingInventoryBinAvailability { - bin_id: listing.primary_bin_id.clone(), + bin_id: listing.primary_bin_id.to_string(), available_count, }]) } @@ -6957,11 +7004,11 @@ fn order_revision_payload_from_status( args: &OrderRevisionProposeArgs, status: &OrderStatusView, ) -> Result<RadrootsOrderRevisionProposal, RuntimeError> { - let revision_id = next_revision_id(); + let revision_id = protocol_revision_id(next_revision_id().as_str(), "revision_id")?; let economics = status.economics.clone().ok_or_else(|| { RuntimeError::Config("accepted order is missing current agreement economics".to_owned()) })?; - let economics = revised_order_economics(args, &revision_id, &economics)?; + let economics = revised_order_economics(args, revision_id.as_str(), &economics)?; let items = economics .items .iter() @@ -6972,10 +7019,13 @@ fn order_revision_payload_from_status( .collect::<Vec<_>>(); Ok(RadrootsOrderRevisionProposal { revision_id, - order_id: status.order_id.clone(), - listing_addr: status.listing_addr.clone().ok_or_else(|| { - RuntimeError::Config("accepted order is missing listing_addr".to_owned()) - })?, + order_id: protocol_order_id(status.order_id.as_str(), "order_id")?, + listing_addr: protocol_listing_addr( + status.listing_addr.as_deref().ok_or_else(|| { + RuntimeError::Config("accepted order is missing listing_addr".to_owned()) + })?, + "listing_addr", + )?, buyer_pubkey: status.buyer_pubkey.clone().ok_or_else(|| { RuntimeError::Config("accepted order is missing buyer_pubkey".to_owned()) })?, @@ -7007,13 +7057,14 @@ fn revised_order_economics( current_canonical.canonicalize(); let mut economics = current_canonical.clone(); let mut changed = false; - economics.quote_id = format!("revision_{revision_id}"); + economics.quote_id = protocol_quote_id(format!("revision_{revision_id}").as_str(), "quote_id")?; economics.quote_version = economics .quote_version .checked_add(1) .ok_or_else(|| RuntimeError::Config("revision quote_version overflowed".to_owned()))?; if let Some(bin_id) = args.bin_id.as_deref().and_then(non_empty_ref) { + let bin_id = protocol_inventory_bin_id(bin_id, "revision bin_id")?; let bin_count = args.bin_count.ok_or_else(|| { RuntimeError::Config("revision bin_count is required with bin_id".to_owned()) })?; @@ -7246,14 +7297,14 @@ fn apply_order_revision_payload( view: &mut OrderRevisionProposalView, payload: &RadrootsOrderRevisionProposal, ) { - view.revision_id = Some(payload.revision_id.clone()); + view.revision_id = Some(payload.revision_id.to_string()); view.root_event_id = Some(payload.root_event_id.clone()); view.prev_event_id = Some(payload.prev_event_id.clone()); view.items = payload .items .iter() .map(|item| OrderDraftItemView { - bin_id: item.bin_id.clone(), + bin_id: item.bin_id.to_string(), bin_count: item.bin_count, }) .collect(); @@ -7264,7 +7315,7 @@ fn apply_order_revision_decision_proposal( view: &mut OrderRevisionDecisionView, proposal: &OrderRevisionProposalRecord, ) { - view.revision_id = Some(proposal.payload.revision_id.clone()); + view.revision_id = Some(proposal.payload.revision_id.to_string()); view.root_event_id = Some(proposal.payload.root_event_id.clone()); view.prev_event_id = Some(proposal.event_id.clone()); view.event_id = Some(proposal.event_id.clone()); @@ -7279,7 +7330,7 @@ fn apply_order_revision_decision_payload( proposal: &OrderRevisionProposalRecord, payload: &RadrootsOrderRevisionDecision, ) { - view.revision_id = Some(payload.revision_id.clone()); + view.revision_id = Some(payload.revision_id.to_string()); view.root_event_id = Some(payload.root_event_id.clone()); view.prev_event_id = Some(payload.prev_event_id.clone()); view.decision = Some( @@ -7345,10 +7396,13 @@ fn order_fulfillment_payload_from_status( fulfillment_state: RadrootsOrderFulfillmentState, ) -> Result<RadrootsOrderFulfillmentUpdate, RuntimeError> { Ok(RadrootsOrderFulfillmentUpdate { - order_id: status.order_id.clone(), - listing_addr: status.listing_addr.clone().ok_or_else(|| { - RuntimeError::Config("accepted order is missing listing_addr".to_owned()) - })?, + order_id: protocol_order_id(status.order_id.as_str(), "order_id")?, + listing_addr: protocol_listing_addr( + status.listing_addr.as_deref().ok_or_else(|| { + RuntimeError::Config("accepted order is missing listing_addr".to_owned()) + })?, + "listing_addr", + )?, buyer_pubkey: status.buyer_pubkey.clone().ok_or_else(|| { RuntimeError::Config("accepted order is missing buyer_pubkey".to_owned()) })?, @@ -7382,10 +7436,13 @@ fn order_cancellation_payload_from_status( status: &OrderStatusView, ) -> Result<RadrootsOrderCancellation, RuntimeError> { Ok(RadrootsOrderCancellation { - order_id: status.order_id.clone(), - listing_addr: status.listing_addr.clone().ok_or_else(|| { - RuntimeError::Config("cancellable order is missing listing_addr".to_owned()) - })?, + order_id: protocol_order_id(status.order_id.as_str(), "order_id")?, + listing_addr: protocol_listing_addr( + status.listing_addr.as_deref().ok_or_else(|| { + RuntimeError::Config("cancellable order is missing listing_addr".to_owned()) + })?, + "listing_addr", + )?, buyer_pubkey: status.buyer_pubkey.clone().ok_or_else(|| { RuntimeError::Config("cancellable order is missing buyer_pubkey".to_owned()) })?, @@ -7415,10 +7472,13 @@ fn order_receipt_payload_from_status( status: &OrderStatusView, ) -> Result<RadrootsOrderReceipt, RuntimeError> { Ok(RadrootsOrderReceipt { - order_id: status.order_id.clone(), - listing_addr: status.listing_addr.clone().ok_or_else(|| { - RuntimeError::Config("receiptable order is missing listing_addr".to_owned()) - })?, + order_id: protocol_order_id(status.order_id.as_str(), "order_id")?, + listing_addr: protocol_listing_addr( + status.listing_addr.as_deref().ok_or_else(|| { + RuntimeError::Config("receiptable order is missing listing_addr".to_owned()) + })?, + "listing_addr", + )?, buyer_pubkey: status.buyer_pubkey.clone().ok_or_else(|| { RuntimeError::Config("receiptable order is missing buyer_pubkey".to_owned()) })?, @@ -7486,10 +7546,13 @@ fn order_payment_payload_from_status( )); } Ok(RadrootsOrderPaymentRecord { - order_id: status.order_id.clone(), - listing_addr: status.listing_addr.clone().ok_or_else(|| { - RuntimeError::Config("payable order is missing listing_addr".to_owned()) - })?, + order_id: protocol_order_id(status.order_id.as_str(), "order_id")?, + listing_addr: protocol_listing_addr( + status.listing_addr.as_deref().ok_or_else(|| { + RuntimeError::Config("payable order is missing listing_addr".to_owned()) + })?, + "listing_addr", + )?, buyer_pubkey: status.buyer_pubkey.clone().ok_or_else(|| { RuntimeError::Config("payable order is missing buyer_pubkey".to_owned()) })?, @@ -7505,8 +7568,12 @@ fn order_payment_payload_from_status( agreement_event_id, quote_id: economics.quote_id.clone(), quote_version: economics.quote_version, - economics_digest: radroots_order_economics_digest(economics) - .map_err(|error| RuntimeError::Config(error.to_string()))?, + economics_digest: protocol_economics_digest( + radroots_order_economics_digest(economics) + .map_err(|error| RuntimeError::Config(error.to_string()))? + .as_str(), + "economics_digest", + )?, amount, currency, method: parse_payment_method(args.method.as_str())?, @@ -7557,10 +7624,13 @@ fn order_settlement_payload_from_status( } let decision = settlement_decision_protocol(args.decision); Ok(RadrootsOrderSettlementDecision { - order_id: status.order_id.clone(), - listing_addr: status.listing_addr.clone().ok_or_else(|| { - RuntimeError::Config("settleable order is missing listing_addr".to_owned()) - })?, + order_id: protocol_order_id(status.order_id.as_str(), "order_id")?, + listing_addr: protocol_listing_addr( + status.listing_addr.as_deref().ok_or_else(|| { + RuntimeError::Config("settleable order is missing listing_addr".to_owned()) + })?, + "listing_addr", + )?, seller_pubkey: status.seller_pubkey.clone().ok_or_else(|| { RuntimeError::Config("settleable order is missing seller_pubkey".to_owned()) })?, @@ -7575,15 +7645,21 @@ fn order_settlement_payload_from_status( RuntimeError::Config("settleable order is missing agreement_event_id".to_owned()) })?, payment_event_id, - quote_id: payment.quote_id.clone().ok_or_else(|| { - RuntimeError::Config("settleable order is missing quote_id".to_owned()) - })?, + quote_id: protocol_quote_id( + payment.quote_id.as_deref().ok_or_else(|| { + RuntimeError::Config("settleable order is missing quote_id".to_owned()) + })?, + "quote_id", + )?, quote_version: payment.quote_version.ok_or_else(|| { RuntimeError::Config("settleable order is missing quote_version".to_owned()) })?, - economics_digest: payment.economics_digest.clone().ok_or_else(|| { - RuntimeError::Config("settleable order is missing economics_digest".to_owned()) - })?, + economics_digest: protocol_economics_digest( + payment.economics_digest.as_deref().ok_or_else(|| { + RuntimeError::Config("settleable order is missing economics_digest".to_owned()) + })?, + "economics_digest", + )?, amount: payment .amount .ok_or_else(|| RuntimeError::Config("settleable order is missing amount".to_owned()))?, @@ -7622,9 +7698,9 @@ fn apply_order_payment_payload(view: &mut OrderPaymentView, payload: &RadrootsOr view.root_event_id = Some(payload.root_event_id.clone()); view.prev_event_id = Some(payload.previous_event_id.clone()); view.agreement_event_id = Some(payload.agreement_event_id.clone()); - view.quote_id = Some(payload.quote_id.clone()); + view.quote_id = Some(payload.quote_id.to_string()); view.quote_version = Some(payload.quote_version); - view.economics_digest = Some(payload.economics_digest.clone()); + view.economics_digest = Some(payload.economics_digest.to_string()); view.amount = Some(payload.amount); view.currency = Some(payload.currency); view.method = Some(payload.method); @@ -7640,9 +7716,9 @@ fn apply_order_settlement_payload( view.prev_event_id = Some(payload.previous_event_id.clone()); view.payment_event_id = Some(payload.payment_event_id.clone()); view.agreement_event_id = Some(payload.agreement_event_id.clone()); - view.quote_id = Some(payload.quote_id.clone()); + view.quote_id = Some(payload.quote_id.to_string()); view.quote_version = Some(payload.quote_version); - view.economics_digest = Some(payload.economics_digest.clone()); + view.economics_digest = Some(payload.economics_digest.to_string()); view.amount = Some(payload.amount); view.currency = Some(payload.currency); view.decision = Some(payload.decision); @@ -7795,7 +7871,7 @@ fn published_order_revision_decision_view( let mut view = order_revision_decision_base_view(config, args, state, false); apply_order_revision_decision_status(&mut view, status); apply_order_revision_decision_payload(&mut view, proposal, payload); - view.revision_id = Some(payload.revision_id.clone()); + view.revision_id = Some(payload.revision_id.to_string()); view.root_event_id = Some(payload.root_event_id.clone()); view.prev_event_id = Some(payload.prev_event_id.clone()); view.event_id = Some(event_id.clone()); @@ -8272,7 +8348,7 @@ fn seller_order_request_from_event( Ok(ResolvedSellerOrderRequest { request_event_id: event.id, listing_event_id, - order_id: envelope.order_id, + order_id: envelope.payload.order_id, listing_addr: envelope.payload.listing_addr, buyer_pubkey: envelope.payload.buyer_pubkey, seller_pubkey: envelope.payload.seller_pubkey, @@ -8768,10 +8844,10 @@ fn resolve_active_listing_event_id( "{}:{}:{}", parsed.kind, parsed.seller_pubkey, parsed.listing_id ); - let state = nostr_event_state::find_one( + let state = nostr_event_head::find_one( &executor, - &INostrEventStateFindOne::On(INostrEventStateFindOneArgs { - on: NostrEventStateQueryBindValues::Key { key }, + &INostrEventHeadFindOne::On(INostrEventHeadFindOneArgs { + on: NostrEventHeadQueryBindValues::Key { key }, }), ) .map_err(|error| RuntimeError::Config(format!("resolve listing event state: {error:?}")))? @@ -8961,7 +9037,7 @@ fn order_economics_from_resolved_listing( unit_price_amount * quantity_amount * RadrootsCoreDecimal::from(item.bin_count); subtotal_amount = subtotal_amount + line_amount; economic_items.push(RadrootsOrderEconomicItem { - bin_id: item.bin_id.clone(), + bin_id: protocol_inventory_bin_id(item.bin_id.as_str(), "order item bin_id")?, bin_count: item.bin_count, quantity_amount, quantity_unit, @@ -8982,7 +9058,7 @@ fn order_economics_from_resolved_listing( let adjustments = basket_adjustment_lines(adjustments)?; let zero = RadrootsCoreMoney::zero(currency); let mut economics = RadrootsOrderEconomics { - quote_id: format!("quote_{order_id}"), + quote_id: protocol_quote_id(format!("quote_{order_id}").as_str(), "quote_id")?, quote_version: 1, pricing_basis: RadrootsOrderPricingBasis::ListingEvent, currency, @@ -11446,21 +11522,27 @@ fn canonical_order_request_payload_from_loaded( loaded.document.order.economics.clone().ok_or_else(|| { RuntimeError::Config("order draft is missing quote economics".to_owned()) })?; + let items = loaded + .document + .order + .items + .iter() + .map(|item| { + Ok(RadrootsOrderItem { + bin_id: protocol_inventory_bin_id(item.bin_id.as_str(), "order item bin_id")?, + bin_count: item.bin_count, + }) + }) + .collect::<Result<Vec<_>, RuntimeError>>()?; let payload = RadrootsOrderRequest { - order_id: loaded.document.order.order_id.clone(), - listing_addr: loaded.document.order.listing_addr.clone(), + order_id: protocol_order_id(loaded.document.order.order_id.as_str(), "order_id")?, + listing_addr: protocol_listing_addr( + loaded.document.order.listing_addr.as_str(), + "listing_addr", + )?, buyer_pubkey: loaded.document.order.buyer_pubkey.clone(), seller_pubkey: loaded.document.order.seller_pubkey.clone(), - items: loaded - .document - .order - .items - .iter() - .map(|item| RadrootsOrderItem { - bin_id: item.bin_id.clone(), - bin_count: item.bin_count, - }) - .collect(), + items, economics, }; canonicalize_order_request_for_signer(payload, signer_pubkey) @@ -12342,6 +12424,10 @@ mod tests { RadrootsCoreCurrency, RadrootsCoreDecimal, RadrootsCoreMoney, RadrootsCoreUnit, }; use radroots_events::RadrootsNostrEventPtr; + use radroots_events::ids::{ + RadrootsEconomicsDigest, RadrootsInventoryBinId, RadrootsListingAddress, RadrootsOrderId, + RadrootsOrderQuoteId, RadrootsOrderRevisionId, + }; use radroots_events::kinds::{ KIND_ORDER_CANCELLATION, KIND_ORDER_DECISION, KIND_ORDER_FULFILLMENT_UPDATE, KIND_ORDER_PAYMENT_RECORD, KIND_ORDER_RECEIPT, KIND_ORDER_REVISION_DECISION, @@ -12426,6 +12512,30 @@ mod tests { }; use crate::runtime::direct_relay::DirectRelayFetchReceipt; + fn test_order_id(value: &str) -> RadrootsOrderId { + value.parse().expect("valid order id") + } + + fn test_listing_addr(value: &str) -> RadrootsListingAddress { + value.parse().expect("valid listing address") + } + + fn test_inventory_bin_id(value: &str) -> RadrootsInventoryBinId { + value.parse().expect("valid inventory bin id") + } + + fn test_order_quote_id(value: &str) -> RadrootsOrderQuoteId { + value.parse().expect("valid order quote id") + } + + fn test_order_revision_id(value: &str) -> RadrootsOrderRevisionId { + value.parse().expect("valid order revision id") + } + + fn test_economics_digest(value: &str) -> RadrootsEconomicsDigest { + value.parse().expect("valid economics digest") + } + #[test] fn generated_order_id_uses_stable_prefix() { let order_id = next_order_id(); @@ -12754,12 +12864,12 @@ mod tests { let listing_addr = format!("30402:{seller_pubkey}:AAAAAAAAAAAAAAAAAAAAAg"); let listing_event_id = "1".repeat(64); let payload = RadrootsOrderRequest { - order_id: "ord_AAAAAAAAAAAAAAAAAAAAAg".to_owned(), - listing_addr: listing_addr.clone(), + order_id: test_order_id("ord_AAAAAAAAAAAAAAAAAAAAAg"), + listing_addr: test_listing_addr(listing_addr.as_str()), buyer_pubkey: buyer_pubkey.clone(), seller_pubkey: seller_pubkey.clone(), items: vec![RadrootsOrderItem { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], economics: sample_order_economics("ord_AAAAAAAAAAAAAAAAAAAAAg", "bin-1", 2), @@ -12834,7 +12944,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -12891,7 +13001,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -12955,7 +13065,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -13017,7 +13127,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -13083,7 +13193,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -13152,7 +13262,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -13227,7 +13337,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -13278,7 +13388,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -13392,7 +13502,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -13457,7 +13567,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -14303,7 +14413,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -14503,7 +14613,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -14647,7 +14757,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -14713,7 +14823,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -14811,7 +14921,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -14873,7 +14983,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -14931,7 +15041,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -14994,7 +15104,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -15084,7 +15194,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -15161,7 +15271,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -15255,7 +15365,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -15333,7 +15443,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -15413,7 +15523,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -15490,7 +15600,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -15567,7 +15677,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -15636,7 +15746,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -15705,7 +15815,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -15752,7 +15862,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -15797,7 +15907,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -15854,7 +15964,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -15913,7 +16023,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -15971,7 +16081,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -16022,7 +16132,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -16109,7 +16219,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -16188,7 +16298,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -16250,7 +16360,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -16307,7 +16417,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -16378,7 +16488,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -16434,7 +16544,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -16492,7 +16602,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -16555,7 +16665,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -16618,7 +16728,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -16692,7 +16802,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -16765,7 +16875,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -16818,7 +16928,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -16886,7 +16996,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -16963,7 +17073,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -17042,7 +17152,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -17255,7 +17365,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -17333,7 +17443,7 @@ mod tests { wrong_buyer.public_key_hex().as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -17378,7 +17488,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -17445,7 +17555,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -17546,12 +17656,12 @@ mod tests { let existing_request = ResolvedSellerOrderRequest { request_event_id: existing_request_event.id.to_string(), listing_event_id: Some(fixture.listing_event_id.clone()), - order_id: existing_order_id.to_owned(), - listing_addr: fixture.listing_addr.clone(), + order_id: test_order_id(existing_order_id), + listing_addr: test_listing_addr(fixture.listing_addr.as_str()), buyer_pubkey: fixture.buyer_pubkey.clone(), seller_pubkey: fixture.seller_pubkey.clone(), items: vec![RadrootsOrderItem { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], economics: sample_order_economics(existing_order_id, "bin-1", 2), @@ -17644,12 +17754,12 @@ mod tests { let existing_request = ResolvedSellerOrderRequest { request_event_id: existing_request_event.id.to_string(), listing_event_id: Some(fixture.listing_event_id.clone()), - order_id: existing_order_id.to_owned(), - listing_addr: fixture.listing_addr.clone(), + order_id: test_order_id(existing_order_id), + listing_addr: test_listing_addr(fixture.listing_addr.as_str()), buyer_pubkey: fixture.buyer_pubkey.clone(), seller_pubkey: fixture.seller_pubkey.clone(), items: vec![RadrootsOrderItem { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], economics: sample_order_economics(existing_order_id, "bin-1", 2), @@ -17741,7 +17851,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 1, }], }, @@ -17823,7 +17933,7 @@ mod tests { fixture.seller_pubkey.as_str(), RadrootsOrderDecisionOutcome::Accepted { inventory_commitments: vec![RadrootsOrderInventoryCommitment { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], }, @@ -18201,12 +18311,12 @@ mod tests { let unit_price_amount = RadrootsCoreDecimal::from(unit_price); let line_amount = unit_price_amount * RadrootsCoreDecimal::from(bin_count); RadrootsOrderEconomics { - quote_id: format!("quote_{order_id}"), + quote_id: test_order_quote_id(format!("quote_{order_id}").as_str()), quote_version: 1, pricing_basis: RadrootsOrderPricingBasis::ListingEvent, currency, items: vec![RadrootsOrderEconomicItem { - bin_id: bin_id.to_owned(), + bin_id: test_inventory_bin_id(bin_id), bin_count, quantity_amount: RadrootsCoreDecimal::ONE, quantity_unit: RadrootsCoreUnit::Each, @@ -18503,8 +18613,8 @@ mod tests { decision: RadrootsOrderDecisionOutcome, ) -> radroots_nostr::prelude::RadrootsNostrEvent { let payload = RadrootsOrderDecision { - order_id: order_id.to_owned(), - listing_addr: listing_addr.to_owned(), + order_id: test_order_id(order_id), + listing_addr: test_listing_addr(listing_addr), buyer_pubkey: buyer_pubkey.to_owned(), seller_pubkey: seller_pubkey.to_owned(), decision, @@ -18541,19 +18651,19 @@ mod tests { bin_count: u32, ) -> radroots_nostr::prelude::RadrootsNostrEvent { let mut economics = sample_order_economics(order_id, "bin-1", bin_count); - economics.quote_id = "revision_rev_test".to_owned(); + economics.quote_id = test_order_quote_id("revision_rev_test"); economics.quote_version = 2; economics.canonicalize(); let payload = RadrootsOrderRevisionProposal { - revision_id: "rev_test".to_owned(), - order_id: order_id.to_owned(), - listing_addr: listing_addr.to_owned(), + revision_id: test_order_revision_id("rev_test"), + order_id: test_order_id(order_id), + listing_addr: test_listing_addr(listing_addr), buyer_pubkey: buyer_pubkey.to_owned(), seller_pubkey: seller_pubkey.to_owned(), root_event_id: request_event.id.to_string(), prev_event_id: decision_event.id.to_string(), items: vec![RadrootsOrderItem { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count, }], economics, @@ -18612,8 +18722,8 @@ mod tests { status: RadrootsOrderFulfillmentState, ) -> radroots_nostr::prelude::RadrootsNostrEvent { let payload = RadrootsOrderFulfillmentUpdate { - order_id: order_id.to_owned(), - listing_addr: listing_addr.to_owned(), + order_id: test_order_id(order_id), + listing_addr: test_listing_addr(listing_addr), buyer_pubkey: buyer_pubkey.to_owned(), seller_pubkey: seller_pubkey.to_owned(), status, @@ -18643,8 +18753,8 @@ mod tests { reason: &str, ) -> radroots_nostr::prelude::RadrootsNostrEvent { let payload = RadrootsOrderCancellation { - order_id: order_id.to_owned(), - listing_addr: listing_addr.to_owned(), + order_id: test_order_id(order_id), + listing_addr: test_listing_addr(listing_addr), buyer_pubkey: buyer_pubkey.to_owned(), seller_pubkey: seller_pubkey.to_owned(), reason: reason.to_owned(), @@ -18675,8 +18785,8 @@ mod tests { issue: Option<&str>, ) -> radroots_nostr::prelude::RadrootsNostrEvent { let payload = RadrootsOrderReceipt { - order_id: order_id.to_owned(), - listing_addr: listing_addr.to_owned(), + order_id: test_order_id(order_id), + listing_addr: test_listing_addr(listing_addr), buyer_pubkey: buyer_pubkey.to_owned(), seller_pubkey: seller_pubkey.to_owned(), received, @@ -18706,8 +18816,8 @@ mod tests { ) -> radroots_nostr::prelude::RadrootsNostrEvent { let economics = sample_order_economics(order_id, "bin-1", 2); let payload = RadrootsOrderPaymentRecord { - order_id: order_id.to_owned(), - listing_addr: listing_addr.to_owned(), + order_id: test_order_id(order_id), + listing_addr: test_listing_addr(listing_addr), buyer_pubkey: buyer_pubkey.to_owned(), seller_pubkey: seller_pubkey.to_owned(), root_event_id: request_event.id.to_string(), @@ -18715,8 +18825,11 @@ mod tests { agreement_event_id: agreement_event.id.to_string(), quote_id: economics.quote_id.clone(), quote_version: economics.quote_version, - economics_digest: radroots_trade::order::radroots_order_economics_digest(&economics) - .expect("economics digest"), + economics_digest: test_economics_digest( + radroots_trade::order::radroots_order_economics_digest(&economics) + .expect("economics digest") + .as_str(), + ), amount: economics.total.amount, currency: economics.total.currency, method: RadrootsOrderPaymentMethod::ManualTransfer, @@ -18783,12 +18896,12 @@ mod tests { listing_event_id: &str, ) -> radroots_nostr::prelude::RadrootsNostrEvent { let payload = RadrootsOrderRequest { - order_id: order_id.to_owned(), - listing_addr: listing_addr.to_owned(), + order_id: test_order_id(order_id), + listing_addr: test_listing_addr(listing_addr), buyer_pubkey: buyer_pubkey.to_owned(), seller_pubkey: seller_pubkey.to_owned(), items: vec![RadrootsOrderItem { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], economics: sample_order_economics(order_id, "bin-1", 2), @@ -18836,12 +18949,12 @@ mod tests { economics: RadrootsOrderEconomics, ) -> radroots_nostr::prelude::RadrootsNostrEvent { let payload = RadrootsOrderRequest { - order_id: order_id.to_owned(), - listing_addr: listing_addr.to_owned(), + order_id: test_order_id(order_id), + listing_addr: test_listing_addr(listing_addr), buyer_pubkey: buyer_pubkey.to_owned(), seller_pubkey: seller_pubkey.to_owned(), items: vec![RadrootsOrderItem { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], economics, diff --git a/src/runtime/sync.rs b/src/runtime/sync.rs @@ -17,7 +17,7 @@ use radroots_nostr::prelude::{ use radroots_replica_db::{ReplicaSql, migrations}; use radroots_replica_sync::{ RadrootsReplicaEventsError, RadrootsReplicaIngestOutcome, RadrootsReplicaPendingPublishEvent, - radroots_replica_ingest_event, radroots_replica_ingest_event_state, + radroots_replica_ingest_event, radroots_replica_ingest_event_head, radroots_replica_pending_publish_batch, radroots_replica_sync_status, }; use radroots_sql_core::{SqlExecutor, SqliteExecutor}; @@ -439,12 +439,7 @@ where push_unique_many(&mut acknowledged_relays, receipt.acknowledged_relays.iter()); failed_relays.extend(relay_failures(receipt.failed_relays)); let signed_event = radroots_event_from_nostr(&receipt.event); - radroots_replica_ingest_event_state( - &executor, - &signed_event, - event.d_tag.as_str(), - event.content_hash.as_str(), - )?; + radroots_replica_ingest_event_head(&executor, &signed_event)?; counts.published_count += 1; } Err(error) => { diff --git a/tests/support/mod.rs b/tests/support/mod.rs @@ -420,7 +420,7 @@ pub fn replace_latest_listing_event_id( let params = serde_json::to_string(&vec![event_id, key.as_str()]).expect("update params"); executor .exec( - "UPDATE nostr_event_state SET last_event_id = ? WHERE key = ?;", + "UPDATE nostr_event_head SET last_event_id = ? WHERE key = ?;", params.as_str(), ) .expect("update latest listing event id"); diff --git a/tests/target_cli.rs b/tests/target_cli.rs @@ -8,6 +8,7 @@ use std::thread::{self, JoinHandle}; use std::time::Duration; use radroots_events::RadrootsNostrEventPtr; +use radroots_events::ids::{RadrootsInventoryBinId, RadrootsListingAddress, RadrootsOrderId}; use radroots_events::kinds::{KIND_FARM, KIND_ORDER_REQUEST, KIND_PROFILE}; use radroots_events::order::{RadrootsOrderEconomics, RadrootsOrderItem, RadrootsOrderRequest}; use radroots_events_codec::order::order_request_event_build; @@ -41,6 +42,18 @@ const LISTING_ADDR: &str = "30402:1111111111111111111111111111111111111111111111111111111111111111:AAAAAAAAAAAAAAAAAAAAAg"; const SYNC_PUSH_FARM_D_TAG: &str = "AAAAAAAAAAAAAAAAAAAAAA"; +fn test_order_id(value: &str) -> RadrootsOrderId { + value.parse().expect("valid order id") +} + +fn test_listing_addr(value: &str) -> RadrootsListingAddress { + value.parse().expect("valid listing address") +} + +fn test_inventory_bin_id(value: &str) -> RadrootsInventoryBinId { + value.parse().expect("valid inventory bin id") +} + struct RelayPublishServer { endpoint: String, requests: Receiver<Value>, @@ -731,12 +744,12 @@ fn signed_app_order_request_event( bin_count: u32, ) -> RadrootsNostrEvent { let payload = RadrootsOrderRequest { - order_id: order_id.to_owned(), - listing_addr: listing_addr.to_owned(), + order_id: test_order_id(order_id), + listing_addr: test_listing_addr(listing_addr), buyer_pubkey: buyer.public_key_hex(), seller_pubkey: seller_pubkey.to_owned(), items: vec![RadrootsOrderItem { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count, }], economics: app_order_economics(order_id, bin_count), @@ -6100,12 +6113,12 @@ fn signed_order_request_event_for_quote( let buyer_pubkey = buyer.public_key_hex(); let seller_pubkey = "1".repeat(64); let payload = RadrootsOrderRequest { - order_id: order_id.to_owned(), - listing_addr: LISTING_ADDR.to_owned(), + order_id: test_order_id(order_id), + listing_addr: test_listing_addr(LISTING_ADDR), buyer_pubkey, seller_pubkey, items: vec![RadrootsOrderItem { - bin_id: "bin-1".to_owned(), + bin_id: test_inventory_bin_id("bin-1"), bin_count: 2, }], economics,