mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-01 12:27:56 +00:00
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: Sergei 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: Sergei Shulepov <sergei@parity.io>
This commit is contained in:
@@ -134,7 +134,7 @@ fn make_runtime_api_request<Client>(
|
||||
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<CoreState>,
|
||||
validation_data: HashMap<ParaId, ValidationData>,
|
||||
session_index_for_child: SessionIndex,
|
||||
session_info: HashMap<SessionIndex, SessionInfo>,
|
||||
validation_code: HashMap<ParaId, ValidationCode>,
|
||||
historical_validation_code: HashMap<ParaId, Vec<(BlockNumber, ValidationCode)>>,
|
||||
validation_outputs_results: HashMap<ParaId, bool>,
|
||||
@@ -289,6 +290,10 @@ mod tests {
|
||||
self.session_index_for_child.clone()
|
||||
}
|
||||
|
||||
fn session_info(&self, index: SessionIndex) -> Option<SessionInfo> {
|
||||
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<ValidatorId>) -> Vec<Option<AuthorityDiscoveryId>> {
|
||||
vec![None; ids.len()]
|
||||
}
|
||||
|
||||
fn dmq_contents(
|
||||
&self,
|
||||
recipient: ParaId,
|
||||
@@ -569,6 +570,33 @@ mod tests {
|
||||
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]
|
||||
fn requests_validation_code() {
|
||||
let (ctx, mut ctx_handle) = test_helpers::make_subsystem_context(TaskExecutor::new());
|
||||
|
||||
@@ -738,6 +738,7 @@ mod tests {
|
||||
use polkadot_primitives::v1::{
|
||||
BlockData, CandidateDescriptor, CollatorPair, ScheduledCore,
|
||||
ValidatorIndex, GroupRotationInfo, AuthorityDiscoveryId,
|
||||
SessionIndex, SessionInfo,
|
||||
};
|
||||
use polkadot_subsystem::{ActiveLeavesUpdate, messages::{RuntimeApiMessage, RuntimeApiRequest}};
|
||||
use polkadot_node_subsystem_util::TimeoutExt;
|
||||
@@ -776,6 +777,7 @@ mod tests {
|
||||
relay_parent: Hash,
|
||||
availability_core: CoreState,
|
||||
our_collator_pair: CollatorPair,
|
||||
session_index: SessionIndex,
|
||||
}
|
||||
|
||||
fn validator_pubkeys(val_ids: &[Sr25519Keyring]) -> Vec<ValidatorId> {
|
||||
@@ -832,6 +834,7 @@ mod tests {
|
||||
relay_parent,
|
||||
availability_core,
|
||||
our_collator_pair,
|
||||
session_index: 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -841,6 +844,10 @@ mod tests {
|
||||
&self.validator_groups.0[0]
|
||||
}
|
||||
|
||||
fn current_session_index(&self) -> SessionIndex {
|
||||
self.session_index
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
@@ -870,20 +877,6 @@ mod tests {
|
||||
.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.
|
||||
///
|
||||
/// 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 {
|
||||
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(test_state.current_session_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, 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 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();
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -60,16 +60,6 @@ enum Error {
|
||||
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>;
|
||||
|
||||
/// What side of the collator protocol is being engaged
|
||||
|
||||
@@ -27,8 +27,6 @@ pub enum Error {
|
||||
#[error(transparent)]
|
||||
Runtime(#[from] polkadot_subsystem::errors::RuntimeApiError),
|
||||
#[error(transparent)]
|
||||
ValidatorDiscovery(#[from] polkadot_node_subsystem_util::validator_discovery::Error),
|
||||
#[error(transparent)]
|
||||
Util(#[from] polkadot_node_subsystem_util::Error),
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ use sp_keyring::Sr25519Keyring;
|
||||
|
||||
use polkadot_primitives::v1::{
|
||||
AuthorityDiscoveryId, BlockData, CoreState, GroupRotationInfo, Id as ParaId,
|
||||
ScheduledCore, ValidatorIndex,
|
||||
ScheduledCore, ValidatorIndex, SessionIndex, SessionInfo,
|
||||
};
|
||||
use polkadot_subsystem::messages::{RuntimeApiMessage, RuntimeApiRequest};
|
||||
use polkadot_node_subsystem_test_helpers as test_helpers;
|
||||
@@ -37,8 +37,10 @@ fn validator_authority_id(val_ids: &[Sr25519Keyring]) -> Vec<AuthorityDiscoveryI
|
||||
val_ids.iter().map(|v| v.public().into()).collect()
|
||||
}
|
||||
|
||||
type VirtualOverseer = test_helpers::TestSubsystemContextHandle<PoVDistributionMessage>;
|
||||
|
||||
struct TestHarness {
|
||||
virtual_overseer: test_helpers::TestSubsystemContextHandle<PoVDistributionMessage>,
|
||||
virtual_overseer: VirtualOverseer,
|
||||
}
|
||||
|
||||
fn test_harness<T: Future<Output = ()>>(
|
||||
@@ -75,7 +77,7 @@ fn test_harness<T: Future<Output = ()>>(
|
||||
const TIMEOUT: Duration = Duration::from_millis(100);
|
||||
|
||||
async fn overseer_send(
|
||||
overseer: &mut test_helpers::TestSubsystemContextHandle<PoVDistributionMessage>,
|
||||
overseer: &mut VirtualOverseer,
|
||||
msg: PoVDistributionMessage,
|
||||
) {
|
||||
trace!("Sending message:\n{:?}", &msg);
|
||||
@@ -87,7 +89,7 @@ async fn overseer_send(
|
||||
}
|
||||
|
||||
async fn overseer_recv(
|
||||
overseer: &mut test_helpers::TestSubsystemContextHandle<PoVDistributionMessage>,
|
||||
overseer: &mut VirtualOverseer,
|
||||
) -> AllMessages {
|
||||
let msg = overseer_recv_with_timeout(overseer, TIMEOUT)
|
||||
.await
|
||||
@@ -99,7 +101,7 @@ async fn overseer_recv(
|
||||
}
|
||||
|
||||
async fn overseer_recv_with_timeout(
|
||||
overseer: &mut test_helpers::TestSubsystemContextHandle<PoVDistributionMessage>,
|
||||
overseer: &mut VirtualOverseer,
|
||||
timeout: Duration,
|
||||
) -> Option<AllMessages> {
|
||||
trace!("Waiting for message...");
|
||||
@@ -110,7 +112,7 @@ async fn overseer_recv_with_timeout(
|
||||
}
|
||||
|
||||
async fn overseer_signal(
|
||||
overseer: &mut test_helpers::TestSubsystemContextHandle<PoVDistributionMessage>,
|
||||
overseer: &mut VirtualOverseer,
|
||||
signal: OverseerSignal,
|
||||
) {
|
||||
overseer
|
||||
@@ -130,6 +132,7 @@ struct TestState {
|
||||
validator_groups: (Vec<Vec<ValidatorIndex>>, GroupRotationInfo),
|
||||
relay_parent: Hash,
|
||||
availability_cores: Vec<CoreState>,
|
||||
session_index: SessionIndex,
|
||||
}
|
||||
|
||||
impl Default for TestState {
|
||||
@@ -184,10 +187,56 @@ impl Default for TestState {
|
||||
validator_groups,
|
||||
relay_parent,
|
||||
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]
|
||||
fn ask_validators_for_povs() {
|
||||
let test_state = TestState::default();
|
||||
@@ -271,25 +320,14 @@ fn ask_validators_for_povs() {
|
||||
}
|
||||
);
|
||||
|
||||
// obtain the validator_id to authority_id mapping
|
||||
assert_matches!(
|
||||
overseer_recv(&mut virtual_overseer).await,
|
||||
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
|
||||
relay_parent,
|
||||
RuntimeApiRequest::ValidatorDiscovery(validators, tx),
|
||||
)) => {
|
||||
assert_eq!(relay_parent, current);
|
||||
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();
|
||||
}
|
||||
);
|
||||
test_validator_discovery(
|
||||
&mut virtual_overseer,
|
||||
current,
|
||||
test_state.session_index,
|
||||
&test_state.validator_public,
|
||||
&test_state.validator_authority_id,
|
||||
&test_state.validator_groups.0[0],
|
||||
).await;
|
||||
|
||||
// We now should connect to our validator group.
|
||||
assert_matches!(
|
||||
@@ -448,24 +486,14 @@ fn ask_validators_for_povs() {
|
||||
);
|
||||
|
||||
// obtain the validator_id to authority_id mapping
|
||||
assert_matches!(
|
||||
overseer_recv(&mut virtual_overseer).await,
|
||||
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
|
||||
relay_parent,
|
||||
RuntimeApiRequest::ValidatorDiscovery(validators, tx),
|
||||
)) => {
|
||||
assert_eq!(relay_parent, next_leaf);
|
||||
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();
|
||||
}
|
||||
);
|
||||
test_validator_discovery(
|
||||
&mut virtual_overseer,
|
||||
next_leaf,
|
||||
test_state.session_index,
|
||||
&test_state.validator_public,
|
||||
&test_state.validator_authority_id,
|
||||
&test_state.validator_groups.0[0],
|
||||
).await;
|
||||
|
||||
// We now should connect to our validator group.
|
||||
assert_matches!(
|
||||
@@ -716,7 +744,7 @@ fn we_inform_peers_with_same_view_we_are_awaiting() {
|
||||
RuntimeApiRequest::ValidatorGroups(tx)
|
||||
)) => {
|
||||
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() {
|
||||
}
|
||||
);
|
||||
|
||||
assert_matches!(
|
||||
handle.recv().await,
|
||||
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
|
||||
relay_parent,
|
||||
RuntimeApiRequest::ValidatorDiscovery(validators_res, tx),
|
||||
)) => {
|
||||
assert_eq!(relay_parent, hash_a);
|
||||
assert_eq!(validators_res.len(), 3);
|
||||
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();
|
||||
}
|
||||
);
|
||||
test_validator_discovery(
|
||||
&mut handle,
|
||||
hash_a,
|
||||
1,
|
||||
&validators,
|
||||
&validator_authority_id,
|
||||
&validator_groups.0[0],
|
||||
).await;
|
||||
|
||||
assert_matches!(
|
||||
handle.recv().await,
|
||||
|
||||
@@ -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,
|
||||
@@ -193,6 +194,7 @@ specialize_requests! {
|
||||
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_events() -> Vec<CandidateEvent>; CandidateEvents;
|
||||
fn request_session_info(index: SessionIndex) -> Option<SessionInfo>; SessionInfo;
|
||||
}
|
||||
|
||||
/// Request some data from the `RuntimeApi` via a SubsystemContext.
|
||||
@@ -274,6 +276,7 @@ specialize_requests_ctx! {
|
||||
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_events_ctx() -> Vec<CandidateEvent>; CandidateEvents;
|
||||
fn request_session_info_ctx(index: SessionIndex) -> Option<SessionInfo>; SessionInfo;
|
||||
}
|
||||
|
||||
/// From the given set of validators, find the first key we can sign with, if any.
|
||||
|
||||
@@ -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 polkadot_primitives::v1::{Hash, ValidatorId, AuthorityDiscoveryId, SessionIndex};
|
||||
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<Context: SubsystemContext>(
|
||||
@@ -55,17 +41,42 @@ pub async fn connect_to_validators<Context: SubsystemContext>(
|
||||
relay_parent: Hash,
|
||||
validators: Vec<ValidatorId>,
|
||||
) -> Result<ConnectionRequest, Error> {
|
||||
// ValidatorId -> AuthorityDiscoveryId
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let current_index = crate::request_session_index_for_child_ctx(relay_parent, ctx).await?.await??;
|
||||
connect_to_past_session_validators(ctx, relay_parent, validators, current_index).await
|
||||
}
|
||||
|
||||
ctx.send_message(AllMessages::RuntimeApi(
|
||||
RuntimeApiMessage::Request(
|
||||
relay_parent,
|
||||
RuntimeApiRequest::ValidatorDiscovery(validators.clone(), tx),
|
||||
)
|
||||
)).await;
|
||||
/// Utility function to make it easier to connect to validators in the past sessions.
|
||||
pub async fn connect_to_past_session_validators<Context: SubsystemContext>(
|
||||
ctx: &mut Context,
|
||||
relay_parent: Hash,
|
||||
validators: Vec<ValidatorId>,
|
||||
session_index: SessionIndex,
|
||||
) -> Result<ConnectionRequest, Error> {
|
||||
let session_info = crate::request_session_info_ctx(
|
||||
relay_parent,
|
||||
session_index,
|
||||
ctx,
|
||||
).await?.await??;
|
||||
|
||||
let (session_validators, discovery_keys) = match session_info {
|
||||
Some(info) => (info.validators, info.discovery_keys),
|
||||
None => return Err(RuntimeApiError::from(
|
||||
format!("No SessionInfo found for the index {}", session_index)
|
||||
).into()),
|
||||
};
|
||||
|
||||
let id_to_index = session_validators.iter()
|
||||
.zip(0usize..)
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
// 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)
|
||||
|
||||
@@ -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<Vec<CandidateEvent>>),
|
||||
/// 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<ValidatorId>,
|
||||
RuntimeApiSender<Vec<Option<AuthorityDiscoveryId>>>,
|
||||
),
|
||||
/// Get the session info for the given session, if stored.
|
||||
SessionInfo(SessionIndex, RuntimeApiSender<Option<SessionInfo>>),
|
||||
/// Get all the pending inbound messages in the downward message queue for a para.
|
||||
DmqContents(
|
||||
ParaId,
|
||||
|
||||
@@ -25,6 +25,7 @@ use primitives::RuntimeDebug;
|
||||
use runtime_primitives::traits::AppVerify;
|
||||
use inherents::InherentIdentifier;
|
||||
use sp_arithmetic::traits::{BaseArithmetic, Saturating, Zero};
|
||||
use application_crypto::KeyTypeId;
|
||||
|
||||
pub use runtime_primitives::traits::{BlakeTwo256, Hash as HashT};
|
||||
|
||||
@@ -57,6 +58,34 @@ pub use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
|
||||
/// Unique identifier for the Inclusion Inherent
|
||||
pub const INCLUSION_INHERENT_IDENTIFIER: InherentIdentifier = *b"inclusn0";
|
||||
|
||||
|
||||
/// The key type ID for a parachain approval voting key.
|
||||
pub const APPROVAL_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"aprv");
|
||||
|
||||
mod approval_app {
|
||||
use application_crypto::{app_crypto, sr25519};
|
||||
app_crypto!(sr25519, super::APPROVAL_KEY_TYPE_ID);
|
||||
}
|
||||
|
||||
/// The public key of a keypair used by a validator for approval voting
|
||||
/// on included parachain candidates.
|
||||
pub type ApprovalId = approval_app::Public;
|
||||
|
||||
/// The key type ID for parachain assignment key.
|
||||
pub const ASSIGNMENT_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"asgn");
|
||||
|
||||
// The public key of a keypair used by a validator for determining assignments
|
||||
/// to approve included parachain candidates.
|
||||
mod assigment_app {
|
||||
use application_crypto::{app_crypto, sr25519};
|
||||
app_crypto!(sr25519, super::ASSIGNMENT_KEY_TYPE_ID);
|
||||
}
|
||||
|
||||
/// The public key of a keypair used by a validator for determining assignments
|
||||
/// to approve included parachain candidates.
|
||||
pub type AssignmentId = assigment_app::Public;
|
||||
|
||||
|
||||
/// Get a collator signature payload on a relay-parent, block-data combo.
|
||||
pub fn collator_signature_payload<H: AsRef<[u8]>>(
|
||||
relay_parent: &H,
|
||||
@@ -671,6 +700,35 @@ pub enum CandidateEvent<H = Hash> {
|
||||
CandidateTimedOut(CandidateReceipt<H>, HeadData),
|
||||
}
|
||||
|
||||
/// Information about validator sets of a session.
|
||||
#[derive(Clone, Encode, Decode, RuntimeDebug)]
|
||||
#[cfg_attr(feature = "std", derive(PartialEq, Default))]
|
||||
pub struct SessionInfo {
|
||||
/// Validators in canonical ordering.
|
||||
pub validators: Vec<ValidatorId>,
|
||||
/// Validators' authority discovery keys for the session in canonical ordering.
|
||||
pub discovery_keys: Vec<AuthorityDiscoveryId>,
|
||||
/// The assignment and approval keys for validators.
|
||||
pub approval_keys: Vec<(ApprovalId, AssignmentId)>,
|
||||
/// Validators in shuffled ordering - these are the validator groups as produced
|
||||
/// by the `Scheduler` module for the session and are typically referred to by
|
||||
/// `GroupIndex`.
|
||||
pub validator_groups: Vec<Vec<ValidatorIndex>>,
|
||||
/// The number of availability cores used by the protocol during this session.
|
||||
pub n_cores: u32,
|
||||
/// The zeroth delay tranche width.
|
||||
pub zeroth_delay_tranche_width: u32,
|
||||
/// The number of samples we do of relay_vrf_modulo.
|
||||
pub relay_vrf_modulo_samples: u32,
|
||||
/// The number of delay tranches in total.
|
||||
pub n_delay_tranches: u32,
|
||||
/// How many slots (BABE / SASSAFRAS) must pass before an assignment is considered a
|
||||
/// no-show.
|
||||
pub no_show_slots: u32,
|
||||
/// The number of validators needed to approve a block.
|
||||
pub needed_approvals: u32,
|
||||
}
|
||||
|
||||
sp_api::decl_runtime_apis! {
|
||||
/// The API for querying the state of parachains on-chain.
|
||||
pub trait ParachainHost<H: Decode = Hash, N: Encode + Decode = BlockNumber> {
|
||||
@@ -710,6 +768,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<SessionInfo>;
|
||||
|
||||
/// 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`
|
||||
@@ -735,13 +796,6 @@ sp_api::decl_runtime_apis! {
|
||||
#[skip_initialize_block]
|
||||
fn candidate_events() -> Vec<CandidateEvent<H>>;
|
||||
|
||||
/// 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<ValidatorId>) -> Vec<Option<AuthorityDiscoveryId>>;
|
||||
|
||||
/// Get all the pending inbound messages in the downward message queue for a para.
|
||||
fn dmq_contents(
|
||||
recipient: Id,
|
||||
|
||||
@@ -23,7 +23,7 @@ The other parachains modules are initialized in this order:
|
||||
1. Paras
|
||||
1. Scheduler
|
||||
1. Inclusion
|
||||
1. Validity
|
||||
1. SessionInfo
|
||||
1. DMP
|
||||
1. UMP
|
||||
1. HRMP
|
||||
|
||||
@@ -30,11 +30,11 @@ struct SessionInfo {
|
||||
// no-show.
|
||||
no_show_slots: u32,
|
||||
/// The number of validators needed to approve a block.
|
||||
needed_approvals: u32,
|
||||
needed_approvals: u32,
|
||||
}
|
||||
```
|
||||
|
||||
Storage Layout:
|
||||
Storage Layout:
|
||||
|
||||
```rust
|
||||
/// The earliest session for which previous session info is stored.
|
||||
@@ -45,11 +45,10 @@ Sessions: map SessionIndex => Option<SessionInfo>,
|
||||
|
||||
## Session Change
|
||||
|
||||
1. Update the `CurrentSessionIndex`.
|
||||
1. Update `EarliestStoredSession` based on `config.dispute_period` and remove all entries from `Sessions` from the previous value up to the new value.
|
||||
1. Create a new entry in `Sessions` with information about the current session.
|
||||
|
||||
## Routines
|
||||
|
||||
* `earliest_stored_session() -> SessionIndex`: Yields the earliest session for which we have information stored.
|
||||
* `session_info(session: SessionIndex) -> Option<SessionInfo>`: Yields the session info for the given session, if stored.
|
||||
* `session_info(session: SessionIndex) -> Option<SessionInfo>`: Yields the session info for the given session, if stored.
|
||||
|
||||
@@ -424,14 +424,8 @@ enum RuntimeApiRequest {
|
||||
Validators(ResponseChannel<Vec<ValidatorId>>),
|
||||
/// Get the validator groups and rotation info.
|
||||
ValidatorGroups(ResponseChannel<(Vec<Vec<ValidatorIndex>>, GroupRotationInfo)>),
|
||||
/// Get the session index for children of the block. This can be used to construct a signing
|
||||
/// context.
|
||||
SessionIndex(ResponseChannel<SessionIndex>),
|
||||
/// Get the validation code for a specific para, using the given occupied core assumption.
|
||||
ValidationCode(ParaId, OccupiedCoreAssumption, ResponseChannel<Option<ValidationCode>>),
|
||||
/// 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<Option<ValidationCode>>),
|
||||
/// Get information about all availability cores.
|
||||
AvailabilityCores(ResponseChannel<Vec<CoreState>>),
|
||||
/// with the given occupied core assumption.
|
||||
PersistedValidationData(
|
||||
ParaId,
|
||||
@@ -450,12 +444,25 @@ enum RuntimeApiRequest {
|
||||
CandidateCommitments,
|
||||
RuntimeApiSender<bool>,
|
||||
),
|
||||
/// Get information about all availability cores.
|
||||
AvailabilityCores(ResponseChannel<Vec<CoreState>>),
|
||||
/// Get the session index for children of the block. This can be used to construct a signing
|
||||
/// context.
|
||||
SessionIndexForChild(ResponseChannel<SessionIndex>),
|
||||
/// Get the validation code for a specific para, using the given occupied core assumption.
|
||||
ValidationCode(ParaId, OccupiedCoreAssumption, ResponseChannel<Option<ValidationCode>>),
|
||||
/// 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<Option<ValidationCode>>),
|
||||
/// Get a committed candidate receipt for all candidates pending availability.
|
||||
CandidatePendingAvailability(ParaId, ResponseChannel<Option<CommittedCandidateReceipt>>),
|
||||
/// Get all events concerning candidates in the last block.
|
||||
CandidateEvents(ResponseChannel<Vec<CandidateEvent>>),
|
||||
/// Get the session info for the given session, if stored.
|
||||
SessionInfo(SessionIndex, ResponseChannel<Option<SessionInfo>>),
|
||||
/// Get all the pending inbound messages in the downward message queue for a para.
|
||||
DmqContents(ParaId, ResponseChannel<Vec<InboundDownwardMessage<BlockNumber>>>),
|
||||
/// Get the contents of all channels addressed to the given recipient. Channels that have no
|
||||
/// messages in them are also included.
|
||||
InboundHrmpChannelsContents(ParaId, ResponseChannel<BTreeMap<ParaId, Vec<InboundHrmpMessage<BlockNumber>>>>),
|
||||
}
|
||||
|
||||
enum RuntimeApiMessage {
|
||||
|
||||
@@ -12,6 +12,9 @@ struct HostConfiguration {
|
||||
pub validation_upgrade_frequency: BlockNumber,
|
||||
/// The delay, in blocks, before a validation upgrade is applied.
|
||||
pub validation_upgrade_delay: BlockNumber,
|
||||
/// The acceptance period, in blocks. This is the amount of blocks after availability that validators
|
||||
/// and fishermen have to perform secondary checks or issue reports.
|
||||
pub acceptance_period: BlockNumber,
|
||||
/// The maximum validation code size, in bytes.
|
||||
pub max_code_size: u32,
|
||||
/// The maximum head-data size, in bytes.
|
||||
@@ -37,6 +40,8 @@ struct HostConfiguration {
|
||||
/// submitting an approval vote before a validator is considered a no-show.
|
||||
/// Must be at least 1.
|
||||
pub no_show_slots: u32,
|
||||
/// The number of delay tranches in total.
|
||||
pub n_delay_tranches: u32,
|
||||
/// The width of the zeroth delay tranche for approval assignments. This many delay tranches
|
||||
/// beyond 0 are all consolidated to form a wide 0 tranche.
|
||||
pub zeroth_delay_tranche_width: u32,
|
||||
|
||||
@@ -262,14 +262,14 @@ mod tests {
|
||||
}, testing::{UintAuthorityId, TestXt}, Perbill, curve::PiecewiseLinear,
|
||||
};
|
||||
use primitives::v1::{
|
||||
Balance, BlockNumber, Header, Signature,
|
||||
Balance, BlockNumber, Header, Signature, AuthorityDiscoveryId,
|
||||
};
|
||||
use frame_support::{
|
||||
traits::{Randomness, OnInitialize, OnFinalize},
|
||||
impl_outer_origin, impl_outer_dispatch, assert_ok, parameter_types,
|
||||
};
|
||||
use keyring::Sr25519Keyring;
|
||||
use runtime_parachains::{initializer, configuration, inclusion, scheduler, dmp, ump, hrmp};
|
||||
use runtime_parachains::{initializer, configuration, inclusion, session_info, scheduler, dmp, ump, hrmp};
|
||||
use pallet_session::OneSessionHandler;
|
||||
|
||||
impl_outer_origin! {
|
||||
@@ -477,6 +477,14 @@ mod tests {
|
||||
type Event = ();
|
||||
}
|
||||
|
||||
impl session_info::AuthorityDiscoveryTrait for Test {
|
||||
fn authorities() -> Vec<AuthorityDiscoveryId> {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl session_info::Trait for Test { }
|
||||
|
||||
pub struct TestRandomness;
|
||||
|
||||
impl Randomness<H256> for TestRandomness {
|
||||
|
||||
@@ -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<SessionInfo> {
|
||||
None
|
||||
}
|
||||
|
||||
fn validation_code(_: Id, _: OccupiedCoreAssumption) -> Option<ValidationCode> {
|
||||
None
|
||||
}
|
||||
@@ -1108,10 +1112,6 @@ sp_api::impl_runtime_apis! {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn validator_discovery(_: Vec<ValidatorId>) -> Vec<Option<AuthorityDiscoveryId>> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn dmq_contents(
|
||||
_recipient: Id,
|
||||
) -> Vec<InboundDownwardMessage<BlockNumber>> {
|
||||
|
||||
@@ -19,9 +19,10 @@
|
||||
//! Configuration can change only at session boundaries and is buffered until then.
|
||||
|
||||
use sp_std::prelude::*;
|
||||
use primitives::v1::{Balance, ValidatorId};
|
||||
use primitives::v1::{Balance, ValidatorId, SessionIndex};
|
||||
use frame_support::{
|
||||
decl_storage, decl_module, decl_error,
|
||||
ensure,
|
||||
dispatch::DispatchResult,
|
||||
weights::{DispatchClass, Weight},
|
||||
};
|
||||
@@ -60,6 +61,21 @@ pub struct HostConfiguration<BlockNumber> {
|
||||
pub thread_availability_period: BlockNumber,
|
||||
/// The amount of blocks ahead to schedule parachains and parathreads.
|
||||
pub scheduling_lookahead: u32,
|
||||
/// The amount of sessions to keep for disputes.
|
||||
pub dispute_period: SessionIndex,
|
||||
/// The amount of consensus slots that must pass between submitting an assignment and
|
||||
/// submitting an approval vote before a validator is considered a no-show.
|
||||
/// Must be at least 1.
|
||||
pub no_show_slots: u32,
|
||||
/// The number of delay tranches in total.
|
||||
pub n_delay_tranches: u32,
|
||||
/// The width of the zeroth delay tranche for approval assignments. This many delay tranches
|
||||
/// beyond 0 are all consolidated to form a wide 0 tranche.
|
||||
pub zeroth_delay_tranche_width: u32,
|
||||
/// The number of validators needed to approve a block.
|
||||
pub needed_approvals: u32,
|
||||
/// The number of samples to do of the RelayVRFModulo approval assignment criterion.
|
||||
pub relay_vrf_modulo_samples: u32,
|
||||
/// Total number of individual messages allowed in the parachain -> relay-chain message queue.
|
||||
pub max_upward_queue_count: u32,
|
||||
/// Total size of messages allowed in the parachain -> relay-chain message queue before which
|
||||
@@ -255,6 +271,68 @@ decl_module! {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the dispute period, in number of sessions to keep for disputes.
|
||||
#[weight = (1_000, DispatchClass::Operational)]
|
||||
pub fn set_dispute_period(origin, new: SessionIndex) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.dispute_period, new) != new
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the no show slots, in number of number of consensus slots.
|
||||
/// Must be at least 1.
|
||||
#[weight = (1_000, DispatchClass::Operational)]
|
||||
pub fn set_no_show_slots(origin, new: u32) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
ensure!(new >= 1, "no_show_slots must be at least 1");
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.no_show_slots, new) != new
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the total number of delay tranches.
|
||||
#[weight = (1_000, DispatchClass::Operational)]
|
||||
pub fn set_n_delay_tranches(origin, new: u32) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.n_delay_tranches, new) != new
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the zeroth delay tranche width.
|
||||
#[weight = (1_000, DispatchClass::Operational)]
|
||||
pub fn set_zeroth_delay_tranche_width(origin, new: u32) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.zeroth_delay_tranche_width, new) != new
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the number of validators needed to approve a block.
|
||||
#[weight = (1_000, DispatchClass::Operational)]
|
||||
pub fn set_needed_approvals(origin, new: u32) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.needed_approvals, new) != new
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the number of samples to do of the RelayVRFModulo approval assignment criterion.
|
||||
#[weight = (1_000, DispatchClass::Operational)]
|
||||
pub fn set_relay_vrf_modulo_samples(origin, new: u32) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.relay_vrf_modulo_samples, new) != new
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets the maximum items that can present in a upward dispatch queue at once.
|
||||
#[weight = (1_000, DispatchClass::Operational)]
|
||||
pub fn set_max_upward_queue_count(origin, new: u32) -> DispatchResult {
|
||||
@@ -504,6 +582,12 @@ mod tests {
|
||||
chain_availability_period: 10,
|
||||
thread_availability_period: 8,
|
||||
scheduling_lookahead: 3,
|
||||
dispute_period: 239,
|
||||
no_show_slots: 240,
|
||||
n_delay_tranches: 241,
|
||||
zeroth_delay_tranche_width: 242,
|
||||
needed_approvals: 242,
|
||||
relay_vrf_modulo_samples: 243,
|
||||
max_upward_queue_count: 1337,
|
||||
max_upward_queue_size: 228,
|
||||
max_downward_message_size: 2048,
|
||||
@@ -561,6 +645,24 @@ mod tests {
|
||||
Configuration::set_scheduling_lookahead(
|
||||
Origin::root(), new_config.scheduling_lookahead,
|
||||
).unwrap();
|
||||
Configuration::set_dispute_period(
|
||||
Origin::root(), new_config.dispute_period,
|
||||
).unwrap();
|
||||
Configuration::set_no_show_slots(
|
||||
Origin::root(), new_config.no_show_slots,
|
||||
).unwrap();
|
||||
Configuration::set_n_delay_tranches(
|
||||
Origin::root(), new_config.n_delay_tranches,
|
||||
).unwrap();
|
||||
Configuration::set_zeroth_delay_tranche_width(
|
||||
Origin::root(), new_config.zeroth_delay_tranche_width,
|
||||
).unwrap();
|
||||
Configuration::set_needed_approvals(
|
||||
Origin::root(), new_config.needed_approvals,
|
||||
).unwrap();
|
||||
Configuration::set_relay_vrf_modulo_samples(
|
||||
Origin::root(), new_config.relay_vrf_modulo_samples,
|
||||
).unwrap();
|
||||
Configuration::set_max_upward_queue_count(
|
||||
Origin::root(), new_config.max_upward_queue_count,
|
||||
).unwrap();
|
||||
|
||||
@@ -29,7 +29,7 @@ use sp_runtime::traits::One;
|
||||
use parity_scale_codec::{Encode, Decode};
|
||||
use crate::{
|
||||
configuration::{self, HostConfiguration},
|
||||
paras, scheduler, inclusion, dmp, ump, hrmp,
|
||||
paras, scheduler, inclusion, session_info, dmp, ump, hrmp,
|
||||
};
|
||||
|
||||
/// Information about a session change that has just occurred.
|
||||
@@ -63,6 +63,7 @@ pub trait Trait:
|
||||
+ paras::Trait
|
||||
+ scheduler::Trait
|
||||
+ inclusion::Trait
|
||||
+ session_info::Trait
|
||||
+ dmp::Trait
|
||||
+ ump::Trait
|
||||
+ hrmp::Trait
|
||||
@@ -123,6 +124,7 @@ decl_module! {
|
||||
// - Paras
|
||||
// - Scheduler
|
||||
// - Inclusion
|
||||
// - SessionInfo
|
||||
// - Validity
|
||||
// - DMP
|
||||
// - UMP
|
||||
@@ -131,6 +133,7 @@ decl_module! {
|
||||
paras::Module::<T>::initializer_initialize(now) +
|
||||
scheduler::Module::<T>::initializer_initialize(now) +
|
||||
inclusion::Module::<T>::initializer_initialize(now) +
|
||||
session_info::Module::<T>::initializer_initialize(now) +
|
||||
dmp::Module::<T>::initializer_initialize(now) +
|
||||
ump::Module::<T>::initializer_initialize(now) +
|
||||
hrmp::Module::<T>::initializer_initialize(now);
|
||||
@@ -146,6 +149,7 @@ decl_module! {
|
||||
hrmp::Module::<T>::initializer_finalize();
|
||||
ump::Module::<T>::initializer_finalize();
|
||||
dmp::Module::<T>::initializer_finalize();
|
||||
session_info::Module::<T>::initializer_finalize();
|
||||
inclusion::Module::<T>::initializer_finalize();
|
||||
scheduler::Module::<T>::initializer_finalize();
|
||||
paras::Module::<T>::initializer_finalize();
|
||||
@@ -189,6 +193,7 @@ impl<T: Trait> Module<T> {
|
||||
paras::Module::<T>::initializer_on_new_session(¬ification);
|
||||
scheduler::Module::<T>::initializer_on_new_session(¬ification);
|
||||
inclusion::Module::<T>::initializer_on_new_session(¬ification);
|
||||
session_info::Module::<T>::initializer_on_new_session(¬ification);
|
||||
dmp::Module::<T>::initializer_on_new_session(¬ification);
|
||||
ump::Module::<T>::initializer_on_new_session(¬ification);
|
||||
hrmp::Module::<T>::initializer_on_new_session(¬ification);
|
||||
|
||||
@@ -28,6 +28,7 @@ pub mod inclusion_inherent;
|
||||
pub mod initializer;
|
||||
pub mod paras;
|
||||
pub mod scheduler;
|
||||
pub mod session_info;
|
||||
pub mod validity;
|
||||
pub mod origin;
|
||||
pub mod dmp;
|
||||
|
||||
@@ -24,7 +24,7 @@ use sp_runtime::{
|
||||
BlakeTwo256, IdentityLookup,
|
||||
},
|
||||
};
|
||||
use primitives::v1::{BlockNumber, Header};
|
||||
use primitives::v1::{AuthorityDiscoveryId, BlockNumber, Header};
|
||||
use frame_support::{
|
||||
impl_outer_origin, impl_outer_dispatch, impl_outer_event, parameter_types,
|
||||
weights::Weight, traits::Randomness as RandomnessT,
|
||||
@@ -124,6 +124,14 @@ impl crate::inclusion::Trait for Test {
|
||||
type Event = TestEvent;
|
||||
}
|
||||
|
||||
impl crate::session_info::Trait for Test { }
|
||||
|
||||
impl crate::session_info::AuthorityDiscoveryTrait for Test {
|
||||
fn authorities() -> Vec<AuthorityDiscoveryId> {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub type System = frame_system::Module<Test>;
|
||||
|
||||
/// Mocked initializer.
|
||||
@@ -150,6 +158,9 @@ pub type Scheduler = crate::scheduler::Module<Test>;
|
||||
/// Mocked inclusion module.
|
||||
pub type Inclusion = crate::inclusion::Module<Test>;
|
||||
|
||||
/// Mocked session info module.
|
||||
pub type SessionInfo = crate::session_info::Module<Test>;
|
||||
|
||||
/// Create a new set of test externalities.
|
||||
pub fn new_test_ext(state: GenesisConfig) -> TestExternalities {
|
||||
let mut t = state.system.build_storage::<Test>().unwrap();
|
||||
|
||||
@@ -23,12 +23,12 @@ 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;
|
||||
use frame_support::debug;
|
||||
use crate::{initializer, inclusion, scheduler, configuration, paras, dmp, hrmp};
|
||||
use crate::{initializer, inclusion, scheduler, configuration, paras, session_info, dmp, hrmp};
|
||||
|
||||
/// Implementation for the `validators` function of the runtime API.
|
||||
pub fn validators<T: initializer::Trait>() -> Vec<ValidatorId> {
|
||||
@@ -285,28 +285,9 @@ where
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// 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.
|
||||
// FIXME: handle previous sessions:
|
||||
// https://github.com/paritytech/polkadot/issues/1461
|
||||
pub fn validator_discovery<T>(validators: Vec<ValidatorId>) -> Vec<Option<AuthorityDiscoveryId>>
|
||||
where
|
||||
T: initializer::Trait + pallet_authority_discovery::Trait,
|
||||
{
|
||||
// FIXME: the mapping might be invalid if a session change happens in between the calls
|
||||
// use SessionInfo from https://github.com/paritytech/polkadot/pull/1691
|
||||
let current_validators = <inclusion::Module<T>>::validators();
|
||||
let authorities = <pallet_authority_discovery::Module<T>>::authorities();
|
||||
// We assume the same ordering in authorities as in validators so we can do an index search
|
||||
validators.iter().map(|id| {
|
||||
// FIXME: linear search is slow O(n^2)
|
||||
// use SessionInfo from https://github.com/paritytech/polkadot/pull/1691
|
||||
let validator_index = current_validators.iter().position(|v| v == id);
|
||||
validator_index.and_then(|i| authorities.get(i).cloned())
|
||||
}).collect()
|
||||
/// Get the session info for the given session, if stored.
|
||||
pub fn session_info<T: session_info::Trait>(index: SessionIndex) -> Option<SessionInfo> {
|
||||
<session_info::Module<T>>::session_info(index)
|
||||
}
|
||||
|
||||
/// Implementation for the `dmq_contents` function of the runtime API.
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
// Copyright 2020 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Polkadot is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! The session info module provides information about validator sets
|
||||
//! from prior sessions needed for approvals and disputes.
|
||||
//!
|
||||
//! See https://w3f.github.io/parachain-implementers-guide/runtime/session_info.html.
|
||||
|
||||
use primitives::v1::{AuthorityDiscoveryId, SessionIndex, SessionInfo};
|
||||
use frame_support::{
|
||||
decl_storage, decl_module, decl_error,
|
||||
weights::Weight,
|
||||
};
|
||||
use crate::{configuration, paras, scheduler};
|
||||
use sp_std::{cmp, vec::Vec};
|
||||
|
||||
pub trait Trait:
|
||||
frame_system::Trait
|
||||
+ configuration::Trait
|
||||
+ paras::Trait
|
||||
+ scheduler::Trait
|
||||
+ AuthorityDiscoveryTrait
|
||||
{
|
||||
}
|
||||
|
||||
decl_storage! {
|
||||
trait Store for Module<T: Trait> as ParaSessionInfo {
|
||||
/// The earliest session for which previous session info is stored.
|
||||
EarliestStoredSession get(fn earliest_stored_session): SessionIndex;
|
||||
/// Session information in a rolling window.
|
||||
/// Should have an entry in range `EarliestStoredSession..=CurrentSessionIndex`.
|
||||
/// Does not have any entries before the session index in the first session change notification.
|
||||
Sessions get(fn session_info): map hasher(identity) SessionIndex => Option<SessionInfo>;
|
||||
}
|
||||
}
|
||||
|
||||
decl_error! {
|
||||
pub enum Error for Module<T: Trait> { }
|
||||
}
|
||||
|
||||
decl_module! {
|
||||
/// The session info module.
|
||||
pub struct Module<T: Trait> for enum Call where origin: <T as frame_system::Trait>::Origin {
|
||||
type Error = Error<T>;
|
||||
}
|
||||
}
|
||||
|
||||
/// An abstraction for the authority discovery pallet
|
||||
/// to help with mock testing.
|
||||
pub trait AuthorityDiscoveryTrait {
|
||||
/// Retrieve authority identifiers of the current and next authority set.
|
||||
fn authorities() -> Vec<AuthorityDiscoveryId>;
|
||||
}
|
||||
|
||||
impl<T: pallet_authority_discovery::Trait> AuthorityDiscoveryTrait for T {
|
||||
fn authorities() -> Vec<AuthorityDiscoveryId> {
|
||||
<pallet_authority_discovery::Module<T>>::authorities()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Trait> Module<T> {
|
||||
/// Handle an incoming session change.
|
||||
pub(crate) fn initializer_on_new_session(
|
||||
notification: &crate::initializer::SessionChangeNotification<T::BlockNumber>
|
||||
) {
|
||||
let config = <configuration::Module<T>>::config();
|
||||
|
||||
let dispute_period = config.dispute_period;
|
||||
let n_parachains = <paras::Module<T>>::parachains().len() as u32;
|
||||
|
||||
let validators = notification.validators.clone();
|
||||
let discovery_keys = <T as AuthorityDiscoveryTrait>::authorities();
|
||||
// FIXME: once we store these keys: https://github.com/paritytech/polkadot/issues/1975
|
||||
let approval_keys = Default::default();
|
||||
let validator_groups = <scheduler::Module<T>>::validator_groups();
|
||||
let n_cores = n_parachains + config.parathread_cores;
|
||||
let zeroth_delay_tranche_width = config.zeroth_delay_tranche_width;
|
||||
let relay_vrf_modulo_samples = config.relay_vrf_modulo_samples;
|
||||
let n_delay_tranches = config.n_delay_tranches;
|
||||
let no_show_slots = config.no_show_slots;
|
||||
let needed_approvals = config.needed_approvals;
|
||||
|
||||
let new_session_index = notification.session_index;
|
||||
let old_earliest_stored_session = EarliestStoredSession::get();
|
||||
let dispute_period = cmp::max(1, dispute_period);
|
||||
let new_earliest_stored_session = new_session_index.checked_sub(dispute_period - 1).unwrap_or(0);
|
||||
let new_earliest_stored_session = cmp::max(new_earliest_stored_session, old_earliest_stored_session);
|
||||
// update `EarliestStoredSession` based on `config.dispute_period`
|
||||
EarliestStoredSession::set(new_earliest_stored_session);
|
||||
// remove all entries from `Sessions` from the previous value up to the new value
|
||||
for idx in old_earliest_stored_session..new_earliest_stored_session {
|
||||
Sessions::remove(&idx);
|
||||
}
|
||||
// create a new entry in `Sessions` with information about the current session
|
||||
let new_session_info = SessionInfo {
|
||||
validators,
|
||||
discovery_keys,
|
||||
approval_keys,
|
||||
validator_groups,
|
||||
n_cores,
|
||||
zeroth_delay_tranche_width,
|
||||
relay_vrf_modulo_samples,
|
||||
n_delay_tranches,
|
||||
no_show_slots,
|
||||
needed_approvals,
|
||||
};
|
||||
Sessions::insert(&new_session_index, &new_session_info);
|
||||
}
|
||||
|
||||
/// Called by the initializer to initialize the session info module.
|
||||
pub(crate) fn initializer_initialize(_now: T::BlockNumber) -> Weight {
|
||||
0
|
||||
}
|
||||
|
||||
/// Called by the initializer to finalize the session info module.
|
||||
pub(crate) fn initializer_finalize() {}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mock::{
|
||||
new_test_ext, Configuration, SessionInfo, System, GenesisConfig as MockGenesisConfig,
|
||||
Origin,
|
||||
};
|
||||
use crate::initializer::SessionChangeNotification;
|
||||
use crate::configuration::HostConfiguration;
|
||||
use frame_support::traits::{OnFinalize, OnInitialize};
|
||||
use primitives::v1::BlockNumber;
|
||||
|
||||
fn run_to_block(
|
||||
to: BlockNumber,
|
||||
new_session: impl Fn(BlockNumber) -> Option<SessionChangeNotification<BlockNumber>>,
|
||||
) {
|
||||
while System::block_number() < to {
|
||||
let b = System::block_number();
|
||||
|
||||
SessionInfo::initializer_finalize();
|
||||
Configuration::initializer_finalize();
|
||||
|
||||
System::on_finalize(b);
|
||||
|
||||
System::on_initialize(b + 1);
|
||||
System::set_block_number(b + 1);
|
||||
|
||||
if let Some(notification) = new_session(b + 1) {
|
||||
Configuration::initializer_on_new_session(¬ification.validators, ¬ification.queued);
|
||||
SessionInfo::initializer_on_new_session(¬ification);
|
||||
}
|
||||
|
||||
Configuration::initializer_initialize(b + 1);
|
||||
SessionInfo::initializer_initialize(b + 1);
|
||||
}
|
||||
}
|
||||
|
||||
fn default_config() -> HostConfiguration<BlockNumber> {
|
||||
HostConfiguration {
|
||||
parathread_cores: 1,
|
||||
dispute_period: 2,
|
||||
needed_approvals: 3,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn genesis_config() -> MockGenesisConfig {
|
||||
MockGenesisConfig {
|
||||
configuration: configuration::GenesisConfig {
|
||||
config: default_config(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn session_changes(n: BlockNumber) -> Option<SessionChangeNotification<BlockNumber>> {
|
||||
match n {
|
||||
100 => Some(SessionChangeNotification {
|
||||
session_index: 10,
|
||||
..Default::default()
|
||||
}),
|
||||
200 => Some(SessionChangeNotification {
|
||||
session_index: 20,
|
||||
..Default::default()
|
||||
}),
|
||||
300 => Some(SessionChangeNotification {
|
||||
session_index: 30,
|
||||
..Default::default()
|
||||
}),
|
||||
400 => Some(SessionChangeNotification {
|
||||
session_index: 40,
|
||||
..Default::default()
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn new_session_every_block(n: BlockNumber) -> Option<SessionChangeNotification<BlockNumber>> {
|
||||
Some(SessionChangeNotification{
|
||||
session_index: n,
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn session_pruning_is_based_on_dispute_deriod() {
|
||||
new_test_ext(genesis_config()).execute_with(|| {
|
||||
run_to_block(100, session_changes);
|
||||
assert_eq!(EarliestStoredSession::get(), 9);
|
||||
|
||||
// changing dispute_period works
|
||||
let dispute_period = 5;
|
||||
Configuration::set_dispute_period(Origin::root(), dispute_period).unwrap();
|
||||
run_to_block(200, session_changes);
|
||||
assert_eq!(EarliestStoredSession::get(), 20 - dispute_period + 1);
|
||||
|
||||
// we don't have that many sessions stored
|
||||
let new_dispute_period = 16;
|
||||
Configuration::set_dispute_period(Origin::root(), new_dispute_period).unwrap();
|
||||
run_to_block(300, session_changes);
|
||||
assert_eq!(EarliestStoredSession::get(), 20 - dispute_period + 1);
|
||||
|
||||
// now we do
|
||||
run_to_block(400, session_changes);
|
||||
assert_eq!(EarliestStoredSession::get(), 40 - new_dispute_period + 1);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn session_info_is_based_on_config() {
|
||||
new_test_ext(genesis_config()).execute_with(|| {
|
||||
run_to_block(1, new_session_every_block);
|
||||
let session = Sessions::get(&1).unwrap();
|
||||
assert_eq!(session.needed_approvals, 3);
|
||||
|
||||
// change some param
|
||||
Configuration::set_needed_approvals(Origin::root(), 42).unwrap();
|
||||
run_to_block(2, new_session_every_block);
|
||||
let session = Sessions::get(&2).unwrap();
|
||||
assert_eq!(session.needed_approvals, 42);
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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<SessionInfo> {
|
||||
None
|
||||
}
|
||||
|
||||
fn validation_code(_: Id, _: OccupiedCoreAssumption) -> Option<ValidationCode> {
|
||||
None
|
||||
}
|
||||
@@ -1102,10 +1106,6 @@ sp_api::impl_runtime_apis! {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn validator_discovery(_: Vec<ValidatorId>) -> Vec<Option<AuthorityDiscoveryId>> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn dmq_contents(
|
||||
_recipient: Id,
|
||||
) -> Vec<InboundDownwardMessage<BlockNumber>> {
|
||||
|
||||
@@ -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,
|
||||
@@ -72,6 +72,7 @@ use runtime_parachains::configuration as parachains_configuration;
|
||||
use runtime_parachains::inclusion as parachains_inclusion;
|
||||
use runtime_parachains::inclusion_inherent as parachains_inclusion_inherent;
|
||||
use runtime_parachains::initializer as parachains_initializer;
|
||||
use runtime_parachains::session_info as parachains_session_info;
|
||||
use runtime_parachains::paras as parachains_paras;
|
||||
use runtime_parachains::dmp as parachains_dmp;
|
||||
use runtime_parachains::ump as parachains_ump;
|
||||
@@ -536,6 +537,8 @@ impl parachains_paras::Trait for Runtime {
|
||||
type Origin = Origin;
|
||||
}
|
||||
|
||||
impl parachains_session_info::Trait for Runtime {}
|
||||
|
||||
impl parachains_ump::Trait for Runtime {
|
||||
type UmpSink = (); // TODO: #1873 To be handled by the XCM receiver.
|
||||
}
|
||||
@@ -688,8 +691,9 @@ sp_api::impl_runtime_apis! {
|
||||
}
|
||||
})
|
||||
}
|
||||
fn validator_discovery(validators: Vec<ValidatorId>) -> Vec<Option<AuthorityDiscoveryId>> {
|
||||
runtime_api_impl::validator_discovery::<Runtime>(validators)
|
||||
|
||||
fn session_info(index: SessionIndex) -> Option<SessionInfo> {
|
||||
runtime_api_impl::session_info::<Runtime>(index)
|
||||
}
|
||||
|
||||
fn dmq_contents(recipient: Id) -> Vec<InboundDownwardMessage<BlockNumber>> {
|
||||
|
||||
@@ -29,6 +29,7 @@ use polkadot_runtime_parachains::configuration as parachains_configuration;
|
||||
use polkadot_runtime_parachains::inclusion as parachains_inclusion;
|
||||
use polkadot_runtime_parachains::inclusion_inherent as parachains_inclusion_inherent;
|
||||
use polkadot_runtime_parachains::initializer as parachains_initializer;
|
||||
use polkadot_runtime_parachains::session_info as parachains_session_info;
|
||||
use polkadot_runtime_parachains::paras as parachains_paras;
|
||||
use polkadot_runtime_parachains::dmp as parachains_dmp;
|
||||
use polkadot_runtime_parachains::ump as parachains_ump;
|
||||
@@ -40,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,
|
||||
@@ -457,6 +458,8 @@ impl parachains_initializer::Trait for Runtime {
|
||||
type Randomness = RandomnessCollectiveFlip;
|
||||
}
|
||||
|
||||
impl parachains_session_info::Trait for Runtime {}
|
||||
|
||||
impl parachains_paras::Trait for Runtime {
|
||||
type Origin = Origin;
|
||||
}
|
||||
@@ -678,8 +681,8 @@ sp_api::impl_runtime_apis! {
|
||||
runtime_impl::candidate_events::<Runtime, _>(|trait_event| trait_event.try_into().ok())
|
||||
}
|
||||
|
||||
fn validator_discovery(validators: Vec<ValidatorId>) -> Vec<Option<AuthorityDiscoveryId>> {
|
||||
runtime_impl::validator_discovery::<Runtime>(validators)
|
||||
fn session_info(index: SessionIndex) -> Option<SessionInfo> {
|
||||
runtime_impl::session_info::<Runtime>(index)
|
||||
}
|
||||
|
||||
fn dmq_contents(
|
||||
|
||||
@@ -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<SessionInfo> {
|
||||
None
|
||||
}
|
||||
|
||||
fn validation_code(_: Id, _: OccupiedCoreAssumption) -> Option<ValidationCode> {
|
||||
None
|
||||
}
|
||||
@@ -852,10 +856,6 @@ sp_api::impl_runtime_apis! {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn validator_discovery(_: Vec<ValidatorId>) -> Vec<Option<AuthorityDiscoveryId>> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn dmq_contents(
|
||||
_recipient: Id,
|
||||
) -> Vec<InboundDownwardMessage<BlockNumber>> {
|
||||
|
||||
Reference in New Issue
Block a user