Migrate from MQCs in persisted validation data to merkle proofs (#317)

* Update polkadot

* Migrate all uses of MQC heads to merkle proofs

* Mass rename `relay_parent_storage_root`

* Restore parachain-system tests

* Update polkadot and libp2p swarm for testing

* Collapse match into an if let

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* Fix compilation error in test-service

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
Sergei Shulepov
2021-02-08 19:48:30 +01:00
committed by GitHub
parent 9c125817f0
commit a4998998a9
10 changed files with 553 additions and 398 deletions
+318 -283
View File
File diff suppressed because it is too large Load Diff
+36 -1
View File
@@ -219,6 +219,31 @@ where
}) })
.ok()?; .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 let egress_channels = relay_parent_state_backend
.storage(&relay_well_known_keys::hrmp_egress_channel_index( .storage(&relay_well_known_keys::hrmp_egress_channel_index(
self.para_id, self.para_id,
@@ -246,12 +271,22 @@ where
let mut relevant_keys = vec![]; let mut relevant_keys = vec![];
relevant_keys.push(relay_well_known_keys::ACTIVE_CONFIG.to_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( relevant_keys.push(relay_well_known_keys::relay_dispatch_queue_size(
self.para_id, 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( relevant_keys.push(relay_well_known_keys::hrmp_egress_channel_index(
self.para_id, 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| { relevant_keys.extend(egress_channels.into_iter().map(|recipient| {
relay_well_known_keys::hrmp_channels(HrmpChannelId { relay_well_known_keys::hrmp_channels(HrmpChannelId {
sender: self.para_id, sender: self.para_id,
@@ -586,7 +621,7 @@ where
); );
let collation = let collation =
self.build_collation(b, block_hash, validation_data.block_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
+62 -72
View File
@@ -179,18 +179,18 @@ decl_module! {
// which means we can put the initialization logic here to remove the // which means we can put the initialization logic here to remove the
// sequencing problem. // sequencing problem.
if let Some((apply_block, validation_function)) = PendingValidationFunction::get() { if let Some((apply_block, validation_function)) = PendingValidationFunction::get() {
if vfp.block_number >= apply_block { if vfp.relay_parent_number >= apply_block {
PendingValidationFunction::kill(); PendingValidationFunction::kill();
LastUpgrade::put(&apply_block); LastUpgrade::put(&apply_block);
Self::put_parachain_code(&validation_function); Self::put_parachain_code(&validation_function);
Self::deposit_event(Event::ValidationFunctionApplied(vfp.block_number)); Self::deposit_event(Event::ValidationFunctionApplied(vfp.relay_parent_number));
} }
} }
let (host_config, relevant_messaging_state) = let (host_config, relevant_messaging_state) =
relay_state_snapshot::extract_from_proof( relay_state_snapshot::extract_from_proof(
T::SelfParaId::get(), T::SelfParaId::get(),
vfp.relay_storage_root, vfp.relay_parent_storage_root,
relay_chain_state relay_chain_state
) )
.map_err(|err| { .map_err(|err| {
@@ -200,13 +200,19 @@ decl_module! {
storage::unhashed::put(VALIDATION_DATA, &vfp); storage::unhashed::put(VALIDATION_DATA, &vfp);
DidUpdateValidationData::put(true); DidUpdateValidationData::put(true);
RelevantMessagingState::put(relevant_messaging_state); RelevantMessagingState::put(relevant_messaging_state.clone());
HostConfiguration::put(host_config); HostConfiguration::put(host_config);
<T::OnValidationData as OnValidationData>::on_validation_data(&vfp); <T::OnValidationData as OnValidationData>::on_validation_data(&vfp);
Self::process_inbound_downward_messages(&vfp, downward_messages)?; Self::process_inbound_downward_messages(
Self::process_inbound_horizontal_messages(&vfp, horizontal_messages)?; relevant_messaging_state.dmq_mqc_head,
downward_messages,
)?;
Self::process_inbound_horizontal_messages(
&relevant_messaging_state.ingress_channels,
horizontal_messages,
)?;
Ok(()) Ok(())
} }
@@ -437,7 +443,7 @@ impl<T: Config> Module<T> {
/// Checks if the sequence of the messages is valid, dispatches them and communicates the number /// Checks if the sequence of the messages is valid, dispatches them and communicates the number
/// of processed messages to the collator via a storage update. /// of processed messages to the collator via a storage update.
fn process_inbound_downward_messages( fn process_inbound_downward_messages(
vfp: &PersistedValidationData, expected_dmq_mqc_head: relay_chain::Hash,
downward_messages: Vec<InboundDownwardMessage>, downward_messages: Vec<InboundDownwardMessage>,
) -> DispatchResult { ) -> DispatchResult {
let dm_count = downward_messages.len() as u32; let dm_count = downward_messages.len() as u32;
@@ -453,7 +459,7 @@ impl<T: Config> Module<T> {
// After hashing each message in the message queue chain submitted by the collator, we should // After hashing each message in the message queue chain submitted by the collator, we should
// arrive to the MQC head provided by the relay chain. // arrive to the MQC head provided by the relay chain.
ensure!( ensure!(
result_mqc_head == vfp.dmq_mqc_head, result_mqc_head == expected_dmq_mqc_head,
Error::<T>::DmpMqcMismatch Error::<T>::DmpMqcMismatch
); );
@@ -469,14 +475,14 @@ impl<T: Config> Module<T> {
/// This is similar to [`process_inbound_downward_messages`], but works on multiple inbound /// This is similar to [`process_inbound_downward_messages`], but works on multiple inbound
/// channels. /// channels.
fn process_inbound_horizontal_messages( fn process_inbound_horizontal_messages(
vfp: &PersistedValidationData, ingress_channels: &[(ParaId, cumulus_primitives::AbridgedHrmpChannel)],
horizontal_messages: BTreeMap<ParaId, Vec<InboundHrmpMessage>>, horizontal_messages: BTreeMap<ParaId, Vec<InboundHrmpMessage>>,
) -> DispatchResult { ) -> DispatchResult {
// First, check that all submitted messages are sent from channels that exist. The channel // First, check that all submitted messages are sent from channels that exist. The channel
// exists if its MQC head is present in `vfp.hrmp_mqc_heads`. // exists if its MQC head is present in `vfp.hrmp_mqc_heads`.
for sender in horizontal_messages.keys() { for sender in horizontal_messages.keys() {
ensure!( ensure!(
vfp.hrmp_mqc_heads ingress_channels
.binary_search_by_key(sender, |&(s, _)| s) .binary_search_by_key(sender, |&(s, _)| s)
.is_ok(), .is_ok(),
Error::<T>::HrmpNoMqc, Error::<T>::HrmpNoMqc,
@@ -533,13 +539,14 @@ impl<T: Config> Module<T> {
// `running_mqc_heads`. Otherwise, in a block where no messages were sent in a channel // `running_mqc_heads`. Otherwise, in a block where no messages were sent in a channel
// it won't get into next block's `last_mqc_heads` and thus will be all zeros, which // it won't get into next block's `last_mqc_heads` and thus will be all zeros, which
// would corrupt the message queue chain. // would corrupt the message queue chain.
for &(ref sender, ref target_head) in &vfp.hrmp_mqc_heads { for &(ref sender, ref channel) in ingress_channels {
let cur_head = running_mqc_heads let cur_head = running_mqc_heads
.entry(*sender) .entry(*sender)
.or_insert_with(|| last_mqc_heads.get(&sender).cloned().unwrap_or_default()) .or_insert_with(|| last_mqc_heads.get(&sender).cloned().unwrap_or_default())
.head(); .head();
let target_head = channel.mqc_head.unwrap_or_default();
ensure!(&cur_head == target_head, Error::<T>::HrmpMqcMismatch); ensure!(cur_head == target_head, Error::<T>::HrmpMqcMismatch);
} }
LastHrmpMqcHeads::put(running_mqc_heads); LastHrmpMqcHeads::put(running_mqc_heads);
@@ -592,7 +599,7 @@ impl<T: Config> Module<T> {
} }
let relay_blocks_since_last_upgrade = vfp let relay_blocks_since_last_upgrade = vfp
.block_number .relay_parent_number
.saturating_sub(LastUpgrade::get()); .saturating_sub(LastUpgrade::get());
if relay_blocks_since_last_upgrade <= cfg.validation_upgrade_frequency { if relay_blocks_since_last_upgrade <= cfg.validation_upgrade_frequency {
@@ -600,7 +607,7 @@ impl<T: Config> Module<T> {
return None; return None;
} }
Some(vfp.block_number + cfg.validation_upgrade_delay) Some(vfp.relay_parent_number + cfg.validation_upgrade_delay)
} }
/// The implementation of the runtime upgrade scheduling. /// The implementation of the runtime upgrade scheduling.
@@ -1072,6 +1079,7 @@ mod tests {
self self
} }
#[allow(dead_code)] // might come in handy in future. If now is future and it still hasn't - feel free.
fn with_validation_data<F>(mut self, f: F) -> Self fn with_validation_data<F>(mut self, f: F) -> Self
where where
F: 'static + Fn(&BlockTests, RelayChainBlockNumber, &mut PersistedValidationData), F: 'static + Fn(&BlockTests, RelayChainBlockNumber, &mut PersistedValidationData),
@@ -1117,11 +1125,11 @@ mod tests {
if let Some(ref hook) = self.relay_sproof_builder_hook { if let Some(ref hook) = self.relay_sproof_builder_hook {
hook(self, *n as RelayChainBlockNumber, &mut sproof_builder); hook(self, *n as RelayChainBlockNumber, &mut sproof_builder);
} }
let (relay_storage_root, relay_chain_state) = let (relay_parent_storage_root, relay_chain_state) =
sproof_builder.into_state_root_and_proof(); sproof_builder.into_state_root_and_proof();
let mut vfp = PersistedValidationData { let mut vfp = PersistedValidationData {
block_number: *n as RelayChainBlockNumber, relay_parent_number: *n as RelayChainBlockNumber,
relay_storage_root, relay_parent_storage_root,
..Default::default() ..Default::default()
}; };
if let Some(ref hook) = self.persisted_validation_data_hook { if let Some(ref hook) = self.persisted_validation_data_hook {
@@ -1612,11 +1620,11 @@ mod tests {
} }
BlockTests::new() BlockTests::new()
.with_validation_data( .with_relay_sproof_builder(
|_, relay_block_num, validation_data| match relay_block_num { |_, relay_block_num, sproof| match relay_block_num {
1 => { 1 => {
validation_data.dmq_mqc_head = sproof.dmq_mqc_head =
MessageQueueChain::default().extend_downward(&MSG).head(); Some(MessageQueueChain::default().extend_downward(&MSG).head());
} }
_ => unreachable!(), _ => unreachable!(),
}, },
@@ -1661,39 +1669,31 @@ mod tests {
} }
BlockTests::new() BlockTests::new()
.with_validation_data( .with_relay_sproof_builder(
|_, relay_block_num, validation_data| match relay_block_num { |_, relay_block_num, sproof| match relay_block_num {
1 => { 1 => {
// 200 - doesn't exist yet // 200 - doesn't exist yet
// 300 - one new message // 300 - one new message
validation_data.hrmp_mqc_heads.push(( sproof.upsert_inbound_channel(ParaId::from(300)).mqc_head =
ParaId::from(300), Some(MessageQueueChain::default().extend_hrmp(&MSG_1).head());
MessageQueueChain::default().extend_hrmp(&MSG_1).head(),
));
} }
2 => { 2 => {
// 200 - two new messages // 200 - two new messages
// 300 - now present with one message. // 300 - now present with one message.
validation_data.hrmp_mqc_heads.push(( sproof.upsert_inbound_channel(ParaId::from(200)).mqc_head =
ParaId::from(200), Some(MessageQueueChain::default().extend_hrmp(&MSG_4).head());
MessageQueueChain::default().extend_hrmp(&MSG_4).head(), sproof.upsert_inbound_channel(ParaId::from(300)).mqc_head =
)); Some(MessageQueueChain::default()
validation_data.hrmp_mqc_heads.push((
ParaId::from(300),
MessageQueueChain::default()
.extend_hrmp(&MSG_1) .extend_hrmp(&MSG_1)
.extend_hrmp(&MSG_2) .extend_hrmp(&MSG_2)
.extend_hrmp(&MSG_3) .extend_hrmp(&MSG_3)
.head(), .head());
));
} }
3 => { 3 => {
// 200 - no new messages // 200 - no new messages
// 300 - is gone // 300 - is gone
validation_data.hrmp_mqc_heads.push(( sproof.upsert_inbound_channel(ParaId::from(200)).mqc_head =
ParaId::from(200), Some(MessageQueueChain::default().extend_hrmp(&MSG_4).head());
MessageQueueChain::default().extend_hrmp(&MSG_4).head(),
));
} }
_ => unreachable!(), _ => unreachable!(),
}, },
@@ -1747,21 +1747,17 @@ mod tests {
#[test] #[test]
fn receive_hrmp_empty_channel() { fn receive_hrmp_empty_channel() {
BlockTests::new() BlockTests::new()
.with_validation_data( .with_relay_sproof_builder(|_, relay_block_num, sproof| match relay_block_num {
|_, relay_block_num, validation_data| match relay_block_num { 1 => {
1 => { // no channels
// no channels }
} 2 => {
2 => { // one new channel
// one new channel sproof.upsert_inbound_channel(ParaId::from(300)).mqc_head =
validation_data.hrmp_mqc_heads.push(( Some(MessageQueueChain::default().head());
ParaId::from(300), }
MessageQueueChain::default().head(), _ => unreachable!(),
)); })
}
_ => unreachable!(),
},
)
.add(1, || {}) .add(1, || {})
.add(2, || {}); .add(2, || {});
} }
@@ -1783,30 +1779,24 @@ mod tests {
const ALICE: ParaId = ParaId::new(300); const ALICE: ParaId = ParaId::new(300);
BlockTests::new() BlockTests::new()
.with_validation_data( .with_relay_sproof_builder(
|_, relay_block_num, validation_data| match relay_block_num { |_, relay_block_num, sproof| match relay_block_num {
1 => { 1 => {
validation_data.hrmp_mqc_heads.push(( sproof.upsert_inbound_channel(ALICE).mqc_head
ALICE, = Some(MessageQueueChain::default().extend_hrmp(&MSG_1).head());
MessageQueueChain::default().extend_hrmp(&MSG_1).head(),
));
} }
2 => { 2 => {
// 300 - no new messages, mqc stayed the same. // 300 - no new messages, mqc stayed the same.
validation_data.hrmp_mqc_heads.push(( sproof.upsert_inbound_channel(ALICE).mqc_head
ALICE, = Some(MessageQueueChain::default().extend_hrmp(&MSG_1).head());
MessageQueueChain::default().extend_hrmp(&MSG_1).head(),
));
} }
3 => { 3 => {
// 300 - new message. // 300 - new message.
validation_data.hrmp_mqc_heads.push(( sproof.upsert_inbound_channel(ALICE).mqc_head
ALICE, = Some(MessageQueueChain::default()
MessageQueueChain::default() .extend_hrmp(&MSG_1)
.extend_hrmp(&MSG_1) .extend_hrmp(&MSG_2)
.extend_hrmp(&MSG_2) .head());
.head(),
));
} }
_ => unreachable!(), _ => unreachable!(),
}, },
@@ -27,14 +27,27 @@ use sp_std::vec::Vec;
/// This data is essential for making sure that the parachain is aware of current resource use on /// This data is essential for making sure that the parachain is aware of current resource use on
/// the relay chain and that the candidates produced for this parachain do not exceed any of these /// the relay chain and that the candidates produced for this parachain do not exceed any of these
/// limits. /// limits.
#[derive(Encode, Decode)] #[derive(Clone, Encode, Decode)]
pub struct MessagingStateSnapshot { pub struct MessagingStateSnapshot {
/// The current message queue chain head for downward message queue.
///
/// If the value is absent on the relay chain this will be set to all zeros.
pub dmq_mqc_head: relay_chain::Hash,
/// The current capacity of the upward message queue of the current parachain on the relay chain. /// The current capacity of the upward message queue of the current parachain on the relay chain.
/// ///
/// The capacity is represented by a tuple that consist of the `count` of the messages and the /// The capacity is represented by a tuple that consist of the `count` of the messages and the
/// `total_size` expressed as the sum of byte sizes of all messages in the queue. /// `total_size` expressed as the sum of byte sizes of all messages in the queue.
pub relay_dispatch_queue_size: (u32, u32), pub relay_dispatch_queue_size: (u32, u32),
/// Information about all the inbound HRMP channels.
///
/// These are structured as a list of tuples. The para id in the tuple specifies the sender
/// of the channel. Obviously, the recipient is the current parachain.
///
/// The channels are sorted by the sender para id ascension.
pub ingress_channels: Vec<(ParaId, AbridgedHrmpChannel)>,
/// Information about all the outbound HRMP channels. /// Information about all the outbound HRMP channels.
/// ///
/// These are structured as a list of tuples. The para id in the tuple specifies the recipient /// These are structured as a list of tuples. The para id in the tuple specifies the recipient
@@ -50,12 +63,16 @@ pub enum Error {
RootMismatch, RootMismatch,
/// The host configuration cannot be extracted. /// The host configuration cannot be extracted.
Config(ReadEntryErr), Config(ReadEntryErr),
/// The DMQ MQC head cannot be extracted.
DmqMqcHead(ReadEntryErr),
/// Relay dispatch queue cannot be extracted. /// Relay dispatch queue cannot be extracted.
RelayDispatchQueueSize(ReadEntryErr), RelayDispatchQueueSize(ReadEntryErr),
/// The hrmp inress channel index cannot be extracted.
HrmpIngressChannelIndex(ReadEntryErr),
/// The hrmp egress channel index cannot be extracted. /// The hrmp egress channel index cannot be extracted.
HrmpEgressChannelIndex(ReadEntryErr), HrmpEgressChannelIndex(ReadEntryErr),
/// The hrmp channel for the given recipient cannot be extracted. /// The channel identified by the sender and receiver cannot be extracted.
HrmpChannel(ParaId, ReadEntryErr), HrmpChannel(ParaId, ParaId, ReadEntryErr),
} }
#[derive(Debug)] #[derive(Debug)]
@@ -92,14 +109,14 @@ where
/// of the current parachain and the expected storage root the proof should stem from. /// of the current parachain and the expected storage root the proof should stem from.
pub fn extract_from_proof( pub fn extract_from_proof(
para_id: ParaId, para_id: ParaId,
relay_storage_root: relay_chain::v1::Hash, relay_parent_storage_root: relay_chain::v1::Hash,
proof: StorageProof, proof: StorageProof,
) -> Result<(AbridgedHostConfiguration, MessagingStateSnapshot), Error> { ) -> Result<(AbridgedHostConfiguration, MessagingStateSnapshot), Error> {
let db = proof.into_memory_db::<HashFor<relay_chain::Block>>(); let db = proof.into_memory_db::<HashFor<relay_chain::Block>>();
if !db.contains(&relay_storage_root, EMPTY_PREFIX) { if !db.contains(&relay_parent_storage_root, EMPTY_PREFIX) {
return Err(Error::RootMismatch); return Err(Error::RootMismatch);
} }
let backend = TrieBackend::new(db, relay_storage_root); let backend = TrieBackend::new(db, relay_parent_storage_root);
let host_config: AbridgedHostConfiguration = read_entry( let host_config: AbridgedHostConfiguration = read_entry(
&backend, &backend,
@@ -108,6 +125,13 @@ pub fn extract_from_proof(
) )
.map_err(Error::Config)?; .map_err(Error::Config)?;
let dmq_mqc_head: relay_chain::Hash = read_entry(
&backend,
&relay_chain::well_known_keys::dmq_mqc_head(para_id),
Some(Default::default()),
)
.map_err(Error::DmqMqcHead)?;
let relay_dispatch_queue_size: (u32, u32) = read_entry( let relay_dispatch_queue_size: (u32, u32) = read_entry(
&backend, &backend,
&relay_chain::well_known_keys::relay_dispatch_queue_size(para_id), &relay_chain::well_known_keys::relay_dispatch_queue_size(para_id),
@@ -115,6 +139,13 @@ pub fn extract_from_proof(
) )
.map_err(Error::RelayDispatchQueueSize)?; .map_err(Error::RelayDispatchQueueSize)?;
let ingress_channel_index: Vec<ParaId> = read_entry(
&backend,
&relay_chain::well_known_keys::hrmp_ingress_channel_index(para_id),
Some(Vec::new()),
)
.map_err(Error::HrmpIngressChannelIndex)?;
let egress_channel_index: Vec<ParaId> = read_entry( let egress_channel_index: Vec<ParaId> = read_entry(
&backend, &backend,
&relay_chain::well_known_keys::hrmp_egress_channel_index(para_id), &relay_chain::well_known_keys::hrmp_egress_channel_index(para_id),
@@ -122,6 +153,21 @@ pub fn extract_from_proof(
) )
.map_err(Error::HrmpEgressChannelIndex)?; .map_err(Error::HrmpEgressChannelIndex)?;
let mut ingress_channels = Vec::with_capacity(ingress_channel_index.len());
for sender in ingress_channel_index {
let channel_id = relay_chain::v1::HrmpChannelId {
sender,
recipient: para_id,
};
let hrmp_channel: AbridgedHrmpChannel = read_entry(
&backend,
&relay_chain::well_known_keys::hrmp_channels(channel_id),
None,
)
.map_err(|read_err| Error::HrmpChannel(sender, para_id, read_err))?;
ingress_channels.push((sender, hrmp_channel));
}
let mut egress_channels = Vec::with_capacity(egress_channel_index.len()); let mut egress_channels = Vec::with_capacity(egress_channel_index.len());
for recipient in egress_channel_index { for recipient in egress_channel_index {
let channel_id = relay_chain::v1::HrmpChannelId { let channel_id = relay_chain::v1::HrmpChannelId {
@@ -133,17 +179,19 @@ pub fn extract_from_proof(
&relay_chain::well_known_keys::hrmp_channels(channel_id), &relay_chain::well_known_keys::hrmp_channels(channel_id),
None, None,
) )
.map_err(|read_err| Error::HrmpChannel(recipient, read_err))?; .map_err(|read_err| Error::HrmpChannel(para_id, recipient, read_err))?;
egress_channels.push((recipient, hrmp_channel)); egress_channels.push((recipient, hrmp_channel));
} }
// NOTE that egress_channels promises to be sorted. We satisfy this property by relying on // NOTE that ingress_channels and egress_channels promise to be sorted. We satisfy this property
// the fact that `egress_channel_index` is itself sorted. // by relying on the fact that `ingress_channel_index` and `egress_channel_index` are themselves sorted.
Ok(( Ok((
host_config, host_config,
MessagingStateSnapshot { MessagingStateSnapshot {
dmq_mqc_head,
relay_dispatch_queue_size, relay_dispatch_queue_size,
ingress_channels,
egress_channels, egress_channels,
}, },
)) ))
+1
View File
@@ -63,6 +63,7 @@ pub fn new_partial(
let transaction_pool = sc_transaction_pool::BasicPool::new_full( let transaction_pool = sc_transaction_pool::BasicPool::new_full(
config.transaction_pool.clone(), config.transaction_pool.clone(),
config.role.is_authority().into(),
config.prometheus_registry(), config.prometheus_registry(),
task_manager.spawn_handle(), task_manager.spawn_handle(),
client.clone(), client.clone(),
@@ -180,7 +180,7 @@ pub fn validate_block<B: BlockT, E: ExecuteBlock<B>>(params: ValidationParams) -
.storage(HRMP_WATERMARK) .storage(HRMP_WATERMARK)
.flatten() .flatten()
.map(|v| Decode::decode(&mut &v[..]).expect("HRMP watermark is not encoded correctly")) .map(|v| Decode::decode(&mut &v[..]).expect("HRMP watermark is not encoded correctly"))
.unwrap_or(validation_data.block_number); .unwrap_or(validation_data.relay_parent_number);
ValidationResult { ValidationResult {
head_data, head_data,
@@ -210,23 +210,15 @@ impl<'a, B: BlockT> WitnessExt<'a, B> {
assert_eq!( assert_eq!(
self.params.parent_head, self.params.parent_head,
validation_data.parent_head validation_data.parent_head,
); );
assert_eq!( assert_eq!(
self.params.relay_chain_height, self.params.relay_parent_number,
validation_data.block_number validation_data.relay_parent_number,
); );
assert_eq!( assert_eq!(
self.params.hrmp_mqc_heads, self.params.relay_parent_storage_root,
validation_data.hrmp_mqc_heads validation_data.relay_parent_storage_root,
);
assert_eq!(
self.params.dmq_mqc_head,
validation_data.dmq_mqc_head,
);
assert_eq!(
self.params.relay_storage_root,
validation_data.relay_storage_root,
); );
} }
} }
+13 -15
View File
@@ -42,17 +42,15 @@ use codec::{Decode, Encode};
fn call_validate_block( fn call_validate_block(
parent_head: Header, parent_head: Header,
block_data: ParachainBlockData<Block>, block_data: ParachainBlockData<Block>,
relay_storage_root: Hash, relay_parent_storage_root: Hash,
) -> Result<Header> { ) -> Result<Header> {
let mut ext = TestExternalities::default(); let mut ext = TestExternalities::default();
let mut ext_ext = ext.ext(); let mut ext_ext = ext.ext();
let params = ValidationParams { let params = ValidationParams {
block_data: BlockData(block_data.encode()), block_data: BlockData(block_data.encode()),
parent_head: HeadData(parent_head.encode()), parent_head: HeadData(parent_head.encode()),
relay_chain_height: 1, relay_parent_number: 1,
relay_storage_root, relay_parent_storage_root,
hrmp_mqc_heads: Vec::new(),
dmq_mqc_head: Default::default(),
} }
.encode(); .encode();
@@ -87,7 +85,7 @@ fn create_test_client() -> (Client, LongestChain) {
struct TestBlockData { struct TestBlockData {
block: Block, block: Block,
witness: sp_trie::StorageProof, witness: sp_trie::StorageProof,
relay_storage_root: Hash, relay_parent_storage_root: Hash,
} }
fn build_block_with_witness( fn build_block_with_witness(
@@ -96,12 +94,12 @@ fn build_block_with_witness(
parent_head: Header, parent_head: Header,
) -> TestBlockData { ) -> TestBlockData {
let sproof_builder = RelayStateSproofBuilder::default(); let sproof_builder = RelayStateSproofBuilder::default();
let (relay_storage_root, _) = sproof_builder.clone().into_state_root_and_proof(); let (relay_parent_storage_root, _) = sproof_builder.clone().into_state_root_and_proof();
let block_id = BlockId::Hash(client.info().best_hash); let block_id = BlockId::Hash(client.info().best_hash);
let mut builder = client.init_block_builder_at( let mut builder = client.init_block_builder_at(
&block_id, &block_id,
Some(PersistedValidationData { Some(PersistedValidationData {
block_number: 1, relay_parent_number: 1,
parent_head: parent_head.encode().into(), parent_head: parent_head.encode().into(),
..Default::default() ..Default::default()
}), }),
@@ -119,7 +117,7 @@ fn build_block_with_witness(
witness: built_block witness: built_block
.proof .proof
.expect("We enabled proof recording before."), .expect("We enabled proof recording before."),
relay_storage_root, relay_parent_storage_root,
} }
} }
@@ -132,13 +130,13 @@ fn validate_block_no_extra_extrinsics() {
let TestBlockData { let TestBlockData {
block, block,
witness, witness,
relay_storage_root, relay_parent_storage_root,
} = build_block_with_witness(&client, vec![], parent_head.clone()); } = build_block_with_witness(&client, vec![], parent_head.clone());
let (header, extrinsics) = block.deconstruct(); let (header, extrinsics) = block.deconstruct();
let block_data = ParachainBlockData::new(header.clone(), extrinsics, witness); let block_data = ParachainBlockData::new(header.clone(), extrinsics, witness);
let res_header = call_validate_block(parent_head, block_data, relay_storage_root) let res_header = call_validate_block(parent_head, block_data, relay_parent_storage_root)
.expect("Calls `validate_block`"); .expect("Calls `validate_block`");
assert_eq!(header, res_header); assert_eq!(header, res_header);
} }
@@ -158,13 +156,13 @@ fn validate_block_with_extra_extrinsics() {
let TestBlockData { let TestBlockData {
block, block,
witness, witness,
relay_storage_root, relay_parent_storage_root,
} = build_block_with_witness(&client, extra_extrinsics, parent_head.clone()); } = build_block_with_witness(&client, extra_extrinsics, parent_head.clone());
let (header, extrinsics) = block.deconstruct(); let (header, extrinsics) = block.deconstruct();
let block_data = ParachainBlockData::new(header.clone(), extrinsics, witness); let block_data = ParachainBlockData::new(header.clone(), extrinsics, witness);
let res_header = call_validate_block(parent_head, block_data, relay_storage_root) let res_header = call_validate_block(parent_head, block_data, relay_parent_storage_root)
.expect("Calls `validate_block`"); .expect("Calls `validate_block`");
assert_eq!(header, res_header); assert_eq!(header, res_header);
} }
@@ -179,12 +177,12 @@ fn validate_block_invalid_parent_hash() {
let TestBlockData { let TestBlockData {
block, block,
witness, witness,
relay_storage_root, relay_parent_storage_root,
} = build_block_with_witness(&client, vec![], parent_head.clone()); } = build_block_with_witness(&client, vec![], parent_head.clone());
let (mut header, extrinsics) = block.deconstruct(); let (mut header, extrinsics) = block.deconstruct();
header.set_parent_hash(Hash::from_low_u64_be(1)); header.set_parent_hash(Hash::from_low_u64_be(1));
let block_data = ParachainBlockData::new(header, extrinsics, witness); let block_data = ParachainBlockData::new(header, extrinsics, witness);
call_validate_block(parent_head, block_data, relay_storage_root) call_validate_block(parent_head, block_data, relay_parent_storage_root)
.expect("Calls `validate_block`"); .expect("Calls `validate_block`");
} }
+3 -3
View File
@@ -88,16 +88,16 @@ impl InitBlockBuilder for Client {
.put_data(sp_timestamp::INHERENT_IDENTIFIER, &timestamp) .put_data(sp_timestamp::INHERENT_IDENTIFIER, &timestamp)
.expect("Put timestamp failed"); .expect("Put timestamp failed");
let (relay_storage_root, relay_chain_state) = let (relay_parent_storage_root, relay_chain_state) =
relay_sproof_builder.into_state_root_and_proof(); relay_sproof_builder.into_state_root_and_proof();
let mut validation_data = validation_data.unwrap_or_default(); let mut validation_data = validation_data.unwrap_or_default();
assert_eq!( assert_eq!(
validation_data.relay_storage_root, validation_data.relay_parent_storage_root,
Default::default(), Default::default(),
"Overriding the relay storage root is not implemented", "Overriding the relay storage root is not implemented",
); );
validation_data.relay_storage_root = relay_storage_root; validation_data.relay_parent_storage_root = relay_parent_storage_root;
inherent_data inherent_data
.put_data( .put_data(
+56 -1
View File
@@ -22,9 +22,20 @@ use sp_std::collections::btree_map::BTreeMap;
/// Builds a sproof (portmanteau of 'spoof' and 'proof') of the relay chain state. /// Builds a sproof (portmanteau of 'spoof' and 'proof') of the relay chain state.
#[derive(Clone)] #[derive(Clone)]
pub struct RelayStateSproofBuilder { pub struct RelayStateSproofBuilder {
/// The para id of the current parachain.
///
/// This doesn't get into the storage proof produced by the builder, however, it is used for
/// generation of the storage image and by auxilary methods.
///
/// It's recommended to change this value once in the very beginning of usage.
///
/// The default value is 200.
pub para_id: ParaId, pub para_id: ParaId,
pub host_config: AbridgedHostConfiguration, pub host_config: AbridgedHostConfiguration,
pub dmq_mqc_head: Option<relay_chain::Hash>,
pub relay_dispatch_queue_size: Option<(u32, u32)>, pub relay_dispatch_queue_size: Option<(u32, u32)>,
pub hrmp_ingress_channel_index: Option<Vec<ParaId>>,
pub hrmp_egress_channel_index: Option<Vec<ParaId>>, pub hrmp_egress_channel_index: Option<Vec<ParaId>>,
pub hrmp_channels: BTreeMap<relay_chain::v1::HrmpChannelId, AbridgedHrmpChannel>, pub hrmp_channels: BTreeMap<relay_chain::v1::HrmpChannelId, AbridgedHrmpChannel>,
} }
@@ -44,7 +55,9 @@ impl Default for RelayStateSproofBuilder {
validation_upgrade_frequency: 6, validation_upgrade_frequency: 6,
validation_upgrade_delay: 6, validation_upgrade_delay: 6,
}, },
dmq_mqc_head: None,
relay_dispatch_queue_size: None, relay_dispatch_queue_size: None,
hrmp_ingress_channel_index: None,
hrmp_egress_channel_index: None, hrmp_egress_channel_index: None,
hrmp_channels: BTreeMap::new(), hrmp_channels: BTreeMap::new(),
} }
@@ -52,6 +65,32 @@ impl Default for RelayStateSproofBuilder {
} }
impl RelayStateSproofBuilder { impl RelayStateSproofBuilder {
/// Returns a mutable reference to HRMP channel metadata for a channel (`sender`, `self.para_id`).
///
/// If there is no channel, a new default one is created.
///
/// It also updates the `hrmp_ingress_channel_index`, creating it if needed.
pub fn upsert_inbound_channel(&mut self, sender: ParaId) -> &mut AbridgedHrmpChannel {
let in_index = self.hrmp_ingress_channel_index.get_or_insert_with(Vec::new);
if let Err(idx) = in_index.binary_search(&sender) {
in_index.insert(idx, sender);
}
self.hrmp_channels
.entry(relay_chain::v1::HrmpChannelId {
sender,
recipient: self.para_id,
})
.or_insert_with(|| AbridgedHrmpChannel {
max_capacity: 0,
max_total_size: 0,
max_message_size: 0,
msg_count: 0,
total_size: 0,
mqc_head: None,
})
}
pub fn into_state_root_and_proof( pub fn into_state_root_and_proof(
self, self,
) -> ( ) -> (
@@ -74,16 +113,32 @@ impl RelayStateSproofBuilder {
relay_chain::well_known_keys::ACTIVE_CONFIG.to_vec(), relay_chain::well_known_keys::ACTIVE_CONFIG.to_vec(),
self.host_config.encode(), self.host_config.encode(),
); );
if let Some(dmq_mqc_head) = self.dmq_mqc_head {
insert(
relay_chain::well_known_keys::dmq_mqc_head(self.para_id),
dmq_mqc_head.encode(),
);
}
if let Some(relay_dispatch_queue_size) = self.relay_dispatch_queue_size { if let Some(relay_dispatch_queue_size) = self.relay_dispatch_queue_size {
insert( insert(
relay_chain::well_known_keys::relay_dispatch_queue_size(self.para_id), relay_chain::well_known_keys::relay_dispatch_queue_size(self.para_id),
relay_dispatch_queue_size.encode(), relay_dispatch_queue_size.encode(),
); );
} }
if let Some(hrmp_ingress_channel_index) = self.hrmp_ingress_channel_index {
let mut sorted = hrmp_ingress_channel_index.clone();
sorted.sort();
assert_eq!(sorted, hrmp_ingress_channel_index);
insert(
relay_chain::well_known_keys::hrmp_ingress_channel_index(self.para_id),
hrmp_ingress_channel_index.encode(),
);
}
if let Some(hrmp_egress_channel_index) = self.hrmp_egress_channel_index { if let Some(hrmp_egress_channel_index) = self.hrmp_egress_channel_index {
let mut sorted = hrmp_egress_channel_index.clone(); let mut sorted = hrmp_egress_channel_index.clone();
sorted.sort(); sorted.sort();
assert_eq!(sorted, hrmp_egress_channel_index,); assert_eq!(sorted, hrmp_egress_channel_index);
insert( insert(
relay_chain::well_known_keys::hrmp_egress_channel_index(self.para_id), relay_chain::well_known_keys::hrmp_egress_channel_index(self.para_id),
+1
View File
@@ -87,6 +87,7 @@ pub fn new_partial(
let transaction_pool = sc_transaction_pool::BasicPool::new_full( let transaction_pool = sc_transaction_pool::BasicPool::new_full(
config.transaction_pool.clone(), config.transaction_pool.clone(),
config.role.is_authority().into(),
config.prometheus_registry(), config.prometheus_registry(),
task_manager.spawn_handle(), task_manager.spawn_handle(),
client.clone(), client.clone(),