From f2d7cfe985f75f8aae1356a4d901b241629dc1fe Mon Sep 17 00:00:00 2001 From: "Eduard S." Date: Wed, 15 Oct 2025 15:34:08 +0200 Subject: [PATCH 1/8] add st builder macros --- Cargo.lock | 1 - Cargo.toml | 3 + app/src/lib.rs | 330 ++++++++++++++++++++++--------------------------- 3 files changed, 153 insertions(+), 181 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8df1ebc..0ba8a21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3774,7 +3774,6 @@ dependencies = [ [[package]] name = "pod2_onchain" version = "0.1.0" -source = "git+https://github.com/0xPARC/pod2-onchain.git?rev=0df0e99ddf37842eb8395ae06ab92a8d79b76cfb#0df0e99ddf37842eb8395ae06ab92a8d79b76cfb" dependencies = [ "anyhow", "bindgen", diff --git a/Cargo.toml b/Cargo.toml index cc0b662..e078974 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,5 +50,8 @@ pod2 = { git = "https://github.com/0xPARC/pod2?rev=main", rev = "d355e55159dbe7e # [patch."https://github.com/0xPARC/plonky2"] # plonky2 = { path = "../plonky2/plonky2" } +[patch."https://github.com/0xPARC/pod2-onchain"] +pod2_onchain = { path = "../pod2-onchain" } + # [profile.release] # debug = true diff --git a/app/src/lib.rs b/app/src/lib.rs index 5fba430..de6aafb 100644 --- a/app/src/lib.rs +++ b/app/src/lib.rs @@ -6,7 +6,7 @@ use std::{ str::FromStr, }; -use anyhow::{Context, Result}; +use anyhow::{Context, Result, bail}; use common::set_from_value; use hex::ToHex; use pod2::{ @@ -21,13 +21,33 @@ use serde::{Deserialize, Serialize}; pub const DEPTH: usize = 32; +#[macro_export] +macro_rules! set { + () => ({ + pod2::middleware::containers::Set::new(DEPTH, std::collections::HashSet::new()).unwrap() + }); + ($($val:expr),* ,) => ( + $crate::set!($($val),*).unwrap() + ); + ($($val:expr),*) => ({ + let mut set = std::collections::HashSet::new(); + $( set.insert($crate::middleware::Value::from($val)); )* + pod2::middleware::containers::Set::new(DEPTH, set).unwrap() + }); +} + #[macro_export] macro_rules! dict { + ({ }) => ( + pod2::middleware::containers::Dictionary::new(DEPTH, std::collections::HashMap::new()).unwrap() + ); ({ $($key:expr => $val:expr),* , }) => ( $crate::dict!({ $($key => $val),* }).unwrap() ); ({ $($key:expr => $val:expr),* }) => ({ - pod2::dict!(DEPTH, { $($key => $val),* }).unwrap() + let mut map = std::collections::HashMap::new(); + $( map.insert(pod2::middleware::Key::from($key.clone()), pod2::middleware::Value::from($val.clone())); )* + pod2::middleware::containers::Dictionary::new(DEPTH, map).unwrap() }); } @@ -340,6 +360,58 @@ pub fn build_predicates(params: &Params) -> (Predicates, RevPredicates) { (state_preds, rev_preds) } +macro_rules! op { + (Equal($a:expr, $b:expr)) => { + pod2::frontend::Operation::eq($a.clone(), $b.clone()) + }; + (DictContains($dict:expr, $key:expr, $value:expr)) => { + pod2::frontend::Operation::dict_contains($dict.clone(), $key.clone(), $value.clone()) + }; + (DictUpdate($dict:expr, $old_dict:expr, $key:expr, $value:expr)) => { + pod2::frontend::Operation::dict_update( + $dict.clone(), + $old_dict.clone(), + $key.clone(), + $value.clone(), + ) + }; + (DictInsert($dict:expr, $old_dict:expr, $key:expr, $value:expr)) => { + pod2::frontend::Operation::dict_insert( + $dict.clone(), + $old_dict.clone(), + $key.clone(), + $value.clone(), + ) + }; + (DictDelete($dict:expr, $old_dict:expr, $key:expr)) => { + pod2::frontend::Operation::dict_delete($dict.clone(), $old_dict.clone(), $key.clone()) + }; + (SetInsert($set:expr, $old_set:expr, $value:expr)) => { + pod2::frontend::Operation::set_insert($set.clone(), $old_set.clone(), $value.clone()) + }; + (SetDelete($set:expr, $old_set:expr, $value:expr)) => { + pod2::frontend::Operation::set_delete($set.clone(), $old_set.clone(), $value.clone()) + }; +} + +macro_rules! st { + ($builder:expr, $pred:ident($($args:expr),+)) => { + $builder.priv_op(op!($pred($($args),+))).unwrap() + }; +} + +macro_rules! st_custom_from_ops { + ($builder:expr, $custom_pred:expr, ($($ops:expr),+)) => ({ + let mut input_sts = Vec::new(); + $( input_sts.push($builder.priv_op($ops).unwrap()); )* + $builder.priv_op(pod2::frontend::Operation::custom( + $custom_pred.clone(), + input_sts + )) + .unwrap() + }) +} + pub struct Helper<'a> { pub builder: &'a mut MainPodBuilder, pub predicates: &'a Predicates, @@ -356,37 +428,25 @@ impl<'a> Helper<'a> { pub fn st_init(&mut self, old: Dictionary, op: Dictionary) -> Result<(Dictionary, Statement)> { let name = String::try_from(op.get(&Key::from("name")).unwrap().typed()).unwrap(); assert_eq!(name, "init"); - // DictContains(op, "name", "init") - let st0 = self - .builder - .priv_op(Operation::dict_contains(op.clone(), "name", "init")) - .unwrap(); - // Equal(old, EMPTY) - let st1 = self - .builder - .priv_op(Operation::eq(old.clone(), EMPTY_VALUE)) - .context("old state is not empty")?; - - let empty_group = Value::from(Set::new(DEPTH, HashSet::new()).unwrap()); + if Value::from(old.clone()) != Value::from(EMPTY_VALUE) { + bail!("old state is not empty") + } let init_state = dict!({ - "red" => empty_group.clone(), - "green" => empty_group.clone(), - "blue" => empty_group} + "red" => set!(), + "green" => set!(), + "blue" => set!()} ); - // Equal(new, {"red": EMPTY, "green": EMPTY, "blue": EMPTY}) - let st2 = self - .builder - .priv_op(Operation::eq(init_state.clone(), init_state.clone())) - .unwrap(); // init(new, old, op) - let st = self - .builder - .priv_op(Operation::custom( - self.predicates.init.clone(), - [st0, st1, st2], - )) - .unwrap(); + let st = st_custom_from_ops!( + self.builder, + self.predicates.init, + ( + op!(DictContains(op, "name", "init")), + op!(Equal(old, EMPTY_VALUE)), + op!(Equal(init_state, init_state)) + ) + ); Ok((init_state, st)) } @@ -399,28 +459,14 @@ impl<'a> Helper<'a> { assert!(name == "add" || name == "del"); let st0 = if name == "add" { - // DictContains(op, "name", "add") - self.builder - .priv_op(Operation::dict_contains(op.clone(), "name", "add")) - .unwrap() + st!(self.builder, DictContains(op, "name", "add")) } else { - // DictContains(op, "name", "del") - self.builder - .priv_op(Operation::dict_contains(op.clone(), "name", "del")) - .unwrap() + st!(self.builder, DictContains(op, "name", "del")) }; let group = Key::try_from(op.get(&Key::from("group")).unwrap().typed()).unwrap(); let old_group = old.get(&group).unwrap(); - // DictContains(old, op.group, old_group) - let st1 = self - .builder - .priv_op(Operation::dict_contains( - old.clone(), - (&op, "group"), - old_group.clone(), - )) - .unwrap(); + let st1 = st!(self.builder, DictContains(old, (&op, "group"), old_group)); let user = op.get(&Key::from("user")).unwrap(); let mut new_group = if let TypedValue::Set(set) = old_group.typed() { @@ -429,39 +475,26 @@ impl<'a> Helper<'a> { panic!("Value not a Set: {:?}", old_group) }; let st2 = if name == "add" { + if new_group.contains(user) { + bail!("old_group already contains user"); + } new_group.insert(user).unwrap(); - // SetInsert(new_group, old_group, op.user) - self.builder - .priv_op(Operation::set_insert( - new_group.clone(), - old_group.clone(), - (&op, "user"), - )) - .context("old_group already contains user")? + st!(self.builder, SetInsert(new_group, old_group, (&op, "user"))) } else { + if !new_group.contains(user) { + bail!("old_group doesn't contain user"); + } new_group.delete(user).unwrap(); - // SetDelete(new_group, old_group, op.user) - self.builder - .priv_op(Operation::set_delete( - new_group.clone(), - old_group.clone(), - (&op, "user"), - )) - .context("old_group doesn't contain user")? + st!(self.builder, SetDelete(new_group, old_group, (&op, "user"))) }; let mut new = old.clone(); new.update(&group, &Value::from(new_group.clone())).unwrap(); // DictUpdate(new, old, op.group, new_group) - let st3 = self - .builder - .priv_op(Operation::dict_update( - new.clone(), - old.clone(), - (&op, "group"), - new_group, - )) - .unwrap(); + let st3 = st!( + self.builder, + DictUpdate(new, old, (&op, "group"), new_group) + ); let st = if name == "add" { // add(new, old, op, private: old_group, new_group) @@ -542,15 +575,9 @@ impl<'a> RevHelper<'a> { st_update: Statement, op: Dictionary, ) -> (Dictionary, Statement) { - let init_rev_state = Dictionary::new(DEPTH, HashMap::new()).unwrap(); - let st1 = self - .builder - .priv_op(Operation::dict_contains(op.clone(), "name", "init")) - .unwrap(); - let st2 = self - .builder - .priv_op(Operation::eq(init_rev_state.clone(), EMPTY_VALUE)) - .unwrap(); + let init_rev_state = dict!({}); + let st1 = st!(self.builder, DictContains(op, "name", "init")); + let st2 = st!(self.builder, Equal(init_rev_state, EMPTY_VALUE)); ( init_rev_state, self.builder @@ -576,23 +603,14 @@ impl<'a> RevHelper<'a> { new_rev .insert(user, &Value::from(user_groups.clone())) .unwrap(); - let st0 = self - .builder - .priv_op(Operation::set_insert( - user_groups.clone(), - empty_set, - (&op, "group"), - )) - .unwrap(); - let st1 = self - .builder - .priv_op(Operation::dict_insert( - new_rev.clone(), - old_rev, - (&op, "user"), - user_groups, - )) - .unwrap(); + let st0 = st!( + self.builder, + SetInsert(user_groups, empty_set, (&op, "group")) + ); + let st1 = st!( + self.builder, + DictInsert(new_rev, old_rev, (&op, "user"), user_groups) + ); ( new_rev, self.builder @@ -623,31 +641,18 @@ impl<'a> RevHelper<'a> { .update(user, &Value::from(user_groups.clone())) .unwrap(); - let st0 = self - .builder - .priv_op(Operation::dict_contains( - old_rev.clone(), - (&op, "user"), - old_user_groups.clone(), - )) - .unwrap(); - let st1 = self - .builder - .priv_op(Operation::set_insert( - user_groups.clone(), - old_user_groups.clone(), - (&op, "group"), - )) - .unwrap(); - let st2 = self - .builder - .priv_op(Operation::dict_update( - new_rev.clone(), - old_rev, - (&op, "user"), - user_groups, - )) - .unwrap(); + let st0 = st!( + self.builder, + DictContains(old_rev, (&op, "user"), old_user_groups) + ); + let st1 = st!( + self.builder, + SetInsert(user_groups, old_user_groups, (&op, "group")) + ); + let st2 = st!( + self.builder, + DictUpdate(new_rev, old_rev, (&op, "user"), user_groups) + ); ( new_rev, self.builder @@ -690,34 +695,18 @@ impl<'a> RevHelper<'a> { user: &Key, ) -> (Dictionary, Statement) { let old_user_groups = old_rev.get(user).unwrap(); - let empty_set = Set::new(DEPTH, HashSet::new()).unwrap(); let mut new_rev = old_rev.clone(); new_rev.delete(user).unwrap(); - let st0 = self - .builder - .priv_op(Operation::dict_contains( - old_rev.clone(), - (&op, "user"), - old_user_groups.clone(), - )) - .unwrap(); - let st1 = self - .builder - .priv_op(Operation::set_delete( - empty_set, - old_user_groups.clone(), - (&op, "group"), - )) - .unwrap(); - let st2 = self - .builder - .priv_op(Operation::dict_delete( - new_rev.clone(), - old_rev, - (&op, "user"), - )) - .unwrap(); + let st0 = st!( + self.builder, + DictContains(old_rev, (&op, "user"), old_user_groups) + ); + let st1 = st!( + self.builder, + SetDelete(set!(), old_user_groups, (&op, "group")) + ); + let st2 = st!(self.builder, DictDelete(new_rev, old_rev, (&op, "user"))); ( new_rev, self.builder @@ -748,31 +737,18 @@ impl<'a> RevHelper<'a> { .update(user, &Value::from(user_groups.clone())) .unwrap(); - let st0 = self - .builder - .priv_op(Operation::dict_contains( - old_rev.clone(), - (&op, "user"), - old_user_groups.clone(), - )) - .unwrap(); - let st1 = self - .builder - .priv_op(Operation::set_delete( - user_groups.clone(), - old_user_groups.clone(), - (&op, "group"), - )) - .unwrap(); - let st2 = self - .builder - .priv_op(Operation::dict_update( - new_rev.clone(), - old_rev, - (&op, "user"), - user_groups, - )) - .unwrap(); + let st0 = st!( + self.builder, + DictContains(old_rev, (&op, "user"), old_user_groups) + ); + let st1 = st!( + self.builder, + SetDelete(user_groups, old_user_groups, (&op, "group")) + ); + let st2 = st!( + self.builder, + DictUpdate(new_rev, old_rev, (&op, "user"), user_groups) + ); ( new_rev, self.builder @@ -822,10 +798,7 @@ impl<'a> RevHelper<'a> { old_st_rev_sync: Statement, op: Dictionary, ) -> (Dictionary, Statement) { - let st2 = self - .builder - .priv_op(Operation::dict_contains(op.clone(), "name", "add")) - .unwrap(); + let st2 = st!(self.builder, DictContains(op, "name", "add")); let (new, st3) = self.st_rev_add(old_rev, op); ( new, @@ -845,10 +818,7 @@ impl<'a> RevHelper<'a> { old_st_rev_sync: Statement, op: Dictionary, ) -> (Dictionary, Statement) { - let st2 = self - .builder - .priv_op(Operation::dict_contains(op.clone(), "name", "del")) - .unwrap(); + let st2 = st!(self.builder, DictContains(op.clone(), "name", "del")); let (new, st3) = self.st_rev_del(old_rev, op); ( new, From b7aac950de3ba0fc9701ca02778651530f4f8540 Mon Sep 17 00:00:00 2001 From: "Eduard S." Date: Wed, 15 Oct 2025 16:00:09 +0200 Subject: [PATCH 2/8] wip --- app/src/lib.rs | 144 +++++++++++++++++++++++++++++++------------------ 1 file changed, 93 insertions(+), 51 deletions(-) diff --git a/app/src/lib.rs b/app/src/lib.rs index de6aafb..0aa7bd4 100644 --- a/app/src/lib.rs +++ b/app/src/lib.rs @@ -4,6 +4,7 @@ use std::{ collections::{HashMap, HashSet}, fmt, str::FromStr, + sync::Arc, }; use anyhow::{Context, Result, bail}; @@ -13,7 +14,8 @@ use pod2::{ frontend::{MainPodBuilder, Operation}, lang::parse, middleware::{ - CustomPredicateRef, EMPTY_VALUE, Key, Params, Statement, TypedValue, Value, + CustomPredicateBatch, CustomPredicateRef, EMPTY_VALUE, Key, Params, Statement, TypedValue, + Value, containers::{Dictionary, Set}, }, }; @@ -412,16 +414,52 @@ macro_rules! st_custom_from_ops { }) } +fn find_custom_pred_by_name( + batches: &[Arc], + name: &str, +) -> Option { + for batch in batches { + for (index, predicate) in batch.predicates().iter().enumerate() { + if predicate.name == name { + return Some(CustomPredicateRef { + batch: batch.clone(), + index, + }); + } + } + } + return None; +} + +macro_rules! st_custom_from_ops2 { + ($builder:expr, $batches:expr, $pred:ident($($ops:expr),+)) => ({ + let custom_pred = find_custom_pred_by_name($batches, stringify!($pred)).unwrap(); + let mut input_sts = Vec::new(); + $( input_sts.push($builder.priv_op($ops).unwrap()); )* + $builder.priv_op(pod2::frontend::Operation::custom( + custom_pred, + input_sts + )) + .unwrap() + }) +} + pub struct Helper<'a> { pub builder: &'a mut MainPodBuilder, + pub batches: &'a [Arc], pub predicates: &'a Predicates, } impl<'a> Helper<'a> { - pub fn new(pod_builder: &'a mut MainPodBuilder, predicates: &'a Predicates) -> Self { + pub fn new( + pod_builder: &'a mut MainPodBuilder, + predicates: &'a Predicates, + batches: &'a [Arc], + ) -> Self { Self { builder: pod_builder, predicates, + batches, } } @@ -438,10 +476,10 @@ impl<'a> Helper<'a> { ); // init(new, old, op) - let st = st_custom_from_ops!( + let st = st_custom_from_ops2!( self.builder, - self.predicates.init, - ( + self.batches, + init( op!(DictContains(op, "name", "init")), op!(Equal(old, EMPTY_VALUE)), op!(Equal(init_state, init_state)) @@ -450,23 +488,12 @@ impl<'a> Helper<'a> { Ok((init_state, st)) } - pub fn st_add_del( - &mut self, - old: Dictionary, - op: Dictionary, - ) -> Result<(Dictionary, Statement)> { + pub fn st_add(&mut self, old: Dictionary, op: Dictionary) -> Result<(Dictionary, Statement)> { let name = String::try_from(op.get(&Key::from("name")).unwrap().typed()).unwrap(); - assert!(name == "add" || name == "del"); - - let st0 = if name == "add" { - st!(self.builder, DictContains(op, "name", "add")) - } else { - st!(self.builder, DictContains(op, "name", "del")) - }; + assert!(name == "add"); let group = Key::try_from(op.get(&Key::from("group")).unwrap().typed()).unwrap(); let old_group = old.get(&group).unwrap(); - let st1 = st!(self.builder, DictContains(old, (&op, "group"), old_group)); let user = op.get(&Key::from("user")).unwrap(); let mut new_group = if let TypedValue::Set(set) = old_group.typed() { @@ -474,45 +501,60 @@ impl<'a> Helper<'a> { } else { panic!("Value not a Set: {:?}", old_group) }; - let st2 = if name == "add" { - if new_group.contains(user) { - bail!("old_group already contains user"); - } - new_group.insert(user).unwrap(); - st!(self.builder, SetInsert(new_group, old_group, (&op, "user"))) - } else { - if !new_group.contains(user) { - bail!("old_group doesn't contain user"); - } - new_group.delete(user).unwrap(); - st!(self.builder, SetDelete(new_group, old_group, (&op, "user"))) - }; + if new_group.contains(user) { + bail!("old_group already contains user"); + } + new_group.insert(user).unwrap(); let mut new = old.clone(); new.update(&group, &Value::from(new_group.clone())).unwrap(); - // DictUpdate(new, old, op.group, new_group) - let st3 = st!( + + // add(new, old, op, private: old_group, new_group) + let st = st_custom_from_ops!( self.builder, - DictUpdate(new, old, (&op, "group"), new_group) + self.predicates.add, + ( + op!(DictContains(op, "name", "add")), + op!(DictContains(old, (&op, "group"), old_group)), + op!(SetInsert(new_group, old_group, (&op, "user"))), + op!(DictUpdate(new, old, (&op, "group"), new_group)) + ) ); + Ok((new, st)) + } - let st = if name == "add" { - // add(new, old, op, private: old_group, new_group) - self.builder - .priv_op(Operation::custom( - self.predicates.add.clone(), - [st0, st1, st2, st3], - )) - .unwrap() + pub fn st_del(&mut self, old: Dictionary, op: Dictionary) -> Result<(Dictionary, Statement)> { + let name = String::try_from(op.get(&Key::from("name")).unwrap().typed()).unwrap(); + assert!(name == "del"); + + let group = Key::try_from(op.get(&Key::from("group")).unwrap().typed()).unwrap(); + let old_group = old.get(&group).unwrap(); + + let user = op.get(&Key::from("user")).unwrap(); + let mut new_group = if let TypedValue::Set(set) = old_group.typed() { + set.clone() } else { - // del(new, old, op, private: old_group, new_group) - self.builder - .priv_op(Operation::custom( - self.predicates.del.clone(), - [st0, st1, st2, st3], - )) - .unwrap() + panic!("Value not a Set: {:?}", old_group) }; + if !new_group.contains(user) { + bail!("old_group doesn't contain user"); + } + new_group.delete(user).unwrap(); + + let mut new = old.clone(); + new.update(&group, &Value::from(new_group.clone())).unwrap(); + + // del(new, old, op, private: old_group, new_group) + let st = st_custom_from_ops!( + self.builder, + self.predicates.add, + ( + op!(DictContains(op, "name", "del")), + op!(DictContains(old, (&op, "group"), old_group)), + op!(SetDelete(new_group, old_group, (&op, "user"))), + op!(DictUpdate(new, old, (&op, "group"), new_group)) + ) + ); Ok((new, st)) } @@ -531,12 +573,12 @@ impl<'a> Helper<'a> { } "add" => { // add(new, old, op, private: old_group, new_group) - let (new, st) = self.st_add_del(old, op)?; + let (new, st) = self.st_add(old, op)?; (new, [st_none.clone(), st, st_none.clone()]) } "del" => { // del(new, old, op, private: old_group, new_group) - let (new, st) = self.st_add_del(old, op)?; + let (new, st) = self.st_del(old, op)?; (new, [st_none.clone(), st_none.clone(), st]) } _ => panic!("invalid op.name = {}", name), From 53c9288ec03f78e6be854100a270117d854820d2 Mon Sep 17 00:00:00 2001 From: "Eduard S." Date: Wed, 15 Oct 2025 17:35:11 +0200 Subject: [PATCH 3/8] wip --- app/src/lib.rs | 319 +++++++++++++++++++++++-------------------------- 1 file changed, 151 insertions(+), 168 deletions(-) diff --git a/app/src/lib.rs b/app/src/lib.rs index 0aa7bd4..b2644a7 100644 --- a/app/src/lib.rs +++ b/app/src/lib.rs @@ -139,7 +139,9 @@ impl From for TypedValue { /// "green" => Set(...), /// "blue" => Set(...), /// } -pub fn build_predicates(params: &Params) -> (Predicates, RevPredicates) { +pub fn build_predicates( + params: &Params, +) -> (Predicates, RevPredicates, Vec>) { let empty = format!("Raw({:#})", EMPTY_VALUE); let empty_state = format!( r#"{{"{r}": {empty}, "{g}": {empty}, "{b}": {empty}}}"#, @@ -319,6 +321,13 @@ pub fn build_predicates(params: &Params) -> (Predicates, RevPredicates) { // State batch predicates + let batches = vec![ + state_batch.clone(), + rev_state_add_batch.clone(), + rev_state_del_batch.clone(), + rev_state_batch.clone(), + ]; + let state_preds = Predicates { init: state_batch.predicate_ref_by_name("init").unwrap(), add: state_batch.predicate_ref_by_name("add").unwrap(), @@ -359,7 +368,7 @@ pub fn build_predicates(params: &Params) -> (Predicates, RevPredicates) { sync: rev_state_batch.predicate_ref_by_name("rev_sync").unwrap(), }; - (state_preds, rev_preds) + (state_preds, rev_preds, batches) } macro_rules! op { @@ -431,34 +440,43 @@ fn find_custom_pred_by_name( return None; } -macro_rules! st_custom_from_ops2 { - ($builder:expr, $batches:expr, $pred:ident($($ops:expr),+)) => ({ +macro_rules! _st_custom_args { + ($builder:expr, $input_sts:expr,) => {{ + }}; + ($builder:expr, $input_sts:expr, $pred:ident($($args:expr),+), $($tail:tt)*) => {{ + $input_sts.push($builder.priv_op(op!($pred($($args),+))).unwrap()); + _st_custom_args!($builder, $input_sts, $($tail)*) + }}; + ($builder:expr, $input_sts:expr, $st:expr, $($tail:tt)*) => {{ + $input_sts.push($st); + _st_custom_args!($builder, $input_sts, $($tail)*) + }}; +} + +/// `$builder: &mut MainPodBuilder, $batches: &[Arc {{ let custom_pred = find_custom_pred_by_name($batches, stringify!($pred)).unwrap(); let mut input_sts = Vec::new(); - $( input_sts.push($builder.priv_op($ops).unwrap()); )* - $builder.priv_op(pod2::frontend::Operation::custom( - custom_pred, - input_sts - )) - .unwrap() - }) + _st_custom_args!($builder, &mut input_sts, $($args)*); + $builder + .priv_op(pod2::frontend::Operation::custom(custom_pred, input_sts)) + .unwrap() + }}; } pub struct Helper<'a> { pub builder: &'a mut MainPodBuilder, pub batches: &'a [Arc], - pub predicates: &'a Predicates, } impl<'a> Helper<'a> { pub fn new( pod_builder: &'a mut MainPodBuilder, - predicates: &'a Predicates, batches: &'a [Arc], ) -> Self { Self { builder: pod_builder, - predicates, batches, } } @@ -476,13 +494,12 @@ impl<'a> Helper<'a> { ); // init(new, old, op) - let st = st_custom_from_ops2!( - self.builder, - self.batches, + let st = st_custom!( + (self.builder, self.batches), init( - op!(DictContains(op, "name", "init")), - op!(Equal(old, EMPTY_VALUE)), - op!(Equal(init_state, init_state)) + DictContains(op, "name", "init"), + Equal(old, EMPTY_VALUE), + Equal(init_state, init_state), ) ); Ok((init_state, st)) @@ -510,14 +527,13 @@ impl<'a> Helper<'a> { new.update(&group, &Value::from(new_group.clone())).unwrap(); // add(new, old, op, private: old_group, new_group) - let st = st_custom_from_ops!( - self.builder, - self.predicates.add, - ( - op!(DictContains(op, "name", "add")), - op!(DictContains(old, (&op, "group"), old_group)), - op!(SetInsert(new_group, old_group, (&op, "user"))), - op!(DictUpdate(new, old, (&op, "group"), new_group)) + let st = st_custom!( + (self.builder, self.batches), + add( + DictContains(op, "name", "add"), + DictContains(old, (&op, "group"), old_group), + SetInsert(new_group, old_group, (&op, "user")), + DictUpdate(new, old, (&op, "group"), new_group), ) ); Ok((new, st)) @@ -545,14 +561,13 @@ impl<'a> Helper<'a> { new.update(&group, &Value::from(new_group.clone())).unwrap(); // del(new, old, op, private: old_group, new_group) - let st = st_custom_from_ops!( - self.builder, - self.predicates.add, - ( - op!(DictContains(op, "name", "del")), - op!(DictContains(old, (&op, "group"), old_group)), - op!(SetDelete(new_group, old_group, (&op, "user"))), - op!(DictUpdate(new, old, (&op, "group"), new_group)) + let st = st_custom!( + (self.builder, self.batches), + del( + DictContains(op, "name", "del"), + DictContains(old, (&op, "group"), old_group), + SetDelete(new_group, old_group, (&op, "user")), + DictUpdate(new, old, (&op, "group"), new_group), ) ); Ok((new, st)) @@ -564,32 +579,36 @@ impl<'a> Helper<'a> { op: Dictionary, ) -> Result<(Dictionary, Statement)> { let name = String::try_from(op.get(&Key::from("name")).unwrap().typed()).unwrap(); - let st_none = Statement::None; - let (new, sts) = match name.as_str() { + match name.as_str() { "init" => { // init(new, old, op) - let (new, st) = self.st_init(old, op)?; - (new, [st, st_none.clone(), st_none.clone()]) + let (new, st_init) = self.st_init(old, op)?; + let st = st_custom!( + (self.builder, self.batches), + update(st_init, Statement::None, Statement::None,) + ); + Ok((new, st)) } "add" => { // add(new, old, op, private: old_group, new_group) - let (new, st) = self.st_add(old, op)?; - (new, [st_none.clone(), st, st_none.clone()]) + let (new, st_add) = self.st_add(old, op)?; + let st = st_custom!( + (self.builder, self.batches), + update(Statement::None, st_add, Statement::None,) + ); + Ok((new, st)) } "del" => { // del(new, old, op, private: old_group, new_group) - let (new, st) = self.st_del(old, op)?; - (new, [st_none.clone(), st_none.clone(), st]) + let (new, st_del) = self.st_del(old, op)?; + let st = st_custom!( + (self.builder, self.batches), + update(Statement::None, Statement::None, st_del,) + ); + Ok((new, st)) } _ => panic!("invalid op.name = {}", name), - }; - - // update(new, old, op) - let st = self - .builder - .priv_op(Operation::custom(self.predicates.update.clone(), sts)) - .unwrap(); - Ok((new, st)) + } } } @@ -597,6 +616,7 @@ pub struct RevHelper<'a> { pub builder: &'a mut MainPodBuilder, pub predicates: &'a Predicates, pub rev_predicates: &'a RevPredicates, + pub batches: &'a [Arc], } impl<'a> RevHelper<'a> { @@ -604,11 +624,13 @@ impl<'a> RevHelper<'a> { pod_builder: &'a mut MainPodBuilder, predicates: &'a Predicates, rev_predicates: &'a RevPredicates, + batches: &'a [Arc], ) -> Self { Self { builder: pod_builder, predicates, rev_predicates, + batches, } } @@ -618,17 +640,15 @@ impl<'a> RevHelper<'a> { op: Dictionary, ) -> (Dictionary, Statement) { let init_rev_state = dict!({}); - let st1 = st!(self.builder, DictContains(op, "name", "init")); - let st2 = st!(self.builder, Equal(init_rev_state, EMPTY_VALUE)); - ( - init_rev_state, - self.builder - .priv_op(Operation::custom( - self.rev_predicates.sync_init.clone(), - [st_update, st1, st2], - )) - .unwrap(), - ) + let st = st_custom!( + (self.builder, self.batches), + rev_sync_init( + st_update, + DictContains(op, "name", "init"), + Equal(init_rev_state, EMPTY_VALUE), + ) + ); + (init_rev_state, st) } pub fn st_rev_add_fresh( @@ -645,23 +665,15 @@ impl<'a> RevHelper<'a> { new_rev .insert(user, &Value::from(user_groups.clone())) .unwrap(); - let st0 = st!( - self.builder, - SetInsert(user_groups, empty_set, (&op, "group")) - ); - let st1 = st!( - self.builder, - DictInsert(new_rev, old_rev, (&op, "user"), user_groups) + + let st = st_custom!( + (self.builder, self.batches), + rev_add_fresh( + SetInsert(user_groups, empty_set, (&op, "group")), + DictInsert(new_rev, old_rev, (&op, "user"), user_groups), + ) ); - ( - new_rev, - self.builder - .priv_op(Operation::custom( - self.rev_predicates.add_fresh.clone(), - [st0, st1], - )) - .unwrap(), - ) + (new_rev, st) } pub fn st_rev_add_existing( @@ -683,27 +695,15 @@ impl<'a> RevHelper<'a> { .update(user, &Value::from(user_groups.clone())) .unwrap(); - let st0 = st!( - self.builder, - DictContains(old_rev, (&op, "user"), old_user_groups) - ); - let st1 = st!( - self.builder, - SetInsert(user_groups, old_user_groups, (&op, "group")) - ); - let st2 = st!( - self.builder, - DictUpdate(new_rev, old_rev, (&op, "user"), user_groups) + let st = st_custom!( + (self.builder, self.batches), + rev_add_existing( + DictContains(old_rev, (&op, "user"), old_user_groups), + SetInsert(user_groups, old_user_groups, (&op, "group")), + DictUpdate(new_rev, old_rev, (&op, "user"), user_groups), + ) ); - ( - new_rev, - self.builder - .priv_op(Operation::custom( - self.rev_predicates.add_existing.clone(), - [st0, st1, st2], - )) - .unwrap(), - ) + (new_rev, st) } pub fn st_rev_add(&mut self, old_rev: Dictionary, op: Dictionary) -> (Dictionary, Statement) { @@ -740,24 +740,15 @@ impl<'a> RevHelper<'a> { let mut new_rev = old_rev.clone(); new_rev.delete(user).unwrap(); - let st0 = st!( - self.builder, - DictContains(old_rev, (&op, "user"), old_user_groups) - ); - let st1 = st!( - self.builder, - SetDelete(set!(), old_user_groups, (&op, "group")) + let st = st_custom!( + (self.builder, self.batches), + rev_del_singleton( + DictContains(old_rev, (&op, "user"), old_user_groups), + SetDelete(set!(), old_user_groups, (&op, "group")), + DictDelete(new_rev, old_rev, (&op, "user")), + ) ); - let st2 = st!(self.builder, DictDelete(new_rev, old_rev, (&op, "user"))); - ( - new_rev, - self.builder - .priv_op(Operation::custom( - self.rev_predicates.del_singleton.clone(), - [st0, st1, st2], - )) - .unwrap(), - ) + (new_rev, st) } pub fn st_rev_del_else( @@ -779,27 +770,15 @@ impl<'a> RevHelper<'a> { .update(user, &Value::from(user_groups.clone())) .unwrap(); - let st0 = st!( - self.builder, - DictContains(old_rev, (&op, "user"), old_user_groups) - ); - let st1 = st!( - self.builder, - SetDelete(user_groups, old_user_groups, (&op, "group")) - ); - let st2 = st!( - self.builder, - DictUpdate(new_rev, old_rev, (&op, "user"), user_groups) + let st = st_custom!( + (self.builder, self.batches), + rev_del_else( + DictContains(old_rev, (&op, "user"), old_user_groups), + SetDelete(user_groups, old_user_groups, (&op, "group")), + DictUpdate(new_rev, old_rev, (&op, "user"), user_groups), + ) ); - ( - new_rev, - self.builder - .priv_op(Operation::custom( - self.rev_predicates.del_else.clone(), - [st0, st1, st2], - )) - .unwrap(), - ) + (new_rev, st) } pub fn st_rev_del(&mut self, old_rev: Dictionary, op: Dictionary) -> (Dictionary, Statement) { @@ -807,30 +786,29 @@ impl<'a> RevHelper<'a> { Key::from(String::try_from(op.get(&Key::from("user")).unwrap().typed()).unwrap()); let group = Value::from(String::try_from(op.get(&Key::from("group")).unwrap().typed()).unwrap()); - let st_none = Statement::None; let groups = set_from_value(old_rev.get(&user).unwrap()).unwrap(); - let (new, sts) = match groups.set().len() { + match groups.set().len() { 1 => { - if groups.contains(&group) { - let (new, st) = self.st_rev_del_singleton(old_rev, op, &user); - (new, [st, st_none]) - } else { + if !groups.contains(&group) { panic!("User is not a member of the specified group.") } + let (new, st_rev_del_singleton) = self.st_rev_del_singleton(old_rev, op, &user); + let st = st_custom!( + (self.builder, self.batches), + rev_del(st_rev_del_singleton, Statement::None,) + ); + (new, st) } _ => { - let (new, st) = self.st_rev_del_else(old_rev, op, &user, &group); - (new, [st_none, st]) + let (new, st_rev_del_else) = self.st_rev_del_else(old_rev, op, &user, &group); + let st = st_custom!( + (self.builder, self.batches), + rev_del(Statement::None, st_rev_del_else,) + ); + (new, st) } - }; - - ( - new, - self.builder - .priv_op(Operation::custom(self.rev_predicates.del.clone(), sts)) - .unwrap(), - ) + } } pub fn st_rev_sync_add( @@ -840,17 +818,17 @@ impl<'a> RevHelper<'a> { old_st_rev_sync: Statement, op: Dictionary, ) -> (Dictionary, Statement) { - let st2 = st!(self.builder, DictContains(op, "name", "add")); - let (new, st3) = self.st_rev_add(old_rev, op); - ( - new, - self.builder - .priv_op(Operation::custom( - self.rev_predicates.sync_add.clone(), - [old_st_rev_sync, st_update, st2, st3], - )) - .unwrap(), - ) + let (new, st_rev_add) = self.st_rev_add(old_rev, op.clone()); + let st = st_custom!( + (self.builder, self.batches), + rev_sync_add( + old_st_rev_sync, + st_update, + DictContains(op, "name", "add"), + st_rev_add, + ) + ); + (new, st) } pub fn st_rev_sync_del( @@ -929,13 +907,14 @@ mod tests { prover: &dyn MainPodProver, predicates: &Predicates, rev_predicates: &RevPredicates, + batches: &[Arc], state: Dictionary, rev_state: Dictionary, op: Op, old_rev_state_pod: Option, ) -> (Dictionary, Dictionary, Option) { let mut builder = MainPodBuilder::new(params, vd_set); - let mut helper = Helper::new(&mut builder, predicates); + let mut helper = Helper::new(&mut builder, batches); // State Pod let (state, st_update) = helper @@ -960,7 +939,7 @@ mod tests { } else { Statement::None }; - let mut rev_helper = RevHelper::new(&mut builder, predicates, rev_predicates); + let mut rev_helper = RevHelper::new(&mut builder, predicates, rev_predicates, batches); let (rev_state, rev_st_update) = rev_helper.st_rev_sync(rev_state, Dictionary::from(op), st_update, old_st_rev_sync); builder.reveal(&rev_st_update); @@ -979,11 +958,14 @@ mod tests { #[test] fn test_app() { env_logger::init(); - // let (vd_set, prover) = (&VDSet::new(8, &[]).unwrap(), &MockProver {}); - let (vd_set, prover) = (&*DEFAULT_VD_SET, &Prover {}); + let (vd_set, prover) = ( + &VDSet::new(8, &[]).unwrap(), + &pod2::backends::plonky2::mock::mainpod::MockProver {}, + ); + // let (vd_set, prover) = (&*DEFAULT_VD_SET, &Prover {}); let params = Params::default(); - let (state_predicates, rev_predicates) = build_predicates(¶ms); + let (state_predicates, rev_predicates, batches) = build_predicates(¶ms); // Initial state let mut state = dict!({}); @@ -1022,6 +1004,7 @@ mod tests { prover, &state_predicates, &rev_predicates, + &batches, state, rev_state, op, From 505889d0872df7739cdd0db1fce165ff46c092be Mon Sep 17 00:00:00 2001 From: "Eduard S." Date: Wed, 15 Oct 2025 17:54:58 +0200 Subject: [PATCH 4/8] move macros to new module --- Cargo.toml | 3 - ad-server/src/main.rs | 17 ++- ad-server/src/queue.rs | 10 +- app/src/lib.rs | 326 ++++++++--------------------------------- app/src/macros.rs | 116 +++++++++++++++ 5 files changed, 193 insertions(+), 279 deletions(-) create mode 100644 app/src/macros.rs diff --git a/Cargo.toml b/Cargo.toml index e078974..cc0b662 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,8 +50,5 @@ pod2 = { git = "https://github.com/0xPARC/pod2?rev=main", rev = "d355e55159dbe7e # [patch."https://github.com/0xPARC/plonky2"] # plonky2 = { path = "../plonky2/plonky2" } -[patch."https://github.com/0xPARC/pod2-onchain"] -pod2_onchain = { path = "../pod2-onchain" } - # [profile.release] # debug = true diff --git a/ad-server/src/main.rs b/ad-server/src/main.rs index a91ea90..6359608 100644 --- a/ad-server/src/main.rs +++ b/ad-server/src/main.rs @@ -3,14 +3,14 @@ use std::{collections::HashMap, str::FromStr, sync::Arc}; use alloy::primitives::Address; use anyhow::{Context as _, Result}; -use app::{Predicates, RevPredicates, build_predicates}; +use app::build_predicates; use common::{ ProofType, shrink::{ShrunkMainPodBuild, ShrunkMainPodSetup}, }; use pod2::{ backends::plonky2::basetypes::DEFAULT_VD_SET, - middleware::{Params, VDSet}, + middleware::{CustomPredicateBatch, CustomPredicateRef, Params, VDSet}, }; use sqlx::{ migrate::MigrateDatabase, @@ -70,8 +70,8 @@ impl Config { pub struct PodConfig { params: Params, vd_set: VDSet, - state_predicates: Predicates, - rev_predicates: RevPredicates, + batches: Vec>, + pred_update: CustomPredicateRef, } pub struct Context { @@ -137,13 +137,16 @@ async fn main() -> Result<()> { info!("Prebuilding circuits to calculate vd_set..."); let vd_set = &*DEFAULT_VD_SET; info!("vd_set calculation complete"); - let (state_predicates, rev_predicates) = build_predicates(¶ms); + let batches = build_predicates(¶ms); + let pred_update = batches[0] + .predicate_ref_by_name("update") + .expect("update defined"); let shrunk_main_pod_build = ShrunkMainPodSetup::new(¶ms).build()?; let pod_config = PodConfig { params, vd_set: vd_set.clone(), - state_predicates, - rev_predicates, + batches, + pred_update, }; if cfg.proof_type == ProofType::Groth16 { diff --git a/ad-server/src/queue.rs b/ad-server/src/queue.rs index b595ba5..5ca2df2 100644 --- a/ad-server/src/queue.rs +++ b/ad-server/src/queue.rs @@ -160,7 +160,7 @@ async fn handle_create(ctx: Arc, req_id: Uuid) -> Result<()> { // send the payload to ethereum let payload_bytes = Payload::Create(PayloadCreate { id: Hash::from(RawValue::from(new_id)), // TODO hash - custom_predicate_ref: ctx.pod_config.state_predicates.update.clone(), + custom_predicate_ref: ctx.pod_config.pred_update.clone(), vds_root: ctx.pod_config.vd_set.root(), }) .to_bytes(); @@ -204,7 +204,7 @@ async fn handle_update(ctx: Arc, req_id: Uuid, id: i64, op: Op) -> Resu let start = std::time::Instant::now(); let mut builder = MainPodBuilder::new(&ctx.pod_config.params, &ctx.pod_config.vd_set); - let mut helper = Helper::new(&mut builder, &ctx.pod_config.state_predicates); + let mut helper = Helper::new(&mut builder, &ctx.pod_config.batches); let op = Dictionary::from(op); let op_raw = RawValue::from(op.commitment()); @@ -319,11 +319,7 @@ async fn handle_update_rev(ctx: Arc, req_id: Uuid, id: i64, num: i64) - Statement::None }; - let mut rev_helper = RevHelper::new( - &mut builder, - &ctx.pod_config.state_predicates, - &ctx.pod_config.rev_predicates, - ); + let mut rev_helper = RevHelper::new(&mut builder, &ctx.pod_config.batches); let (rev_state, rev_st_update) = rev_helper.st_rev_sync(rev_state, op, st_update, old_st_rev_sync); diff --git a/app/src/lib.rs b/app/src/lib.rs index b2644a7..7585fa8 100644 --- a/app/src/lib.rs +++ b/app/src/lib.rs @@ -1,21 +1,17 @@ #![allow(clippy::uninlined_format_args)] -use std::{ - collections::{HashMap, HashSet}, - fmt, - str::FromStr, - sync::Arc, -}; +mod macros; + +use std::{collections::HashSet, fmt, str::FromStr, sync::Arc}; -use anyhow::{Context, Result, bail}; +use anyhow::{Result, bail}; use common::set_from_value; use hex::ToHex; use pod2::{ - frontend::{MainPodBuilder, Operation}, + frontend::MainPodBuilder, lang::parse, middleware::{ - CustomPredicateBatch, CustomPredicateRef, EMPTY_VALUE, Key, Params, Statement, TypedValue, - Value, + CustomPredicateBatch, EMPTY_VALUE, Key, Params, Statement, TypedValue, Value, containers::{Dictionary, Set}, }, }; @@ -23,58 +19,6 @@ use serde::{Deserialize, Serialize}; pub const DEPTH: usize = 32; -#[macro_export] -macro_rules! set { - () => ({ - pod2::middleware::containers::Set::new(DEPTH, std::collections::HashSet::new()).unwrap() - }); - ($($val:expr),* ,) => ( - $crate::set!($($val),*).unwrap() - ); - ($($val:expr),*) => ({ - let mut set = std::collections::HashSet::new(); - $( set.insert($crate::middleware::Value::from($val)); )* - pod2::middleware::containers::Set::new(DEPTH, set).unwrap() - }); -} - -#[macro_export] -macro_rules! dict { - ({ }) => ( - pod2::middleware::containers::Dictionary::new(DEPTH, std::collections::HashMap::new()).unwrap() - ); - ({ $($key:expr => $val:expr),* , }) => ( - $crate::dict!({ $($key => $val),* }).unwrap() - ); - ({ $($key:expr => $val:expr),* }) => ({ - let mut map = std::collections::HashMap::new(); - $( map.insert(pod2::middleware::Key::from($key.clone()), pod2::middleware::Value::from($val.clone())); )* - pod2::middleware::containers::Dictionary::new(DEPTH, map).unwrap() - }); -} - -#[derive(Debug, Clone)] -pub struct Predicates { - pub init: CustomPredicateRef, - pub add: CustomPredicateRef, - pub del: CustomPredicateRef, - pub update: CustomPredicateRef, -} - -#[derive(Debug, Clone)] -pub struct RevPredicates { - pub add_fresh: CustomPredicateRef, - pub add_existing: CustomPredicateRef, - pub add: CustomPredicateRef, - pub del_singleton: CustomPredicateRef, - pub del_else: CustomPredicateRef, - pub del: CustomPredicateRef, - pub sync_init: CustomPredicateRef, - pub sync_add: CustomPredicateRef, - pub sync_del: CustomPredicateRef, - pub sync: CustomPredicateRef, -} - #[derive(PartialEq, Eq, Hash, Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum Op { @@ -139,9 +83,7 @@ impl From for TypedValue { /// "green" => Set(...), /// "blue" => Set(...), /// } -pub fn build_predicates( - params: &Params, -) -> (Predicates, RevPredicates, Vec>) { +pub fn build_predicates(params: &Params) -> Vec> { let empty = format!("Raw({:#})", EMPTY_VALUE); let empty_state = format!( r#"{{"{r}": {empty}, "{g}": {empty}, "{b}": {empty}}}"#, @@ -320,149 +262,12 @@ pub fn build_predicates( .custom_batch; // State batch predicates - - let batches = vec![ + vec![ state_batch.clone(), rev_state_add_batch.clone(), rev_state_del_batch.clone(), rev_state_batch.clone(), - ]; - - let state_preds = Predicates { - init: state_batch.predicate_ref_by_name("init").unwrap(), - add: state_batch.predicate_ref_by_name("add").unwrap(), - del: state_batch.predicate_ref_by_name("del").unwrap(), - update: state_batch.predicate_ref_by_name("update").unwrap(), - }; - - // Reverse index state predicates - - let rev_preds = RevPredicates { - add_fresh: rev_state_add_batch - .predicate_ref_by_name("rev_add_fresh") - .unwrap(), - add_existing: rev_state_add_batch - .predicate_ref_by_name("rev_add_existing") - .unwrap(), - add: rev_state_add_batch - .predicate_ref_by_name("rev_add") - .unwrap(), - del_singleton: rev_state_del_batch - .predicate_ref_by_name("rev_del_singleton") - .unwrap(), - del_else: rev_state_del_batch - .predicate_ref_by_name("rev_del_else") - .unwrap(), - del: rev_state_del_batch - .predicate_ref_by_name("rev_del") - .unwrap(), - sync_init: rev_state_batch - .predicate_ref_by_name("rev_sync_init") - .unwrap(), - sync_add: rev_state_batch - .predicate_ref_by_name("rev_sync_add") - .unwrap(), - sync_del: rev_state_batch - .predicate_ref_by_name("rev_sync_del") - .unwrap(), - sync: rev_state_batch.predicate_ref_by_name("rev_sync").unwrap(), - }; - - (state_preds, rev_preds, batches) -} - -macro_rules! op { - (Equal($a:expr, $b:expr)) => { - pod2::frontend::Operation::eq($a.clone(), $b.clone()) - }; - (DictContains($dict:expr, $key:expr, $value:expr)) => { - pod2::frontend::Operation::dict_contains($dict.clone(), $key.clone(), $value.clone()) - }; - (DictUpdate($dict:expr, $old_dict:expr, $key:expr, $value:expr)) => { - pod2::frontend::Operation::dict_update( - $dict.clone(), - $old_dict.clone(), - $key.clone(), - $value.clone(), - ) - }; - (DictInsert($dict:expr, $old_dict:expr, $key:expr, $value:expr)) => { - pod2::frontend::Operation::dict_insert( - $dict.clone(), - $old_dict.clone(), - $key.clone(), - $value.clone(), - ) - }; - (DictDelete($dict:expr, $old_dict:expr, $key:expr)) => { - pod2::frontend::Operation::dict_delete($dict.clone(), $old_dict.clone(), $key.clone()) - }; - (SetInsert($set:expr, $old_set:expr, $value:expr)) => { - pod2::frontend::Operation::set_insert($set.clone(), $old_set.clone(), $value.clone()) - }; - (SetDelete($set:expr, $old_set:expr, $value:expr)) => { - pod2::frontend::Operation::set_delete($set.clone(), $old_set.clone(), $value.clone()) - }; -} - -macro_rules! st { - ($builder:expr, $pred:ident($($args:expr),+)) => { - $builder.priv_op(op!($pred($($args),+))).unwrap() - }; -} - -macro_rules! st_custom_from_ops { - ($builder:expr, $custom_pred:expr, ($($ops:expr),+)) => ({ - let mut input_sts = Vec::new(); - $( input_sts.push($builder.priv_op($ops).unwrap()); )* - $builder.priv_op(pod2::frontend::Operation::custom( - $custom_pred.clone(), - input_sts - )) - .unwrap() - }) -} - -fn find_custom_pred_by_name( - batches: &[Arc], - name: &str, -) -> Option { - for batch in batches { - for (index, predicate) in batch.predicates().iter().enumerate() { - if predicate.name == name { - return Some(CustomPredicateRef { - batch: batch.clone(), - index, - }); - } - } - } - return None; -} - -macro_rules! _st_custom_args { - ($builder:expr, $input_sts:expr,) => {{ - }}; - ($builder:expr, $input_sts:expr, $pred:ident($($args:expr),+), $($tail:tt)*) => {{ - $input_sts.push($builder.priv_op(op!($pred($($args),+))).unwrap()); - _st_custom_args!($builder, $input_sts, $($tail)*) - }}; - ($builder:expr, $input_sts:expr, $st:expr, $($tail:tt)*) => {{ - $input_sts.push($st); - _st_custom_args!($builder, $input_sts, $($tail)*) - }}; -} - -/// `$builder: &mut MainPodBuilder, $batches: &[Arc {{ - let custom_pred = find_custom_pred_by_name($batches, stringify!($pred)).unwrap(); - let mut input_sts = Vec::new(); - _st_custom_args!($builder, &mut input_sts, $($args)*); - $builder - .priv_op(pod2::frontend::Operation::custom(custom_pred, input_sts)) - .unwrap() - }}; + ] } pub struct Helper<'a> { @@ -614,22 +419,16 @@ impl<'a> Helper<'a> { pub struct RevHelper<'a> { pub builder: &'a mut MainPodBuilder, - pub predicates: &'a Predicates, - pub rev_predicates: &'a RevPredicates, pub batches: &'a [Arc], } impl<'a> RevHelper<'a> { pub fn new( pod_builder: &'a mut MainPodBuilder, - predicates: &'a Predicates, - rev_predicates: &'a RevPredicates, batches: &'a [Arc], ) -> Self { Self { builder: pod_builder, - predicates, - rev_predicates, batches, } } @@ -711,23 +510,25 @@ impl<'a> RevHelper<'a> { Key::from(String::try_from(op.get(&Key::from("user")).unwrap().typed()).unwrap()); let group = Value::from(String::try_from(op.get(&Key::from("group")).unwrap().typed()).unwrap()); - let st_none = Statement::None; - let (new, sts) = match old_rev.get(&user) { + match old_rev.get(&user) { Err(_) => { - let (new, st) = self.st_rev_add_fresh(old_rev, op, &user, &group); - (new, [st, st_none]) + let (new, st_rev_add_fresh) = self.st_rev_add_fresh(old_rev, op, &user, &group); + let st = st_custom!( + (self.builder, self.batches), + rev_add(st_rev_add_fresh, Statement::None,) + ); + (new, st) } Ok(_) => { - let (new, st) = self.st_rev_add_existing(old_rev, op, &user, &group); - (new, [st_none, st]) + let (new, st_rev_add_existing) = + self.st_rev_add_existing(old_rev, op, &user, &group); + let st = st_custom!( + (self.builder, self.batches), + rev_add(Statement::None, st_rev_add_existing,) + ); + (new, st) } - }; - ( - new, - self.builder - .priv_op(Operation::custom(self.rev_predicates.add.clone(), sts)) - .unwrap(), - ) + } } pub fn st_rev_del_singleton( @@ -838,17 +639,17 @@ impl<'a> RevHelper<'a> { old_st_rev_sync: Statement, op: Dictionary, ) -> (Dictionary, Statement) { - let st2 = st!(self.builder, DictContains(op.clone(), "name", "del")); - let (new, st3) = self.st_rev_del(old_rev, op); - ( - new, - self.builder - .priv_op(Operation::custom( - self.rev_predicates.sync_del.clone(), - [old_st_rev_sync, st_update, st2, st3], - )) - .unwrap(), - ) + let (new, st_rev_del) = self.st_rev_del(old_rev, op.clone()); + let st = st_custom!( + (self.builder, self.batches), + rev_sync_del( + old_st_rev_sync, + st_update, + DictContains(op.clone(), "name", "del"), + st_rev_del, + ) + ); + (new, st) } pub fn st_rev_sync( @@ -859,33 +660,38 @@ impl<'a> RevHelper<'a> { old_st_rev_sync: Statement, ) -> (Dictionary, Statement) { let name = String::try_from(op.get(&Key::from("name")).unwrap().typed()).unwrap(); - let st_none = Statement::None; - let (new, sts) = match name.as_str() { + match name.as_str() { "init" => { // rev_sync_init(rev_state, state) - let (new, st) = self.st_rev_sync_init(st_update, op); - (new, [st, st_none.clone(), st_none.clone()]) + let (new, st_rev_sync_init) = self.st_rev_sync_init(st_update, op); + let st = st_custom!( + (self.builder, self.batches), + rev_sync(st_rev_sync_init, Statement::None, Statement::None,) + ); + (new, st) } "add" => { // rev_sync_add(rev_state, state) - let (new, st) = self.st_rev_sync_add(old_rev, st_update, old_st_rev_sync, op); - (new, [st_none.clone(), st, st_none.clone()]) + let (new, st_rev_sync_add) = + self.st_rev_sync_add(old_rev, st_update, old_st_rev_sync, op); + let st = st_custom!( + (self.builder, self.batches), + rev_sync(Statement::None, st_rev_sync_add, Statement::None,) + ); + (new, st) } "del" => { // rev_sync_del(rev_state, state) - let (new, st) = self.st_rev_sync_del(old_rev, st_update, old_st_rev_sync, op); - (new, [st_none.clone(), st_none.clone(), st]) + let (new, st_rev_sync_del) = + self.st_rev_sync_del(old_rev, st_update, old_st_rev_sync, op); + let st = st_custom!( + (self.builder, self.batches), + rev_sync(Statement::None, Statement::None, st_rev_sync_del,) + ); + (new, st) } _ => panic!("invalid op.name = {}", name), - }; - - ( - new, - // rev_sync(rev_state, state) - self.builder - .priv_op(Operation::custom(self.rev_predicates.sync.clone(), sts)) - .unwrap(), - ) + } } } @@ -905,8 +711,6 @@ mod tests { params: &Params, vd_set: &VDSet, prover: &dyn MainPodProver, - predicates: &Predicates, - rev_predicates: &RevPredicates, batches: &[Arc], state: Dictionary, rev_state: Dictionary, @@ -939,7 +743,7 @@ mod tests { } else { Statement::None }; - let mut rev_helper = RevHelper::new(&mut builder, predicates, rev_predicates, batches); + let mut rev_helper = RevHelper::new(&mut builder, batches); let (rev_state, rev_st_update) = rev_helper.st_rev_sync(rev_state, Dictionary::from(op), st_update, old_st_rev_sync); builder.reveal(&rev_st_update); @@ -958,14 +762,14 @@ mod tests { #[test] fn test_app() { env_logger::init(); - let (vd_set, prover) = ( - &VDSet::new(8, &[]).unwrap(), - &pod2::backends::plonky2::mock::mainpod::MockProver {}, - ); - // let (vd_set, prover) = (&*DEFAULT_VD_SET, &Prover {}); + // let (vd_set, prover) = ( + // &VDSet::new(8, &[]).unwrap(), + // &pod2::backends::plonky2::mock::mainpod::MockProver {}, + // ); + let (vd_set, prover) = (&*DEFAULT_VD_SET, &Prover {}); let params = Params::default(); - let (state_predicates, rev_predicates, batches) = build_predicates(¶ms); + let batches = build_predicates(¶ms); // Initial state let mut state = dict!({}); @@ -1002,8 +806,6 @@ mod tests { ¶ms, vd_set, prover, - &state_predicates, - &rev_predicates, &batches, state, rev_state, diff --git a/app/src/macros.rs b/app/src/macros.rs new file mode 100644 index 0000000..83d01ed --- /dev/null +++ b/app/src/macros.rs @@ -0,0 +1,116 @@ +use std::sync::Arc; + +use pod2::middleware::{CustomPredicateBatch, CustomPredicateRef}; + +#[macro_export] +macro_rules! set { + () => ({ + pod2::middleware::containers::Set::new(DEPTH, std::collections::HashSet::new()).unwrap() + }); + ($($val:expr),* ,) => ( + $crate::set!($($val),*).unwrap() + ); + ($($val:expr),*) => ({ + let mut set = std::collections::HashSet::new(); + $( set.insert($crate::middleware::Value::from($val)); )* + pod2::middleware::containers::Set::new(DEPTH, set).unwrap() + }); +} + +#[macro_export] +macro_rules! dict { + ({ }) => ( + pod2::middleware::containers::Dictionary::new(DEPTH, std::collections::HashMap::new()).unwrap() + ); + ({ $($key:expr => $val:expr),* , }) => ( + $crate::dict!({ $($key => $val),* }).unwrap() + ); + ({ $($key:expr => $val:expr),* }) => ({ + let mut map = std::collections::HashMap::new(); + $( map.insert(pod2::middleware::Key::from($key.clone()), pod2::middleware::Value::from($val.clone())); )* + pod2::middleware::containers::Dictionary::new(DEPTH, map).unwrap() + }); +} + +#[macro_export] +macro_rules! op { + (Equal($a:expr, $b:expr)) => { + pod2::frontend::Operation::eq($a.clone(), $b.clone()) + }; + (DictContains($dict:expr, $key:expr, $value:expr)) => { + pod2::frontend::Operation::dict_contains($dict.clone(), $key.clone(), $value.clone()) + }; + (DictUpdate($dict:expr, $old_dict:expr, $key:expr, $value:expr)) => { + pod2::frontend::Operation::dict_update( + $dict.clone(), + $old_dict.clone(), + $key.clone(), + $value.clone(), + ) + }; + (DictInsert($dict:expr, $old_dict:expr, $key:expr, $value:expr)) => { + pod2::frontend::Operation::dict_insert( + $dict.clone(), + $old_dict.clone(), + $key.clone(), + $value.clone(), + ) + }; + (DictDelete($dict:expr, $old_dict:expr, $key:expr)) => { + pod2::frontend::Operation::dict_delete($dict.clone(), $old_dict.clone(), $key.clone()) + }; + (SetInsert($set:expr, $old_set:expr, $value:expr)) => { + pod2::frontend::Operation::set_insert($set.clone(), $old_set.clone(), $value.clone()) + }; + (SetDelete($set:expr, $old_set:expr, $value:expr)) => { + pod2::frontend::Operation::set_delete($set.clone(), $old_set.clone(), $value.clone()) + }; +} + +pub fn find_custom_pred_by_name( + batches: &[Arc], + name: &str, +) -> Option { + for batch in batches { + for (index, predicate) in batch.predicates().iter().enumerate() { + if predicate.name == name { + return Some(CustomPredicateRef { + batch: batch.clone(), + index, + }); + } + } + } + return None; +} + +#[macro_export] +macro_rules! _st_custom_args { + ($builder:expr, $input_sts:expr,) => {{ + }}; + ($builder:expr, $input_sts:expr, $pred:ident($($args:expr),+), $($tail:tt)*) => {{ + $input_sts.push($builder.priv_op(op!($pred($($args),+))).unwrap()); + _st_custom_args!($builder, $input_sts, $($tail)*) + }}; + ($builder:expr, $input_sts:expr, $st:expr, $($tail:tt)*) => {{ + $input_sts.push($st); + _st_custom_args!($builder, $input_sts, $($tail)*) + }}; +} + +/// ``` +/// $builder: &mut MainPodBuilder +/// $batches: &[Arc {{ + let custom_pred = crate::macros::find_custom_pred_by_name($batches, stringify!($pred)).unwrap(); + let mut input_sts = Vec::new(); + _st_custom_args!($builder, &mut input_sts, $($args)*); + $builder + .priv_op(pod2::frontend::Operation::custom(custom_pred, input_sts)) + .unwrap() + }}; +} From c6172c2a9254e3f02182b329d64611ebcbbc879d Mon Sep 17 00:00:00 2001 From: "Eduard S." Date: Wed, 15 Oct 2025 17:58:44 +0200 Subject: [PATCH 5/8] fix tests --- Cargo.toml | 3 +++ ad-server/src/endpoints.rs | 9 ++++++--- common/src/groth.rs | 4 ++-- common/src/payload.rs | 13 +++++-------- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cc0b662..e078974 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,5 +50,8 @@ pod2 = { git = "https://github.com/0xPARC/pod2?rev=main", rev = "d355e55159dbe7e # [patch."https://github.com/0xPARC/plonky2"] # plonky2 = { path = "../plonky2/plonky2" } +[patch."https://github.com/0xPARC/pod2-onchain"] +pod2_onchain = { path = "../pod2-onchain" } + # [profile.release] # debug = true diff --git a/ad-server/src/endpoints.rs b/ad-server/src/endpoints.rs index 63c463d..1828c56 100644 --- a/ad-server/src/endpoints.rs +++ b/ad-server/src/endpoints.rs @@ -268,13 +268,16 @@ mod tests { println!("Prebuilding circuits to calculate vd_set..."); let vd_set = &*DEFAULT_VD_SET; println!("vd_set calculation complete"); - let (state_predicates, rev_predicates) = app::build_predicates(¶ms); + let batches = app::build_predicates(¶ms); + let pred_update = batches[0] + .predicate_ref_by_name("update") + .expect("update defined"); let shrunk_main_pod_build = ShrunkMainPodSetup::new(¶ms).build()?; let pod_config = PodConfig { params, vd_set: vd_set.clone(), - state_predicates, - rev_predicates, + batches, + pred_update, }; let (queue_tx, queue_rx) = mpsc::channel::(8); diff --git a/common/src/groth.rs b/common/src/groth.rs index 63d1ef9..174b6b3 100644 --- a/common/src/groth.rs +++ b/common/src/groth.rs @@ -74,10 +74,10 @@ mod tests { fn compute_pod_proof() -> Result { let params = Params::default(); let vd_set = &*DEFAULT_VD_SET; - let (state_predicates, _) = app::build_predicates(¶ms); + let batches = app::build_predicates(¶ms); let mut builder = MainPodBuilder::new(¶ms, vd_set); - let mut helper = app::Helper::new(&mut builder, &state_predicates); + let mut helper = app::Helper::new(&mut builder, &batches); let initial_state = Dictionary::new( params.max_depth_mt_containers, diff --git a/common/src/payload.rs b/common/src/payload.rs index 2db7e7c..f1e48e0 100644 --- a/common/src/payload.rs +++ b/common/src/payload.rs @@ -256,14 +256,11 @@ mod tests { println!("ShrunkMainPod setup"); let shrunk_main_pod_build = ShrunkMainPodSetup::new(¶ms).build().unwrap(); let common_data = &shrunk_main_pod_build.circuit_data.common; - let (state_predicates, _rev_predicates) = app::build_predicates(¶ms); + let batches = app::build_predicates(¶ms); let id = Hash([F(1), F(2), F(3), F(4)]); let custom_predicate_ref = CustomPredicateRef { - batch: CustomPredicateBatch::new_opaque( - "unknown".to_string(), - state_predicates.update.batch.id(), - ), - index: state_predicates.update.index, + batch: CustomPredicateBatch::new_opaque("unknown".to_string(), batches[0].id()), + index: batches[0].predicate_ref_by_name("update").unwrap().index, }; let vd_set = &*DEFAULT_VD_SET; let vds_root = vd_set.root(); @@ -280,8 +277,8 @@ mod tests { assert_eq!(payload_create, payload_create_decoded); let mut builder = MainPodBuilder::new(¶ms, vd_set); - let (state_predicates, _rev_predicates) = app::build_predicates(¶ms); - let mut helper = app::Helper::new(&mut builder, &state_predicates); + let batches = app::build_predicates(¶ms); + let mut helper = app::Helper::new(&mut builder, &batches); let state = containers::Dictionary::new(params.max_depth_mt_containers, HashMap::new()).unwrap(); From 16028990a585a929d1ef68fef4266022330bb7fe Mon Sep 17 00:00:00 2001 From: "Eduard S." Date: Wed, 15 Oct 2025 17:59:26 +0200 Subject: [PATCH 6/8] fix clippy --- Cargo.toml | 3 --- app/src/macros.rs | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e078974..cc0b662 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,8 +50,5 @@ pod2 = { git = "https://github.com/0xPARC/pod2?rev=main", rev = "d355e55159dbe7e # [patch."https://github.com/0xPARC/plonky2"] # plonky2 = { path = "../plonky2/plonky2" } -[patch."https://github.com/0xPARC/pod2-onchain"] -pod2_onchain = { path = "../pod2-onchain" } - # [profile.release] # debug = true diff --git a/app/src/macros.rs b/app/src/macros.rs index 83d01ed..73c4f7b 100644 --- a/app/src/macros.rs +++ b/app/src/macros.rs @@ -81,7 +81,7 @@ pub fn find_custom_pred_by_name( } } } - return None; + None } #[macro_export] @@ -106,7 +106,7 @@ macro_rules! _st_custom_args { #[macro_export] macro_rules! st_custom { (($builder:expr, $batches:expr), $pred:ident($($args:tt)*)) => {{ - let custom_pred = crate::macros::find_custom_pred_by_name($batches, stringify!($pred)).unwrap(); + let custom_pred = $crate::macros::find_custom_pred_by_name($batches, stringify!($pred)).unwrap(); let mut input_sts = Vec::new(); _st_custom_args!($builder, &mut input_sts, $($args)*); $builder From e020b72c76a095f771e706e63e6c81230c94994e Mon Sep 17 00:00:00 2001 From: "Eduard S." Date: Wed, 15 Oct 2025 18:15:41 +0200 Subject: [PATCH 7/8] clean up --- Cargo.lock | 1 + app/src/lib.rs | 84 ++++++++++++++++---------------------------------- 2 files changed, 27 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0ba8a21..8a06222 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3774,6 +3774,7 @@ dependencies = [ [[package]] name = "pod2_onchain" version = "0.1.0" +source = "git+https://github.com/0xPARC/pod2-onchain.git?rev=36c1b426b05e3a5e13f2ba251d1ea3e8eed5bb66#36c1b426b05e3a5e13f2ba251d1ea3e8eed5bb66" dependencies = [ "anyhow", "bindgen", diff --git a/app/src/lib.rs b/app/src/lib.rs index 7585fa8..265d65d 100644 --- a/app/src/lib.rs +++ b/app/src/lib.rs @@ -384,36 +384,26 @@ impl<'a> Helper<'a> { op: Dictionary, ) -> Result<(Dictionary, Statement)> { let name = String::try_from(op.get(&Key::from("name")).unwrap().typed()).unwrap(); - match name.as_str() { + let (new, [st0, st1, st2]) = match name.as_str() { "init" => { // init(new, old, op) let (new, st_init) = self.st_init(old, op)?; - let st = st_custom!( - (self.builder, self.batches), - update(st_init, Statement::None, Statement::None,) - ); - Ok((new, st)) + (new, [st_init, Statement::None, Statement::None]) } "add" => { // add(new, old, op, private: old_group, new_group) let (new, st_add) = self.st_add(old, op)?; - let st = st_custom!( - (self.builder, self.batches), - update(Statement::None, st_add, Statement::None,) - ); - Ok((new, st)) + (new, [Statement::None, st_add, Statement::None]) } "del" => { // del(new, old, op, private: old_group, new_group) let (new, st_del) = self.st_del(old, op)?; - let st = st_custom!( - (self.builder, self.batches), - update(Statement::None, Statement::None, st_del,) - ); - Ok((new, st)) + (new, [Statement::None, Statement::None, st_del]) } _ => panic!("invalid op.name = {}", name), - } + }; + let st = st_custom!((self.builder, self.batches), update(st0, st1, st2,)); + Ok((new, st)) } } @@ -510,25 +500,19 @@ impl<'a> RevHelper<'a> { Key::from(String::try_from(op.get(&Key::from("user")).unwrap().typed()).unwrap()); let group = Value::from(String::try_from(op.get(&Key::from("group")).unwrap().typed()).unwrap()); - match old_rev.get(&user) { + let (new, [st0, st1]) = match old_rev.get(&user) { Err(_) => { let (new, st_rev_add_fresh) = self.st_rev_add_fresh(old_rev, op, &user, &group); - let st = st_custom!( - (self.builder, self.batches), - rev_add(st_rev_add_fresh, Statement::None,) - ); - (new, st) + (new, [st_rev_add_fresh, Statement::None]) } Ok(_) => { let (new, st_rev_add_existing) = self.st_rev_add_existing(old_rev, op, &user, &group); - let st = st_custom!( - (self.builder, self.batches), - rev_add(Statement::None, st_rev_add_existing,) - ); - (new, st) + (new, [Statement::None, st_rev_add_existing]) } - } + }; + let st = st_custom!((self.builder, self.batches), rev_add(st0, st1,)); + (new, st) } pub fn st_rev_del_singleton( @@ -589,27 +573,21 @@ impl<'a> RevHelper<'a> { Value::from(String::try_from(op.get(&Key::from("group")).unwrap().typed()).unwrap()); let groups = set_from_value(old_rev.get(&user).unwrap()).unwrap(); - match groups.set().len() { + let (new, [st0, st1]) = match groups.set().len() { 1 => { if !groups.contains(&group) { panic!("User is not a member of the specified group.") } let (new, st_rev_del_singleton) = self.st_rev_del_singleton(old_rev, op, &user); - let st = st_custom!( - (self.builder, self.batches), - rev_del(st_rev_del_singleton, Statement::None,) - ); - (new, st) + (new, [st_rev_del_singleton, Statement::None]) } _ => { let (new, st_rev_del_else) = self.st_rev_del_else(old_rev, op, &user, &group); - let st = st_custom!( - (self.builder, self.batches), - rev_del(Statement::None, st_rev_del_else,) - ); - (new, st) + (new, [Statement::None, st_rev_del_else]) } - } + }; + let st = st_custom!((self.builder, self.batches), rev_del(st0, st1,)); + (new, st) } pub fn st_rev_sync_add( @@ -660,38 +638,28 @@ impl<'a> RevHelper<'a> { old_st_rev_sync: Statement, ) -> (Dictionary, Statement) { let name = String::try_from(op.get(&Key::from("name")).unwrap().typed()).unwrap(); - match name.as_str() { + let (new, [st0, st1, st2]) = match name.as_str() { "init" => { // rev_sync_init(rev_state, state) let (new, st_rev_sync_init) = self.st_rev_sync_init(st_update, op); - let st = st_custom!( - (self.builder, self.batches), - rev_sync(st_rev_sync_init, Statement::None, Statement::None,) - ); - (new, st) + (new, [st_rev_sync_init, Statement::None, Statement::None]) } "add" => { // rev_sync_add(rev_state, state) let (new, st_rev_sync_add) = self.st_rev_sync_add(old_rev, st_update, old_st_rev_sync, op); - let st = st_custom!( - (self.builder, self.batches), - rev_sync(Statement::None, st_rev_sync_add, Statement::None,) - ); - (new, st) + (new, [Statement::None, st_rev_sync_add, Statement::None]) } "del" => { // rev_sync_del(rev_state, state) let (new, st_rev_sync_del) = self.st_rev_sync_del(old_rev, st_update, old_st_rev_sync, op); - let st = st_custom!( - (self.builder, self.batches), - rev_sync(Statement::None, Statement::None, st_rev_sync_del,) - ); - (new, st) + (new, [Statement::None, Statement::None, st_rev_sync_del]) } _ => panic!("invalid op.name = {}", name), - } + }; + let st = st_custom!((self.builder, self.batches), rev_sync(st0, st1, st2,)); + (new, st) } } From 67eb42039a2935bfb63e4fd86e3fa47a37f8b4cf Mon Sep 17 00:00:00 2001 From: "Eduard S." Date: Mon, 20 Oct 2025 10:52:56 +0200 Subject: [PATCH 8/8] fix comment --- app/src/macros.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/macros.rs b/app/src/macros.rs index 73c4f7b..08ce1ef 100644 --- a/app/src/macros.rs +++ b/app/src/macros.rs @@ -98,11 +98,10 @@ macro_rules! _st_custom_args { }}; } -/// ``` +/// Argument types: /// $builder: &mut MainPodBuilder /// $batches: &[Arc {{