1use std::{fmt, io, sync::Arc};
2
3use ark_ff::fields::arithmetic::InvalidBigInt;
4use binprot::{BinProtRead, BinProtWrite};
5use generated::MinaStateBlockchainStateValueStableV2;
6use mina_curves::pasta::Fp;
7use poseidon::hash::{
8 hash_with_kimchi,
9 params::{MINA_PROTO_STATE, MINA_PROTO_STATE_BODY},
10 Inputs,
11};
12use serde::{Deserialize, Serialize};
13use sha2::{
14 digest::{generic_array::GenericArray, typenum::U32},
15 Digest, Sha256,
16};
17
18use crate::{bigint::BigInt, hash::MinaHash, hash_input::FailableToInputs};
19
20use super::{
21 generated, ConsensusBodyReferenceStableV1, ConsensusGlobalSlotStableV1,
22 ConsensusProofOfStakeDataConsensusStateValueStableV2,
23 ConsensusProofOfStakeDataEpochDataNextValueVersionedValueStableV1,
24 ConsensusProofOfStakeDataEpochDataStakingValueVersionedValueStableV1,
25 ConsensusVrfOutputTruncatedStableV1, DataHashLibStateHashStableV1, LedgerHash,
26 MinaBaseControlStableV2, MinaBaseEpochLedgerValueStableV1, MinaBaseFeeExcessStableV1,
27 MinaBaseLedgerHash0StableV1, MinaBasePendingCoinbaseHashBuilderStableV1,
28 MinaBasePendingCoinbaseHashVersionedStableV1, MinaBasePendingCoinbaseStackVersionedStableV1,
29 MinaBasePendingCoinbaseStateStackStableV1, MinaBaseProtocolConstantsCheckedValueStableV1,
30 MinaBaseStagedLedgerHashNonSnarkStableV1, MinaBaseStagedLedgerHashStableV1,
31 MinaBaseStateBodyHashStableV1, MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesAA,
32 MinaNumbersGlobalSlotSinceGenesisMStableV1, MinaNumbersGlobalSlotSinceHardForkMStableV1,
33 MinaNumbersGlobalSlotSpanStableV1, MinaStateBlockchainStateValueStableV2LedgerProofStatement,
34 MinaStateBlockchainStateValueStableV2LedgerProofStatementSource,
35 MinaStateBlockchainStateValueStableV2SignedAmount, MinaStateProtocolStateBodyValueStableV2,
36 MinaStateProtocolStateValueStableV2,
37 MinaTransactionLogicZkappCommandLogicLocalStateValueStableV1,
38 NonZeroCurvePointUncompressedStableV1, PendingCoinbaseHash, SgnStableV1, SignedAmount,
39 StateHash, TokenFeeExcess,
40};
41
42impl generated::MinaBaseStagedLedgerHashNonSnarkStableV1 {
43 pub fn sha256(&self) -> GenericArray<u8, U32> {
44 let mut ledger_hash_bytes: [u8; 32] = [0; 32];
45
46 ledger_hash_bytes.copy_from_slice(&self.ledger_hash.to_bytes()[..]);
47 ledger_hash_bytes.reverse();
48
49 let mut hasher = Sha256::new();
50 hasher.update(ledger_hash_bytes);
51 hasher.update(self.aux_hash.as_ref());
52 hasher.update(self.pending_coinbase_aux.as_ref());
53
54 hasher.finalize()
55 }
56}
57
58impl generated::ConsensusVrfOutputTruncatedStableV1 {
59 pub fn blake2b(&self) -> Vec<u8> {
60 use blake2::{
61 digest::{Update, VariableOutput},
62 Blake2bVar,
63 };
64 let mut hasher = Blake2bVar::new(32).expect("Invalid Blake2bVar output size");
65 hasher.update(&self.0);
66 hasher.finalize_boxed().to_vec()
67 }
68}
69
70#[derive(Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
71pub struct TransactionHash(Arc<[u8; 32]>);
72
73impl std::str::FromStr for TransactionHash {
74 type Err = bs58::decode::Error;
75
76 fn from_str(s: &str) -> Result<Self, Self::Err> {
77 let bytes = bs58::decode(s).with_check(Some(0x1D)).into_vec()?;
78 dbg!(bytes.len());
79 let bytes = (&bytes[2..])
80 .try_into()
81 .map_err(|_| bs58::decode::Error::BufferTooSmall)?;
82 Ok(Self(Arc::new(bytes)))
83 }
84}
85
86impl fmt::Display for TransactionHash {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 let mut bytes = [32; 33];
89 bytes[1..].copy_from_slice(&*self.0);
90 bs58::encode(bytes)
91 .with_check_version(0x1D)
92 .into_string()
93 .fmt(f)
94 }
95}
96
97impl fmt::Debug for TransactionHash {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 write!(f, "{:?}", self.0)
100 }
102}
103
104impl From<&[u8; 32]> for TransactionHash {
105 fn from(value: &[u8; 32]) -> Self {
106 Self(Arc::new(*value))
107 }
108}
109
110impl Serialize for TransactionHash {
111 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
112 where
113 S: serde::Serializer,
114 {
115 if serializer.is_human_readable() {
116 serializer.serialize_str(&self.to_string())
117 } else {
118 serde_bytes::serialize(&*self.0, serializer)
119 }
120 }
121}
122
123impl<'de> serde::Deserialize<'de> for TransactionHash {
124 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
125 where
126 D: serde::Deserializer<'de>,
127 {
128 if deserializer.is_human_readable() {
129 let b58: String = Deserialize::deserialize(deserializer)?;
130 Ok(b58.parse().map_err(|err| serde::de::Error::custom(err))?)
131 } else {
132 serde_bytes::deserialize(deserializer)
133 .map(Arc::new)
134 .map(Self)
135 }
136 }
137}
138
139impl BinProtWrite for TransactionHash {
140 fn binprot_write<W: io::Write>(&self, w: &mut W) -> std::io::Result<()> {
141 w.write_all(&*self.0)
142 }
143}
144
145impl BinProtRead for TransactionHash {
146 fn binprot_read<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, binprot::Error>
147 where
148 Self: Sized,
149 {
150 let mut bytes = [0; 32];
151 r.read_exact(&mut bytes)?;
152 Ok(Self(bytes.into()))
153 }
154}
155
156impl generated::MinaTransactionTransactionStableV2 {
157 pub fn hash(&self) -> io::Result<TransactionHash> {
158 match self {
159 Self::Command(v) => v.hash(),
160 Self::FeeTransfer(_) => Err(io::Error::new(
161 io::ErrorKind::Unsupported,
162 "fee transfer tx hashing is not yet supported",
163 )),
164 Self::Coinbase(_) => Err(io::Error::new(
165 io::ErrorKind::Unsupported,
166 "coinbase tx hashing is not yet supported",
167 )),
168 }
169 }
170}
171
172impl generated::MinaBaseUserCommandStableV2 {
173 pub fn hash(&self) -> io::Result<TransactionHash> {
174 match self {
175 Self::SignedCommand(v) => v.hash(),
176 Self::ZkappCommand(v) => v.hash(),
177 }
178 }
179}
180
181impl generated::MinaBaseSignedCommandStableV2 {
182 pub fn binprot_write_with_default_sig(&self) -> io::Result<Vec<u8>> {
183 let default_signature = generated::MinaBaseSignatureStableV1(BigInt::one(), BigInt::one());
184
185 let mut encoded = vec![];
186 self.payload.binprot_write(&mut encoded)?;
187 self.signer.binprot_write(&mut encoded)?;
188 default_signature.binprot_write(&mut encoded)?;
189 Ok(encoded)
190 }
191
192 pub fn hash(&self) -> io::Result<TransactionHash> {
193 use blake2::{
194 digest::{Update, VariableOutput},
195 Blake2bVar,
196 };
197 let mut hasher = Blake2bVar::new(32).expect("Invalid Blake2bVar output size");
198
199 hasher.update(&self.binprot_write_with_default_sig()?);
200 let mut hash = [0; 32];
201 hasher
202 .finalize_variable(&mut hash)
203 .expect("Invalid buffer size"); Ok(TransactionHash(hash.into()))
206 }
207}
208
209impl generated::MinaBaseZkappCommandTStableV1WireStableV1 {
211 fn binprot_write_with_default(&self) -> io::Result<Vec<u8>> {
212 let default_signature = generated::MinaBaseSignatureStableV1(BigInt::one(), BigInt::one());
213
214 let mut encoded = vec![];
215
216 let mut modified = self.clone();
217
218 modified.fee_payer.authorization = default_signature.clone().into();
219
220 modified.account_updates.iter_mut().for_each(|u| {
221 Self::replace_auth_recursive(&mut u.elt);
222 });
223
224 modified.binprot_write(&mut encoded)?;
225 Ok(encoded)
226 }
227
228 fn replace_auth_recursive(
229 update_elt: &mut MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesAA,
230 ) {
231 Self::replace_auth(&mut update_elt.account_update.authorization);
232 update_elt.calls.iter_mut().for_each(|call| {
237 Self::replace_auth_recursive(&mut call.elt);
238 });
239
240 }
244
245 pub fn replace_auth(auth: &mut MinaBaseControlStableV2) {
246 let default_signature = generated::MinaBaseSignatureStableV1(BigInt::one(), BigInt::one());
247 let default_proof = super::dummy_transaction_proof();
248 *auth = match auth {
249 MinaBaseControlStableV2::Proof(_) => {
250 MinaBaseControlStableV2::Proof(Box::new(default_proof.0.clone().into()))
251 }
252 MinaBaseControlStableV2::Signature(_) => {
253 MinaBaseControlStableV2::Signature(default_signature.clone().into())
254 }
255 MinaBaseControlStableV2::NoneGiven => MinaBaseControlStableV2::NoneGiven,
256 };
257 }
258
259 pub fn hash(&self) -> io::Result<TransactionHash> {
260 use blake2::{
261 digest::{Update, VariableOutput},
262 Blake2bVar,
263 };
264 let mut hasher = Blake2bVar::new(32).expect("Invalid Blake2bVar output size");
265
266 hasher.update(&self.binprot_write_with_default()?);
267 let mut hash = [0; 32];
268 hasher
269 .finalize_variable(&mut hash)
270 .expect("Invalid buffer size"); Ok(TransactionHash(hash.into()))
273 }
274}
275
276#[cfg(test)]
277mod tests {
278 use super::{super::manual, *};
279 use manual::MinaBaseSignedCommandMemoStableV1;
280
281 fn pub_key(address: &str) -> manual::NonZeroCurvePoint {
282 let key = mina_signer::PubKey::from_address(address)
283 .unwrap()
284 .into_compressed();
285 let v = generated::NonZeroCurvePointUncompressedStableV1 {
286 x: crate::bigint::BigInt::from(key.x),
287 is_odd: key.is_odd,
288 };
289 v.into()
290 }
291
292 fn tx_hash(
293 from: &str,
294 to: &str,
295 amount: u64,
296 fee: u64,
297 nonce: u32,
298 valid_until: u32,
299 ) -> String {
300 use crate::{number::Number, string::CharString};
301
302 let from = pub_key(from);
303 let to = pub_key(to);
304
305 let v = Number(fee);
306 let v = generated::UnsignedExtendedUInt64Int64ForVersionTagsStableV1(v);
307 let fee = generated::CurrencyFeeStableV1(v);
308
309 let nonce = generated::UnsignedExtendedUInt32StableV1(Number(nonce));
310
311 let valid_until = generated::UnsignedExtendedUInt32StableV1(Number(valid_until));
312
313 let memo = bs58::decode("E4Yks7aARFemZJqucP5eaARRYRthGdzaFjGfXqQRS3UeidsECRBvR")
314 .with_check(Some(0x14))
315 .into_vec()
316 .unwrap()[1..]
317 .to_vec();
318 let v = CharString::from(&memo[..]);
319 let memo = MinaBaseSignedCommandMemoStableV1(v);
320
321 let common = generated::MinaBaseSignedCommandPayloadCommonStableV2 {
322 fee,
323 fee_payer_pk: from.clone(),
324 nonce,
325 valid_until: MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis(valid_until),
326 memo,
327 };
328
329 let v = Number(amount);
330 let v = generated::UnsignedExtendedUInt64Int64ForVersionTagsStableV1(v);
331 let amount = generated::CurrencyAmountStableV1(v);
332
333 let v = generated::MinaBasePaymentPayloadStableV2 {
334 receiver_pk: to.clone(),
335 amount,
336 };
337 let body = generated::MinaBaseSignedCommandPayloadBodyStableV2::Payment(v);
338
339 let payload = generated::MinaBaseSignedCommandPayloadStableV2 { common, body };
340
341 let signature = generated::MinaBaseSignatureStableV1(
343 BigInt::binprot_read(&mut &[122; 32][..]).unwrap(),
344 BigInt::binprot_read(&mut &[123; 32][..]).unwrap(),
345 );
346
347 let v = generated::MinaBaseSignedCommandStableV2 {
348 payload,
349 signer: from.clone(),
350 signature: signature.into(),
351 };
352 let v = generated::MinaBaseUserCommandStableV2::SignedCommand(v);
353 dbg!(v.hash().unwrap()).to_string()
354 }
355
356 #[test]
368 #[ignore = "fix expected hash/hasing"]
369 fn test_payment_hash_1() {
370 let expected_hash = "5JthQdVqzEJRLBLALeuwPdbnGhFmCow2bVnkfHGH6vZ7R6fiMf2o";
371 let expected_tx_hash: TransactionHash = expected_hash.parse().unwrap();
372 dbg!(expected_tx_hash);
373
374 assert_eq!(
375 tx_hash(
376 "B62qp3B9VW1ir5qL1MWRwr6ecjC2NZbGr8vysGeme9vXGcFXTMNXb2t",
377 "B62qoieQNrsNKCNTZ6R4D6cib3NxVbkwZaAtRVbfS3ndrb2MkFJ1UVJ",
378 1089541195,
379 89541195,
380 26100,
381 u32::MAX,
382 ),
383 expected_hash
384 )
385 }
386}
387
388fn fp_state_hash_from_fp_hashes(previous_state_hash: Fp, body_hash: Fp) -> Fp {
389 let mut inputs = Inputs::new();
390 inputs.append_field(previous_state_hash);
391 inputs.append_field(body_hash);
392 hash_with_kimchi(&MINA_PROTO_STATE, &inputs.to_fields())
393}
394
395impl StateHash {
396 pub fn from_fp(fp: Fp) -> Self {
397 DataHashLibStateHashStableV1(fp.into()).into()
398 }
399
400 pub fn try_from_hashes(
401 pred_state_hash: &StateHash,
402 body_hash: &MinaBaseStateBodyHashStableV1,
403 ) -> Result<Self, InvalidBigInt> {
404 Ok(Self::from_fp(fp_state_hash_from_fp_hashes(
405 pred_state_hash.to_field()?,
406 body_hash.to_field()?,
407 )))
408 }
409}
410
411impl LedgerHash {
412 pub fn from_fp(fp: Fp) -> Self {
413 MinaBaseLedgerHash0StableV1(fp.into()).into()
414 }
415
416 pub fn zero() -> Self {
417 MinaBaseLedgerHash0StableV1(BigInt::zero()).into()
418 }
419}
420
421impl PendingCoinbaseHash {
422 pub fn from_fp(fp: Fp) -> Self {
423 MinaBasePendingCoinbaseHashVersionedStableV1(MinaBasePendingCoinbaseHashBuilderStableV1(
424 fp.into(),
425 ))
426 .into()
427 }
428}
429
430impl generated::MinaStateProtocolStateBodyValueStableV2 {
431 pub fn try_hash(&self) -> Result<MinaBaseStateBodyHashStableV1, InvalidBigInt> {
433 let fp = MinaHash::try_hash(self)?;
434 Ok(MinaBaseStateBodyHashStableV1(fp.into()))
435 }
436}
437
438impl generated::MinaStateProtocolStateValueStableV2 {
439 pub fn try_hash(&self) -> Result<StateHash, InvalidBigInt> {
440 Ok(StateHash::from_fp(MinaHash::try_hash(self)?))
441 }
442}
443
444impl generated::MinaBlockHeaderStableV2 {
445 pub fn try_hash(&self) -> Result<StateHash, InvalidBigInt> {
446 self.protocol_state.try_hash()
447 }
448}
449
450impl generated::MinaBlockBlockStableV2 {
451 pub fn try_hash(&self) -> Result<StateHash, InvalidBigInt> {
452 self.header.protocol_state.try_hash()
453 }
454}
455
456impl MinaHash for MinaStateProtocolStateBodyValueStableV2 {
457 fn try_hash(&self) -> Result<mina_curves::pasta::Fp, InvalidBigInt> {
458 let mut inputs = Inputs::new();
459 self.to_input(&mut inputs)?;
460 Ok(hash_with_kimchi(
461 &MINA_PROTO_STATE_BODY,
462 &inputs.to_fields(),
463 ))
464 }
465}
466
467impl MinaHash for MinaStateProtocolStateValueStableV2 {
468 fn try_hash(&self) -> Result<mina_curves::pasta::Fp, InvalidBigInt> {
469 Ok(fp_state_hash_from_fp_hashes(
470 self.previous_state_hash.to_field()?,
471 MinaHash::try_hash(&self.body)?,
472 ))
473 }
474}
475
476impl FailableToInputs for MinaStateProtocolStateBodyValueStableV2 {
477 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
478 let MinaStateProtocolStateBodyValueStableV2 {
479 genesis_state_hash,
480 blockchain_state,
481 consensus_state,
482 constants,
483 } = self;
484
485 constants.to_input(inputs)?;
486 genesis_state_hash.to_input(inputs)?;
487 blockchain_state.to_input(inputs)?;
488 consensus_state.to_input(inputs)?;
489 Ok(())
490 }
491}
492
493impl FailableToInputs for MinaBaseProtocolConstantsCheckedValueStableV1 {
494 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
495 let MinaBaseProtocolConstantsCheckedValueStableV1 {
496 k,
497 slots_per_epoch,
498 slots_per_sub_window,
499 grace_period_slots,
500 delta,
501 genesis_state_timestamp,
502 } = self;
503
504 k.to_input(inputs)?;
505 delta.to_input(inputs)?;
506 slots_per_epoch.to_input(inputs)?;
507 slots_per_sub_window.to_input(inputs)?;
508 grace_period_slots.to_input(inputs)?;
509 genesis_state_timestamp.to_input(inputs)?;
510 Ok(())
511 }
512}
513
514impl FailableToInputs for MinaStateBlockchainStateValueStableV2 {
515 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
516 let MinaStateBlockchainStateValueStableV2 {
517 staged_ledger_hash,
518 genesis_ledger_hash,
519 ledger_proof_statement,
520 timestamp,
521 body_reference,
522 } = self;
523
524 staged_ledger_hash.to_input(inputs)?;
525 genesis_ledger_hash.to_input(inputs)?;
526 ledger_proof_statement.to_input(inputs)?;
527 timestamp.to_input(inputs)?;
528 body_reference.to_input(inputs)?;
529
530 Ok(())
531 }
532}
533
534impl FailableToInputs for ConsensusProofOfStakeDataConsensusStateValueStableV2 {
535 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
536 let ConsensusProofOfStakeDataConsensusStateValueStableV2 {
537 blockchain_length,
538 epoch_count,
539 min_window_density,
540 sub_window_densities,
541 last_vrf_output,
542 total_currency,
543 curr_global_slot_since_hard_fork,
544 global_slot_since_genesis,
545 staking_epoch_data,
546 next_epoch_data,
547 has_ancestor_in_same_checkpoint_window,
548 block_stake_winner,
549 block_creator,
550 coinbase_receiver,
551 supercharge_coinbase,
552 } = self;
553 blockchain_length.to_input(inputs)?;
554 epoch_count.to_input(inputs)?;
555 min_window_density.to_input(inputs)?;
556 sub_window_densities.to_input(inputs)?;
557 last_vrf_output.to_input(inputs)?;
558 total_currency.to_input(inputs)?;
559 curr_global_slot_since_hard_fork.to_input(inputs)?;
560 global_slot_since_genesis.to_input(inputs)?;
561 has_ancestor_in_same_checkpoint_window.to_input(inputs)?;
562 supercharge_coinbase.to_input(inputs)?;
563 staking_epoch_data.to_input(inputs)?;
564 next_epoch_data.to_input(inputs)?;
565 block_stake_winner.to_input(inputs)?;
566 block_creator.to_input(inputs)?;
567 coinbase_receiver.to_input(inputs)?;
568 Ok(())
569 }
570}
571
572impl FailableToInputs for MinaBaseStagedLedgerHashStableV1 {
573 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
574 let MinaBaseStagedLedgerHashStableV1 {
575 non_snark,
576 pending_coinbase_hash,
577 } = self;
578 non_snark.to_input(inputs)?;
579 pending_coinbase_hash.to_input(inputs)?;
580 Ok(())
581 }
582}
583
584impl FailableToInputs for MinaBaseStagedLedgerHashNonSnarkStableV1 {
585 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
586 inputs.append_bytes(self.sha256().as_ref());
587 Ok(())
588 }
589}
590
591impl FailableToInputs for MinaStateBlockchainStateValueStableV2LedgerProofStatement {
592 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
593 let MinaStateBlockchainStateValueStableV2LedgerProofStatement {
594 source,
595 target,
596 connecting_ledger_left,
597 connecting_ledger_right,
598 supply_increase,
599 fee_excess,
600 sok_digest: _,
601 } = self;
602 source.to_input(inputs)?;
603 target.to_input(inputs)?;
604 connecting_ledger_left.to_input(inputs)?;
605 connecting_ledger_right.to_input(inputs)?;
606 supply_increase.to_input(inputs)?;
607 fee_excess.to_input(inputs)?;
608 Ok(())
609 }
610}
611
612impl FailableToInputs for ConsensusBodyReferenceStableV1 {
613 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
614 inputs.append_bytes(self.as_ref());
615 Ok(())
616 }
617}
618
619impl FailableToInputs for ConsensusVrfOutputTruncatedStableV1 {
620 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
621 let vrf: &[u8] = self.as_ref();
622 inputs.append_bytes(&vrf[..31]);
623 let last_byte = vrf[31];
625 for bit in [1, 2, 4, 8, 16] {
626 inputs.append_bool(last_byte & bit != 0);
627 }
628 Ok(())
629 }
630}
631
632impl FailableToInputs for ConsensusGlobalSlotStableV1 {
633 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
634 let ConsensusGlobalSlotStableV1 {
635 slot_number,
636 slots_per_epoch,
637 } = self;
638 slot_number.to_input(inputs)?;
639 slots_per_epoch.to_input(inputs)?;
640 Ok(())
641 }
642}
643
644impl FailableToInputs for ConsensusProofOfStakeDataEpochDataStakingValueVersionedValueStableV1 {
645 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
646 let ConsensusProofOfStakeDataEpochDataStakingValueVersionedValueStableV1 {
647 ledger,
648 seed,
649 start_checkpoint,
650 lock_checkpoint,
651 epoch_length,
652 } = self;
653 seed.to_input(inputs)?;
654 start_checkpoint.to_input(inputs)?;
655 epoch_length.to_input(inputs)?;
656 ledger.to_input(inputs)?;
657 lock_checkpoint.to_input(inputs)?;
658 Ok(())
659 }
660}
661
662impl FailableToInputs for ConsensusProofOfStakeDataEpochDataNextValueVersionedValueStableV1 {
663 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
664 let ConsensusProofOfStakeDataEpochDataNextValueVersionedValueStableV1 {
665 ledger,
666 seed,
667 start_checkpoint,
668 lock_checkpoint,
669 epoch_length,
670 } = self;
671 seed.to_input(inputs)?;
672 start_checkpoint.to_input(inputs)?;
673 epoch_length.to_input(inputs)?;
674 ledger.to_input(inputs)?;
675 lock_checkpoint.to_input(inputs)?;
676 Ok(())
677 }
678}
679
680impl FailableToInputs for NonZeroCurvePointUncompressedStableV1 {
681 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
682 let NonZeroCurvePointUncompressedStableV1 { x, is_odd } = self;
683 x.to_input(inputs)?;
684 is_odd.to_input(inputs)?;
685 Ok(())
686 }
687}
688
689impl FailableToInputs for MinaStateBlockchainStateValueStableV2LedgerProofStatementSource {
690 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
691 let MinaStateBlockchainStateValueStableV2LedgerProofStatementSource {
692 first_pass_ledger,
693 second_pass_ledger,
694 pending_coinbase_stack,
695 local_state,
696 } = self;
697 first_pass_ledger.to_input(inputs)?;
698 second_pass_ledger.to_input(inputs)?;
699 pending_coinbase_stack.to_input(inputs)?;
700 local_state.to_input(inputs)?;
701 Ok(())
702 }
703}
704
705impl FailableToInputs for SignedAmount {
706 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
707 let SignedAmount { magnitude, sgn } = self;
708 magnitude.to_input(inputs)?;
709 sgn.to_input(inputs)?;
710 Ok(())
711 }
712}
713
714impl FailableToInputs for MinaBaseFeeExcessStableV1 {
715 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
716 let MinaBaseFeeExcessStableV1(left, right) = self;
717 left.to_input(inputs)?;
718 right.to_input(inputs)?;
719 Ok(())
720 }
721}
722
723impl FailableToInputs for TokenFeeExcess {
724 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
725 let TokenFeeExcess { token, amount } = self;
726 token.to_input(inputs)?;
727 amount.to_input(inputs)?;
728 Ok(())
729 }
730}
731
732impl FailableToInputs for MinaBaseEpochLedgerValueStableV1 {
733 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
734 let MinaBaseEpochLedgerValueStableV1 {
735 hash,
736 total_currency,
737 } = self;
738 hash.to_input(inputs)?;
739 total_currency.to_input(inputs)?;
740 Ok(())
741 }
742}
743
744impl FailableToInputs for MinaBasePendingCoinbaseStackVersionedStableV1 {
745 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
746 let MinaBasePendingCoinbaseStackVersionedStableV1 { data, state } = self;
747 data.to_input(inputs)?;
748 state.to_input(inputs)?;
749 Ok(())
750 }
751}
752
753impl FailableToInputs for MinaBasePendingCoinbaseStateStackStableV1 {
754 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
755 let MinaBasePendingCoinbaseStateStackStableV1 { init, curr } = self;
756 init.to_input(inputs)?;
757 curr.to_input(inputs)?;
758 Ok(())
759 }
760}
761
762impl FailableToInputs for MinaTransactionLogicZkappCommandLogicLocalStateValueStableV1 {
763 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
764 let MinaTransactionLogicZkappCommandLogicLocalStateValueStableV1 {
765 stack_frame,
766 call_stack,
767 transaction_commitment,
768 full_transaction_commitment,
769 excess,
770 supply_increase,
771 ledger,
772 success,
773 account_update_index,
774 failure_status_tbl: _,
775 will_succeed,
776 } = self;
777 stack_frame.to_input(inputs)?;
778 call_stack.to_input(inputs)?;
779 transaction_commitment.to_input(inputs)?;
780 full_transaction_commitment.to_input(inputs)?;
781 excess.to_input(inputs)?;
782 supply_increase.to_input(inputs)?;
783 ledger.to_input(inputs)?;
784 account_update_index.to_input(inputs)?;
785 success.to_input(inputs)?;
786 will_succeed.to_input(inputs)?;
787 Ok(())
788 }
789}
790
791impl FailableToInputs for SgnStableV1 {
792 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
793 inputs.append_bool(self == &SgnStableV1::Pos);
794 Ok(())
795 }
796}
797
798impl FailableToInputs for MinaNumbersGlobalSlotSinceGenesisMStableV1 {
799 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
800 match self {
801 MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis(v) => v.to_input(inputs),
802 }
803 }
804}
805
806impl FailableToInputs for MinaStateBlockchainStateValueStableV2SignedAmount {
807 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
808 let MinaStateBlockchainStateValueStableV2SignedAmount { magnitude, sgn } = self;
809 magnitude.to_input(inputs)?;
810 sgn.to_input(inputs)?;
811 Ok(())
812 }
813}
814
815impl FailableToInputs for MinaNumbersGlobalSlotSinceHardForkMStableV1 {
816 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
817 match self {
818 MinaNumbersGlobalSlotSinceHardForkMStableV1::SinceHardFork(v) => v.to_input(inputs),
819 }
820 }
821}
822
823impl FailableToInputs for MinaNumbersGlobalSlotSpanStableV1 {
824 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
825 match self {
826 MinaNumbersGlobalSlotSpanStableV1::GlobalSlotSpan(v) => v.to_input(inputs),
827 }
828 }
829}
830
831#[cfg(test)]
832mod hash_tests {
833 use binprot::BinProtRead;
834
835 use crate::v2::{
836 MinaBaseZkappCommandTStableV1WireStableV1, MinaStateProtocolStateValueStableV2,
837 };
838
839 #[test]
840 #[ignore = "fix expected hash/hasing"]
841 fn state_hash() {
842 const HASH: &str = "3NKpXp2SXWGC3XHnAJYjGtNcbq8tzossqj6kK4eGr6mSyJoFmpxR";
843 const JSON: &str = include_str!("../../tests/files/v2/state/617-3NKpXp2SXWGC3XHnAJYjGtNcbq8tzossqj6kK4eGr6mSyJoFmpxR.json");
844
845 let state: MinaStateProtocolStateValueStableV2 = serde_json::from_str(JSON).unwrap();
846 let hash = state.try_hash().unwrap();
847 let expected_hash = serde_json::from_value(serde_json::json!(HASH)).unwrap();
848 assert_eq!(hash, expected_hash)
849 }
850
851 #[test]
852 fn test_zkapp_with_proof_auth_hash() {
853 let expected_hash = "5JtkEP5AugQKKQAk3YKFxxUDggWf8AiAYyCQy49t2kLHRgPqcP8o".to_string();
857 let bytes = include_bytes!("../../../tests/files/zkapps/with_proof_auth.bin");
858 let zkapp =
859 MinaBaseZkappCommandTStableV1WireStableV1::binprot_read(&mut bytes.as_slice()).unwrap();
860 let hash = zkapp.hash().unwrap().to_string();
861
862 assert_eq!(expected_hash, hash);
863 }
864
865 #[test]
866
867 fn test_zkapp_with_sig_auth_hash() {
868 let expected_hash = "5JvQ6xQeGgCTe2d4KpCsJ97yK61mNRZHixJxPbKTppY1qSGgtj6t".to_string();
869 let bytes = include_bytes!("../../../tests/files/zkapps/with_sig_auth.bin");
870 let zkapp =
871 MinaBaseZkappCommandTStableV1WireStableV1::binprot_read(&mut bytes.as_slice()).unwrap();
872 let hash = zkapp.hash().unwrap().to_string();
873
874 assert_eq!(expected_hash, hash);
875 }
876}