mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-20 22:05:42 +00:00
Implement HRMP (#1900)
* HRMP: Update the impl guide * HRMP: Incorporate the channel notifications into the guide * HRMP: Renaming in the impl guide * HRMP: Constrain the maximum number of HRMP messages per candidate This commit addresses the HRMP part of https://github.com/paritytech/polkadot/issues/1869 * XCM: Introduce HRMP related message types * HRMP: Data structures and plumbing * HRMP: Configuration * HRMP: Data layout * HRMP: Acceptance & Enactment * HRMP: Test base logic * Update adder collator * HRMP: Runtime API for accessing inbound messages Also, removing some redundant fully-qualified names. * HRMP: Add diagnostic logging in acceptance criteria * HRMP: Additional tests * Self-review fixes * save test refactorings for the next time * Missed a return statement. * a formatting blip * Add missing logic for appending HRMP digests * Remove the channel contents vectors which became empty * Tighten HRMP channel digests invariants. * Apply suggestions from code review Co-authored-by: Peter Goodspeed-Niklaus <coriolinus@users.noreply.github.com> * Remove a note about sorting for channel id * Add missing rustdocs to the configuration * Clarify and update the invariant for HrmpChannelDigests * Make the onboarding invariant less sloppy Namely, introduce `Paras::is_valid_para` (in fact, it already is present in the implementation) and hook up the invariant to that. Note that this says "within a session" because I don't want to make it super strict on the session boundary. The logic on the session boundary should be extremely careful. * Make `CandidateCheckContext` use T::BlockNumber for hrmp_watermark Co-authored-by: Peter Goodspeed-Niklaus <coriolinus@users.noreply.github.com>
This commit is contained in:
Generated
+1
@@ -5478,6 +5478,7 @@ dependencies = [
|
|||||||
"sp-std",
|
"sp-std",
|
||||||
"sp-trie",
|
"sp-trie",
|
||||||
"sp-version",
|
"sp-version",
|
||||||
|
"xcm",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -102,6 +102,26 @@ pub struct InboundDownwardMessage<BlockNumber = crate::BlockNumber> {
|
|||||||
pub msg: DownwardMessage,
|
pub msg: DownwardMessage,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An HRMP message seen from the perspective of a recipient.
|
||||||
|
#[derive(codec::Encode, codec::Decode, Clone, sp_runtime::RuntimeDebug, PartialEq)]
|
||||||
|
pub struct InboundHrmpMessage<BlockNumber = crate::BlockNumber> {
|
||||||
|
/// The block number at which this message was sent.
|
||||||
|
/// Specifically, it is the block number at which the candidate that sends this message was
|
||||||
|
/// enacted.
|
||||||
|
pub sent_at: BlockNumber,
|
||||||
|
/// The message payload.
|
||||||
|
pub data: sp_std::vec::Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An HRMP message seen from the perspective of a sender.
|
||||||
|
#[derive(codec::Encode, codec::Decode, Clone, sp_runtime::RuntimeDebug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct OutboundHrmpMessage<Id> {
|
||||||
|
/// The para that will get this message in its downward message queue.
|
||||||
|
pub recipient: Id,
|
||||||
|
/// The message payload.
|
||||||
|
pub data: sp_std::vec::Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
/// V1 primitives.
|
/// V1 primitives.
|
||||||
pub mod v1 {
|
pub mod v1 {
|
||||||
pub use super::*;
|
pub use super::*;
|
||||||
|
|||||||
@@ -274,10 +274,12 @@ async fn handle_new_activations<Context: SubsystemContext>(
|
|||||||
|
|
||||||
let commitments = CandidateCommitments {
|
let commitments = CandidateCommitments {
|
||||||
upward_messages: collation.upward_messages,
|
upward_messages: collation.upward_messages,
|
||||||
|
horizontal_messages: collation.horizontal_messages,
|
||||||
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,
|
processed_downward_messages: collation.processed_downward_messages,
|
||||||
|
hrmp_watermark: collation.hrmp_watermark,
|
||||||
};
|
};
|
||||||
|
|
||||||
let ccr = CandidateReceipt {
|
let ccr = CandidateReceipt {
|
||||||
@@ -382,12 +384,14 @@ mod tests {
|
|||||||
fn test_collation() -> Collation {
|
fn test_collation() -> Collation {
|
||||||
Collation {
|
Collation {
|
||||||
upward_messages: Default::default(),
|
upward_messages: Default::default(),
|
||||||
|
horizontal_messages: Default::default(),
|
||||||
new_validation_code: Default::default(),
|
new_validation_code: Default::default(),
|
||||||
head_data: Default::default(),
|
head_data: Default::default(),
|
||||||
proof_of_validity: PoV {
|
proof_of_validity: PoV {
|
||||||
block_data: BlockData(Vec::new()),
|
block_data: BlockData(Vec::new()),
|
||||||
},
|
},
|
||||||
processed_downward_messages: Default::default(),
|
processed_downward_messages: Default::default(),
|
||||||
|
hrmp_watermark: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -726,10 +726,12 @@ impl CandidateBackingJob {
|
|||||||
|
|
||||||
let commitments = CandidateCommitments {
|
let commitments = CandidateCommitments {
|
||||||
upward_messages: outputs.upward_messages,
|
upward_messages: outputs.upward_messages,
|
||||||
|
horizontal_messages: outputs.horizontal_messages,
|
||||||
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,
|
processed_downward_messages: outputs.processed_downward_messages,
|
||||||
|
hrmp_watermark: outputs.hrmp_watermark,
|
||||||
};
|
};
|
||||||
|
|
||||||
let res = match with_commitments(commitments) {
|
let res = match with_commitments(commitments) {
|
||||||
@@ -1209,9 +1211,11 @@ mod tests {
|
|||||||
tx.send(Ok(
|
tx.send(Ok(
|
||||||
ValidationResult::Valid(ValidationOutputs {
|
ValidationResult::Valid(ValidationOutputs {
|
||||||
head_data: expected_head_data.clone(),
|
head_data: expected_head_data.clone(),
|
||||||
|
horizontal_messages: Vec::new(),
|
||||||
upward_messages: Vec::new(),
|
upward_messages: Vec::new(),
|
||||||
new_validation_code: None,
|
new_validation_code: None,
|
||||||
processed_downward_messages: 0,
|
processed_downward_messages: 0,
|
||||||
|
hrmp_watermark: 0,
|
||||||
}, test_state.validation_data.persisted),
|
}, test_state.validation_data.persisted),
|
||||||
)).unwrap();
|
)).unwrap();
|
||||||
}
|
}
|
||||||
@@ -1346,8 +1350,10 @@ mod tests {
|
|||||||
ValidationResult::Valid(ValidationOutputs {
|
ValidationResult::Valid(ValidationOutputs {
|
||||||
head_data: expected_head_data.clone(),
|
head_data: expected_head_data.clone(),
|
||||||
upward_messages: Vec::new(),
|
upward_messages: Vec::new(),
|
||||||
|
horizontal_messages: Vec::new(),
|
||||||
new_validation_code: None,
|
new_validation_code: None,
|
||||||
processed_downward_messages: 0,
|
processed_downward_messages: 0,
|
||||||
|
hrmp_watermark: 0,
|
||||||
}, test_state.validation_data.persisted),
|
}, test_state.validation_data.persisted),
|
||||||
)).unwrap();
|
)).unwrap();
|
||||||
}
|
}
|
||||||
@@ -1495,8 +1501,10 @@ mod tests {
|
|||||||
ValidationResult::Valid(ValidationOutputs {
|
ValidationResult::Valid(ValidationOutputs {
|
||||||
head_data: expected_head_data.clone(),
|
head_data: expected_head_data.clone(),
|
||||||
upward_messages: Vec::new(),
|
upward_messages: Vec::new(),
|
||||||
|
horizontal_messages: Vec::new(),
|
||||||
new_validation_code: None,
|
new_validation_code: None,
|
||||||
processed_downward_messages: 0,
|
processed_downward_messages: 0,
|
||||||
|
hrmp_watermark: 0,
|
||||||
}, test_state.validation_data.persisted),
|
}, test_state.validation_data.persisted),
|
||||||
)).unwrap();
|
)).unwrap();
|
||||||
}
|
}
|
||||||
@@ -1678,8 +1686,10 @@ mod tests {
|
|||||||
ValidationResult::Valid(ValidationOutputs {
|
ValidationResult::Valid(ValidationOutputs {
|
||||||
head_data: expected_head_data.clone(),
|
head_data: expected_head_data.clone(),
|
||||||
upward_messages: Vec::new(),
|
upward_messages: Vec::new(),
|
||||||
|
horizontal_messages: Vec::new(),
|
||||||
new_validation_code: None,
|
new_validation_code: None,
|
||||||
processed_downward_messages: 0,
|
processed_downward_messages: 0,
|
||||||
|
hrmp_watermark: 0,
|
||||||
}, test_state.validation_data.persisted),
|
}, test_state.validation_data.persisted),
|
||||||
)).unwrap();
|
)).unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -489,8 +489,10 @@ fn validate_candidate_exhaustive<B: ValidationBackend, S: SpawnNamed + 'static>(
|
|||||||
let outputs = ValidationOutputs {
|
let outputs = ValidationOutputs {
|
||||||
head_data: res.head_data,
|
head_data: res.head_data,
|
||||||
upward_messages: res.upward_messages,
|
upward_messages: res.upward_messages,
|
||||||
|
horizontal_messages: res.horizontal_messages,
|
||||||
new_validation_code: res.new_validation_code,
|
new_validation_code: res.new_validation_code,
|
||||||
processed_downward_messages: res.processed_downward_messages,
|
processed_downward_messages: res.processed_downward_messages,
|
||||||
|
hrmp_watermark: res.hrmp_watermark,
|
||||||
};
|
};
|
||||||
Ok(ValidationResult::Valid(outputs, persisted_validation_data))
|
Ok(ValidationResult::Valid(outputs, persisted_validation_data))
|
||||||
}
|
}
|
||||||
@@ -833,7 +835,9 @@ mod tests {
|
|||||||
head_data: HeadData(vec![1, 1, 1]),
|
head_data: HeadData(vec![1, 1, 1]),
|
||||||
new_validation_code: Some(vec![2, 2, 2].into()),
|
new_validation_code: Some(vec![2, 2, 2].into()),
|
||||||
upward_messages: Vec::new(),
|
upward_messages: Vec::new(),
|
||||||
|
horizontal_messages: Vec::new(),
|
||||||
processed_downward_messages: 0,
|
processed_downward_messages: 0,
|
||||||
|
hrmp_watermark: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
let v = validate_candidate_exhaustive::<MockValidationBackend, _>(
|
let v = validate_candidate_exhaustive::<MockValidationBackend, _>(
|
||||||
@@ -848,7 +852,9 @@ mod tests {
|
|||||||
assert_matches!(v, ValidationResult::Valid(outputs, used_validation_data) => {
|
assert_matches!(v, ValidationResult::Valid(outputs, used_validation_data) => {
|
||||||
assert_eq!(outputs.head_data, HeadData(vec![1, 1, 1]));
|
assert_eq!(outputs.head_data, HeadData(vec![1, 1, 1]));
|
||||||
assert_eq!(outputs.upward_messages, Vec::<UpwardMessage>::new());
|
assert_eq!(outputs.upward_messages, Vec::<UpwardMessage>::new());
|
||||||
|
assert_eq!(outputs.horizontal_messages, Vec::new());
|
||||||
assert_eq!(outputs.new_validation_code, Some(vec![2, 2, 2].into()));
|
assert_eq!(outputs.new_validation_code, Some(vec![2, 2, 2].into()));
|
||||||
|
assert_eq!(outputs.hrmp_watermark, 0);
|
||||||
assert_eq!(used_validation_data, validation_data);
|
assert_eq!(used_validation_data, validation_data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ fn make_runtime_api_request<Client>(
|
|||||||
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),
|
Request::DmqContents(id, sender) => query!(dmq_contents(id), sender),
|
||||||
|
Request::InboundHrmpChannelsContents(id, sender) => query!(inbound_hrmp_channels_contents(id), sender),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,12 +181,11 @@ mod tests {
|
|||||||
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, AuthorityDiscoveryId, InboundDownwardMessage,
|
||||||
BlockNumber,
|
BlockNumber, InboundHrmpMessage,
|
||||||
};
|
};
|
||||||
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;
|
||||||
|
use std::collections::{HashMap, BTreeMap};
|
||||||
use std::collections::HashMap;
|
|
||||||
use futures::channel::oneshot;
|
use futures::channel::oneshot;
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
@@ -201,6 +201,7 @@ mod tests {
|
|||||||
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>>,
|
dmq_contents: HashMap<ParaId, Vec<InboundDownwardMessage>>,
|
||||||
|
hrmp_channels: HashMap<ParaId, BTreeMap<ParaId, Vec<InboundHrmpMessage>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProvideRuntimeApi<Block> for MockRuntimeApi {
|
impl ProvideRuntimeApi<Block> for MockRuntimeApi {
|
||||||
@@ -306,9 +307,16 @@ mod tests {
|
|||||||
fn dmq_contents(
|
fn dmq_contents(
|
||||||
&self,
|
&self,
|
||||||
recipient: ParaId,
|
recipient: ParaId,
|
||||||
) -> Vec<polkadot_primitives::v1::InboundDownwardMessage> {
|
) -> Vec<InboundDownwardMessage> {
|
||||||
self.dmq_contents.get(&recipient).map(|q| q.clone()).unwrap_or_default()
|
self.dmq_contents.get(&recipient).map(|q| q.clone()).unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inbound_hrmp_channels_contents(
|
||||||
|
&self,
|
||||||
|
recipient: ParaId
|
||||||
|
) -> BTreeMap<ParaId, Vec<InboundHrmpMessage>> {
|
||||||
|
self.hrmp_channels.get(&recipient).map(|q| q.clone()).unwrap_or_default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -701,6 +709,72 @@ 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_inbound_hrmp_channels_contents() {
|
||||||
|
let (ctx, mut ctx_handle) = test_helpers::make_subsystem_context(TaskExecutor::new());
|
||||||
|
|
||||||
|
let relay_parent = [1; 32].into();
|
||||||
|
let para_a = 99.into();
|
||||||
|
let para_b = 66.into();
|
||||||
|
let para_c = 33.into();
|
||||||
|
|
||||||
|
let para_b_inbound_channels = [
|
||||||
|
(para_a, vec![]),
|
||||||
|
(
|
||||||
|
para_c,
|
||||||
|
vec![InboundHrmpMessage {
|
||||||
|
sent_at: 1,
|
||||||
|
data: "𝙀=𝙈𝘾²".as_bytes().to_owned(),
|
||||||
|
}],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect::<BTreeMap<_, _>>();
|
||||||
|
|
||||||
|
let runtime_api = Arc::new({
|
||||||
|
let mut runtime_api = MockRuntimeApi::default();
|
||||||
|
|
||||||
|
runtime_api.hrmp_channels.insert(para_a, BTreeMap::new());
|
||||||
|
runtime_api
|
||||||
|
.hrmp_channels
|
||||||
|
.insert(para_b, para_b_inbound_channels.clone());
|
||||||
|
|
||||||
|
runtime_api
|
||||||
|
});
|
||||||
|
|
||||||
|
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::InboundHrmpChannelsContents(para_a, tx),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
assert_eq!(rx.await.unwrap().unwrap(), BTreeMap::new());
|
||||||
|
|
||||||
|
let (tx, rx) = oneshot::channel();
|
||||||
|
ctx_handle
|
||||||
|
.send(FromOverseer::Communication {
|
||||||
|
msg: RuntimeApiMessage::Request(
|
||||||
|
relay_parent,
|
||||||
|
Request::InboundHrmpChannelsContents(para_b, tx),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
assert_eq!(rx.await.unwrap().unwrap(), para_b_inbound_channels,);
|
||||||
|
|
||||||
|
ctx_handle
|
||||||
|
.send(FromOverseer::Signal(OverseerSignal::Conclude))
|
||||||
|
.await;
|
||||||
|
};
|
||||||
|
futures::executor::block_on(future::join(subsystem_task, test_task));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn requests_historical_code() {
|
fn requests_historical_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());
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ use polkadot_primitives::v1::{
|
|||||||
Hash, CommittedCandidateReceipt, CandidateReceipt, CompactStatement,
|
Hash, CommittedCandidateReceipt, CandidateReceipt, CompactStatement,
|
||||||
EncodeAs, Signed, SigningContext, ValidatorIndex, ValidatorId,
|
EncodeAs, Signed, SigningContext, ValidatorIndex, ValidatorId,
|
||||||
UpwardMessage, ValidationCode, PersistedValidationData, ValidationData,
|
UpwardMessage, ValidationCode, PersistedValidationData, ValidationData,
|
||||||
HeadData, PoV, CollatorPair, Id as ParaId, ValidationOutputs, CandidateHash,
|
HeadData, PoV, CollatorPair, Id as ParaId, OutboundHrmpMessage, ValidationOutputs, CandidateHash,
|
||||||
};
|
};
|
||||||
use polkadot_statement_table::{
|
use polkadot_statement_table::{
|
||||||
generic::{
|
generic::{
|
||||||
@@ -252,9 +252,11 @@ impl std::convert::TryFrom<FromTableMisbehavior> for MisbehaviorReport {
|
|||||||
/// - does not contain the erasure root; that's computed at the Polkadot level, not at Cumulus
|
/// - does not contain the erasure root; that's computed at the Polkadot level, not at Cumulus
|
||||||
/// - contains a proof of validity.
|
/// - contains a proof of validity.
|
||||||
#[derive(Clone, Encode, Decode)]
|
#[derive(Clone, Encode, Decode)]
|
||||||
pub struct Collation {
|
pub struct Collation<BlockNumber = polkadot_primitives::v1::BlockNumber> {
|
||||||
/// Messages destined to be interpreted by the Relay chain itself.
|
/// Messages destined to be interpreted by the Relay chain itself.
|
||||||
pub upward_messages: Vec<UpwardMessage>,
|
pub upward_messages: Vec<UpwardMessage>,
|
||||||
|
/// The horizontal messages sent by the parachain.
|
||||||
|
pub horizontal_messages: Vec<OutboundHrmpMessage<ParaId>>,
|
||||||
/// New validation code.
|
/// New validation code.
|
||||||
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.
|
||||||
@@ -263,6 +265,8 @@ pub struct Collation {
|
|||||||
pub proof_of_validity: PoV,
|
pub proof_of_validity: PoV,
|
||||||
/// The number of messages processed from the DMQ.
|
/// The number of messages processed from the DMQ.
|
||||||
pub processed_downward_messages: u32,
|
pub processed_downward_messages: u32,
|
||||||
|
/// The mark which specifies the block number up to which all inbound HRMP messages are processed.
|
||||||
|
pub hrmp_watermark: BlockNumber,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration for the collation generator
|
/// Configuration for the collation generator
|
||||||
|
|||||||
@@ -37,9 +37,10 @@ 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, CandidateHash,
|
ValidationCode, ValidatorId, ValidationData, CandidateHash,
|
||||||
ValidatorIndex, ValidatorSignature, InboundDownwardMessage,
|
ValidatorIndex, ValidatorSignature, InboundDownwardMessage, InboundHrmpMessage,
|
||||||
};
|
};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::collections::btree_map::BTreeMap;
|
||||||
|
|
||||||
/// A notification of a new backed candidate.
|
/// A notification of a new backed candidate.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -452,6 +453,12 @@ pub enum RuntimeApiRequest {
|
|||||||
ParaId,
|
ParaId,
|
||||||
RuntimeApiSender<Vec<InboundDownwardMessage<BlockNumber>>>,
|
RuntimeApiSender<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,
|
||||||
|
RuntimeApiSender<BTreeMap<ParaId, Vec<InboundHrmpMessage<BlockNumber>>>>,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A message to the Runtime API subsystem.
|
/// A message to the Runtime API subsystem.
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ use serde::{Serialize, Deserialize};
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use sp_core::bytes;
|
use sp_core::bytes;
|
||||||
|
|
||||||
use polkadot_core_primitives::Hash;
|
use polkadot_core_primitives::{Hash, OutboundHrmpMessage};
|
||||||
|
|
||||||
/// Block number type used by the relay chain.
|
/// Block number type used by the relay chain.
|
||||||
pub use polkadot_core_primitives::BlockNumber as RelayChainBlockNumber;
|
pub use polkadot_core_primitives::BlockNumber as RelayChainBlockNumber;
|
||||||
@@ -186,6 +186,21 @@ impl<T: Encode + Decode + Default> AccountIdConversion<T> for Id {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A type that uniquely identifies an HRMP channel. An HRMP channel is established between two paras.
|
||||||
|
/// In text, we use the notation `(A, B)` to specify a channel between A and B. The channels are
|
||||||
|
/// unidirectional, meaning that `(A, B)` and `(B, A)` refer to different channels. The convention is
|
||||||
|
/// that we use the first item tuple for the sender and the second for the recipient. Only one channel
|
||||||
|
/// is allowed between two participants in one direction, i.e. there cannot be 2 different channels
|
||||||
|
/// identified by `(A, B)`.
|
||||||
|
#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)]
|
||||||
|
#[cfg_attr(feature = "std", derive(Hash))]
|
||||||
|
pub struct HrmpChannelId {
|
||||||
|
/// The para that acts as the sender in this channel.
|
||||||
|
pub sender: Id,
|
||||||
|
/// The para that acts as the recipient in this channel.
|
||||||
|
pub recipient: Id,
|
||||||
|
}
|
||||||
|
|
||||||
/// A message from a parachain to its Relay Chain.
|
/// A message from a parachain to its Relay Chain.
|
||||||
pub type UpwardMessage = Vec<u8>;
|
pub type UpwardMessage = Vec<u8>;
|
||||||
|
|
||||||
@@ -212,7 +227,7 @@ pub struct ValidationParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The result of parachain validation.
|
/// The result of parachain validation.
|
||||||
// TODO: egress and balance uploads (https://github.com/paritytech/polkadot/issues/220)
|
// TODO: balance uploads (https://github.com/paritytech/polkadot/issues/220)
|
||||||
#[derive(PartialEq, Eq, Encode)]
|
#[derive(PartialEq, Eq, Encode)]
|
||||||
#[cfg_attr(feature = "std", derive(Debug, Decode))]
|
#[cfg_attr(feature = "std", derive(Debug, Decode))]
|
||||||
pub struct ValidationResult {
|
pub struct ValidationResult {
|
||||||
@@ -222,8 +237,12 @@ pub struct ValidationResult {
|
|||||||
pub new_validation_code: Option<ValidationCode>,
|
pub new_validation_code: Option<ValidationCode>,
|
||||||
/// Upward messages send by the Parachain.
|
/// Upward messages send by the Parachain.
|
||||||
pub upward_messages: Vec<UpwardMessage>,
|
pub upward_messages: Vec<UpwardMessage>,
|
||||||
|
/// Outbound horizontal messages sent by the parachain.
|
||||||
|
pub horizontal_messages: Vec<OutboundHrmpMessage<Id>>,
|
||||||
/// Number of downward messages that were processed by the Parachain.
|
/// Number of downward messages that were processed by the Parachain.
|
||||||
///
|
///
|
||||||
/// It is expected that the Parachain processes them from first to last.
|
/// It is expected that the Parachain processes them from first to last.
|
||||||
pub processed_downward_messages: u32,
|
pub processed_downward_messages: u32,
|
||||||
|
/// The mark which specifies the block number up to which all inbound HRMP messages are processed.
|
||||||
|
pub hrmp_watermark: RelayChainBlockNumber,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,10 +114,12 @@ impl Collator {
|
|||||||
|
|
||||||
let collation = Collation {
|
let collation = Collation {
|
||||||
upward_messages: Vec::new(),
|
upward_messages: Vec::new(),
|
||||||
|
horizontal_messages: Vec::new(),
|
||||||
new_validation_code: None,
|
new_validation_code: None,
|
||||||
head_data: head_data.encode().into(),
|
head_data: head_data.encode().into(),
|
||||||
proof_of_validity: PoV { block_data: block_data.encode().into() },
|
proof_of_validity: PoV { block_data: block_data.encode().into() },
|
||||||
processed_downward_messages: 0,
|
processed_downward_messages: 0,
|
||||||
|
hrmp_watermark: validation_data.persisted.block_number,
|
||||||
};
|
};
|
||||||
|
|
||||||
async move { Some(collation) }.boxed()
|
async move { Some(collation) }.boxed()
|
||||||
|
|||||||
@@ -17,12 +17,13 @@
|
|||||||
//! WASM validation for adder parachain.
|
//! WASM validation for adder parachain.
|
||||||
|
|
||||||
use crate::{HeadData, BlockData};
|
use crate::{HeadData, BlockData};
|
||||||
use core::{intrinsics, panic};
|
use core::panic;
|
||||||
|
use sp_std::vec::Vec;
|
||||||
use parachain::primitives::{ValidationResult, HeadData as GenericHeadData};
|
use parachain::primitives::{ValidationResult, HeadData as GenericHeadData};
|
||||||
use codec::{Encode, Decode};
|
use codec::{Encode, Decode};
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern fn validate_block(params: *const u8, len: usize) -> u64 {
|
pub extern "C" fn validate_block(params: *const u8, len: usize) -> u64 {
|
||||||
let params = unsafe { parachain::load_params(params, len) };
|
let params = unsafe { parachain::load_params(params, len) };
|
||||||
let parent_head = HeadData::decode(&mut ¶ms.parent_head.0[..])
|
let parent_head = HeadData::decode(&mut ¶ms.parent_head.0[..])
|
||||||
.expect("invalid parent head format.");
|
.expect("invalid parent head format.");
|
||||||
@@ -38,7 +39,9 @@ pub extern fn validate_block(params: *const u8, len: usize) -> u64 {
|
|||||||
head_data: GenericHeadData(new_head.encode()),
|
head_data: GenericHeadData(new_head.encode()),
|
||||||
new_validation_code: None,
|
new_validation_code: None,
|
||||||
upward_messages: sp_std::vec::Vec::new(),
|
upward_messages: sp_std::vec::Vec::new(),
|
||||||
|
horizontal_messages: sp_std::vec::Vec::new(),
|
||||||
processed_downward_messages: 0,
|
processed_downward_messages: 0,
|
||||||
|
hrmp_watermark: params.relay_chain_height,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
//! V1 Primitives.
|
//! V1 Primitives.
|
||||||
|
|
||||||
use sp_std::prelude::*;
|
use sp_std::prelude::*;
|
||||||
|
use sp_std::collections::btree_map::BTreeMap;
|
||||||
use parity_scale_codec::{Encode, Decode};
|
use parity_scale_codec::{Encode, Decode};
|
||||||
use bitvec::vec::BitVec;
|
use bitvec::vec::BitVec;
|
||||||
|
|
||||||
@@ -29,14 +30,14 @@ pub use runtime_primitives::traits::{BlakeTwo256, Hash as HashT};
|
|||||||
|
|
||||||
// Export some core primitives.
|
// Export some core primitives.
|
||||||
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,
|
||||||
ChainId, Hash, Nonce, Balance, Header, Block, BlockId, UncheckedExtrinsic,
|
Balance, Header, Block, BlockId, UncheckedExtrinsic, Remark, DownwardMessage,
|
||||||
Remark, DownwardMessage, InboundDownwardMessage, CandidateHash,
|
InboundDownwardMessage, CandidateHash, InboundHrmpMessage, OutboundHrmpMessage,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Export some polkadot-parachain primitives
|
// Export some polkadot-parachain primitives
|
||||||
pub use polkadot_parachain::primitives::{
|
pub use polkadot_parachain::primitives::{
|
||||||
Id, LOWEST_USER_ID, UpwardMessage, HeadData, BlockData, ValidationCode,
|
Id, LOWEST_USER_ID, HrmpChannelId, UpwardMessage, HeadData, BlockData, ValidationCode,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Export some basic parachain primitives from v0.
|
// Export some basic parachain primitives from v0.
|
||||||
@@ -317,18 +318,24 @@ pub struct ValidationOutputs {
|
|||||||
pub head_data: HeadData,
|
pub head_data: HeadData,
|
||||||
/// Upward messages to the relay chain.
|
/// Upward messages to the relay chain.
|
||||||
pub upward_messages: Vec<UpwardMessage>,
|
pub upward_messages: Vec<UpwardMessage>,
|
||||||
|
/// The horizontal messages sent by the parachain.
|
||||||
|
pub horizontal_messages: Vec<OutboundHrmpMessage<Id>>,
|
||||||
/// 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.
|
/// The number of messages processed from the DMQ.
|
||||||
pub processed_downward_messages: u32,
|
pub processed_downward_messages: u32,
|
||||||
|
/// The mark which specifies the block number up to which all inbound HRMP messages are processed.
|
||||||
|
pub hrmp_watermark: BlockNumber,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commitments made in a `CandidateReceipt`. Many of these are outputs of validation.
|
/// Commitments made in a `CandidateReceipt`. Many of these are outputs of validation.
|
||||||
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
|
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
|
||||||
#[cfg_attr(feature = "std", derive(Debug, Default, Hash))]
|
#[cfg_attr(feature = "std", derive(Debug, Default, Hash))]
|
||||||
pub struct CandidateCommitments {
|
pub struct CandidateCommitments<N = BlockNumber> {
|
||||||
/// Messages destined to be interpreted by the Relay chain itself.
|
/// Messages destined to be interpreted by the Relay chain itself.
|
||||||
pub upward_messages: Vec<UpwardMessage>,
|
pub upward_messages: Vec<UpwardMessage>,
|
||||||
|
/// Horizontal messages sent by the parachain.
|
||||||
|
pub horizontal_messages: Vec<OutboundHrmpMessage<Id>>,
|
||||||
/// The root of a block's erasure encoding Merkle tree.
|
/// The root of a block's erasure encoding Merkle tree.
|
||||||
pub erasure_root: Hash,
|
pub erasure_root: Hash,
|
||||||
/// New validation code.
|
/// New validation code.
|
||||||
@@ -337,6 +344,8 @@ pub struct CandidateCommitments {
|
|||||||
pub head_data: HeadData,
|
pub head_data: HeadData,
|
||||||
/// The number of messages processed from the DMQ.
|
/// The number of messages processed from the DMQ.
|
||||||
pub processed_downward_messages: u32,
|
pub processed_downward_messages: u32,
|
||||||
|
/// The mark which specifies the block number up to which all inbound HRMP messages are processed.
|
||||||
|
pub hrmp_watermark: N,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CandidateCommitments {
|
impl CandidateCommitments {
|
||||||
@@ -735,6 +744,10 @@ sp_api::decl_runtime_apis! {
|
|||||||
fn dmq_contents(
|
fn dmq_contents(
|
||||||
recipient: Id,
|
recipient: Id,
|
||||||
) -> Vec<InboundDownwardMessage<N>>;
|
) -> Vec<InboundDownwardMessage<N>>;
|
||||||
|
|
||||||
|
/// Get the contents of all channels addressed to the given recipient. Channels that have no
|
||||||
|
/// messages in them are also included.
|
||||||
|
fn inbound_hrmp_channels_contents(recipient: Id) -> BTreeMap<Id, Vec<InboundHrmpMessage<N>>>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,8 +70,7 @@ All failed checks should lead to an unrecoverable error making the block invalid
|
|||||||
1. call `Router::check_upward_messages(para, commitments.upward_messages)` to check that the upward messages are valid.
|
1. call `Router::check_upward_messages(para, commitments.upward_messages)` to check that the upward messages are valid.
|
||||||
1. call `Router::check_processed_downward_messages(para, commitments.processed_downward_messages)` to check that the DMQ is properly drained.
|
1. call `Router::check_processed_downward_messages(para, commitments.processed_downward_messages)` to check that the DMQ is properly drained.
|
||||||
1. call `Router::check_hrmp_watermark(para, commitments.hrmp_watermark)` for each candidate to check rules of processing the HRMP watermark.
|
1. call `Router::check_hrmp_watermark(para, commitments.hrmp_watermark)` for each candidate to check rules of processing the HRMP watermark.
|
||||||
1. check that in the commitments of each candidate the horizontal messages are sorted by ascending recipient ParaId and there is no two horizontal messages have the same recipient.
|
1. using `Router::check_outbound_hrmp(sender, commitments.horizontal_messages)` ensure that the each candidate sent a valid set of horizontal messages
|
||||||
1. using `Router::verify_outbound_hrmp(sender, commitments.horizontal_messages)` ensure that the each candidate send a valid set of horizontal messages
|
|
||||||
1. create an entry in the `PendingAvailability` map for each backed candidate with a blank `availability_votes` bitfield.
|
1. create an entry in the `PendingAvailability` map for each backed candidate with a blank `availability_votes` bitfield.
|
||||||
1. create a corresponding entry in the `PendingAvailabilityCommitments` with the commitments.
|
1. create a corresponding entry in the `PendingAvailabilityCommitments` with the commitments.
|
||||||
1. Return a `Vec<CoreIndex>` of all scheduled cores of the list of passed assignments that a candidate was successfully backed for, sorted ascending by CoreIndex.
|
1. Return a `Vec<CoreIndex>` of all scheduled cores of the list of passed assignments that a candidate was successfully backed for, sorted ascending by CoreIndex.
|
||||||
@@ -79,9 +78,9 @@ All failed checks should lead to an unrecoverable error making the block invalid
|
|||||||
1. If the receipt contains a code upgrade, Call `Paras::schedule_code_upgrade(para_id, code, relay_parent_number + config.validationl_upgrade_delay)`.
|
1. If the receipt contains a code upgrade, Call `Paras::schedule_code_upgrade(para_id, code, relay_parent_number + config.validationl_upgrade_delay)`.
|
||||||
> TODO: Note that this is safe as long as we never enact candidates where the relay parent is across a session boundary. In that case, which we should be careful to avoid with contextual execution, the configuration might have changed and the para may de-sync from the host's understanding of it.
|
> TODO: Note that this is safe as long as we never enact candidates where the relay parent is across a session boundary. In that case, which we should be careful to avoid with contextual execution, the configuration might have changed and the para may de-sync from the host's understanding of it.
|
||||||
1. call `Router::enact_upward_messages` for each backed candidate, using the [`UpwardMessage`s](../types/messages.md#upward-message) from the [`CandidateCommitments`](../types/candidate.md#candidate-commitments).
|
1. call `Router::enact_upward_messages` for each backed candidate, using the [`UpwardMessage`s](../types/messages.md#upward-message) from the [`CandidateCommitments`](../types/candidate.md#candidate-commitments).
|
||||||
1. call `Router::queue_outbound_hrmp` with the para id of the candidate and the list of horizontal messages taken from the commitment,
|
|
||||||
1. call `Router::prune_hrmp` with the para id of the candiate and the candidate's `hrmp_watermark`.
|
|
||||||
1. call `Router::prune_dmq` with the para id of the candidate and the candidate's `processed_downward_messages`.
|
1. call `Router::prune_dmq` with the para id of the candidate and the candidate's `processed_downward_messages`.
|
||||||
|
1. call `Router::prune_hrmp` with the para id of the candiate and the candidate's `hrmp_watermark`.
|
||||||
|
1. call `Router::queue_outbound_hrmp` with the para id of the candidate and the list of horizontal messages taken from the commitment,
|
||||||
1. Call `Paras::note_new_head` using the `HeadData` from the receipt and `relay_parent_number`.
|
1. Call `Paras::note_new_head` using the `HeadData` from the receipt and `relay_parent_number`.
|
||||||
* `collect_pending`:
|
* `collect_pending`:
|
||||||
|
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ OutgoingParas: Vec<ParaId>;
|
|||||||
* `note_new_head(ParaId, HeadData, BlockNumber)`: note that a para has progressed to a new head, where the new head was executed in the context of a relay-chain block with given number. This will apply pending code upgrades based on the block number provided.
|
* `note_new_head(ParaId, HeadData, BlockNumber)`: note that a para has progressed to a new head, where the new head was executed in the context of a relay-chain block with given number. This will apply pending code upgrades based on the block number provided.
|
||||||
* `validation_code_at(ParaId, at: BlockNumber, assume_intermediate: Option<BlockNumber>)`: Fetches the validation code to be used when validating a block in the context of the given relay-chain height. A second block number parameter may be used to tell the lookup to proceed as if an intermediate parablock has been included at the given relay-chain height. This may return past, current, or (with certain choices of `assume_intermediate`) future code. `assume_intermediate`, if provided, must be before `at`. If the validation code has been pruned, this will return `None`.
|
* `validation_code_at(ParaId, at: BlockNumber, assume_intermediate: Option<BlockNumber>)`: Fetches the validation code to be used when validating a block in the context of the given relay-chain height. A second block number parameter may be used to tell the lookup to proceed as if an intermediate parablock has been included at the given relay-chain height. This may return past, current, or (with certain choices of `assume_intermediate`) future code. `assume_intermediate`, if provided, must be before `at`. If the validation code has been pruned, this will return `None`.
|
||||||
* `is_parathread(ParaId) -> bool`: Returns true if the para ID references any live parathread.
|
* `is_parathread(ParaId) -> bool`: Returns true if the para ID references any live parathread.
|
||||||
|
* `is_valid_para(ParaId) -> bool`: Returns true if the para ID references either a live parathread or live parachain.
|
||||||
|
|
||||||
* `last_code_upgrade(id: ParaId, include_future: bool) -> Option<BlockNumber>`: The block number of the last scheduled upgrade of the requested para. Includes future upgrades if the flag is set. This is the `expected_at` number, not the `activated_at` number.
|
* `last_code_upgrade(id: ParaId, include_future: bool) -> Option<BlockNumber>`: The block number of the last scheduled upgrade of the requested para. Includes future upgrades if the flag is set. This is the `expected_at` number, not the `activated_at` number.
|
||||||
* `persisted_validation_data(id: ParaId) -> Option<PersistedValidationData>`: Get the PersistedValidationData of the given para, assuming the context is the parent block. Returns `None` if the para is not known.
|
* `persisted_validation_data(id: ParaId) -> Option<PersistedValidationData>`: Get the PersistedValidationData of the given para, assuming the context is the parent block. Returns `None` if the para is not known.
|
||||||
|
|||||||
@@ -78,10 +78,12 @@ struct HrmpOpenChannelRequest {
|
|||||||
age: SessionIndex,
|
age: SessionIndex,
|
||||||
/// The amount that the sender supplied at the time of creation of this request.
|
/// The amount that the sender supplied at the time of creation of this request.
|
||||||
sender_deposit: Balance,
|
sender_deposit: Balance,
|
||||||
|
/// The maximum message size that could be put into the channel.
|
||||||
|
max_message_size: u32,
|
||||||
/// The maximum number of messages that can be pending in the channel at once.
|
/// The maximum number of messages that can be pending in the channel at once.
|
||||||
limit_used_places: u32,
|
max_capacity: u32,
|
||||||
/// The maximum total size of the messages that can be pending in the channel at once.
|
/// The maximum total size of the messages that can be pending in the channel at once.
|
||||||
limit_used_bytes: u32,
|
max_total_size: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A metadata of an HRMP channel.
|
/// A metadata of an HRMP channel.
|
||||||
@@ -91,25 +93,25 @@ struct HrmpChannel {
|
|||||||
/// The amount that the recipient supplied as a deposit when accepting opening this channel.
|
/// The amount that the recipient supplied as a deposit when accepting opening this channel.
|
||||||
recipient_deposit: Balance,
|
recipient_deposit: Balance,
|
||||||
/// The maximum number of messages that can be pending in the channel at once.
|
/// The maximum number of messages that can be pending in the channel at once.
|
||||||
limit_used_places: u32,
|
max_capacity: u32,
|
||||||
/// The maximum total size of the messages that can be pending in the channel at once.
|
/// The maximum total size of the messages that can be pending in the channel at once.
|
||||||
limit_used_bytes: u32,
|
max_total_size: u32,
|
||||||
/// The maximum message size that could be put into the channel.
|
/// The maximum message size that could be put into the channel.
|
||||||
limit_message_size: u32,
|
max_message_size: u32,
|
||||||
/// The current number of messages pending in the channel.
|
/// The current number of messages pending in the channel.
|
||||||
/// Invariant: should be less or equal to `limit_used_places`.
|
/// Invariant: should be less or equal to `max_capacity`.
|
||||||
used_places: u32,
|
msg_count: u32,
|
||||||
/// The total size in bytes of all message payloads in the channel.
|
/// The total size in bytes of all message payloads in the channel.
|
||||||
/// Invariant: should be less or equal to `limit_used_bytes`.
|
/// Invariant: should be less or equal to `max_total_size`.
|
||||||
used_bytes: u32,
|
total_size: u32,
|
||||||
/// A head of the Message Queue Chain for this channel. Each link in this chain has a form:
|
/// A head of the Message Queue Chain for this channel. Each link in this chain has a form:
|
||||||
/// `(prev_head, B, H(M))`, where
|
/// `(prev_head, B, H(M))`, where
|
||||||
/// - `prev_head`: is the previous value of `mqc_head`.
|
/// - `prev_head`: is the previous value of `mqc_head` or zero if none.
|
||||||
/// - `B`: is the [relay-chain] block number in which a message was appended
|
/// - `B`: is the [relay-chain] block number in which a message was appended
|
||||||
/// - `H(M)`: is the hash of the message being appended.
|
/// - `H(M)`: is the hash of the message being appended.
|
||||||
/// This value is initialized to a special value that consists of all zeroes which indicates
|
/// This value is initialized to a special value that consists of all zeroes which indicates
|
||||||
/// that no messages were previously added.
|
/// that no messages were previously added.
|
||||||
mqc_head: Hash,
|
mqc_head: Option<Hash>,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
HRMP related storage layout
|
HRMP related storage layout
|
||||||
@@ -144,14 +146,26 @@ HrmpCloseChannelRequests: map HrmpChannelId => Option<()>;
|
|||||||
HrmpCloseChannelRequestsList: Vec<HrmpChannelId>;
|
HrmpCloseChannelRequestsList: Vec<HrmpChannelId>;
|
||||||
|
|
||||||
/// The HRMP watermark associated with each para.
|
/// The HRMP watermark associated with each para.
|
||||||
|
/// Invariant:
|
||||||
|
/// - each para `P` used here as a key should satisfy `Paras::is_valid_para(P)` within a session.
|
||||||
HrmpWatermarks: map ParaId => Option<BlockNumber>;
|
HrmpWatermarks: map ParaId => Option<BlockNumber>;
|
||||||
/// HRMP channel data associated with each para.
|
/// HRMP channel data associated with each para.
|
||||||
|
/// Invariant:
|
||||||
|
/// - each participant in the channel should satisfy `Paras::is_valid_para(P)` within a session.
|
||||||
HrmpChannels: map HrmpChannelId => Option<HrmpChannel>;
|
HrmpChannels: map HrmpChannelId => Option<HrmpChannel>;
|
||||||
/// The indexes that map all senders to their recievers and vise versa.
|
/// Ingress/egress indexes allow to find all the senders and receivers given the opposite
|
||||||
|
/// side. I.e.
|
||||||
|
///
|
||||||
|
/// (a) ingress index allows to find all the senders for a given recipient.
|
||||||
|
/// (b) egress index allows to find all the recipients for a given sender.
|
||||||
|
///
|
||||||
/// Invariants:
|
/// Invariants:
|
||||||
/// - for each ingress index entry for `P` each item `I` in the index should present in `HrmpChannels` as `(I, P)`.
|
/// - for each ingress index entry for `P` each item `I` in the index should present in `HrmpChannels`
|
||||||
/// - for each egress index entry for `P` each item `E` in the index should present in `HrmpChannels` as `(P, E)`.
|
/// as `(I, P)`.
|
||||||
|
/// - for each egress index entry for `P` each item `E` in the index should present in `HrmpChannels`
|
||||||
|
/// as `(P, E)`.
|
||||||
/// - there should be no other dangling channels in `HrmpChannels`.
|
/// - there should be no other dangling channels in `HrmpChannels`.
|
||||||
|
/// - the vectors are sorted.
|
||||||
HrmpIngressChannelsIndex: map ParaId => Vec<ParaId>;
|
HrmpIngressChannelsIndex: map ParaId => Vec<ParaId>;
|
||||||
HrmpEgressChannelsIndex: map ParaId => Vec<ParaId>;
|
HrmpEgressChannelsIndex: map ParaId => Vec<ParaId>;
|
||||||
/// Storage for the messages for each channel.
|
/// Storage for the messages for each channel.
|
||||||
@@ -159,7 +173,11 @@ HrmpEgressChannelsIndex: map ParaId => Vec<ParaId>;
|
|||||||
HrmpChannelContents: map HrmpChannelId => Vec<InboundHrmpMessage>;
|
HrmpChannelContents: map HrmpChannelId => Vec<InboundHrmpMessage>;
|
||||||
/// Maintains a mapping that can be used to answer the question:
|
/// Maintains a mapping that can be used to answer the question:
|
||||||
/// What paras sent a message at the given block number for a given reciever.
|
/// What paras sent a message at the given block number for a given reciever.
|
||||||
/// Invariant: The para ids vector is never empty.
|
/// Invariants:
|
||||||
|
/// - The inner `Vec<ParaId>` is never empty.
|
||||||
|
/// - The inner `Vec<ParaId>` cannot store two same `ParaId`.
|
||||||
|
/// - The outer vector is sorted ascending by block number and cannot store two items with the same
|
||||||
|
/// block number.
|
||||||
HrmpChannelDigests: map ParaId => Vec<(BlockNumber, Vec<ParaId>)>;
|
HrmpChannelDigests: map ParaId => Vec<(BlockNumber, Vec<ParaId>)>;
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -184,12 +202,14 @@ Candidate Acceptance Function:
|
|||||||
1. `new_hrmp_watermark` should be either
|
1. `new_hrmp_watermark` should be either
|
||||||
1. equal to the context's block number
|
1. equal to the context's block number
|
||||||
1. or in `HrmpChannelDigests` for `P` an entry with the block number should exist
|
1. or in `HrmpChannelDigests` for `P` an entry with the block number should exist
|
||||||
* `verify_outbound_hrmp(sender: ParaId, Vec<OutboundHrmpMessage>)`:
|
* `check_outbound_hrmp(sender: ParaId, Vec<OutboundHrmpMessage>)`:
|
||||||
|
1. Checks that there are at most `config.hrmp_max_message_num_per_candidate` messages.
|
||||||
|
1. Checks that horizontal messages are sorted by ascending recipient ParaId and there is no two horizontal messages have the same recipient.
|
||||||
1. For each horizontal message `M` with the channel `C` identified by `(sender, M.recipient)` check:
|
1. For each horizontal message `M` with the channel `C` identified by `(sender, M.recipient)` check:
|
||||||
1. exists
|
1. exists
|
||||||
1. `M`'s payload size doesn't exceed a preconfigured limit `C.limit_message_size`
|
1. `M`'s payload size doesn't exceed a preconfigured limit `C.max_message_size`
|
||||||
1. `M`'s payload size summed with the `C.used_bytes` doesn't exceed a preconfigured limit `C.limit_used_bytes`.
|
1. `M`'s payload size summed with the `C.total_size` doesn't exceed a preconfigured limit `C.max_total_size`.
|
||||||
1. `C.used_places + 1` doesn't exceed a preconfigured limit `C.limit_used_places`.
|
1. `C.msg_count + 1` doesn't exceed a preconfigured limit `C.max_capacity`.
|
||||||
|
|
||||||
Candidate Enactment:
|
Candidate Enactment:
|
||||||
|
|
||||||
@@ -197,17 +217,21 @@ Candidate Enactment:
|
|||||||
1. For each horizontal message `HM` with the channel `C` identified by `(sender, HM.recipient)`:
|
1. For each horizontal message `HM` with the channel `C` identified by `(sender, HM.recipient)`:
|
||||||
1. Append `HM` into `HrmpChannelContents` that corresponds to `C` with `sent_at` equals to the current block number.
|
1. Append `HM` into `HrmpChannelContents` that corresponds to `C` with `sent_at` equals to the current block number.
|
||||||
1. Locate or create an entry in `HrmpChannelDigests` for `HM.recipient` and append `sender` into the entry's list.
|
1. Locate or create an entry in `HrmpChannelDigests` for `HM.recipient` and append `sender` into the entry's list.
|
||||||
1. Increment `C.used_places`
|
1. Increment `C.msg_count`
|
||||||
1. Increment `C.used_bytes` by `HM`'s payload size
|
1. Increment `C.total_size` by `HM`'s payload size
|
||||||
1. Append a new link to the MQC and save the new head in `C.mqc_head`. Note that the current block number as of enactment is used for the link.
|
1. Append a new link to the MQC and save the new head in `C.mqc_head`. Note that the current block number as of enactment is used for the link.
|
||||||
* `prune_hrmp(recipient, new_hrmp_watermark)`:
|
* `prune_hrmp(recipient, new_hrmp_watermark)`:
|
||||||
1. From `HrmpChannelDigests` for `recipient` remove all entries up to an entry with block number equal to `new_hrmp_watermark`.
|
1. From `HrmpChannelDigests` for `recipient` remove all entries up to an entry with block number equal to `new_hrmp_watermark`.
|
||||||
1. From the removed digests construct a set of paras that sent new messages within the interval between the old and new watermarks.
|
1. From the removed digests construct a set of paras that sent new messages within the interval between the old and new watermarks.
|
||||||
1. For each channel `C` identified by `(sender, recipient)` for each `sender` coming from the set, prune messages up to the `new_hrmp_watermark`.
|
1. For each channel `C` identified by `(sender, recipient)` for each `sender` coming from the set, prune messages up to the `new_hrmp_watermark`.
|
||||||
1. For each pruned message `M` from channel `C`:
|
1. For each pruned message `M` from channel `C`:
|
||||||
1. Decrement `C.used_places`
|
1. Decrement `C.msg_count`
|
||||||
1. Decrement `C.used_bytes` by `M`'s payload size.
|
1. Decrement `C.total_size` by `M`'s payload size.
|
||||||
1. Set `HrmpWatermarks` for `P` to be equal to `new_hrmp_watermark`
|
1. Set `HrmpWatermarks` for `P` to be equal to `new_hrmp_watermark`
|
||||||
|
> NOTE: That collecting digests can be inefficient and the time it takes grows very fast. Thanks to the aggresive
|
||||||
|
> parametrization this shouldn't be a big of a deal.
|
||||||
|
> If that becomes a problem consider introducing an extra dictionary which says at what block the given sender
|
||||||
|
> sent a message to the recipient.
|
||||||
* `prune_dmq(P: ParaId, processed_downward_messages)`:
|
* `prune_dmq(P: ParaId, processed_downward_messages)`:
|
||||||
1. Remove the first `processed_downward_messages` from the `DownwardMessageQueues` of `P`.
|
1. Remove the first `processed_downward_messages` from the `DownwardMessageQueues` of `P`.
|
||||||
* `enact_upward_messages(P: ParaId, Vec<UpwardMessage>)`:
|
* `enact_upward_messages(P: ParaId, Vec<UpwardMessage>)`:
|
||||||
@@ -251,10 +275,10 @@ The following entry-points are meant to be used for HRMP channel management.
|
|||||||
Those entry-points are meant to be called from a parachain. `origin` is defined as the `ParaId` of
|
Those entry-points are meant to be called from a parachain. `origin` is defined as the `ParaId` of
|
||||||
the parachain executed the message.
|
the parachain executed the message.
|
||||||
|
|
||||||
* `hrmp_init_open_channel(recipient, max_places, max_message_size)`:
|
* `hrmp_init_open_channel(recipient, proposed_max_capacity, proposed_max_message_size)`:
|
||||||
1. Check that the `origin` is not `recipient`.
|
1. Check that the `origin` is not `recipient`.
|
||||||
1. Check that `max_places` is less or equal to `config.hrmp_channel_max_places` and greater than zero.
|
1. Check that `proposed_max_capacity` is less or equal to `config.hrmp_channel_max_capacity` and greater than zero.
|
||||||
1. Check that `max_message_size` is less or equal to `config.hrmp_channel_max_message_size` and greater than zero.
|
1. Check that `proposed_max_message_size` is less or equal to `config.hrmp_channel_max_message_size` and greater than zero.
|
||||||
1. Check that `recipient` is a valid para.
|
1. Check that `recipient` is a valid para.
|
||||||
1. Check that there is no existing channel for `(origin, recipient)` in `HrmpChannels`.
|
1. Check that there is no existing channel for `(origin, recipient)` in `HrmpChannels`.
|
||||||
1. Check that there is no existing open channel request (`origin`, `recipient`) in `HrmpOpenChannelRequests`.
|
1. Check that there is no existing open channel request (`origin`, `recipient`) in `HrmpOpenChannelRequests`.
|
||||||
@@ -268,9 +292,15 @@ the parachain executed the message.
|
|||||||
1. Append `(origin, recipient)` to `HrmpOpenChannelRequestsList`.
|
1. Append `(origin, recipient)` to `HrmpOpenChannelRequestsList`.
|
||||||
1. Add a new entry to `HrmpOpenChannelRequests` for `(origin, recipient)`
|
1. Add a new entry to `HrmpOpenChannelRequests` for `(origin, recipient)`
|
||||||
1. Set `sender_deposit` to `config.hrmp_sender_deposit`
|
1. Set `sender_deposit` to `config.hrmp_sender_deposit`
|
||||||
1. Set `limit_used_places` to `max_places`
|
1. Set `max_capacity` to `proposed_max_capacity`
|
||||||
1. Set `limit_message_size` to `max_message_size`
|
1. Set `max_message_size` to `proposed_max_message_size`
|
||||||
1. Set `limit_used_bytes` to `config.hrmp_channel_max_size`
|
1. Set `max_total_size` to `config.hrmp_channel_max_total_size`
|
||||||
|
1. Send a downward message to `recipient` notifying about an inbound HRMP channel request.
|
||||||
|
- The DM is sent using `queue_downward_message`.
|
||||||
|
- The DM is represented by the `HrmpNewChannelOpenRequest` XCM message.
|
||||||
|
- `sender` is set to `origin`,
|
||||||
|
- `max_message_size` is set to `proposed_max_message_size`,
|
||||||
|
- `max_capacity` is set to `proposed_max_capacity`.
|
||||||
* `hrmp_accept_open_channel(sender)`:
|
* `hrmp_accept_open_channel(sender)`:
|
||||||
1. Check that there is an existing request between (`sender`, `origin`) in `HrmpOpenChannelRequests`
|
1. Check that there is an existing request between (`sender`, `origin`) in `HrmpOpenChannelRequests`
|
||||||
1. Check that it is not confirmed.
|
1. Check that it is not confirmed.
|
||||||
@@ -283,12 +313,23 @@ the parachain executed the message.
|
|||||||
1. Reserve the deposit for the `origin` according to `config.hrmp_recipient_deposit`
|
1. Reserve the deposit for the `origin` according to `config.hrmp_recipient_deposit`
|
||||||
1. For the request in `HrmpOpenChannelRequests` identified by `(sender, P)`, set `confirmed` flag to `true`.
|
1. For the request in `HrmpOpenChannelRequests` identified by `(sender, P)`, set `confirmed` flag to `true`.
|
||||||
1. Increase `HrmpAcceptedChannelRequestCount` by 1 for `origin`.
|
1. Increase `HrmpAcceptedChannelRequestCount` by 1 for `origin`.
|
||||||
|
1. Send a downward message to `sender` notifying that the channel request was accepted.
|
||||||
|
- The DM is sent using `queue_downward_message`.
|
||||||
|
- The DM is represented by the `HrmpChannelAccepted` XCM message.
|
||||||
|
- `recipient` is set to `origin`.
|
||||||
* `hrmp_close_channel(ch)`:
|
* `hrmp_close_channel(ch)`:
|
||||||
1. Check that `origin` is either `ch.sender` or `ch.recipient`
|
1. Check that `origin` is either `ch.sender` or `ch.recipient`
|
||||||
1. Check that `HrmpChannels` for `ch` exists.
|
1. Check that `HrmpChannels` for `ch` exists.
|
||||||
1. Check that `ch` is not in the `HrmpCloseChannelRequests` set.
|
1. Check that `ch` is not in the `HrmpCloseChannelRequests` set.
|
||||||
1. If not already there, insert a new entry `Some(())` to `HrmpCloseChannelRequests` for `ch`
|
1. If not already there, insert a new entry `Some(())` to `HrmpCloseChannelRequests` for `ch`
|
||||||
and append `ch` to `HrmpCloseChannelRequestsList`.
|
and append `ch` to `HrmpCloseChannelRequestsList`.
|
||||||
|
1. Send a downward message to the opposite party notifying about the channel closing.
|
||||||
|
- The DM is sent using `queue_downward_message`.
|
||||||
|
- The DM is represented by the `HrmpChannelClosing` XCM message with:
|
||||||
|
- `initator` is set to `origin`,
|
||||||
|
- `sender` is set to `ch.sender`,
|
||||||
|
- `recipient` is set to `ch.recipient`.
|
||||||
|
- The opposite party is `ch.sender` if `origin` is `ch.recipient` and `ch.recipient` if `origin` is `ch.sender`.
|
||||||
|
|
||||||
## Session Change
|
## Session Change
|
||||||
|
|
||||||
|
|||||||
@@ -42,8 +42,6 @@ that we use the first item tuple for the sender and the second for the recipient
|
|||||||
is allowed between two participants in one direction, i.e. there cannot be 2 different channels
|
is allowed between two participants in one direction, i.e. there cannot be 2 different channels
|
||||||
identified by `(A, B)`.
|
identified by `(A, B)`.
|
||||||
|
|
||||||
`HrmpChannelId` has a defined ordering: first `sender` and tie is resolved by `recipient`.
|
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
struct HrmpChannelId {
|
struct HrmpChannelId {
|
||||||
sender: ParaId,
|
sender: ParaId,
|
||||||
|
|||||||
@@ -77,18 +77,24 @@ struct HostConfiguration {
|
|||||||
/// The deposit that the recipient should provide for accepting opening an HRMP channel.
|
/// The deposit that the recipient should provide for accepting opening an HRMP channel.
|
||||||
pub hrmp_recipient_deposit: u32,
|
pub hrmp_recipient_deposit: u32,
|
||||||
/// The maximum number of messages allowed in an HRMP channel at once.
|
/// The maximum number of messages allowed in an HRMP channel at once.
|
||||||
pub hrmp_channel_max_places: u32,
|
pub hrmp_channel_max_capacity: u32,
|
||||||
/// The maximum total size of messages in bytes allowed in an HRMP channel at once.
|
/// The maximum total size of messages in bytes allowed in an HRMP channel at once.
|
||||||
pub hrmp_channel_max_size: u32,
|
pub hrmp_channel_max_total_size: u32,
|
||||||
/// The maximum number of inbound HRMP channels a parachain is allowed to accept.
|
/// The maximum number of inbound HRMP channels a parachain is allowed to accept.
|
||||||
pub hrmp_max_parachain_inbound_channels: u32,
|
pub hrmp_max_parachain_inbound_channels: u32,
|
||||||
/// The maximum number of inbound HRMP channels a parathread is allowed to accept.
|
/// The maximum number of inbound HRMP channels a parathread is allowed to accept.
|
||||||
pub hrmp_max_parathread_inbound_channels: u32,
|
pub hrmp_max_parathread_inbound_channels: u32,
|
||||||
/// The maximum size of a message that could ever be put into an HRMP channel.
|
/// The maximum size of a message that could ever be put into an HRMP channel.
|
||||||
|
///
|
||||||
|
/// This parameter affects the upper bound of size of `CandidateCommitments`.
|
||||||
pub hrmp_channel_max_message_size: u32,
|
pub hrmp_channel_max_message_size: u32,
|
||||||
/// The maximum number of outbound HRMP channels a parachain is allowed to open.
|
/// The maximum number of outbound HRMP channels a parachain is allowed to open.
|
||||||
pub hrmp_max_parachain_outbound_channels: u32,
|
pub hrmp_max_parachain_outbound_channels: u32,
|
||||||
/// The maximum number of outbound HRMP channels a parathread is allowed to open.
|
/// The maximum number of outbound HRMP channels a parathread is allowed to open.
|
||||||
pub hrmp_max_parathread_outbound_channels: u32,
|
pub hrmp_max_parathread_outbound_channels: u32,
|
||||||
|
/// The maximum number of outbound HRMP messages can be sent by a candidate.
|
||||||
|
///
|
||||||
|
/// This parameter affects the upper bound of size of `CandidateCommitments`.
|
||||||
|
pub hrmp_max_message_num_per_candidate: u32,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -427,6 +427,7 @@ mod tests {
|
|||||||
|
|
||||||
impl router::Trait for Test {
|
impl router::Trait for Test {
|
||||||
type UmpSink = ();
|
type UmpSink = ();
|
||||||
|
type Origin = Origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl pallet_session::historical::Trait for Test {
|
impl pallet_session::historical::Trait for Test {
|
||||||
|
|||||||
@@ -22,12 +22,14 @@
|
|||||||
|
|
||||||
use pallet_transaction_payment::CurrencyAdapter;
|
use pallet_transaction_payment::CurrencyAdapter;
|
||||||
use sp_std::prelude::*;
|
use sp_std::prelude::*;
|
||||||
|
use sp_std::collections::btree_map::BTreeMap;
|
||||||
use sp_core::u32_trait::{_1, _2, _3, _5};
|
use sp_core::u32_trait::{_1, _2, _3, _5};
|
||||||
use codec::{Encode, Decode};
|
use codec::{Encode, Decode};
|
||||||
use primitives::v1::{
|
use primitives::v1::{
|
||||||
AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CommittedCandidateReceipt,
|
AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CommittedCandidateReceipt,
|
||||||
CoreState, GroupRotationInfo, Hash, Id, Moment, Nonce, OccupiedCoreAssumption,
|
CoreState, GroupRotationInfo, Hash, Id, Moment, Nonce, OccupiedCoreAssumption,
|
||||||
PersistedValidationData, Signature, ValidationCode, ValidationData, ValidatorId, ValidatorIndex,
|
PersistedValidationData, Signature, ValidationCode, ValidationData, ValidatorId, ValidatorIndex,
|
||||||
|
InboundDownwardMessage, InboundHrmpMessage,
|
||||||
};
|
};
|
||||||
use runtime_common::{
|
use runtime_common::{
|
||||||
claims, SlowAdjustingFeeUpdate, CurrencyToVote,
|
claims, SlowAdjustingFeeUpdate, CurrencyToVote,
|
||||||
@@ -1112,9 +1114,15 @@ sp_api::impl_runtime_apis! {
|
|||||||
|
|
||||||
fn dmq_contents(
|
fn dmq_contents(
|
||||||
_recipient: Id,
|
_recipient: Id,
|
||||||
) -> Vec<primitives::v1::InboundDownwardMessage<BlockNumber>> {
|
) -> Vec<InboundDownwardMessage<BlockNumber>> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inbound_hrmp_channels_contents(
|
||||||
|
_recipient: Id
|
||||||
|
) -> BTreeMap<Id, Vec<InboundHrmpMessage<BlockNumber>>> {
|
||||||
|
BTreeMap::new()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fg_primitives::GrandpaApi<Block> for Runtime {
|
impl fg_primitives::GrandpaApi<Block> for Runtime {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ pallet-vesting = { git = "https://github.com/paritytech/substrate", branch = "ma
|
|||||||
pallet-offences = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
pallet-offences = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||||
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }
|
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }
|
||||||
|
|
||||||
|
xcm = { package = "xcm", path = "../../xcm", default-features = false }
|
||||||
primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false }
|
primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false }
|
||||||
libsecp256k1 = { version = "0.3.2", default-features = false, optional = true }
|
libsecp256k1 = { version = "0.3.2", default-features = false, optional = true }
|
||||||
|
|
||||||
@@ -81,6 +82,7 @@ std = [
|
|||||||
"frame-system/std",
|
"frame-system/std",
|
||||||
"pallet-timestamp/std",
|
"pallet-timestamp/std",
|
||||||
"pallet-vesting/std",
|
"pallet-vesting/std",
|
||||||
|
"xcm/std",
|
||||||
]
|
]
|
||||||
runtime-benchmarks = [
|
runtime-benchmarks = [
|
||||||
"libsecp256k1/hmac",
|
"libsecp256k1/hmac",
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
//! Configuration can change only at session boundaries and is buffered until then.
|
//! Configuration can change only at session boundaries and is buffered until then.
|
||||||
|
|
||||||
use sp_std::prelude::*;
|
use sp_std::prelude::*;
|
||||||
use primitives::v1::ValidatorId;
|
use primitives::v1::{Balance, ValidatorId};
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
decl_storage, decl_module, decl_error,
|
decl_storage, decl_module, decl_error,
|
||||||
dispatch::DispatchResult,
|
dispatch::DispatchResult,
|
||||||
@@ -84,6 +84,32 @@ pub struct HostConfiguration<BlockNumber> {
|
|||||||
///
|
///
|
||||||
/// This parameter affects the size upper bound of the `CandidateCommitments`.
|
/// This parameter affects the size upper bound of the `CandidateCommitments`.
|
||||||
pub max_upward_message_num_per_candidate: u32,
|
pub max_upward_message_num_per_candidate: u32,
|
||||||
|
/// Number of sessions after which an HRMP open channel request expires.
|
||||||
|
pub hrmp_open_request_ttl: u32,
|
||||||
|
/// The deposit that the sender should provide for opening an HRMP channel.
|
||||||
|
pub hrmp_sender_deposit: Balance,
|
||||||
|
/// The deposit that the recipient should provide for accepting opening an HRMP channel.
|
||||||
|
pub hrmp_recipient_deposit: Balance,
|
||||||
|
/// The maximum number of messages allowed in an HRMP channel at once.
|
||||||
|
pub hrmp_channel_max_capacity: u32,
|
||||||
|
/// The maximum total size of messages in bytes allowed in an HRMP channel at once.
|
||||||
|
pub hrmp_channel_max_total_size: u32,
|
||||||
|
/// The maximum number of inbound HRMP channels a parachain is allowed to accept.
|
||||||
|
pub hrmp_max_parachain_inbound_channels: u32,
|
||||||
|
/// The maximum number of inbound HRMP channels a parathread is allowed to accept.
|
||||||
|
pub hrmp_max_parathread_inbound_channels: u32,
|
||||||
|
/// The maximum size of a message that could ever be put into an HRMP channel.
|
||||||
|
///
|
||||||
|
/// This parameter affects the upper bound of size of `CandidateCommitments`.
|
||||||
|
pub hrmp_channel_max_message_size: u32,
|
||||||
|
/// The maximum number of outbound HRMP channels a parachain is allowed to open.
|
||||||
|
pub hrmp_max_parachain_outbound_channels: u32,
|
||||||
|
/// The maximum number of outbound HRMP channels a parathread is allowed to open.
|
||||||
|
pub hrmp_max_parathread_outbound_channels: u32,
|
||||||
|
/// The maximum number of outbound HRMP messages can be sent by a candidate.
|
||||||
|
///
|
||||||
|
/// This parameter affects the upper bound of size of `CandidateCommitments`.
|
||||||
|
pub hrmp_max_message_num_per_candidate: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Trait: frame_system::Trait { }
|
pub trait Trait: frame_system::Trait { }
|
||||||
@@ -276,6 +302,117 @@ decl_module! {
|
|||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the number of sessions after which an HRMP open channel request expires.
|
||||||
|
#[weight = (1_000, DispatchClass::Operational)]
|
||||||
|
pub fn set_hrmp_open_request_ttl(origin, new: u32) -> DispatchResult {
|
||||||
|
ensure_root(origin)?;
|
||||||
|
Self::update_config_member(|config| {
|
||||||
|
sp_std::mem::replace(&mut config.hrmp_open_request_ttl, new) != new
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the amount of funds that the sender should provide for opening an HRMP channel.
|
||||||
|
#[weight = (1_000, DispatchClass::Operational)]
|
||||||
|
pub fn set_hrmp_sender_deposit(origin, new: Balance) -> DispatchResult {
|
||||||
|
ensure_root(origin)?;
|
||||||
|
Self::update_config_member(|config| {
|
||||||
|
sp_std::mem::replace(&mut config.hrmp_sender_deposit, new) != new
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the amount of funds that the recipient should provide for accepting opening an HRMP
|
||||||
|
/// channel.
|
||||||
|
#[weight = (1_000, DispatchClass::Operational)]
|
||||||
|
pub fn set_hrmp_recipient_deposit(origin, new: Balance) -> DispatchResult {
|
||||||
|
ensure_root(origin)?;
|
||||||
|
Self::update_config_member(|config| {
|
||||||
|
sp_std::mem::replace(&mut config.hrmp_recipient_deposit, new) != new
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the maximum number of messages allowed in an HRMP channel at once.
|
||||||
|
#[weight = (1_000, DispatchClass::Operational)]
|
||||||
|
pub fn set_hrmp_channel_max_capacity(origin, new: u32) -> DispatchResult {
|
||||||
|
ensure_root(origin)?;
|
||||||
|
Self::update_config_member(|config| {
|
||||||
|
sp_std::mem::replace(&mut config.hrmp_channel_max_capacity, new) != new
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the maximum total size of messages in bytes allowed in an HRMP channel at once.
|
||||||
|
#[weight = (1_000, DispatchClass::Operational)]
|
||||||
|
pub fn set_hrmp_channel_max_total_size(origin, new: u32) -> DispatchResult {
|
||||||
|
ensure_root(origin)?;
|
||||||
|
Self::update_config_member(|config| {
|
||||||
|
sp_std::mem::replace(&mut config.hrmp_channel_max_total_size, new) != new
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the maximum number of inbound HRMP channels a parachain is allowed to accept.
|
||||||
|
#[weight = (1_000, DispatchClass::Operational)]
|
||||||
|
pub fn set_hrmp_max_parachain_inbound_channels(origin, new: u32) -> DispatchResult {
|
||||||
|
ensure_root(origin)?;
|
||||||
|
Self::update_config_member(|config| {
|
||||||
|
sp_std::mem::replace(&mut config.hrmp_max_parachain_inbound_channels, new) != new
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the maximum number of inbound HRMP channels a parathread is allowed to accept.
|
||||||
|
#[weight = (1_000, DispatchClass::Operational)]
|
||||||
|
pub fn set_hrmp_max_parathread_inbound_channels(origin, new: u32) -> DispatchResult {
|
||||||
|
ensure_root(origin)?;
|
||||||
|
Self::update_config_member(|config| {
|
||||||
|
sp_std::mem::replace(&mut config.hrmp_max_parathread_inbound_channels, new) != new
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the maximum size of a message that could ever be put into an HRMP channel.
|
||||||
|
#[weight = (1_000, DispatchClass::Operational)]
|
||||||
|
pub fn set_hrmp_channel_max_message_size(origin, new: u32) -> DispatchResult {
|
||||||
|
ensure_root(origin)?;
|
||||||
|
Self::update_config_member(|config| {
|
||||||
|
sp_std::mem::replace(&mut config.hrmp_channel_max_message_size, new) != new
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the maximum number of outbound HRMP channels a parachain is allowed to open.
|
||||||
|
#[weight = (1_000, DispatchClass::Operational)]
|
||||||
|
pub fn set_hrmp_max_parachain_outbound_channels(origin, new: u32) -> DispatchResult {
|
||||||
|
ensure_root(origin)?;
|
||||||
|
Self::update_config_member(|config| {
|
||||||
|
sp_std::mem::replace(&mut config.hrmp_max_parachain_outbound_channels, new) != new
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the maximum number of outbound HRMP channels a parathread is allowed to open.
|
||||||
|
#[weight = (1_000, DispatchClass::Operational)]
|
||||||
|
pub fn set_hrmp_max_parathread_outbound_channels(origin, new: u32) -> DispatchResult {
|
||||||
|
ensure_root(origin)?;
|
||||||
|
Self::update_config_member(|config| {
|
||||||
|
sp_std::mem::replace(&mut config.hrmp_max_parathread_outbound_channels, new) != new
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the maximum number of outbound HRMP messages can be sent by a candidate.
|
||||||
|
#[weight = (1_000, DispatchClass::Operational)]
|
||||||
|
pub fn set_hrmp_max_message_num_per_candidate(origin, new: u32) -> DispatchResult {
|
||||||
|
ensure_root(origin)?;
|
||||||
|
Self::update_config_member(|config| {
|
||||||
|
sp_std::mem::replace(&mut config.hrmp_max_message_num_per_candidate, new) != new
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,6 +497,17 @@ mod tests {
|
|||||||
preferred_dispatchable_upward_messages_step_weight: 20000,
|
preferred_dispatchable_upward_messages_step_weight: 20000,
|
||||||
max_upward_message_size: 448,
|
max_upward_message_size: 448,
|
||||||
max_upward_message_num_per_candidate: 5,
|
max_upward_message_num_per_candidate: 5,
|
||||||
|
hrmp_open_request_ttl: 1312,
|
||||||
|
hrmp_sender_deposit: 22,
|
||||||
|
hrmp_recipient_deposit: 4905,
|
||||||
|
hrmp_channel_max_capacity: 3921,
|
||||||
|
hrmp_channel_max_total_size: 7687,
|
||||||
|
hrmp_max_parachain_inbound_channels: 3722,
|
||||||
|
hrmp_max_parathread_inbound_channels: 1967,
|
||||||
|
hrmp_channel_max_message_size: 8192,
|
||||||
|
hrmp_max_parachain_outbound_channels: 100,
|
||||||
|
hrmp_max_parathread_outbound_channels: 200,
|
||||||
|
hrmp_max_message_num_per_candidate: 20,
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(<Configuration as Store>::PendingConfig::get().is_none());
|
assert!(<Configuration as Store>::PendingConfig::get().is_none());
|
||||||
@@ -415,6 +563,50 @@ mod tests {
|
|||||||
Configuration::set_max_upward_message_num_per_candidate(
|
Configuration::set_max_upward_message_num_per_candidate(
|
||||||
Origin::root(), new_config.max_upward_message_num_per_candidate,
|
Origin::root(), new_config.max_upward_message_num_per_candidate,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
Configuration::set_hrmp_open_request_ttl(
|
||||||
|
Origin::root(),
|
||||||
|
new_config.hrmp_open_request_ttl,
|
||||||
|
).unwrap();
|
||||||
|
Configuration::set_hrmp_sender_deposit(
|
||||||
|
Origin::root(),
|
||||||
|
new_config.hrmp_sender_deposit,
|
||||||
|
).unwrap();
|
||||||
|
Configuration::set_hrmp_recipient_deposit(
|
||||||
|
Origin::root(),
|
||||||
|
new_config.hrmp_recipient_deposit,
|
||||||
|
).unwrap();
|
||||||
|
Configuration::set_hrmp_channel_max_capacity(
|
||||||
|
Origin::root(),
|
||||||
|
new_config.hrmp_channel_max_capacity,
|
||||||
|
).unwrap();
|
||||||
|
Configuration::set_hrmp_channel_max_total_size(
|
||||||
|
Origin::root(),
|
||||||
|
new_config.hrmp_channel_max_total_size,
|
||||||
|
).unwrap();
|
||||||
|
Configuration::set_hrmp_max_parachain_inbound_channels(
|
||||||
|
Origin::root(),
|
||||||
|
new_config.hrmp_max_parachain_inbound_channels,
|
||||||
|
).unwrap();
|
||||||
|
Configuration::set_hrmp_max_parathread_inbound_channels(
|
||||||
|
Origin::root(),
|
||||||
|
new_config.hrmp_max_parathread_inbound_channels,
|
||||||
|
).unwrap();
|
||||||
|
Configuration::set_hrmp_channel_max_message_size(
|
||||||
|
Origin::root(),
|
||||||
|
new_config.hrmp_channel_max_message_size,
|
||||||
|
).unwrap();
|
||||||
|
Configuration::set_hrmp_max_parachain_outbound_channels(
|
||||||
|
Origin::root(),
|
||||||
|
new_config.hrmp_max_parachain_outbound_channels,
|
||||||
|
).unwrap();
|
||||||
|
Configuration::set_hrmp_max_parathread_outbound_channels(
|
||||||
|
Origin::root(),
|
||||||
|
new_config.hrmp_max_parathread_outbound_channels,
|
||||||
|
).unwrap();
|
||||||
|
Configuration::set_hrmp_max_message_num_per_candidate(
|
||||||
|
Origin::root(),
|
||||||
|
new_config.hrmp_max_message_num_per_candidate,
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
assert_eq!(<Configuration as Store>::PendingConfig::get(), Some(new_config));
|
assert_eq!(<Configuration as Store>::PendingConfig::get(), Some(new_config));
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -157,6 +157,10 @@ decl_error! {
|
|||||||
IncorrectDownwardMessageHandling,
|
IncorrectDownwardMessageHandling,
|
||||||
/// At least one upward message sent does not pass the acceptance criteria.
|
/// At least one upward message sent does not pass the acceptance criteria.
|
||||||
InvalidUpwardMessages,
|
InvalidUpwardMessages,
|
||||||
|
/// The candidate didn't follow the rules of HRMP watermark advancement.
|
||||||
|
HrmpWatermarkMishandling,
|
||||||
|
/// The HRMP messages sent by the candidate is not valid.
|
||||||
|
InvalidOutboundHrmp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,6 +419,8 @@ impl<T: Trait> Module<T> {
|
|||||||
&candidate.candidate.commitments.new_validation_code,
|
&candidate.candidate.commitments.new_validation_code,
|
||||||
candidate.candidate.commitments.processed_downward_messages,
|
candidate.candidate.commitments.processed_downward_messages,
|
||||||
&candidate.candidate.commitments.upward_messages,
|
&candidate.candidate.commitments.upward_messages,
|
||||||
|
T::BlockNumber::from(candidate.candidate.commitments.hrmp_watermark),
|
||||||
|
&candidate.candidate.commitments.horizontal_messages,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
for (i, assignment) in scheduled[skip..].iter().enumerate() {
|
for (i, assignment) in scheduled[skip..].iter().enumerate() {
|
||||||
@@ -548,6 +554,8 @@ impl<T: Trait> Module<T> {
|
|||||||
&validation_outputs.new_validation_code,
|
&validation_outputs.new_validation_code,
|
||||||
validation_outputs.processed_downward_messages,
|
validation_outputs.processed_downward_messages,
|
||||||
&validation_outputs.upward_messages,
|
&validation_outputs.upward_messages,
|
||||||
|
T::BlockNumber::from(validation_outputs.hrmp_watermark),
|
||||||
|
&validation_outputs.horizontal_messages,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -578,6 +586,14 @@ impl<T: Trait> Module<T> {
|
|||||||
receipt.descriptor.para_id,
|
receipt.descriptor.para_id,
|
||||||
commitments.upward_messages,
|
commitments.upward_messages,
|
||||||
);
|
);
|
||||||
|
weight += <router::Module<T>>::prune_hrmp(
|
||||||
|
receipt.descriptor.para_id,
|
||||||
|
T::BlockNumber::from(commitments.hrmp_watermark),
|
||||||
|
);
|
||||||
|
weight += <router::Module<T>>::queue_outbound_hrmp(
|
||||||
|
receipt.descriptor.para_id,
|
||||||
|
commitments.horizontal_messages,
|
||||||
|
);
|
||||||
|
|
||||||
Self::deposit_event(
|
Self::deposit_event(
|
||||||
Event::<T>::CandidateIncluded(plain, commitments.head_data.clone())
|
Event::<T>::CandidateIncluded(plain, commitments.head_data.clone())
|
||||||
@@ -702,6 +718,8 @@ impl<T: Trait> CandidateCheckContext<T> {
|
|||||||
new_validation_code: &Option<primitives::v1::ValidationCode>,
|
new_validation_code: &Option<primitives::v1::ValidationCode>,
|
||||||
processed_downward_messages: u32,
|
processed_downward_messages: u32,
|
||||||
upward_messages: &[primitives::v1::UpwardMessage],
|
upward_messages: &[primitives::v1::UpwardMessage],
|
||||||
|
hrmp_watermark: T::BlockNumber,
|
||||||
|
horizontal_messages: &[primitives::v1::OutboundHrmpMessage<ParaId>],
|
||||||
) -> Result<(), DispatchError> {
|
) -> Result<(), DispatchError> {
|
||||||
ensure!(
|
ensure!(
|
||||||
head_data.0.len() <= self.config.max_head_data_size as _,
|
head_data.0.len() <= self.config.max_head_data_size as _,
|
||||||
@@ -739,6 +757,22 @@ impl<T: Trait> CandidateCheckContext<T> {
|
|||||||
),
|
),
|
||||||
Error::<T>::InvalidUpwardMessages,
|
Error::<T>::InvalidUpwardMessages,
|
||||||
);
|
);
|
||||||
|
ensure!(
|
||||||
|
<router::Module<T>>::check_hrmp_watermark(
|
||||||
|
para_id,
|
||||||
|
self.relay_parent_number,
|
||||||
|
hrmp_watermark,
|
||||||
|
),
|
||||||
|
Error::<T>::HrmpWatermarkMishandling,
|
||||||
|
);
|
||||||
|
ensure!(
|
||||||
|
<router::Module<T>>::check_outbound_hrmp(
|
||||||
|
&self.config,
|
||||||
|
para_id,
|
||||||
|
horizontal_messages,
|
||||||
|
),
|
||||||
|
Error::<T>::InvalidOutboundHrmp,
|
||||||
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -946,6 +980,7 @@ mod tests {
|
|||||||
relay_parent: Hash,
|
relay_parent: Hash,
|
||||||
persisted_validation_data_hash: Hash,
|
persisted_validation_data_hash: Hash,
|
||||||
new_validation_code: Option<ValidationCode>,
|
new_validation_code: Option<ValidationCode>,
|
||||||
|
hrmp_watermark: BlockNumber,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestCandidateBuilder {
|
impl TestCandidateBuilder {
|
||||||
@@ -961,6 +996,7 @@ mod tests {
|
|||||||
commitments: CandidateCommitments {
|
commitments: CandidateCommitments {
|
||||||
head_data: self.head_data,
|
head_data: self.head_data,
|
||||||
new_validation_code: self.new_validation_code,
|
new_validation_code: self.new_validation_code,
|
||||||
|
hrmp_watermark: self.hrmp_watermark,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -1359,6 +1395,9 @@ mod tests {
|
|||||||
let chain_b = ParaId::from(2);
|
let chain_b = ParaId::from(2);
|
||||||
let thread_a = ParaId::from(3);
|
let thread_a = ParaId::from(3);
|
||||||
|
|
||||||
|
// The block number of the relay-parent for testing.
|
||||||
|
const RELAY_PARENT_NUM: BlockNumber = 4;
|
||||||
|
|
||||||
let paras = vec![(chain_a, true), (chain_b, true), (thread_a, false)];
|
let paras = vec![(chain_a, true), (chain_b, true), (thread_a, false)];
|
||||||
let validators = vec![
|
let validators = vec![
|
||||||
Sr25519Keyring::Alice,
|
Sr25519Keyring::Alice,
|
||||||
@@ -1421,6 +1460,7 @@ mod tests {
|
|||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([1; 32]),
|
pov_hash: Hash::from([1; 32]),
|
||||||
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||||
|
hrmp_watermark: RELAY_PARENT_NUM,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
collator_sign_candidate(
|
collator_sign_candidate(
|
||||||
@@ -1454,6 +1494,7 @@ mod tests {
|
|||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([1; 32]),
|
pov_hash: Hash::from([1; 32]),
|
||||||
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||||
|
hrmp_watermark: RELAY_PARENT_NUM,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
let mut candidate_b = TestCandidateBuilder {
|
let mut candidate_b = TestCandidateBuilder {
|
||||||
@@ -1461,6 +1502,7 @@ mod tests {
|
|||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([2; 32]),
|
pov_hash: Hash::from([2; 32]),
|
||||||
persisted_validation_data_hash: make_vdata_hash(chain_b).unwrap(),
|
persisted_validation_data_hash: make_vdata_hash(chain_b).unwrap(),
|
||||||
|
hrmp_watermark: RELAY_PARENT_NUM,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
|
|
||||||
@@ -1510,6 +1552,7 @@ mod tests {
|
|||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([1; 32]),
|
pov_hash: Hash::from([1; 32]),
|
||||||
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||||
|
hrmp_watermark: RELAY_PARENT_NUM,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
collator_sign_candidate(
|
collator_sign_candidate(
|
||||||
@@ -1579,6 +1622,7 @@ mod tests {
|
|||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([1; 32]),
|
pov_hash: Hash::from([1; 32]),
|
||||||
persisted_validation_data_hash: make_vdata_hash(thread_a).unwrap(),
|
persisted_validation_data_hash: make_vdata_hash(thread_a).unwrap(),
|
||||||
|
hrmp_watermark: RELAY_PARENT_NUM,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
|
|
||||||
@@ -1618,6 +1662,7 @@ mod tests {
|
|||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([1; 32]),
|
pov_hash: Hash::from([1; 32]),
|
||||||
persisted_validation_data_hash: make_vdata_hash(thread_a).unwrap(),
|
persisted_validation_data_hash: make_vdata_hash(thread_a).unwrap(),
|
||||||
|
hrmp_watermark: RELAY_PARENT_NUM,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
|
|
||||||
@@ -1656,6 +1701,7 @@ mod tests {
|
|||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([1; 32]),
|
pov_hash: Hash::from([1; 32]),
|
||||||
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||||
|
hrmp_watermark: RELAY_PARENT_NUM,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
|
|
||||||
@@ -1703,6 +1749,7 @@ mod tests {
|
|||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([1; 32]),
|
pov_hash: Hash::from([1; 32]),
|
||||||
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||||
|
hrmp_watermark: RELAY_PARENT_NUM,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
|
|
||||||
@@ -1743,6 +1790,7 @@ mod tests {
|
|||||||
pov_hash: Hash::from([1; 32]),
|
pov_hash: Hash::from([1; 32]),
|
||||||
new_validation_code: Some(vec![5, 6, 7, 8].into()),
|
new_validation_code: Some(vec![5, 6, 7, 8].into()),
|
||||||
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||||
|
hrmp_watermark: RELAY_PARENT_NUM,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
|
|
||||||
@@ -1785,6 +1833,7 @@ mod tests {
|
|||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([1; 32]),
|
pov_hash: Hash::from([1; 32]),
|
||||||
persisted_validation_data_hash: [42u8; 32].into(),
|
persisted_validation_data_hash: [42u8; 32].into(),
|
||||||
|
hrmp_watermark: RELAY_PARENT_NUM,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
|
|
||||||
@@ -1820,6 +1869,9 @@ mod tests {
|
|||||||
let chain_b = ParaId::from(2);
|
let chain_b = ParaId::from(2);
|
||||||
let thread_a = ParaId::from(3);
|
let thread_a = ParaId::from(3);
|
||||||
|
|
||||||
|
// The block number of the relay-parent for testing.
|
||||||
|
const RELAY_PARENT_NUM: BlockNumber = 4;
|
||||||
|
|
||||||
let paras = vec![(chain_a, true), (chain_b, true), (thread_a, false)];
|
let paras = vec![(chain_a, true), (chain_b, true), (thread_a, false)];
|
||||||
let validators = vec![
|
let validators = vec![
|
||||||
Sr25519Keyring::Alice,
|
Sr25519Keyring::Alice,
|
||||||
@@ -1880,6 +1932,7 @@ mod tests {
|
|||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([1; 32]),
|
pov_hash: Hash::from([1; 32]),
|
||||||
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||||
|
hrmp_watermark: RELAY_PARENT_NUM,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
collator_sign_candidate(
|
collator_sign_candidate(
|
||||||
@@ -1892,6 +1945,7 @@ mod tests {
|
|||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([2; 32]),
|
pov_hash: Hash::from([2; 32]),
|
||||||
persisted_validation_data_hash: make_vdata_hash(chain_b).unwrap(),
|
persisted_validation_data_hash: make_vdata_hash(chain_b).unwrap(),
|
||||||
|
hrmp_watermark: RELAY_PARENT_NUM,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
collator_sign_candidate(
|
collator_sign_candidate(
|
||||||
@@ -1904,6 +1958,7 @@ mod tests {
|
|||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([3; 32]),
|
pov_hash: Hash::from([3; 32]),
|
||||||
persisted_validation_data_hash: make_vdata_hash(thread_a).unwrap(),
|
persisted_validation_data_hash: make_vdata_hash(thread_a).unwrap(),
|
||||||
|
hrmp_watermark: RELAY_PARENT_NUM,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
collator_sign_candidate(
|
collator_sign_candidate(
|
||||||
@@ -2001,6 +2056,9 @@ mod tests {
|
|||||||
fn can_include_candidate_with_ok_code_upgrade() {
|
fn can_include_candidate_with_ok_code_upgrade() {
|
||||||
let chain_a = ParaId::from(1);
|
let chain_a = ParaId::from(1);
|
||||||
|
|
||||||
|
// The block number of the relay-parent for testing.
|
||||||
|
const RELAY_PARENT_NUM: BlockNumber = 4;
|
||||||
|
|
||||||
let paras = vec![(chain_a, true)];
|
let paras = vec![(chain_a, true)];
|
||||||
let validators = vec![
|
let validators = vec![
|
||||||
Sr25519Keyring::Alice,
|
Sr25519Keyring::Alice,
|
||||||
@@ -2044,6 +2102,7 @@ mod tests {
|
|||||||
pov_hash: Hash::from([1; 32]),
|
pov_hash: Hash::from([1; 32]),
|
||||||
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||||
new_validation_code: Some(vec![1, 2, 3].into()),
|
new_validation_code: Some(vec![1, 2, 3].into()),
|
||||||
|
hrmp_watermark: RELAY_PARENT_NUM,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
collator_sign_candidate(
|
collator_sign_candidate(
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ impl crate::paras::Trait for Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl crate::router::Trait for Test {
|
impl crate::router::Trait for Test {
|
||||||
|
type Origin = Origin;
|
||||||
type UmpSink = crate::router::MockUmpSink;
|
type UmpSink = crate::router::MockUmpSink;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -541,6 +541,12 @@ impl<T: Trait> Module<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether the given ID refers to a valid para.
|
||||||
|
pub(crate) fn is_valid_para(id: ParaId) -> bool {
|
||||||
|
Self::parachains().binary_search(&id).is_ok()
|
||||||
|
|| Self::is_parathread(id)
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether a para ID corresponds to any live parathread.
|
/// Whether a para ID corresponds to any live parathread.
|
||||||
pub(crate) fn is_parathread(id: ParaId) -> bool {
|
pub(crate) fn is_parathread(id: ParaId) -> bool {
|
||||||
Parathreads::get(&id).is_some()
|
Parathreads::get(&id).is_some()
|
||||||
|
|||||||
@@ -20,25 +20,30 @@
|
|||||||
//! routing the messages at their destinations and informing the parachains about the incoming
|
//! routing the messages at their destinations and informing the parachains about the incoming
|
||||||
//! messages.
|
//! messages.
|
||||||
|
|
||||||
use crate::{
|
use crate::{configuration, paras, initializer, ensure_parachain};
|
||||||
configuration,
|
|
||||||
initializer,
|
|
||||||
};
|
|
||||||
use sp_std::prelude::*;
|
use sp_std::prelude::*;
|
||||||
use frame_support::{decl_error, decl_module, decl_storage, weights::Weight};
|
use frame_support::{decl_error, decl_module, decl_storage, dispatch::DispatchResult, weights::Weight};
|
||||||
use sp_std::collections::vec_deque::VecDeque;
|
use sp_std::collections::vec_deque::VecDeque;
|
||||||
use primitives::v1::{Id as ParaId, InboundDownwardMessage, Hash, UpwardMessage};
|
use primitives::v1::{
|
||||||
|
Id as ParaId, InboundDownwardMessage, Hash, UpwardMessage, HrmpChannelId, InboundHrmpMessage,
|
||||||
|
};
|
||||||
|
|
||||||
mod dmp;
|
mod dmp;
|
||||||
|
mod hrmp;
|
||||||
mod ump;
|
mod ump;
|
||||||
|
|
||||||
|
use hrmp::{HrmpOpenChannelRequest, HrmpChannel};
|
||||||
pub use dmp::QueueDownwardMessageError;
|
pub use dmp::QueueDownwardMessageError;
|
||||||
pub use ump::UmpSink;
|
pub use ump::UmpSink;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub use ump::mock_sink::MockUmpSink;
|
pub use ump::mock_sink::MockUmpSink;
|
||||||
|
|
||||||
pub trait Trait: frame_system::Trait + configuration::Trait {
|
pub trait Trait: frame_system::Trait + configuration::Trait + paras::Trait {
|
||||||
|
type Origin: From<crate::Origin>
|
||||||
|
+ From<<Self as frame_system::Trait>::Origin>
|
||||||
|
+ Into<Result<crate::Origin, <Self as Trait>::Origin>>;
|
||||||
|
|
||||||
/// A place where all received upward messages are funneled.
|
/// A place where all received upward messages are funneled.
|
||||||
type UmpSink: UmpSink;
|
type UmpSink: UmpSink;
|
||||||
}
|
}
|
||||||
@@ -103,17 +108,148 @@ decl_storage! {
|
|||||||
/// Invariant:
|
/// Invariant:
|
||||||
/// - If `Some(para)`, then `para` must be present in `NeedsDispatch`.
|
/// - If `Some(para)`, then `para` must be present in `NeedsDispatch`.
|
||||||
NextDispatchRoundStartWith: Option<ParaId>;
|
NextDispatchRoundStartWith: Option<ParaId>;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Horizontally Relay-routed Message Passing (HRMP)
|
||||||
|
*
|
||||||
|
* HRMP related storage layout
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// The set of pending HRMP open channel requests.
|
||||||
|
///
|
||||||
|
/// The set is accompanied by a list for iteration.
|
||||||
|
///
|
||||||
|
/// Invariant:
|
||||||
|
/// - There are no channels that exists in list but not in the set and vice versa.
|
||||||
|
HrmpOpenChannelRequests: map hasher(twox_64_concat) HrmpChannelId => Option<HrmpOpenChannelRequest>;
|
||||||
|
HrmpOpenChannelRequestsList: Vec<HrmpChannelId>;
|
||||||
|
|
||||||
|
/// This mapping tracks how many open channel requests are inititated by a given sender para.
|
||||||
|
/// Invariant: `HrmpOpenChannelRequests` should contain the same number of items that has `(X, _)`
|
||||||
|
/// as the number of `HrmpOpenChannelRequestCount` for `X`.
|
||||||
|
HrmpOpenChannelRequestCount: map hasher(twox_64_concat) ParaId => u32;
|
||||||
|
/// This mapping tracks how many open channel requests were accepted by a given recipient para.
|
||||||
|
/// Invariant: `HrmpOpenChannelRequests` should contain the same number of items `(_, X)` with
|
||||||
|
/// `confirmed` set to true, as the number of `HrmpAcceptedChannelRequestCount` for `X`.
|
||||||
|
HrmpAcceptedChannelRequestCount: map hasher(twox_64_concat) ParaId => u32;
|
||||||
|
|
||||||
|
/// A set of pending HRMP close channel requests that are going to be closed during the session change.
|
||||||
|
/// Used for checking if a given channel is registered for closure.
|
||||||
|
///
|
||||||
|
/// The set is accompanied by a list for iteration.
|
||||||
|
///
|
||||||
|
/// Invariant:
|
||||||
|
/// - There are no channels that exists in list but not in the set and vice versa.
|
||||||
|
HrmpCloseChannelRequests: map hasher(twox_64_concat) HrmpChannelId => Option<()>;
|
||||||
|
HrmpCloseChannelRequestsList: Vec<HrmpChannelId>;
|
||||||
|
|
||||||
|
/// The HRMP watermark associated with each para.
|
||||||
|
/// Invariant:
|
||||||
|
/// - each para `P` used here as a key should satisfy `Paras::is_valid_para(P)` within a session.
|
||||||
|
HrmpWatermarks: map hasher(twox_64_concat) ParaId => Option<T::BlockNumber>;
|
||||||
|
/// HRMP channel data associated with each para.
|
||||||
|
/// Invariant:
|
||||||
|
/// - each participant in the channel should satisfy `Paras::is_valid_para(P)` within a session.
|
||||||
|
HrmpChannels: map hasher(twox_64_concat) HrmpChannelId => Option<HrmpChannel>;
|
||||||
|
/// Ingress/egress indexes allow to find all the senders and receivers given the opposite
|
||||||
|
/// side. I.e.
|
||||||
|
///
|
||||||
|
/// (a) ingress index allows to find all the senders for a given recipient.
|
||||||
|
/// (b) egress index allows to find all the recipients for a given sender.
|
||||||
|
///
|
||||||
|
/// Invariants:
|
||||||
|
/// - for each ingress index entry for `P` each item `I` in the index should present in `HrmpChannels`
|
||||||
|
/// as `(I, P)`.
|
||||||
|
/// - for each egress index entry for `P` each item `E` in the index should present in `HrmpChannels`
|
||||||
|
/// as `(P, E)`.
|
||||||
|
/// - there should be no other dangling channels in `HrmpChannels`.
|
||||||
|
/// - the vectors are sorted.
|
||||||
|
HrmpIngressChannelsIndex: map hasher(twox_64_concat) ParaId => Vec<ParaId>;
|
||||||
|
HrmpEgressChannelsIndex: map hasher(twox_64_concat) ParaId => Vec<ParaId>;
|
||||||
|
/// Storage for the messages for each channel.
|
||||||
|
/// Invariant: cannot be non-empty if the corresponding channel in `HrmpChannels` is `None`.
|
||||||
|
HrmpChannelContents: map hasher(twox_64_concat) HrmpChannelId => Vec<InboundHrmpMessage<T::BlockNumber>>;
|
||||||
|
/// Maintains a mapping that can be used to answer the question:
|
||||||
|
/// What paras sent a message at the given block number for a given reciever.
|
||||||
|
/// Invariants:
|
||||||
|
/// - The inner `Vec<ParaId>` is never empty.
|
||||||
|
/// - The inner `Vec<ParaId>` cannot store two same `ParaId`.
|
||||||
|
/// - The outer vector is sorted ascending by block number and cannot store two items with the same
|
||||||
|
/// block number.
|
||||||
|
HrmpChannelDigests: map hasher(twox_64_concat) ParaId => Vec<(T::BlockNumber, Vec<ParaId>)>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
decl_error! {
|
decl_error! {
|
||||||
pub enum Error for Module<T: Trait> { }
|
pub enum Error for Module<T: Trait> {
|
||||||
|
/// The sender tried to open a channel to themselves.
|
||||||
|
OpenHrmpChannelToSelf,
|
||||||
|
/// The recipient is not a valid para.
|
||||||
|
OpenHrmpChannelInvalidRecipient,
|
||||||
|
/// The requested capacity is zero.
|
||||||
|
OpenHrmpChannelZeroCapacity,
|
||||||
|
/// The requested capacity exceeds the global limit.
|
||||||
|
OpenHrmpChannelCapacityExceedsLimit,
|
||||||
|
/// The requested maximum message size is 0.
|
||||||
|
OpenHrmpChannelZeroMessageSize,
|
||||||
|
/// The open request requested the message size that exceeds the global limit.
|
||||||
|
OpenHrmpChannelMessageSizeExceedsLimit,
|
||||||
|
/// The channel already exists
|
||||||
|
OpenHrmpChannelAlreadyExists,
|
||||||
|
/// There is already a request to open the same channel.
|
||||||
|
OpenHrmpChannelAlreadyRequested,
|
||||||
|
/// The sender already has the maximum number of allowed outbound channels.
|
||||||
|
OpenHrmpChannelLimitExceeded,
|
||||||
|
/// The channel from the sender to the origin doesn't exist.
|
||||||
|
AcceptHrmpChannelDoesntExist,
|
||||||
|
/// The channel is already confirmed.
|
||||||
|
AcceptHrmpChannelAlreadyConfirmed,
|
||||||
|
/// The recipient already has the maximum number of allowed inbound channels.
|
||||||
|
AcceptHrmpChannelLimitExceeded,
|
||||||
|
/// The origin tries to close a channel where it is neither the sender nor the recipient.
|
||||||
|
CloseHrmpChannelUnauthorized,
|
||||||
|
/// The channel to be closed doesn't exist.
|
||||||
|
CloseHrmpChannelDoesntExist,
|
||||||
|
/// The channel close request is already requested.
|
||||||
|
CloseHrmpChannelAlreadyUnderway,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
decl_module! {
|
decl_module! {
|
||||||
/// The router module.
|
/// The router module.
|
||||||
pub struct Module<T: Trait> for enum Call where origin: <T as frame_system::Trait>::Origin {
|
pub struct Module<T: Trait> for enum Call where origin: <T as frame_system::Trait>::Origin {
|
||||||
type Error = Error<T>;
|
type Error = Error<T>;
|
||||||
|
|
||||||
|
#[weight = 0]
|
||||||
|
fn hrmp_init_open_channel(
|
||||||
|
origin,
|
||||||
|
recipient: ParaId,
|
||||||
|
proposed_max_capacity: u32,
|
||||||
|
proposed_max_message_size: u32,
|
||||||
|
) -> DispatchResult {
|
||||||
|
let origin = ensure_parachain(<T as Trait>::Origin::from(origin))?;
|
||||||
|
Self::init_open_channel(
|
||||||
|
origin,
|
||||||
|
recipient,
|
||||||
|
proposed_max_capacity,
|
||||||
|
proposed_max_message_size
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[weight = 0]
|
||||||
|
fn hrmp_accept_open_channel(origin, sender: ParaId) -> DispatchResult {
|
||||||
|
let origin = ensure_parachain(<T as Trait>::Origin::from(origin))?;
|
||||||
|
Self::accept_open_channel(origin, sender)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[weight = 0]
|
||||||
|
fn hrmp_close_channel(origin, channel_id: HrmpChannelId) -> DispatchResult {
|
||||||
|
let origin = ensure_parachain(<T as Trait>::Origin::from(origin))?;
|
||||||
|
Self::close_channel(origin, channel_id)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,12 +264,21 @@ impl<T: Trait> Module<T> {
|
|||||||
|
|
||||||
/// Called by the initializer to note that a new session has started.
|
/// Called by the initializer to note that a new session has started.
|
||||||
pub(crate) fn initializer_on_new_session(
|
pub(crate) fn initializer_on_new_session(
|
||||||
_notification: &initializer::SessionChangeNotification<T::BlockNumber>,
|
notification: &initializer::SessionChangeNotification<T::BlockNumber>,
|
||||||
) {
|
) {
|
||||||
|
Self::perform_outgoing_para_cleanup();
|
||||||
|
Self::process_hrmp_open_channel_requests(¬ification.prev_config);
|
||||||
|
Self::process_hrmp_close_channel_requests();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterate over all paras that were registered for offboarding and remove all the data
|
||||||
|
/// associated with them.
|
||||||
|
fn perform_outgoing_para_cleanup() {
|
||||||
let outgoing = OutgoingParas::take();
|
let outgoing = OutgoingParas::take();
|
||||||
for outgoing_para in outgoing {
|
for outgoing_para in outgoing {
|
||||||
Self::clean_dmp_after_outgoing(outgoing_para);
|
Self::clean_dmp_after_outgoing(outgoing_para);
|
||||||
Self::clean_ump_after_outgoing(outgoing_para);
|
Self::clean_ump_after_outgoing(outgoing_para);
|
||||||
|
Self::clean_hrmp_after_outgoing(outgoing_para);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -18,12 +18,13 @@
|
|||||||
//! functions.
|
//! functions.
|
||||||
|
|
||||||
use sp_std::prelude::*;
|
use sp_std::prelude::*;
|
||||||
|
use sp_std::collections::btree_map::BTreeMap;
|
||||||
use primitives::v1::{
|
use primitives::v1::{
|
||||||
ValidatorId, ValidatorIndex, GroupRotationInfo, CoreState, ValidationData,
|
ValidatorId, ValidatorIndex, GroupRotationInfo, CoreState, ValidationData,
|
||||||
Id as ParaId, OccupiedCoreAssumption, SessionIndex, ValidationCode,
|
Id as ParaId, OccupiedCoreAssumption, SessionIndex, ValidationCode,
|
||||||
CommittedCandidateReceipt, ScheduledCore, OccupiedCore, CoreOccupied, CoreIndex,
|
CommittedCandidateReceipt, ScheduledCore, OccupiedCore, CoreOccupied, CoreIndex,
|
||||||
GroupIndex, CandidateEvent, PersistedValidationData, AuthorityDiscoveryId,
|
GroupIndex, CandidateEvent, PersistedValidationData, AuthorityDiscoveryId,
|
||||||
InboundDownwardMessage,
|
InboundDownwardMessage, InboundHrmpMessage,
|
||||||
};
|
};
|
||||||
use sp_runtime::traits::Zero;
|
use sp_runtime::traits::Zero;
|
||||||
use frame_support::debug;
|
use frame_support::debug;
|
||||||
@@ -328,3 +329,10 @@ pub fn dmq_contents<T: router::Trait>(
|
|||||||
) -> Vec<InboundDownwardMessage<T::BlockNumber>> {
|
) -> Vec<InboundDownwardMessage<T::BlockNumber>> {
|
||||||
<router::Module<T>>::dmq_contents(recipient)
|
<router::Module<T>>::dmq_contents(recipient)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Implementation for the `inbound_hrmp_channels_contents` function of the runtime API.
|
||||||
|
pub fn inbound_hrmp_channels_contents<T: router::Trait>(
|
||||||
|
recipient: ParaId,
|
||||||
|
) -> BTreeMap<ParaId, Vec<InboundHrmpMessage<T::BlockNumber>>> {
|
||||||
|
<router::Module<T>>::inbound_hrmp_channels_contents(recipient)
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
use sp_runtime::traits::{One, Saturating};
|
use sp_runtime::traits::{One, Saturating};
|
||||||
use primitives::v1::{Id as ParaId, PersistedValidationData, TransientValidationData};
|
use primitives::v1::{Id as ParaId, PersistedValidationData, TransientValidationData};
|
||||||
use sp_std::prelude::*;
|
|
||||||
|
|
||||||
use crate::{configuration, paras, router};
|
use crate::{configuration, paras, router};
|
||||||
|
|
||||||
@@ -34,7 +33,7 @@ pub fn make_persisted_validation_data<T: paras::Trait + router::Trait>(
|
|||||||
Some(PersistedValidationData {
|
Some(PersistedValidationData {
|
||||||
parent_head: <paras::Module<T>>::para_head(¶_id)?,
|
parent_head: <paras::Module<T>>::para_head(¶_id)?,
|
||||||
block_number: relay_parent_number,
|
block_number: relay_parent_number,
|
||||||
hrmp_mqc_heads: Vec::new(),
|
hrmp_mqc_heads: <router::Module<T>>::hrmp_mqc_heads(para_id),
|
||||||
dmq_mqc_head: <router::Module<T>>::dmq_mqc_head(para_id),
|
dmq_mqc_head: <router::Module<T>>::dmq_mqc_head(para_id),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,12 +30,14 @@ use runtime_common::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use sp_std::prelude::*;
|
use sp_std::prelude::*;
|
||||||
|
use sp_std::collections::btree_map::BTreeMap;
|
||||||
use sp_core::u32_trait::{_1, _2, _3, _4, _5};
|
use sp_core::u32_trait::{_1, _2, _3, _4, _5};
|
||||||
use codec::{Encode, Decode};
|
use codec::{Encode, Decode};
|
||||||
use primitives::v1::{
|
use primitives::v1::{
|
||||||
AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CommittedCandidateReceipt,
|
AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CommittedCandidateReceipt,
|
||||||
CoreState, GroupRotationInfo, Hash, Id, Moment, Nonce, OccupiedCoreAssumption,
|
CoreState, GroupRotationInfo, Hash, Id, Moment, Nonce, OccupiedCoreAssumption,
|
||||||
PersistedValidationData, Signature, ValidationCode, ValidationData, ValidatorId, ValidatorIndex,
|
PersistedValidationData, Signature, ValidationCode, ValidationData, ValidatorId, ValidatorIndex,
|
||||||
|
InboundDownwardMessage, InboundHrmpMessage,
|
||||||
};
|
};
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
create_runtime_str, generic, impl_opaque_keys, ModuleId, ApplyExtrinsicResult,
|
create_runtime_str, generic, impl_opaque_keys, ModuleId, ApplyExtrinsicResult,
|
||||||
@@ -1106,9 +1108,16 @@ sp_api::impl_runtime_apis! {
|
|||||||
|
|
||||||
fn dmq_contents(
|
fn dmq_contents(
|
||||||
_recipient: Id,
|
_recipient: Id,
|
||||||
) -> Vec<primitives::v1::InboundDownwardMessage<BlockNumber>> {
|
) -> Vec<InboundDownwardMessage<BlockNumber>> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inbound_hrmp_channels_contents(
|
||||||
|
_recipient: Id
|
||||||
|
) -> BTreeMap<Id, Vec<InboundHrmpMessage<BlockNumber>>> {
|
||||||
|
BTreeMap::new()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fg_primitives::GrandpaApi<Block> for Runtime {
|
impl fg_primitives::GrandpaApi<Block> for Runtime {
|
||||||
|
|||||||
@@ -22,12 +22,13 @@
|
|||||||
|
|
||||||
use pallet_transaction_payment::CurrencyAdapter;
|
use pallet_transaction_payment::CurrencyAdapter;
|
||||||
use sp_std::prelude::*;
|
use sp_std::prelude::*;
|
||||||
|
use sp_std::collections::btree_map::BTreeMap;
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
use primitives::v1::{
|
use primitives::v1::{
|
||||||
AccountId, AccountIndex, Balance, BlockNumber, Hash, Nonce, Signature, Moment,
|
AccountId, AccountIndex, Balance, BlockNumber, Hash, Nonce, Signature, Moment,
|
||||||
GroupRotationInfo, CoreState, Id, ValidationData, ValidationCode, CandidateEvent,
|
GroupRotationInfo, CoreState, Id, ValidationData, ValidationCode, CandidateEvent,
|
||||||
ValidatorId, ValidatorIndex, CommittedCandidateReceipt, OccupiedCoreAssumption,
|
ValidatorId, ValidatorIndex, CommittedCandidateReceipt, OccupiedCoreAssumption,
|
||||||
PersistedValidationData,
|
PersistedValidationData, InboundDownwardMessage, InboundHrmpMessage,
|
||||||
};
|
};
|
||||||
use runtime_common::{
|
use runtime_common::{
|
||||||
SlowAdjustingFeeUpdate,
|
SlowAdjustingFeeUpdate,
|
||||||
@@ -532,6 +533,7 @@ impl parachains_paras::Trait for Runtime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl parachains_router::Trait for Runtime {
|
impl parachains_router::Trait for Runtime {
|
||||||
|
type Origin = Origin;
|
||||||
type UmpSink = (); // TODO: #1873 To be handled by the XCM receiver.
|
type UmpSink = (); // TODO: #1873 To be handled by the XCM receiver.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -681,9 +683,15 @@ sp_api::impl_runtime_apis! {
|
|||||||
runtime_api_impl::validator_discovery::<Runtime>(validators)
|
runtime_api_impl::validator_discovery::<Runtime>(validators)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dmq_contents(recipient: Id) -> Vec<primitives::v1::InboundDownwardMessage<BlockNumber>> {
|
fn dmq_contents(recipient: Id) -> Vec<InboundDownwardMessage<BlockNumber>> {
|
||||||
runtime_api_impl::dmq_contents::<Runtime>(recipient)
|
runtime_api_impl::dmq_contents::<Runtime>(recipient)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inbound_hrmp_channels_contents(
|
||||||
|
recipient: Id
|
||||||
|
) -> BTreeMap<Id, Vec<InboundHrmpMessage<BlockNumber>>> {
|
||||||
|
runtime_api_impl::inbound_hrmp_channels_contents::<Runtime>(recipient)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fg_primitives::GrandpaApi<Block> for Runtime {
|
impl fg_primitives::GrandpaApi<Block> for Runtime {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
use pallet_transaction_payment::CurrencyAdapter;
|
use pallet_transaction_payment::CurrencyAdapter;
|
||||||
use sp_std::prelude::*;
|
use sp_std::prelude::*;
|
||||||
|
use sp_std::collections::btree_map::BTreeMap;
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
use polkadot_runtime_parachains::{
|
use polkadot_runtime_parachains::{
|
||||||
configuration,
|
configuration,
|
||||||
@@ -36,6 +37,7 @@ use primitives::v1::{
|
|||||||
AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CommittedCandidateReceipt,
|
AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CommittedCandidateReceipt,
|
||||||
CoreState, GroupRotationInfo, Hash as HashT, Id as ParaId, Moment, Nonce, OccupiedCoreAssumption,
|
CoreState, GroupRotationInfo, Hash as HashT, Id as ParaId, Moment, Nonce, OccupiedCoreAssumption,
|
||||||
PersistedValidationData, Signature, ValidationCode, ValidationData, ValidatorId, ValidatorIndex,
|
PersistedValidationData, Signature, ValidationCode, ValidationData, ValidatorId, ValidatorIndex,
|
||||||
|
InboundDownwardMessage, InboundHrmpMessage,
|
||||||
};
|
};
|
||||||
use runtime_common::{
|
use runtime_common::{
|
||||||
claims, SlowAdjustingFeeUpdate, paras_sudo_wrapper,
|
claims, SlowAdjustingFeeUpdate, paras_sudo_wrapper,
|
||||||
@@ -453,6 +455,7 @@ impl paras::Trait for Runtime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl router::Trait for Runtime {
|
impl router::Trait for Runtime {
|
||||||
|
type Origin = Origin;
|
||||||
type UmpSink = ();
|
type UmpSink = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -668,9 +671,15 @@ sp_api::impl_runtime_apis! {
|
|||||||
|
|
||||||
fn dmq_contents(
|
fn dmq_contents(
|
||||||
recipient: ParaId,
|
recipient: ParaId,
|
||||||
) -> Vec<primitives::v1::InboundDownwardMessage<BlockNumber>> {
|
) -> Vec<InboundDownwardMessage<BlockNumber>> {
|
||||||
runtime_impl::dmq_contents::<Runtime>(recipient)
|
runtime_impl::dmq_contents::<Runtime>(recipient)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inbound_hrmp_channels_contents(
|
||||||
|
recipient: ParaId,
|
||||||
|
) -> BTreeMap<ParaId, Vec<InboundHrmpMessage<BlockNumber>>> {
|
||||||
|
runtime_impl::inbound_hrmp_channels_contents::<Runtime>(recipient)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fg_primitives::GrandpaApi<Block> for Runtime {
|
impl fg_primitives::GrandpaApi<Block> for Runtime {
|
||||||
|
|||||||
@@ -22,11 +22,13 @@
|
|||||||
|
|
||||||
use pallet_transaction_payment::CurrencyAdapter;
|
use pallet_transaction_payment::CurrencyAdapter;
|
||||||
use sp_std::prelude::*;
|
use sp_std::prelude::*;
|
||||||
|
use sp_std::collections::btree_map::BTreeMap;
|
||||||
use codec::{Encode, Decode};
|
use codec::{Encode, Decode};
|
||||||
use primitives::v1::{
|
use primitives::v1::{
|
||||||
AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CommittedCandidateReceipt,
|
AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CommittedCandidateReceipt,
|
||||||
CoreState, GroupRotationInfo, Hash, Id, Moment, Nonce, OccupiedCoreAssumption,
|
CoreState, GroupRotationInfo, Hash, Id, Moment, Nonce, OccupiedCoreAssumption,
|
||||||
PersistedValidationData, Signature, ValidationCode, ValidationData, ValidatorId, ValidatorIndex,
|
PersistedValidationData, Signature, ValidationCode, ValidationData, ValidatorId, ValidatorIndex,
|
||||||
|
InboundDownwardMessage, InboundHrmpMessage,
|
||||||
};
|
};
|
||||||
use runtime_common::{
|
use runtime_common::{
|
||||||
SlowAdjustingFeeUpdate, CurrencyToVote,
|
SlowAdjustingFeeUpdate, CurrencyToVote,
|
||||||
@@ -856,9 +858,15 @@ sp_api::impl_runtime_apis! {
|
|||||||
|
|
||||||
fn dmq_contents(
|
fn dmq_contents(
|
||||||
_recipient: Id,
|
_recipient: Id,
|
||||||
) -> Vec<primitives::v1::InboundDownwardMessage<BlockNumber>> {
|
) -> Vec<InboundDownwardMessage<BlockNumber>> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inbound_hrmp_channels_contents(
|
||||||
|
_recipient: Id
|
||||||
|
) -> BTreeMap<Id, Vec<InboundHrmpMessage<BlockNumber>>> {
|
||||||
|
BTreeMap::new()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fg_primitives::GrandpaApi<Block> for Runtime {
|
impl fg_primitives::GrandpaApi<Block> for Runtime {
|
||||||
|
|||||||
@@ -158,6 +158,51 @@ pub enum Xcm {
|
|||||||
///
|
///
|
||||||
/// Errors:
|
/// Errors:
|
||||||
RelayedFrom { superorigin: MultiLocation, inner: Box<VersionedXcm> },
|
RelayedFrom { superorigin: MultiLocation, inner: Box<VersionedXcm> },
|
||||||
|
|
||||||
|
/// A message to notify about a new incoming HRMP channel. This message is meant to be sent by the
|
||||||
|
/// relay-chain to a para.
|
||||||
|
///
|
||||||
|
/// - `sender`: The sender in the to-be opened channel. Also, the initiator of the channel opening.
|
||||||
|
/// - `max_message_size`: The maximum size of a message proposed by the sender.
|
||||||
|
/// - `max_capacity`: The maximum number of messages that can be queued in the channel.
|
||||||
|
///
|
||||||
|
/// Safety: The message should originate directly from the relay-chain.
|
||||||
|
///
|
||||||
|
/// Kind: *System Notification*
|
||||||
|
HrmpNewChannelOpenRequest {
|
||||||
|
#[codec(compact)] sender: u32,
|
||||||
|
#[codec(compact)] max_message_size: u32,
|
||||||
|
#[codec(compact)] max_capacity: u32,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// A message to notify about that a previously sent open channel request has been accepted by
|
||||||
|
/// the recipient. That means that the channel will be opened during the next relay-chain session
|
||||||
|
/// change. This message is meant to be sent by the relay-chain to a para.
|
||||||
|
///
|
||||||
|
/// Safety: The message should originate directly from the relay-chain.
|
||||||
|
///
|
||||||
|
/// Kind: *System Notification*
|
||||||
|
///
|
||||||
|
/// Errors:
|
||||||
|
HrmpChannelAccepted {
|
||||||
|
#[codec(compact)] recipient: u32,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// A message to notify that the other party in an open channel decided to close it. In particular,
|
||||||
|
/// `inititator` is going to close the channel opened from `sender` to the `recipient`. The close
|
||||||
|
/// will be enacted at the next relay-chain session change. This message is meant to be sent by
|
||||||
|
/// the relay-chain to a para.
|
||||||
|
///
|
||||||
|
/// Safety: The message should originate directly from the relay-chain.
|
||||||
|
///
|
||||||
|
/// Kind: *System Notification*
|
||||||
|
///
|
||||||
|
/// Errors:
|
||||||
|
HrmpChannelClosing {
|
||||||
|
#[codec(compact)] initiator: u32,
|
||||||
|
#[codec(compact)] sender: u32,
|
||||||
|
#[codec(compact)] recipient: u32,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Xcm> for VersionedXcm {
|
impl From<Xcm> for VersionedXcm {
|
||||||
|
|||||||
Reference in New Issue
Block a user