diff --git a/node/core/runtime-api/src/lib.rs b/node/core/runtime-api/src/lib.rs index 4dec90b33c4a..bbfc26ef188e 100644 --- a/node/core/runtime-api/src/lib.rs +++ b/node/core/runtime-api/src/lib.rs @@ -134,7 +134,7 @@ fn make_runtime_api_request( Request::CandidatePendingAvailability(para, sender) => query!(candidate_pending_availability(para), sender), Request::CandidateEvents(sender) => query!(candidate_events(), sender), - Request::ValidatorDiscovery(ids, sender) => query!(validator_discovery(ids), sender), + Request::SessionInfo(index, sender) => query!(session_info(index), sender), Request::DmqContents(id, sender) => query!(dmq_contents(id), sender), Request::InboundHrmpChannelsContents(id, sender) => query!(inbound_hrmp_channels_contents(id), sender), } @@ -201,8 +201,8 @@ mod tests { use polkadot_primitives::v1::{ ValidatorId, ValidatorIndex, GroupRotationInfo, CoreState, PersistedValidationData, Id as ParaId, OccupiedCoreAssumption, ValidationData, SessionIndex, ValidationCode, - CommittedCandidateReceipt, CandidateEvent, AuthorityDiscoveryId, InboundDownwardMessage, - BlockNumber, InboundHrmpMessage, + CommittedCandidateReceipt, CandidateEvent, InboundDownwardMessage, + BlockNumber, InboundHrmpMessage, SessionInfo, }; use polkadot_node_subsystem_test_helpers as test_helpers; use sp_core::testing::TaskExecutor; @@ -216,6 +216,7 @@ mod tests { availability_cores: Vec, validation_data: HashMap, session_index_for_child: SessionIndex, + session_info: HashMap, validation_code: HashMap, historical_validation_code: HashMap>, validation_outputs_results: HashMap, @@ -289,6 +290,10 @@ mod tests { self.session_index_for_child.clone() } + fn session_info(&self, index: SessionIndex) -> Option { + self.session_info.get(&index).cloned() + } + fn validation_code( &self, para: ParaId, @@ -321,10 +326,6 @@ mod tests { self.candidate_events.clone() } - fn validator_discovery(ids: Vec) -> Vec> { - vec![None; ids.len()] - } - fn dmq_contents( &self, recipient: ParaId, diff --git a/node/network/collator-protocol/src/collator_side.rs b/node/network/collator-protocol/src/collator_side.rs index b0a61c66a91c..03173777c3b2 100644 --- a/node/network/collator-protocol/src/collator_side.rs +++ b/node/network/collator-protocol/src/collator_side.rs @@ -738,6 +738,7 @@ mod tests { use polkadot_primitives::v1::{ BlockData, CandidateDescriptor, CollatorPair, ScheduledCore, ValidatorIndex, GroupRotationInfo, AuthorityDiscoveryId, + SessionInfo, }; use polkadot_subsystem::{ActiveLeavesUpdate, messages::{RuntimeApiMessage, RuntimeApiRequest}}; use polkadot_node_subsystem_util::TimeoutExt; @@ -870,20 +871,6 @@ mod tests { .collect() } - fn next_group_validator_ids(&self) -> Vec { - self.next_group_validator_indices() - .iter() - .map(|i| self.validator_public[*i as usize].clone()) - .collect() - } - - /// Returns the unique count of validators in the current and next group. - fn current_and_next_group_unique_validator_count(&self) -> usize { - let mut indices = self.next_group_validator_indices().iter().collect::>(); - indices.extend(self.current_group_validator_indices()); - indices.len() - } - /// Generate a new relay parent and inform the subsystem about the new view. /// /// If `merge_views == true` it means the subsystem will be informed that we working on the old `relay_parent` @@ -1085,25 +1072,40 @@ mod tests { } ); + let current_index = 1; + // obtain the validator_id to authority_id mapping assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( relay_parent, - RuntimeApiRequest::ValidatorDiscovery(validators, tx), + RuntimeApiRequest::SessionIndexForChild(tx), )) => { assert_eq!(relay_parent, test_state.relay_parent); - assert_eq!(validators.len(), test_state.current_and_next_group_unique_validator_count()); + tx.send(Ok(current_index)).unwrap(); + } + ); - let current_validators = test_state.current_group_validator_ids(); - let next_validators = test_state.next_group_validator_ids(); + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionInfo(index, tx), + )) => { + assert_eq!(relay_parent, test_state.relay_parent); + assert_eq!(index, current_index); - assert!(validators.iter().all(|v| current_validators.contains(&v) || next_validators.contains(&v))); + let validators = test_state.current_group_validator_ids(); + let current_discovery_keys = test_state.current_group_validator_authority_ids(); + let next_discovery_keys = test_state.next_group_validator_authority_ids(); - let current_validators = test_state.current_group_validator_authority_ids(); - let next_validators = test_state.next_group_validator_authority_ids(); + let discovery_keys = [¤t_discovery_keys[..], &next_discovery_keys[..]].concat(); - tx.send(Ok(current_validators.into_iter().chain(next_validators).map(Some).collect())).unwrap(); + tx.send(Ok(Some(SessionInfo { + validators, + discovery_keys, + ..Default::default() + }))).unwrap(); } ); diff --git a/node/network/collator-protocol/src/lib.rs b/node/network/collator-protocol/src/lib.rs index 3b58d9b96b00..ba1147fef94f 100644 --- a/node/network/collator-protocol/src/lib.rs +++ b/node/network/collator-protocol/src/lib.rs @@ -60,16 +60,6 @@ enum Error { Prometheus(#[from] prometheus::PrometheusError), } -impl From for Error { - fn from(me: util::validator_discovery::Error) -> Self { - match me { - util::validator_discovery::Error::Subsystem(s) => Error::Subsystem(s), - util::validator_discovery::Error::RuntimeApi(ra) => Error::RuntimeApi(ra), - util::validator_discovery::Error::Oneshot(c) => Error::Oneshot(c), - } - } -} - type Result = std::result::Result; /// What side of the collator protocol is being engaged diff --git a/node/subsystem-util/src/lib.rs b/node/subsystem-util/src/lib.rs index 750939a57a1d..4a1a736995b0 100644 --- a/node/subsystem-util/src/lib.rs +++ b/node/subsystem-util/src/lib.rs @@ -37,6 +37,7 @@ use polkadot_primitives::v1::{ CandidateEvent, CommittedCandidateReceipt, CoreState, EncodeAs, PersistedValidationData, GroupRotationInfo, Hash, Id as ParaId, ValidationData, OccupiedCoreAssumption, SessionIndex, Signed, SigningContext, ValidationCode, ValidatorId, ValidatorIndex, + SessionInfo, }; use sp_core::{ traits::SpawnNamed, @@ -274,6 +275,7 @@ specialize_requests_ctx! { fn request_validation_code_ctx(para_id: ParaId, assumption: OccupiedCoreAssumption) -> Option; ValidationCode; fn request_candidate_pending_availability_ctx(para_id: ParaId) -> Option; CandidatePendingAvailability; fn request_candidate_events_ctx() -> Vec; CandidateEvents; + fn request_session_info_ctx(index: SessionIndex) -> Option; SessionInfo; } /// From the given set of validators, find the first key we can sign with, if any. diff --git a/node/subsystem-util/src/validator_discovery.rs b/node/subsystem-util/src/validator_discovery.rs index 83c405a3f4b5..615372543570 100644 --- a/node/subsystem-util/src/validator_discovery.rs +++ b/node/subsystem-util/src/validator_discovery.rs @@ -20,34 +20,20 @@ use std::collections::HashMap; use std::pin::Pin; use futures::{ - channel::{mpsc, oneshot}, + channel::mpsc, task::{Poll, self}, stream, }; use streamunordered::{StreamUnordered, StreamYield}; -use thiserror::Error; use polkadot_node_subsystem::{ - errors::RuntimeApiError, SubsystemError, - messages::{AllMessages, RuntimeApiMessage, RuntimeApiRequest, NetworkBridgeMessage}, + errors::RuntimeApiError, + messages::{AllMessages, NetworkBridgeMessage}, SubsystemContext, }; use polkadot_primitives::v1::{Hash, ValidatorId, AuthorityDiscoveryId}; use sc_network::PeerId; - -/// Error when making a request to connect to validators. -#[derive(Debug, Error)] -pub enum Error { - /// Attempted to send or receive on a oneshot channel which had been canceled - #[error(transparent)] - Oneshot(#[from] oneshot::Canceled), - /// A subsystem error. - #[error(transparent)] - Subsystem(#[from] SubsystemError), - /// An error in the Runtime API. - #[error(transparent)] - RuntimeApi(#[from] RuntimeApiError), -} +use crate::Error; /// Utility function to make it easier to connect to validators. pub async fn connect_to_validators( @@ -55,17 +41,32 @@ pub async fn connect_to_validators( relay_parent: Hash, validators: Vec, ) -> Result { - // ValidatorId -> AuthorityDiscoveryId - let (tx, rx) = oneshot::channel(); - - ctx.send_message(AllMessages::RuntimeApi( - RuntimeApiMessage::Request( - relay_parent, - RuntimeApiRequest::ValidatorDiscovery(validators.clone(), tx), - ) - )).await; + let current_index = crate::request_session_index_for_child_ctx(relay_parent, ctx).await?.await??; + let session_info = crate::request_session_info_ctx( + relay_parent, + current_index, + ctx, + ).await?.await??; + + let (session_validators, discovery_keys) = match session_info { + Some(info) => (info.validators, info.discovery_keys), + None => return Err(RuntimeApiError::from( + "No session_info found for the current index".to_owned() + ).into()), + }; + + let id_to_index = session_validators.iter() + .zip(0usize..) + .collect::>(); + + // We assume the same ordering in authorities as in validators so we can do an index search + let maybe_authorities: Vec<_> = validators.iter() + .map(|id| { + let validator_index = id_to_index.get(&id); + validator_index.and_then(|i| discovery_keys.get(*i).cloned()) + }) + .collect(); - let maybe_authorities = rx.await??; let authorities: Vec<_> = maybe_authorities.iter() .cloned() .filter_map(|id| id) diff --git a/node/subsystem/src/messages.rs b/node/subsystem/src/messages.rs index 87d2981b546b..979364b13ca9 100644 --- a/node/subsystem/src/messages.rs +++ b/node/subsystem/src/messages.rs @@ -31,7 +31,7 @@ use polkadot_node_primitives::{ CollationGenerationConfig, MisbehaviorReport, SignedFullStatement, ValidationResult, }; use polkadot_primitives::v1::{ - AuthorityDiscoveryId, AvailableData, BackedCandidate, BlockNumber, + AuthorityDiscoveryId, AvailableData, BackedCandidate, BlockNumber, SessionInfo, Header as BlockHeader, CandidateDescriptor, CandidateEvent, CandidateReceipt, CollatorId, CommittedCandidateReceipt, CoreState, ErasureChunk, GroupRotationInfo, Hash, Id as ParaId, OccupiedCoreAssumption, @@ -434,14 +434,8 @@ pub enum RuntimeApiRequest { /// Get all events concerning candidates (backing, inclusion, time-out) in the parent of /// the block in whose state this request is executed. CandidateEvents(RuntimeApiSender>), - /// Get the `AuthorityDiscoveryId`s corresponding to the given `ValidatorId`s. - /// Currently this request is limited to validators in the current session. - /// - /// Returns `None` for validators not found in the current session. - ValidatorDiscovery( - Vec, - RuntimeApiSender>>, - ), + /// Get the session info for the given session, if stored. + SessionInfo(SessionIndex, RuntimeApiSender>), /// Get all the pending inbound messages in the downward message queue for a para. DmqContents( ParaId, diff --git a/primitives/src/v1.rs b/primitives/src/v1.rs index 8b2673c75020..a55cbb189e3e 100644 --- a/primitives/src/v1.rs +++ b/primitives/src/v1.rs @@ -672,7 +672,8 @@ pub enum CandidateEvent { } /// Information about validator sets of a session. -#[derive(Clone, Encode, Decode)] +#[derive(Clone, Encode, Decode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(PartialEq, Default))] pub struct SessionInfo { /// Validators in canonical ordering. pub validators: Vec, @@ -740,6 +741,9 @@ sp_api::decl_runtime_apis! { /// This can be used to instantiate a `SigningContext`. fn session_index_for_child() -> SessionIndex; + /// Get the session info for the given session, if stored. + fn session_info(index: SessionIndex) -> Option; + /// Fetch the validation code used by a para, making the given `OccupiedCoreAssumption`. /// /// Returns `None` if either the para is not registered or the assumption is `Freed` @@ -765,13 +769,6 @@ sp_api::decl_runtime_apis! { #[skip_initialize_block] fn candidate_events() -> Vec>; - /// Get the `AuthorityDiscoveryId`s corresponding to the given `ValidatorId`s. - /// Currently this request is limited to validators in the current session. - /// - /// We assume that every validator runs authority discovery, - /// which would allow us to establish point-to-point connection to given validators. - fn validator_discovery(validators: Vec) -> Vec>; - /// Get all the pending inbound messages in the downward message queue for a para. fn dmq_contents( recipient: Id, diff --git a/roadmap/implementers-guide/src/types/overseer-protocol.md b/roadmap/implementers-guide/src/types/overseer-protocol.md index 3b4b0d5b02d4..5a05947cdab9 100644 --- a/roadmap/implementers-guide/src/types/overseer-protocol.md +++ b/roadmap/implementers-guide/src/types/overseer-protocol.md @@ -398,14 +398,8 @@ enum RuntimeApiRequest { Validators(ResponseChannel>), /// Get the validator groups and rotation info. ValidatorGroups(ResponseChannel<(Vec>, GroupRotationInfo)>), - /// Get the session index for children of the block. This can be used to construct a signing - /// context. - SessionIndex(ResponseChannel), - /// Get the validation code for a specific para, using the given occupied core assumption. - ValidationCode(ParaId, OccupiedCoreAssumption, ResponseChannel>), - /// Fetch the historical validation code used by a para for candidates executed in - /// the context of a given block height in the current chain. - HistoricalValidationCode(ParaId, BlockNumber, ResponseChannel>), + /// Get information about all availability cores. + AvailabilityCores(ResponseChannel>), /// with the given occupied core assumption. PersistedValidationData( ParaId, @@ -424,12 +418,25 @@ enum RuntimeApiRequest { CandidateCommitments, RuntimeApiSender, ), - /// Get information about all availability cores. - AvailabilityCores(ResponseChannel>), + /// Get the session index for children of the block. This can be used to construct a signing + /// context. + SessionIndexForChild(ResponseChannel), + /// Get the validation code for a specific para, using the given occupied core assumption. + ValidationCode(ParaId, OccupiedCoreAssumption, ResponseChannel>), + /// Fetch the historical validation code used by a para for candidates executed in + /// the context of a given block height in the current chain. + HistoricalValidationCode(ParaId, BlockNumber, ResponseChannel>), /// Get a committed candidate receipt for all candidates pending availability. CandidatePendingAvailability(ParaId, ResponseChannel>), /// Get all events concerning candidates in the last block. CandidateEvents(ResponseChannel>), + /// Get the session info for the given session, if stored. + SessionInfo(SessionIndex, ResponseChannel>), + /// Get all the pending inbound messages in the downward message queue for a para. + DmqContents(ParaId, ResponseChannel>>), + /// Get the contents of all channels addressed to the given recipient. Channels that have no + /// messages in them are also included. + InboundHrmpChannelsContents(ParaId, ResponseChannel>>>), } enum RuntimeApiMessage { diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index c30bf59a6a9d..0aa1a4cadb9e 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -29,7 +29,7 @@ use primitives::v1::{ AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CommittedCandidateReceipt, CoreState, GroupRotationInfo, Hash, Id, Moment, Nonce, OccupiedCoreAssumption, PersistedValidationData, Signature, ValidationCode, ValidationData, ValidatorId, ValidatorIndex, - InboundDownwardMessage, InboundHrmpMessage, + InboundDownwardMessage, InboundHrmpMessage, SessionInfo, }; use runtime_common::{ claims, SlowAdjustingFeeUpdate, CurrencyToVote, @@ -1092,6 +1092,10 @@ sp_api::impl_runtime_apis! { 0 } + fn session_info(_: SessionIndex) -> Option { + None + } + fn validation_code(_: Id, _: OccupiedCoreAssumption) -> Option { None } @@ -1108,10 +1112,6 @@ sp_api::impl_runtime_apis! { Vec::new() } - fn validator_discovery(_: Vec) -> Vec> { - Vec::new() - } - fn dmq_contents( _recipient: Id, ) -> Vec> { diff --git a/runtime/parachains/src/runtime_api_impl/v1.rs b/runtime/parachains/src/runtime_api_impl/v1.rs index e055d37fb734..abecbbaeb181 100644 --- a/runtime/parachains/src/runtime_api_impl/v1.rs +++ b/runtime/parachains/src/runtime_api_impl/v1.rs @@ -23,7 +23,7 @@ use primitives::v1::{ ValidatorId, ValidatorIndex, GroupRotationInfo, CoreState, ValidationData, Id as ParaId, OccupiedCoreAssumption, SessionIndex, ValidationCode, CommittedCandidateReceipt, ScheduledCore, OccupiedCore, CoreOccupied, CoreIndex, - GroupIndex, CandidateEvent, PersistedValidationData, AuthorityDiscoveryId, + GroupIndex, CandidateEvent, PersistedValidationData, SessionInfo, InboundDownwardMessage, InboundHrmpMessage, }; use sp_runtime::traits::Zero; @@ -285,29 +285,9 @@ where .collect() } -/// Get the `AuthorityDiscoveryId`s corresponding to the given `ValidatorId`s and session. -/// -/// We assume that every validator runs authority discovery, -/// which would allow us to establish point-to-point connection to given validators. -pub fn validator_discovery(index: SessionIndex, validators: Vec) -> Vec> -where - T: initializer::Trait + pallet_authority_discovery::Trait, -{ - let (session_validators, discovery_keys) = match >::session_info(index) { - Some(info) => (info.validators, info.discovery_keys), - None => return Vec::new(), - }; - - let id_to_index = session_validators.iter() - .zip(0usize..) - .collect::>(); - // We assume the same ordering in authorities as in validators so we can do an index search - validators.iter() - .map(|id| { - let validator_index = id_to_index.get(&id); - validator_index.and_then(|i| discovery_keys.get(*i).cloned()) - }) - .collect() +/// Get the session info for the given session, if stored. +pub fn session_info(index: SessionIndex) -> Option { + >::session_info(index) } /// Implementation for the `dmq_contents` function of the runtime API. diff --git a/runtime/polkadot/src/lib.rs b/runtime/polkadot/src/lib.rs index 8d9e9897a63f..b12c98541e43 100644 --- a/runtime/polkadot/src/lib.rs +++ b/runtime/polkadot/src/lib.rs @@ -37,7 +37,7 @@ use primitives::v1::{ AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CommittedCandidateReceipt, CoreState, GroupRotationInfo, Hash, Id, Moment, Nonce, OccupiedCoreAssumption, PersistedValidationData, Signature, ValidationCode, ValidationData, ValidatorId, ValidatorIndex, - InboundDownwardMessage, InboundHrmpMessage, + InboundDownwardMessage, InboundHrmpMessage, SessionInfo, }; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, ModuleId, ApplyExtrinsicResult, @@ -1086,6 +1086,10 @@ sp_api::impl_runtime_apis! { 0 } + fn session_info(_: SessionIndex) -> Option { + None + } + fn validation_code(_: Id, _: OccupiedCoreAssumption) -> Option { None } @@ -1102,10 +1106,6 @@ sp_api::impl_runtime_apis! { Vec::new() } - fn validator_discovery(_: Vec) -> Vec> { - Vec::new() - } - fn dmq_contents( _recipient: Id, ) -> Vec> { diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index 1dd16d68dce7..2cc0a83398cd 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -28,7 +28,7 @@ use primitives::v1::{ AccountId, AccountIndex, Balance, BlockNumber, Hash, Nonce, Signature, Moment, GroupRotationInfo, CoreState, Id, ValidationData, ValidationCode, CandidateEvent, ValidatorId, ValidatorIndex, CommittedCandidateReceipt, OccupiedCoreAssumption, - PersistedValidationData, InboundDownwardMessage, InboundHrmpMessage, + PersistedValidationData, InboundDownwardMessage, InboundHrmpMessage, SessionInfo, }; use runtime_common::{ SlowAdjustingFeeUpdate, @@ -691,8 +691,9 @@ sp_api::impl_runtime_apis! { } }) } - fn validator_discovery(validators: Vec) -> Vec> { - runtime_api_impl::validator_discovery::(validators) + + fn session_info(index: SessionIndex) -> Option { + runtime_api_impl::session_info::(index) } fn dmq_contents(recipient: Id) -> Vec> { diff --git a/runtime/test-runtime/src/lib.rs b/runtime/test-runtime/src/lib.rs index 52f1e5e3b4f6..6b490eb8c29d 100644 --- a/runtime/test-runtime/src/lib.rs +++ b/runtime/test-runtime/src/lib.rs @@ -41,7 +41,7 @@ use primitives::v1::{ AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CommittedCandidateReceipt, CoreState, GroupRotationInfo, Hash as HashT, Id as ParaId, Moment, Nonce, OccupiedCoreAssumption, PersistedValidationData, Signature, ValidationCode, ValidationData, ValidatorId, ValidatorIndex, - InboundDownwardMessage, InboundHrmpMessage, + InboundDownwardMessage, InboundHrmpMessage, SessionInfo, }; use runtime_common::{ claims, SlowAdjustingFeeUpdate, paras_sudo_wrapper, @@ -681,8 +681,8 @@ sp_api::impl_runtime_apis! { runtime_impl::candidate_events::(|trait_event| trait_event.try_into().ok()) } - fn validator_discovery(validators: Vec) -> Vec> { - runtime_impl::validator_discovery::(validators) + fn session_info(index: SessionIndex) -> Option { + runtime_api_impl::session_info::(index) } fn dmq_contents( diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index 08e0ab6a28c9..e8f55dead8d7 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -28,7 +28,7 @@ use primitives::v1::{ AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CommittedCandidateReceipt, CoreState, GroupRotationInfo, Hash, Id, Moment, Nonce, OccupiedCoreAssumption, PersistedValidationData, Signature, ValidationCode, ValidationData, ValidatorId, ValidatorIndex, - InboundDownwardMessage, InboundHrmpMessage, + InboundDownwardMessage, InboundHrmpMessage, SessionInfo, }; use runtime_common::{ SlowAdjustingFeeUpdate, CurrencyToVote, @@ -840,6 +840,10 @@ sp_api::impl_runtime_apis! { 0 } + fn session_info(_: SessionIndex) -> Option { + None + } + fn validation_code(_: Id, _: OccupiedCoreAssumption) -> Option { None } @@ -852,10 +856,6 @@ sp_api::impl_runtime_apis! { Vec::new() } - fn validator_discovery(_: Vec) -> Vec> { - Vec::new() - } - fn dmq_contents( _recipient: Id, ) -> Vec> {