mina_node_common/service/
snarks.rs1use std::sync::Arc;
2
3use ledger::{
4 scan_state::{
5 scan_state::transaction_snark::{SokDigest, Statement},
6 transaction_logic::WithStatus,
7 },
8 transaction_pool::{TransactionError, TransactionPoolErrors},
9};
10use mina_p2p_messages::{bigint::InvalidBigInt, v2};
11use node::{
12 core::{
13 channels::mpsc,
14 snark::{Snark, SnarkJobId},
15 thread,
16 },
17 snark::{
18 block_verify::{SnarkBlockVerifyError, SnarkBlockVerifyId, VerifiableBlockWithHash},
19 work_verify::{SnarkWorkVerifyError, SnarkWorkVerifyId},
20 BlockVerifier, SnarkEvent, TransactionVerifier, VerifierSRS,
21 },
22};
23use rand::prelude::*;
24
25use crate::NodeService;
26
27use super::EventSender;
28
29pub struct SnarkBlockVerifyArgs {
30 pub req_id: SnarkBlockVerifyId,
31 pub verifier_index: BlockVerifier,
32 pub verifier_srs: Arc<VerifierSRS>,
33 pub block: VerifiableBlockWithHash,
34}
35
36impl NodeService {
37 pub fn snark_block_proof_verifier_spawn(
38 event_sender: EventSender,
39 ) -> mpsc::TrackedUnboundedSender<SnarkBlockVerifyArgs> {
40 let (tx, mut rx) = mpsc::tracked_unbounded_channel();
41 thread::Builder::new()
42 .name("block_proof_verifier".to_owned())
43 .spawn(move || {
44 while let Some(msg) = rx.blocking_recv() {
45 let SnarkBlockVerifyArgs {
46 req_id,
47 verifier_index,
48 verifier_srs,
49 block,
50 } = msg.0;
51 eprintln!("verify({}) - start", block.hash_ref());
52 let header = block.header_ref();
53 let result = {
54 if !ledger::proofs::verification::verify_block(
55 header,
56 &verifier_index,
57 &verifier_srs,
58 ) {
59 Err(SnarkBlockVerifyError::VerificationFailed)
60 } else {
61 Ok(())
62 }
63 };
64 eprintln!("verify({}) - end", block.hash_ref());
65
66 let _ = event_sender.send(SnarkEvent::BlockVerify(req_id, result).into());
67 }
68 })
69 .expect("failed to spawn block_proof_verifier thread");
70
71 tx
72 }
73}
74
75impl node::service::SnarkBlockVerifyService for NodeService {
76 fn verify_init(
77 &mut self,
78 req_id: SnarkBlockVerifyId,
79 verifier_index: BlockVerifier,
80 verifier_srs: Arc<VerifierSRS>,
81 block: VerifiableBlockWithHash,
82 ) {
83 if self.replayer.is_some() {
84 return;
85 }
86 let args = SnarkBlockVerifyArgs {
87 req_id,
88 verifier_index,
89 verifier_srs,
90 block,
91 };
92 let _ = self.snark_block_proof_verify.tracked_send(args);
93 }
94}
95
96impl node::service::SnarkWorkVerifyService for NodeService {
97 fn verify_init(
98 &mut self,
99 req_id: SnarkWorkVerifyId,
100 verifier_index: TransactionVerifier,
101 verifier_srs: Arc<VerifierSRS>,
102 work: Vec<Snark>,
103 ) {
104 if self.replayer.is_some() {
105 return;
106 }
107 let tx = self.event_sender().clone();
108 rayon::spawn_fifo(move || {
109 let result = (|| {
110 let conv = |proof: &v2::LedgerProofProdStableV2| -> Result<_, InvalidBigInt> {
111 Ok((
112 Statement::<SokDigest>::try_from(&proof.0.statement)?,
113 proof.proof.clone(),
114 ))
115 };
116 let Ok(works) = work
117 .into_iter()
118 .flat_map(|work| match &*work.proofs {
119 v2::TransactionSnarkWorkTStableV2Proofs::One(v) => {
120 [conv(v).map(Some), Ok(None)]
121 }
122 v2::TransactionSnarkWorkTStableV2Proofs::Two((v1, v2)) => {
123 [conv(v1).map(Some), conv(v2).map(Some)]
124 }
125 })
126 .collect::<Result<Vec<_>, _>>()
127 else {
128 return Err(SnarkWorkVerifyError::VerificationFailed);
129 };
130 if !ledger::proofs::verification::verify_transaction(
131 works.iter().flatten().map(|(v1, v2)| (v1, v2)),
132 &verifier_index,
133 &verifier_srs,
134 ) {
135 Err(SnarkWorkVerifyError::VerificationFailed)
136 } else {
137 Ok(())
138 }
139 })();
140
141 let _ = tx.send(SnarkEvent::WorkVerify(req_id, result).into());
142 });
143 }
144}
145
146impl node::service::SnarkUserCommandVerifyService for NodeService {
147 fn verify_init(
148 &mut self,
149 req_id: node::snark::user_command_verify::SnarkUserCommandVerifyId,
150 commands: Vec<WithStatus<ledger::scan_state::transaction_logic::verifiable::UserCommand>>,
151 ) {
152 if self.replayer.is_some() {
153 return;
154 }
155
156 let tx = self.event_sender().clone();
157 rayon::spawn_fifo(move || {
158 let result = {
159 let (verified, invalid): (Vec<_>, Vec<_>) = ledger::verifier::Verifier
160 .verify_commands(commands, None)
161 .into_iter()
162 .partition(Result::is_ok);
163
164 let verified: Vec<_> = verified.into_iter().map(Result::unwrap).collect();
165 let invalid: Vec<_> = invalid.into_iter().map(Result::unwrap_err).collect();
166
167 if !invalid.is_empty() {
168 let transaction_pool_errors = invalid
169 .into_iter()
170 .map(TransactionError::Verifier)
171 .collect();
172 Err(TransactionPoolErrors::BatchedErrors(
173 transaction_pool_errors,
174 ))
175 } else {
176 Ok(verified)
177 }
178 };
179
180 let result = result.map_err(|err| err.to_string());
181
182 let _ = tx.send(SnarkEvent::UserCommandVerify(req_id, result).into());
183 });
184 }
185}
186
187impl node::service::SnarkPoolService for NodeService {
188 fn random_choose<'a>(
189 &mut self,
190 iter: impl Iterator<Item = &'a SnarkJobId>,
191 n: usize,
192 ) -> Vec<SnarkJobId> {
193 iter.choose_multiple(&mut self.rng, n)
194 .into_iter()
195 .cloned()
196 .collect()
197 }
198}