diff --git a/runtime/parachains/src/inclusion.rs b/runtime/parachains/src/inclusion.rs index a8702c873c2f..5240b99bbe3d 100644 --- a/runtime/parachains/src/inclusion.rs +++ b/runtime/parachains/src/inclusion.rs @@ -240,8 +240,10 @@ impl Pallet { for _ in >::drain() {} } - /// Process a set of incoming bitfields. Return a `vec` of cores freed by candidates - /// becoming available. + /// Process a set of incoming bitfields. + /// + /// Returns a `Vec` of `CandidateHash`es and their respective `AvailabilityCore`s that became available, + /// and cores free. pub(crate) fn process_bitfields( expected_bits: usize, unchecked_bitfields: UncheckedSignedAvailabilityBitfields, @@ -250,10 +252,12 @@ impl Pallet { let validators = shared::Pallet::::active_validator_keys(); let session_index = shared::Pallet::::session_index(); - let mut assigned_paras_record: Vec<_> = (0..expected_bits) + let mut assigned_paras_record = (0..expected_bits) .map(|bit_index| core_lookup(CoreIndex::from(bit_index as u32))) - .map(|core_para| core_para.map(|p| (p, PendingAvailability::::get(&p)))) - .collect(); + .map(|opt_para_id| { + opt_para_id.map(|para_id| (para_id, PendingAvailability::::get(¶_id))) + }) + .collect::>(); // do sanity checks on the bitfields: // 1. no more than one bitfield per validator @@ -320,17 +324,25 @@ impl Pallet { for (bit_idx, _) in signed_bitfield.payload().0.iter().enumerate().filter(|(_, is_av)| **is_av) { - let (_, pending_availability) = assigned_paras_record[bit_idx] - .as_mut() - .expect("validator bitfields checked not to contain bits corresponding to unoccupied cores; qed"); + let pending_availability = if let Some((_, pending_availability)) = + assigned_paras_record[bit_idx].as_mut() + { + pending_availability + } else { + // For honest validators, this happens in case of unoccupied cores, + // which in turn happens in case of a disputed candidate. + // A malicious one might include arbitrary indices, but they are represented + // by `None` values and will be sorted out in the next if case. + continue + }; // defensive check - this is constructed by loading the availability bitfield record, // which is always `Some` if the core is occupied - that's why we're here. let val_idx = signed_bitfield.validator_index().0 as usize; - if let Some(mut bit) = pending_availability - .as_mut() - .and_then(|r| r.availability_votes.get_mut(val_idx)) - { + if let Some(mut bit) = + pending_availability.as_mut().and_then(|candidate_pending_availability| { + candidate_pending_availability.availability_votes.get_mut(val_idx) + }) { *bit = true; } else if cfg!(debug_assertions) { ensure!(false, Error::::InternalError); diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index 38431246bb5b..944455553b66 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -105,7 +105,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("rococo"), impl_name: create_runtime_str!("parity-rococo-v1.8"), authoring_version: 0, - spec_version: 9104, + spec_version: 9105, impl_version: 0, #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS,