mina_tree/sparse_ledger/
sparse_ledger_impl.rs

1use std::collections::{BTreeMap, HashMap, VecDeque};
2
3use ark_ff::Zero;
4use mina_curves::pasta::Fp;
5use mina_signer::CompressedPubKey;
6use poseidon::hash::params::get_merkle_param_for_height;
7
8use crate::{
9    scan_state::{currency::Slot, transaction_logic::AccountState},
10    Account, AccountId, AccountIndex, Address, AddressIterator, BaseLedger, Direction,
11    HashesMatrix, Mask, MerklePath, TreeVersion, V2,
12};
13
14use super::LedgerIntf;
15
16#[derive(Clone, Debug, PartialEq)]
17pub(super) struct SparseLedgerImpl<K: Eq + std::hash::Hash, V> {
18    pub values: BTreeMap<AccountIndex, V>,
19    pub indexes: HashMap<K, Address>,
20    /// Mirror OCaml, where the index is ordered, and can have duplicates
21    pub indexes_list: VecDeque<K>,
22    pub hashes_matrix: HashesMatrix,
23    pub depth: usize,
24}
25
26impl SparseLedgerImpl<AccountId, Account> {
27    pub fn create(depth: usize, root_hash: Fp) -> Self {
28        let mut hashes_matrix = HashesMatrix::new(depth);
29        hashes_matrix.set(&Address::root(), root_hash);
30
31        Self {
32            values: BTreeMap::new(),
33            indexes: HashMap::new(),
34            indexes_list: VecDeque::new(),
35            depth,
36            hashes_matrix,
37        }
38    }
39
40    pub fn of_ledger_subset_exn(oledger: Mask, keys: &[AccountId]) -> Self {
41        use crate::GetOrCreated::{Added, Existed};
42
43        let mut ledger = oledger.copy();
44        let mut sparse = Self::create(
45            ledger.depth() as usize,
46            BaseLedger::merkle_root(&mut ledger),
47        );
48
49        for key in keys {
50            match BaseLedger::location_of_account(&ledger, key) {
51                Some(addr) => {
52                    let account = BaseLedger::get(&ledger, addr.clone()).unwrap();
53                    let merkle_path = ledger.merkle_path(addr);
54                    sparse.add_path(&merkle_path, key.clone(), *account);
55                }
56                None => {
57                    let addr = match ledger
58                        .get_or_create_account(key.clone(), Account::empty())
59                        .unwrap()
60                    {
61                        Added(addr) => addr,
62                        Existed(_) => panic!("create_empty for a key already present"),
63                    };
64
65                    let merkle_path = ledger.merkle_path(addr);
66                    sparse.add_path(&merkle_path, key.clone(), Account::empty());
67                }
68            }
69        }
70
71        assert_eq!(BaseLedger::merkle_root(&mut ledger), sparse.merkle_root());
72
73        sparse
74    }
75
76    fn get_or_initialize_exn(
77        &self,
78        account_id: &AccountId,
79        addr: &Address,
80    ) -> (AccountState, Account) {
81        let mut account = self.get_exn(addr).clone();
82
83        if account.public_key == CompressedPubKey::empty() {
84            let public_key = account_id.public_key.clone();
85            let token_id = account_id.token_id.clone();
86
87            // Only allow delegation if this account is for the default token.
88            let delegate = if token_id.is_default() {
89                Some(public_key.clone())
90            } else {
91                None
92            };
93
94            account.delegate = delegate;
95            account.public_key = public_key;
96            account.token_id = token_id;
97
98            (AccountState::Added, account)
99        } else {
100            (AccountState::Existed, account)
101        }
102    }
103
104    pub fn has_locked_tokens_exn(&self, global_slot: Slot, account_id: AccountId) -> bool {
105        let addr = self.find_index_exn(account_id.clone());
106        let (_, account) = self.get_or_initialize_exn(&account_id, &addr);
107        account.has_locked_tokens(global_slot)
108    }
109
110    pub fn iteri<F>(&self, fun: F)
111    where
112        F: Fn(Address, &Account),
113    {
114        let addr = |index: &AccountIndex| Address::from_index(*index, self.depth);
115
116        for (index, value) in &self.values {
117            fun(addr(index), value);
118        }
119    }
120
121    pub fn add_path(
122        &mut self,
123        merkle_path: &[MerklePath],
124        account_id: AccountId,
125        account: Account,
126    ) {
127        assert_eq!(self.depth, merkle_path.len());
128
129        let mut set_hash = |addr: Address, hash: &Fp| {
130            if let Some(prev_hash) = self.hashes_matrix.get(&addr) {
131                assert_eq!(prev_hash, hash);
132                return;
133            };
134
135            self.hashes_matrix.set(&addr, *hash);
136        };
137
138        let mut addr = Address::root();
139
140        // Go until the account address
141        for path in merkle_path.iter().rev() {
142            addr = match path {
143                MerklePath::Left(right) => {
144                    set_hash(addr.child_right(), right);
145                    addr.child_left()
146                }
147                MerklePath::Right(left) => {
148                    set_hash(addr.child_left(), left);
149                    addr.child_right()
150                }
151            }
152        }
153
154        let account_addr = addr.clone();
155
156        let mut current = account.hash();
157
158        // Go back from the account to root, to compute missing hashes
159        for (height, path) in merkle_path.iter().enumerate() {
160            set_hash(addr.clone(), &current);
161
162            let hashes = match path {
163                MerklePath::Left(right) => [current, *right],
164                MerklePath::Right(left) => [*left, current],
165            };
166
167            let param = get_merkle_param_for_height(height);
168            current = poseidon::hash::hash_with_kimchi(param, &hashes);
169
170            addr = addr.parent().unwrap();
171        }
172
173        assert!(addr.is_root());
174        set_hash(addr, &current);
175
176        let index = account_addr.to_index();
177        self.indexes
178            .entry(account_id.clone())
179            .or_insert(account_addr);
180        self.indexes_list.push_front(account_id);
181        self.values.insert(index, account);
182    }
183
184    pub(super) fn get_index(&self, account_id: &AccountId) -> Option<&Address> {
185        self.indexes.get(account_id)
186    }
187
188    fn get(&self, addr: &Address) -> Option<&Account> {
189        assert_eq!(addr.length(), self.depth);
190
191        let index = addr.to_index();
192        self.values.get(&index)
193    }
194
195    pub fn get_exn(&self, addr: &Address) -> &Account {
196        self.get(addr).unwrap()
197    }
198
199    pub fn set_exn(&mut self, addr: Address, value: Box<Account>) {
200        assert_eq!(addr.length(), self.depth);
201
202        let index = addr.to_index();
203        self.values.insert(index, *value);
204
205        self.hashes_matrix.invalidate_hashes(addr.to_index());
206    }
207
208    pub fn find_index_exn(&self, key: AccountId) -> Address {
209        self.get_index(&key).cloned().unwrap()
210    }
211
212    pub fn path_exn(&mut self, addr: Address) -> Vec<MerklePath> {
213        let mut merkle_path = Vec::with_capacity(addr.length());
214        let mut path_to_addr = addr.into_iter();
215        let root = Address::root();
216
217        self.emulate_tree_to_get_path(root, &mut path_to_addr, &mut merkle_path);
218
219        merkle_path
220    }
221
222    fn get_value_hash(&mut self, addr: Address) -> Fp {
223        if let Some(hash) = self.hashes_matrix.get(&addr) {
224            return *hash;
225        }
226
227        let hash = match self.get(&addr) {
228            Some(value) => V2::hash_leaf(value),
229            None => V2::empty_hash_at_height(0),
230        };
231
232        self.hashes_matrix.set(&addr, hash);
233
234        hash
235    }
236
237    fn get_node_hash(&mut self, addr: &Address, left: Fp, right: Fp) -> Fp {
238        if let Some(hash) = self.hashes_matrix.get(addr) {
239            return *hash;
240        };
241
242        let depth_in_tree = self.depth - addr.length();
243
244        let hash = V2::hash_node(depth_in_tree - 1, left, right);
245        self.hashes_matrix.set(addr, hash);
246        hash
247    }
248
249    fn emulate_tree_to_get_path(
250        &mut self,
251        addr: Address,
252        path: &mut AddressIterator,
253        merkle_path: &mut Vec<MerklePath>,
254    ) -> Fp {
255        if addr.length() == self.depth {
256            return self.get_value_hash(addr);
257        }
258
259        let next_direction = path.next();
260
261        // We go until the end of the path
262        if let Some(direction) = next_direction.as_ref() {
263            let child = match direction {
264                Direction::Left => addr.child_left(),
265                Direction::Right => addr.child_right(),
266            };
267            self.emulate_tree_to_get_path(child, path, merkle_path);
268        };
269
270        let mut get_child_hash = |addr: Address| match self.hashes_matrix.get(&addr) {
271            Some(hash) => *hash,
272            None => {
273                if let Some(hash) = self.hashes_matrix.get(&addr) {
274                    *hash
275                } else {
276                    self.emulate_tree_to_get_path(addr, path, merkle_path)
277                }
278            }
279        };
280
281        let left = get_child_hash(addr.child_left());
282        let right = get_child_hash(addr.child_right());
283
284        if let Some(direction) = next_direction {
285            let hash = match direction {
286                Direction::Left => MerklePath::Left(right),
287                Direction::Right => MerklePath::Right(left),
288            };
289            merkle_path.push(hash);
290        };
291
292        self.get_node_hash(&addr, left, right)
293    }
294
295    pub fn merkle_root(&mut self) -> Fp {
296        let root = Address::root();
297
298        if let Some(hash) = self.hashes_matrix.get(&root) {
299            return *hash;
300        };
301
302        self.emulate_tree_merkle_root(root)
303    }
304
305    pub fn emulate_tree_merkle_root(&mut self, addr: Address) -> Fp {
306        let current_depth = self.depth - addr.length();
307
308        if current_depth == 0 {
309            return self.get_value_hash(addr);
310        }
311
312        let mut get_child_hash = |addr: Address| {
313            if let Some(hash) = self.hashes_matrix.get(&addr) {
314                *hash
315            } else {
316                self.emulate_tree_merkle_root(addr)
317            }
318        };
319
320        let left_hash = get_child_hash(addr.child_left());
321        let right_hash = get_child_hash(addr.child_right());
322
323        self.get_node_hash(&addr, left_hash, right_hash)
324    }
325
326    fn location_of_account_impl(&self, account_id: &AccountId) -> Option<Address> {
327        self.get_index(account_id).cloned()
328    }
329
330    // let apply_transaction_first_pass ~constraint_constants ~global_slot
331    //     ~txn_state_view =
332    //   apply_transaction_logic
333    //     (T.apply_transaction_first_pass ~constraint_constants ~global_slot
334    //        ~txn_state_view )
335}
336
337impl LedgerIntf for SparseLedgerImpl<AccountId, Account> {
338    type Location = Address;
339
340    /// <https://github.com/MinaProtocol/mina/blob/05c2f73d0f6e4f1341286843814ce02dcb3919e0/src/lib/mina_base/sparse_ledger_base.ml#L58>
341    fn get(&self, addr: &Self::Location) -> Option<Box<Account>> {
342        let account = self.get(addr)?;
343
344        if account.public_key == CompressedPubKey::empty() {
345            None
346        } else {
347            Some(Box::new(account.clone()))
348        }
349    }
350
351    /// <https://github.com/MinaProtocol/mina/blob/05c2f73d0f6e4f1341286843814ce02dcb3919e0/src/lib/mina_base/sparse_ledger_base.ml#L66>
352    fn location_of_account(&self, account_id: &AccountId) -> Option<Self::Location> {
353        let addr = self.get_index(account_id)?;
354        let account = self.get(addr)?;
355
356        if account.public_key == CompressedPubKey::empty() {
357            None
358        } else {
359            Some(addr.clone())
360        }
361    }
362
363    /// <https://github.com/MinaProtocol/mina/blob/05c2f73d0f6e4f1341286843814ce02dcb3919e0/src/lib/mina_base/sparse_ledger_base.ml#L75>
364    fn set(&mut self, addr: &Self::Location, account: Box<Account>) {
365        self.set_exn(addr.clone(), account);
366    }
367
368    /// <https://github.com/MinaProtocol/mina/blob/05c2f73d0f6e4f1341286843814ce02dcb3919e0/src/lib/mina_base/sparse_ledger_base.ml#L96>
369    fn get_or_create(
370        &mut self,
371        account_id: &AccountId,
372    ) -> Result<(AccountState, Box<Account>, Self::Location), String> {
373        let addr = self
374            .get_index(account_id)
375            .ok_or_else(|| "failed".to_string())?;
376        let account = self.get(addr).ok_or_else(|| "failed".to_string())?;
377        let mut account = Box::new(account.clone());
378
379        let addr = addr.clone();
380        if account.public_key == CompressedPubKey::empty() {
381            let public_key = account_id.public_key.clone();
382
383            account.delegate = Some(public_key.clone());
384            account.public_key = public_key;
385            account.token_id = account_id.token_id.clone();
386
387            self.set(&addr, account.clone());
388            Ok((AccountState::Added, account, addr))
389        } else {
390            Ok((AccountState::Existed, account, addr))
391        }
392    }
393
394    /// <https://github.com/MinaProtocol/mina/blob/05c2f73d0f6e4f1341286843814ce02dcb3919e0/src/lib/mina_base/sparse_ledger_base.ml#L109>
395    fn create_new_account(&mut self, account_id: AccountId, to_set: Account) -> Result<(), ()> {
396        let addr = self.get_index(&account_id).ok_or(())?;
397        let account = self.get(addr).ok_or(())?;
398
399        if account.public_key == CompressedPubKey::empty() {
400            let addr = addr.clone();
401            self.set(&addr, Box::new(to_set));
402        }
403
404        Ok(())
405    }
406
407    /// <https://github.com/MinaProtocol/mina/blob/05c2f73d0f6e4f1341286843814ce02dcb3919e0/src/lib/mina_base/sparse_ledger_base.ml#L112>
408    fn remove_accounts_exn(&mut self, _account_ids: &[AccountId]) {
409        unimplemented!("remove_accounts_exn: not implemented")
410    }
411
412    /// <https://github.com/MinaProtocol/mina/blob/05c2f73d0f6e4f1341286843814ce02dcb3919e0/src/lib/mina_base/sparse_ledger_base.ml#L115>
413    fn merkle_root(&mut self) -> Fp {
414        self.merkle_root()
415    }
416
417    /// <https://github.com/MinaProtocol/mina/blob/05c2f73d0f6e4f1341286843814ce02dcb3919e0/src/lib/mina_base/sparse_ledger_base.ml#L142>
418    fn empty(depth: usize) -> Self {
419        Self::create(depth, Fp::zero())
420    }
421
422    fn create_masked(&self) -> Self {
423        unimplemented!() // Implemented for `SparseLedger`
424    }
425
426    fn apply_mask(&mut self, _mask: Self) {
427        unimplemented!() // Implemented for `SparseLedger`
428    }
429
430    fn account_locations(&self) -> Vec<Self::Location> {
431        let mut addrs: Vec<Address> = self.indexes.values().cloned().collect();
432
433        addrs.sort_by_key(Address::to_index);
434
435        addrs
436    }
437}