1use std::{collections::HashMap, fmt::Write, marker::PhantomData};
22
23use ark_ff::{fields::arithmetic::InvalidBigInt, Zero};
24use mina_curves::pasta::Fp;
25use mina_signer::CompressedPubKey;
26use openmina_core::constants::constraint_constants;
27use poseidon::hash::{
28 hash_noinputs, hash_with_kimchi,
29 params::{
30 get_coinbase_param_for_height, COINBASE_STACK, MINA_PROTO_STATE, NO_INPUT_COINBASE_STACK,
31 },
32 Inputs,
33};
34use sha2::{Digest, Sha256};
35
36use crate::{
37 proofs::{
38 field::{field, Boolean},
39 numbers::{
40 currency::{CheckedAmount, CheckedCurrency},
41 nat::{CheckedNat, CheckedSlot},
42 },
43 transaction::transaction_snark::checked_hash,
44 witness::Witness,
45 },
46 staged_ledger::hash::PendingCoinbaseAux,
47 Address, AppendToInputs as _, MerklePath, ToInputs,
48};
49
50use self::merkle_tree::MiniMerkleTree;
51
52use super::{
53 currency::{Amount, Magnitude, Slot},
54 transaction_logic::Coinbase,
55};
56
57#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
58pub struct StackId(u64);
59
60impl std::fmt::Debug for StackId {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 f.write_fmt(format_args!("StackId({})", self.0))
63 }
64}
65
66impl StackId {
67 pub fn incr_by_one(&self) -> Self {
68 self.0
69 .checked_add(1)
70 .map(Self)
71 .ok_or_else(|| "Stack_id overflow".to_string())
72 .unwrap()
73 }
74
75 pub fn zero() -> Self {
76 Self(0)
77 }
78
79 pub(super) fn new(number: u64) -> Self {
80 Self(number)
81 }
82
83 pub(super) fn as_u64(&self) -> u64 {
84 self.0
85 }
86}
87
88struct CoinbaseData {
89 receiver: CompressedPubKey,
90 amount: Amount,
91}
92
93impl ToInputs for CoinbaseData {
94 fn to_inputs(&self, inputs: &mut Inputs) {
95 let Self { receiver, amount } = self;
96 inputs.append(receiver);
97 inputs.append(amount);
98 }
99}
100
101impl CoinbaseData {
102 pub fn empty() -> Self {
103 Self {
104 receiver: CompressedPubKey::empty(),
105 amount: Amount::zero(),
106 }
107 }
108
109 pub fn of_coinbase(cb: Coinbase) -> Self {
110 let Coinbase {
111 receiver,
112 amount,
113 fee_transfer: _,
114 } = cb;
115 Self { receiver, amount }
116 }
117
118 pub fn genesis() -> Self {
119 Self::empty()
120 }
121}
122
123#[derive(Clone, Debug)]
124pub struct StackState {
125 pub source: Stack,
126 pub target: Stack,
127}
128
129#[derive(Clone, PartialEq, Eq)]
130pub struct CoinbaseStack(pub Fp);
131
132impl ToInputs for CoinbaseStack {
133 fn to_inputs(&self, inputs: &mut Inputs) {
134 let Self(fp) = self;
135
136 inputs.append(fp)
137 }
138}
139
140impl std::fmt::Debug for CoinbaseStack {
141 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142 if self.is_empty() {
143 f.write_fmt(format_args!("CoinbaseStack(Empty)"))
144 } else {
145 f.debug_tuple("CoinbaseStack").field(&self.0).finish()
146 }
147 }
148}
149
150impl CoinbaseStack {
151 pub fn push(&self, cb: Coinbase) -> Self {
153 let mut inputs = Inputs::new();
154
155 inputs.append(&CoinbaseData::of_coinbase(cb));
156 inputs.append_field(self.0);
157
158 let hash = hash_with_kimchi(&COINBASE_STACK, &inputs.to_fields());
159 Self(hash)
160 }
161
162 pub fn checked_push(&self, cb: Coinbase, w: &mut Witness<Fp>) -> Self {
163 let mut inputs = Inputs::new();
164
165 inputs.append(&CoinbaseData::of_coinbase(cb));
166 inputs.append_field(self.0);
167
168 let hash = checked_hash(&COINBASE_STACK, &inputs.to_fields(), w);
169 Self(hash)
170 }
171
172 fn check_merge(
173 (_, t1): (&Self, &Self),
174 (s2, _): (&Self, &Self),
175 w: &mut Witness<Fp>,
176 ) -> Boolean {
177 field::equal(t1.0, s2.0, w)
178 }
179
180 pub fn empty() -> Self {
182 Self(hash_noinputs(&NO_INPUT_COINBASE_STACK))
183 }
184
185 fn is_empty(&self) -> bool {
187 self == &Self::empty()
188 }
189}
190
191type StackHash = Fp;
192
193#[derive(Clone, PartialEq, Eq)]
194pub struct StateStack {
195 pub init: StackHash,
196 pub curr: StackHash,
197}
198
199impl ToInputs for StateStack {
200 fn to_inputs(&self, inputs: &mut Inputs) {
202 let Self { init, curr } = self;
203 inputs.append(init);
204 inputs.append(curr);
205 }
206}
207
208impl std::fmt::Debug for StateStack {
209 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210 if self.is_empty() {
211 f.write_fmt(format_args!("StateStack(Empty)"))
212 } else {
213 f.debug_struct("StateStack")
214 .field("init", &self.init)
215 .field("curr", &self.curr)
216 .finish()
217 }
218 }
219}
220
221impl StateStack {
222 fn push(&self, state_body_hash: Fp, global_slot: Slot) -> Self {
223 let mut inputs = Inputs::new();
224
225 inputs.append_field(self.curr);
226 inputs.append_field(state_body_hash);
227 inputs.append_field(global_slot.to_field());
228
229 let hash = hash_with_kimchi(&MINA_PROTO_STATE, &inputs.to_fields());
230
231 Self {
232 init: self.init,
233 curr: hash,
234 }
235 }
236
237 fn checked_push(
238 &self,
239 state_body_hash: Fp,
240 global_slot: CheckedSlot<Fp>,
241 w: &mut Witness<Fp>,
242 ) -> Self {
243 let mut inputs = Inputs::new();
244
245 inputs.append_field(self.curr);
246 inputs.append_field(state_body_hash);
247 inputs.append_field(global_slot.to_field());
248
249 let hash = checked_hash(&MINA_PROTO_STATE, &inputs.to_fields(), w);
250
251 Self {
252 init: self.init,
253 curr: hash,
254 }
255 }
256
257 fn equal_var(&self, other: &Self, w: &mut Witness<Fp>) -> Boolean {
258 let b1 = field::equal(self.init, other.init, w);
259 let b2 = field::equal(self.curr, other.curr, w);
260 b1.and(&b2, w)
261 }
262
263 fn check_merge(
264 (s1, t1): (&Self, &Self),
265 (s2, t2): (&Self, &Self),
266 w: &mut Witness<Fp>,
267 ) -> Boolean {
268 let eq_src = s1.equal_var(s2, w);
269 let eq_target = t1.equal_var(t2, w);
270 let correct_transition = t1.equal_var(s2, w);
271 let same_update = eq_src.and(&eq_target, w);
272 Boolean::any(&[same_update, correct_transition], w)
273 }
274
275 fn empty() -> Self {
276 Self {
277 init: Fp::zero(),
278 curr: Fp::zero(),
279 }
280 }
281
282 fn is_empty(&self) -> bool {
284 self.curr.is_zero() && self.init.is_zero()
285 }
286
287 fn create(init: StackHash) -> Self {
288 Self { init, curr: init }
289 }
290}
291
292pub mod update {
293 use crate::scan_state::currency::{Amount, Magnitude};
294
295 #[derive(Clone, Debug)]
296 pub enum Action {
297 None,
298 One,
299 TwoCoinbaseInFirst,
300 TwoCoinbaseInSecond,
301 }
302
303 #[derive(Debug)]
304 pub enum StackUpdate {
305 None,
306 One(super::Stack),
307 Two((super::Stack, super::Stack)),
308 }
309
310 #[derive(Clone, Debug)]
311 pub struct Update {
312 pub action: Action,
313 pub coinbase_amount: Amount,
314 }
315
316 impl Update {
317 fn genesis() -> Self {
318 Self {
319 action: Action::None,
320 coinbase_amount: Amount::zero(),
321 }
322 }
323 }
324}
325
326#[derive(Clone, PartialEq, Eq)]
327pub struct Stack {
328 pub data: CoinbaseStack,
329 pub state: StateStack,
330}
331
332impl ToInputs for Stack {
333 fn to_inputs(&self, inputs: &mut Inputs) {
335 let Self { data, state } = self;
336 inputs.append(data);
337 inputs.append(state);
338 }
339}
340
341impl std::fmt::Debug for Stack {
342 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
343 if self.data.is_empty() && self.state.is_empty() {
344 f.write_fmt(format_args!("Stack(Empty)"))
345 } else {
346 f.debug_struct("Stack")
347 .field("data", &self.data)
348 .field("state", &self.state)
349 .finish()
350 }
351 }
352}
353
354impl Stack {
355 pub fn empty() -> Self {
356 Self {
357 data: CoinbaseStack::empty(),
358 state: StateStack::empty(),
359 }
360 }
361
362 pub fn push_coinbase(&self, cb: Coinbase) -> Self {
363 Self {
364 data: self.data.push(cb),
365 state: self.state.clone(),
366 }
367 }
368
369 pub fn push_state(&self, state_body_hash: Fp, global_slot: Slot) -> Self {
370 Self {
371 data: self.data.clone(),
372 state: self.state.push(state_body_hash, global_slot),
373 }
374 }
375
376 pub fn checked_push_coinbase(&self, cb: Coinbase, w: &mut Witness<Fp>) -> Self {
377 Self {
378 data: self.data.checked_push(cb, w),
379 state: self.state.clone(),
380 }
381 }
382
383 pub fn checked_push_state(
384 &self,
385 state_body_hash: Fp,
386 global_slot: CheckedSlot<Fp>,
387 w: &mut Witness<Fp>,
388 ) -> Self {
389 Self {
390 data: self.data.clone(),
391 state: self.state.checked_push(state_body_hash, global_slot, w),
392 }
393 }
394
395 pub fn equal_var(&self, other: &Self, w: &mut Witness<Fp>) -> Boolean {
396 let b1 = field::equal(self.data.0, other.data.0, w);
397 let b2 = {
398 let b1 = field::equal(self.state.init, other.state.init, w);
399 let b2 = field::equal(self.state.curr, other.state.curr, w);
400 b1.and(&b2, w)
401 };
402 b1.and(&b2, w)
403 }
404
405 pub fn check_merge(
406 transition1: (&Self, &Self),
407 transition2: (&Self, &Self),
408 w: &mut Witness<Fp>,
409 ) -> Boolean {
410 let (s, t) = transition1;
411 let (s2, t2) = transition2;
412
413 let valid_coinbase_stacks =
414 CoinbaseStack::check_merge((&s.data, &t.data), (&s2.data, &t2.data), w);
415 let valid_state_stacks =
416 StateStack::check_merge((&s.state, &t.state), (&s2.state, &t2.state), w);
417
418 valid_coinbase_stacks.and(&valid_state_stacks, w)
419 }
420
421 pub fn create_with(other: &Self) -> Self {
423 Self {
424 state: StateStack::create(other.state.curr),
425 ..Self::empty()
426 }
427 }
428
429 pub fn var_create_with(other: &Self) -> Self {
431 Self {
433 state: StateStack::create(other.state.init),
434 ..Self::empty()
435 }
436 }
437
438 pub fn connected(first: &Self, second: &Self, prev: Option<&Self>) -> bool {
440 let coinbase_stack_connected =
442 (first.data == second.data) || { second.data == CoinbaseStack::empty() };
443
444 let state_stack_connected = first.state == second.state
450 || second.state.init == second.state.curr
451 || first.state.curr == second.state.curr
452 || prev
453 .map(|prev| prev.state.curr == second.state.curr)
454 .unwrap_or(true);
455
456 coinbase_stack_connected && state_stack_connected
457 }
458
459 fn hash_var(&self, w: &mut Witness<Fp>) -> Fp {
460 checked_hash(&COINBASE_STACK, &self.to_inputs_owned().to_fields(), w)
461 }
462}
463
464#[derive(Clone, Debug)]
465pub struct PendingCoinbase {
466 pub(super) tree: merkle_tree::MiniMerkleTree<StackId, Stack, StackHasher>,
467 pub(super) pos_list: Vec<StackId>,
468 pub(super) new_pos: StackId,
469}
470
471#[derive(Clone, Debug)]
472pub(super) struct StackHasher;
473
474impl merkle_tree::TreeHasher<Stack> for StackHasher {
475 fn hash_value(value: &Stack) -> Fp {
476 let mut inputs = Inputs::new();
477
478 inputs.append_field(value.data.0);
479
480 inputs.append_field(value.state.init);
481 inputs.append_field(value.state.curr);
482
483 hash_with_kimchi(&COINBASE_STACK, &inputs.to_fields())
484 }
485
486 fn merge_hash(height: usize, left: Fp, right: Fp) -> Fp {
487 let param = get_coinbase_param_for_height(height);
488 poseidon::hash::hash_with_kimchi(param, &[left, right])
489 }
490
491 fn empty_value() -> Stack {
492 Stack::empty()
493 }
494}
495
496impl PendingCoinbase {
497 pub fn create(depth: usize) -> Self {
498 let mut tree = MiniMerkleTree::create(depth);
499
500 let nstacks = 2u64.pow(depth as u32);
501 let mut stack_id = StackId::zero();
502
503 assert_eq!(depth, 5);
504
505 tree.fill_with((0..nstacks).map(|_| {
506 let this_id = stack_id;
507 stack_id = stack_id.incr_by_one();
508 (this_id, Stack::empty())
509 }));
510
511 Self {
512 tree,
513 pos_list: Vec::with_capacity(128),
514 new_pos: StackId::zero(),
515 }
516 }
517
518 pub fn merkle_root(&mut self) -> Fp {
519 self.tree.merkle_root()
520 }
521
522 fn get_stack(&self, addr: Address) -> &Stack {
523 self.tree.get_exn(addr)
524 }
525
526 fn path(&mut self, addr: Address) -> Vec<MerklePath> {
527 self.tree.path_exn(addr)
528 }
529
530 fn find_index(&self, key: StackId) -> Address {
531 self.tree.find_index_exn(key)
532 }
533
534 fn next_index(&self, depth: usize) -> StackId {
535 if self.new_pos.0 == (2u64.pow(depth as u32) - 1) {
536 StackId::zero()
537 } else {
538 self.new_pos.incr_by_one()
539 }
540 }
541
542 fn next_stack_id(&self, depth: usize, is_new_stack: bool) -> StackId {
543 if is_new_stack {
544 self.next_index(depth)
545 } else {
546 self.new_pos
547 }
548 }
549
550 fn incr_index(&mut self, depth: usize, is_new_stack: bool) {
551 if is_new_stack {
552 let new_pos = self.next_index(depth);
553 self.pos_list.push(self.new_pos);
554 self.new_pos = new_pos;
555 }
556 }
557
558 fn set_stack(&mut self, depth: usize, addr: Address, stack: Stack, is_new_stack: bool) {
559 self.tree.set_exn(addr, stack);
560 self.incr_index(depth, is_new_stack);
561 }
562
563 fn latest_stack_id(&self, is_new_stack: bool) -> StackId {
564 if is_new_stack {
565 self.new_pos
566 } else {
567 self.pos_list.last().cloned().unwrap_or_else(StackId::zero)
568 }
569 }
570
571 fn current_stack_id(&self) -> Option<StackId> {
572 self.pos_list.last().cloned()
573 }
574
575 fn current_stack(&self) -> &Stack {
576 let prev_stack_id = self.current_stack_id().unwrap_or_else(StackId::zero);
577 let addr = self.tree.find_index_exn(prev_stack_id);
578 self.tree.get_exn(addr)
579 }
580
581 pub fn latest_stack(&self, is_new_stack: bool) -> Stack {
582 let key = self.latest_stack_id(is_new_stack);
583 let addr = self.tree.find_index_exn(key);
584 let mut res = self.tree.get_exn(addr).clone();
585 if is_new_stack {
586 let prev_stack = self.current_stack();
587 res.state = StateStack::create(prev_stack.state.curr);
588 }
589 res
590 }
591
592 fn oldest_stack_id(&self) -> Option<StackId> {
593 self.pos_list.first().cloned()
594 }
595
596 fn remove_oldest_stack_id(&mut self) {
597 todo!()
598 }
599
600 fn oldest_stack(&self) -> &Stack {
601 let key = self.oldest_stack_id().unwrap_or_else(StackId::zero);
602 let addr = self.find_index(key);
603 self.get_stack(addr)
604 }
605
606 fn update_stack<F>(&mut self, depth: usize, is_new_stack: bool, fun: F)
607 where
608 F: FnOnce(&Stack) -> Stack,
609 {
610 let key = self.latest_stack_id(is_new_stack);
611 let stack_addr = self.find_index(key);
612 let stack_before = self.get_stack(stack_addr.clone());
613 let stack_after = fun(stack_before);
614 self.set_stack(depth, stack_addr, stack_after, is_new_stack);
616 }
617
618 fn add_coinbase(&mut self, depth: usize, coinbase: Coinbase, is_new_stack: bool) {
619 self.update_stack(depth, is_new_stack, |stack| stack.push_coinbase(coinbase))
620 }
621
622 fn add_state(
623 &mut self,
624 depth: usize,
625 state_body_hash: Fp,
626 global_slot: Slot,
627 is_new_stack: bool,
628 ) {
629 self.update_stack(depth, is_new_stack, |stack| {
630 stack.push_state(state_body_hash, global_slot)
631 })
632 }
633
634 pub fn update_coinbase_stack(
635 &mut self,
636 depth: usize,
637 stack: Stack,
638 is_new_stack: bool,
639 ) -> Result<(), String> {
640 self.update_stack(depth, is_new_stack, |_| stack);
641 Ok(())
642 }
643
644 pub fn remove_coinbase_stack(&mut self, depth: usize) -> Result<Stack, String> {
645 let oldest_stack_id = if !self.pos_list.is_empty() {
646 self.pos_list.remove(0) } else {
648 return Err("No coinbase stack-with-state-hash to pop".to_string());
649 };
650 let stack_addr = self.find_index(oldest_stack_id);
651 let stack = self.get_stack(stack_addr.clone()).clone();
652 self.set_stack(depth, stack_addr, Stack::empty(), false);
653 Ok(stack)
654 }
655
656 pub fn hash_extra(&self) -> PendingCoinbaseAux {
657 let mut s = String::with_capacity(64 * 1024);
658 for pos in self.pos_list.iter().rev() {
659 write!(&mut s, "{}", pos.0).unwrap();
660 }
661
662 let mut sha = Sha256::new();
663 sha.update(s.as_bytes());
664
665 s.clear();
666 write!(&mut s, "{}", self.new_pos.0).unwrap();
667 sha.update(s);
668
669 let digest = sha.finalize();
670 PendingCoinbaseAux(digest.into())
671 }
672
673 pub fn pop_coinbases(
674 proof_emitted: Boolean,
675 pending_coinbase_witness: &mut PendingCoinbaseWitness,
676 w: &mut Witness<Fp>,
677 ) -> Result<(Fp, Stack), InvalidBigInt> {
678 let addr = w.exists(pending_coinbase_witness.find_index_of_oldest_stack());
679 let (prev, prev_path) = w.exists(pending_coinbase_witness.get_coinbase_stack(addr.clone()));
680
681 checked_verify_merkle_path(&prev, &prev_path, w);
682
683 let next = w.exists_no_check(match proof_emitted {
684 Boolean::True => Stack::empty(),
685 Boolean::False => prev.clone(),
686 });
687
688 pending_coinbase_witness.set_oldest_coinbase_stack(addr, next.clone());
689
690 let new_root = checked_verify_merkle_path(&next, &prev_path, w);
692
693 Ok((new_root, prev))
694 }
695
696 pub fn add_coinbase_checked(
697 update: &update::Update,
698 coinbase_receiver: &CompressedPubKey,
699 supercharge_coinbase: Boolean,
700 state_body_hash: Fp,
701 global_slot: &CheckedSlot<Fp>,
702 pending_coinbase_witness: &mut PendingCoinbaseWitness,
703 w: &mut Witness<Fp>,
704 ) -> Result<Fp, InvalidBigInt> {
705 let no_update = |[b0, b1]: &[Boolean; 2], w: &mut Witness<Fp>| b0.neg().and(&b1.neg(), w);
706 let update_two_stacks_coinbase_in_first =
707 |[b0, b1]: &[Boolean; 2], w: &mut Witness<Fp>| b0.neg().and(b1, w);
708 let update_two_stacks_coinbase_in_second =
709 |[b0, b1]: &[Boolean; 2], w: &mut Witness<Fp>| b0.and(b1, w);
710
711 let update::Update {
712 action,
713 coinbase_amount: amount,
714 } = update;
715
716 let amount = Amount::from_u64(amount.as_u64()).to_checked();
717 let (addr1, addr2) = w.exists(pending_coinbase_witness.find_index_of_newest_stacks());
718
719 let action = {
720 use update::Action::*;
721 match action {
722 None => [Boolean::False, Boolean::False],
723 One => [Boolean::True, Boolean::False],
724 TwoCoinbaseInFirst => [Boolean::False, Boolean::True],
725 TwoCoinbaseInSecond => [Boolean::True, Boolean::True],
726 }
727 };
728
729 let no_update = no_update(&action, w);
730
731 let update_state_stack = |stack: Stack,
732 pending_coinbase_witness: &mut PendingCoinbaseWitness,
733 w: &mut Witness<Fp>| {
734 let previous_state_stack = w.exists(pending_coinbase_witness.get_previous_stack());
735 let stack_initialized = Stack {
736 state: previous_state_stack,
737 ..stack.clone()
738 };
739 let stack_with_state_hash =
740 stack_initialized.checked_push_state(state_body_hash, *global_slot, w);
741 w.exists_no_check(match no_update {
742 Boolean::True => stack,
743 Boolean::False => stack_with_state_hash,
744 })
745 };
746
747 let update_stack1 = |stack: Stack,
748 pending_coinbase_witness: &mut PendingCoinbaseWitness,
749 w: &mut Witness<Fp>| {
750 let stack = update_state_stack(stack, pending_coinbase_witness, w);
751 let total_coinbase_amount = {
752 let coinbase_amount = Amount::from_u64(constraint_constants().coinbase_amount);
753 let superchaged_coinbase = coinbase_amount
754 .scale(constraint_constants().supercharged_coinbase_factor)
755 .unwrap()
756 .to_checked::<Fp>();
757 let coinbase_amount = coinbase_amount.to_checked::<Fp>();
758
759 match supercharge_coinbase {
760 Boolean::True => superchaged_coinbase,
761 Boolean::False => coinbase_amount,
762 }
763 };
764
765 let rem_amount = total_coinbase_amount.sub(&amount, w);
766 let no_coinbase_in_this_stack = update_two_stacks_coinbase_in_second(&action, w);
767
768 let amount1_equal_to_zero = amount.equal(&CheckedAmount::zero(), w);
769 let amount2_equal_to_zero = rem_amount.equal(&CheckedAmount::zero(), w);
770
771 no_update.equal(&amount1_equal_to_zero, w);
772
773 let no_coinbase = no_update.or(&no_coinbase_in_this_stack, w);
774
775 let stack_with_amount1 = stack.checked_push_coinbase(
776 Coinbase {
777 receiver: coinbase_receiver.clone(),
778 amount: amount.to_inner(), fee_transfer: None,
780 },
781 w,
782 );
783
784 let stack_with_amount2 = stack_with_amount1.checked_push_coinbase(
785 Coinbase {
786 receiver: coinbase_receiver.clone(),
787 amount: rem_amount.to_inner(), fee_transfer: None,
789 },
790 w,
791 );
792
793 let on_false = {
794 w.exists_no_check(match amount2_equal_to_zero {
795 Boolean::True => stack_with_amount1,
796 Boolean::False => stack_with_amount2,
797 })
798 };
799
800 w.exists_no_check(match no_coinbase {
801 Boolean::True => stack,
802 Boolean::False => on_false,
803 })
804 };
805
806 let update_stack2 = |init_stack: Stack, stack0: Stack, w: &mut Witness<Fp>| {
807 let add_coinbase = update_two_stacks_coinbase_in_second(&action, w);
808 let update_state = {
809 let update_second_stack = update_two_stacks_coinbase_in_first(&action, w);
810 update_second_stack.or(&add_coinbase, w)
811 };
812
813 let stack = {
814 let stack_with_state = Stack {
815 state: StateStack::create(init_stack.state.curr),
816 ..stack0.clone()
817 }
818 .checked_push_state(state_body_hash, *global_slot, w);
819 w.exists_no_check(match update_state {
820 Boolean::True => stack_with_state,
821 Boolean::False => stack0,
822 })
823 };
824
825 let stack_with_coinbase = stack.checked_push_coinbase(
826 Coinbase {
827 receiver: coinbase_receiver.clone(),
828 amount: amount.to_inner(), fee_transfer: None,
830 },
831 w,
832 );
833
834 w.exists_no_check(match add_coinbase {
835 Boolean::True => stack_with_coinbase,
836 Boolean::False => stack,
837 })
838 };
839
840 let (_new_root, prev, _updated_stack1) = {
841 let (stack, path) = w.exists_no_check({
842 let pc = &mut pending_coinbase_witness.pending_coinbase;
843 let stack = pc.get_stack(addr1.clone()).clone();
844 let path = pc.path(addr1.clone());
845 (stack, path)
846 });
847 checked_verify_merkle_path(&stack, &path, w);
848
849 let next = update_stack1(stack.clone(), pending_coinbase_witness, w);
850
851 pending_coinbase_witness.set_coinbase_stack(addr1, next.clone());
852 let new_root = checked_verify_merkle_path(&next, &path, w);
853 (new_root, stack, next)
854 };
855
856 let (root, _, _) = {
857 let (stack, path) = w.exists_no_check({
858 let pc = &mut pending_coinbase_witness.pending_coinbase;
859 let stack = pc.get_stack(addr2.clone()).clone();
860 let path = pc.path(addr2.clone());
861 (stack, path)
862 });
863 checked_verify_merkle_path(&stack, &path, w);
864
865 let next = update_stack2(prev, stack.clone(), w);
866
867 pending_coinbase_witness.set_coinbase_stack(addr2, next.clone());
868 let new_root = checked_verify_merkle_path(&next, &path, w);
869 (new_root, stack, next)
870 };
871
872 Ok(root)
873 }
874}
875
876pub fn checked_verify_merkle_path(
878 account: &Stack,
879 merkle_path: &[MerklePath],
880 w: &mut Witness<Fp>,
881) -> Fp {
882 let account_hash = account.hash_var(w);
883
884 let hash = merkle_path
885 .iter()
886 .enumerate()
887 .fold(account_hash, |accum, (height, path)| {
888 let hashes = match path {
889 MerklePath::Left(right) => [accum, *right],
890 MerklePath::Right(left) => [*left, accum],
891 };
892 w.exists(hashes);
893
894 let param = get_coinbase_param_for_height(height);
895 checked_hash(param, &hashes, w)
896 });
897
898 hash
899}
900
901pub struct PendingCoinbaseWitness {
902 pub pending_coinbase: PendingCoinbase,
903 pub is_new_stack: bool,
904}
905
906impl PendingCoinbaseWitness {
907 fn coinbase_stack_path_exn(&mut self, idx: Address) -> Vec<MerklePath> {
908 self.pending_coinbase.path(idx)
909 }
910
911 fn find_index_of_oldest_stack(&self) -> Address {
912 let stack_id = self
913 .pending_coinbase
914 .oldest_stack_id()
915 .unwrap_or_else(StackId::zero);
916 self.pending_coinbase.find_index(stack_id)
917 }
918
919 fn get_coinbase_stack(&mut self, idx: Address) -> (Stack, Vec<MerklePath>) {
920 let elt = self.pending_coinbase.get_stack(idx.clone()).clone();
921 let path = self.coinbase_stack_path_exn(idx);
922 (elt, path)
923 }
924
925 fn set_oldest_coinbase_stack(&mut self, idx: Address, stack: Stack) {
926 let depth = constraint_constants().pending_coinbase_depth;
927 self.pending_coinbase.set_stack(depth, idx, stack, false);
928 }
929
930 fn find_index_of_newest_stacks(&self) -> (Address, Address) {
931 let depth = constraint_constants().pending_coinbase_depth;
932
933 let index1 = {
934 let stack_id = self.pending_coinbase.latest_stack_id(self.is_new_stack);
935 self.pending_coinbase.find_index(stack_id)
936 };
937
938 let index2 = {
939 let stack_id = self
940 .pending_coinbase
941 .next_stack_id(depth, self.is_new_stack);
942 self.pending_coinbase.find_index(stack_id)
943 };
944
945 (index1, index2)
946 }
947
948 fn get_previous_stack(&self) -> StateStack {
949 if self.is_new_stack {
950 let stack = self.pending_coinbase.current_stack();
951 StateStack {
952 init: stack.state.curr,
953 curr: stack.state.curr,
954 }
955 } else {
956 let stack = self.pending_coinbase.latest_stack(self.is_new_stack);
957 stack.state
958 }
959 }
960
961 fn set_coinbase_stack(&mut self, idx: Address, stack: Stack) {
962 let depth = constraint_constants().pending_coinbase_depth;
963 self.pending_coinbase
964 .set_stack(depth, idx, stack, self.is_new_stack);
965 }
966}
967
968pub mod merkle_tree {
970 use crate::{AccountIndex, AddressIterator, Direction, HashesMatrix};
971
972 use super::*;
973
974 pub trait TreeHasher<V> {
975 fn hash_value(value: &V) -> Fp;
976 fn empty_value() -> V;
977 fn merge_hash(depth: usize, left: Fp, right: Fp) -> Fp;
978 }
979
980 #[derive(Clone)]
981 pub struct MiniMerkleTree<K, V, H> {
982 pub values: Vec<V>,
983 pub indexes: HashMap<K, Address>,
984 pub hashes_matrix: HashesMatrix,
985 pub depth: usize,
986 pub _hasher: PhantomData<H>,
987 }
988
989 impl<K, V, H> std::fmt::Debug for MiniMerkleTree<K, V, H>
990 where
991 K: std::fmt::Debug + Ord,
992 V: std::fmt::Debug,
993 {
994 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
995 let mut indexes = self.indexes.iter().collect::<Vec<_>>();
996 indexes.sort_by_key(|(key, _addr)| *key);
997 f.debug_struct("MiniMerkleTree")
1000 .field("values", &self.values)
1001 .field("indexes_len", &indexes.len())
1002 .field("indexes", &indexes)
1003 .field("depth", &self.depth)
1005 .finish()
1006 }
1007 }
1008
1009 impl<K, V, H> MiniMerkleTree<K, V, H>
1010 where
1011 K: Eq + std::hash::Hash,
1012 H: TreeHasher<V>,
1013 V: PartialEq,
1014 {
1015 pub fn create(depth: usize) -> Self {
1016 let max_values = 2u64.pow(depth as u32) as usize;
1017
1018 Self {
1019 values: Vec::with_capacity(max_values),
1020 indexes: HashMap::new(),
1021 depth,
1022 hashes_matrix: HashesMatrix::new(depth),
1023 _hasher: PhantomData,
1024 }
1025 }
1026
1027 pub fn fill_with<I>(&mut self, data: I)
1028 where
1029 I: Iterator<Item = (K, V)>,
1030 {
1031 assert!(self.values.is_empty());
1032
1033 assert_eq!(self.depth, 5);
1034
1035 let indexes: HashMap<usize, usize> = [
1037 (31, 31),
1038 (30, 15),
1039 (29, 23),
1040 (28, 7),
1041 (27, 27),
1042 (26, 11),
1043 (25, 19),
1044 (24, 3),
1045 (23, 29),
1046 (22, 13),
1047 (21, 21),
1048 (20, 5),
1049 (19, 25),
1050 (18, 9),
1051 (17, 17),
1052 (16, 1),
1053 (15, 30),
1054 (14, 14),
1055 (13, 22),
1056 (12, 6),
1057 (11, 26),
1058 (10, 10),
1059 (9, 18),
1060 (8, 2),
1061 (7, 28),
1062 (6, 12),
1063 (5, 20),
1064 (4, 4),
1065 (3, 24),
1066 (2, 8),
1067 (1, 16),
1068 (0, 0),
1069 ]
1070 .iter()
1071 .copied()
1072 .collect();
1073
1074 for (index, (key, value)) in data.enumerate() {
1075 self.values.push(value);
1076
1077 let index = indexes
1078 .get(&index)
1079 .copied()
1080 .map(AccountIndex::from)
1081 .unwrap();
1082 self.indexes
1083 .insert(key, Address::from_index(index, self.depth));
1084 }
1085 }
1086
1087 fn get(&self, addr: Address) -> Option<&V> {
1088 assert_eq!(addr.length(), self.depth);
1089
1090 let index = addr.to_index().0 as usize;
1091 self.values.get(index)
1092 }
1093
1094 pub fn get_exn(&self, addr: Address) -> &V {
1095 self.get(addr).unwrap()
1096 }
1097
1098 pub fn set_exn(&mut self, addr: Address, value: V) {
1099 use std::cmp::Ordering::*;
1100
1101 assert_eq!(addr.length(), self.depth);
1102 let index = addr.to_index().0 as usize;
1103
1104 let mut invalidate = true;
1105
1106 match index.cmp(&self.values.len()) {
1107 Less => {
1108 invalidate = self.values[index] != value;
1109 self.values[index] = value
1110 }
1111 Equal => self.values.push(value),
1112 Greater => panic!("wrong use of `set_exn`"),
1113 }
1114
1115 if invalidate {
1116 self.hashes_matrix.invalidate_hashes(addr.to_index());
1117 }
1118 }
1119
1120 pub fn find_index_exn(&self, key: K) -> Address {
1121 self.indexes.get(&key).cloned().unwrap()
1122 }
1123
1124 pub fn path_exn(&mut self, addr: Address) -> Vec<MerklePath> {
1125 let mut merkle_path = Vec::with_capacity(addr.length());
1126 let mut path_to_addr = addr.into_iter();
1127 let root = Address::root();
1128
1129 self.emulate_tree_to_get_path(root, &mut path_to_addr, &mut merkle_path);
1130
1131 merkle_path
1132 }
1133
1134 fn get_value_hash(&mut self, addr: Address) -> Fp {
1135 if let Some(hash) = self.hashes_matrix.get(&addr) {
1136 return *hash;
1137 }
1138
1139 let hash = match self.get(addr.clone()) {
1140 Some(value) => H::hash_value(value),
1141 None => H::hash_value(&H::empty_value()),
1142 };
1143
1144 self.hashes_matrix.set(&addr, hash);
1145
1146 hash
1147 }
1148
1149 fn get_node_hash(&mut self, addr: &Address, left: Fp, right: Fp) -> Fp {
1150 if let Some(hash) = self.hashes_matrix.get(addr) {
1151 return *hash;
1152 };
1153
1154 let depth_in_tree = self.depth - addr.length();
1155
1156 let hash = H::merge_hash(depth_in_tree - 1, left, right);
1157 self.hashes_matrix.set(addr, hash);
1158 hash
1159 }
1160
1161 fn emulate_tree_to_get_path(
1162 &mut self,
1163 addr: Address,
1164 path: &mut AddressIterator,
1165 merkle_path: &mut Vec<MerklePath>,
1166 ) -> Fp {
1167 if addr.length() == self.depth {
1168 return self.get_value_hash(addr);
1169 }
1170
1171 let next_direction = path.next();
1172
1173 if let Some(direction) = next_direction.as_ref() {
1175 let child = match direction {
1176 Direction::Left => addr.child_left(),
1177 Direction::Right => addr.child_right(),
1178 };
1179 self.emulate_tree_to_get_path(child, path, merkle_path);
1180 };
1181
1182 let mut get_child_hash = |addr: Address| match self.hashes_matrix.get(&addr) {
1183 Some(hash) => *hash,
1184 None => {
1185 if let Some(hash) = self.hashes_matrix.get(&addr) {
1186 *hash
1187 } else {
1188 self.emulate_tree_to_get_path(addr, path, merkle_path)
1189 }
1190 }
1191 };
1192
1193 let left = get_child_hash(addr.child_left());
1194 let right = get_child_hash(addr.child_right());
1195
1196 if let Some(direction) = next_direction {
1197 let hash = match direction {
1198 Direction::Left => MerklePath::Left(right),
1199 Direction::Right => MerklePath::Right(left),
1200 };
1201 merkle_path.push(hash);
1202 };
1203
1204 self.get_node_hash(&addr, left, right)
1205 }
1206
1207 pub fn merkle_root(&mut self) -> Fp {
1208 let root = Address::root();
1209
1210 if let Some(hash) = self.hashes_matrix.get(&root) {
1211 return *hash;
1212 };
1213
1214 self.emulate_tree_merkle_root(root)
1215 }
1216
1217 pub fn emulate_tree_merkle_root(&mut self, addr: Address) -> Fp {
1218 let current_depth = self.depth - addr.length();
1219
1220 if current_depth == 0 {
1221 return self.get_value_hash(addr);
1222 }
1223
1224 let mut get_child_hash = |addr: Address| {
1225 if let Some(hash) = self.hashes_matrix.get(&addr) {
1226 *hash
1227 } else {
1228 self.emulate_tree_merkle_root(addr)
1229 }
1230 };
1231
1232 let left_hash = get_child_hash(addr.child_left());
1233 let right_hash = get_child_hash(addr.child_right());
1234
1235 self.get_node_hash(&addr, left_hash, right_hash)
1236 }
1237 }
1238
1239 }
1250
1251#[cfg(test)]
1252mod tests {
1253 use crate::FpExt;
1254
1255 use super::*;
1256
1257 #[cfg(target_family = "wasm")]
1258 use wasm_bindgen_test::wasm_bindgen_test as test;
1259
1260 #[test]
1261 fn test_merkle_tree() {
1262 {
1263 const DEPTH: usize = 3;
1264 let mut tree = MiniMerkleTree::<StackId, Stack, StackHasher>::create(DEPTH);
1265 let merkle_root = tree.merkle_root();
1266 assert_eq!(
1267 merkle_root.to_decimal(),
1268 "9939061863620980199451530646711695641079091335264396436068661296746064363179"
1269 );
1270 }
1271
1272 {
1273 const DEPTH: usize = 5;
1274 let mut tree = MiniMerkleTree::<StackId, Stack, StackHasher>::create(DEPTH);
1275 let merkle_root = tree.merkle_root();
1276 assert_eq!(
1277 merkle_root.to_decimal(),
1278 "25504365445533103805898245102289650498571312278321176071043666991586378788150"
1279 );
1280 }
1281 }
1282}