mina_tree/database/
database_impl.rs

1use std::{
2    collections::{HashMap, HashSet},
3    ops::ControlFlow,
4    path::PathBuf,
5};
6
7use mina_curves::pasta::Fp;
8use mina_signer::CompressedPubKey;
9
10use crate::{
11    next_uuid, Account, AccountId, AccountIndex, AccountLegacy, Address, AddressIterator,
12    BaseLedger, Direction, GetOrCreated, HashesMatrix, MerklePath, TokenId, TreeVersion, Uuid, V1,
13    V2,
14};
15
16use super::DatabaseError;
17
18#[derive(Clone)]
19pub struct DatabaseImpl<T: TreeVersion> {
20    accounts: Vec<Option<T::Account>>,
21    pub hashes_matrix: HashesMatrix,
22    id_to_addr: HashMap<AccountId, Address>,
23    token_owners: Option<HashMap<T::TokenId, AccountId>>,
24    depth: u8,
25    last_location: Option<Address>,
26    naccounts: usize,
27    uuid: Uuid,
28    directory: PathBuf,
29}
30
31impl<T: TreeVersion> std::fmt::Debug for DatabaseImpl<T> {
32    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33        f.debug_struct("Database")
34            // .field("accounts", &self.accounts)
35            .field("hashes_matrix", &self.hashes_matrix)
36            // .field("id_to_addr", &self.id_to_addr)
37            // .field("token_owners", &self.token_owners)
38            // .field("depth", &self.depth)
39            // .field("last_location", &self.last_location)
40            .field("naccounts", &self.naccounts)
41            .field("uuid", &self.uuid)
42            .field("directory", &self.directory)
43            .finish()
44    }
45}
46
47impl DatabaseImpl<V2> {
48    pub fn clone_db(&self, new_directory: PathBuf) -> Self {
49        Self {
50            accounts: self.accounts.clone(),
51            id_to_addr: self.id_to_addr.clone(),
52            token_owners: self.token_owners.clone(),
53            depth: self.depth,
54            last_location: self.last_location.clone(),
55            naccounts: self.naccounts,
56            uuid: next_uuid(),
57            directory: new_directory,
58            hashes_matrix: self.hashes_matrix.clone(),
59        }
60    }
61
62    fn remove(&mut self, addr: Address) -> Option<Account> {
63        let index = addr.to_index();
64        let index: usize = index.0 as usize;
65
66        if let Some(account) = self.accounts.get_mut(index) {
67            return account.take();
68        }
69
70        None
71    }
72
73    fn create_account(
74        &mut self,
75        account_id: AccountId,
76        account: Account,
77    ) -> Result<GetOrCreated, DatabaseError> {
78        if let Some(addr) = self.id_to_addr.get(&account_id).cloned() {
79            return Ok(GetOrCreated::Existed(addr));
80        }
81
82        let token_id = account.token_id.clone();
83        let location = match self.last_location.as_ref() {
84            Some(last) => last.next().ok_or(DatabaseError::OutOfLeaves)?,
85            None => Address::first(self.depth as usize),
86        };
87
88        assert_eq!(location.to_index(), self.accounts.len());
89        self.accounts.push(Some(account));
90
91        self.last_location = Some(location.clone());
92        self.naccounts += 1;
93
94        if !token_id.is_default() {
95            if let Some(token_owners) = self.token_owners.as_mut() {
96                token_owners.insert(account_id.derive_token_id(), account_id.clone());
97            }
98        }
99        self.id_to_addr.insert(account_id, location.clone());
100
101        Ok(GetOrCreated::Added(location))
102    }
103
104    pub fn iter_with_addr<F>(&self, mut fun: F)
105    where
106        F: FnMut(Address, &Account),
107    {
108        let depth = self.depth as usize;
109
110        for (index, account) in self.accounts.iter().enumerate() {
111            let account = match account {
112                Some(account) => account,
113                None => continue,
114            };
115
116            let addr = Address::from_index(index.into(), depth);
117            fun(addr, account);
118        }
119    }
120
121    fn emulate_tree_to_get_hash_at(&mut self, addr: Address) -> Fp {
122        if let Some(hash) = self.hashes_matrix.get(&addr) {
123            return *hash;
124        };
125
126        let last_account = self
127            .last_filled()
128            .unwrap_or_else(|| Address::first(self.depth as usize));
129
130        self.emulate_tree_recursive(addr, &last_account)
131    }
132
133    pub fn emulate_tree_recursive(&mut self, addr: Address, last_account: &Address) -> Fp {
134        let tree_depth = self.depth as usize;
135        let current_depth = tree_depth - addr.length();
136
137        if current_depth == 0 {
138            return self
139                .get_account_hash(addr.to_index())
140                .unwrap_or_else(|| self.hashes_matrix.empty_hash_at_height(0));
141        }
142
143        let mut get_child_hash = |addr: Address| {
144            if let Some(hash) = self.hashes_matrix.get(&addr) {
145                *hash
146            } else if addr.is_before(last_account) {
147                self.emulate_tree_recursive(addr, last_account)
148            } else {
149                self.hashes_matrix.empty_hash_at_height(current_depth - 1)
150            }
151        };
152
153        let left_hash = get_child_hash(addr.child_left());
154        let right_hash = get_child_hash(addr.child_right());
155
156        match self.hashes_matrix.get(&addr) {
157            Some(hash) => *hash,
158            None => {
159                let hash = V2::hash_node(current_depth - 1, left_hash, right_hash);
160                self.hashes_matrix.set(&addr, hash);
161                hash
162            }
163        }
164    }
165
166    pub fn emulate_tree_to_get_path(
167        &mut self,
168        addr: Address,
169        last_account: &Address,
170        path: &mut AddressIterator,
171        merkle_path: &mut Vec<MerklePath>,
172    ) -> Fp {
173        let tree_depth = self.depth as usize;
174
175        if addr.length() == self.depth as usize {
176            return self
177                .get_account_hash(addr.to_index())
178                .unwrap_or_else(|| self.hashes_matrix.empty_hash_at_height(0));
179        }
180
181        let next_direction = path.next();
182
183        // We go until the end of the path
184        if let Some(direction) = next_direction.as_ref() {
185            let child = match direction {
186                Direction::Left => addr.child_left(),
187                Direction::Right => addr.child_right(),
188            };
189            self.emulate_tree_to_get_path(child, last_account, path, merkle_path);
190        };
191
192        let depth_in_tree = tree_depth - addr.length();
193
194        let mut get_child_hash = |addr: Address| match self.hashes_matrix.get(&addr) {
195            Some(hash) => *hash,
196            None => {
197                if let Some(hash) = self.hashes_matrix.get(&addr) {
198                    *hash
199                } else if addr.is_before(last_account) {
200                    self.emulate_tree_to_get_path(addr, last_account, path, merkle_path)
201                } else {
202                    self.hashes_matrix.empty_hash_at_height(depth_in_tree - 1)
203                }
204            }
205        };
206
207        let left = get_child_hash(addr.child_left());
208        let right = get_child_hash(addr.child_right());
209
210        if let Some(direction) = next_direction {
211            let hash = match direction {
212                Direction::Left => MerklePath::Left(right),
213                Direction::Right => MerklePath::Right(left),
214            };
215            merkle_path.push(hash);
216        };
217
218        match self.hashes_matrix.get(&addr) {
219            Some(hash) => *hash,
220            None => {
221                let hash = V2::hash_node(depth_in_tree - 1, left, right);
222                self.hashes_matrix.set(&addr, hash);
223                hash
224            }
225        }
226    }
227
228    pub fn create_checkpoint(&self, directory_name: String) {
229        elog!("create_checkpoint {}", directory_name);
230    }
231
232    pub fn make_checkpoint(&self, directory_name: String) {
233        elog!("make_checkpoint {}", directory_name);
234    }
235
236    pub fn get_cached_hash(&self, addr: &Address) -> Option<Fp> {
237        self.hashes_matrix.get(addr).copied()
238    }
239
240    pub fn set_cached_hash(&mut self, addr: &Address, hash: Fp) {
241        self.hashes_matrix.set(addr, hash);
242    }
243
244    pub fn empty_hash_at_height(&mut self, height: usize) -> Fp {
245        self.hashes_matrix.empty_hash_at_height(height)
246    }
247
248    pub fn invalidate_hashes(&mut self, account_index: AccountIndex) {
249        self.hashes_matrix.invalidate_hashes(account_index)
250    }
251
252    pub fn transfert_hashes(&mut self, hashes: HashesMatrix) {
253        self.hashes_matrix.transfert_hashes(hashes)
254    }
255
256    pub fn has_token_owners(&self) -> bool {
257        self.token_owners.is_some()
258    }
259}
260
261impl DatabaseImpl<V1> {
262    pub fn create_account(
263        &mut self,
264        _account_id: (),
265        account: AccountLegacy,
266    ) -> Result<Address, DatabaseError> {
267        let location = match self.last_location.as_ref() {
268            Some(last) => last.next().ok_or(DatabaseError::OutOfLeaves)?,
269            None => Address::first(self.depth as usize),
270        };
271
272        assert_eq!(location.to_index(), self.accounts.len());
273        self.accounts.push(Some(account));
274
275        self.last_location = Some(location.clone());
276        self.naccounts += 1;
277
278        Ok(location)
279    }
280}
281
282impl DatabaseImpl<V2> {
283    const NACCOUNTS: usize = 10_000;
284    const NTOKENS: usize = 10;
285
286    pub fn create_with_dir(depth: u8, dir_name: Option<PathBuf>) -> Self {
287        assert!((1..0xfe).contains(&depth));
288
289        let uuid = next_uuid();
290
291        let path = match dir_name {
292            Some(dir_name) => dir_name,
293            None => {
294                let directory = format!("minadb-{uuid}");
295
296                let mut path = PathBuf::from("/tmp");
297                path.push(&directory);
298                path
299            }
300        };
301
302        Self {
303            depth,
304            accounts: Vec::with_capacity(Self::NACCOUNTS),
305            last_location: None,
306            naccounts: 0,
307            id_to_addr: HashMap::with_capacity(Self::NACCOUNTS),
308            token_owners: None,
309            uuid,
310            directory: path,
311            hashes_matrix: HashesMatrix::new(depth as usize),
312        }
313    }
314
315    pub fn create(depth: u8) -> Self {
316        Self::create_with_dir(depth, None)
317    }
318
319    pub fn create_with_token_owners(depth: u8) -> Self {
320        let mut db = Self::create_with_dir(depth, None);
321        db.set_token_owners();
322        db
323    }
324
325    pub fn set_token_owners(&mut self) {
326        if self.token_owners.is_none() {
327            self.token_owners = Some(HashMap::with_capacity(Self::NTOKENS));
328        }
329    }
330
331    pub fn unset_token_owners(&mut self) {
332        self.token_owners = None;
333    }
334
335    pub fn root_hash(&mut self) -> Fp {
336        self.emulate_tree_to_get_hash_at(Address::root())
337    }
338
339    // Do not use
340    pub fn naccounts(&self) -> usize {
341        self.accounts.iter().filter_map(Option::as_ref).count()
342    }
343
344    fn get_account_ref(&self, addr: Address) -> Option<&Account> {
345        let index = addr.to_index();
346        let index: usize = index.0 as usize;
347
348        self.accounts.get(index)?.as_ref()
349    }
350}
351
352impl BaseLedger for DatabaseImpl<V2> {
353    fn to_list(&self) -> Vec<Account> {
354        self.accounts
355            .iter()
356            .filter_map(Option::as_ref)
357            .cloned()
358            .collect()
359    }
360
361    fn iter<F>(&self, fun: F)
362    where
363        F: FnMut(&Account),
364    {
365        self.accounts
366            .iter()
367            .filter_map(Option::as_ref)
368            .for_each(fun);
369    }
370
371    fn fold<B, F>(&self, init: B, mut fun: F) -> B
372    where
373        F: FnMut(B, &Account) -> B,
374    {
375        let mut accum = init;
376        for account in self.accounts.iter().filter_map(Option::as_ref) {
377            accum = fun(accum, account);
378        }
379        accum
380    }
381
382    fn fold_with_ignored_accounts<B, F>(
383        &self,
384        ignoreds: HashSet<AccountId>,
385        init: B,
386        mut fun: F,
387    ) -> B
388    where
389        F: FnMut(B, &Account) -> B,
390    {
391        let mut accum = init;
392        for account in self.accounts.iter().filter_map(Option::as_ref) {
393            let account_id = account.id();
394
395            if !ignoreds.contains(&account_id) {
396                accum = fun(accum, account);
397            }
398        }
399        accum
400    }
401
402    fn fold_until<B, F>(&self, init: B, mut fun: F) -> B
403    where
404        F: FnMut(B, &Account) -> ControlFlow<B, B>,
405    {
406        let mut accum = init;
407        for account in self.accounts.iter().filter_map(Option::as_ref) {
408            match fun(accum, account) {
409                ControlFlow::Continue(v) => {
410                    accum = v;
411                }
412                ControlFlow::Break(v) => {
413                    accum = v;
414                    break;
415                }
416            }
417        }
418        accum
419    }
420
421    fn accounts(&self) -> HashSet<AccountId> {
422        self.id_to_addr.keys().cloned().collect()
423    }
424
425    fn token_owner(&self, token_id: TokenId) -> Option<AccountId> {
426        self.token_owners
427            .as_ref()
428            .and_then(|token_owners| token_owners.get(&token_id).cloned())
429    }
430
431    fn tokens(&self, public_key: CompressedPubKey) -> HashSet<TokenId> {
432        let mut set = HashSet::with_capacity(100);
433
434        for account in self.accounts.iter().filter_map(Option::as_ref) {
435            if account.public_key == public_key {
436                set.insert(account.token_id.clone());
437            }
438        }
439        set
440    }
441
442    fn location_of_account(&self, account_id: &AccountId) -> Option<Address> {
443        self.id_to_addr.get(account_id).cloned()
444    }
445
446    fn location_of_account_batch(
447        &self,
448        account_ids: &[AccountId],
449    ) -> Vec<(AccountId, Option<Address>)> {
450        let res: Vec<_> = account_ids
451            .iter()
452            .map(|account_id| {
453                let addr = self.id_to_addr.get(account_id).cloned();
454                (account_id.clone(), addr)
455            })
456            .collect();
457
458        elog!(
459            "location_of_account_batch ids={:?}\nres={:?}={:?}",
460            account_ids,
461            res.len(),
462            res
463        );
464
465        res
466    }
467
468    fn get_or_create_account(
469        &mut self,
470        account_id: AccountId,
471        account: Account,
472    ) -> Result<GetOrCreated, DatabaseError> {
473        let result = self.create_account(account_id, account);
474
475        if let Ok(GetOrCreated::Added(addr)) = result.as_ref() {
476            let account_index = addr.to_index();
477            self.hashes_matrix.invalidate_hashes(account_index);
478        };
479
480        result
481    }
482
483    fn close(&self) {
484        elog!(
485            "close pid={:?} uuid={:?} path={:?}",
486            crate::util::pid(),
487            self.uuid,
488            self.directory
489        );
490        // Drop
491    }
492
493    fn last_filled(&self) -> Option<Address> {
494        self.last_location.clone()
495    }
496
497    fn get_uuid(&self) -> crate::base::Uuid {
498        self.uuid.clone()
499    }
500
501    fn get_directory(&self) -> Option<PathBuf> {
502        Some(self.directory.clone())
503    }
504
505    fn get_account_hash(&mut self, account_index: AccountIndex) -> Option<Fp> {
506        let addr = Address::from_index(account_index, self.depth as usize);
507
508        if let Some(hash) = self.hashes_matrix.get(&addr) {
509            return Some(*hash);
510        }
511
512        let account = self.get_account_ref(addr.clone())?;
513        let hash = account.hash();
514
515        self.hashes_matrix.set(&addr, hash);
516
517        Some(hash)
518    }
519
520    #[inline(never)]
521    fn get(&self, addr: Address) -> Option<Box<Account>> {
522        self.get_account_ref(addr).cloned().map(Box::new)
523    }
524
525    fn get_batch(&self, addr: &[Address]) -> Vec<(Address, Option<Box<Account>>)> {
526        let res: Vec<_> = addr
527            .iter()
528            .map(|addr| (addr.clone(), self.get(addr.clone())))
529            .collect();
530
531        elog!("get_batch addrs={:?}\nres={:?}={:?}", addr, res.len(), res);
532
533        res
534    }
535
536    fn set(&mut self, addr: Address, account: Box<Account>) {
537        let index = addr.to_index();
538
539        self.hashes_matrix.invalidate_hashes(index);
540
541        let index: usize = index.0 as usize;
542
543        if self.accounts.len() <= index {
544            self.accounts.resize(index + 1, None);
545        }
546
547        let id = account.id();
548
549        // Remove account at the address and it's index
550        if let Some(account) = self.get(addr.clone()) {
551            let id = account.id();
552            self.id_to_addr.remove(&id);
553            if !id.token_id.is_default() {
554                if let Some(token_owners) = self.token_owners.as_mut() {
555                    token_owners.remove(&id.derive_token_id());
556                }
557            }
558        } else {
559            self.naccounts += 1;
560        }
561
562        if !account.token_id.is_default() {
563            if let Some(token_owners) = self.token_owners.as_mut() {
564                token_owners.insert(account.id().derive_token_id(), id.clone());
565            }
566        }
567        self.id_to_addr.insert(id, addr.clone());
568        self.accounts[index] = Some(*account);
569
570        if self
571            .last_location
572            .as_ref()
573            .map(|l| l.to_index() < addr.to_index())
574            .unwrap_or(true)
575        {
576            self.last_location = Some(addr);
577        }
578    }
579
580    fn set_batch(&mut self, list: &[(Address, Box<Account>)]) {
581        elog!("SET_BATCH {:?}", list.len());
582        for (addr, account) in list {
583            assert_eq!(addr.length(), self.depth as usize, "addr={:?}", addr);
584            self.set(addr.clone(), account.clone());
585        }
586    }
587
588    fn get_at_index(&self, index: AccountIndex) -> Option<Box<Account>> {
589        let addr = Address::from_index(index, self.depth as usize);
590        self.get(addr)
591    }
592
593    fn set_at_index(&mut self, index: AccountIndex, account: Box<Account>) -> Result<(), ()> {
594        let addr = Address::from_index(index, self.depth as usize);
595        self.set(addr, account);
596
597        Ok(())
598    }
599
600    fn index_of_account(&self, account_id: AccountId) -> Option<AccountIndex> {
601        self.id_to_addr.get(&account_id).map(Address::to_index)
602    }
603
604    fn merkle_root(&mut self) -> Fp {
605        self.root_hash()
606    }
607
608    fn merkle_path(&mut self, addr: Address) -> Vec<MerklePath> {
609        elog!("merkle_path called depth={:?} addr={:?}", self.depth, addr);
610
611        let mut merkle_path = Vec::with_capacity(addr.length());
612        let mut path = addr.into_iter();
613        let addr = Address::root();
614
615        let last_account = self
616            .last_filled()
617            .unwrap_or_else(|| Address::first(self.depth as usize));
618
619        self.emulate_tree_to_get_path(addr, &last_account, &mut path, &mut merkle_path);
620
621        merkle_path
622    }
623
624    fn merkle_path_at_index(&mut self, index: AccountIndex) -> Vec<MerklePath> {
625        let addr = Address::from_index(index, self.depth as usize);
626        self.merkle_path(addr)
627    }
628
629    fn remove_accounts(&mut self, ids: &[AccountId]) {
630        let mut addrs = ids
631            .iter()
632            .map(|accound_id| self.id_to_addr.remove(accound_id).unwrap())
633            .collect::<Vec<_>>();
634        addrs.sort_by_key(Address::to_index);
635
636        for addr in addrs.iter().rev() {
637            let account_index = addr.to_index();
638            self.hashes_matrix.invalidate_hashes(account_index);
639
640            let account = match self.remove(addr.clone()) {
641                Some(account) => account,
642                None => continue,
643            };
644
645            let id = account.id();
646            self.id_to_addr.remove(&id);
647            if !id.token_id.is_default() {
648                if let Some(token_owners) = self.token_owners.as_mut() {
649                    token_owners.remove(&id.derive_token_id());
650                }
651            }
652
653            self.naccounts = self
654                .naccounts
655                .checked_sub(1)
656                .expect("invalid naccounts counter");
657
658            if self
659                .last_location
660                .as_ref()
661                .map(|last| last == addr)
662                .unwrap_or(false)
663            {
664                self.last_location = addr.prev();
665            }
666        }
667    }
668
669    fn detached_signal(&mut self) {
670        todo!()
671    }
672
673    fn depth(&self) -> u8 {
674        self.depth
675    }
676
677    fn num_accounts(&self) -> usize {
678        self.naccounts
679    }
680
681    fn merkle_path_at_addr(&mut self, addr: Address) -> Vec<MerklePath> {
682        self.merkle_path(addr)
683    }
684
685    fn get_inner_hash_at_addr(&mut self, addr: Address) -> Result<Fp, String> {
686        let res = self.emulate_tree_to_get_hash_at(addr.clone());
687
688        elog!("get_inner_hash_at_addr addr={:?} hash={}", addr, res);
689
690        Ok(res)
691    }
692
693    fn set_inner_hash_at_addr(&mut self, _addr: Address, _hash: Fp) -> Result<(), ()> {
694        // No-op for now, because we don't store the hashes anywhere
695        Ok(())
696    }
697
698    fn set_all_accounts_rooted_at(
699        &mut self,
700        addr: Address,
701        accounts: &[Box<Account>],
702    ) -> Result<(), ()> {
703        if addr.length() > self.depth as usize {
704            return Err(());
705        }
706
707        for (child_addr, account) in addr.iter_children(self.depth as usize).zip(accounts) {
708            self.set(child_addr, account.clone());
709        }
710
711        Ok(())
712    }
713
714    fn get_all_accounts_rooted_at(&self, addr: Address) -> Option<Vec<(Address, Box<Account>)>> {
715        if addr.length() > self.depth as usize {
716            return None;
717        }
718
719        let children = addr.iter_children(self.depth as usize);
720        let mut accounts = Vec::with_capacity(children.len());
721
722        for child_addr in children {
723            let account = match self.get(child_addr.clone()) {
724                Some(account) => account,
725                None => continue,
726            };
727            accounts.push((child_addr, account));
728        }
729
730        if accounts.is_empty() {
731            None
732        } else {
733            Some(accounts)
734        }
735    }
736
737    fn make_space_for(&mut self, _space: usize) {
738        // No op, we're in memory
739    }
740
741    fn commit(&mut self) {
742        // no-op
743    }
744}