de_mls/core/provider.rs
1//! Service provider trait for dependency injection.
2//!
3//! The [`DeMlsProvider`] trait bundles all configurable services needed
4//! by DE-MLS into a single type parameter. This enables swapping out
5//! implementations for testing or custom deployments.
6//!
7//! # Architecture
8//!
9//! ```text
10//! ┌─────────────────────────────────────────────────────────────┐
11//! │ DeMlsProvider │
12//! ├─────────────────────────────────────────────────────────────┤
13//! │ Storage │ MLS + DE-MLS state persistence │
14//! │ Scope │ Group identifier type (usually String) │
15//! │ CStorage │ Consensus proposal/vote persistence │
16//! │ EventBus │ Consensus event distribution │
17//! │ Consensus │ Voting service (hashgraph-like) │
18//! └─────────────────────────────────────────────────────────────┘
19//! ```
20//!
21//! # Default vs Custom Providers
22//!
23//! Use [`DefaultProvider`] for production deployments:
24//! - `MemoryDeMlsStorage` for MLS state storage
25//! - `InMemoryConsensusStorage` for proposal/vote storage
26//! - `BroadcastEventBus` for consensus event distribution
27//! - `DefaultConsensusService` for hashgraph-like voting
28//!
29//! Create custom providers for:
30//! - **Testing**: Mock services that don't require network
31//! - **Persistence**: Database-backed storage
32//!
33//! # Example
34//!
35//! ```ignore
36//! use de_mls::core::{DeMlsProvider, DefaultProvider};
37//! use de_mls::app::User;
38//!
39//! // Production: use DefaultProvider
40//! let user: User<DefaultProvider> = User::with_private_key(
41//! "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
42//! consensus,
43//! handler,
44//! )?;
45//! ```
46
47use hashgraph_like_consensus::{
48 api::ConsensusServiceAPI,
49 events::{BroadcastEventBus, ConsensusEventBus},
50 scope::ConsensusScope,
51 service::DefaultConsensusService,
52 storage::{ConsensusStorage, InMemoryConsensusStorage},
53};
54
55use openmls_rust_crypto::MemoryStorage;
56
57use crate::mls_crypto::{DeMlsStorage, MemoryDeMlsStorage};
58
59/// Bundles all configurable services for a DE-MLS deployment.
60///
61/// This trait uses associated types to define the concrete implementations
62/// of each service. All types must be `Send + Sync + 'static` for async use.
63///
64/// # Implementing Custom Providers
65///
66/// ```ignore
67/// struct MyProvider;
68///
69/// impl DeMlsProvider for MyProvider {
70/// // Storage backend for MLS state
71/// type Storage = SqliteDeMlsStorage;
72///
73/// // Group identifier (String works for most cases)
74/// type Scope = String;
75///
76/// // Where to store proposals and votes
77/// type ConsensusStorage = PostgresConsensusStorage<String>;
78///
79/// // How to distribute consensus events
80/// type EventBus = BroadcastEventBus<String>;
81///
82/// // The voting service implementation
83/// type Consensus = DefaultConsensusService;
84/// }
85/// ```
86pub trait DeMlsProvider: 'static {
87 /// Storage backend for MLS operations.
88 ///
89 /// Must implement `DeMlsStorage` for key package tracking and OpenMLS delegation.
90 /// Currently constrained to `MemoryStorage` for MLS storage backend.
91 ///
92 /// Default: `MemoryDeMlsStorage`
93 type Storage: DeMlsStorage<MlsStorage = MemoryStorage> + Send + Sync + 'static;
94
95 /// Consensus scope type for grouping proposals.
96 ///
97 /// This is typically `String` (the group name). Each group has its
98 /// own consensus scope, so proposals don't interfere across groups.
99 ///
100 /// Default: `String`
101 type Scope: ConsensusScope + From<String> + Send + Sync + 'static;
102
103 /// Consensus storage backend for proposals and votes.
104 ///
105 /// Stores pending proposals, vote tallies, and consensus state.
106 /// Can be in-memory for testing or database-backed for production.
107 ///
108 /// Default: `InMemoryConsensusStorage<String>`
109 type ConsensusStorage: ConsensusStorage<Self::Scope> + Send + Sync + 'static;
110
111 /// Event bus for distributing consensus outcomes.
112 ///
113 /// When consensus is reached or fails, events are broadcast to
114 /// all subscribers (typically the app layer's event loop).
115 ///
116 /// Default: `BroadcastEventBus<String>`
117 type EventBus: ConsensusEventBus<Self::Scope> + Send + Sync + 'static;
118
119 /// Consensus service implementing the voting protocol.
120 ///
121 /// Handles proposal creation, vote casting, and outcome determination.
122 /// Uses hashgraph-like consensus for Byzantine fault tolerance.
123 ///
124 /// Default: `DefaultConsensusService`
125 type Consensus: ConsensusServiceAPI<Self::Scope, Self::ConsensusStorage, Self::EventBus>
126 + Send
127 + Sync
128 + 'static;
129}
130
131/// Default provider for production deployments.
132///
133/// Uses:
134/// - `MemoryDeMlsStorage`: In-memory MLS state storage
135/// - `String` scope: Group names as consensus scopes
136/// - `InMemoryConsensusStorage`: Fast in-memory proposal/vote storage
137/// - `BroadcastEventBus`: Tokio broadcast channels for events
138/// - `DefaultConsensusService`: Hashgraph-like voting protocol
139///
140/// # Example
141///
142/// ```ignore
143/// use de_mls::core::DefaultProvider;
144/// use de_mls::app::User;
145///
146/// let user: User<DefaultProvider> = User::with_private_key(
147/// private_key,
148/// consensus,
149/// handler,
150/// )?;
151/// ```
152pub struct DefaultProvider;
153
154impl DeMlsProvider for DefaultProvider {
155 type Storage = MemoryDeMlsStorage;
156 type Scope = String;
157 type ConsensusStorage = InMemoryConsensusStorage<String>;
158 type EventBus = BroadcastEventBus<String>;
159 type Consensus = DefaultConsensusService;
160}