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:
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 =