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
159#[cfg(feature = "openapi")]
160const _: () = {
161 use utoipa::{PartialSchema, ToSchema};
162
163 impl PartialSchema for TransactionHash {
164 fn schema() -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
165 <String as PartialSchema>::schema()
167 }
168 }
169 impl ToSchema for TransactionHash {
170 fn name() -> std::borrow::Cow<'static, str> {
171 std::borrow::Cow::Borrowed("TransactionHash")
172 }
173 }
174};
175
176impl generated::MinaTransactionTransactionStableV2 {
177 pub fn hash(&self) -> io::Result<TransactionHash> {
178 match self {
179 Self::Command(v) => v.hash(),
180 Self::FeeTransfer(_) => Err(io::Error::new(
181 io::ErrorKind::Unsupported,
182 "fee transfer tx hashing is not yet supported",
183 )),
184 Self::Coinbase(_) => Err(io::Error::new(
185 io::ErrorKind::Unsupported,
186 "coinbase tx hashing is not yet supported",
187 )),
188 }
189 }
190}
191
192impl generated::MinaBaseUserCommandStableV2 {
193 pub fn hash(&self) -> io::Result<TransactionHash> {
194 match self {
195 Self::SignedCommand(v) => v.hash(),
196 Self::ZkappCommand(v) => v.hash(),
197 }
198 }
199}
200
201impl generated::MinaBaseSignedCommandStableV2 {
202 pub fn binprot_write_with_default_sig(&self) -> io::Result<Vec<u8>> {
203 let default_signature = generated::MinaBaseSignatureStableV1(BigInt::one(), BigInt::one());
204
205 let mut encoded = vec![];
206 self.payload.binprot_write(&mut encoded)?;
207 self.signer.binprot_write(&mut encoded)?;
208 default_signature.binprot_write(&mut encoded)?;
209 Ok(encoded)
210 }
211
212 pub fn hash(&self) -> io::Result<TransactionHash> {
213 use blake2::{
214 digest::{Update, VariableOutput},
215 Blake2bVar,
216 };
217 let mut hasher = Blake2bVar::new(32).expect("Invalid Blake2bVar output size");
218
219 hasher.update(&self.binprot_write_with_default_sig()?);
220 let mut hash = [0; 32];
221 hasher
222 .finalize_variable(&mut hash)
223 .expect("Invalid buffer size"); Ok(TransactionHash(hash.into()))
226 }
227}
228
229impl generated::MinaBaseZkappCommandTStableV1WireStableV1 {
231 fn binprot_write_with_default(&self) -> io::Result<Vec<u8>> {
232 let default_signature = generated::MinaBaseSignatureStableV1(BigInt::one(), BigInt::one());
233
234 let mut encoded = vec![];
235
236 let mut modified = self.clone();
237
238 modified.fee_payer.authorization = default_signature.clone().into();
239
240 modified.account_updates.iter_mut().for_each(|u| {
241 Self::replace_auth_recursive(&mut u.elt);
242 });
243
244 modified.binprot_write(&mut encoded)?;
245 Ok(encoded)
246 }
247
248 fn replace_auth_recursive(
249 update_elt: &mut MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesAA,
250 ) {
251 Self::replace_auth(&mut update_elt.account_update.authorization);
252 update_elt.calls.iter_mut().for_each(|call| {
257 Self::replace_auth_recursive(&mut call.elt);
258 });
259
260 }
264
265 pub fn replace_auth(auth: &mut MinaBaseControlStableV2) {
266 let default_signature = generated::MinaBaseSignatureStableV1(BigInt::one(), BigInt::one());
267 let default_proof = super::dummy_transaction_proof();
268 *auth = match auth {
269 MinaBaseControlStableV2::Proof(_) => {
270 MinaBaseControlStableV2::Proof(Box::new(default_proof.0.clone().into()))
271 }
272 MinaBaseControlStableV2::Signature(_) => {
273 MinaBaseControlStableV2::Signature(default_signature.clone().into())
274 }
275 MinaBaseControlStableV2::NoneGiven => MinaBaseControlStableV2::NoneGiven,
276 };
277 }
278
279 pub fn hash(&self) -> io::Result<TransactionHash> {
280 use blake2::{
281 digest::{Update, VariableOutput},
282 Blake2bVar,
283 };
284 let mut hasher = Blake2bVar::new(32).expect("Invalid Blake2bVar output size");
285
286 hasher.update(&self.binprot_write_with_default()?);
287 let mut hash = [0; 32];
288 hasher
289 .finalize_variable(&mut hash)
290 .expect("Invalid buffer size"); Ok(TransactionHash(hash.into()))
293 }
294}
295
296#[cfg(test)]
297mod tests {
298 use super::{super::manual, *};
299 use manual::MinaBaseSignedCommandMemoStableV1;
300
301 fn pub_key(address: &str) -> manual::NonZeroCurvePoint {
302 let key = mina_signer::PubKey::from_address(address)
303 .unwrap()
304 .into_compressed();
305 let v = generated::NonZeroCurvePointUncompressedStableV1 {
306 x: crate::bigint::BigInt::from(key.x),
307 is_odd: key.is_odd,
308 };
309 v.into()
310 }
311
312 fn tx_hash(
313 from: &str,
314 to: &str,
315 amount: u64,
316 fee: u64,
317 nonce: u32,
318 valid_until: u32,
319 ) -> String {
320 use crate::{number::Number, string::CharString};
321
322 let from = pub_key(from);
323 let to = pub_key(to);
324
325 let v = Number(fee);
326 let v = generated::UnsignedExtendedUInt64Int64ForVersionTagsStableV1(v);
327 let fee = generated::CurrencyFeeStableV1(v);
328
329 let nonce = generated::UnsignedExtendedUInt32StableV1(Number(nonce));
330
331 let valid_until = generated::UnsignedExtendedUInt32StableV1(Number(valid_until));
332
333 let memo = bs58::decode("E4Yks7aARFemZJqucP5eaARRYRthGdzaFjGfXqQRS3UeidsECRBvR")
334 .with_check(Some(0x14))
335 .into_vec()
336 .unwrap()[1..]
337 .to_vec();
338 let v = CharString::from(&memo[..]);
339 let memo = MinaBaseSignedCommandMemoStableV1(v);
340
341 let common = generated::MinaBaseSignedCommandPayloadCommonStableV2 {
342 fee,
343 fee_payer_pk: from.clone(),
344 nonce,
345 valid_until: MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis(valid_until),
346 memo,
347 };
348
349 let v = Number(amount);
350 let v = generated::UnsignedExtendedUInt64Int64ForVersionTagsStableV1(v);
351 let amount = generated::CurrencyAmountStableV1(v);
352
353 let v = generated::MinaBasePaymentPayloadStableV2 {
354 receiver_pk: to.clone(),
355 amount,
356 };
357 let body = generated::MinaBaseSignedCommandPayloadBodyStableV2::Payment(v);
358
359 let payload = generated::MinaBaseSignedCommandPayloadStableV2 { common, body };
360
361 let signature = generated::MinaBaseSignatureStableV1(
363 BigInt::binprot_read(&mut &[122; 32][..]).unwrap(),
364 BigInt::binprot_read(&mut &[123; 32][..]).unwrap(),
365 );
366
367 let v = generated::MinaBaseSignedCommandStableV2 {
368 payload,
369 signer: from.clone(),
370 signature: signature.into(),
371 };
372 let v = generated::MinaBaseUserCommandStableV2::SignedCommand(v);
373 dbg!(v.hash().unwrap()).to_string()
374 }
375
376 #[test]
388 #[ignore = "fix expected hash/hasing"]
389 fn test_payment_hash_1() {
390 let expected_hash = "5JthQdVqzEJRLBLALeuwPdbnGhFmCow2bVnkfHGH6vZ7R6fiMf2o";
391 let expected_tx_hash: TransactionHash = expected_hash.parse().unwrap();
392 dbg!(expected_tx_hash);
393
394 assert_eq!(
395 tx_hash(
396 "B62qp3B9VW1ir5qL1MWRwr6ecjC2NZbGr8vysGeme9vXGcFXTMNXb2t",
397 "B62qoieQNrsNKCNTZ6R4D6cib3NxVbkwZaAtRVbfS3ndrb2MkFJ1UVJ",
398 1089541195,
399 89541195,
400 26100,
401 u32::MAX,
402 ),
403 expected_hash
404 )
405 }
406}
407
408fn fp_state_hash_from_fp_hashes(previous_state_hash: Fp, body_hash: Fp) -> Fp {
409 let mut inputs = Inputs::new();
410 inputs.append_field(previous_state_hash);
411 inputs.append_field(body_hash);
412 hash_with_kimchi(&MINA_PROTO_STATE, &inputs.to_fields())
413}
414
415impl StateHash {
416 pub fn from_fp(fp: Fp) -> Self {
417 DataHashLibStateHashStableV1(fp.into()).into()
418 }
419
420 pub fn try_from_hashes(
421 pred_state_hash: &StateHash,
422 body_hash: &MinaBaseStateBodyHashStableV1,
423 ) -> Result<Self, InvalidBigInt> {
424 Ok(Self::from_fp(fp_state_hash_from_fp_hashes(
425 pred_state_hash.to_field().map_err(|_| InvalidBigInt)?,
426 body_hash.to_field()?,
427 )))
428 }
429}
430
431impl LedgerHash {
432 pub fn from_fp(fp: Fp) -> Self {
433 MinaBaseLedgerHash0StableV1(fp.into()).into()
434 }
435
436 pub fn zero() -> Self {
437 MinaBaseLedgerHash0StableV1(BigInt::zero()).into()
438 }
439}
440
441impl PendingCoinbaseHash {
442 pub fn from_fp(fp: Fp) -> Self {
443 MinaBasePendingCoinbaseHashVersionedStableV1(MinaBasePendingCoinbaseHashBuilderStableV1(
444 fp.into(),
445 ))
446 .into()
447 }
448}
449
450impl generated::MinaStateProtocolStateBodyValueStableV2 {
451 pub fn try_hash(&self) -> Result<MinaBaseStateBodyHashStableV1, InvalidBigInt> {
453 let fp = MinaHash::try_hash(self)?;
454 Ok(MinaBaseStateBodyHashStableV1(fp.into()))
455 }
456}
457
458impl generated::MinaStateProtocolStateValueStableV2 {
459 pub fn try_hash(&self) -> Result<StateHash, InvalidBigInt> {
460 Ok(StateHash::from_fp(MinaHash::try_hash(self)?))
461 }
462}
463
464impl generated::MinaBlockHeaderStableV2 {
465 pub fn try_hash(&self) -> Result<StateHash, InvalidBigInt> {
466 self.protocol_state.try_hash()
467 }
468}
469
470impl generated::MinaBlockBlockStableV2 {
471 pub fn try_hash(&self) -> Result<StateHash, InvalidBigInt> {
472 self.header.protocol_state.try_hash()
473 }
474}
475
476impl MinaHash for MinaStateProtocolStateBodyValueStableV2 {
477 fn try_hash(&self) -> Result<mina_curves::pasta::Fp, InvalidBigInt> {
478 let mut inputs = Inputs::new();
479 self.to_input(&mut inputs)?;
480 Ok(hash_with_kimchi(
481 &MINA_PROTO_STATE_BODY,
482 &inputs.to_fields(),
483 ))
484 }
485}
486
487impl MinaHash for MinaStateProtocolStateValueStableV2 {
488 fn try_hash(&self) -> Result<mina_curves::pasta::Fp, InvalidBigInt> {
489 Ok(fp_state_hash_from_fp_hashes(
490 self.previous_state_hash
491 .to_field()
492 .map_err(|_| InvalidBigInt)?,
493 MinaHash::try_hash(&self.body)?,
494 ))
495 }
496}
497
498impl FailableToInputs for MinaStateProtocolStateBodyValueStableV2 {
499 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
500 let MinaStateProtocolStateBodyValueStableV2 {
501 genesis_state_hash,
502 blockchain_state,
503 consensus_state,
504 constants,
505 } = self;
506
507 constants.to_input(inputs)?;
508 genesis_state_hash.to_input(inputs)?;
509 blockchain_state.to_input(inputs)?;
510 consensus_state.to_input(inputs)?;
511 Ok(())
512 }
513}
514
515impl FailableToInputs for MinaBaseProtocolConstantsCheckedValueStableV1 {
516 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
517 let MinaBaseProtocolConstantsCheckedValueStableV1 {
518 k,
519 slots_per_epoch,
520 slots_per_sub_window,
521 grace_period_slots,
522 delta,
523 genesis_state_timestamp,
524 } = self;
525
526 k.to_input(inputs)?;
527 delta.to_input(inputs)?;
528 slots_per_epoch.to_input(inputs)?;
529 slots_per_sub_window.to_input(inputs)?;
530 grace_period_slots.to_input(inputs)?;
531 genesis_state_timestamp.to_input(inputs)?;
532 Ok(())
533 }
534}
535
536impl FailableToInputs for MinaStateBlockchainStateValueStableV2 {
537 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
538 let MinaStateBlockchainStateValueStableV2 {
539 staged_ledger_hash,
540 genesis_ledger_hash,
541 ledger_proof_statement,
542 timestamp,
543 body_reference,
544 } = self;
545
546 staged_ledger_hash.to_input(inputs)?;
547 genesis_ledger_hash.to_input(inputs)?;
548 ledger_proof_statement.to_input(inputs)?;
549 timestamp.to_input(inputs)?;
550 body_reference.to_input(inputs)?;
551
552 Ok(())
553 }
554}
555
556impl FailableToInputs for ConsensusProofOfStakeDataConsensusStateValueStableV2 {
557 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
558 let ConsensusProofOfStakeDataConsensusStateValueStableV2 {
559 blockchain_length,
560 epoch_count,
561 min_window_density,
562 sub_window_densities,
563 last_vrf_output,
564 total_currency,
565 curr_global_slot_since_hard_fork,
566 global_slot_since_genesis,
567 staking_epoch_data,
568 next_epoch_data,
569 has_ancestor_in_same_checkpoint_window,
570 block_stake_winner,
571 block_creator,
572 coinbase_receiver,
573 supercharge_coinbase,
574 } = self;
575 blockchain_length.to_input(inputs)?;
576 epoch_count.to_input(inputs)?;
577 min_window_density.to_input(inputs)?;
578 sub_window_densities.to_input(inputs)?;
579 last_vrf_output.to_input(inputs)?;
580 total_currency.to_input(inputs)?;
581 curr_global_slot_since_hard_fork.to_input(inputs)?;
582 global_slot_since_genesis.to_input(inputs)?;
583 has_ancestor_in_same_checkpoint_window.to_input(inputs)?;
584 supercharge_coinbase.to_input(inputs)?;
585 staking_epoch_data.to_input(inputs)?;
586 next_epoch_data.to_input(inputs)?;
587 block_stake_winner.to_input(inputs)?;
588 block_creator.to_input(inputs)?;
589 coinbase_receiver.to_input(inputs)?;
590 Ok(())
591 }
592}
593
594impl FailableToInputs for MinaBaseStagedLedgerHashStableV1 {
595 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
596 let MinaBaseStagedLedgerHashStableV1 {
597 non_snark,
598 pending_coinbase_hash,
599 } = self;
600 non_snark.to_input(inputs)?;
601 pending_coinbase_hash.to_input(inputs)?;
602 Ok(())
603 }
604}
605
606impl FailableToInputs for MinaBaseStagedLedgerHashNonSnarkStableV1 {
607 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
608 inputs.append_bytes(self.sha256().as_ref());
609 Ok(())
610 }
611}
612
613impl FailableToInputs for MinaStateBlockchainStateValueStableV2LedgerProofStatement {
614 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
615 let MinaStateBlockchainStateValueStableV2LedgerProofStatement {
616 source,
617 target,
618 connecting_ledger_left,
619 connecting_ledger_right,
620 supply_increase,
621 fee_excess,
622 sok_digest: _,
623 } = self;
624 source.to_input(inputs)?;
625 target.to_input(inputs)?;
626 connecting_ledger_left.to_input(inputs)?;
627 connecting_ledger_right.to_input(inputs)?;
628 supply_increase.to_input(inputs)?;
629 fee_excess.to_input(inputs)?;
630 Ok(())
631 }
632}
633
634impl FailableToInputs for ConsensusBodyReferenceStableV1 {
635 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
636 inputs.append_bytes(self.as_ref());
637 Ok(())
638 }
639}
640
641impl FailableToInputs for ConsensusVrfOutputTruncatedStableV1 {
642 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
643 let vrf: &[u8] = self.as_ref();
644 inputs.append_bytes(&vrf[..31]);
645 let last_byte = vrf[31];
647 for bit in [1, 2, 4, 8, 16] {
648 inputs.append_bool(last_byte & bit != 0);
649 }
650 Ok(())
651 }
652}
653
654impl FailableToInputs for ConsensusGlobalSlotStableV1 {
655 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
656 let ConsensusGlobalSlotStableV1 {
657 slot_number,
658 slots_per_epoch,
659 } = self;
660 slot_number.to_input(inputs)?;
661 slots_per_epoch.to_input(inputs)?;
662 Ok(())
663 }
664}
665
666impl FailableToInputs for ConsensusProofOfStakeDataEpochDataStakingValueVersionedValueStableV1 {
667 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
668 let ConsensusProofOfStakeDataEpochDataStakingValueVersionedValueStableV1 {
669 ledger,
670 seed,
671 start_checkpoint,
672 lock_checkpoint,
673 epoch_length,
674 } = self;
675 seed.to_input(inputs)?;
676 start_checkpoint.to_input(inputs)?;
677 epoch_length.to_input(inputs)?;
678 ledger.to_input(inputs)?;
679 lock_checkpoint.to_input(inputs)?;
680 Ok(())
681 }
682}
683
684impl FailableToInputs for ConsensusProofOfStakeDataEpochDataNextValueVersionedValueStableV1 {
685 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
686 let ConsensusProofOfStakeDataEpochDataNextValueVersionedValueStableV1 {
687 ledger,
688 seed,
689 start_checkpoint,
690 lock_checkpoint,
691 epoch_length,
692 } = self;
693 seed.to_input(inputs)?;
694 start_checkpoint.to_input(inputs)?;
695 epoch_length.to_input(inputs)?;
696 ledger.to_input(inputs)?;
697 lock_checkpoint.to_input(inputs)?;
698 Ok(())
699 }
700}
701
702impl FailableToInputs for NonZeroCurvePointUncompressedStableV1 {
703 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
704 let NonZeroCurvePointUncompressedStableV1 { x, is_odd } = self;
705 x.to_input(inputs)?;
706 is_odd.to_input(inputs)?;
707 Ok(())
708 }
709}
710
711impl FailableToInputs for MinaStateBlockchainStateValueStableV2LedgerProofStatementSource {
712 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
713 let MinaStateBlockchainStateValueStableV2LedgerProofStatementSource {
714 first_pass_ledger,
715 second_pass_ledger,
716 pending_coinbase_stack,
717 local_state,
718 } = self;
719 first_pass_ledger.to_input(inputs)?;
720 second_pass_ledger.to_input(inputs)?;
721 pending_coinbase_stack.to_input(inputs)?;
722 local_state.to_input(inputs)?;
723 Ok(())
724 }
725}
726
727impl FailableToInputs for SignedAmount {
728 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
729 let SignedAmount { magnitude, sgn } = self;
730 magnitude.to_input(inputs)?;
731 sgn.to_input(inputs)?;
732 Ok(())
733 }
734}
735
736impl FailableToInputs for MinaBaseFeeExcessStableV1 {
737 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
738 let MinaBaseFeeExcessStableV1(left, right) = self;
739 left.to_input(inputs)?;
740 right.to_input(inputs)?;
741 Ok(())
742 }
743}
744
745impl FailableToInputs for TokenFeeExcess {
746 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
747 let TokenFeeExcess { token, amount } = self;
748 token.to_input(inputs)?;
749 amount.to_input(inputs)?;
750 Ok(())
751 }
752}
753
754impl FailableToInputs for MinaBaseEpochLedgerValueStableV1 {
755 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
756 let MinaBaseEpochLedgerValueStableV1 {
757 hash,
758 total_currency,
759 } = self;
760 hash.to_input(inputs)?;
761 total_currency.to_input(inputs)?;
762 Ok(())
763 }
764}
765
766impl FailableToInputs for MinaBasePendingCoinbaseStackVersionedStableV1 {
767 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
768 let MinaBasePendingCoinbaseStackVersionedStableV1 { data, state } = self;
769 data.to_input(inputs)?;
770 state.to_input(inputs)?;
771 Ok(())
772 }
773}
774
775impl FailableToInputs for MinaBasePendingCoinbaseStateStackStableV1 {
776 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
777 let MinaBasePendingCoinbaseStateStackStableV1 { init, curr } = self;
778 init.to_input(inputs)?;
779 curr.to_input(inputs)?;
780 Ok(())
781 }
782}
783
784impl FailableToInputs for MinaTransactionLogicZkappCommandLogicLocalStateValueStableV1 {
785 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
786 let MinaTransactionLogicZkappCommandLogicLocalStateValueStableV1 {
787 stack_frame,
788 call_stack,
789 transaction_commitment,
790 full_transaction_commitment,
791 excess,
792 supply_increase,
793 ledger,
794 success,
795 account_update_index,
796 failure_status_tbl: _,
797 will_succeed,
798 } = self;
799 stack_frame.to_input(inputs)?;
800 call_stack.to_input(inputs)?;
801 transaction_commitment.to_input(inputs)?;
802 full_transaction_commitment.to_input(inputs)?;
803 excess.to_input(inputs)?;
804 supply_increase.to_input(inputs)?;
805 ledger.to_input(inputs)?;
806 account_update_index.to_input(inputs)?;
807 success.to_input(inputs)?;
808 will_succeed.to_input(inputs)?;
809 Ok(())
810 }
811}
812
813impl FailableToInputs for SgnStableV1 {
814 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
815 inputs.append_bool(self == &SgnStableV1::Pos);
816 Ok(())
817 }
818}
819
820impl FailableToInputs for MinaNumbersGlobalSlotSinceGenesisMStableV1 {
821 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
822 match self {
823 MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis(v) => v.to_input(inputs),
824 }
825 }
826}
827
828impl FailableToInputs for MinaStateBlockchainStateValueStableV2SignedAmount {
829 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
830 let MinaStateBlockchainStateValueStableV2SignedAmount { magnitude, sgn } = self;
831 magnitude.to_input(inputs)?;
832 sgn.to_input(inputs)?;
833 Ok(())
834 }
835}
836
837impl FailableToInputs for MinaNumbersGlobalSlotSinceHardForkMStableV1 {
838 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
839 match self {
840 MinaNumbersGlobalSlotSinceHardForkMStableV1::SinceHardFork(v) => v.to_input(inputs),
841 }
842 }
843}
844
845impl FailableToInputs for MinaNumbersGlobalSlotSpanStableV1 {
846 fn to_input(&self, inputs: &mut Inputs) -> Result<(), InvalidBigInt> {
847 match self {
848 MinaNumbersGlobalSlotSpanStableV1::GlobalSlotSpan(v) => v.to_input(inputs),
849 }
850 }
851}
852
853#[cfg(test)]
854mod hash_tests {
855 use binprot::BinProtRead;
856
857 use crate::v2::{
858 MinaBaseZkappCommandTStableV1WireStableV1, MinaStateProtocolStateValueStableV2,
859 };
860
861 #[test]
862 #[ignore = "fix expected hash/hasing"]
863 fn state_hash() {
864 const HASH: &str = "3NKpXp2SXWGC3XHnAJYjGtNcbq8tzossqj6kK4eGr6mSyJoFmpxR";
865 const JSON: &str = include_str!("../../tests/files/v2/state/617-3NKpXp2SXWGC3XHnAJYjGtNcbq8tzossqj6kK4eGr6mSyJoFmpxR.json");
866
867 let state: MinaStateProtocolStateValueStableV2 = serde_json::from_str(JSON).unwrap();
868 let hash = state.try_hash().unwrap();
869 let expected_hash = serde_json::from_value(serde_json::json!(HASH)).unwrap();
870 assert_eq!(hash, expected_hash)
871 }
872
873 #[test]
874 fn test_zkapp_with_proof_auth_hash() {
875 let expected_hash = "5JtkEP5AugQKKQAk3YKFxxUDggWf8AiAYyCQy49t2kLHRgPqcP8o".to_string();
879 let bytes = include_bytes!("../../../../tests/files/zkapps/with_proof_auth.bin");
880 let zkapp =
881 MinaBaseZkappCommandTStableV1WireStableV1::binprot_read(&mut bytes.as_slice()).unwrap();
882 let hash = zkapp.hash().unwrap().to_string();
883
884 assert_eq!(expected_hash, hash);
885 }
886
887 #[test]
888
889 fn test_zkapp_with_sig_auth_hash() {
890 let expected_hash = "5JvQ6xQeGgCTe2d4KpCsJ97yK61mNRZHixJxPbKTppY1qSGgtj6t".to_string();
891 let bytes = include_bytes!("../../../../tests/files/zkapps/with_sig_auth.bin");
892 let zkapp =
893 MinaBaseZkappCommandTStableV1WireStableV1::binprot_read(&mut bytes.as_slice()).unwrap();
894 let hash = zkapp.hash().unwrap().to_string();
895
896 assert_eq!(expected_hash, hash);
897 }
898}