@@ -3,6 +3,9 @@ use crate::{attempt, Aggregator, Client, ClientCommand, Devnet, MithrilInfrastru
3
3
use mithril_common:: chain_observer:: { CardanoCliChainObserver , ChainObserver } ;
4
4
use mithril_common:: digesters:: ImmutableFile ;
5
5
use mithril_common:: entities:: { Certificate , Epoch , EpochSettings , ProtocolParameters , Snapshot } ;
6
+ use mithril_common:: messages:: {
7
+ MithrilStakeDistributionListMessage , MithrilStakeDistributionMessage ,
8
+ } ;
6
9
use reqwest:: StatusCode ;
7
10
use slog_scope:: { info, warn} ;
8
11
use std:: error:: Error ;
@@ -70,6 +73,22 @@ impl Spec {
70
73
)
71
74
. await ?;
72
75
76
+ // Verify that mithril stake distribution artifacts are produced and signed correctly
77
+ let hash = assert_node_producing_mithril_stake_distribution ( & aggregator_endpoint) . await ?;
78
+ let certificate_hash = assert_signer_is_signing_mithril_stake_distribution (
79
+ & aggregator_endpoint,
80
+ & hash,
81
+ target_epoch - 2 ,
82
+ )
83
+ . await ?;
84
+ assert_is_creating_certificate_with_enough_signers (
85
+ & aggregator_endpoint,
86
+ & certificate_hash,
87
+ self . infrastructure . signers ( ) . len ( ) ,
88
+ )
89
+ . await ?;
90
+
91
+ // Verify that snapshot artifacts are produced and signed correctly
73
92
let digest = assert_node_producing_snapshot ( & aggregator_endpoint) . await ?;
74
93
let certificate_hash =
75
94
assert_signer_is_signing_snapshot ( & aggregator_endpoint, & digest, target_epoch - 2 )
@@ -240,6 +259,79 @@ async fn update_protocol_parameters(aggregator: &mut Aggregator) -> Result<(), S
240
259
Ok ( ( ) )
241
260
}
242
261
262
+ async fn assert_node_producing_mithril_stake_distribution (
263
+ aggregator_endpoint : & str ,
264
+ ) -> Result < String , String > {
265
+ let url = format ! ( "{aggregator_endpoint}/artifact/mithril-stake-distributions" ) ;
266
+ info ! ( "Waiting for the aggregator to produce a mithril stake distribution" ) ;
267
+
268
+ // todo: reduce the number of attempts if we can reduce the delay between two immutables
269
+ match attempt ! ( 45 , Duration :: from_millis( 2000 ) , {
270
+ match reqwest:: get( url. clone( ) ) . await {
271
+ Ok ( response) => match response. status( ) {
272
+ StatusCode :: OK => match response. json:: <MithrilStakeDistributionListMessage >( ) . await . as_deref( ) {
273
+ Ok ( [ stake_distribution, ..] ) => Ok ( Some ( stake_distribution. hash. clone( ) ) ) ,
274
+ Ok ( & [ ] ) => Ok ( None ) ,
275
+ Err ( err) => Err ( format!( "Invalid mithril stake distribution body : {err}" , ) ) ,
276
+ } ,
277
+ s => Err ( format!( "Unexpected status code from Aggregator: {s}" ) ) ,
278
+ } ,
279
+ Err ( err) => Err ( format!( "Request to `{url}` failed: {err}" ) ) ,
280
+ }
281
+ } ) {
282
+ AttemptResult :: Ok ( hash) => {
283
+ info ! ( "Aggregator produced a mithril stake distribution" ; "hash" => & hash) ;
284
+ Ok ( hash)
285
+ }
286
+ AttemptResult :: Err ( error) => Err ( error) ,
287
+ AttemptResult :: Timeout ( ) => Err ( format ! (
288
+ "Timeout exhausted assert_node_producing_mithril_stake_distribution, no response from `{url}`"
289
+ ) ) ,
290
+ }
291
+ }
292
+
293
+ async fn assert_signer_is_signing_mithril_stake_distribution (
294
+ aggregator_endpoint : & str ,
295
+ hash : & str ,
296
+ expected_epoch_min : Epoch ,
297
+ ) -> Result < String , String > {
298
+ let url = format ! ( "{aggregator_endpoint}/artifact/mithril-stake-distribution/{hash}" ) ;
299
+ info ! (
300
+ "Asserting the aggregator is signing the mithril stake distribution message `{}` with an expected min epoch of `{}`" ,
301
+ hash,
302
+ expected_epoch_min
303
+ ) ;
304
+
305
+ match attempt ! ( 10 , Duration :: from_millis( 1000 ) , {
306
+ match reqwest:: get( url. clone( ) ) . await {
307
+ Ok ( response) => match response. status( ) {
308
+ StatusCode :: OK => match response. json:: <MithrilStakeDistributionMessage >( ) . await {
309
+ Ok ( stake_distribution) => match stake_distribution. epoch {
310
+ epoch if epoch >= expected_epoch_min => Ok ( Some ( stake_distribution) ) ,
311
+ epoch => Err ( format!(
312
+ "Minimum expected mithril stake distribution epoch not reached : {epoch} < {expected_epoch_min}"
313
+ ) ) ,
314
+ } ,
315
+ Err ( err) => Err ( format!( "Invalid mithril stake distribution body : {err}" , ) ) ,
316
+ } ,
317
+ StatusCode :: NOT_FOUND => Ok ( None ) ,
318
+ s => Err ( format!( "Unexpected status code from Aggregator: {s}" ) ) ,
319
+ } ,
320
+ Err ( err) => Err ( format!( "Request to `{url}` failed: {err}" ) ) ,
321
+ }
322
+ } ) {
323
+ AttemptResult :: Ok ( stake_distribution) => {
324
+ // todo: assert that the mithril stake distribution is really signed
325
+ info ! ( "Signer signed a mithril stake distribution" ; "certificate_hash" => & stake_distribution. certificate_hash) ;
326
+ Ok ( stake_distribution. certificate_hash )
327
+ }
328
+ AttemptResult :: Err ( error) => Err ( error) ,
329
+ AttemptResult :: Timeout ( ) => Err ( format ! (
330
+ "Timeout exhausted assert_signer_is_signing_mithril_stake_distribution, no response from `{url}`"
331
+ ) ) ,
332
+ }
333
+ }
334
+
243
335
async fn assert_node_producing_snapshot ( aggregator_endpoint : & str ) -> Result < String , String > {
244
336
let url = format ! ( "{aggregator_endpoint}/artifact/snapshots" ) ;
245
337
info ! ( "Waiting for the aggregator to produce a snapshot" ) ;
0 commit comments