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("hashes_matrix", &self.hashes_matrix)
36 .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 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 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 }
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 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 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 }
740
741 fn commit(&mut self) {
742 }
744}