node/external_snark_worker/
external_snark_worker_actions.rs

1use std::time::Duration;
2
3use openmina_core::{snark::SnarkJobId, ActionEvent};
4use redux::{EnablingCondition, Timestamp};
5use serde::{Deserialize, Serialize};
6
7use crate::{snark_pool::JobSummary, State};
8
9use super::{
10    ExternalSnarkWorkerError, ExternalSnarkWorkerState, ExternalSnarkWorkerWorkError,
11    SnarkWorkResult,
12};
13
14#[derive(Debug, Clone, Serialize, Deserialize, ActionEvent)]
15#[action_event(fields(display(job_id), display(error)))]
16pub enum ExternalSnarkWorkerAction {
17    Start,
18    Started,
19    StartTimeout {
20        now: Timestamp,
21    },
22    Kill,
23    Killed,
24
25    SubmitWork {
26        job_id: SnarkJobId,
27        summary: JobSummary,
28    },
29    WorkResult {
30        result: SnarkWorkResult,
31    },
32    WorkError {
33        error: ExternalSnarkWorkerWorkError,
34    },
35    WorkTimeout {
36        now: Timestamp,
37    },
38
39    CancelWork,
40    WorkCancelled,
41
42    PruneWork,
43
44    Error {
45        error: ExternalSnarkWorkerError,
46        permanent: bool,
47    },
48}
49
50pub type ExternalSnarkWorkerActionWithMetaRef<'a> =
51    redux::ActionWithMeta<&'a ExternalSnarkWorkerAction>;
52
53impl EnablingCondition<State> for ExternalSnarkWorkerAction {
54    fn is_enabled(&self, state: &State, _time: redux::Timestamp) -> bool {
55        match self {
56            ExternalSnarkWorkerAction::Start => {
57                state.config.snarker.is_some()
58                    && matches!(
59                        state.external_snark_worker.0.state,
60                        ExternalSnarkWorkerState::None
61                    )
62            }
63            ExternalSnarkWorkerAction::Started => {
64                matches!(
65                    state.external_snark_worker.0.state,
66                    ExternalSnarkWorkerState::Starting
67                )
68            }
69            ExternalSnarkWorkerAction::StartTimeout { now } => {
70                const TIMEOUT: Duration = Duration::from_secs(120);
71                matches!(
72                    state.external_snark_worker.0.state,
73                    ExternalSnarkWorkerState::Starting
74                ) && now
75                    .checked_sub(state.external_snark_worker.0.timestamp)
76                    .is_some_and(|d| d > TIMEOUT)
77            }
78            ExternalSnarkWorkerAction::Kill => !matches!(
79                state.external_snark_worker.0.state,
80                ExternalSnarkWorkerState::Error(_, false)
81                    | ExternalSnarkWorkerState::None
82                    | ExternalSnarkWorkerState::Killing
83            ),
84            ExternalSnarkWorkerAction::Killed => {
85                matches!(
86                    state.external_snark_worker.0.state,
87                    ExternalSnarkWorkerState::Killing
88                )
89            }
90            ExternalSnarkWorkerAction::SubmitWork { .. } => state.external_snark_worker.is_idle(),
91            ExternalSnarkWorkerAction::WorkResult { .. } => {
92                matches!(
93                    state.external_snark_worker.0.state,
94                    ExternalSnarkWorkerState::Working(..)
95                )
96            }
97            ExternalSnarkWorkerAction::WorkError { .. } => {
98                matches!(
99                    state.external_snark_worker.0.state,
100                    ExternalSnarkWorkerState::Working(..)
101                )
102            }
103            ExternalSnarkWorkerAction::WorkTimeout { now } => {
104                if let ExternalSnarkWorkerState::Working(_, summary) =
105                    &state.external_snark_worker.0.state
106                {
107                    now.checked_sub(state.external_snark_worker.0.timestamp)
108                        .is_some_and(|d| d > summary.estimated_duration())
109                } else {
110                    false
111                }
112            }
113            ExternalSnarkWorkerAction::CancelWork => {
114                matches!(
115                    state.external_snark_worker.0.state,
116                    ExternalSnarkWorkerState::Working(..)
117                )
118            }
119            ExternalSnarkWorkerAction::WorkCancelled => {
120                matches!(
121                    state.external_snark_worker.0.state,
122                    ExternalSnarkWorkerState::Cancelling(_)
123                )
124            }
125            ExternalSnarkWorkerAction::PruneWork => {
126                matches!(
127                    state.external_snark_worker.0.state,
128                    ExternalSnarkWorkerState::WorkReady(..)
129                        | ExternalSnarkWorkerState::WorkError(..)
130                        | ExternalSnarkWorkerState::Cancelled(..)
131                )
132            }
133            ExternalSnarkWorkerAction::Error { .. } => true,
134        }
135    }
136}