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