ab_client_proof_of_time/source/
state.rs1use crate::PotNextSlotInput;
2use crate::verifier::PotVerifier;
3use ab_core_primitives::pot::{PotOutput, PotParametersChange, SlotNumber};
4use parking_lot::Mutex;
5
6#[derive(Debug, Copy, Clone, Eq, PartialEq)]
7struct InnerState {
8 next_slot_input: PotNextSlotInput,
9 parameters_change: Option<PotParametersChange>,
10}
11
12impl InnerState {
13 #[expect(
14 clippy::option_option,
15 reason = "External option indicates whether the change should be done, while internal is \
16 the value itself"
17 )]
18 fn update(
19 mut self,
20 mut slot: SlotNumber,
21 mut output: PotOutput,
22 maybe_updated_parameters_change: Option<Option<PotParametersChange>>,
23 pot_verifier: &PotVerifier,
24 ) -> Self {
25 if let Some(updated_parameters_change) = maybe_updated_parameters_change {
26 self.parameters_change = updated_parameters_change;
27 }
28
29 loop {
30 self.next_slot_input = PotNextSlotInput::derive(
31 self.next_slot_input.slot_iterations,
32 slot,
33 output,
34 &self.parameters_change,
35 );
36
37 if let Some(checkpoints) = pot_verifier.try_get_checkpoints(
39 self.next_slot_input.slot_iterations,
40 self.next_slot_input.seed,
41 ) {
42 slot = self.next_slot_input.slot;
43 output = checkpoints.output();
44 } else {
45 break;
46 }
47 }
48
49 self
50 }
51}
52
53#[derive(Debug)]
55pub enum PotStateSetOutcome {
56 NoChange,
58 Extension {
60 from: PotNextSlotInput,
61 to: PotNextSlotInput,
62 },
63 Reorg {
65 from: PotNextSlotInput,
66 to: PotNextSlotInput,
67 },
68}
69
70#[derive(Debug)]
74pub struct PotState {
75 inner_state: Mutex<InnerState>,
76 verifier: PotVerifier,
77}
78
79impl PotState {
80 pub fn new(
82 next_slot_input: PotNextSlotInput,
83 parameters_change: Option<PotParametersChange>,
84 verifier: PotVerifier,
85 ) -> Self {
86 let inner = InnerState {
87 next_slot_input,
88 parameters_change,
89 };
90
91 Self {
92 inner_state: Mutex::new(inner),
93 verifier,
94 }
95 }
96
97 pub fn next_slot_input(&self) -> PotNextSlotInput {
99 self.inner_state.lock().next_slot_input
100 }
101
102 pub fn try_extend(
107 &self,
108 expected_existing_next_slot_input: PotNextSlotInput,
109 best_slot: SlotNumber,
110 best_output: PotOutput,
111 maybe_updated_parameters_change: Option<Option<PotParametersChange>>,
112 ) -> Result<PotNextSlotInput, PotNextSlotInput> {
113 let mut existing_inner_state = self.inner_state.lock();
114 if expected_existing_next_slot_input != existing_inner_state.next_slot_input {
115 return Err(existing_inner_state.next_slot_input);
116 }
117
118 *existing_inner_state = existing_inner_state.update(
119 best_slot,
120 best_output,
121 maybe_updated_parameters_change,
122 &self.verifier,
123 );
124
125 Ok(existing_inner_state.next_slot_input)
126 }
127
128 pub fn set_known_good_output(
134 &self,
135 slot: SlotNumber,
136 output: PotOutput,
137 updated_parameters_change: Option<PotParametersChange>,
138 ) -> PotStateSetOutcome {
139 let previous_best_state;
140 let new_best_state;
141 {
142 let mut inner_state = self.inner_state.lock();
143 previous_best_state = *inner_state;
144 new_best_state = previous_best_state.update(
145 slot,
146 output,
147 Some(updated_parameters_change),
148 &self.verifier,
149 );
150 *inner_state = new_best_state;
151 }
152
153 if previous_best_state.next_slot_input == new_best_state.next_slot_input {
154 return PotStateSetOutcome::NoChange;
155 }
156
157 if previous_best_state.next_slot_input.slot < new_best_state.next_slot_input.slot {
158 let mut slot_iterations = previous_best_state.next_slot_input.slot_iterations;
159 let mut seed = previous_best_state.next_slot_input.seed;
160
161 for slot in
162 previous_best_state.next_slot_input.slot..new_best_state.next_slot_input.slot
163 {
164 let Some(checkpoints) = self.verifier.try_get_checkpoints(slot_iterations, seed)
165 else {
166 break;
167 };
168
169 let pot_input = PotNextSlotInput::derive(
170 slot_iterations,
171 slot,
172 checkpoints.output(),
173 &updated_parameters_change,
174 );
175
176 let next_slot = slot + SlotNumber::ONE;
179 slot_iterations = pot_input.slot_iterations;
180 seed = pot_input.seed;
181
182 if next_slot == new_best_state.next_slot_input.slot
183 && slot_iterations == new_best_state.next_slot_input.slot_iterations
184 && seed == new_best_state.next_slot_input.seed
185 {
186 return PotStateSetOutcome::Extension {
187 from: previous_best_state.next_slot_input,
188 to: new_best_state.next_slot_input,
189 };
190 }
191 }
192 }
193
194 PotStateSetOutcome::Reorg {
195 from: previous_best_state.next_slot_input,
196 to: new_best_state.next_slot_input,
197 }
198 }
199}