snark/block_verify/
snark_block_verify_reducer.rs

1use openmina_core::{Substate, SubstateAccess};
2use redux::EnablingCondition;
3
4use crate::block_verify_effectful::SnarkBlockVerifyEffectfulAction;
5
6use super::{
7    SnarkBlockVerifyAction, SnarkBlockVerifyActionWithMetaRef, SnarkBlockVerifyState,
8    SnarkBlockVerifyStatus,
9};
10
11pub fn reducer<State, Action>(
12    mut state_context: Substate<Action, State, SnarkBlockVerifyState>,
13    action: SnarkBlockVerifyActionWithMetaRef<'_>,
14) where
15    State: SubstateAccess<SnarkBlockVerifyState> + SubstateAccess<crate::SnarkState>,
16    Action: From<SnarkBlockVerifyAction>
17        + From<SnarkBlockVerifyEffectfulAction>
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        SnarkBlockVerifyAction::Init {
29            block,
30            on_init,
31            on_success,
32            on_error,
33        } => {
34            let req_id = state.jobs.add(SnarkBlockVerifyStatus::Init {
35                time: meta.time(),
36                block: block.clone(),
37                on_success: on_success.clone(),
38                on_error: on_error.clone(),
39            });
40
41            // Dispatch
42            let verifier_index = state.verifier_index.clone();
43            let verifier_srs = state.verifier_srs.clone();
44            let dispatcher = state_context.into_dispatcher();
45            dispatcher.push_callback(on_init.clone(), (block.hash_ref().clone(), req_id));
46            dispatcher.push(SnarkBlockVerifyEffectfulAction::Init {
47                req_id,
48                block: block.clone(),
49                verifier_index,
50                verifier_srs,
51            });
52            dispatcher.push(SnarkBlockVerifyAction::Pending { req_id });
53        }
54        SnarkBlockVerifyAction::Pending { req_id } => {
55            if let Some(req) = state.jobs.get_mut(*req_id) {
56                *req = match req {
57                    SnarkBlockVerifyStatus::Init {
58                        block,
59                        on_success,
60                        on_error,
61                        ..
62                    } => SnarkBlockVerifyStatus::Pending {
63                        time: meta.time(),
64                        block: block.clone(),
65                        on_success: on_success.clone(),
66                        on_error: on_error.clone(),
67                    },
68                    _ => return,
69                };
70            }
71        }
72        SnarkBlockVerifyAction::Error { req_id, error, .. } => {
73            let callback_and_arg = state.jobs.get_mut(*req_id).and_then(|req| {
74                if let SnarkBlockVerifyStatus::Pending {
75                    block, on_error, ..
76                } = req
77                {
78                    let callback = on_error.clone();
79                    let block_hash = block.hash_ref().clone();
80                    *req = SnarkBlockVerifyStatus::Error {
81                        time: meta.time(),
82                        block: block.clone(),
83                        error: error.clone(),
84                    };
85
86                    Some((callback, (block_hash, error.clone())))
87                } else {
88                    None
89                }
90            });
91
92            // Dispatch
93            let dispatcher = state_context.into_dispatcher();
94
95            if let Some((callback, args)) = callback_and_arg {
96                dispatcher.push_callback(callback, args);
97            }
98
99            dispatcher.push(SnarkBlockVerifyAction::Finish { req_id: *req_id });
100        }
101        SnarkBlockVerifyAction::Success { req_id, .. } => {
102            let callback_and_arg = state.jobs.get_mut(*req_id).and_then(|req| {
103                if let SnarkBlockVerifyStatus::Pending {
104                    block, on_success, ..
105                } = req
106                {
107                    let callback = on_success.clone();
108                    let block_hash = block.hash_ref().clone();
109                    *req = SnarkBlockVerifyStatus::Success {
110                        time: meta.time(),
111                        block: block.clone(),
112                    };
113                    Some((callback, block_hash))
114                } else {
115                    None
116                }
117            });
118
119            // Dispatch
120            let dispatcher = state_context.into_dispatcher();
121
122            if let Some((callback, block_hash)) = callback_and_arg {
123                dispatcher.push_callback(callback, block_hash);
124            }
125
126            dispatcher.push(SnarkBlockVerifyAction::Finish { req_id: *req_id });
127        }
128        SnarkBlockVerifyAction::Finish { req_id, .. } => {
129            state.jobs.remove(*req_id);
130        }
131    }
132}