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