sc_proof_of_time/source/
state.rs1use crate::verifier::PotVerifier;
2use parking_lot::Mutex;
3use sp_consensus_slots::Slot;
4use sp_consensus_subspace::{PotNextSlotInput, PotParametersChange};
5use subspace_core_primitives::pot::PotOutput;
6
7#[derive(Debug, Copy, Clone, Eq, PartialEq)]
8struct InnerState {
9 next_slot_input: PotNextSlotInput,
10 parameters_change: Option<PotParametersChange>,
11}
12
13impl InnerState {
14 pub(super) fn update(
15 mut self,
16 mut best_slot: Slot,
17 mut best_output: PotOutput,
18 maybe_updated_parameters_change: Option<Option<PotParametersChange>>,
19 pot_verifier: &PotVerifier,
20 ) -> Self {
21 if let Some(updated_parameters_change) = maybe_updated_parameters_change {
22 self.parameters_change = updated_parameters_change;
23 }
24
25 loop {
26 self.next_slot_input = PotNextSlotInput::derive(
27 self.next_slot_input.slot_iterations,
28 best_slot,
29 best_output,
30 &self.parameters_change,
31 );
32
33 if let Some(checkpoints) = pot_verifier.try_get_checkpoints(
35 self.next_slot_input.slot_iterations,
36 self.next_slot_input.seed,
37 ) {
38 best_slot = self.next_slot_input.slot;
39 best_output = checkpoints.output();
40 } else {
41 break;
42 }
43 }
44
45 self
46 }
47}
48
49#[derive(Debug)]
50pub(super) enum PotStateUpdateOutcome {
51 NoChange,
52 Extension {
53 from: PotNextSlotInput,
54 to: PotNextSlotInput,
55 },
56 Reorg {
57 from: PotNextSlotInput,
58 to: PotNextSlotInput,
59 },
60}
61
62#[derive(Debug)]
63pub(super) struct PotState {
64 inner_state: Mutex<InnerState>,
65 verifier: PotVerifier,
66}
67
68impl PotState {
69 pub(super) fn new(
70 next_slot_input: PotNextSlotInput,
71 parameters_change: Option<PotParametersChange>,
72 verifier: PotVerifier,
73 ) -> Self {
74 let inner = InnerState {
75 next_slot_input,
76 parameters_change,
77 };
78
79 Self {
80 inner_state: Mutex::new(inner),
81 verifier,
82 }
83 }
84
85 pub(super) fn next_slot_input(&self) -> PotNextSlotInput {
86 self.inner_state.lock().next_slot_input
87 }
88
89 pub(super) fn try_extend(
94 &self,
95 expected_existing_next_slot_input: PotNextSlotInput,
96 best_slot: Slot,
97 best_output: PotOutput,
98 maybe_updated_parameters_change: Option<Option<PotParametersChange>>,
99 ) -> Result<PotNextSlotInput, PotNextSlotInput> {
100 let mut existing_inner_state = self.inner_state.lock();
101 if expected_existing_next_slot_input != existing_inner_state.next_slot_input {
102 return Err(existing_inner_state.next_slot_input);
103 }
104
105 *existing_inner_state = existing_inner_state.update(
106 best_slot,
107 best_output,
108 maybe_updated_parameters_change,
109 &self.verifier,
110 );
111
112 Ok(existing_inner_state.next_slot_input)
113 }
114
115 pub(super) fn update(
119 &self,
120 best_slot: Slot,
121 best_output: PotOutput,
122 maybe_updated_parameters_change: Option<Option<PotParametersChange>>,
123 ) -> PotStateUpdateOutcome {
124 let previous_best_state;
125 let new_best_state;
126 {
127 let mut inner_state = self.inner_state.lock();
128 previous_best_state = *inner_state;
129 new_best_state = previous_best_state.update(
130 best_slot,
131 best_output,
132 maybe_updated_parameters_change,
133 &self.verifier,
134 );
135 *inner_state = new_best_state;
136 }
137
138 if previous_best_state.next_slot_input == new_best_state.next_slot_input {
139 return PotStateUpdateOutcome::NoChange;
140 }
141
142 if previous_best_state.next_slot_input.slot < new_best_state.next_slot_input.slot {
143 let mut slot_iterations = previous_best_state.next_slot_input.slot_iterations;
144 let mut seed = previous_best_state.next_slot_input.seed;
145
146 for slot in u64::from(previous_best_state.next_slot_input.slot)
147 ..u64::from(new_best_state.next_slot_input.slot)
148 {
149 let slot = Slot::from(slot);
150
151 let Some(checkpoints) = self.verifier.try_get_checkpoints(slot_iterations, seed)
152 else {
153 break;
154 };
155
156 let pot_input = PotNextSlotInput::derive(
157 slot_iterations,
158 slot,
159 checkpoints.output(),
160 &maybe_updated_parameters_change.flatten(),
161 );
162
163 let next_slot = slot + Slot::from(1);
166 slot_iterations = pot_input.slot_iterations;
167 seed = pot_input.seed;
168
169 if next_slot == new_best_state.next_slot_input.slot
170 && slot_iterations == new_best_state.next_slot_input.slot_iterations
171 && seed == new_best_state.next_slot_input.seed
172 {
173 return PotStateUpdateOutcome::Extension {
174 from: previous_best_state.next_slot_input,
175 to: new_best_state.next_slot_input,
176 };
177 }
178 }
179 }
180
181 PotStateUpdateOutcome::Reorg {
182 from: previous_best_state.next_slot_input,
183 to: new_best_state.next_slot_input,
184 }
185 }
186}