diff --git a/polkadot/node/core/bitfield-signing/src/lib.rs b/polkadot/node/core/bitfield-signing/src/lib.rs index 15ab1983c9..3b30736a0a 100644 --- a/polkadot/node/core/bitfield-signing/src/lib.rs +++ b/polkadot/node/core/bitfield-signing/src/lib.rs @@ -78,37 +78,7 @@ async fn get_core_availability( ) -> Result { let span = jaeger::hash_span(&relay_parent, "core-availability"); if let CoreState::Occupied(core) = core { - tracing::trace!(target: LOG_TARGET, para_id = %core.para_id, "Getting core availability"); - - let _span = span.child("occupied"); - let (tx, rx) = oneshot::channel(); - sender - .lock() - .await - .send( - AllMessages::from(RuntimeApiMessage::Request( - relay_parent, - RuntimeApiRequest::CandidatePendingAvailability(core.para_id, tx), - )).into(), - ) - .await?; - - let committed_candidate_receipt = match rx.await? { - Ok(Some(ccr)) => ccr, - Ok(None) => { - tracing::trace!(target: LOG_TARGET, para_id = %core.para_id, "No committed candidate"); - return Ok(false) - }, - Err(e) => { - // Don't take down the node on runtime API errors. - tracing::warn!(target: LOG_TARGET, err = ?e, "Encountered a runtime API error"); - return Ok(false); - } - }; - - drop(_span); let _span = span.child("query chunk"); - let candidate_hash = committed_candidate_receipt.hash(); let (tx, rx) = oneshot::channel(); sender @@ -116,7 +86,7 @@ async fn get_core_availability( .await .send( AllMessages::from(AvailabilityStoreMessage::QueryChunkAvailability( - candidate_hash, + core.candidate_hash, validator_idx, tx, )).into(), @@ -127,9 +97,9 @@ async fn get_core_availability( tracing::trace!( target: LOG_TARGET, - para_id = %core.para_id, + para_id = %core.para_id(), availability = ?res, - ?candidate_hash, + ?core.candidate_hash, "Candidate availability", ); @@ -325,17 +295,18 @@ pub type BitfieldSigningSubsystem = JobManager CoreState { + fn occupied_core(para_id: u32, candidate_hash: CandidateHash) -> CoreState { CoreState::Occupied(OccupiedCore { - para_id: para_id.into(), group_responsible: para_id.into(), next_up_on_available: None, occupied_since: 100_u32, time_out_at: 200_u32, next_up_on_time_out: None, availability: Default::default(), + candidate_hash, + candidate_descriptor: Default::default(), }) } @@ -354,6 +325,9 @@ mod tests { ).fuse(); pin_mut!(future); + let hash_a = CandidateHash(Hash::repeat_byte(1)); + let hash_b = CandidateHash(Hash::repeat_byte(2)); + loop { futures::select! { m = receiver.next() => match m.unwrap() { @@ -363,29 +337,16 @@ mod tests { ), ) => { assert_eq!(relay_parent, rp); - tx.send(Ok(vec![CoreState::Free, occupied_core(1), occupied_core(2)])).unwrap(); - }, - FromJobCommand::SendMessage( - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(rp, RuntimeApiRequest::CandidatePendingAvailability(para_id, tx)), - ), - ) => { - assert_eq!(relay_parent, rp); - - if para_id == 1.into() { - tx.send(Ok(Some(Default::default()))).unwrap(); - } else { - tx.send(Ok(None)).unwrap(); - } + tx.send(Ok(vec![CoreState::Free, occupied_core(1, hash_a), occupied_core(2, hash_b)])).unwrap(); }, FromJobCommand::SendMessage( AllMessages::AvailabilityStore( - AvailabilityStoreMessage::QueryChunkAvailability(_, vidx, tx), + AvailabilityStoreMessage::QueryChunkAvailability(c_hash, vidx, tx), ), ) => { assert_eq!(validator_index, vidx); - tx.send(true).unwrap(); + tx.send(c_hash == hash_a).unwrap(); }, o => panic!("Unknown message: {:?}", o), }, diff --git a/polkadot/node/core/provisioner/src/tests.rs b/polkadot/node/core/provisioner/src/tests.rs index cc3750591e..f6977d69ec 100644 --- a/polkadot/node/core/provisioner/src/tests.rs +++ b/polkadot/node/core/provisioner/src/tests.rs @@ -4,13 +4,14 @@ use polkadot_primitives::v1::{OccupiedCore, ScheduledCore}; pub fn occupied_core(para_id: u32) -> CoreState { CoreState::Occupied(OccupiedCore { - para_id: para_id.into(), group_responsible: para_id.into(), next_up_on_available: None, occupied_since: 100_u32, time_out_at: 200_u32, next_up_on_time_out: None, availability: bitvec![bitvec::order::Lsb0, u8; 0; 32], + candidate_descriptor: Default::default(), + candidate_hash: Default::default(), }) } diff --git a/polkadot/node/network/availability-distribution/src/lib.rs b/polkadot/node/network/availability-distribution/src/lib.rs index 9559aa3ef4..7ce4afe2ad 100644 --- a/polkadot/node/network/availability-distribution/src/lib.rs +++ b/polkadot/node/network/availability-distribution/src/lib.rs @@ -36,7 +36,7 @@ use polkadot_node_network_protocol::{ }; use polkadot_node_subsystem_util::metrics::{self, prometheus}; use polkadot_primitives::v1::{ - BlakeTwo256, CommittedCandidateReceipt, CoreState, ErasureChunk, Hash, HashT, Id as ParaId, + BlakeTwo256, CoreState, ErasureChunk, Hash, HashT, SessionIndex, ValidatorId, ValidatorIndex, PARACHAIN_KEY_TYPE_ID, CandidateHash, CandidateDescriptor, }; @@ -62,11 +62,6 @@ const LOG_TARGET: &'static str = "availability_distribution"; #[derive(Debug, Error)] enum Error { - #[error("Response channel to obtain PendingAvailability failed")] - QueryPendingAvailabilityResponseChannel(#[source] oneshot::Canceled), - #[error("RuntimeAPI to obtain PendingAvailability failed")] - QueryPendingAvailability(#[source] RuntimeApiError), - #[error("Response channel to obtain StoreChunk failed")] StoreChunkResponseChannel(#[source] oneshot::Canceled), @@ -795,19 +790,12 @@ where e => e.or_default(), }; - for para in query_para_ids(ctx, relay_parent).await? { - if let Some(ccr) = query_pending_availability(ctx, relay_parent, para).await? { - let receipt_hash = ccr.hash(); - let descriptor = ccr.descriptor().clone(); - - // unfortunately we have no good way of telling the candidate was - // cached until now. But we don't clobber a `Cached` entry if there - // is one already. - live_candidates.entry(receipt_hash) - .or_insert(FetchedLiveCandidate::Fresh(descriptor)); - - receipts_for.insert(receipt_hash); - } + for (receipt_hash, descriptor) in query_pending_availability(ctx, relay_parent).await? { + // unfortunately we have no good way of telling the candidate was + // cached until now. But we don't clobber a `Cached` entry if there + // is one already. + live_candidates.entry(receipt_hash).or_insert(FetchedLiveCandidate::Fresh(descriptor)); + receipts_for.insert(receipt_hash); } } @@ -850,9 +838,10 @@ where Ok((live_candidates, ancestors)) } -/// Query all para IDs that are occupied under a given relay-parent. +/// Query all hashes and descriptors of candidates pending availability at a particular block. #[tracing::instrument(level = "trace", skip(ctx), fields(subsystem = LOG_TARGET))] -async fn query_para_ids(ctx: &mut Context, relay_parent: Hash) -> Result> +async fn query_pending_availability(ctx: &mut Context, relay_parent: Hash) + -> Result> where Context: SubsystemContext, { @@ -863,22 +852,18 @@ where ))) .await; - let all_para_ids = rx + let cores: Vec<_> = rx .await .map_err(|e| Error::AvailabilityCoresResponseChannel(e))? .map_err(|e| Error::AvailabilityCores(e))?; - let occupied_para_ids = all_para_ids - .into_iter() - .filter_map(|core_state| { - if let CoreState::Occupied(occupied) = core_state { - Some(occupied.para_id) - } else { - None - } + Ok(cores.into_iter() + .filter_map(|core_state| if let CoreState::Occupied(occupied) = core_state { + Some((occupied.candidate_hash, occupied.candidate_descriptor)) + } else { + None }) - .collect(); - Ok(occupied_para_ids) + .collect()) } /// Modify the reputation of a peer based on its behavior. @@ -954,27 +939,6 @@ where rx.await.map_err(|e| Error::StoreChunkResponseChannel(e)) } -/// Request the head data for a particular para. -#[tracing::instrument(level = "trace", skip(ctx), fields(subsystem = LOG_TARGET))] -async fn query_pending_availability( - ctx: &mut Context, - relay_parent: Hash, - para: ParaId, -) -> Result> -where - Context: SubsystemContext, -{ - let (tx, rx) = oneshot::channel(); - ctx.send_message(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - relay_parent, - RuntimeApiRequest::CandidatePendingAvailability(para, tx), - ))).await; - - rx.await - .map_err(|e| Error::QueryPendingAvailabilityResponseChannel(e))? - .map_err(|e| Error::QueryPendingAvailability(e)) -} - /// Query the validator set. #[tracing::instrument(level = "trace", skip(ctx), fields(subsystem = LOG_TARGET))] async fn query_validators( diff --git a/polkadot/node/network/availability-distribution/src/tests.rs b/polkadot/node/network/availability-distribution/src/tests.rs index cdf5c76fb2..a34caec7ab 100644 --- a/polkadot/node/network/availability-distribution/src/tests.rs +++ b/polkadot/node/network/availability-distribution/src/tests.rs @@ -21,7 +21,8 @@ use polkadot_node_network_protocol::{view, ObservedRole}; use polkadot_node_subsystem_util::TimeoutExt; use polkadot_primitives::v1::{ AvailableData, BlockData, CandidateCommitments, CandidateDescriptor, GroupIndex, - GroupRotationInfo, HeadData, OccupiedCore, PersistedValidationData, PoV, ScheduledCore, + GroupRotationInfo, HeadData, OccupiedCore, PersistedValidationData, PoV, ScheduledCore, Id as ParaId, + CommittedCandidateReceipt, }; use polkadot_subsystem_testhelpers as test_helpers; @@ -29,6 +30,7 @@ use futures::{executor, future, Future}; use sc_keystore::LocalKeystore; use sp_application_crypto::AppKey; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; +use sp_keyring::Sr25519Keyring; use std::{sync::Arc, time::Duration}; use maplit::hashmap; @@ -95,20 +97,19 @@ async fn overseer_recv( msg } -fn dummy_occupied_core(para: ParaId) -> CoreState { +fn occupied_core_from_candidate(receipt: &CommittedCandidateReceipt) -> CoreState { CoreState::Occupied(OccupiedCore { - para_id: para, next_up_on_available: None, occupied_since: 0, time_out_at: 5, next_up_on_time_out: None, availability: Default::default(), group_responsible: GroupIndex::from(0), + candidate_hash: receipt.hash(), + candidate_descriptor: receipt.descriptor().clone(), }) } -use sp_keyring::Sr25519Keyring; - #[derive(Clone)] struct TestState { chain_ids: Vec, @@ -388,7 +389,6 @@ async fn change_our_view( ancestors: Vec, session_per_relay_parent: HashMap, availability_cores_per_relay_parent: HashMap>, - candidate_pending_availabilities_per_relay_parent: HashMap>, data_availability: HashMap, chunk_data_per_candidate: HashMap, send_chunks_to: HashMap>, @@ -436,7 +436,7 @@ async fn change_our_view( } for _ in 0..availability_cores_per_relay_parent.len() { - let relay_parent = assert_matches!( + assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( relay_parent, @@ -446,30 +446,8 @@ async fn change_our_view( .expect(&format!("Availability core for relay parent {:?} does not exist", relay_parent)); tx.send(Ok(cores.clone())).unwrap(); - relay_parent } ); - - let pending_availability = candidate_pending_availabilities_per_relay_parent.get(&relay_parent) - .expect(&format!("Candidate pending availability for relay parent {:?} does not exist", relay_parent)); - - for _ in 0..pending_availability.len() { - assert_matches!( - overseer_recv(virtual_overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - hash, - RuntimeApiRequest::CandidatePendingAvailability(para, tx) - )) => { - assert_eq!(relay_parent, hash); - - let candidate = pending_availability.iter() - .find(|c| c.descriptor.para_id == para) - .expect(&format!("Pending candidate for para {} does not exist", para)); - - tx.send(Ok(Some(candidate.clone()))).unwrap(); - } - ); - } } for _ in 0..data_availability.len() { @@ -571,7 +549,6 @@ fn check_views() { let mut virtual_overseer = test_harness.virtual_overseer; let TestState { - chain_ids, validator_public, relay_parent: current, ancestors, @@ -588,36 +565,37 @@ fn check_views() { vec![ancestors[0], genesis], hashmap! { current => 1, genesis => 1 }, hashmap! { - ancestors[0] => vec![dummy_occupied_core(chain_ids[0]), dummy_occupied_core(chain_ids[1])], + ancestors[0] => vec![ + occupied_core_from_candidate(&candidates[0]), + occupied_core_from_candidate(&candidates[1]), + ], current => vec![ CoreState::Occupied(OccupiedCore { - para_id: chain_ids[0].clone(), next_up_on_available: None, occupied_since: 0, time_out_at: 10, next_up_on_time_out: None, availability: Default::default(), group_responsible: GroupIndex::from(0), + candidate_hash: candidates[0].hash(), + candidate_descriptor: candidates[0].descriptor().clone(), }), CoreState::Free, CoreState::Free, CoreState::Occupied(OccupiedCore { - para_id: chain_ids[1].clone(), next_up_on_available: None, occupied_since: 1, time_out_at: 7, next_up_on_time_out: None, availability: Default::default(), group_responsible: GroupIndex::from(0), + candidate_hash: candidates[1].hash(), + candidate_descriptor: candidates[1].descriptor().clone(), }), CoreState::Free, CoreState::Free, ] }, - hashmap! { - ancestors[0] => vec![candidates[0].clone(), candidates[1].clone()], - current => vec![candidates[0].clone(), candidates[1].clone()], - }, hashmap! { candidates[0].hash() => true, candidates[1].hash() => false, @@ -690,11 +668,10 @@ fn reputation_verification() { hashmap! { current => 1 }, hashmap! { current => vec![ - dummy_occupied_core(candidates[0].descriptor.para_id), - dummy_occupied_core(candidates[1].descriptor.para_id) + occupied_core_from_candidate(&candidates[0]), + occupied_core_from_candidate(&candidates[1]), ], }, - hashmap! { current => vec![candidates[0].clone(), candidates[1].clone()] }, hashmap! { candidates[0].hash() => true, candidates[1].hash() => false }, hashmap! { candidates[0].hash() => (pov_blocks[0].clone(), test_state.persisted_validation_data.clone())}, hashmap! {}, @@ -783,10 +760,9 @@ fn not_a_live_candidate_is_detected() { hashmap! { current => 1 }, hashmap! { current => vec![ - dummy_occupied_core(candidates[0].descriptor.para_id), + occupied_core_from_candidate(&candidates[0]), ], }, - hashmap! { current => vec![candidates[0].clone()] }, hashmap! { candidates[0].hash() => true }, hashmap! { candidates[0].hash() => (pov_blocks[0].clone(), test_state.persisted_validation_data.clone())}, hashmap! {}, @@ -832,10 +808,9 @@ fn peer_change_view_before_us() { hashmap! { current => 1 }, hashmap! { current => vec![ - dummy_occupied_core(candidates[0].descriptor.para_id), + occupied_core_from_candidate(&candidates[0]), ], }, - hashmap! { current => vec![candidates[0].clone()] }, hashmap! { candidates[0].hash() => true }, hashmap! { candidates[0].hash() => (pov_blocks[0].clone(), test_state.persisted_validation_data.clone())}, hashmap! { candidates[0].hash() => vec![peer_a.clone()] }, @@ -880,10 +855,9 @@ fn candidate_chunks_are_put_into_message_vault_when_candidate_is_first_seen() { hashmap! { ancestors[0] => 1 }, hashmap! { ancestors[0] => vec![ - dummy_occupied_core(candidates[0].descriptor.para_id), + occupied_core_from_candidate(&candidates[0]), ], }, - hashmap! { ancestors[0] => vec![candidates[0].clone()] }, hashmap! { candidates[0].hash() => true }, hashmap! { candidates[0].hash() => (pov_blocks[0].clone(), test_state.persisted_validation_data.clone())}, hashmap! {}, @@ -897,10 +871,9 @@ fn candidate_chunks_are_put_into_message_vault_when_candidate_is_first_seen() { hashmap! { current => 1 }, hashmap! { current => vec![ - dummy_occupied_core(candidates[0].descriptor.para_id), + occupied_core_from_candidate(&candidates[0]), ], }, - hashmap! { current => vec![candidates[0].clone()] }, hashmap! { candidates[0].hash() => true }, hashmap! {}, hashmap! {}, @@ -1168,50 +1141,28 @@ fn query_pending_availability_at_pulls_from_and_updates_receipts() { ) if r == hash_b => { let _ = tx.send(Ok(vec![ CoreState::Occupied(OccupiedCore { - para_id: para_b, next_up_on_available: None, occupied_since: 0, time_out_at: 0, next_up_on_time_out: None, availability: Default::default(), group_responsible: GroupIndex::from(0), + candidate_hash: candidate_hash_b, + candidate_descriptor: candidate_b.descriptor.clone(), }), CoreState::Occupied(OccupiedCore { - para_id: para_c, next_up_on_available: None, occupied_since: 0, time_out_at: 0, next_up_on_time_out: None, availability: Default::default(), group_responsible: GroupIndex::from(0), + candidate_hash: candidate_hash_c, + candidate_descriptor: candidate_c.descriptor.clone(), }), ])); } ); - - assert_matches!( - overseer_recv(&mut virtual_overseer).await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request( - r, - RuntimeApiRequest::CandidatePendingAvailability(p, tx), - ) - ) if r == hash_b && p == para_b => { - let _ = tx.send(Ok(Some(candidate_b))); - } - ); - - assert_matches!( - overseer_recv(&mut virtual_overseer).await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request( - r, - RuntimeApiRequest::CandidatePendingAvailability(p, tx), - ) - ) if r == hash_b && p == para_c => { - let _ = tx.send(Ok(Some(candidate_c))); - } - ); }; futures::pin_mut!(test_fut); @@ -1256,11 +1207,10 @@ fn new_peer_gets_all_chunks_send() { hashmap! { current => 1 }, hashmap! { current => vec![ - dummy_occupied_core(candidates[0].descriptor.para_id), - dummy_occupied_core(candidates[1].descriptor.para_id) + occupied_core_from_candidate(&candidates[0]), + occupied_core_from_candidate(&candidates[1]) ], }, - hashmap! { current => vec![candidates[0].clone(), candidates[1].clone()] }, hashmap! { candidates[0].hash() => true, candidates[1].hash() => false }, hashmap! { candidates[0].hash() => (pov_blocks[0].clone(), test_state.persisted_validation_data.clone())}, hashmap! {}, diff --git a/polkadot/primitives/src/v1.rs b/polkadot/primitives/src/v1.rs index 46ae17444b..1553100b74 100644 --- a/polkadot/primitives/src/v1.rs +++ b/polkadot/primitives/src/v1.rs @@ -576,11 +576,11 @@ impl GroupRotationInfo { } /// Information about a core which is currently occupied. -#[derive(Clone, Encode, Decode, Debug)] -#[cfg_attr(feature = "std", derive(PartialEq))] -pub struct OccupiedCore { - /// The ID of the para occupying the core. - pub para_id: Id, +#[derive(Clone, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Debug, PartialEq))] +pub struct OccupiedCore { + // NOTE: this has no ParaId as it can be deduced from the candidate descriptor. + /// If this core is freed by availability, this is the assignment that is next up on this /// core, if any. None if there is nothing queued for this core. pub next_up_on_available: Option, @@ -598,11 +598,22 @@ pub struct OccupiedCore { pub availability: BitVec, /// The group assigned to distribute availability pieces of this candidate. pub group_responsible: GroupIndex, + /// The hash of the candidate occupying the core. + pub candidate_hash: CandidateHash, + /// The descriptor of the candidate occupying the core. + pub candidate_descriptor: CandidateDescriptor, +} + +impl OccupiedCore { + /// Get the Para currently occupying this core. + pub fn para_id(&self) -> Id { + self.candidate_descriptor.para_id + } } /// Information about a core which is currently occupied. -#[derive(Clone, Encode, Decode, Debug)] -#[cfg_attr(feature = "std", derive(PartialEq, Default))] +#[derive(Clone, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Debug, PartialEq, Default))] pub struct ScheduledCore { /// The ID of a para scheduled. pub para_id: Id, @@ -611,12 +622,12 @@ pub struct ScheduledCore { } /// The state of a particular availability core. -#[derive(Clone, Encode, Decode, Debug)] -#[cfg_attr(feature = "std", derive(PartialEq))] -pub enum CoreState { +#[derive(Clone, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Debug, PartialEq))] +pub enum CoreState { /// The core is currently occupied. #[codec(index = "0")] - Occupied(OccupiedCore), + Occupied(OccupiedCore), /// The core is currently free, with a para scheduled and given the opportunity /// to occupy. /// @@ -634,7 +645,7 @@ impl CoreState { /// If this core state has a `para_id`, return it. pub fn para_id(&self) -> Option { match self { - Self::Occupied(OccupiedCore { para_id, ..}) => Some(*para_id), + Self::Occupied(ref core) => Some(core.para_id()), Self::Scheduled(ScheduledCore { para_id, .. }) => Some(*para_id), Self::Free => None, } @@ -718,7 +729,7 @@ sp_api::decl_runtime_apis! { /// Yields information on all availability cores. Cores are either free or occupied. Free /// cores can have paras assigned to them. - fn availability_cores() -> Vec>; + fn availability_cores() -> Vec>; /// Yields the full validation data for the given ParaId along with an assumption that /// should be used if the para currently occupieds a core. diff --git a/polkadot/roadmap/implementers-guide/src/node/availability/bitfield-signing.md b/polkadot/roadmap/implementers-guide/src/node/availability/bitfield-signing.md index 0ca9badd32..f3ef3a4e75 100644 --- a/polkadot/roadmap/implementers-guide/src/node/availability/bitfield-signing.md +++ b/polkadot/roadmap/implementers-guide/src/node/availability/bitfield-signing.md @@ -24,6 +24,6 @@ If not running as a validator, do nothing. - Begin by waiting a fixed period of time so availability distribution has the chance to make candidates available. - Determine our validator index `i`, the set of backed candidates pending availability in `r`, and which bit of the bitfield each corresponds to. -- Start with an empty bitfield. For each bit in the bitfield, if there is a candidate pending availability, query the [Availability Store](../utility/availability-store.md) for whether we have the availability chunk for our validator index. +- Start with an empty bitfield. For each bit in the bitfield, if there is a candidate pending availability, query the [Availability Store](../utility/availability-store.md) for whether we have the availability chunk for our validator index. The `OccupiedCore` struct contains the candidate hash so the full candidate does not need to be fetched from runtime. - For all chunks we have, set the corresponding bit in the bitfield. - Sign the bitfield and dispatch a `BitfieldDistribution::DistributeBitfield` message. diff --git a/polkadot/roadmap/implementers-guide/src/runtime-api/availability-cores.md b/polkadot/roadmap/implementers-guide/src/runtime-api/availability-cores.md index 561e817cca..87b06e2906 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime-api/availability-cores.md +++ b/polkadot/roadmap/implementers-guide/src/runtime-api/availability-cores.md @@ -12,8 +12,7 @@ This is all the information that a validator needs about scheduling for the curr ```rust struct OccupiedCore { - /// The ID of the para occupying the core. - para_id: ParaId, + // NOTE: this has no ParaId as it can be deduced from the candidate descriptor. /// If this core is freed by availability, this is the assignment that is next up on this /// core, if any. None if there is nothing queued for this core. next_up_on_available: Option, @@ -31,6 +30,10 @@ struct OccupiedCore { availability: Bitfield, /// The group assigned to distribute availability pieces of this candidate. group_responsible: GroupIndex, + /// The hash of the candidate occupying the core. + candidate_hash: CandidateHash, + /// The descriptor of the candidate occupying the core. + candidate_descriptor: CandidateDescriptor, } struct ScheduledCore { diff --git a/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md b/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md index 7433d51b96..9a6228a8c1 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md @@ -14,6 +14,7 @@ struct AvailabilityBitfield { struct CandidatePendingAvailability { core: CoreIndex, // availability core + hash: CandidateHash, descriptor: CandidateDescriptor, availability_votes: Bitfield, // one bit per validator. relay_parent_number: BlockNumber, // number of the relay-parent. diff --git a/polkadot/runtime/kusama/src/lib.rs b/polkadot/runtime/kusama/src/lib.rs index 7eb2003961..65899c915a 100644 --- a/polkadot/runtime/kusama/src/lib.rs +++ b/polkadot/runtime/kusama/src/lib.rs @@ -1347,7 +1347,7 @@ sp_api::impl_runtime_apis! { (Vec::new(), GroupRotationInfo { session_start_block: 0, group_rotation_frequency: 0, now: 0 }) } - fn availability_cores() -> Vec> { + fn availability_cores() -> Vec> { Vec::new() } diff --git a/polkadot/runtime/parachains/src/inclusion.rs b/polkadot/runtime/parachains/src/inclusion.rs index 08f9ae124c..3e312a0d45 100644 --- a/polkadot/runtime/parachains/src/inclusion.rs +++ b/polkadot/runtime/parachains/src/inclusion.rs @@ -25,7 +25,7 @@ use primitives::v1::{ ValidatorId, CandidateCommitments, CandidateDescriptor, ValidatorIndex, Id as ParaId, AvailabilityBitfield as AvailabilityBitfield, SignedAvailabilityBitfields, SigningContext, BackedCandidate, CoreIndex, GroupIndex, CommittedCandidateReceipt, - CandidateReceipt, HeadData, + CandidateReceipt, HeadData, CandidateHash, }; use frame_support::{ decl_storage, decl_module, decl_error, decl_event, ensure, debug, @@ -58,6 +58,8 @@ pub struct AvailabilityBitfieldRecord { pub struct CandidatePendingAvailability { /// The availability core this is assigned to. core: CoreIndex, + /// The candidate hash. + hash: CandidateHash, /// The candidate descriptor. descriptor: CandidateDescriptor, /// The received availability votes. One bit per validator. @@ -85,6 +87,16 @@ impl CandidatePendingAvailability { pub(crate) fn core_occupied(&self)-> CoreIndex { self.core.clone() } + + /// Get the candidate hash. + pub(crate) fn candidate_hash(&self) -> CandidateHash { + self.hash + } + + /// Get the canddiate descriptor. + pub(crate) fn candidate_descriptor(&self) -> &CandidateDescriptor { + &self.descriptor + } } /// A hook for applying validator rewards @@ -568,6 +580,8 @@ impl Module { candidate.candidate.commitments.head_data.clone(), )); + let candidate_hash = candidate.candidate.hash(); + let (descriptor, commitments) = ( candidate.candidate.descriptor, candidate.candidate.commitments, @@ -575,6 +589,7 @@ impl Module { >::insert(¶_id, CandidatePendingAvailability { core, + hash: candidate_hash, descriptor, availability_votes, relay_parent_number: check_cx.relay_parent_number, @@ -1112,6 +1127,7 @@ mod tests { let default_candidate = TestCandidateBuilder::default().build(); >::insert(chain_a, CandidatePendingAvailability { core: CoreIndex::from(0), + hash: default_candidate.hash(), descriptor: default_candidate.descriptor.clone(), availability_votes: default_availability_votes(), relay_parent_number: 0, @@ -1122,6 +1138,7 @@ mod tests { >::insert(&chain_b, CandidatePendingAvailability { core: CoreIndex::from(1), + hash: default_candidate.hash(), descriptor: default_candidate.descriptor, availability_votes: default_availability_votes(), relay_parent_number: 0, @@ -1286,6 +1303,7 @@ mod tests { let default_candidate = TestCandidateBuilder::default().build(); >::insert(chain_a, CandidatePendingAvailability { core: CoreIndex::from(0), + hash: default_candidate.hash(), descriptor: default_candidate.descriptor, availability_votes: default_availability_votes(), relay_parent_number: 0, @@ -1321,6 +1339,7 @@ mod tests { let default_candidate = TestCandidateBuilder::default().build(); >::insert(chain_a, CandidatePendingAvailability { core: CoreIndex::from(0), + hash: default_candidate.hash(), descriptor: default_candidate.descriptor, availability_votes: default_availability_votes(), relay_parent_number: 0, @@ -1393,6 +1412,7 @@ mod tests { >::insert(chain_a, CandidatePendingAvailability { core: CoreIndex::from(0), + hash: candidate_a.hash(), descriptor: candidate_a.descriptor, availability_votes: default_availability_votes(), relay_parent_number: 0, @@ -1409,6 +1429,7 @@ mod tests { >::insert(chain_b, CandidatePendingAvailability { core: CoreIndex::from(1), + hash: candidate_b.hash(), descriptor: candidate_b.descriptor, availability_votes: default_availability_votes(), relay_parent_number: 0, @@ -1839,6 +1860,7 @@ mod tests { let candidate = TestCandidateBuilder::default().build(); >::insert(&chain_a, CandidatePendingAvailability { core: CoreIndex::from(0), + hash: candidate.hash(), descriptor: candidate.descriptor, availability_votes: default_availability_votes(), relay_parent_number: 3, @@ -2127,6 +2149,7 @@ mod tests { >::get(&chain_a), Some(CandidatePendingAvailability { core: CoreIndex::from(0), + hash: candidate_a.hash(), descriptor: candidate_a.descriptor, availability_votes: default_availability_votes(), relay_parent_number: System::block_number() - 1, @@ -2143,6 +2166,7 @@ mod tests { >::get(&chain_b), Some(CandidatePendingAvailability { core: CoreIndex::from(1), + hash: candidate_b.hash(), descriptor: candidate_b.descriptor, availability_votes: default_availability_votes(), relay_parent_number: System::block_number() - 1, @@ -2159,6 +2183,7 @@ mod tests { >::get(&thread_a), Some(CandidatePendingAvailability { core: CoreIndex::from(2), + hash: candidate_c.hash(), descriptor: candidate_c.descriptor, availability_votes: default_availability_votes(), relay_parent_number: System::block_number() - 1, @@ -2254,6 +2279,7 @@ mod tests { >::get(&chain_a), Some(CandidatePendingAvailability { core: CoreIndex::from(0), + hash: candidate_a.hash(), descriptor: candidate_a.descriptor, availability_votes: default_availability_votes(), relay_parent_number: System::block_number() - 1, @@ -2329,6 +2355,7 @@ mod tests { let candidate = TestCandidateBuilder::default().build(); >::insert(&chain_a, CandidatePendingAvailability { core: CoreIndex::from(0), + hash: candidate.hash(), descriptor: candidate.descriptor.clone(), availability_votes: default_availability_votes(), relay_parent_number: 5, @@ -2339,6 +2366,7 @@ mod tests { >::insert(&chain_b, CandidatePendingAvailability { core: CoreIndex::from(1), + hash: candidate.hash(), descriptor: candidate.descriptor, availability_votes: default_availability_votes(), relay_parent_number: 6, diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/v1.rs b/polkadot/runtime/parachains/src/runtime_api_impl/v1.rs index f099c0db15..a171f9eb44 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/v1.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/v1.rs @@ -46,7 +46,7 @@ pub fn validator_groups() -> ( } /// Implementation for the `availability_cores` function of the runtime API. -pub fn availability_cores() -> Vec> { +pub fn availability_cores() -> Vec> { let cores = >::availability_cores(); let parachains = >::parachains(); let config = >::config(); @@ -96,7 +96,6 @@ pub fn availability_cores() -> Vec>::next_up_on_available( CoreIndex(i as u32) ), @@ -113,6 +112,8 @@ pub fn availability_cores() -> Vec { @@ -123,7 +124,6 @@ pub fn availability_cores() -> Vec>::next_up_on_available( CoreIndex(i as u32) ), @@ -140,6 +140,8 @@ pub fn availability_cores() -> Vec Vec> { + fn availability_cores() -> Vec> { Vec::new() } diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index f2a6732006..fddf700770 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -691,7 +691,7 @@ sp_api::impl_runtime_apis! { runtime_api_impl::validator_groups::() } - fn availability_cores() -> Vec> { + fn availability_cores() -> Vec> { runtime_api_impl::availability_cores::() } diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 7d68a6f69c..5e3908f14a 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -631,7 +631,7 @@ sp_api::impl_runtime_apis! { runtime_impl::validator_groups::() } - fn availability_cores() -> Vec> { + fn availability_cores() -> Vec> { runtime_impl::availability_cores::() } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index c99b1a1500..4cf3e26c5f 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -844,7 +844,7 @@ sp_api::impl_runtime_apis! { (Vec::new(), GroupRotationInfo { session_start_block: 0, group_rotation_frequency: 0, now: 0 }) } - fn availability_cores() -> Vec> { + fn availability_cores() -> Vec> { Vec::new() }