mina_node/external_snark_worker/
external_snark_worker_impls.rs1use ledger::scan_state::scan_state::{
2 transaction_snark::{OneOrTwo, Statement},
3 AvailableJobMessage,
4};
5use mina_p2p_messages::v2::{
6 SnarkWorkerWorkerRpcsVersionedGetWorkV2TResponseA0Instances,
7 SnarkWorkerWorkerRpcsVersionedGetWorkV2TResponseA0Single, StateBodyHash,
8 TransactionSnarkScanStateLedgerProofWithSokMessageStableV2,
9 TransactionSnarkScanStateTransactionWithWitnessStableV2,
10};
11use serde::{Deserialize, Serialize};
12
13use crate::transition_frontier::TransitionFrontierState;
14
15#[derive(Clone, Debug, derive_more::From, Serialize, Deserialize, thiserror::Error)]
16#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
17pub enum SnarkWorkSpecError {
18 #[error("unknown state body hash: {_0}")]
19 UnknownStateBodyHash(StateBodyHash),
20 #[error("error merging statements: {_0}")]
21 MergeStatementError(String),
22 #[error("Invalid BigInt")]
23 InvalidBigInt,
24}
25
26pub fn available_job_to_snark_worker_spec(
27 job: OneOrTwo<AvailableJobMessage>,
28 transition_frontier: &TransitionFrontierState,
29) -> Result<SnarkWorkerWorkerRpcsVersionedGetWorkV2TResponseA0Instances, SnarkWorkSpecError> {
30 Ok(match job {
31 OneOrTwo::One(v) => SnarkWorkerWorkerRpcsVersionedGetWorkV2TResponseA0Instances::One(
32 with_merged_statement(v, transition_frontier)?,
33 ),
34 OneOrTwo::Two((v1, v2)) => {
35 SnarkWorkerWorkerRpcsVersionedGetWorkV2TResponseA0Instances::Two((
36 with_merged_statement(v1, transition_frontier)?,
37 with_merged_statement(v2, transition_frontier)?,
38 ))
39 }
40 })
41}
42
43fn with_merged_statement(
45 job: AvailableJobMessage,
46 transition_frontier: &TransitionFrontierState,
47) -> Result<SnarkWorkerWorkerRpcsVersionedGetWorkV2TResponseA0Single, SnarkWorkSpecError> {
48 match job {
49 AvailableJobMessage::Base(TransactionSnarkScanStateTransactionWithWitnessStableV2 {
50 transaction_with_info,
51 state_hash,
52 statement,
53 init_stack,
54 first_pass_ledger_witness,
55 second_pass_ledger_witness,
56 block_global_slot,
57 }) => {
58 let (transaction, status) = transaction_with_info.varying.into();
59 let mina_p2p_messages::v2::MinaStateSnarkedLedgerStatePendingCoinbaseStackStateInitStackStableV1::Base(init_stack) = init_stack else {
60 panic!("merge in base transaction");
61 };
62 let protocol_state_body = transition_frontier
63 .get_state_body(&state_hash.0)
64 .ok_or_else(|| SnarkWorkSpecError::UnknownStateBodyHash(state_hash.1.clone()))?
65 .clone();
66 let transaction_witness = mina_p2p_messages::v2::TransactionWitnessStableV2 {
67 transaction,
68 first_pass_ledger: first_pass_ledger_witness,
69 second_pass_ledger: second_pass_ledger_witness,
70 protocol_state_body,
71 init_stack,
72 status,
73 block_global_slot,
74 };
75 Ok(
76 SnarkWorkerWorkerRpcsVersionedGetWorkV2TResponseA0Single::Transition(
77 statement,
78 transaction_witness,
79 ),
80 )
81 }
82 AvailableJobMessage::Merge {
83 left:
84 TransactionSnarkScanStateLedgerProofWithSokMessageStableV2(ledger_proof1, _message1),
85 right:
86 TransactionSnarkScanStateLedgerProofWithSokMessageStableV2(ledger_proof2, _message2),
87 } => {
88 let (Ok(ledger_stmt1), Ok(ledger_stmt2)) = (
89 Statement::<()>::try_from(&ledger_proof1.statement),
90 Statement::<()>::try_from(&ledger_proof2.statement),
91 ) else {
92 return Err(SnarkWorkSpecError::InvalidBigInt);
93 };
94 let merged_stmt = ledger_stmt1
95 .merge(&ledger_stmt2)
96 .map_err(SnarkWorkSpecError::MergeStatementError)?;
97 Ok(
98 SnarkWorkerWorkerRpcsVersionedGetWorkV2TResponseA0Single::Merge(Box::new((
99 (&merged_stmt).into(),
100 ledger_proof1,
101 ledger_proof2,
102 ))),
103 )
104 }
105 }
106}