1
1
use crate :: {
2
+ genesis_values:: GenesisValues ,
2
3
rational_number:: { ChameleonFraction , RationalNumber } ,
3
- BlockVersionData , Committee , Constitution , CostModel , DRepVotingThresholds , ExUnitPrices ,
4
- ExUnits , PoolVotingThresholds , ProtocolConsts ,
4
+ BlockVersionData , Committee , Constitution , CostModel , DRepVotingThresholds , Era , ExUnitPrices ,
5
+ ExUnits , NetworkId , PoolVotingThresholds , ProtocolConsts ,
5
6
} ;
7
+ use anyhow:: Result ;
8
+ use blake2:: { digest:: consts:: U32 , Blake2b , Digest } ;
6
9
use chrono:: { DateTime , Utc } ;
7
10
use serde_with:: serde_as;
8
11
@@ -95,12 +98,6 @@ pub struct ShelleyProtocolParams {
95
98
pub pool_pledge_influence : RationalNumber ,
96
99
}
97
100
98
- #[ derive( Debug , Clone , PartialEq , Eq , serde:: Serialize , serde:: Deserialize ) ]
99
- pub enum NetworkId {
100
- Testnet ,
101
- Mainnet ,
102
- }
103
-
104
101
#[ serde_as]
105
102
#[ derive( Debug , Clone , PartialEq , serde:: Serialize , serde:: Deserialize ) ]
106
103
#[ serde( rename_all = "camelCase" ) ]
@@ -127,6 +124,55 @@ pub struct ShelleyParams {
127
124
pub update_quorum : u32 ,
128
125
}
129
126
127
+ #[ serde_as]
128
+ #[ derive( Debug , Clone , PartialEq , serde:: Serialize , serde:: Deserialize ) ]
129
+ #[ serde( rename_all = "camelCase" ) ]
130
+ pub struct PraosParams {
131
+ pub security_param : u32 ,
132
+ #[ serde_as( as = "ChameleonFraction" ) ]
133
+ pub active_slots_coeff : RationalNumber ,
134
+ pub epoch_length : u32 ,
135
+ pub max_kes_evolutions : u32 ,
136
+ pub max_lovelace_supply : u64 ,
137
+ pub network_id : NetworkId ,
138
+ pub slot_length : u32 ,
139
+ pub slots_per_kes_period : u32 ,
140
+
141
+ /// Relative slot from which data of the previous epoch can be considered stable.
142
+ /// This value is used for all TPraos eras AND Babbage Era from Praos
143
+ pub stability_window : u64 ,
144
+
145
+ /// Number of slots at the end of each epoch which do NOT contribute randomness to the candidate
146
+ /// nonce of the following epoch.
147
+ /// This value is used for all Praos eras except Babbage
148
+ pub randomness_stabilization_window : u64 ,
149
+ }
150
+
151
+ impl From < & ShelleyParams > for PraosParams {
152
+ fn from ( params : & ShelleyParams ) -> Self {
153
+ let active_slots_coeff = params. active_slots_coeff ;
154
+ let security_param = params. security_param ;
155
+ let stability_window =
156
+ ( security_param as u64 ) * active_slots_coeff. denom ( ) / active_slots_coeff. numer ( ) * 3 ;
157
+ let randomness_stabilization_window =
158
+ ( security_param as u64 ) * active_slots_coeff. denom ( ) / active_slots_coeff. numer ( ) * 4 ;
159
+
160
+ Self {
161
+ security_param : security_param,
162
+ active_slots_coeff : active_slots_coeff,
163
+ epoch_length : params. epoch_length ,
164
+ max_kes_evolutions : params. max_kes_evolutions ,
165
+ max_lovelace_supply : params. max_lovelace_supply ,
166
+ network_id : params. network_id . clone ( ) ,
167
+ slot_length : params. slot_length ,
168
+ slots_per_kes_period : params. slots_per_kes_period ,
169
+
170
+ stability_window : stability_window,
171
+ randomness_stabilization_window : randomness_stabilization_window,
172
+ }
173
+ }
174
+ }
175
+
130
176
//
131
177
// Babbage protocol parameters
132
178
//
@@ -164,16 +210,133 @@ pub struct ProtocolVersion {
164
210
pub major : u64 ,
165
211
}
166
212
167
- #[ derive( Debug , Clone , PartialEq , Eq , serde:: Serialize , serde:: Deserialize ) ]
213
+ #[ derive(
214
+ Default , Debug , Clone , PartialEq , Eq , PartialOrd , Ord , serde:: Serialize , serde:: Deserialize ,
215
+ ) ]
168
216
#[ serde( rename_all = "PascalCase" ) ]
169
217
pub enum NonceVariant {
218
+ #[ default]
170
219
NeutralNonce ,
171
220
Nonce ,
172
221
}
173
222
174
- #[ derive( Debug , Clone , PartialEq , Eq , serde:: Serialize , serde:: Deserialize ) ]
223
+ pub type NonceHash = [ u8 ; 32 ] ;
224
+
225
+ #[ derive( Debug , Clone , PartialEq , Eq , PartialOrd , Ord , serde:: Serialize , serde:: Deserialize ) ]
175
226
#[ serde( rename_all = "camelCase" ) ]
176
227
pub struct Nonce {
177
228
pub tag : NonceVariant ,
178
- pub hash : Option < Vec < u8 > > ,
229
+ pub hash : Option < NonceHash > ,
230
+ }
231
+
232
+ impl Default for Nonce {
233
+ fn default ( ) -> Self {
234
+ Self {
235
+ tag : NonceVariant :: NeutralNonce ,
236
+ hash : None ,
237
+ }
238
+ }
239
+ }
240
+
241
+ impl From < NonceHash > for Nonce {
242
+ fn from ( hash : NonceHash ) -> Self {
243
+ Self {
244
+ tag : NonceVariant :: Nonce ,
245
+ hash : Some ( hash) ,
246
+ }
247
+ }
248
+ }
249
+
250
+ #[ derive(
251
+ Default , Debug , PartialEq , Eq , PartialOrd , Ord , Clone , serde:: Serialize , serde:: Deserialize ,
252
+ ) ]
253
+ pub struct Nonces {
254
+ pub epoch : u64 ,
255
+ pub active : Nonce ,
256
+ pub evolving : Nonce ,
257
+ pub candidate : Nonce ,
258
+ // Nonce constructed from the hash of the Last Applied Block
259
+ pub lab : Nonce ,
260
+ // Nonce corresponding to the LAB nonce of the last block of the previous epoch
261
+ pub prev_lab : Nonce ,
262
+ }
263
+
264
+ impl Nonces {
265
+ pub fn shelley_genesis_nonces ( genesis : & GenesisValues ) -> Nonces {
266
+ Nonces {
267
+ epoch : genesis. shelley_epoch ,
268
+ active : genesis. shelley_genesis_hash . into ( ) ,
269
+ evolving : genesis. shelley_genesis_hash . into ( ) ,
270
+ candidate : genesis. shelley_genesis_hash . into ( ) ,
271
+ lab : Nonce :: default ( ) ,
272
+ prev_lab : Nonce :: default ( ) ,
273
+ }
274
+ }
275
+
276
+ pub fn from_candidate ( candidate : & Nonce , prev_lab : & Nonce ) -> Result < Nonce > {
277
+ let Some ( candidate_hash) = candidate. hash . as_ref ( ) else {
278
+ return Err ( anyhow:: anyhow!( "Candidate hash is not set" ) ) ;
279
+ } ;
280
+
281
+ // if prev_lab is Neutral then just return candidate
282
+ // this is for second shelley epoch boundary (from 208 to 209 in mainnet)
283
+ match prev_lab. tag {
284
+ NonceVariant :: NeutralNonce => {
285
+ return Ok ( candidate. clone ( ) ) ;
286
+ }
287
+ NonceVariant :: Nonce => {
288
+ let Some ( prev_lab_hash) = prev_lab. hash . as_ref ( ) else {
289
+ return Err ( anyhow:: anyhow!( "Prev lab hash is not set" ) ) ;
290
+ } ;
291
+ let mut hasher = Blake2b :: < U32 > :: new ( ) ;
292
+ hasher. update ( & [ & candidate_hash. clone ( ) [ ..] , & prev_lab_hash. clone ( ) [ ..] ] . concat ( ) ) ;
293
+ let hash: NonceHash = hasher. finalize ( ) . into ( ) ;
294
+ Ok ( Nonce :: from ( hash) )
295
+ }
296
+ }
297
+ }
298
+
299
+ /// Evolve the current nonce by combining it with the current rolling nonce and the
300
+ /// range-extended tagged leader VRF output.
301
+ ///
302
+ /// Specifically, we combine it with `η` (a.k.a eta), which is a blake2b-256 hash of the
303
+ /// tagged leader VRF output after a range extension. The range extension is, yet another
304
+ /// blake2b-256 hash.
305
+ pub fn evolve ( current : & Nonce , nonce_vrf_output : & Vec < u8 > , ) -> Result < Nonce > {
306
+ // first hash nonce_vrf_output
307
+ let mut hasher = Blake2b :: < U32 > :: new ( ) ;
308
+ hasher. update ( nonce_vrf_output. as_slice ( ) ) ;
309
+ let nonce_vrf_output_hash: [ u8 ; 32 ] = hasher. finalize ( ) . into ( ) ;
310
+
311
+ match current. hash . as_ref ( ) {
312
+ Some ( nonce) => {
313
+ let mut hasher = Blake2b :: < U32 > :: new ( ) ;
314
+ hasher. update ( & [ & nonce. clone ( ) [ ..] , & nonce_vrf_output_hash[ ..] ] . concat ( ) ) ;
315
+ let hash: NonceHash = hasher. finalize ( ) . into ( ) ;
316
+ Ok ( Nonce :: from ( hash) )
317
+ }
318
+ _ => Err ( anyhow:: anyhow!( "Current nonce is not set" ) ) ,
319
+ }
320
+ }
321
+
322
+ pub fn randomness_stability_window (
323
+ era : Era ,
324
+ slot : u64 ,
325
+ genesis : & GenesisValues ,
326
+ params : & PraosParams ,
327
+ ) -> bool {
328
+ let ( epoch, _) = genesis. slot_to_epoch ( slot) ;
329
+ let next_epoch_first_slot = genesis. epoch_to_first_slot ( epoch + 1 ) ;
330
+
331
+ // For Praos in Babbage (just as in all TPraos eras) we use the
332
+ // smaller (3k/f vs 4k/f slots) stability window here for
333
+ // backwards-compatibility. See erratum 17.3 in the Shelley ledger
334
+ // specs for context
335
+ let window = match era {
336
+ Era :: Conway => params. randomness_stabilization_window ,
337
+ _ => params. stability_window ,
338
+ } ;
339
+
340
+ slot + window < next_epoch_first_slot
341
+ }
179
342
}
0 commit comments