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)]
16pub enum SnarkWorkSpecError {
17    #[error("unknown state body hash: {_0}")]
18    UnknownStateBodyHash(StateBodyHash),
19    #[error("error merging statements: {_0}")]
20    MergeStatementError(String),
21    #[error("Invalid BigInt")]
22    InvalidBigInt,
23}
24
25pub fn available_job_to_snark_worker_spec(
26    job: OneOrTwo<AvailableJobMessage>,
27    transition_frontier: &TransitionFrontierState,
28) -> Result<SnarkWorkerWorkerRpcsVersionedGetWorkV2TResponseA0Instances, SnarkWorkSpecError> {
29    Ok(match job {
30        OneOrTwo::One(v) => SnarkWorkerWorkerRpcsVersionedGetWorkV2TResponseA0Instances::One(
31            with_merged_statement(v, transition_frontier)?,
32        ),
33        OneOrTwo::Two((v1, v2)) => {
34            SnarkWorkerWorkerRpcsVersionedGetWorkV2TResponseA0Instances::Two((
35                with_merged_statement(v1, transition_frontier)?,
36                with_merged_statement(v2, transition_frontier)?,
37            ))
38        }
39    })
40}
41
42/// Converts [AvailableJobMessage] instance to the specification suitable for Mina snark worker.
43fn with_merged_statement(
44    job: AvailableJobMessage,
45    transition_frontier: &TransitionFrontierState,
46) -> Result<SnarkWorkerWorkerRpcsVersionedGetWorkV2TResponseA0Single, SnarkWorkSpecError> {
47    match job {
48        AvailableJobMessage::Base(TransactionSnarkScanStateTransactionWithWitnessStableV2 {
49            transaction_with_info,
50            state_hash,
51            statement,
52            init_stack,
53            first_pass_ledger_witness,
54            second_pass_ledger_witness,
55            block_global_slot,
56        }) => {
57            let (transaction, status) = transaction_with_info.varying.into();
58            let mina_p2p_messages::v2::MinaStateSnarkedLedgerStatePendingCoinbaseStackStateInitStackStableV1::Base(init_stack) = init_stack else {
59                panic!("merge in base transaction");
60            };
61            let protocol_state_body = transition_frontier
62                .get_state_body(&state_hash.0)
63                .ok_or_else(|| SnarkWorkSpecError::UnknownStateBodyHash(state_hash.1.clone()))?
64                .clone();
65            let transaction_witness = mina_p2p_messages::v2::TransactionWitnessStableV2 {
66                transaction,
67                first_pass_ledger: first_pass_ledger_witness,
68                second_pass_ledger: second_pass_ledger_witness,
69                protocol_state_body,
70                init_stack,
71                status,
72                block_global_slot,
73            };
74            Ok(
75                SnarkWorkerWorkerRpcsVersionedGetWorkV2TResponseA0Single::Transition(
76                    statement,
77                    transaction_witness,
78                ),
79            )
80        }
81        AvailableJobMessage::Merge {
82            left:
83                TransactionSnarkScanStateLedgerProofWithSokMessageStableV2(ledger_proof1, _message1),
84            right:
85                TransactionSnarkScanStateLedgerProofWithSokMessageStableV2(ledger_proof2, _message2),
86        } => {
87            let (Ok(ledger_stmt1), Ok(ledger_stmt2)) = (
88                Statement::<()>::try_from(&ledger_proof1.statement),
89                Statement::<()>::try_from(&ledger_proof2.statement),
90            ) else {
91                return Err(SnarkWorkSpecError::InvalidBigInt);
92            };
93            let merged_stmt = ledger_stmt1
94                .merge(&ledger_stmt2)
95                .map_err(SnarkWorkSpecError::MergeStatementError)?;
96            Ok(
97                SnarkWorkerWorkerRpcsVersionedGetWorkV2TResponseA0Single::Merge(Box::new((
98                    (&merged_stmt).into(),
99                    ledger_proof1,
100                    ledger_proof2,
101                ))),
102            )
103        }
104    }
105}