commit fe05bb1ced1d75a9d7975b6f114ecd257df652d3
parent e465fa1b13daf879b43e522a05ee30abc9d215e1
Author: triesap <tyson@radroots.org>
Date: Wed, 15 Jul 2026 08:19:33 +0000
protocol: remove retired trade event surfaces
- remove retired listing draft, revision, proof, question, answer, discount, fulfillment, and receipt event contracts
- cut trade reducers, listing mutation, SP1 evidence, and projection schema to the stable V1 catalog
- refresh conformance vectors, contract text, canonical boundary checks, and retired-surface hygiene guards
- validate with focused checks, tests, contract validation, hygiene, release preflight, and diff checks
Diffstat:
36 files changed, 482 insertions(+), 4683 deletions(-)
diff --git a/contracts/conformance/vectors/social/upgraded_boundaries.v1.json b/contracts/conformance/vectors/social/upgraded_boundaries.v1.json
@@ -44,21 +44,6 @@
}
},
{
- "id": "social_listing_draft_uses_listing_model_valid_003",
- "kind": "social.listing_draft.parse_event.valid",
- "input": {
- "event": {
- "kind": 30403,
- "content_shape": "listing_markdown",
- "tags_shape": "listing_tags_full"
- }
- },
- "expected": {
- "result": "ok",
- "model": "RadrootsListing"
- }
- },
- {
"id": "social_relay_list_read_write_valid_004",
"kind": "social.relay_list.parse_event.valid",
"input": {
@@ -234,7 +219,7 @@
"input": {
"kinds": {
"active_listing": 30402,
- "listing_draft": 30403,
+ "retired_listing_kind": 30403,
"report": 1984,
"farm_crdt_change": 78,
"relay_auth": 22242,
@@ -244,15 +229,15 @@
"expected": {
"result": "ok",
"home_feed_active_listing": true,
- "home_feed_listing_draft": false,
+ "home_feed_retired_listing_kind": false,
"home_feed_report": false,
"home_feed_farm_crdt_change": false,
"home_feed_relay_auth": false,
"home_feed_http_auth": false,
"market_active_listing": true,
- "market_listing_draft": false,
+ "market_retired_listing_kind": false,
"moderation_report": true,
- "draft_owner_listing_draft": true,
+ "retired_listing_kind_accepted": false,
"private_farm_ops_farm_crdt_change": true,
"private_farm_ops_relay_auth": false,
"private_farm_ops_http_auth": false
diff --git a/contracts/conformance/vectors/trade_validation/validate_listing_event.v1.json b/contracts/conformance/vectors/trade_validation/validate_listing_event.v1.json
@@ -13,7 +13,7 @@
}
},
"expected": {
- "validation_shape": "trade_listing_validation_result"
+ "validation_shape": "trade_validation_receipt"
}
}
]
diff --git a/contracts/events/social-events.md b/contracts/events/social-events.md
@@ -18,8 +18,8 @@ deterministic fixtures live under `contracts/conformance`.
## Implementation Inventory
The repository implements public social support for kind `1` `RadrootsPost`, kind `1111`
-`RadrootsComment`, kind `7` `RadrootsReaction`, generic `RadrootsList` entries, listing draft kind
-`30403` through `RadrootsListing`, articles, generic public file metadata, calendar date events,
+`RadrootsComment`, kind `7` `RadrootsReaction`, generic `RadrootsList` entries, stable listing
+records through `RadrootsListing`, articles, generic public file metadata, calendar date events,
calendar time events, reposts, generic reposts, calendar collections, RSVP events, and reports.
The closeout contract requires:
@@ -50,7 +50,7 @@ The production-v1 public social substrate includes:
- `RadrootsCalendar` for NIP-52 kind `31924`
- `RadrootsCalendarEventRsvp` for NIP-52 kind `31925`
- `RadrootsReport` for NIP-56 kind `1984`
-- listing draft kind `30403` validation through `RadrootsListing`
+- stable listing kind `30402` validation through `RadrootsListing`
- relay-list kind `10002` validation through `RadrootsList`
## Contract Decisions
@@ -85,16 +85,14 @@ uppercase `D` tag so timestamped events retain a deterministic calendar-date anc
Product routing uses surface-specific kind classifiers rather than a broad public-social set. Home,
Events, Market, Map, and Profile public-content candidates are explicit. Active listing kind `30402`
-can appear in public product surfaces, but listing draft kind `30403` is limited to draft-owner
-contexts. Report kind `1984` is a moderation/admin candidate, not normal feed content. Relay and HTTP
-auth kinds are transient and excluded from durable social and farm-ops candidate sets. Private farm
-operations candidates include the farm workspace manifest, farm CRDT change envelope, farm file
-metadata, and the supported NIP-29 group event subset.
-
-`RadrootsListingDraft` and `RadrootsRelayList` are not separate model types in the target contract.
-Listing draft kind `30403` is represented through `RadrootsListing`, and NIP-51 standard and
-list-set entries, including NIP-65 relay metadata kind `10002`, are represented through
-`RadrootsList`.
+can appear in public product surfaces. Report kind `1984` is a moderation/admin candidate, not
+normal feed content. Relay and HTTP auth kinds are transient and excluded from durable social and
+farm-ops candidate sets. Private farm operations candidates include the farm workspace manifest,
+farm CRDT change envelope, farm file metadata, and the supported NIP-29 group event subset.
+
+`RadrootsRelayList` is not a separate model type in the target contract. Stable listings are
+represented through `RadrootsListing`, and NIP-51 standard and list-set entries, including NIP-65
+relay metadata kind `10002`, are represented through `RadrootsList`.
## Exclusions
diff --git a/crates/authority/src/authorization.rs b/crates/authority/src/authorization.rs
@@ -175,7 +175,7 @@ mod tests {
RadrootsActorContext::explicit_pubkey(pubkey, [RadrootsActorRole::Buyer]).expect("buyer")
}
- fn listing_draft(pubkey: &str) -> RadrootsEventDraft {
+ fn listing_event_draft(pubkey: &str) -> RadrootsEventDraft {
RadrootsEventDraft::new(
"radroots.listing.published.v1",
KIND_LISTING,
@@ -184,7 +184,7 @@ mod tests {
"{}",
pubkey,
)
- .expect("listing draft")
+ .expect("listing event draft")
}
#[derive(Default)]
@@ -326,10 +326,8 @@ mod tests {
fn buyer_and_seller_contract_roles_match_current_contracts() {
let listing = event_contract("radroots.listing.published.v1").expect("listing contract");
let order_request = event_contract("radroots.order.request.v1").expect("order contract");
- let order_revision_proposal =
- event_contract("radroots.order.revision_proposal.v1").expect("revision proposal");
- let order_revision_decision =
- event_contract("radroots.order.revision_decision.v1").expect("revision decision");
+ let order_decision =
+ event_contract("radroots.order.decision.v1").expect("decision contract");
let seller = seller_actor(hex_64('a').as_str());
let buyer = buyer_actor(hex_64('b').as_str());
@@ -344,29 +342,17 @@ mod tests {
authorize_actor_for_contract(&seller, order_request),
Err(RadrootsAuthorityError::ActorRoleUnsatisfied { .. })
));
- assert_eq!(
- order_revision_proposal.author_role,
- RadrootsActorRole::Seller
- );
- assert!(authorize_actor_for_contract(&seller, order_revision_proposal).is_ok());
- assert!(matches!(
- authorize_actor_for_contract(&buyer, order_revision_proposal),
- Err(RadrootsAuthorityError::ActorRoleUnsatisfied { .. })
- ));
- assert_eq!(
- order_revision_decision.author_role,
- RadrootsActorRole::Buyer
- );
- assert!(authorize_actor_for_contract(&buyer, order_revision_decision).is_ok());
+ assert_eq!(order_decision.author_role, RadrootsActorRole::Seller);
+ assert!(authorize_actor_for_contract(&seller, order_decision).is_ok());
assert!(matches!(
- authorize_actor_for_contract(&seller, order_revision_decision),
+ authorize_actor_for_contract(&buyer, order_decision),
Err(RadrootsAuthorityError::ActorRoleUnsatisfied { .. })
));
}
#[test]
fn actor_pubkey_mismatch_fails() {
- let draft = listing_draft(hex_64('a').as_str());
+ let draft = listing_event_draft(hex_64('a').as_str());
let actor = seller_actor(hex_64('b').as_str());
assert!(matches!(
@@ -377,7 +363,7 @@ mod tests {
#[test]
fn signer_pubkey_mismatch_fails() {
- let draft = listing_draft(hex_64('a').as_str());
+ let draft = listing_event_draft(hex_64('a').as_str());
let signer = StaticSigner::new(hex_64('b').as_str());
assert!(matches!(
@@ -389,7 +375,7 @@ mod tests {
#[test]
fn signer_explicit_id_mismatch_fails_before_authorized_signing() {
let pubkey = hex_64('a');
- let draft = listing_draft(pubkey.as_str());
+ let draft = listing_event_draft(pubkey.as_str());
let actor = seller_actor(pubkey.as_str());
let signer = StaticSigner::with_event_id(pubkey.as_str(), hex_64('e'));
@@ -404,7 +390,7 @@ mod tests {
#[test]
fn signed_event_created_at_mismatch_fails() {
let pubkey = hex_64('a');
- let draft = listing_draft(pubkey.as_str());
+ let draft = listing_event_draft(pubkey.as_str());
let actor = seller_actor(pubkey.as_str());
let signer = StaticSigner::with_overrides(
pubkey.as_str(),
@@ -423,7 +409,7 @@ mod tests {
#[test]
fn signed_event_kind_mismatch_fails() {
let pubkey = hex_64('a');
- let draft = listing_draft(pubkey.as_str());
+ let draft = listing_event_draft(pubkey.as_str());
let actor = seller_actor(pubkey.as_str());
let signer = StaticSigner::with_overrides(
pubkey.as_str(),
@@ -445,7 +431,7 @@ mod tests {
#[test]
fn signed_event_tags_mismatch_fails() {
let pubkey = hex_64('a');
- let draft = listing_draft(pubkey.as_str());
+ let draft = listing_event_draft(pubkey.as_str());
let actor = seller_actor(pubkey.as_str());
let signer = StaticSigner::with_overrides(
pubkey.as_str(),
@@ -471,7 +457,7 @@ mod tests {
#[test]
fn signed_event_content_mismatch_fails() {
let pubkey = hex_64('a');
- let draft = listing_draft(pubkey.as_str());
+ let draft = listing_event_draft(pubkey.as_str());
let actor = seller_actor(pubkey.as_str());
let signer = StaticSigner::with_overrides(
pubkey.as_str(),
@@ -497,7 +483,7 @@ mod tests {
#[test]
fn signed_event_exactly_matching_draft_passes() {
let pubkey = hex_64('a');
- let draft = listing_draft(pubkey.as_str());
+ let draft = listing_event_draft(pubkey.as_str());
let signed = signed_event_from_draft(&draft);
validate_signed_event_matches_draft(&signed, &draft).expect("signed event matches draft");
@@ -506,7 +492,7 @@ mod tests {
#[test]
fn signed_event_pubkey_mismatch_fails() {
let pubkey = hex_64('a');
- let draft = listing_draft(pubkey.as_str());
+ let draft = listing_event_draft(pubkey.as_str());
let signed = signed_event_from_parts(
hex_64('b'),
draft.created_at_u64(),
@@ -536,7 +522,7 @@ mod tests {
#[test]
fn static_signer_maps_invalid_signed_event_parts() {
let pubkey = hex_64('a');
- let draft = listing_draft(pubkey.as_str());
+ let draft = listing_event_draft(pubkey.as_str());
let signer = StaticSigner::with_event_id(pubkey.as_str(), "bad-id".to_owned());
assert!(matches!(
@@ -548,7 +534,7 @@ mod tests {
#[test]
fn authorized_actor_and_signer_return_signed_event() {
let pubkey = hex_64('a');
- let draft = listing_draft(pubkey.as_str());
+ let draft = listing_event_draft(pubkey.as_str());
let actor = seller_actor(pubkey.as_str());
let signer = StaticSigner::new(pubkey.as_str());
diff --git a/crates/event/src/contract.rs b/crates/event/src/contract.rs
@@ -573,20 +573,6 @@ const TAG_LISTING_EVENT: RadrootsTagContract = tag(
RadrootsTagValueType::EventId,
false,
);
-const TAG_SERVICE_INPUT: RadrootsTagContract = tag(
- "i",
- RadrootsTagCardinality::RequiredOne,
- RadrootsTagSemantic::ServiceInput,
- RadrootsTagValueType::Text,
- true,
-);
-const TAG_SERVICE_REQUEST: RadrootsTagContract = tag(
- "request",
- RadrootsTagCardinality::RequiredOne,
- RadrootsTagSemantic::ServiceInput,
- RadrootsTagValueType::EventId,
- false,
-);
const TAG_SERVICE_OUTPUT: RadrootsTagContract = tag(
"output",
RadrootsTagCardinality::RequiredOne,
@@ -702,9 +688,6 @@ const CHAINED_ORDER_TAGS: &[RadrootsTagContract] = &[
TAG_E_ROOT,
TAG_E_PREVIOUS,
];
-const TRADE_VALIDATION_REQUEST_TAGS: &[RadrootsTagContract] = &[TAG_SERVICE_INPUT, TAG_A_REQUIRED];
-const TRADE_VALIDATION_RESULT_TAGS: &[RadrootsTagContract] =
- &[TAG_SERVICE_REQUEST, TAG_SERVICE_OUTPUT];
const TRADE_VALIDATION_RECEIPT_TAGS: &[RadrootsTagContract] =
&[TAG_E_ROOT, TAG_A_OPTIONAL, TAG_SERVICE_OUTPUT];
const KNOWLEDGE_SOURCE_TAGS: &[RadrootsTagContract] = &[
@@ -1482,14 +1465,6 @@ static ALL_KIND_CONTRACTS: &[RadrootsKindContract] = &[
["radroots.listing.published.v1"]
),
kind_contract!(
- KIND_LISTING_DRAFT,
- "KIND_LISTING_DRAFT",
- "Listing Draft",
- RadrootsEventClass::Addressable,
- RadrootsNostrStandard::Radroots,
- ["radroots.listing.draft.v1"]
- ),
- kind_contract!(
KIND_KNOWLEDGE_SOURCE,
"KIND_KNOWLEDGE_SOURCE",
"Knowledge Source",
@@ -1594,38 +1569,6 @@ static ALL_KIND_CONTRACTS: &[RadrootsKindContract] = &[
["radroots.group.roles.v1"]
),
kind_contract!(
- KIND_TRADE_LISTING_VALIDATION_REQUEST,
- "KIND_TRADE_LISTING_VALIDATION_REQUEST",
- "Trade Listing Validation Request",
- RadrootsEventClass::Regular,
- RadrootsNostrStandard::Nip90,
- ["radroots.trade.listing_validation.request.v1"]
- ),
- kind_contract!(
- KIND_TRADE_LISTING_VALIDATION_RESULT,
- "KIND_TRADE_LISTING_VALIDATION_RESULT",
- "Trade Listing Validation Result",
- RadrootsEventClass::Regular,
- RadrootsNostrStandard::Nip90,
- ["radroots.trade.listing_validation.result.v1"]
- ),
- kind_contract!(
- KIND_TRADE_TRANSITION_PROOF_REQUEST,
- "KIND_TRADE_TRANSITION_PROOF_REQUEST",
- "Trade Transition Proof Request",
- RadrootsEventClass::Regular,
- RadrootsNostrStandard::Nip90,
- ["radroots.trade.transition_proof.request.v1"]
- ),
- kind_contract!(
- KIND_TRADE_TRANSITION_PROOF_RESULT,
- "KIND_TRADE_TRANSITION_PROOF_RESULT",
- "Trade Transition Proof Result",
- RadrootsEventClass::Regular,
- RadrootsNostrStandard::Nip90,
- ["radroots.trade.transition_proof.result.v1"]
- ),
- kind_contract!(
KIND_ORDER_REQUEST,
"KIND_ORDER_REQUEST",
"Order Request",
@@ -1642,22 +1585,6 @@ static ALL_KIND_CONTRACTS: &[RadrootsKindContract] = &[
["radroots.order.decision.v1"]
),
kind_contract!(
- KIND_ORDER_REVISION_PROPOSAL,
- "KIND_ORDER_REVISION_PROPOSAL",
- "Order Revision Proposal",
- RadrootsEventClass::Regular,
- RadrootsNostrStandard::Radroots,
- ["radroots.order.revision_proposal.v1"]
- ),
- kind_contract!(
- KIND_ORDER_REVISION_DECISION,
- "KIND_ORDER_REVISION_DECISION",
- "Order Revision Decision",
- RadrootsEventClass::Regular,
- RadrootsNostrStandard::Radroots,
- ["radroots.order.revision_decision.v1"]
- ),
- kind_contract!(
KIND_ORDER_CANCELLATION,
"KIND_ORDER_CANCELLATION",
"Order Cancellation",
@@ -2690,19 +2617,6 @@ static ALL_EVENT_CONTRACTS: &[RadrootsEventContract] = &[
LISTING_TAGS,
LISTING_REDUCERS
),
- event_contract!(
- "radroots.listing.draft.v1",
- KIND_LISTING_DRAFT,
- "Listing Draft",
- "RadrootsListing",
- RadrootsEventClass::Addressable,
- RadrootsEventPrivacy::Secret,
- RadrootsActorRole::Seller,
- RadrootsContentSchema::JsonObject,
- RadrootsEventDiscriminator::KindOnly,
- LISTING_TAGS,
- LISTING_REDUCERS
- ),
experimental_event_contract!(
"radroots.knowledge.source.v1",
KIND_KNOWLEDGE_SOURCE,
@@ -2897,58 +2811,6 @@ static ALL_EVENT_CONTRACTS: &[RadrootsEventContract] = &[
GROUP_REDUCERS
),
event_contract!(
- "radroots.trade.listing_validation.request.v1",
- KIND_TRADE_LISTING_VALIDATION_REQUEST,
- "Trade Listing Validation Request",
- "RadrootsTradeValidationListingRequest",
- RadrootsEventClass::Regular,
- RadrootsEventPrivacy::Public,
- RadrootsActorRole::Service,
- RadrootsContentSchema::JsonObject,
- RadrootsEventDiscriminator::KindOnly,
- TRADE_VALIDATION_REQUEST_TAGS,
- TRADE_VALIDATION_REDUCERS
- ),
- event_contract!(
- "radroots.trade.listing_validation.result.v1",
- KIND_TRADE_LISTING_VALIDATION_RESULT,
- "Trade Listing Validation Result",
- "RadrootsTradeValidationListingResult",
- RadrootsEventClass::Regular,
- RadrootsEventPrivacy::Public,
- RadrootsActorRole::Service,
- RadrootsContentSchema::JsonObject,
- RadrootsEventDiscriminator::KindOnly,
- TRADE_VALIDATION_RESULT_TAGS,
- TRADE_VALIDATION_REDUCERS
- ),
- event_contract!(
- "radroots.trade.transition_proof.request.v1",
- KIND_TRADE_TRANSITION_PROOF_REQUEST,
- "Trade Transition Proof Request",
- "RadrootsTradeTransitionProofRequest",
- RadrootsEventClass::Regular,
- RadrootsEventPrivacy::Public,
- RadrootsActorRole::Service,
- RadrootsContentSchema::JsonObject,
- RadrootsEventDiscriminator::KindOnly,
- TRADE_VALIDATION_REQUEST_TAGS,
- TRADE_VALIDATION_REDUCERS
- ),
- event_contract!(
- "radroots.trade.transition_proof.result.v1",
- KIND_TRADE_TRANSITION_PROOF_RESULT,
- "Trade Transition Proof Result",
- "RadrootsTradeTransitionProofResult",
- RadrootsEventClass::Regular,
- RadrootsEventPrivacy::Public,
- RadrootsActorRole::Service,
- RadrootsContentSchema::JsonObject,
- RadrootsEventDiscriminator::KindOnly,
- TRADE_VALIDATION_RESULT_TAGS,
- TRADE_VALIDATION_REDUCERS
- ),
- event_contract!(
"radroots.order.request.v1",
KIND_ORDER_REQUEST,
"Order Request",
@@ -2975,32 +2837,6 @@ static ALL_EVENT_CONTRACTS: &[RadrootsEventContract] = &[
ORDER_REDUCERS
),
event_contract!(
- "radroots.order.revision_proposal.v1",
- KIND_ORDER_REVISION_PROPOSAL,
- "Order Revision Proposal",
- "RadrootsOrderRevisionProposal",
- RadrootsEventClass::Regular,
- RadrootsEventPrivacy::Public,
- RadrootsActorRole::Seller,
- RadrootsContentSchema::JsonObject,
- RadrootsEventDiscriminator::KindOnly,
- CHAINED_ORDER_TAGS,
- ORDER_REDUCERS
- ),
- event_contract!(
- "radroots.order.revision_decision.v1",
- KIND_ORDER_REVISION_DECISION,
- "Order Revision Decision",
- "RadrootsOrderRevisionDecision",
- RadrootsEventClass::Regular,
- RadrootsEventPrivacy::Public,
- RadrootsActorRole::Buyer,
- RadrootsContentSchema::JsonObject,
- RadrootsEventDiscriminator::KindOnly,
- CHAINED_ORDER_TAGS,
- ORDER_REDUCERS
- ),
- event_contract!(
"radroots.order.cancellation.v1",
KIND_ORDER_CANCELLATION,
"Order Cancellation",
@@ -3108,16 +2944,10 @@ pub fn kind_contract_family(contract: &RadrootsKindContract) -> Option<RadrootsC
| KIND_RESOURCE_HARVEST_CAP
| KIND_FARM_WORKSPACE_MANIFEST
| KIND_FARM_CRDT_CHANGE => RadrootsContractFamily::Farm,
- KIND_LISTING | KIND_LISTING_DRAFT => RadrootsContractFamily::Market,
- KIND_TRADE_LISTING_VALIDATION_REQUEST
- | KIND_TRADE_LISTING_VALIDATION_RESULT
- | KIND_TRADE_TRANSITION_PROOF_REQUEST
- | KIND_TRADE_TRANSITION_PROOF_RESULT
- | KIND_TRADE_VALIDATION_RECEIPT
+ KIND_LISTING => RadrootsContractFamily::Market,
+ KIND_TRADE_VALIDATION_RECEIPT
| KIND_ORDER_REQUEST
| KIND_ORDER_DECISION
- | KIND_ORDER_REVISION_PROPOSAL
- | KIND_ORDER_REVISION_DECISION
| KIND_ORDER_CANCELLATION => RadrootsContractFamily::Trade,
KIND_WIKI_MERGE_REQUEST
| KIND_WIKI_ARTICLE
diff --git a/crates/event/src/dto.rs b/crates/event/src/dto.rs
@@ -125,6 +125,11 @@ mod tests {
"RadrootsOrderResponse",
"RadrootsOrderRevision",
"RadrootsOrderRevisionResponse",
+ "RadrootsOrderRevisionProposal",
+ "RadrootsOrderRevisionDecision",
+ "RadrootsOrderRevisionOutcome",
+ "RadrootsTradeValidationListingRequest",
+ "RadrootsTradeValidationListingResult",
] {
assert!(
!export_names.contains(obsolete_export),
@@ -138,9 +143,6 @@ mod tests {
"RadrootsOrderRequest",
"RadrootsOrderDecision",
"RadrootsOrderDecisionOutcome",
- "RadrootsOrderRevisionProposal",
- "RadrootsOrderRevisionDecision",
- "RadrootsOrderRevisionOutcome",
"RadrootsOrderCancellation",
"RadrootsListingParseError",
] {
diff --git a/crates/event/src/generated/dto_roots.rs b/crates/event/src/generated/dto_roots.rs
@@ -110,9 +110,6 @@ pub fn dto_bindgen_roots() -> ::std::vec::Vec<::dto_bindgen::export::RootDescrip
::dto_bindgen::export::RootDescriptor::new::<crate::order::RadrootsOrderInventoryCommitment>(
),
::dto_bindgen::export::RootDescriptor::new::<crate::order::RadrootsOrderRequest>(),
- ::dto_bindgen::export::RootDescriptor::new::<crate::order::RadrootsOrderRevisionDecision>(),
- ::dto_bindgen::export::RootDescriptor::new::<crate::order::RadrootsOrderRevisionOutcome>(),
- ::dto_bindgen::export::RootDescriptor::new::<crate::order::RadrootsOrderRevisionProposal>(),
::dto_bindgen::export::RootDescriptor::new::<
crate::order_economics::RadrootsOrderEconomicActor,
>(),
@@ -161,11 +158,5 @@ pub fn dto_bindgen_roots() -> ::std::vec::Vec<::dto_bindgen::export::RootDescrip
::dto_bindgen::export::RootDescriptor::new::<
crate::trade_validation::RadrootsTradeValidationListingError,
>(),
- ::dto_bindgen::export::RootDescriptor::new::<
- crate::trade_validation::RadrootsTradeValidationListingRequest,
- >(),
- ::dto_bindgen::export::RootDescriptor::new::<
- crate::trade_validation::RadrootsTradeValidationListingResult,
- >(),
]
}
diff --git a/crates/event/src/ids.rs b/crates/event/src/ids.rs
@@ -183,7 +183,6 @@ validated_string_id!(
);
validated_string_id!(RadrootsListingAddress, validate_addressable_coordinate);
validated_string_id!(RadrootsOrderId, validate_commercial_id);
-validated_string_id!(RadrootsOrderRevisionId, validate_commercial_id);
validated_string_id!(RadrootsOrderQuoteId, validate_commercial_id);
validated_string_id!(RadrootsInventoryBinId, validate_commercial_id);
validated_string_id!(RadrootsEconomicsDigest, validate_economics_digest);
@@ -523,10 +522,6 @@ mod tests {
"order-1"
);
assert_eq!(
- RadrootsOrderRevisionId::parse("rev 1").unwrap_err(),
- RadrootsIdParseError::InvalidCharacter
- );
- assert_eq!(
RadrootsInventoryBinId::parse("a".repeat(129)).unwrap_err(),
RadrootsIdParseError::TooLong {
max: 128,
@@ -578,7 +573,6 @@ mod tests {
assert_identifier_impls!(RadrootsAddressableCoordinate, addressable.as_str());
assert_identifier_impls!(RadrootsListingAddress, addressable.as_str());
assert_identifier_impls!(RadrootsOrderId, "order-1");
- assert_identifier_impls!(RadrootsOrderRevisionId, "revision-1");
assert_identifier_impls!(RadrootsOrderQuoteId, "quote-1");
assert_identifier_impls!(RadrootsInventoryBinId, "bin-1");
assert_identifier_impls!(RadrootsEconomicsDigest, "digest-1");
@@ -723,11 +717,6 @@ mod tests {
}
#[allow(dead_code)]
#[derive(Debug, serde::Deserialize)]
- struct MissingOrderRevisionId {
- value: RadrootsOrderRevisionId,
- }
- #[allow(dead_code)]
- #[derive(Debug, serde::Deserialize)]
struct MissingOrderQuoteId {
value: RadrootsOrderQuoteId,
}
@@ -752,7 +741,6 @@ mod tests {
assert_eq!(missing_field_message::<MissingDTag>(), missing);
assert_eq!(missing_field_message::<MissingListingAddress>(), missing);
assert_eq!(missing_field_message::<MissingOrderId>(), missing);
- assert_eq!(missing_field_message::<MissingOrderRevisionId>(), missing);
assert_eq!(missing_field_message::<MissingOrderQuoteId>(), missing);
assert_eq!(missing_field_message::<MissingInventoryBinId>(), missing);
}
diff --git a/crates/event/src/kinds.rs b/crates/event/src/kinds.rs
@@ -76,30 +76,16 @@ pub const KIND_ACCOUNT_CLAIM: u32 = 30380;
pub const KIND_APP_DATA: u32 = 30078;
pub const KIND_FARM_WORKSPACE_MANIFEST: u32 = KIND_APP_DATA;
pub const KIND_LISTING: u32 = 30402;
-pub const KIND_LISTING_DRAFT: u32 = 30403;
pub const KIND_APPLICATION_HANDLER: u32 = 31990;
pub const KIND_GROUP_METADATA: u32 = 39000;
pub const KIND_GROUP_ADMINS: u32 = 39001;
pub const KIND_GROUP_MEMBERS: u32 = 39002;
pub const KIND_GROUP_ROLES: u32 = 39003;
-pub const KIND_TRADE_LISTING_VALIDATION_REQUEST: u32 = 5321;
-pub const KIND_TRADE_LISTING_VALIDATION_RESULT: u32 = 6321;
-pub const KIND_TRADE_TRANSITION_PROOF_REQUEST: u32 = 5322;
-pub const KIND_TRADE_TRANSITION_PROOF_RESULT: u32 = 6322;
pub const KIND_ORDER_REQUEST: u32 = 3422;
pub const KIND_ORDER_DECISION: u32 = 3423;
-pub const KIND_ORDER_REVISION_PROPOSAL: u32 = 3424;
-pub const KIND_ORDER_REVISION_DECISION: u32 = 3425;
pub const KIND_ORDER_CANCELLATION: u32 = 3432;
-pub const KIND_TRADE_QUESTION: u32 = 3426;
-pub const KIND_TRADE_ANSWER: u32 = 3427;
-pub const KIND_TRADE_DISCOUNT_REQUEST: u32 = 3428;
-pub const KIND_TRADE_DISCOUNT_OFFER: u32 = 3429;
-pub const KIND_TRADE_DISCOUNT_ACCEPT: u32 = 3430;
pub const KIND_TRADE_FORBIDDEN_3431: u32 = 3431;
-pub const KIND_TRADE_FULFILLMENT_UPDATE: u32 = 3433;
-pub const KIND_TRADE_RECEIPT: u32 = 3434;
pub const KIND_TRADE_VALIDATION_RECEIPT: u32 = 3440;
pub const KIND_KNOWLEDGE_CLAIM: u32 = 3460;
pub const KIND_KNOWLEDGE_RELATION: u32 = 3461;
@@ -110,7 +96,7 @@ pub const KIND_CONTRIBUTION_ATTESTATION: u32 = 3465;
pub const KIND_KNOWLEDGE_SOURCE: u32 = 30450;
pub const KIND_EVIDENCE_BOUNTY: u32 = 30451;
-pub const LISTING_EVENT_KINDS: [u32; 2] = [KIND_LISTING, KIND_LISTING_DRAFT];
+pub const LISTING_EVENT_KINDS: [u32; 1] = [KIND_LISTING];
pub const WIKI_EVENT_KINDS: [u32; 3] = [
KIND_WIKI_MERGE_REQUEST,
@@ -166,41 +152,19 @@ pub const KNOWLEDGE_REGULAR_EVENT_KINDS: [u32; 7] = [
KIND_CONTRIBUTION_ATTESTATION,
];
-pub const ORDER_EVENT_KINDS: [u32; 5] = [
+pub const ORDER_EVENT_KINDS: [u32; 3] = [
KIND_ORDER_REQUEST,
KIND_ORDER_DECISION,
- KIND_ORDER_REVISION_PROPOSAL,
- KIND_ORDER_REVISION_DECISION,
KIND_ORDER_CANCELLATION,
];
-pub const TRADE_VALIDATION_SERVICE_EVENT_KINDS: [u32; 4] = [
- KIND_TRADE_LISTING_VALIDATION_REQUEST,
- KIND_TRADE_LISTING_VALIDATION_RESULT,
- KIND_TRADE_TRANSITION_PROOF_REQUEST,
- KIND_TRADE_TRANSITION_PROOF_RESULT,
-];
-
-pub const TRADE_VALIDATION_EVENT_KINDS: [u32; 5] = [
- KIND_TRADE_LISTING_VALIDATION_REQUEST,
- KIND_TRADE_LISTING_VALIDATION_RESULT,
- KIND_TRADE_TRANSITION_PROOF_REQUEST,
- KIND_TRADE_TRANSITION_PROOF_RESULT,
- KIND_TRADE_VALIDATION_RECEIPT,
-];
+pub const TRADE_VALIDATION_EVENT_KINDS: [u32; 1] = [KIND_TRADE_VALIDATION_RECEIPT];
-pub const COMMERCIAL_EVENT_KINDS: [u32; 12] = [
+pub const COMMERCIAL_EVENT_KINDS: [u32; 5] = [
KIND_LISTING,
- KIND_LISTING_DRAFT,
KIND_ORDER_REQUEST,
KIND_ORDER_DECISION,
- KIND_ORDER_REVISION_PROPOSAL,
- KIND_ORDER_REVISION_DECISION,
KIND_ORDER_CANCELLATION,
- KIND_TRADE_LISTING_VALIDATION_REQUEST,
- KIND_TRADE_LISTING_VALIDATION_RESULT,
- KIND_TRADE_TRANSITION_PROOF_REQUEST,
- KIND_TRADE_TRANSITION_PROOF_RESULT,
KIND_TRADE_VALIDATION_RECEIPT,
];
@@ -254,8 +218,6 @@ pub const PROFILE_PUBLIC_CONTENT_KINDS: [u32; 8] = [
pub const MODERATION_ADMIN_CANDIDATE_KINDS: [u32; 1] = [KIND_REPORT];
-pub const DRAFT_OWNER_CANDIDATE_KINDS: [u32; 1] = [KIND_LISTING_DRAFT];
-
pub const NIP29_GROUP_KINDS: [u32; 13] = [
KIND_GROUP_METADATA,
KIND_GROUP_ADMINS,
@@ -335,7 +297,7 @@ pub const PRODUCTION_SOCIAL_KINDS: [u32; 4] = [
#[inline]
pub const fn is_listing_kind(kind: u32) -> bool {
- matches!(kind, KIND_LISTING | KIND_LISTING_DRAFT)
+ kind == KIND_LISTING
}
#[inline]
@@ -520,11 +482,6 @@ pub const fn is_moderation_admin_candidate_kind(kind: u32) -> bool {
}
#[inline]
-pub const fn is_draft_owner_candidate_kind(kind: u32) -> bool {
- kind == KIND_LISTING_DRAFT
-}
-
-#[inline]
pub const fn is_nip29_group_kind(kind: u32) -> bool {
matches!(
kind,
@@ -554,18 +511,14 @@ pub const fn is_private_farm_ops_kind(kind: u32) -> bool {
#[inline]
pub const fn is_trade_validation_service_request_kind(kind: u32) -> bool {
- matches!(
- kind,
- KIND_TRADE_LISTING_VALIDATION_REQUEST | KIND_TRADE_TRANSITION_PROOF_REQUEST
- )
+ let _ = kind;
+ false
}
#[inline]
pub const fn is_trade_validation_service_result_kind(kind: u32) -> bool {
- matches!(
- kind,
- KIND_TRADE_LISTING_VALIDATION_RESULT | KIND_TRADE_TRANSITION_PROOF_RESULT
- )
+ let _ = kind;
+ false
}
#[inline]
@@ -577,11 +530,7 @@ pub const fn is_trade_validation_service_event_kind(kind: u32) -> bool {
pub const fn is_order_event_kind(kind: u32) -> bool {
matches!(
kind,
- KIND_ORDER_REQUEST
- | KIND_ORDER_DECISION
- | KIND_ORDER_REVISION_PROPOSAL
- | KIND_ORDER_REVISION_DECISION
- | KIND_ORDER_CANCELLATION
+ KIND_ORDER_REQUEST | KIND_ORDER_DECISION | KIND_ORDER_CANCELLATION
)
}
@@ -602,20 +551,14 @@ pub const fn is_commercial_event_kind(kind: u32) -> bool {
#[inline]
pub const fn trade_validation_service_result_kind_for_request(kind: u32) -> Option<u32> {
- match kind {
- KIND_TRADE_LISTING_VALIDATION_REQUEST => Some(KIND_TRADE_LISTING_VALIDATION_RESULT),
- KIND_TRADE_TRANSITION_PROOF_REQUEST => Some(KIND_TRADE_TRANSITION_PROOF_RESULT),
- _ => None,
- }
+ let _ = kind;
+ None
}
#[inline]
pub const fn trade_validation_service_request_kind_for_result(kind: u32) -> Option<u32> {
- match kind {
- KIND_TRADE_LISTING_VALIDATION_RESULT => Some(KIND_TRADE_LISTING_VALIDATION_REQUEST),
- KIND_TRADE_TRANSITION_PROOF_RESULT => Some(KIND_TRADE_TRANSITION_PROOF_REQUEST),
- _ => None,
- }
+ let _ = kind;
+ None
}
#[inline]
@@ -775,7 +718,6 @@ mod tests {
assert!(is_public_social_kind(KIND_CALENDAR_EVENT_RSVP));
assert!(!is_public_social_kind(KIND_REPORT));
assert!(!is_public_social_kind(KIND_LISTING));
- assert!(!is_public_social_kind(KIND_LISTING_DRAFT));
assert!(!is_public_social_kind(KIND_LIST_READ_WRITE_RELAYS));
assert!(!is_public_social_kind(KIND_FARM_CRDT_CHANGE));
assert!(!is_public_social_kind(KIND_FARM_WORKSPACE_MANIFEST));
@@ -846,7 +788,6 @@ mod tests {
assert_eq!(MAP_CANDIDATE_KINDS.len(), 7);
assert_eq!(PROFILE_PUBLIC_CONTENT_KINDS.len(), 8);
assert_eq!(MODERATION_ADMIN_CANDIDATE_KINDS.len(), 1);
- assert_eq!(DRAFT_OWNER_CANDIDATE_KINDS.len(), 1);
assert_eq!(NIP29_GROUP_KINDS.len(), 13);
assert_eq!(PRIVATE_FARM_OPS_KINDS.len(), 16);
@@ -859,7 +800,6 @@ mod tests {
assert!(is_home_feed_candidate_kind(KIND_CALENDAR_TIME_EVENT));
assert!(is_home_feed_candidate_kind(KIND_FARM));
assert!(is_home_feed_candidate_kind(KIND_PUBLIC_FILE_METADATA));
- assert!(!is_home_feed_candidate_kind(KIND_LISTING_DRAFT));
assert!(!is_home_feed_candidate_kind(KIND_REPORT));
assert!(!is_home_feed_candidate_kind(KIND_FARM_CRDT_CHANGE));
assert!(!is_home_feed_candidate_kind(KIND_RELAY_AUTH));
@@ -875,7 +815,6 @@ mod tests {
assert!(is_market_candidate_kind(KIND_LISTING));
assert!(is_market_candidate_kind(KIND_FARM));
assert!(is_market_candidate_kind(KIND_PUBLIC_FILE_METADATA));
- assert!(!is_market_candidate_kind(KIND_LISTING_DRAFT));
assert!(!is_market_candidate_kind(KIND_REPORT));
assert!(is_map_candidate_kind(KIND_FARM));
@@ -885,7 +824,6 @@ mod tests {
assert!(is_map_candidate_kind(KIND_POST));
assert!(is_map_candidate_kind(KIND_ARTICLE));
assert!(is_map_candidate_kind(KIND_PUBLIC_FILE_METADATA));
- assert!(!is_map_candidate_kind(KIND_LISTING_DRAFT));
assert!(!is_map_candidate_kind(KIND_REPORT));
assert!(is_profile_public_content_kind(KIND_POST));
@@ -896,13 +834,10 @@ mod tests {
assert!(is_profile_public_content_kind(KIND_CALENDAR_DATE_EVENT));
assert!(is_profile_public_content_kind(KIND_CALENDAR_TIME_EVENT));
assert!(is_profile_public_content_kind(KIND_PUBLIC_FILE_METADATA));
- assert!(!is_profile_public_content_kind(KIND_LISTING_DRAFT));
assert!(!is_profile_public_content_kind(KIND_REPORT));
assert!(is_moderation_admin_candidate_kind(KIND_REPORT));
assert!(!is_moderation_admin_candidate_kind(KIND_POST));
- assert!(is_draft_owner_candidate_kind(KIND_LISTING_DRAFT));
- assert!(!is_draft_owner_candidate_kind(KIND_LISTING));
assert!(is_private_farm_ops_kind(KIND_FARM_WORKSPACE_MANIFEST));
assert!(is_private_farm_ops_kind(KIND_FARM_CRDT_CHANGE));
@@ -924,7 +859,6 @@ mod tests {
assert!(!is_private_farm_ops_kind(KIND_RELAY_AUTH));
assert!(!is_private_farm_ops_kind(KIND_HTTP_AUTH));
assert!(!is_private_farm_ops_kind(KIND_REPORT));
- assert!(!is_private_farm_ops_kind(KIND_LISTING_DRAFT));
}
#[test]
@@ -946,85 +880,53 @@ mod tests {
#[test]
fn classifies_commercial_event_kinds() {
- assert_eq!(LISTING_EVENT_KINDS, [KIND_LISTING, KIND_LISTING_DRAFT]);
+ assert_eq!(LISTING_EVENT_KINDS, [KIND_LISTING]);
assert_eq!(
ORDER_EVENT_KINDS,
[
KIND_ORDER_REQUEST,
KIND_ORDER_DECISION,
- KIND_ORDER_REVISION_PROPOSAL,
- KIND_ORDER_REVISION_DECISION,
- KIND_ORDER_CANCELLATION,
+ KIND_ORDER_CANCELLATION
]
);
assert_eq!(
- TRADE_VALIDATION_SERVICE_EVENT_KINDS,
- [
- KIND_TRADE_LISTING_VALIDATION_REQUEST,
- KIND_TRADE_LISTING_VALIDATION_RESULT,
- KIND_TRADE_TRANSITION_PROOF_REQUEST,
- KIND_TRADE_TRANSITION_PROOF_RESULT,
- ]
+ TRADE_VALIDATION_EVENT_KINDS,
+ [KIND_TRADE_VALIDATION_RECEIPT]
);
assert_eq!(
- TRADE_VALIDATION_EVENT_KINDS,
+ COMMERCIAL_EVENT_KINDS,
[
- KIND_TRADE_LISTING_VALIDATION_REQUEST,
- KIND_TRADE_LISTING_VALIDATION_RESULT,
- KIND_TRADE_TRANSITION_PROOF_REQUEST,
- KIND_TRADE_TRANSITION_PROOF_RESULT,
+ KIND_LISTING,
+ KIND_ORDER_REQUEST,
+ KIND_ORDER_DECISION,
+ KIND_ORDER_CANCELLATION,
KIND_TRADE_VALIDATION_RECEIPT,
]
);
- assert_eq!(COMMERCIAL_EVENT_KINDS.len(), 12);
assert!(is_listing_event_kind(KIND_LISTING));
- assert!(is_listing_event_kind(KIND_LISTING_DRAFT));
assert!(!is_listing_event_kind(KIND_PROFILE));
assert!(is_order_event_kind(KIND_ORDER_REQUEST));
assert!(is_order_event_kind(KIND_ORDER_DECISION));
- assert!(is_order_event_kind(KIND_ORDER_REVISION_PROPOSAL));
- assert!(is_order_event_kind(KIND_ORDER_REVISION_DECISION));
assert!(is_order_event_kind(KIND_ORDER_CANCELLATION));
+ assert!(!is_order_event_kind(3424));
+ assert!(!is_order_event_kind(3425));
assert!(!is_order_event_kind(3433));
assert!(!is_order_event_kind(3434));
assert!(!is_order_event_kind(3435));
assert!(!is_order_event_kind(3436));
- assert!(!is_order_event_kind(KIND_TRADE_LISTING_VALIDATION_REQUEST));
assert!(!is_order_event_kind(KIND_TRADE_VALIDATION_RECEIPT));
assert!(!is_order_event_kind(3431));
- assert!(is_trade_validation_service_request_kind(
- KIND_TRADE_LISTING_VALIDATION_REQUEST
- ));
- assert!(is_trade_validation_service_request_kind(
- KIND_TRADE_TRANSITION_PROOF_REQUEST
- ));
- assert!(!is_trade_validation_service_request_kind(
- KIND_TRADE_LISTING_VALIDATION_RESULT
- ));
- assert!(is_trade_validation_service_result_kind(
- KIND_TRADE_LISTING_VALIDATION_RESULT
- ));
- assert!(is_trade_validation_service_result_kind(
- KIND_TRADE_TRANSITION_PROOF_RESULT
- ));
- assert!(!is_trade_validation_service_result_kind(
- KIND_TRADE_LISTING_VALIDATION_REQUEST
- ));
- assert!(is_trade_validation_service_event_kind(
- KIND_TRADE_LISTING_VALIDATION_REQUEST
- ));
- assert!(is_trade_validation_service_event_kind(
- KIND_TRADE_LISTING_VALIDATION_RESULT
- ));
- assert!(is_trade_validation_service_event_kind(
- KIND_TRADE_TRANSITION_PROOF_REQUEST
- ));
- assert!(is_trade_validation_service_event_kind(
- KIND_TRADE_TRANSITION_PROOF_RESULT
- ));
+ assert!(!is_trade_validation_service_request_kind(5321));
+ assert!(!is_trade_validation_service_request_kind(5322));
+ assert!(!is_trade_validation_service_result_kind(6321));
+ assert!(!is_trade_validation_service_result_kind(6322));
+ assert!(!is_trade_validation_service_event_kind(5321));
+ assert!(!is_trade_validation_service_event_kind(6321));
+ assert!(!is_trade_validation_service_event_kind(5322));
+ assert!(!is_trade_validation_service_event_kind(6322));
assert!(!is_trade_validation_service_event_kind(KIND_ORDER_REQUEST));
assert!(is_trade_validation_receipt_kind(
KIND_TRADE_VALIDATION_RECEIPT
@@ -1033,42 +935,18 @@ mod tests {
assert!(is_trade_validation_event_kind(
KIND_TRADE_VALIDATION_RECEIPT
));
- assert!(is_trade_validation_event_kind(
- KIND_TRADE_TRANSITION_PROOF_RESULT
- ));
+ assert!(!is_trade_validation_event_kind(6322));
assert!(!is_trade_validation_event_kind(3434));
assert!(is_commercial_event_kind(KIND_LISTING));
assert!(is_commercial_event_kind(KIND_ORDER_REQUEST));
- assert!(is_commercial_event_kind(
- KIND_TRADE_LISTING_VALIDATION_REQUEST
- ));
assert!(is_commercial_event_kind(KIND_TRADE_VALIDATION_RECEIPT));
assert!(!is_commercial_event_kind(KIND_PROFILE));
+ assert!(!is_commercial_event_kind(30403));
+ assert!(!is_commercial_event_kind(5321));
+ assert!(!is_commercial_event_kind(6321));
- assert_eq!(
- trade_validation_service_result_kind_for_request(KIND_TRADE_LISTING_VALIDATION_REQUEST),
- Some(KIND_TRADE_LISTING_VALIDATION_RESULT)
- );
- assert_eq!(
- trade_validation_service_result_kind_for_request(KIND_TRADE_TRANSITION_PROOF_REQUEST),
- Some(KIND_TRADE_TRANSITION_PROOF_RESULT)
- );
- assert_eq!(
- trade_validation_service_result_kind_for_request(KIND_ORDER_REQUEST),
- None
- );
- assert_eq!(
- trade_validation_service_request_kind_for_result(KIND_TRADE_LISTING_VALIDATION_RESULT),
- Some(KIND_TRADE_LISTING_VALIDATION_REQUEST)
- );
- assert_eq!(
- trade_validation_service_request_kind_for_result(KIND_TRADE_TRANSITION_PROOF_RESULT),
- Some(KIND_TRADE_TRANSITION_PROOF_REQUEST)
- );
- assert_eq!(
- trade_validation_service_request_kind_for_result(KIND_ORDER_DECISION),
- None
- );
+ assert_eq!(trade_validation_service_result_kind_for_request(5321), None);
+ assert_eq!(trade_validation_service_request_kind_for_result(6321), None);
}
}
diff --git a/crates/event/src/listing.rs b/crates/event/src/listing.rs
@@ -192,8 +192,8 @@ mod tests {
}
#[test]
- fn listing_model_covers_published_draft_metadata() {
- use crate::kinds::{KIND_LISTING_DRAFT, is_listing_kind};
+ fn listing_model_covers_published_metadata() {
+ use crate::kinds::{KIND_LISTING, is_listing_kind};
let listing = super::RadrootsListing {
d_tag: "listing-draft".parse().unwrap(),
@@ -223,7 +223,7 @@ mod tests {
};
assert_eq!(listing.published_at, Some(1_700_000_000));
- assert!(is_listing_kind(KIND_LISTING_DRAFT));
+ assert!(is_listing_kind(KIND_LISTING));
}
#[test]
diff --git a/crates/event/src/order.rs b/crates/event/src/order.rs
@@ -9,8 +9,7 @@ use alloc::{
#[cfg(test)]
use crate::ids::RadrootsOrderQuoteId;
use crate::ids::{
- RadrootsEventId, RadrootsInventoryBinId, RadrootsListingAddress, RadrootsOrderId,
- RadrootsOrderRevisionId, RadrootsPublicKey,
+ RadrootsInventoryBinId, RadrootsListingAddress, RadrootsOrderId, RadrootsPublicKey,
};
use crate::kinds::*;
pub use crate::order_economics::*;
@@ -199,106 +198,6 @@ impl RadrootsOrderRequest {
#[cfg_attr(feature = "dto-bindgen", dto(export))]
#[cfg_attr(
feature = "dto-bindgen",
- dto(ts(name = "RadrootsOrderRevisionProposal"))
-)]
-#[cfg_attr(
- any(feature = "serde", test),
- derive(serde::Serialize, serde::Deserialize)
-)]
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsOrderRevisionProposal {
- pub revision_id: RadrootsOrderRevisionId,
- pub order_id: RadrootsOrderId,
- pub listing_addr: RadrootsListingAddress,
- pub buyer_pubkey: RadrootsPublicKey,
- pub seller_pubkey: RadrootsPublicKey,
- pub root_event_id: RadrootsEventId,
- pub prev_event_id: RadrootsEventId,
- pub items: Vec<RadrootsOrderItem>,
- pub economics: RadrootsOrderEconomics,
- pub reason: String,
-}
-
-impl RadrootsOrderRevisionProposal {
- pub fn validate(&self) -> Result<(), RadrootsOrderPayloadError> {
- validate_required_field(&self.revision_id, "revision_id")?;
- validate_required_field(&self.order_id, "order_id")?;
- validate_required_field(&self.listing_addr, "listing_addr")?;
- validate_required_field(&self.buyer_pubkey, "buyer_pubkey")?;
- validate_required_field(&self.seller_pubkey, "seller_pubkey")?;
- validate_required_field(&self.root_event_id, "root_event_id")?;
- validate_required_field(&self.prev_event_id, "prev_event_id")?;
- validate_required_field(&self.reason, "reason")?;
- validate_order_items(&self.items)?;
- self.economics.validate()?;
- validate_order_economics_binding(&self.items, &self.economics)
- }
-}
-
-#[cfg_attr(
- any(feature = "serde", test),
- derive(serde::Serialize, serde::Deserialize)
-)]
-#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
-#[cfg_attr(feature = "dto-bindgen", dto(export))]
-#[cfg_attr(
- any(feature = "serde", test),
- serde(rename_all = "snake_case", tag = "decision")
-)]
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum RadrootsOrderRevisionOutcome {
- Accepted,
- Declined { reason: String },
-}
-
-impl RadrootsOrderRevisionOutcome {
- pub fn validate(&self) -> Result<(), RadrootsOrderPayloadError> {
- match self {
- Self::Accepted => Ok(()),
- Self::Declined { reason } => validate_required_field(reason, "reason"),
- }
- }
-}
-
-#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
-#[cfg_attr(feature = "dto-bindgen", dto(export))]
-#[cfg_attr(
- feature = "dto-bindgen",
- dto(ts(name = "RadrootsOrderRevisionDecision"))
-)]
-#[cfg_attr(
- any(feature = "serde", test),
- derive(serde::Serialize, serde::Deserialize)
-)]
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsOrderRevisionDecision {
- pub revision_id: RadrootsOrderRevisionId,
- pub order_id: RadrootsOrderId,
- pub listing_addr: RadrootsListingAddress,
- pub buyer_pubkey: RadrootsPublicKey,
- pub seller_pubkey: RadrootsPublicKey,
- pub root_event_id: RadrootsEventId,
- pub prev_event_id: RadrootsEventId,
- pub decision: RadrootsOrderRevisionOutcome,
-}
-
-impl RadrootsOrderRevisionDecision {
- pub fn validate(&self) -> Result<(), RadrootsOrderPayloadError> {
- validate_required_field(&self.revision_id, "revision_id")?;
- validate_required_field(&self.order_id, "order_id")?;
- validate_required_field(&self.listing_addr, "listing_addr")?;
- validate_required_field(&self.buyer_pubkey, "buyer_pubkey")?;
- validate_required_field(&self.seller_pubkey, "seller_pubkey")?;
- validate_required_field(&self.root_event_id, "root_event_id")?;
- validate_required_field(&self.prev_event_id, "prev_event_id")?;
- self.decision.validate()
- }
-}
-
-#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
-#[cfg_attr(feature = "dto-bindgen", dto(export))]
-#[cfg_attr(
- feature = "dto-bindgen",
dto(ts(name = "RadrootsOrderInventoryCommitment"))
)]
#[cfg_attr(
@@ -425,16 +324,6 @@ pub enum RadrootsOrderEventType {
OrderRequested,
#[cfg_attr(any(feature = "serde", test), serde(rename = "TradeOrderDecision"))]
OrderDecision,
- #[cfg_attr(
- any(feature = "serde", test),
- serde(rename = "TradeOrderRevisionProposed")
- )]
- OrderRevisionProposed,
- #[cfg_attr(
- any(feature = "serde", test),
- serde(rename = "TradeOrderRevisionDecision")
- )]
- OrderRevisionDecision,
#[cfg_attr(any(feature = "serde", test), serde(rename = "TradeOrderCancelled"))]
OrderCancelled,
}
@@ -445,8 +334,6 @@ impl RadrootsOrderEventType {
match kind {
KIND_ORDER_REQUEST => Some(Self::OrderRequested),
KIND_ORDER_DECISION => Some(Self::OrderDecision),
- KIND_ORDER_REVISION_PROPOSAL => Some(Self::OrderRevisionProposed),
- KIND_ORDER_REVISION_DECISION => Some(Self::OrderRevisionDecision),
KIND_ORDER_CANCELLATION => Some(Self::OrderCancelled),
_ => None,
}
@@ -457,8 +344,6 @@ impl RadrootsOrderEventType {
match self {
Self::OrderRequested => KIND_ORDER_REQUEST,
Self::OrderDecision => KIND_ORDER_DECISION,
- Self::OrderRevisionProposed => KIND_ORDER_REVISION_PROPOSAL,
- Self::OrderRevisionDecision => KIND_ORDER_REVISION_DECISION,
Self::OrderCancelled => KIND_ORDER_CANCELLATION,
}
}
@@ -468,8 +353,6 @@ impl RadrootsOrderEventType {
match self {
Self::OrderRequested => "TradeOrderRequested",
Self::OrderDecision => "TradeOrderDecision",
- Self::OrderRevisionProposed => "TradeOrderRevisionProposed",
- Self::OrderRevisionDecision => "TradeOrderRevisionDecision",
Self::OrderCancelled => "TradeOrderCancelled",
}
}
@@ -481,13 +364,7 @@ impl RadrootsOrderEventType {
#[inline]
pub const fn requires_order_chain(self) -> bool {
- matches!(
- self,
- Self::OrderDecision
- | Self::OrderRevisionProposed
- | Self::OrderRevisionDecision
- | Self::OrderCancelled
- )
+ matches!(self, Self::OrderDecision | Self::OrderCancelled)
}
}
@@ -925,13 +802,6 @@ mod tests {
.unwrap()
}
- fn event_id(character: char) -> RadrootsEventId {
- core::iter::repeat_n(character, 64)
- .collect::<String>()
- .parse()
- .unwrap()
- }
-
fn buyer_pubkey() -> RadrootsPublicKey {
pubkey('b')
}
@@ -950,10 +820,6 @@ mod tests {
raw.parse().unwrap()
}
- fn revision_id(raw: &str) -> RadrootsOrderRevisionId {
- raw.parse().unwrap()
- }
-
fn quote_id(raw: &str) -> RadrootsOrderQuoteId {
raw.parse().unwrap()
}
@@ -1096,39 +962,6 @@ mod tests {
}
}
- fn sample_order_revision_proposal() -> RadrootsOrderRevisionProposal {
- RadrootsOrderRevisionProposal {
- revision_id: revision_id("rev-1"),
- order_id: order_id("order-1"),
- listing_addr: sample_listing_addr(),
- buyer_pubkey: buyer_pubkey(),
- seller_pubkey: seller_pubkey(),
- root_event_id: event_id('1'),
- prev_event_id: event_id('2'),
- items: vec![RadrootsOrderItem {
- bin_id: bin_id("bin-1"),
- bin_count: 2,
- }],
- economics: sample_bound_order_economics(),
- reason: "update quantity".into(),
- }
- }
-
- fn sample_order_revision_decision(
- decision: RadrootsOrderRevisionOutcome,
- ) -> RadrootsOrderRevisionDecision {
- RadrootsOrderRevisionDecision {
- revision_id: revision_id("rev-1"),
- order_id: order_id("order-1"),
- listing_addr: sample_listing_addr(),
- buyer_pubkey: buyer_pubkey(),
- seller_pubkey: seller_pubkey(),
- root_event_id: event_id('1'),
- prev_event_id: event_id('2'),
- decision,
- }
- }
-
#[test]
fn order_message_type_uses_canonical_names_and_kinds() {
assert_eq!(
@@ -1139,14 +972,8 @@ mod tests {
RadrootsOrderEventType::from_kind(KIND_ORDER_DECISION),
Some(RadrootsOrderEventType::OrderDecision)
);
- assert_eq!(
- RadrootsOrderEventType::from_kind(KIND_ORDER_REVISION_PROPOSAL),
- Some(RadrootsOrderEventType::OrderRevisionProposed)
- );
- assert_eq!(
- RadrootsOrderEventType::from_kind(KIND_ORDER_REVISION_DECISION),
- Some(RadrootsOrderEventType::OrderRevisionDecision)
- );
+ assert_eq!(RadrootsOrderEventType::from_kind(3424), None);
+ assert_eq!(RadrootsOrderEventType::from_kind(3425), None);
assert_eq!(
RadrootsOrderEventType::from_kind(KIND_ORDER_CANCELLATION),
Some(RadrootsOrderEventType::OrderCancelled)
@@ -1165,14 +992,6 @@ mod tests {
KIND_ORDER_DECISION
);
assert_eq!(
- RadrootsOrderEventType::OrderRevisionProposed.kind(),
- KIND_ORDER_REVISION_PROPOSAL
- );
- assert_eq!(
- RadrootsOrderEventType::OrderRevisionDecision.kind(),
- KIND_ORDER_REVISION_DECISION
- );
- assert_eq!(
RadrootsOrderEventType::OrderCancelled.kind(),
KIND_ORDER_CANCELLATION
);
@@ -1185,42 +1004,20 @@ mod tests {
"TradeOrderDecision"
);
assert_eq!(
- RadrootsOrderEventType::OrderRevisionProposed.name(),
- "TradeOrderRevisionProposed"
- );
- assert_eq!(
- RadrootsOrderEventType::OrderRevisionDecision.name(),
- "TradeOrderRevisionDecision"
- );
- assert_eq!(
RadrootsOrderEventType::OrderCancelled.name(),
"TradeOrderCancelled"
);
assert!(RadrootsOrderEventType::OrderRequested.requires_listing_snapshot());
assert!(RadrootsOrderEventType::OrderDecision.requires_order_chain());
- assert!(RadrootsOrderEventType::OrderRevisionProposed.requires_order_chain());
- assert!(RadrootsOrderEventType::OrderRevisionDecision.requires_order_chain());
assert!(RadrootsOrderEventType::OrderCancelled.requires_order_chain());
assert!(!RadrootsOrderEventType::OrderRequested.requires_order_chain());
let request_name = serde_json::to_value(RadrootsOrderEventType::OrderRequested).unwrap();
let decision_name = serde_json::to_value(RadrootsOrderEventType::OrderDecision).unwrap();
- let revision_proposed_name =
- serde_json::to_value(RadrootsOrderEventType::OrderRevisionProposed).unwrap();
- let revision_decision_name =
- serde_json::to_value(RadrootsOrderEventType::OrderRevisionDecision).unwrap();
let cancellation_name =
serde_json::to_value(RadrootsOrderEventType::OrderCancelled).unwrap();
assert_eq!(request_name, serde_json::json!("TradeOrderRequested"));
assert_eq!(decision_name, serde_json::json!("TradeOrderDecision"));
- assert_eq!(
- revision_proposed_name,
- serde_json::json!("TradeOrderRevisionProposed")
- );
- assert_eq!(
- revision_decision_name,
- serde_json::json!("TradeOrderRevisionDecision")
- );
assert_eq!(cancellation_name, serde_json::json!("TradeOrderCancelled"));
}
@@ -1269,10 +1066,6 @@ mod tests {
let mut request = serde_json::to_value(sample_order_request()).unwrap();
request["buyer_pubkey"] = serde_json::json!("not-a-pubkey");
assert!(serde_json::from_value::<RadrootsOrderRequest>(request).is_err());
-
- let mut revision = serde_json::to_value(sample_order_revision_proposal()).unwrap();
- revision["root_event_id"] = serde_json::json!("not-an-event-id");
- assert!(serde_json::from_value::<RadrootsOrderRevisionProposal>(revision).is_err());
}
#[test]
@@ -1299,38 +1092,6 @@ mod tests {
}
#[test]
- fn order_revision_outcome_json_preserves_internal_tagged_shape() {
- assert_eq!(
- serde_json::to_value(RadrootsOrderRevisionOutcome::Accepted).unwrap(),
- serde_json::json!({ "decision": "accepted" })
- );
- assert_eq!(
- serde_json::to_value(RadrootsOrderRevisionOutcome::Declined {
- reason: "out of stock".into(),
- })
- .unwrap(),
- serde_json::json!({ "decision": "declined", "reason": "out of stock" })
- );
- assert_eq!(
- serde_json::from_value::<RadrootsOrderRevisionOutcome>(serde_json::json!({
- "decision": "accepted"
- }))
- .unwrap(),
- RadrootsOrderRevisionOutcome::Accepted
- );
- assert_eq!(
- serde_json::from_value::<RadrootsOrderRevisionOutcome>(serde_json::json!({
- "decision": "declined",
- "reason": "out of stock"
- }))
- .unwrap(),
- RadrootsOrderRevisionOutcome::Declined {
- reason: "out of stock".into()
- }
- );
- }
-
- #[test]
fn order_economics_validation_accepts_canonical_totals() {
let economics = sample_order_economics();
assert_eq!(economics.validate(), Ok(()));
@@ -1721,32 +1482,6 @@ mod tests {
}
#[test]
- fn order_revision_validation_covers_proposed_and_decision_paths() {
- assert_eq!(sample_order_revision_proposal().validate(), Ok(()));
-
- assert_eq!(
- sample_order_revision_decision(RadrootsOrderRevisionOutcome::Accepted).validate(),
- Ok(())
- );
- assert_eq!(
- sample_order_revision_decision(RadrootsOrderRevisionOutcome::Declined {
- reason: "out of stock".into(),
- })
- .validate(),
- Ok(())
- );
-
- let declined_without_reason =
- sample_order_revision_decision(RadrootsOrderRevisionOutcome::Declined {
- reason: " ".into(),
- });
- assert_eq!(
- declined_without_reason.validate().unwrap_err(),
- RadrootsOrderPayloadError::EmptyField("reason")
- );
- }
-
- #[test]
fn order_cancellation_validation_requires_buyer_bindings_and_reason() {
assert_eq!(sample_order_cancellation().validate(), Ok(()));
diff --git a/crates/event/src/trade_validation.rs b/crates/event/src/trade_validation.rs
@@ -1,9 +1,9 @@
#![forbid(unsafe_code)]
#[cfg(not(feature = "std"))]
-use alloc::{string::String, vec::Vec};
+use alloc::string::String;
-use crate::{RadrootsEventPtr, order::RadrootsListingParseError};
+use crate::order::RadrootsListingParseError;
#[cfg_attr(
any(feature = "serde", test),
@@ -81,37 +81,6 @@ impl core::fmt::Display for RadrootsTradeValidationListingError {
#[cfg(feature = "std")]
impl std::error::Error for RadrootsTradeValidationListingError {}
-#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
-#[cfg_attr(feature = "dto-bindgen", dto(export))]
-#[cfg_attr(
- feature = "dto-bindgen",
- dto(ts(name = "RadrootsTradeListingValidateRequest"))
-)]
-#[cfg_attr(
- any(feature = "serde", test),
- derive(serde::Serialize, serde::Deserialize)
-)]
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsTradeValidationListingRequest {
- pub listing_event: Option<RadrootsEventPtr>,
-}
-
-#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
-#[cfg_attr(feature = "dto-bindgen", dto(export))]
-#[cfg_attr(
- feature = "dto-bindgen",
- dto(ts(name = "RadrootsTradeListingValidateResult"))
-)]
-#[cfg_attr(
- any(feature = "serde", test),
- derive(serde::Serialize, serde::Deserialize)
-)]
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsTradeValidationListingResult {
- pub valid: bool,
- pub errors: Vec<RadrootsTradeValidationListingError>,
-}
-
#[cfg(test)]
mod tests {
use super::*;
diff --git a/crates/event_codec/Cargo.toml b/crates/event_codec/Cargo.toml
@@ -39,3 +39,4 @@ sha2 = { workspace = true, default-features = false, optional = true }
[dev-dependencies]
radroots_test_fixtures = { workspace = true }
+serde_json = { workspace = true, features = ["std"] }
diff --git a/crates/event_codec/src/farm/mod.rs b/crates/event_codec/src/farm/mod.rs
@@ -4,7 +4,9 @@ pub mod list_sets;
#[cfg(test)]
mod tests {
- use crate::error::{EventEncodeError, EventParseError};
+ use crate::error::EventEncodeError;
+ #[cfg(feature = "serde_json")]
+ use crate::error::EventParseError;
#[cfg(feature = "serde_json")]
use crate::farm::decode::{farm_from_event, parsed_from_event};
use crate::farm::encode::{farm_build_tags, farm_ref_tags};
@@ -23,8 +25,11 @@ mod tests {
use radroots_event::listing::{RadrootsListing, RadrootsListingBin, RadrootsListingProduct};
use radroots_event::plot::RadrootsPlot;
+ #[cfg(feature = "serde_json")]
const EVENT_ID: &str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+ #[cfg(feature = "serde_json")]
const AUTHOR: &str = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
+ #[cfg(feature = "serde_json")]
const EVENT_SIG: &str = concat!(
"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
diff --git a/crates/event_codec/src/listing/decode.rs b/crates/event_codec/src/listing/decode.rs
@@ -30,7 +30,7 @@ use crate::d_tag::validate_d_tag_tag;
use crate::error::EventParseError;
use crate::parsed::{RadrootsParsedData, RadrootsParsedEvent};
-const EXPECTED_LISTING_KINDS: &str = "30402 or 30403";
+const EXPECTED_LISTING_KINDS: &str = "30402";
const TAG_A: &str = "a";
const TAG_P: &str = "p";
const TAG_PRICE: &str = "price";
diff --git a/crates/event_codec/src/order/decode.rs b/crates/event_codec/src/order/decode.rs
@@ -9,7 +9,7 @@ use radroots_event::{
order::{
RadrootsOrderCancellation, RadrootsOrderDecision, RadrootsOrderEnvelope,
RadrootsOrderEnvelopeError, RadrootsOrderEventType, RadrootsOrderPayloadError,
- RadrootsOrderRequest, RadrootsOrderRevisionDecision, RadrootsOrderRevisionProposal,
+ RadrootsOrderRequest,
},
tags::{TAG_D, TAG_E_PREV, TAG_E_ROOT},
};
@@ -189,80 +189,6 @@ pub fn order_decision_from_event(
}
#[cfg(feature = "serde_json")]
-pub fn order_revision_proposal_from_event(
- event: &RadrootsEventEnvelope,
-) -> Result<RadrootsOrderEnvelope<RadrootsOrderRevisionProposal>, RadrootsOrderEnvelopeParseError> {
- let envelope = order_envelope_from_event::<RadrootsOrderRevisionProposal>(event)?;
- if envelope.message_type != RadrootsOrderEventType::OrderRevisionProposed {
- return Err(RadrootsOrderEnvelopeParseError::MessageTypeKindMismatch {
- event_kind: event.kind_u32(),
- message_type: envelope.message_type,
- });
- }
- envelope
- .payload
- .validate()
- .map_err(RadrootsOrderEnvelopeParseError::InvalidPayload)?;
- validate_order_binding(
- event,
- &envelope,
- &envelope.payload.order_id,
- &envelope.payload.listing_addr,
- &envelope.payload.seller_pubkey,
- &envelope.payload.buyer_pubkey,
- )?;
- let context = order_event_context_from_tags(envelope.message_type, &event.tags_as_vec())?;
- if context.root_event_id.as_deref() != Some(envelope.payload.root_event_id.as_str()) {
- return Err(RadrootsOrderEnvelopeParseError::PayloadBindingMismatch(
- "root_event_id",
- ));
- }
- if context.prev_event_id.as_deref() != Some(envelope.payload.prev_event_id.as_str()) {
- return Err(RadrootsOrderEnvelopeParseError::PayloadBindingMismatch(
- "prev_event_id",
- ));
- }
- Ok(envelope)
-}
-
-#[cfg(feature = "serde_json")]
-pub fn order_revision_decision_from_event(
- event: &RadrootsEventEnvelope,
-) -> Result<RadrootsOrderEnvelope<RadrootsOrderRevisionDecision>, RadrootsOrderEnvelopeParseError> {
- let envelope = order_envelope_from_event::<RadrootsOrderRevisionDecision>(event)?;
- if envelope.message_type != RadrootsOrderEventType::OrderRevisionDecision {
- return Err(RadrootsOrderEnvelopeParseError::MessageTypeKindMismatch {
- event_kind: event.kind_u32(),
- message_type: envelope.message_type,
- });
- }
- envelope
- .payload
- .validate()
- .map_err(RadrootsOrderEnvelopeParseError::InvalidPayload)?;
- validate_order_binding(
- event,
- &envelope,
- &envelope.payload.order_id,
- &envelope.payload.listing_addr,
- &envelope.payload.buyer_pubkey,
- &envelope.payload.seller_pubkey,
- )?;
- let context = order_event_context_from_tags(envelope.message_type, &event.tags_as_vec())?;
- if context.root_event_id.as_deref() != Some(envelope.payload.root_event_id.as_str()) {
- return Err(RadrootsOrderEnvelopeParseError::PayloadBindingMismatch(
- "root_event_id",
- ));
- }
- if context.prev_event_id.as_deref() != Some(envelope.payload.prev_event_id.as_str()) {
- return Err(RadrootsOrderEnvelopeParseError::PayloadBindingMismatch(
- "prev_event_id",
- ));
- }
- Ok(envelope)
-}
-
-#[cfg(feature = "serde_json")]
pub fn order_cancellation_from_event(
event: &RadrootsEventEnvelope,
) -> Result<RadrootsOrderEnvelope<RadrootsOrderCancellation>, RadrootsOrderEnvelopeParseError> {
@@ -417,16 +343,11 @@ mod tests {
RadrootsOrderEnvelopeParseError, map_tag_parse_error_for_order_envelope,
order_cancellation_from_event, order_decision_from_event, order_envelope_from_event,
order_event_context_from_tags, order_request_from_event,
- order_revision_decision_from_event, order_revision_proposal_from_event,
};
- use crate::order::tags::TAG_LISTING_EVENT;
- use crate::{
- error::EventEncodeError,
- order::encode::{
- order_cancellation_event_build, order_decision_event_build, order_request_event_build,
- order_revision_decision_event_build, order_revision_proposal_event_build,
- },
+ use crate::order::encode::{
+ order_cancellation_event_build, order_decision_event_build, order_request_event_build,
};
+ use crate::order::tags::TAG_LISTING_EVENT;
use radroots_core::{
RadrootsCoreCurrency, RadrootsCoreDecimal, RadrootsCoreMoney, RadrootsCoreUnit,
};
@@ -434,19 +355,15 @@ mod tests {
RadrootsEventEnvelope, RadrootsEventEnvelopeParts, RadrootsEventPtr,
ids::{
RadrootsEventId, RadrootsInventoryBinId, RadrootsListingAddress, RadrootsOrderId,
- RadrootsOrderQuoteId, RadrootsOrderRevisionId, RadrootsPublicKey,
- },
- kinds::{
- KIND_ORDER_CANCELLATION, KIND_ORDER_DECISION, KIND_ORDER_REQUEST,
- KIND_ORDER_REVISION_DECISION, KIND_ORDER_REVISION_PROPOSAL,
+ RadrootsOrderQuoteId, RadrootsPublicKey,
},
+ kinds::{KIND_ORDER_CANCELLATION, KIND_ORDER_DECISION, KIND_ORDER_REQUEST},
order::{
RadrootsOrderCancellation, RadrootsOrderDecision, RadrootsOrderDecisionOutcome,
RadrootsOrderEconomicItem, RadrootsOrderEconomicLine, RadrootsOrderEconomics,
RadrootsOrderEnvelope, RadrootsOrderEnvelopeError, RadrootsOrderEventType,
RadrootsOrderInventoryCommitment, RadrootsOrderItem, RadrootsOrderPayloadError,
- RadrootsOrderPricingBasis, RadrootsOrderRequest, RadrootsOrderRevisionDecision,
- RadrootsOrderRevisionOutcome, RadrootsOrderRevisionProposal,
+ RadrootsOrderPricingBasis, RadrootsOrderRequest,
},
tags::{TAG_D, TAG_E_PREV, TAG_E_ROOT},
};
@@ -488,10 +405,6 @@ mod tests {
raw.parse().unwrap()
}
- fn revision_id(raw: &str) -> RadrootsOrderRevisionId {
- raw.parse().unwrap()
- }
-
fn quote_id(raw: &str) -> RadrootsOrderQuoteId {
raw.parse().unwrap()
}
@@ -594,47 +507,6 @@ mod tests {
}
}
- fn order_revision_proposal() -> RadrootsOrderRevisionProposal {
- let mut economics = request_economics();
- economics.quote_id = quote_id("revision-quote-1");
- economics.quote_version = 2;
- economics.items[0].bin_count = 4;
- economics.items[0].line_subtotal = usd("20");
- economics.subtotal = usd("20");
- economics.total = usd("20");
- economics.canonicalize();
- RadrootsOrderRevisionProposal {
- revision_id: revision_id("rev-1"),
- order_id: order_id("order-1"),
- listing_addr: listing_addr(),
- buyer_pubkey: buyer_pubkey(),
- seller_pubkey: seller_pubkey(),
- root_event_id: event_id('1'),
- prev_event_id: event_id('2'),
- items: vec![RadrootsOrderItem {
- bin_id: bin_id("lb"),
- bin_count: 4,
- }],
- economics,
- reason: "update count".into(),
- }
- }
-
- fn order_revision_decision(
- decision: RadrootsOrderRevisionOutcome,
- ) -> RadrootsOrderRevisionDecision {
- RadrootsOrderRevisionDecision {
- revision_id: revision_id("rev-1"),
- order_id: order_id("order-1"),
- listing_addr: listing_addr(),
- buyer_pubkey: buyer_pubkey(),
- seller_pubkey: seller_pubkey(),
- root_event_id: event_id('1'),
- prev_event_id: event_id('3'),
- decision,
- }
- }
-
fn order_cancelled() -> RadrootsOrderCancellation {
RadrootsOrderCancellation {
order_id: order_id("order-1"),
@@ -762,121 +634,6 @@ mod tests {
}
#[test]
- fn order_revision_proposal_builder_emits_canonical_chain_shape() {
- let payload = order_revision_proposal();
- let built = order_revision_proposal_event_build(
- &payload.root_event_id,
- &payload.prev_event_id,
- &payload,
- )
- .unwrap();
- let envelope: RadrootsOrderEnvelope<RadrootsOrderRevisionProposal> =
- serde_json::from_str(&built.content).unwrap();
-
- assert_eq!(built.kind, KIND_ORDER_REVISION_PROPOSAL);
- assert_eq!(
- envelope.message_type,
- RadrootsOrderEventType::OrderRevisionProposed
- );
- assert_eq!(built.tags[0], vec!["p".to_string(), buyer_pubkey_wire()]);
- assert_eq!(
- built.tags[2],
- vec![TAG_D.to_string(), "order-1".to_string()]
- );
- assert_eq!(envelope.payload.revision_id, "rev-1");
- assert_eq!(envelope.payload.economics.quote_version, 2);
- assert!(
- built
- .tags
- .iter()
- .any(|tag| tag == &vec![TAG_E_ROOT.to_string(), event_id_wire('1')])
- );
- assert!(
- built
- .tags
- .iter()
- .any(|tag| tag == &vec![TAG_E_PREV.to_string(), event_id_wire('2')])
- );
- }
-
- #[test]
- fn order_revision_decision_builder_emits_canonical_chain_shape() {
- let payload = order_revision_decision(RadrootsOrderRevisionOutcome::Accepted);
- let built = order_revision_decision_event_build(
- &payload.root_event_id,
- &payload.prev_event_id,
- &payload,
- )
- .unwrap();
- let envelope: RadrootsOrderEnvelope<RadrootsOrderRevisionDecision> =
- serde_json::from_str(&built.content).unwrap();
-
- assert_eq!(built.kind, KIND_ORDER_REVISION_DECISION);
- assert_eq!(
- envelope.message_type,
- RadrootsOrderEventType::OrderRevisionDecision
- );
- assert_eq!(built.tags[0], vec!["p".to_string(), seller_pubkey_wire()]);
- assert_eq!(
- built.tags[2],
- vec![TAG_D.to_string(), "order-1".to_string()]
- );
- assert_eq!(envelope.payload.revision_id, "rev-1");
- assert!(
- built
- .tags
- .iter()
- .any(|tag| tag == &vec![TAG_E_ROOT.to_string(), event_id_wire('1')])
- );
- assert!(
- built
- .tags
- .iter()
- .any(|tag| tag == &vec![TAG_E_PREV.to_string(), event_id_wire('3')])
- );
- }
-
- #[test]
- fn order_revision_builders_reject_mismatched_chain_context() {
- let proposal = order_revision_proposal();
- let wrong_root = event_id('9');
- let wrong_prev = event_id('8');
-
- let err =
- order_revision_proposal_event_build(&wrong_root, &proposal.prev_event_id, &proposal)
- .unwrap_err();
- assert!(matches!(
- err,
- EventEncodeError::InvalidField("root_event_id")
- ));
-
- let err =
- order_revision_proposal_event_build(&proposal.root_event_id, &wrong_prev, &proposal)
- .unwrap_err();
- assert!(matches!(
- err,
- EventEncodeError::InvalidField("prev_event_id")
- ));
-
- let decision = order_revision_decision(RadrootsOrderRevisionOutcome::Accepted);
- let err =
- order_revision_decision_event_build(&wrong_root, &decision.prev_event_id, &decision)
- .unwrap_err();
- assert!(matches!(
- err,
- EventEncodeError::InvalidField("root_event_id")
- ));
-
- let err =
- order_revision_decision_event_build(&decision.root_event_id, &wrong_prev, &decision)
- .unwrap_err();
- assert!(matches!(
- err,
- EventEncodeError::InvalidField("prev_event_id")
- ));
- }
-
- #[test]
fn order_cancellation_builder_emits_canonical_buyer_chain_shape() {
let payload = order_cancelled();
let root_event_id = event_id('1');
@@ -983,56 +740,6 @@ mod tests {
);
}
- #[test]
- fn order_revision_proposal_parse_validates_actor_counterparty_and_chain_payload() {
- let payload = order_revision_proposal();
- let built = order_revision_proposal_event_build(
- &payload.root_event_id,
- &payload.prev_event_id,
- &payload,
- )
- .unwrap();
- let event = event_envelope(
- seller_pubkey_wire(),
- built.kind,
- built.tags.clone(),
- built.content.clone(),
- );
- let envelope = order_revision_proposal_from_event(&event).unwrap();
- assert_eq!(envelope.payload, payload);
-
- let wrong_author_event =
- event_envelope(buyer_pubkey_wire(), built.kind, built.tags, built.content);
- let err = order_revision_proposal_from_event(&wrong_author_event).unwrap_err();
- assert_eq!(err, RadrootsOrderEnvelopeParseError::AuthorMismatch);
- }
-
- #[test]
- fn order_revision_decision_parse_validates_actor_counterparty_and_chain_payload() {
- let payload = order_revision_decision(RadrootsOrderRevisionOutcome::Declined {
- reason: "no change".into(),
- });
- let built = order_revision_decision_event_build(
- &payload.root_event_id,
- &payload.prev_event_id,
- &payload,
- )
- .unwrap();
- let event = event_envelope(
- buyer_pubkey_wire(),
- built.kind,
- built.tags.clone(),
- built.content.clone(),
- );
- let envelope = order_revision_decision_from_event(&event).unwrap();
- assert_eq!(envelope.payload, payload);
-
- let wrong_author_event =
- event_envelope(seller_pubkey_wire(), built.kind, built.tags, built.content);
- let err = order_revision_decision_from_event(&wrong_author_event).unwrap_err();
- assert_eq!(err, RadrootsOrderEnvelopeParseError::AuthorMismatch);
- }
-
#[cfg(feature = "std")]
#[test]
fn order_parse_error_display_and_source_cover_variants() {
@@ -1208,9 +915,6 @@ mod tests {
fn order_typed_parsers_reject_message_type_mismatches() {
let request_payload = order_request();
let decision_payload = order_decision();
- let proposal_payload = order_revision_proposal();
- let revision_decision_payload =
- order_revision_decision(RadrootsOrderRevisionOutcome::Accepted);
let cancellation_payload = order_cancelled();
let request_as_decision = order_event_with_envelope(
@@ -1241,34 +945,6 @@ mod tests {
RadrootsOrderEnvelopeParseError::MessageTypeKindMismatch { .. }
));
- let proposal_as_cancellation = order_event_with_envelope(
- KIND_ORDER_CANCELLATION,
- seller_pubkey_wire(),
- RadrootsOrderEventType::OrderCancelled,
- listing_addr_wire(),
- "order-1",
- &proposal_payload,
- order_chain_tags(buyer_pubkey_wire()),
- );
- assert!(matches!(
- order_revision_proposal_from_event(&proposal_as_cancellation).unwrap_err(),
- RadrootsOrderEnvelopeParseError::MessageTypeKindMismatch { .. }
- ));
-
- let revision_decision_as_cancellation = order_event_with_envelope(
- KIND_ORDER_CANCELLATION,
- buyer_pubkey_wire(),
- RadrootsOrderEventType::OrderCancelled,
- listing_addr_wire(),
- "order-1",
- &revision_decision_payload,
- order_chain_tags(seller_pubkey_wire()),
- );
- assert!(matches!(
- order_revision_decision_from_event(&revision_decision_as_cancellation).unwrap_err(),
- RadrootsOrderEnvelopeParseError::MessageTypeKindMismatch { .. }
- ));
-
let cancellation_as_decision = order_event_with_envelope(
KIND_ORDER_DECISION,
buyer_pubkey_wire(),
@@ -1328,85 +1004,6 @@ mod tests {
order_request_from_event(&request_event).unwrap_err(),
RadrootsOrderEnvelopeParseError::PayloadBindingMismatch("listing_addr")
);
-
- let proposal_payload = order_revision_proposal();
- let proposal_built = order_revision_proposal_event_build(
- &proposal_payload.root_event_id,
- &proposal_payload.prev_event_id,
- &proposal_payload,
- )
- .unwrap();
- let mut proposal_tags = proposal_built.tags.clone();
- proposal_tags
- .iter_mut()
- .find(|tag| tag.first().map(String::as_str) == Some(TAG_E_ROOT))
- .unwrap()[1] = event_id_wire('4');
- let proposal_event = event_envelope(
- seller_pubkey_wire(),
- proposal_built.kind,
- proposal_tags,
- proposal_built.content.clone(),
- );
- assert_eq!(
- order_revision_proposal_from_event(&proposal_event).unwrap_err(),
- RadrootsOrderEnvelopeParseError::PayloadBindingMismatch("root_event_id")
- );
-
- let mut proposal_tags = proposal_built.tags;
- proposal_tags
- .iter_mut()
- .find(|tag| tag.first().map(String::as_str) == Some(TAG_E_PREV))
- .unwrap()[1] = event_id_wire('5');
- let proposal_event = event_envelope(
- seller_pubkey_wire(),
- proposal_built.kind,
- proposal_tags,
- proposal_built.content,
- );
- assert_eq!(
- order_revision_proposal_from_event(&proposal_event).unwrap_err(),
- RadrootsOrderEnvelopeParseError::PayloadBindingMismatch("prev_event_id")
- );
-
- let revision_decision_payload =
- order_revision_decision(RadrootsOrderRevisionOutcome::Accepted);
- let revision_decision_built = order_revision_decision_event_build(
- &revision_decision_payload.root_event_id,
- &revision_decision_payload.prev_event_id,
- &revision_decision_payload,
- )
- .unwrap();
- let mut revision_decision_tags = revision_decision_built.tags.clone();
- revision_decision_tags
- .iter_mut()
- .find(|tag| tag.first().map(String::as_str) == Some(TAG_E_ROOT))
- .unwrap()[1] = event_id_wire('6');
- let revision_decision_event = event_envelope(
- buyer_pubkey_wire(),
- revision_decision_built.kind,
- revision_decision_tags,
- revision_decision_built.content.clone(),
- );
- assert_eq!(
- order_revision_decision_from_event(&revision_decision_event).unwrap_err(),
- RadrootsOrderEnvelopeParseError::PayloadBindingMismatch("root_event_id")
- );
-
- let mut revision_decision_tags = revision_decision_built.tags;
- revision_decision_tags
- .iter_mut()
- .find(|tag| tag.first().map(String::as_str) == Some(TAG_E_PREV))
- .unwrap()[1] = event_id_wire('7');
- let revision_decision_event = event_envelope(
- buyer_pubkey_wire(),
- revision_decision_built.kind,
- revision_decision_tags,
- revision_decision_built.content,
- );
- assert_eq!(
- order_revision_decision_from_event(&revision_decision_event).unwrap_err(),
- RadrootsOrderEnvelopeParseError::PayloadBindingMismatch("prev_event_id")
- );
}
#[test]
@@ -1480,40 +1077,6 @@ mod tests {
}
#[test]
- fn order_revision_kinds_parse_with_chain_tags() {
- for (kind, message_type) in [
- (
- KIND_ORDER_REVISION_PROPOSAL,
- RadrootsOrderEventType::OrderRevisionProposed,
- ),
- (
- KIND_ORDER_REVISION_DECISION,
- RadrootsOrderEventType::OrderRevisionDecision,
- ),
- ] {
- let payload = serde_json::json!({});
- let envelope =
- RadrootsOrderEnvelope::new(message_type, listing_addr_wire(), "order-1", &payload);
- let event = event_envelope(
- seller_pubkey_wire(),
- kind,
- vec![
- vec!["p".into(), buyer_pubkey_wire()],
- vec!["a".into(), listing_addr_wire()],
- vec![TAG_D.into(), "order-1".into()],
- vec![TAG_E_ROOT.into(), event_id_wire('1')],
- vec![TAG_E_PREV.into(), event_id_wire('9')],
- ],
- serde_json::to_string(&envelope).unwrap(),
- );
- let parsed = order_envelope_from_event::<serde_json::Value>(&event).unwrap();
-
- assert_eq!(parsed.message_type, message_type);
- assert_eq!(parsed.order_id, "order-1");
- }
- }
-
- #[test]
fn order_parse_rejects_forbidden_kind() {
let event = event_envelope(seller_pubkey_wire(), 3431, Vec::new(), "{}".into());
let err = order_envelope_from_event::<serde_json::Value>(&event).unwrap_err();
diff --git a/crates/event_codec/src/order/encode.rs b/crates/event_codec/src/order/encode.rs
@@ -5,7 +5,7 @@ use radroots_event::{
order::{
RadrootsOrderCancellation, RadrootsOrderDecision, RadrootsOrderEnvelope,
RadrootsOrderEnvelopeError, RadrootsOrderEventType, RadrootsOrderPayloadError,
- RadrootsOrderRequest, RadrootsOrderRevisionDecision, RadrootsOrderRevisionProposal,
+ RadrootsOrderRequest,
},
};
@@ -162,56 +162,6 @@ pub fn order_decision_event_build(
}
#[cfg(feature = "serde_json")]
-pub fn order_revision_proposal_event_build(
- root_event_id: &RadrootsEventId,
- prev_event_id: &RadrootsEventId,
- payload: &RadrootsOrderRevisionProposal,
-) -> Result<RadrootsNip01EventWireParts, EventEncodeError> {
- payload.validate().map_err(map_order_payload_error)?;
- if payload.root_event_id.as_str() != root_event_id.as_str() {
- return Err(EventEncodeError::InvalidField("root_event_id"));
- }
- if payload.prev_event_id.as_str() != prev_event_id.as_str() {
- return Err(EventEncodeError::InvalidField("prev_event_id"));
- }
- order_envelope_event_build(OrderEnvelopeEventBuildParts {
- recipient_pubkey: &payload.buyer_pubkey,
- message_type: RadrootsOrderEventType::OrderRevisionProposed,
- listing_addr: &payload.listing_addr,
- order_id: &payload.order_id,
- listing_event: None,
- root_event_id: Some(root_event_id),
- prev_event_id: Some(prev_event_id),
- payload,
- })
-}
-
-#[cfg(feature = "serde_json")]
-pub fn order_revision_decision_event_build(
- root_event_id: &RadrootsEventId,
- prev_event_id: &RadrootsEventId,
- payload: &RadrootsOrderRevisionDecision,
-) -> Result<RadrootsNip01EventWireParts, EventEncodeError> {
- payload.validate().map_err(map_order_payload_error)?;
- if payload.root_event_id.as_str() != root_event_id.as_str() {
- return Err(EventEncodeError::InvalidField("root_event_id"));
- }
- if payload.prev_event_id.as_str() != prev_event_id.as_str() {
- return Err(EventEncodeError::InvalidField("prev_event_id"));
- }
- order_envelope_event_build(OrderEnvelopeEventBuildParts {
- recipient_pubkey: &payload.seller_pubkey,
- message_type: RadrootsOrderEventType::OrderRevisionDecision,
- listing_addr: &payload.listing_addr,
- order_id: &payload.order_id,
- listing_event: None,
- root_event_id: Some(root_event_id),
- prev_event_id: Some(prev_event_id),
- payload,
- })
-}
-
-#[cfg(feature = "serde_json")]
pub fn order_cancellation_event_build(
root_event_id: &RadrootsEventId,
prev_event_id: &RadrootsEventId,
diff --git a/crates/event_codec/src/order/mod.rs b/crates/event_codec/src/order/mod.rs
@@ -6,13 +6,11 @@ pub mod tags;
pub use decode::{
RadrootsOrderEnvelopeParseError, RadrootsOrderEventContext, order_cancellation_from_event,
order_decision_from_event, order_envelope_from_event, order_event_context_from_tags,
- order_request_from_event, order_revision_decision_from_event,
- order_revision_proposal_from_event,
+ order_request_from_event,
};
#[cfg(feature = "serde_json")]
pub use encode::{
order_cancellation_event_build, order_decision_event_build, order_request_event_build,
- order_revision_decision_event_build, order_revision_proposal_event_build,
};
pub use tags::{
TAG_LISTING_EVENT, order_envelope_tags, parse_order_counterparty_tag,
diff --git a/crates/event_codec/tests/listing.rs b/crates/event_codec/tests/listing.rs
@@ -9,9 +9,7 @@ use radroots_event::{
RadrootsEventEnvelope, RadrootsEventEnvelopeParts,
farm::RadrootsFarmRef,
ids::{RadrootsDTag, RadrootsInventoryBinId},
- kinds::{
- KIND_FARM, KIND_LISTING, KIND_LISTING_DRAFT, KIND_PLOT, KIND_POST, KIND_RESOURCE_AREA,
- },
+ kinds::{KIND_FARM, KIND_LISTING, KIND_PLOT, KIND_POST, KIND_RESOURCE_AREA},
listing::{
RadrootsListing, RadrootsListingAvailability, RadrootsListingBin,
RadrootsListingDeliveryMethod, RadrootsListingImage, RadrootsListingImageSize,
@@ -241,9 +239,9 @@ fn listing_roundtrip_from_event() {
#[test]
fn listing_json_wire_parts_with_kind_serializes_listing_object() {
let listing = sample_listing("AAAAAAAAAAAAAAAAAAAAAg");
- let parts = to_json_wire_parts_with_kind(&listing, KIND_LISTING_DRAFT).unwrap();
+ let parts = to_json_wire_parts_with_kind(&listing, KIND_LISTING).unwrap();
- assert_eq!(parts.kind, KIND_LISTING_DRAFT);
+ assert_eq!(parts.kind, KIND_LISTING);
let decoded: RadrootsListing = serde_json::from_str(&parts.content).unwrap();
assert_eq!(decoded.d_tag, listing.d_tag);
assert_eq!(decoded.product.title, listing.product.title);
@@ -311,7 +309,7 @@ fn listing_from_event_rejects_wrong_kind() {
assert!(matches!(
err,
EventParseError::InvalidKind {
- expected: "30402 or 30403",
+ expected: "30402",
got: KIND_POST
}
));
@@ -968,23 +966,21 @@ fn listing_parsed_wrappers_preserve_event_metadata() {
assert!(matches!(
err,
EventParseError::InvalidKind {
- expected: "30402 or 30403",
+ expected: "30402",
got: KIND_POST
}
));
}
#[test]
-fn draft_listing_roundtrip_from_event() {
+fn retired_listing_kind_is_rejected() {
let mut listing = sample_listing("AAAAAAAAAAAAAAAAAAAAAQ");
listing.published_at = Some(1_781_895_600);
- let parts = to_wire_parts_with_kind(&listing, KIND_LISTING_DRAFT).unwrap();
- let decoded = listing_from_event(parts.kind, &parts.tags, &parts.content).unwrap();
- assert_eq!(parts.kind, KIND_LISTING_DRAFT);
- assert_eq!(parts.content, "# Widget");
- assert_eq!(decoded.d_tag, listing.d_tag);
- assert_eq!(decoded.published_at, Some(1_781_895_600));
+ assert!(matches!(
+ to_wire_parts_with_kind(&listing, 30403),
+ Err(EventEncodeError::InvalidKind(30403))
+ ));
}
#[test]
diff --git a/crates/event_codec/tests/social_events.rs b/crates/event_codec/tests/social_events.rs
@@ -8,9 +8,9 @@ use radroots_event::{
group::{RadrootsGroupEditableMetadata, RadrootsGroupMetadata},
kinds::{
KIND_ARTICLE, KIND_FARM, KIND_FARM_CRDT_CHANGE, KIND_GROUP_METADATA, KIND_HTTP_AUTH,
- KIND_LISTING, KIND_LISTING_DRAFT, KIND_POST, KIND_PUBLIC_FILE_METADATA, KIND_RELAY_AUTH,
- KIND_REPORT, is_home_feed_candidate_kind, is_market_candidate_kind,
- is_private_farm_ops_kind, is_public_social_kind,
+ KIND_LISTING, KIND_POST, KIND_PUBLIC_FILE_METADATA, KIND_RELAY_AUTH, KIND_REPORT,
+ is_home_feed_candidate_kind, is_market_candidate_kind, is_private_farm_ops_kind,
+ is_public_social_kind,
},
social::RadrootsSocialMediaDimensions,
};
@@ -90,7 +90,7 @@ fn social_events_reject_private_farm_ops_semantics_in_public_codecs() {
assert!(matches!(
listing_from_event(KIND_FARM_CRDT_CHANGE, &[], "farm task"),
Err(EventParseError::InvalidKind {
- expected: "30402 or 30403",
+ expected: "30402",
got: KIND_FARM_CRDT_CHANGE
})
));
@@ -102,13 +102,13 @@ fn social_events_reject_private_farm_ops_semantics_in_public_codecs() {
assert!(is_home_feed_candidate_kind(KIND_LISTING));
assert!(is_home_feed_candidate_kind(KIND_FARM));
assert!(is_home_feed_candidate_kind(KIND_PUBLIC_FILE_METADATA));
- assert!(!is_home_feed_candidate_kind(KIND_LISTING_DRAFT));
+ assert!(!is_home_feed_candidate_kind(30403));
assert!(!is_home_feed_candidate_kind(KIND_REPORT));
assert!(!is_home_feed_candidate_kind(KIND_FARM_CRDT_CHANGE));
assert!(!is_home_feed_candidate_kind(KIND_RELAY_AUTH));
assert!(!is_home_feed_candidate_kind(KIND_HTTP_AUTH));
assert!(is_market_candidate_kind(KIND_LISTING));
- assert!(!is_market_candidate_kind(KIND_LISTING_DRAFT));
+ assert!(!is_market_candidate_kind(30403));
}
#[test]
diff --git a/crates/event_codec/tests/structured_encode_default.rs b/crates/event_codec/tests/structured_encode_default.rs
@@ -1,3 +1,5 @@
+#![cfg(feature = "serde_json")]
+
#[path = "../src/test_fixtures.rs"]
mod test_fixtures;
diff --git a/crates/event_store/migrations/0001_event_store.up.sql b/crates/event_store/migrations/0001_event_store.up.sql
@@ -143,7 +143,6 @@ CREATE TABLE IF NOT EXISTS trade_projection (
request_event_id TEXT REFERENCES event_envelopes(event_id) ON DELETE SET NULL,
decision_event_id TEXT REFERENCES event_envelopes(event_id) ON DELETE SET NULL,
agreement_event_id TEXT REFERENCES event_envelopes(event_id) ON DELETE SET NULL,
- pending_revision_event_id TEXT REFERENCES event_envelopes(event_id) ON DELETE SET NULL,
cancellation_event_id TEXT REFERENCES event_envelopes(event_id) ON DELETE SET NULL,
validation_receipt_event_id TEXT REFERENCES event_envelopes(event_id) ON DELETE SET NULL,
last_event_id TEXT REFERENCES event_envelopes(event_id) ON DELETE SET NULL,
diff --git a/crates/trade/src/dto.rs b/crates/trade/src/dto.rs
@@ -309,7 +309,6 @@ mod tests {
"validation_receipt_event_id",
"economics",
"agreement_event_id",
- "pending_revision_event_id",
"listing_addr",
"buyer_pubkey",
"seller_pubkey",
diff --git a/crates/trade/src/dvm.rs b/crates/trade/src/dvm.rs
@@ -1,1498 +0,0 @@
-#![forbid(unsafe_code)]
-
-#[cfg(not(feature = "std"))]
-use alloc::{
- string::{String, ToString},
- vec,
- vec::Vec,
-};
-#[cfg(feature = "std")]
-use std::{
- string::{String, ToString},
- vec::Vec,
-};
-
-use radroots_event::{
- RadrootsEventEnvelope,
- ids::{
- RadrootsEventId, RadrootsIdParseError, RadrootsInventoryBinId, RadrootsListingAddress,
- RadrootsOrderId, RadrootsPublicKey,
- },
- kinds::{
- KIND_JOB_FEEDBACK, KIND_TRADE_TRANSITION_PROOF_REQUEST, KIND_TRADE_TRANSITION_PROOF_RESULT,
- },
- tags::{TAG_A, TAG_E, TAG_I, TAG_P, TAG_STATUS},
-};
-use thiserror::Error;
-
-pub const RADROOTS_DVM_TAG_REQUEST: &str = "request";
-pub const RADROOTS_DVM_TAG_LISTING_EVENT: &str = "radroots:listing_event";
-pub const RADROOTS_DVM_TAG_ROOT_EVENT: &str = "radroots:root_event";
-pub const RADROOTS_DVM_TAG_TARGET_EVENT: &str = "radroots:target_event";
-pub const RADROOTS_DVM_TAG_VALIDATION_RECEIPT: &str = "radroots:validation_receipt";
-pub const RADROOTS_DVM_INPUT_TYPE_EVENT: &str = "event";
-
-#[derive(Debug, Error)]
-pub enum RadrootsTradeDvmError {
- #[error("unsupported DVM event kind: expected {expected}, received {actual}")]
- UnsupportedKind { expected: u32, actual: u32 },
- #[error("missing required {tag} tag")]
- MissingTag { tag: &'static str },
- #[error("invalid {tag} tag value {value}: {source}")]
- InvalidTag {
- tag: &'static str,
- value: String,
- source: RadrootsIdParseError,
- },
- #[error("invalid DVM content JSON: {0}")]
- InvalidContent(serde_json::Error),
- #[error("failed to serialize DVM request event: {0}")]
- SerializeRequestEvent(serde_json::Error),
- #[error("invalid stringified DVM request event: {0}")]
- InvalidRequestEvent(serde_json::Error),
- #[error("stringified DVM request event has unsupported kind: {kind}")]
- RequestEventKind { kind: u32 },
- #[error("DVM content field {field} does not match required tags")]
- ContentMismatch { field: &'static str },
- #[error("DVM request event id does not match the result e tag")]
- RequestEventIdMismatch,
- #[error("invalid proof mode: {value}")]
- InvalidProofMode { value: String },
- #[error("invalid DVM input role: {value}")]
- InvalidInputRole { value: String },
- #[error("invalid hash in {field}")]
- InvalidHash { field: &'static str },
-}
-
-#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
-#[cfg_attr(feature = "dto-bindgen", dto(export))]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum RadrootsTradeProofMode {
- None,
- Core,
- Compressed,
- Groth16,
- Plonk,
-}
-
-impl RadrootsTradeProofMode {
- pub fn as_str(self) -> &'static str {
- match self {
- Self::None => "none",
- Self::Core => "core",
- Self::Compressed => "compressed",
- Self::Groth16 => "groth16",
- Self::Plonk => "plonk",
- }
- }
-
- pub fn parse(value: impl AsRef<str>) -> Result<Self, RadrootsTradeDvmError> {
- match value.as_ref() {
- "none" => Ok(Self::None),
- "core" => Ok(Self::Core),
- "compressed" => Ok(Self::Compressed),
- "groth16" => Ok(Self::Groth16),
- "plonk" => Ok(Self::Plonk),
- value => Err(RadrootsTradeDvmError::InvalidProofMode {
- value: value.to_string(),
- }),
- }
- }
-}
-
-#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
-#[cfg_attr(feature = "dto-bindgen", dto(export))]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum RadrootsTradeDvmInputRole {
- Listing,
- OrderRequest,
- OrderDecision,
-}
-
-impl RadrootsTradeDvmInputRole {
- pub fn as_str(self) -> &'static str {
- match self {
- Self::Listing => "radroots:listing_event",
- Self::OrderRequest => "radroots:order_request_event",
- Self::OrderDecision => "radroots:order_decision_event",
- }
- }
-
- pub fn parse(value: impl AsRef<str>) -> Result<Self, RadrootsTradeDvmError> {
- match value.as_ref() {
- "radroots:listing_event" => Ok(Self::Listing),
- "radroots:order_request_event" => Ok(Self::OrderRequest),
- "radroots:order_decision_event" => Ok(Self::OrderDecision),
- value => Err(RadrootsTradeDvmError::InvalidInputRole {
- value: value.to_string(),
- }),
- }
- }
-}
-
-#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
-#[cfg_attr(feature = "dto-bindgen", dto(export))]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsTradeDvmInputTag {
- pub event_id: RadrootsEventId,
- pub role: RadrootsTradeDvmInputRole,
-}
-
-#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
-#[cfg_attr(feature = "dto-bindgen", dto(export))]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum RadrootsTradeCanonicalEventEvidenceRole {
- Buyer,
- Seller,
-}
-
-#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
-#[cfg_attr(feature = "dto-bindgen", dto(export))]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum RadrootsTradeCanonicalEventWorkflowPosition {
- Listing,
- OrderRequest,
- OrderDecision,
-}
-
-#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
-#[cfg_attr(feature = "dto-bindgen", dto(export))]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsTradeCanonicalEventEvidenceDto {
- pub event_id: RadrootsEventId,
- pub signer_pubkey: RadrootsPublicKey,
- pub kind: u32,
- pub canonical_event_hash: String,
- pub signature_hash: String,
- pub preverified_signature: bool,
- pub role: RadrootsTradeCanonicalEventEvidenceRole,
- pub workflow_position: RadrootsTradeCanonicalEventWorkflowPosition,
- pub content_hash: String,
- pub tags_hash: String,
- pub ordering_key: String,
-}
-
-#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
-#[cfg_attr(feature = "dto-bindgen", dto(export))]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsTradeInventoryBinWitnessDto {
- pub bin_id: RadrootsInventoryBinId,
- pub listing_capacity: u64,
- pub previous_reserved: u64,
-}
-
-#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
-#[cfg_attr(feature = "dto-bindgen", dto(export))]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsOrderItemWitnessDto {
- pub bin_id: RadrootsInventoryBinId,
- pub bin_count: u32,
-}
-
-#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
-#[cfg_attr(feature = "dto-bindgen", dto(export))]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsOrderRequestWitnessDto {
- pub order_id: RadrootsOrderId,
- pub listing_addr: RadrootsListingAddress,
- pub buyer_pubkey: RadrootsPublicKey,
- pub seller_pubkey: RadrootsPublicKey,
- pub items: Vec<RadrootsOrderItemWitnessDto>,
-}
-
-#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
-#[cfg_attr(feature = "dto-bindgen", dto(export))]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum RadrootsOrderDecisionWitnessDto {
- Accepted {
- inventory_commitments: Vec<RadrootsTradeInventoryCommitmentWitnessDto>,
- },
- Declined {
- reason: String,
- },
-}
-
-#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
-#[cfg_attr(feature = "dto-bindgen", dto(export))]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsTradeInventoryCommitmentWitnessDto {
- pub bin_id: RadrootsInventoryBinId,
- pub bin_count: u32,
-}
-
-#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
-#[cfg_attr(feature = "dto-bindgen", dto(export))]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsOrderDecisionEventWitnessDto {
- pub order_id: RadrootsOrderId,
- pub listing_addr: RadrootsListingAddress,
- pub buyer_pubkey: RadrootsPublicKey,
- pub seller_pubkey: RadrootsPublicKey,
- pub decision: RadrootsOrderDecisionWitnessDto,
-}
-
-#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
-#[cfg_attr(feature = "dto-bindgen", dto(export))]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsTradeTransitionProofRequestV1 {
- pub witness_version: u32,
- pub proof_target: String,
- pub listing_event_id: RadrootsEventId,
- pub request_event_id: RadrootsEventId,
- pub decision_event_id: RadrootsEventId,
- pub event_evidence: Vec<RadrootsTradeCanonicalEventEvidenceDto>,
- pub request: RadrootsOrderRequestWitnessDto,
- pub decision: RadrootsOrderDecisionEventWitnessDto,
- pub inventory_bins: Vec<RadrootsTradeInventoryBinWitnessDto>,
- pub inventory_sequence: u128,
- pub previous_state_root: Option<String>,
- pub proof_mode: RadrootsTradeProofMode,
- pub reducer_program_hash: String,
- pub radroots_protocol_version: String,
- pub sp1_program_hash: Option<String>,
- pub sp1_verifying_key_hash: Option<String>,
-}
-
-#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
-#[cfg_attr(feature = "dto-bindgen", dto(export))]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsTradeTransitionProofResultV1 {
- pub version: u32,
- pub listing_event_id: RadrootsEventId,
- pub root_event_id: RadrootsEventId,
- pub target_event_id: RadrootsEventId,
- pub validation_receipt_event_id: Option<RadrootsEventId>,
- pub proof_mode: RadrootsTradeProofMode,
- pub proof_reference: Option<String>,
- pub inline_proof_base64: Option<String>,
- pub program_hash: Option<String>,
- pub verifying_key_hash: Option<String>,
- pub public_values_hash: String,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsTradeTransitionProofRequestTags {
- pub worker_pubkey: RadrootsPublicKey,
- pub listing_addr: RadrootsListingAddress,
- pub inputs: Vec<RadrootsTradeDvmInputTag>,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsTradeTransitionProofRequestEnvelope {
- pub tags: RadrootsTradeTransitionProofRequestTags,
- pub content: RadrootsTradeTransitionProofRequestV1,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsTradeTransitionProofResultBinding {
- pub listing_event_id: RadrootsEventId,
- pub root_event_id: RadrootsEventId,
- pub target_event_id: RadrootsEventId,
- pub validation_receipt_event_id: Option<RadrootsEventId>,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsTradeTransitionProofResultTags {
- pub request_event: RadrootsEventEnvelope,
- pub request_event_id: RadrootsEventId,
- pub customer_pubkey: RadrootsPublicKey,
- pub inputs: Vec<RadrootsTradeDvmInputTag>,
- pub binding: RadrootsTradeTransitionProofResultBinding,
-}
-
-#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
-#[cfg_attr(feature = "dto-bindgen", dto(export))]
-#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
-#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum RadrootsTradeDvmFeedbackStatus {
- PaymentRequired,
- Processing,
- Error,
- Success,
- Partial,
-}
-
-impl RadrootsTradeDvmFeedbackStatus {
- pub fn as_str(self) -> &'static str {
- match self {
- Self::PaymentRequired => "payment-required",
- Self::Processing => "processing",
- Self::Error => "error",
- Self::Success => "success",
- Self::Partial => "partial",
- }
- }
-
- pub fn parse(value: impl AsRef<str>) -> Result<Self, RadrootsTradeDvmError> {
- match value.as_ref() {
- "payment-required" => Ok(Self::PaymentRequired),
- "processing" => Ok(Self::Processing),
- "error" => Ok(Self::Error),
- "success" => Ok(Self::Success),
- "partial" => Ok(Self::Partial),
- value => Err(RadrootsTradeDvmError::InvalidTag {
- tag: TAG_STATUS,
- value: value.to_string(),
- source: RadrootsIdParseError::InvalidFormat,
- }),
- }
- }
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsTradeDvmFeedbackTags {
- pub status: RadrootsTradeDvmFeedbackStatus,
- pub request_event_id: RadrootsEventId,
- pub customer_pubkey: RadrootsPublicKey,
-}
-
-pub fn build_transition_proof_request_tags(
- worker_pubkey: &RadrootsPublicKey,
- request: &RadrootsTradeTransitionProofRequestV1,
-) -> Vec<Vec<String>> {
- vec![
- vec![TAG_P.to_string(), worker_pubkey.as_str().to_string()],
- vec![
- TAG_A.to_string(),
- request.request.listing_addr.as_str().to_string(),
- ],
- input_event_tag(
- RadrootsTradeDvmInputRole::Listing,
- &request.listing_event_id,
- ),
- input_event_tag(
- RadrootsTradeDvmInputRole::OrderRequest,
- &request.request_event_id,
- ),
- input_event_tag(
- RadrootsTradeDvmInputRole::OrderDecision,
- &request.decision_event_id,
- ),
- ]
-}
-
-pub fn parse_transition_proof_request_event(
- event: &RadrootsEventEnvelope,
-) -> Result<RadrootsTradeTransitionProofRequestEnvelope, RadrootsTradeDvmError> {
- if event.kind_u32() != KIND_TRADE_TRANSITION_PROOF_REQUEST {
- return Err(RadrootsTradeDvmError::UnsupportedKind {
- expected: KIND_TRADE_TRANSITION_PROOF_REQUEST,
- actual: event.kind_u32(),
- });
- }
- let event_tags = event.tags_as_vec();
- let tags = parse_transition_proof_request_tags(&event_tags)?;
- let content: RadrootsTradeTransitionProofRequestV1 =
- serde_json::from_str(event.content()).map_err(RadrootsTradeDvmError::InvalidContent)?;
- validate_transition_proof_request_binding(&tags, &content)?;
- validate_transition_proof_request_content(&content)?;
- Ok(RadrootsTradeTransitionProofRequestEnvelope { tags, content })
-}
-
-pub fn parse_transition_proof_request_tags(
- tags: &[Vec<String>],
-) -> Result<RadrootsTradeTransitionProofRequestTags, RadrootsTradeDvmError> {
- let worker_pubkey = parse_pubkey_tag(TAG_P, required_tag_value(tags, TAG_P)?)?;
- let listing_addr = parse_listing_addr_tag(TAG_A, required_tag_value(tags, TAG_A)?)?;
- let inputs = parse_input_tags(tags)?;
- if inputs.is_empty() {
- return Err(RadrootsTradeDvmError::MissingTag { tag: TAG_I });
- }
- Ok(RadrootsTradeTransitionProofRequestTags {
- worker_pubkey,
- listing_addr,
- inputs,
- })
-}
-
-pub fn build_transition_proof_result_tags(
- request_event: &RadrootsEventEnvelope,
- customer_pubkey: &RadrootsPublicKey,
- inputs: &[RadrootsTradeDvmInputTag],
- binding: &RadrootsTradeTransitionProofResultBinding,
-) -> Result<Vec<Vec<String>>, RadrootsTradeDvmError> {
- let request_event_id = request_event.id().clone();
- let request_json = serialize_request_event(request_event)?;
- let mut tags = vec![
- vec![RADROOTS_DVM_TAG_REQUEST.to_string(), request_json],
- vec![
- TAG_E.to_string(),
- request_event_id.as_str().to_string(),
- String::new(),
- String::new(),
- "request".to_string(),
- ],
- vec![
- TAG_E.to_string(),
- binding.root_event_id.as_str().to_string(),
- String::new(),
- String::new(),
- "root".to_string(),
- ],
- vec![TAG_P.to_string(), customer_pubkey.as_str().to_string()],
- vec![
- RADROOTS_DVM_TAG_LISTING_EVENT.to_string(),
- binding.listing_event_id.as_str().to_string(),
- ],
- vec![
- RADROOTS_DVM_TAG_ROOT_EVENT.to_string(),
- binding.root_event_id.as_str().to_string(),
- ],
- vec![
- RADROOTS_DVM_TAG_TARGET_EVENT.to_string(),
- binding.target_event_id.as_str().to_string(),
- ],
- ];
- if let Some(receipt_event_id) = binding.validation_receipt_event_id.as_ref() {
- tags.push(vec![
- RADROOTS_DVM_TAG_VALIDATION_RECEIPT.to_string(),
- receipt_event_id.as_str().to_string(),
- ]);
- tags.push(vec![
- TAG_E.to_string(),
- receipt_event_id.as_str().to_string(),
- String::new(),
- String::new(),
- "receipt".to_string(),
- ]);
- }
- for input in inputs {
- tags.push(input_event_tag(input.role, &input.event_id));
- }
- Ok(tags)
-}
-
-#[cfg_attr(coverage_nightly, coverage(off))]
-fn serialize_request_event(
- request_event: &RadrootsEventEnvelope,
-) -> Result<String, RadrootsTradeDvmError> {
- serde_json::to_string(request_event).map_err(RadrootsTradeDvmError::SerializeRequestEvent)
-}
-
-pub fn parse_transition_proof_result_tags(
- kind: u32,
- tags: &[Vec<String>],
-) -> Result<RadrootsTradeTransitionProofResultTags, RadrootsTradeDvmError> {
- if kind != KIND_TRADE_TRANSITION_PROOF_RESULT {
- return Err(RadrootsTradeDvmError::UnsupportedKind {
- expected: KIND_TRADE_TRANSITION_PROOF_RESULT,
- actual: kind,
- });
- }
- let request_event_json = required_tag_value(tags, RADROOTS_DVM_TAG_REQUEST)?;
- let request_event: RadrootsEventEnvelope = serde_json::from_str(request_event_json)
- .map_err(RadrootsTradeDvmError::InvalidRequestEvent)?;
- if request_event.kind_u32() != KIND_TRADE_TRANSITION_PROOF_REQUEST {
- return Err(RadrootsTradeDvmError::RequestEventKind {
- kind: request_event.kind_u32(),
- });
- }
- let request_event_id = parse_event_id_tag(TAG_E, required_tag_value(tags, TAG_E)?)?;
- if request_event.id() != &request_event_id {
- return Err(RadrootsTradeDvmError::RequestEventIdMismatch);
- }
- let customer_pubkey = parse_pubkey_tag(TAG_P, required_tag_value(tags, TAG_P)?)?;
- let binding = RadrootsTradeTransitionProofResultBinding {
- listing_event_id: parse_event_id_tag(
- RADROOTS_DVM_TAG_LISTING_EVENT,
- required_tag_value(tags, RADROOTS_DVM_TAG_LISTING_EVENT)?,
- )?,
- root_event_id: parse_event_id_tag(
- RADROOTS_DVM_TAG_ROOT_EVENT,
- required_tag_value(tags, RADROOTS_DVM_TAG_ROOT_EVENT)?,
- )?,
- target_event_id: parse_event_id_tag(
- RADROOTS_DVM_TAG_TARGET_EVENT,
- required_tag_value(tags, RADROOTS_DVM_TAG_TARGET_EVENT)?,
- )?,
- validation_receipt_event_id: optional_event_id_tag(
- RADROOTS_DVM_TAG_VALIDATION_RECEIPT,
- tag_value(tags, RADROOTS_DVM_TAG_VALIDATION_RECEIPT),
- )?,
- };
- Ok(RadrootsTradeTransitionProofResultTags {
- request_event,
- request_event_id,
- customer_pubkey,
- inputs: parse_input_tags(tags)?,
- binding,
- })
-}
-
-pub fn build_job_feedback_tags(
- status: RadrootsTradeDvmFeedbackStatus,
- request_event_id: &RadrootsEventId,
- customer_pubkey: &RadrootsPublicKey,
-) -> Vec<Vec<String>> {
- vec![
- vec![TAG_STATUS.to_string(), status.as_str().to_string()],
- vec![TAG_E.to_string(), request_event_id.as_str().to_string()],
- vec![TAG_P.to_string(), customer_pubkey.as_str().to_string()],
- ]
-}
-
-pub fn parse_job_feedback_tags(
- kind: u32,
- tags: &[Vec<String>],
-) -> Result<RadrootsTradeDvmFeedbackTags, RadrootsTradeDvmError> {
- if kind != KIND_JOB_FEEDBACK {
- return Err(RadrootsTradeDvmError::UnsupportedKind {
- expected: KIND_JOB_FEEDBACK,
- actual: kind,
- });
- }
- Ok(RadrootsTradeDvmFeedbackTags {
- status: RadrootsTradeDvmFeedbackStatus::parse(required_tag_value(tags, TAG_STATUS)?)?,
- request_event_id: parse_event_id_tag(TAG_E, required_tag_value(tags, TAG_E)?)?,
- customer_pubkey: parse_pubkey_tag(TAG_P, required_tag_value(tags, TAG_P)?)?,
- })
-}
-
-fn validate_transition_proof_request_binding(
- tags: &RadrootsTradeTransitionProofRequestTags,
- content: &RadrootsTradeTransitionProofRequestV1,
-) -> Result<(), RadrootsTradeDvmError> {
- if tags.listing_addr != content.request.listing_addr {
- return Err(RadrootsTradeDvmError::ContentMismatch {
- field: "request.listing_addr",
- });
- }
- require_input(
- &tags.inputs,
- RadrootsTradeDvmInputRole::Listing,
- &content.listing_event_id,
- )?;
- require_input(
- &tags.inputs,
- RadrootsTradeDvmInputRole::OrderRequest,
- &content.request_event_id,
- )?;
- require_input(
- &tags.inputs,
- RadrootsTradeDvmInputRole::OrderDecision,
- &content.decision_event_id,
- )?;
- Ok(())
-}
-
-fn validate_transition_proof_request_content(
- content: &RadrootsTradeTransitionProofRequestV1,
-) -> Result<(), RadrootsTradeDvmError> {
- if content.request.order_id != content.decision.order_id {
- return Err(RadrootsTradeDvmError::ContentMismatch { field: "order_id" });
- }
- if content.request.listing_addr != content.decision.listing_addr {
- return Err(RadrootsTradeDvmError::ContentMismatch {
- field: "listing_addr",
- });
- }
- if content.request.buyer_pubkey != content.decision.buyer_pubkey {
- return Err(RadrootsTradeDvmError::ContentMismatch {
- field: "buyer_pubkey",
- });
- }
- if content.request.seller_pubkey != content.decision.seller_pubkey {
- return Err(RadrootsTradeDvmError::ContentMismatch {
- field: "seller_pubkey",
- });
- }
- validate_hash32(&content.reducer_program_hash, "reducer_program_hash")?;
- validate_optional_hash32(&content.previous_state_root, "previous_state_root")?;
- validate_optional_hash32(&content.sp1_program_hash, "sp1_program_hash")?;
- validate_optional_hash32(&content.sp1_verifying_key_hash, "sp1_verifying_key_hash")?;
- Ok(())
-}
-
-#[cfg_attr(coverage_nightly, coverage(off))]
-fn validate_optional_hash32(
- value: &Option<String>,
- field: &'static str,
-) -> Result<(), RadrootsTradeDvmError> {
- if let Some(value) = value.as_ref() {
- validate_hash32(value, field)?;
- }
- Ok(())
-}
-
-fn require_input(
- inputs: &[RadrootsTradeDvmInputTag],
- role: RadrootsTradeDvmInputRole,
- expected_event_id: &RadrootsEventId,
-) -> Result<(), RadrootsTradeDvmError> {
- if inputs
- .iter()
- .any(|input| input.role == role && &input.event_id == expected_event_id)
- {
- return Ok(());
- }
- Err(RadrootsTradeDvmError::ContentMismatch {
- field: role.as_str(),
- })
-}
-
-fn parse_input_tags(
- tags: &[Vec<String>],
-) -> Result<Vec<RadrootsTradeDvmInputTag>, RadrootsTradeDvmError> {
- let mut inputs = Vec::new();
- for tag in tags
- .iter()
- .filter(|tag| tag.first().map(String::as_str) == Some(TAG_I))
- {
- let Some(value) = tag.get(1) else {
- return Err(RadrootsTradeDvmError::MissingTag { tag: TAG_I });
- };
- let input_type = tag.get(2).map(String::as_str).unwrap_or("");
- if input_type != RADROOTS_DVM_INPUT_TYPE_EVENT {
- return Err(RadrootsTradeDvmError::InvalidTag {
- tag: TAG_I,
- value: input_type.to_string(),
- source: RadrootsIdParseError::InvalidFormat,
- });
- }
- let Some(role_value) = tag.get(3) else {
- return Err(RadrootsTradeDvmError::MissingTag { tag: TAG_I });
- };
- inputs.push(RadrootsTradeDvmInputTag {
- event_id: parse_event_id_tag(TAG_I, value)?,
- role: RadrootsTradeDvmInputRole::parse(role_value)?,
- });
- }
- Ok(inputs)
-}
-
-fn input_event_tag(role: RadrootsTradeDvmInputRole, event_id: &RadrootsEventId) -> Vec<String> {
- vec![
- TAG_I.to_string(),
- event_id.as_str().to_string(),
- RADROOTS_DVM_INPUT_TYPE_EVENT.to_string(),
- role.as_str().to_string(),
- ]
-}
-
-fn required_tag_value<'a>(
- tags: &'a [Vec<String>],
- tag: &'static str,
-) -> Result<&'a str, RadrootsTradeDvmError> {
- tag_value(tags, tag).ok_or(RadrootsTradeDvmError::MissingTag { tag })
-}
-
-fn tag_value<'a>(tags: &'a [Vec<String>], tag: &str) -> Option<&'a str> {
- tags.iter()
- .find(|candidate| candidate.first().map(String::as_str) == Some(tag))
- .and_then(|candidate| candidate.get(1))
- .map(String::as_str)
-}
-
-fn optional_event_id_tag(
- tag: &'static str,
- value: Option<&str>,
-) -> Result<Option<RadrootsEventId>, RadrootsTradeDvmError> {
- value
- .map(|value| parse_event_id_tag(tag, value))
- .transpose()
-}
-
-fn parse_event_id_tag(
- tag: &'static str,
- value: &str,
-) -> Result<RadrootsEventId, RadrootsTradeDvmError> {
- RadrootsEventId::parse(value).map_err(|source| RadrootsTradeDvmError::InvalidTag {
- tag,
- value: value.to_string(),
- source,
- })
-}
-
-fn parse_pubkey_tag(
- tag: &'static str,
- value: &str,
-) -> Result<RadrootsPublicKey, RadrootsTradeDvmError> {
- RadrootsPublicKey::parse(value).map_err(|source| RadrootsTradeDvmError::InvalidTag {
- tag,
- value: value.to_string(),
- source,
- })
-}
-
-fn parse_listing_addr_tag(
- tag: &'static str,
- value: &str,
-) -> Result<RadrootsListingAddress, RadrootsTradeDvmError> {
- RadrootsListingAddress::parse(value).map_err(|source| RadrootsTradeDvmError::InvalidTag {
- tag,
- value: value.to_string(),
- source,
- })
-}
-
-fn validate_hash32(value: &str, field: &'static str) -> Result<(), RadrootsTradeDvmError> {
- if !is_hash32(value) {
- return Err(RadrootsTradeDvmError::InvalidHash { field });
- }
- Ok(())
-}
-
-#[cfg_attr(coverage_nightly, coverage(off))]
-fn is_hash32(value: &str) -> bool {
- let Some(hex) = value.strip_prefix("0x") else {
- return false;
- };
- hex.len() == 64
- && hex
- .bytes()
- .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte))
-}
-
-#[cfg(test)]
-#[cfg_attr(coverage_nightly, coverage(off))]
-mod tests {
- use super::*;
- use radroots_event::kinds::{KIND_LISTING, KIND_PROFILE};
-
- const BUYER: &str = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
- const SELLER: &str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
- const WORKER: &str = "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc";
-
- fn event_id(raw: u8) -> RadrootsEventId {
- RadrootsEventId::parse(format!("{raw:064x}")).expect("event id")
- }
-
- fn has_marked_event_tag(
- tags: &[Vec<String>],
- event_id: &RadrootsEventId,
- marker: &str,
- ) -> bool {
- tags.iter().any(|tag| {
- tag.first().map(String::as_str) == Some(TAG_E)
- && tag.get(1).map(String::as_str) == Some(event_id.as_str())
- && tag.get(4).map(String::as_str) == Some(marker)
- })
- }
-
- fn public_key(raw: &str) -> RadrootsPublicKey {
- RadrootsPublicKey::parse(raw).expect("public key")
- }
-
- fn listing_addr() -> RadrootsListingAddress {
- RadrootsListingAddress::parse(format!("{KIND_LISTING}:{SELLER}:AAAAAAAAAAAAAAAAAAAAAg"))
- .expect("listing address")
- }
-
- fn hash(raw: char) -> String {
- format!("0x{}", raw.to_string().repeat(64))
- }
-
- fn request_content() -> RadrootsTradeTransitionProofRequestV1 {
- RadrootsTradeTransitionProofRequestV1 {
- witness_version: 1,
- proof_target: "trade_transition".to_string(),
- listing_event_id: event_id(1),
- request_event_id: event_id(2),
- decision_event_id: event_id(3),
- event_evidence: Vec::new(),
- request: RadrootsOrderRequestWitnessDto {
- order_id: RadrootsOrderId::parse("order-1").expect("order id"),
- listing_addr: listing_addr(),
- buyer_pubkey: public_key(BUYER),
- seller_pubkey: public_key(SELLER),
- items: vec![RadrootsOrderItemWitnessDto {
- bin_id: RadrootsInventoryBinId::parse("bin-1").expect("bin id"),
- bin_count: 2,
- }],
- },
- decision: RadrootsOrderDecisionEventWitnessDto {
- order_id: RadrootsOrderId::parse("order-1").expect("order id"),
- listing_addr: listing_addr(),
- buyer_pubkey: public_key(BUYER),
- seller_pubkey: public_key(SELLER),
- decision: RadrootsOrderDecisionWitnessDto::Accepted {
- inventory_commitments: vec![RadrootsTradeInventoryCommitmentWitnessDto {
- bin_id: RadrootsInventoryBinId::parse("bin-1").expect("bin id"),
- bin_count: 2,
- }],
- },
- },
- inventory_bins: vec![RadrootsTradeInventoryBinWitnessDto {
- bin_id: RadrootsInventoryBinId::parse("bin-1").expect("bin id"),
- listing_capacity: 10,
- previous_reserved: 1,
- }],
- inventory_sequence: 7,
- previous_state_root: Some(hash('b')),
- proof_mode: RadrootsTradeProofMode::None,
- reducer_program_hash: hash('a'),
- radroots_protocol_version: "radroots-trade-v1".to_string(),
- sp1_program_hash: None,
- sp1_verifying_key_hash: None,
- }
- }
-
- fn request_event(content: &RadrootsTradeTransitionProofRequestV1) -> RadrootsEventEnvelope {
- request_event_with_parts(
- event_id(10),
- KIND_TRADE_TRANSITION_PROOF_REQUEST,
- build_transition_proof_request_tags(&public_key(WORKER), content),
- serde_json::to_string(content).expect("content"),
- )
- }
-
- fn request_event_with_parts(
- id: RadrootsEventId,
- kind: u32,
- tags: Vec<Vec<String>>,
- content: String,
- ) -> RadrootsEventEnvelope {
- RadrootsEventEnvelope::new(radroots_event::RadrootsEventEnvelopeParts {
- id: id.into_string(),
- author: BUYER.to_string(),
- created_at: 1,
- kind,
- tags,
- content,
- sig: "f".repeat(128),
- })
- .expect("request event")
- }
-
- fn request_event_with_tags(
- content: &RadrootsTradeTransitionProofRequestV1,
- tags: Vec<Vec<String>>,
- ) -> RadrootsEventEnvelope {
- request_event_with_parts(
- event_id(10),
- KIND_TRADE_TRANSITION_PROOF_REQUEST,
- tags,
- serde_json::to_string(content).expect("content"),
- )
- }
-
- fn request_event_with_kind(
- content: &RadrootsTradeTransitionProofRequestV1,
- kind: u32,
- ) -> RadrootsEventEnvelope {
- request_event_with_parts(
- event_id(10),
- kind,
- build_transition_proof_request_tags(&public_key(WORKER), content),
- serde_json::to_string(content).expect("content"),
- )
- }
-
- fn request_event_with_content(
- content: &RadrootsTradeTransitionProofRequestV1,
- event_content: String,
- ) -> RadrootsEventEnvelope {
- request_event_with_parts(
- event_id(10),
- KIND_TRADE_TRANSITION_PROOF_REQUEST,
- build_transition_proof_request_tags(&public_key(WORKER), content),
- event_content,
- )
- }
-
- #[test]
- fn transition_proof_request_tags_and_content_parse_together() {
- let content = request_content();
- let envelope =
- parse_transition_proof_request_event(&request_event(&content)).expect("request");
-
- assert_eq!(envelope.tags.worker_pubkey, public_key(WORKER));
- assert_eq!(envelope.tags.listing_addr, listing_addr());
- assert_eq!(envelope.content.request_event_id, event_id(2));
- assert_eq!(envelope.tags.inputs.len(), 3);
- }
-
- #[test]
- fn transition_proof_result_tags_bind_stringified_request() {
- let content = request_content();
- let request_event = request_event(&content);
- let request_tags = parse_transition_proof_request_tags(&request_event.tags_as_vec())
- .expect("request tags");
- let binding = RadrootsTradeTransitionProofResultBinding {
- listing_event_id: content.listing_event_id.clone(),
- root_event_id: content.request_event_id.clone(),
- target_event_id: content.decision_event_id.clone(),
- validation_receipt_event_id: Some(event_id(11)),
- };
- let tags = build_transition_proof_result_tags(
- &request_event,
- &public_key(BUYER),
- &request_tags.inputs,
- &binding,
- )
- .expect("result tags");
-
- let parsed = parse_transition_proof_result_tags(KIND_TRADE_TRANSITION_PROOF_RESULT, &tags)
- .expect("result tags");
-
- assert_eq!(parsed.request_event_id, event_id(10));
- assert_eq!(parsed.customer_pubkey, public_key(BUYER));
- assert_eq!(parsed.inputs, request_tags.inputs);
- assert_eq!(parsed.binding, binding);
- assert!(has_marked_event_tag(&tags, &event_id(10), "request"));
- assert!(has_marked_event_tag(
- &tags,
- &content.request_event_id,
- "root"
- ));
- assert!(has_marked_event_tag(&tags, &event_id(11), "receipt"));
- }
-
- #[test]
- fn job_feedback_tags_parse_required_status_event_and_customer() {
- let tags = build_job_feedback_tags(
- RadrootsTradeDvmFeedbackStatus::Processing,
- &event_id(10),
- &public_key(BUYER),
- );
-
- let parsed = parse_job_feedback_tags(KIND_JOB_FEEDBACK, &tags).expect("feedback tags");
-
- assert_eq!(parsed.status, RadrootsTradeDvmFeedbackStatus::Processing);
- assert_eq!(parsed.request_event_id, event_id(10));
- assert_eq!(parsed.customer_pubkey, public_key(BUYER));
- }
-
- #[test]
- fn transition_proof_request_rejects_missing_input_tags() {
- let content = request_content();
- let mut tags = request_event(&content).tags_as_vec();
- tags.retain(|tag| tag.first().map(String::as_str) != Some(TAG_I));
- let event = request_event_with_tags(&content, tags);
-
- assert!(matches!(
- parse_transition_proof_request_event(&event),
- Err(RadrootsTradeDvmError::MissingTag { tag: TAG_I })
- ));
- }
-
- #[test]
- fn dvm_label_helpers_cover_all_variants_and_unknown_values() {
- for (mode, label) in [
- (RadrootsTradeProofMode::None, "none"),
- (RadrootsTradeProofMode::Core, "core"),
- (RadrootsTradeProofMode::Compressed, "compressed"),
- (RadrootsTradeProofMode::Groth16, "groth16"),
- (RadrootsTradeProofMode::Plonk, "plonk"),
- ] {
- assert_eq!(mode.as_str(), label);
- assert_eq!(RadrootsTradeProofMode::parse(label).unwrap(), mode);
- }
- assert!(matches!(
- RadrootsTradeProofMode::parse("stark"),
- Err(RadrootsTradeDvmError::InvalidProofMode { value }) if value == "stark"
- ));
-
- for (role, label) in [
- (RadrootsTradeDvmInputRole::Listing, "radroots:listing_event"),
- (
- RadrootsTradeDvmInputRole::OrderRequest,
- "radroots:order_request_event",
- ),
- (
- RadrootsTradeDvmInputRole::OrderDecision,
- "radroots:order_decision_event",
- ),
- ] {
- assert_eq!(role.as_str(), label);
- assert_eq!(RadrootsTradeDvmInputRole::parse(label).unwrap(), role);
- }
- assert!(matches!(
- RadrootsTradeDvmInputRole::parse("radroots:legacy"),
- Err(RadrootsTradeDvmError::InvalidInputRole { value }) if value == "radroots:legacy"
- ));
-
- for (status, label) in [
- (
- RadrootsTradeDvmFeedbackStatus::PaymentRequired,
- "payment-required",
- ),
- (RadrootsTradeDvmFeedbackStatus::Processing, "processing"),
- (RadrootsTradeDvmFeedbackStatus::Error, "error"),
- (RadrootsTradeDvmFeedbackStatus::Success, "success"),
- (RadrootsTradeDvmFeedbackStatus::Partial, "partial"),
- ] {
- assert_eq!(status.as_str(), label);
- assert_eq!(
- RadrootsTradeDvmFeedbackStatus::parse(label).unwrap(),
- status
- );
- }
- assert!(matches!(
- RadrootsTradeDvmFeedbackStatus::parse("queued"),
- Err(RadrootsTradeDvmError::InvalidTag {
- tag: TAG_STATUS,
- value,
- ..
- }) if value == "queued"
- ));
- }
-
- #[test]
- fn transition_proof_request_parser_rejects_kind_tag_content_and_hash_edges() {
- let content = request_content();
- let event = request_event_with_kind(&content, KIND_PROFILE);
- assert!(matches!(
- parse_transition_proof_request_event(&event),
- Err(RadrootsTradeDvmError::UnsupportedKind {
- expected: KIND_TRADE_TRANSITION_PROOF_REQUEST,
- actual: KIND_PROFILE
- })
- ));
-
- let event = request_event_with_content(&content, "{".to_string());
- assert!(matches!(
- parse_transition_proof_request_event(&event),
- Err(RadrootsTradeDvmError::InvalidContent(_))
- ));
-
- let mut tags = request_event(&content).tags_as_vec();
- tags.iter_mut().for_each(|tag| {
- if tag.first().map(String::as_str) == Some(TAG_P) {
- tag[1] = "bad".to_string();
- }
- });
- let event = request_event_with_tags(&content, tags);
- assert!(matches!(
- parse_transition_proof_request_event(&event),
- Err(RadrootsTradeDvmError::InvalidTag { tag: TAG_P, .. })
- ));
-
- let mut tags = request_event(&content).tags_as_vec();
- tags.iter_mut().for_each(|tag| {
- if tag.first().map(String::as_str) == Some(TAG_A) {
- tag[1] = "bad".to_string();
- }
- });
- let event = request_event_with_tags(&content, tags);
- assert!(matches!(
- parse_transition_proof_request_event(&event),
- Err(RadrootsTradeDvmError::InvalidTag { tag: TAG_A, .. })
- ));
-
- let mut tags = request_event(&content).tags_as_vec();
- tags.iter_mut().for_each(|tag| {
- if tag.first().map(String::as_str) == Some(TAG_A) {
- tag[1] = format!("{KIND_LISTING}:{SELLER}:BBBBBBBBBBBBBBBBBBBBBg");
- }
- });
- let event = request_event_with_tags(&content, tags);
- assert!(matches!(
- parse_transition_proof_request_event(&event),
- Err(RadrootsTradeDvmError::ContentMismatch {
- field: "request.listing_addr"
- })
- ));
-
- let mut tags = request_event(&content).tags_as_vec();
- tags.iter_mut().for_each(|tag| {
- if tag.first().map(String::as_str) == Some(TAG_I)
- && tag.get(3).map(String::as_str)
- == Some(RadrootsTradeDvmInputRole::Listing.as_str())
- {
- tag[1] = event_id(99).into_string();
- }
- });
- let event = request_event_with_tags(&content, tags);
- assert!(matches!(
- parse_transition_proof_request_event(&event),
- Err(RadrootsTradeDvmError::ContentMismatch {
- field: "radroots:listing_event"
- })
- ));
-
- for (bad_content, field) in [
- {
- let mut bad = content.clone();
- bad.decision.order_id = RadrootsOrderId::parse("order-2").unwrap();
- (bad, "order_id")
- },
- {
- let mut bad = content.clone();
- bad.decision.listing_addr = RadrootsListingAddress::parse(format!(
- "{KIND_LISTING}:{SELLER}:BBBBBBBBBBBBBBBBBBBBBg"
- ))
- .unwrap();
- (bad, "listing_addr")
- },
- {
- let mut bad = content.clone();
- bad.decision.buyer_pubkey = public_key(WORKER);
- (bad, "buyer_pubkey")
- },
- {
- let mut bad = content.clone();
- bad.decision.seller_pubkey = public_key(WORKER);
- (bad, "seller_pubkey")
- },
- ] {
- let event = request_event(&bad_content);
- assert!(matches!(
- parse_transition_proof_request_event(&event),
- Err(RadrootsTradeDvmError::ContentMismatch { field: got }) if got == field
- ));
- }
-
- for (bad_content, field) in [
- {
- let mut bad = content.clone();
- bad.reducer_program_hash = "bad".to_string();
- (bad, "reducer_program_hash")
- },
- {
- let mut bad = content.clone();
- bad.previous_state_root = Some("bad".to_string());
- (bad, "previous_state_root")
- },
- {
- let mut bad = content.clone();
- bad.sp1_program_hash = Some("bad".to_string());
- (bad, "sp1_program_hash")
- },
- {
- let mut bad = content.clone();
- bad.sp1_verifying_key_hash = Some("bad".to_string());
- (bad, "sp1_verifying_key_hash")
- },
- ] {
- let event = request_event(&bad_content);
- assert!(matches!(
- parse_transition_proof_request_event(&event),
- Err(RadrootsTradeDvmError::InvalidHash { field: got }) if got == field
- ));
- }
-
- let mut tags = request_event(&content).tags_as_vec();
- tags.push(vec![TAG_I.to_string()]);
- let event = request_event_with_tags(&content, tags);
- assert!(matches!(
- parse_transition_proof_request_event(&event),
- Err(RadrootsTradeDvmError::MissingTag { tag: TAG_I })
- ));
-
- let mut tags = request_event(&content).tags_as_vec();
- tags.push(vec![
- TAG_I.to_string(),
- event_id(44).into_string(),
- "url".to_string(),
- RadrootsTradeDvmInputRole::Listing.as_str().to_string(),
- ]);
- let event = request_event_with_tags(&content, tags);
- assert!(matches!(
- parse_transition_proof_request_event(&event),
- Err(RadrootsTradeDvmError::InvalidTag { tag: TAG_I, .. })
- ));
-
- let mut tags = request_event(&content).tags_as_vec();
- tags.push(vec![
- TAG_I.to_string(),
- event_id(44).into_string(),
- RADROOTS_DVM_INPUT_TYPE_EVENT.to_string(),
- ]);
- let event = request_event_with_tags(&content, tags);
- assert!(matches!(
- parse_transition_proof_request_event(&event),
- Err(RadrootsTradeDvmError::MissingTag { tag: TAG_I })
- ));
-
- let mut tags = request_event(&content).tags_as_vec();
- tags.push(vec![
- TAG_I.to_string(),
- event_id(44).into_string(),
- RADROOTS_DVM_INPUT_TYPE_EVENT.to_string(),
- "radroots:legacy_event".to_string(),
- ]);
- let event = request_event_with_tags(&content, tags);
- assert!(matches!(
- parse_transition_proof_request_event(&event),
- Err(RadrootsTradeDvmError::InvalidInputRole { .. })
- ));
- }
-
- #[test]
- fn transition_proof_request_parser_covers_required_tag_and_input_mismatch_edges() {
- let content = request_content();
- let tags = build_transition_proof_request_tags(&public_key(WORKER), &content);
-
- for required in [TAG_P, TAG_A] {
- let missing = tags
- .iter()
- .filter(|tag| tag.first().map(String::as_str) != Some(required))
- .cloned()
- .collect::<Vec<_>>();
- assert!(matches!(
- parse_transition_proof_request_tags(&missing),
- Err(RadrootsTradeDvmError::MissingTag { tag }) if tag == required
- ));
- }
-
- for (role, field, event_id) in [
- (
- RadrootsTradeDvmInputRole::OrderRequest,
- "radroots:order_request_event",
- event_id(98),
- ),
- (
- RadrootsTradeDvmInputRole::OrderDecision,
- "radroots:order_decision_event",
- event_id(97),
- ),
- ] {
- let mut tags = request_event(&content).tags_as_vec();
- tags.iter_mut().for_each(|tag| {
- if tag.first().map(String::as_str) == Some(TAG_I)
- && tag.get(3).map(String::as_str) == Some(role.as_str())
- {
- tag[1] = event_id.clone().into_string();
- }
- });
- let event = request_event_with_tags(&content, tags);
- assert!(matches!(
- parse_transition_proof_request_event(&event),
- Err(RadrootsTradeDvmError::ContentMismatch { field: got }) if got == field
- ));
- }
-
- let mut tags = request_event(&content).tags_as_vec();
- tags.push(vec![
- TAG_I.to_string(),
- "bad".to_string(),
- RADROOTS_DVM_INPUT_TYPE_EVENT.to_string(),
- RadrootsTradeDvmInputRole::Listing.as_str().to_string(),
- ]);
- let event = request_event_with_tags(&content, tags);
- assert!(matches!(
- parse_transition_proof_request_event(&event),
- Err(RadrootsTradeDvmError::InvalidTag { tag: TAG_I, .. })
- ));
-
- let mut uppercase_hash = content.clone();
- uppercase_hash.reducer_program_hash = format!("0x{}", "A".repeat(64));
- assert!(matches!(
- parse_transition_proof_request_event(&request_event(&uppercase_hash)),
- Err(RadrootsTradeDvmError::InvalidHash {
- field: "reducer_program_hash"
- })
- ));
- }
-
- #[test]
- fn transition_proof_result_and_feedback_parsers_cover_error_edges() {
- let content = request_content();
- let request_event = request_event(&content);
- let request_tags = parse_transition_proof_request_tags(&request_event.tags_as_vec())
- .expect("request tags");
- let binding = RadrootsTradeTransitionProofResultBinding {
- listing_event_id: content.listing_event_id.clone(),
- root_event_id: content.request_event_id.clone(),
- target_event_id: content.decision_event_id.clone(),
- validation_receipt_event_id: None,
- };
- let tags = build_transition_proof_result_tags(
- &request_event,
- &public_key(BUYER),
- &request_tags.inputs,
- &binding,
- )
- .expect("result tags without receipt");
- let parsed = parse_transition_proof_result_tags(KIND_TRADE_TRANSITION_PROOF_RESULT, &tags)
- .expect("result tags without receipt");
- assert_eq!(parsed.binding.validation_receipt_event_id, None);
-
- for required in [
- RADROOTS_DVM_TAG_REQUEST,
- TAG_E,
- TAG_P,
- RADROOTS_DVM_TAG_LISTING_EVENT,
- RADROOTS_DVM_TAG_ROOT_EVENT,
- RADROOTS_DVM_TAG_TARGET_EVENT,
- ] {
- let missing = tags
- .iter()
- .filter(|tag| tag.first().map(String::as_str) != Some(required))
- .cloned()
- .collect::<Vec<_>>();
- assert!(matches!(
- parse_transition_proof_result_tags(KIND_TRADE_TRANSITION_PROOF_RESULT, &missing),
- Err(RadrootsTradeDvmError::MissingTag { tag }) if tag == required
- ));
- }
-
- assert!(matches!(
- parse_transition_proof_result_tags(KIND_PROFILE, &tags),
- Err(RadrootsTradeDvmError::UnsupportedKind {
- expected: KIND_TRADE_TRANSITION_PROOF_RESULT,
- actual: KIND_PROFILE
- })
- ));
-
- let mut invalid_json = tags.clone();
- invalid_json[0][1] = "{".to_string();
- assert!(matches!(
- parse_transition_proof_result_tags(KIND_TRADE_TRANSITION_PROOF_RESULT, &invalid_json),
- Err(RadrootsTradeDvmError::InvalidRequestEvent(_))
- ));
-
- let wrong_kind_request = request_event_with_kind(&content, KIND_PROFILE);
- let mut wrong_kind = tags.clone();
- wrong_kind[0][1] = serde_json::to_string(&wrong_kind_request).unwrap();
- assert!(matches!(
- parse_transition_proof_result_tags(KIND_TRADE_TRANSITION_PROOF_RESULT, &wrong_kind),
- Err(RadrootsTradeDvmError::RequestEventKind { kind: KIND_PROFILE })
- ));
-
- let mut mismatched_request_id = tags.clone();
- let request_id_tag = mismatched_request_id
- .iter_mut()
- .find(|tag| tag.first().map(String::as_str) == Some(TAG_E))
- .expect("request e tag");
- request_id_tag[1] = event_id(99).into_string();
- assert!(matches!(
- parse_transition_proof_result_tags(
- KIND_TRADE_TRANSITION_PROOF_RESULT,
- &mismatched_request_id,
- ),
- Err(RadrootsTradeDvmError::RequestEventIdMismatch)
- ));
-
- let mut invalid_customer = tags.clone();
- let customer_tag = invalid_customer
- .iter_mut()
- .find(|tag| tag.first().map(String::as_str) == Some(TAG_P))
- .expect("customer p tag");
- customer_tag[1] = "bad".to_string();
- assert!(matches!(
- parse_transition_proof_result_tags(
- KIND_TRADE_TRANSITION_PROOF_RESULT,
- &invalid_customer,
- ),
- Err(RadrootsTradeDvmError::InvalidTag { tag: TAG_P, .. })
- ));
-
- for required in [
- RADROOTS_DVM_TAG_LISTING_EVENT,
- RADROOTS_DVM_TAG_ROOT_EVENT,
- RADROOTS_DVM_TAG_TARGET_EVENT,
- ] {
- let mut invalid_event_tag = tags.clone();
- let tag = invalid_event_tag
- .iter_mut()
- .find(|tag| tag.first().map(String::as_str) == Some(required))
- .expect("event tag");
- tag[1] = "bad".to_string();
- assert!(matches!(
- parse_transition_proof_result_tags(
- KIND_TRADE_TRANSITION_PROOF_RESULT,
- &invalid_event_tag,
- ),
- Err(RadrootsTradeDvmError::InvalidTag { tag, .. }) if tag == required
- ));
- }
-
- let mut invalid_input_event = tags.clone();
- let input_tag = invalid_input_event
- .iter_mut()
- .find(|tag| tag.first().map(String::as_str) == Some(TAG_I))
- .expect("input tag");
- input_tag[1] = "bad".to_string();
- assert!(matches!(
- parse_transition_proof_result_tags(
- KIND_TRADE_TRANSITION_PROOF_RESULT,
- &invalid_input_event,
- ),
- Err(RadrootsTradeDvmError::InvalidTag { tag: TAG_I, .. })
- ));
-
- let mut invalid_receipt = tags.clone();
- invalid_receipt.push(vec![
- RADROOTS_DVM_TAG_VALIDATION_RECEIPT.to_string(),
- "bad".to_string(),
- ]);
- assert!(matches!(
- parse_transition_proof_result_tags(
- KIND_TRADE_TRANSITION_PROOF_RESULT,
- &invalid_receipt
- ),
- Err(RadrootsTradeDvmError::InvalidTag {
- tag: RADROOTS_DVM_TAG_VALIDATION_RECEIPT,
- ..
- })
- ));
-
- assert!(matches!(
- parse_job_feedback_tags(KIND_PROFILE, &[]),
- Err(RadrootsTradeDvmError::UnsupportedKind {
- expected: KIND_JOB_FEEDBACK,
- actual: KIND_PROFILE
- })
- ));
-
- for required in [TAG_STATUS, TAG_E, TAG_P] {
- let missing = build_job_feedback_tags(
- RadrootsTradeDvmFeedbackStatus::Success,
- &event_id(10),
- &public_key(BUYER),
- )
- .into_iter()
- .filter(|tag| tag.first().map(String::as_str) != Some(required))
- .collect::<Vec<_>>();
- assert!(matches!(
- parse_job_feedback_tags(KIND_JOB_FEEDBACK, &missing),
- Err(RadrootsTradeDvmError::MissingTag { tag }) if tag == required
- ));
- }
-
- let mut bad_feedback = build_job_feedback_tags(
- RadrootsTradeDvmFeedbackStatus::Success,
- &event_id(10),
- &public_key(BUYER),
- );
- bad_feedback[0][1] = "queued".to_string();
- assert!(matches!(
- parse_job_feedback_tags(KIND_JOB_FEEDBACK, &bad_feedback),
- Err(RadrootsTradeDvmError::InvalidTag {
- tag: TAG_STATUS,
- ..
- })
- ));
- bad_feedback[0][1] = RadrootsTradeDvmFeedbackStatus::Success.as_str().to_string();
- bad_feedback[1][1] = "bad".to_string();
- assert!(matches!(
- parse_job_feedback_tags(KIND_JOB_FEEDBACK, &bad_feedback),
- Err(RadrootsTradeDvmError::InvalidTag { tag: TAG_E, .. })
- ));
- bad_feedback[1][1] = event_id(10).into_string();
- bad_feedback[2][1] = "bad".to_string();
- assert!(matches!(
- parse_job_feedback_tags(KIND_JOB_FEEDBACK, &bad_feedback),
- Err(RadrootsTradeDvmError::InvalidTag { tag: TAG_P, .. })
- ));
- }
-}
diff --git a/crates/trade/src/lib.rs b/crates/trade/src/lib.rs
@@ -5,8 +5,6 @@ extern crate alloc;
#[cfg(feature = "dto-bindgen")]
pub mod dto;
-#[cfg(feature = "serde_json")]
-pub mod dvm;
pub mod identity;
pub mod listing;
pub mod order;
diff --git a/crates/trade/src/listing/draft.rs b/crates/trade/src/listing/draft.rs
@@ -1,10 +1,4 @@
//! Canonicalization for Radroots Listing v1 drafts.
-//!
-//! Listing v1 uses NIP-99 listing kind numbers and Radroots-specific JSON
-//! content. Strict NIP-99 Markdown-content interoperability is protocol-v2 work.
-//! Canonical drafts derive both addresses from the same seller pubkey and
-//! d-tag: the public address is for publish or update intent, and the draft
-//! address is for save-draft intent.
#![forbid(unsafe_code)]
@@ -20,18 +14,18 @@ use radroots_event::{
ids::{
RadrootsIdParseError, RadrootsInventoryBinId, RadrootsListingAddress, RadrootsPublicKey,
},
- kinds::{KIND_LISTING, KIND_LISTING_DRAFT},
+ kinds::KIND_LISTING,
listing::RadrootsListing,
};
use thiserror::Error;
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug)]
-pub struct RadrootsListingDraftDocumentV1 {
+pub struct RadrootsListingEditDocumentV1 {
pub listing: RadrootsListing,
}
-impl RadrootsListingDraftDocumentV1 {
+impl RadrootsListingEditDocumentV1 {
pub fn new(listing: RadrootsListing) -> Self {
Self { listing }
}
@@ -39,22 +33,21 @@ impl RadrootsListingDraftDocumentV1 {
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[derive(Clone, Debug)]
-pub struct RadrootsCanonicalListingDraft {
+pub struct RadrootsCanonicalListingEdit {
listing: RadrootsListing,
seller_pubkey: RadrootsPublicKey,
public_listing_addr: RadrootsListingAddress,
- draft_listing_addr: RadrootsListingAddress,
}
-impl RadrootsCanonicalListingDraft {
+impl RadrootsCanonicalListingEdit {
pub fn new(
mut listing: RadrootsListing,
seller_pubkey: RadrootsPublicKey,
- ) -> Result<Self, RadrootsListingDraftError> {
+ ) -> Result<Self, RadrootsListingEditError> {
let farm_pubkey = RadrootsPublicKey::parse(listing.farm.pubkey.as_str())
- .map_err(RadrootsListingDraftError::InvalidFarmPubkey)?;
+ .map_err(RadrootsListingEditError::InvalidFarmPubkey)?;
if farm_pubkey != seller_pubkey {
- return Err(RadrootsListingDraftError::FarmPubkeyMismatch {
+ return Err(RadrootsListingEditError::FarmPubkeyMismatch {
expected_pubkey: seller_pubkey,
actual_pubkey: farm_pubkey,
});
@@ -64,14 +57,11 @@ impl RadrootsCanonicalListingDraft {
let public_listing_addr =
listing_addr(KIND_LISTING, &seller_pubkey, listing.d_tag.as_str())?;
- let draft_listing_addr =
- listing_addr(KIND_LISTING_DRAFT, &seller_pubkey, listing.d_tag.as_str())?;
Ok(Self {
listing,
seller_pubkey,
public_listing_addr,
- draft_listing_addr,
})
}
@@ -86,34 +76,30 @@ impl RadrootsCanonicalListingDraft {
pub fn public_listing_addr(&self) -> &RadrootsListingAddress {
&self.public_listing_addr
}
-
- pub fn draft_listing_addr(&self) -> &RadrootsListingAddress {
- &self.draft_listing_addr
- }
}
#[derive(Clone, Debug, Error, PartialEq, Eq)]
-pub enum RadrootsListingDraftError {
- #[error("invalid listing draft farm pubkey: {0}")]
+pub enum RadrootsListingEditError {
+ #[error("invalid listing edit farm pubkey: {0}")]
InvalidFarmPubkey(RadrootsIdParseError),
- #[error("invalid listing draft address: {0}")]
+ #[error("invalid listing edit address: {0}")]
InvalidListingAddress(RadrootsIdParseError),
- #[error("listing draft actor does not satisfy required role {required_role:?}")]
+ #[error("listing edit actor does not satisfy required role {required_role:?}")]
ActorRoleUnsatisfied { required_role: RadrootsActorRole },
- #[error("listing draft farm pubkey does not match seller")]
+ #[error("listing edit farm pubkey does not match seller")]
FarmPubkeyMismatch {
expected_pubkey: RadrootsPublicKey,
actual_pubkey: RadrootsPublicKey,
},
- #[error("listing draft primary bin is missing")]
+ #[error("listing edit primary bin is missing")]
MissingPrimaryBin {
primary_bin_id: RadrootsInventoryBinId,
},
- #[error("listing draft contains duplicate bin ID")]
+ #[error("listing edit contains duplicate bin ID")]
DuplicateBinId { bin_id: RadrootsInventoryBinId },
}
-fn validate_listing_bins(listing: &RadrootsListing) -> Result<(), RadrootsListingDraftError> {
+fn validate_listing_bins(listing: &RadrootsListing) -> Result<(), RadrootsListingEditError> {
let primary_bin_id = listing.primary_bin_id.clone();
let mut seen_bin_ids = Vec::new();
let mut primary_bin_found = false;
@@ -122,7 +108,7 @@ fn validate_listing_bins(listing: &RadrootsListing) -> Result<(), RadrootsListin
.iter()
.any(|seen_bin_id| seen_bin_id == &bin.bin_id)
{
- return Err(RadrootsListingDraftError::DuplicateBinId {
+ return Err(RadrootsListingEditError::DuplicateBinId {
bin_id: bin.bin_id.clone(),
});
}
@@ -133,7 +119,7 @@ fn validate_listing_bins(listing: &RadrootsListing) -> Result<(), RadrootsListin
}
if !primary_bin_found {
- return Err(RadrootsListingDraftError::MissingPrimaryBin { primary_bin_id });
+ return Err(RadrootsListingEditError::MissingPrimaryBin { primary_bin_id });
}
Ok(())
}
@@ -142,17 +128,17 @@ fn listing_addr(
kind: u32,
seller_pubkey: &RadrootsPublicKey,
d_tag: &str,
-) -> Result<RadrootsListingAddress, RadrootsListingDraftError> {
+) -> Result<RadrootsListingAddress, RadrootsListingEditError> {
RadrootsListingAddress::parse(format!("{kind}:{}:{d_tag}", seller_pubkey.as_str()))
- .map_err(RadrootsListingDraftError::InvalidListingAddress)
+ .map_err(RadrootsListingEditError::InvalidListingAddress)
}
-pub fn canonicalize_listing_draft(
+pub fn canonicalize_listing_edit(
actor: &RadrootsActorContext,
- mut document: RadrootsListingDraftDocumentV1,
-) -> Result<RadrootsCanonicalListingDraft, RadrootsListingDraftError> {
+ mut document: RadrootsListingEditDocumentV1,
+) -> Result<RadrootsCanonicalListingEdit, RadrootsListingEditError> {
if !actor.satisfies(RadrootsActorRole::Seller) {
- return Err(RadrootsListingDraftError::ActorRoleUnsatisfied {
+ return Err(RadrootsListingEditError::ActorRoleUnsatisfied {
required_role: RadrootsActorRole::Seller,
});
}
@@ -163,7 +149,7 @@ pub fn canonicalize_listing_draft(
document.listing.farm.pubkey = seller_pubkey.as_str().to_string();
}
- RadrootsCanonicalListingDraft::new(document.listing, seller_pubkey)
+ RadrootsCanonicalListingEdit::new(document.listing, seller_pubkey)
}
#[cfg(test)]
@@ -177,13 +163,13 @@ mod tests {
contract::RadrootsActorRole,
farm::RadrootsFarmRef,
ids::{RadrootsDTag, RadrootsInventoryBinId, RadrootsListingAddress, RadrootsPublicKey},
- kinds::{KIND_LISTING, KIND_LISTING_DRAFT},
+ kinds::KIND_LISTING,
listing::{RadrootsListing, RadrootsListingBin, RadrootsListingProduct},
};
use super::{
- RadrootsCanonicalListingDraft, RadrootsListingDraftDocumentV1, RadrootsListingDraftError,
- canonicalize_listing_draft,
+ RadrootsCanonicalListingEdit, RadrootsListingEditDocumentV1, RadrootsListingEditError,
+ canonicalize_listing_edit,
};
const SELLER: &str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
@@ -260,7 +246,7 @@ mod tests {
#[test]
fn draft_document_wraps_listing() {
- let document = RadrootsListingDraftDocumentV1::new(listing());
+ let document = RadrootsListingEditDocumentV1::new(listing());
assert_eq!(document.listing.d_tag.as_str(), "AAAAAAAAAAAAAAAAAAAAAg");
assert_eq!(document.listing.product.title, "Coffee");
@@ -269,13 +255,13 @@ mod tests {
#[cfg(feature = "serde_json")]
#[test]
fn draft_document_deserializes_as_untrusted_input() {
- let json = serde_json::to_string(&RadrootsListingDraftDocumentV1::new(listing()))
+ let json = serde_json::to_string(&RadrootsListingEditDocumentV1::new(listing()))
.expect("serialize document");
- let document: RadrootsListingDraftDocumentV1 =
+ let document: RadrootsListingEditDocumentV1 =
serde_json::from_str(&json).expect("deserialize document");
let canonical =
- canonicalize_listing_draft(&seller_actor(), document).expect("canonical draft");
+ canonicalize_listing_edit(&seller_actor(), document).expect("canonical draft");
assert_eq!(canonical.seller_pubkey().as_str(), SELLER);
assert_eq!(canonical.listing().product.title, "Coffee");
@@ -287,96 +273,88 @@ mod tests {
let listing = listing();
let canonical =
- RadrootsCanonicalListingDraft::new(listing, seller_pubkey.clone()).expect("canonical");
+ RadrootsCanonicalListingEdit::new(listing, seller_pubkey.clone()).expect("canonical");
assert_eq!(canonical.seller_pubkey(), &seller_pubkey);
assert_eq!(
canonical.public_listing_addr().as_str(),
format!("{KIND_LISTING}:{SELLER}:AAAAAAAAAAAAAAAAAAAAAg")
);
- assert_eq!(
- canonical.draft_listing_addr().as_str(),
- format!("{KIND_LISTING_DRAFT}:{SELLER}:AAAAAAAAAAAAAAAAAAAAAg")
- );
assert_eq!(canonical.listing().d_tag.as_str(), "AAAAAAAAAAAAAAAAAAAAAg");
}
#[test]
- fn listing_draft_error_variants_are_precise() {
+ fn listing_edit_error_variants_are_precise() {
assert!(matches!(
- RadrootsListingDraftError::InvalidFarmPubkey(
+ RadrootsListingEditError::InvalidFarmPubkey(
RadrootsPublicKey::parse("bad").unwrap_err()
),
- RadrootsListingDraftError::InvalidFarmPubkey(_)
+ RadrootsListingEditError::InvalidFarmPubkey(_)
));
assert!(matches!(
- RadrootsListingDraftError::InvalidListingAddress(
+ RadrootsListingEditError::InvalidListingAddress(
RadrootsListingAddress::parse("bad").unwrap_err()
),
- RadrootsListingDraftError::InvalidListingAddress(_)
+ RadrootsListingEditError::InvalidListingAddress(_)
));
}
#[test]
- fn canonicalize_listing_draft_fills_missing_farm_pubkey_and_derives_address() {
+ fn canonicalize_listing_edit_fills_missing_farm_pubkey_and_derives_address() {
let mut listing = listing();
listing.farm.pubkey.clear();
- let document = RadrootsListingDraftDocumentV1::new(listing);
+ let document = RadrootsListingEditDocumentV1::new(listing);
let canonical =
- canonicalize_listing_draft(&seller_actor(), document).expect("canonical draft");
+ canonicalize_listing_edit(&seller_actor(), document).expect("canonical draft");
assert_eq!(canonical.seller_pubkey().as_str(), SELLER);
assert_eq!(
canonical.public_listing_addr().as_str(),
format!("{KIND_LISTING}:{SELLER}:AAAAAAAAAAAAAAAAAAAAAg")
);
- assert_eq!(
- canonical.draft_listing_addr().as_str(),
- format!("{KIND_LISTING_DRAFT}:{SELLER}:AAAAAAAAAAAAAAAAAAAAAg")
- );
assert_eq!(canonical.listing().farm.pubkey, SELLER);
}
#[test]
- fn canonicalize_listing_draft_rejects_non_seller_actor() {
- let document = RadrootsListingDraftDocumentV1::new(listing());
+ fn canonicalize_listing_edit_rejects_non_seller_actor() {
+ let document = RadrootsListingEditDocumentV1::new(listing());
- let error = canonicalize_listing_draft(&buyer_actor(), document).unwrap_err();
+ let error = canonicalize_listing_edit(&buyer_actor(), document).unwrap_err();
assert_eq!(
error,
- RadrootsListingDraftError::ActorRoleUnsatisfied {
+ RadrootsListingEditError::ActorRoleUnsatisfied {
required_role: RadrootsActorRole::Seller
}
);
}
#[test]
- fn canonicalize_listing_draft_rejects_mismatched_farm_pubkey() {
+ fn canonicalize_listing_edit_rejects_mismatched_farm_pubkey() {
let mut listing = listing();
listing.farm.pubkey = OTHER.to_string();
- let document = RadrootsListingDraftDocumentV1::new(listing);
+ let document = RadrootsListingEditDocumentV1::new(listing);
- let error = canonicalize_listing_draft(&seller_actor(), document).unwrap_err();
+ let error = canonicalize_listing_edit(&seller_actor(), document).unwrap_err();
assert!(matches!(
error,
- RadrootsListingDraftError::FarmPubkeyMismatch { .. }
+ RadrootsListingEditError::FarmPubkeyMismatch { .. }
));
}
#[test]
- fn canonicalize_listing_draft_rejects_invalid_farm_pubkey() {
+ fn canonicalize_listing_edit_rejects_invalid_farm_pubkey() {
let mut listing = listing();
listing.farm.pubkey = "bad".to_string();
- let document = RadrootsListingDraftDocumentV1::new(listing);
+ let document = RadrootsListingEditDocumentV1::new(listing);
- let error = canonicalize_listing_draft(&seller_actor(), document).unwrap_err();
+ let error = canonicalize_listing_edit(&seller_actor(), document).unwrap_err();
assert!(matches!(
error,
- RadrootsListingDraftError::InvalidFarmPubkey(_)
+ RadrootsListingEditError::InvalidFarmPubkey(_)
));
}
@@ -385,7 +363,7 @@ mod tests {
let mut listing = listing();
listing.farm.pubkey = OTHER.to_string();
- let error = RadrootsCanonicalListingDraft::new(
+ let error = RadrootsCanonicalListingEdit::new(
listing,
RadrootsPublicKey::parse(SELLER).expect("seller"),
)
@@ -393,7 +371,7 @@ mod tests {
assert!(matches!(
error,
- RadrootsListingDraftError::FarmPubkeyMismatch { .. }
+ RadrootsListingEditError::FarmPubkeyMismatch { .. }
));
}
@@ -402,7 +380,7 @@ mod tests {
let mut listing = listing();
listing.farm.pubkey = "bad".to_string();
- let error = RadrootsCanonicalListingDraft::new(
+ let error = RadrootsCanonicalListingEdit::new(
listing,
RadrootsPublicKey::parse(SELLER).expect("seller"),
)
@@ -410,7 +388,7 @@ mod tests {
assert!(matches!(
error,
- RadrootsListingDraftError::InvalidFarmPubkey(_)
+ RadrootsListingEditError::InvalidFarmPubkey(_)
));
}
@@ -419,7 +397,7 @@ mod tests {
let mut listing = listing();
listing.farm.pubkey.clear();
- let error = RadrootsCanonicalListingDraft::new(
+ let error = RadrootsCanonicalListingEdit::new(
listing,
RadrootsPublicKey::parse(SELLER).expect("seller"),
)
@@ -427,21 +405,21 @@ mod tests {
assert!(matches!(
error,
- RadrootsListingDraftError::InvalidFarmPubkey(_)
+ RadrootsListingEditError::InvalidFarmPubkey(_)
));
}
#[test]
- fn canonicalize_listing_draft_rejects_missing_primary_bin() {
+ fn canonicalize_listing_edit_rejects_missing_primary_bin() {
let mut listing = listing();
listing.primary_bin_id = bin_id("bin-2");
- let document = RadrootsListingDraftDocumentV1::new(listing);
+ let document = RadrootsListingEditDocumentV1::new(listing);
- let error = canonicalize_listing_draft(&seller_actor(), document).unwrap_err();
+ let error = canonicalize_listing_edit(&seller_actor(), document).unwrap_err();
assert_eq!(
error,
- RadrootsListingDraftError::MissingPrimaryBin {
+ RadrootsListingEditError::MissingPrimaryBin {
primary_bin_id: bin_id("bin-2")
}
);
@@ -452,7 +430,7 @@ mod tests {
let mut listing = listing();
listing.primary_bin_id = bin_id("bin-2");
- let error = RadrootsCanonicalListingDraft::new(
+ let error = RadrootsCanonicalListingEdit::new(
listing,
RadrootsPublicKey::parse(SELLER).expect("seller"),
)
@@ -460,23 +438,23 @@ mod tests {
assert_eq!(
error,
- RadrootsListingDraftError::MissingPrimaryBin {
+ RadrootsListingEditError::MissingPrimaryBin {
primary_bin_id: bin_id("bin-2")
}
);
}
#[test]
- fn canonicalize_listing_draft_rejects_duplicate_bin_ids() {
+ fn canonicalize_listing_edit_rejects_duplicate_bin_ids() {
let mut listing = listing();
listing.bins.push(listing.bins[0].clone());
- let document = RadrootsListingDraftDocumentV1::new(listing);
+ let document = RadrootsListingEditDocumentV1::new(listing);
- let error = canonicalize_listing_draft(&seller_actor(), document).unwrap_err();
+ let error = canonicalize_listing_edit(&seller_actor(), document).unwrap_err();
assert_eq!(
error,
- RadrootsListingDraftError::DuplicateBinId {
+ RadrootsListingEditError::DuplicateBinId {
bin_id: bin_id("bin-1")
}
);
@@ -487,7 +465,7 @@ mod tests {
let mut listing = listing();
listing.bins.push(listing.bins[0].clone());
- let error = RadrootsCanonicalListingDraft::new(
+ let error = RadrootsCanonicalListingEdit::new(
listing,
RadrootsPublicKey::parse(SELLER).expect("seller"),
)
@@ -495,7 +473,7 @@ mod tests {
assert_eq!(
error,
- RadrootsListingDraftError::DuplicateBinId {
+ RadrootsListingEditError::DuplicateBinId {
bin_id: bin_id("bin-1")
}
);
diff --git a/crates/trade/src/listing/mod.rs b/crates/trade/src/listing/mod.rs
@@ -17,8 +17,8 @@ use radroots_event::{
use thiserror::Error;
pub use self::draft::{
- RadrootsCanonicalListingDraft, RadrootsListingDraftDocumentV1, RadrootsListingDraftError,
- canonicalize_listing_draft,
+ RadrootsCanonicalListingEdit, RadrootsListingEditDocumentV1, RadrootsListingEditError,
+ canonicalize_listing_edit,
};
#[cfg(feature = "serde_json")]
pub use self::mutation::build_listing_mutation_draft;
@@ -146,7 +146,7 @@ mod tests {
use radroots_event::{
RadrootsEventEnvelope, RadrootsEventEnvelopeParts,
ids::RadrootsListingAddress,
- kinds::{KIND_LISTING, KIND_LISTING_DRAFT, KIND_PROFILE},
+ kinds::{KIND_LISTING, KIND_PROFILE},
order::RadrootsListingParseError,
};
@@ -246,25 +246,16 @@ mod tests {
}
#[test]
- fn parse_listing_address_accepts_draft_listing_kind() {
- let raw = format!("{KIND_LISTING_DRAFT}:{SELLER}:listing-1");
- let parsed = parse_listing_address(&raw).expect("listing address");
-
- assert_eq!(parsed.address.as_str(), raw);
- assert_eq!(parsed.kind, KIND_LISTING_DRAFT);
- assert_eq!(parsed.seller_pubkey.as_str(), SELLER);
- assert_eq!(parsed.listing_id.as_str(), "listing-1");
- }
-
- #[test]
- fn parse_public_listing_address_rejects_draft_listing_kind() {
- let raw = format!("{KIND_LISTING_DRAFT}:{SELLER}:listing-1");
+ fn parse_listing_address_rejects_retired_listing_kind() {
+ let raw = format!("30403:{SELLER}:listing-1");
assert!(matches!(
+ parse_listing_address(&raw),
+ Err(RadrootsListingAddressError::InvalidKind { actual: 30403 })
+ ));
+ assert!(matches!(
parse_public_listing_address(&raw),
- Err(RadrootsPublicListingAddressError::InvalidKind {
- actual: KIND_LISTING_DRAFT
- })
+ Err(RadrootsPublicListingAddressError::InvalidListingKind { actual: 30403 })
));
}
diff --git a/crates/trade/src/listing/mutation.rs b/crates/trade/src/listing/mutation.rs
@@ -1,10 +1,4 @@
//! Mutation draft preparation for Radroots Listing v1.
-//!
-//! Publish and update produce the stable public NIP-99 listing-kind event with
-//! Radroots-specific JSON content, save-draft produces the stable listing-draft
-//! event, and archive remains unsupported because Listing v1 has no archive
-//! wire event. Strict NIP-99 Markdown-content interoperability is protocol-v2
-//! work.
#![forbid(unsafe_code)]
@@ -18,29 +12,28 @@ use radroots_event::ids::RadrootsListingAddress;
#[cfg(feature = "serde_json")]
use radroots_event::{
draft::{RadrootsDraftError, RadrootsEventDraft},
- kinds::{KIND_LISTING, KIND_LISTING_DRAFT},
+ kinds::KIND_LISTING,
};
#[cfg(feature = "serde_json")]
use radroots_event_codec::listing::encode::to_json_wire_parts_with_kind;
use thiserror::Error;
-use crate::listing::draft::RadrootsCanonicalListingDraft;
+use crate::listing::draft::RadrootsCanonicalListingEdit;
/// Listing v1 mutation intent for draft preparation only.
///
-/// Publish and update target the public listing event, save-draft targets the
-/// secret listing-draft event, and archive is intentionally unsupported because
-/// listing v1 defines no archive wire event.
+/// Publish and update target the public listing event, while local-only draft
+/// persistence and archive are intentionally unsupported as wire events.
#[derive(Clone, Debug)]
pub enum RadrootsListingMutation {
Publish {
- draft: RadrootsCanonicalListingDraft,
+ draft: RadrootsCanonicalListingEdit,
},
Update {
- draft: RadrootsCanonicalListingDraft,
+ draft: RadrootsCanonicalListingEdit,
},
SaveDraft {
- draft: RadrootsCanonicalListingDraft,
+ draft: RadrootsCanonicalListingEdit,
},
Archive {
listing_addr: RadrootsListingAddress,
@@ -66,18 +59,17 @@ pub enum RadrootsListingMutationError {
}
const LISTING_PUBLISHED_CONTRACT_ID: &str = "radroots.listing.published.v1";
-const LISTING_DRAFT_CONTRACT_ID: &str = "radroots.listing.draft.v1";
impl RadrootsListingMutation {
- pub fn publish(draft: RadrootsCanonicalListingDraft) -> Self {
+ pub fn publish(draft: RadrootsCanonicalListingEdit) -> Self {
Self::Publish { draft }
}
- pub fn update(draft: RadrootsCanonicalListingDraft) -> Self {
+ pub fn update(draft: RadrootsCanonicalListingEdit) -> Self {
Self::Update { draft }
}
- pub fn save_draft(draft: RadrootsCanonicalListingDraft) -> Self {
+ pub fn save_draft(draft: RadrootsCanonicalListingEdit) -> Self {
Self::SaveDraft { draft }
}
@@ -99,7 +91,7 @@ impl RadrootsListingMutation {
pub fn canonical_draft(
&self,
- ) -> Result<&RadrootsCanonicalListingDraft, RadrootsListingMutationError> {
+ ) -> Result<&RadrootsCanonicalListingEdit, RadrootsListingMutationError> {
match self {
Self::Publish { draft } | Self::Update { draft } | Self::SaveDraft { draft } => {
Ok(draft)
@@ -111,7 +103,7 @@ impl RadrootsListingMutation {
pub fn listing_addr(&self) -> Result<&RadrootsListingAddress, RadrootsListingMutationError> {
match self {
Self::Publish { draft } | Self::Update { draft } => Ok(draft.public_listing_addr()),
- Self::SaveDraft { draft } => Ok(draft.draft_listing_addr()),
+ Self::SaveDraft { draft } => Ok(draft.public_listing_addr()),
Self::Archive { .. } => Err(RadrootsListingMutationError::UnsupportedMutation),
}
}
@@ -126,10 +118,7 @@ pub fn build_listing_mutation_draft(
RadrootsListingMutation::Publish { draft } | RadrootsListingMutation::Update { draft } => {
(draft, KIND_LISTING, LISTING_PUBLISHED_CONTRACT_ID)
}
- RadrootsListingMutation::SaveDraft { draft } => {
- (draft, KIND_LISTING_DRAFT, LISTING_DRAFT_CONTRACT_ID)
- }
- RadrootsListingMutation::Archive { .. } => {
+ RadrootsListingMutation::SaveDraft { .. } | RadrootsListingMutation::Archive { .. } => {
return Err(RadrootsListingMutationError::UnsupportedMutation);
}
};
@@ -156,7 +145,7 @@ mod tests {
RadrootsEventEnvelope, RadrootsEventEnvelopeParts,
farm::RadrootsFarmRef,
ids::{RadrootsDTag, RadrootsInventoryBinId, RadrootsListingAddress, RadrootsPublicKey},
- kinds::{KIND_LISTING, KIND_LISTING_DRAFT},
+ kinds::KIND_LISTING,
listing::{
RadrootsListing, RadrootsListingAvailability, RadrootsListingBin,
RadrootsListingDeliveryMethod, RadrootsListingProduct, RadrootsListingPublicLocation,
@@ -165,12 +154,12 @@ mod tests {
resource_area::RadrootsResourceAreaRef,
};
- use crate::listing::draft::RadrootsCanonicalListingDraft;
+ use crate::listing::draft::RadrootsCanonicalListingEdit;
use crate::listing::validation::validate_listing_event;
use super::{
- LISTING_DRAFT_CONTRACT_ID, LISTING_PUBLISHED_CONTRACT_ID, RadrootsListingLifecycleState,
- RadrootsListingMutation, RadrootsListingMutationError, build_listing_mutation_draft,
+ LISTING_PUBLISHED_CONTRACT_ID, RadrootsListingLifecycleState, RadrootsListingMutation,
+ RadrootsListingMutationError, build_listing_mutation_draft,
};
const SELLER: &str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
@@ -244,12 +233,12 @@ mod tests {
}
}
- fn canonical_draft() -> RadrootsCanonicalListingDraft {
- RadrootsCanonicalListingDraft::new(
+ fn canonical_draft() -> RadrootsCanonicalListingEdit {
+ RadrootsCanonicalListingEdit::new(
listing(),
RadrootsPublicKey::parse(SELLER).expect("seller"),
)
- .expect("canonical listing draft")
+ .expect("canonical listing edit")
}
#[test]
@@ -331,7 +320,7 @@ mod tests {
);
assert_eq!(
save_draft.listing_addr().expect("address").as_str(),
- format!("{KIND_LISTING_DRAFT}:{SELLER}:AAAAAAAAAAAAAAAAAAAAAg")
+ format!("{KIND_LISTING}:{SELLER}:AAAAAAAAAAAAAAAAAAAAAg")
);
}
@@ -379,18 +368,13 @@ mod tests {
}
#[test]
- fn build_listing_mutation_draft_maps_save_draft_to_listing_draft() {
+ fn build_listing_mutation_draft_rejects_save_draft() {
let save_draft = RadrootsListingMutation::save_draft(canonical_draft());
- let draft = build_listing_mutation_draft(&save_draft, 1_700_000_000).expect("draft");
-
- assert_eq!(draft.kind_u32(), KIND_LISTING_DRAFT);
- assert_eq!(draft.contract_id(), LISTING_DRAFT_CONTRACT_ID);
- assert_eq!(draft.expected_pubkey_str(), SELLER);
- assert_eq!(draft.created_at_u64(), 1_700_000_000);
- let draft_content: RadrootsListing =
- serde_json::from_str(draft.content()).expect("listing json");
- assert_eq!(draft_content.d_tag.as_str(), "AAAAAAAAAAAAAAAAAAAAAg");
+ assert_eq!(
+ build_listing_mutation_draft(&save_draft, 1_700_000_000).unwrap_err(),
+ RadrootsListingMutationError::UnsupportedMutation
+ );
}
#[test]
@@ -415,11 +399,11 @@ mod tests {
pubkey: SELLER.to_string(),
d_tag: "bad d tag".to_string(),
});
- let draft = RadrootsCanonicalListingDraft::new(
+ let draft = RadrootsCanonicalListingEdit::new(
listing,
RadrootsPublicKey::parse(SELLER).expect("seller"),
)
- .expect("canonical listing draft");
+ .expect("canonical listing edit");
let publish = RadrootsListingMutation::publish(draft);
let err = build_listing_mutation_draft(&publish, 1_700_000_000).unwrap_err();
diff --git a/crates/trade/src/listing/validation.rs b/crates/trade/src/listing/validation.rs
@@ -194,7 +194,7 @@ mod tests {
RadrootsEventEnvelope,
farm::RadrootsFarmRef,
ids::{RadrootsDTag, RadrootsInventoryBinId},
- kinds::{KIND_LISTING, KIND_LISTING_DRAFT},
+ kinds::KIND_LISTING,
listing::{
RadrootsListing, RadrootsListingAvailability, RadrootsListingBin,
RadrootsListingDeliveryMethod, RadrootsListingProduct, RadrootsListingPublicLocation,
@@ -321,18 +321,18 @@ mod tests {
}
#[test]
- fn validate_draft_listing_ok() {
+ fn validate_listing_rejects_retired_kind() {
let listing = base_listing();
let event = event_with_parts(
SELLER,
- KIND_LISTING_DRAFT,
+ 30403,
base_event(&listing).tags_as_vec(),
serde_json::to_string(&listing).unwrap(),
);
- let validated = validate_listing_event(&event).expect("draft listing");
+ let err = validate_listing_event(&event).unwrap_err();
assert_eq!(
- validated.listing_addr,
- format!("30403:{SELLER}:{}", listing.d_tag)
+ err,
+ TradeListingValidationError::InvalidKind { kind: 30403 }
);
}
diff --git a/crates/trade/src/order.rs b/crates/trade/src/order.rs
@@ -19,16 +19,14 @@ use radroots_event::order::RadrootsOrderEventType;
use radroots_event::order::{
RadrootsOrderCancellation, RadrootsOrderDecision, RadrootsOrderDecisionOutcome,
RadrootsOrderEconomics, RadrootsOrderInventoryCommitment, RadrootsOrderItem,
- RadrootsOrderRequest, RadrootsOrderRevisionDecision, RadrootsOrderRevisionOutcome,
- RadrootsOrderRevisionProposal,
+ RadrootsOrderRequest,
};
#[cfg(feature = "event_store")]
use radroots_event::tags::TAG_D;
#[cfg(feature = "serde_json")]
use radroots_event_codec::order::{
RadrootsOrderEnvelopeParseError, order_cancellation_from_event, order_decision_from_event,
- order_event_context_from_tags, order_request_from_event, order_revision_decision_from_event,
- order_revision_proposal_from_event,
+ order_event_context_from_tags, order_request_from_event,
};
#[cfg(feature = "event_store")]
use radroots_event_store::{RadrootsEventStore, RadrootsEventStoreError, RadrootsStoredEvent};
@@ -64,11 +62,9 @@ pub enum RadrootsOrderCanonicalizationError {
InvalidInventoryCommitmentCount { index: usize },
}
-pub const ORDER_EVENT_CONTRACT_IDS: [&str; 5] = [
+pub const ORDER_EVENT_CONTRACT_IDS: [&str; 3] = [
"radroots.order.request.v1",
"radroots.order.decision.v1",
- "radroots.order.revision_proposal.v1",
- "radroots.order.revision_decision.v1",
"radroots.order.cancellation.v1",
];
@@ -90,26 +86,6 @@ pub struct RadrootsOrderDecisionRecord {
}
#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsOrderRevisionProposalRecord {
- pub event_id: RadrootsEventId,
- pub author_pubkey: RadrootsPublicKey,
- pub counterparty_pubkey: RadrootsPublicKey,
- pub root_event_id: RadrootsEventId,
- pub prev_event_id: RadrootsEventId,
- pub payload: RadrootsOrderRevisionProposal,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsOrderRevisionDecisionRecord {
- pub event_id: RadrootsEventId,
- pub author_pubkey: RadrootsPublicKey,
- pub counterparty_pubkey: RadrootsPublicKey,
- pub root_event_id: RadrootsEventId,
- pub prev_event_id: RadrootsEventId,
- pub payload: RadrootsOrderRevisionDecision,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RadrootsOrderCancellationRecord {
pub event_id: RadrootsEventId,
pub author_pubkey: RadrootsPublicKey,
@@ -123,8 +99,6 @@ pub struct RadrootsOrderCancellationRecord {
pub enum RadrootsOrderEventRecord {
Request(RadrootsOrderRequestRecord),
Decision(RadrootsOrderDecisionRecord),
- RevisionProposal(RadrootsOrderRevisionProposalRecord),
- RevisionDecision(RadrootsOrderRevisionDecisionRecord),
Cancellation(RadrootsOrderCancellationRecord),
}
@@ -133,8 +107,6 @@ impl RadrootsOrderEventRecord {
match self {
Self::Request(record) => &record.event_id,
Self::Decision(record) => &record.event_id,
- Self::RevisionProposal(record) => &record.event_id,
- Self::RevisionDecision(record) => &record.event_id,
Self::Cancellation(record) => &record.event_id,
}
}
@@ -143,8 +115,6 @@ impl RadrootsOrderEventRecord {
match self {
Self::Request(record) => &record.payload.order_id,
Self::Decision(record) => &record.payload.order_id,
- Self::RevisionProposal(record) => &record.payload.order_id,
- Self::RevisionDecision(record) => &record.payload.order_id,
Self::Cancellation(record) => &record.payload.order_id,
}
}
@@ -205,32 +175,6 @@ pub fn order_event_record_from_event(
},
))
}
- RadrootsOrderEventType::OrderRevisionProposed => {
- let envelope = order_revision_proposal_from_event(event)?;
- Ok(RadrootsOrderEventRecord::RevisionProposal(
- RadrootsOrderRevisionProposalRecord {
- event_id,
- author_pubkey,
- counterparty_pubkey: context.counterparty_pubkey.clone(),
- root_event_id: require_context_root_event_id(&context)?,
- prev_event_id: require_context_prev_event_id(&context)?,
- payload: envelope.payload,
- },
- ))
- }
- RadrootsOrderEventType::OrderRevisionDecision => {
- let envelope = order_revision_decision_from_event(event)?;
- Ok(RadrootsOrderEventRecord::RevisionDecision(
- RadrootsOrderRevisionDecisionRecord {
- event_id,
- author_pubkey,
- counterparty_pubkey: context.counterparty_pubkey.clone(),
- root_event_id: require_context_root_event_id(&context)?,
- prev_event_id: require_context_prev_event_id(&context)?,
- payload: envelope.payload,
- },
- ))
- }
RadrootsOrderEventType::OrderCancelled => {
let envelope = order_cancellation_from_event(event)?;
Ok(RadrootsOrderEventRecord::Cancellation(
@@ -476,72 +420,6 @@ pub enum RadrootsOrderIssue {
ConflictingDecisions {
event_ids: Vec<RadrootsEventId>,
},
- RevisionProposalPayloadInvalid {
- event_id: RadrootsEventId,
- },
- RevisionProposalOrderIdMismatch {
- event_id: RadrootsEventId,
- },
- RevisionProposalAuthorMismatch {
- event_id: RadrootsEventId,
- },
- RevisionProposalCounterpartyMismatch {
- event_id: RadrootsEventId,
- },
- RevisionProposalBuyerMismatch {
- event_id: RadrootsEventId,
- },
- RevisionProposalSellerMismatch {
- event_id: RadrootsEventId,
- },
- RevisionProposalListingAddressInvalid {
- event_id: RadrootsEventId,
- },
- RevisionProposalListingMismatch {
- event_id: RadrootsEventId,
- },
- RevisionProposalRootMismatch {
- event_id: RadrootsEventId,
- },
- RevisionProposalPreviousMismatch {
- event_id: RadrootsEventId,
- },
- RevisionDecisionWithoutProposal {
- event_id: RadrootsEventId,
- },
- RevisionDecisionPayloadInvalid {
- event_id: RadrootsEventId,
- },
- RevisionDecisionOrderIdMismatch {
- event_id: RadrootsEventId,
- },
- RevisionDecisionAuthorMismatch {
- event_id: RadrootsEventId,
- },
- RevisionDecisionCounterpartyMismatch {
- event_id: RadrootsEventId,
- },
- RevisionDecisionBuyerMismatch {
- event_id: RadrootsEventId,
- },
- RevisionDecisionSellerMismatch {
- event_id: RadrootsEventId,
- },
- RevisionDecisionListingAddressInvalid {
- event_id: RadrootsEventId,
- },
- RevisionDecisionListingMismatch {
- event_id: RadrootsEventId,
- },
- RevisionDecisionRootMismatch {
- event_id: RadrootsEventId,
- },
- RevisionDecisionPreviousMismatch {
- event_id: RadrootsEventId,
- },
- RevisionDecisionRevisionIdMismatch {
- event_id: RadrootsEventId,
- },
CancellationWithoutCancellableOrder {
event_id: RadrootsEventId,
},
@@ -620,7 +498,6 @@ pub struct RadrootsOrderProjection {
pub lifecycle_terminal: bool,
pub economics: Option<RadrootsOrderEconomics>,
pub agreement_event_id: Option<RadrootsEventId>,
- pub pending_revision_event_id: Option<RadrootsEventId>,
pub pending_inventory_reservations: Vec<RadrootsOrderInventoryCommitment>,
pub committed_inventory_reservations: Vec<RadrootsOrderInventoryCommitment>,
pub listing_addr: Option<RadrootsListingAddress>,
@@ -653,7 +530,6 @@ pub struct RadrootsOrderWorkflowProjection {
pub lifecycle_terminal: bool,
pub economics: Option<RadrootsOrderEconomics>,
pub agreement_event_id: Option<RadrootsEventId>,
- pub pending_revision_event_id: Option<RadrootsEventId>,
pub pending_inventory_reservations: Vec<RadrootsOrderInventoryCommitment>,
pub committed_inventory_reservations: Vec<RadrootsOrderInventoryCommitment>,
pub listing_addr: Option<RadrootsListingAddress>,
@@ -675,7 +551,6 @@ impl From<RadrootsOrderProjection> for RadrootsOrderWorkflowProjection {
lifecycle_terminal: projection.lifecycle_terminal,
economics: projection.economics,
agreement_event_id: projection.agreement_event_id,
- pending_revision_event_id: projection.pending_revision_event_id,
pending_inventory_reservations: projection.pending_inventory_reservations,
committed_inventory_reservations: projection.committed_inventory_reservations,
listing_addr: projection.listing_addr,
@@ -759,20 +634,16 @@ pub struct RadrootsListingInventoryAccountingProjection {
}
#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsOrderReductionInputs<I, J, K, L, M> {
+pub struct RadrootsOrderReductionInputs<I, J, K> {
pub requests: I,
pub decisions: J,
- pub revision_proposals: K,
- pub revision_decisions: L,
- pub cancellations: M,
+ pub cancellations: K,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct RadrootsGroupedOrderEventRecords {
pub requests: Vec<RadrootsOrderRequestRecord>,
pub decisions: Vec<RadrootsOrderDecisionRecord>,
- pub revision_proposals: Vec<RadrootsOrderRevisionProposalRecord>,
- pub revision_decisions: Vec<RadrootsOrderRevisionDecisionRecord>,
pub cancellations: Vec<RadrootsOrderCancellationRecord>,
}
@@ -792,13 +663,11 @@ pub(crate) enum RadrootsTradeLocatorGroupedOrderEventRecordsResolution {
}
#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsListingInventoryAccountingInputs<I, J, K, L, M, N> {
+pub struct RadrootsListingInventoryAccountingInputs<I, J, K, L> {
pub bins: I,
pub requests: J,
pub decisions: K,
- pub revision_proposals: L,
- pub revision_decisions: M,
- pub cancellations: N,
+ pub cancellations: L,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
@@ -806,29 +675,23 @@ struct RadrootsListingInventoryAccountingRecords {
bins: Vec<RadrootsListingInventoryBinAvailability>,
requests: Vec<RadrootsOrderRequestRecord>,
decisions: Vec<RadrootsOrderDecisionRecord>,
- revision_proposals: Vec<RadrootsOrderRevisionProposalRecord>,
- revision_decisions: Vec<RadrootsOrderRevisionDecisionRecord>,
cancellations: Vec<RadrootsOrderCancellationRecord>,
}
-pub fn reduce_order_events<I, J, K, L, M>(
+pub fn reduce_order_events<I, J, K>(
order_id: &RadrootsOrderId,
- inputs: RadrootsOrderReductionInputs<I, J, K, L, M>,
+ inputs: RadrootsOrderReductionInputs<I, J, K>,
) -> RadrootsOrderProjection
where
I: IntoIterator<Item = RadrootsOrderRequestRecord>,
J: IntoIterator<Item = RadrootsOrderDecisionRecord>,
- K: IntoIterator<Item = RadrootsOrderRevisionProposalRecord>,
- L: IntoIterator<Item = RadrootsOrderRevisionDecisionRecord>,
- M: IntoIterator<Item = RadrootsOrderCancellationRecord>,
+ K: IntoIterator<Item = RadrootsOrderCancellationRecord>,
{
reduce_grouped_order_event_records(
order_id,
RadrootsGroupedOrderEventRecords {
requests: inputs.requests.into_iter().collect(),
decisions: inputs.decisions.into_iter().collect(),
- revision_proposals: inputs.revision_proposals.into_iter().collect(),
- revision_decisions: inputs.revision_decisions.into_iter().collect(),
cancellations: inputs.cancellations.into_iter().collect(),
},
)
@@ -860,12 +723,6 @@ where
match record {
RadrootsOrderEventRecord::Request(record) => grouped.requests.push(record),
RadrootsOrderEventRecord::Decision(record) => grouped.decisions.push(record),
- RadrootsOrderEventRecord::RevisionProposal(record) => {
- grouped.revision_proposals.push(record);
- }
- RadrootsOrderEventRecord::RevisionDecision(record) => {
- grouped.revision_decisions.push(record);
- }
RadrootsOrderEventRecord::Cancellation(record) => grouped.cancellations.push(record),
}
}
@@ -997,22 +854,6 @@ fn filter_grouped_order_records_for_trade_candidate(
&& decision.root_event_id == candidate.root_event_id
})
.collect(),
- revision_proposals: records
- .revision_proposals
- .into_iter()
- .filter(|proposal| {
- proposal.payload.order_id == *candidate.trade_id.as_order_id()
- && proposal.root_event_id == candidate.root_event_id
- })
- .collect(),
- revision_decisions: records
- .revision_decisions
- .into_iter()
- .filter(|decision| {
- decision.payload.order_id == *candidate.trade_id.as_order_id()
- && decision.root_event_id == candidate.root_event_id
- })
- .collect(),
cancellations: records
.cancellations
.into_iter()
@@ -1030,15 +871,8 @@ pub(crate) fn reduce_grouped_order_event_records(
) -> RadrootsOrderProjection {
let requests = unique_request_records(records.requests);
let decisions = unique_decision_records(records.decisions);
- let revision_proposals = unique_revision_proposal_records(records.revision_proposals);
- let revision_decisions = unique_revision_decision_records(records.revision_decisions);
let cancellations = unique_cancellation_records(records.cancellations);
- if requests.is_empty()
- && decisions.is_empty()
- && revision_proposals.is_empty()
- && revision_decisions.is_empty()
- && cancellations.is_empty()
- {
+ if requests.is_empty() && decisions.is_empty() && cancellations.is_empty() {
return empty_projection(order_id, RadrootsTradeWorkflowState::Missing, false);
}
@@ -1060,11 +894,7 @@ pub(crate) fn reduce_grouped_order_event_records(
}
let Some(request) = valid_requests.first() else {
- if !decisions.is_empty()
- || !revision_proposals.is_empty()
- || !revision_decisions.is_empty()
- || !cancellations.is_empty()
- {
+ if !decisions.is_empty() || !cancellations.is_empty() {
issues.push(RadrootsOrderIssue::MissingRequest);
}
return invalid_projection(order_id, None, issues);
@@ -1081,20 +911,6 @@ pub(crate) fn reduce_grouped_order_event_records(
}
}
- let mut valid_revision_proposals = Vec::new();
- for proposal in revision_proposals {
- if validate_order_revision_proposal_record(request, &proposal, &mut issues) {
- valid_revision_proposals.push(proposal);
- }
- }
-
- let mut valid_revision_decisions = Vec::new();
- for decision in revision_decisions {
- if validate_order_revision_decision_record(request, &decision, &mut issues) {
- valid_revision_decisions.push(decision);
- }
- }
-
let mut valid_cancellations = Vec::new();
for cancellation in cancellations {
if validate_order_cancellation_record(request, &cancellation, &mut issues) {
@@ -1120,30 +936,12 @@ pub(crate) fn reduce_grouped_order_event_records(
}
if let Some(cancellation) = valid_cancellations.first() {
- return cancelled_projection(
- order_id,
- request,
- cancellation,
- &valid_decisions,
- &valid_revision_proposals,
- &valid_revision_decisions,
- );
+ return cancelled_projection(order_id, request, cancellation, &valid_decisions);
}
match valid_decisions.len() {
- 0 => negotiation_projection(
- order_id,
- request,
- &valid_revision_proposals,
- &valid_revision_decisions,
- ),
- 1 => decided_projection(
- order_id,
- request,
- &valid_decisions[0],
- &valid_revision_proposals,
- &valid_revision_decisions,
- ),
+ 0 => request_projection(order_id, request, RadrootsTradeWorkflowState::Requested),
+ 1 => decided_projection(order_id, request, &valid_decisions[0]),
_ => {
let mut event_ids = valid_decisions
.iter()
@@ -1159,18 +957,16 @@ pub(crate) fn reduce_grouped_order_event_records(
}
}
-pub fn reduce_listing_inventory_accounting<I, J, K, L, M, N>(
+pub fn reduce_listing_inventory_accounting<I, J, K, L>(
listing_addr: &RadrootsListingAddress,
listing_event_id: &RadrootsEventId,
- inputs: RadrootsListingInventoryAccountingInputs<I, J, K, L, M, N>,
+ inputs: RadrootsListingInventoryAccountingInputs<I, J, K, L>,
) -> RadrootsListingInventoryAccountingProjection
where
I: IntoIterator<Item = RadrootsListingInventoryBinAvailability>,
J: IntoIterator<Item = RadrootsOrderRequestRecord>,
K: IntoIterator<Item = RadrootsOrderDecisionRecord>,
- L: IntoIterator<Item = RadrootsOrderRevisionProposalRecord>,
- M: IntoIterator<Item = RadrootsOrderRevisionDecisionRecord>,
- N: IntoIterator<Item = RadrootsOrderCancellationRecord>,
+ L: IntoIterator<Item = RadrootsOrderCancellationRecord>,
{
reduce_listing_inventory_accounting_records(
listing_addr,
@@ -1179,8 +975,6 @@ where
bins: inputs.bins.into_iter().collect(),
requests: inputs.requests.into_iter().collect(),
decisions: inputs.decisions.into_iter().collect(),
- revision_proposals: inputs.revision_proposals.into_iter().collect(),
- revision_decisions: inputs.revision_decisions.into_iter().collect(),
cancellations: inputs.cancellations.into_iter().collect(),
},
)
@@ -1200,25 +994,11 @@ fn reduce_listing_inventory_accounting_records(
.into_iter()
.filter(|decision| decision.payload.listing_addr.as_str() == listing_addr.as_str())
.collect::<Vec<_>>();
- let revision_proposals = unique_revision_proposal_records(records.revision_proposals)
- .into_iter()
- .filter(|proposal| proposal.payload.listing_addr.as_str() == listing_addr.as_str())
- .collect::<Vec<_>>();
- let revision_decisions = unique_revision_decision_records(records.revision_decisions)
- .into_iter()
- .filter(|decision| decision.payload.listing_addr.as_str() == listing_addr.as_str())
- .collect::<Vec<_>>();
let cancellations = unique_cancellation_records(records.cancellations)
.into_iter()
.filter(|cancellation| cancellation.payload.listing_addr.as_str() == listing_addr.as_str())
.collect::<Vec<_>>();
- let mut order_ids = listing_order_ids(
- &requests,
- &decisions,
- &revision_proposals,
- &revision_decisions,
- &cancellations,
- );
+ let mut order_ids = listing_order_ids(&requests, &decisions, &cancellations);
let mut declined_order_ids = Vec::new();
let mut cancelled_order_ids = Vec::new();
let mut invalid_event_ids = Vec::new();
@@ -1234,16 +1014,6 @@ fn reduce_listing_inventory_accounting_records(
.filter(|decision| decision.payload.order_id == order_id)
.cloned()
.collect::<Vec<_>>();
- let order_revision_proposals = revision_proposals
- .iter()
- .filter(|proposal| proposal.payload.order_id == order_id)
- .cloned()
- .collect::<Vec<_>>();
- let order_revision_decisions = revision_decisions
- .iter()
- .filter(|decision| decision.payload.order_id == order_id)
- .cloned()
- .collect::<Vec<_>>();
let order_cancellations = cancellations
.iter()
.filter(|cancellation| cancellation.payload.order_id == order_id)
@@ -1254,8 +1024,6 @@ fn reduce_listing_inventory_accounting_records(
RadrootsOrderReductionInputs {
requests: order_requests.clone(),
decisions: order_decisions.clone(),
- revision_proposals: order_revision_proposals.clone(),
- revision_decisions: order_revision_decisions.clone(),
cancellations: order_cancellations.clone(),
},
);
@@ -1283,8 +1051,6 @@ fn reduce_listing_inventory_accounting_records(
event_ids = fallback_order_event_ids(
&order_requests,
&order_decisions,
- &order_revision_proposals,
- &order_revision_decisions,
&order_cancellations,
);
}
@@ -1320,24 +1086,12 @@ fn reduce_listing_inventory_accounting_records(
fn fallback_order_event_ids(
requests: &[RadrootsOrderRequestRecord],
decisions: &[RadrootsOrderDecisionRecord],
- revision_proposals: &[RadrootsOrderRevisionProposalRecord],
- revision_decisions: &[RadrootsOrderRevisionDecisionRecord],
cancellations: &[RadrootsOrderCancellationRecord],
) -> Vec<RadrootsEventId> {
let mut event_ids = Vec::new();
event_ids.extend(requests.iter().map(|request| request.event_id.clone()));
event_ids.extend(decisions.iter().map(|decision| decision.event_id.clone()));
event_ids.extend(
- revision_proposals
- .iter()
- .map(|proposal| proposal.event_id.clone()),
- );
- event_ids.extend(
- revision_decisions
- .iter()
- .map(|decision| decision.event_id.clone()),
- );
- event_ids.extend(
cancellations
.iter()
.map(|cancellation| cancellation.event_id.clone()),
@@ -1420,30 +1174,10 @@ fn cancelled_projection(
request: &RadrootsOrderRequestRecord,
cancellation: &RadrootsOrderCancellationRecord,
decisions: &[RadrootsOrderDecisionRecord],
- revision_proposals: &[RadrootsOrderRevisionProposalRecord],
- revision_decisions: &[RadrootsOrderRevisionDecisionRecord],
) -> RadrootsOrderProjection {
- if !decisions.is_empty() || !revision_decisions.is_empty() {
+ if !decisions.is_empty() {
let mut event_ids = Vec::new();
event_ids.extend(decisions.iter().map(|decision| decision.event_id.clone()));
- event_ids.extend(
- revision_decisions
- .iter()
- .map(|decision| decision.event_id.clone()),
- );
- event_ids.push(cancellation.event_id.clone());
- sort_and_dedup_values(&mut event_ids);
- return invalid_projection(
- order_id,
- Some(request),
- vec![RadrootsOrderIssue::ForkedLifecycle { event_ids }],
- );
- }
- if revision_proposals.len() > 1 {
- let mut event_ids = revision_proposals
- .iter()
- .map(|proposal| proposal.event_id.clone())
- .collect::<Vec<_>>();
event_ids.push(cancellation.event_id.clone());
sort_and_dedup_values(&mut event_ids);
return invalid_projection(
@@ -1452,11 +1186,7 @@ fn cancelled_projection(
vec![RadrootsOrderIssue::ForkedLifecycle { event_ids }],
);
}
- let expected_prev_event_id = revision_proposals
- .first()
- .map(|proposal| &proposal.event_id)
- .unwrap_or(&request.event_id);
- if &cancellation.prev_event_id != expected_prev_event_id {
+ if cancellation.prev_event_id != request.event_id {
return invalid_projection(
order_id,
Some(request),
@@ -1474,117 +1204,11 @@ fn cancelled_projection(
projection
}
-fn negotiation_projection(
- order_id: &RadrootsOrderId,
- request: &RadrootsOrderRequestRecord,
- revision_proposals: &[RadrootsOrderRevisionProposalRecord],
- revision_decisions: &[RadrootsOrderRevisionDecisionRecord],
-) -> RadrootsOrderProjection {
- match revision_proposals.len() {
- 0 => {
- if revision_decisions.is_empty() {
- request_projection(order_id, request, RadrootsTradeWorkflowState::Requested)
- } else {
- invalid_projection(
- order_id,
- Some(request),
- revision_decisions
- .iter()
- .map(
- |decision| RadrootsOrderIssue::RevisionDecisionWithoutProposal {
- event_id: decision.event_id.clone(),
- },
- )
- .collect(),
- )
- }
- }
- 1 => {
- let proposal = &revision_proposals[0];
- if proposal.prev_event_id != request.event_id {
- return invalid_projection(
- order_id,
- Some(request),
- vec![RadrootsOrderIssue::RevisionProposalPreviousMismatch {
- event_id: proposal.event_id.clone(),
- }],
- );
- }
- match revision_decisions.len() {
- 0 => {
- let mut projection = request_projection(
- order_id,
- request,
- RadrootsTradeWorkflowState::Requested,
- );
- projection.pending_revision_event_id = Some(proposal.event_id.clone());
- projection.economics = Some(proposal.payload.economics.clone());
- projection.last_event_id = Some(proposal.event_id.clone());
- projection
- }
- 1 => revision_decision_projection(
- order_id,
- request,
- proposal,
- &revision_decisions[0],
- ),
- _ => {
- let mut event_ids = revision_decisions
- .iter()
- .map(|decision| decision.event_id.clone())
- .collect::<Vec<_>>();
- sort_and_dedup_values(&mut event_ids);
- invalid_projection(
- order_id,
- Some(request),
- vec![RadrootsOrderIssue::ForkedLifecycle { event_ids }],
- )
- }
- }
- }
- _ => {
- let mut event_ids = revision_proposals
- .iter()
- .map(|proposal| proposal.event_id.clone())
- .collect::<Vec<_>>();
- sort_and_dedup_values(&mut event_ids);
- invalid_projection(
- order_id,
- Some(request),
- vec![RadrootsOrderIssue::ForkedLifecycle { event_ids }],
- )
- }
- }
-}
-
fn decided_projection(
order_id: &RadrootsOrderId,
request: &RadrootsOrderRequestRecord,
decision: &RadrootsOrderDecisionRecord,
- revision_proposals: &[RadrootsOrderRevisionProposalRecord],
- revision_decisions: &[RadrootsOrderRevisionDecisionRecord],
) -> RadrootsOrderProjection {
- if !revision_proposals.is_empty() || !revision_decisions.is_empty() {
- let mut event_ids = Vec::new();
- event_ids.extend(
- revision_proposals
- .iter()
- .map(|proposal| proposal.event_id.clone()),
- );
- event_ids.extend(
- revision_decisions
- .iter()
- .map(|decision| decision.event_id.clone()),
- );
- event_ids.push(decision.event_id.clone());
- sort_and_dedup_values(&mut event_ids);
- return invalid_projection(
- order_id,
- Some(request),
- vec![RadrootsOrderIssue::ForkedLifecycle { event_ids }],
- );
- }
-
match &decision.payload.decision {
RadrootsOrderDecisionOutcome::Accepted { .. } => {
let mut projection = request_projection(
@@ -1611,56 +1235,6 @@ fn decided_projection(
}
}
-fn revision_decision_projection(
- order_id: &RadrootsOrderId,
- request: &RadrootsOrderRequestRecord,
- proposal: &RadrootsOrderRevisionProposalRecord,
- decision: &RadrootsOrderRevisionDecisionRecord,
-) -> RadrootsOrderProjection {
- if decision.prev_event_id != proposal.event_id {
- return invalid_projection(
- order_id,
- Some(request),
- vec![RadrootsOrderIssue::RevisionDecisionPreviousMismatch {
- event_id: decision.event_id.clone(),
- }],
- );
- }
- if decision.payload.revision_id != proposal.payload.revision_id {
- return invalid_projection(
- order_id,
- Some(request),
- vec![RadrootsOrderIssue::RevisionDecisionRevisionIdMismatch {
- event_id: decision.event_id.clone(),
- }],
- );
- }
-
- match &decision.payload.decision {
- RadrootsOrderRevisionOutcome::Accepted => {
- let mut projection = request_projection(
- order_id,
- request,
- RadrootsTradeWorkflowState::AgreedPendingValidation,
- );
- projection.economics = Some(proposal.payload.economics.clone());
- projection.agreement_event_id = Some(decision.event_id.clone());
- projection.pending_inventory_reservations =
- inventory_commitments_from_items(&proposal.payload.items);
- projection.last_event_id = Some(decision.event_id.clone());
- projection
- }
- RadrootsOrderRevisionOutcome::Declined { .. } => {
- let mut projection =
- request_projection(order_id, request, RadrootsTradeWorkflowState::Declined);
- projection.lifecycle_terminal = true;
- projection.pending_revision_event_id = Some(proposal.event_id.clone());
- projection.last_event_id = Some(decision.event_id.clone());
- projection
- }
- }
-}
-
fn request_projection(
order_id: &RadrootsOrderId,
request: &RadrootsOrderRequestRecord,
@@ -1676,7 +1250,6 @@ fn request_projection(
lifecycle_terminal: false,
economics: Some(request.payload.economics.clone()),
agreement_event_id: None,
- pending_revision_event_id: None,
pending_inventory_reservations: Vec::new(),
committed_inventory_reservations: Vec::new(),
listing_addr: Some(request.payload.listing_addr.clone()),
@@ -1728,7 +1301,6 @@ fn empty_projection(
lifecycle_terminal,
economics: None,
agreement_event_id: None,
- pending_revision_event_id: None,
pending_inventory_reservations: Vec::new(),
committed_inventory_reservations: Vec::new(),
listing_addr: None,
@@ -1871,242 +1443,84 @@ fn validate_order_decision_record(
valid
}
-fn validate_order_revision_proposal_record(
+fn validate_order_cancellation_record(
request: &RadrootsOrderRequestRecord,
- proposal: &RadrootsOrderRevisionProposalRecord,
+ cancellation: &RadrootsOrderCancellationRecord,
issues: &mut Vec<RadrootsOrderIssue>,
) -> bool {
let mut valid = true;
- if proposal.payload.validate().is_err() {
- issues.push(RadrootsOrderIssue::RevisionProposalPayloadInvalid {
- event_id: proposal.event_id.clone(),
+ if cancellation.payload.validate().is_err() {
+ issues.push(RadrootsOrderIssue::CancellationPayloadInvalid {
+ event_id: cancellation.event_id.clone(),
});
valid = false;
}
- if proposal.payload.order_id != request.payload.order_id {
- issues.push(RadrootsOrderIssue::RevisionProposalOrderIdMismatch {
- event_id: proposal.event_id.clone(),
+ if cancellation.payload.order_id != request.payload.order_id {
+ issues.push(RadrootsOrderIssue::CancellationOrderIdMismatch {
+ event_id: cancellation.event_id.clone(),
});
valid = false;
}
- if proposal.author_pubkey != proposal.payload.seller_pubkey {
- issues.push(RadrootsOrderIssue::RevisionProposalAuthorMismatch {
- event_id: proposal.event_id.clone(),
+ if cancellation.author_pubkey != cancellation.payload.buyer_pubkey {
+ issues.push(RadrootsOrderIssue::CancellationAuthorMismatch {
+ event_id: cancellation.event_id.clone(),
});
valid = false;
}
- if proposal.counterparty_pubkey != request.payload.buyer_pubkey {
- issues.push(RadrootsOrderIssue::RevisionProposalCounterpartyMismatch {
- event_id: proposal.event_id.clone(),
+ if cancellation.counterparty_pubkey != request.payload.seller_pubkey {
+ issues.push(RadrootsOrderIssue::CancellationCounterpartyMismatch {
+ event_id: cancellation.event_id.clone(),
});
valid = false;
}
- if proposal.payload.buyer_pubkey != request.payload.buyer_pubkey {
- issues.push(RadrootsOrderIssue::RevisionProposalBuyerMismatch {
- event_id: proposal.event_id.clone(),
+ if cancellation.payload.buyer_pubkey != request.payload.buyer_pubkey {
+ issues.push(RadrootsOrderIssue::CancellationBuyerMismatch {
+ event_id: cancellation.event_id.clone(),
});
valid = false;
}
- if proposal.payload.seller_pubkey != request.payload.seller_pubkey {
- issues.push(RadrootsOrderIssue::RevisionProposalSellerMismatch {
- event_id: proposal.event_id.clone(),
+ if cancellation.payload.seller_pubkey != request.payload.seller_pubkey {
+ issues.push(RadrootsOrderIssue::CancellationSellerMismatch {
+ event_id: cancellation.event_id.clone(),
});
valid = false;
}
- match parse_public_listing_addr(&proposal.payload.listing_addr) {
+ match parse_public_listing_addr(&cancellation.payload.listing_addr) {
Ok(listing_addr) => {
- if proposal.payload.listing_addr != request.payload.listing_addr
- || listing_addr.seller_pubkey != proposal.payload.seller_pubkey
+ if cancellation.payload.listing_addr != request.payload.listing_addr
+ || listing_addr.seller_pubkey != cancellation.payload.seller_pubkey
{
- issues.push(RadrootsOrderIssue::RevisionProposalListingMismatch {
- event_id: proposal.event_id.clone(),
+ issues.push(RadrootsOrderIssue::CancellationListingMismatch {
+ event_id: cancellation.event_id.clone(),
});
valid = false;
}
}
Err(_) => {
- issues.push(RadrootsOrderIssue::RevisionProposalListingAddressInvalid {
- event_id: proposal.event_id.clone(),
+ issues.push(RadrootsOrderIssue::CancellationListingAddressInvalid {
+ event_id: cancellation.event_id.clone(),
});
valid = false;
}
}
- if proposal.root_event_id != request.event_id
- || proposal.payload.root_event_id != request.event_id
- {
- issues.push(RadrootsOrderIssue::RevisionProposalRootMismatch {
- event_id: proposal.event_id.clone(),
+ if cancellation.root_event_id != request.event_id {
+ issues.push(RadrootsOrderIssue::CancellationRootMismatch {
+ event_id: cancellation.event_id.clone(),
});
valid = false;
}
- if proposal.prev_event_id == proposal.event_id
- || proposal.payload.prev_event_id != proposal.prev_event_id
- {
- issues.push(RadrootsOrderIssue::RevisionProposalPreviousMismatch {
- event_id: proposal.event_id.clone(),
+ if cancellation.prev_event_id == cancellation.event_id {
+ issues.push(RadrootsOrderIssue::CancellationPreviousMismatch {
+ event_id: cancellation.event_id.clone(),
});
valid = false;
}
valid
}
-fn validate_order_revision_decision_record(
- request: &RadrootsOrderRequestRecord,
- decision: &RadrootsOrderRevisionDecisionRecord,
- issues: &mut Vec<RadrootsOrderIssue>,
-) -> bool {
- let mut valid = true;
- if decision.payload.validate().is_err() {
- issues.push(RadrootsOrderIssue::RevisionDecisionPayloadInvalid {
- event_id: decision.event_id.clone(),
- });
- valid = false;
- }
- if decision.payload.order_id != request.payload.order_id {
- issues.push(RadrootsOrderIssue::RevisionDecisionOrderIdMismatch {
- event_id: decision.event_id.clone(),
- });
- valid = false;
- }
- if decision.author_pubkey != decision.payload.buyer_pubkey {
- issues.push(RadrootsOrderIssue::RevisionDecisionAuthorMismatch {
- event_id: decision.event_id.clone(),
- });
- valid = false;
- }
- if decision.counterparty_pubkey != request.payload.seller_pubkey {
- issues.push(RadrootsOrderIssue::RevisionDecisionCounterpartyMismatch {
- event_id: decision.event_id.clone(),
- });
- valid = false;
- }
- if decision.payload.buyer_pubkey != request.payload.buyer_pubkey {
- issues.push(RadrootsOrderIssue::RevisionDecisionBuyerMismatch {
- event_id: decision.event_id.clone(),
- });
- valid = false;
- }
- if decision.payload.seller_pubkey != request.payload.seller_pubkey {
- issues.push(RadrootsOrderIssue::RevisionDecisionSellerMismatch {
- event_id: decision.event_id.clone(),
- });
- valid = false;
- }
- match parse_public_listing_addr(&decision.payload.listing_addr) {
- Ok(listing_addr) => {
- if decision.payload.listing_addr != request.payload.listing_addr
- || listing_addr.seller_pubkey != decision.payload.seller_pubkey
- {
- issues.push(RadrootsOrderIssue::RevisionDecisionListingMismatch {
- event_id: decision.event_id.clone(),
- });
- valid = false;
- }
- }
- Err(_) => {
- issues.push(RadrootsOrderIssue::RevisionDecisionListingAddressInvalid {
- event_id: decision.event_id.clone(),
- });
- valid = false;
- }
- }
- if decision.root_event_id != request.event_id
- || decision.payload.root_event_id != request.event_id
- {
- issues.push(RadrootsOrderIssue::RevisionDecisionRootMismatch {
- event_id: decision.event_id.clone(),
- });
- valid = false;
- }
- if decision.prev_event_id == decision.event_id
- || decision.payload.prev_event_id != decision.prev_event_id
- {
- issues.push(RadrootsOrderIssue::RevisionDecisionPreviousMismatch {
- event_id: decision.event_id.clone(),
- });
- valid = false;
- }
- valid
-}
-
-fn validate_order_cancellation_record(
- request: &RadrootsOrderRequestRecord,
- cancellation: &RadrootsOrderCancellationRecord,
- issues: &mut Vec<RadrootsOrderIssue>,
-) -> bool {
- let mut valid = true;
- if cancellation.payload.validate().is_err() {
- issues.push(RadrootsOrderIssue::CancellationPayloadInvalid {
- event_id: cancellation.event_id.clone(),
- });
- valid = false;
- }
- if cancellation.payload.order_id != request.payload.order_id {
- issues.push(RadrootsOrderIssue::CancellationOrderIdMismatch {
- event_id: cancellation.event_id.clone(),
- });
- valid = false;
- }
- if cancellation.author_pubkey != cancellation.payload.buyer_pubkey {
- issues.push(RadrootsOrderIssue::CancellationAuthorMismatch {
- event_id: cancellation.event_id.clone(),
- });
- valid = false;
- }
- if cancellation.counterparty_pubkey != request.payload.seller_pubkey {
- issues.push(RadrootsOrderIssue::CancellationCounterpartyMismatch {
- event_id: cancellation.event_id.clone(),
- });
- valid = false;
- }
- if cancellation.payload.buyer_pubkey != request.payload.buyer_pubkey {
- issues.push(RadrootsOrderIssue::CancellationBuyerMismatch {
- event_id: cancellation.event_id.clone(),
- });
- valid = false;
- }
- if cancellation.payload.seller_pubkey != request.payload.seller_pubkey {
- issues.push(RadrootsOrderIssue::CancellationSellerMismatch {
- event_id: cancellation.event_id.clone(),
- });
- valid = false;
- }
- match parse_public_listing_addr(&cancellation.payload.listing_addr) {
- Ok(listing_addr) => {
- if cancellation.payload.listing_addr != request.payload.listing_addr
- || listing_addr.seller_pubkey != cancellation.payload.seller_pubkey
- {
- issues.push(RadrootsOrderIssue::CancellationListingMismatch {
- event_id: cancellation.event_id.clone(),
- });
- valid = false;
- }
- }
- Err(_) => {
- issues.push(RadrootsOrderIssue::CancellationListingAddressInvalid {
- event_id: cancellation.event_id.clone(),
- });
- valid = false;
- }
- }
- if cancellation.root_event_id != request.event_id {
- issues.push(RadrootsOrderIssue::CancellationRootMismatch {
- event_id: cancellation.event_id.clone(),
- });
- valid = false;
- }
- if cancellation.prev_event_id == cancellation.event_id {
- issues.push(RadrootsOrderIssue::CancellationPreviousMismatch {
- event_id: cancellation.event_id.clone(),
- });
- valid = false;
- }
- valid
-}
-
-fn decision_payload_issue(
- decision: &RadrootsOrderDecisionOutcome,
- event_id: &RadrootsEventId,
+fn decision_payload_issue(
+ decision: &RadrootsOrderDecisionOutcome,
+ event_id: &RadrootsEventId,
issues: &mut Vec<RadrootsOrderIssue>,
) -> bool {
match decision {
@@ -2147,18 +1561,6 @@ fn unique_decision_records(
unique_records_by_event_id(decisions, |record| &record.event_id)
}
-fn unique_revision_proposal_records(
- revision_proposals: Vec<RadrootsOrderRevisionProposalRecord>,
-) -> Vec<RadrootsOrderRevisionProposalRecord> {
- unique_records_by_event_id(revision_proposals, |record| &record.event_id)
-}
-
-fn unique_revision_decision_records(
- revision_decisions: Vec<RadrootsOrderRevisionDecisionRecord>,
-) -> Vec<RadrootsOrderRevisionDecisionRecord> {
- unique_records_by_event_id(revision_decisions, |record| &record.event_id)
-}
-
fn unique_cancellation_records(
cancellations: Vec<RadrootsOrderCancellationRecord>,
) -> Vec<RadrootsOrderCancellationRecord> {
@@ -2232,8 +1634,6 @@ where
fn listing_order_ids(
requests: &[RadrootsOrderRequestRecord],
decisions: &[RadrootsOrderDecisionRecord],
- revision_proposals: &[RadrootsOrderRevisionProposalRecord],
- revision_decisions: &[RadrootsOrderRevisionDecisionRecord],
cancellations: &[RadrootsOrderCancellationRecord],
) -> Vec<RadrootsOrderId> {
let mut order_ids = Vec::new();
@@ -2248,16 +1648,6 @@ fn listing_order_ids(
.map(|decision| decision.payload.order_id.clone()),
);
order_ids.extend(
- revision_proposals
- .iter()
- .map(|proposal| proposal.payload.order_id.clone()),
- );
- order_ids.extend(
- revision_decisions
- .iter()
- .map(|decision| decision.payload.order_id.clone()),
- );
- order_ids.extend(
cancellations
.iter()
.map(|cancellation| cancellation.payload.order_id.clone()),
@@ -2386,28 +1776,6 @@ fn projection_issue_event_ids(issues: &[RadrootsOrderIssue]) -> Vec<RadrootsEven
| RadrootsOrderIssue::DecisionMissingInventoryCommitments { event_id }
| RadrootsOrderIssue::DecisionInventoryCommitmentMismatch { event_id }
| RadrootsOrderIssue::DecisionMissingReason { event_id }
- | RadrootsOrderIssue::RevisionProposalPayloadInvalid { event_id }
- | RadrootsOrderIssue::RevisionProposalOrderIdMismatch { event_id }
- | RadrootsOrderIssue::RevisionProposalAuthorMismatch { event_id }
- | RadrootsOrderIssue::RevisionProposalCounterpartyMismatch { event_id }
- | RadrootsOrderIssue::RevisionProposalBuyerMismatch { event_id }
- | RadrootsOrderIssue::RevisionProposalSellerMismatch { event_id }
- | RadrootsOrderIssue::RevisionProposalListingAddressInvalid { event_id }
- | RadrootsOrderIssue::RevisionProposalListingMismatch { event_id }
- | RadrootsOrderIssue::RevisionProposalRootMismatch { event_id }
- | RadrootsOrderIssue::RevisionProposalPreviousMismatch { event_id }
- | RadrootsOrderIssue::RevisionDecisionWithoutProposal { event_id }
- | RadrootsOrderIssue::RevisionDecisionPayloadInvalid { event_id }
- | RadrootsOrderIssue::RevisionDecisionOrderIdMismatch { event_id }
- | RadrootsOrderIssue::RevisionDecisionAuthorMismatch { event_id }
- | RadrootsOrderIssue::RevisionDecisionCounterpartyMismatch { event_id }
- | RadrootsOrderIssue::RevisionDecisionBuyerMismatch { event_id }
- | RadrootsOrderIssue::RevisionDecisionSellerMismatch { event_id }
- | RadrootsOrderIssue::RevisionDecisionListingAddressInvalid { event_id }
- | RadrootsOrderIssue::RevisionDecisionListingMismatch { event_id }
- | RadrootsOrderIssue::RevisionDecisionRootMismatch { event_id }
- | RadrootsOrderIssue::RevisionDecisionPreviousMismatch { event_id }
- | RadrootsOrderIssue::RevisionDecisionRevisionIdMismatch { event_id }
| RadrootsOrderIssue::CancellationWithoutCancellableOrder { event_id }
| RadrootsOrderIssue::CancellationPayloadInvalid { event_id }
| RadrootsOrderIssue::CancellationOrderIdMismatch { event_id }
@@ -2615,49 +1983,27 @@ fn order_issue_rank(issue: &RadrootsOrderIssue) -> u8 {
RadrootsOrderIssue::DecisionInventoryCommitmentMismatch { .. } => 18,
RadrootsOrderIssue::DecisionMissingReason { .. } => 19,
RadrootsOrderIssue::ConflictingDecisions { .. } => 20,
- RadrootsOrderIssue::RevisionProposalPayloadInvalid { .. } => 21,
- RadrootsOrderIssue::RevisionProposalOrderIdMismatch { .. } => 22,
- RadrootsOrderIssue::RevisionProposalAuthorMismatch { .. } => 23,
- RadrootsOrderIssue::RevisionProposalCounterpartyMismatch { .. } => 24,
- RadrootsOrderIssue::RevisionProposalBuyerMismatch { .. } => 25,
- RadrootsOrderIssue::RevisionProposalSellerMismatch { .. } => 26,
- RadrootsOrderIssue::RevisionProposalListingAddressInvalid { .. } => 27,
- RadrootsOrderIssue::RevisionProposalListingMismatch { .. } => 28,
- RadrootsOrderIssue::RevisionProposalRootMismatch { .. } => 29,
- RadrootsOrderIssue::RevisionProposalPreviousMismatch { .. } => 30,
- RadrootsOrderIssue::RevisionDecisionWithoutProposal { .. } => 31,
- RadrootsOrderIssue::RevisionDecisionPayloadInvalid { .. } => 32,
- RadrootsOrderIssue::RevisionDecisionOrderIdMismatch { .. } => 33,
- RadrootsOrderIssue::RevisionDecisionAuthorMismatch { .. } => 34,
- RadrootsOrderIssue::RevisionDecisionCounterpartyMismatch { .. } => 35,
- RadrootsOrderIssue::RevisionDecisionBuyerMismatch { .. } => 36,
- RadrootsOrderIssue::RevisionDecisionSellerMismatch { .. } => 37,
- RadrootsOrderIssue::RevisionDecisionListingAddressInvalid { .. } => 38,
- RadrootsOrderIssue::RevisionDecisionListingMismatch { .. } => 39,
- RadrootsOrderIssue::RevisionDecisionRootMismatch { .. } => 40,
- RadrootsOrderIssue::RevisionDecisionPreviousMismatch { .. } => 41,
- RadrootsOrderIssue::RevisionDecisionRevisionIdMismatch { .. } => 42,
- RadrootsOrderIssue::CancellationWithoutCancellableOrder { .. } => 43,
- RadrootsOrderIssue::CancellationPayloadInvalid { .. } => 44,
- RadrootsOrderIssue::CancellationOrderIdMismatch { .. } => 45,
- RadrootsOrderIssue::CancellationAuthorMismatch { .. } => 46,
- RadrootsOrderIssue::CancellationCounterpartyMismatch { .. } => 47,
- RadrootsOrderIssue::CancellationBuyerMismatch { .. } => 48,
- RadrootsOrderIssue::CancellationSellerMismatch { .. } => 49,
- RadrootsOrderIssue::CancellationListingAddressInvalid { .. } => 50,
- RadrootsOrderIssue::CancellationListingMismatch { .. } => 51,
- RadrootsOrderIssue::CancellationRootMismatch { .. } => 52,
- RadrootsOrderIssue::CancellationPreviousMismatch { .. } => 53,
- RadrootsOrderIssue::ForkedLifecycle { .. } => 54,
- RadrootsOrderIssue::ValidationReceiptWithoutPendingAgreement { .. } => 55,
- RadrootsOrderIssue::ValidationReceiptOrderIdMismatch { .. } => 56,
- RadrootsOrderIssue::ValidationReceiptTypeMismatch { .. } => 57,
- RadrootsOrderIssue::ValidationReceiptRootMismatch { .. } => 58,
- RadrootsOrderIssue::ValidationReceiptTargetMismatch { .. } => 59,
- RadrootsOrderIssue::ValidationReceiptListingMismatch { .. } => 60,
- RadrootsOrderIssue::ConflictingValidationReceipts { .. } => 61,
- RadrootsOrderIssue::DeterministicValidationFailure { .. } => 62,
- RadrootsOrderIssue::StaleListingEvent { .. } => 63,
+ RadrootsOrderIssue::CancellationWithoutCancellableOrder { .. } => 21,
+ RadrootsOrderIssue::CancellationPayloadInvalid { .. } => 22,
+ RadrootsOrderIssue::CancellationOrderIdMismatch { .. } => 23,
+ RadrootsOrderIssue::CancellationAuthorMismatch { .. } => 24,
+ RadrootsOrderIssue::CancellationCounterpartyMismatch { .. } => 25,
+ RadrootsOrderIssue::CancellationBuyerMismatch { .. } => 26,
+ RadrootsOrderIssue::CancellationSellerMismatch { .. } => 27,
+ RadrootsOrderIssue::CancellationListingAddressInvalid { .. } => 28,
+ RadrootsOrderIssue::CancellationListingMismatch { .. } => 29,
+ RadrootsOrderIssue::CancellationRootMismatch { .. } => 30,
+ RadrootsOrderIssue::CancellationPreviousMismatch { .. } => 31,
+ RadrootsOrderIssue::ForkedLifecycle { .. } => 32,
+ RadrootsOrderIssue::ValidationReceiptWithoutPendingAgreement { .. } => 33,
+ RadrootsOrderIssue::ValidationReceiptOrderIdMismatch { .. } => 34,
+ RadrootsOrderIssue::ValidationReceiptTypeMismatch { .. } => 35,
+ RadrootsOrderIssue::ValidationReceiptRootMismatch { .. } => 36,
+ RadrootsOrderIssue::ValidationReceiptTargetMismatch { .. } => 37,
+ RadrootsOrderIssue::ValidationReceiptListingMismatch { .. } => 38,
+ RadrootsOrderIssue::ConflictingValidationReceipts { .. } => 39,
+ RadrootsOrderIssue::DeterministicValidationFailure { .. } => 40,
+ RadrootsOrderIssue::StaleListingEvent { .. } => 41,
}
}
@@ -2668,12 +2014,10 @@ mod tests {
RadrootsListingInventoryAccountingInputs, RadrootsListingInventoryAccountingIssue,
RadrootsListingInventoryBinAvailability, RadrootsOrderCancellationRecord,
RadrootsOrderDecisionRecord, RadrootsOrderEventRecord, RadrootsOrderIssue,
- RadrootsOrderReductionInputs, RadrootsOrderRequestRecord,
- RadrootsOrderRevisionDecisionRecord, RadrootsOrderRevisionProposalRecord,
- RadrootsOrderWorkflowProjection, RadrootsTradeLocatorProjectionResolution,
- RadrootsTradeWorkflowState, reduce_listing_inventory_accounting,
- reduce_order_event_records, reduce_order_event_records_for_trade_locator,
- reduce_order_events,
+ RadrootsOrderReductionInputs, RadrootsOrderRequestRecord, RadrootsOrderWorkflowProjection,
+ RadrootsTradeLocatorProjectionResolution, RadrootsTradeWorkflowState,
+ reduce_listing_inventory_accounting, reduce_order_event_records,
+ reduce_order_event_records_for_trade_locator, reduce_order_events,
};
use crate::identity::{RadrootsTradeLocator, RadrootsTradeLocatorCandidate};
use core::mem::discriminant;
@@ -2684,22 +2028,19 @@ mod tests {
RadrootsEventEnvelope, RadrootsEventEnvelopeParts, RadrootsEventPtr,
ids::{
RadrootsEventId, RadrootsInventoryBinId, RadrootsListingAddress, RadrootsOrderId,
- RadrootsOrderQuoteId, RadrootsOrderRevisionId, RadrootsPublicKey,
+ RadrootsOrderQuoteId, RadrootsPublicKey,
},
- kinds::{KIND_LISTING, KIND_LISTING_DRAFT},
+ kinds::KIND_LISTING,
order::{
RadrootsOrderCancellation, RadrootsOrderDecision, RadrootsOrderDecisionOutcome,
RadrootsOrderEconomicItem, RadrootsOrderEconomics, RadrootsOrderInventoryCommitment,
RadrootsOrderItem, RadrootsOrderPricingBasis, RadrootsOrderRequest,
- RadrootsOrderRevisionDecision, RadrootsOrderRevisionOutcome,
- RadrootsOrderRevisionProposal,
},
wire::RadrootsNip01EventWireParts,
};
#[cfg(feature = "serde_json")]
use radroots_event_codec::order::{
order_cancellation_event_build, order_decision_event_build, order_request_event_build,
- order_revision_decision_event_build, order_revision_proposal_event_build,
};
const BUYER: &str = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
@@ -2718,10 +2059,6 @@ mod tests {
RadrootsOrderId::parse(raw).expect("order id")
}
- fn revision_id(raw: &str) -> RadrootsOrderRevisionId {
- RadrootsOrderRevisionId::parse(raw).expect("revision id")
- }
-
fn quote_id(raw: &str) -> RadrootsOrderQuoteId {
RadrootsOrderQuoteId::parse(raw).expect("quote id")
}
@@ -2735,18 +2072,16 @@ mod tests {
.expect("listing address")
}
- fn draft_listing_addr() -> RadrootsListingAddress {
- RadrootsListingAddress::parse(format!(
- "{KIND_LISTING_DRAFT}:{SELLER}:AAAAAAAAAAAAAAAAAAAAAg"
- ))
- .expect("draft listing address")
- }
-
fn other_seller_listing_addr() -> RadrootsListingAddress {
RadrootsListingAddress::parse(format!("{KIND_LISTING}:{OTHER}:AAAAAAAAAAAAAAAAAAAAAg"))
.expect("other seller listing address")
}
+ fn retired_listing_addr() -> RadrootsListingAddress {
+ RadrootsListingAddress::parse(format!("30403:{SELLER}:AAAAAAAAAAAAAAAAAAAAAg"))
+ .expect("retired listing address")
+ }
+
#[cfg(feature = "serde_json")]
fn listing_event_ptr() -> RadrootsEventPtr {
RadrootsEventPtr {
@@ -2867,51 +2202,6 @@ mod tests {
}
}
- fn revision_proposal() -> RadrootsOrderRevisionProposalRecord {
- RadrootsOrderRevisionProposalRecord {
- event_id: event_id(3),
- author_pubkey: public_key(SELLER),
- counterparty_pubkey: public_key(BUYER),
- root_event_id: event_id(1),
- prev_event_id: event_id(1),
- payload: RadrootsOrderRevisionProposal {
- revision_id: revision_id("revision-1"),
- order_id: order_id("order-1"),
- listing_addr: listing_addr(),
- buyer_pubkey: public_key(BUYER),
- seller_pubkey: public_key(SELLER),
- root_event_id: event_id(1),
- prev_event_id: event_id(1),
- items: vec![RadrootsOrderItem {
- bin_id: bin_id("bin-1"),
- bin_count: 1,
- }],
- economics: economics(1),
- reason: "one bin remains".into(),
- },
- }
- }
-
- fn accepted_revision_decision() -> RadrootsOrderRevisionDecisionRecord {
- RadrootsOrderRevisionDecisionRecord {
- event_id: event_id(4),
- author_pubkey: public_key(BUYER),
- counterparty_pubkey: public_key(SELLER),
- root_event_id: event_id(1),
- prev_event_id: event_id(3),
- payload: RadrootsOrderRevisionDecision {
- revision_id: revision_id("revision-1"),
- order_id: order_id("order-1"),
- listing_addr: listing_addr(),
- buyer_pubkey: public_key(BUYER),
- seller_pubkey: public_key(SELLER),
- root_event_id: event_id(1),
- prev_event_id: event_id(3),
- decision: RadrootsOrderRevisionOutcome::Accepted,
- },
- }
- }
-
fn cancellation(prev_event_id: RadrootsEventId) -> RadrootsOrderCancellationRecord {
RadrootsOrderCancellationRecord {
event_id: event_id(5),
@@ -2983,38 +2273,6 @@ mod tests {
assert_order_issue_kind(&issues, expected);
}
- fn assert_revision_proposal_issue(
- mutate: impl FnOnce(&mut RadrootsOrderRevisionProposalRecord),
- expected: RadrootsOrderIssue,
- ) {
- let request = request_record();
- let mut proposal = revision_proposal();
- mutate(&mut proposal);
- let mut issues = Vec::new();
- assert!(!super::validate_order_revision_proposal_record(
- &request,
- &proposal,
- &mut issues
- ));
- assert_order_issue_kind(&issues, expected);
- }
-
- fn assert_revision_decision_issue(
- mutate: impl FnOnce(&mut RadrootsOrderRevisionDecisionRecord),
- expected: RadrootsOrderIssue,
- ) {
- let request = request_record();
- let mut decision = accepted_revision_decision();
- mutate(&mut decision);
- let mut issues = Vec::new();
- assert!(!super::validate_order_revision_decision_record(
- &request,
- &decision,
- &mut issues
- ));
- assert_order_issue_kind(&issues, expected);
- }
-
fn assert_cancellation_issue(
mutate: impl FnOnce(&mut RadrootsOrderCancellationRecord),
expected: RadrootsOrderIssue,
@@ -3033,8 +2291,6 @@ mod tests {
fn reduce(
decisions: Vec<RadrootsOrderDecisionRecord>,
- revision_proposals: Vec<RadrootsOrderRevisionProposalRecord>,
- revision_decisions: Vec<RadrootsOrderRevisionDecisionRecord>,
cancellations: Vec<RadrootsOrderCancellationRecord>,
) -> super::RadrootsOrderProjection {
reduce_order_events(
@@ -3042,8 +2298,6 @@ mod tests {
RadrootsOrderReductionInputs {
requests: vec![request_record()],
decisions,
- revision_proposals,
- revision_decisions,
cancellations,
},
)
@@ -3054,8 +2308,6 @@ mod tests {
let records = [
RadrootsOrderEventRecord::Request(request_record()),
RadrootsOrderEventRecord::Decision(accepted_decision()),
- RadrootsOrderEventRecord::RevisionProposal(revision_proposal()),
- RadrootsOrderEventRecord::RevisionDecision(accepted_revision_decision()),
RadrootsOrderEventRecord::Cancellation(cancellation(event_id(1))),
];
@@ -3070,17 +2322,8 @@ mod tests {
.cloned()
.collect::<Vec<_>>();
- assert_eq!(
- event_ids,
- vec![
- event_id(1),
- event_id(2),
- event_id(3),
- event_id(4),
- event_id(5)
- ]
- );
- assert_eq!(order_ids, vec![order_id("order-1"); 5]);
+ assert_eq!(event_ids, vec![event_id(1), event_id(2), event_id(5)]);
+ assert_eq!(order_ids, vec![order_id("order-1"); 3]);
}
#[test]
@@ -3148,18 +2391,6 @@ mod tests {
second_decision.event_id = event_id(10);
second_decision.root_event_id = event_id(9);
second_decision.prev_event_id = event_id(9);
- let mut second_proposal = revision_proposal();
- second_proposal.event_id = event_id(11);
- second_proposal.root_event_id = event_id(9);
- second_proposal.prev_event_id = event_id(9);
- second_proposal.payload.root_event_id = event_id(9);
- second_proposal.payload.prev_event_id = event_id(9);
- let mut second_revision_decision = accepted_revision_decision();
- second_revision_decision.event_id = event_id(12);
- second_revision_decision.root_event_id = event_id(9);
- second_revision_decision.prev_event_id = event_id(11);
- second_revision_decision.payload.root_event_id = event_id(9);
- second_revision_decision.payload.prev_event_id = event_id(11);
let mut second_cancellation = cancellation(event_id(10));
second_cancellation.event_id = event_id(13);
second_cancellation.root_event_id = event_id(9);
@@ -3169,12 +2400,6 @@ mod tests {
let mut wrong_order_decision = accepted_decision();
wrong_order_decision.event_id = event_id(15);
wrong_order_decision.payload.order_id = order_id("order-2");
- let mut wrong_order_proposal = revision_proposal();
- wrong_order_proposal.event_id = event_id(16);
- wrong_order_proposal.payload.order_id = order_id("order-2");
- let mut wrong_order_revision_decision = accepted_revision_decision();
- wrong_order_revision_decision.event_id = event_id(17);
- wrong_order_revision_decision.payload.order_id = order_id("order-2");
let mut wrong_order_cancellation = cancellation(event_id(2));
wrong_order_cancellation.event_id = event_id(18);
wrong_order_cancellation.payload.order_id = order_id("order-2");
@@ -3190,12 +2415,6 @@ mod tests {
RadrootsOrderEventRecord::Decision(accepted_decision()),
RadrootsOrderEventRecord::Decision(second_decision),
RadrootsOrderEventRecord::Decision(wrong_order_decision),
- RadrootsOrderEventRecord::RevisionProposal(revision_proposal()),
- RadrootsOrderEventRecord::RevisionProposal(second_proposal),
- RadrootsOrderEventRecord::RevisionProposal(wrong_order_proposal),
- RadrootsOrderEventRecord::RevisionDecision(accepted_revision_decision()),
- RadrootsOrderEventRecord::RevisionDecision(second_revision_decision),
- RadrootsOrderEventRecord::RevisionDecision(wrong_order_revision_decision),
RadrootsOrderEventRecord::Cancellation(cancellation(event_id(2))),
RadrootsOrderEventRecord::Cancellation(second_cancellation),
RadrootsOrderEventRecord::Cancellation(wrong_order_cancellation),
@@ -3317,45 +2536,6 @@ mod tests {
&& record.prev_event_id == event_id(1)
));
- let proposal = revision_proposal();
- let proposal_parts = order_revision_proposal_event_build(
- &proposal.root_event_id,
- &proposal.prev_event_id,
- &proposal.payload,
- )
- .unwrap();
- let proposal_record =
- super::order_event_record_from_event(&event_from_parts(13, SELLER, proposal_parts))
- .unwrap();
- assert!(matches!(
- proposal_record,
- RadrootsOrderEventRecord::RevisionProposal(record)
- if record.event_id == event_id(13)
- && record.counterparty_pubkey == public_key(BUYER)
- && record.payload.revision_id == revision_id("revision-1")
- ));
-
- let revision_decision = accepted_revision_decision();
- let revision_decision_parts = order_revision_decision_event_build(
- &revision_decision.root_event_id,
- &revision_decision.prev_event_id,
- &revision_decision.payload,
- )
- .unwrap();
- let revision_decision_record = super::order_event_record_from_event(&event_from_parts(
- 14,
- BUYER,
- revision_decision_parts,
- ))
- .unwrap();
- assert!(matches!(
- revision_decision_record,
- RadrootsOrderEventRecord::RevisionDecision(record)
- if record.event_id == event_id(14)
- && record.counterparty_pubkey == public_key(SELLER)
- && record.payload.revision_id == revision_id("revision-1")
- ));
-
let cancellation = cancellation(event_id(1));
let cancellation_parts = order_cancellation_event_build(
&cancellation.root_event_id,
@@ -3418,8 +2598,6 @@ mod tests {
&order_id("order-1"),
vec![
RadrootsOrderEventRecord::Cancellation(cancellation(event_id(1))),
- RadrootsOrderEventRecord::RevisionDecision(accepted_revision_decision()),
- RadrootsOrderEventRecord::RevisionProposal(revision_proposal()),
RadrootsOrderEventRecord::Decision(accepted_decision()),
RadrootsOrderEventRecord::Decision(duplicate_decision),
RadrootsOrderEventRecord::Request(request_record()),
@@ -3435,7 +2613,7 @@ mod tests {
);
assert_eq!(
super::projection_issue_event_ids(&projection.issues),
- vec![event_id(2), event_id(4), event_id(5)]
+ vec![event_id(2), event_id(5)]
);
let mut duplicate_request = request_record();
@@ -3464,8 +2642,6 @@ mod tests {
RadrootsOrderReductionInputs {
requests: vec![request_record(), duplicate_request],
decisions: Vec::<RadrootsOrderDecisionRecord>::new(),
- revision_proposals: Vec::<RadrootsOrderRevisionProposalRecord>::new(),
- revision_decisions: Vec::<RadrootsOrderRevisionDecisionRecord>::new(),
cancellations: Vec::<RadrootsOrderCancellationRecord>::new(),
},
);
@@ -3478,41 +2654,11 @@ mod tests {
RadrootsOrderReductionInputs {
requests: vec![request_record()],
decisions: vec![accepted_decision(), duplicate_decision],
- revision_proposals: Vec::<RadrootsOrderRevisionProposalRecord>::new(),
- revision_decisions: Vec::<RadrootsOrderRevisionDecisionRecord>::new(),
cancellations: Vec::<RadrootsOrderCancellationRecord>::new(),
},
);
assert_eq!(decided.decision_event_id, Some(event_id(2)));
- let mut duplicate_proposal = revision_proposal();
- duplicate_proposal.payload.order_id = order_id("order-duplicate-proposal");
- let proposed = reduce_order_events(
- &order_id("order-1"),
- RadrootsOrderReductionInputs {
- requests: vec![request_record()],
- decisions: Vec::<RadrootsOrderDecisionRecord>::new(),
- revision_proposals: vec![revision_proposal(), duplicate_proposal],
- revision_decisions: Vec::<RadrootsOrderRevisionDecisionRecord>::new(),
- cancellations: Vec::<RadrootsOrderCancellationRecord>::new(),
- },
- );
- assert_eq!(proposed.pending_revision_event_id, Some(event_id(3)));
-
- let mut duplicate_revision_decision = accepted_revision_decision();
- duplicate_revision_decision.payload.order_id = order_id("order-duplicate-revision");
- let revision_decided = reduce_order_events(
- &order_id("order-1"),
- RadrootsOrderReductionInputs {
- requests: vec![request_record()],
- decisions: Vec::<RadrootsOrderDecisionRecord>::new(),
- revision_proposals: vec![revision_proposal()],
- revision_decisions: vec![accepted_revision_decision(), duplicate_revision_decision],
- cancellations: Vec::<RadrootsOrderCancellationRecord>::new(),
- },
- );
- assert_eq!(revision_decided.agreement_event_id, Some(event_id(4)));
-
let mut duplicate_cancellation = cancellation(event_id(1));
duplicate_cancellation.payload.order_id = order_id("order-duplicate-cancellation");
let cancelled = reduce_order_events(
@@ -3520,8 +2666,6 @@ mod tests {
RadrootsOrderReductionInputs {
requests: vec![request_record()],
decisions: Vec::<RadrootsOrderDecisionRecord>::new(),
- revision_proposals: Vec::<RadrootsOrderRevisionProposalRecord>::new(),
- revision_decisions: Vec::<RadrootsOrderRevisionDecisionRecord>::new(),
cancellations: vec![cancellation(event_id(1)), duplicate_cancellation],
},
);
@@ -3550,9 +2694,7 @@ mod tests {
Err(super::RadrootsOrderCanonicalizationError::InvalidListingAddress(_))
));
assert!(matches!(
- super::parse_public_listing_addr(format!(
- "{KIND_LISTING_DRAFT}:{SELLER}:AAAAAAAAAAAAAAAAAAAAAg"
- )),
+ super::parse_public_listing_addr(format!("30403:{SELLER}:AAAAAAAAAAAAAAAAAAAAAg")),
Err(super::RadrootsOrderCanonicalizationError::InvalidListingKind)
));
assert!(matches!(
@@ -3573,7 +2715,9 @@ mod tests {
));
let mut invalid_kind = request_record().payload;
- invalid_kind.listing_addr = draft_listing_addr();
+ invalid_kind.listing_addr =
+ RadrootsListingAddress::parse(format!("30403:{SELLER}:AAAAAAAAAAAAAAAAAAAAAg"))
+ .expect("retired listing draft address");
assert!(matches!(
super::canonicalize_order_request_for_signer(invalid_kind, BUYER),
Err(super::RadrootsOrderCanonicalizationError::InvalidListingKind)
@@ -3922,128 +3066,62 @@ mod tests {
RadrootsOrderIssue::ConflictingDecisions {
event_ids: event_ids.clone(),
},
- RadrootsOrderIssue::RevisionProposalPayloadInvalid {
+ RadrootsOrderIssue::CancellationWithoutCancellableOrder {
event_id: id.clone(),
},
- RadrootsOrderIssue::RevisionProposalOrderIdMismatch {
+ RadrootsOrderIssue::CancellationPayloadInvalid {
event_id: id.clone(),
},
- RadrootsOrderIssue::RevisionProposalAuthorMismatch {
+ RadrootsOrderIssue::CancellationOrderIdMismatch {
event_id: id.clone(),
},
- RadrootsOrderIssue::RevisionProposalCounterpartyMismatch {
+ RadrootsOrderIssue::CancellationAuthorMismatch {
event_id: id.clone(),
},
- RadrootsOrderIssue::RevisionProposalBuyerMismatch {
+ RadrootsOrderIssue::CancellationCounterpartyMismatch {
event_id: id.clone(),
},
- RadrootsOrderIssue::RevisionProposalSellerMismatch {
+ RadrootsOrderIssue::CancellationBuyerMismatch {
event_id: id.clone(),
},
- RadrootsOrderIssue::RevisionProposalListingAddressInvalid {
+ RadrootsOrderIssue::CancellationSellerMismatch {
event_id: id.clone(),
},
- RadrootsOrderIssue::RevisionProposalListingMismatch {
+ RadrootsOrderIssue::CancellationListingAddressInvalid {
event_id: id.clone(),
},
- RadrootsOrderIssue::RevisionProposalRootMismatch {
+ RadrootsOrderIssue::CancellationListingMismatch {
event_id: id.clone(),
},
- RadrootsOrderIssue::RevisionProposalPreviousMismatch {
+ RadrootsOrderIssue::CancellationRootMismatch {
event_id: id.clone(),
},
- RadrootsOrderIssue::RevisionDecisionWithoutProposal {
+ RadrootsOrderIssue::CancellationPreviousMismatch {
event_id: id.clone(),
},
- RadrootsOrderIssue::RevisionDecisionPayloadInvalid {
- event_id: id.clone(),
+ RadrootsOrderIssue::ForkedLifecycle {
+ event_ids: event_ids.clone(),
},
- RadrootsOrderIssue::RevisionDecisionOrderIdMismatch {
+ RadrootsOrderIssue::ValidationReceiptWithoutPendingAgreement {
event_id: id.clone(),
},
- RadrootsOrderIssue::RevisionDecisionAuthorMismatch {
+ RadrootsOrderIssue::ValidationReceiptOrderIdMismatch {
event_id: id.clone(),
},
- RadrootsOrderIssue::RevisionDecisionCounterpartyMismatch {
+ RadrootsOrderIssue::ValidationReceiptTypeMismatch {
event_id: id.clone(),
},
- RadrootsOrderIssue::RevisionDecisionBuyerMismatch {
+ RadrootsOrderIssue::ValidationReceiptRootMismatch {
event_id: id.clone(),
},
- RadrootsOrderIssue::RevisionDecisionSellerMismatch {
+ RadrootsOrderIssue::ValidationReceiptTargetMismatch {
event_id: id.clone(),
},
- RadrootsOrderIssue::RevisionDecisionListingAddressInvalid {
+ RadrootsOrderIssue::ValidationReceiptListingMismatch {
event_id: id.clone(),
},
- RadrootsOrderIssue::RevisionDecisionListingMismatch {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::RevisionDecisionRootMismatch {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::RevisionDecisionPreviousMismatch {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::RevisionDecisionRevisionIdMismatch {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::CancellationWithoutCancellableOrder {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::CancellationPayloadInvalid {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::CancellationOrderIdMismatch {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::CancellationAuthorMismatch {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::CancellationCounterpartyMismatch {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::CancellationBuyerMismatch {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::CancellationSellerMismatch {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::CancellationListingAddressInvalid {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::CancellationListingMismatch {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::CancellationRootMismatch {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::CancellationPreviousMismatch {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::ForkedLifecycle {
- event_ids: event_ids.clone(),
- },
- RadrootsOrderIssue::ValidationReceiptWithoutPendingAgreement {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::ValidationReceiptOrderIdMismatch {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::ValidationReceiptTypeMismatch {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::ValidationReceiptRootMismatch {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::ValidationReceiptTargetMismatch {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::ValidationReceiptListingMismatch {
- event_id: id.clone(),
- },
- RadrootsOrderIssue::ConflictingValidationReceipts {
- event_ids: event_ids.clone(),
+ RadrootsOrderIssue::ConflictingValidationReceipts {
+ event_ids: event_ids.clone(),
},
RadrootsOrderIssue::DeterministicValidationFailure {
event_id: id.clone(),
@@ -4073,7 +3151,6 @@ mod tests {
lifecycle_terminal: true,
economics: None,
agreement_event_id: None,
- pending_revision_event_id: None,
pending_inventory_reservations: Vec::new(),
committed_inventory_reservations: Vec::new(),
listing_addr: None,
@@ -4135,47 +3212,16 @@ mod tests {
RadrootsOrderReductionInputs {
requests: Vec::<RadrootsOrderRequestRecord>::new(),
decisions: vec![accepted_decision()],
- revision_proposals: Vec::<RadrootsOrderRevisionProposalRecord>::new(),
- revision_decisions: Vec::<RadrootsOrderRevisionDecisionRecord>::new(),
cancellations: Vec::<RadrootsOrderCancellationRecord>::new(),
},
);
assert_order_issue_kind(&decision_only.issues, RadrootsOrderIssue::MissingRequest);
- let proposal_only = reduce_order_events(
- &order_id("order-1"),
- RadrootsOrderReductionInputs {
- requests: Vec::<RadrootsOrderRequestRecord>::new(),
- decisions: Vec::<RadrootsOrderDecisionRecord>::new(),
- revision_proposals: vec![revision_proposal()],
- revision_decisions: Vec::<RadrootsOrderRevisionDecisionRecord>::new(),
- cancellations: Vec::<RadrootsOrderCancellationRecord>::new(),
- },
- );
- assert_order_issue_kind(&proposal_only.issues, RadrootsOrderIssue::MissingRequest);
-
- let revision_decision_only = reduce_order_events(
- &order_id("order-1"),
- RadrootsOrderReductionInputs {
- requests: Vec::<RadrootsOrderRequestRecord>::new(),
- decisions: Vec::<RadrootsOrderDecisionRecord>::new(),
- revision_proposals: Vec::<RadrootsOrderRevisionProposalRecord>::new(),
- revision_decisions: vec![accepted_revision_decision()],
- cancellations: Vec::<RadrootsOrderCancellationRecord>::new(),
- },
- );
- assert_order_issue_kind(
- &revision_decision_only.issues,
- RadrootsOrderIssue::MissingRequest,
- );
-
let cancellation_only = reduce_order_events(
&order_id("order-1"),
RadrootsOrderReductionInputs {
requests: Vec::<RadrootsOrderRequestRecord>::new(),
decisions: Vec::<RadrootsOrderDecisionRecord>::new(),
- revision_proposals: Vec::<RadrootsOrderRevisionProposalRecord>::new(),
- revision_decisions: Vec::<RadrootsOrderRevisionDecisionRecord>::new(),
cancellations: vec![cancellation(event_id(1))],
},
);
@@ -4191,8 +3237,6 @@ mod tests {
second_cancellation.event_id = event_id(6);
let projection = reduce(
Vec::new(),
- Vec::new(),
- Vec::new(),
vec![cancellation(event_id(1)), second_cancellation],
);
@@ -4323,29 +3367,14 @@ mod tests {
fallback_request.event_id = event_id(95);
let mut fallback_decision = accepted_decision();
fallback_decision.event_id = event_id(93);
- let mut fallback_proposal = revision_proposal();
- fallback_proposal.event_id = event_id(94);
- let mut fallback_revision_decision = accepted_revision_decision();
- fallback_revision_decision.event_id = event_id(92);
let mut fallback_cancellation = cancellation(event_id(3));
fallback_cancellation.event_id = event_id(91);
let fallback_ids = super::fallback_order_event_ids(
&[fallback_request],
&[fallback_decision],
- &[fallback_proposal],
- &[fallback_revision_decision],
&[fallback_cancellation],
);
- assert_eq!(
- fallback_ids,
- vec![
- event_id(91),
- event_id(92),
- event_id(93),
- event_id(94),
- event_id(95)
- ]
- );
+ assert_eq!(fallback_ids, vec![event_id(91), event_id(93), event_id(95)]);
}
#[test]
@@ -4355,8 +3384,6 @@ mod tests {
RadrootsOrderReductionInputs {
requests: Vec::<RadrootsOrderRequestRecord>::new(),
decisions: Vec::<RadrootsOrderDecisionRecord>::new(),
- revision_proposals: Vec::<RadrootsOrderRevisionProposalRecord>::new(),
- revision_decisions: Vec::<RadrootsOrderRevisionDecisionRecord>::new(),
cancellations: Vec::<RadrootsOrderCancellationRecord>::new(),
},
);
@@ -4367,8 +3394,6 @@ mod tests {
RadrootsOrderReductionInputs {
requests: Vec::<RadrootsOrderRequestRecord>::new(),
decisions: vec![accepted_decision()],
- revision_proposals: Vec::<RadrootsOrderRevisionProposalRecord>::new(),
- revision_decisions: Vec::<RadrootsOrderRevisionDecisionRecord>::new(),
cancellations: Vec::<RadrootsOrderCancellationRecord>::new(),
},
);
@@ -4381,8 +3406,6 @@ mod tests {
RadrootsOrderReductionInputs {
requests: vec![request_record(), duplicate_request],
decisions: Vec::<RadrootsOrderDecisionRecord>::new(),
- revision_proposals: Vec::<RadrootsOrderRevisionProposalRecord>::new(),
- revision_decisions: Vec::<RadrootsOrderRevisionDecisionRecord>::new(),
cancellations: Vec::<RadrootsOrderCancellationRecord>::new(),
},
);
@@ -4395,176 +3418,19 @@ mod tests {
let mut second_decision = declined_decision();
second_decision.event_id = event_id(6);
- let conflicting = reduce(
- vec![accepted_decision(), second_decision],
- vec![],
- vec![],
- vec![],
- );
+ let conflicting = reduce(vec![accepted_decision(), second_decision], vec![]);
assert_order_issue_kind(
&conflicting.issues,
RadrootsOrderIssue::ConflictingDecisions {
event_ids: Vec::new(),
},
);
-
- let without_proposal = reduce(
- Vec::new(),
- Vec::new(),
- vec![accepted_revision_decision()],
- Vec::new(),
- );
- assert_order_issue_kind(
- &without_proposal.issues,
- RadrootsOrderIssue::RevisionDecisionWithoutProposal {
- event_id: event_id(4),
- },
- );
-
- let mut second_proposal = revision_proposal();
- second_proposal.event_id = event_id(6);
- let multiple_proposals = reduce(
- Vec::new(),
- vec![revision_proposal(), second_proposal],
- vec![],
- vec![],
- );
- assert_order_issue_kind(
- &multiple_proposals.issues,
- RadrootsOrderIssue::ForkedLifecycle {
- event_ids: Vec::new(),
- },
- );
-
- let mut second_revision_decision = accepted_revision_decision();
- second_revision_decision.event_id = event_id(7);
- let multiple_revision_decisions = reduce(
- Vec::new(),
- vec![revision_proposal()],
- vec![accepted_revision_decision(), second_revision_decision],
- Vec::new(),
- );
- assert_order_issue_kind(
- &multiple_revision_decisions.issues,
- RadrootsOrderIssue::ForkedLifecycle {
- event_ids: Vec::new(),
- },
- );
-
- let decided_then_revised = reduce(
- vec![accepted_decision()],
- vec![revision_proposal()],
- Vec::new(),
- Vec::new(),
- );
- assert_order_issue_kind(
- &decided_then_revised.issues,
- RadrootsOrderIssue::ForkedLifecycle {
- event_ids: Vec::new(),
- },
- );
-
- let decided_then_revision_decision = reduce(
- vec![accepted_decision()],
- Vec::new(),
- vec![accepted_revision_decision()],
- Vec::new(),
- );
- assert_order_issue_kind(
- &decided_then_revision_decision.issues,
- RadrootsOrderIssue::ForkedLifecycle {
- event_ids: Vec::new(),
- },
- );
}
#[test]
- fn reducer_covers_revision_and_cancellation_edge_paths() {
- let pending_revision = reduce(
- Vec::new(),
- vec![revision_proposal()],
- Vec::new(),
- Vec::new(),
- );
- assert_eq!(
- pending_revision.status,
- RadrootsTradeWorkflowState::Requested
- );
- assert_eq!(
- pending_revision.pending_revision_event_id,
- Some(event_id(3))
- );
- assert_eq!(
- pending_revision.economics.expect("pending economics").items[0].bin_count,
- 1
- );
-
- let mut bad_proposal_previous = revision_proposal();
- bad_proposal_previous.prev_event_id = event_id(8);
- bad_proposal_previous.payload.prev_event_id = event_id(8);
- let bad_proposal = reduce(
- Vec::new(),
- vec![bad_proposal_previous],
- Vec::new(),
- Vec::new(),
- );
- assert_order_issue_kind(
- &bad_proposal.issues,
- RadrootsOrderIssue::RevisionProposalPreviousMismatch {
- event_id: event_id(3),
- },
- );
-
- let mut bad_decision_previous = accepted_revision_decision();
- bad_decision_previous.prev_event_id = event_id(8);
- bad_decision_previous.payload.prev_event_id = event_id(8);
- let bad_decision = reduce(
- Vec::new(),
- vec![revision_proposal()],
- vec![bad_decision_previous],
- Vec::new(),
- );
- assert_order_issue_kind(
- &bad_decision.issues,
- RadrootsOrderIssue::RevisionDecisionPreviousMismatch {
- event_id: event_id(4),
- },
- );
-
- let mut bad_revision_id = accepted_revision_decision();
- bad_revision_id.payload.revision_id = revision_id("revision-2");
- let bad_revision = reduce(
- Vec::new(),
- vec![revision_proposal()],
- vec![bad_revision_id],
- Vec::new(),
- );
- assert_order_issue_kind(
- &bad_revision.issues,
- RadrootsOrderIssue::RevisionDecisionRevisionIdMismatch {
- event_id: event_id(4),
- },
- );
-
- let mut declined_revision = accepted_revision_decision();
- declined_revision.payload.decision = RadrootsOrderRevisionOutcome::Declined {
- reason: "too late".into(),
- };
- let declined = reduce(
- Vec::new(),
- vec![revision_proposal()],
- vec![declined_revision],
- Vec::new(),
- );
- assert_eq!(declined.status, RadrootsTradeWorkflowState::Declined);
- assert_eq!(declined.pending_revision_event_id, Some(event_id(3)));
-
- let cancellation_after_decision = reduce(
- vec![declined_decision()],
- Vec::new(),
- Vec::new(),
- vec![cancellation(event_id(2))],
- );
+ fn reducer_covers_cancellation_edge_paths() {
+ let cancellation_after_decision =
+ reduce(vec![declined_decision()], vec![cancellation(event_id(2))]);
assert_order_issue_kind(
&cancellation_after_decision.issues,
RadrootsOrderIssue::ForkedLifecycle {
@@ -4572,40 +3438,7 @@ mod tests {
},
);
- let cancellation_after_revision_decision = reduce(
- Vec::new(),
- vec![revision_proposal()],
- vec![accepted_revision_decision()],
- vec![cancellation(event_id(4))],
- );
- assert_order_issue_kind(
- &cancellation_after_revision_decision.issues,
- RadrootsOrderIssue::ForkedLifecycle {
- event_ids: Vec::new(),
- },
- );
-
- let mut second_proposal = revision_proposal();
- second_proposal.event_id = event_id(6);
- let cancellation_after_multiple_proposals = reduce(
- Vec::new(),
- vec![revision_proposal(), second_proposal],
- Vec::new(),
- vec![cancellation(event_id(3))],
- );
- assert_order_issue_kind(
- &cancellation_after_multiple_proposals.issues,
- RadrootsOrderIssue::ForkedLifecycle {
- event_ids: Vec::new(),
- },
- );
-
- let cancellation_previous_mismatch = reduce(
- Vec::new(),
- vec![revision_proposal()],
- Vec::new(),
- vec![cancellation(event_id(1))],
- );
+ let cancellation_previous_mismatch = reduce(Vec::new(), vec![cancellation(event_id(8))]);
assert_order_issue_kind(
&cancellation_previous_mismatch.issues,
RadrootsOrderIssue::CancellationPreviousMismatch {
@@ -4635,7 +3468,7 @@ mod tests {
},
);
assert_request_issue(
- |request| request.payload.listing_addr = draft_listing_addr(),
+ |request| request.payload.listing_addr = retired_listing_addr(),
RadrootsOrderIssue::RequestListingAddressInvalid {
event_id: event_id(1),
},
@@ -4697,7 +3530,7 @@ mod tests {
},
);
assert_decision_issue(
- |decision| decision.payload.listing_addr = draft_listing_addr(),
+ |decision| decision.payload.listing_addr = retired_listing_addr(),
RadrootsOrderIssue::DecisionListingAddressInvalid {
event_id: event_id(2),
},
@@ -4736,168 +3569,7 @@ mod tests {
}
#[test]
- fn reducer_validators_report_revision_and_cancellation_issue_kinds() {
- assert_revision_proposal_issue(
- |proposal| proposal.payload.items.clear(),
- RadrootsOrderIssue::RevisionProposalPayloadInvalid {
- event_id: event_id(3),
- },
- );
- assert_revision_proposal_issue(
- |proposal| proposal.payload.order_id = order_id("order-2"),
- RadrootsOrderIssue::RevisionProposalOrderIdMismatch {
- event_id: event_id(3),
- },
- );
- assert_revision_proposal_issue(
- |proposal| proposal.author_pubkey = public_key(BUYER),
- RadrootsOrderIssue::RevisionProposalAuthorMismatch {
- event_id: event_id(3),
- },
- );
- assert_revision_proposal_issue(
- |proposal| proposal.counterparty_pubkey = public_key(SELLER),
- RadrootsOrderIssue::RevisionProposalCounterpartyMismatch {
- event_id: event_id(3),
- },
- );
- assert_revision_proposal_issue(
- |proposal| proposal.payload.buyer_pubkey = public_key(SELLER),
- RadrootsOrderIssue::RevisionProposalBuyerMismatch {
- event_id: event_id(3),
- },
- );
- assert_revision_proposal_issue(
- |proposal| proposal.payload.seller_pubkey = public_key(BUYER),
- RadrootsOrderIssue::RevisionProposalSellerMismatch {
- event_id: event_id(3),
- },
- );
- assert_revision_proposal_issue(
- |proposal| proposal.payload.listing_addr = draft_listing_addr(),
- RadrootsOrderIssue::RevisionProposalListingAddressInvalid {
- event_id: event_id(3),
- },
- );
- assert_revision_proposal_issue(
- |proposal| proposal.payload.listing_addr = other_seller_listing_addr(),
- RadrootsOrderIssue::RevisionProposalListingMismatch {
- event_id: event_id(3),
- },
- );
- assert_revision_proposal_issue(
- |proposal| proposal.root_event_id = event_id(8),
- RadrootsOrderIssue::RevisionProposalRootMismatch {
- event_id: event_id(3),
- },
- );
- assert_revision_proposal_issue(
- |proposal| proposal.payload.root_event_id = event_id(8),
- RadrootsOrderIssue::RevisionProposalRootMismatch {
- event_id: event_id(3),
- },
- );
- assert_revision_proposal_issue(
- |proposal| proposal.prev_event_id = event_id(8),
- RadrootsOrderIssue::RevisionProposalPreviousMismatch {
- event_id: event_id(3),
- },
- );
- assert_revision_proposal_issue(
- |proposal| proposal.prev_event_id = event_id(3),
- RadrootsOrderIssue::RevisionProposalPreviousMismatch {
- event_id: event_id(3),
- },
- );
- assert_revision_proposal_issue(
- |proposal| proposal.payload.prev_event_id = event_id(8),
- RadrootsOrderIssue::RevisionProposalPreviousMismatch {
- event_id: event_id(3),
- },
- );
-
- assert_revision_decision_issue(
- |decision| {
- decision.payload.decision =
- RadrootsOrderRevisionOutcome::Declined { reason: " ".into() };
- },
- RadrootsOrderIssue::RevisionDecisionPayloadInvalid {
- event_id: event_id(4),
- },
- );
- assert_revision_decision_issue(
- |decision| decision.payload.order_id = order_id("order-2"),
- RadrootsOrderIssue::RevisionDecisionOrderIdMismatch {
- event_id: event_id(4),
- },
- );
- assert_revision_decision_issue(
- |decision| decision.author_pubkey = public_key(SELLER),
- RadrootsOrderIssue::RevisionDecisionAuthorMismatch {
- event_id: event_id(4),
- },
- );
- assert_revision_decision_issue(
- |decision| decision.counterparty_pubkey = public_key(BUYER),
- RadrootsOrderIssue::RevisionDecisionCounterpartyMismatch {
- event_id: event_id(4),
- },
- );
- assert_revision_decision_issue(
- |decision| decision.payload.buyer_pubkey = public_key(SELLER),
- RadrootsOrderIssue::RevisionDecisionBuyerMismatch {
- event_id: event_id(4),
- },
- );
- assert_revision_decision_issue(
- |decision| decision.payload.seller_pubkey = public_key(BUYER),
- RadrootsOrderIssue::RevisionDecisionSellerMismatch {
- event_id: event_id(4),
- },
- );
- assert_revision_decision_issue(
- |decision| decision.payload.listing_addr = draft_listing_addr(),
- RadrootsOrderIssue::RevisionDecisionListingAddressInvalid {
- event_id: event_id(4),
- },
- );
- assert_revision_decision_issue(
- |decision| decision.payload.listing_addr = other_seller_listing_addr(),
- RadrootsOrderIssue::RevisionDecisionListingMismatch {
- event_id: event_id(4),
- },
- );
- assert_revision_decision_issue(
- |decision| decision.root_event_id = event_id(8),
- RadrootsOrderIssue::RevisionDecisionRootMismatch {
- event_id: event_id(4),
- },
- );
- assert_revision_decision_issue(
- |decision| decision.payload.root_event_id = event_id(8),
- RadrootsOrderIssue::RevisionDecisionRootMismatch {
- event_id: event_id(4),
- },
- );
- assert_revision_decision_issue(
- |decision| decision.prev_event_id = event_id(8),
- RadrootsOrderIssue::RevisionDecisionPreviousMismatch {
- event_id: event_id(4),
- },
- );
- assert_revision_decision_issue(
- |decision| decision.prev_event_id = event_id(4),
- RadrootsOrderIssue::RevisionDecisionPreviousMismatch {
- event_id: event_id(4),
- },
- );
- assert_revision_decision_issue(
- |decision| decision.payload.prev_event_id = event_id(8),
- RadrootsOrderIssue::RevisionDecisionPreviousMismatch {
- event_id: event_id(4),
- },
- );
-
+ fn reducer_validators_report_cancellation_issue_kinds() {
assert_cancellation_issue(
|cancellation| cancellation.payload.reason = " ".into(),
RadrootsOrderIssue::CancellationPayloadInvalid {
@@ -4935,7 +3607,7 @@ mod tests {
},
);
assert_cancellation_issue(
- |cancellation| cancellation.payload.listing_addr = draft_listing_addr(),
+ |cancellation| cancellation.payload.listing_addr = retired_listing_addr(),
RadrootsOrderIssue::CancellationListingAddressInvalid {
event_id: event_id(5),
},
@@ -4969,8 +3641,6 @@ mod tests {
RadrootsOrderReductionInputs {
requests: vec![bad_request],
decisions: Vec::<RadrootsOrderDecisionRecord>::new(),
- revision_proposals: Vec::<RadrootsOrderRevisionProposalRecord>::new(),
- revision_decisions: Vec::<RadrootsOrderRevisionDecisionRecord>::new(),
cancellations: Vec::<RadrootsOrderCancellationRecord>::new(),
},
);
@@ -4983,10 +3653,6 @@ mod tests {
let mut bad_decision = accepted_decision();
bad_decision.payload.order_id = order_id("order-2");
- let mut bad_proposal = revision_proposal();
- bad_proposal.payload.order_id = order_id("order-2");
- let mut bad_revision_decision = accepted_revision_decision();
- bad_revision_decision.payload.order_id = order_id("order-2");
let mut bad_cancellation = cancellation(event_id(1));
bad_cancellation.payload.order_id = order_id("order-2");
let invalid_non_requests = reduce_order_events(
@@ -4994,8 +3660,6 @@ mod tests {
RadrootsOrderReductionInputs {
requests: vec![request_record()],
decisions: vec![bad_decision],
- revision_proposals: vec![bad_proposal],
- revision_decisions: vec![bad_revision_decision],
cancellations: vec![bad_cancellation],
},
);
@@ -5008,18 +3672,6 @@ mod tests {
);
assert_order_issue_kind(
&invalid_non_requests.issues,
- RadrootsOrderIssue::RevisionProposalOrderIdMismatch {
- event_id: event_id(3),
- },
- );
- assert_order_issue_kind(
- &invalid_non_requests.issues,
- RadrootsOrderIssue::RevisionDecisionOrderIdMismatch {
- event_id: event_id(4),
- },
- );
- assert_order_issue_kind(
- &invalid_non_requests.issues,
RadrootsOrderIssue::CancellationOrderIdMismatch {
event_id: event_id(5),
},
@@ -5088,8 +3740,6 @@ mod tests {
cancelled_request,
],
decisions: vec![accepted_decision(), unknown_bin_decision, terminal_decline],
- revision_proposals: Vec::<RadrootsOrderRevisionProposalRecord>::new(),
- revision_decisions: Vec::<RadrootsOrderRevisionDecisionRecord>::new(),
cancellations: vec![terminal_cancellation],
},
);
@@ -5127,8 +3777,6 @@ mod tests {
bins: Vec::<RadrootsListingInventoryBinAvailability>::new(),
requests: Vec::<RadrootsOrderRequestRecord>::new(),
decisions: vec![accepted_decision()],
- revision_proposals: Vec::<RadrootsOrderRevisionProposalRecord>::new(),
- revision_decisions: Vec::<RadrootsOrderRevisionDecisionRecord>::new(),
cancellations: Vec::<RadrootsOrderCancellationRecord>::new(),
},
);
@@ -5150,8 +3798,6 @@ mod tests {
bins: Vec::<RadrootsListingInventoryBinAvailability>::new(),
requests: vec![request_record(), duplicate_request],
decisions: Vec::<RadrootsOrderDecisionRecord>::new(),
- revision_proposals: Vec::<RadrootsOrderRevisionProposalRecord>::new(),
- revision_decisions: Vec::<RadrootsOrderRevisionDecisionRecord>::new(),
cancellations: Vec::<RadrootsOrderCancellationRecord>::new(),
},
);
@@ -5166,35 +3812,11 @@ mod tests {
event_ids: Vec::new(),
},
);
-
- let invalid_revision_streams = reduce_listing_inventory_accounting(
- &listing_addr(),
- &event_id(9),
- RadrootsListingInventoryAccountingInputs {
- bins: Vec::<RadrootsListingInventoryBinAvailability>::new(),
- requests: Vec::<RadrootsOrderRequestRecord>::new(),
- decisions: vec![accepted_decision()],
- revision_proposals: vec![revision_proposal()],
- revision_decisions: vec![accepted_revision_decision()],
- cancellations: vec![cancellation(event_id(3))],
- },
- );
- assert_eq!(
- invalid_revision_streams.invalid_event_ids,
- vec![event_id(2), event_id(3), event_id(4), event_id(5)]
- );
- assert_inventory_issue_kind(
- &invalid_revision_streams.issues,
- RadrootsListingInventoryAccountingIssue::InvalidOrder {
- order_id: order_id("order-1"),
- event_ids: Vec::new(),
- },
- );
}
#[test]
fn reducer_projects_requested_order() {
- let projection = reduce(Vec::new(), Vec::new(), Vec::new(), Vec::new());
+ let projection = reduce(Vec::new(), Vec::new());
assert_eq!(projection.issues, Vec::new());
assert_eq!(projection.status, RadrootsTradeWorkflowState::Requested);
@@ -5210,8 +3832,6 @@ mod tests {
RadrootsOrderReductionInputs {
requests: Vec::<RadrootsOrderRequestRecord>::new(),
decisions: Vec::<RadrootsOrderDecisionRecord>::new(),
- revision_proposals: Vec::<RadrootsOrderRevisionProposalRecord>::new(),
- revision_decisions: Vec::<RadrootsOrderRevisionDecisionRecord>::new(),
cancellations: Vec::<RadrootsOrderCancellationRecord>::new(),
},
);
@@ -5237,7 +3857,7 @@ mod tests {
assert!(json.get("last_discount_request").is_none());
}
- let requested = reduce(Vec::new(), Vec::new(), Vec::new(), Vec::new());
+ let requested = reduce(Vec::new(), Vec::new());
let requested_dto = RadrootsOrderWorkflowProjection::from(&requested);
assert_eq!(requested_dto.status, RadrootsTradeWorkflowState::Requested);
@@ -5252,12 +3872,7 @@ mod tests {
#[test]
fn reducer_projects_accepted_order_agreement() {
- let projection = reduce(
- vec![accepted_decision()],
- Vec::new(),
- Vec::new(),
- Vec::new(),
- );
+ let projection = reduce(vec![accepted_decision()], Vec::new());
assert_eq!(
projection.status,
@@ -5272,12 +3887,7 @@ mod tests {
#[test]
fn reducer_projects_declined_order() {
- let projection = reduce(
- vec![declined_decision()],
- Vec::new(),
- Vec::new(),
- Vec::new(),
- );
+ let projection = reduce(vec![declined_decision()], Vec::new());
assert_eq!(projection.status, RadrootsTradeWorkflowState::Declined);
assert_eq!(projection.decision_event_id, Some(event_id(2)));
@@ -5285,36 +3895,8 @@ mod tests {
}
#[test]
- fn reducer_projects_revision_acceptance_as_agreement() {
- let projection = reduce(
- Vec::new(),
- vec![revision_proposal()],
- vec![accepted_revision_decision()],
- Vec::new(),
- );
-
- assert_eq!(
- projection.status,
- RadrootsTradeWorkflowState::AgreedPendingValidation
- );
- assert_eq!(projection.agreement_event_id, Some(event_id(4)));
- assert_eq!(
- projection.economics.expect("economics").items[0].bin_count,
- 1
- );
- assert!(!projection.lifecycle_terminal);
- assert_eq!(projection.pending_inventory_reservations.len(), 1);
- assert!(projection.committed_inventory_reservations.is_empty());
- }
-
- #[test]
fn reducer_allows_pre_agreement_cancellation() {
- let projection = reduce(
- Vec::new(),
- Vec::new(),
- Vec::new(),
- vec![cancellation(event_id(1))],
- );
+ let projection = reduce(Vec::new(), vec![cancellation(event_id(1))]);
assert_eq!(projection.status, RadrootsTradeWorkflowState::Cancelled);
assert_eq!(projection.cancellation_event_id, Some(event_id(5)));
@@ -5323,12 +3905,7 @@ mod tests {
#[test]
fn reducer_rejects_cancellation_after_agreement() {
- let projection = reduce(
- vec![accepted_decision()],
- Vec::new(),
- Vec::new(),
- vec![cancellation(event_id(2))],
- );
+ let projection = reduce(vec![accepted_decision()], vec![cancellation(event_id(2))]);
assert_eq!(projection.status, RadrootsTradeWorkflowState::Invalid);
assert!(projection.lifecycle_terminal);
@@ -5363,8 +3940,6 @@ mod tests {
}],
requests: vec![request_record()],
decisions: Vec::<RadrootsOrderDecisionRecord>::new(),
- revision_proposals: Vec::<RadrootsOrderRevisionProposalRecord>::new(),
- revision_decisions: Vec::<RadrootsOrderRevisionDecisionRecord>::new(),
cancellations: Vec::<RadrootsOrderCancellationRecord>::new(),
},
);
@@ -5382,8 +3957,6 @@ mod tests {
}],
requests: vec![request_record()],
decisions: vec![accepted_decision()],
- revision_proposals: Vec::<RadrootsOrderRevisionProposalRecord>::new(),
- revision_decisions: Vec::<RadrootsOrderRevisionDecisionRecord>::new(),
cancellations: Vec::<RadrootsOrderCancellationRecord>::new(),
},
);
diff --git a/crates/trade/src/prelude.rs b/crates/trade/src/prelude.rs
@@ -1,5 +1,3 @@
-#[cfg(feature = "serde_json")]
-pub use crate::dvm::*;
pub use crate::identity::*;
pub use crate::listing::*;
pub use crate::order::*;
diff --git a/crates/trade/src/projection.rs b/crates/trade/src/projection.rs
@@ -40,11 +40,9 @@ pub const RADROOTS_PRODUCT_PROJECTION_VERSION: u32 = 1;
pub const RADROOTS_TRADE_VALIDATION_RECEIPT_CONTRACT_ID: &str =
"radroots.trade.validation_receipt.v1";
-const PRODUCT_PROJECTION_CONTRACT_IDS: [&str; 6] = [
+const PRODUCT_PROJECTION_CONTRACT_IDS: [&str; 4] = [
"radroots.order.request.v1",
"radroots.order.decision.v1",
- "radroots.order.revision_proposal.v1",
- "radroots.order.revision_decision.v1",
"radroots.order.cancellation.v1",
RADROOTS_TRADE_VALIDATION_RECEIPT_CONTRACT_ID,
];
@@ -532,7 +530,7 @@ async fn upsert_trade_projection_row(
})?;
sqlx::query(
- "INSERT INTO trade_projection(order_id, root_event_id, projection_version, status, lifecycle_terminal, rhi_state, listing_addr, buyer_pubkey, seller_pubkey, request_event_id, decision_event_id, agreement_event_id, pending_revision_event_id, cancellation_event_id, validation_receipt_event_id, last_event_id, expected_listing_event_id, current_listing_event_id, economics_json, pending_inventory_json, committed_inventory_json, issues_json, issue_count, source_event_count, transport_observation_count, evidence_hash, last_source_event_seq, updated_at_ms) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(order_id, root_event_id, projection_version) DO UPDATE SET status = excluded.status, lifecycle_terminal = excluded.lifecycle_terminal, rhi_state = excluded.rhi_state, listing_addr = excluded.listing_addr, buyer_pubkey = excluded.buyer_pubkey, seller_pubkey = excluded.seller_pubkey, request_event_id = excluded.request_event_id, decision_event_id = excluded.decision_event_id, agreement_event_id = excluded.agreement_event_id, pending_revision_event_id = excluded.pending_revision_event_id, cancellation_event_id = excluded.cancellation_event_id, validation_receipt_event_id = excluded.validation_receipt_event_id, last_event_id = excluded.last_event_id, expected_listing_event_id = excluded.expected_listing_event_id, current_listing_event_id = excluded.current_listing_event_id, economics_json = excluded.economics_json, pending_inventory_json = excluded.pending_inventory_json, committed_inventory_json = excluded.committed_inventory_json, issues_json = excluded.issues_json, issue_count = excluded.issue_count, source_event_count = excluded.source_event_count, transport_observation_count = excluded.transport_observation_count, evidence_hash = excluded.evidence_hash, last_source_event_seq = excluded.last_source_event_seq, updated_at_ms = excluded.updated_at_ms",
+ "INSERT INTO trade_projection(order_id, root_event_id, projection_version, status, lifecycle_terminal, rhi_state, listing_addr, buyer_pubkey, seller_pubkey, request_event_id, decision_event_id, agreement_event_id, cancellation_event_id, validation_receipt_event_id, last_event_id, expected_listing_event_id, current_listing_event_id, economics_json, pending_inventory_json, committed_inventory_json, issues_json, issue_count, source_event_count, transport_observation_count, evidence_hash, last_source_event_seq, updated_at_ms) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(order_id, root_event_id, projection_version) DO UPDATE SET status = excluded.status, lifecycle_terminal = excluded.lifecycle_terminal, rhi_state = excluded.rhi_state, listing_addr = excluded.listing_addr, buyer_pubkey = excluded.buyer_pubkey, seller_pubkey = excluded.seller_pubkey, request_event_id = excluded.request_event_id, decision_event_id = excluded.decision_event_id, agreement_event_id = excluded.agreement_event_id, cancellation_event_id = excluded.cancellation_event_id, validation_receipt_event_id = excluded.validation_receipt_event_id, last_event_id = excluded.last_event_id, expected_listing_event_id = excluded.expected_listing_event_id, current_listing_event_id = excluded.current_listing_event_id, economics_json = excluded.economics_json, pending_inventory_json = excluded.pending_inventory_json, committed_inventory_json = excluded.committed_inventory_json, issues_json = excluded.issues_json, issue_count = excluded.issue_count, source_event_count = excluded.source_event_count, transport_observation_count = excluded.transport_observation_count, evidence_hash = excluded.evidence_hash, last_source_event_seq = excluded.last_source_event_seq, updated_at_ms = excluded.updated_at_ms",
)
.bind(order_id.as_str())
.bind(root_event_id.as_str())
@@ -546,7 +544,6 @@ async fn upsert_trade_projection_row(
.bind(projection.request_event_id.as_ref().map(|value| value.as_str()))
.bind(projection.decision_event_id.as_ref().map(|value| value.as_str()))
.bind(projection.agreement_event_id.as_ref().map(|value| value.as_str()))
- .bind(projection.pending_revision_event_id.as_ref().map(|value| value.as_str()))
.bind(projection.cancellation_event_id.as_ref().map(|value| value.as_str()))
.bind(projection.validation_receipt_event_id.as_ref().map(|value| value.as_str()))
.bind(projection.last_event_id.as_ref().map(|value| value.as_str()))
@@ -679,7 +676,6 @@ fn projection_source_event_ids(
projection.request_event_id.clone(),
projection.decision_event_id.clone(),
projection.agreement_event_id.clone(),
- projection.pending_revision_event_id.clone(),
projection.cancellation_event_id.clone(),
projection.validation_receipt_event_id.clone(),
projection.last_event_id.clone(),
@@ -708,12 +704,6 @@ fn push_order_record(
match record {
RadrootsOrderEventRecord::Request(record) => records.requests.push(record),
RadrootsOrderEventRecord::Decision(record) => records.decisions.push(record),
- RadrootsOrderEventRecord::RevisionProposal(record) => {
- records.revision_proposals.push(record)
- }
- RadrootsOrderEventRecord::RevisionDecision(record) => {
- records.revision_decisions.push(record)
- }
RadrootsOrderEventRecord::Cancellation(record) => records.cancellations.push(record),
}
}
diff --git a/crates/trade/src/workflow.rs b/crates/trade/src/workflow.rs
@@ -310,22 +310,19 @@ mod tests {
use radroots_event::{
ids::{
RadrootsEventId, RadrootsInventoryBinId, RadrootsListingAddress, RadrootsOrderId,
- RadrootsOrderQuoteId, RadrootsOrderRevisionId, RadrootsPublicKey,
+ RadrootsOrderQuoteId, RadrootsPublicKey,
},
kinds::KIND_LISTING,
order::{
RadrootsOrderCancellation, RadrootsOrderDecision, RadrootsOrderDecisionOutcome,
RadrootsOrderEconomicItem, RadrootsOrderEconomics, RadrootsOrderInventoryCommitment,
RadrootsOrderItem, RadrootsOrderPricingBasis, RadrootsOrderRequest,
- RadrootsOrderRevisionDecision, RadrootsOrderRevisionOutcome,
- RadrootsOrderRevisionProposal,
},
};
use crate::order::{
RadrootsGroupedOrderEventRecords, RadrootsOrderCancellationRecord,
RadrootsOrderDecisionRecord, RadrootsOrderIssue, RadrootsOrderRequestRecord,
- RadrootsOrderRevisionDecisionRecord, RadrootsOrderRevisionProposalRecord,
RadrootsTradeLocatorProjectionResolution,
};
use crate::validation_receipt::{
@@ -386,10 +383,6 @@ mod tests {
RadrootsOrderId::parse("order-1").expect("order id")
}
- fn revision_id() -> RadrootsOrderRevisionId {
- RadrootsOrderRevisionId::parse("revision-1").expect("revision id")
- }
-
fn quote_id(raw: &str) -> RadrootsOrderQuoteId {
RadrootsOrderQuoteId::parse(raw).expect("quote id")
}
@@ -477,51 +470,6 @@ mod tests {
}
}
- fn revision_proposal() -> RadrootsOrderRevisionProposalRecord {
- RadrootsOrderRevisionProposalRecord {
- event_id: event_id(3),
- author_pubkey: public_key(SELLER),
- counterparty_pubkey: public_key(BUYER),
- root_event_id: event_id(1),
- prev_event_id: event_id(1),
- payload: RadrootsOrderRevisionProposal {
- revision_id: revision_id(),
- order_id: order_id(),
- listing_addr: listing_addr(),
- buyer_pubkey: public_key(BUYER),
- seller_pubkey: public_key(SELLER),
- root_event_id: event_id(1),
- prev_event_id: event_id(1),
- items: vec![RadrootsOrderItem {
- bin_id: bin_id("bin-1"),
- bin_count: 1,
- }],
- economics: economics(1),
- reason: "one bin remains".to_string(),
- },
- }
- }
-
- fn accepted_revision_decision() -> RadrootsOrderRevisionDecisionRecord {
- RadrootsOrderRevisionDecisionRecord {
- event_id: event_id(4),
- author_pubkey: public_key(BUYER),
- counterparty_pubkey: public_key(SELLER),
- root_event_id: event_id(1),
- prev_event_id: event_id(3),
- payload: RadrootsOrderRevisionDecision {
- revision_id: revision_id(),
- order_id: order_id(),
- listing_addr: listing_addr(),
- buyer_pubkey: public_key(BUYER),
- seller_pubkey: public_key(SELLER),
- root_event_id: event_id(1),
- prev_event_id: event_id(3),
- decision: RadrootsOrderRevisionOutcome::Accepted,
- },
- }
- }
-
fn cancellation(prev_event_id: RadrootsEventId) -> RadrootsOrderCancellationRecord {
RadrootsOrderCancellationRecord {
event_id: event_id(5),
@@ -544,8 +492,6 @@ mod tests {
order_events: RadrootsGroupedOrderEventRecords {
requests: vec![request_record()],
decisions: Vec::new(),
- revision_proposals: Vec::new(),
- revision_decisions: Vec::new(),
cancellations: Vec::new(),
},
validation_receipts: Vec::new(),
@@ -709,25 +655,7 @@ mod tests {
}
#[test]
- fn workflow_revision_acceptance_waits_for_rhi_and_cancellation_after_agreement_is_invalid() {
- let mut records = workflow_records();
- records
- .order_events
- .revision_proposals
- .push(revision_proposal());
- records
- .order_events
- .revision_decisions
- .push(accepted_revision_decision());
-
- let projection = reduce_trade_workflow_records(&order_id(), records);
- assert_eq!(
- projection.status,
- RadrootsTradeWorkflowState::AgreedPendingValidation
- );
- assert_eq!(projection.agreement_event_id, Some(event_id(4)));
- assert_eq!(projection.pending_inventory_reservations[0].bin_count, 1);
-
+ fn workflow_cancellation_after_agreement_is_invalid() {
let mut cancelled = workflow_records();
cancelled.order_events.decisions.push(accepted_decision());
cancelled
diff --git a/crates/trade_sp1_guest/src/lib.rs b/crates/trade_sp1_guest/src/lib.rs
@@ -13,7 +13,6 @@ pub const RADROOTS_SP1_TRADE_REDUCER_PROGRAM_HASH: &str =
"0x3d8f7f463904d71f2d0d14b1551450756697e51c7b658e10c6d5c20a7bc61f08";
pub const RADROOTS_SP1_TRADE_ORDER_ACCEPTANCE_PROOF_TARGET: &str = "trade.order_acceptance.v1";
pub const RADROOTS_SP1_TRADE_KIND_LISTING: u32 = 30402;
-pub const RADROOTS_SP1_TRADE_KIND_LISTING_DRAFT: u32 = 30403;
pub const RADROOTS_SP1_TRADE_KIND_ORDER_REQUEST: u32 = 3422;
pub const RADROOTS_SP1_TRADE_KIND_ORDER_DECISION: u32 = 3423;
@@ -422,10 +421,7 @@ fn validate_event_evidence(
&witness.listing_event_id,
&witness.request.seller_pubkey,
RadrootsSp1TradeEventEvidenceRole::Seller,
- &[
- RADROOTS_SP1_TRADE_KIND_LISTING,
- RADROOTS_SP1_TRADE_KIND_LISTING_DRAFT,
- ],
+ &[RADROOTS_SP1_TRADE_KIND_LISTING],
"listing",
)?;
@@ -806,17 +802,17 @@ struct StateRootMaterial<'a> {
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use super::{
- RADROOTS_SP1_TRADE_KIND_LISTING, RADROOTS_SP1_TRADE_KIND_LISTING_DRAFT,
- RADROOTS_SP1_TRADE_KIND_ORDER_DECISION, RADROOTS_SP1_TRADE_KIND_ORDER_REQUEST,
- RADROOTS_SP1_TRADE_ORDER_ACCEPTANCE_PROOF_TARGET, RADROOTS_SP1_TRADE_PROTOCOL_VERSION,
- RADROOTS_SP1_TRADE_REDUCER_PROGRAM_HASH, RADROOTS_SP1_TRADE_WITNESS_VERSION,
- RadrootsSp1TradeCanonicalEventEvidence, RadrootsSp1TradeEventEvidenceRole,
- RadrootsSp1TradeEventWorkflowPosition, RadrootsSp1TradeGuestError,
- RadrootsSp1TradeInventoryBinWitness, RadrootsSp1TradeInventoryCommitmentWitness,
- RadrootsSp1TradeOrderAcceptanceWitness, RadrootsSp1TradeOrderDecisionEventWitness,
- RadrootsSp1TradeOrderDecisionWitness, RadrootsSp1TradeOrderItemWitness,
- RadrootsSp1TradeOrderRequestWitness, RadrootsSp1TradeProofResult,
- RadrootsSp1TradeProofTransitionKind, canonical_public_values_bytes, public_values_hash_hex,
+ RADROOTS_SP1_TRADE_KIND_LISTING, RADROOTS_SP1_TRADE_KIND_ORDER_DECISION,
+ RADROOTS_SP1_TRADE_KIND_ORDER_REQUEST, RADROOTS_SP1_TRADE_ORDER_ACCEPTANCE_PROOF_TARGET,
+ RADROOTS_SP1_TRADE_PROTOCOL_VERSION, RADROOTS_SP1_TRADE_REDUCER_PROGRAM_HASH,
+ RADROOTS_SP1_TRADE_WITNESS_VERSION, RadrootsSp1TradeCanonicalEventEvidence,
+ RadrootsSp1TradeEventEvidenceRole, RadrootsSp1TradeEventWorkflowPosition,
+ RadrootsSp1TradeGuestError, RadrootsSp1TradeInventoryBinWitness,
+ RadrootsSp1TradeInventoryCommitmentWitness, RadrootsSp1TradeOrderAcceptanceWitness,
+ RadrootsSp1TradeOrderDecisionEventWitness, RadrootsSp1TradeOrderDecisionWitness,
+ RadrootsSp1TradeOrderItemWitness, RadrootsSp1TradeOrderRequestWitness,
+ RadrootsSp1TradeProofResult, RadrootsSp1TradeProofTransitionKind,
+ canonical_public_values_bytes, public_values_hash_hex,
reduce_order_acceptance_canonical_public_values, reduce_order_acceptance_public_values,
};
@@ -1278,8 +1274,11 @@ mod tests {
);
let mut input = witness();
- input.event_evidence[0].kind = RADROOTS_SP1_TRADE_KIND_LISTING_DRAFT;
- reduce_order_acceptance_public_values(&input).expect("listing draft evidence");
+ input.event_evidence[0].kind = 30403;
+ assert_eq!(
+ reduce_order_acceptance_public_values(&input).expect_err("retired listing evidence"),
+ RadrootsSp1TradeGuestError::UnsupportedEventEvidenceKind(30403)
+ );
}
#[test]
diff --git a/tools/xtask/src/contract.rs b/tools/xtask/src/contract.rs
@@ -679,17 +679,6 @@ const LISTING_WITNESSES: [EventBoundarySourceWitness; 2] = [
},
];
-const LISTING_DRAFT_WITNESSES: [EventBoundarySourceWitness; 2] = [
- EventBoundarySourceWitness {
- relative_path: "crates/event/src/listing.rs",
- required_fragments: &["pub struct RadrootsListing"],
- },
- EventBoundarySourceWitness {
- relative_path: "crates/event/src/kinds.rs",
- required_fragments: &["pub const KIND_LISTING_DRAFT: u32 = 30403;"],
- },
-];
-
const DVM_REQUEST_WITNESSES: [EventBoundarySourceWitness; 2] = [
EventBoundarySourceWitness {
relative_path: "crates/event/src/job_request.rs",
@@ -788,65 +777,6 @@ const TRADE_ORDER_DECISION_WITNESSES: [EventBoundarySourceWitness; 5] = [
},
];
-const TRADE_ORDER_REVISION_PROPOSED_WITNESSES: [EventBoundarySourceWitness; 5] = [
- EventBoundarySourceWitness {
- relative_path: "crates/event/src/kinds.rs",
- required_fragments: &["pub const KIND_ORDER_REVISION_PROPOSAL: u32 = 3424;"],
- },
- EventBoundarySourceWitness {
- relative_path: "crates/event/src/order.rs",
- required_fragments: &[
- "pub struct RadrootsOrderRevisionProposal",
- "Self::OrderRevisionProposed => KIND_ORDER_REVISION_PROPOSAL",
- ],
- },
- EventBoundarySourceWitness {
- relative_path: "crates/event_codec/src/order/encode.rs",
- required_fragments: &["pub fn order_revision_proposal_event_build"],
- },
- EventBoundarySourceWitness {
- relative_path: "crates/event_codec/src/order/decode.rs",
- required_fragments: &["pub fn order_revision_proposal_from_event"],
- },
- EventBoundarySourceWitness {
- relative_path: "crates/trade/src/order.rs",
- required_fragments: &[
- "pub struct RadrootsOrderRevisionProposalRecord",
- "pub fn reduce_order_events",
- ],
- },
-];
-
-const TRADE_ORDER_REVISION_DECISION_WITNESSES: [EventBoundarySourceWitness; 5] = [
- EventBoundarySourceWitness {
- relative_path: "crates/event/src/kinds.rs",
- required_fragments: &["pub const KIND_ORDER_REVISION_DECISION: u32 = 3425;"],
- },
- EventBoundarySourceWitness {
- relative_path: "crates/event/src/order.rs",
- required_fragments: &[
- "pub enum RadrootsOrderRevisionOutcome",
- "pub struct RadrootsOrderRevisionDecision",
- "Self::OrderRevisionDecision => KIND_ORDER_REVISION_DECISION",
- ],
- },
- EventBoundarySourceWitness {
- relative_path: "crates/event_codec/src/order/encode.rs",
- required_fragments: &["pub fn order_revision_decision_event_build"],
- },
- EventBoundarySourceWitness {
- relative_path: "crates/event_codec/src/order/decode.rs",
- required_fragments: &["pub fn order_revision_decision_from_event"],
- },
- EventBoundarySourceWitness {
- relative_path: "crates/trade/src/order.rs",
- required_fragments: &[
- "pub struct RadrootsOrderRevisionDecisionRecord",
- "pub fn reduce_order_events",
- ],
- },
-];
-
const TRADE_ORDER_CANCELLED_WITNESSES: [EventBoundarySourceWitness; 5] = [
EventBoundarySourceWitness {
relative_path: "crates/event/src/kinds.rs",
@@ -900,7 +830,7 @@ const RELAY_DOC_WITNESSES: [EventBoundarySourceWitness; 2] = [
},
];
-const CANONICAL_EVENT_BOUNDARY_EXPECTATIONS: [EventBoundaryExpectation; 42] = [
+const CANONICAL_EVENT_BOUNDARY_EXPECTATIONS: [EventBoundaryExpectation; 39] = [
EventBoundaryExpectation {
domain: "profile",
kind: "0",
@@ -1219,17 +1149,6 @@ const CANONICAL_EVENT_BOUNDARY_EXPECTATIONS: [EventBoundaryExpectation; 42] = [
witnesses: &LISTING_WITNESSES,
},
EventBoundaryExpectation {
- domain: "listing_draft",
- kind: "30403",
- radroots_type: "RadrootsListing",
- rpc_methods: &[
- "events.listing_draft.publish",
- "events.listing_draft.list",
- "events.listing_draft.get",
- ],
- witnesses: &LISTING_DRAFT_WITNESSES,
- },
- EventBoundaryExpectation {
domain: "dvm_request",
kind: "5000-5999",
radroots_type: "RadrootsJobRequest",
@@ -1286,29 +1205,6 @@ const CANONICAL_EVENT_BOUNDARY_EXPECTATIONS: [EventBoundaryExpectation; 42] = [
witnesses: &TRADE_ORDER_DECISION_WITNESSES,
},
EventBoundaryExpectation {
- domain: "trade:order_revision_proposed",
- kind: "3424",
- radroots_type: "TradeOrderRevisionProposed",
- rpc_methods: &[
- "active CLI `order revision propose`",
- "SDK encode/decode/validate",
- "trade reducer",
- ],
- witnesses: &TRADE_ORDER_REVISION_PROPOSED_WITNESSES,
- },
- EventBoundaryExpectation {
- domain: "trade:order_revision_decision",
- kind: "3425",
- radroots_type: "TradeOrderRevisionDecision",
- rpc_methods: &[
- "active CLI `order revision accept`",
- "active CLI `order revision decline`",
- "SDK encode/decode/validate",
- "trade reducer",
- ],
- witnesses: &TRADE_ORDER_REVISION_DECISION_WITNESSES,
- },
- EventBoundaryExpectation {
domain: "trade:order_cancelled",
kind: "3432",
radroots_type: "TradeOrderCancelled",
diff --git a/tools/xtask/src/hygiene.rs b/tools/xtask/src/hygiene.rs
@@ -13,6 +13,60 @@ const BINDING_DEPENDENCIES: &[&str] = &[
"wasm-bindgen-test",
];
+const RETIRED_PROTOCOL_EVENT_SURFACE_PATTERNS: &[&str] = &[
+ "KIND_LISTING_DRAFT",
+ "KIND_ORDER_REVISION",
+ "KIND_TRADE_QUESTION",
+ "KIND_TRADE_ANSWER",
+ "KIND_TRADE_DISCOUNT_REQUEST",
+ "KIND_TRADE_DISCOUNT_OFFER",
+ "KIND_TRADE_DISCOUNT_ACCEPT",
+ "KIND_TRADE_FULFILLMENT_UPDATE",
+ "KIND_TRADE_RECEIPT",
+ "KIND_TRADE_LISTING_VALIDATION_REQUEST",
+ "KIND_TRADE_LISTING_VALIDATION_RESULT",
+ "KIND_TRADE_TRANSITION_PROOF_REQUEST",
+ "KIND_TRADE_TRANSITION_PROOF_RESULT",
+ "RADROOTS_SP1_TRADE_KIND_LISTING_DRAFT",
+ "RadrootsListingDraft",
+ "RadrootsCanonicalListingDraft",
+ "RadrootsListingDraftError",
+ "RadrootsOrderRevision",
+ "RadrootsOrderRevisionId",
+ "RadrootsTradeValidationListingRequest",
+ "RadrootsTradeValidationListingResult",
+ "ListingValidationRequest",
+ "ListingValidationResult",
+ "TransitionProof",
+ "TradeQuestion",
+ "TradeAnswer",
+ "TradeFulfillment",
+ "TradeReceipt",
+ "canonicalize_listing_draft",
+ "listing_draft",
+ "order_revision",
+ "pending_revision_event_id",
+ "trade_answer",
+ "trade_discount_accept",
+ "trade_discount_offer",
+ "trade_discount_request",
+ "trade_fulfillment_update",
+ "trade_listing_validation_request",
+ "trade_listing_validation_result",
+ "trade_order_revision_decision",
+ "trade_order_revision_proposal",
+ "trade_question",
+ "trade_receipt",
+ "trade_transition_proof_request",
+ "trade_transition_proof_result",
+];
+
+const RETIRED_PROTOCOL_EVENT_SURFACE_ALLOWED_PATHS: &[&str] = &[
+ "crates/event/src/dto.rs",
+ "crates/protocol_contract_v1/src/lib.rs",
+ "tools/xtask/src/hygiene.rs",
+];
+
pub fn run(args: &[String], root: &Path) -> Result<(), String> {
match args.first().map(String::as_str) {
Some("forbidden-identifiers") => validate_forbidden_identifiers(root),
@@ -112,6 +166,18 @@ pub fn validate_forbidden_identifiers(root: &Path) -> Result<(), String> {
PathBuf::from("crates"),
PathBuf::from("contracts"),
PathBuf::from("tools"),
+ ],
+ RETIRED_PROTOCOL_EVENT_SURFACE_PATTERNS,
+ "retired V1 public event surfaces must not reappear outside negative contract guards",
+ RETIRED_PROTOCOL_EVENT_SURFACE_ALLOWED_PATHS,
+ &mut failures,
+ );
+ reject_substrings(
+ root,
+ &[
+ PathBuf::from("crates"),
+ PathBuf::from("contracts"),
+ PathBuf::from("tools"),
PathBuf::from("build"),
],
&["tangle"],
@@ -421,6 +487,21 @@ mod tests {
"crates/trade/src/order.rs",
"pub struct RadrootsOrderProjection { pub order_id: RadrootsOrderId, }\n",
);
+ write_file(
+ &root,
+ "crates/protocol_contract_v1/src/lib.rs",
+ "const RETIRED: &str = \"listing_draft\";\n",
+ );
+ write_file(
+ &root,
+ "crates/event/src/dto.rs",
+ "const OBSOLETE: &str = \"RadrootsOrderRevision\";\n",
+ );
+ write_file(
+ &root,
+ "tools/xtask/src/hygiene.rs",
+ "const GUARD: &str = \"trade_order_revision_proposal\";\n",
+ );
validate_forbidden_identifiers(&root).expect("clean tree");
let _ = fs::remove_dir_all(root);
}
@@ -447,7 +528,12 @@ mod tests {
write_file(
&root,
"crates/event/src/kinds.rs",
- "pub const KIND_TRADE_LISTING_ORDER: u64 = 1;\npub const KIND_TRADE_LISTING_VALIDATE_REQ: u64 = 5321;\n",
+ "pub const KIND_TRADE_LISTING_ORDER: u64 = 1;\npub const KIND_TRADE_LISTING_VALIDATE_REQ: u64 = 5321;\npub const KIND_LISTING_DRAFT: u32 = 30403;\n",
+ );
+ write_file(
+ &root,
+ "contracts/conformance/retired.json",
+ "{\"name\":\"trade_order_revision_proposal\"}\n",
);
write_file(
&root,
@@ -463,6 +549,7 @@ mod tests {
assert!(err.contains("raw commercial protocol identifier String fields are forbidden"));
assert!(err.contains("removed identifier 'tangle' must not reappear"));
assert!(err.contains("removed trade and DVM kind constants must not reappear"));
+ assert!(err.contains("retired V1 public event surfaces must not reappear"));
assert!(err.contains("wasm-bindgen"));
assert!(err.contains("uniffi"));
assert!(err.contains("crates/sql_wasm_bridge"));