Skip to content

Commit 834bead

Browse files
Sawchordeichhorl
andauthored
refactor(consensus): Refactor code in NiDkg to prepare VetKD implementation (dfinity#3522)
This PR makes changes to DKG in order to prepare the implementation of CON-1413. In particular, it makes two changes: 1. `Summary::current_transcript` now returns an `Option`, rather than panicking. With the introduction of the `NiDkgTag::HighThresholdForKey(_)`, we can no longer enumerate all variants, and we should not assume that the `Summary` contains all the tags we assume. In fact, when generating a vetkey, we will end up in situations where `next_transcripts` contains tags that `current_transctips` doesn't have. This PR simply adds unwraps at all call sites, since the code should not panic, if called with `NiDkgTag::LowThreshold` or `NiDkgTag::HighThreshold`. 2. Reimplement `into_next_transcripts` and move it into `dkg` crate The current implementation is slightly wrong, since it enumerates the tags from the `current_transcripts`, which makes the assumption that the tags of `next_transcripts` is a subset of the tags of `current_transcripts`. This is not correct. When we add a new vetkey, we generate a `Config` for it at put it in the`Summary`. This will generate a `NiDkgTag::HighThresholdForKey(_)` transcript for it and put it into `next_transcripts` of the next block. So this transcript would never become a `current_transcript` with the old code. The new code simply copies `next_transcripts` over to the new summary as `current_transcripts` and then looks for old `current_trascripts` whose tags are missing and copies them over too. Also the code was moved from `ic-types` into the `dkg` crate, since it was only used there, and this way we can add some logging. --------- Co-authored-by: Leo Eichhorn <[email protected]>
1 parent d37cb7b commit 834bead

File tree

9 files changed

+49
-33
lines changed

9 files changed

+49
-33
lines changed

rs/consensus/dkg/src/dkg_key_manager.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ impl DkgKeyManager {
484484
.set(summary.registry_version.get() as i64);
485485

486486
for tag in [NiDkgTag::LowThreshold, NiDkgTag::HighThreshold].iter() {
487-
let current_transcript = summary.current_transcript(tag);
487+
let current_transcript = summary.current_transcript(tag).unwrap();
488488
let metric_label = &format!("{:?}", tag);
489489

490490
self.metrics

rs/consensus/dkg/src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1646,7 +1646,7 @@ mod tests {
16461646
RegistryVersion::from(5)
16471647
);
16481648
for tag in TAGS.iter() {
1649-
let current_transcript = dkg_summary.current_transcript(tag);
1649+
let current_transcript = dkg_summary.current_transcript(tag).unwrap();
16501650
assert_eq!(
16511651
current_transcript.dkg_id.start_block_height,
16521652
Height::from(0)
@@ -1700,7 +1700,7 @@ mod tests {
17001700
);
17011701
for tag in TAGS.iter() {
17021702
// We reused the transcript.
1703-
let current_transcript = dkg_summary.current_transcript(tag);
1703+
let current_transcript = dkg_summary.current_transcript(tag).unwrap();
17041704
assert_eq!(
17051705
current_transcript.dkg_id.start_block_height,
17061706
Height::from(0)
@@ -1763,7 +1763,7 @@ mod tests {
17631763
conf.receivers().get(),
17641764
&committee3.clone().into_iter().collect::<BTreeSet<_>>()
17651765
);
1766-
let current_transcript = dkg_summary.current_transcript(tag);
1766+
let current_transcript = dkg_summary.current_transcript(tag).unwrap();
17671767
assert_eq!(
17681768
current_transcript.dkg_id.start_block_height,
17691769
Height::from(0)
@@ -1803,7 +1803,7 @@ mod tests {
18031803
conf.receivers().get(),
18041804
&committee3.clone().into_iter().collect::<BTreeSet<_>>()
18051805
);
1806-
let current_transcript = dkg_summary.current_transcript(tag);
1806+
let current_transcript = dkg_summary.current_transcript(tag).unwrap();
18071807
assert_eq!(
18081808
current_transcript.dkg_id.start_block_height,
18091809
Height::from(5)
@@ -1841,7 +1841,7 @@ mod tests {
18411841
conf.receivers().get(),
18421842
&committee3.clone().into_iter().collect::<BTreeSet<_>>()
18431843
);
1844-
let current_transcript = dkg_summary.current_transcript(tag);
1844+
let current_transcript = dkg_summary.current_transcript(tag).unwrap();
18451845
assert_eq!(
18461846
current_transcript.dkg_id.start_block_height,
18471847
Height::from(10)

rs/consensus/dkg/src/payload_builder.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ pub(super) fn create_summary_payload(
212212
subnet_id,
213213
)?;
214214
// Current transcripts come from next transcripts of the last_summary.
215-
let current_transcripts = last_summary.clone().into_next_transcripts();
215+
let current_transcripts = as_next_transcripts(last_summary, &logger);
216216

217217
// If the config for the currently computed DKG intervals requires a transcript
218218
// resharing (currently for high-threshold DKG only), we are going to re-share
@@ -266,6 +266,24 @@ fn create_transcript(
266266
ic_interfaces::crypto::NiDkgAlgorithm::create_transcript(crypto, config, dealings)
267267
}
268268

269+
/// Return the set of next transcripts for all tags. If for some tag
270+
/// the next transcript is not available, the current transcript is used.
271+
fn as_next_transcripts(
272+
summary: &Summary,
273+
logger: &ReplicaLogger,
274+
) -> BTreeMap<NiDkgTag, NiDkgTranscript> {
275+
let mut next_transcripts = summary.next_transcripts().clone();
276+
277+
for (tag, transcript) in summary.current_transcripts().iter() {
278+
if !next_transcripts.contains_key(tag) {
279+
warn!(logger, "Reusing current transcript for tag {:?}", tag);
280+
next_transcripts.insert(tag.clone(), transcript.clone());
281+
}
282+
}
283+
284+
next_transcripts
285+
}
286+
269287
#[allow(clippy::type_complexity)]
270288
#[allow(clippy::too_many_arguments)]
271289
fn compute_remote_dkg_data(
@@ -1135,7 +1153,8 @@ mod tests {
11351153
assert_eq!(
11361154
next_summary
11371155
.clone()
1138-
.current_transcript(&NiDkgTag::HighThreshold),
1156+
.current_transcript(&NiDkgTag::HighThreshold)
1157+
.unwrap(),
11391158
&conf.resharing_transcript().clone().unwrap()
11401159
)
11411160
}

rs/consensus/dkg/src/payload_validator.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
use std::collections::HashSet;
2-
3-
use super::{payload_builder, utils, PayloadCreationError};
1+
use crate::{payload_builder, utils, PayloadCreationError};
42
use ic_consensus_utils::{crypto::ConsensusCrypto, pool_reader::PoolReader};
53
use ic_interfaces::{
64
dkg::DkgPool,
@@ -24,6 +22,7 @@ use ic_types::{
2422
Height, NodeId, SubnetId,
2523
};
2624
use prometheus::IntCounterVec;
25+
use std::collections::HashSet;
2726

2827
/// Reasons for why a dkg payload might be invalid.
2928
// The `Debug` implementation is ignored during the dead code analysis and we are getting a `field

rs/consensus/src/cup_utils.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,12 @@ pub fn make_registry_cup_from_cup_contents(
7474

7575
let low_dkg_id = dkg_summary
7676
.current_transcript(&NiDkgTag::LowThreshold)
77+
.expect("No current low threshold transcript available")
7778
.dkg_id
7879
.clone();
7980
let high_dkg_id = dkg_summary
8081
.current_transcript(&NiDkgTag::HighThreshold)
82+
.expect("No current high threshold transcript available")
8183
.dkg_id
8284
.clone();
8385

rs/consensus/utils/src/lib.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,10 @@ pub fn active_low_threshold_nidkg_id(
263263
) -> Option<NiDkgId> {
264264
get_active_data_at(reader, height, |block, height| {
265265
get_transcript_data_at_given_summary(block, height, NiDkgTag::LowThreshold, |transcript| {
266-
transcript.dkg_id.clone()
266+
transcript
267+
.expect("No active low threshold transcript available for tag {:?}")
268+
.dkg_id
269+
.clone()
267270
})
268271
})
269272
}
@@ -275,7 +278,10 @@ pub fn active_high_threshold_nidkg_id(
275278
) -> Option<NiDkgId> {
276279
get_active_data_at(reader, height, |block, height| {
277280
get_transcript_data_at_given_summary(block, height, NiDkgTag::HighThreshold, |transcript| {
278-
transcript.dkg_id.clone()
281+
transcript
282+
.expect("No active high threshold transcript available for tag {:?}")
283+
.dkg_id
284+
.clone()
279285
})
280286
})
281287
}
@@ -287,6 +293,7 @@ pub fn active_low_threshold_committee(
287293
) -> Option<(Threshold, NiDkgReceivers)> {
288294
get_active_data_at(reader, height, |block, height| {
289295
get_transcript_data_at_given_summary(block, height, NiDkgTag::LowThreshold, |transcript| {
296+
let transcript = transcript.expect("No active low threshold transcript available");
290297
(
291298
transcript.threshold.get().get() as usize,
292299
transcript.committee.clone(),
@@ -302,6 +309,7 @@ pub fn active_high_threshold_committee(
302309
) -> Option<(Threshold, NiDkgReceivers)> {
303310
get_active_data_at(reader, height, |block, height| {
304311
get_transcript_data_at_given_summary(block, height, NiDkgTag::HighThreshold, |transcript| {
312+
let transcript = transcript.expect("No active high threshold transcript available");
305313
(
306314
transcript.threshold.get().get() as usize,
307315
transcript.committee.clone(),
@@ -357,15 +365,15 @@ fn get_transcript_data_at_given_summary<T>(
357365
summary_block: &Block,
358366
height: Height,
359367
tag: NiDkgTag,
360-
getter: impl Fn(&NiDkgTranscript) -> T,
368+
getter: impl Fn(Option<&NiDkgTranscript>) -> T,
361369
) -> Option<T> {
362370
let dkg_summary = &summary_block.payload.as_ref().as_summary().dkg;
363371
if dkg_summary.current_interval_includes(height) {
364372
Some(getter(dkg_summary.current_transcript(&tag)))
365373
} else if dkg_summary.next_interval_includes(height) {
366374
let transcript = dkg_summary
367375
.next_transcript(&tag)
368-
.unwrap_or_else(|| dkg_summary.current_transcript(&tag));
376+
.or(dkg_summary.current_transcript(&tag));
369377
Some(getter(transcript))
370378
} else {
371379
None

rs/replay/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,10 +240,12 @@ fn cmd_get_recovery_cup(
240240
let low_threshold_transcript = summary
241241
.dkg
242242
.current_transcript(&NiDkgTag::LowThreshold)
243+
.expect("No current low threshold transcript available")
243244
.clone();
244245
let high_threshold_transcript = summary
245246
.dkg
246247
.current_transcript(&NiDkgTag::HighThreshold)
248+
.expect("No current high threshold transcript available")
247249
.clone();
248250
let initial_ni_dkg_transcript_low_threshold =
249251
Some(InitialNiDkgTranscriptRecord::from(low_threshold_transcript));

rs/test_utilities/consensus/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,12 @@ pub fn make_genesis(summary: dkg::Summary) -> CatchUpPackage {
140140
let height = summary.height;
141141
let low_dkg_id = summary
142142
.current_transcript(&NiDkgTag::LowThreshold)
143+
.unwrap()
143144
.dkg_id
144145
.clone();
145146
let high_dkg_id = summary
146147
.current_transcript(&NiDkgTag::HighThreshold)
148+
.unwrap()
147149
.dkg_id
148150
.clone();
149151
let block = Block::new(

rs/types/types/src/consensus/dkg.rs

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,8 @@ impl Summary {
209209
/// Returns a reference to the current transcript for the given tag. Note
210210
/// that currently we expect that a valid summary contains the current
211211
/// transcript for any DKG tag.
212-
pub fn current_transcript(&self, tag: &NiDkgTag) -> &NiDkgTranscript {
213-
self.current_transcripts
214-
.get(tag)
215-
.unwrap_or_else(|| panic!("No current transcript available for tag {:?}", tag))
212+
pub fn current_transcript(&self, tag: &NiDkgTag) -> Option<&NiDkgTranscript> {
213+
self.current_transcripts.get(tag)
216214
}
217215

218216
/// Returns a reference to the current transcripts.
@@ -241,20 +239,6 @@ impl Summary {
241239
.collect()
242240
}
243241

244-
/// Return the set of next transcripts for all tags. If for some tag
245-
/// the next transcript is not available, the current transcript is used.
246-
/// This function avoids expensive copying when transcripts are large.
247-
pub fn into_next_transcripts(self) -> BTreeMap<NiDkgTag, NiDkgTranscript> {
248-
let mut next_transcripts = self.next_transcripts;
249-
self.current_transcripts
250-
.into_iter()
251-
.map(|(tag, current)| {
252-
let new_next_transcripts = next_transcripts.remove(&tag).unwrap_or(current);
253-
(tag, new_next_transcripts)
254-
})
255-
.collect()
256-
}
257-
258242
/// Returns `true` if the provided height is included in the DKG interval
259243
/// corresponding to the current summary. Note that the summary block is
260244
/// considered to be part of the interval. For example, if the start height

0 commit comments

Comments
 (0)