Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Adds ability to clear obsolete reports in Offences pallet #14048

Open
wants to merge 39 commits into
base: master
Choose a base branch
from

Conversation

gupnik
Copy link
Contributor

@gupnik gupnik commented Apr 30, 2023

Fixes https://github.com/paritytech/srlabs_findings/issues/224

As discussed in #13936 (review), this PR introduces SessionReports that are sorted by SessionIndex. On start of a new session, reports that are older than max_session_report_age are removed.

Todo:

  1. Add a start hook to call clear_obsolete_reports at the appropriate time.
  2. Reject offences older than max_session_report_age at the time of reporting itself
  3. Update params for offences pallet everywhere
  4. Companion PRs

polkadot companion: paritytech/polkadot#7183

Will need a migration to clear existing data once max_session_report_age has passed.

@gupnik gupnik added A0-please_review Pull request needs code review. C3-medium PR touches the given topic and has a medium impact on builders. D9-needsaudit 👮 PR contains changes to fund-managing logic that should be properly reviewed and externally audited B1-note_worthy Changes should be noted in the release notes E2-dependencies Pull requests that update a dependency file. E3-host_functions PR adds new host functions which requires a node release before a runtime upgrade. T1-runtime This PR/Issue is related to the topic “runtime”. rust Pull requests that update Rust code labels Apr 30, 2023
@gupnik gupnik added A3-in_progress Pull request is in progress. No review needed at this stage. and removed E2-dependencies Pull requests that update a dependency file. E3-host_functions PR adds new host functions which requires a node release before a runtime upgrade. rust Pull requests that update Rust code A0-please_review Pull request needs code review. labels Apr 30, 2023
@gupnik gupnik marked this pull request as ready for review May 5, 2023 04:43
@gupnik gupnik requested a review from a team May 5, 2023 04:55
@gupnik gupnik requested a review from acatangiu as a code owner May 5, 2023 04:55
Offence { validator_set_count: 5, session_index, time_slot, offenders: vec![5] };
assert_eq!(Offences::report_offence(vec![], offence), Err(OffenceError::ObsoleteReport));

with_on_offence_fractions(|f| {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why we use this convoluted helper function here. Isn't it equal to assert!(OnOffencePerbill::get().is_empty())?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using the helper function to just assert equality is a bit weird to me.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or else at least a const SESSION_INDEX:u32 = 10;

@kianenigma kianenigma requested a review from a team May 16, 2023 09:56
@kianenigma
Copy link
Contributor

I have a further testing plan as well:

Recently, someone developed a root-offences pallet exactly for testing such cases. But I don't think anyone at Parity is actively owning this pallet's usage.

The goal would be to add this pallet to eg. Westend and Rococo (probably the former, as it has a lot of nominators) and test and e2e slash going through correctly. Part of that would also be to observe how the pallet behaves with concurrent offences and such, and when the offences are cleared.

I highly encourage this as this is a super critical code path that is not often exercised in eg. even Kusama.

@paritytech-ci paritytech-ci requested a review from a team May 17, 2023 04:53
primitives/session/Cargo.toml Outdated Show resolved Hide resolved

/// A trait to be notified when the session changes.
/// This is in contrast to `SessionHandler` which handles events for specific keys.
#[impl_trait_for_tuples::impl_for_tuples(30)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This always comes with an increased compile time.
Maybe we can start with 8 or 16 until someone complains that they need more?

@@ -92,6 +120,22 @@ pub mod pallet {
ValueQuery,
>;

/// A map that stores all reports along with
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please try to break lines at 100 chars.
I am not sure if the formatter does it, but many editors support a vertical line that makes it easy to do it manually.

frame/offences/src/lib.rs Outdated Show resolved Hide resolved
frame/offences/src/lib.rs Outdated Show resolved Hide resolved
let session_reports = SessionReports::<T>::take(obsolete_session_index);
let session_reports =
Vec::<(Kind, OpaqueTimeSlot, ReportIdOf<T>)>::decode(&mut &session_reports[..])
.unwrap_or_default();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. If it is empty it just returns Ok(vec![]), an error here means that the storage is corrupted.

DQ but why is this double-encode anyway? Why not store Vec<StorageReportOf<T>>?

Vec::<SessionReportOf<T>>::decode(&mut &session_reports[..])
.unwrap_or_default();

for (kind, time_slot, report_id) in &session_reports {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any upper limit to the length of this vector?
We always need to keep the weight of on_initialize bounded…

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I'd expect that the session reports can be very large, especially if there's a bug. We should be able to clear the offences through governance when these are resulting from a bug, but still it's better to bound a loop on_initialize.

Perhaps we should instead queue clearing offences and process a fixed number on_initialize, until the queue is empty (simple multi-block clearing process).

frame/offences/src/lib.rs Outdated Show resolved Hide resolved
frame/offences/src/lib.rs Show resolved Hide resolved
fn get_session_reports<T: Config>(session_index: SessionIndex) -> Vec<SessionReportOf<T>> {
let session_reports = SessionReports::<T>::get(session_index);
Vec::<SessionReportOf<T>>::decode(&mut &session_reports[..])
.unwrap_or_default()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This unwrap_or_default also seems to ignore the fact that either: There is nothing in storage and it should therefore return vec![] or there is corrupted storage.
defensive_unwrap_or_default should be better. Or you return an error and bubble it up 🤷‍♂️

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's actually fine to have an empty vec here as a session might not have any reports.

@paritytech-ci paritytech-ci requested a review from a team May 17, 2023 16:17
frame/offences/src/lib.rs Outdated Show resolved Hide resolved
frame/offences/src/lib.rs Outdated Show resolved Hide resolved
Vec::<SessionReportOf<T>>::decode(&mut &session_reports[..])
.unwrap_or_default();

for (kind, time_slot, report_id) in &session_reports {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I'd expect that the session reports can be very large, especially if there's a bug. We should be able to clear the offences through governance when these are resulting from a bug, but still it's better to bound a loop on_initialize.

Perhaps we should instead queue clearing offences and process a fixed number on_initialize, until the queue is empty (simple multi-block clearing process).

@paritytech-ci paritytech-ci requested a review from a team May 19, 2023 07:43
@paritytech-ci paritytech-ci requested a review from a team May 22, 2023 15:18
gupnik and others added 4 commits July 3, 2023 15:34
@paritytech-cicd-pr
Copy link

The CI pipeline was cancelled due to failure one of the required jobs.
Job name: cargo-check-benches
Logs: https://gitlab.parity.io/parity/mirrors/substrate/-/jobs/3107838

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A3-in_progress Pull request is in progress. No review needed at this stage. B1-note_worthy Changes should be noted in the release notes C3-medium PR touches the given topic and has a medium impact on builders. D9-needsaudit 👮 PR contains changes to fund-managing logic that should be properly reviewed and externally audited T1-runtime This PR/Issue is related to the topic “runtime”.
Projects
Development

Successfully merging this pull request may close these issues.

5 participants