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

Refactor runtime fn enter(...) to select disputes, bitfields and backing candidates to protect against over length block issues#4020

Closed
Lldenaurois wants to merge 14 commits intoparitytech:masterfrom
Lldenaurois:limit_paras_inherent
Closed

Refactor runtime fn enter(...) to select disputes, bitfields and backing candidates to protect against over length block issues#4020
Lldenaurois wants to merge 14 commits intoparitytech:masterfrom
Lldenaurois:limit_paras_inherent

Conversation

@Lldenaurois
Copy link
Contributor

TBD

@Lldenaurois Lldenaurois force-pushed the limit_paras_inherent branch from a2d157c to 77a5b7f Compare October 5, 2021 17:45
@Lldenaurois Lldenaurois changed the title First attempt at a skeleton diff Refactor runtime fn enter(...) to select disputes, bitfields and backing candidates to protect against over length block issues Oct 5, 2021
@Lldenaurois Lldenaurois added A0-please_review Pull request needs code review. B0-silent Changes should not be mentioned in any release notes C3-medium PR touches the given topic and has a medium impact on builders. I8-refactor Code needs refactoring. D2-notlive 💤 PR contains changes in a runtime directory that is not deployed to a chain that requires an audit. labels Oct 5, 2021
included_in: BlockNumber,
);

fn get_included(session: SessionIndex, candidate_hash: CandidateHash) -> Option<BlockNumber>;
Copy link
Contributor

Choose a reason for hiding this comment

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

Note #4054 does the same, and it's an antipattern in Rust to call a getter get_.

Copy link
Contributor

Choose a reason for hiding this comment

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

missing docs

MINIMAL_INCLUSION_INHERENT_WEIGHT + data.backed_candidates.len() as Weight * BACKED_CANDIDATE_WEIGHT,
MINIMAL_INCLUSION_INHERENT_WEIGHT +
count_dispute_statements(&data.disputes) as Weight * DISPUTE_PER_STATEMENT_WEIGHT +
count_bitfield_bits(&data.bitfields) as Weight * BITFIELD_WEIGHT +
Copy link
Contributor

Choose a reason for hiding this comment

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

it really should be based on the number of bitfields, so the amount of signatures checked. That should be the dominant factor

MINIMAL_INCLUSION_INHERENT_WEIGHT +
count_dispute_statements(&data.disputes) as Weight * DISPUTE_PER_STATEMENT_WEIGHT +
count_bitfield_bits(&data.bitfields) as Weight * BITFIELD_WEIGHT +
data.backed_candidates.len() as Weight * BACKED_CANDIDATE_WEIGHT,
Copy link
Contributor

Choose a reason for hiding this comment

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

I could see this being based on the number of signatures checked as well plus a constant for any candidates that do code upgrades.

Error::<T>::InvalidParentHeader,
);

limit_paras_inherent::<T>(&mut disputes, &mut signed_bitfields, &mut backed_candidates);
Copy link
Contributor

Choose a reason for hiding this comment

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

limiting shouldn't be done within enter, but instead outside of it.

Copy link
Contributor

Choose a reason for hiding this comment

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

@drahnr - we had further discussions that imply both should do limiting, but the on-chain limiting should be a no-op

Copy link
Contributor

Choose a reason for hiding this comment

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

No-op as in, filter(filter(x)) should be equal to filter(x) so if on-chain filtering catches anything it was probably not produced by the usual block authoring code or there's a bug.

limit_paras_inherent::<T>(&mut disputes, &mut signed_bitfields, &mut backed_candidates);
let num_dispute_statements = count_dispute_statements(&disputes) as Weight;
let num_bitfield_bits = count_bitfield_bits(&signed_bitfields) as Weight;
let backed_candidates_len = backed_candidates.len() as Weight;
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't this already done above?

let b_local_block = T::DisputesHandler::get_included(b.session, b.candidate_hash);
match (a_local_block, b_local_block) {
// Prioritize local disputes over remote disputes.
(None, Some(_)) => Ordering::Greater,
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't this do the opposite? This says a > b if a not local and b local

// Prioritize local disputes over remote disputes.
(None, Some(_)) => Ordering::Greater,
(Some(_), None) => Ordering::Less,
// For local disputes, prioritize those with votes for invalidity.
Copy link
Contributor

Choose a reason for hiding this comment

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

Disputes have to have 1 vote on either side. I don't get it.

return
}

