@@ -6,7 +6,7 @@ use sha2::Sha256;
6
6
use std:: time:: Duration ;
7
7
use strum:: { AsRefStr , Display , EnumDiscriminants , EnumString } ;
8
8
9
- use super :: { BlockNumber , CardanoDbBeacon , Epoch , TimePoint } ;
9
+ use super :: { BlockNumber , BlockRange , CardanoDbBeacon , Epoch , TimePoint } ;
10
10
11
11
/// Database representation of the SignedEntityType::MithrilStakeDistribution value
12
12
const ENTITY_TYPE_MITHRIL_STAKE_DISTRIBUTION : usize = 0 ;
@@ -44,6 +44,52 @@ pub enum SignedEntityType {
44
44
CardanoTransactions ( Epoch , BlockNumber ) ,
45
45
}
46
46
47
+ /// Configuration for the signing of Cardano transactions
48
+ ///
49
+ /// Allow to compute the block number to be signed based on the chain tip block number.
50
+ ///
51
+ #[ derive( Debug , Clone , PartialEq , Eq , Serialize , Deserialize ) ]
52
+ pub struct CardanoTransactionsSigningConfig {
53
+ /// Number of blocks to wait before taking in account a transaction.
54
+ pub security_parameter : BlockNumber ,
55
+
56
+ /// The frequency at which the transactions are signed.
57
+ ///
58
+ /// *Note: The step is adjusted to be a multiple of the block range length in order.*
59
+ pub step : BlockNumber ,
60
+ }
61
+
62
+ impl CardanoTransactionsSigningConfig {
63
+ cfg_test_tools ! {
64
+ /// Create a dummy config
65
+ pub fn dummy( ) -> Self {
66
+ Self {
67
+ security_parameter: 0 ,
68
+ step: 15 ,
69
+ }
70
+ }
71
+ }
72
+
73
+ /// Compute the block number to be signed based on che chain tip block number.
74
+ ///
75
+ /// Given k' = `security_parameter` and n = `step`,
76
+ /// the latest block number to be signed is computed as *(this use a integer division)*:
77
+ ///
78
+ /// **block_number = ((tip.block_number - k') / n) × n**
79
+ ///
80
+ /// *Note: The step is adjusted to be a multiple of the block range length in order
81
+ /// to guarantee that the block number signed in a certificate is effectively signed.*
82
+ pub fn compute_block_number_to_be_signed ( & self , block_number : BlockNumber ) -> BlockNumber {
83
+ // TODO: See if we can remove this adjustment by including a "partial" block range in
84
+ // the signed data.
85
+ let adjusted_step = BlockRange :: from_block_number ( self . step ) . start ;
86
+ // We can't have a step lower than the block range length.
87
+ let adjusted_step = std:: cmp:: max ( adjusted_step, BlockRange :: LENGTH ) ;
88
+
89
+ ( block_number - self . security_parameter ) / adjusted_step * adjusted_step
90
+ }
91
+ }
92
+
47
93
impl SignedEntityType {
48
94
/// Retrieve a dummy enty (for test only)
49
95
pub fn dummy ( ) -> Self {
@@ -108,6 +154,7 @@ impl SignedEntityType {
108
154
discriminant : & SignedEntityTypeDiscriminants ,
109
155
network : & str ,
110
156
time_point : & TimePoint ,
157
+ cardano_transactions_signing_config : & CardanoTransactionsSigningConfig ,
111
158
) -> Self {
112
159
match discriminant {
113
160
SignedEntityTypeDiscriminants :: MithrilStakeDistribution => {
@@ -123,9 +170,11 @@ impl SignedEntityType {
123
170
time_point. immutable_file_number ,
124
171
) )
125
172
}
126
- SignedEntityTypeDiscriminants :: CardanoTransactions => {
127
- Self :: CardanoTransactions ( time_point. epoch , time_point. chain_point . block_number )
128
- }
173
+ SignedEntityTypeDiscriminants :: CardanoTransactions => Self :: CardanoTransactions (
174
+ time_point. epoch ,
175
+ cardano_transactions_signing_config
176
+ . compute_block_number_to_be_signed ( time_point. chain_point . block_number ) ,
177
+ ) ,
129
178
}
130
179
}
131
180
@@ -311,4 +360,84 @@ mod tests {
311
360
]
312
361
) ;
313
362
}
363
+
364
+ #[ test]
365
+ fn computing_block_number_to_be_signed ( ) {
366
+ // **block_number = ((tip.block_number - k') / n) × n**
367
+ assert_eq ! (
368
+ CardanoTransactionsSigningConfig {
369
+ security_parameter: 0 ,
370
+ step: 15 ,
371
+ }
372
+ . compute_block_number_to_be_signed( 105 ) ,
373
+ 105
374
+ ) ;
375
+
376
+ assert_eq ! (
377
+ CardanoTransactionsSigningConfig {
378
+ security_parameter: 5 ,
379
+ step: 15 ,
380
+ }
381
+ . compute_block_number_to_be_signed( 100 ) ,
382
+ 90
383
+ ) ;
384
+
385
+ assert_eq ! (
386
+ CardanoTransactionsSigningConfig {
387
+ security_parameter: 85 ,
388
+ step: 15 ,
389
+ }
390
+ . compute_block_number_to_be_signed( 100 ) ,
391
+ 15
392
+ ) ;
393
+
394
+ assert_eq ! (
395
+ CardanoTransactionsSigningConfig {
396
+ security_parameter: 0 ,
397
+ step: 30 ,
398
+ }
399
+ . compute_block_number_to_be_signed( 29 ) ,
400
+ 0
401
+ ) ;
402
+ }
403
+
404
+ #[ test]
405
+ fn computing_block_number_to_be_signed_round_step_to_a_block_range_start ( ) {
406
+ assert_eq ! (
407
+ CardanoTransactionsSigningConfig {
408
+ security_parameter: 0 ,
409
+ step: BlockRange :: LENGTH * 2 - 1 ,
410
+ }
411
+ . compute_block_number_to_be_signed( BlockRange :: LENGTH * 5 + 1 ) ,
412
+ BlockRange :: LENGTH * 5
413
+ ) ;
414
+
415
+ assert_eq ! (
416
+ CardanoTransactionsSigningConfig {
417
+ security_parameter: 0 ,
418
+ step: BlockRange :: LENGTH * 2 + 1 ,
419
+ }
420
+ . compute_block_number_to_be_signed( BlockRange :: LENGTH * 5 + 1 ) ,
421
+ BlockRange :: LENGTH * 4
422
+ ) ;
423
+
424
+ // Adjusted step is always at least BLOCK_RANGE_LENGTH.
425
+ assert_eq ! (
426
+ CardanoTransactionsSigningConfig {
427
+ security_parameter: 0 ,
428
+ step: BlockRange :: LENGTH - 1 ,
429
+ }
430
+ . compute_block_number_to_be_signed( BlockRange :: LENGTH * 10 - 1 ) ,
431
+ BlockRange :: LENGTH * 9
432
+ ) ;
433
+
434
+ assert_eq ! (
435
+ CardanoTransactionsSigningConfig {
436
+ security_parameter: 0 ,
437
+ step: BlockRange :: LENGTH - 1 ,
438
+ }
439
+ . compute_block_number_to_be_signed( BlockRange :: LENGTH - 1 ) ,
440
+ 0
441
+ ) ;
442
+ }
314
443
}
0 commit comments