1
1
use chrono:: NaiveDateTime ;
2
2
use mithril_common:: entities:: Beacon ;
3
3
use mithril_common:: entities:: Epoch ;
4
+ use mithril_common:: StdError ;
4
5
5
6
use mithril_common:: sqlite:: Provider ;
6
7
use mithril_common:: sqlite:: SourceAlias ;
@@ -10,18 +11,33 @@ use mithril_common::{
10
11
} ;
11
12
use sqlite:: Row ;
12
13
use sqlite:: { Connection , Value } ;
14
+ use uuid:: Uuid ;
15
+
16
+ type StdResult < T > = Result < T , StdError > ;
13
17
14
18
/// ## OpenMessage
15
19
///
16
20
/// An open message is a message open for signatures. Every signer may send a
17
21
/// single signature for this message from which a multi signature will be
18
22
/// generated if possible.
19
- struct OpenMessage {
20
- open_message_id : String ,
23
+ pub struct OpenMessage {
24
+ /// OpenMessage unique identifier
25
+ open_message_id : Uuid ,
26
+
27
+ /// Epoch
21
28
epoch : Epoch ,
29
+
30
+ /// Beacon, this is the discriminant of this message type in the current
31
+ /// Epoch
22
32
beacon : Beacon ,
33
+
34
+ /// Type of message
23
35
signed_entity_type : SignedEntityType ,
36
+
37
+ /// Message content
24
38
message : String ,
39
+
40
+ /// Message creation datetime, it is set by the database.
25
41
created_at : NaiveDateTime ,
26
42
}
27
43
@@ -31,6 +47,11 @@ impl SqLiteEntity for OpenMessage {
31
47
Self : Sized ,
32
48
{
33
49
let open_message_id = row. get :: < String , _ > ( 0 ) ;
50
+ let open_message_id = Uuid :: parse_str ( & open_message_id) . map_err ( |e| {
51
+ HydrationError :: InvalidData ( format ! (
52
+ "Invalid UUID in open_message.open_message_id: '{open_message_id}'. Error: {e}"
53
+ ) )
54
+ } ) ?;
34
55
let message = row. get :: < String , _ > ( 4 ) ;
35
56
let epoch_settings_id = row. get :: < i64 , _ > ( 1 ) ;
36
57
let epoch_val = u64:: try_from ( epoch_settings_id)
@@ -96,13 +117,13 @@ struct OpenMessageProvider<'client> {
96
117
}
97
118
98
119
impl < ' client > OpenMessageProvider < ' client > {
99
- fn new ( connection : & ' client Connection ) -> Self {
120
+ pub fn new ( connection : & ' client Connection ) -> Self {
100
121
Self { connection }
101
122
}
102
123
103
124
fn get_epoch_condition ( & self , epoch : Epoch ) -> WhereCondition {
104
125
WhereCondition :: new (
105
- "{:open_message:}. epoch_settings_id = ?*" ,
126
+ "epoch_settings_id = ?*" ,
106
127
vec ! [ Value :: Integer ( epoch. 0 as i64 ) ] ,
107
128
)
108
129
}
@@ -112,14 +133,14 @@ impl<'client> OpenMessageProvider<'client> {
112
133
signed_entity_type : & SignedEntityType ,
113
134
) -> WhereCondition {
114
135
WhereCondition :: new (
115
- "{:open_message:}. signed_entity_type_id = ?*" ,
136
+ "signed_entity_type_id = ?*" ,
116
137
vec ! [ Value :: Integer ( * signed_entity_type as i64 ) ] ,
117
138
)
118
139
}
119
140
120
141
fn get_open_message_id_condition ( & self , open_message_id : & str ) -> WhereCondition {
121
142
WhereCondition :: new (
122
- "{:open_message:}. open_message_id = ?*" ,
143
+ "open_message_id = ?*" ,
123
144
vec ! [ Value :: String ( open_message_id. to_owned( ) ) ] ,
124
145
)
125
146
}
@@ -140,6 +161,128 @@ impl<'client> Provider<'client> for OpenMessageProvider<'client> {
140
161
}
141
162
}
142
163
164
+ struct InsertOpenMessageProvider < ' client > {
165
+ connection : & ' client Connection ,
166
+ }
167
+ impl < ' client > InsertOpenMessageProvider < ' client > {
168
+ pub fn new ( connection : & ' client Connection ) -> Self {
169
+ Self { connection }
170
+ }
171
+
172
+ fn get_insert_condition (
173
+ & self ,
174
+ epoch : Epoch ,
175
+ beacon : & Beacon ,
176
+ signed_entity_type : & SignedEntityType ,
177
+ message : & str ,
178
+ ) -> StdResult < WhereCondition > {
179
+ let expression = "(open_message_id, epoch_settings_id, beacon, signed_entity_type_id, message) values (?*, ?*, ?*, ?*, ?*)" ;
180
+ let parameters = vec ! [
181
+ Value :: String ( Uuid :: new_v4( ) . to_string( ) ) ,
182
+ Value :: Integer ( epoch. 0 as i64 ) ,
183
+ Value :: String ( serde_json:: to_string( beacon) ?) ,
184
+ Value :: Integer ( * signed_entity_type as i64 ) ,
185
+ Value :: String ( message. to_string( ) ) ,
186
+ ] ;
187
+
188
+ Ok ( WhereCondition :: new ( expression, parameters) )
189
+ }
190
+ }
191
+
192
+ impl < ' client > Provider < ' client > for InsertOpenMessageProvider < ' client > {
193
+ type Entity = OpenMessage ;
194
+
195
+ fn get_connection ( & ' client self ) -> & ' client Connection {
196
+ self . connection
197
+ }
198
+
199
+ fn get_definition ( & self , condition : & str ) -> String {
200
+ let aliases = SourceAlias :: new ( & [ ( "{:open_message:}" , "open_message" ) ] ) ;
201
+ let projection = Self :: Entity :: get_projection ( ) . expand ( aliases) ;
202
+
203
+ format ! ( "insert into open_message {condition} returning {projection}" )
204
+ }
205
+ }
206
+
207
+ struct DeleteOpenMessageProvider < ' client > {
208
+ connection : & ' client Connection ,
209
+ }
210
+
211
+ impl < ' client > DeleteOpenMessageProvider < ' client > {
212
+ pub fn new ( connection : & ' client Connection ) -> Self {
213
+ Self { connection }
214
+ }
215
+
216
+ fn get_epoch_condition ( & self , epoch : Epoch ) -> WhereCondition {
217
+ WhereCondition :: new (
218
+ "epoch_settings_id = ?*" ,
219
+ vec ! [ Value :: Integer ( epoch. 0 as i64 ) ] ,
220
+ )
221
+ }
222
+ }
223
+
224
+ impl < ' client > Provider < ' client > for DeleteOpenMessageProvider < ' client > {
225
+ type Entity = OpenMessage ;
226
+
227
+ fn get_connection ( & ' client self ) -> & ' client Connection {
228
+ self . connection
229
+ }
230
+
231
+ fn get_definition ( & self , condition : & str ) -> String {
232
+ let aliases = SourceAlias :: new ( & [ ( "{:open_message:}" , "open_message" ) ] ) ;
233
+ let projection = Self :: Entity :: get_projection ( ) . expand ( aliases) ;
234
+
235
+ format ! ( "delete from open_message where {condition} returning {projection}" )
236
+ }
237
+ }
238
+
239
+ pub struct OpenMessageRepository < ' client > {
240
+ connection : & ' client Connection ,
241
+ }
242
+
243
+ impl < ' client > OpenMessageRepository < ' client > {
244
+ /// Return the latest [OpenMessage] for the given Epoch and [SignedEntityType].
245
+ pub fn get_open_message (
246
+ & self ,
247
+ epoch : Epoch ,
248
+ signed_entity_type : & SignedEntityType ,
249
+ ) -> StdResult < Option < OpenMessage > > {
250
+ let provider = OpenMessageProvider :: new ( self . connection ) ;
251
+ let filters = provider
252
+ . get_epoch_condition ( epoch)
253
+ . and_where ( provider. get_signed_entity_type_condition ( signed_entity_type) ) ;
254
+ let mut messages = provider. find ( filters) ?;
255
+
256
+ Ok ( messages. next ( ) )
257
+ }
258
+
259
+ /// Create a new [OpenMessage] in the database.
260
+ pub fn create_open_message (
261
+ & self ,
262
+ epoch : Epoch ,
263
+ beacon : & Beacon ,
264
+ signed_entity_type : & SignedEntityType ,
265
+ message : & str ,
266
+ ) -> StdResult < OpenMessage > {
267
+ let provider = InsertOpenMessageProvider :: new ( self . connection ) ;
268
+ let filters = provider. get_insert_condition ( epoch, beacon, signed_entity_type, message) ?;
269
+ let mut cursor = provider. find ( filters) ?;
270
+
271
+ cursor
272
+ . next ( )
273
+ . ok_or_else ( || panic ! ( "Inserting an open_message should not return nothing." ) )
274
+ }
275
+
276
+ /// Remove all the [OpenMessage] for the given Epoch in the database.
277
+ pub fn clean_epoch ( & self , epoch : Epoch ) -> StdResult < ( ) > {
278
+ let provider = DeleteOpenMessageProvider :: new ( self . connection ) ;
279
+ let filters = provider. get_epoch_condition ( epoch) ;
280
+ let _ = provider. find ( filters) ?;
281
+
282
+ Ok ( ( ) )
283
+ }
284
+ }
285
+
143
286
#[ cfg( test) ]
144
287
mod tests {
145
288
use mithril_common:: sqlite:: SourceAlias ;
@@ -163,7 +306,7 @@ mod tests {
163
306
let provider = OpenMessageProvider :: new ( & connection) ;
164
307
let ( expr, params) = provider. get_epoch_condition ( Epoch ( 12 ) ) . expand ( ) ;
165
308
166
- assert_eq ! ( "{:open_message:}. epoch_settings_id = ?1" . to_string( ) , expr) ;
309
+ assert_eq ! ( "epoch_settings_id = ?1" . to_string( ) , expr) ;
167
310
assert_eq ! ( vec![ Value :: Integer ( 12 ) ] , params, ) ;
168
311
}
169
312
@@ -175,10 +318,7 @@ mod tests {
175
318
. get_signed_entity_type_condition ( & SignedEntityType :: CardanoImmutableFilesFull )
176
319
. expand ( ) ;
177
320
178
- assert_eq ! (
179
- "{:open_message:}.signed_entity_type_id = ?1" . to_string( ) ,
180
- expr
181
- ) ;
321
+ assert_eq ! ( "signed_entity_type_id = ?1" . to_string( ) , expr) ;
182
322
assert_eq ! ( vec![ Value :: Integer ( 2 ) ] , params, ) ;
183
323
}
184
324
@@ -190,12 +330,46 @@ mod tests {
190
330
. get_open_message_id_condition ( "cecd7983-8b3a-42b1-b778-6d75e87828ee" )
191
331
. expand ( ) ;
192
332
193
- assert_eq ! ( "{:open_message:}. open_message_id = ?1" . to_string( ) , expr) ;
333
+ assert_eq ! ( "open_message_id = ?1" . to_string( ) , expr) ;
194
334
assert_eq ! (
195
335
vec![ Value :: String (
196
336
"cecd7983-8b3a-42b1-b778-6d75e87828ee" . to_string( )
197
337
) ] ,
198
338
params,
199
339
) ;
200
340
}
341
+
342
+ #[ test]
343
+ fn insert_provider_condition ( ) {
344
+ let connection = Connection :: open ( ":memory:" ) . unwrap ( ) ;
345
+ let provider = InsertOpenMessageProvider :: new ( & connection) ;
346
+ let ( expr, params) = provider
347
+ . get_insert_condition (
348
+ Epoch ( 12 ) ,
349
+ & Beacon :: default ( ) ,
350
+ & SignedEntityType :: CardanoStakeDistribution ,
351
+ "This is a message" ,
352
+ )
353
+ . unwrap ( )
354
+ . expand ( ) ;
355
+
356
+ assert_eq ! ( "(open_message_id, epoch_settings_id, beacon, signed_entity_type_id, message) values (?1, ?2, ?3, ?4, ?5)" . to_string( ) , expr) ;
357
+ assert_eq ! ( Value :: Integer ( 12 ) , params[ 1 ] ) ;
358
+ assert_eq ! (
359
+ Value :: String ( r#"{"network":"","epoch":0,"immutable_file_number":0}"# . to_string( ) ) ,
360
+ params[ 2 ]
361
+ ) ;
362
+ assert_eq ! ( Value :: Integer ( 1 ) , params[ 3 ] ) ;
363
+ assert_eq ! ( Value :: String ( "This is a message" . to_string( ) ) , params[ 4 ] ) ;
364
+ }
365
+
366
+ #[ test]
367
+ fn delete_provider_epoch_condition ( ) {
368
+ let connection = Connection :: open ( ":memory:" ) . unwrap ( ) ;
369
+ let provider = DeleteOpenMessageProvider :: new ( & connection) ;
370
+ let ( expr, params) = provider. get_epoch_condition ( Epoch ( 12 ) ) . expand ( ) ;
371
+
372
+ assert_eq ! ( "epoch_settings_id = ?1" . to_string( ) , expr) ;
373
+ assert_eq ! ( vec![ Value :: Integer ( 12 ) ] , params, ) ;
374
+ }
201
375
}
0 commit comments