if disputes_weight + bitfields_weight > max_non_inclusion_weight {
Copy link
Contributor

Choose a reason for hiding this comment

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

We should recalculate disputes weight after filtering.


if disputes_weight + bitfields_weight > max_non_inclusion_weight {
let mut total_weight = disputes_weight;
bitfields.retain(|b| {
Copy link
Contributor

Choose a reason for hiding this comment

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

If we assume that the bitfield weight is constant, this whole block could be replaced by a simple division to check how many bitfields we need to cut off.

return
}

if total_non_inclusion_weight > max_non_inclusion_weight {
Copy link
Contributor

Choose a reason for hiding this comment

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

again, new bitfields weight needs to be recalculated.

&signing_context,
));

}: { Pallet::<T>::process_bitfields(expected_bits(), vec![signed.into()], core_lookup).unwrap() }
Copy link
Contributor

@rphmeier rphmeier Oct 11, 2021

Choose a reason for hiding this comment

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

This isn't going to be very useful unless we actually set some occupied cores i.e. CandidatePendingAvailability in the inclusion pallet.

@rphmeier
Copy link
Contributor

This looks very incomplete and not at the state I'd expect after this time. Still, the direction looks ~ok, although it is extremely minimal. It might help to map out in english, not in code, what you intend for this PR to do.

It's also worth noting that filtering things based on weight will affect the validity of other things that are included. i.e. disputes affect occupied cores, which affects bitfields, which affects backing. This ties in heavily with #3989 and #4028.

Copy link
Member

@eskimor eskimor left a comment

Choose a reason for hiding this comment

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

Quick first review. Another more in depth one to come.

let backed_candidates_weight =
count_backed_candidate_signatures::<T>(&backed_candidates) as Weight *
BACKED_CANDIDATE_WEIGHT +
count_code_upgrades::<T>(&backed_candidates) as Weight * CODE_UPGRADE_WEIGHT;
Copy link
Member

Choose a reason for hiding this comment

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

CODE_UPGRADE_WEIGHT can hardly be a constant, as it will depend on the size of the runtime.

Copy link
Member

Choose a reason for hiding this comment

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

Also I am missing taking into account messages.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I believe that the messages are accounted for by ensuring we only consider available weight, i.e. other messages in the block are already deducted from the max_block weight.

.saturating_sub(num_code_upgrades as u64 * CODE_UPGRADE_WEIGHT);
let num_candidates_to_retain = min(
num_backed_candidate_signatures as u64,
block_weight_available / BACKED_CANDIDATE_WEIGHT,
Copy link
Member

Choose a reason for hiding this comment

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

Not sure how this can work with a constant, with runtime upgrades + messages.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have modified the calculation shortly after you performed the review.

For Code upgrades, I was unaware that this would depend on the size of the runtime, but that makes perfect sense. I assume that will mean that we must unpack the Option on the candidate and determine the weight via NUM_BYTES * PER_BYTE_WEIGHT

//! as it has no initialization logic and its finalization logic depends only on the details of
//! this module.

use no_std_compat::cmp::Ordering;
Copy link
Contributor

Choose a reason for hiding this comment

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

usually it's imported as sp_std::cmp

// Sort the dispute statements according to the following prioritization:
// 1. Prioritize local disputes over remote disputes.
// 2. Prioritize older disputes over newer disputes.
// 3. Prioritize local disputes withan invalid vote over valid votes.
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this comment outdated?

match (a_local_block, b_local_block) {
// Prioritize local disputes over remote disputes.
(None, Some(_)) => Ordering::Less,
(Some(_), None) => Ordering::Greater,
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't this and the above backwards? local dispute > remote dispute so sort ascending puts remote before local.

Copy link
Contributor Author

@Lldenaurois Lldenaurois Oct 18, 2021

Choose a reason for hiding this comment

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

I was quite certain it was correct before but then you added a comment saying it's backward, so I changed it.

Going to write a test to confirm which of the two is desired.

Comment on lines +442 to +445
seed[31] = (index % (1 << 8)) as u8;
seed[30] = ((index >> 8) % (1 << 8)) as u8;
seed[29] = ((index >> 16) % (1 << 8)) as u8;
seed[29] = ((index >> 24) % (1 << 8)) as u8;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
seed[31] = (index % (1 << 8)) as u8;
seed[30] = ((index >> 8) % (1 << 8)) as u8;
seed[29] = ((index >> 16) % (1 << 8)) as u8;
seed[29] = ((index >> 24) % (1 << 8)) as u8;
seed[31] = (index & 0xFF) as u8;
seed[30] = ((index >> 8) & 0xFF) as u8;
seed[29] = ((index >> 16) & 0xFF) as u8;
seed[29] = ((index >> 24) & 0xFF) as u8;

candidate.validity_votes.len() as Weight * BACKED_CANDIDATE_WEIGHT +
match &candidate.candidate.commitments.new_validation_code {
Some(v) => v.0.len() as u64 * CODE_UPGRADE_WEIGHT_VARIABLE + CODE_UPGRADE_WEIGHT_FIXED,
_ => 0 as Weight,
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
_ => 0 as Weight,
None => 0 as Weight,

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

A0-please_review Pull request needs code review. B0-silent Changes should not be mentioned in any release notes C3-medium PR touches the given topic and has a medium impact on builders. D2-notlive 💤 PR contains changes in a runtime directory that is not deployed to a chain that requires an audit. I8-refactor Code needs refactoring.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants