Skip to main content

mina_tree/
base.rs

1use std::{
2    collections::HashSet,
3    ops::{ControlFlow, Deref},
4    path::PathBuf,
5    sync::atomic::AtomicU64,
6};
7
8use mina_curves::pasta::Fp;
9use mina_signer::CompressedPubKey;
10use serde::{Deserialize, Serialize};
11
12use crate::{
13    account::{Account, AccountId, TokenId},
14    address::Address,
15    database::DatabaseError,
16    scan_state::transaction_logic::AccountState,
17    sparse_ledger::LedgerIntf,
18    Mask,
19};
20
21pub type Uuid = String;
22
23static UUID_GENERATOR: AtomicU64 = AtomicU64::new(0);
24
25pub fn next_uuid() -> Uuid {
26    // use uuid::Uuid;
27
28    uuid::Uuid::new_v4().to_string()
29
30    // "a".to_string()
31    // UUID_GENERATOR.fetch_add(1, Ordering::AcqRel)
32}
33
34#[derive(PartialEq, Eq)]
35pub enum MerklePath {
36    Left(Fp),
37    Right(Fp),
38}
39
40impl MerklePath {
41    pub fn hash(&self) -> &Fp {
42        match self {
43            MerklePath::Left(h) => h,
44            MerklePath::Right(h) => h,
45        }
46    }
47}
48
49impl std::fmt::Debug for MerklePath {
50    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        match self {
52            Self::Left(arg0) => f.write_fmt(format_args!("Left({:?})", arg0)),
53            Self::Right(arg0) => f.write_fmt(format_args!("Right({:?})", arg0)),
54        }
55    }
56}
57
58pub trait BaseLedger {
59    /// list of accounts in the ledger
60    fn to_list(&self) -> Vec<Account>;
61
62    /// iterate over all indexes and accounts
63    fn iter<F>(&self, fun: F)
64    where
65        F: FnMut(&Account);
66
67    /// fold over accounts in the ledger, passing the Merkle address
68    fn fold<B, F>(&self, init: B, fun: F) -> B
69    where
70        F: FnMut(B, &Account) -> B;
71
72    /// the set of `account_id`s are ledger elements to skip during the fold,
73    /// because they're in a mask
74    fn fold_with_ignored_accounts<B, F>(&self, ignoreds: HashSet<AccountId>, init: B, fun: F) -> B
75    where
76        F: FnMut(B, &Account) -> B;
77
78    /// fold until `fun` returns `ControlFlow::Stop`
79    fn fold_until<B, F>(&self, init: B, fun: F) -> B
80    where
81        F: FnMut(B, &Account) -> ControlFlow<B, B>;
82
83    /// set of account ids associated with accounts
84    fn accounts(&self) -> HashSet<AccountId>;
85
86    /// Get the account id that owns a token.
87    fn token_owner(&self, token_id: TokenId) -> Option<AccountId>;
88
89    /// Get all of the tokens for which a public key has accounts.
90    fn tokens(&self, public_key: CompressedPubKey) -> HashSet<TokenId>;
91
92    fn location_of_account(&self, account_id: &AccountId) -> Option<Address>;
93
94    fn location_of_account_batch(
95        &self,
96        account_ids: &[AccountId],
97    ) -> Vec<(AccountId, Option<Address>)>;
98
99    /// This may return an error if the ledger is full.
100    fn get_or_create_account(
101        &mut self,
102        account_id: AccountId,
103        account: Account,
104    ) -> Result<GetOrCreated, DatabaseError>;
105
106    /// the ledger should not be used after calling `close`
107    fn close(&self);
108
109    /// for account locations in the ledger, the last (rightmost) filled location
110    fn last_filled(&self) -> Option<Address>;
111
112    fn get_uuid(&self) -> Uuid;
113
114    /// return Some `directory` for ledgers that use a file system, else None
115    fn get_directory(&self) -> Option<PathBuf>;
116
117    fn get(&self, addr: Address) -> Option<Box<Account>>;
118
119    fn get_batch(&self, addr: &[Address]) -> Vec<(Address, Option<Box<Account>>)>;
120
121    fn set(&mut self, addr: Address, account: Box<Account>);
122
123    fn set_batch(&mut self, list: &[(Address, Box<Account>)]);
124
125    fn get_at_index(&self, index: AccountIndex) -> Option<Box<Account>>;
126
127    fn set_at_index(&mut self, index: AccountIndex, account: Box<Account>) -> Result<(), ()>;
128
129    fn index_of_account(&self, account_id: AccountId) -> Option<AccountIndex>;
130
131    /// meant to be a fast operation: the root hash is stored, rather
132    /// than calculated dynamically
133    fn merkle_root(&mut self) -> Fp;
134
135    fn merkle_path(&mut self, addr: Address) -> Vec<MerklePath>;
136
137    fn merkle_path_at_index(&mut self, index: AccountIndex) -> Vec<MerklePath>;
138
139    fn remove_accounts(&mut self, ids: &[AccountId]);
140
141    /// Triggers when the ledger has been detached and should no longer be
142    /// accessed.
143    fn detached_signal(&mut self);
144
145    // Following methods from Syncable_intf
146
147    fn depth(&self) -> u8;
148
149    fn num_accounts(&self) -> usize;
150
151    fn merkle_path_at_addr(&mut self, addr: Address) -> Vec<MerklePath>;
152
153    fn get_inner_hash_at_addr(&mut self, addr: Address) -> Result<Fp, String>;
154
155    fn set_inner_hash_at_addr(&mut self, addr: Address, hash: Fp) -> Result<(), ()>;
156
157    fn set_all_accounts_rooted_at(
158        &mut self,
159        addr: Address,
160        accounts: &[Box<Account>],
161    ) -> Result<(), ()>;
162
163    fn set_batch_accounts(&mut self, list: &[(Address, Box<Account>)]) {
164        Self::set_batch(self, list)
165    }
166
167    /// Get all of the accounts that are in a subtree of the underlying Merkle
168    /// tree rooted at `address`. The accounts are ordered by their addresses.
169    fn get_all_accounts_rooted_at(&self, addr: Address) -> Option<Vec<(Address, Box<Account>)>>;
170
171    fn make_space_for(&mut self, space: usize);
172
173    // Following are internal methods, they might be better in a private trait
174    fn get_account_hash(&mut self, account_index: AccountIndex) -> Option<Fp>;
175    /// Used on mask only, has no effect with other implementation
176    /// Required for `LedgerIntf` on masks
177    fn commit(&mut self);
178}
179
180#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
181#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema), schema(value_type = u64))]
182pub struct AccountIndex(pub u64);
183
184impl AccountIndex {
185    pub fn as_u64(&self) -> u64 {
186        self.0
187    }
188}
189
190impl PartialEq<u64> for AccountIndex {
191    fn eq(&self, other: &u64) -> bool {
192        self.0 == *other
193    }
194}
195
196impl PartialEq<usize> for AccountIndex {
197    fn eq(&self, other: &usize) -> bool {
198        let other: u64 = (*other).try_into().unwrap();
199        self.0 == other
200    }
201}
202
203impl From<usize> for AccountIndex {
204    fn from(n: usize) -> Self {
205        Self(n.try_into().unwrap())
206    }
207}
208
209#[derive(Clone, Debug)]
210pub enum GetOrCreated {
211    Added(Address),
212    Existed(Address),
213}
214
215impl GetOrCreated {
216    pub fn addr(self) -> Address {
217        match self {
218            GetOrCreated::Added(addr) => addr,
219            GetOrCreated::Existed(addr) => addr,
220        }
221    }
222}
223
224impl Deref for GetOrCreated {
225    type Target = Address;
226
227    fn deref(&self) -> &Self::Target {
228        match self {
229            GetOrCreated::Added(addr) => addr,
230            GetOrCreated::Existed(addr) => addr,
231        }
232    }
233}
234
235impl LedgerIntf for Mask {
236    type Location = Address;
237
238    fn get(&self, addr: &Address) -> Option<Box<Account>> {
239        BaseLedger::get(self, addr.clone())
240    }
241
242    fn location_of_account(&self, account_id: &AccountId) -> Option<Address> {
243        BaseLedger::location_of_account(self, account_id)
244    }
245
246    fn set(&mut self, addr: &Address, account: Box<Account>) {
247        BaseLedger::set(self, addr.clone(), account)
248    }
249
250    /// <https://github.com/MinaProtocol/mina/blob/05c2f73d0f6e4f1341286843814ce02dcb3919e0/src/lib/mina_ledger/ledger.ml#L311>
251    fn get_or_create(
252        &mut self,
253        account_id: &AccountId,
254    ) -> Result<(AccountState, Box<Account>, Address), String> {
255        let location = BaseLedger::get_or_create_account(
256            self,
257            account_id.clone(),
258            Account::initialize(account_id),
259        )
260        .map_err(|e| format!("{:?}", e))?;
261
262        let action = match location {
263            GetOrCreated::Added(_) => AccountState::Added,
264            GetOrCreated::Existed(_) => AccountState::Existed,
265        };
266
267        let addr = location.addr();
268        let account = BaseLedger::get(self, addr.clone()).ok_or_else(|| {
269            "get_or_create: Account was not found in the ledger after creation".to_string()
270        })?;
271
272        Ok((action, account, addr))
273    }
274
275    /// <https://github.com/MinaProtocol/mina/blob/05c2f73d0f6e4f1341286843814ce02dcb3919e0/src/lib/mina_ledger/ledger.ml#L304>
276    fn create_new_account(&mut self, account_id: AccountId, account: Account) -> Result<(), ()> {
277        match BaseLedger::get_or_create_account(self, account_id, account).unwrap() {
278            GetOrCreated::Added(_) => {}
279            GetOrCreated::Existed(_) => panic!(),
280        }
281        Ok(())
282    }
283
284    fn remove_accounts_exn(&mut self, account_ids: &[AccountId]) {
285        BaseLedger::remove_accounts(self, account_ids)
286    }
287
288    fn merkle_root(&mut self) -> Fp {
289        BaseLedger::merkle_root(self)
290    }
291
292    fn empty(depth: usize) -> Self {
293        let root = Mask::new_unattached(depth);
294        root.make_child()
295    }
296
297    /// Create a ledger as a mask on top of the existing ledger.
298    /// Warning: This skips mask registration, for use in transaction logic,
299    /// where we always have either 0 or 1 masks, and the mask is always either
300    /// committed or discarded. This function is deliberately not exposed in the
301    /// public API of this module.
302    /// This should *NOT* be used to create a ledger for other purposes.
303    fn create_masked(&self) -> Self {
304        let mut mask = Mask::new_unattached(self.depth() as usize);
305
306        if self.has_token_owners() {
307            mask.set_token_owners();
308        }
309
310        // We don't register the mask here. This is only used in transaction logic,
311        // where we don't want to unregister. Transaction logic is also
312        // synchronous, so we don't need to worry that our mask will be reparented.
313
314        mask.set_parent(self.clone(), None)
315    }
316
317    fn apply_mask(&mut self, mask: Self) {
318        // ignore `self` here:
319        // <https://github.com/MinaProtocol/mina/blob/f6756507ff7380a691516ce02a3cf7d9d32915ae/src/lib/mina_ledger/ledger.ml#L236-L246>
320        mask.commit()
321    }
322
323    fn account_locations(&self) -> Vec<Self::Location> {
324        let mut addrs: Vec<Address> = self
325            .accounts()
326            .into_iter()
327            .map(|account_id| BaseLedger::location_of_account(self, &account_id).unwrap())
328            .collect();
329
330        addrs.sort_by_key(Address::to_index);
331
332        addrs
333    }
334}