Skip to content

Commit 193ae4e

Browse files
committed
feat(consensus): [CON-1238] Always purge artifacts which are at least 50 heights below the last CUP height.
1 parent cce5c97 commit 193ae4e

File tree

7 files changed

+161
-67
lines changed

7 files changed

+161
-67
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rs/consensus/src/consensus/purger.rs

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -226,24 +226,24 @@ impl Purger {
226226
changeset: &mut ChangeSet,
227227
) -> bool {
228228
if let Some(purge_height) = get_purge_height(pool_reader) {
229-
if purge_height < self.state_manager.latest_state_height() {
230-
changeset.push(ChangeAction::PurgeValidatedBelow(purge_height));
231-
trace!(self.log, "Purge validated pool below {:?}", purge_height);
232-
self.metrics
233-
.validated_pool_purge_height
234-
.set(purge_height.get() as i64);
235-
true
236-
} else {
229+
changeset.push(ChangeAction::PurgeValidatedBelow(purge_height));
230+
trace!(self.log, "Purge validated pool below {:?}", purge_height);
231+
self.metrics
232+
.validated_pool_purge_height
233+
.set(purge_height.get() as i64);
234+
235+
if purge_height > self.state_manager.latest_state_height() {
237236
warn!(
238237
every_n_seconds => 30,
239238
self.log,
240-
"Execution state is not yet available at {:?} that is below \
241-
CUP height at {:?}. Cancel purge.",
239+
"Execution state is not yet available at height {} that is below \
240+
CUP height at {}. Purging anyways.",
242241
purge_height,
243242
pool_reader.get_catch_up_height()
244243
);
245-
false
246244
}
245+
246+
true
247247
} else {
248248
false
249249
}
@@ -374,10 +374,6 @@ impl Purger {
374374
/// validated pool. Usually things with height less than a min_length below the
375375
/// latest catch up height can be purged, but if there is nothing to purge,
376376
/// this function will return None.
377-
///
378-
/// Note that for actual purging, we must also consider execution state
379-
/// so that we don't purge below latest known state height. Otherwise
380-
/// we cannot replay past blocks to catch up state during a replica restart.
381377
fn get_purge_height(pool_reader: &PoolReader<'_>) -> Option<Height> {
382378
pool_reader
383379
.pool()

rs/consensus/src/consensus/validator.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1603,7 +1603,8 @@ impl Validator {
16031603
Some(timestamp) if now > timestamp + CATCH_UP_HOLD_OF_TIME => {
16041604
warn!(
16051605
self.log,
1606-
"Validating CUP after holding it back for {} seconds",
1606+
"Validating CUP at height {} after holding it back for {} seconds",
1607+
cup_height,
16071608
CATCH_UP_HOLD_OF_TIME.as_secs()
16081609
);
16091610
Ok(())

rs/consensus/utils/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ DEV_DEPENDENCIES = [
2828
"//rs/test_utilities/time",
2929
"//rs/test_utilities/types",
3030
"//rs/types/management_canister_types",
31+
"@crate_index//:assert_matches",
3132
]
3233

3334
rust_library(

rs/consensus/utils/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ hex = "0.4.2"
2121
slog = { workspace = true }
2222

2323
[dev-dependencies]
24+
assert_matches = "1.3.0"
2425
ic-consensus = { path = "../" }
2526
ic-consensus-mocks = { path = "../mocks" }
2627
ic-test-utilities = { path = "../../test_utilities" }

rs/consensus/utils/src/lib.rs

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -163,20 +163,29 @@ pub fn get_adjusted_notary_delay(
163163
rank,
164164
) {
165165
NotaryDelay::CanNotarizeAfter(duration) => Some(duration),
166-
NotaryDelay::ReachedMaxNotarizationCertificationGap => {
166+
NotaryDelay::ReachedMaxNotarizationCertificationGap {
167+
notarized_height,
168+
certified_height,
169+
} => {
167170
warn!(
168171
every_n_seconds => 5,
169172
log,
170-
"notarization certification gap exceeds hard bound of\
173+
"The gap between the notarization height ({notarized_height}) and \
174+
the certification height ({certified_height}) exceeds hard bound of \
171175
{ACCEPTABLE_NOTARIZATION_CERTIFICATION_GAP}"
172176
);
173177
None
174178
}
175-
NotaryDelay::ReachedMaxNotarizationCUPGap => {
179+
NotaryDelay::ReachedMaxNotarizationCUPGap {
180+
notarized_height,
181+
cup_height,
182+
} => {
176183
warn!(
177184
every_n_seconds => 5,
178185
log,
179-
"notarization CUP gap exceeds hard bound of {ACCEPTABLE_NOTARIZATION_CUP_GAP}"
186+
"The gap between the notarization height ({notarized_height}) and \
187+
the CUP height ({cup_height}) exceeds hard bound of \
188+
{ACCEPTABLE_NOTARIZATION_CUP_GAP}"
180189
);
181190
None
182191
}
@@ -189,10 +198,16 @@ pub enum NotaryDelay {
189198
CanNotarizeAfter(Duration),
190199
/// Gap between notarization and certification is too large. Because we have a
191200
/// hard limit on this gap, the notary cannot progress for now.
192-
ReachedMaxNotarizationCertificationGap,
201+
ReachedMaxNotarizationCertificationGap {
202+
notarized_height: Height,
203+
certified_height: Height,
204+
},
193205
/// Gap between notarization and the next CUP is too large. Because we have a
194206
/// hard limit on this gap, the notary cannot progress for now.
195-
ReachedMaxNotarizationCUPGap,
207+
ReachedMaxNotarizationCUPGap {
208+
notarized_height: Height,
209+
cup_height: Height,
210+
},
196211
}
197212

198213
/// Calculate the required delay for notary based on the rank of block to notarize,
@@ -212,12 +227,17 @@ pub fn get_adjusted_notary_delay_from_settings(
212227
} = settings;
213228

214229
// We impose a hard limit on the gap between notarization and certification.
215-
let notarized_height = pool.get_notarized_height().get();
216-
let certified_height = state_manager.latest_certified_height().get();
217-
if notarized_height.saturating_sub(certified_height)
230+
let notarized_height = pool.get_notarized_height();
231+
let certified_height = state_manager.latest_certified_height();
232+
if notarized_height
233+
.get()
234+
.saturating_sub(certified_height.get())
218235
>= ACCEPTABLE_NOTARIZATION_CERTIFICATION_GAP
219236
{
220-
return NotaryDelay::ReachedMaxNotarizationCertificationGap;
237+
return NotaryDelay::ReachedMaxNotarizationCertificationGap {
238+
notarized_height,
239+
certified_height,
240+
};
221241
}
222242

223243
// We adjust regular delay based on the gap between finalization and
@@ -247,7 +267,6 @@ pub fn get_adjusted_notary_delay_from_settings(
247267
// We measure the gap between our current CUP height and the current notarized
248268
// height. If the notarized height is in a DKG interval for which we don't yet have
249269
// the CUP, we limit the notarization-CUP gap to ACCEPTABLE_NOTARIZATION_CUP_GAP.
250-
let cup_gap = notarized_height.saturating_sub(pool.get_catch_up_height().get());
251270
let last_cup = pool.get_highest_catch_up_package();
252271
let last_cup_dkg_info = &last_cup
253272
.content
@@ -257,8 +276,13 @@ pub fn get_adjusted_notary_delay_from_settings(
257276
.as_ref()
258277
.as_summary()
259278
.dkg;
279+
let cup_height = last_cup.height();
280+
let cup_gap = notarized_height.get().saturating_sub(cup_height.get());
260281
if cup_gap >= last_cup_dkg_info.interval_length.get() + ACCEPTABLE_NOTARIZATION_CUP_GAP {
261-
return NotaryDelay::ReachedMaxNotarizationCUPGap;
282+
return NotaryDelay::ReachedMaxNotarizationCUPGap {
283+
notarized_height,
284+
cup_height,
285+
};
262286
}
263287

264288
NotaryDelay::CanNotarizeAfter(Duration::from_millis(certified_adjusted_delay))
@@ -575,6 +599,7 @@ pub fn get_oldest_ecdsa_state_registry_version(
575599

576600
#[cfg(test)]
577601
mod tests {
602+
use assert_matches::assert_matches;
578603
use std::str::FromStr;
579604

580605
use super::*;
@@ -676,14 +701,14 @@ mod tests {
676701
.expect_latest_certified_height()
677702
.return_const(gap_trigger_height);
678703

679-
assert_eq!(
704+
assert_matches!(
680705
get_adjusted_notary_delay_from_settings(
681706
settings.clone(),
682707
&PoolReader::new(&pool),
683708
state_manager.as_ref(),
684709
Rank(0),
685710
),
686-
NotaryDelay::ReachedMaxNotarizationCertificationGap,
711+
NotaryDelay::ReachedMaxNotarizationCertificationGap { .. }
687712
);
688713

689714
state_manager.get_mut().checkpoint();
@@ -710,14 +735,14 @@ mod tests {
710735

711736
pool.advance_round_normal_operation_no_cup();
712737

713-
assert_eq!(
738+
assert_matches!(
714739
get_adjusted_notary_delay_from_settings(
715740
settings,
716741
&PoolReader::new(&pool),
717742
state_manager.as_ref(),
718743
Rank(0),
719744
),
720-
NotaryDelay::ReachedMaxNotarizationCUPGap,
745+
NotaryDelay::ReachedMaxNotarizationCUPGap { .. }
721746
);
722747
});
723748
}

0 commit comments

Comments
 (0)