mina_tree/
tree.rs

1use std::{collections::BTreeMap, fmt::Debug, sync::Mutex};
2
3use crate::{
4    address::Address,
5    base::AccountIndex,
6    tree_version::{TreeVersion, V2},
7};
8use mina_curves::pasta::Fp;
9use once_cell::sync::Lazy;
10
11#[derive(Clone, Debug)]
12struct Leaf<T: TreeVersion> {
13    account: Option<Box<T::Account>>,
14}
15
16#[derive(PartialEq)]
17pub struct HashesMatrix {
18    /// 2 dimensions matrix
19    // matrix: Vec<Option<Fp>>,
20    matrix: BTreeMap<u64, Fp>,
21    empty_hashes: Vec<Option<Fp>>,
22    ledger_depth: usize,
23    nhashes: usize,
24}
25
26impl Clone for HashesMatrix {
27    fn clone(&self) -> Self {
28        Self {
29            matrix: self.matrix.clone(),
30            empty_hashes: self.empty_hashes.clone(),
31            ledger_depth: self.ledger_depth,
32            nhashes: self.nhashes,
33        }
34    }
35}
36
37impl Debug for HashesMatrix {
38    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39        // const SPACES: &[usize] = &[
40        //     0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192,
41        // ];
42
43        // let mut s = String::with_capacity(self.matrix.len() * 2);
44        // let mut spaces = SPACES;
45        // let mut current = 0;
46        // let naccounts = 2u64.pow(self.ledger_depth as u32) as usize;
47
48        // for h in self.matrix.iter() {
49        //     let c = if h.is_some() { 'I' } else { '0' };
50        //     s.push(c);
51
52        //     if current == spaces[0] && current != naccounts {
53        //         s.push(' ');
54        //         current = 0;
55        //         spaces = &spaces[1..];
56        //     }
57
58        //     current += 1;
59        // }
60
61        f.debug_struct("HashesMatrix")
62            // .field("matrix", &s)
63            .field("matrix_len", &self.matrix.len())
64            // .field("real_matrix", &real)
65            // .field("empty_hashes", &self.empty_hashes)
66            // .field("ledger_depth", &self.ledger_depth)
67            .field("nhashes", &self.nhashes)
68            // .field("capacity", &self.matrix.capacity())
69            .finish()
70    }
71}
72
73impl HashesMatrix {
74    pub fn new(ledger_depth: usize) -> Self {
75        // let capacity = 2 * 2usize.pow(ledger_depth as u32) - 1;
76
77        Self {
78            // matrix: vec![None; capacity],
79            matrix: BTreeMap::new(),
80            ledger_depth,
81            empty_hashes: vec![None; ledger_depth],
82            nhashes: 0,
83        }
84    }
85
86    pub fn get(&self, addr: &Address) -> Option<&Fp> {
87        let linear: u64 = addr.to_linear_index();
88
89        // self.matrix.get(linear)?.as_ref()
90        self.matrix.get(&linear)
91    }
92
93    pub fn set(&mut self, addr: &Address, hash: Fp) {
94        let linear: u64 = addr.to_linear_index();
95
96        // if self.matrix.len() <= linear {
97        //     self.matrix.resize(linear + 1, None);
98        // }
99
100        // assert!(self.matrix[linear].is_none());
101        // self.matrix[linear] = Some(hash);
102        let old = self.matrix.insert(linear, hash);
103        assert!(old.is_none());
104        self.nhashes += 1;
105    }
106
107    /// Do not use directly. Used to forcefully reconstructing the hashes
108    /// matrix from raw data.
109    pub fn set_raw_index(&mut self, idx: u64, hash: Fp) {
110        let old = self.matrix.insert(idx, hash);
111        assert!(old.is_none());
112        self.nhashes += 1;
113    }
114
115    pub fn remove(&mut self, addr: &Address) {
116        let linear: u64 = addr.to_linear_index();
117        self.remove_at_index(linear);
118    }
119
120    fn remove_at_index(&mut self, linear: u64) {
121        let old = self.matrix.remove(&linear);
122        if old.is_some() {
123            self.nhashes -= 1;
124        }
125
126        // let hash = match self.matrix.get_mut(index) {
127        //     Some(hash) => hash,
128        //     None => return,
129        // };
130
131        // if hash.is_some() {
132        //     self.nhashes -= 1;
133        //     *hash = None;
134        // }
135    }
136
137    pub(super) fn transfert_hashes(&mut self, hashes: HashesMatrix) {
138        for (index, hash) in hashes.matrix {
139            let old = self.matrix.insert(index, hash);
140            if old.is_none() {
141                self.nhashes += 1;
142            }
143        }
144    }
145
146    pub fn invalidate_hashes(&mut self, account_index: AccountIndex) {
147        let mut addr = Address::from_index(account_index, self.ledger_depth);
148
149        loop {
150            let index = addr.to_linear_index();
151            self.remove_at_index(index);
152            addr = match addr.parent() {
153                Some(addr) => addr,
154                None => break,
155            }
156        }
157    }
158
159    pub fn empty_hash_at_height(&mut self, height: usize) -> Fp {
160        if let Some(Some(hash)) = self.empty_hashes.get(height) {
161            return *hash;
162        };
163
164        // If `depth` is out of bound, see `HASH_EMPTIES`
165        let hash = HASH_EMPTIES.lock().unwrap()[height];
166        self.empty_hashes[height] = Some(hash);
167
168        hash
169    }
170
171    pub fn clear(&mut self) {
172        let ledger_depth = self.ledger_depth;
173        // let capacity = 2 * 2usize.pow(ledger_depth as u32) - 1;
174
175        *self = Self {
176            // matrix: vec![None; capacity],
177            matrix: BTreeMap::new(),
178            ledger_depth,
179            empty_hashes: vec![None; ledger_depth],
180            nhashes: 0,
181        }
182        // self.matrix.clear();
183        // self.empty_hashes.clear();
184        // self.nhashes = 0;
185    }
186
187    pub fn take(&mut self) -> Self {
188        let Self {
189            matrix,
190            empty_hashes,
191            ledger_depth,
192            nhashes,
193        } = self;
194
195        Self {
196            matrix: std::mem::take(matrix),
197            empty_hashes: std::mem::take(empty_hashes),
198            ledger_depth: *ledger_depth,
199            nhashes: *nhashes,
200        }
201    }
202
203    pub fn get_raw_inner_hashes(&self) -> Vec<(u64, Fp)> {
204        self.matrix.clone().into_iter().collect()
205    }
206
207    pub fn set_raw_inner_hashes(&mut self, hashes: Vec<(u64, Fp)>) {
208        for (idx, hash) in hashes {
209            self.set_raw_index(idx, hash);
210        }
211    }
212}
213
214static HASH_EMPTIES: Lazy<Mutex<Vec<Fp>>> = Lazy::new(|| {
215    /// This value needs to be changed when the tree's height change
216    const RANGE_HEIGHT: std::ops::Range<usize> = 0..36;
217
218    Mutex::new((RANGE_HEIGHT).map(V2::empty_hash_at_height).collect())
219});