mina_tree/account/
legacy.rs

1use std::borrow::Cow;
2
3use ark_ff::Zero;
4use mina_hasher::{create_legacy, Fp, Hashable, Hasher, ROInput};
5use mina_signer::CompressedPubKey;
6use o1_utils::FieldHelpers;
7
8use crate::scan_state::currency::{Balance, Magnitude, Nonce};
9
10use super::common::*;
11
12#[derive(Clone, Debug, Hash, PartialEq, Eq)]
13pub struct TokenIdLegacy(pub u64);
14
15impl Default for TokenIdLegacy {
16    fn default() -> Self {
17        Self(1)
18    }
19}
20
21#[derive(Clone, Debug)]
22pub struct PermissionsLegacy<Controller> {
23    pub stake: bool,
24    pub edit_state: Controller,
25    pub send: Controller,
26    pub receive: Controller,
27    pub set_delegate: Controller,
28    pub set_permissions: Controller,
29    pub set_verification_key: Controller,
30}
31
32impl PermissionsLegacy<AuthRequired> {
33    pub fn user_default() -> Self {
34        use AuthRequired::*;
35
36        Self {
37            stake: true,
38            edit_state: Signature,
39            send: Signature,
40            receive: None,
41            set_delegate: Signature,
42            set_permissions: Signature,
43            set_verification_key: Signature,
44        }
45    }
46
47    pub fn empty() -> Self {
48        use AuthRequired::*;
49
50        Self {
51            stake: false,
52            edit_state: None,
53            send: None,
54            receive: None,
55            set_delegate: None,
56            set_permissions: None,
57            set_verification_key: None,
58        }
59    }
60}
61
62impl Default for PermissionsLegacy<AuthRequired> {
63    fn default() -> Self {
64        Self::user_default()
65    }
66}
67
68#[derive(Clone, Debug)]
69pub struct SnappAccount {
70    pub app_state: Vec<Fp>,
71    pub verification_key: Option<Fp>,
72}
73
74impl Default for SnappAccount {
75    fn default() -> Self {
76        Self {
77            app_state: vec![Fp::zero(); 8],
78            verification_key: None,
79        }
80    }
81}
82
83impl Hashable for SnappAccount {
84    type D = ();
85
86    fn to_roinput(&self) -> ROInput {
87        let mut roi = ROInput::new();
88
89        if let Some(vk) = self.verification_key.as_ref() {
90            roi = roi.append_field(*vk);
91        } else {
92            roi = roi.append_field(
93                // Value of `dummy_vk_hash`:
94                // <https://github.com/MinaProtocol/mina/blob/4f765c866b81fa6fed66be52707fd91fd915041d/src/lib/mina_base/snapp_account.ml#L116>
95                Fp::from_hex("77a430a03efafd14d72e1a3c45a1fdca8267fcce9a729a1d25128bb5dec69d3f")
96                    .unwrap(),
97            );
98        }
99
100        for field in &self.app_state {
101            roi = roi.append_field(*field);
102        }
103
104        roi
105    }
106
107    fn domain_string(_domain_param: Self::D) -> Option<String> {
108        Some("CodaSnappAccount****".to_string())
109    }
110}
111
112// <https://github.com/MinaProtocol/mina/blob/1765ba6bdfd7c454e5ae836c49979fa076de1bea/src/lib/mina_base/account.ml#L368>
113#[derive(Clone, Debug)]
114pub struct AccountLegacy {
115    pub public_key: CompressedPubKey,         // Public_key.Compressed.t
116    pub token_id: TokenIdLegacy,              // Token_id.t
117    pub token_permissions: TokenPermissions,  // Token_permissions.t
118    pub balance: Balance,                     // Balance.t
119    pub nonce: Nonce,                         // Nonce.t
120    pub receipt_chain_hash: ReceiptChainHash, // Receipt.Chain_hash.t
121    pub delegate: Option<CompressedPubKey>,   // Public_key.Compressed.t option
122    pub voting_for: VotingFor,                // State_hash.t
123    pub timing: Timing,                       // Timing.t
124    pub permissions: PermissionsLegacy<AuthRequired>, // Permissions.t
125    pub snap: Option<SnappAccount>,
126}
127
128pub fn get_legacy_hash_of<T: Hashable>(init_value: T::D, item: &T) -> Fp {
129    let mut hasher = create_legacy::<T>(init_value);
130    hasher.update(item);
131    hasher.digest()
132}
133
134impl Hashable for AccountLegacy {
135    type D = ();
136
137    fn to_roinput(&self) -> ROInput {
138        let mut roi = ROInput::new();
139
140        // Self::snapp
141        let snapp_accout = match self.snap.as_ref() {
142            Some(snapp) => Cow::Borrowed(snapp),
143            None => Cow::Owned(SnappAccount::default()),
144        };
145        let snapp_digest = get_legacy_hash_of((), snapp_accout.as_ref());
146
147        roi = roi.append_field(snapp_digest);
148
149        // Self::permissions
150        for auth in [
151            self.permissions.set_verification_key,
152            self.permissions.set_permissions,
153            self.permissions.set_delegate,
154            self.permissions.receive,
155            self.permissions.send,
156            self.permissions.edit_state,
157        ] {
158            for bit in auth.encode().to_bits() {
159                roi = roi.append_bool(bit);
160            }
161        }
162        roi = roi.append_bool(self.permissions.stake);
163
164        // Self::timing
165        match &self.timing {
166            Timing::Untimed => {
167                roi = roi.append_bool(false);
168                roi = roi.append_u64(0); // initial_minimum_balance
169                roi = roi.append_u32(0); // cliff_time
170                roi = roi.append_u64(0); // cliff_amount
171                roi = roi.append_u32(1); // vesting_period
172                roi = roi.append_u64(0); // vesting_increment
173            }
174            Timing::Timed {
175                initial_minimum_balance,
176                cliff_time,
177                cliff_amount,
178                vesting_period,
179                vesting_increment,
180            } => {
181                roi = roi.append_bool(true);
182                roi = roi.append_u64(initial_minimum_balance.as_u64());
183                roi = roi.append_u32(cliff_time.as_u32());
184                roi = roi.append_u64(cliff_amount.as_u64());
185                roi = roi.append_u32(vesting_period.as_u32());
186                roi = roi.append_u64(vesting_increment.as_u64());
187            }
188        }
189
190        // Self::voting_for
191        roi = roi.append_field(self.voting_for.0);
192
193        // Self::delegate
194        match self.delegate.as_ref() {
195            Some(delegate) => {
196                roi = roi.append_field(delegate.x);
197                roi = roi.append_bool(delegate.is_odd);
198            }
199            None => {
200                // Public_key.Compressed.empty
201                roi = roi.append_field(Fp::zero());
202                roi = roi.append_bool(false);
203            }
204        }
205
206        // Self::receipt_chain_hash
207        roi = roi.append_field(self.receipt_chain_hash.0);
208
209        // Self::nonce
210        roi = roi.append_u32(self.nonce.as_u32());
211
212        // Self::balance
213        roi = roi.append_u64(self.balance.as_u64());
214
215        // Self::token_permissions
216        match self.token_permissions {
217            TokenPermissions::TokenOwned {
218                disable_new_accounts,
219            } => {
220                roi = roi.append_bool(true);
221                roi = roi.append_bool(disable_new_accounts);
222            }
223            TokenPermissions::NotOwned { account_disabled } => {
224                roi = roi.append_bool(false);
225                roi = roi.append_bool(account_disabled);
226            }
227        }
228
229        // Self::token_id
230        roi = roi.append_u64(self.token_id.0);
231
232        // Self::public_key
233        roi = roi.append_field(self.public_key.x);
234        roi = roi.append_bool(self.public_key.is_odd);
235
236        roi
237    }
238
239    fn domain_string(_: ()) -> Option<String> {
240        Some("CodaAccount*********".to_string())
241    }
242}
243
244impl AccountLegacy {
245    pub fn create() -> Self {
246        let pubkey = CompressedPubKey::from_address(
247            "B62qnzbXmRNo9q32n4SNu2mpB8e7FYYLH8NmaX6oFCBYjjQ8SbD7uzV",
248        )
249        .unwrap();
250
251        Self {
252            public_key: pubkey.clone(),
253            token_id: TokenIdLegacy::default(),
254            token_permissions: TokenPermissions::NotOwned {
255                account_disabled: false,
256            },
257            balance: Balance::from_u64(10101),
258            nonce: Nonce::from_u32(62772),
259            receipt_chain_hash: ReceiptChainHash::default(),
260            delegate: Some(pubkey),
261            voting_for: VotingFor::default(),
262            timing: Timing::Untimed,
263            permissions: PermissionsLegacy::user_default(),
264            snap: None,
265        }
266    }
267
268    pub fn empty() -> Self {
269        Self {
270            public_key: CompressedPubKey {
271                x: Fp::zero(),
272                is_odd: false,
273            },
274            token_id: TokenIdLegacy::default(),
275            token_permissions: TokenPermissions::default(),
276            balance: Balance::zero(),
277            nonce: Nonce::zero(),
278            receipt_chain_hash: ReceiptChainHash::empty_legacy(),
279            delegate: None,
280            voting_for: VotingFor::dummy(),
281            timing: Timing::Untimed,
282            permissions: PermissionsLegacy::user_default(),
283            snap: None,
284        }
285    }
286}