1use super::{
2 protocol_state::{self, ProtocolStateView},
3 zkapp_statement::TransactionCommitment,
4 Memo, TransactionFailure, TransactionStatus, WithStatus,
5};
6use crate::{
7 dummy, gen_compressed, gen_keypair,
8 hash::AppendToInputs,
9 proofs::{
10 field::{Boolean, ToBoolean},
11 to_field_elements::ToFieldElements,
12 transaction::Check,
13 witness::Witness,
14 },
15 scan_state::{
16 currency::{
17 Amount, Balance, Fee, Length, Magnitude, MinMax, Nonce, Sgn, Signed, Slot, SlotSpan,
18 },
19 fee_excess::FeeExcess,
20 GenesisConstant, GENESIS_CONSTANT,
21 },
22 zkapps::checks::{ZkappCheck, ZkappCheckOps},
23 AccountId, AuthRequired, ControlTag, MutableFp, MyCow, Permissions, SetVerificationKey,
24 ToInputs, TokenId, TokenSymbol, VerificationKey, VerificationKeyWire, VotingFor, ZkAppAccount,
25 ZkAppUri,
26};
27use ark_ff::{UniformRand, Zero};
28use itertools::Itertools;
29use mina_curves::pasta::Fp;
30use mina_p2p_messages::v2::MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesA;
31use mina_signer::{CompressedPubKey, Signature};
32use poseidon::hash::{
33 hash_noinputs, hash_with_kimchi,
34 params::{
35 MINA_ACCOUNT_UPDATE_CONS, MINA_ACCOUNT_UPDATE_NODE, MINA_ZKAPP_EVENT, MINA_ZKAPP_EVENTS,
36 MINA_ZKAPP_SEQ_EVENTS, NO_INPUT_MINA_ZKAPP_ACTIONS_EMPTY, NO_INPUT_MINA_ZKAPP_EVENTS_EMPTY,
37 },
38 Inputs,
39};
40use rand::{seq::SliceRandom, Rng};
41use std::sync::Arc;
42
43pub mod from_applied_sequence;
44pub mod from_unapplied_sequence;
45pub mod valid;
46pub mod verifiable;
47pub mod zkapp_weight;
48
49#[derive(Debug, Clone, PartialEq)]
50pub struct Event(pub Vec<Fp>);
51
52impl Event {
53 pub fn empty() -> Self {
54 Self(Vec::new())
55 }
56
57 pub fn hash(&self) -> Fp {
58 hash_with_kimchi(&MINA_ZKAPP_EVENT, &self.0[..])
59 }
60
61 pub fn len(&self) -> usize {
62 let Self(list) = self;
63 list.len()
64 }
65}
66
67#[derive(Debug, Clone, PartialEq)]
69pub struct Events(pub Vec<Event>);
70
71#[derive(Debug, Clone, PartialEq)]
73pub struct Actions(pub Vec<Event>);
74
75pub fn gen_events() -> Vec<Event> {
76 let mut rng = rand::thread_rng();
77
78 let n = rng.gen_range(0..=5);
79
80 (0..=n)
81 .map(|_| {
82 let n = rng.gen_range(0..=3);
83 let event = (0..=n).map(|_| Fp::rand(&mut rng)).collect();
84 Event(event)
85 })
86 .collect()
87}
88
89use poseidon::hash::LazyParam;
90
91pub trait MakeEvents {
93 const DERIVER_NAME: (); fn get_salt_phrase() -> &'static LazyParam;
96
97 fn get_hash_prefix() -> &'static LazyParam;
98
99 fn events(&self) -> &[Event];
100
101 fn empty_hash() -> Fp;
102}
103
104impl MakeEvents for Events {
106 const DERIVER_NAME: () = ();
107
108 fn get_salt_phrase() -> &'static LazyParam {
109 &NO_INPUT_MINA_ZKAPP_EVENTS_EMPTY
110 }
111
112 fn get_hash_prefix() -> &'static poseidon::hash::LazyParam {
113 &MINA_ZKAPP_EVENTS
114 }
115
116 fn events(&self) -> &[Event] {
117 self.0.as_slice()
118 }
119
120 fn empty_hash() -> Fp {
121 cache_one!(Fp, events_to_field(&Events::empty()))
122 }
123}
124
125impl MakeEvents for Actions {
127 const DERIVER_NAME: () = ();
128
129 fn get_salt_phrase() -> &'static LazyParam {
130 &NO_INPUT_MINA_ZKAPP_ACTIONS_EMPTY
131 }
132
133 fn get_hash_prefix() -> &'static poseidon::hash::LazyParam {
134 &MINA_ZKAPP_SEQ_EVENTS
135 }
136
137 fn events(&self) -> &[Event] {
138 self.0.as_slice()
139 }
140
141 fn empty_hash() -> Fp {
142 cache_one!(Fp, events_to_field(&Actions::empty()))
143 }
144}
145
146pub fn events_to_field<E>(e: &E) -> Fp
148where
149 E: MakeEvents,
150{
151 let init = hash_noinputs(E::get_salt_phrase());
152
153 e.events().iter().rfold(init, |accum, elem| {
154 hash_with_kimchi(E::get_hash_prefix(), &[accum, elem.hash()])
155 })
156}
157
158impl ToInputs for Events {
159 fn to_inputs(&self, inputs: &mut Inputs) {
160 inputs.append(&events_to_field(self));
161 }
162}
163
164impl ToInputs for Actions {
165 fn to_inputs(&self, inputs: &mut Inputs) {
166 inputs.append(&events_to_field(self));
167 }
168}
169
170impl ToFieldElements<Fp> for Events {
171 fn to_field_elements(&self, fields: &mut Vec<Fp>) {
172 events_to_field(self).to_field_elements(fields);
173 }
174}
175
176impl ToFieldElements<Fp> for Actions {
177 fn to_field_elements(&self, fields: &mut Vec<Fp>) {
178 events_to_field(self).to_field_elements(fields);
179 }
180}
181
182#[derive(Clone, Debug, PartialEq, Eq)]
186pub struct Timing {
187 pub initial_minimum_balance: Balance,
188 pub cliff_time: Slot,
189 pub cliff_amount: Amount,
190 pub vesting_period: SlotSpan,
191 pub vesting_increment: Amount,
192}
193
194impl Timing {
195 fn dummy() -> Self {
197 Self {
198 initial_minimum_balance: Balance::zero(),
199 cliff_time: Slot::zero(),
200 cliff_amount: Amount::zero(),
201 vesting_period: SlotSpan::zero(),
202 vesting_increment: Amount::zero(),
203 }
204 }
205
206 pub fn of_account_timing(timing: crate::account::Timing) -> Option<Self> {
209 match timing {
210 crate::Timing::Untimed => None,
211 crate::Timing::Timed {
212 initial_minimum_balance,
213 cliff_time,
214 cliff_amount,
215 vesting_period,
216 vesting_increment,
217 } => Some(Self {
218 initial_minimum_balance,
219 cliff_time,
220 cliff_amount,
221 vesting_period,
222 vesting_increment,
223 }),
224 }
225 }
226
227 pub fn to_account_timing(self) -> crate::account::Timing {
229 let Self {
230 initial_minimum_balance,
231 cliff_time,
232 cliff_amount,
233 vesting_period,
234 vesting_increment,
235 } = self;
236
237 crate::account::Timing::Timed {
238 initial_minimum_balance,
239 cliff_time,
240 cliff_amount,
241 vesting_period,
242 vesting_increment,
243 }
244 }
245}
246
247impl ToFieldElements<Fp> for Timing {
248 fn to_field_elements(&self, fields: &mut Vec<Fp>) {
249 let Self {
250 initial_minimum_balance,
251 cliff_time,
252 cliff_amount,
253 vesting_period,
254 vesting_increment,
255 } = self;
256
257 initial_minimum_balance.to_field_elements(fields);
258 cliff_time.to_field_elements(fields);
259 cliff_amount.to_field_elements(fields);
260 vesting_period.to_field_elements(fields);
261 vesting_increment.to_field_elements(fields);
262 }
263}
264
265impl Check<Fp> for Timing {
266 fn check(&self, w: &mut Witness<Fp>) {
267 let Self {
268 initial_minimum_balance,
269 cliff_time,
270 cliff_amount,
271 vesting_period,
272 vesting_increment,
273 } = self;
274
275 initial_minimum_balance.check(w);
276 cliff_time.check(w);
277 cliff_amount.check(w);
278 vesting_period.check(w);
279 vesting_increment.check(w);
280 }
281}
282
283impl ToInputs for Timing {
284 fn to_inputs(&self, inputs: &mut Inputs) {
286 let Timing {
287 initial_minimum_balance,
288 cliff_time,
289 cliff_amount,
290 vesting_period,
291 vesting_increment,
292 } = self;
293
294 inputs.append_u64(initial_minimum_balance.as_u64());
295 inputs.append_u32(cliff_time.as_u32());
296 inputs.append_u64(cliff_amount.as_u64());
297 inputs.append_u32(vesting_period.as_u32());
298 inputs.append_u64(vesting_increment.as_u64());
299 }
300}
301
302impl Events {
303 pub fn empty() -> Self {
304 Self(Vec::new())
305 }
306
307 pub fn is_empty(&self) -> bool {
308 self.0.is_empty()
309 }
310
311 pub fn push_event(acc: Fp, event: Event) -> Fp {
312 hash_with_kimchi(Self::get_hash_prefix(), &[acc, event.hash()])
313 }
314
315 pub fn push_events(&self, acc: Fp) -> Fp {
316 let hash = self
317 .0
318 .iter()
319 .rfold(hash_noinputs(Self::get_salt_phrase()), |acc, e| {
320 Self::push_event(acc, e.clone())
321 });
322 hash_with_kimchi(Self::get_hash_prefix(), &[acc, hash])
323 }
324}
325
326impl Actions {
327 pub fn empty() -> Self {
328 Self(Vec::new())
329 }
330
331 pub fn is_empty(&self) -> bool {
332 self.0.is_empty()
333 }
334
335 pub fn push_event(acc: Fp, event: Event) -> Fp {
336 hash_with_kimchi(Self::get_hash_prefix(), &[acc, event.hash()])
337 }
338
339 pub fn push_events(&self, acc: Fp) -> Fp {
340 let hash = self
341 .0
342 .iter()
343 .rfold(hash_noinputs(Self::get_salt_phrase()), |acc, e| {
344 Self::push_event(acc, e.clone())
345 });
346 hash_with_kimchi(Self::get_hash_prefix(), &[acc, hash])
347 }
348}
349
350#[derive(Debug, Clone, PartialEq, Eq)]
352pub enum SetOrKeep<T: Clone> {
353 Set(T),
354 Keep,
355}
356
357impl<T: Clone> SetOrKeep<T> {
358 fn map<'a, F, U>(&'a self, fun: F) -> SetOrKeep<U>
359 where
360 F: FnOnce(&'a T) -> U,
361 U: Clone,
362 {
363 match self {
364 SetOrKeep::Set(v) => SetOrKeep::Set(fun(v)),
365 SetOrKeep::Keep => SetOrKeep::Keep,
366 }
367 }
368
369 pub fn into_map<F, U>(self, fun: F) -> SetOrKeep<U>
370 where
371 F: FnOnce(T) -> U,
372 U: Clone,
373 {
374 match self {
375 SetOrKeep::Set(v) => SetOrKeep::Set(fun(v)),
376 SetOrKeep::Keep => SetOrKeep::Keep,
377 }
378 }
379
380 pub fn set_or_keep(&self, x: T) -> T {
381 match self {
382 Self::Set(data) => data.clone(),
383 Self::Keep => x,
384 }
385 }
386
387 pub fn is_keep(&self) -> bool {
388 match self {
389 Self::Keep => true,
390 Self::Set(_) => false,
391 }
392 }
393
394 pub fn is_set(&self) -> bool {
395 !self.is_keep()
396 }
397
398 pub fn gen<F>(mut fun: F) -> Self
399 where
400 F: FnMut() -> T,
401 {
402 let mut rng = rand::thread_rng();
403
404 if rng.gen() {
405 Self::Set(fun())
406 } else {
407 Self::Keep
408 }
409 }
410}
411
412impl<T, F> ToInputs for (&SetOrKeep<T>, F)
413where
414 T: ToInputs,
415 T: Clone,
416 F: Fn() -> T,
417{
418 fn to_inputs(&self, inputs: &mut Inputs) {
420 let (set_or_keep, default_fn) = self;
421
422 match set_or_keep {
423 SetOrKeep::Set(this) => {
424 inputs.append_bool(true);
425 this.to_inputs(inputs);
426 }
427 SetOrKeep::Keep => {
428 inputs.append_bool(false);
429 let default = default_fn();
430 default.to_inputs(inputs);
431 }
432 }
433 }
434}
435
436impl<T, F> ToFieldElements<Fp> for (&SetOrKeep<T>, F)
437where
438 T: ToFieldElements<Fp>,
439 T: Clone,
440 F: Fn() -> T,
441{
442 fn to_field_elements(&self, fields: &mut Vec<Fp>) {
443 let (set_or_keep, default_fn) = self;
444
445 match set_or_keep {
446 SetOrKeep::Set(this) => {
447 Boolean::True.to_field_elements(fields);
448 this.to_field_elements(fields);
449 }
450 SetOrKeep::Keep => {
451 Boolean::False.to_field_elements(fields);
452 let default = default_fn();
453 default.to_field_elements(fields);
454 }
455 }
456 }
457}
458
459impl<T, F> Check<Fp> for (&SetOrKeep<T>, F)
460where
461 T: Check<Fp>,
462 T: Clone,
463 F: Fn() -> T,
464{
465 fn check(&self, w: &mut Witness<Fp>) {
466 let (set_or_keep, default_fn) = self;
467 let value = match set_or_keep {
468 SetOrKeep::Set(this) => MyCow::Borrow(this),
469 SetOrKeep::Keep => MyCow::Own(default_fn()),
470 };
471 value.check(w);
472 }
473}
474
475#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
476pub struct WithHash<T, H = Fp> {
477 pub data: T,
478 pub hash: H,
479}
480
481impl<T, H: Ord> Ord for WithHash<T, H> {
482 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
483 self.hash.cmp(&other.hash)
484 }
485}
486
487impl<T, H: PartialOrd> PartialOrd for WithHash<T, H> {
488 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
489 self.hash.partial_cmp(&other.hash)
490 }
491}
492
493impl<T, H: Eq> Eq for WithHash<T, H> {}
494
495impl<T, H: PartialEq> PartialEq for WithHash<T, H> {
496 fn eq(&self, other: &Self) -> bool {
497 self.hash == other.hash
498 }
499}
500
501impl<T, Hash: std::hash::Hash> std::hash::Hash for WithHash<T, Hash> {
502 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
503 let Self { data: _, hash } = self;
504 hash.hash(state);
505 }
506}
507
508impl<T> ToFieldElements<Fp> for WithHash<T> {
509 fn to_field_elements(&self, fields: &mut Vec<Fp>) {
510 let Self { data: _, hash } = self;
511 hash.to_field_elements(fields);
512 }
513}
514
515impl<T> std::ops::Deref for WithHash<T> {
516 type Target = T;
517
518 fn deref(&self) -> &Self::Target {
519 &self.data
520 }
521}
522
523impl<T> WithHash<T> {
524 pub fn of_data(data: T, hash_data: impl Fn(&T) -> Fp) -> Self {
525 let hash = hash_data(&data);
526 Self { data, hash }
527 }
528}
529
530#[derive(Debug, Clone, PartialEq, Eq)]
532pub struct Update {
533 pub app_state: [SetOrKeep<Fp>; 8],
534 pub delegate: SetOrKeep<CompressedPubKey>,
535 pub verification_key: SetOrKeep<VerificationKeyWire>,
536 pub permissions: SetOrKeep<Permissions<AuthRequired>>,
537 pub zkapp_uri: SetOrKeep<ZkAppUri>,
538 pub token_symbol: SetOrKeep<TokenSymbol>,
539 pub timing: SetOrKeep<Timing>,
540 pub voting_for: SetOrKeep<VotingFor>,
541}
542
543impl ToFieldElements<Fp> for Update {
544 fn to_field_elements(&self, fields: &mut Vec<Fp>) {
545 let Self {
546 app_state,
547 delegate,
548 verification_key,
549 permissions,
550 zkapp_uri,
551 token_symbol,
552 timing,
553 voting_for,
554 } = self;
555
556 for s in app_state {
557 (s, Fp::zero).to_field_elements(fields);
558 }
559 (delegate, CompressedPubKey::empty).to_field_elements(fields);
560 (&verification_key.map(|w| w.hash()), Fp::zero).to_field_elements(fields);
561 (permissions, Permissions::empty).to_field_elements(fields);
562 (&zkapp_uri.map(Some), || Option::<&ZkAppUri>::None).to_field_elements(fields);
563 (token_symbol, TokenSymbol::default).to_field_elements(fields);
564 (timing, Timing::dummy).to_field_elements(fields);
565 (voting_for, VotingFor::dummy).to_field_elements(fields);
566 }
567}
568
569impl Update {
570 pub fn noop() -> Self {
572 Self {
573 app_state: std::array::from_fn(|_| SetOrKeep::Keep),
574 delegate: SetOrKeep::Keep,
575 verification_key: SetOrKeep::Keep,
576 permissions: SetOrKeep::Keep,
577 zkapp_uri: SetOrKeep::Keep,
578 token_symbol: SetOrKeep::Keep,
579 timing: SetOrKeep::Keep,
580 voting_for: SetOrKeep::Keep,
581 }
582 }
583
584 pub fn dummy() -> Self {
586 Self::noop()
587 }
588
589 pub fn gen(
591 token_account: Option<bool>,
592 zkapp_account: Option<bool>,
593 vk: Option<&VerificationKeyWire>,
594 permissions_auth: Option<crate::ControlTag>,
595 ) -> Self {
596 let mut rng = rand::thread_rng();
597
598 let token_account = token_account.unwrap_or(false);
599 let zkapp_account = zkapp_account.unwrap_or(false);
600
601 let app_state: [_; 8] = std::array::from_fn(|_| SetOrKeep::gen(|| Fp::rand(&mut rng)));
602
603 let delegate = if !token_account {
604 SetOrKeep::gen(|| gen_keypair().public.into_compressed())
605 } else {
606 SetOrKeep::Keep
607 };
608
609 let verification_key = if zkapp_account {
610 SetOrKeep::gen(|| match vk {
611 None => VerificationKeyWire::dummy(),
612 Some(vk) => vk.clone(),
613 })
614 } else {
615 SetOrKeep::Keep
616 };
617
618 let permissions = match permissions_auth {
619 None => SetOrKeep::Keep,
620 Some(auth_tag) => SetOrKeep::Set(Permissions::gen(auth_tag)),
621 };
622
623 let zkapp_uri = SetOrKeep::gen(|| {
624 ZkAppUri::from(
625 [
626 "https://www.example.com",
627 "https://www.minaprotocol.com",
628 "https://www.gurgle.com",
629 "https://faceplant.com",
630 ]
631 .choose(&mut rng)
632 .unwrap()
633 .to_string()
634 .into_bytes(),
635 )
636 });
637
638 let token_symbol = SetOrKeep::gen(|| {
639 TokenSymbol::from(
640 ["MINA", "TOKEN1", "TOKEN2", "TOKEN3", "TOKEN4", "TOKEN5"]
641 .choose(&mut rng)
642 .unwrap()
643 .to_string()
644 .into_bytes(),
645 )
646 });
647
648 let voting_for = SetOrKeep::gen(|| VotingFor(Fp::rand(&mut rng)));
649
650 let timing = SetOrKeep::Keep;
651
652 Self {
653 app_state,
654 delegate,
655 verification_key,
656 permissions,
657 zkapp_uri,
658 token_symbol,
659 timing,
660 voting_for,
661 }
662 }
663}
664
665#[derive(Debug, Clone, PartialEq)]
668pub struct ClosedInterval<T> {
669 pub lower: T,
670 pub upper: T,
671}
672
673impl<T> ClosedInterval<T>
674where
675 T: MinMax,
676{
677 pub fn min_max() -> Self {
678 Self {
679 lower: T::min(),
680 upper: T::max(),
681 }
682 }
683}
684
685impl<T> ToInputs for ClosedInterval<T>
686where
687 T: ToInputs,
688{
689 fn to_inputs(&self, inputs: &mut Inputs) {
691 let ClosedInterval { lower, upper } = self;
692
693 lower.to_inputs(inputs);
694 upper.to_inputs(inputs);
695 }
696}
697
698impl<T> ToFieldElements<Fp> for ClosedInterval<T>
699where
700 T: ToFieldElements<Fp>,
701{
702 fn to_field_elements(&self, fields: &mut Vec<Fp>) {
703 let ClosedInterval { lower, upper } = self;
704
705 lower.to_field_elements(fields);
706 upper.to_field_elements(fields);
707 }
708}
709
710impl<T> Check<Fp> for ClosedInterval<T>
711where
712 T: Check<Fp>,
713{
714 fn check(&self, w: &mut Witness<Fp>) {
715 let ClosedInterval { lower, upper } = self;
716 lower.check(w);
717 upper.check(w);
718 }
719}
720
721impl<T> ClosedInterval<T>
722where
723 T: PartialOrd,
724{
725 pub fn is_constant(&self) -> bool {
726 self.lower == self.upper
727 }
728
729 pub fn gen<F>(mut fun: F) -> Self
731 where
732 F: FnMut() -> T,
733 {
734 let a1 = fun();
735 let a2 = fun();
736
737 if a1 <= a2 {
738 Self {
739 lower: a1,
740 upper: a2,
741 }
742 } else {
743 Self {
744 lower: a2,
745 upper: a1,
746 }
747 }
748 }
749}
750
751#[derive(Debug, Clone, PartialEq)]
753pub enum OrIgnore<T> {
754 Check(T),
755 Ignore,
756}
757
758impl<T, F> ToInputs for (&OrIgnore<T>, F)
759where
760 T: ToInputs,
761 F: Fn() -> T,
762{
763 fn to_inputs(&self, inputs: &mut Inputs) {
765 let (or_ignore, default_fn) = self;
766
767 match or_ignore {
768 OrIgnore::Check(this) => {
769 inputs.append_bool(true);
770 this.to_inputs(inputs);
771 }
772 OrIgnore::Ignore => {
773 inputs.append_bool(false);
774 let default = default_fn();
775 default.to_inputs(inputs);
776 }
777 }
778 }
779}
780
781impl<T, F> ToFieldElements<Fp> for (&OrIgnore<T>, F)
782where
783 T: ToFieldElements<Fp>,
784 F: Fn() -> T,
785{
786 fn to_field_elements(&self, fields: &mut Vec<Fp>) {
787 let (or_ignore, default_fn) = self;
788
789 match or_ignore {
790 OrIgnore::Check(this) => {
791 Boolean::True.to_field_elements(fields);
792 this.to_field_elements(fields);
793 }
794 OrIgnore::Ignore => {
795 Boolean::False.to_field_elements(fields);
796 let default = default_fn();
797 default.to_field_elements(fields);
798 }
799 };
800 }
801}
802
803impl<T, F> Check<Fp> for (&OrIgnore<T>, F)
804where
805 T: Check<Fp>,
806 F: Fn() -> T,
807{
808 fn check(&self, w: &mut Witness<Fp>) {
809 let (or_ignore, default_fn) = self;
810 let value = match or_ignore {
811 OrIgnore::Check(this) => MyCow::Borrow(this),
812 OrIgnore::Ignore => MyCow::Own(default_fn()),
813 };
814 value.check(w);
815 }
816}
817
818impl<T> OrIgnore<T> {
819 pub fn gen<F>(mut fun: F) -> Self
821 where
822 F: FnMut() -> T,
823 {
824 let mut rng = rand::thread_rng();
825
826 if rng.gen() {
827 Self::Check(fun())
828 } else {
829 Self::Ignore
830 }
831 }
832
833 pub fn map<F, V>(&self, fun: F) -> OrIgnore<V>
834 where
835 F: Fn(&T) -> V,
836 {
837 match self {
838 OrIgnore::Check(v) => OrIgnore::Check(fun(v)),
839 OrIgnore::Ignore => OrIgnore::Ignore,
840 }
841 }
842}
843
844impl<T> OrIgnore<ClosedInterval<T>>
845where
846 T: PartialOrd,
847{
848 pub fn is_constant(&self) -> bool {
850 match self {
851 OrIgnore::Check(interval) => interval.lower == interval.upper,
852 OrIgnore::Ignore => false,
853 }
854 }
855}
856
857pub type Hash<T> = OrIgnore<T>;
859
860pub type EqData<T> = OrIgnore<T>;
862
863pub type Numeric<T> = OrIgnore<ClosedInterval<T>>;
865
866#[derive(Debug, Clone, PartialEq)]
868pub struct EpochLedger {
869 pub hash: Hash<Fp>,
870 pub total_currency: Numeric<Amount>,
871}
872
873#[derive(Debug, Clone, PartialEq)]
875pub struct EpochData {
876 pub(crate) ledger: EpochLedger,
877 pub seed: Hash<Fp>,
878 pub start_checkpoint: Hash<Fp>,
879 pub lock_checkpoint: Hash<Fp>,
880 pub epoch_length: Numeric<Length>,
881}
882
883#[cfg(feature = "fuzzing")]
884impl EpochData {
885 pub fn new(
886 ledger: EpochLedger,
887 seed: Hash<Fp>,
888 start_checkpoint: Hash<Fp>,
889 lock_checkpoint: Hash<Fp>,
890 epoch_length: Numeric<Length>,
891 ) -> Self {
892 EpochData {
893 ledger,
894 seed,
895 start_checkpoint,
896 lock_checkpoint,
897 epoch_length,
898 }
899 }
900
901 pub fn ledger_mut(&mut self) -> &mut EpochLedger {
902 &mut self.ledger
903 }
904}
905
906impl ToInputs for EpochData {
907 fn to_inputs(&self, inputs: &mut Inputs) {
909 let EpochData {
910 ledger,
911 seed,
912 start_checkpoint,
913 lock_checkpoint,
914 epoch_length,
915 } = self;
916
917 {
918 let EpochLedger {
919 hash,
920 total_currency,
921 } = ledger;
922
923 inputs.append(&(hash, Fp::zero));
924 inputs.append(&(total_currency, ClosedInterval::min_max));
925 }
926
927 inputs.append(&(seed, Fp::zero));
928 inputs.append(&(start_checkpoint, Fp::zero));
929 inputs.append(&(lock_checkpoint, Fp::zero));
930 inputs.append(&(epoch_length, ClosedInterval::min_max));
931 }
932}
933
934impl ToFieldElements<Fp> for EpochData {
935 fn to_field_elements(&self, fields: &mut Vec<Fp>) {
936 let EpochData {
937 ledger,
938 seed,
939 start_checkpoint,
940 lock_checkpoint,
941 epoch_length,
942 } = self;
943
944 {
945 let EpochLedger {
946 hash,
947 total_currency,
948 } = ledger;
949
950 (hash, Fp::zero).to_field_elements(fields);
951 (total_currency, ClosedInterval::min_max).to_field_elements(fields);
952 }
953
954 (seed, Fp::zero).to_field_elements(fields);
955 (start_checkpoint, Fp::zero).to_field_elements(fields);
956 (lock_checkpoint, Fp::zero).to_field_elements(fields);
957 (epoch_length, ClosedInterval::min_max).to_field_elements(fields);
958 }
959}
960
961impl Check<Fp> for EpochData {
962 fn check(&self, w: &mut Witness<Fp>) {
963 let EpochData {
964 ledger,
965 seed,
966 start_checkpoint,
967 lock_checkpoint,
968 epoch_length,
969 } = self;
970
971 {
972 let EpochLedger {
973 hash,
974 total_currency,
975 } = ledger;
976
977 (hash, Fp::zero).check(w);
978 (total_currency, ClosedInterval::min_max).check(w);
979 }
980
981 (seed, Fp::zero).check(w);
982 (start_checkpoint, Fp::zero).check(w);
983 (lock_checkpoint, Fp::zero).check(w);
984 (epoch_length, ClosedInterval::min_max).check(w);
985 }
986}
987
988impl EpochData {
989 pub fn gen() -> Self {
990 let mut rng = rand::thread_rng();
991
992 EpochData {
993 ledger: EpochLedger {
994 hash: OrIgnore::gen(|| Fp::rand(&mut rng)),
995 total_currency: OrIgnore::gen(|| ClosedInterval::gen(|| rng.gen())),
996 },
997 seed: OrIgnore::gen(|| Fp::rand(&mut rng)),
998 start_checkpoint: OrIgnore::gen(|| Fp::rand(&mut rng)),
999 lock_checkpoint: OrIgnore::gen(|| Fp::rand(&mut rng)),
1000 epoch_length: OrIgnore::gen(|| ClosedInterval::gen(|| rng.gen())),
1001 }
1002 }
1003}
1004
1005#[derive(Debug, Clone, PartialEq)]
1007pub struct ZkAppPreconditions {
1008 pub snarked_ledger_hash: Hash<Fp>,
1009 pub blockchain_length: Numeric<Length>,
1010 pub min_window_density: Numeric<Length>,
1011 pub total_currency: Numeric<Amount>,
1012 pub global_slot_since_genesis: Numeric<Slot>,
1013 pub staking_epoch_data: EpochData,
1014 pub next_epoch_data: EpochData,
1015}
1016
1017impl ZkAppPreconditions {
1018 pub fn zcheck<Ops: ZkappCheckOps>(
1019 &self,
1020 s: &ProtocolStateView,
1021 w: &mut Witness<Fp>,
1022 ) -> Boolean {
1023 let Self {
1024 snarked_ledger_hash,
1025 blockchain_length,
1026 min_window_density,
1027 total_currency,
1028 global_slot_since_genesis,
1029 staking_epoch_data,
1030 next_epoch_data,
1031 } = self;
1032
1033 let epoch_data =
1036 |epoch_data: &EpochData, view: &protocol_state::EpochData<Fp>, w: &mut Witness<Fp>| {
1037 let EpochData {
1038 ledger:
1039 EpochLedger {
1040 hash,
1041 total_currency,
1042 },
1043 seed: _,
1044 start_checkpoint,
1045 lock_checkpoint,
1046 epoch_length,
1047 } = epoch_data;
1048 [
1051 (epoch_length, ClosedInterval::min_max).zcheck::<Ops>(&view.epoch_length, w),
1052 (lock_checkpoint, Fp::zero).zcheck::<Ops>(&view.lock_checkpoint, w),
1053 (start_checkpoint, Fp::zero).zcheck::<Ops>(&view.start_checkpoint, w),
1054 (total_currency, ClosedInterval::min_max)
1055 .zcheck::<Ops>(&view.ledger.total_currency, w),
1056 (hash, Fp::zero).zcheck::<Ops>(&view.ledger.hash, w),
1057 ]
1058 };
1059
1060 let next_epoch_data = epoch_data(next_epoch_data, &s.next_epoch_data, w);
1061 let staking_epoch_data = epoch_data(staking_epoch_data, &s.staking_epoch_data, w);
1062
1063 let bools = [
1066 (global_slot_since_genesis, ClosedInterval::min_max)
1067 .zcheck::<Ops>(&s.global_slot_since_genesis, w),
1068 (total_currency, ClosedInterval::min_max).zcheck::<Ops>(&s.total_currency, w),
1069 (min_window_density, ClosedInterval::min_max).zcheck::<Ops>(&s.min_window_density, w),
1070 (blockchain_length, ClosedInterval::min_max).zcheck::<Ops>(&s.blockchain_length, w),
1071 (snarked_ledger_hash, Fp::zero).zcheck::<Ops>(&s.snarked_ledger_hash, w),
1072 ]
1073 .into_iter()
1074 .rev()
1075 .chain(staking_epoch_data.into_iter().rev())
1076 .chain(next_epoch_data.into_iter().rev());
1077
1078 Ops::boolean_all(bools, w)
1079 }
1080
1081 pub fn accept() -> Self {
1083 let epoch_data = || EpochData {
1084 ledger: EpochLedger {
1085 hash: OrIgnore::Ignore,
1086 total_currency: OrIgnore::Ignore,
1087 },
1088 seed: OrIgnore::Ignore,
1089 start_checkpoint: OrIgnore::Ignore,
1090 lock_checkpoint: OrIgnore::Ignore,
1091 epoch_length: OrIgnore::Ignore,
1092 };
1093
1094 Self {
1095 snarked_ledger_hash: OrIgnore::Ignore,
1096 blockchain_length: OrIgnore::Ignore,
1097 min_window_density: OrIgnore::Ignore,
1098 total_currency: OrIgnore::Ignore,
1099 global_slot_since_genesis: OrIgnore::Ignore,
1100 staking_epoch_data: epoch_data(),
1101 next_epoch_data: epoch_data(),
1102 }
1103 }
1104}
1105
1106impl ToInputs for ZkAppPreconditions {
1107 fn to_inputs(&self, inputs: &mut Inputs) {
1109 let ZkAppPreconditions {
1110 snarked_ledger_hash,
1111 blockchain_length,
1112 min_window_density,
1113 total_currency,
1114 global_slot_since_genesis,
1115 staking_epoch_data,
1116 next_epoch_data,
1117 } = &self;
1118
1119 inputs.append(&(snarked_ledger_hash, Fp::zero));
1120 inputs.append(&(blockchain_length, ClosedInterval::min_max));
1121 inputs.append(&(min_window_density, ClosedInterval::min_max));
1122 inputs.append(&(total_currency, ClosedInterval::min_max));
1123 inputs.append(&(global_slot_since_genesis, ClosedInterval::min_max));
1124 inputs.append(staking_epoch_data);
1125 inputs.append(next_epoch_data);
1126 }
1127}
1128
1129impl ToFieldElements<Fp> for ZkAppPreconditions {
1130 fn to_field_elements(&self, fields: &mut Vec<Fp>) {
1131 let Self {
1132 snarked_ledger_hash,
1133 blockchain_length,
1134 min_window_density,
1135 total_currency,
1136 global_slot_since_genesis,
1137 staking_epoch_data,
1138 next_epoch_data,
1139 } = self;
1140
1141 (snarked_ledger_hash, Fp::zero).to_field_elements(fields);
1142 (blockchain_length, ClosedInterval::min_max).to_field_elements(fields);
1143 (min_window_density, ClosedInterval::min_max).to_field_elements(fields);
1144 (total_currency, ClosedInterval::min_max).to_field_elements(fields);
1145 (global_slot_since_genesis, ClosedInterval::min_max).to_field_elements(fields);
1146 staking_epoch_data.to_field_elements(fields);
1147 next_epoch_data.to_field_elements(fields);
1148 }
1149}
1150
1151impl Check<Fp> for ZkAppPreconditions {
1152 fn check(&self, w: &mut Witness<Fp>) {
1153 let Self {
1154 snarked_ledger_hash,
1155 blockchain_length,
1156 min_window_density,
1157 total_currency,
1158 global_slot_since_genesis,
1159 staking_epoch_data,
1160 next_epoch_data,
1161 } = self;
1162
1163 (snarked_ledger_hash, Fp::zero).check(w);
1164 (blockchain_length, ClosedInterval::min_max).check(w);
1165 (min_window_density, ClosedInterval::min_max).check(w);
1166 (total_currency, ClosedInterval::min_max).check(w);
1167 (global_slot_since_genesis, ClosedInterval::min_max).check(w);
1168 staking_epoch_data.check(w);
1169 next_epoch_data.check(w);
1170 }
1171}
1172
1173fn invalid_public_key() -> CompressedPubKey {
1175 CompressedPubKey {
1176 x: Fp::zero(),
1177 is_odd: false,
1178 }
1179}
1180
1181#[derive(Debug, Clone, PartialEq)]
1183pub struct Account {
1184 pub balance: Numeric<Balance>,
1185 pub nonce: Numeric<Nonce>,
1186 pub receipt_chain_hash: Hash<Fp>, pub delegate: EqData<CompressedPubKey>,
1188 pub state: [EqData<Fp>; 8],
1189 pub action_state: EqData<Fp>,
1190 pub proved_state: EqData<bool>,
1191 pub is_new: EqData<bool>,
1192}
1193
1194impl Account {
1195 pub fn accept() -> Self {
1197 Self {
1198 balance: Numeric::Ignore,
1199 nonce: Numeric::Ignore,
1200 receipt_chain_hash: Hash::Ignore,
1201 delegate: EqData::Ignore,
1202 state: std::array::from_fn(|_| EqData::Ignore),
1203 action_state: EqData::Ignore,
1204 proved_state: EqData::Ignore,
1205 is_new: EqData::Ignore,
1206 }
1207 }
1208}
1209
1210impl Account {
1211 fn zchecks<Ops: ZkappCheckOps>(
1212 &self,
1213 account: &crate::Account,
1214 new_account: Boolean,
1215 w: &mut Witness<Fp>,
1216 ) -> Vec<(TransactionFailure, Boolean)> {
1217 use TransactionFailure::*;
1218
1219 let Self {
1220 balance,
1221 nonce,
1222 receipt_chain_hash,
1223 delegate,
1224 state,
1225 action_state,
1226 proved_state,
1227 is_new,
1228 } = self;
1229
1230 let zkapp_account = account.zkapp_or_empty();
1231 let is_new = is_new.map(ToBoolean::to_boolean);
1232 let proved_state = proved_state.map(ToBoolean::to_boolean);
1233
1234 let mut checks: Vec<(TransactionFailure, _)> = [
1241 (
1242 AccountIsNewPreconditionUnsatisfied,
1243 (&is_new, || Boolean::False).zcheck::<Ops>(&new_account, w),
1244 ),
1245 (
1246 AccountProvedStatePreconditionUnsatisfied,
1247 (&proved_state, || Boolean::False)
1248 .zcheck::<Ops>(&zkapp_account.proved_state.to_boolean(), w),
1249 ),
1250 ]
1251 .into_iter()
1252 .chain({
1253 let bools = state
1254 .iter()
1255 .zip(&zkapp_account.app_state)
1256 .enumerate()
1257 .rev()
1259 .map(|(i, (s, account_s))| {
1260 let b = (s, Fp::zero).zcheck::<Ops>(account_s, w);
1261 (AccountAppStatePreconditionUnsatisfied(i as u64), b)
1262 })
1263 .collect::<Vec<_>>();
1264 bools.into_iter()
1267 })
1268 .chain([
1269 {
1270 let bools: Vec<_> = zkapp_account
1271 .action_state
1272 .iter()
1273 .rev()
1275 .map(|account_s| {
1276 (action_state, ZkAppAccount::empty_action_state).zcheck::<Ops>(account_s, w)
1277 })
1278 .collect();
1279 (
1280 AccountActionStatePreconditionUnsatisfied,
1281 Ops::boolean_any(bools, w),
1282 )
1283 },
1284 (
1285 AccountDelegatePreconditionUnsatisfied,
1286 (delegate, CompressedPubKey::empty).zcheck::<Ops>(&*account.delegate_or_empty(), w),
1287 ),
1288 (
1289 AccountReceiptChainHashPreconditionUnsatisfied,
1290 (receipt_chain_hash, Fp::zero).zcheck::<Ops>(&account.receipt_chain_hash.0, w),
1291 ),
1292 (
1293 AccountNoncePreconditionUnsatisfied,
1294 (nonce, ClosedInterval::min_max).zcheck::<Ops>(&account.nonce, w),
1295 ),
1296 (
1297 AccountBalancePreconditionUnsatisfied,
1298 (balance, ClosedInterval::min_max).zcheck::<Ops>(&account.balance, w),
1299 ),
1300 ])
1301 .collect::<Vec<_>>();
1302
1303 checks.reverse();
1304 checks
1305 }
1306}
1307
1308#[derive(Debug, Clone, PartialEq)]
1310pub struct AccountPreconditions(pub Account);
1311
1312impl ToInputs for AccountPreconditions {
1313 fn to_inputs(&self, inputs: &mut Inputs) {
1316 let Account {
1317 balance,
1318 nonce,
1319 receipt_chain_hash,
1320 delegate,
1321 state,
1322 action_state,
1323 proved_state,
1324 is_new,
1325 } = &self.0;
1326
1327 inputs.append(&(balance, ClosedInterval::min_max));
1328 inputs.append(&(nonce, ClosedInterval::min_max));
1329 inputs.append(&(receipt_chain_hash, Fp::zero));
1330 inputs.append(&(delegate, CompressedPubKey::empty));
1331 for s in state.iter() {
1332 inputs.append(&(s, Fp::zero));
1333 }
1334 inputs.append(&(action_state, ZkAppAccount::empty_action_state));
1336 inputs.append(&(proved_state, || false));
1337 inputs.append(&(is_new, || false));
1338 }
1339}
1340
1341impl ToFieldElements<Fp> for AccountPreconditions {
1342 fn to_field_elements(&self, fields: &mut Vec<Fp>) {
1343 let Account {
1344 balance,
1345 nonce,
1346 receipt_chain_hash,
1347 delegate,
1348 state,
1349 action_state,
1350 proved_state,
1351 is_new,
1352 } = &self.0;
1353
1354 (balance, ClosedInterval::min_max).to_field_elements(fields);
1355 (nonce, ClosedInterval::min_max).to_field_elements(fields);
1356 (receipt_chain_hash, Fp::zero).to_field_elements(fields);
1357 (delegate, CompressedPubKey::empty).to_field_elements(fields);
1358 state.iter().for_each(|s| {
1359 (s, Fp::zero).to_field_elements(fields);
1360 });
1361 (action_state, ZkAppAccount::empty_action_state).to_field_elements(fields);
1362 (proved_state, || false).to_field_elements(fields);
1363 (is_new, || false).to_field_elements(fields);
1364 }
1365}
1366
1367impl Check<Fp> for AccountPreconditions {
1368 fn check(&self, w: &mut Witness<Fp>) {
1369 let Account {
1370 balance,
1371 nonce,
1372 receipt_chain_hash,
1373 delegate,
1374 state,
1375 action_state,
1376 proved_state,
1377 is_new,
1378 } = &self.0;
1379
1380 (balance, ClosedInterval::min_max).check(w);
1381 (nonce, ClosedInterval::min_max).check(w);
1382 (receipt_chain_hash, Fp::zero).check(w);
1383 (delegate, CompressedPubKey::empty).check(w);
1384 state.iter().for_each(|s| {
1385 (s, Fp::zero).check(w);
1386 });
1387 (action_state, ZkAppAccount::empty_action_state).check(w);
1388 (proved_state, || false).check(w);
1389 (is_new, || false).check(w);
1390 }
1391}
1392
1393impl AccountPreconditions {
1394 pub fn with_nonce(nonce: Nonce) -> Self {
1395 use OrIgnore::{Check, Ignore};
1396 AccountPreconditions(Account {
1397 balance: Ignore,
1398 nonce: Check(ClosedInterval {
1399 lower: nonce,
1400 upper: nonce,
1401 }),
1402 receipt_chain_hash: Ignore,
1403 delegate: Ignore,
1404 state: std::array::from_fn(|_| EqData::Ignore),
1405 action_state: Ignore,
1406 proved_state: Ignore,
1407 is_new: Ignore,
1408 })
1409 }
1410
1411 pub fn nonce(&self) -> Numeric<Nonce> {
1412 self.0.nonce.clone()
1413 }
1414
1415 pub fn to_full(&self) -> MyCow<'_, Account> {
1417 MyCow::Borrow(&self.0)
1418 }
1419
1420 pub fn zcheck<Ops, Fun>(
1421 &self,
1422 new_account: Boolean,
1423 account: &crate::Account,
1424 mut check: Fun,
1425 w: &mut Witness<Fp>,
1426 ) where
1427 Ops: ZkappCheckOps,
1428 Fun: FnMut(TransactionFailure, Boolean, &mut Witness<Fp>),
1429 {
1430 let this = self.to_full();
1431 for (failure, passed) in this.zchecks::<Ops>(account, new_account, w) {
1432 check(failure, passed, w);
1433 }
1434 }
1435}
1436
1437#[derive(Debug, Clone, PartialEq)]
1439pub struct Preconditions {
1440 pub network: ZkAppPreconditions,
1441 pub account: AccountPreconditions,
1442 pub valid_while: Numeric<Slot>,
1443}
1444
1445#[cfg(feature = "fuzzing")]
1446impl Preconditions {
1447 pub fn new(
1448 network: ZkAppPreconditions,
1449 account: AccountPreconditions,
1450 valid_while: Numeric<Slot>,
1451 ) -> Self {
1452 Self {
1453 network,
1454 account,
1455 valid_while,
1456 }
1457 }
1458
1459 pub fn network_mut(&mut self) -> &mut ZkAppPreconditions {
1460 &mut self.network
1461 }
1462}
1463
1464impl ToFieldElements<Fp> for Preconditions {
1465 fn to_field_elements(&self, fields: &mut Vec<Fp>) {
1466 let Self {
1467 network,
1468 account,
1469 valid_while,
1470 } = self;
1471
1472 network.to_field_elements(fields);
1473 account.to_field_elements(fields);
1474 (valid_while, ClosedInterval::min_max).to_field_elements(fields);
1475 }
1476}
1477
1478impl Check<Fp> for Preconditions {
1479 fn check(&self, w: &mut Witness<Fp>) {
1480 let Self {
1481 network,
1482 account,
1483 valid_while,
1484 } = self;
1485
1486 network.check(w);
1487 account.check(w);
1488 (valid_while, ClosedInterval::min_max).check(w);
1489 }
1490}
1491
1492impl ToInputs for Preconditions {
1493 fn to_inputs(&self, inputs: &mut Inputs) {
1495 let Self {
1496 network,
1497 account,
1498 valid_while,
1499 } = self;
1500
1501 inputs.append(network);
1502 inputs.append(account);
1503 inputs.append(&(valid_while, ClosedInterval::min_max));
1504 }
1505}
1506
1507#[derive(Debug, Clone, PartialEq, Eq)]
1509pub enum AuthorizationKind {
1510 NoneGiven,
1511 Signature,
1512 Proof(Fp), }
1514
1515impl AuthorizationKind {
1516 pub fn vk_hash(&self) -> Fp {
1517 match self {
1518 AuthorizationKind::NoneGiven | AuthorizationKind::Signature => {
1519 VerificationKey::dummy().hash()
1520 }
1521 AuthorizationKind::Proof(hash) => *hash,
1522 }
1523 }
1524
1525 pub fn is_proved(&self) -> bool {
1526 match self {
1527 AuthorizationKind::Proof(_) => true,
1528 AuthorizationKind::NoneGiven => false,
1529 AuthorizationKind::Signature => false,
1530 }
1531 }
1532
1533 pub fn is_signed(&self) -> bool {
1534 match self {
1535 AuthorizationKind::Proof(_) => false,
1536 AuthorizationKind::NoneGiven => false,
1537 AuthorizationKind::Signature => true,
1538 }
1539 }
1540
1541 fn to_structured(&self) -> ([bool; 2], Fp) {
1542 let bits = match self {
1544 AuthorizationKind::NoneGiven => [false, false],
1545 AuthorizationKind::Signature => [true, false],
1546 AuthorizationKind::Proof(_) => [false, true],
1547 };
1548 let field = self.vk_hash();
1549 (bits, field)
1550 }
1551}
1552
1553impl ToInputs for AuthorizationKind {
1554 fn to_inputs(&self, inputs: &mut Inputs) {
1556 let (bits, field) = self.to_structured();
1557
1558 for bit in bits {
1559 inputs.append_bool(bit);
1560 }
1561 inputs.append_field(field);
1562 }
1563}
1564
1565impl ToFieldElements<Fp> for AuthorizationKind {
1566 fn to_field_elements(&self, fields: &mut Vec<Fp>) {
1567 self.to_structured().to_field_elements(fields);
1568 }
1569}
1570
1571#[derive(Debug, Clone, PartialEq)]
1573pub struct Body {
1574 pub public_key: CompressedPubKey,
1575 pub token_id: TokenId,
1576 pub update: Update,
1577 pub balance_change: Signed<Amount>,
1578 pub increment_nonce: bool,
1579 pub events: Events,
1580 pub actions: Actions,
1581 pub call_data: Fp,
1582 pub preconditions: Preconditions,
1583 pub use_full_commitment: bool,
1584 pub implicit_account_creation_fee: bool,
1585 pub may_use_token: MayUseToken,
1586 pub authorization_kind: AuthorizationKind,
1587}
1588
1589impl ToInputs for Body {
1590 fn to_inputs(&self, inputs: &mut Inputs) {
1592 let Self {
1593 public_key,
1594 token_id,
1595 update,
1596 balance_change,
1597 increment_nonce,
1598 events,
1599 actions,
1600 call_data,
1601 preconditions,
1602 use_full_commitment,
1603 implicit_account_creation_fee,
1604 may_use_token,
1605 authorization_kind,
1606 } = self;
1607
1608 inputs.append(public_key);
1609 inputs.append(token_id);
1610
1611 {
1613 let Update {
1614 app_state,
1615 delegate,
1616 verification_key,
1617 permissions,
1618 zkapp_uri,
1619 token_symbol,
1620 timing,
1621 voting_for,
1622 } = update;
1623
1624 for state in app_state {
1625 inputs.append(&(state, Fp::zero));
1626 }
1627
1628 inputs.append(&(delegate, CompressedPubKey::empty));
1629 inputs.append(&(&verification_key.map(|w| w.hash()), Fp::zero));
1630 inputs.append(&(permissions, Permissions::empty));
1631 inputs.append(&(&zkapp_uri.map(Some), || Option::<&ZkAppUri>::None));
1632 inputs.append(&(token_symbol, TokenSymbol::default));
1633 inputs.append(&(timing, Timing::dummy));
1634 inputs.append(&(voting_for, VotingFor::dummy));
1635 }
1636
1637 inputs.append(balance_change);
1638 inputs.append(increment_nonce);
1639 inputs.append(events);
1640 inputs.append(actions);
1641 inputs.append(call_data);
1642 inputs.append(preconditions);
1643 inputs.append(use_full_commitment);
1644 inputs.append(implicit_account_creation_fee);
1645 inputs.append(may_use_token);
1646 inputs.append(authorization_kind);
1647 }
1648}
1649
1650impl ToFieldElements<Fp> for Body {
1651 fn to_field_elements(&self, fields: &mut Vec<Fp>) {
1652 let Self {
1653 public_key,
1654 token_id,
1655 update,
1656 balance_change,
1657 increment_nonce,
1658 events,
1659 actions,
1660 call_data,
1661 preconditions,
1662 use_full_commitment,
1663 implicit_account_creation_fee,
1664 may_use_token,
1665 authorization_kind,
1666 } = self;
1667
1668 public_key.to_field_elements(fields);
1669 token_id.to_field_elements(fields);
1670 update.to_field_elements(fields);
1671 balance_change.to_field_elements(fields);
1672 increment_nonce.to_field_elements(fields);
1673 events.to_field_elements(fields);
1674 actions.to_field_elements(fields);
1675 call_data.to_field_elements(fields);
1676 preconditions.to_field_elements(fields);
1677 use_full_commitment.to_field_elements(fields);
1678 implicit_account_creation_fee.to_field_elements(fields);
1679 may_use_token.to_field_elements(fields);
1680 authorization_kind.to_field_elements(fields);
1681 }
1682}
1683
1684impl Check<Fp> for Body {
1685 fn check(&self, w: &mut Witness<Fp>) {
1686 let Self {
1687 public_key: _,
1688 token_id: _,
1689 update:
1690 Update {
1691 app_state: _,
1692 delegate: _,
1693 verification_key: _,
1694 permissions,
1695 zkapp_uri: _,
1696 token_symbol,
1697 timing,
1698 voting_for: _,
1699 },
1700 balance_change,
1701 increment_nonce: _,
1702 events: _,
1703 actions: _,
1704 call_data: _,
1705 preconditions,
1706 use_full_commitment: _,
1707 implicit_account_creation_fee: _,
1708 may_use_token,
1709 authorization_kind: _,
1710 } = self;
1711
1712 (permissions, Permissions::empty).check(w);
1713 (token_symbol, TokenSymbol::default).check(w);
1714 (timing, Timing::dummy).check(w);
1715 balance_change.check(w);
1716
1717 preconditions.check(w);
1718 may_use_token.check(w);
1719 }
1720}
1721
1722impl Body {
1723 pub fn account_id(&self) -> AccountId {
1724 let Self {
1725 public_key,
1726 token_id,
1727 ..
1728 } = self;
1729 AccountId::create(public_key.clone(), token_id.clone())
1730 }
1731}
1732
1733#[derive(Debug, Clone, PartialEq)]
1735pub struct BodySimple {
1736 pub public_key: CompressedPubKey,
1737 pub token_id: TokenId,
1738 pub update: Update,
1739 pub balance_change: Signed<Amount>,
1740 pub increment_nonce: bool,
1741 pub events: Events,
1742 pub actions: Actions,
1743 pub call_data: Fp,
1744 pub call_depth: usize,
1745 pub preconditions: Preconditions,
1746 pub use_full_commitment: bool,
1747 pub implicit_account_creation_fee: bool,
1748 pub may_use_token: MayUseToken,
1749 pub authorization_kind: AuthorizationKind,
1750}
1751
1752pub type SideLoadedProof = Arc<mina_p2p_messages::v2::PicklesProofProofsVerifiedMaxStableV2>;
1762
1763#[derive(Clone, PartialEq)]
1769pub enum Control {
1770 Proof(SideLoadedProof),
1773 Signature(Signature),
1775 NoneGiven,
1777}
1778
1779impl std::fmt::Debug for Control {
1780 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1781 match self {
1782 Self::Proof(_) => f.debug_tuple("Proof").field(&"_").finish(),
1783 Self::Signature(arg0) => f.debug_tuple("Signature").field(arg0).finish(),
1784 Self::NoneGiven => write!(f, "NoneGiven"),
1785 }
1786 }
1787}
1788
1789impl Control {
1790 pub fn tag(&self) -> crate::ControlTag {
1792 match self {
1793 Control::Proof(_) => crate::ControlTag::Proof,
1794 Control::Signature(_) => crate::ControlTag::Signature,
1795 Control::NoneGiven => crate::ControlTag::NoneGiven,
1796 }
1797 }
1798
1799 pub fn dummy_of_tag(tag: ControlTag) -> Self {
1800 match tag {
1801 ControlTag::Proof => Self::Proof(dummy::sideloaded_proof()),
1802 ControlTag::Signature => Self::Signature(Signature::dummy()),
1803 ControlTag::NoneGiven => Self::NoneGiven,
1804 }
1805 }
1806
1807 pub fn dummy(&self) -> Self {
1808 Self::dummy_of_tag(self.tag())
1809 }
1810}
1811
1812#[derive(Clone, Debug, PartialEq)]
1813pub enum MayUseToken {
1814 No,
1817 ParentsOwnToken,
1821 InheritFromParent,
1823}
1824
1825impl MayUseToken {
1826 pub fn parents_own_token(&self) -> bool {
1827 matches!(self, Self::ParentsOwnToken)
1828 }
1829
1830 pub fn inherit_from_parent(&self) -> bool {
1831 matches!(self, Self::InheritFromParent)
1832 }
1833
1834 fn to_bits(&self) -> [bool; 2] {
1835 match self {
1837 MayUseToken::No => [false, false],
1838 MayUseToken::ParentsOwnToken => [true, false],
1839 MayUseToken::InheritFromParent => [false, true],
1840 }
1841 }
1842}
1843
1844impl ToInputs for MayUseToken {
1845 fn to_inputs(&self, inputs: &mut Inputs) {
1846 for bit in self.to_bits() {
1847 inputs.append_bool(bit);
1848 }
1849 }
1850}
1851
1852impl ToFieldElements<Fp> for MayUseToken {
1853 fn to_field_elements(&self, fields: &mut Vec<Fp>) {
1854 for bit in self.to_bits() {
1855 bit.to_field_elements(fields);
1856 }
1857 }
1858}
1859
1860impl Check<Fp> for MayUseToken {
1861 fn check(&self, w: &mut Witness<Fp>) {
1862 use crate::proofs::field::field;
1863
1864 let [parents_own_token, inherit_from_parent] = self.to_bits();
1865 let [parents_own_token, inherit_from_parent] = [
1866 parents_own_token.to_boolean(),
1867 inherit_from_parent.to_boolean(),
1868 ];
1869
1870 let sum = parents_own_token.to_field::<Fp>() + inherit_from_parent.to_field::<Fp>();
1871 let _sum_squared = field::mul(sum, sum, w);
1872 }
1873}
1874
1875pub struct CheckAuthorizationResult<Bool> {
1876 pub proof_verifies: Bool,
1877 pub signature_verifies: Bool,
1878}
1879
1880pub type AccountUpdate = AccountUpdateSkeleton<Body>;
1882
1883#[derive(Debug, Clone, PartialEq)]
1884pub struct AccountUpdateSkeleton<Body> {
1885 pub body: Body,
1886 pub authorization: Control,
1887}
1888
1889#[derive(Debug, Clone, PartialEq)]
1891pub struct AccountUpdateSimple {
1892 pub body: BodySimple,
1893 pub authorization: Control,
1894}
1895
1896impl ToInputs for AccountUpdate {
1897 fn to_inputs(&self, inputs: &mut Inputs) {
1899 let Self {
1901 body,
1902 authorization: _,
1903 } = self;
1904
1905 inputs.append(body);
1906 }
1907}
1908
1909impl AccountUpdate {
1910 pub fn of_fee_payer(fee_payer: FeePayer) -> Self {
1913 let FeePayer {
1914 body:
1915 FeePayerBody {
1916 public_key,
1917 fee,
1918 valid_until,
1919 nonce,
1920 },
1921 authorization,
1922 } = fee_payer;
1923
1924 Self {
1925 body: Body {
1926 public_key,
1927 token_id: TokenId::default(),
1928 update: Update::noop(),
1929 balance_change: Signed {
1930 magnitude: Amount::of_fee(&fee),
1931 sgn: Sgn::Neg,
1932 },
1933 increment_nonce: true,
1934 events: Events::empty(),
1935 actions: Actions::empty(),
1936 call_data: Fp::zero(),
1937 preconditions: Preconditions {
1938 network: {
1939 let mut network = ZkAppPreconditions::accept();
1940
1941 let valid_util = valid_until.unwrap_or_else(Slot::max);
1942 network.global_slot_since_genesis = OrIgnore::Check(ClosedInterval {
1943 lower: Slot::zero(),
1944 upper: valid_util,
1945 });
1946
1947 network
1948 },
1949 account: AccountPreconditions::with_nonce(nonce),
1950 valid_while: Numeric::Ignore,
1951 },
1952 use_full_commitment: true,
1953 authorization_kind: AuthorizationKind::Signature,
1954 implicit_account_creation_fee: true,
1955 may_use_token: MayUseToken::No,
1956 },
1957 authorization: Control::Signature(authorization),
1958 }
1959 }
1960
1961 pub fn account_id(&self) -> AccountId {
1963 AccountId::new(self.body.public_key.clone(), self.body.token_id.clone())
1964 }
1965
1966 pub fn digest(&self) -> Fp {
1968 self.hash_with_param(mina_core::NetworkConfig::global().account_update_hash_param)
1969 }
1970
1971 pub fn timing(&self) -> SetOrKeep<Timing> {
1972 self.body.update.timing.clone()
1973 }
1974
1975 pub fn may_use_parents_own_token(&self) -> bool {
1976 self.body.may_use_token.parents_own_token()
1977 }
1978
1979 pub fn may_use_token_inherited_from_parent(&self) -> bool {
1980 self.body.may_use_token.inherit_from_parent()
1981 }
1982
1983 pub fn public_key(&self) -> CompressedPubKey {
1984 self.body.public_key.clone()
1985 }
1986
1987 pub fn token_id(&self) -> TokenId {
1988 self.body.token_id.clone()
1989 }
1990
1991 pub fn increment_nonce(&self) -> bool {
1992 self.body.increment_nonce
1993 }
1994
1995 pub fn implicit_account_creation_fee(&self) -> bool {
1996 self.body.implicit_account_creation_fee
1997 }
1998
1999 pub fn check_authorization(
2001 &self,
2002 _will_succeed: bool,
2003 _commitment: Fp,
2004 _calls: CallForest<AccountUpdate>,
2005 ) -> CheckAuthorizationResult<bool> {
2006 match self.authorization {
2007 Control::Signature(_) => CheckAuthorizationResult {
2008 proof_verifies: false,
2009 signature_verifies: true,
2010 },
2011 Control::Proof(_) => CheckAuthorizationResult {
2012 proof_verifies: true,
2013 signature_verifies: false,
2014 },
2015 Control::NoneGiven => CheckAuthorizationResult {
2016 proof_verifies: false,
2017 signature_verifies: false,
2018 },
2019 }
2020 }
2021
2022 pub fn permissions(&self) -> SetOrKeep<Permissions<AuthRequired>> {
2023 self.body.update.permissions.clone()
2024 }
2025
2026 pub fn app_state(&self) -> [SetOrKeep<Fp>; 8] {
2027 self.body.update.app_state.clone()
2028 }
2029
2030 pub fn zkapp_uri(&self) -> SetOrKeep<ZkAppUri> {
2031 self.body.update.zkapp_uri.clone()
2032 }
2033
2034 pub fn token_symbol(&self) -> SetOrKeep<TokenSymbol> {
2041 self.body.update.token_symbol.clone()
2042 }
2043
2044 pub fn delegate(&self) -> SetOrKeep<CompressedPubKey> {
2045 self.body.update.delegate.clone()
2046 }
2047
2048 pub fn voting_for(&self) -> SetOrKeep<VotingFor> {
2049 self.body.update.voting_for.clone()
2050 }
2051
2052 pub fn verification_key(&self) -> SetOrKeep<VerificationKeyWire> {
2053 self.body.update.verification_key.clone()
2054 }
2055
2056 pub fn valid_while_precondition(&self) -> OrIgnore<ClosedInterval<Slot>> {
2057 self.body.preconditions.valid_while.clone()
2058 }
2059
2060 pub fn actions(&self) -> Actions {
2061 self.body.actions.clone()
2062 }
2063
2064 pub fn balance_change(&self) -> Signed<Amount> {
2065 self.body.balance_change
2066 }
2067 pub fn use_full_commitment(&self) -> bool {
2068 self.body.use_full_commitment
2069 }
2070
2071 pub fn protocol_state_precondition(&self) -> ZkAppPreconditions {
2072 self.body.preconditions.network.clone()
2073 }
2074
2075 pub fn account_precondition(&self) -> AccountPreconditions {
2076 self.body.preconditions.account.clone()
2077 }
2078
2079 pub fn is_proved(&self) -> bool {
2080 match &self.body.authorization_kind {
2081 AuthorizationKind::Proof(_) => true,
2082 AuthorizationKind::Signature | AuthorizationKind::NoneGiven => false,
2083 }
2084 }
2085
2086 pub fn is_signed(&self) -> bool {
2087 match &self.body.authorization_kind {
2088 AuthorizationKind::Signature => true,
2089 AuthorizationKind::Proof(_) | AuthorizationKind::NoneGiven => false,
2090 }
2091 }
2092
2093 pub fn verification_key_hash(&self) -> Option<Fp> {
2095 match &self.body.authorization_kind {
2096 AuthorizationKind::Proof(vk_hash) => Some(*vk_hash),
2097 _ => None,
2098 }
2099 }
2100
2101 pub fn of_simple(simple: &AccountUpdateSimple) -> Self {
2103 let AccountUpdateSimple {
2104 body:
2105 BodySimple {
2106 public_key,
2107 token_id,
2108 update,
2109 balance_change,
2110 increment_nonce,
2111 events,
2112 actions,
2113 call_data,
2114 call_depth: _,
2115 preconditions,
2116 use_full_commitment,
2117 implicit_account_creation_fee,
2118 may_use_token,
2119 authorization_kind,
2120 },
2121 authorization,
2122 } = simple.clone();
2123
2124 Self {
2125 body: Body {
2126 public_key,
2127 token_id,
2128 update,
2129 balance_change,
2130 increment_nonce,
2131 events,
2132 actions,
2133 call_data,
2134 preconditions,
2135 use_full_commitment,
2136 implicit_account_creation_fee,
2137 may_use_token,
2138 authorization_kind,
2139 },
2140 authorization,
2141 }
2142 }
2143
2144 pub fn rand() -> Self {
2146 let mut rng = rand::thread_rng();
2147 let rng = &mut rng;
2148
2149 Self {
2150 body: Body {
2151 public_key: gen_compressed(),
2152 token_id: TokenId(Fp::rand(rng)),
2153 update: Update {
2154 app_state: std::array::from_fn(|_| SetOrKeep::gen(|| Fp::rand(rng))),
2155 delegate: SetOrKeep::gen(gen_compressed),
2156 verification_key: SetOrKeep::gen(VerificationKeyWire::gen),
2157 permissions: SetOrKeep::gen(|| {
2158 let auth_tag = [
2159 ControlTag::NoneGiven,
2160 ControlTag::Proof,
2161 ControlTag::Signature,
2162 ]
2163 .choose(rng)
2164 .unwrap();
2165
2166 Permissions::gen(*auth_tag)
2167 }),
2168 zkapp_uri: SetOrKeep::gen(ZkAppUri::gen),
2169 token_symbol: SetOrKeep::gen(TokenSymbol::gen),
2170 timing: SetOrKeep::gen(|| Timing {
2171 initial_minimum_balance: rng.gen(),
2172 cliff_time: rng.gen(),
2173 cliff_amount: rng.gen(),
2174 vesting_period: rng.gen(),
2175 vesting_increment: rng.gen(),
2176 }),
2177 voting_for: SetOrKeep::gen(|| VotingFor(Fp::rand(rng))),
2178 },
2179 balance_change: Signed::gen(),
2180 increment_nonce: rng.gen(),
2181 events: Events(gen_events()),
2182 actions: Actions(gen_events()),
2183 call_data: Fp::rand(rng),
2184 preconditions: Preconditions {
2185 network: ZkAppPreconditions {
2186 snarked_ledger_hash: OrIgnore::gen(|| Fp::rand(rng)),
2187 blockchain_length: OrIgnore::gen(|| ClosedInterval::gen(|| rng.gen())),
2188 min_window_density: OrIgnore::gen(|| ClosedInterval::gen(|| rng.gen())),
2189 total_currency: OrIgnore::gen(|| ClosedInterval::gen(|| rng.gen())),
2190 global_slot_since_genesis: OrIgnore::gen(|| {
2191 ClosedInterval::gen(|| rng.gen())
2192 }),
2193 staking_epoch_data: EpochData::gen(),
2194 next_epoch_data: EpochData::gen(),
2195 },
2196 account: AccountPreconditions(Account {
2197 balance: OrIgnore::gen(|| ClosedInterval::gen(|| rng.gen())),
2198 nonce: OrIgnore::gen(|| ClosedInterval::gen(|| rng.gen())),
2199 receipt_chain_hash: OrIgnore::gen(|| Fp::rand(rng)),
2200 delegate: OrIgnore::gen(gen_compressed),
2201 state: std::array::from_fn(|_| OrIgnore::gen(|| Fp::rand(rng))),
2202 action_state: OrIgnore::gen(|| Fp::rand(rng)),
2203 proved_state: OrIgnore::gen(|| rng.gen()),
2204 is_new: OrIgnore::gen(|| rng.gen()),
2205 }),
2206 valid_while: OrIgnore::gen(|| ClosedInterval::gen(|| rng.gen())),
2207 },
2208 use_full_commitment: rng.gen(),
2209 implicit_account_creation_fee: rng.gen(),
2210 may_use_token: {
2211 match MayUseToken::No {
2212 MayUseToken::No => (),
2213 MayUseToken::ParentsOwnToken => (),
2214 MayUseToken::InheritFromParent => (),
2215 };
2216
2217 [
2218 MayUseToken::No,
2219 MayUseToken::InheritFromParent,
2220 MayUseToken::ParentsOwnToken,
2221 ]
2222 .choose(rng)
2223 .cloned()
2224 .unwrap()
2225 },
2226 authorization_kind: {
2227 match AuthorizationKind::NoneGiven {
2228 AuthorizationKind::NoneGiven => (),
2229 AuthorizationKind::Signature => (),
2230 AuthorizationKind::Proof(_) => (),
2231 };
2232
2233 [
2234 AuthorizationKind::NoneGiven,
2235 AuthorizationKind::Signature,
2236 AuthorizationKind::Proof(Fp::rand(rng)),
2237 ]
2238 .choose(rng)
2239 .cloned()
2240 .unwrap()
2241 },
2242 },
2243 authorization: {
2244 match Control::NoneGiven {
2245 Control::Proof(_) => (),
2246 Control::Signature(_) => (),
2247 Control::NoneGiven => (),
2248 };
2249
2250 match rng.gen_range(0..3) {
2251 0 => Control::NoneGiven,
2252 1 => Control::Signature(Signature::dummy()),
2253 _ => Control::Proof(dummy::sideloaded_proof()),
2254 }
2255 },
2256 }
2257 }
2258}
2259
2260#[derive(Debug, Clone, PartialEq)]
2262pub struct Tree<AccUpdate: Clone + AccountUpdateRef> {
2263 pub account_update: AccUpdate,
2264 pub account_update_digest: MutableFp,
2265 pub calls: CallForest<AccUpdate>,
2266}
2267
2268impl<AccUpdate: Clone + AccountUpdateRef> Tree<AccUpdate> {
2269 pub fn digest(&self) -> Fp {
2271 let stack_hash = match self.calls.0.first() {
2272 Some(e) => e.stack_hash.get().expect("Must call `ensure_hashed`"),
2273 None => Fp::zero(),
2274 };
2275 let account_update_digest = self.account_update_digest.get().unwrap();
2276 hash_with_kimchi(
2277 &MINA_ACCOUNT_UPDATE_NODE,
2278 &[account_update_digest, stack_hash],
2279 )
2280 }
2281
2282 fn fold<F>(&self, init: Vec<AccountId>, f: &mut F) -> Vec<AccountId>
2283 where
2284 F: FnMut(Vec<AccountId>, &AccUpdate) -> Vec<AccountId>,
2285 {
2286 self.calls.fold(f(init, &self.account_update), f)
2287 }
2288}
2289
2290#[derive(Debug, Clone)]
2292pub struct WithStackHash<AccUpdate: Clone + AccountUpdateRef> {
2293 pub elt: Tree<AccUpdate>,
2294 pub stack_hash: MutableFp,
2295}
2296
2297impl<AccUpdate: Clone + AccountUpdateRef + PartialEq> PartialEq for WithStackHash<AccUpdate> {
2298 fn eq(&self, other: &Self) -> bool {
2299 self.elt == other.elt && self.stack_hash == other.stack_hash
2300 }
2301}
2302
2303#[derive(Debug, Clone, PartialEq)]
2305pub struct CallForest<AccUpdate: Clone + AccountUpdateRef>(pub Vec<WithStackHash<AccUpdate>>);
2306
2307impl<Data: Clone + AccountUpdateRef> Default for CallForest<Data> {
2308 fn default() -> Self {
2309 Self::new()
2310 }
2311}
2312
2313#[derive(Clone)]
2314struct CallForestContext {
2315 caller: TokenId,
2316 this: TokenId,
2317}
2318
2319pub trait AccountUpdateRef {
2320 fn account_update_ref(&self) -> &AccountUpdate;
2321}
2322impl AccountUpdateRef for AccountUpdate {
2323 fn account_update_ref(&self) -> &AccountUpdate {
2324 self
2325 }
2326}
2327impl<T> AccountUpdateRef for (AccountUpdate, T) {
2328 fn account_update_ref(&self) -> &AccountUpdate {
2329 let (this, _) = self;
2330 this
2331 }
2332}
2333impl AccountUpdateRef for AccountUpdateSimple {
2334 fn account_update_ref(&self) -> &AccountUpdate {
2335 unreachable!()
2337 }
2338}
2339
2340impl<AccUpdate: Clone + AccountUpdateRef> CallForest<AccUpdate> {
2341 pub fn new() -> Self {
2342 Self(Vec::new())
2343 }
2344
2345 pub fn empty() -> Self {
2346 Self::new()
2347 }
2348
2349 pub fn is_empty(&self) -> bool {
2350 self.0.is_empty()
2351 }
2352
2353 pub fn iter(&self) -> impl Iterator<Item = &WithStackHash<AccUpdate>> {
2357 self.0.iter() }
2359 pub fn first(&self) -> Option<&WithStackHash<AccUpdate>> {
2361 self.0.first()
2362 }
2363 pub fn tail(&self) -> Option<&[WithStackHash<AccUpdate>]> {
2365 self.0.get(1..)
2366 }
2367
2368 pub fn hash(&self) -> Fp {
2369 self.ensure_hashed();
2370 if let Some(x) = self.first() {
2377 x.stack_hash.get().unwrap() } else {
2379 Fp::zero()
2380 }
2381 }
2382
2383 fn cons_tree(&self, tree: Tree<AccUpdate>) -> Self {
2384 self.ensure_hashed();
2385
2386 let hash = tree.digest();
2387 let h_tl = self.hash();
2388
2389 let stack_hash = hash_with_kimchi(&MINA_ACCOUNT_UPDATE_CONS, &[hash, h_tl]);
2390 let node = WithStackHash::<AccUpdate> {
2391 elt: tree,
2392 stack_hash: MutableFp::new(stack_hash),
2393 };
2394 let mut forest = Vec::with_capacity(self.0.len() + 1);
2395 forest.push(node);
2396 forest.extend(self.0.iter().cloned());
2397
2398 Self(forest)
2399 }
2400
2401 pub fn pop_exn(&self) -> ((AccUpdate, CallForest<AccUpdate>), CallForest<AccUpdate>) {
2402 if self.0.is_empty() {
2403 panic!()
2404 }
2405
2406 let Tree::<AccUpdate> {
2407 account_update,
2408 calls,
2409 ..
2410 } = self.0[0].elt.clone();
2411 (
2412 (account_update, calls),
2413 CallForest(Vec::from_iter(self.0[1..].iter().cloned())),
2414 )
2415 }
2416
2417 fn fold_impl<'a, A, F>(&'a self, init: A, fun: &mut F) -> A
2419 where
2420 F: FnMut(A, &'a AccUpdate) -> A,
2421 {
2422 let mut accum = init;
2423 for elem in self.iter() {
2424 accum = fun(accum, &elem.elt.account_update);
2425 accum = elem.elt.calls.fold_impl(accum, fun);
2426 }
2427 accum
2428 }
2429
2430 pub fn fold<'a, A, F>(&'a self, init: A, mut fun: F) -> A
2431 where
2432 F: FnMut(A, &'a AccUpdate) -> A,
2433 {
2434 self.fold_impl(init, &mut fun)
2435 }
2436
2437 pub fn exists<'a, F>(&'a self, mut fun: F) -> bool
2438 where
2439 F: FnMut(&'a AccUpdate) -> bool,
2440 {
2441 self.fold(false, |acc, x| acc || fun(x))
2442 }
2443
2444 fn map_to_impl<F, AnotherAccUpdate: Clone + AccountUpdateRef>(
2445 &self,
2446 fun: &F,
2447 ) -> CallForest<AnotherAccUpdate>
2448 where
2449 F: Fn(&AccUpdate) -> AnotherAccUpdate,
2450 {
2451 CallForest::<AnotherAccUpdate>(
2452 self.iter()
2453 .map(|item| WithStackHash::<AnotherAccUpdate> {
2454 elt: Tree::<AnotherAccUpdate> {
2455 account_update: fun(&item.elt.account_update),
2456 account_update_digest: item.elt.account_update_digest.clone(),
2457 calls: item.elt.calls.map_to_impl(fun),
2458 },
2459 stack_hash: item.stack_hash.clone(),
2460 })
2461 .collect(),
2462 )
2463 }
2464
2465 #[must_use]
2466 pub fn map_to<F, AnotherAccUpdate: Clone + AccountUpdateRef>(
2467 &self,
2468 fun: F,
2469 ) -> CallForest<AnotherAccUpdate>
2470 where
2471 F: Fn(&AccUpdate) -> AnotherAccUpdate,
2472 {
2473 self.map_to_impl(&fun)
2474 }
2475
2476 fn map_with_trees_to_impl<F, AnotherAccUpdate: Clone + AccountUpdateRef>(
2477 &self,
2478 fun: &F,
2479 ) -> CallForest<AnotherAccUpdate>
2480 where
2481 F: Fn(&AccUpdate, &Tree<AccUpdate>) -> AnotherAccUpdate,
2482 {
2483 CallForest::<AnotherAccUpdate>(
2484 self.iter()
2485 .map(|item| {
2486 let account_update = fun(&item.elt.account_update, &item.elt);
2487
2488 WithStackHash::<AnotherAccUpdate> {
2489 elt: Tree::<AnotherAccUpdate> {
2490 account_update,
2491 account_update_digest: item.elt.account_update_digest.clone(),
2492 calls: item.elt.calls.map_with_trees_to_impl(fun),
2493 },
2494 stack_hash: item.stack_hash.clone(),
2495 }
2496 })
2497 .collect(),
2498 )
2499 }
2500
2501 #[must_use]
2502 pub fn map_with_trees_to<F, AnotherAccUpdate: Clone + AccountUpdateRef>(
2503 &self,
2504 fun: F,
2505 ) -> CallForest<AnotherAccUpdate>
2506 where
2507 F: Fn(&AccUpdate, &Tree<AccUpdate>) -> AnotherAccUpdate,
2508 {
2509 self.map_with_trees_to_impl(&fun)
2510 }
2511
2512 fn try_map_to_impl<F, E, AnotherAccUpdate: Clone + AccountUpdateRef>(
2513 &self,
2514 fun: &mut F,
2515 ) -> Result<CallForest<AnotherAccUpdate>, E>
2516 where
2517 F: FnMut(&AccUpdate) -> Result<AnotherAccUpdate, E>,
2518 {
2519 Ok(CallForest::<AnotherAccUpdate>(
2520 self.iter()
2521 .map(|item| {
2522 Ok(WithStackHash::<AnotherAccUpdate> {
2523 elt: Tree::<AnotherAccUpdate> {
2524 account_update: fun(&item.elt.account_update)?,
2525 account_update_digest: item.elt.account_update_digest.clone(),
2526 calls: item.elt.calls.try_map_to_impl(fun)?,
2527 },
2528 stack_hash: item.stack_hash.clone(),
2529 })
2530 })
2531 .collect::<Result<_, E>>()?,
2532 ))
2533 }
2534
2535 pub fn try_map_to<F, E, AnotherAccUpdate: Clone + AccountUpdateRef>(
2536 &self,
2537 mut fun: F,
2538 ) -> Result<CallForest<AnotherAccUpdate>, E>
2539 where
2540 F: FnMut(&AccUpdate) -> Result<AnotherAccUpdate, E>,
2541 {
2542 self.try_map_to_impl(&mut fun)
2543 }
2544
2545 fn to_account_updates_impl(&self, accounts: &mut Vec<AccUpdate>) {
2546 for elem in self.iter() {
2548 accounts.push(elem.elt.account_update.clone());
2549 elem.elt.calls.to_account_updates_impl(accounts);
2550 }
2551 }
2552
2553 pub fn to_account_updates(&self) -> Vec<AccUpdate> {
2555 let mut accounts = Vec::with_capacity(128);
2556 self.to_account_updates_impl(&mut accounts);
2557 accounts
2558 }
2559
2560 fn to_zkapp_command_with_hashes_list_impl(&self, output: &mut Vec<(AccUpdate, Fp)>) {
2561 self.iter().for_each(|item| {
2562 let WithStackHash { elt, stack_hash } = item;
2563 let Tree {
2564 account_update,
2565 account_update_digest: _,
2566 calls,
2567 } = elt;
2568 output.push((account_update.clone(), stack_hash.get().unwrap())); calls.to_zkapp_command_with_hashes_list_impl(output);
2570 });
2571 }
2572
2573 pub fn to_zkapp_command_with_hashes_list(&self) -> Vec<(AccUpdate, Fp)> {
2574 self.ensure_hashed();
2575
2576 let mut output = Vec::with_capacity(128);
2577 self.to_zkapp_command_with_hashes_list_impl(&mut output);
2578 output
2579 }
2580
2581 pub fn ensure_hashed(&self) {
2582 let Some(first) = self.first() else {
2583 return;
2584 };
2585 if first.stack_hash.get().is_none() {
2586 self.accumulate_hashes();
2587 }
2588 }
2589}
2590
2591impl<AccUpdate: Clone + AccountUpdateRef> CallForest<AccUpdate> {
2592 pub fn accumulate_hashes(&self) {
2594 fn cons(hash: Fp, h_tl: Fp) -> Fp {
2596 hash_with_kimchi(&MINA_ACCOUNT_UPDATE_CONS, &[hash, h_tl])
2597 }
2598
2599 fn hash<AccUpdate: Clone + AccountUpdateRef>(
2601 elem: Option<&WithStackHash<AccUpdate>>,
2602 ) -> Fp {
2603 match elem {
2604 Some(next) => next.stack_hash.get().unwrap(), None => Fp::zero(),
2606 }
2607 }
2608
2609 for index in (0..self.0.len()).rev() {
2615 let elem = &self.0[index];
2616 let WithStackHash {
2617 elt:
2618 Tree::<AccUpdate> {
2619 account_update,
2620 account_update_digest,
2621 calls,
2622 ..
2623 },
2624 ..
2625 } = elem;
2626
2627 calls.accumulate_hashes();
2628 account_update_digest.set(account_update.account_update_ref().digest());
2629
2630 let node_hash = elem.elt.digest();
2631 let hash = hash(self.0.get(index + 1));
2632
2633 self.0[index].stack_hash.set(cons(node_hash, hash));
2634 }
2635 }
2636}
2637
2638impl CallForest<AccountUpdate> {
2639 pub fn cons(
2640 &self,
2641 calls: Option<CallForest<AccountUpdate>>,
2642 account_update: AccountUpdate,
2643 ) -> Self {
2644 let account_update_digest = account_update.digest();
2645
2646 let tree = Tree::<AccountUpdate> {
2647 account_update,
2648 account_update_digest: MutableFp::new(account_update_digest),
2649 calls: calls.unwrap_or_else(|| CallForest(Vec::new())),
2650 };
2651 self.cons_tree(tree)
2652 }
2653
2654 pub fn accumulate_hashes_predicated(&mut self) {
2655 self.accumulate_hashes();
2657 }
2658
2659 pub fn of_wire(&mut self, _wired: &[MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesA]) {
2661 self.accumulate_hashes();
2662 }
2663
2664 pub fn to_wire(&self, _wired: &mut [MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesA]) {
2666 }
2668}
2669
2670impl CallForest<(AccountUpdate, Option<WithHash<VerificationKey>>)> {
2671 }
2689
2690#[derive(Debug, Clone, PartialEq, Eq)]
2692pub struct FeePayerBody {
2693 pub public_key: CompressedPubKey,
2694 pub fee: Fee,
2695 pub valid_until: Option<Slot>,
2696 pub nonce: Nonce,
2697}
2698
2699#[derive(Debug, Clone, PartialEq, Eq)]
2701pub struct FeePayer {
2702 pub body: FeePayerBody,
2703 pub authorization: Signature,
2704}
2705
2706#[derive(Debug, Clone, PartialEq)]
2708pub struct ZkAppCommand {
2709 pub fee_payer: FeePayer,
2710 pub account_updates: CallForest<AccountUpdate>,
2711 pub memo: Memo,
2712}
2713
2714#[derive(Debug, Clone, PartialEq, Hash, Eq, Ord, PartialOrd)]
2715pub enum AccessedOrNot {
2716 Accessed,
2717 NotAccessed,
2718}
2719
2720impl ZkAppCommand {
2721 pub fn fee_payer(&self) -> AccountId {
2722 let public_key = self.fee_payer.body.public_key.clone();
2723 AccountId::new(public_key, self.fee_token())
2724 }
2725
2726 pub fn fee_token(&self) -> TokenId {
2727 TokenId::default()
2728 }
2729
2730 pub fn fee(&self) -> Fee {
2731 self.fee_payer.body.fee
2732 }
2733
2734 pub fn fee_excess(&self) -> FeeExcess {
2735 FeeExcess::of_single((self.fee_token(), Signed::<Fee>::of_unsigned(self.fee())))
2736 }
2737
2738 fn fee_payer_account_update(&self) -> &FeePayer {
2739 let Self { fee_payer, .. } = self;
2740 fee_payer
2741 }
2742
2743 pub fn applicable_at_nonce(&self) -> Nonce {
2744 self.fee_payer_account_update().body.nonce
2745 }
2746
2747 pub fn weight(&self) -> u64 {
2748 let Self {
2749 fee_payer,
2750 account_updates,
2751 memo,
2752 } = self;
2753 [
2754 zkapp_weight::fee_payer(fee_payer),
2755 zkapp_weight::account_updates(account_updates),
2756 zkapp_weight::memo(memo),
2757 ]
2758 .iter()
2759 .sum()
2760 }
2761
2762 pub fn has_zero_vesting_period(&self) -> bool {
2763 self.account_updates
2764 .exists(|account_update| match &account_update.body.update.timing {
2765 SetOrKeep::Keep => false,
2766 SetOrKeep::Set(Timing { vesting_period, .. }) => vesting_period.is_zero(),
2767 })
2768 }
2769
2770 pub fn is_incompatible_version(&self) -> bool {
2771 self.account_updates.exists(|account_update| {
2772 match &account_update.body.update.permissions {
2773 SetOrKeep::Keep => false,
2774 SetOrKeep::Set(Permissions {
2775 set_verification_key,
2776 ..
2777 }) => {
2778 let SetVerificationKey {
2779 auth: _,
2780 txn_version,
2781 } = set_verification_key;
2782 *txn_version != crate::TXN_VERSION_CURRENT
2783 }
2784 }
2785 })
2786 }
2787
2788 fn zkapp_cost(
2789 proof_segments: usize,
2790 signed_single_segments: usize,
2791 signed_pair_segments: usize,
2792 ) -> f64 {
2793 let GenesisConstant {
2795 zkapp_proof_update_cost: proof_cost,
2796 zkapp_signed_pair_update_cost: signed_pair_cost,
2797 zkapp_signed_single_update_cost: signed_single_cost,
2798 ..
2799 } = GENESIS_CONSTANT;
2800
2801 (proof_cost * (proof_segments as f64))
2802 + (signed_pair_cost * (signed_pair_segments as f64))
2803 + (signed_single_cost * (signed_single_segments as f64))
2804 }
2805
2806 pub fn valid_size(&self) -> Result<(), String> {
2810 use crate::proofs::zkapp::group::{SegmentBasic, ZkappCommandIntermediateState};
2811
2812 let Self {
2813 account_updates,
2814 fee_payer: _,
2815 memo: _,
2816 } = self;
2817
2818 let events_elements = |events: &[Event]| -> usize { events.iter().map(Event::len).sum() };
2819
2820 let mut n_account_updates = 0;
2821 let (mut num_event_elements, mut num_action_elements) = (0, 0);
2822
2823 account_updates.fold((), |_, account_update| {
2824 num_event_elements += events_elements(account_update.body.events.events());
2825 num_action_elements += events_elements(account_update.body.actions.events());
2826 n_account_updates += 1;
2827 });
2828
2829 let group = std::iter::repeat(((), (), ()))
2830 .take(n_account_updates + 2) .collect::<Vec<_>>();
2832
2833 let groups = crate::proofs::zkapp::group::group_by_zkapp_command_rev::<_, (), (), ()>(
2834 [self],
2835 vec![vec![((), (), ())], group],
2836 );
2837
2838 let (mut proof_segments, mut signed_single_segments, mut signed_pair_segments) = (0, 0, 0);
2839
2840 for ZkappCommandIntermediateState { spec, .. } in &groups {
2841 match spec {
2842 SegmentBasic::Proved => proof_segments += 1,
2843 SegmentBasic::OptSigned => signed_single_segments += 1,
2844 SegmentBasic::OptSignedOptSigned => signed_pair_segments += 1,
2845 }
2846 }
2847
2848 let GenesisConstant {
2849 zkapp_transaction_cost_limit: cost_limit,
2850 max_event_elements,
2851 max_action_elements,
2852 ..
2853 } = GENESIS_CONSTANT;
2854
2855 let zkapp_cost_within_limit =
2856 Self::zkapp_cost(proof_segments, signed_single_segments, signed_pair_segments)
2857 < cost_limit;
2858 let valid_event_elements = num_event_elements <= max_event_elements;
2859 let valid_action_elements = num_action_elements <= max_action_elements;
2860
2861 if zkapp_cost_within_limit && valid_event_elements && valid_action_elements {
2862 return Ok(());
2863 }
2864
2865 let err = [
2866 (zkapp_cost_within_limit, "zkapp transaction too expensive"),
2867 (valid_event_elements, "too many event elements"),
2868 (valid_action_elements, "too many action elements"),
2869 ]
2870 .iter()
2871 .filter(|(b, _s)| !b)
2872 .map(|(_b, s)| s)
2873 .join(";");
2874
2875 Err(err)
2876 }
2877
2878 pub fn account_access_statuses(
2880 &self,
2881 status: &TransactionStatus,
2882 ) -> Vec<(AccountId, AccessedOrNot)> {
2883 use AccessedOrNot::*;
2884 use TransactionStatus::*;
2885
2886 let init = vec![(self.fee_payer(), Accessed)];
2888
2889 let status_sym = match status {
2890 Applied => Accessed,
2891 Failed(_) => NotAccessed,
2892 };
2893
2894 let ids = self
2895 .account_updates
2896 .fold(init, |mut accum, account_update| {
2897 accum.push((account_update.account_id(), status_sym.clone()));
2898 accum
2899 });
2900 ids.iter()
2902 .unique() .cloned()
2904 .collect()
2905 }
2906
2907 pub fn accounts_referenced(&self) -> Vec<AccountId> {
2909 self.account_access_statuses(&TransactionStatus::Applied)
2910 .into_iter()
2911 .map(|(id, _status)| id)
2912 .collect()
2913 }
2914
2915 pub fn of_verifiable(verifiable: verifiable::ZkAppCommand) -> Self {
2917 Self {
2918 fee_payer: verifiable.fee_payer,
2919 account_updates: verifiable.account_updates.map_to(|(acc, _)| acc.clone()),
2920 memo: verifiable.memo,
2921 }
2922 }
2923
2924 pub fn account_updates_hash(&self) -> Fp {
2926 self.account_updates.hash()
2927 }
2928
2929 pub fn extract_vks(&self) -> Vec<(AccountId, VerificationKeyWire)> {
2931 self.account_updates
2932 .fold(Vec::with_capacity(256), |mut acc, p| {
2933 if let SetOrKeep::Set(vk) = &p.body.update.verification_key {
2934 acc.push((p.account_id(), vk.clone()));
2935 };
2936 acc
2937 })
2938 }
2939
2940 pub fn all_account_updates(&self) -> CallForest<AccountUpdate> {
2941 let p = &self.fee_payer;
2942
2943 let mut fee_payer = AccountUpdate::of_fee_payer(p.clone());
2944 fee_payer.authorization = Control::Signature(p.authorization.clone());
2945
2946 self.account_updates.cons(None, fee_payer)
2947 }
2948
2949 pub fn all_account_updates_list(&self) -> Vec<AccountUpdate> {
2950 let mut account_updates = Vec::with_capacity(16);
2951 account_updates.push(AccountUpdate::of_fee_payer(self.fee_payer.clone()));
2952
2953 self.account_updates.fold(account_updates, |mut acc, u| {
2954 acc.push(u.clone());
2955 acc
2956 })
2957 }
2958
2959 pub fn commitment(&self) -> TransactionCommitment {
2960 let account_updates_hash = self.account_updates_hash();
2961 TransactionCommitment::create(account_updates_hash)
2962 }
2963}
2964
2965pub struct MaybeWithStatus<T> {
2966 pub cmd: T,
2967 pub status: Option<TransactionStatus>,
2968}
2969
2970impl<T> From<WithStatus<T>> for MaybeWithStatus<T> {
2971 fn from(value: WithStatus<T>) -> Self {
2972 let WithStatus { data, status } = value;
2973 Self {
2974 cmd: data,
2975 status: Some(status),
2976 }
2977 }
2978}
2979
2980impl<T> From<MaybeWithStatus<T>> for WithStatus<T> {
2981 fn from(value: MaybeWithStatus<T>) -> Self {
2982 let MaybeWithStatus { cmd, status } = value;
2983 Self {
2984 data: cmd,
2985 status: status.unwrap(),
2986 }
2987 }
2988}
2989
2990impl<T> MaybeWithStatus<T> {
2991 pub fn cmd(&self) -> &T {
2992 &self.cmd
2993 }
2994 pub fn is_failed(&self) -> bool {
2995 self.status
2996 .as_ref()
2997 .map(TransactionStatus::is_failed)
2998 .unwrap_or(false)
2999 }
3000 pub fn map<V, F>(self, fun: F) -> MaybeWithStatus<V>
3001 where
3002 F: FnOnce(T) -> V,
3003 {
3004 MaybeWithStatus {
3005 cmd: fun(self.cmd),
3006 status: self.status,
3007 }
3008 }
3009}
3010
3011pub trait ToVerifiableCache {
3012 fn find(&self, account_id: &AccountId, vk_hash: &Fp) -> Option<&VerificationKeyWire>;
3013 fn add(&mut self, account_id: AccountId, vk: VerificationKeyWire);
3014}
3015
3016pub trait ToVerifiableStrategy {
3017 type Cache: ToVerifiableCache;
3018
3019 fn create_all(
3020 cmd: &ZkAppCommand,
3021 is_failed: bool,
3022 cache: &mut Self::Cache,
3023 ) -> Result<verifiable::ZkAppCommand, String> {
3024 let verified_cmd = verifiable::create(cmd, is_failed, |vk_hash, account_id| {
3025 cache
3026 .find(account_id, &vk_hash)
3027 .cloned()
3028 .or_else(|| {
3029 cmd.extract_vks()
3030 .iter()
3031 .find(|(id, _)| account_id == id)
3032 .map(|(_, key)| key.clone())
3033 })
3034 .ok_or_else(|| format!("verification key not found in cache: {:?}", vk_hash))
3035 })?;
3036 if !is_failed {
3037 for (account_id, vk) in cmd.extract_vks() {
3038 cache.add(account_id, vk);
3039 }
3040 }
3041 Ok(verified_cmd)
3042 }
3043}