cli

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

commit e7d7a9be4a46135e77b7f385dfa6a236595c1a53
parent 90cbacef0fca23c000bf811be00ce015a431eba5
Author: triesap <tyson@radroots.org>
Date:   Wed, 29 Apr 2026 19:10:43 +0000

order: scope status to selected actor

Diffstat:
Msrc/runtime/order.rs | 152++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 139 insertions(+), 13 deletions(-)

diff --git a/src/runtime/order.rs b/src/runtime/order.rs @@ -916,7 +916,17 @@ pub fn status( Err(error) => return Err(RuntimeError::Network(error.to_string())), }; - let mut view = order_status_from_receipt(args.key.as_str(), receipt); + let selected_account = accounts::resolve_account(config)?; + let selected_account_pubkey = selected_account + .as_ref() + .map(|account| account.record.public_identity.public_key_hex.as_str()); + let mut view = order_status_from_receipt_with_context( + OrderStatusContext { + order_id: args.key.as_str(), + selected_account_pubkey, + }, + receipt, + ); enrich_order_status_inventory(config, &mut view)?; Ok(view) } @@ -935,7 +945,26 @@ struct OrderRequestCandidateContext<'a> { seller_pubkey: Option<&'a str>, } +#[derive(Debug, Clone, Copy)] +struct OrderStatusContext<'a> { + order_id: &'a str, + selected_account_pubkey: Option<&'a str>, +} + fn order_status_from_receipt(order_id: &str, receipt: DirectRelayFetchReceipt) -> OrderStatusView { + order_status_from_receipt_with_context( + OrderStatusContext { + order_id, + selected_account_pubkey: None, + }, + receipt, + ) +} + +fn order_status_from_receipt_with_context( + context: OrderStatusContext<'_>, + receipt: DirectRelayFetchReceipt, +) -> OrderStatusView { let DirectRelayFetchReceipt { target_relays, connected_relays, @@ -956,6 +985,10 @@ fn order_status_from_receipt(order_id: &str, receipt: DirectRelayFetchReceipt) - listing_event_id, record, }) => { + if !order_status_request_matches_context(&record, context) { + skipped_count += 1; + continue; + } decoded_count += 1; request_listing_events.push((record.event_id.clone(), listing_event_id)); requests.push(record); @@ -966,7 +999,7 @@ fn order_status_from_receipt(order_id: &str, receipt: DirectRelayFetchReceipt) - } Err(error) => { skipped_count += 1; - if order_status_request_candidate(&event, order_id) { + if order_status_request_candidate(&event, context) { let event_id = event.id.to_string(); candidate_issues.push(issue_with_events( "invalid_request_candidate", @@ -986,6 +1019,7 @@ fn order_status_from_receipt(order_id: &str, receipt: DirectRelayFetchReceipt) - .then_with(|| left.message.cmp(&right.message)) }); + let order_id = context.order_id; let projection = reduce_active_order_events(order_id, requests, decisions.clone()); let listing_event_id = projection .request_event_id @@ -1042,6 +1076,18 @@ fn order_status_from_receipt(order_id: &str, receipt: DirectRelayFetchReceipt) - } } +fn order_status_request_matches_context( + record: &RadrootsActiveOrderRequestRecord, + context: OrderStatusContext<'_>, +) -> bool { + if record.payload.order_id != context.order_id { + return false; + } + context.selected_account_pubkey.is_none_or(|pubkey| { + record.payload.buyer_pubkey == pubkey || record.payload.seller_pubkey == pubkey + }) +} + fn enrich_order_status_inventory( config: &RuntimeConfig, view: &mut OrderStatusView, @@ -1207,14 +1253,18 @@ fn listing_inventory_issue_involves_order( } } -fn order_status_request_candidate(event: &RadrootsNostrEvent, order_id: &str) -> bool { - order_request_candidate_matches( - event, - OrderRequestCandidateContext { - order_id, - seller_pubkey: None, - }, - ) +fn order_status_request_candidate( + event: &RadrootsNostrEvent, + context: OrderStatusContext<'_>, +) -> bool { + if event_kind_u32(event) != KIND_TRADE_ORDER_REQUEST + || !event_matches_tag_value(event, "d", context.order_id) + { + return false; + } + context.selected_account_pubkey.is_none_or(|pubkey| { + event.pubkey.to_string() == pubkey || event_matches_tag_value(event, "p", pubkey) + }) } fn order_request_candidate_matches( @@ -4149,15 +4199,16 @@ mod tests { use super::{ LoadedOrderDraft, ORDER_DRAFT_KIND, OrderDraft, OrderDraftDocument, OrderDraftItem, - ResolvedSellerOrderRequest, SellerOrderRequestResolution, + OrderStatusContext, ResolvedSellerOrderRequest, SellerOrderRequestResolution, accepted_order_decision_payload_from_request, active_request_record_from_resolved, canonical_order_request_payload_from_loaded, collect_issues, declined_order_decision_payload_from_request, inspect_document, next_order_id, order_accept_inventory_preflight_view_from_projection, order_decision_dry_run_view, order_decision_preflight_view_from_status, order_decision_view_from_resolution, order_history_entry_from_event, order_history_from_receipt, order_request_filter, - order_status_from_receipt, order_submit_existing_request_view_from_receipt, - proposed_accept_decision_record, seller_order_request_resolution_from_receipt, + order_status_from_receipt, order_status_from_receipt_with_context, + order_submit_existing_request_view_from_receipt, proposed_accept_decision_record, + seller_order_request_resolution_from_receipt, }; use crate::runtime::config::{ AccountConfig, AccountSecretContractConfig, HyfConfig, IdentityConfig, InteractionConfig, @@ -4765,6 +4816,81 @@ mod tests { } #[test] + fn order_status_with_selected_seller_skips_wrong_seller_same_order_request() { + let fixture = order_status_fixture(); + let other_seller = RadrootsIdentity::generate(); + let other_seller_pubkey = other_seller.public_key_hex(); + let other_listing_addr = format!("30402:{other_seller_pubkey}:AAAAAAAAAAAAAAAAAAAAAw"); + let other_request_event = signed_order_request_event( + &fixture.buyer, + fixture.order_id.as_str(), + other_listing_addr.as_str(), + fixture.buyer_pubkey.as_str(), + other_seller_pubkey.as_str(), + "2".repeat(64).as_str(), + ); + let receipt = DirectRelayFetchReceipt { + target_relays: vec!["ws://relay.test".to_owned()], + connected_relays: vec!["ws://relay.test".to_owned()], + failed_relays: Vec::new(), + events: vec![fixture.request_event.clone(), other_request_event], + }; + let expected_request_event_id = fixture.request_event.id.to_string(); + + let view = order_status_from_receipt_with_context( + OrderStatusContext { + order_id: fixture.order_id.as_str(), + selected_account_pubkey: Some(fixture.seller_pubkey.as_str()), + }, + receipt, + ); + + assert_eq!(view.state, "requested"); + assert_eq!(view.decoded_count, 1); + assert_eq!(view.skipped_count, 1); + assert_eq!( + view.request_event_id.as_deref(), + Some(expected_request_event_id.as_str()) + ); + assert!(view.reducer_issues.is_empty()); + } + + #[test] + fn order_status_with_selected_seller_ignores_malformed_wrong_seller_candidate() { + let fixture = order_status_fixture(); + let other_seller = RadrootsIdentity::generate(); + let other_seller_pubkey = other_seller.public_key_hex(); + let other_listing_addr = format!("30402:{other_seller_pubkey}:AAAAAAAAAAAAAAAAAAAAAw"); + let invalid_event = signed_malformed_order_request_event( + &fixture.buyer, + fixture.order_id.as_str(), + other_listing_addr.as_str(), + fixture.buyer_pubkey.as_str(), + other_seller_pubkey.as_str(), + "2".repeat(64).as_str(), + ); + let receipt = DirectRelayFetchReceipt { + target_relays: vec!["ws://relay.test".to_owned()], + connected_relays: vec!["ws://relay.test".to_owned()], + failed_relays: Vec::new(), + events: vec![fixture.request_event.clone(), invalid_event], + }; + + let view = order_status_from_receipt_with_context( + OrderStatusContext { + order_id: fixture.order_id.as_str(), + selected_account_pubkey: Some(fixture.seller_pubkey.as_str()), + }, + receipt, + ); + + assert_eq!(view.state, "requested"); + assert_eq!(view.decoded_count, 1); + assert_eq!(view.skipped_count, 1); + assert!(view.reducer_issues.is_empty()); + } + + #[test] fn order_decision_dry_run_view_preserves_ready_preflight_without_publish_fields() { let dir = tempdir().expect("tempdir"); let mut config = sample_config(dir.path());