• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 // Copyright by contributors to this project.
3 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
4 
5 use core::fmt::{self, Debug};
6 
7 use crate::error::IntoAnyError;
8 #[cfg(mls_build_async)]
9 use alloc::boxed::Box;
10 use alloc::vec::Vec;
11 
12 /// Generic representation of a group's state.
13 #[derive(Clone, PartialEq, Eq)]
14 pub struct GroupState {
15     /// A unique group identifier.
16     pub id: Vec<u8>,
17     pub data: Vec<u8>,
18 }
19 
20 impl Debug for GroupState {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result21     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22         f.debug_struct("GroupState")
23             .field("id", &crate::debug::pretty_bytes(&self.id))
24             .field("data", &crate::debug::pretty_bytes(&self.data))
25             .finish()
26     }
27 }
28 
29 /// Generic representation of a prior epoch.
30 #[derive(Clone, PartialEq, Eq)]
31 pub struct EpochRecord {
32     /// A unique epoch identifier within a particular group.
33     pub id: u64,
34     pub data: Vec<u8>,
35 }
36 
37 impl Debug for EpochRecord {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result38     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39         f.debug_struct("EpochRecord")
40             .field("id", &self.id)
41             .field("data", &crate::debug::pretty_bytes(&self.data))
42             .finish()
43     }
44 }
45 
46 impl EpochRecord {
new(id: u64, data: Vec<u8>) -> Self47     pub fn new(id: u64, data: Vec<u8>) -> Self {
48         Self { id, data }
49     }
50 }
51 
52 /// Storage that can persist and reload a group state.
53 ///
54 /// A group state is recorded as a combination of the current state
55 /// (represented by the [`GroupState`] trait) and some number of prior
56 /// group states (represented by the [`EpochRecord`] trait).
57 /// This trait implements reading and writing group data as requested by the protocol
58 /// implementation.
59 ///
60 /// # Cleaning up records
61 ///
62 /// Group state will not be purged when the local member is removed from the
63 /// group. It is up to the implementer of this trait to provide a mechanism
64 /// to delete records that can be used by an application.
65 ///
66 
67 #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)]
68 #[cfg_attr(mls_build_async, maybe_async::must_be_async)]
69 pub trait GroupStateStorage: Send + Sync {
70     type Error: IntoAnyError;
71 
72     /// Fetch a group state from storage.
state(&self, group_id: &[u8]) -> Result<Option<Vec<u8>>, Self::Error>73     async fn state(&self, group_id: &[u8]) -> Result<Option<Vec<u8>>, Self::Error>;
74 
75     /// Lazy load cached epoch data from a particular group.
epoch(&self, group_id: &[u8], epoch_id: u64) -> Result<Option<Vec<u8>>, Self::Error>76     async fn epoch(&self, group_id: &[u8], epoch_id: u64) -> Result<Option<Vec<u8>>, Self::Error>;
77 
78     /// Write pending state updates.
79     ///
80     /// The group id that this update belongs to can be retrieved with
81     /// [`GroupState::id`]. Prior epoch id values can be retrieved with
82     /// [`EpochRecord::id`].
83     ///
84     /// The protocol implementation handles managing the max size of a prior epoch
85     /// cache and the deleting of prior states based on group activity.
86     /// The maximum number of prior epochs that will be stored is controlled by the
87     /// `Preferences::max_epoch_retention` function in `mls_rs`.
88     /// value. Requested deletes are communicated by the `delete_epoch_under`
89     /// parameter being set to `Some`.
90     ///
91     /// # Warning
92     ///
93     /// It is important to consider error recovery when creating an implementation
94     /// of this trait. Calls to [`write`](GroupStateStorage::write) should
95     /// optimally be a single atomic transaction in order to avoid partial writes
96     /// that may corrupt the group state.
write( &mut self, state: GroupState, epoch_inserts: Vec<EpochRecord>, epoch_updates: Vec<EpochRecord>, ) -> Result<(), Self::Error>97     async fn write(
98         &mut self,
99         state: GroupState,
100         epoch_inserts: Vec<EpochRecord>,
101         epoch_updates: Vec<EpochRecord>,
102     ) -> Result<(), Self::Error>;
103 
104     /// The [`EpochRecord::id`] value that is associated with a stored
105     /// prior epoch for a particular group.
max_epoch_id(&self, group_id: &[u8]) -> Result<Option<u64>, Self::Error>106     async fn max_epoch_id(&self, group_id: &[u8]) -> Result<Option<u64>, Self::Error>;
107 }
108