Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 46 additions & 5 deletions runtime/parachains/src/paras_inherent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ where
DisputedBitfield::from(bitvec)
}

/// Select a random subset
/// Select a random subset, with preference for certain indices.
///
/// Adds random items to the set until all candidates
/// are tried or the remaining weight is depleted.
Expand All @@ -682,28 +682,52 @@ where
fn random_sel<X, F: Fn(&X) -> Weight>(
rng: &mut rand_chacha::ChaChaRng,
selectables: Vec<X>,
mut preferred_indices: Vec<usize>,
weight_fn: F,
weight_limit: Weight,
) -> (Weight, Vec<usize>) {
if selectables.is_empty() {
return (0 as Weight, Vec::new())
}
let mut indices = (0..selectables.len()).into_iter().collect::<Vec<_>>();
// all indices that are not part of the preferred set
let mut indices = (0..selectables.len())
.into_iter()
.filter(|idx| !preferred_indices.contains(idx))
.collect::<Vec<_>>();
let mut picked_indices = Vec::with_capacity(selectables.len().saturating_sub(1));

let mut weight_acc = 0 as Weight;

while !preferred_indices.is_empty() {
// randomly pick an index from the preferred set
let pick = rng.gen_range(0..preferred_indices.len());
// remove the index from the available set of preferred indices
let preferred_idx = preferred_indices.swap_remove(pick);

// preferred indices originate from outside
if let Some(item) = selectables.get(preferred_idx) {
let updated = weight_acc + weight_fn(item);
if updated > weight_limit {
continue
}
weight_acc = updated;
picked_indices.push(preferred_idx);
}
}

while !indices.is_empty() {
// randomly pick an index
let pick = rng.gen_range(0..indices.len());
// remove the index from the available set of indices
let idx = indices.swap_remove(pick);

let item = &selectables[idx];
weight_acc += weight_fn(item);
let updated = weight_acc + weight_fn(item);

if weight_acc > weight_limit {
break
if updated > weight_limit {
continue
}
weight_acc = updated;

picked_indices.push(idx);
}
Expand Down Expand Up @@ -743,13 +767,24 @@ fn apply_weight_limit<T: Config + inclusion::Config>(
return total
}

// Prefer code upgrades, they tend to be large and hence stand no chance to be picked
// late while maintaining the weight bounds
let preferred_indices = candidates
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yep, but this also means that by means of this a single malicious Parachain (e.g. hacked collator), could DOS all other parachains. A solution would be some kind of rate limiting for parachain runtime upgrades, longer term we really want them to be off-chain. The question is how quickly can we get that done.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Created a tracking issue #4335

.iter()
.enumerate()
.filter_map(|(idx, candidate)| {
candidate.candidate.commitments.new_validation_code.as_ref().map(|_code| idx)
})
.collect::<Vec<usize>>();

// There is weight remaining to be consumed by a subset of candidates
// which are going to be picked now.
if let Some(remaining_weight) = remaining_weight.checked_sub(total_bitfields_weight) {
let (acc_candidate_weight, indices) =
random_sel::<BackedCandidate<<T as frame_system::Config>::Hash>, _>(
rng,
candidates.clone(),
preferred_indices,
|c| backed_candidate_weight::<T>(c),
remaining_weight,
);
Expand All @@ -772,6 +807,7 @@ fn apply_weight_limit<T: Config + inclusion::Config>(
let (total, indices) = random_sel::<UncheckedSignedAvailabilityBitfield, _>(
rng,
bitfields.clone(),
vec![],
|_| <<T as Config>::WeightInfo as WeightInfo>::enter_bitfields(),
remaining_weight,
);
Expand Down Expand Up @@ -928,6 +964,10 @@ fn sanitize_backed_candidates<T: crate::inclusion::Config, F: Fn(CandidateHash)
backed_candidates
}

/// Derive entropy from babe provided per block randomness.
///
/// In the odd case none is available, uses the `parent_hash` and
/// a const value, while emitting a warning.
fn compute_entropy<T: Config>(parent_hash: T::Hash) -> [u8; 32] {
const CANDIDATE_SEED_SUBJECT: [u8; 32] = *b"candidate-seed-selection-subject";
let vrf_random = CurrentBlockRandomness::<T>::random(&CANDIDATE_SEED_SUBJECT[..]).0;
Expand Down Expand Up @@ -1010,6 +1050,7 @@ fn limit_disputes<T: Config>(
let (acc_remote_disputes_weight, indices) = random_sel::<u32, _>(
rng,
d,
vec![],
|v| <<T as Config>::WeightInfo as WeightInfo>::enter_variable_disputes(*v),
remaining_weight,
);
Expand Down