1use std::str::FromStr;
2
3use ark_ff::{UniformRand, Zero};
4use mina_curves::pasta::Fp;
5use o1_utils::{field_helpers::FieldHelpersError, FieldHelpers};
6use serde::{Deserialize, Serialize};
7
8use crate::{
9 proofs::{
10 field::{Boolean, FieldWitness, ToBoolean},
11 numbers::{
12 currency::{CheckedAmount, CheckedBalance},
13 nat::{CheckedSlot, CheckedSlotSpan},
14 },
15 to_field_elements::ToFieldElements,
16 },
17 scan_state::currency::{Amount, Balance, Magnitude, Slot, SlotSpan},
18 ControlTag, ToInputs,
19};
20
21#[derive(Clone, Debug, Default, PartialEq, Eq)]
22pub struct VotingFor(pub Fp);
23
24impl VotingFor {
25 pub fn dummy() -> Self {
26 Self(Fp::zero())
27 }
28
29 pub fn parse_str(s: &str) -> Result<Self, FieldHelpersError> {
30 let b58check_hash = mina_p2p_messages::v2::StateHash::from_str(s).unwrap();
31 Ok(Self(
32 b58check_hash
33 .into_inner()
34 .0
35 .try_into()
36 .map_err(|_| FieldHelpersError::FromBigToField)?,
37 ))
38 }
39
40 pub fn to_base58check(&self) -> String {
41 let state_hash = mina_p2p_messages::v2::StateHash::from_fp(self.0);
42 state_hash.to_string()
43 }
44
45 pub fn to_base58check_graphql(&self) -> String {
46 let receipt_chain_hash = ReceiptChainHash(self.0);
48 let receipt_chain_hash = mina_p2p_messages::v2::ReceiptChainHash::from(receipt_chain_hash);
49 receipt_chain_hash.to_string()
50 }
51}
52
53#[test]
54fn test_voting_for_b58decode() {
55 let source = "3NK2tkzqqK5spR2sZ7tujjqPksL45M3UUrcA4WhCkeiPtnugyE2x";
56 let voting_for = VotingFor::parse_str(source).unwrap();
57 assert_eq!(&voting_for.to_base58check(), source);
58}
59
60impl ToFieldElements<Fp> for VotingFor {
61 fn to_field_elements(&self, fields: &mut Vec<Fp>) {
62 let Self(f) = self;
63 f.to_field_elements(fields)
64 }
65}
66
67impl ToInputs for VotingFor {
68 fn to_inputs(&self, inputs: &mut poseidon::hash::Inputs) {
69 inputs.append_field(self.0);
70 }
71}
72
73#[derive(Clone, Debug, PartialEq, Eq)]
74pub struct ReceiptChainHash(pub Fp);
75
76impl ToInputs for ReceiptChainHash {
77 fn to_inputs(&self, inputs: &mut poseidon::hash::Inputs) {
78 inputs.append_field(self.0);
79 }
80}
81
82impl ReceiptChainHash {
83 pub fn empty_legacy() -> Self {
84 Self::from_hex("0b143c0645497a5987a7b88f66340e03db943f0a0df48b69a3a82921ce97b10a").unwrap()
86 }
87
88 pub fn empty() -> Self {
89 Self::empty_legacy()
90 }
92
93 pub fn from_hex(s: &str) -> Result<Self, FieldHelpersError> {
94 Fp::from_hex(s).map(Self)
95 }
96
97 pub fn parse_str(s: &str) -> Result<Self, FieldHelpersError> {
98 let b58check_hash = mina_p2p_messages::v2::PendingCoinbaseHash::from_str(s).unwrap();
99 Ok(Self(
100 b58check_hash
101 .into_inner()
102 .0
103 .0
104 .try_into()
105 .map_err(|_| FieldHelpersError::FromBigToField)?,
106 ))
107 }
108
109 pub fn gen() -> Self {
112 Self(Fp::rand(&mut rand::thread_rng()))
113 }
114}
115
116#[test]
117fn test_receipt_chain_b58decode() {
118 let source = "2mzbV7WevxLuchs2dAMY4vQBS6XttnCUF8Hvks4XNBQ5qiSGGBQe";
119 ReceiptChainHash::parse_str(source).unwrap();
120
121 let source = "2n2K1aziimdYu5QCf8mU4gducZCB5u5s78sGnp56zT2tig4ugVHD";
122 ReceiptChainHash::parse_str(source).unwrap();
123}
124
125impl Default for ReceiptChainHash {
126 fn default() -> Self {
127 Self::empty_legacy()
128 }
129}
130
131#[derive(Clone, Debug, PartialEq, Eq)]
145pub enum Timing {
146 Untimed,
147 Timed {
148 initial_minimum_balance: Balance,
149 cliff_time: Slot,
150 cliff_amount: Amount,
151 vesting_period: SlotSpan,
152 vesting_increment: Amount,
153 },
154}
155
156impl Timing {
157 pub fn is_timed(&self) -> bool {
158 match self {
159 Timing::Untimed => false,
160 Timing::Timed { .. } => true,
161 }
162 }
163
164 pub fn to_record(&self) -> TimingAsRecord {
165 match self.clone() {
166 Timing::Untimed => TimingAsRecord {
167 is_timed: false,
168 initial_minimum_balance: Balance::zero(),
169 cliff_time: Slot::zero(),
170 cliff_amount: Amount::zero(),
171 vesting_period: SlotSpan::from_u32(1),
172 vesting_increment: Amount::zero(),
173 },
174 Timing::Timed {
175 initial_minimum_balance,
176 cliff_time,
177 cliff_amount,
178 vesting_period,
179 vesting_increment,
180 } => TimingAsRecord {
181 is_timed: true,
182 initial_minimum_balance,
183 cliff_time,
184 cliff_amount,
185 vesting_period,
186 vesting_increment,
187 },
188 }
189 }
190
191 pub fn to_record_checked<F: FieldWitness>(&self) -> TimingAsRecordChecked<F> {
192 let TimingAsRecord {
193 is_timed,
194 initial_minimum_balance,
195 cliff_time,
196 cliff_amount,
197 vesting_period,
198 vesting_increment,
199 } = self.to_record();
200
201 TimingAsRecordChecked {
202 is_timed: is_timed.to_boolean(),
203 initial_minimum_balance: initial_minimum_balance.to_checked(),
204 cliff_time: cliff_time.to_checked(),
205 cliff_amount: cliff_amount.to_checked(),
206 vesting_period: vesting_period.to_checked(),
207 vesting_increment: vesting_increment.to_checked(),
208 }
209 }
210}
211
212pub struct TimingAsRecord {
213 pub is_timed: bool,
214 pub initial_minimum_balance: Balance,
215 pub cliff_time: Slot,
216 pub cliff_amount: Amount,
217 pub vesting_period: SlotSpan,
218 pub vesting_increment: Amount,
219}
220
221pub struct TimingAsRecordChecked<F: FieldWitness> {
222 pub is_timed: Boolean,
223 pub initial_minimum_balance: CheckedBalance<F>,
224 pub cliff_time: CheckedSlot<F>,
225 pub cliff_amount: CheckedAmount<F>,
226 pub vesting_period: CheckedSlotSpan<F>,
227 pub vesting_increment: CheckedAmount<F>,
228}
229
230#[derive(Clone, Debug, PartialEq, Eq)]
235pub enum TokenPermissions {
236 TokenOwned { disable_new_accounts: bool },
237 NotOwned { account_disabled: bool },
238}
239
240impl Default for TokenPermissions {
241 fn default() -> Self {
242 Self::NotOwned {
243 account_disabled: false,
244 }
245 }
246}
247
248#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, strum_macros::Display)]
250#[serde(rename_all = "lowercase")]
251pub enum AuthRequired {
252 None,
253 Either,
254 Proof,
255 Signature,
256 Impossible,
257 Both, }
259
260impl Default for AuthRequired {
261 fn default() -> Self {
262 Self::None
263 }
264}
265
266impl From<ControlTag> for AuthRequired {
267 fn from(value: ControlTag) -> Self {
269 match value {
270 ControlTag::Proof => Self::Proof,
271 ControlTag::Signature => Self::Signature,
272 ControlTag::NoneGiven => Self::None,
273 }
274 }
275}
276
277#[derive(Copy, Clone, Debug)]
278pub struct AuthRequiredEncoded<Bool> {
279 pub constant: Bool,
280 pub signature_necessary: Bool,
281 pub signature_sufficient: Bool,
282}
283
284impl AuthRequired {
285 pub fn encode(self) -> AuthRequiredEncoded<bool> {
286 let (constant, signature_necessary, signature_sufficient) = match self {
287 AuthRequired::None => (true, false, true),
288 AuthRequired::Either => (false, false, true),
289 AuthRequired::Proof => (false, false, false),
290 AuthRequired::Signature => (false, true, true),
291 AuthRequired::Impossible => (true, true, false),
292 AuthRequired::Both => (false, true, false),
293 };
294
295 AuthRequiredEncoded {
296 constant,
297 signature_necessary,
298 signature_sufficient,
299 }
300 }
301
302 pub fn gen_for_proof_authorization(rng: &mut rand::rngs::ThreadRng) -> Self {
306 use rand::seq::SliceRandom;
307
308 [Self::None, Self::Either, Self::Proof]
309 .choose(rng)
310 .cloned()
311 .unwrap()
312 }
313
314 pub fn gen_for_signature_authorization(rng: &mut rand::rngs::ThreadRng) -> Self {
318 use rand::seq::SliceRandom;
319
320 [Self::None, Self::Either, Self::Signature]
321 .choose(rng)
322 .cloned()
323 .unwrap()
324 }
325
326 pub fn gen_for_none_given_authorization(_rng: &mut rand::rngs::ThreadRng) -> Self {
330 Self::None
331 }
332
333 pub fn verification_key_perm_fallback_to_signature_with_older_version(&self) -> Self {
334 use AuthRequired::*;
335
336 match self {
337 Impossible | Proof => Signature,
338 x => *x,
339 }
340 }
341}
342
343impl AuthRequiredEncoded<bool> {
344 pub fn decode(self) -> AuthRequired {
345 match (
346 self.constant,
347 self.signature_necessary,
348 self.signature_sufficient,
349 ) {
350 (true, _, false) => AuthRequired::Impossible,
351 (true, _, true) => AuthRequired::None,
352 (false, false, false) => AuthRequired::Proof,
353 (false, true, true) => AuthRequired::Signature,
354 (false, false, true) => AuthRequired::Either,
355 (false, true, false) => AuthRequired::Both,
356 }
357 }
358
359 pub fn to_bits(self) -> [bool; 3] {
360 [
361 self.constant,
362 self.signature_necessary,
363 self.signature_sufficient,
364 ]
365 }
366}