lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

commit a0c833d1c9b0fc6a77e35437811d54887569e0f5
parent 3e8fa15999ccedcb39b96db8984e5b44ffda80cf
Author: triesap <tyson@radroots.org>
Date:   Sun, 17 May 2026 19:30:54 +0000

sp1: add host execute path

- add a light SP1 execute path for order acceptance public values
- narrow the guest witness to bincode-safe proof inputs
- compare committed canonical bytes against deterministic reducer output
- gate guest ELF builds behind the expensive_proofs feature

Diffstat:
MCargo.lock | 6++----
MCargo.toml | 1+
Mcrates/sp1_guest_trade/Cargo.toml | 11-----------
Mcrates/sp1_guest_trade/src/bin/order_acceptance_guest.rs | 2+-
Mcrates/sp1_guest_trade/src/lib.rs | 192+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mcrates/sp1_host_trade/Cargo.toml | 8++++++--
Acrates/sp1_host_trade/build.rs | 13+++++++++++++
Mcrates/sp1_host_trade/src/lib.rs | 190++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
8 files changed, 277 insertions(+), 146 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -4379,9 +4379,6 @@ dependencies = [ name = "radroots_sp1_guest_trade" version = "0.1.0-alpha.2" dependencies = [ - "radroots_core", - "radroots_events", - "radroots_trade", "serde", "serde_json", "sha2", @@ -4394,15 +4391,16 @@ name = "radroots_sp1_host_trade" version = "0.1.0-alpha.2" dependencies = [ "base64 0.22.1", - "radroots_core", "radroots_events", "radroots_sp1_guest_trade", "radroots_trade", "serde", "serde_json", "sha2", + "sp1-build", "sp1-sdk", "thiserror 1.0.69", + "tokio", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml @@ -135,6 +135,7 @@ serde = { version = "1", default-features = false, features = [ serde_json = { version = "1", default-features = false, features = ["alloc"] } serde-wasm-bindgen = { version = "0.6" } sha2 = { version = "0.10", default-features = false } +sp1-build = { version = "6.2.1" } sp1-sdk = { version = "6.2.1", default-features = false } sp1-zkvm = { version = "6.2.1" } reqwest = { version = "0.12", default-features = false } diff --git a/crates/sp1_guest_trade/Cargo.toml b/crates/sp1_guest_trade/Cargo.toml @@ -20,19 +20,8 @@ default = [] sp1_guest = ["dep:sp1-zkvm"] [dependencies] -radroots_events = { workspace = true, default-features = false, features = [ - "serde", - "std", -] } -radroots_trade = { workspace = true, default-features = false, features = [ - "serde_json", - "std", -] } serde = { workspace = true, default-features = false, features = ["alloc", "derive"] } serde_json = { workspace = true, default-features = false, features = ["alloc"] } sha2 = { workspace = true, default-features = false } sp1-zkvm = { workspace = true, optional = true } thiserror = { workspace = true } - -[dev-dependencies] -radroots_core = { workspace = true } diff --git a/crates/sp1_guest_trade/src/bin/order_acceptance_guest.rs b/crates/sp1_guest_trade/src/bin/order_acceptance_guest.rs @@ -10,5 +10,5 @@ fn main() { let witness = sp1_zkvm::io::read::<RadrootsSp1TradeOrderAcceptanceWitness>(); let public_values = reduce_order_acceptance_canonical_public_values(&witness) .expect("valid radroots order acceptance witness"); - sp1_zkvm::io::commit_slice(&public_values); + sp1_zkvm::io::commit(&public_values); } diff --git a/crates/sp1_guest_trade/src/lib.rs b/crates/sp1_guest_trade/src/lib.rs @@ -1,9 +1,5 @@ #![forbid(unsafe_code)] -use radroots_events::trade::{ - RadrootsTradeOrderDecision, RadrootsTradeOrderDecisionEvent, RadrootsTradeOrderRequested, -}; -use radroots_trade::validation_receipt::validation_receipt_public_values_hash_hex; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use std::collections::BTreeMap; @@ -69,12 +65,56 @@ pub struct RadrootsSp1TradeInventoryBinWitness { #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(deny_unknown_fields)] +pub struct RadrootsSp1TradeOrderItemWitness { + pub bin_id: String, + pub bin_count: u32, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct RadrootsSp1TradeOrderRequestWitness { + pub order_id: String, + pub listing_addr: String, + pub buyer_pubkey: String, + pub seller_pubkey: String, + pub items: Vec<RadrootsSp1TradeOrderItemWitness>, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct RadrootsSp1TradeInventoryCommitmentWitness { + pub bin_id: String, + pub bin_count: u32, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub enum RadrootsSp1TradeOrderDecisionWitness { + Accepted { + inventory_commitments: Vec<RadrootsSp1TradeInventoryCommitmentWitness>, + }, + Declined { + reason: String, + }, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct RadrootsSp1TradeOrderDecisionEventWitness { + pub order_id: String, + pub listing_addr: String, + pub buyer_pubkey: String, + pub seller_pubkey: String, + pub decision: RadrootsSp1TradeOrderDecisionWitness, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] pub struct RadrootsSp1TradeOrderAcceptanceWitness { pub listing_event_id: String, pub request_event_id: String, pub decision_event_id: String, - pub request: RadrootsTradeOrderRequested, - pub decision: RadrootsTradeOrderDecisionEvent, + pub request: RadrootsSp1TradeOrderRequestWitness, + pub decision: RadrootsSp1TradeOrderDecisionEventWitness, pub inventory_bins: Vec<RadrootsSp1TradeInventoryBinWitness>, pub inventory_sequence: u128, pub previous_state_root: Option<String>, @@ -124,14 +164,8 @@ pub fn reduce_order_acceptance_public_values( witness: &RadrootsSp1TradeOrderAcceptanceWitness, ) -> Result<RadrootsSp1TradePublicValuesExecution, RadrootsSp1TradeGuestError> { validate_witness_header(witness)?; - witness - .request - .validate() - .map_err(|_| RadrootsSp1TradeGuestError::InvalidOrderRequest)?; - witness - .decision - .validate() - .map_err(|_| RadrootsSp1TradeGuestError::InvalidOrderDecision)?; + validate_order_request_shape(&witness.request)?; + validate_order_decision_shape(&witness.decision)?; validate_order_binding(witness)?; let request_counts = aggregate_requested_counts(&witness.request)?; @@ -233,6 +267,13 @@ pub fn public_values_hash_hex( Ok(validation_receipt_public_values_hash_hex(&bytes)) } +pub fn validation_receipt_public_values_hash_hex(public_values: &[u8]) -> String { + let mut hasher = Sha256::new(); + hasher.update(b"radroots:sp1-public-values:v1"); + hasher.update(public_values); + format!("0x{}", hex_lower(hasher.finalize().as_slice())) +} + pub fn empty_state_root() -> String { hash_bytes("radroots:state-empty:v1", &[]) } @@ -255,12 +296,60 @@ fn validate_witness_header( Ok(()) } +fn validate_order_request_shape( + request: &RadrootsSp1TradeOrderRequestWitness, +) -> Result<(), RadrootsSp1TradeGuestError> { + validate_required_str(&request.order_id, "request.order_id")?; + validate_required_str(&request.listing_addr, "request.listing_addr")?; + validate_required_str(&request.buyer_pubkey, "request.buyer_pubkey")?; + validate_required_str(&request.seller_pubkey, "request.seller_pubkey")?; + if request.items.is_empty() { + return Err(RadrootsSp1TradeGuestError::InvalidOrderRequest); + } + for item in &request.items { + validate_required_str(&item.bin_id, "request.items.bin_id")?; + if item.bin_count == 0 { + return Err(RadrootsSp1TradeGuestError::InvalidOrderRequest); + } + } + Ok(()) +} + +fn validate_order_decision_shape( + decision: &RadrootsSp1TradeOrderDecisionEventWitness, +) -> Result<(), RadrootsSp1TradeGuestError> { + validate_required_str(&decision.order_id, "decision.order_id")?; + validate_required_str(&decision.listing_addr, "decision.listing_addr")?; + validate_required_str(&decision.buyer_pubkey, "decision.buyer_pubkey")?; + validate_required_str(&decision.seller_pubkey, "decision.seller_pubkey")?; + match &decision.decision { + RadrootsSp1TradeOrderDecisionWitness::Accepted { + inventory_commitments, + } => { + if inventory_commitments.is_empty() { + return Err(RadrootsSp1TradeGuestError::InvalidOrderDecision); + } + for commitment in inventory_commitments { + validate_required_str(&commitment.bin_id, "decision.inventory_commitments.bin_id")?; + if commitment.bin_count == 0 { + return Err(RadrootsSp1TradeGuestError::InvalidOrderDecision); + } + } + Ok(()) + } + RadrootsSp1TradeOrderDecisionWitness::Declined { reason } => { + validate_required_str(reason, "decision.reason")?; + Ok(()) + } + } +} + fn validate_order_binding( witness: &RadrootsSp1TradeOrderAcceptanceWitness, ) -> Result<(), RadrootsSp1TradeGuestError> { if !matches!( witness.decision.decision, - RadrootsTradeOrderDecision::Accepted { .. } + RadrootsSp1TradeOrderDecisionWitness::Accepted { .. } ) { return Err(RadrootsSp1TradeGuestError::DecisionNotAccepted); } @@ -286,7 +375,7 @@ fn validate_order_binding( } fn aggregate_requested_counts( - request: &RadrootsTradeOrderRequested, + request: &RadrootsSp1TradeOrderRequestWitness, ) -> Result<BTreeMap<String, u64>, RadrootsSp1TradeGuestError> { let mut counts = BTreeMap::new(); for item in &request.items { @@ -299,9 +388,9 @@ fn aggregate_requested_counts( } fn aggregate_accepted_counts( - decision: &RadrootsTradeOrderDecisionEvent, + decision: &RadrootsSp1TradeOrderDecisionEventWitness, ) -> Result<BTreeMap<String, u64>, RadrootsSp1TradeGuestError> { - let RadrootsTradeOrderDecision::Accepted { + let RadrootsSp1TradeOrderDecisionWitness::Accepted { inventory_commitments, } = &decision.decision else { @@ -495,18 +584,12 @@ mod tests { use super::{ RADROOTS_SP1_TRADE_PROTOCOL_VERSION, RADROOTS_SP1_TRADE_REDUCER_PROGRAM_HASH, RadrootsSp1TradeGuestError, RadrootsSp1TradeInventoryBinWitness, - RadrootsSp1TradeOrderAcceptanceWitness, RadrootsSp1TradeProofResult, - RadrootsSp1TradeProofTransitionKind, canonical_public_values_bytes, - reduce_order_acceptance_canonical_public_values, reduce_order_acceptance_public_values, - }; - use radroots_core::{ - RadrootsCoreCurrency, RadrootsCoreDecimal, RadrootsCoreMoney, RadrootsCoreUnit, - }; - use radroots_events::trade::{ - RadrootsTradeInventoryCommitment, RadrootsTradeOrderDecision, - RadrootsTradeOrderDecisionEvent, RadrootsTradeOrderEconomicItem, - RadrootsTradeOrderEconomicLine, RadrootsTradeOrderEconomics, RadrootsTradeOrderItem, - RadrootsTradeOrderRequested, RadrootsTradePricingBasis, + RadrootsSp1TradeInventoryCommitmentWitness, RadrootsSp1TradeOrderAcceptanceWitness, + RadrootsSp1TradeOrderDecisionEventWitness, RadrootsSp1TradeOrderDecisionWitness, + RadrootsSp1TradeOrderItemWitness, RadrootsSp1TradeOrderRequestWitness, + RadrootsSp1TradeProofResult, RadrootsSp1TradeProofTransitionKind, + canonical_public_values_bytes, reduce_order_acceptance_canonical_public_values, + reduce_order_acceptance_public_values, }; fn witness() -> RadrootsSp1TradeOrderAcceptanceWitness { @@ -534,8 +617,8 @@ mod tests { } } - fn request(bin_count: u32) -> RadrootsTradeOrderRequested { - RadrootsTradeOrderRequested { + fn request(bin_count: u32) -> RadrootsSp1TradeOrderRequestWitness { + RadrootsSp1TradeOrderRequestWitness { order_id: "order-1".to_string(), listing_addr: "30402:1111111111111111111111111111111111111111111111111111111111111111:listing-1" @@ -544,16 +627,15 @@ mod tests { .to_string(), seller_pubkey: "1111111111111111111111111111111111111111111111111111111111111111" .to_string(), - items: vec![RadrootsTradeOrderItem { + items: vec![RadrootsSp1TradeOrderItemWitness { bin_id: "bin-1".to_string(), bin_count, }], - economics: economics(bin_count), } } - fn decision(bin_count: u32) -> RadrootsTradeOrderDecisionEvent { - RadrootsTradeOrderDecisionEvent { + fn decision(bin_count: u32) -> RadrootsSp1TradeOrderDecisionEventWitness { + RadrootsSp1TradeOrderDecisionEventWitness { order_id: "order-1".to_string(), listing_addr: "30402:1111111111111111111111111111111111111111111111111111111111111111:listing-1" @@ -562,8 +644,8 @@ mod tests { .to_string(), seller_pubkey: "1111111111111111111111111111111111111111111111111111111111111111" .to_string(), - decision: RadrootsTradeOrderDecision::Accepted { - inventory_commitments: vec![RadrootsTradeInventoryCommitment { + decision: RadrootsSp1TradeOrderDecisionWitness::Accepted { + inventory_commitments: vec![RadrootsSp1TradeInventoryCommitmentWitness { bin_id: "bin-1".to_string(), bin_count, }], @@ -571,40 +653,6 @@ mod tests { } } - fn economics(bin_count: u32) -> RadrootsTradeOrderEconomics { - let subtotal = - (RadrootsCoreDecimal::from(5u32) * RadrootsCoreDecimal::from(bin_count)).to_string(); - RadrootsTradeOrderEconomics { - quote_id: "quote-1".to_string(), - quote_version: 1, - pricing_basis: RadrootsTradePricingBasis::ListingEvent, - currency: RadrootsCoreCurrency::USD, - items: vec![RadrootsTradeOrderEconomicItem { - bin_id: "bin-1".to_string(), - bin_count, - quantity_amount: decimal("1"), - quantity_unit: RadrootsCoreUnit::Each, - unit_price_amount: decimal("5"), - unit_price_currency: RadrootsCoreCurrency::USD, - line_subtotal: usd(&subtotal), - }], - discounts: Vec::<RadrootsTradeOrderEconomicLine>::new(), - adjustments: Vec::<RadrootsTradeOrderEconomicLine>::new(), - subtotal: usd(&subtotal), - discount_total: usd("0"), - adjustment_total: usd("0"), - total: usd(&subtotal), - } - } - - fn decimal(raw: &str) -> RadrootsCoreDecimal { - raw.parse().expect("decimal") - } - - fn usd(raw: &str) -> RadrootsCoreMoney { - RadrootsCoreMoney::new(decimal(raw), RadrootsCoreCurrency::USD) - } - #[test] fn order_acceptance_public_values_are_deterministic() { let left = reduce_order_acceptance_public_values(&witness()).expect("left execution"); diff --git a/crates/sp1_host_trade/Cargo.toml b/crates/sp1_host_trade/Cargo.toml @@ -3,6 +3,7 @@ name = "radroots_sp1_host_trade" publish = false version = "0.1.0-alpha.2" edition.workspace = true +build = "build.rs" authors = ["Tyson Lupul <tyson@radroots.org>"] rust-version.workspace = true license.workspace = true @@ -12,7 +13,7 @@ homepage.workspace = true [features] default = [] -expensive_proofs = ["dep:sp1-sdk"] +expensive_proofs = ["dep:sp1-build", "dep:sp1-sdk"] [dependencies] base64 = { workspace = true } @@ -27,6 +28,9 @@ sha2 = { workspace = true } sp1-sdk = { workspace = true, optional = true } thiserror = { workspace = true } +[build-dependencies] +sp1-build = { workspace = true, optional = true } + [dev-dependencies] -radroots_core = { workspace = true } radroots_events = { workspace = true, features = ["serde"] } +tokio = { workspace = true, features = ["rt-multi-thread"] } diff --git a/crates/sp1_host_trade/build.rs b/crates/sp1_host_trade/build.rs @@ -0,0 +1,13 @@ +fn main() { + println!("cargo:rerun-if-env-changed=CARGO_FEATURE_EXPENSIVE_PROOFS"); + #[cfg(feature = "expensive_proofs")] + { + let args = sp1_build::BuildArgs { + binaries: vec!["radroots_sp1_trade_order_acceptance_guest".to_string()], + features: vec!["sp1_guest".to_string()], + locked: true, + ..sp1_build::BuildArgs::default() + }; + sp1_build::build_program_with_args("../sp1_guest_trade", args); + } +} diff --git a/crates/sp1_host_trade/src/lib.rs b/crates/sp1_host_trade/src/lib.rs @@ -80,6 +80,14 @@ pub enum RadrootsSp1TradeHostError { MissingProofMaterial, #[error("receipt binding field {0} is missing")] MissingReceiptBinding(&'static str), + #[error("SP1 execution failed: {0}")] + Sp1ExecuteFailed(String), + #[error("SP1 execution returned exit code {0}")] + Sp1ExitCode(u64), + #[error("SP1 public values failed to decode: {0}")] + Sp1PublicValuesDecode(String), + #[error("SP1 public values do not match deterministic reducer output")] + Sp1PublicValuesMismatch, #[error("proof artifact encoding failed")] ProofEncoding, } @@ -96,6 +104,97 @@ pub fn execute_order_acceptance_public_values( Ok(reduce_order_acceptance_public_values(witness)?) } +#[cfg(feature = "expensive_proofs")] +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct RadrootsSp1TradeExecuteReport { + pub exit_code: u64, + pub gas: Option<u64>, + pub total_instruction_count: u64, + pub total_syscall_count: u64, +} + +#[cfg(feature = "expensive_proofs")] +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct RadrootsSp1TradeExecuteBundle { + pub committed_public_values: Vec<u8>, + pub execution: RadrootsSp1TradePublicValuesExecution, + pub report: RadrootsSp1TradeExecuteReport, +} + +#[cfg(feature = "expensive_proofs")] +pub fn order_acceptance_guest_elf() -> sp1_sdk::Elf { + sp1_sdk::include_elf!("radroots_sp1_trade_order_acceptance_guest") +} + +#[cfg(feature = "expensive_proofs")] +pub async fn execute_order_acceptance_sp1_public_values( + witness: &RadrootsSp1TradeOrderAcceptanceWitness, +) -> Result<RadrootsSp1TradeExecuteBundle, RadrootsSp1TradeHostError> { + execute_order_acceptance_sp1_public_values_with_elf(order_acceptance_guest_elf(), witness).await +} + +#[cfg(feature = "expensive_proofs")] +pub async fn execute_order_acceptance_sp1_public_values_with_elf( + elf: sp1_sdk::Elf, + witness: &RadrootsSp1TradeOrderAcceptanceWitness, +) -> Result<RadrootsSp1TradeExecuteBundle, RadrootsSp1TradeHostError> { + use sp1_sdk::{Prover, ProverClient, SP1Stdin, StatusCode}; + + let expected = execute_order_acceptance_public_values(witness)?; + let mut stdin = SP1Stdin::new(); + stdin.write(witness); + let client = ProverClient::builder().light().build().await; + let (public_values, report) = client + .execute(elf, stdin) + .calculate_gas(true) + .expected_exit_code(StatusCode::SUCCESS) + .await + .map_err(|error| RadrootsSp1TradeHostError::Sp1ExecuteFailed(error.to_string()))?; + if report.exit_code != 0 { + return Err(RadrootsSp1TradeHostError::Sp1ExitCode(report.exit_code)); + } + + let committed_public_values = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + let mut public_values = public_values; + public_values.read::<Vec<u8>>() + })) + .map_err(|_| { + RadrootsSp1TradeHostError::Sp1PublicValuesDecode( + "SP1 public values stream did not contain canonical bytes".to_string(), + ) + })?; + let decoded: radroots_sp1_guest_trade::RadrootsSp1TradeProofPublicValues = + serde_json::from_slice(&committed_public_values).map_err(|error| { + RadrootsSp1TradeHostError::Sp1PublicValuesDecode(format!( + "{error}; public values bytes={}; prefix={}", + committed_public_values.len(), + public_values_prefix(&committed_public_values) + )) + })?; + let canonical_public_values = radroots_sp1_guest_trade::canonical_public_values_bytes(&decoded) + .map_err(|error| RadrootsSp1TradeHostError::Sp1PublicValuesDecode(error.to_string()))?; + let public_values_hash = radroots_sp1_guest_trade::public_values_hash_hex(&decoded)?; + let execution = RadrootsSp1TradePublicValuesExecution { + public_values: decoded, + public_values_hash, + canonical_public_values, + }; + if execution != expected { + return Err(RadrootsSp1TradeHostError::Sp1PublicValuesMismatch); + } + + Ok(RadrootsSp1TradeExecuteBundle { + committed_public_values, + execution, + report: RadrootsSp1TradeExecuteReport { + exit_code: report.exit_code, + gas: report.gas(), + total_instruction_count: report.total_instruction_count(), + total_syscall_count: report.total_syscall_count(), + }, + }) +} + pub fn generate_order_acceptance_proof( witness: &RadrootsSp1TradeOrderAcceptanceWitness, mode: RadrootsSp1TradeProofMode, @@ -238,6 +337,12 @@ fn hex_lower(bytes: &[u8]) -> String { out } +#[cfg(feature = "expensive_proofs")] +fn public_values_prefix(bytes: &[u8]) -> String { + const PREFIX_LEN: usize = 32; + hex_lower(&bytes[..bytes.len().min(PREFIX_LEN)]) +} + #[derive(Serialize)] struct ProofDigestMaterial<'a> { canonical_public_values: &'a [u8], @@ -255,22 +360,13 @@ mod tests { RadrootsSp1TradeHostError, RadrootsSp1TradeProofMode, generate_order_acceptance_proof, validation_receipt_for_order_acceptance_proof, verify_order_acceptance_proof_artifact, }; - use radroots_core::{ - RadrootsCoreCurrency, RadrootsCoreDecimal, RadrootsCoreMoney, RadrootsCoreUnit, - }; - use radroots_events::{ - RadrootsNostrEvent, - kinds::KIND_TRADE_VALIDATION_RECEIPT, - trade::{ - RadrootsTradeInventoryCommitment, RadrootsTradeOrderDecision, - RadrootsTradeOrderDecisionEvent, RadrootsTradeOrderEconomicItem, - RadrootsTradeOrderEconomicLine, RadrootsTradeOrderEconomics, RadrootsTradeOrderItem, - RadrootsTradeOrderRequested, RadrootsTradePricingBasis, - }, - }; + use radroots_events::{RadrootsNostrEvent, kinds::KIND_TRADE_VALIDATION_RECEIPT}; use radroots_sp1_guest_trade::{ RADROOTS_SP1_TRADE_PROTOCOL_VERSION, RADROOTS_SP1_TRADE_REDUCER_PROGRAM_HASH, - RadrootsSp1TradeInventoryBinWitness, RadrootsSp1TradeOrderAcceptanceWitness, + RadrootsSp1TradeInventoryBinWitness, RadrootsSp1TradeInventoryCommitmentWitness, + RadrootsSp1TradeOrderAcceptanceWitness, RadrootsSp1TradeOrderDecisionEventWitness, + RadrootsSp1TradeOrderDecisionWitness, RadrootsSp1TradeOrderItemWitness, + RadrootsSp1TradeOrderRequestWitness, }; use radroots_trade::validation_receipt::{ RadrootsValidationReceiptExpectedBinding, RadrootsValidationReceiptProofSystem, @@ -302,8 +398,8 @@ mod tests { } } - fn request(bin_count: u32) -> RadrootsTradeOrderRequested { - RadrootsTradeOrderRequested { + fn request(bin_count: u32) -> RadrootsSp1TradeOrderRequestWitness { + RadrootsSp1TradeOrderRequestWitness { order_id: "order-1".to_string(), listing_addr: "30402:1111111111111111111111111111111111111111111111111111111111111111:listing-1" @@ -312,16 +408,15 @@ mod tests { .to_string(), seller_pubkey: "1111111111111111111111111111111111111111111111111111111111111111" .to_string(), - items: vec![RadrootsTradeOrderItem { + items: vec![RadrootsSp1TradeOrderItemWitness { bin_id: "bin-1".to_string(), bin_count, }], - economics: economics(bin_count), } } - fn decision(bin_count: u32) -> RadrootsTradeOrderDecisionEvent { - RadrootsTradeOrderDecisionEvent { + fn decision(bin_count: u32) -> RadrootsSp1TradeOrderDecisionEventWitness { + RadrootsSp1TradeOrderDecisionEventWitness { order_id: "order-1".to_string(), listing_addr: "30402:1111111111111111111111111111111111111111111111111111111111111111:listing-1" @@ -330,8 +425,8 @@ mod tests { .to_string(), seller_pubkey: "1111111111111111111111111111111111111111111111111111111111111111" .to_string(), - decision: RadrootsTradeOrderDecision::Accepted { - inventory_commitments: vec![RadrootsTradeInventoryCommitment { + decision: RadrootsSp1TradeOrderDecisionWitness::Accepted { + inventory_commitments: vec![RadrootsSp1TradeInventoryCommitmentWitness { bin_id: "bin-1".to_string(), bin_count, }], @@ -339,40 +434,6 @@ mod tests { } } - fn economics(bin_count: u32) -> RadrootsTradeOrderEconomics { - let subtotal = - (RadrootsCoreDecimal::from(5u32) * RadrootsCoreDecimal::from(bin_count)).to_string(); - RadrootsTradeOrderEconomics { - quote_id: "quote-1".to_string(), - quote_version: 1, - pricing_basis: RadrootsTradePricingBasis::ListingEvent, - currency: RadrootsCoreCurrency::USD, - items: vec![RadrootsTradeOrderEconomicItem { - bin_id: "bin-1".to_string(), - bin_count, - quantity_amount: decimal("1"), - quantity_unit: RadrootsCoreUnit::Each, - unit_price_amount: decimal("5"), - unit_price_currency: RadrootsCoreCurrency::USD, - line_subtotal: usd(&subtotal), - }], - discounts: Vec::<RadrootsTradeOrderEconomicLine>::new(), - adjustments: Vec::<RadrootsTradeOrderEconomicLine>::new(), - subtotal: usd(&subtotal), - discount_total: usd("0"), - adjustment_total: usd("0"), - total: usd(&subtotal), - } - } - - fn decimal(raw: &str) -> RadrootsCoreDecimal { - raw.parse().expect("decimal") - } - - fn usd(raw: &str) -> RadrootsCoreMoney { - RadrootsCoreMoney::new(decimal(raw), RadrootsCoreCurrency::USD) - } - #[test] fn execute_public_values_and_bind_validation_receipt() { let bundle = @@ -468,6 +529,23 @@ mod tests { } #[cfg(feature = "expensive_proofs")] + #[tokio::test] + async fn sp1_execute_public_values_match_deterministic_reducer() { + let execution = super::execute_order_acceptance_sp1_public_values(&witness()) + .await + .expect("sp1 execute"); + let expected = super::execute_order_acceptance_public_values(&witness()) + .expect("deterministic execution"); + assert_eq!(execution.execution, expected); + assert_eq!( + execution.committed_public_values, + expected.canonical_public_values + ); + assert_eq!(execution.report.exit_code, 0); + assert!(execution.report.total_instruction_count > 0); + } + + #[cfg(feature = "expensive_proofs")] #[test] fn expensive_proof_generation_and_verification_is_runnable() { let bundle =