Skip to content

Commit e95a839

Browse files
Alenarsfauveldlachaume
committed
Introduce CardanoTransactionSigning config
To compute the block number to be signed based on the chain tip. Co-authored-by: Sébastien Fauvel <[email protected]> Co-authored-by: Damien Lachaume <[email protected]>
1 parent dcceb41 commit e95a839

File tree

1 file changed

+133
-4
lines changed

1 file changed

+133
-4
lines changed

mithril-common/src/entities/signed_entity_type.rs

Lines changed: 133 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use sha2::Sha256;
66
use std::time::Duration;
77
use strum::{AsRefStr, Display, EnumDiscriminants, EnumString};
88

9-
use super::{BlockNumber, CardanoDbBeacon, Epoch, TimePoint};
9+
use super::{BlockNumber, BlockRange, CardanoDbBeacon, Epoch, TimePoint};
1010

1111
/// Database representation of the SignedEntityType::MithrilStakeDistribution value
1212
const ENTITY_TYPE_MITHRIL_STAKE_DISTRIBUTION: usize = 0;
@@ -44,6 +44,52 @@ pub enum SignedEntityType {
4444
CardanoTransactions(Epoch, BlockNumber),
4545
}
4646

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+
4793
impl SignedEntityType {
4894
/// Retrieve a dummy enty (for test only)
4995
pub fn dummy() -> Self {
@@ -108,6 +154,7 @@ impl SignedEntityType {
108154
discriminant: &SignedEntityTypeDiscriminants,
109155
network: &str,
110156
time_point: &TimePoint,
157+
cardano_transactions_signing_config: &CardanoTransactionsSigningConfig,
111158
) -> Self {
112159
match discriminant {
113160
SignedEntityTypeDiscriminants::MithrilStakeDistribution => {
@@ -123,9 +170,11 @@ impl SignedEntityType {
123170
time_point.immutable_file_number,
124171
))
125172
}
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+
),
129178
}
130179
}
131180

@@ -311,4 +360,84 @@ mod tests {
311360
]
312361
);
313362
}
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+
}
314443
}

0 commit comments

Comments
 (0)