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