1use std::collections::{HashMap, HashSet};
25use std::sync::{Arc, RwLock};
26
27use hashgraph_like_consensus::{
28 events::BroadcastEventBus, signing::EthereumConsensusSigner, storage::InMemoryConsensusStorage,
29};
30use openmls_rust_crypto::MemoryStorage;
31
32use crate::core::{
33 ConsensusPlugin, ConversationPluginsFactory, DeterministicStewardList, PeerScoreStorage,
34 PeerScoringService, ScoringConfig, StewardListConfig, default_score_deltas,
35};
36use crate::mls_crypto::{DeMlsStorage, KeyPackageBytes, MlsCredentials, MlsError, OpenMlsService};
37
38#[derive(Default)]
47pub struct MemoryDeMlsStorage {
48 key_package_refs: RwLock<HashSet<Vec<u8>>>,
49 mls: MemoryStorage,
50}
51
52impl MemoryDeMlsStorage {
53 pub fn new() -> Self {
54 Self::default()
55 }
56}
57
58impl DeMlsStorage for MemoryDeMlsStorage {
59 type MlsStorage = MemoryStorage;
60 type StorageError = openmls_rust_crypto::MemoryStorageError;
61
62 fn store_key_package_ref(&self, hash_ref: &[u8]) -> Result<(), MlsError> {
63 self.key_package_refs.write()?.insert(hash_ref.to_vec());
64 Ok(())
65 }
66
67 fn is_our_key_package(&self, hash_ref: &[u8]) -> Result<bool, MlsError> {
68 Ok(self.key_package_refs.read()?.contains(hash_ref))
69 }
70
71 fn remove_key_package_ref(&self, hash_ref: &[u8]) -> Result<(), MlsError> {
72 self.key_package_refs.write()?.remove(hash_ref);
73 Ok(())
74 }
75
76 fn mls_storage(&self) -> &Self::MlsStorage {
77 &self.mls
78 }
79}
80
81#[derive(Debug, Clone, Default)]
84pub struct InMemoryPeerScoreStorage {
85 scores: HashMap<Vec<u8>, i64>,
86}
87
88impl InMemoryPeerScoreStorage {
89 pub fn new() -> Self {
90 Self::default()
91 }
92}
93
94impl PeerScoreStorage for InMemoryPeerScoreStorage {
95 fn get(&self, member_id: &[u8]) -> Option<i64> {
96 self.scores.get(member_id).copied()
97 }
98
99 fn set(&mut self, member_id: &[u8], score: i64) {
100 self.scores.insert(member_id.to_vec(), score);
101 }
102
103 fn remove(&mut self, member_id: &[u8]) {
104 self.scores.remove(member_id);
105 }
106
107 fn all_scores(&self) -> Vec<(Vec<u8>, i64)> {
108 self.scores.iter().map(|(k, v)| (k.clone(), *v)).collect()
109 }
110}
111
112pub struct DefaultConsensusPlugin;
119
120impl ConsensusPlugin for DefaultConsensusPlugin {
121 type Scope = String;
122 type ConsensusStorage = InMemoryConsensusStorage<String>;
123 type EventBus = BroadcastEventBus<String>;
124 type Signer = EthereumConsensusSigner;
125
126 fn new_storage() -> Self::ConsensusStorage {
127 InMemoryConsensusStorage::new()
128 }
129
130 fn new_event_bus() -> Self::EventBus {
131 BroadcastEventBus::default()
132 }
133}
134
135pub type DefaultMlsService = OpenMlsService<Arc<MemoryDeMlsStorage>>;
143
144pub type DefaultPeerScoring = PeerScoringService<InMemoryPeerScoreStorage>;
148
149pub type DefaultStewardList = DeterministicStewardList;
152
153pub struct DefaultConversationPluginsFactory {
157 pub(crate) storage: Arc<MemoryDeMlsStorage>,
158 pub(crate) credentials: Arc<MlsCredentials>,
159}
160
161impl DefaultConversationPluginsFactory {
162 pub fn new(storage: Arc<MemoryDeMlsStorage>, credentials: Arc<MlsCredentials>) -> Self {
166 Self {
167 storage,
168 credentials,
169 }
170 }
171}
172
173impl ConversationPluginsFactory for DefaultConversationPluginsFactory {
174 type Mls = DefaultMlsService;
175 type Scoring = DefaultPeerScoring;
176 type StewardList = DefaultStewardList;
177
178 fn create_mls(&self, conversation_id: String) -> Result<Self::Mls, MlsError> {
179 OpenMlsService::new_as_creator(
180 conversation_id,
181 Arc::clone(&self.storage),
182 Arc::clone(&self.credentials),
183 )
184 }
185
186 fn welcome_mls(&self, welcome_bytes: &[u8]) -> Result<Option<Self::Mls>, MlsError> {
187 OpenMlsService::new_from_welcome(
188 welcome_bytes,
189 Arc::clone(&self.storage),
190 Arc::clone(&self.credentials),
191 )
192 }
193
194 fn make_scoring(&self, config: &ScoringConfig) -> Self::Scoring {
195 PeerScoringService::new(
196 InMemoryPeerScoreStorage::new(),
197 default_score_deltas(),
198 config.clone(),
199 )
200 }
201
202 fn make_steward_list(
203 &self,
204 conversation_id: &[u8],
205 config: StewardListConfig,
206 ) -> Self::StewardList {
207 DeterministicStewardList::empty(conversation_id.to_vec(), config)
208 }
209
210 fn generate_key_package(&self) -> Result<KeyPackageBytes, MlsError> {
211 OpenMlsService::<Arc<MemoryDeMlsStorage>>::generate_key_package(
212 &self.storage,
213 &self.credentials,
214 )
215 }
216}
217
218#[cfg(test)]
219mod tests {
220 use super::*;
221
222 #[test]
223 fn in_memory_storage_round_trip() {
224 let mut storage = InMemoryPeerScoreStorage::new();
225 assert_eq!(storage.get(b"alice"), None);
226 storage.set(b"alice", 42);
227 assert_eq!(storage.get(b"alice"), Some(42));
228 storage.set(b"bob", -3);
229 let all = storage.all_scores();
230 assert_eq!(all.len(), 2);
231 storage.remove(b"alice");
232 assert_eq!(storage.get(b"alice"), None);
233 assert_eq!(storage.all_scores().len(), 1);
234 }
235}