battleware_types/
api.rs

1use crate::{
2    execution::{Output, Progress, Seed, Transaction, Value},
3    Identity, NAMESPACE,
4};
5use bytes::{Buf, BufMut};
6use commonware_codec::{EncodeSize, Error, Read, ReadExt, ReadRangeExt, Write};
7use commonware_consensus::aggregation::types::Certificate;
8use commonware_cryptography::{
9    bls12381::primitives::variant::MinSig, ed25519::PublicKey, sha256::Digest, Digestible, Sha256,
10};
11use commonware_storage::{
12    adb::{verify::verify_proof_and_extract_digests, verify_multi_proof, verify_proof},
13    mmr::{hasher::Standard, verification::Proof},
14    store::operation::{Keyless, Variable},
15};
16
17/// Maximum number of transactions that can be submitted in a single submission
18pub const MAX_SUBMISSION_TRANSACTIONS: usize = 128;
19
20pub enum Query {
21    Latest,
22    Index(u64),
23}
24
25impl Write for Query {
26    fn write(&self, writer: &mut impl BufMut) {
27        match self {
28            Query::Latest => 0u8.write(writer),
29            Query::Index(index) => {
30                1u8.write(writer);
31                index.write(writer);
32            }
33        }
34    }
35}
36
37impl Read for Query {
38    type Cfg = ();
39
40    fn read_cfg(reader: &mut impl Buf, _: &Self::Cfg) -> Result<Self, Error> {
41        let kind = u8::read(reader)?;
42        match kind {
43            0 => Ok(Query::Latest),
44            1 => Ok(Query::Index(u64::read(reader)?)),
45            _ => Err(Error::InvalidEnum(kind)),
46        }
47    }
48}
49
50impl EncodeSize for Query {
51    fn encode_size(&self) -> usize {
52        1 + match self {
53            Query::Latest => 0,
54            Query::Index(index) => index.encode_size(),
55        }
56    }
57}
58
59#[derive(Clone, Eq, PartialEq, Debug)]
60pub struct Summary {
61    pub progress: Progress,
62    pub certificate: Certificate<MinSig, Digest>,
63    pub state_proof: Proof<Digest>,
64    pub state_proof_ops: Vec<Variable<Digest, Value>>,
65    pub events_proof: Proof<Digest>,
66    pub events_proof_ops: Vec<Keyless<Output>>,
67}
68
69impl Summary {
70    /// Verify the summary and return the digests from both state and events proofs.
71    /// Returns (state_digests, events_digests) on success.
72    #[allow(clippy::type_complexity)]
73    pub fn verify(&self, identity: &Identity) -> Option<(Vec<(u64, Digest)>, Vec<(u64, Digest)>)> {
74        // Verify the signature
75        if !self.certificate.verify(NAMESPACE, identity) {
76            return None;
77        }
78        if self.progress.digest() != self.certificate.item.digest {
79            return None;
80        }
81
82        // Verify the state proof
83        if self.progress.state_start_op + self.state_proof_ops.len() as u64
84            != self.progress.state_end_op
85        {
86            return None;
87        }
88        let mut hasher = Standard::<Sha256>::new();
89        let Ok(state_proof_digests) = verify_proof_and_extract_digests(
90            &mut hasher,
91            &self.state_proof,
92            self.progress.state_start_op,
93            &self.state_proof_ops,
94            &self.progress.state_root,
95        ) else {
96            return None;
97        };
98
99        // Verify the events proof and extract digests
100        if self.progress.events_start_op + self.events_proof_ops.len() as u64
101            != self.progress.events_end_op
102        {
103            return None;
104        }
105        let Ok(events_proof_digests) = verify_proof_and_extract_digests(
106            &mut hasher,
107            &self.events_proof,
108            self.progress.events_start_op,
109            &self.events_proof_ops,
110            &self.progress.events_root,
111        ) else {
112            return None;
113        };
114
115        Some((state_proof_digests, events_proof_digests))
116    }
117}
118
119impl Write for Summary {
120    fn write(&self, writer: &mut impl BufMut) {
121        self.progress.write(writer);
122        self.certificate.write(writer);
123        self.state_proof.write(writer);
124        self.state_proof_ops.write(writer);
125        self.events_proof.write(writer);
126        self.events_proof_ops.write(writer);
127    }
128}
129
130impl Read for Summary {
131    type Cfg = ();
132
133    fn read_cfg(reader: &mut impl Buf, _: &Self::Cfg) -> Result<Self, Error> {
134        let progress = Progress::read(reader)?;
135        let certificate = Certificate::read(reader)?;
136        let state_proof = Proof::read_cfg(reader, &500)?;
137        let state_proof_ops = Vec::read_range(reader, 0..=500)?;
138        let events_proof = Proof::read_cfg(reader, &500)?;
139        let events_proof_ops = Vec::read_range(reader, 0..=500)?;
140        Ok(Self {
141            progress,
142            certificate,
143            state_proof,
144            state_proof_ops,
145            events_proof,
146            events_proof_ops,
147        })
148    }
149}
150
151impl EncodeSize for Summary {
152    fn encode_size(&self) -> usize {
153        self.progress.encode_size()
154            + self.certificate.encode_size()
155            + self.state_proof.encode_size()
156            + self.state_proof_ops.encode_size()
157            + self.events_proof.encode_size()
158            + self.events_proof_ops.encode_size()
159    }
160}
161
162#[derive(Clone, Eq, PartialEq, Debug)]
163pub struct Events {
164    pub progress: Progress,
165    pub certificate: Certificate<MinSig, Digest>,
166    pub events_proof: Proof<Digest>,
167    pub events_proof_ops: Vec<Keyless<Output>>,
168}
169
170impl Events {
171    pub fn verify(&self, identity: &Identity) -> bool {
172        // Verify the signature
173        if !self.certificate.verify(NAMESPACE, identity) {
174            return false;
175        }
176        if self.progress.digest() != self.certificate.item.digest {
177            return false;
178        }
179
180        // Verify the events proof
181        if self.progress.events_start_op + self.events_proof_ops.len() as u64
182            != self.progress.events_end_op
183        {
184            return false;
185        }
186        let mut hasher = Standard::<Sha256>::new();
187        verify_proof(
188            &mut hasher,
189            &self.events_proof,
190            self.progress.events_start_op,
191            &self.events_proof_ops,
192            &self.progress.events_root,
193        )
194    }
195}
196impl Write for Events {
197    fn write(&self, writer: &mut impl BufMut) {
198        self.progress.write(writer);
199        self.certificate.write(writer);
200        self.events_proof.write(writer);
201        self.events_proof_ops.write(writer);
202    }
203}
204
205impl Read for Events {
206    type Cfg = ();
207
208    fn read_cfg(reader: &mut impl Buf, _: &Self::Cfg) -> Result<Self, Error> {
209        let progress = Progress::read(reader)?;
210        let certificate = Certificate::read(reader)?;
211        let events_proof = Proof::read_cfg(reader, &500)?;
212        let events_proof_ops = Vec::read_range(reader, 0..=500)?;
213        Ok(Self {
214            progress,
215            certificate,
216            events_proof,
217            events_proof_ops,
218        })
219    }
220}
221
222impl EncodeSize for Events {
223    fn encode_size(&self) -> usize {
224        self.progress.encode_size()
225            + self.certificate.encode_size()
226            + self.events_proof.encode_size()
227            + self.events_proof_ops.encode_size()
228    }
229}
230
231pub struct Lookup {
232    pub progress: Progress,
233    pub certificate: Certificate<MinSig, Digest>,
234    pub proof: Proof<Digest>,
235    pub location: u64,
236    pub operation: Variable<Digest, Value>,
237}
238
239impl Lookup {
240    pub fn verify(&self, identity: &Identity) -> bool {
241        // Verify the signature
242        if !self.certificate.verify(NAMESPACE, identity) {
243            return false;
244        }
245        if self.progress.digest() != self.certificate.item.digest {
246            return false;
247        }
248
249        // Verify the proof
250        let mut hasher = Standard::<Sha256>::new();
251        verify_proof(
252            &mut hasher,
253            &self.proof,
254            self.location,
255            std::slice::from_ref(&self.operation),
256            &self.progress.state_root,
257        )
258    }
259}
260
261impl Write for Lookup {
262    fn write(&self, writer: &mut impl BufMut) {
263        self.progress.write(writer);
264        self.certificate.write(writer);
265        self.proof.write(writer);
266        self.location.write(writer);
267        self.operation.write(writer);
268    }
269}
270
271impl Read for Lookup {
272    type Cfg = ();
273
274    fn read_cfg(reader: &mut impl Buf, _: &Self::Cfg) -> Result<Self, Error> {
275        let progress = Progress::read(reader)?;
276        let certificate = Certificate::read(reader)?;
277        let proof = Proof::read_cfg(reader, &500)?;
278        let location = u64::read(reader)?;
279        let operation = Variable::read(reader)?;
280        Ok(Self {
281            progress,
282            certificate,
283            proof,
284            location,
285            operation,
286        })
287    }
288}
289
290impl EncodeSize for Lookup {
291    fn encode_size(&self) -> usize {
292        self.progress.encode_size()
293            + self.certificate.encode_size()
294            + self.proof.encode_size()
295            + self.location.encode_size()
296            + self.operation.encode_size()
297    }
298}
299
300#[derive(Clone, Debug)]
301pub struct FilteredEvents {
302    pub progress: Progress,
303    pub certificate: Certificate<MinSig, Digest>,
304    pub events_proof: Proof<Digest>,
305    pub events_proof_ops: Vec<(u64, Keyless<Output>)>,
306}
307
308impl FilteredEvents {
309    pub fn verify(&self, identity: &Identity) -> bool {
310        // Verify the signature
311        if !self.certificate.verify(NAMESPACE, identity) {
312            return false;
313        }
314        if self.progress.digest() != self.certificate.item.digest {
315            return false;
316        }
317
318        // Ensure all operations are within the range of the events proof
319        for (loc, _) in &self.events_proof_ops {
320            if *loc < self.progress.events_start_op || *loc > self.progress.events_end_op {
321                return false;
322            }
323        }
324
325        // Verify the multi-proof for the filtered operations
326        let mut hasher = Standard::<Sha256>::new();
327        verify_multi_proof(
328            &mut hasher,
329            &self.events_proof,
330            &self.events_proof_ops,
331            &self.progress.events_root,
332        )
333    }
334}
335
336impl Write for FilteredEvents {
337    fn write(&self, writer: &mut impl BufMut) {
338        self.progress.write(writer);
339        self.certificate.write(writer);
340        self.events_proof.write(writer);
341        self.events_proof_ops.write(writer);
342    }
343}
344
345impl Read for FilteredEvents {
346    type Cfg = ();
347
348    fn read_cfg(reader: &mut impl Buf, _: &Self::Cfg) -> Result<Self, Error> {
349        let progress = Progress::read(reader)?;
350        let certificate = Certificate::read(reader)?;
351        let events_proof = Proof::read_cfg(reader, &500)?;
352        let events_proof_ops = Vec::read_range(reader, 0..=500)?;
353        Ok(Self {
354            progress,
355            certificate,
356            events_proof,
357            events_proof_ops,
358        })
359    }
360}
361
362impl EncodeSize for FilteredEvents {
363    fn encode_size(&self) -> usize {
364        self.progress.encode_size()
365            + self.certificate.encode_size()
366            + self.events_proof.encode_size()
367            + self.events_proof_ops.encode_size()
368    }
369}
370
371#[derive(Clone, Debug)]
372#[allow(clippy::large_enum_variant)]
373pub enum Update {
374    Seed(Seed),
375    Events(Events),
376    FilteredEvents(FilteredEvents),
377}
378
379impl Write for Update {
380    fn write(&self, writer: &mut impl BufMut) {
381        match self {
382            Update::Seed(seed) => {
383                0u8.write(writer);
384                seed.write(writer);
385            }
386            Update::Events(events) => {
387                1u8.write(writer);
388                events.write(writer);
389            }
390            Update::FilteredEvents(events) => {
391                2u8.write(writer);
392                events.write(writer);
393            }
394        }
395    }
396}
397
398impl Read for Update {
399    type Cfg = ();
400
401    fn read_cfg(reader: &mut impl Buf, _: &Self::Cfg) -> Result<Self, Error> {
402        let kind = u8::read(reader)?;
403        match kind {
404            0 => Ok(Update::Seed(Seed::read(reader)?)),
405            1 => Ok(Update::Events(Events::read(reader)?)),
406            2 => Ok(Update::FilteredEvents(FilteredEvents::read(reader)?)),
407            _ => Err(Error::InvalidEnum(kind)),
408        }
409    }
410}
411
412impl EncodeSize for Update {
413    fn encode_size(&self) -> usize {
414        1 + match self {
415            Update::Seed(seed) => seed.encode_size(),
416            Update::Events(events) => events.encode_size(),
417            Update::FilteredEvents(events) => events.encode_size(),
418        }
419    }
420}
421
422#[derive(Clone, Debug)]
423#[allow(clippy::large_enum_variant)]
424pub enum Submission {
425    Seed(Seed),
426    Transactions(Vec<Transaction>),
427    Summary(Summary),
428}
429
430impl Write for Submission {
431    fn write(&self, writer: &mut impl BufMut) {
432        match self {
433            Submission::Seed(seed) => {
434                0u8.write(writer);
435                seed.write(writer);
436            }
437            Submission::Transactions(txs) => {
438                1u8.write(writer);
439                txs.write(writer);
440            }
441            Submission::Summary(summary) => {
442                2u8.write(writer);
443                summary.write(writer);
444            }
445        }
446    }
447}
448
449impl Read for Submission {
450    type Cfg = ();
451
452    fn read_cfg(reader: &mut impl Buf, _: &Self::Cfg) -> Result<Self, Error> {
453        let kind = u8::read(reader)?;
454        match kind {
455            0 => Ok(Submission::Seed(Seed::read(reader)?)),
456            1 => Ok(Submission::Transactions(Vec::read_range(
457                reader,
458                1..=MAX_SUBMISSION_TRANSACTIONS,
459            )?)),
460            2 => Ok(Submission::Summary(Summary::read(reader)?)),
461            _ => Err(Error::InvalidEnum(kind)),
462        }
463    }
464}
465
466impl EncodeSize for Submission {
467    fn encode_size(&self) -> usize {
468        1 + match self {
469            Submission::Seed(seed) => seed.encode_size(),
470            Submission::Transactions(txs) => txs.encode_size(),
471            Submission::Summary(summary) => summary.encode_size(),
472        }
473    }
474}
475
476/// Subscription filter for updates stream
477#[derive(Clone, Debug, Hash, Eq, PartialEq)]
478#[allow(clippy::large_enum_variant)]
479pub enum UpdatesFilter {
480    /// Subscribe to all events
481    All,
482    /// Subscribe to events for a specific account
483    Account(PublicKey),
484}
485
486impl Write for UpdatesFilter {
487    fn write(&self, writer: &mut impl BufMut) {
488        match self {
489            UpdatesFilter::All => 0u8.write(writer),
490            UpdatesFilter::Account(key) => {
491                1u8.write(writer);
492                key.write(writer);
493            }
494        }
495    }
496}
497
498impl Read for UpdatesFilter {
499    type Cfg = ();
500
501    fn read_cfg(reader: &mut impl Buf, _: &Self::Cfg) -> Result<Self, Error> {
502        let kind = u8::read(reader)?;
503        match kind {
504            0 => Ok(UpdatesFilter::All),
505            1 => Ok(UpdatesFilter::Account(PublicKey::read(reader)?)),
506            _ => Err(Error::InvalidEnum(kind)),
507        }
508    }
509}
510
511impl EncodeSize for UpdatesFilter {
512    fn encode_size(&self) -> usize {
513        1 + match self {
514            UpdatesFilter::All => 0,
515            UpdatesFilter::Account(key) => key.encode_size(),
516        }
517    }
518}
519
520#[derive(Clone, Debug)]
521pub struct Pending {
522    pub transactions: Vec<Transaction>,
523}
524
525impl Write for Pending {
526    fn write(&self, writer: &mut impl BufMut) {
527        self.transactions.write(writer);
528    }
529}
530
531impl Read for Pending {
532    type Cfg = ();
533
534    fn read_cfg(reader: &mut impl Buf, _: &Self::Cfg) -> Result<Self, Error> {
535        let transactions = Vec::<Transaction>::read_range(reader, 1..=MAX_SUBMISSION_TRANSACTIONS)?;
536        Ok(Self { transactions })
537    }
538}
539
540impl EncodeSize for Pending {
541    fn encode_size(&self) -> usize {
542        self.transactions.encode_size()
543    }
544}