Skip to content

Commit fda020e

Browse files
committed
Merge branch 'eichhorl/fetch-complaints' into 'master'
fix(ecdsa): CON-1039 Do not drop complaints/openings for requested transcripts Let [A, B, C, D] be a subnet. Let `h_r` be the height at which transcripts `t1`, `t2` are requested (i.a. their configs are written into the block and the id is added to `requested_transcripts`). Assume `t1` and `t2` are completed at a height `h_c > h_r`. They are added to `active_transcripts` and a new config for a transcript `t'` building on `t1` and `t2` is created. Assume further that node A (B) was unable to support `t1` (`t2`) due to a corrupted dealing. When A (B) tries to create a dealing for `t'`, it is unable to load `t1` (`t2`), thus proceeds by sending a complaint for `t1` (`t2`). Now assume that nodes C and D are slightly behind at a height `h` with `h_c > h >= h_r`. They receive A and B's complaints for `t1` and `t2`, but as the transcripts are not yet completed (`h_c > h`), in the current implementation, C and D will drop the adverts of the complaints and never receive them again or send the corresponding openings. Therefore, A and B are unable to create a dealing for `t'` and the transcript is stuck. With this MR we fetch Complaints/Openings even if the corresponding transcript is requested but not yet completed. As processing Complaints/Openings without the completed transcript is impossible, we defer processing until later, when the transcript has moved from `requested` to `active`. Additionally: - Stop trying to create openings for own complaints. This fails when calling the crypto function and creates unnecessary logs and overhead. See merge request dfinity-lab/public/ic!12486
2 parents 01cbc1c + 2a95674 commit fda020e

File tree

2 files changed

+63
-14
lines changed

2 files changed

+63
-14
lines changed

rs/consensus/src/ecdsa.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,9 @@ fn compute_priority(
520520
| EcdsaMessageAttribute::EcdsaOpening(transcript_id) => {
521521
let height = transcript_id.source_height();
522522
if height <= args.finalized_height {
523-
if args.active_transcripts.contains(transcript_id) {
523+
if args.active_transcripts.contains(transcript_id)
524+
|| args.requested_transcripts.contains(transcript_id)
525+
{
524526
Priority::Fetch
525527
} else {
526528
metrics
@@ -695,15 +697,18 @@ mod tests {
695697
let transcript_id_drop = IDkgTranscriptId::new(subnet_id, 2, Height::from(70));
696698
let transcript_id_fetch_2 = IDkgTranscriptId::new(subnet_id, 3, Height::from(102));
697699
let transcript_id_stash = IDkgTranscriptId::new(subnet_id, 4, Height::from(200));
700+
let transcript_id_fetch_3 = IDkgTranscriptId::new(subnet_id, 5, Height::from(80));
698701

699702
let metrics_registry = MetricsRegistry::new();
700703
let metrics = EcdsaGossipMetrics::new(metrics_registry);
701704

702705
let mut active_transcripts = BTreeSet::new();
703706
active_transcripts.insert(transcript_id_fetch_1);
707+
let mut requested_transcripts = BTreeSet::new();
708+
requested_transcripts.insert(transcript_id_fetch_3);
704709
let args = EcdsaPriorityFnArgs {
705710
finalized_height: Height::from(100),
706-
requested_transcripts: BTreeSet::new(),
711+
requested_transcripts,
707712
requested_signatures: BTreeSet::new(),
708713
active_transcripts,
709714
};
@@ -726,6 +731,10 @@ mod tests {
726731
EcdsaMessageAttribute::EcdsaComplaint(transcript_id_stash),
727732
Priority::Stash,
728733
),
734+
(
735+
EcdsaMessageAttribute::EcdsaComplaint(transcript_id_fetch_3),
736+
Priority::Fetch,
737+
),
729738
// Openings
730739
(
731740
EcdsaMessageAttribute::EcdsaOpening(transcript_id_fetch_1),
@@ -743,6 +752,10 @@ mod tests {
743752
EcdsaMessageAttribute::EcdsaOpening(transcript_id_stash),
744753
Priority::Stash,
745754
),
755+
(
756+
EcdsaMessageAttribute::EcdsaOpening(transcript_id_fetch_3),
757+
Priority::Fetch,
758+
),
746759
];
747760

748761
for (attr, expected) in tests {

rs/consensus/src/ecdsa/complaints.rs

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ impl EcdsaComplaintHandlerImpl {
100100
block_reader: &dyn EcdsaBlockReader,
101101
) -> EcdsaChangeSet {
102102
let active_transcripts = self.active_transcripts(block_reader);
103+
let requested_transcripts = self.requested_transcripts(block_reader);
103104

104105
// Collection of validated complaints <complainer Id, transcript Id, dealer Id>
105106
let mut validated_complaints = BTreeSet::new();
@@ -125,6 +126,7 @@ impl EcdsaComplaintHandlerImpl {
125126
match Action::action(
126127
block_reader,
127128
&active_transcripts,
129+
&requested_transcripts,
128130
complaint.idkg_complaint.transcript_id.source_height(),
129131
&complaint.idkg_complaint.transcript_id,
130132
) {
@@ -182,6 +184,10 @@ impl EcdsaComplaintHandlerImpl {
182184
.validated()
183185
.complaints()
184186
.filter(|(_, signed_complaint)| {
187+
// Do not try to create openings for own complaints.
188+
if signed_complaint.signature.signer == self.node_id {
189+
return false;
190+
}
185191
let complaint = signed_complaint.get();
186192
!self.has_node_issued_opening(
187193
ecdsa_pool,
@@ -217,6 +223,7 @@ impl EcdsaComplaintHandlerImpl {
217223
block_reader: &dyn EcdsaBlockReader,
218224
) -> EcdsaChangeSet {
219225
let active_transcripts = self.active_transcripts(block_reader);
226+
let requested_transcripts = self.requested_transcripts(block_reader);
220227

221228
// Collection of validated openings <opener Id, transcript Id, dealer Id>
222229
let mut validated_openings = BTreeSet::new();
@@ -240,6 +247,7 @@ impl EcdsaComplaintHandlerImpl {
240247
match Action::action(
241248
block_reader,
242249
&active_transcripts,
250+
&requested_transcripts,
243251
opening.idkg_opening.transcript_id.source_height(),
244252
&opening.idkg_opening.transcript_id,
245253
) {
@@ -749,6 +757,17 @@ impl EcdsaComplaintHandlerImpl {
749757
.map(|transcript_ref| (transcript_ref.transcript_id, *transcript_ref))
750758
.collect::<BTreeMap<_, _>>()
751759
}
760+
761+
/// Returns the requested transcript map.
762+
fn requested_transcripts(
763+
&self,
764+
block_reader: &dyn EcdsaBlockReader,
765+
) -> BTreeSet<IDkgTranscriptId> {
766+
block_reader
767+
.requested_transcripts()
768+
.map(|transcript_ref| transcript_ref.transcript_id)
769+
.collect::<BTreeSet<_>>()
770+
}
752771
}
753772

754773
impl EcdsaComplaintHandler for EcdsaComplaintHandlerImpl {
@@ -922,6 +941,7 @@ impl<'a> Action<'a> {
922941
fn action(
923942
block_reader: &'a dyn EcdsaBlockReader,
924943
active_transcripts: &'a BTreeMap<IDkgTranscriptId, TranscriptRef>,
944+
requested_transcripts: &'a BTreeSet<IDkgTranscriptId>,
925945
msg_height: Height,
926946
msg_transcript_id: &IDkgTranscriptId,
927947
) -> Action<'a> {
@@ -931,10 +951,17 @@ impl<'a> Action<'a> {
931951
return Action::Defer;
932952
}
933953

934-
match active_transcripts.get(msg_transcript_id) {
935-
Some(transcript_ref) => Action::Process(transcript_ref),
936-
None => Action::Drop,
954+
if let Some(transcript_ref) = active_transcripts.get(msg_transcript_id) {
955+
return Action::Process(transcript_ref);
956+
}
957+
958+
// The transcript is not yet completed on this node, process
959+
// the message later when it is.
960+
if requested_transcripts.contains(msg_transcript_id) {
961+
return Action::Defer;
937962
}
963+
964+
Action::Drop
938965
}
939966
}
940967

@@ -955,44 +982,53 @@ mod tests {
955982
// Tests the Action logic
956983
#[test]
957984
fn test_ecdsa_complaint_action() {
958-
let (id_1, id_2, id_3, id_4) = (
985+
let (id_1, id_2, id_3, id_4, id_5) = (
959986
create_transcript_id(1),
960987
create_transcript_id(2),
961988
create_transcript_id(3),
962989
create_transcript_id(4),
990+
create_transcript_id(5),
963991
);
964992

965993
let ref_1 = TranscriptRef::new(Height::new(10), id_1);
966994
let ref_2 = TranscriptRef::new(Height::new(20), id_2);
967995
let block_reader =
968996
TestEcdsaBlockReader::for_complainer_test(Height::new(100), vec![ref_1, ref_2]);
969-
let mut active_transcripts = BTreeMap::new();
970-
active_transcripts.insert(id_1, ref_1);
971-
active_transcripts.insert(id_2, ref_2);
997+
let mut active = BTreeMap::new();
998+
active.insert(id_1, ref_1);
999+
active.insert(id_2, ref_2);
1000+
let mut requested = BTreeSet::new();
1001+
requested.insert(id_5);
9721002

9731003
// Message from a node ahead of us
9741004
assert_eq!(
975-
Action::action(&block_reader, &active_transcripts, Height::from(200), &id_3),
1005+
Action::action(&block_reader, &active, &requested, Height::from(200), &id_3),
9761006
Action::Defer
9771007
);
9781008

9791009
// Messages for transcripts not currently active
9801010
assert_eq!(
981-
Action::action(&block_reader, &active_transcripts, Height::from(10), &id_3),
1011+
Action::action(&block_reader, &active, &requested, Height::from(10), &id_3),
9821012
Action::Drop
9831013
);
9841014
assert_eq!(
985-
Action::action(&block_reader, &active_transcripts, Height::from(20), &id_4),
1015+
Action::action(&block_reader, &active, &requested, Height::from(20), &id_4),
9861016
Action::Drop
9871017
);
9881018

1019+
// Messages for transcripts not currently active but requested
1020+
assert_eq!(
1021+
Action::action(&block_reader, &active, &requested, Height::from(10), &id_5),
1022+
Action::Defer
1023+
);
1024+
9891025
// Messages for transcripts currently active
9901026
assert!(matches!(
991-
Action::action(&block_reader, &active_transcripts, Height::from(10), &id_1),
1027+
Action::action(&block_reader, &active, &requested, Height::from(10), &id_1),
9921028
Action::Process(_)
9931029
));
9941030
assert!(matches!(
995-
Action::action(&block_reader, &active_transcripts, Height::from(20), &id_2),
1031+
Action::action(&block_reader, &active, &requested, Height::from(20), &id_2),
9961032
Action::Process(_)
9971033
));
9981034
}

0 commit comments

Comments
 (0)