snark/work_verify/
snark_work_verify_reducer.rs

1use openmina_core::{bug_condition, snark::Snark, Substate, SubstateAccess};
2use redux::EnablingCondition;
3
4use crate::work_verify_effectful::SnarkWorkVerifyEffectfulAction;
5
6use super::{
7    SnarkWorkVerifyAction, SnarkWorkVerifyActionWithMetaRef, SnarkWorkVerifyState,
8    SnarkWorkVerifyStatus,
9};
10
11pub fn reducer<State, Action>(
12    mut state_context: Substate<Action, State, SnarkWorkVerifyState>,
13    action: SnarkWorkVerifyActionWithMetaRef<'_>,
14) where
15    State: SubstateAccess<SnarkWorkVerifyState> + SubstateAccess<crate::SnarkState>,
16    Action: From<SnarkWorkVerifyAction>
17        + From<SnarkWorkVerifyEffectfulAction>
18        + From<redux::AnyAction>
19        + EnablingCondition<State>,
20{
21    let Ok(state) = state_context.get_substate_mut() else {
22        // TODO: log or propagate
23        return;
24    };
25    let (action, meta) = action.split();
26
27    match action {
28        SnarkWorkVerifyAction::Init {
29            batch,
30            sender,
31            req_id,
32            on_error,
33            on_success,
34        } => {
35            state.jobs.add(SnarkWorkVerifyStatus::Init {
36                time: meta.time(),
37                batch: batch.clone(),
38                sender: sender.clone(),
39                on_error: on_error.clone(),
40                on_success: on_success.clone(),
41            });
42
43            // Dispatch
44            let verifier_index = state.verifier_index.clone();
45            let verifier_srs = state.verifier_srs.clone();
46            let dispatcher = state_context.into_dispatcher();
47            dispatcher.push(SnarkWorkVerifyEffectfulAction::Init {
48                req_id: *req_id,
49                batch: batch.clone(),
50                verifier_index,
51                verifier_srs,
52            });
53            dispatcher.push(SnarkWorkVerifyAction::Pending { req_id: *req_id });
54        }
55        SnarkWorkVerifyAction::Pending { req_id } => {
56            if let Some(req) = state.jobs.get_mut(*req_id) {
57                *req = match req {
58                    SnarkWorkVerifyStatus::Init {
59                        batch,
60                        sender,
61                        on_error,
62                        on_success,
63                        ..
64                    } => SnarkWorkVerifyStatus::Pending {
65                        time: meta.time(),
66                        batch: std::mem::take(batch),
67                        sender: std::mem::take(sender),
68                        on_error: on_error.clone(),
69                        on_success: on_success.clone(),
70                    },
71                    _ => return,
72                };
73            }
74        }
75        SnarkWorkVerifyAction::Error { req_id, error } => {
76            let Some(req) = state.jobs.get_mut(*req_id) else {
77                bug_condition!(
78                    "Invalid state for `SnarkWorkVerifyAction::Error` job not found with id: {}",
79                    req_id
80                );
81                return;
82            };
83            let SnarkWorkVerifyStatus::Pending {
84                batch,
85                sender,
86                on_error,
87                ..
88            } = req
89            else {
90                bug_condition!(
91                    "Invalid state of `SnarkWorkVerifyStatus` for `SnarkWorkVerifyAction::Error`"
92                );
93                return;
94            };
95            let callback = on_error.clone();
96            let sender = std::mem::take(sender);
97            let batch = std::mem::take(batch);
98            let job_ids = batch.iter().map(Snark::job_id).collect();
99            *req = SnarkWorkVerifyStatus::Error {
100                time: meta.time(),
101                batch,
102                sender: sender.clone(),
103                error: error.clone(),
104            };
105            // Dispatch
106            let dispatcher = state_context.into_dispatcher();
107            dispatcher.push_callback(callback, (*req_id, sender, job_ids));
108            dispatcher.push(SnarkWorkVerifyAction::Finish { req_id: *req_id });
109        }
110        SnarkWorkVerifyAction::Success { req_id } => {
111            let Some(req) = state.jobs.get_mut(*req_id) else {
112                bug_condition!(
113                    "Invalid state for `SnarkWorkVerifyAction::Success` job not found with id: {}",
114                    req_id
115                );
116                return;
117            };
118            let SnarkWorkVerifyStatus::Pending {
119                batch,
120                sender,
121                on_success,
122                ..
123            } = req
124            else {
125                bug_condition!(
126                    "Invalid state of `SnarkWorkVerifyStatus` for `SnarkWorkVerifyAction::Error`"
127                );
128                return;
129            };
130
131            let callback = on_success.clone();
132            let sender = std::mem::take(sender);
133            let batch = std::mem::take(batch);
134
135            *req = SnarkWorkVerifyStatus::Success {
136                time: meta.time(),
137                batch: batch.clone(),
138                sender: sender.clone(),
139            };
140
141            // Dispatch
142            let dispatcher = state_context.into_dispatcher();
143            dispatcher.push_callback(callback, (*req_id, sender, batch));
144            dispatcher.push(SnarkWorkVerifyAction::Finish { req_id: *req_id });
145        }
146        SnarkWorkVerifyAction::Finish { req_id } => {
147            state.jobs.remove(*req_id);
148        }
149    }
150}