mina_tree/
tree_version.rs

1use std::{fmt::Debug, hash::Hash};
2
3use mina_curves::pasta::Fp;
4use poseidon::hash::params::get_merkle_param_for_height;
5
6use crate::account::{get_legacy_hash_of, Account, AccountLegacy, TokenId, TokenIdLegacy};
7
8pub trait TreeVersion {
9    type Account: Debug + Clone;
10    type TokenId: Debug + Clone + Hash + PartialEq;
11
12    fn hash_node(depth: usize, left: Fp, right: Fp) -> Fp;
13    fn hash_leaf(leaf: &Self::Account) -> Fp;
14    fn empty_hash_at_height(height: usize) -> Fp;
15}
16
17#[derive(Clone, Debug)]
18pub struct V1;
19
20#[derive(Clone, Debug)]
21pub struct V2;
22
23impl TreeVersion for V2 {
24    type Account = Account;
25    type TokenId = TokenId;
26
27    fn hash_node(height: usize, left: Fp, right: Fp) -> Fp {
28        let param = get_merkle_param_for_height(height);
29        poseidon::hash::hash_with_kimchi(param, &[left, right])
30    }
31
32    fn hash_leaf(leaf: &Self::Account) -> Fp {
33        leaf.hash()
34    }
35
36    fn empty_hash_at_height(height: usize) -> Fp {
37        // let now = redux::Instant::now();
38
39        (0..height).fold(Account::empty().hash(), |prev_hash, height| {
40            Self::hash_node(height, prev_hash, prev_hash)
41        })
42        // elog!("empty_hash_at_height={:?} {:?}", height, now.elapsed());
43
44        // res
45    }
46}
47
48impl TreeVersion for V1 {
49    type Account = AccountLegacy;
50    type TokenId = TokenIdLegacy;
51
52    fn hash_node(depth: usize, left: Fp, right: Fp) -> Fp {
53        use mina_hasher::{create_legacy, Hashable, Hasher, ROInput};
54
55        #[derive(Clone)]
56        struct TwoHashes(Fp, Fp);
57
58        impl Hashable for TwoHashes {
59            type D = u32; // depth
60
61            fn to_roinput(&self) -> ROInput {
62                let mut roi = ROInput::new();
63                roi = roi.append_field(self.0);
64                roi = roi.append_field(self.1);
65                roi
66            }
67
68            fn domain_string(depth: Self::D) -> Option<String> {
69                Some(format!("CodaMklTree{:03}", depth))
70            }
71        }
72
73        let mut hasher = create_legacy::<TwoHashes>(depth as u32);
74        hasher.update(&TwoHashes(left, right));
75        hasher.digest()
76    }
77
78    fn hash_leaf(leaf: &Self::Account) -> Fp {
79        use mina_hasher::{create_legacy, Hasher};
80
81        let mut hasher = create_legacy::<AccountLegacy>(());
82        hasher.update(leaf);
83        hasher.digest()
84    }
85
86    fn empty_hash_at_height(height: usize) -> Fp {
87        (0..height).fold(account_empty_legacy_hash(), |prev_hash, height| {
88            Self::hash_node(height, prev_hash, prev_hash)
89        })
90    }
91}
92
93pub fn account_empty_legacy_hash() -> Fp {
94    get_legacy_hash_of((), &AccountLegacy::empty())
95}