1pub mod conv;
2
3use ark_ff::BigInteger256;
4use binprot::{BinProtRead, BinProtWrite};
5use binprot_derive::{BinProtRead, BinProtWrite};
6use derive_more::Deref;
7use malloc_size_of_derive::MallocSizeOf;
8use poseidon::hash::params::NO_INPUT_COINBASE_STACK;
9use serde::{de::Visitor, ser::SerializeTuple, Deserialize, Serialize, Serializer};
10use time::OffsetDateTime;
11
12use crate::{
13 b58::{self, Base58CheckOfBinProt, Base58CheckOfBytes},
14 b58version::USER_COMMAND_MEMO,
15 bigint::BigInt,
16 list::List,
17 number::Number,
18 string::ByteString,
19 versioned::Versioned,
20};
21
22use super::*;
23
24pub type TransactionSnarkScanStateStableV2TreesABase = (
25 ParallelScanWeightStableV1,
26 TransactionSnarkScanStateStableV2ScanStateTreesABaseT1,
27);
28
29pub type TransactionSnarkScanStateStableV2TreesAMerge = (
30 (ParallelScanWeightStableV1, ParallelScanWeightStableV1),
31 TransactionSnarkScanStateStableV2ScanStateTreesAMergeT1,
32);
33
34#[derive(Clone, Debug, PartialEq, BinProtRead, BinProtWrite, Deref, MallocSizeOf)]
47pub struct MinaBaseSignedCommandMemoStableV1(pub crate::string::CharString);
48
49impl MinaBaseSignedCommandMemoStableV1 {
50 pub fn to_base58check(&self) -> String {
51 b58::encode(self.0.as_ref(), USER_COMMAND_MEMO)
52 }
53
54 pub fn from_base58check(s: &str) -> Self {
55 let decoded = b58::decode(s, USER_COMMAND_MEMO).unwrap();
56 MinaBaseSignedCommandMemoStableV1(decoded[1..].into())
57 }
58}
59
60impl Serialize for MinaBaseSignedCommandMemoStableV1 {
61 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
62 where
63 S: serde::ser::Serializer,
64 {
65 if serializer.is_human_readable() {
66 let base58check = b58::encode(self.0.as_ref(), USER_COMMAND_MEMO);
67 base58check.serialize(serializer)
68 } else {
69 self.0.serialize(serializer)
70 }
71 }
72}
73
74impl<'de> Deserialize<'de> for MinaBaseSignedCommandMemoStableV1 {
75 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
76 where
77 D: serde::de::Deserializer<'de>,
78 {
79 if deserializer.is_human_readable() {
80 let base58check = String::deserialize(deserializer)?;
81 let decoded = b58::decode(&base58check, USER_COMMAND_MEMO)
82 .map_err(|err| serde::de::Error::custom(format!("Base58 decode error: {}", err)))?;
83 Ok(MinaBaseSignedCommandMemoStableV1(decoded[1..].into()))
84 } else {
85 let char_string = crate::string::CharString::deserialize(deserializer)?;
86 Ok(MinaBaseSignedCommandMemoStableV1(char_string))
87 }
88 }
89}
90
91#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
96pub enum TransactionSnarkScanStateStableV2ScanStateTreesA {
97 Leaf(Vec<TransactionSnarkScanStateStableV2TreesABase>),
98 Node {
99 depth: crate::number::Int32,
100 value: Vec<TransactionSnarkScanStateStableV2TreesAMerge>,
101 sub_tree: Box<TransactionSnarkScanStateStableV2ScanStateTreesA>,
102 },
103}
104
105#[derive(BinProtRead, BinProtWrite)]
106enum _Tree {
107 Leaf,
108 Node,
109}
110
111impl BinProtRead for TransactionSnarkScanStateStableV2ScanStateTreesA {
112 fn binprot_read<R: std::io::Read + ?Sized>(r: &mut R) -> Result<Self, binprot::Error>
113 where
114 Self: Sized,
115 {
116 let mut depth: i32 = 0;
117 let mut values: Vec<Vec<TransactionSnarkScanStateStableV2TreesAMerge>> = Vec::new();
118 loop {
119 match _Tree::binprot_read(r)? {
120 _Tree::Leaf => {
121 let len = 1 << depth;
122 let mut data = Vec::with_capacity(len);
123 for _ in 0..len {
124 data.push(TransactionSnarkScanStateStableV2TreesABase::binprot_read(
125 r,
126 )?)
127 }
128 let mut tree = Self::Leaf(data);
129 while let Some(value) = values.pop() {
130 depth = depth - 1;
131 tree = Self::Node {
132 depth: depth.into(),
133 value,
134 sub_tree: Box::new(tree),
135 }
136 }
137 return Ok(tree);
138 }
139 _Tree::Node => {
140 let _depth = i32::binprot_read(r)?;
141 if _depth != depth {
142 return Err(binprot::Error::CustomError(
143 format!("Incorrect tree depth, expected `{depth}`, got `{_depth}`")
144 .into(),
145 ));
146 }
147 let len = 1 << depth;
148 let mut value = Vec::with_capacity(len);
149 for _ in 0..len {
150 value.push(TransactionSnarkScanStateStableV2TreesAMerge::binprot_read(
151 r,
152 )?)
153 }
154 values.push(value);
155 depth += 1;
156 }
157 }
158 }
159 }
160}
161
162impl BinProtWrite for TransactionSnarkScanStateStableV2ScanStateTreesA {
163 fn binprot_write<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
164 let mut curr = self;
165 let mut curr_depth = 0;
166 loop {
167 match curr {
168 Self::Leaf(leaf) => {
169 let len = 1 << curr_depth;
170 if leaf.len() != len {
171 return Err(std::io::Error::new(
172 std::io::ErrorKind::InvalidInput,
173 format!(
174 "Invalid leaf data lenght, expecting {len}, got {}",
175 leaf.len()
176 ),
177 ));
178 }
179 _Tree::Leaf.binprot_write(w)?;
180 leaf.iter().try_for_each(|b| b.binprot_write(w))?;
181 return Ok(());
182 }
183 Self::Node {
184 depth,
185 value,
186 sub_tree,
187 } => {
188 if &depth.0 != &curr_depth {
189 return Err(std::io::Error::new(
190 std::io::ErrorKind::InvalidInput,
191 format!(
192 "Invalid depth, expecting {curr_depth}, got {depth}",
193 depth = depth.0
194 ),
195 ));
196 }
197 if value.len() != (1 << curr_depth) {
198 return Err(std::io::Error::new(
199 std::io::ErrorKind::InvalidInput,
200 format!(
201 "Invalid node data lenght, expecting {}, got {}",
202 1 << curr_depth,
203 value.len()
204 ),
205 ));
206 }
207 _Tree::Node.binprot_write(w)?;
208 depth.binprot_write(w)?;
209 value.iter().try_for_each(|b| b.binprot_write(w))?;
210 curr = sub_tree;
211 curr_depth += 1;
212 }
213 }
214 }
215 }
216}
217
218impl rsexp::OfSexp for PicklesBaseProofsVerifiedStableV1 {
222 fn of_sexp(s: &rsexp::Sexp) -> Result<Self, rsexp::IntoSexpError>
223 where
224 Self: Sized,
225 {
226 match s.extract_enum("PicklesBaseProofsVerifiedStableV1")? {
227 (b"N0", _) => Ok(PicklesBaseProofsVerifiedStableV1::N0),
228 (b"N1", _) => Ok(PicklesBaseProofsVerifiedStableV1::N1),
229 (b"N2", _) => Ok(PicklesBaseProofsVerifiedStableV1::N2),
230 (ctor, _) => Err(rsexp::IntoSexpError::UnknownConstructorForEnum {
231 type_: "PicklesBaseProofsVerifiedStableV1",
232 constructor: String::from_utf8_lossy(ctor).to_string(),
233 }),
234 }
235 }
236}
237
238impl rsexp::OfSexp for LimbVectorConstantHex64StableV1 {
239 fn of_sexp(s: &rsexp::Sexp) -> Result<Self, rsexp::IntoSexpError>
240 where
241 Self: Sized,
242 {
243 let bytes = s.extract_atom("LimbVectorConstantHex64StableV1")?;
244 let hex_str = std::str::from_utf8(bytes).map_err(|_| {
245 rsexp::IntoSexpError::StringConversionError {
246 err: format!("Expected 16 bytes hex string, got {bytes:?}"),
247 }
248 })?;
249 if hex_str.len() != 16 {
250 return Err(rsexp::IntoSexpError::StringConversionError {
251 err: format!("Expected 16 bytes hex string, got {hex_str:?}"),
252 });
253 }
254 let n = u64::from_str_radix(hex_str, 16).map_err(|_| {
255 rsexp::IntoSexpError::StringConversionError {
256 err: format!("Expected 16 bytes hex string, got {hex_str:?}"),
257 }
258 })?;
259
260 Ok(Self(n.into()))
261 }
262}
263
264impl rsexp::SexpOf for LimbVectorConstantHex64StableV1 {
265 fn sexp_of(&self) -> rsexp::Sexp {
266 let value: u64 = self.0.as_u64();
267 let hex_str = format!("{:016x}", value);
268
269 rsexp::Sexp::Atom(format!("0x{}", hex_str).into_bytes())
270 }
271}
272
273impl rsexp::OfSexp for CompositionTypesBranchDataDomainLog2StableV1 {
274 fn of_sexp(s: &rsexp::Sexp) -> Result<Self, rsexp::IntoSexpError>
275 where
276 Self: Sized,
277 {
278 match s.extract_atom("CompositionTypesBranchDataDomainLog2StableV1")? {
279 [ch] => Ok(Self((*ch).into())),
280 bytes => Err(rsexp::IntoSexpError::StringConversionError {
281 err: format!("Expected single byte string, got {bytes:?}"),
282 }),
283 }
284 }
285}
286
287impl rsexp::SexpOf for CompositionTypesBranchDataDomainLog2StableV1 {
288 fn sexp_of(&self) -> rsexp::Sexp {
289 rsexp::Sexp::Atom(vec![self.0.as_u8()])
290 }
291}
292
293impl rsexp::OfSexp for CompositionTypesDigestConstantStableV1 {
294 fn of_sexp(s: &rsexp::Sexp) -> std::result::Result<Self, rsexp::IntoSexpError> {
295 Ok(Self(crate::pseq::PaddedSeq::<
296 LimbVectorConstantHex64StableV1,
297 4,
298 >::of_sexp(s)?))
299 }
300}
301
302impl rsexp::SexpOf for CompositionTypesDigestConstantStableV1 {
303 fn sexp_of(&self) -> rsexp::Sexp {
304 self.0.sexp_of()
305 }
306}
307
308impl rsexp::OfSexp for PicklesReducedMessagesForNextProofOverSameFieldWrapChallengesVectorStableV2 {
309 fn of_sexp(s: &rsexp::Sexp) -> std::result::Result<Self, rsexp::IntoSexpError> {
310 Ok(Self(crate::pseq::PaddedSeq::<
311 PicklesReducedMessagesForNextProofOverSameFieldWrapChallengesVectorStableV2A,
312 15,
313 >::of_sexp(s)?))
314 }
315}
316
317impl rsexp::SexpOf for PicklesReducedMessagesForNextProofOverSameFieldWrapChallengesVectorStableV2 {
318 fn sexp_of(&self) -> rsexp::Sexp {
319 self.0.sexp_of()
320 }
321}
322
323impl rsexp::OfSexp for TransactionSnarkProofStableV2 {
324 fn of_sexp(s: &rsexp::Sexp) -> std::result::Result<Self, rsexp::IntoSexpError> {
325 Ok(Self(PicklesProofProofsVerified2ReprStableV2::of_sexp(s)?))
326 }
327}
328
329impl rsexp::SexpOf for TransactionSnarkProofStableV2 {
330 fn sexp_of(&self) -> rsexp::Sexp {
331 self.0.sexp_of()
332 }
333}
334
335impl serde::Serialize for TransactionSnarkProofStableV2 {
336 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
337 where
338 S: serde::Serializer,
339 {
340 if serializer.is_human_readable() {
341 use base64::{engine::general_purpose::URL_SAFE, Engine as _};
342 use rsexp::SexpOf;
343
344 let sexp = self.sexp_of();
345 let sexp_bytes = sexp.to_bytes();
346 let base64_data = URL_SAFE.encode(&sexp_bytes);
347
348 base64_data.serialize(serializer)
349 } else {
350 serializer.serialize_newtype_struct("TransactionSnarkProofStableV2", &self.0)
351 }
352 }
353}
354
355impl<'de> Deserialize<'de> for TransactionSnarkProofStableV2 {
356 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
357 where
358 D: serde::de::Deserializer<'de>,
359 {
360 if deserializer.is_human_readable() {
361 use base64::{engine::general_purpose::URL_SAFE, Engine as _};
362 use rsexp::OfSexp;
363 let base64_data = String::deserialize(deserializer)?;
364 let sexp_data = URL_SAFE
365 .decode(&base64_data)
366 .map_err(serde::de::Error::custom)?;
367 let sexp = rsexp::from_slice(&sexp_data).map_err(|err| {
368 serde::de::Error::custom(format!("S-exp parsing failure: {err:?}"))
369 })?;
370 let proof = Self::of_sexp(&sexp).map_err(serde::de::Error::custom)?;
371 Ok(proof)
372 } else {
373 struct TransactionSnarkProofStableV2Visitor;
374
375 impl<'de> serde::de::Visitor<'de> for TransactionSnarkProofStableV2Visitor {
376 type Value = TransactionSnarkProofStableV2;
377
378 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
379 formatter.write_str("a valid TransactionSnarkProofStableV2")
380 }
381
382 fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
383 where
384 D: serde::de::Deserializer<'de>,
385 {
386 let inner_value =
387 PicklesProofProofsVerified2ReprStableV2::deserialize(deserializer)?;
388 Ok(TransactionSnarkProofStableV2(inner_value))
389 }
390 }
391
392 deserializer.deserialize_newtype_struct(
393 "TransactionSnarkProofStableV2",
394 TransactionSnarkProofStableV2Visitor,
395 )
396 }
397 }
398}
399
400impl<'de> Deserialize<'de> for PicklesProofProofsVerifiedMaxStableV2 {
401 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
402 where
403 D: serde::de::Deserializer<'de>,
404 {
405 if deserializer.is_human_readable() {
406 use base64::{engine::general_purpose::URL_SAFE, Engine as _};
407 use rsexp::OfSexp;
408 let base64_data = String::deserialize(deserializer)?;
409 let sexp_data = URL_SAFE
410 .decode(&base64_data)
411 .map_err(serde::de::Error::custom)?;
412 let sexp = rsexp::from_slice(&sexp_data).map_err(|err| {
413 serde::de::Error::custom(format!("S-exp parsing failure: {err:?}"))
414 })?;
415 let proof = Self::of_sexp(&sexp).map_err(serde::de::Error::custom)?;
416 Ok(proof)
417 } else {
418 #[derive(Deserialize)]
419 struct Inner {
420 statement: PicklesProofProofsVerified2ReprStableV2Statement,
421 prev_evals: PicklesProofProofsVerified2ReprStableV2PrevEvals,
422 proof: PicklesWrapWireProofStableV1,
423 }
424
425 let inner = Inner::deserialize(deserializer)?;
426 Ok(PicklesProofProofsVerifiedMaxStableV2 {
427 statement: inner.statement,
428 prev_evals: inner.prev_evals,
429 proof: inner.proof,
430 })
431 }
432 }
433}
434
435impl serde::Serialize for PicklesProofProofsVerifiedMaxStableV2 {
436 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
437 where
438 S: serde::Serializer,
439 {
440 if serializer.is_human_readable() {
441 use base64::{engine::general_purpose::URL_SAFE, Engine as _};
442 use rsexp::SexpOf as _;
443
444 let sexp = self.sexp_of();
445 let sexp_bytes = sexp.to_bytes();
446 let base64_data = URL_SAFE.encode(&sexp_bytes);
447
448 base64_data.serialize(serializer)
449 } else {
450 use serde::ser::SerializeStruct;
451 let mut state =
452 serializer.serialize_struct("PicklesProofProofsVerifiedMaxStableV2", 3)?;
453 state.serialize_field("statement", &self.statement)?;
454 state.serialize_field("prev_evals", &self.prev_evals)?;
455 state.serialize_field("proof", &self.proof)?;
456 state.end()
457 }
458 }
459}
460
461macro_rules! base58check_of_binprot {
462 ($name:ident, versioned($ty:ty, $version:expr), $version_byte:ident) => {
463 impl From<Versioned<$ty, $version>> for $ty {
464 fn from(source: Versioned<$ty, $version>) -> Self {
465 source.into_inner()
466 }
467 }
468
469 pub type $name = Base58CheckOfBinProt<
470 $ty,
471 Versioned<$ty, $version>,
472 { $crate::b58version::$version_byte },
473 >;
474 };
475 ($name:ident, versioned $ty:ty, $version_byte:ident) => {
476 base58check_of_binprot!($name, versioned($ty, 1), $version_byte);
477 };
478 ($name:ident, $ty:ty, $version_byte:ident) => {
479 pub type $name = Base58CheckOfBinProt<$ty, $ty, { $crate::b58version::$version_byte }>;
480 };
481}
482
483macro_rules! base58check_of_bytes {
484 ($name:ident, $ty:ty, $version_byte:ident) => {
485 pub type $name = Base58CheckOfBytes<$ty, { $crate::b58version::$version_byte }>;
486 };
487}
488
489base58check_of_binprot!(LedgerHash, versioned MinaBaseLedgerHash0StableV1, LEDGER_HASH);
490base58check_of_bytes!(
491 StagedLedgerHashAuxHash,
492 crate::string::ByteString,
493 STAGED_LEDGER_HASH_AUX_HASH
494);
495base58check_of_binprot!(EpochSeed, versioned MinaBaseEpochSeedStableV1, EPOCH_SEED);
496base58check_of_bytes!(
497 StagedLedgerHashPendingCoinbaseAux,
498 crate::string::ByteString,
499 STAGED_LEDGER_HASH_PENDING_COINBASE_AUX
500);
501base58check_of_binprot!(StateHash, versioned DataHashLibStateHashStableV1, STATE_HASH);
502base58check_of_binprot!(StateBodyHash, versioned MinaBaseStateBodyHashStableV1, STATE_BODY_HASH);
503base58check_of_binprot!(
504 PendingCoinbaseHash,
505 versioned MinaBasePendingCoinbaseHashVersionedStableV1,
506 RECEIPT_CHAIN_HASH
507);
508base58check_of_binprot!(
509 ReceiptChainHash,
510 versioned MinaBaseReceiptChainHashStableV1,
511 RECEIPT_CHAIN_HASH
512);
513base58check_of_binprot!(
514 TokenIdKeyHash,
515 MinaBaseAccountIdDigestStableV1,
516 TOKEN_ID_KEY
517);
518base58check_of_binprot!(
519 CoinbaseStackData,
520 versioned MinaBasePendingCoinbaseCoinbaseStackStableV1,
521 COINBASE_STACK_DATA
522);
523base58check_of_binprot!(
524 CoinbaseStackHash,
525 versioned MinaBasePendingCoinbaseStackHashStableV1,
526 COINBASE_STACK_HASH
527);
528base58check_of_binprot!(
529 Signature,
530 versioned MinaBaseSignatureStableV1,
531 SIGNATURE
532);
533
534impl StateHash {
535 pub fn zero() -> Self {
536 DataHashLibStateHashStableV1(BigInt::zero()).into()
537 }
538}
539
540impl EpochSeed {
541 pub fn zero() -> Self {
542 MinaBaseEpochSeedStableV1(BigInt::zero()).into()
543 }
544}
545
546impl CoinbaseStackData {
547 pub fn empty() -> Self {
548 let empty = poseidon::hash::hash_noinputs(&NO_INPUT_COINBASE_STACK);
551 MinaBasePendingCoinbaseCoinbaseStackStableV1(empty.into()).into()
552 }
553}
554
555impl CoinbaseStackHash {
556 pub fn zero() -> Self {
557 MinaBasePendingCoinbaseStackHashStableV1(BigInt::zero()).into()
558 }
559}
560
561impl StagedLedgerHashAuxHash {
562 pub fn zero() -> Self {
563 crate::string::ByteString::from(vec![0; 32]).into()
564 }
565}
566
567impl StagedLedgerHashPendingCoinbaseAux {
568 pub fn zero() -> Self {
569 crate::string::ByteString::from(vec![0; 32]).into()
570 }
571}
572
573impl ConsensusVrfOutputTruncatedStableV1 {
574 pub fn zero() -> Self {
575 Self(crate::string::ByteString::from(vec![0; 32]))
576 }
577}
578
579impl MinaBaseStagedLedgerHashNonSnarkStableV1 {
580 pub fn zero(genesis_ledger_hash: LedgerHash) -> Self {
581 Self {
582 ledger_hash: genesis_ledger_hash,
583 aux_hash: StagedLedgerHashAuxHash::zero(),
584 pending_coinbase_aux: StagedLedgerHashPendingCoinbaseAux::zero(),
585 }
586 }
587}
588
589impl From<mina_curves::pasta::Fp> for LedgerHash {
590 fn from(value: mina_curves::pasta::Fp) -> Self {
591 MinaBaseLedgerHash0StableV1(value.into()).into()
592 }
593}
594
595impl From<&mina_curves::pasta::Fp> for LedgerHash {
596 fn from(value: &mina_curves::pasta::Fp) -> Self {
597 MinaBaseLedgerHash0StableV1(value.into()).into()
598 }
599}
600
601impl MinaBaseStagedLedgerHashStableV1 {
602 pub fn zero(
603 genesis_ledger_hash: LedgerHash,
604 empty_pending_coinbase_hash: PendingCoinbaseHash,
605 ) -> Self {
606 Self {
607 non_snark: MinaBaseStagedLedgerHashNonSnarkStableV1::zero(genesis_ledger_hash),
608 pending_coinbase_hash: empty_pending_coinbase_hash,
609 }
610 }
611}
612
613impl MinaBasePendingCoinbaseUpdateStableV1 {
614 pub fn zero() -> Self {
615 Self {
616 action: MinaBasePendingCoinbaseUpdateActionStableV1::UpdateNone,
617 coinbase_amount: CurrencyAmountStableV1(0u64.into()),
618 }
619 }
620}
621
622impl MinaBasePendingCoinbaseStackVersionedStableV1 {
623 pub fn empty() -> Self {
624 Self {
625 data: CoinbaseStackData::empty(),
626 state: MinaBasePendingCoinbaseStateStackStableV1 {
627 init: CoinbaseStackHash::zero(),
628 curr: CoinbaseStackHash::zero(),
629 },
630 }
631 }
632}
633
634impl ConsensusProofOfStakeDataEpochDataStakingValueVersionedValueStableV1 {
635 pub fn zero(
636 ledger_hash: LedgerHash,
637 total_currency: CurrencyAmountStableV1,
638 seed: EpochSeed,
639 ) -> Self {
640 Self {
641 ledger: MinaBaseEpochLedgerValueStableV1 {
642 hash: ledger_hash,
643 total_currency,
644 },
645 seed,
646 start_checkpoint: StateHash::zero(),
647 lock_checkpoint: StateHash::zero(),
648 epoch_length: 1.into(),
649 }
650 }
651}
652
653impl ConsensusProofOfStakeDataEpochDataNextValueVersionedValueStableV1 {
654 pub fn zero(
655 ledger_hash: LedgerHash,
656 total_currency: CurrencyAmountStableV1,
657 seed: EpochSeed,
658 ) -> Self {
659 Self {
660 ledger: MinaBaseEpochLedgerValueStableV1 {
661 hash: ledger_hash,
662 total_currency,
663 },
664 seed,
665 start_checkpoint: StateHash::zero(),
666 lock_checkpoint: StateHash::zero(),
667 epoch_length: 1.into(),
668 }
669 }
670}
671
672impl AsRef<BigInteger256> for LedgerHash {
673 fn as_ref(&self) -> &BigInteger256 {
674 self.0.as_ref()
675 }
676}
677
678impl Default for TokenIdKeyHash {
679 fn default() -> Self {
680 MinaBaseAccountIdDigestStableV1(BigInt::one()).into()
681 }
682}
683
684#[derive(
685 Clone,
686 Debug,
687 PartialEq,
688 Eq,
689 PartialOrd,
690 Ord,
691 Serialize,
692 Deserialize,
693 BinProtRead,
694 BinProtWrite,
695 MallocSizeOf,
696)]
697pub struct NonZeroCurvePointWithVersions {
698 x: Versioned<crate::bigint::BigInt, 1>,
699 is_odd: bool,
700}
701
702impl From<NonZeroCurvePointUncompressedStableV1> for Versioned<NonZeroCurvePointWithVersions, 1> {
703 fn from(source: NonZeroCurvePointUncompressedStableV1) -> Self {
704 NonZeroCurvePointWithVersions {
705 x: source.x.into(),
706 is_odd: source.is_odd,
707 }
708 .into()
709 }
710}
711
712impl From<Versioned<NonZeroCurvePointWithVersions, 1>> for NonZeroCurvePointUncompressedStableV1 {
713 fn from(source: Versioned<NonZeroCurvePointWithVersions, 1>) -> Self {
714 let source = source.into_inner();
715 Self {
716 x: source.x.into_inner(),
717 is_odd: source.is_odd,
718 }
719 }
720}
721
722pub type NonZeroCurvePoint = Base58CheckOfBinProt<
723 NonZeroCurvePointUncompressedStableV1,
724 Versioned<NonZeroCurvePointWithVersions, 1>,
725 { crate::b58version::NON_ZERO_CURVE_POINT_COMPRESSED },
726>;
727
728#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, BinProtRead, BinProtWrite)]
729pub enum ArchiveTransitionFrontierDiff {
730 BreadcrumbAdded {
731 block: (MinaBlockBlockStableV2, (Option<StateBodyHash>, StateHash)),
732 accounts_accessed: List<(crate::number::UInt64, MinaBaseAccountBinableArgStableV2)>,
733 accounts_created: List<(MinaBaseAccountIdStableV2, CurrencyFeeStableV1)>,
734 tokens_used: List<(MinaBaseTokenIdStableV2, Option<MinaBaseAccountIdStableV2>)>,
735 sender_receipt_chains_from_parent_ledger:
736 List<(MinaBaseAccountIdStableV2, MinaBaseReceiptChainHashStableV1)>,
737 },
738 RootTransitioned(()),
740 BoostrapOf(()),
741}
742
743impl ArchiveTransitionFrontierDiff {
744 pub fn block(&self) -> Option<MinaBlockBlockStableV2> {
745 match self {
746 ArchiveTransitionFrontierDiff::BreadcrumbAdded { block, .. } => Some(block.0.clone()),
748 _ => None,
749 }
750 }
751
752 pub fn accounts_accessed(
753 &self,
754 ) -> List<(crate::number::UInt64, MinaBaseAccountBinableArgStableV2)> {
755 match self {
756 ArchiveTransitionFrontierDiff::BreadcrumbAdded {
757 accounts_accessed, ..
758 } => accounts_accessed.clone(),
759 _ => List::new(),
760 }
761 }
762
763 pub fn accounts_created(&self) -> List<(MinaBaseAccountIdStableV2, CurrencyFeeStableV1)> {
764 match self {
765 ArchiveTransitionFrontierDiff::BreadcrumbAdded {
766 accounts_created, ..
767 } => accounts_created.clone(),
768 _ => List::new(),
769 }
770 }
771
772 pub fn tokens_used(
773 &self,
774 ) -> List<(MinaBaseTokenIdStableV2, Option<MinaBaseAccountIdStableV2>)> {
775 match self {
776 ArchiveTransitionFrontierDiff::BreadcrumbAdded { tokens_used, .. } => {
777 tokens_used.clone()
778 }
779 _ => List::new(),
780 }
781 }
782}
783
784#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, BinProtRead, BinProtWrite)]
785pub enum ArchiveRpc {
786 SendDiff(ArchiveTransitionFrontierDiff),
787}
788
789#[derive(Clone, Debug, PartialEq, BinProtRead, BinProtWrite)]
790pub struct PrecomputedBlockProof(pub MinaBaseProofStableV2);
791
792impl Serialize for PrecomputedBlockProof {
793 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
794 where
795 S: serde::ser::Serializer,
796 {
797 use base64::{engine::general_purpose::URL_SAFE, Engine as _};
798 use binprot::BinProtWrite;
799 let mut buf = Vec::new();
800 self.0
801 .binprot_write(&mut buf)
802 .map_err(serde::ser::Error::custom)?;
803 let base64_data = URL_SAFE.encode(&buf);
804 serializer.serialize_str(&base64_data)
805 }
806}
807
808impl<'de> Deserialize<'de> for PrecomputedBlockProof {
809 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
810 where
811 D: serde::de::Deserializer<'de>,
812 {
813 use base64::{engine::general_purpose::URL_SAFE, Engine as _};
814 let base64_data = String::deserialize(deserializer)?;
815 let binprot_data = URL_SAFE
816 .decode(&base64_data)
817 .map_err(serde::de::Error::custom)?;
818 let mut read = binprot_data.as_slice();
819 let proof: MinaBaseProofStableV2 =
820 binprot::BinProtRead::binprot_read(&mut read).map_err(serde::de::Error::custom)?;
821 Ok(PrecomputedBlockProof(proof))
822 }
823}
824
825impl From<MinaBaseProofStableV2> for PrecomputedBlockProof {
826 fn from(value: MinaBaseProofStableV2) -> Self {
827 Self(value)
828 }
829}
830
831#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, BinProtRead, BinProtWrite)]
832pub struct PrecomputedBlock {
833 pub scheduled_time: BlockTimeTimeStableV1,
834 pub protocol_state: MinaStateProtocolStateValueStableV2,
835 pub protocol_state_proof: PrecomputedBlockProof,
836 pub staged_ledger_diff: StagedLedgerDiffDiffStableV2,
837 pub delta_transition_chain_proof: (
841 StateHash, List<StateBodyHash>, ),
844 pub protocol_version: ProtocolVersionStableV2,
845 #[serde(default)]
846 pub proposed_protocol_version: Option<ProtocolVersionStableV2>,
847 pub accounts_accessed: List<(crate::number::UInt64, MinaBaseAccountBinableArgStableV2)>,
848 pub accounts_created: List<(MinaBaseAccountIdStableV2, CurrencyFeeStableV1)>,
849 pub tokens_used: List<(MinaBaseTokenIdStableV2, Option<MinaBaseAccountIdStableV2>)>,
850}
851
852#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, BinProtRead, BinProtWrite)]
853pub struct PrecomputedBlockData {
854 pub version: u32,
855 pub data: PrecomputedBlock,
856}
857
858impl PrecomputedBlock {
859 pub fn with_version(&self, version: u32) -> PrecomputedBlockData {
860 PrecomputedBlockData {
861 version,
862 data: self.clone(),
863 }
864 }
865}
866
867#[cfg(test)]
868mod tests {
869 use std::fmt::Debug;
870
871 use binprot::{BinProtRead, BinProtWrite};
872 use serde::{de::DeserializeOwned, Serialize};
873
874 use super::*;
875
876 fn base58check_test<T: Serialize + DeserializeOwned + BinProtRead + BinProtWrite + Debug>(
877 b58: &str,
878 hex: &str,
879 ) {
880 let bin: T = serde_json::from_value(serde_json::json!(b58)).unwrap();
881 let json = serde_json::to_value(&bin).unwrap();
882
883 let mut binprot = Vec::new();
884 bin.binprot_write(&mut binprot).unwrap();
885
886 println!("{b58} => {}", hex::encode(&binprot));
887
888 let binprot1 = hex::decode(hex).unwrap();
889 let mut b = binprot1.as_slice();
890 let from_hex = T::binprot_read(&mut b).unwrap();
891 println!("{hex} => {}", serde_json::to_string(&from_hex).unwrap());
892
893 assert_eq!(hex::encode(&binprot), hex);
894 assert_eq!(json.as_str().unwrap(), b58);
895 }
896
897 macro_rules! b58t {
898 ($name:ident, $ty:ty, $b58:expr, $hex:expr) => {
899 #[test]
900 fn $name() {
901 base58check_test::<$ty>($b58, $hex);
902 }
903 };
904 }
905
906 b58t!(
907 ledger_hash,
908 LedgerHash,
909 "jwrPvAMUNo3EKT2puUk5Fxz6B7apRAoKNTGpAA49t3TRSfzvdrL",
910 "636f5b2d67278e17bc4343c7c23fb4991f8cf0bbbfd8558615b124d5d6254801"
911 );
912
913 b58t!(
914 staged_ledger_hash_aux_hash,
915 StagedLedgerHashAuxHash,
916 "UbhWTJLi4JM5bizFQVPvfMbjh4tCiTUTrNhedn8WdMPR1KHKJh",
917 "203294e118730ad8b7c0f2ab6d74d244eec02cfef221790bb1274fdb3b97854e50"
918 );
919
920 b58t!(
921 epoch_seed,
922 EpochSeed,
923 "2vajKi2Cxx58mByzxbJA3G6gYh1j2BoizW4zzoLcZa3kYECjhaXV",
924 "4d8802db5beb98f13e10475ddc9e718f6890613276331c062f5d71b915d6941d"
925 );
926
927 b58t!(
928 staged_ledger_hash_pending_coinbase_aux,
929 StagedLedgerHashPendingCoinbaseAux,
930 "XgkNHpgSvmF7CyRBGUzcwvCD9daBRhZUDLg3xTvohmTX1mRqHR",
931 "20c922885bfeda2c2568e32fcc595fe0ad2292dcf756be637545bc553f7f7028e8"
932 );
933
934 b58t!(
935 state_hash,
936 StateHash,
937 "3NL7AkynW6hbDrhHTAht1GLG563Fo9fdcEQk1zEyy5XedC6aZTeB",
938 "8d67aadd018581a812623915b13d5c3a6da7dfe8a195172d9bbd206810bc2329"
939 );
940
941 b58t!(
942 state_body_hash,
943 StateBodyHash,
944 "3WtsPNWF7Ua5zbvHEARuEL32KEfMM7pPYNXWVGtTStdYJRYA2rta",
945 "1b11c26e5541d2f719a50f2e5bdcd23e7995883036f3d2e5675dfd3015ec6202"
946 );
947
948 b58t!(
949 pending_coinbase_hash,
950 PendingCoinbaseHash,
951 "2n2EEn3yH1oRU8tCXTjw7dJKHQVcFTkfeDCTpBzum3sZcssPeaVM",
952 "e23a19254e600402e4474371450d498c75a9b3e28c34160d489af61c255f722c"
953 );
954
955 b58t!(
956 token_id_key,
957 TokenIdKeyHash,
958 "wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf",
959 "0100000000000000000000000000000000000000000000000000000000000000"
960 );
961
962 b58t!(
963 vrf_truncated_output,
964 ConsensusVrfOutputTruncatedStableV1,
965 "48H9Qk4D6RzS9kAJQX9HCDjiJ5qLiopxgxaS6xbDCWNaKQMQ9Y4C",
966 "20dfd73283866632d9dbfda15421eacd02800957caad91f3a9ab4cc5ccfb298e03"
967 );
968
969 b58t!(
970 coinbase_stack_data,
971 CoinbaseStackData,
972 "4QNrZFBTDQCPfEZqBZsaPYx8qdaNFv1nebUyCUsQW9QUJqyuD3un",
973 "35b9d51e5d7c741456f86720731241a8280273cfc6c21668fd7bc6c587d0cc1d"
974 );
975
976 b58t!(
977 coinbase_stack_hash,
978 CoinbaseStackHash,
979 "4Yx5U3t3EYQycZ91yj4478bHkLwGkhDHnPbCY9TxgUk69SQityej",
980 "0000000000000000000000000000000000000000000000000000000000000000"
981 );
982
983 b58t!(
984 signature,
985 Signature,
986 "7mXS9Y91bWtTYNKuDbxTuG18wUiZLHUySy9Ms8bPyAT9KNnME1q2nctwnvowJi2Y79dnsL18iVSCuaQF1ufUKwUZZKAXHqnF",
987 "d290f924705fb714e91fedb9bed77e85bce8f5d932c3f4d692b20e4c3e5f9a3343c2baffce9ab0c2391e2f3de8ac891633338d827e6fd4f269331c248029b106"
988 );
989
990 #[test]
991 fn non_zero_curve_point() {
992 let b58 = r#""B62qkUHaJUHERZuCHQhXCQ8xsGBqyYSgjQsKnKN5HhSJecakuJ4pYyk""#;
993
994 let v = serde_json::from_str::<NonZeroCurvePoint>(&b58)
995 .unwrap()
996 .into_inner();
997 assert_eq!(v.is_odd, false);
998 assert_eq!(
999 &hex::encode(&v.x.to_bytes()),
1000 "3c2b5b48c22dc8b8c9d2c9d76a2ceaaf02beabb364301726c3f8e989653af513"
1001 );
1002 }
1003}
1004
1005const SHIFTED_VALUE: &str = "Shifted_value";
1006
1007impl Serialize for PicklesProofProofsVerified2ReprStableV2StatementFp {
1008 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1009 where
1010 S: serde::Serializer,
1011 {
1012 if serializer.is_human_readable() {
1013 let mut serializer = serializer.serialize_tuple(2)?;
1014 match self {
1015 PicklesProofProofsVerified2ReprStableV2StatementFp::ShiftedValue(v) => {
1016 serializer.serialize_element(SHIFTED_VALUE)?;
1017 serializer.serialize_element(v)?;
1018 }
1019 }
1020 serializer.end()
1021 } else {
1022 match self {
1023 PicklesProofProofsVerified2ReprStableV2StatementFp::ShiftedValue(v) => serializer
1024 .serialize_newtype_variant(
1025 "PicklesProofProofsVerified2ReprStableV2StatementFp",
1026 0,
1027 "ShiftedValue",
1028 v,
1029 ),
1030 }
1031 }
1032 }
1033}
1034
1035impl<'de> Deserialize<'de> for PicklesProofProofsVerified2ReprStableV2StatementFp {
1036 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1037 where
1038 D: serde::Deserializer<'de>,
1039 {
1040 struct V;
1041 impl<'de> Visitor<'de> for V {
1042 type Value = PicklesProofProofsVerified2ReprStableV2StatementFp;
1043
1044 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1045 formatter.write_str("tuple of tag and value")
1046 }
1047
1048 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
1049 where
1050 A: serde::de::SeqAccess<'de>,
1051 {
1052 match seq.next_element::<String>()? {
1053 Some(v) if &v == SHIFTED_VALUE => {}
1054 Some(v) => {
1055 return Err(serde::de::Error::custom(format!(
1056 "expecting `{SHIFTED_VALUE}`, got `{v}`"
1057 )))
1058 }
1059 None => return Err(serde::de::Error::custom("expecting a tag")),
1060 }
1061 match seq.next_element::<BigInt>()? {
1062 Some(v) => {
1063 Ok(PicklesProofProofsVerified2ReprStableV2StatementFp::ShiftedValue(v))
1064 }
1065 None => return Err(serde::de::Error::custom("expecting a value")),
1066 }
1067 }
1068 }
1069
1070 if deserializer.is_human_readable() {
1071 deserializer.deserialize_tuple(2, V)
1072 } else {
1073 #[derive(Deserialize)]
1074 pub enum PicklesProofProofsVerified2ReprStableV2StatementFp {
1075 ShiftedValue(crate::bigint::BigInt),
1076 }
1077 let PicklesProofProofsVerified2ReprStableV2StatementFp::ShiftedValue(v) =
1078 Deserialize::deserialize(deserializer)?;
1079 Ok(Self::ShiftedValue(v))
1080 }
1081 }
1082}
1083
1084impl Serialize for ConsensusVrfOutputTruncatedStableV1 {
1085 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1086 where
1087 S: serde::Serializer,
1088 {
1089 if serializer.is_human_readable() {
1090 use base64::{engine::general_purpose::URL_SAFE, Engine as _};
1092 let base64_data = URL_SAFE.encode(&self.0 .0);
1093 serializer.serialize_str(&base64_data)
1094 } else {
1095 serializer.serialize_newtype_struct("ConsensusVrfOutputTruncatedStableV1", &self.0)
1096 }
1097 }
1098}
1099
1100impl<'de> Deserialize<'de> for ConsensusVrfOutputTruncatedStableV1 {
1101 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1102 where
1103 D: serde::Deserializer<'de>,
1104 {
1105 if deserializer.is_human_readable() {
1106 use base64::{engine::general_purpose::URL_SAFE, Engine as _};
1108 let base64_data = String::deserialize(deserializer)?;
1109 URL_SAFE
1110 .decode(&base64_data)
1111 .map(|vec| ByteString::from(vec))
1112 .map_err(|e| serde::de::Error::custom(format!("Error deserializing vrf: {e}")))
1113 } else {
1114 Deserialize::deserialize(deserializer)
1115 }
1116 .map(Self)
1117 }
1118}
1119
1120impl MinaBaseVerificationKeyWireStableV1 {
1121 pub fn to_base64(&self) -> Result<String, conv::Error> {
1122 let mut buffer: Vec<u8> = Vec::new();
1123 self.binprot_write(&mut buffer)?;
1124 use base64::{engine::general_purpose::STANDARD, Engine as _};
1125
1126 let base64_data = STANDARD.encode(buffer);
1127 Ok(base64_data)
1128 }
1129
1130 pub fn from_base64(base64_data: &str) -> Result<Self, conv::Error> {
1131 use base64::{engine::general_purpose::STANDARD, Engine as _};
1132 let decoded_data = STANDARD.decode(base64_data)?;
1133 let res = MinaBaseVerificationKeyWireStableV1::binprot_read(&mut decoded_data.as_slice())?;
1134 Ok(res)
1135 }
1136}
1137
1138impl MinaBaseSignedCommandStableV2 {
1140 pub fn to_base64(&self) -> Result<String, conv::Error> {
1141 const COMMAND_VERSION_TAG: u8 = 2;
1142
1143 let mut buffer: Vec<u8> = Vec::new();
1144 COMMAND_VERSION_TAG.binprot_write(&mut buffer)?;
1145 self.binprot_write(&mut buffer)?;
1146 use base64::{engine::general_purpose::STANDARD, Engine as _};
1147
1148 let base64_data = STANDARD.encode(buffer);
1149 Ok(base64_data)
1150 }
1151
1152 pub fn from_base64(base64_data: &str) -> Result<Self, conv::Error> {
1153 use base64::{engine::general_purpose::STANDARD, Engine as _};
1154 let decoded_data = STANDARD.decode(&base64_data)?;
1155 let res = MinaBaseSignedCommandStableV2::binprot_read(&mut decoded_data[1..].as_ref())?;
1156 Ok(res)
1157 }
1158}
1159
1160impl MinaBaseZkappCommandTStableV1WireStableV1 {
1162 pub fn to_base64(&self) -> Result<String, conv::Error> {
1163 const ZKAPP_VERSION_TAG: u8 = 1;
1164
1165 let mut buffer: Vec<u8> = Vec::new();
1166 ZKAPP_VERSION_TAG.binprot_write(&mut buffer)?;
1167 self.binprot_write(&mut buffer)?;
1168 use base64::{engine::general_purpose::STANDARD, Engine as _};
1169
1170 let base64_data = STANDARD.encode(buffer);
1171 Ok(base64_data)
1172 }
1173
1174 pub fn from_base64(base64_data: &str) -> Result<Self, conv::Error> {
1175 use base64::{engine::general_purpose::STANDARD, Engine as _};
1176 let decoded_data = STANDARD.decode(&base64_data)?;
1177 let res = MinaBaseZkappCommandTStableV1WireStableV1::binprot_read(
1178 &mut decoded_data[1..].as_ref(),
1179 )?;
1180 Ok(res)
1181 }
1182}
1183
1184impl Serialize for ConsensusBodyReferenceStableV1 {
1185 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1186 where
1187 S: serde::ser::Serializer,
1188 {
1189 if serializer.is_human_readable() {
1190 let hex_string = hex::encode(&self.0);
1191 serializer.serialize_str(&hex_string)
1192 } else {
1193 self.0.serialize(serializer)
1194 }
1195 }
1196}
1197
1198impl<'de> Deserialize<'de> for ConsensusBodyReferenceStableV1 {
1199 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1200 where
1201 D: serde::de::Deserializer<'de>,
1202 {
1203 if deserializer.is_human_readable() {
1204 let hex_string = String::deserialize(deserializer)?;
1205 let decoded_bytes = hex::decode(&hex_string).map_err(serde::de::Error::custom)?;
1206 Ok(ConsensusBodyReferenceStableV1(
1207 crate::string::ByteString::from(decoded_bytes),
1208 ))
1209 } else {
1210 let inner_value = crate::string::ByteString::deserialize(deserializer)?;
1211 Ok(ConsensusBodyReferenceStableV1(inner_value))
1212 }
1213 }
1214}
1215
1216impl<'de> Deserialize<'de> for MinaNumbersGlobalSlotSinceGenesisMStableV1 {
1218 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1219 where
1220 D: serde::de::Deserializer<'de>,
1221 {
1222 let value = UnsignedExtendedUInt32StableV1::deserialize(deserializer)?;
1223 Ok(MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis(
1224 value,
1225 ))
1226 }
1227}
1228
1229impl<'de> Deserialize<'de> for MinaNumbersGlobalSlotSinceHardForkMStableV1 {
1231 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1232 where
1233 D: serde::de::Deserializer<'de>,
1234 {
1235 let value = UnsignedExtendedUInt32StableV1::deserialize(deserializer)?;
1236 Ok(MinaNumbersGlobalSlotSinceHardForkMStableV1::SinceHardFork(
1237 value,
1238 ))
1239 }
1240}
1241
1242pub type MerkleTreePath = Vec<MerkleTreeNode>;
1243
1244#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, BinProtRead, BinProtWrite)]
1245#[polymorphic_variant]
1246pub enum MerkleTreeNode {
1247 Left(BigInt),
1248 Right(BigInt),
1249}
1250
1251impl ConsensusProofOfStakeDataConsensusStateValueStableV2 {
1252 pub fn global_slot(&self) -> u32 {
1253 match &self.curr_global_slot_since_hard_fork.slot_number {
1254 super::MinaNumbersGlobalSlotSinceHardForkMStableV1::SinceHardFork(s) => s.as_u32(),
1255 }
1256 }
1257}
1258
1259impl AsRef<str> for SgnStableV1 {
1260 fn as_ref(&self) -> &str {
1261 match self {
1262 SgnStableV1::Pos => "Pos",
1263 SgnStableV1::Neg => "Neg",
1264 }
1265 }
1266}
1267
1268impl Serialize for SgnStableV1 {
1269 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1270 where
1271 S: serde::Serializer,
1272 {
1273 if serializer.is_human_readable() {
1274 let mut tuple = serializer.serialize_tuple(1)?;
1275 tuple.serialize_element(self.as_ref())?;
1276 tuple.end()
1277 } else {
1278 match *self {
1279 SgnStableV1::Pos => {
1280 Serializer::serialize_unit_variant(serializer, "SgnStableV1", 0u32, "Pos")
1281 }
1282 SgnStableV1::Neg => {
1283 Serializer::serialize_unit_variant(serializer, "SgnStableV1", 1u32, "Neg")
1284 }
1285 }
1286 }
1287 }
1288}
1289
1290impl<'de> Deserialize<'de> for SgnStableV1 {
1291 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1292 where
1293 D: serde::Deserializer<'de>,
1294 {
1295 if deserializer.is_human_readable() {
1296 struct V;
1297
1298 impl<'de> Visitor<'de> for V {
1299 type Value = String;
1300
1301 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1302 formatter.write_str("`Pos` or `Neg`")?;
1303 panic!("foo")
1304 }
1305
1306 fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
1307 where
1308 E: serde::de::Error,
1309 {
1310 Ok(v)
1311 }
1312
1313 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
1314 where
1315 A: serde::de::SeqAccess<'de>,
1316 {
1317 let Some(elt) = seq.next_element()? else {
1318 return Err(serde::de::Error::custom("No tag"));
1319 };
1320 Ok(elt)
1321 }
1322 }
1323 let v = deserializer.deserialize_tuple(1, V)?;
1324 match v.as_str() {
1325 "Pos" => Ok(SgnStableV1::Pos),
1326 "Neg" => Ok(SgnStableV1::Neg),
1327 _ => Err(serde::de::Error::custom(format!("Invalid tag {v}"))),
1328 }
1329 } else {
1330 #[derive(Deserialize)]
1331 enum _SgnStableV1 {
1332 Pos,
1333 Neg,
1334 }
1335
1336 let s: _SgnStableV1 = Deserialize::deserialize(deserializer)?;
1337 match s {
1338 _SgnStableV1::Pos => Ok(SgnStableV1::Pos),
1339 _SgnStableV1::Neg => Ok(SgnStableV1::Neg),
1340 }
1341 }
1342 }
1343}
1344
1345const PRECISION: usize = 9;
1346const PRECISION_EXP: u64 = 10u64.pow(PRECISION as u32);
1347
1348impl Serialize for CurrencyFeeStableV1 {
1349 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1350 where
1351 S: serde::ser::Serializer,
1352 {
1353 let amount = self.0 .0.as_u64();
1354 let whole = amount / PRECISION_EXP;
1355 let remainder = amount % PRECISION_EXP;
1356
1357 if remainder == 0 {
1358 serializer.serialize_str(&whole.to_string())
1359 } else {
1360 let tmp = format!("{:0width$}", remainder, width = PRECISION);
1361 let fractional_str = tmp.trim_end_matches('0');
1362 serializer.serialize_str(&format!("{}.{}", whole, fractional_str))
1363 }
1364 }
1365}
1366
1367impl<'de> Deserialize<'de> for CurrencyFeeStableV1 {
1368 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1369 where
1370 D: serde::de::Deserializer<'de>,
1371 {
1372 let s: String = Deserialize::deserialize(deserializer)?;
1373 let parts: Vec<&str> = s.split('.').collect();
1374 let result = match parts.as_slice() {
1375 [whole] => format!("{}{}", whole, "0".repeat(PRECISION)),
1376 [whole, decimal] => {
1377 let decimal_length = decimal.len();
1378 if decimal_length > PRECISION {
1379 format!("{}{}", whole, &decimal[0..PRECISION])
1380 } else {
1381 format!(
1382 "{}{}{}",
1383 whole,
1384 decimal,
1385 "0".repeat(PRECISION - decimal_length)
1386 )
1387 }
1388 }
1389 _ => return Err(serde::de::Error::custom("Invalid currency input")),
1390 };
1391 let fee_in_nanomina: u64 = result.parse().map_err(serde::de::Error::custom)?;
1392 Ok(CurrencyFeeStableV1(
1393 UnsignedExtendedUInt64Int64ForVersionTagsStableV1(fee_in_nanomina.into()),
1394 ))
1395 }
1396}
1397
1398#[cfg(test)]
1399mod tests_currency_fee_serialization {
1400 use super::*;
1401 use serde_json;
1402
1403 #[test]
1404 fn test_correct_serialization() {
1405 let amount = 1_000_000u64;
1406 let currency = CurrencyFeeStableV1(amount.into());
1407
1408 let serialized = serde_json::to_string(¤cy).unwrap();
1409 assert_eq!(serialized, "\"0.001\"", "Serialization output is incorrect");
1410 }
1411
1412 #[test]
1413 fn test_zero_remainder() {
1414 let amount = 1_000_000_000u64;
1415 let currency = CurrencyFeeStableV1(amount.into());
1416
1417 let serialized = serde_json::to_string(¤cy).unwrap();
1418 assert_eq!(
1419 serialized, "\"1\"",
1420 "Serialization output is incorrect for whole numbers"
1421 );
1422 }
1423
1424 #[test]
1425 fn test_fractional_serialization() {
1426 let amount = 1_234_567_890u64;
1427 let currency = CurrencyFeeStableV1(amount.into());
1428
1429 let serialized = serde_json::to_string(¤cy).unwrap();
1430 assert_eq!(
1431 serialized, "\"1.23456789\"",
1432 "Serialization output is incorrect for fractional numbers"
1433 );
1434 }
1435
1436 #[test]
1437 fn test_trailing_zeros() {
1438 let amount = 1_230_000_000u64;
1439 let currency = CurrencyFeeStableV1(amount.into());
1440
1441 let serialized = serde_json::to_string(¤cy).unwrap();
1442 assert_eq!(
1443 serialized, "\"1.23\"",
1444 "Serialization output is incorrect when fractional part has trailing zeros"
1445 );
1446 }
1447
1448 #[test]
1449 fn test_deserialization_correct_serialization() {
1450 let serialized = "\"0.001\"";
1451 let currency: CurrencyFeeStableV1 = serde_json::from_str(serialized).unwrap();
1452 let expected_amount = 1_000_000u64;
1453 assert_eq!(
1454 currency,
1455 CurrencyFeeStableV1(expected_amount.into()),
1456 "Deserialization output is incorrect"
1457 );
1458 }
1459
1460 #[test]
1461 fn test_deserialization_zero_remainder() {
1462 let serialized = "\"1\"";
1463 let currency: CurrencyFeeStableV1 = serde_json::from_str(serialized).unwrap();
1464 let expected_amount = 1_000_000_000u64;
1465 assert_eq!(
1466 currency,
1467 CurrencyFeeStableV1(expected_amount.into()),
1468 "Deserialization output is incorrect for whole numbers"
1469 );
1470 }
1471
1472 #[test]
1473 fn test_deserialization_fractional() {
1474 let serialized = "\"1.23456789\"";
1475 let currency: CurrencyFeeStableV1 = serde_json::from_str(serialized).unwrap();
1476 let expected_amount = 1_234_567_890u64;
1477 assert_eq!(
1478 currency,
1479 CurrencyFeeStableV1(expected_amount.into()),
1480 "Deserialization output is incorrect for fractional numbers"
1481 );
1482 }
1483
1484 #[test]
1485 fn test_deserialization_trailing_zeros() {
1486 let serialized = "\"1.23\"";
1487 let currency: CurrencyFeeStableV1 = serde_json::from_str(serialized).unwrap();
1488 let expected_amount = 1_230_000_000u64;
1489 assert_eq!(
1490 currency,
1491 CurrencyFeeStableV1(expected_amount.into()),
1492 "Deserialization output is incorrect when fractional part has trailing zeros"
1493 );
1494 }
1495
1496 #[test]
1497 fn test_deserialization_truncates_extra_decimals() {
1498 let serialized = "\"0.1234567890123\""; let currency: CurrencyFeeStableV1 = serde_json::from_str(serialized).unwrap();
1500 let expected_amount = 123_456_789u64; assert_eq!(
1502 currency,
1503 CurrencyFeeStableV1(expected_amount.into()),
1504 "Deserialization did not correctly truncate extra decimal places"
1505 );
1506 }
1507
1508 #[test]
1509 fn test_deserialization_invalid_number() {
1510 let serialized = "\"abc\"";
1511 let result: Result<CurrencyFeeStableV1, _> = serde_json::from_str(serialized);
1512 assert!(
1513 result.is_err(),
1514 "Deserialization should fail for invalid number strings"
1515 );
1516 }
1517}
1518
1519#[cfg(test)]
1520mod tests_sgn {
1521 use crate::v2::SgnStableV1;
1522
1523 #[test]
1524 fn test_json() {
1525 assert_eq!(
1526 serde_json::to_value(&SgnStableV1::Pos).unwrap(),
1527 serde_json::json!(["Pos"])
1528 );
1529 assert_eq!(
1530 serde_json::to_value(&SgnStableV1::Neg).unwrap(),
1531 serde_json::json!(["Neg"])
1532 );
1533
1534 assert_eq!(
1535 serde_json::from_value::<SgnStableV1>(serde_json::json!(["Pos"])).unwrap(),
1536 SgnStableV1::Pos
1537 );
1538 assert_eq!(
1539 serde_json::from_value::<SgnStableV1>(serde_json::json!(["Neg"])).unwrap(),
1540 SgnStableV1::Neg
1541 );
1542 }
1543}
1544
1545#[derive(
1551 Clone, Debug, PartialEq, Serialize, Deserialize, BinProtRead, BinProtWrite, MallocSizeOf,
1552)]
1553pub struct SignedAmount {
1554 pub magnitude: CurrencyFeeStableV1,
1555 pub sgn: SgnStableV1,
1556}
1557
1558#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, BinProtRead, BinProtWrite)]
1568pub struct MinaBaseFeeExcessStableV1(pub TokenFeeExcess, pub TokenFeeExcess);
1569
1570#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, BinProtRead, BinProtWrite)]
1571pub struct TokenFeeExcess {
1572 pub token: TokenIdKeyHash,
1573 pub amount: SignedAmount,
1574}
1575
1576impl Default for NonZeroCurvePointUncompressedStableV1 {
1577 fn default() -> Self {
1578 Self {
1579 x: Default::default(),
1580 is_odd: false,
1581 }
1582 }
1583}
1584
1585impl MinaNumbersGlobalSlotSinceGenesisMStableV1 {
1586 pub fn as_u32(&self) -> u32 {
1587 let Self::SinceGenesis(slot) = self;
1588 slot.as_u32()
1589 }
1590}
1591
1592impl MinaNumbersGlobalSlotSinceHardForkMStableV1 {
1593 pub fn as_u32(&self) -> u32 {
1594 let Self::SinceHardFork(slot) = self;
1595 slot.as_u32()
1596 }
1597}
1598
1599impl MinaNumbersGlobalSlotSpanStableV1 {
1600 pub fn as_u32(&self) -> u32 {
1601 let Self::GlobalSlotSpan(slot) = self;
1602 slot.as_u32()
1603 }
1604}
1605
1606impl From<u32> for UnsignedExtendedUInt32StableV1 {
1607 fn from(value: u32) -> Self {
1608 Self(value.into())
1609 }
1610}
1611
1612impl From<u64> for UnsignedExtendedUInt64Int64ForVersionTagsStableV1 {
1613 fn from(value: u64) -> Self {
1614 Self(value.into())
1615 }
1616}
1617
1618impl From<&PicklesProofProofsVerifiedMaxStableV2> for PicklesProofProofsVerified2ReprStableV2 {
1619 fn from(value: &PicklesProofProofsVerifiedMaxStableV2) -> Self {
1620 let PicklesProofProofsVerifiedMaxStableV2 {
1621 statement,
1622 prev_evals,
1623 proof,
1624 } = value;
1625
1626 Self {
1627 statement: statement.clone(),
1628 prev_evals: prev_evals.clone(),
1629 proof: proof.clone(),
1630 }
1631 }
1632}
1633
1634impl std::fmt::Debug for UnsignedExtendedUInt32StableV1 {
1635 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1636 let Self(inner) = self;
1637 f.write_fmt(format_args!("UnsignedExtendedUInt32StableV1({:?})", inner))
1639 }
1640}
1641
1642impl std::fmt::Debug for UnsignedExtendedUInt64Int64ForVersionTagsStableV1 {
1643 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1644 let Self(inner) = self;
1645 f.write_fmt(format_args!(
1647 "UnsignedExtendedUInt64Int64ForVersionTagsStableV1({:?})",
1648 inner
1649 ))
1650 }
1651}
1652
1653impl MinaBaseProtocolConstantsCheckedValueStableV1 {
1654 const fn default_constants() -> Self {
1655 const fn from_u32(v: u32) -> UnsignedExtendedUInt32StableV1 {
1656 UnsignedExtendedUInt32StableV1(Number(v))
1657 }
1658
1659 Self {
1660 k: from_u32(290),
1661 slots_per_epoch: from_u32(7140),
1662 slots_per_sub_window: from_u32(7),
1663 grace_period_slots: from_u32(2160),
1664 delta: from_u32(0),
1665 genesis_state_timestamp: BlockTimeTimeStableV1(
1666 UnsignedExtendedUInt64Int64ForVersionTagsStableV1(Number(1600251300000)), ),
1668 }
1669 }
1670}
1671
1672impl Default for MinaBaseProtocolConstantsCheckedValueStableV1 {
1673 fn default() -> Self {
1674 Self::default_constants()
1675 }
1676}
1677
1678pub const PROTOCOL_CONSTANTS: MinaBaseProtocolConstantsCheckedValueStableV1 =
1679 MinaBaseProtocolConstantsCheckedValueStableV1::default_constants();
1680
1681impl From<OffsetDateTime> for BlockTimeTimeStableV1 {
1682 fn from(value: OffsetDateTime) -> Self {
1683 debug_assert!(value.unix_timestamp() >= 0);
1684 BlockTimeTimeStableV1((value.unix_timestamp() as u64 * 1000).into())
1685 }
1686}
1687
1688impl AsRef<MinaBaseUserCommandStableV2> for MinaBaseUserCommandStableV2 {
1689 fn as_ref(&self) -> &MinaBaseUserCommandStableV2 {
1690 self
1691 }
1692}
1693
1694impl MinaBlockHeaderStableV2 {
1695 pub fn genesis_state_hash(&self) -> &StateHash {
1696 &self.protocol_state.body.genesis_state_hash
1697 }
1698}
1699
1700impl StagedLedgerDiffBodyStableV1 {
1701 pub fn diff(&self) -> &StagedLedgerDiffDiffDiffStableV2 {
1702 &self.staged_ledger_diff.diff
1703 }
1704 pub fn commands_iter<'a>(
1705 &'a self,
1706 ) -> Box<dyn 'a + Iterator<Item = &'a StagedLedgerDiffDiffPreDiffWithAtMostTwoCoinbaseStableV2B>>
1707 {
1708 let diff = self.diff();
1709 let iter = diff.0.commands.iter();
1710 if let Some(_1) = diff.1.as_ref() {
1711 Box::new(iter.chain(_1.commands.iter()))
1712 } else {
1713 Box::new(iter)
1714 }
1715 }
1716
1717 pub fn transactions(&self) -> impl Iterator<Item = &MinaBaseUserCommandStableV2> {
1718 self.commands_iter().map(|command| &command.data)
1719 }
1720
1721 pub fn tranasctions_with_status(
1722 &self,
1723 ) -> impl Iterator<
1724 Item = (
1725 &MinaBaseUserCommandStableV2,
1726 &MinaBaseTransactionStatusStableV2,
1727 ),
1728 > {
1729 self.commands_iter()
1730 .map(|command| (&command.data, &command.status))
1731 }
1732
1733 pub fn coinbase_fee_transfers_iter(
1734 &self,
1735 ) -> impl Iterator<Item = &StagedLedgerDiffDiffFtStableV1> {
1736 let diff = self.diff();
1737 let mut coinbases = Vec::with_capacity(4);
1738 match &diff.0.coinbase {
1739 StagedLedgerDiffDiffPreDiffWithAtMostTwoCoinbaseStableV2Coinbase::Zero => {}
1740 StagedLedgerDiffDiffPreDiffWithAtMostTwoCoinbaseStableV2Coinbase::One(v) => {
1741 coinbases.push(v.as_ref());
1742 }
1743 StagedLedgerDiffDiffPreDiffWithAtMostTwoCoinbaseStableV2Coinbase::Two(v) => {
1744 match v.as_ref() {
1745 None => {}
1746 Some((v1, v2)) => {
1747 coinbases.push(Some(v1));
1748 coinbases.push(v2.as_ref());
1749 }
1750 }
1751 }
1752 }
1753
1754 if let Some(StagedLedgerDiffDiffPreDiffWithAtMostOneCoinbaseStableV2Coinbase::One(v)) =
1755 diff.1.as_ref().map(|v| &v.coinbase)
1756 {
1757 coinbases.push(v.as_ref());
1758 }
1759
1760 coinbases.into_iter().flatten()
1761 }
1762
1763 pub fn completed_works_iter<'a>(
1764 &'a self,
1765 ) -> Box<dyn 'a + Iterator<Item = &'a TransactionSnarkWorkTStableV2>> {
1766 let diff = self.diff();
1767 let _0 = &diff.0;
1768 if let Some(_1) = diff.1.as_ref() {
1769 Box::new(_0.completed_works.iter().chain(_1.completed_works.iter()))
1770 } else {
1771 Box::new(_0.completed_works.iter())
1772 }
1773 }
1774
1775 pub fn completed_works_count(&self) -> usize {
1776 self.diff().0.completed_works.len()
1777 + self
1778 .diff()
1779 .1
1780 .as_ref()
1781 .map_or(0, |d| d.completed_works.len())
1782 }
1783
1784 pub fn has_coinbase(&self) -> bool {
1785 let (first_pre_diff, second_pre_diff) = (
1786 self.diff().0.coinbase.clone(),
1787 self.diff().1.as_ref().map_or(
1788 StagedLedgerDiffDiffPreDiffWithAtMostOneCoinbaseStableV2Coinbase::Zero,
1789 |v| v.coinbase.clone(),
1790 ),
1791 );
1792
1793 match (first_pre_diff, second_pre_diff) {
1794 (
1795 StagedLedgerDiffDiffPreDiffWithAtMostTwoCoinbaseStableV2Coinbase::Zero,
1796 StagedLedgerDiffDiffPreDiffWithAtMostOneCoinbaseStableV2Coinbase::Zero,
1797 ) => false,
1798 _ => true,
1799 }
1800 }
1801
1802 pub fn fees_sum(&self) -> u64 {
1803 self.commands_iter()
1804 .map(|v| match &v.data {
1805 MinaBaseUserCommandStableV2::SignedCommand(v) => v.payload.common.fee.as_u64(),
1806 MinaBaseUserCommandStableV2::ZkappCommand(v) => v.fee_payer.body.fee.as_u64(),
1807 })
1808 .sum()
1809 }
1810
1811 pub fn snark_fees_sum(&self) -> u64 {
1812 self.completed_works_iter().map(|v| v.fee.as_u64()).sum()
1813 }
1814}
1815
1816impl From<PicklesProofProofsVerifiedMaxStableV2> for PicklesProofProofsVerified2ReprStableV2 {
1819 fn from(value: PicklesProofProofsVerifiedMaxStableV2) -> Self {
1820 Self {
1821 statement: value.statement,
1822 prev_evals: value.prev_evals,
1823 proof: value.proof,
1824 }
1825 }
1826}
1827
1828impl From<PicklesProofProofsVerified2ReprStableV2> for PicklesProofProofsVerifiedMaxStableV2 {
1829 fn from(value: PicklesProofProofsVerified2ReprStableV2) -> Self {
1830 Self {
1831 statement: value.statement,
1832 prev_evals: value.prev_evals,
1833 proof: value.proof,
1834 }
1835 }
1836}
1837
1838impl std::fmt::Display for SgnStableV1 {
1839 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1840 match self {
1841 SgnStableV1::Pos => write!(f, "Positive"),
1842 SgnStableV1::Neg => write!(f, "Negative"),
1843 }
1844 }
1845}
1846
1847impl std::str::FromStr for SgnStableV1 {
1848 type Err = String;
1849
1850 fn from_str(s: &str) -> Result<Self, Self::Err> {
1851 match s {
1852 "Positive" => Ok(SgnStableV1::Pos),
1853 "Negative" => Ok(SgnStableV1::Neg),
1854 _ => Err("Invalid Sgn string, expected Positive or Negative".to_string()),
1855 }
1856 }
1857}
1858
1859#[cfg(test)]
1860mod test {
1861 use binprot::BinProtRead;
1862
1863 use crate::v2;
1864
1865 #[test]
1866 fn test_zkapp_with_sig_auth_hash() {
1867 let expexcted = "AbliNXLg4Keq0ZJyxK/QNAx8SxrJeffYytk5lbcTF9s9Af0A4fUFAP2+oQMA48vntxcABLty3SXWjvuadrLtBjcsxT1oJ3C2hwS/LDh364LKUxrLe3uF/9lr8VlW/J+ctbiI+m9I61sb9BC/AAG5YjVy4OCnqtGScsSv0DQMfEsayXn32MrZOZW3ExfbPQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAAEBAQEBAQH9AJQ1dwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAAAAAePL57cXAAS7ct0l1o77mnay7QY3LMU9aCdwtocEvyw4d+uCylMay3t7hf/Za/FZVvyfnLW4iPpvSOtbG/QQvwAAAcwXZjv4NJwWwlJhFZPh2AK+o0dKOpIy1a6CXlskW7gmAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEAAQEBAQEBAf0AlDV3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQAAAAICAAAAACIBFlRlc3QgWktBcHAgdG8gUmVjZWl2ZXIAAAAAAAAAAAAA".to_string();
1868 let bytes = include_bytes!("../../../tests/files/zkapps/with_sig_auth.bin");
1869 let zkapp =
1870 v2::MinaBaseZkappCommandTStableV1WireStableV1::binprot_read(&mut bytes.as_slice())
1871 .unwrap();
1872
1873 let zkapp_id = zkapp.to_base64().unwrap();
1874 assert_eq!(expexcted, zkapp_id);
1875 }
1876
1877 #[test]
1878 fn test_verification_key_base64_decode() {
1879 use base64::{engine::general_purpose::STANDARD, Engine as _};
1880 let verification_key_encoded = "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";
1882
1883 let decoded = STANDARD.decode(verification_key_encoded).unwrap();
1884 let verification_key =
1885 v2::MinaBaseVerificationKeyWireStableV1::binprot_read(&mut decoded.as_slice());
1886 assert!(verification_key.is_ok());
1887 }
1888
1889 #[test]
1890 fn test_archive_breadcrumb_deserialization() {
1891 let breadcrumb_bytes = include_bytes!("../../../tests/files/archive-breadcrumb/3NK56ZbCS31qb8SvCtCCYza4beRDtKgXA2JL6s3evKouG2KkKtiy.bin");
1892 let result =
1893 v2::ArchiveTransitionFrontierDiff::binprot_read(&mut breadcrumb_bytes.as_slice());
1894
1895 assert!(result.is_ok());
1896 }
1897}