Move parachain inherent data into its own crate (#326)

This renames and moves the `SystemInherentData` into its own crate.
The struct is now called `ParachainInherentData`. Besides moving the
struct, this also moves the code for creating this struct into this crate.
This commit is contained in:
Bastian Köcher
2021-02-11 13:05:17 +01:00
committed by GitHub
parent 119e0859b9
commit ba0bdc84a5
13 changed files with 445 additions and 305 deletions
+20 -2
View File
@@ -1075,6 +1075,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"cumulus-client-network", "cumulus-client-network",
"cumulus-primitives-core", "cumulus-primitives-core",
"cumulus-primitives-parachain-inherent",
"cumulus-test-client", "cumulus-test-client",
"cumulus-test-runtime", "cumulus-test-runtime",
"env_logger", "env_logger",
@@ -1188,6 +1189,7 @@ name = "cumulus-pallet-parachain-system"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cumulus-primitives-core", "cumulus-primitives-core",
"cumulus-primitives-parachain-inherent",
"cumulus-test-client", "cumulus-test-client",
"cumulus-test-relay-sproof-builder", "cumulus-test-relay-sproof-builder",
"env_logger", "env_logger",
@@ -1241,18 +1243,34 @@ dependencies = [
"polkadot-core-primitives", "polkadot-core-primitives",
"polkadot-parachain", "polkadot-parachain",
"polkadot-primitives", "polkadot-primitives",
"sp-core",
"sp-inherents",
"sp-runtime", "sp-runtime",
"sp-std", "sp-std",
"sp-trie", "sp-trie",
] ]
[[package]]
name = "cumulus-primitives-parachain-inherent"
version = "0.1.0"
dependencies = [
"cumulus-primitives-core",
"parity-scale-codec",
"sc-client-api",
"sp-api",
"sp-core",
"sp-inherents",
"sp-runtime",
"sp-state-machine",
"sp-std",
"sp-trie",
"tracing",
]
[[package]] [[package]]
name = "cumulus-test-client" name = "cumulus-test-client"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cumulus-primitives-core", "cumulus-primitives-core",
"cumulus-primitives-parachain-inherent",
"cumulus-test-relay-sproof-builder", "cumulus-test-relay-sproof-builder",
"cumulus-test-runtime", "cumulus-test-runtime",
"cumulus-test-service", "cumulus-test-service",
+1
View File
@@ -6,6 +6,7 @@ members = [
"pallets/parachain-system", "pallets/parachain-system",
"pallets/xcm-handler", "pallets/xcm-handler",
"primitives/core", "primitives/core",
"primitives/parachain-inherent",
"rococo-parachains/", "rococo-parachains/",
"rococo-parachains/pallets/parachain-info", "rococo-parachains/pallets/parachain-info",
"rococo-parachains/primitives", "rococo-parachains/primitives",
+1
View File
@@ -27,6 +27,7 @@ polkadot-node-subsystem = { git = "https://github.com/paritytech/polkadot", bran
# Cumulus dependencies # Cumulus dependencies
cumulus-client-network = { path = "../network" } cumulus-client-network = { path = "../network" }
cumulus-primitives-core = { path = "../../primitives/core" } cumulus-primitives-core = { path = "../../primitives/core" }
cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" }
# Other dependencies # Other dependencies
log = "0.4.8" log = "0.4.8"
+70 -247
View File
@@ -18,10 +18,9 @@
use cumulus_client_network::WaitToAnnounce; use cumulus_client_network::WaitToAnnounce;
use cumulus_primitives_core::{ use cumulus_primitives_core::{
inherents, ParachainBlockData, well_known_keys, OutboundHrmpMessage, ParachainBlockData, PersistedValidationData,
well_known_keys, InboundDownwardMessage, InboundHrmpMessage, OutboundHrmpMessage,
PersistedValidationData, relay_chain,
}; };
use cumulus_primitives_parachain_inherent::ParachainInherentData;
use sc_client_api::{BlockBackend, StateBackend}; use sc_client_api::{BlockBackend, StateBackend};
use sp_consensus::{ use sp_consensus::{
@@ -41,7 +40,7 @@ use polkadot_node_subsystem::messages::{CollationGenerationMessage, CollatorProt
use polkadot_overseer::OverseerHandler; use polkadot_overseer::OverseerHandler;
use polkadot_primitives::v1::{ use polkadot_primitives::v1::{
Block as PBlock, BlockData, BlockNumber as PBlockNumber, CollatorPair, Hash as PHash, HeadData, Block as PBlock, BlockData, BlockNumber as PBlockNumber, CollatorPair, Hash as PHash, HeadData,
Id as ParaId, PoV, UpwardMessage, HrmpChannelId, Id as ParaId, PoV, UpwardMessage,
}; };
use polkadot_service::RuntimeApiCollection; use polkadot_service::RuntimeApiCollection;
@@ -51,7 +50,7 @@ use log::{debug, error, info, trace};
use futures::prelude::*; use futures::prelude::*;
use std::{collections::BTreeMap, marker::PhantomData, sync::Arc, time::Duration}; use std::{marker::PhantomData, sync::Arc, time::Duration};
use parking_lot::Mutex; use parking_lot::Mutex;
@@ -101,10 +100,10 @@ where
PF: Environment<Block> + 'static + Send, PF: Environment<Block> + 'static + Send,
PF::Proposer: Send, PF::Proposer: Send,
BI: BlockImport< BI: BlockImport<
Block, Block,
Error = ConsensusError, Error = ConsensusError,
Transaction = <PF::Proposer as Proposer<Block>>::Transaction, Transaction = <PF::Proposer as Proposer<Block>>::Transaction,
> + Send > + Send
+ Sync + Sync
+ 'static, + 'static,
BS: BlockBackend<Block>, BS: BlockBackend<Block>,
@@ -150,161 +149,6 @@ where
} }
} }
/// Returns the whole contents of the downward message queue for the parachain we are collating
/// for.
///
/// Returns `None` in case of an error.
fn retrieve_dmq_contents(&self, relay_parent: PHash) -> Option<Vec<InboundDownwardMessage>> {
self.polkadot_client
.runtime_api()
.dmq_contents_with_context(
&BlockId::hash(relay_parent),
sp_core::ExecutionContext::Importing,
self.para_id,
)
.map_err(|e| {
error!(
target: LOG_TARGET,
"An error occured during requesting the downward messages for {}: {:?}",
relay_parent, e,
);
})
.ok()
}
/// Returns channels contents for each inbound HRMP channel addressed to the parachain we are
/// collating for.
///
/// Empty channels are also included.
fn retrieve_all_inbound_hrmp_channel_contents(
&self,
relay_parent: PHash,
) -> Option<BTreeMap<ParaId, Vec<InboundHrmpMessage>>> {
self.polkadot_client
.runtime_api()
.inbound_hrmp_channels_contents_with_context(
&BlockId::hash(relay_parent),
sp_core::ExecutionContext::Importing,
self.para_id,
)
.map_err(|e| {
error!(
target: LOG_TARGET,
"An error occured during requesting the inbound HRMP messages for {}: {:?}",
relay_parent, e,
);
})
.ok()
}
/// Collect the relevant relay chain state in form of a proof for putting it into the validation
/// data inherent.
fn collect_relay_storage_proof(
&self,
relay_parent: PHash,
) -> Option<sp_state_machine::StorageProof> {
use relay_chain::well_known_keys as relay_well_known_keys;
let relay_parent_state_backend = self
.polkadot_backend
.state_at(BlockId::Hash(relay_parent))
.map_err(|e| {
error!(
target: LOG_TARGET,
"Cannot obtain the state of the relay chain at `{:?}`: {:?}",
relay_parent,
e,
)
})
.ok()?;
let ingress_channels = relay_parent_state_backend
.storage(&relay_well_known_keys::hrmp_ingress_channel_index(
self.para_id,
))
.map_err(|e| {
error!(
target: LOG_TARGET,
"Cannot obtain the hrmp ingress channel index: {:?}",
e,
)
})
.ok()?;
let ingress_channels = ingress_channels
.map(|raw| <Vec<ParaId>>::decode(&mut &raw[..]))
.transpose()
.map_err(|e| {
error!(
target: LOG_TARGET,
"Cannot decode the hrmp ingress channel index: {:?}",
e,
)
})
.ok()?
.unwrap_or_default();
let egress_channels = relay_parent_state_backend
.storage(&relay_well_known_keys::hrmp_egress_channel_index(
self.para_id,
))
.map_err(|e| {
error!(
target: LOG_TARGET,
"Cannot obtain the hrmp egress channel index: {:?}",
e,
)
})
.ok()?;
let egress_channels = egress_channels
.map(|raw| <Vec<ParaId>>::decode(&mut &raw[..]))
.transpose()
.map_err(|e| {
error!(
target: LOG_TARGET,
"Cannot decode the hrmp egress channel index: {:?}",
e,
)
})
.ok()?
.unwrap_or_default();
let mut relevant_keys = vec![];
relevant_keys.push(relay_well_known_keys::ACTIVE_CONFIG.to_vec());
relevant_keys.push(relay_well_known_keys::dmq_mqc_head(self.para_id));
relevant_keys.push(relay_well_known_keys::relay_dispatch_queue_size(
self.para_id,
));
relevant_keys.push(relay_well_known_keys::hrmp_ingress_channel_index(
self.para_id,
));
relevant_keys.push(relay_well_known_keys::hrmp_egress_channel_index(
self.para_id,
));
relevant_keys.extend(ingress_channels.into_iter().map(|sender| {
relay_well_known_keys::hrmp_channels(HrmpChannelId {
sender,
recipient: self.para_id,
})
}));
relevant_keys.extend(egress_channels.into_iter().map(|recipient| {
relay_well_known_keys::hrmp_channels(HrmpChannelId {
sender: self.para_id,
recipient,
})
}));
sp_state_machine::prove_read(relay_parent_state_backend, relevant_keys)
.map_err(|e| {
error!(
target: LOG_TARGET,
"Failed to collect required relay chain state storage proof at `{:?}`: {:?}",
relay_parent,
e,
)
})
.ok()
}
/// Get the inherent data with validation function parameters injected /// Get the inherent data with validation function parameters injected
fn inherent_data( fn inherent_data(
&mut self, &mut self,
@@ -317,36 +161,28 @@ where
.map_err(|e| { .map_err(|e| {
error!( error!(
target: LOG_TARGET, target: LOG_TARGET,
"Failed to create inherent data: {:?}", "Failed to create inherent data: {:?}", e,
e,
) )
}) })
.ok()?; .ok()?;
let system_inherent_data = { let parachain_inherent_data = ParachainInherentData::create_at(
let relay_chain_state = self.collect_relay_storage_proof(relay_parent)?; relay_parent,
let downward_messages = self.retrieve_dmq_contents(relay_parent)?; &*self.polkadot_client,
let horizontal_messages = &*self.polkadot_backend,
self.retrieve_all_inbound_hrmp_channel_contents(relay_parent)?; validation_data,
self.para_id,
inherents::SystemInherentData { )?;
downward_messages,
horizontal_messages,
validation_data: validation_data.clone(),
relay_chain_state,
}
};
inherent_data inherent_data
.put_data( .put_data(
inherents::SYSTEM_INHERENT_IDENTIFIER, cumulus_primitives_parachain_inherent::INHERENT_IDENTIFIER,
&system_inherent_data, &parachain_inherent_data,
) )
.map_err(|e| { .map_err(|e| {
error!( error!(
target: LOG_TARGET, target: LOG_TARGET,
"Failed to put the system inherent into inherent data: {:?}", "Failed to put the system inherent into inherent data: {:?}", e,
e,
) )
}) })
.ok()?; .ok()?;
@@ -371,8 +207,7 @@ where
Ok(BlockStatus::InChainPruned) => { Ok(BlockStatus::InChainPruned) => {
error!( error!(
target: LOG_TARGET, target: LOG_TARGET,
"Skipping candidate production, because block `{:?}` is already pruned!", "Skipping candidate production, because block `{:?}` is already pruned!", hash,
hash,
); );
false false
} }
@@ -394,8 +229,7 @@ where
} else { } else {
debug!( debug!(
target: LOG_TARGET, target: LOG_TARGET,
"Skipping candidate production, because block `{:?}` is unknown.", "Skipping candidate production, because block `{:?}` is unknown.", hash,
hash,
); );
} }
false false
@@ -403,9 +237,7 @@ where
Err(e) => { Err(e) => {
error!( error!(
target: LOG_TARGET, target: LOG_TARGET,
"Failed to get block status of `{:?}`: {:?}", "Failed to get block status of `{:?}`: {:?}", hash, e,
hash,
e,
); );
false false
} }
@@ -425,39 +257,45 @@ where
let state = match self.backend.state_at(BlockId::Hash(block_hash)) { let state = match self.backend.state_at(BlockId::Hash(block_hash)) {
Ok(state) => state, Ok(state) => state,
Err(e) => { Err(e) => {
error!(target: LOG_TARGET, "Failed to get state of the freshly built block: {:?}", e); error!(
target: LOG_TARGET,
"Failed to get state of the freshly built block: {:?}", e
);
return None; return None;
} }
}; };
state.inspect_state(|| { state.inspect_state(|| {
let upward_messages = sp_io::storage::get(well_known_keys::UPWARD_MESSAGES); let upward_messages = sp_io::storage::get(well_known_keys::UPWARD_MESSAGES);
let upward_messages = match upward_messages.map(|v| Vec::<UpwardMessage>::decode(&mut &v[..])) { let upward_messages =
Some(Ok(msgs)) => msgs, match upward_messages.map(|v| Vec::<UpwardMessage>::decode(&mut &v[..])) {
Some(Err(e)) => { Some(Ok(msgs)) => msgs,
error!(target: LOG_TARGET, "Failed to decode upward messages from the build block: {:?}", e); Some(Err(e)) => {
return None error!(
}, target: LOG_TARGET,
None => Vec::new(), "Failed to decode upward messages from the build block: {:?}", e
}; );
return None;
}
None => Vec::new(),
};
let new_validation_code = sp_io::storage::get(well_known_keys::NEW_VALIDATION_CODE); let new_validation_code = sp_io::storage::get(well_known_keys::NEW_VALIDATION_CODE);
let processed_downward_messages = sp_io::storage::get(well_known_keys::PROCESSED_DOWNWARD_MESSAGES); let processed_downward_messages =
let processed_downward_messages = match processed_downward_messages sp_io::storage::get(well_known_keys::PROCESSED_DOWNWARD_MESSAGES);
.map(|v| u32::decode(&mut &v[..])) let processed_downward_messages =
{ match processed_downward_messages.map(|v| u32::decode(&mut &v[..])) {
Some(Ok(processed_cnt)) => processed_cnt, Some(Ok(processed_cnt)) => processed_cnt,
Some(Err(e)) => { Some(Err(e)) => {
error!( error!(
target: LOG_TARGET, target: LOG_TARGET,
"Failed to decode the count of processed downward messages: {:?}", "Failed to decode the count of processed downward messages: {:?}", e
e );
); return None;
return None }
} None => 0,
None => 0, };
};
let horizontal_messages = sp_io::storage::get(well_known_keys::HRMP_OUTBOUND_MESSAGES); let horizontal_messages = sp_io::storage::get(well_known_keys::HRMP_OUTBOUND_MESSAGES);
let horizontal_messages = match horizontal_messages let horizontal_messages = match horizontal_messages
@@ -467,10 +305,9 @@ where
Some(Err(e)) => { Some(Err(e)) => {
error!( error!(
target: LOG_TARGET, target: LOG_TARGET,
"Failed to decode the horizontal messages: {:?}", "Failed to decode the horizontal messages: {:?}", e
e
); );
return None return None;
} }
None => Vec::new(), None => Vec::new(),
}; };
@@ -481,10 +318,9 @@ where
Some(Err(e)) => { Some(Err(e)) => {
error!( error!(
target: LOG_TARGET, target: LOG_TARGET,
"Failed to decode the HRMP watermark: {:?}", "Failed to decode the HRMP watermark: {:?}", e
e
); );
return None return None;
} }
None => { None => {
// If the runtime didn't set `HRMP_WATERMARK`, then it means no messages were // If the runtime didn't set `HRMP_WATERMARK`, then it means no messages were
@@ -514,14 +350,16 @@ where
) -> Option<Collation> { ) -> Option<Collation> {
trace!(target: LOG_TARGET, "Producing candidate"); trace!(target: LOG_TARGET, "Producing candidate");
let last_head = let last_head = match Block::Header::decode(&mut &validation_data.parent_head.0[..]) {
match Block::Header::decode(&mut &validation_data.parent_head.0[..]) { Ok(x) => x,
Ok(x) => x, Err(e) => {
Err(e) => { error!(
error!(target: LOG_TARGET, "Could not decode the head data: {:?}", e); target: LOG_TARGET,
return None; "Could not decode the head data: {:?}", e
} );
}; return None;
}
};
let last_head_hash = last_head.hash(); let last_head_hash = last_head.hash();
if !self.check_block_status(last_head_hash, &last_head) { if !self.check_block_status(last_head_hash, &last_head) {
@@ -539,13 +377,7 @@ where
let proposer = proposer_future let proposer = proposer_future
.await .await
.map_err(|e| { .map_err(|e| error!(target: LOG_TARGET, "Could not create proposer: {:?}", e,))
error!(
target: LOG_TARGET,
"Could not create proposer: {:?}",
e,
)
})
.ok()?; .ok()?;
let inherent_data = self.inherent_data(&validation_data, relay_parent)?; let inherent_data = self.inherent_data(&validation_data, relay_parent)?;
@@ -563,13 +395,7 @@ where
RecordProof::Yes, RecordProof::Yes,
) )
.await .await
.map_err(|e| { .map_err(|e| error!(target: LOG_TARGET, "Proposing failed: {:?}", e,))
error!(
target: LOG_TARGET,
"Proposing failed: {:?}",
e,
)
})
.ok()?; .ok()?;
let proof = match proof { let proof = match proof {
@@ -619,8 +445,7 @@ where
b.storage_proof().encode().len() as f64 / 1024f64, b.storage_proof().encode().len() as f64 / 1024f64,
); );
let collation = let collation = self.build_collation(b, block_hash, validation_data.relay_parent_number)?;
self.build_collation(b, block_hash, validation_data.relay_parent_number)?;
let pov_hash = collation.proof_of_validity.hash(); let pov_hash = collation.proof_of_validity.hash();
self.wait_to_announce self.wait_to_announce
@@ -629,9 +454,7 @@ where
info!( info!(
target: LOG_TARGET, target: LOG_TARGET,
"Produced proof-of-validity candidate {:?} from block {:?}.", "Produced proof-of-validity candidate {:?} from block {:?}.", pov_hash, block_hash,
pov_hash,
block_hash,
); );
Some(collation) Some(collation)
@@ -8,6 +8,7 @@ description = "Base pallet for cumulus-based parachains"
[dependencies] [dependencies]
# Cumulus dependencies # Cumulus dependencies
cumulus-primitives-core = { path = "../../primitives/core", default-features = false } cumulus-primitives-core = { path = "../../primitives/core", default-features = false }
cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent", default-features = false }
# Polkadot dependencies # Polkadot dependencies
polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, features = [ "wasm-api" ], branch = "master" } polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, features = [ "wasm-api" ], branch = "master" }
@@ -68,4 +69,5 @@ std = [
"frame-system/std", "frame-system/std",
"frame-executive/std", "frame-executive/std",
"cumulus-primitives-core/std", "cumulus-primitives-core/std",
"cumulus-primitives-parachain-inherent/std",
] ]
+14 -10
View File
@@ -28,13 +28,13 @@
//! Users must ensure that they register this pallet as an inherent provider. //! Users must ensure that they register this pallet as an inherent provider.
use cumulus_primitives_core::{ use cumulus_primitives_core::{
inherents::{SystemInherentData, SYSTEM_INHERENT_IDENTIFIER},
relay_chain, relay_chain,
well_known_keys::{self, NEW_VALIDATION_CODE, VALIDATION_DATA}, well_known_keys::{self, NEW_VALIDATION_CODE, VALIDATION_DATA},
AbridgedHostConfiguration, DownwardMessageHandler, HrmpMessageHandler, HrmpMessageSender, AbridgedHostConfiguration, DownwardMessageHandler, HrmpMessageHandler, HrmpMessageSender,
InboundDownwardMessage, InboundHrmpMessage, OnValidationData, OutboundHrmpMessage, ParaId, InboundDownwardMessage, InboundHrmpMessage, OnValidationData, OutboundHrmpMessage, ParaId,
PersistedValidationData, UpwardMessage, UpwardMessageSender, PersistedValidationData, UpwardMessage, UpwardMessageSender,
}; };
use cumulus_primitives_parachain_inherent::ParachainInherentData;
use frame_support::{ use frame_support::{
decl_error, decl_event, decl_module, decl_storage, decl_error, decl_event, decl_module, decl_storage,
dispatch::DispatchResult, dispatch::DispatchResult,
@@ -166,11 +166,11 @@ decl_module! {
/// As a side effect, this function upgrades the current validation function /// As a side effect, this function upgrades the current validation function
/// if the appropriate time has come. /// if the appropriate time has come.
#[weight = (0, DispatchClass::Mandatory)] #[weight = (0, DispatchClass::Mandatory)]
fn set_validation_data(origin, data: SystemInherentData) -> DispatchResult { fn set_validation_data(origin, data: ParachainInherentData) -> DispatchResult {
ensure_none(origin)?; ensure_none(origin)?;
assert!(!DidUpdateValidationData::exists(), "ValidationData must be updated only once in a block"); assert!(!DidUpdateValidationData::exists(), "ValidationData must be updated only once in a block");
let SystemInherentData { let ParachainInherentData {
validation_data: vfp, validation_data: vfp,
relay_chain_state, relay_chain_state,
downward_messages, downward_messages,
@@ -798,11 +798,12 @@ impl<T: Config> HrmpMessageSender for Module<T> {
impl<T: Config> ProvideInherent for Module<T> { impl<T: Config> ProvideInherent for Module<T> {
type Call = Call<T>; type Call = Call<T>;
type Error = sp_inherents::MakeFatalError<()>; type Error = sp_inherents::MakeFatalError<()>;
const INHERENT_IDENTIFIER: InherentIdentifier = SYSTEM_INHERENT_IDENTIFIER; const INHERENT_IDENTIFIER: InherentIdentifier =
cumulus_primitives_parachain_inherent::INHERENT_IDENTIFIER;
fn create_inherent(data: &InherentData) -> Option<Self::Call> { fn create_inherent(data: &InherentData) -> Option<Self::Call> {
let data: SystemInherentData = data let data: ParachainInherentData = data
.get_data(&SYSTEM_INHERENT_IDENTIFIER) .get_data(&Self::INHERENT_IDENTIFIER)
.ok() .ok()
.flatten() .flatten()
.expect("validation function params are always injected into inherent data; qed"); .expect("validation function params are always injected into inherent data; qed");
@@ -1029,7 +1030,7 @@ mod tests {
persisted_validation_data_hook: persisted_validation_data_hook:
Option<Box<dyn Fn(&BlockTests, RelayChainBlockNumber, &mut PersistedValidationData)>>, Option<Box<dyn Fn(&BlockTests, RelayChainBlockNumber, &mut PersistedValidationData)>>,
inherent_data_hook: inherent_data_hook:
Option<Box<dyn Fn(&BlockTests, RelayChainBlockNumber, &mut SystemInherentData)>>, Option<Box<dyn Fn(&BlockTests, RelayChainBlockNumber, &mut ParachainInherentData)>>,
} }
impl BlockTests { impl BlockTests {
@@ -1089,7 +1090,7 @@ mod tests {
fn with_inherent_data<F>(mut self, f: F) -> Self fn with_inherent_data<F>(mut self, f: F) -> Self
where where
F: 'static + Fn(&BlockTests, RelayChainBlockNumber, &mut SystemInherentData), F: 'static + Fn(&BlockTests, RelayChainBlockNumber, &mut ParachainInherentData),
{ {
self.inherent_data_hook = Some(Box::new(f)); self.inherent_data_hook = Some(Box::new(f));
self self
@@ -1142,7 +1143,7 @@ mod tests {
// to storage; they must also be included in the inherent data. // to storage; they must also be included in the inherent data.
let inherent_data = { let inherent_data = {
let mut inherent_data = InherentData::default(); let mut inherent_data = InherentData::default();
let mut system_inherent_data = SystemInherentData { let mut system_inherent_data = ParachainInherentData {
validation_data: vfp.clone(), validation_data: vfp.clone(),
relay_chain_state, relay_chain_state,
downward_messages: Default::default(), downward_messages: Default::default(),
@@ -1152,7 +1153,10 @@ mod tests {
hook(self, *n as RelayChainBlockNumber, &mut system_inherent_data); hook(self, *n as RelayChainBlockNumber, &mut system_inherent_data);
} }
inherent_data inherent_data
.put_data(SYSTEM_INHERENT_IDENTIFIER, &system_inherent_data) .put_data(
cumulus_primitives_parachain_inherent::INHERENT_IDENTIFIER,
&system_inherent_data,
)
.expect("failed to put VFP inherent"); .expect("failed to put VFP inherent");
inherent_data inherent_data
}; };
+3 -9
View File
@@ -6,33 +6,27 @@ edition = "2018"
[dependencies] [dependencies]
# Substrate dependencies # Substrate dependencies
sp-inherents = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-trie = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } sp-trie = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
# Polkadot dependencies # Polkadot dependencies
polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" } polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" } polkadot-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
polkadot-core-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
# Other dependencies # Other dependencies
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ "derive" ] }
impl-trait-for-tuples = "0.2.1" impl-trait-for-tuples = "0.2.1"
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ "derive" ] }
# Polkadot dependencies
polkadot-core-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
[features] [features]
default = [ "std" ] default = [ "std" ]
std = [ std = [
"sp-std/std",
"codec/std", "codec/std",
"sp-std/std",
"polkadot-primitives/std", "polkadot-primitives/std",
"polkadot-parachain/std", "polkadot-parachain/std",
"sp-inherents/std",
"polkadot-core-primitives/std", "polkadot-core-primitives/std",
"sp-runtime/std", "sp-runtime/std",
"sp-core/std",
"sp-trie/std", "sp-trie/std",
] ]
-31
View File
@@ -39,37 +39,6 @@ pub type InboundHrmpMessage = polkadot_primitives::v1::InboundHrmpMessage<relay_
/// And outbound HRMP message /// And outbound HRMP message
pub type OutboundHrmpMessage = polkadot_primitives::v1::OutboundHrmpMessage<ParaId>; pub type OutboundHrmpMessage = polkadot_primitives::v1::OutboundHrmpMessage<ParaId>;
/// Identifiers and types related to Cumulus Inherents
pub mod inherents {
use super::{InboundDownwardMessage, InboundHrmpMessage, ParaId};
use sp_inherents::InherentIdentifier;
use sp_std::{collections::btree_map::BTreeMap, vec::Vec};
/// The identifier for the parachain-system inherent.
pub const SYSTEM_INHERENT_IDENTIFIER: InherentIdentifier = *b"sysi1337";
/// The payload that system inherent carries.
#[derive(codec::Encode, codec::Decode, sp_core::RuntimeDebug, Clone, PartialEq)]
pub struct SystemInherentData {
pub validation_data: crate::PersistedValidationData,
/// A storage proof of a predefined set of keys from the relay-chain.
///
/// Specifically this witness contains the data for:
///
/// - active host configuration as per the relay parent,
/// - the relay dispatch queue sizes
/// - the list of egress HRMP channels (in the list of recipients form)
/// - the metadata for the egress HRMP channels
pub relay_chain_state: sp_trie::StorageProof,
/// Downward messages in the order they were sent.
pub downward_messages: Vec<InboundDownwardMessage>,
/// HRMP messages grouped by channels. The messages in the inner vec must be in order they
/// were sent. In combination with the rule of no more than one message in a channel per block,
/// this means `sent_at` is **strictly** greater than the previous one (if any).
pub horizontal_messages: BTreeMap<ParaId, Vec<InboundHrmpMessage>>,
}
}
/// Well known keys for values in the storage. /// Well known keys for values in the storage.
pub mod well_known_keys { pub mod well_known_keys {
/// The storage key for the upward messages. /// The storage key for the upward messages.
@@ -0,0 +1,39 @@
[package]
name = "cumulus-primitives-parachain-inherent"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
[dependencies]
# Substrate dependencies
sp-inherents = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
sp-trie = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
# Cumulus dependencies
cumulus-primitives-core = { path = "../core", default-features = false }
# Other dependencies
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ "derive" ] }
tracing = { version = "0.1.22", optional = true }
[features]
default = [ "std" ]
std = [
"codec/std",
"cumulus-primitives-core/std",
"sp-inherents/std",
"sp-core/std",
"sp-trie/std",
"sp-std/std",
"sp-state-machine",
"tracing",
"sp-runtime",
"sc-client-api",
"sp-api",
]
@@ -0,0 +1,225 @@
// Copyright 2021 Parity Technologies (UK) Ltd.
// This file is part of Cumulus.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
//! Client side code for generating the parachain inherent.
use crate::ParachainInherentData;
use codec::Decode;
use cumulus_primitives_core::{
relay_chain::{
self,
v1::{HrmpChannelId, ParachainHost},
Block as PBlock, Hash as PHash,
},
InboundDownwardMessage, InboundHrmpMessage, ParaId, PersistedValidationData,
};
use sc_client_api::Backend;
use sp_api::ProvideRuntimeApi;
use sp_runtime::generic::BlockId;
use sp_state_machine::Backend as _;
use std::collections::BTreeMap;
const LOG_TARGET: &str = "parachain-inherent";
/// Returns the whole contents of the downward message queue for the parachain we are collating
/// for.
///
/// Returns `None` in case of an error.
fn retrieve_dmq_contents<PClient>(
polkadot_client: &PClient,
para_id: ParaId,
relay_parent: PHash,
) -> Option<Vec<InboundDownwardMessage>>
where
PClient: ProvideRuntimeApi<PBlock>,
PClient::Api: ParachainHost<PBlock>,
{
polkadot_client
.runtime_api()
.dmq_contents_with_context(
&BlockId::hash(relay_parent),
sp_core::ExecutionContext::Importing,
para_id,
)
.map_err(|e| {
tracing::error!(
target: LOG_TARGET,
relay_parent = ?relay_parent,
error = ?e,
"An error occured during requesting the downward messages.",
);
})
.ok()
}
/// Returns channels contents for each inbound HRMP channel addressed to the parachain we are
/// collating for.
///
/// Empty channels are also included.
fn retrieve_all_inbound_hrmp_channel_contents<PClient>(
polkadot_client: &PClient,
para_id: ParaId,
relay_parent: PHash,
) -> Option<BTreeMap<ParaId, Vec<InboundHrmpMessage>>>
where
PClient: ProvideRuntimeApi<PBlock>,
PClient::Api: ParachainHost<PBlock>,
{
polkadot_client
.runtime_api()
.inbound_hrmp_channels_contents_with_context(
&BlockId::hash(relay_parent),
sp_core::ExecutionContext::Importing,
para_id,
)
.map_err(|e| {
tracing::error!(
target: LOG_TARGET,
relay_parent = ?relay_parent,
error = ?e,
"An error occured during requesting the inbound HRMP messages.",
);
})
.ok()
}
/// Collect the relevant relay chain state in form of a proof for putting it into the validation
/// data inherent.
fn collect_relay_storage_proof(
polkadot_backend: &impl Backend<PBlock>,
para_id: ParaId,
relay_parent: PHash,
) -> Option<sp_state_machine::StorageProof> {
use relay_chain::well_known_keys as relay_well_known_keys;
let relay_parent_state_backend = polkadot_backend
.state_at(BlockId::Hash(relay_parent))
.map_err(|e| {
tracing::error!(
target: LOG_TARGET,
relay_parent = ?relay_parent,
error = ?e,
"Cannot obtain the state of the relay chain.",
)
})
.ok()?;
let ingress_channels = relay_parent_state_backend
.storage(&relay_well_known_keys::hrmp_ingress_channel_index(para_id))
.map_err(|e| {
tracing::error!(
target: LOG_TARGET,
error = ?e,
"Cannot obtain the hrmp ingress channel index."
)
})
.ok()?;
let ingress_channels = ingress_channels
.map(|raw| <Vec<ParaId>>::decode(&mut &raw[..]))
.transpose()
.map_err(|e| {
tracing::error!(
target: LOG_TARGET,
error = ?e,
"Cannot decode the hrmp ingress channel index.",
)
})
.ok()?
.unwrap_or_default();
let egress_channels = relay_parent_state_backend
.storage(&relay_well_known_keys::hrmp_egress_channel_index(para_id))
.map_err(|e| {
tracing::error!(
target: LOG_TARGET,
error = ?e,
"Cannot obtain the hrmp egress channel index.",
)
})
.ok()?;
let egress_channels = egress_channels
.map(|raw| <Vec<ParaId>>::decode(&mut &raw[..]))
.transpose()
.map_err(|e| {
tracing::error!(
target: LOG_TARGET,
error = ?e,
"Cannot decode the hrmp egress channel index.",
)
})
.ok()?
.unwrap_or_default();
let mut relevant_keys = vec![];
relevant_keys.push(relay_well_known_keys::ACTIVE_CONFIG.to_vec());
relevant_keys.push(relay_well_known_keys::dmq_mqc_head(para_id));
relevant_keys.push(relay_well_known_keys::relay_dispatch_queue_size(para_id));
relevant_keys.push(relay_well_known_keys::hrmp_ingress_channel_index(para_id));
relevant_keys.push(relay_well_known_keys::hrmp_egress_channel_index(para_id));
relevant_keys.extend(ingress_channels.into_iter().map(|sender| {
relay_well_known_keys::hrmp_channels(HrmpChannelId {
sender,
recipient: para_id,
})
}));
relevant_keys.extend(egress_channels.into_iter().map(|recipient| {
relay_well_known_keys::hrmp_channels(HrmpChannelId {
sender: para_id,
recipient,
})
}));
sp_state_machine::prove_read(relay_parent_state_backend, relevant_keys)
.map_err(|e| {
tracing::error!(
target: LOG_TARGET,
relay_parent = ?relay_parent,
error = ?e,
"Failed to collect required relay chain state storage proof.",
)
})
.ok()
}
impl ParachainInherentData {
/// Create the [`ParachainInherentData`] at the given `relay_parent`.
///
/// Returns `None` if the creation failed.
pub fn create_at<PClient>(
relay_parent: PHash,
polkadot_client: &PClient,
polkadot_backend: &impl Backend<PBlock>,
validation_data: &PersistedValidationData,
para_id: ParaId,
) -> Option<ParachainInherentData>
where
PClient: ProvideRuntimeApi<PBlock>,
PClient::Api: ParachainHost<PBlock>,
{
let relay_chain_state = collect_relay_storage_proof(polkadot_backend, para_id, relay_parent)?;
let downward_messages = retrieve_dmq_contents(polkadot_client, para_id, relay_parent)?;
let horizontal_messages =
retrieve_all_inbound_hrmp_channel_contents(polkadot_client, para_id, relay_parent)?;
Some(ParachainInherentData {
downward_messages,
horizontal_messages,
validation_data: validation_data.clone(),
relay_chain_state,
})
}
}
@@ -0,0 +1,64 @@
// Copyright 2021 Parity Technologies (UK) Ltd.
// This file is part of Cumulus.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
//! Cumulus parachain inherent
//!
//! The [`ParachainInherentData`] is the data that is passed by the collator to the parachain runtime.
//! The runtime will use this data to execute messages from other parachains/the relay chain or to
//! read data from the relay chain state. When the parachain is validated by a parachain validator on
//! the relay chain, this data is checked for correctnes. If the data passed by the collator to the
//! runtime isn't correct, the parachain candidate is considered invalid.
//!
//! Use [`ParachainInherentData::create_at`] to create the [`ParachainInherentData`] at a given
//! relay chain block to include it in a parachain block.
#![cfg_attr(not(feature = "std"), no_std)]
use cumulus_primitives_core::{
InboundDownwardMessage, InboundHrmpMessage, ParaId, PersistedValidationData,
};
use sp_inherents::InherentIdentifier;
use sp_std::{collections::btree_map::BTreeMap, vec::Vec};
#[cfg(feature = "std")]
mod client_side;
#[cfg(feature = "std")]
pub use client_side::*;
/// The identifier for the parachain inherent.
pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"sysi1337";
/// The inherent data that is passed by the collator to the parachain runtime.
#[derive(codec::Encode, codec::Decode, sp_core::RuntimeDebug, Clone, PartialEq)]
pub struct ParachainInherentData {
pub validation_data: PersistedValidationData,
/// A storage proof of a predefined set of keys from the relay-chain.
///
/// Specifically this witness contains the data for:
///
/// - active host configuration as per the relay parent,
/// - the relay dispatch queue sizes
/// - the list of egress HRMP channels (in the list of recipients form)
/// - the metadata for the egress HRMP channels
pub relay_chain_state: sp_trie::StorageProof,
/// Downward messages in the order they were sent.
pub downward_messages: Vec<InboundDownwardMessage>,
/// HRMP messages grouped by channels. The messages in the inner vec must be in order they
/// were sent. In combination with the rule of no more than one message in a channel per block,
/// this means `sent_at` is **strictly** greater than the previous one (if any).
pub horizontal_messages: BTreeMap<ParaId, Vec<InboundHrmpMessage>>,
}
+1
View File
@@ -27,6 +27,7 @@ cumulus-test-runtime = { path = "../runtime" }
cumulus-test-service = { path = "../service" } cumulus-test-service = { path = "../service" }
cumulus-test-relay-sproof-builder = { path = "../relay-sproof-builder" } cumulus-test-relay-sproof-builder = { path = "../relay-sproof-builder" }
cumulus-primitives-core = { path = "../../primitives/core" } cumulus-primitives-core = { path = "../../primitives/core" }
cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" }
# Polkadot deps # Polkadot deps
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+5 -6
View File
@@ -15,11 +15,10 @@
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>. // along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
use crate::{Backend, Client}; use crate::{Backend, Client};
use cumulus_primitives_core::{ use cumulus_primitives_core::PersistedValidationData;
inherents::{SystemInherentData, SYSTEM_INHERENT_IDENTIFIER}, PersistedValidationData, use cumulus_primitives_parachain_inherent::{ParachainInherentData, INHERENT_IDENTIFIER};
};
use cumulus_test_runtime::{Block, GetLastTimestamp};
use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
use cumulus_test_runtime::{Block, GetLastTimestamp};
use polkadot_primitives::v1::BlockNumber as PBlockNumber; use polkadot_primitives::v1::BlockNumber as PBlockNumber;
use sc_block_builder::{BlockBuilder, BlockBuilderProvider}; use sc_block_builder::{BlockBuilder, BlockBuilderProvider};
use sp_api::ProvideRuntimeApi; use sp_api::ProvideRuntimeApi;
@@ -101,8 +100,8 @@ impl InitBlockBuilder for Client {
inherent_data inherent_data
.put_data( .put_data(
SYSTEM_INHERENT_IDENTIFIER, INHERENT_IDENTIFIER,
&SystemInherentData { &ParachainInherentData {
validation_data, validation_data,
relay_chain_state, relay_chain_state,
downward_messages: Default::default(), downward_messages: Default::default(),