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)]
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
42fn 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}