Skip to main content

mina_node/external_snark_worker/
external_snark_worker_impls.rs

1use 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
43/// Converts [AvailableJobMessage] instance to the specification suitable for Mina snark worker.
44fn 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}