mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 07:01:03 +00:00
Add relay storage root to persisted validation data (#2161)
* Cont.: Implement the state root obtaining during inclusion During inclusion now we obtain the storage root by passing it through the inclusion_inherent. * Fix tests * Bump rococo spec version * Reorder the parent header into the end of the inclusion inherent. When the parent header is in the beginning, it shifts the other two fields, so that a previous version won't be able to decode that. If we put the parent header in the end, the other two fields will stay at their positions, thus make it possible to decode with the previous version. That allows us to perform upgrade of rococo runtime without needing of simultanuous upgrade of nodes and runtime, or restart of the network. * Squash a stray tab
This commit is contained in:
@@ -25,7 +25,7 @@ use primitives::v1::{
|
||||
ValidatorId, CandidateCommitments, CandidateDescriptor, ValidatorIndex, Id as ParaId,
|
||||
AvailabilityBitfield as AvailabilityBitfield, SignedAvailabilityBitfields, SigningContext,
|
||||
BackedCandidate, CoreIndex, GroupIndex, CommittedCandidateReceipt,
|
||||
CandidateReceipt, HeadData, CandidateHash,
|
||||
CandidateReceipt, HeadData, CandidateHash, Hash,
|
||||
};
|
||||
use frame_support::{
|
||||
decl_storage, decl_module, decl_error, decl_event, ensure, debug,
|
||||
@@ -382,11 +382,13 @@ impl<T: Config> Module<T> {
|
||||
Ok(freed_cores)
|
||||
}
|
||||
|
||||
/// Process candidates that have been backed. Provide a set of candidates and scheduled cores.
|
||||
/// Process candidates that have been backed. Provide the relay storage root, a set of candidates
|
||||
/// and scheduled cores.
|
||||
///
|
||||
/// Both should be sorted ascending by core index, and the candidates should be a subset of
|
||||
/// scheduled cores. If these conditions are not met, the execution of the function fails.
|
||||
pub(crate) fn process_candidates(
|
||||
parent_storage_root: Hash,
|
||||
candidates: Vec<BackedCandidate<T::Hash>>,
|
||||
scheduled: Vec<CoreAssignment>,
|
||||
group_validators: impl Fn(GroupIndex) -> Option<Vec<ValidatorIndex>>,
|
||||
@@ -491,6 +493,7 @@ impl<T: Config> Module<T> {
|
||||
match crate::util::make_persisted_validation_data::<T>(
|
||||
para_id,
|
||||
relay_parent_number,
|
||||
parent_storage_root,
|
||||
) {
|
||||
Some(l) => l,
|
||||
None => {
|
||||
@@ -1129,6 +1132,7 @@ mod tests {
|
||||
= crate::util::make_persisted_validation_data::<Test>(
|
||||
para_id,
|
||||
relay_parent_number,
|
||||
Default::default(),
|
||||
)?;
|
||||
Some(persisted_validation_data.hash())
|
||||
}
|
||||
@@ -1634,6 +1638,7 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
Inclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed],
|
||||
vec![chain_b_assignment.clone()],
|
||||
&group_validators,
|
||||
@@ -1692,6 +1697,7 @@ mod tests {
|
||||
// out-of-order manifests as unscheduled.
|
||||
assert_eq!(
|
||||
Inclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed_b, backed_a],
|
||||
vec![chain_a_assignment.clone(), chain_b_assignment.clone()],
|
||||
&group_validators,
|
||||
@@ -1726,6 +1732,7 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
Inclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed],
|
||||
vec![chain_a_assignment.clone()],
|
||||
&group_validators,
|
||||
@@ -1762,6 +1769,7 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
Inclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed],
|
||||
vec![chain_a_assignment.clone()],
|
||||
&group_validators,
|
||||
@@ -1798,6 +1806,7 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
Inclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed],
|
||||
vec![
|
||||
chain_a_assignment.clone(),
|
||||
@@ -1841,6 +1850,7 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
Inclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed],
|
||||
vec![thread_a_assignment.clone()],
|
||||
&group_validators,
|
||||
@@ -1888,6 +1898,7 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
Inclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed],
|
||||
vec![chain_a_assignment.clone()],
|
||||
&group_validators,
|
||||
@@ -1929,6 +1940,7 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
Inclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed],
|
||||
vec![chain_a_assignment.clone()],
|
||||
&group_validators,
|
||||
@@ -1975,6 +1987,7 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
Inclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed],
|
||||
vec![chain_a_assignment.clone()],
|
||||
&group_validators,
|
||||
@@ -2010,6 +2023,7 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
Inclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed],
|
||||
vec![chain_a_assignment.clone()],
|
||||
&group_validators,
|
||||
@@ -2151,6 +2165,7 @@ mod tests {
|
||||
));
|
||||
|
||||
let occupied_cores = Inclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed_a, backed_b, backed_c],
|
||||
vec![
|
||||
chain_a_assignment.clone(),
|
||||
@@ -2283,6 +2298,7 @@ mod tests {
|
||||
));
|
||||
|
||||
let occupied_cores = Inclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed_a],
|
||||
vec![
|
||||
chain_a_assignment.clone(),
|
||||
|
||||
@@ -23,8 +23,9 @@
|
||||
|
||||
use sp_std::prelude::*;
|
||||
use primitives::v1::{
|
||||
BackedCandidate, SignedAvailabilityBitfields, INCLUSION_INHERENT_IDENTIFIER,
|
||||
BackedCandidate, SignedAvailabilityBitfields, INCLUSION_INHERENT_IDENTIFIER, Header,
|
||||
};
|
||||
use sp_runtime::traits::One;
|
||||
use frame_support::{
|
||||
decl_error, decl_module, decl_storage, ensure,
|
||||
dispatch::DispatchResult,
|
||||
@@ -57,6 +58,9 @@ decl_error! {
|
||||
pub enum Error for Module<T: Config> {
|
||||
/// Inclusion inherent called more than once per block.
|
||||
TooManyInclusionInherents,
|
||||
/// The hash of the submitted parent header doesn't correspond to the saved block hash of
|
||||
/// the parent.
|
||||
InvalidParentHeader,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,10 +85,19 @@ decl_module! {
|
||||
origin,
|
||||
signed_bitfields: SignedAvailabilityBitfields,
|
||||
backed_candidates: Vec<BackedCandidate<T::Hash>>,
|
||||
parent_header: Header,
|
||||
) -> DispatchResult {
|
||||
ensure_none(origin)?;
|
||||
ensure!(!<Included>::exists(), Error::<T>::TooManyInclusionInherents);
|
||||
|
||||
// Check that the submitted parent header indeed corresponds to the previous block hash.
|
||||
let now = <frame_system::Module<T>>::block_number();
|
||||
let parent_hash = <frame_system::Module<T>>::block_hash(now - One::one());
|
||||
ensure!(
|
||||
parent_header.hash().as_ref() == parent_hash.as_ref(),
|
||||
Error::<T>::InvalidParentHeader,
|
||||
);
|
||||
|
||||
// Process new availability bitfields, yielding any availability cores whose
|
||||
// work has now concluded.
|
||||
let freed_concluded = <inclusion::Module<T>>::process_bitfields(
|
||||
@@ -107,7 +120,9 @@ decl_module! {
|
||||
<scheduler::Module<T>>::schedule(freed);
|
||||
|
||||
// Process backed candidates according to scheduled cores.
|
||||
let parent_storage_root = parent_header.state_root;
|
||||
let occupied = <inclusion::Module<T>>::process_candidates(
|
||||
parent_storage_root,
|
||||
backed_candidates,
|
||||
<scheduler::Module<T>>::scheduled(),
|
||||
<scheduler::Module<T>>::group_validators,
|
||||
@@ -135,14 +150,27 @@ impl<T: Config> ProvideInherent for Module<T> {
|
||||
fn create_inherent(data: &InherentData) -> Option<Self::Call> {
|
||||
data.get_data(&Self::INHERENT_IDENTIFIER)
|
||||
.expect("inclusion inherent data failed to decode")
|
||||
.map(|(signed_bitfields, backed_candidates): (SignedAvailabilityBitfields, Vec<BackedCandidate<T::Hash>>)| {
|
||||
// Sanity check: session changes can invalidate an inherent, and we _really_ don't want that to happen.
|
||||
// See github.com/paritytech/polkadot/issues/1327
|
||||
if Self::inclusion(frame_system::RawOrigin::None.into(), signed_bitfields.clone(), backed_candidates.clone()).is_ok() {
|
||||
Call::inclusion(signed_bitfields, backed_candidates)
|
||||
} else {
|
||||
Call::inclusion(Vec::new().into(), Vec::new())
|
||||
.map(
|
||||
|(signed_bitfields, backed_candidates, parent_header): (
|
||||
SignedAvailabilityBitfields,
|
||||
Vec<BackedCandidate<T::Hash>>,
|
||||
Header,
|
||||
)| {
|
||||
// Sanity check: session changes can invalidate an inherent, and we _really_ don't want that to happen.
|
||||
// See github.com/paritytech/polkadot/issues/1327
|
||||
if Self::inclusion(
|
||||
frame_system::RawOrigin::None.into(),
|
||||
signed_bitfields.clone(),
|
||||
backed_candidates.clone(),
|
||||
parent_header.clone(),
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
Call::inclusion(signed_bitfields, backed_candidates, parent_header)
|
||||
} else {
|
||||
Call::inclusion(Vec::new().into(), Vec::new(), parent_header)
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ use primitives::v1::{
|
||||
Id as ParaId, OccupiedCoreAssumption, SessionIndex, ValidationCode,
|
||||
CommittedCandidateReceipt, ScheduledCore, OccupiedCore, CoreOccupied, CoreIndex,
|
||||
GroupIndex, CandidateEvent, PersistedValidationData, SessionInfo,
|
||||
InboundDownwardMessage, InboundHrmpMessage,
|
||||
InboundDownwardMessage, InboundHrmpMessage, Hash,
|
||||
};
|
||||
use frame_support::debug;
|
||||
use crate::{initializer, inclusion, scheduler, configuration, paras, session_info, dmp, hrmp};
|
||||
@@ -190,18 +190,24 @@ fn with_assumption<Config, T, F>(
|
||||
pub fn full_validation_data<T: initializer::Config>(
|
||||
para_id: ParaId,
|
||||
assumption: OccupiedCoreAssumption,
|
||||
)
|
||||
-> Option<ValidationData<T::BlockNumber>>
|
||||
{
|
||||
) -> Option<ValidationData<T::BlockNumber>> {
|
||||
use parity_scale_codec::Decode as _;
|
||||
let relay_parent_number = <frame_system::Module<T>>::block_number();
|
||||
with_assumption::<T, _, _>(
|
||||
para_id,
|
||||
assumption,
|
||||
|| Some(ValidationData {
|
||||
persisted: crate::util::make_persisted_validation_data::<T>(para_id, relay_parent_number)?,
|
||||
transient: crate::util::make_transient_validation_data::<T>(para_id, relay_parent_number)?,
|
||||
}),
|
||||
)
|
||||
let relay_storage_root = Hash::decode(&mut &sp_io::storage::root()[..])
|
||||
.expect("storage root must decode to the Hash type; qed");
|
||||
with_assumption::<T, _, _>(para_id, assumption, || {
|
||||
Some(ValidationData {
|
||||
persisted: crate::util::make_persisted_validation_data::<T>(
|
||||
para_id,
|
||||
relay_parent_number,
|
||||
relay_storage_root,
|
||||
)?,
|
||||
transient: crate::util::make_transient_validation_data::<T>(
|
||||
para_id,
|
||||
relay_parent_number,
|
||||
)?,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Implementation for the `persisted_validation_data` function of the runtime API.
|
||||
@@ -209,12 +215,17 @@ pub fn persisted_validation_data<T: initializer::Config>(
|
||||
para_id: ParaId,
|
||||
assumption: OccupiedCoreAssumption,
|
||||
) -> Option<PersistedValidationData<T::BlockNumber>> {
|
||||
use parity_scale_codec::Decode as _;
|
||||
let relay_parent_number = <frame_system::Module<T>>::block_number();
|
||||
with_assumption::<T, _, _>(
|
||||
para_id,
|
||||
assumption,
|
||||
|| crate::util::make_persisted_validation_data::<T>(para_id, relay_parent_number),
|
||||
)
|
||||
let relay_storage_root = Hash::decode(&mut &sp_io::storage::root()[..])
|
||||
.expect("storage root must decode to the Hash type; qed");
|
||||
with_assumption::<T, _, _>(para_id, assumption, || {
|
||||
crate::util::make_persisted_validation_data::<T>(
|
||||
para_id,
|
||||
relay_parent_number,
|
||||
relay_storage_root,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Implementation for the `check_validation_outputs` function of the runtime API.
|
||||
|
||||
@@ -18,22 +18,25 @@
|
||||
//! on all modules.
|
||||
|
||||
use sp_runtime::traits::Saturating;
|
||||
use primitives::v1::{Id as ParaId, PersistedValidationData, TransientValidationData};
|
||||
use primitives::v1::{Id as ParaId, PersistedValidationData, TransientValidationData, Hash};
|
||||
|
||||
use crate::{configuration, paras, dmp, hrmp};
|
||||
|
||||
/// Make the persisted validation data for a particular parachain and a specified relay-parent.
|
||||
/// Make the persisted validation data for a particular parachain, a specified relay-parent and it's
|
||||
/// storage root.
|
||||
///
|
||||
/// This ties together the storage of several modules.
|
||||
pub fn make_persisted_validation_data<T: paras::Config + hrmp::Config>(
|
||||
para_id: ParaId,
|
||||
relay_parent_number: T::BlockNumber,
|
||||
relay_storage_root: Hash,
|
||||
) -> Option<PersistedValidationData<T::BlockNumber>> {
|
||||
let config = <configuration::Module<T>>::config();
|
||||
|
||||
Some(PersistedValidationData {
|
||||
parent_head: <paras::Module<T>>::para_head(¶_id)?,
|
||||
block_number: relay_parent_number,
|
||||
relay_storage_root,
|
||||
hrmp_mqc_heads: <hrmp::Module<T>>::hrmp_mqc_heads(para_id),
|
||||
dmq_mqc_head: <dmp::Module<T>>::dmq_mqc_head(para_id),
|
||||
max_pov_size: config.max_pov_size,
|
||||
|
||||
Reference in New Issue
Block a user