1use openmina_core::constants::ConstraintConstants;
2
3use crate::{
4 scan_state::{
5 currency::{Amount, Magnitude},
6 scan_state::transaction_snark::work,
7 transaction_logic::{
8 valid, CoinbaseFeeTransfer, TransactionStatus, UserCommand, WithStatus,
9 },
10 },
11 split_at_vec,
12 verifier::VerifierError,
13};
14
15use super::{pre_diff_info::PreDiffError, staged_ledger::StagedLedger};
16
17#[derive(Clone, PartialEq)]
19pub enum AtMostTwo<T> {
20 Zero,
21 One(Option<T>),
22 Two(Option<(T, Option<T>)>),
23}
24
25impl<T> std::fmt::Debug for AtMostTwo<T> {
26 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27 match self {
28 Self::Zero => write!(f, "Zero"),
29 Self::One(_) => f.debug_tuple("One(_)").finish(),
30 Self::Two(_) => f.debug_tuple("Two(_, _)").finish(),
31 }
32 }
33}
34
35#[derive(Clone, PartialEq)]
37pub enum AtMostOne<T> {
38 Zero,
39 One(Option<T>),
40}
41
42impl<T> std::fmt::Debug for AtMostOne<T> {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 match self {
45 Self::Zero => write!(f, "Zero"),
46 Self::One(_) => f.debug_tuple("One(_)").finish(),
47 }
48 }
49}
50
51#[derive(Clone, PartialEq)]
53pub struct PreDiffTwo<A, B> {
54 pub completed_works: Vec<A>,
55 pub commands: Vec<B>,
56 pub coinbase: AtMostTwo<CoinbaseFeeTransfer>,
57 pub internal_command_statuses: Vec<TransactionStatus>,
58}
59
60impl<A, B> std::fmt::Debug for PreDiffTwo<A, B> {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 let Self {
63 completed_works,
64 commands,
65 coinbase,
66 internal_command_statuses,
67 } = self;
68
69 f.debug_struct("PreDiffTwo")
70 .field("completed_works", &completed_works.len())
71 .field("commands", &commands.len())
72 .field("coinbase", coinbase)
73 .field("internal_command_statuses", internal_command_statuses)
74 .finish()
75 }
76}
77
78#[derive(Clone, PartialEq)]
80pub struct PreDiffOne<A, B> {
81 pub completed_works: Vec<A>,
82 pub commands: Vec<B>,
83 pub coinbase: AtMostOne<CoinbaseFeeTransfer>,
84 pub internal_command_statuses: Vec<TransactionStatus>,
85}
86
87impl<A, B> std::fmt::Debug for PreDiffOne<A, B> {
88 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89 let Self {
90 completed_works,
91 commands,
92 coinbase,
93 internal_command_statuses,
94 } = self;
95
96 f.debug_struct("PreDiffOne")
97 .field("completed_works", &completed_works.len())
98 .field("commands", &commands.len())
99 .field("coinbase", coinbase)
100 .field("internal_command_statuses", internal_command_statuses)
101 .finish()
102 }
103}
104
105pub type PreDiffWithAtMostTwoCoinbase = PreDiffTwo<work::Work, WithStatus<UserCommand>>;
107
108pub type PreDiffWithAtMostOneCoinbase = PreDiffOne<work::Work, WithStatus<UserCommand>>;
110
111#[derive(Debug, Clone, PartialEq)]
113pub struct Diff {
114 pub diff: (
115 PreDiffWithAtMostTwoCoinbase,
116 Option<PreDiffWithAtMostOneCoinbase>,
117 ),
118}
119
120impl Diff {
121 pub fn completed_works(&self) -> Vec<work::Work> {
123 let first = self.diff.0.completed_works.as_slice();
124
125 let second = match self.diff.1.as_ref() {
126 Some(second) => second.completed_works.as_slice(),
127 None => &[],
128 };
129
130 first.iter().chain(second).cloned().collect()
131 }
132
133 pub fn commands(&self) -> Vec<WithStatus<UserCommand>> {
135 let first = self.diff.0.commands.as_slice();
136
137 let second = match self.diff.1.as_ref() {
138 Some(second) => second.commands.as_slice(),
139 None => &[],
140 };
141
142 first.iter().chain(second).cloned().collect()
143 }
144
145 pub fn validate_commands<F>(self, check: F) -> Result<with_valid_signatures::Diff, PreDiffError>
147 where
148 F: Fn(Vec<WithStatus<UserCommand>>) -> Result<Vec<valid::UserCommand>, VerifierError>,
149 {
150 let validate = |cmds: Vec<WithStatus<UserCommand>>| -> Result<Vec<WithStatus<valid::UserCommand>>, VerifierError> {
151 let valids = check(cmds.clone())?;
152 Ok(valids.into_iter().zip(cmds).map(|(data, c)| {
153 WithStatus { data, status: c.status }
154 }).collect())
155 };
156
157 let commands = self.commands();
158
159 let (d1, d2) = self.diff;
160
161 let commands_all = validate(commands)?;
162
163 let (commands1, commands2) = split_at_vec(commands_all, d1.commands.len());
164
165 let p1 = with_valid_signatures::PreDiffWithAtMostTwoCoinbase {
166 completed_works: d1.completed_works,
167 commands: commands1,
168 coinbase: d1.coinbase,
169 internal_command_statuses: d1.internal_command_statuses,
170 };
171
172 let p2 = d2.map(|d2| with_valid_signatures::PreDiffWithAtMostOneCoinbase {
173 completed_works: d2.completed_works,
174 commands: commands2,
175 coinbase: d2.coinbase,
176 internal_command_statuses: d2.internal_command_statuses,
177 });
178
179 Ok(with_valid_signatures::Diff { diff: (p1, p2) })
180 }
181
182 pub fn empty() -> Self {
183 Self {
184 diff: (
185 PreDiffWithAtMostTwoCoinbase {
186 completed_works: Vec::new(),
187 commands: Vec::new(),
188 coinbase: AtMostTwo::Zero,
189 internal_command_statuses: Vec::new(),
190 },
191 None,
192 ),
193 }
194 }
195}
196
197pub mod with_valid_signatures_and_proofs {
198 use super::*;
199
200 pub type PreDiffWithAtMostTwoCoinbase =
202 PreDiffTwo<work::Checked, WithStatus<valid::UserCommand>>;
203
204 pub type PreDiffWithAtMostOneCoinbase =
206 PreDiffOne<work::Checked, WithStatus<valid::UserCommand>>;
207
208 #[derive(Clone, Debug)]
210 pub struct Diff {
211 pub diff: (
212 PreDiffWithAtMostTwoCoinbase,
213 Option<PreDiffWithAtMostOneCoinbase>,
214 ),
215 }
216
217 fn forget_cw(list: Vec<work::Checked>) -> Vec<work::Unchecked> {
219 list.into_iter().map(work::Checked::forget).collect()
220 }
221
222 impl Diff {
223 pub fn commands(&self) -> Vec<WithStatus<valid::UserCommand>> {
224 let first = self.diff.0.commands.as_slice();
225
226 let second = match self.diff.1.as_ref() {
227 Some(second) => second.commands.as_slice(),
228 None => &[],
229 };
230
231 first.iter().chain(second).cloned().collect()
232 }
233
234 pub fn forget_proof_checks(self) -> super::with_valid_signatures::Diff {
236 let d1 = self.diff.0;
237
238 let p1 = with_valid_signatures::PreDiffWithAtMostTwoCoinbase {
239 completed_works: forget_cw(d1.completed_works),
240 commands: d1.commands,
241 coinbase: d1.coinbase,
242 internal_command_statuses: d1.internal_command_statuses,
243 };
244
245 let p2 = self
246 .diff
247 .1
248 .map(|d2| with_valid_signatures::PreDiffWithAtMostOneCoinbase {
249 completed_works: forget_cw(d2.completed_works),
250 commands: d2.commands,
251 coinbase: d2.coinbase,
252 internal_command_statuses: d2.internal_command_statuses,
253 });
254
255 super::with_valid_signatures::Diff { diff: (p1, p2) }
256 }
257
258 pub fn forget(self) -> super::Diff {
260 let d1 = self.diff.0;
261 let p1 = super::PreDiffWithAtMostTwoCoinbase {
262 completed_works: forget_cw(d1.completed_works),
263 commands: d1
264 .commands
265 .into_iter()
266 .map(|c| c.map(|c| c.forget_check()))
267 .collect(),
268 coinbase: d1.coinbase,
269 internal_command_statuses: d1.internal_command_statuses,
270 };
271
272 let d2 = self.diff.1;
273 let p2 = d2.map(|d2| super::PreDiffWithAtMostOneCoinbase {
274 completed_works: forget_cw(d2.completed_works),
275 commands: d2
276 .commands
277 .into_iter()
278 .map(|c| c.map(|c| c.forget_check()))
279 .collect(),
280 coinbase: d2.coinbase,
281 internal_command_statuses: d2.internal_command_statuses,
282 });
283
284 super::Diff { diff: (p1, p2) }
285 }
286
287 pub fn empty() -> Self {
288 Self {
289 diff: (
290 PreDiffWithAtMostTwoCoinbase {
291 completed_works: Vec::new(),
292 commands: Vec::new(),
293 coinbase: AtMostTwo::Zero,
294 internal_command_statuses: Vec::new(),
295 },
296 None,
297 ),
298 }
299 }
300 }
301}
302
303pub mod with_valid_signatures {
304 use super::*;
305
306 pub type PreDiffWithAtMostTwoCoinbase = PreDiffTwo<work::Work, WithStatus<valid::UserCommand>>;
307
308 pub type PreDiffWithAtMostOneCoinbase = PreDiffOne<work::Work, WithStatus<valid::UserCommand>>;
309
310 pub struct Diff {
311 pub diff: (
312 PreDiffWithAtMostTwoCoinbase,
313 Option<PreDiffWithAtMostOneCoinbase>,
314 ),
315 }
316
317 impl Diff {
318 pub fn empty() -> Self {
319 Self {
320 diff: (
321 PreDiffWithAtMostTwoCoinbase {
322 completed_works: Vec::new(),
323 commands: Vec::new(),
324 coinbase: AtMostTwo::Zero,
325 internal_command_statuses: Vec::new(),
326 },
327 None,
328 ),
329 }
330 }
331 }
332}
333
334pub fn coinbase<A, B>(
336 diff: &(PreDiffTwo<A, B>, Option<PreDiffOne<A, B>>),
337 constraint_constants: &ConstraintConstants,
338 supercharge_coinbase: bool,
339) -> Option<Amount> {
340 let (first_pre_diff, second_pre_diff_opt) = &diff;
341 let coinbase_amount = StagedLedger::coinbase_amount(supercharge_coinbase, constraint_constants);
342
343 match (
344 &first_pre_diff.coinbase,
345 second_pre_diff_opt
346 .as_ref()
347 .map(|s| &s.coinbase)
348 .unwrap_or(&AtMostOne::Zero),
349 ) {
350 (AtMostTwo::Zero, AtMostOne::Zero) => Some(Amount::zero()),
351 _ => coinbase_amount,
352 }
353}