Unverified Commit 734eda87 authored by Andronik Ordian's avatar Andronik Ordian Committed by GitHub
Browse files

past-session validator discovery APIs (#2009)



* guide: fix formatting for SessionInfo module

* primitives: SessionInfo type

* punt on approval keys

* ah, revert the type alias

* session info runtime module skeleton

* update the guide

* runtime/configuration: sync with the guide

* runtime/configuration: setters for newly added fields

* runtime/configuration: set codec indexes

* runtime/configuration: update test

* primitives: fix SessionInfo definition

* runtime/session_info: initial impl

* runtime/session_info: use initializer for session handling (wip)

* runtime/session_info: mock authority discovery trait

* guide: update the initializer's order

* runtime/session_info: tests skeleton

* runtime/session_info: store n_delay_tranches in Configuration

* runtime/session_info: punt on approval keys

* runtime/session_info: add some basic tests

* Update primitives/src/v1.rs

* small fixes

* remove codec index annotation on structs

* fix off-by-one error

* validator_discovery: accept a session index

* runtime: replace validator_discovery api with session_info

* Update runtime/parachains/src/session_info.rs

Co-authored-by: Sergey Pepyakin's avatarSergei Shulepov <sergei@parity.io>

* runtime/session_info: add a comment about missing entries

* runtime/session_info: define the keys

* util: expose connect_to_past_session_validators

* util: allow session_info requests for jobs

* runtime-api: add mock test for session_info

* collator-protocol: add session_index to test state

* util: fix error message for runtime error

* fix compilation

* fix tests after merge with master

Co-authored-by: Sergey Pepyakin's avatarSergei Shulepov <sergei@parity.io>
parent 9a32ab1d
Pipeline #115139 passed with stages
in 21 minutes and 47 seconds
...@@ -134,7 +134,7 @@ fn make_runtime_api_request<Client>( ...@@ -134,7 +134,7 @@ fn make_runtime_api_request<Client>(
Request::CandidatePendingAvailability(para, sender) => Request::CandidatePendingAvailability(para, sender) =>
query!(candidate_pending_availability(para), sender), query!(candidate_pending_availability(para), sender),
Request::CandidateEvents(sender) => query!(candidate_events(), 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::DmqContents(id, sender) => query!(dmq_contents(id), sender),
Request::InboundHrmpChannelsContents(id, sender) => query!(inbound_hrmp_channels_contents(id), sender), Request::InboundHrmpChannelsContents(id, sender) => query!(inbound_hrmp_channels_contents(id), sender),
} }
...@@ -201,8 +201,8 @@ mod tests { ...@@ -201,8 +201,8 @@ mod tests {
use polkadot_primitives::v1::{ use polkadot_primitives::v1::{
ValidatorId, ValidatorIndex, GroupRotationInfo, CoreState, PersistedValidationData, ValidatorId, ValidatorIndex, GroupRotationInfo, CoreState, PersistedValidationData,
Id as ParaId, OccupiedCoreAssumption, ValidationData, SessionIndex, ValidationCode, Id as ParaId, OccupiedCoreAssumption, ValidationData, SessionIndex, ValidationCode,
CommittedCandidateReceipt, CandidateEvent, AuthorityDiscoveryId, InboundDownwardMessage, CommittedCandidateReceipt, CandidateEvent, InboundDownwardMessage,
BlockNumber, InboundHrmpMessage, BlockNumber, InboundHrmpMessage, SessionInfo,
}; };
use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_test_helpers as test_helpers;
use sp_core::testing::TaskExecutor; use sp_core::testing::TaskExecutor;
...@@ -216,6 +216,7 @@ mod tests { ...@@ -216,6 +216,7 @@ mod tests {
availability_cores: Vec<CoreState>, availability_cores: Vec<CoreState>,
validation_data: HashMap<ParaId, ValidationData>, validation_data: HashMap<ParaId, ValidationData>,
session_index_for_child: SessionIndex, session_index_for_child: SessionIndex,
session_info: HashMap<SessionIndex, SessionInfo>,
validation_code: HashMap<ParaId, ValidationCode>, validation_code: HashMap<ParaId, ValidationCode>,
historical_validation_code: HashMap<ParaId, Vec<(BlockNumber, ValidationCode)>>, historical_validation_code: HashMap<ParaId, Vec<(BlockNumber, ValidationCode)>>,
validation_outputs_results: HashMap<ParaId, bool>, validation_outputs_results: HashMap<ParaId, bool>,
...@@ -289,6 +290,10 @@ mod tests { ...@@ -289,6 +290,10 @@ mod tests {
self.session_index_for_child.clone() self.session_index_for_child.clone()
} }
fn session_info(&self, index: SessionIndex) -> Option<SessionInfo> {
self.session_info.get(&index).cloned()
}
fn validation_code( fn validation_code(
&self, &self,
para: ParaId, para: ParaId,
...@@ -321,10 +326,6 @@ mod tests { ...@@ -321,10 +326,6 @@ mod tests {
self.candidate_events.clone() self.candidate_events.clone()
} }
fn validator_discovery(ids: Vec<ValidatorId>) -> Vec<Option<AuthorityDiscoveryId>> {
vec![None; ids.len()]
}
fn dmq_contents( fn dmq_contents(
&self, &self,
recipient: ParaId, recipient: ParaId,
...@@ -569,6 +570,33 @@ mod tests { ...@@ -569,6 +570,33 @@ mod tests {
futures::executor::block_on(future::join(subsystem_task, test_task)); futures::executor::block_on(future::join(subsystem_task, test_task));
} }
#[test]
fn requests_session_info() {
let (ctx, mut ctx_handle) = test_helpers::make_subsystem_context(TaskExecutor::new());
let mut runtime_api = MockRuntimeApi::default();
let session_index = 1;
runtime_api.session_info.insert(session_index, Default::default());
let runtime_api = Arc::new(runtime_api);
let relay_parent = [1; 32].into();
let subsystem = RuntimeApiSubsystem::new(runtime_api.clone(), Metrics(None));
let subsystem_task = run(ctx, subsystem).map(|x| x.unwrap());
let test_task = async move {
let (tx, rx) = oneshot::channel();
ctx_handle.send(FromOverseer::Communication {
msg: RuntimeApiMessage::Request(relay_parent, Request::SessionInfo(session_index, tx))
}).await;
assert_eq!(rx.await.unwrap().unwrap(), Some(Default::default()));
ctx_handle.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
};
futures::executor::block_on(future::join(subsystem_task, test_task));
}
#[test] #[test]
fn requests_validation_code() { fn requests_validation_code() {
let (ctx, mut ctx_handle) = test_helpers::make_subsystem_context(TaskExecutor::new()); let (ctx, mut ctx_handle) = test_helpers::make_subsystem_context(TaskExecutor::new());
......
...@@ -738,6 +738,7 @@ mod tests { ...@@ -738,6 +738,7 @@ mod tests {
use polkadot_primitives::v1::{ use polkadot_primitives::v1::{
BlockData, CandidateDescriptor, CollatorPair, ScheduledCore, BlockData, CandidateDescriptor, CollatorPair, ScheduledCore,
ValidatorIndex, GroupRotationInfo, AuthorityDiscoveryId, ValidatorIndex, GroupRotationInfo, AuthorityDiscoveryId,
SessionIndex, SessionInfo,
}; };
use polkadot_subsystem::{ActiveLeavesUpdate, messages::{RuntimeApiMessage, RuntimeApiRequest}}; use polkadot_subsystem::{ActiveLeavesUpdate, messages::{RuntimeApiMessage, RuntimeApiRequest}};
use polkadot_node_subsystem_util::TimeoutExt; use polkadot_node_subsystem_util::TimeoutExt;
...@@ -776,6 +777,7 @@ mod tests { ...@@ -776,6 +777,7 @@ mod tests {
relay_parent: Hash, relay_parent: Hash,
availability_core: CoreState, availability_core: CoreState,
our_collator_pair: CollatorPair, our_collator_pair: CollatorPair,
session_index: SessionIndex,
} }
fn validator_pubkeys(val_ids: &[Sr25519Keyring]) -> Vec<ValidatorId> { fn validator_pubkeys(val_ids: &[Sr25519Keyring]) -> Vec<ValidatorId> {
...@@ -832,6 +834,7 @@ mod tests { ...@@ -832,6 +834,7 @@ mod tests {
relay_parent, relay_parent,
availability_core, availability_core,
our_collator_pair, our_collator_pair,
session_index: 1,
} }
} }
} }
...@@ -841,6 +844,10 @@ mod tests { ...@@ -841,6 +844,10 @@ mod tests {
&self.validator_groups.0[0] &self.validator_groups.0[0]
} }
fn current_session_index(&self) -> SessionIndex {
self.session_index
}
fn current_group_validator_peer_ids(&self) -> Vec<PeerId> { fn current_group_validator_peer_ids(&self) -> Vec<PeerId> {
self.current_group_validator_indices().iter().map(|i| self.validator_peer_id[*i as usize].clone()).collect() self.current_group_validator_indices().iter().map(|i| self.validator_peer_id[*i as usize].clone()).collect()
} }
...@@ -870,20 +877,6 @@ mod tests { ...@@ -870,20 +877,6 @@ mod tests {
.collect() .collect()
} }
fn next_group_validator_ids(&self) -> Vec<ValidatorId> {
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::<HashSet<_>>();
indices.extend(self.current_group_validator_indices());
indices.len()
}
/// Generate a new relay parent and inform the subsystem about the new view. /// 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` /// If `merge_views == true` it means the subsystem will be informed that we working on the old `relay_parent`
...@@ -1090,20 +1083,33 @@ mod tests { ...@@ -1090,20 +1083,33 @@ mod tests {
overseer_recv(virtual_overseer).await, overseer_recv(virtual_overseer).await,
AllMessages::RuntimeApi(RuntimeApiMessage::Request( AllMessages::RuntimeApi(RuntimeApiMessage::Request(
relay_parent, relay_parent,
RuntimeApiRequest::ValidatorDiscovery(validators, tx), RuntimeApiRequest::SessionIndexForChild(tx),
)) => { )) => {
assert_eq!(relay_parent, test_state.relay_parent); assert_eq!(relay_parent, test_state.relay_parent);
assert_eq!(validators.len(), test_state.current_and_next_group_unique_validator_count()); tx.send(Ok(test_state.current_session_index())).unwrap();
}
);
let current_validators = test_state.current_group_validator_ids(); assert_matches!(
let next_validators = test_state.next_group_validator_ids(); 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, test_state.current_session_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 discovery_keys = [&current_discovery_keys[..], &next_discovery_keys[..]].concat();
let next_validators = test_state.next_group_validator_authority_ids();
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();
} }
); );
......
...@@ -60,16 +60,6 @@ enum Error { ...@@ -60,16 +60,6 @@ enum Error {
Prometheus(#[from] prometheus::PrometheusError), Prometheus(#[from] prometheus::PrometheusError),
} }
impl From<util::validator_discovery::Error> 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<T> = std::result::Result<T, Error>; type Result<T> = std::result::Result<T, Error>;
/// What side of the collator protocol is being engaged /// What side of the collator protocol is being engaged
......
...@@ -27,8 +27,6 @@ pub enum Error { ...@@ -27,8 +27,6 @@ pub enum Error {
#[error(transparent)] #[error(transparent)]
Runtime(#[from] polkadot_subsystem::errors::RuntimeApiError), Runtime(#[from] polkadot_subsystem::errors::RuntimeApiError),
#[error(transparent)] #[error(transparent)]
ValidatorDiscovery(#[from] polkadot_node_subsystem_util::validator_discovery::Error),
#[error(transparent)]
Util(#[from] polkadot_node_subsystem_util::Error), Util(#[from] polkadot_node_subsystem_util::Error),
} }
......
...@@ -11,7 +11,7 @@ use sp_keyring::Sr25519Keyring; ...@@ -11,7 +11,7 @@ use sp_keyring::Sr25519Keyring;
use polkadot_primitives::v1::{ use polkadot_primitives::v1::{
AuthorityDiscoveryId, BlockData, CoreState, GroupRotationInfo, Id as ParaId, AuthorityDiscoveryId, BlockData, CoreState, GroupRotationInfo, Id as ParaId,
ScheduledCore, ValidatorIndex, ScheduledCore, ValidatorIndex, SessionIndex, SessionInfo,
}; };
use polkadot_subsystem::messages::{RuntimeApiMessage, RuntimeApiRequest}; use polkadot_subsystem::messages::{RuntimeApiMessage, RuntimeApiRequest};
use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_test_helpers as test_helpers;
...@@ -37,8 +37,10 @@ fn validator_authority_id(val_ids: &[Sr25519Keyring]) -> Vec<AuthorityDiscoveryI ...@@ -37,8 +37,10 @@ fn validator_authority_id(val_ids: &[Sr25519Keyring]) -> Vec<AuthorityDiscoveryI
val_ids.iter().map(|v| v.public().into()).collect() val_ids.iter().map(|v| v.public().into()).collect()
} }
type VirtualOverseer = test_helpers::TestSubsystemContextHandle<PoVDistributionMessage>;
struct TestHarness { struct TestHarness {
virtual_overseer: test_helpers::TestSubsystemContextHandle<PoVDistributionMessage>, virtual_overseer: VirtualOverseer,
} }
fn test_harness<T: Future<Output = ()>>( fn test_harness<T: Future<Output = ()>>(
...@@ -75,7 +77,7 @@ fn test_harness<T: Future<Output = ()>>( ...@@ -75,7 +77,7 @@ fn test_harness<T: Future<Output = ()>>(
const TIMEOUT: Duration = Duration::from_millis(100); const TIMEOUT: Duration = Duration::from_millis(100);
async fn overseer_send( async fn overseer_send(
overseer: &mut test_helpers::TestSubsystemContextHandle<PoVDistributionMessage>, overseer: &mut VirtualOverseer,
msg: PoVDistributionMessage, msg: PoVDistributionMessage,
) { ) {
trace!("Sending message:\n{:?}", &msg); trace!("Sending message:\n{:?}", &msg);
...@@ -87,7 +89,7 @@ async fn overseer_send( ...@@ -87,7 +89,7 @@ async fn overseer_send(
} }
async fn overseer_recv( async fn overseer_recv(
overseer: &mut test_helpers::TestSubsystemContextHandle<PoVDistributionMessage>, overseer: &mut VirtualOverseer,
) -> AllMessages { ) -> AllMessages {
let msg = overseer_recv_with_timeout(overseer, TIMEOUT) let msg = overseer_recv_with_timeout(overseer, TIMEOUT)
.await .await
...@@ -99,7 +101,7 @@ async fn overseer_recv( ...@@ -99,7 +101,7 @@ async fn overseer_recv(
} }
async fn overseer_recv_with_timeout( async fn overseer_recv_with_timeout(
overseer: &mut test_helpers::TestSubsystemContextHandle<PoVDistributionMessage>, overseer: &mut VirtualOverseer,
timeout: Duration, timeout: Duration,
) -> Option<AllMessages> { ) -> Option<AllMessages> {
trace!("Waiting for message..."); trace!("Waiting for message...");
...@@ -110,7 +112,7 @@ async fn overseer_recv_with_timeout( ...@@ -110,7 +112,7 @@ async fn overseer_recv_with_timeout(
} }
async fn overseer_signal( async fn overseer_signal(
overseer: &mut test_helpers::TestSubsystemContextHandle<PoVDistributionMessage>, overseer: &mut VirtualOverseer,
signal: OverseerSignal, signal: OverseerSignal,
) { ) {
overseer overseer
...@@ -130,6 +132,7 @@ struct TestState { ...@@ -130,6 +132,7 @@ struct TestState {
validator_groups: (Vec<Vec<ValidatorIndex>>, GroupRotationInfo), validator_groups: (Vec<Vec<ValidatorIndex>>, GroupRotationInfo),
relay_parent: Hash, relay_parent: Hash,
availability_cores: Vec<CoreState>, availability_cores: Vec<CoreState>,
session_index: SessionIndex,
} }
impl Default for TestState { impl Default for TestState {
...@@ -184,10 +187,56 @@ impl Default for TestState { ...@@ -184,10 +187,56 @@ impl Default for TestState {
validator_groups, validator_groups,
relay_parent, relay_parent,
availability_cores, availability_cores,
session_index: 1,
} }
} }
} }
async fn test_validator_discovery(
virtual_overseer: &mut VirtualOverseer,
expected_relay_parent: Hash,
session_index: SessionIndex,
validator_ids: &[ValidatorId],
discovery_ids: &[AuthorityDiscoveryId],
validator_group: &[ValidatorIndex],
) {
assert_matches!(
overseer_recv(virtual_overseer).await,
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
relay_parent,
RuntimeApiRequest::SessionIndexForChild(tx),
)) => {
assert_eq!(relay_parent, expected_relay_parent);
tx.send(Ok(session_index)).unwrap();
}
);
assert_matches!(
overseer_recv(virtual_overseer).await,
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
relay_parent,
RuntimeApiRequest::SessionInfo(index, tx),
)) => {
assert_eq!(relay_parent, expected_relay_parent);
assert_eq!(index, session_index);
let validators = validator_group.iter()
.map(|idx| validator_ids[*idx as usize].clone())
.collect();
let discovery_keys = validator_group.iter()
.map(|idx| discovery_ids[*idx as usize].clone())
.collect();
tx.send(Ok(Some(SessionInfo {
validators,
discovery_keys,
..Default::default()
}))).unwrap();
}
);
}
#[test] #[test]
fn ask_validators_for_povs() { fn ask_validators_for_povs() {
let test_state = TestState::default(); let test_state = TestState::default();
...@@ -271,25 +320,14 @@ fn ask_validators_for_povs() { ...@@ -271,25 +320,14 @@ fn ask_validators_for_povs() {
} }
); );
// obtain the validator_id to authority_id mapping test_validator_discovery(
assert_matches!( &mut virtual_overseer,
overseer_recv(&mut virtual_overseer).await, current,
AllMessages::RuntimeApi(RuntimeApiMessage::Request( test_state.session_index,
relay_parent, &test_state.validator_public,
RuntimeApiRequest::ValidatorDiscovery(validators, tx), &test_state.validator_authority_id,
)) => { &test_state.validator_groups.0[0],
assert_eq!(relay_parent, current); ).await;
assert_eq!(validators.len(), 3);
assert!(validators.iter().all(|v| test_state.validator_public.contains(&v)));
let result = vec![
Some(test_state.validator_authority_id[2].clone()),
Some(test_state.validator_authority_id[0].clone()),
Some(test_state.validator_authority_id[4].clone()),
];
tx.send(Ok(result)).unwrap();
}
);
// We now should connect to our validator group. // We now should connect to our validator group.
assert_matches!( assert_matches!(
...@@ -448,24 +486,14 @@ fn ask_validators_for_povs() { ...@@ -448,24 +486,14 @@ fn ask_validators_for_povs() {
); );
// obtain the validator_id to authority_id mapping // obtain the validator_id to authority_id mapping
assert_matches!( test_validator_discovery(
overseer_recv(&mut virtual_overseer).await, &mut virtual_overseer,
AllMessages::RuntimeApi(RuntimeApiMessage::Request( next_leaf,
relay_parent, test_state.session_index,
RuntimeApiRequest::ValidatorDiscovery(validators, tx), &test_state.validator_public,
)) => { &test_state.validator_authority_id,
assert_eq!(relay_parent, next_leaf); &test_state.validator_groups.0[0],
assert_eq!(validators.len(), 3); ).await;
assert!(validators.iter().all(|v| test_state.validator_public.contains(&v)));
let result = vec![
Some(test_state.validator_authority_id[2].clone()),
Some(test_state.validator_authority_id[0].clone()),
Some(test_state.validator_authority_id[4].clone()),
];
tx.send(Ok(result)).unwrap();
}
);
// We now should connect to our validator group. // We now should connect to our validator group.
assert_matches!( assert_matches!(
...@@ -716,7 +744,7 @@ fn we_inform_peers_with_same_view_we_are_awaiting() { ...@@ -716,7 +744,7 @@ fn we_inform_peers_with_same_view_we_are_awaiting() {
RuntimeApiRequest::ValidatorGroups(tx) RuntimeApiRequest::ValidatorGroups(tx)
)) => { )) => {
assert_eq!(relay_parent, hash_a); assert_eq!(relay_parent, hash_a);
tx.send(Ok(validator_groups)).unwrap(); tx.send(Ok(validator_groups.clone())).unwrap();
} }
); );
...@@ -731,25 +759,14 @@ fn we_inform_peers_with_same_view_we_are_awaiting() { ...@@ -731,25 +759,14 @@ fn we_inform_peers_with_same_view_we_are_awaiting() {
} }
); );
assert_matches!( test_validator_discovery(
handle.recv().await, &mut handle,
AllMessages::RuntimeApi(RuntimeApiMessage::Request( hash_a,
relay_parent, 1,
RuntimeApiRequest::ValidatorDiscovery(validators_res, tx), &validators,
)) => { &validator_authority_id,
assert_eq!(relay_parent, hash_a); &validator_groups.0[0],
assert_eq!(validators_res.len(), 3); ).await;
assert!(validators_res.iter().all(|v| validators.contains(&v)));
let result = vec![
Some(validator_authority_id[2].clone()),
Some(validator_authority_id[0].clone()),
Some(validator_authority_id[4].clone()),
];
tx.send(Ok(result)).unwrap();
}
);
assert_matches!( assert_matches!(
handle.recv().await, handle.recv().await,
......
...@@ -37,6 +37,7 @@ use polkadot_primitives::v1::{ ...@@ -37,6 +37,7 @@ use polkadot_primitives::v1::{
CandidateEvent, CommittedCandidateReceipt, CoreState, EncodeAs, PersistedValidationData, CandidateEvent, CommittedCandidateReceipt, CoreState, EncodeAs, PersistedValidationData,
GroupRotationInfo, Hash, Id as ParaId, ValidationData, OccupiedCoreAssumption, GroupRotationInfo, Hash, Id as ParaId, ValidationData, OccupiedCoreAssumption,
SessionIndex, Signed, SigningContext, ValidationCode, ValidatorId, ValidatorIndex, SessionIndex, Signed, SigningContext, ValidationCode, ValidatorId, ValidatorIndex,
SessionInfo,
}; };
use sp_core::{ use sp_core::{
traits::SpawnNamed, traits::SpawnNamed,
...@@ -193,6 +194,7 @@ specialize_requests! { ...@@ -193,6 +194,7 @@ specialize_requests! {
fn request_validation_code(para_id: ParaId, assumption: OccupiedCoreAssumption) -> Option<ValidationCode>; ValidationCode; fn request_validation_code(para_id: ParaId, assumption: OccupiedCoreAssumption) -> Option<ValidationCode>; ValidationCode;
fn request_candidate_pending_availability(para_id: ParaId) -> Option<CommittedCandidateReceipt>; CandidatePendingAvailability; fn request_candidate_pending_availability(para_id: ParaId) -> Option<CommittedCandidateReceipt>; CandidatePendingAvailability;
fn request_candidate_events() -> Vec<CandidateEvent>; CandidateEvents; fn request_candidate_events() -> Vec<CandidateEvent>; CandidateEvents;
fn request_session_info(index: SessionIndex) -> Option<SessionInfo>; SessionInfo;
} }
/// Request some data from the `RuntimeApi` via a SubsystemContext. /// Request some data from the `RuntimeApi` via a SubsystemContext.
...@@ -274,6 +276,7 @@ specialize_requests_ctx! { ...@@ -274,6 +276,7 @@ specialize_requests_ctx! {
fn request_validation_code_ctx(para_id: ParaId, assumption: OccupiedCoreAssumption) -> Option<ValidationCode>; ValidationCode; fn request_validation_code_ctx(para_id: ParaId, assumption: OccupiedCoreAssumption) -> Option<ValidationCode>; ValidationCode;
fn request_candidate_pending_availability_ctx(para_id: ParaId) -> Option<CommittedCandidateReceipt>; CandidatePendingAvailability; fn request_candidate_pending_availability_ctx(para_id: ParaId) -> Option<CommittedCandidateReceipt>; CandidatePendingAvailability;
fn request_candidate_events_ctx() -> Vec<CandidateEvent>; CandidateEvents; fn request_candidate_events_ctx() -> Vec<CandidateEvent>; CandidateEvents;