Unverified Commit ed759c75 authored by Sergey Pepyakin's avatar Sergey Pepyakin Committed by GitHub
Browse files

Downward Message Processing implementation (#1859)

* DMP: data structures and plumbing

* DMP: Implement DMP logic in the router module

DMP: Integrate DMP parts into the inclusion module

* DMP: Introduce the max size limit for the size of a downward message

* DMP: Runtime API for accessing inbound messages

* OCD

Small clean ups

* DMP: fix the naming of the error

* DMP: add caution about a non-existent recipient
parent 798f781f
Pipeline #112381 failed with stages
in 9 minutes and 18 seconds
...@@ -79,20 +79,19 @@ pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; ...@@ -79,20 +79,19 @@ pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;
/// the parachain. /// the parachain.
pub type Remark = [u8; 32]; pub type Remark = [u8; 32];
/// These are special "control" messages that can be passed from the Relaychain to a parachain. /// A message sent from the relay-chain down to a parachain.
/// They should be handled by all parachains. ///
/// The size of the message is limited by the `config.max_downward_message_size` parameter.
pub type DownwardMessage = sp_std::vec::Vec<u8>;
/// A wrapped version of `DownwardMessage`. The difference is that it has attached the block number when
/// the message was sent.
#[derive(codec::Encode, codec::Decode, Clone, sp_runtime::RuntimeDebug, PartialEq)] #[derive(codec::Encode, codec::Decode, Clone, sp_runtime::RuntimeDebug, PartialEq)]
pub enum DownwardMessage<AccountId = crate::AccountId> { pub struct InboundDownwardMessage<BlockNumber = crate::BlockNumber> {
/// Some funds were transferred into the parachain's account. The hash is the identifier that /// The block number at which this messages was put into the downward message queue.
/// was given with the transfer. pub sent_at: BlockNumber,
TransferInto(AccountId, Balance, Remark), /// The actual downward message to processes.
/// An opaque blob of data. The relay chain must somehow know how to form this so that the pub msg: DownwardMessage,
/// destination parachain does something sensible.
///
/// NOTE: Be very careful not to allow users to place arbitrary size information in here.
Opaque(sp_std::vec::Vec<u8>),
/// XCMP message for the Parachain.
XCMPMessage(sp_std::vec::Vec<u8>),
} }
/// V1 primitives. /// V1 primitives.
......
...@@ -277,6 +277,7 @@ async fn handle_new_activations<Context: SubsystemContext>( ...@@ -277,6 +277,7 @@ async fn handle_new_activations<Context: SubsystemContext>(
new_validation_code: collation.new_validation_code, new_validation_code: collation.new_validation_code,
head_data: collation.head_data, head_data: collation.head_data,
erasure_root, erasure_root,
processed_downward_messages: collation.processed_downward_messages,
}; };
let ccr = CandidateReceipt { let ccr = CandidateReceipt {
...@@ -387,6 +388,7 @@ mod tests { ...@@ -387,6 +388,7 @@ mod tests {
proof_of_validity: PoV { proof_of_validity: PoV {
block_data: BlockData(Vec::new()), block_data: BlockData(Vec::new()),
}, },
processed_downward_messages: Default::default(),
} }
} }
......
...@@ -70,6 +70,7 @@ impl Default for TestState { ...@@ -70,6 +70,7 @@ impl Default for TestState {
parent_head: HeadData(vec![7, 8, 9]), parent_head: HeadData(vec![7, 8, 9]),
block_number: 5, block_number: 5,
hrmp_mqc_heads: Vec::new(), hrmp_mqc_heads: Vec::new(),
dmq_mqc_head: Default::default(),
}; };
let pruning_config = PruningConfig { let pruning_config = PruningConfig {
......
...@@ -682,6 +682,7 @@ impl CandidateBackingJob { ...@@ -682,6 +682,7 @@ impl CandidateBackingJob {
erasure_root, erasure_root,
new_validation_code: outputs.new_validation_code, new_validation_code: outputs.new_validation_code,
head_data: outputs.head_data, head_data: outputs.head_data,
processed_downward_messages: outputs.processed_downward_messages,
}; };
let res = match with_commitments(commitments) { let res = match with_commitments(commitments) {
...@@ -977,12 +978,14 @@ mod tests { ...@@ -977,12 +978,14 @@ mod tests {
parent_head: HeadData(vec![7, 8, 9]), parent_head: HeadData(vec![7, 8, 9]),
block_number: Default::default(), block_number: Default::default(),
hrmp_mqc_heads: Vec::new(), hrmp_mqc_heads: Vec::new(),
dmq_mqc_head: Default::default(),
}, },
transient: TransientValidationData { transient: TransientValidationData {
max_code_size: 1000, max_code_size: 1000,
max_head_data_size: 1000, max_head_data_size: 1000,
balance: Default::default(), balance: Default::default(),
code_upgrade_allowed: None, code_upgrade_allowed: None,
dmq_length: 0,
}, },
}; };
...@@ -1159,6 +1162,7 @@ mod tests { ...@@ -1159,6 +1162,7 @@ mod tests {
upward_messages: Vec::new(), upward_messages: Vec::new(),
fees: Default::default(), fees: Default::default(),
new_validation_code: None, new_validation_code: None,
processed_downward_messages: 0,
}, test_state.validation_data.persisted), }, test_state.validation_data.persisted),
)).unwrap(); )).unwrap();
} }
...@@ -1278,6 +1282,7 @@ mod tests { ...@@ -1278,6 +1282,7 @@ mod tests {
upward_messages: Vec::new(), upward_messages: Vec::new(),
fees: Default::default(), fees: Default::default(),
new_validation_code: None, new_validation_code: None,
processed_downward_messages: 0,
}, test_state.validation_data.persisted), }, test_state.validation_data.persisted),
)).unwrap(); )).unwrap();
} }
...@@ -1416,6 +1421,7 @@ mod tests { ...@@ -1416,6 +1421,7 @@ mod tests {
upward_messages: Vec::new(), upward_messages: Vec::new(),
fees: Default::default(), fees: Default::default(),
new_validation_code: None, new_validation_code: None,
processed_downward_messages: 0,
}, test_state.validation_data.persisted), }, test_state.validation_data.persisted),
)).unwrap(); )).unwrap();
} }
...@@ -1571,6 +1577,7 @@ mod tests { ...@@ -1571,6 +1577,7 @@ mod tests {
upward_messages: Vec::new(), upward_messages: Vec::new(),
fees: Default::default(), fees: Default::default(),
new_validation_code: None, new_validation_code: None,
processed_downward_messages: 0,
}, test_state.validation_data.persisted), }, test_state.validation_data.persisted),
)).unwrap(); )).unwrap();
} }
......
...@@ -494,11 +494,13 @@ mod tests { ...@@ -494,11 +494,13 @@ mod tests {
upward_messages: Vec::new(), upward_messages: Vec::new(),
fees: 0, fees: 0,
new_validation_code: None, new_validation_code: None,
processed_downward_messages: 0,
}, },
PersistedValidationData { PersistedValidationData {
parent_head: HeadData(parent_head_data), parent_head: HeadData(parent_head_data),
block_number: 123, block_number: 123,
hrmp_mqc_heads: Vec::new(), hrmp_mqc_heads: Vec::new(),
dmq_mqc_head: Default::default(),
}, },
) )
} }
......
...@@ -468,6 +468,7 @@ fn validate_candidate_exhaustive<B: ValidationBackend, S: SpawnNamed + 'static>( ...@@ -468,6 +468,7 @@ fn validate_candidate_exhaustive<B: ValidationBackend, S: SpawnNamed + 'static>(
parent_head: persisted_validation_data.parent_head.clone(), parent_head: persisted_validation_data.parent_head.clone(),
block_data: pov.block_data.clone(), block_data: pov.block_data.clone(),
relay_chain_height: persisted_validation_data.block_number, relay_chain_height: persisted_validation_data.block_number,
dmq_mqc_head: persisted_validation_data.dmq_mqc_head,
hrmp_mqc_heads: persisted_validation_data.hrmp_mqc_heads.clone(), hrmp_mqc_heads: persisted_validation_data.hrmp_mqc_heads.clone(),
}; };
...@@ -491,6 +492,7 @@ fn validate_candidate_exhaustive<B: ValidationBackend, S: SpawnNamed + 'static>( ...@@ -491,6 +492,7 @@ fn validate_candidate_exhaustive<B: ValidationBackend, S: SpawnNamed + 'static>(
upward_messages: res.upward_messages, upward_messages: res.upward_messages,
fees: 0, fees: 0,
new_validation_code: res.new_validation_code, new_validation_code: res.new_validation_code,
processed_downward_messages: res.processed_downward_messages,
}; };
Ok(ValidationResult::Valid(outputs, persisted_validation_data)) Ok(ValidationResult::Valid(outputs, persisted_validation_data))
} }
......
...@@ -127,6 +127,7 @@ fn make_runtime_api_request<Client>( ...@@ -127,6 +127,7 @@ fn make_runtime_api_request<Client>(
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::ValidatorDiscovery(ids, sender) => query!(validator_discovery(ids), sender),
Request::DmqContents(id, sender) => query!(dmq_contents(id), sender),
} }
} }
...@@ -176,7 +177,7 @@ mod tests { ...@@ -176,7 +177,7 @@ 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, CommittedCandidateReceipt, CandidateEvent, AuthorityDiscoveryId, InboundDownwardMessage,
}; };
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;
...@@ -195,6 +196,7 @@ mod tests { ...@@ -195,6 +196,7 @@ mod tests {
validation_outputs_results: HashMap<ParaId, bool>, validation_outputs_results: HashMap<ParaId, bool>,
candidate_pending_availability: HashMap<ParaId, CommittedCandidateReceipt>, candidate_pending_availability: HashMap<ParaId, CommittedCandidateReceipt>,
candidate_events: Vec<CandidateEvent>, candidate_events: Vec<CandidateEvent>,
dmq_contents: HashMap<ParaId, Vec<InboundDownwardMessage>>,
} }
impl ProvideRuntimeApi<Block> for MockRuntimeApi { impl ProvideRuntimeApi<Block> for MockRuntimeApi {
...@@ -283,6 +285,13 @@ mod tests { ...@@ -283,6 +285,13 @@ mod tests {
fn validator_discovery(ids: Vec<ValidatorId>) -> Vec<Option<AuthorityDiscoveryId>> { fn validator_discovery(ids: Vec<ValidatorId>) -> Vec<Option<AuthorityDiscoveryId>> {
vec![None; ids.len()] vec![None; ids.len()]
} }
fn dmq_contents(
&self,
recipient: ParaId,
) -> Vec<polkadot_primitives::v1::InboundDownwardMessage> {
self.dmq_contents.get(&recipient).map(|q| q.clone()).unwrap_or_default()
}
} }
} }
...@@ -619,4 +628,54 @@ mod tests { ...@@ -619,4 +628,54 @@ 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_dmq_contents() {
let (ctx, mut ctx_handle) = test_helpers::make_subsystem_context(TaskExecutor::new());
let mut runtime_api = MockRuntimeApi::default();
let relay_parent = [1; 32].into();
let para_a = 5.into();
let para_b = 6.into();
runtime_api.dmq_contents.insert(para_a, vec![]);
runtime_api.dmq_contents.insert(
para_b,
vec![InboundDownwardMessage {
sent_at: 228,
msg: b"Novus Ordo Seclorum".to_vec(),
}],
);
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::DmqContents(para_a, tx)),
})
.await;
assert_eq!(rx.await.unwrap().unwrap(), vec![]);
let (tx, rx) = oneshot::channel();
ctx_handle
.send(FromOverseer::Communication {
msg: RuntimeApiMessage::Request(relay_parent, Request::DmqContents(para_b, tx)),
})
.await;
assert_eq!(
rx.await.unwrap().unwrap(),
vec![InboundDownwardMessage {
sent_at: 228,
msg: b"Novus Ordo Seclorum".to_vec(),
}]
);
ctx_handle
.send(FromOverseer::Signal(OverseerSignal::Conclude))
.await;
};
futures::executor::block_on(future::join(subsystem_task, test_task));
}
} }
...@@ -217,6 +217,7 @@ impl Default for TestState { ...@@ -217,6 +217,7 @@ impl Default for TestState {
parent_head: HeadData(vec![7, 8, 9]), parent_head: HeadData(vec![7, 8, 9]),
block_number: Default::default(), block_number: Default::default(),
hrmp_mqc_heads: Vec::new(), hrmp_mqc_heads: Vec::new(),
dmq_mqc_head: Default::default(),
}; };
let validator_index = Some((validators.len() - 1) as ValidatorIndex); let validator_index = Some((validators.len() - 1) as ValidatorIndex);
......
...@@ -263,6 +263,8 @@ pub struct Collation { ...@@ -263,6 +263,8 @@ pub struct Collation {
pub head_data: HeadData, pub head_data: HeadData,
/// Proof to verify the state transition of the parachain. /// Proof to verify the state transition of the parachain.
pub proof_of_validity: PoV, pub proof_of_validity: PoV,
/// The number of messages processed from the DMQ.
pub processed_downward_messages: u32,
} }
/// Configuration for the collation generator /// Configuration for the collation generator
......
...@@ -37,7 +37,7 @@ use polkadot_primitives::v1::{ ...@@ -37,7 +37,7 @@ use polkadot_primitives::v1::{
GroupRotationInfo, Hash, Id as ParaId, OccupiedCoreAssumption, GroupRotationInfo, Hash, Id as ParaId, OccupiedCoreAssumption,
PersistedValidationData, PoV, SessionIndex, SignedAvailabilityBitfield, PersistedValidationData, PoV, SessionIndex, SignedAvailabilityBitfield,
ValidationCode, ValidatorId, ValidationData, ValidationCode, ValidatorId, ValidationData,
ValidatorIndex, ValidatorSignature, ValidatorIndex, ValidatorSignature, InboundDownwardMessage,
}; };
use std::sync::Arc; use std::sync::Arc;
...@@ -419,7 +419,11 @@ pub enum RuntimeApiRequest { ...@@ -419,7 +419,11 @@ pub enum RuntimeApiRequest {
/// Get the validation code for a para, taking the given `OccupiedCoreAssumption`, which /// Get the validation code for a para, taking the given `OccupiedCoreAssumption`, which
/// will inform on how the validation data should be computed if the para currently /// will inform on how the validation data should be computed if the para currently
/// occupies a core. /// occupies a core.
ValidationCode(ParaId, OccupiedCoreAssumption, RuntimeApiSender<Option<ValidationCode>>), ValidationCode(
ParaId,
OccupiedCoreAssumption,
RuntimeApiSender<Option<ValidationCode>>,
),
/// Get a the candidate pending availability for a particular parachain by parachain / core index /// Get a the candidate pending availability for a particular parachain by parachain / core index
CandidatePendingAvailability(ParaId, RuntimeApiSender<Option<CommittedCandidateReceipt>>), CandidatePendingAvailability(ParaId, RuntimeApiSender<Option<CommittedCandidateReceipt>>),
/// Get all events concerning candidates (backing, inclusion, time-out) in the parent of /// Get all events concerning candidates (backing, inclusion, time-out) in the parent of
...@@ -429,7 +433,15 @@ pub enum RuntimeApiRequest { ...@@ -429,7 +433,15 @@ pub enum RuntimeApiRequest {
/// Currently this request is limited to validators in the current session. /// Currently this request is limited to validators in the current session.
/// ///
/// Returns `None` for validators not found in the current session. /// Returns `None` for validators not found in the current session.
ValidatorDiscovery(Vec<ValidatorId>, RuntimeApiSender<Vec<Option<AuthorityDiscoveryId>>>), ValidatorDiscovery(
Vec<ValidatorId>,
RuntimeApiSender<Vec<Option<AuthorityDiscoveryId>>>,
),
/// Get all the pending inbound messages in the downward message queue for a para.
DmqContents(
ParaId,
RuntimeApiSender<Vec<InboundDownwardMessage<BlockNumber>>>,
),
} }
/// A message to the Runtime API subsystem. /// A message to the Runtime API subsystem.
......
...@@ -248,6 +248,11 @@ pub struct ValidationParams { ...@@ -248,6 +248,11 @@ pub struct ValidationParams {
pub block_data: BlockData, pub block_data: BlockData,
/// The current relay-chain block number. /// The current relay-chain block number.
pub relay_chain_height: RelayChainBlockNumber, pub relay_chain_height: RelayChainBlockNumber,
/// The MQC head for the DMQ.
///
/// The DMQ MQC head will be used by the validation function to authorize the downward messages
/// passed by the collator.
pub dmq_mqc_head: Hash,
/// The list of MQC heads for the inbound HRMP channels paired with the sender para ids. This /// The list of MQC heads for the inbound HRMP channels paired with the sender para ids. This
/// vector is sorted ascending by the para id and doesn't contain multiple entries with the same /// vector is sorted ascending by the para id and doesn't contain multiple entries with the same
/// sender. /// sender.
......
...@@ -97,6 +97,7 @@ fn execute_good_on_parent(execution_mode: ExecutionMode) { ...@@ -97,6 +97,7 @@ fn execute_good_on_parent(execution_mode: ExecutionMode) {
block_data: GenericBlockData(block_data.encode()), block_data: GenericBlockData(block_data.encode()),
relay_chain_height: 1, relay_chain_height: 1,
hrmp_mqc_heads: Vec::new(), hrmp_mqc_heads: Vec::new(),
dmq_mqc_head: Default::default(),
}, },
&execution_mode, &execution_mode,
sp_core::testing::TaskExecutor::new(), sp_core::testing::TaskExecutor::new(),
...@@ -135,6 +136,7 @@ fn execute_good_chain_on_parent() { ...@@ -135,6 +136,7 @@ fn execute_good_chain_on_parent() {
block_data: GenericBlockData(block_data.encode()), block_data: GenericBlockData(block_data.encode()),
relay_chain_height: number as RelayChainBlockNumber + 1, relay_chain_height: number as RelayChainBlockNumber + 1,
hrmp_mqc_heads: Vec::new(), hrmp_mqc_heads: Vec::new(),
dmq_mqc_head: Default::default(),
}, },
&execution_mode, &execution_mode,
sp_core::testing::TaskExecutor::new(), sp_core::testing::TaskExecutor::new(),
...@@ -174,6 +176,7 @@ fn execute_bad_on_parent() { ...@@ -174,6 +176,7 @@ fn execute_bad_on_parent() {
block_data: GenericBlockData(block_data.encode()), block_data: GenericBlockData(block_data.encode()),
relay_chain_height: 1, relay_chain_height: 1,
hrmp_mqc_heads: Vec::new(), hrmp_mqc_heads: Vec::new(),
dmq_mqc_head: Default::default(),
}, },
&execution_mode, &execution_mode,
sp_core::testing::TaskExecutor::new(), sp_core::testing::TaskExecutor::new(),
......
...@@ -43,6 +43,7 @@ fn terminates_on_timeout() { ...@@ -43,6 +43,7 @@ fn terminates_on_timeout() {
parent_head: Default::default(), parent_head: Default::default(),
relay_chain_height: 1, relay_chain_height: 1,
hrmp_mqc_heads: Vec::new(), hrmp_mqc_heads: Vec::new(),
dmq_mqc_head: Default::default(),
}, },
&execution_mode, &execution_mode,
sp_core::testing::TaskExecutor::new(), sp_core::testing::TaskExecutor::new(),
...@@ -71,6 +72,7 @@ fn parallel_execution() { ...@@ -71,6 +72,7 @@ fn parallel_execution() {
parent_head: Default::default(), parent_head: Default::default(),
relay_chain_height: 1, relay_chain_height: 1,
hrmp_mqc_heads: Vec::new(), hrmp_mqc_heads: Vec::new(),
dmq_mqc_head: Default::default(),
}, },
&execution_mode, &execution_mode,
sp_core::testing::TaskExecutor::new(), sp_core::testing::TaskExecutor::new(),
...@@ -82,6 +84,7 @@ fn parallel_execution() { ...@@ -82,6 +84,7 @@ fn parallel_execution() {
parent_head: Default::default(), parent_head: Default::default(),
relay_chain_height: 1, relay_chain_height: 1,
hrmp_mqc_heads: Vec::new(), hrmp_mqc_heads: Vec::new(),
dmq_mqc_head: Default::default(),
}, },
&execution_mode2, &execution_mode2,
sp_core::testing::TaskExecutor::new(), sp_core::testing::TaskExecutor::new(),
......
...@@ -31,7 +31,7 @@ pub use runtime_primitives::traits::{BlakeTwo256, Hash as HashT}; ...@@ -31,7 +31,7 @@ pub use runtime_primitives::traits::{BlakeTwo256, Hash as HashT};
pub use polkadot_core_primitives::v1::{ pub use polkadot_core_primitives::v1::{
BlockNumber, Moment, Signature, AccountPublic, AccountId, AccountIndex, BlockNumber, Moment, Signature, AccountPublic, AccountId, AccountIndex,
ChainId, Hash, Nonce, Balance, Header, Block, BlockId, UncheckedExtrinsic, ChainId, Hash, Nonce, Balance, Header, Block, BlockId, UncheckedExtrinsic,
Remark, DownwardMessage, Remark, DownwardMessage, InboundDownwardMessage,
}; };
// Export some polkadot-parachain primitives // Export some polkadot-parachain primitives
...@@ -266,6 +266,11 @@ pub struct PersistedValidationData<N = BlockNumber> { ...@@ -266,6 +266,11 @@ pub struct PersistedValidationData<N = BlockNumber> {
/// vector is sorted ascending by the para id and doesn't contain multiple entries with the same /// vector is sorted ascending by the para id and doesn't contain multiple entries with the same
/// sender. /// sender.
pub hrmp_mqc_heads: Vec<(Id, Hash)>, pub hrmp_mqc_heads: Vec<(Id, Hash)>,
/// The MQC head for the DMQ.
///
/// The DMQ MQC head will be used by the validation function to authorize the downward messages
/// passed by the collator.
pub dmq_mqc_head: Hash,
} }
impl<N: Encode> PersistedValidationData<N> { impl<N: Encode> PersistedValidationData<N> {
...@@ -301,6 +306,8 @@ pub struct TransientValidationData<N = BlockNumber> { ...@@ -301,6 +306,8 @@ pub struct TransientValidationData<N = BlockNumber> {
/// which case the code upgrade should be applied at the end of the signaling /// which case the code upgrade should be applied at the end of the signaling
/// block. /// block.
pub code_upgrade_allowed: Option<N>, pub code_upgrade_allowed: Option<N>,
/// The number of messages pending of the downward message queue.
pub dmq_length: u32,
} }
/// Outputs of validating a candidate. /// Outputs of validating a candidate.
...@@ -315,6 +322,8 @@ pub struct ValidationOutputs { ...@@ -315,6 +322,8 @@ pub struct ValidationOutputs {
pub fees: Balance, pub fees: Balance,
/// The new validation code submitted by the execution, if any. /// The new validation code submitted by the execution, if any.
pub new_validation_code: Option<ValidationCode>, pub new_validation_code: Option<ValidationCode>,
/// The number of messages processed from the DMQ.
pub processed_downward_messages: u32,
} }
/// Commitments made in a `CandidateReceipt`. Many of these are outputs of validation. /// Commitments made in a `CandidateReceipt`. Many of these are outputs of validation.
...@@ -331,6 +340,8 @@ pub struct CandidateCommitments { ...@@ -331,6 +340,8 @@ pub struct CandidateCommitments {
pub new_validation_code: Option<ValidationCode>, pub new_validation_code: Option<ValidationCode>,
/// The head-data produced as a result of execution. /// The head-data produced as a result of execution.
pub head_data: HeadData, pub head_data: HeadData,
/// The number of messages processed from the DMQ.
pub processed_downward_messages: u32,
} }
impl CandidateCommitments { impl CandidateCommitments {
...@@ -712,6 +723,11 @@ sp_api::decl_runtime_apis! { ...@@ -712,6 +723,11 @@ sp_api::decl_runtime_apis! {
/// We assume that every validator runs authority discovery, /// We assume that every validator runs authority discovery,
/// which would allow us to establish point-to-point connection to given validators. /// which would allow us to establish point-to-point connection to given validators.
fn validator_discovery(validators: Vec<ValidatorId>) -> Vec<Option<AuthorityDiscoveryId>>; 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,
) -> Vec<InboundDownwardMessage<N>>;
} }
} }
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
#![recursion_limit="256"] #![recursion_limit = "256"]