node/snark_pool/
snark_pool_actions.rs1use std::sync::Arc;
2
3use ledger::scan_state::scan_state::{transaction_snark::OneOrTwo, AvailableJobMessage};
4use openmina_core::{
5 snark::{Snark, SnarkJobCommitment, SnarkJobId},
6 ActionEvent,
7};
8use serde::{Deserialize, Serialize};
9
10use crate::p2p::PeerId;
11
12use super::{candidate::SnarkPoolCandidateAction, SnarkWork};
13
14pub type SnarkPoolActionWithMeta = redux::ActionWithMeta<SnarkPoolAction>;
15pub type SnarkPoolActionWithMetaRef<'a> = redux::ActionWithMeta<&'a SnarkPoolAction>;
16
17#[derive(Serialize, Deserialize, Debug, Clone, ActionEvent)]
18pub enum SnarkPoolAction {
19 Candidate(SnarkPoolCandidateAction),
20
21 JobsUpdate {
22 jobs: Arc<Vec<OneOrTwo<AvailableJobMessage>>>,
23 orphaned_snarks: Vec<SnarkWork>,
24 },
25 AutoCreateCommitment,
26 CommitmentCreateMany {
27 job_ids: Vec<SnarkJobId>,
28 },
29 CommitmentCreate {
30 job_id: SnarkJobId,
31 },
32 CommitmentAdd {
33 commitment: SnarkJobCommitment,
34 sender: PeerId,
35 },
36 #[action_event(level = info, fields(is_sender_local))]
37 WorkAdd {
38 snark: Snark,
39 sender: PeerId,
40 is_sender_local: bool,
41 },
42 #[action_event(level = trace)]
43 P2pSendAll,
44 #[action_event(level = trace)]
45 P2pSend {
46 peer_id: PeerId,
47 },
48 CheckTimeouts,
49 JobCommitmentTimeout {
50 job_id: SnarkJobId,
51 },
52}
53
54impl redux::EnablingCondition<crate::State> for SnarkPoolAction {
55 fn is_enabled(&self, state: &crate::State, time: redux::Timestamp) -> bool {
56 match self {
57 SnarkPoolAction::Candidate(action) => action.is_enabled(state, time),
58 SnarkPoolAction::AutoCreateCommitment => {
59 state.config.snarker.as_ref().is_some_and(|v| v.auto_commit)
60 }
61 SnarkPoolAction::CommitmentCreateMany { .. } => state.config.snarker.is_some(),
62 SnarkPoolAction::CommitmentCreate { job_id } => {
63 state.config.snarker.is_some() && state.snark_pool.should_create_commitment(job_id)
64 }
65 SnarkPoolAction::CommitmentAdd { commitment, .. } => state
66 .snark_pool
67 .get(&commitment.job_id)
68 .is_some_and(|s| match s.commitment.as_ref() {
69 Some(cur) => commitment > &cur.commitment,
70 None => true,
71 }),
72 SnarkPoolAction::WorkAdd { snark, .. } => state
73 .snark_pool
74 .get(&snark.job_id())
75 .is_some_and(|s| match s.snark.as_ref() {
76 Some(cur) => snark > &cur.work,
77 None => true,
78 }),
79 SnarkPoolAction::P2pSend { peer_id } => state
80 .p2p
81 .get_ready_peer(peer_id)
82 .filter(|_| !state.snark_pool.is_empty())
84 .and_then(|p| {
93 let peer_best_tip = p.best_tip.as_ref()?;
94 let our_best_tip = state.transition_frontier.best_tip()?.hash();
95 Some(p).filter(|_| {
96 peer_best_tip.hash() == our_best_tip
97 || peer_best_tip.pred_hash() == our_best_tip
98 })
99 })
100 .is_some_and(|p| {
101 let check =
102 |(next_index, limit), last_index| limit > 0 && next_index <= last_index;
103 let last_index = state.snark_pool.last_index();
104
105 check(
106 p.channels.snark_job_commitment.next_send_index_and_limit(),
107 last_index,
108 ) || check(p.channels.snark.next_send_index_and_limit(), last_index)
109 }),
110 SnarkPoolAction::CheckTimeouts => time
111 .checked_sub(state.snark_pool.last_check_timeouts)
112 .is_some_and(|dur| dur.as_secs() >= 5),
113 SnarkPoolAction::JobCommitmentTimeout { job_id } => {
114 state.snark_pool.is_commitment_timed_out(job_id, time)
115 }
116 SnarkPoolAction::JobsUpdate { .. } => true,
117 SnarkPoolAction::P2pSendAll => true,
118 }
119 }
120}
121
122#[derive(Serialize, Deserialize, Debug, Clone)]
125pub enum SnarkPoolEffectfulAction {
126 SnarkPoolJobsRandomChoose {
127 choices: Vec<SnarkJobId>,
128 count: usize,
129 on_result: redux::Callback<Vec<SnarkJobId>>,
130 },
131}
132
133pub type SnarkPoolEffectfulActionWithMeta = redux::ActionWithMeta<SnarkPoolEffectfulAction>;
134
135impl redux::EnablingCondition<crate::State> for SnarkPoolEffectfulAction {
136 fn is_enabled(&self, _state: &crate::State, _time: redux::Timestamp) -> bool {
137 true
138 }
139}