mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 06:21:11 +00:00
Include a reference to the validation data in the candidate descriptor (#1442)
* rename GlobalValidationSchedule to GlobalValidationData * guide: update candidate descriptor to contain validation data hash * guide: add note in inclusion module about checking validation data hash * primitives: update CandidateDescriptor to contain new hash * fix payload computation * add helpers for computing validation data to runtime modules * guide: note routines * inclusion: check validation data hash and fix local_validation_data bug * add a case to candidate_checks and improve that test substantially * bump versions * address review comments * add a test for including code upgrade * bump kusama version * bump westend & polkadot versions
This commit is contained in:
committed by
GitHub
parent
1ed17cd467
commit
09f602f8de
@@ -58,7 +58,7 @@ use sp_core::Pair;
|
|||||||
use polkadot_primitives::v0::{
|
use polkadot_primitives::v0::{
|
||||||
BlockId, Hash, Block, DownwardMessage,
|
BlockId, Hash, Block, DownwardMessage,
|
||||||
BlockData, DutyRoster, HeadData, Id as ParaId,
|
BlockData, DutyRoster, HeadData, Id as ParaId,
|
||||||
PoVBlock, ValidatorId, CollatorPair, LocalValidationData, GlobalValidationSchedule,
|
PoVBlock, ValidatorId, CollatorPair, LocalValidationData, GlobalValidationData,
|
||||||
Collation, CollationInfo, collator_signature_payload,
|
Collation, CollationInfo, collator_signature_payload,
|
||||||
};
|
};
|
||||||
use polkadot_cli::{
|
use polkadot_cli::{
|
||||||
@@ -148,7 +148,7 @@ pub trait ParachainContext: Clone {
|
|||||||
fn produce_candidate(
|
fn produce_candidate(
|
||||||
&mut self,
|
&mut self,
|
||||||
relay_parent: Hash,
|
relay_parent: Hash,
|
||||||
global_validation: GlobalValidationSchedule,
|
global_validation: GlobalValidationData,
|
||||||
local_validation: LocalValidationData,
|
local_validation: LocalValidationData,
|
||||||
downward_messages: Vec<DownwardMessage>,
|
downward_messages: Vec<DownwardMessage>,
|
||||||
) -> Self::ProduceCandidate;
|
) -> Self::ProduceCandidate;
|
||||||
@@ -158,7 +158,7 @@ pub trait ParachainContext: Clone {
|
|||||||
pub async fn collate<P>(
|
pub async fn collate<P>(
|
||||||
relay_parent: Hash,
|
relay_parent: Hash,
|
||||||
local_id: ParaId,
|
local_id: ParaId,
|
||||||
global_validation: GlobalValidationSchedule,
|
global_validation: GlobalValidationData,
|
||||||
local_validation_data: LocalValidationData,
|
local_validation_data: LocalValidationData,
|
||||||
downward_messages: Vec<DownwardMessage>,
|
downward_messages: Vec<DownwardMessage>,
|
||||||
mut para_context: P,
|
mut para_context: P,
|
||||||
@@ -315,7 +315,7 @@ fn build_collator_service<P, C, R, Extrinsic>(
|
|||||||
|
|
||||||
let work = future::lazy(move |_| {
|
let work = future::lazy(move |_| {
|
||||||
let api = client.runtime_api();
|
let api = client.runtime_api();
|
||||||
let global_validation = try_fr!(api.global_validation_schedule(&id));
|
let global_validation = try_fr!(api.global_validation_data(&id));
|
||||||
let local_validation = match try_fr!(api.local_validation_data(&id, para_id)) {
|
let local_validation = match try_fr!(api.local_validation_data(&id, para_id)) {
|
||||||
Some(local_validation) => local_validation,
|
Some(local_validation) => local_validation,
|
||||||
None => return future::Either::Left(future::ok(())),
|
None => return future::Either::Left(future::ok(())),
|
||||||
@@ -477,7 +477,7 @@ mod tests {
|
|||||||
fn produce_candidate(
|
fn produce_candidate(
|
||||||
&mut self,
|
&mut self,
|
||||||
_relay_parent: Hash,
|
_relay_parent: Hash,
|
||||||
_global: GlobalValidationSchedule,
|
_global: GlobalValidationData,
|
||||||
_local_validation: LocalValidationData,
|
_local_validation: LocalValidationData,
|
||||||
_: Vec<DownwardMessage>,
|
_: Vec<DownwardMessage>,
|
||||||
) -> Self::ProduceCandidate {
|
) -> Self::ProduceCandidate {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ use polkadot_primitives::v0::{
|
|||||||
Block,
|
Block,
|
||||||
Id as ParaId, Chain, DutyRoster, ParachainHost, ValidatorId,
|
Id as ParaId, Chain, DutyRoster, ParachainHost, ValidatorId,
|
||||||
Retriable, CollatorId, AbridgedCandidateReceipt,
|
Retriable, CollatorId, AbridgedCandidateReceipt,
|
||||||
GlobalValidationSchedule, LocalValidationData, ErasureChunk, SigningContext,
|
GlobalValidationData, LocalValidationData, ErasureChunk, SigningContext,
|
||||||
PoVBlock, BlockData, ValidationCode,
|
PoVBlock, BlockData, ValidationCode,
|
||||||
};
|
};
|
||||||
use polkadot_validation::{SharedTable, TableRouter};
|
use polkadot_validation::{SharedTable, TableRouter};
|
||||||
@@ -180,7 +180,7 @@ sp_api::mock_impl_runtime_apis! {
|
|||||||
Some(ValidationCode(Vec::new()))
|
Some(ValidationCode(Vec::new()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn global_validation_schedule() -> GlobalValidationSchedule {
|
fn global_validation_data() -> GlobalValidationData {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -606,7 +606,7 @@ impl CandidateBackingJob {
|
|||||||
with_commitments: impl FnOnce(CandidateCommitments) -> Result<T, E>,
|
with_commitments: impl FnOnce(CandidateCommitments) -> Result<T, E>,
|
||||||
) -> Result<Result<T, E>, Error> {
|
) -> Result<Result<T, E>, Error> {
|
||||||
let omitted_validation = OmittedValidationData {
|
let omitted_validation = OmittedValidationData {
|
||||||
global_validation: outputs.global_validation_schedule,
|
global_validation: outputs.global_validation_data,
|
||||||
local_validation: outputs.local_validation_data,
|
local_validation: outputs.local_validation_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -773,7 +773,7 @@ mod tests {
|
|||||||
use futures::{executor, future, Future};
|
use futures::{executor, future, Future};
|
||||||
use polkadot_primitives::v1::{
|
use polkadot_primitives::v1::{
|
||||||
AssignmentKind, BlockData, CandidateCommitments, CollatorId, CoreAssignment, CoreIndex,
|
AssignmentKind, BlockData, CandidateCommitments, CollatorId, CoreAssignment, CoreIndex,
|
||||||
LocalValidationData, GlobalValidationSchedule, GroupIndex, HeadData,
|
LocalValidationData, GlobalValidationData, GroupIndex, HeadData,
|
||||||
ValidatorPair, ValidityAttestation,
|
ValidatorPair, ValidityAttestation,
|
||||||
};
|
};
|
||||||
use polkadot_subsystem::{
|
use polkadot_subsystem::{
|
||||||
@@ -792,7 +792,7 @@ mod tests {
|
|||||||
keystore: KeyStorePtr,
|
keystore: KeyStorePtr,
|
||||||
validators: Vec<Sr25519Keyring>,
|
validators: Vec<Sr25519Keyring>,
|
||||||
validator_public: Vec<ValidatorId>,
|
validator_public: Vec<ValidatorId>,
|
||||||
global_validation_schedule: GlobalValidationSchedule,
|
global_validation_data: GlobalValidationData,
|
||||||
local_validation_data: LocalValidationData,
|
local_validation_data: LocalValidationData,
|
||||||
roster: SchedulerRoster,
|
roster: SchedulerRoster,
|
||||||
head_data: HashMap<ParaId, HeadData>,
|
head_data: HashMap<ParaId, HeadData>,
|
||||||
@@ -877,7 +877,7 @@ mod tests {
|
|||||||
validation_code_hash: Default::default(),
|
validation_code_hash: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let global_validation_schedule = GlobalValidationSchedule {
|
let global_validation_data = GlobalValidationData {
|
||||||
max_code_size: 1000,
|
max_code_size: 1000,
|
||||||
max_head_data_size: 1000,
|
max_head_data_size: 1000,
|
||||||
block_number: Default::default(),
|
block_number: Default::default(),
|
||||||
@@ -891,7 +891,7 @@ mod tests {
|
|||||||
roster,
|
roster,
|
||||||
head_data,
|
head_data,
|
||||||
local_validation_data,
|
local_validation_data,
|
||||||
global_validation_schedule,
|
global_validation_data,
|
||||||
signing_context,
|
signing_context,
|
||||||
relay_parent,
|
relay_parent,
|
||||||
}
|
}
|
||||||
@@ -921,7 +921,7 @@ mod tests {
|
|||||||
|
|
||||||
fn make_erasure_root(test: &TestState, pov: PoV) -> Hash {
|
fn make_erasure_root(test: &TestState, pov: PoV) -> Hash {
|
||||||
let omitted_validation = OmittedValidationData {
|
let omitted_validation = OmittedValidationData {
|
||||||
global_validation: test.global_validation_schedule.clone(),
|
global_validation: test.global_validation_data.clone(),
|
||||||
local_validation: test.local_validation_data.clone(),
|
local_validation: test.local_validation_data.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1048,7 +1048,7 @@ mod tests {
|
|||||||
) if pov == pov && &c == candidate.descriptor() => {
|
) if pov == pov && &c == candidate.descriptor() => {
|
||||||
tx.send(Ok(
|
tx.send(Ok(
|
||||||
ValidationResult::Valid(ValidationOutputs {
|
ValidationResult::Valid(ValidationOutputs {
|
||||||
global_validation_schedule: test_state.global_validation_schedule,
|
global_validation_data: test_state.global_validation_data,
|
||||||
local_validation_data: test_state.local_validation_data,
|
local_validation_data: test_state.local_validation_data,
|
||||||
head_data: expected_head_data.clone(),
|
head_data: expected_head_data.clone(),
|
||||||
upward_messages: Vec::new(),
|
upward_messages: Vec::new(),
|
||||||
@@ -1160,7 +1160,7 @@ mod tests {
|
|||||||
) if pov == pov && &c == candidate_a.descriptor() => {
|
) if pov == pov && &c == candidate_a.descriptor() => {
|
||||||
tx.send(Ok(
|
tx.send(Ok(
|
||||||
ValidationResult::Valid(ValidationOutputs {
|
ValidationResult::Valid(ValidationOutputs {
|
||||||
global_validation_schedule: test_state.global_validation_schedule,
|
global_validation_data: test_state.global_validation_data,
|
||||||
local_validation_data: test_state.local_validation_data,
|
local_validation_data: test_state.local_validation_data,
|
||||||
head_data: expected_head_data.clone(),
|
head_data: expected_head_data.clone(),
|
||||||
upward_messages: Vec::new(),
|
upward_messages: Vec::new(),
|
||||||
@@ -1281,7 +1281,7 @@ mod tests {
|
|||||||
) if pov == pov && &c == candidate_a.descriptor() => {
|
) if pov == pov && &c == candidate_a.descriptor() => {
|
||||||
tx.send(Ok(
|
tx.send(Ok(
|
||||||
ValidationResult::Valid(ValidationOutputs {
|
ValidationResult::Valid(ValidationOutputs {
|
||||||
global_validation_schedule: test_state.global_validation_schedule,
|
global_validation_data: test_state.global_validation_data,
|
||||||
local_validation_data: test_state.local_validation_data,
|
local_validation_data: test_state.local_validation_data,
|
||||||
head_data: expected_head_data.clone(),
|
head_data: expected_head_data.clone(),
|
||||||
upward_messages: Vec::new(),
|
upward_messages: Vec::new(),
|
||||||
@@ -1438,7 +1438,7 @@ mod tests {
|
|||||||
) if pov == pov && &c == candidate_b.descriptor() => {
|
) if pov == pov && &c == candidate_b.descriptor() => {
|
||||||
tx.send(Ok(
|
tx.send(Ok(
|
||||||
ValidationResult::Valid(ValidationOutputs {
|
ValidationResult::Valid(ValidationOutputs {
|
||||||
global_validation_schedule: test_state.global_validation_schedule,
|
global_validation_data: test_state.global_validation_data,
|
||||||
local_validation_data: test_state.local_validation_data,
|
local_validation_data: test_state.local_validation_data,
|
||||||
head_data: expected_head_data.clone(),
|
head_data: expected_head_data.clone(),
|
||||||
upward_messages: Vec::new(),
|
upward_messages: Vec::new(),
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ use parity_scale_codec::{Decode, Encode};
|
|||||||
use polkadot_primitives::v1::{
|
use polkadot_primitives::v1::{
|
||||||
Hash, CommittedCandidateReceipt, CandidateReceipt, CompactStatement,
|
Hash, CommittedCandidateReceipt, CandidateReceipt, CompactStatement,
|
||||||
EncodeAs, Signed, SigningContext, ValidatorIndex, ValidatorId,
|
EncodeAs, Signed, SigningContext, ValidatorIndex, ValidatorId,
|
||||||
UpwardMessage, Balance, ValidationCode, GlobalValidationSchedule, LocalValidationData,
|
UpwardMessage, Balance, ValidationCode, GlobalValidationData, LocalValidationData,
|
||||||
HeadData,
|
HeadData,
|
||||||
};
|
};
|
||||||
use polkadot_statement_table::{
|
use polkadot_statement_table::{
|
||||||
@@ -118,7 +118,7 @@ pub struct ValidationOutputs {
|
|||||||
/// The head-data produced by validation.
|
/// The head-data produced by validation.
|
||||||
pub head_data: HeadData,
|
pub head_data: HeadData,
|
||||||
/// The global validation schedule.
|
/// The global validation schedule.
|
||||||
pub global_validation_schedule: GlobalValidationSchedule,
|
pub global_validation_data: GlobalValidationData,
|
||||||
/// The local validation data.
|
/// The local validation data.
|
||||||
pub local_validation_data: LocalValidationData,
|
pub local_validation_data: LocalValidationData,
|
||||||
/// Upward messages to the relay chain.
|
/// Upward messages to the relay chain.
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ use sp_core::Pair;
|
|||||||
use codec::{Encode, Decode};
|
use codec::{Encode, Decode};
|
||||||
use primitives::v0::{
|
use primitives::v0::{
|
||||||
Hash, DownwardMessage,
|
Hash, DownwardMessage,
|
||||||
HeadData, BlockData, Id as ParaId, LocalValidationData, GlobalValidationSchedule,
|
HeadData, BlockData, Id as ParaId, LocalValidationData, GlobalValidationData,
|
||||||
};
|
};
|
||||||
use collator::{ParachainContext, Network, BuildParachainContext, Cli, SubstrateCli};
|
use collator::{ParachainContext, Network, BuildParachainContext, Cli, SubstrateCli};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
@@ -58,7 +58,7 @@ impl ParachainContext for AdderContext {
|
|||||||
fn produce_candidate(
|
fn produce_candidate(
|
||||||
&mut self,
|
&mut self,
|
||||||
_relay_parent: Hash,
|
_relay_parent: Hash,
|
||||||
_global_validation: GlobalValidationSchedule,
|
_global_validation: GlobalValidationData,
|
||||||
local_validation: LocalValidationData,
|
local_validation: LocalValidationData,
|
||||||
_: Vec<DownwardMessage>,
|
_: Vec<DownwardMessage>,
|
||||||
) -> Self::ProduceCandidate
|
) -> Self::ProduceCandidate
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ pub struct DutyRoster {
|
|||||||
/// These are global parameters that apply to all parachain candidates in a block.
|
/// These are global parameters that apply to all parachain candidates in a block.
|
||||||
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
|
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
|
||||||
#[cfg_attr(feature = "std", derive(Debug, Default))]
|
#[cfg_attr(feature = "std", derive(Debug, Default))]
|
||||||
pub struct GlobalValidationSchedule<N = BlockNumber> {
|
pub struct GlobalValidationData<N = BlockNumber> {
|
||||||
/// The maximum code size permitted, in bytes.
|
/// The maximum code size permitted, in bytes.
|
||||||
pub max_code_size: u32,
|
pub max_code_size: u32,
|
||||||
/// The maximum head-data size permitted, in bytes.
|
/// The maximum head-data size permitted, in bytes.
|
||||||
@@ -278,7 +278,7 @@ pub struct CandidateReceipt<H = Hash, N = BlockNumber> {
|
|||||||
/// The hash of the PoV-block.
|
/// The hash of the PoV-block.
|
||||||
pub pov_block_hash: H,
|
pub pov_block_hash: H,
|
||||||
/// The global validation schedule.
|
/// The global validation schedule.
|
||||||
pub global_validation: GlobalValidationSchedule<N>,
|
pub global_validation: GlobalValidationData<N>,
|
||||||
/// The local validation data.
|
/// The local validation data.
|
||||||
pub local_validation: LocalValidationData<N>,
|
pub local_validation: LocalValidationData<N>,
|
||||||
/// Commitments made as a result of validation.
|
/// Commitments made as a result of validation.
|
||||||
@@ -352,7 +352,7 @@ impl Ord for CandidateReceipt {
|
|||||||
#[cfg_attr(feature = "std", derive(Debug, Default))]
|
#[cfg_attr(feature = "std", derive(Debug, Default))]
|
||||||
pub struct OmittedValidationData<N = BlockNumber> {
|
pub struct OmittedValidationData<N = BlockNumber> {
|
||||||
/// The global validation schedule.
|
/// The global validation schedule.
|
||||||
pub global_validation: GlobalValidationSchedule<N>,
|
pub global_validation: GlobalValidationData<N>,
|
||||||
/// The local validation data.
|
/// The local validation data.
|
||||||
pub local_validation: LocalValidationData<N>,
|
pub local_validation: LocalValidationData<N>,
|
||||||
}
|
}
|
||||||
@@ -762,7 +762,7 @@ sp_api::decl_runtime_apis! {
|
|||||||
fn active_parachains() -> Vec<(Id, Option<(CollatorId, Retriable)>)>;
|
fn active_parachains() -> Vec<(Id, Option<(CollatorId, Retriable)>)>;
|
||||||
/// Get the global validation schedule that all parachains should
|
/// Get the global validation schedule that all parachains should
|
||||||
/// be validated under.
|
/// be validated under.
|
||||||
fn global_validation_schedule() -> GlobalValidationSchedule;
|
fn global_validation_data() -> GlobalValidationData;
|
||||||
/// Get the local validation data for a particular parachain.
|
/// Get the local validation data for a particular parachain.
|
||||||
fn local_validation_data(id: Id) -> Option<LocalValidationData>;
|
fn local_validation_data(id: Id) -> Option<LocalValidationData>;
|
||||||
/// Get the given parachain's head code blob.
|
/// Get the given parachain's head code blob.
|
||||||
|
|||||||
@@ -60,14 +60,16 @@ pub const INCLUSION_INHERENT_IDENTIFIER: InherentIdentifier = *b"inclusn0";
|
|||||||
pub fn collator_signature_payload<H: AsRef<[u8]>>(
|
pub fn collator_signature_payload<H: AsRef<[u8]>>(
|
||||||
relay_parent: &H,
|
relay_parent: &H,
|
||||||
para_id: &Id,
|
para_id: &Id,
|
||||||
|
validation_data_hash: &Hash,
|
||||||
pov_hash: &Hash,
|
pov_hash: &Hash,
|
||||||
) -> [u8; 68] {
|
) -> [u8; 100] {
|
||||||
// 32-byte hash length is protected in a test below.
|
// 32-byte hash length is protected in a test below.
|
||||||
let mut payload = [0u8; 68];
|
let mut payload = [0u8; 100];
|
||||||
|
|
||||||
payload[0..32].copy_from_slice(relay_parent.as_ref());
|
payload[0..32].copy_from_slice(relay_parent.as_ref());
|
||||||
u32::from(*para_id).using_encoded(|s| payload[32..32 + s.len()].copy_from_slice(s));
|
u32::from(*para_id).using_encoded(|s| payload[32..32 + s.len()].copy_from_slice(s));
|
||||||
payload[36..68].copy_from_slice(pov_hash.as_ref());
|
payload[36..68].copy_from_slice(validation_data_hash.as_ref());
|
||||||
|
payload[68..100].copy_from_slice(pov_hash.as_ref());
|
||||||
|
|
||||||
payload
|
payload
|
||||||
}
|
}
|
||||||
@@ -75,11 +77,18 @@ pub fn collator_signature_payload<H: AsRef<[u8]>>(
|
|||||||
fn check_collator_signature<H: AsRef<[u8]>>(
|
fn check_collator_signature<H: AsRef<[u8]>>(
|
||||||
relay_parent: &H,
|
relay_parent: &H,
|
||||||
para_id: &Id,
|
para_id: &Id,
|
||||||
|
validation_data_hash: &Hash,
|
||||||
pov_hash: &Hash,
|
pov_hash: &Hash,
|
||||||
collator: &CollatorId,
|
collator: &CollatorId,
|
||||||
signature: &CollatorSignature,
|
signature: &CollatorSignature,
|
||||||
) -> Result<(),()> {
|
) -> Result<(),()> {
|
||||||
let payload = collator_signature_payload(relay_parent, para_id, pov_hash);
|
let payload = collator_signature_payload(
|
||||||
|
relay_parent,
|
||||||
|
para_id,
|
||||||
|
validation_data_hash,
|
||||||
|
pov_hash,
|
||||||
|
);
|
||||||
|
|
||||||
if signature.verify(&payload[..], collator) {
|
if signature.verify(&payload[..], collator) {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
@@ -87,6 +96,14 @@ fn check_collator_signature<H: AsRef<[u8]>>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compute the `validation_data_hash` from global & local validation data.
|
||||||
|
pub fn validation_data_hash<N: Encode>(
|
||||||
|
global: &GlobalValidationData<N>,
|
||||||
|
local: &LocalValidationData<N>,
|
||||||
|
) -> Hash {
|
||||||
|
BlakeTwo256::hash_of(&(global, local))
|
||||||
|
}
|
||||||
|
|
||||||
/// A unique descriptor of the candidate receipt.
|
/// A unique descriptor of the candidate receipt.
|
||||||
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
|
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
|
||||||
#[cfg_attr(feature = "std", derive(Debug, Default))]
|
#[cfg_attr(feature = "std", derive(Debug, Default))]
|
||||||
@@ -97,11 +114,16 @@ pub struct CandidateDescriptor<H = Hash> {
|
|||||||
pub relay_parent: H,
|
pub relay_parent: H,
|
||||||
/// The collator's sr25519 public key.
|
/// The collator's sr25519 public key.
|
||||||
pub collator: CollatorId,
|
pub collator: CollatorId,
|
||||||
/// Signature on blake2-256 of components of this receipt:
|
/// The blake2-256 hash of the validation data. This is extra data derived from
|
||||||
/// The parachain index, the relay parent, and the pov_hash.
|
/// relay-chain state which may vary based on bitfields included before the candidate.
|
||||||
pub signature: CollatorSignature,
|
/// Thus it cannot be derived entirely from the relay-parent.
|
||||||
|
pub validation_data_hash: Hash,
|
||||||
/// The blake2-256 hash of the pov.
|
/// The blake2-256 hash of the pov.
|
||||||
pub pov_hash: Hash,
|
pub pov_hash: Hash,
|
||||||
|
/// Signature on blake2-256 of components of this receipt:
|
||||||
|
/// The parachain index, the relay parent, the validation data hash, and the pov_hash.
|
||||||
|
pub signature: CollatorSignature,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H: AsRef<[u8]>> CandidateDescriptor<H> {
|
impl<H: AsRef<[u8]>> CandidateDescriptor<H> {
|
||||||
@@ -110,6 +132,7 @@ impl<H: AsRef<[u8]>> CandidateDescriptor<H> {
|
|||||||
check_collator_signature(
|
check_collator_signature(
|
||||||
&self.relay_parent,
|
&self.relay_parent,
|
||||||
&self.para_id,
|
&self.para_id,
|
||||||
|
&self.validation_data_hash,
|
||||||
&self.pov_hash,
|
&self.pov_hash,
|
||||||
&self.collator,
|
&self.collator,
|
||||||
&self.signature,
|
&self.signature,
|
||||||
@@ -146,7 +169,7 @@ pub struct FullCandidateReceipt<H = Hash, N = BlockNumber> {
|
|||||||
/// The inner candidate receipt.
|
/// The inner candidate receipt.
|
||||||
pub inner: CandidateReceipt<H>,
|
pub inner: CandidateReceipt<H>,
|
||||||
/// The global validation schedule.
|
/// The global validation schedule.
|
||||||
pub global_validation: GlobalValidationSchedule<N>,
|
pub global_validation: GlobalValidationData<N>,
|
||||||
/// The local validation data.
|
/// The local validation data.
|
||||||
pub local_validation: LocalValidationData<N>,
|
pub local_validation: LocalValidationData<N>,
|
||||||
}
|
}
|
||||||
@@ -232,7 +255,7 @@ pub struct LocalValidationData<N = BlockNumber> {
|
|||||||
/// These are global parameters that apply to all candidates in a block.
|
/// These are global parameters that apply to all candidates in a block.
|
||||||
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
|
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
|
||||||
#[cfg_attr(feature = "std", derive(Debug, Default))]
|
#[cfg_attr(feature = "std", derive(Debug, Default))]
|
||||||
pub struct GlobalValidationSchedule<N = BlockNumber> {
|
pub struct GlobalValidationData<N = BlockNumber> {
|
||||||
/// The maximum code size permitted, in bytes.
|
/// The maximum code size permitted, in bytes.
|
||||||
pub max_code_size: u32,
|
pub max_code_size: u32,
|
||||||
/// The maximum head-data size permitted, in bytes.
|
/// The maximum head-data size permitted, in bytes.
|
||||||
@@ -465,7 +488,7 @@ impl CoreAssignment {
|
|||||||
#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
|
#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
|
||||||
pub struct OmittedValidationData {
|
pub struct OmittedValidationData {
|
||||||
/// The global validation schedule.
|
/// The global validation schedule.
|
||||||
pub global_validation: GlobalValidationSchedule,
|
pub global_validation: GlobalValidationData,
|
||||||
/// The local validation data.
|
/// The local validation data.
|
||||||
pub local_validation: LocalValidationData,
|
pub local_validation: LocalValidationData,
|
||||||
}
|
}
|
||||||
@@ -636,9 +659,9 @@ sp_api::decl_runtime_apis! {
|
|||||||
/// cores can have paras assigned to them.
|
/// cores can have paras assigned to them.
|
||||||
fn availability_cores() -> Vec<CoreState<N>>;
|
fn availability_cores() -> Vec<CoreState<N>>;
|
||||||
|
|
||||||
/// Yields the GlobalValidationSchedule. This applies to all para candidates with the
|
/// Yields the GlobalValidationData. This applies to all para candidates with the
|
||||||
/// relay-parent equal to the block in which context this is invoked in.
|
/// relay-parent equal to the block in which context this is invoked in.
|
||||||
fn global_validation_schedule() -> GlobalValidationSchedule<N>;
|
fn global_validation_data() -> GlobalValidationData<N>;
|
||||||
|
|
||||||
/// Yields the LocalValidationData for the given ParaId along with an assumption that
|
/// Yields the LocalValidationData for the given ParaId along with an assumption that
|
||||||
/// should be used if the para currently occupies a core.
|
/// should be used if the para currently occupies a core.
|
||||||
@@ -696,4 +719,18 @@ mod tests {
|
|||||||
assert_eq!(info.next_rotation_at(), 0);
|
assert_eq!(info.next_rotation_at(), 0);
|
||||||
assert_eq!(info.last_rotation_at(), 0);
|
assert_eq!(info.last_rotation_at(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn collator_signature_payload_is_valid() {
|
||||||
|
// if this fails, collator signature verification code has to be updated.
|
||||||
|
let h = Hash::default();
|
||||||
|
assert_eq!(h.as_ref().len(), 32);
|
||||||
|
|
||||||
|
let _payload = collator_signature_payload(
|
||||||
|
&Hash::from([1; 32]),
|
||||||
|
&5u32.into(),
|
||||||
|
&Hash::from([2; 32]),
|
||||||
|
&Hash::from([3; 32]),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,10 +137,10 @@ enum CoreState {
|
|||||||
|
|
||||||
## Global Validation Schedule
|
## Global Validation Schedule
|
||||||
|
|
||||||
Yields the [`GlobalValidationSchedule`](../types/candidate.md#globalvalidationschedule) at the state of a given block. This applies to all para candidates with the relay-parent equal to that block.
|
Yields the [`GlobalValidationData`](../types/candidate.md#globalvalidationschedule) at the state of a given block. This applies to all para candidates with the relay-parent equal to that block.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn global_validation_schedule(at: Block) -> GlobalValidationSchedule;
|
fn global_validation_data(at: Block) -> GlobalValidationData;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Local Validation Data
|
## Local Validation Data
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ fn update_configuration(f: impl FnOnce(&mut HostConfiguration)) {
|
|||||||
*pending = Some(x);
|
*pending = Some(x);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the GlobalValidationData, assuming the context is the parent block.
|
||||||
|
fn global_validation_data() -> GlobalValidationData;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Entry-points
|
## Entry-points
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ All failed checks should lead to an unrecoverable error making the block invalid
|
|||||||
1. check that each candidate corresponds to a scheduled core and that they are ordered in the same order the cores appear in assignments in `scheduled`.
|
1. check that each candidate corresponds to a scheduled core and that they are ordered in the same order the cores appear in assignments in `scheduled`.
|
||||||
1. check that `scheduled` is sorted ascending by `CoreIndex`, without duplicates.
|
1. check that `scheduled` is sorted ascending by `CoreIndex`, without duplicates.
|
||||||
1. check that there is no candidate pending availability for any scheduled `ParaId`.
|
1. check that there is no candidate pending availability for any scheduled `ParaId`.
|
||||||
|
1. check that each candidate's `validation_data_hash` corresponds to a `(LocalValidationData, GlobalValidationData)` computed from the current state.
|
||||||
1. If the core assignment includes a specific collator, ensure the backed candidate is issued by that collator.
|
1. If the core assignment includes a specific collator, ensure the backed candidate is issued by that collator.
|
||||||
1. Ensure that any code upgrade scheduled by the candidate does not happen within `config.validation_upgrade_frequency` of `Paras::last_code_upgrade(para_id, true)`, if any, comparing against the value of `Paras::FutureCodeUpgrades` for the given para ID.
|
1. Ensure that any code upgrade scheduled by the candidate does not happen within `config.validation_upgrade_frequency` of `Paras::last_code_upgrade(para_id, true)`, if any, comparing against the value of `Paras::FutureCodeUpgrades` for the given para ID.
|
||||||
1. Check the collator's signature on the candidate data.
|
1. Check the collator's signature on the candidate data.
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ OutgoingParas: Vec<ParaId>;
|
|||||||
* `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.
|
||||||
|
|
||||||
* `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.
|
||||||
|
* `local_validation_data(id: ParaId) -> Option<LocalValidationData>`: Get the LocalValidationData of the given para, assuming the context is the parent block. Returns `None` if the para is not known.
|
||||||
|
|
||||||
## Finalization
|
## Finalization
|
||||||
|
|
||||||
|
|||||||
@@ -26,12 +26,12 @@ struct PoV(Vec<u8>);
|
|||||||
|
|
||||||
Validation data that is often omitted from types describing candidates as it can be derived from the relay-parent of the candidate. However, with the expectation of state pruning, these are best kept available elsewhere as well.
|
Validation data that is often omitted from types describing candidates as it can be derived from the relay-parent of the candidate. However, with the expectation of state pruning, these are best kept available elsewhere as well.
|
||||||
|
|
||||||
This contains the [`GlobalValidationSchedule`](candidate.md#globalvalidationschedule) and [`LocalValidationData`](candidate.md#localvalidationdata)
|
This contains the [`GlobalValidationData`](candidate.md#globalvalidationschedule) and [`LocalValidationData`](candidate.md#localvalidationdata)
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
struct OmittedValidationData {
|
struct OmittedValidationData {
|
||||||
/// The global validation schedule.
|
/// The global validation schedule.
|
||||||
global_validation: GlobalValidationSchedule,
|
global_validation: GlobalValidationData,
|
||||||
/// The local validation data.
|
/// The local validation data.
|
||||||
local_validation: LocalValidationData,
|
local_validation: LocalValidationData,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ struct CandidateReceipt {
|
|||||||
|
|
||||||
## Full Candidate Receipt
|
## Full Candidate Receipt
|
||||||
|
|
||||||
This is the full receipt type. The `GlobalValidationSchedule` and the `LocalValidationData` are technically redundant with the `inner.relay_parent`, which uniquely describes the a block in the blockchain from whose state these values are derived. The [`CandidateReceipt`](#candidate-receipt) variant is often used instead for this reason.
|
This is the full receipt type. The `GlobalValidationData` and the `LocalValidationData` are technically redundant with the `inner.relay_parent`, which uniquely describes the a block in the blockchain from whose state these values are derived. The [`CandidateReceipt`](#candidate-receipt) variant is often used instead for this reason.
|
||||||
|
|
||||||
However, the Full Candidate Receipt type is useful as a means of avoiding the implicit dependency on availability of old blockchain state. In situations such as availability and approval, having the full description of the candidate within a self-contained struct is convenient.
|
However, the Full Candidate Receipt type is useful as a means of avoiding the implicit dependency on availability of old blockchain state. In situations such as availability and approval, having the full description of the candidate within a self-contained struct is convenient.
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ However, the Full Candidate Receipt type is useful as a means of avoiding the im
|
|||||||
struct FullCandidateReceipt {
|
struct FullCandidateReceipt {
|
||||||
inner: CandidateReceipt,
|
inner: CandidateReceipt,
|
||||||
/// The global validation schedule.
|
/// The global validation schedule.
|
||||||
global_validation: GlobalValidationSchedule,
|
global_validation: GlobalValidationData,
|
||||||
/// The local validation data.
|
/// The local validation data.
|
||||||
local_validation: LocalValidationData,
|
local_validation: LocalValidationData,
|
||||||
}
|
}
|
||||||
@@ -77,16 +77,19 @@ struct CandidateDescriptor {
|
|||||||
relay_parent: Hash,
|
relay_parent: Hash,
|
||||||
/// The collator's sr25519 public key.
|
/// The collator's sr25519 public key.
|
||||||
collator: CollatorId,
|
collator: CollatorId,
|
||||||
/// Signature on blake2-256 of components of this receipt:
|
/// The blake2-256 hash of the validation data. These are extra parameters
|
||||||
/// The parachain index, the relay parent, and the pov_hash.
|
/// derived from relay-chain state that influence the validity of the block.
|
||||||
signature: CollatorSignature,
|
validation_data_hash: Hash,
|
||||||
/// The blake2-256 hash of the pov-block.
|
/// The blake2-256 hash of the pov-block.
|
||||||
pov_hash: Hash,
|
pov_hash: Hash,
|
||||||
|
/// Signature on blake2-256 of components of this receipt:
|
||||||
|
/// The parachain index, the relay parent, the validation data hash, and the pov_hash.
|
||||||
|
signature: CollatorSignature,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## GlobalValidationSchedule
|
## GlobalValidationData
|
||||||
|
|
||||||
The global validation schedule comprises of information describing the global environment for para execution, as derived from a particular relay-parent. These are parameters that will apply to all parablocks executed in the context of this relay-parent.
|
The global validation schedule comprises of information describing the global environment for para execution, as derived from a particular relay-parent. These are parameters that will apply to all parablocks executed in the context of this relay-parent.
|
||||||
|
|
||||||
@@ -95,7 +98,7 @@ The global validation schedule comprises of information describing the global en
|
|||||||
/// to fully validate the candidate.
|
/// to fully validate the candidate.
|
||||||
///
|
///
|
||||||
/// These are global parameters that apply to all candidates in a block.
|
/// These are global parameters that apply to all candidates in a block.
|
||||||
struct GlobalValidationSchedule {
|
struct GlobalValidationData {
|
||||||
/// The maximum code size permitted, in bytes.
|
/// The maximum code size permitted, in bytes.
|
||||||
max_code_size: u32,
|
max_code_size: u32,
|
||||||
/// The maximum head-data size permitted, in bytes.
|
/// The maximum head-data size permitted, in bytes.
|
||||||
@@ -197,7 +200,7 @@ struct ValidationOutputs {
|
|||||||
/// The head-data produced by validation.
|
/// The head-data produced by validation.
|
||||||
head_data: HeadData,
|
head_data: HeadData,
|
||||||
/// The global validation schedule.
|
/// The global validation schedule.
|
||||||
global_validation_schedule: GlobalValidationSchedule,
|
global_validation_data: GlobalValidationData,
|
||||||
/// The local validation data.
|
/// The local validation data.
|
||||||
local_validation_data: LocalValidationData,
|
local_validation_data: LocalValidationData,
|
||||||
/// Upwards messages to the relay chain.
|
/// Upwards messages to the relay chain.
|
||||||
|
|||||||
@@ -255,7 +255,7 @@ enum RuntimeApiRequest {
|
|||||||
/// Get the validation code for a specific para, using the given occupied core assumption.
|
/// Get the validation code for a specific para, using the given occupied core assumption.
|
||||||
ValidationCode(ParaId, OccupiedCoreAssumption, ResponseChannel<Option<ValidationCode>>),
|
ValidationCode(ParaId, OccupiedCoreAssumption, ResponseChannel<Option<ValidationCode>>),
|
||||||
/// Get the global validation schedule at the state of a given block.
|
/// Get the global validation schedule at the state of a given block.
|
||||||
GlobalValidationSchedule(ResponseChannel<GlobalValidationSchedule>),
|
GlobalValidationData(ResponseChannel<GlobalValidationData>),
|
||||||
/// Get the local validation data for a specific para, with the given occupied core assumption.
|
/// Get the local validation data for a specific para, with the given occupied core assumption.
|
||||||
LocalValidationData(
|
LocalValidationData(
|
||||||
ParaId,
|
ParaId,
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ use primitives::v0::{
|
|||||||
Balance, BlockNumber,
|
Balance, BlockNumber,
|
||||||
Id as ParaId, Chain, DutyRoster, AttestedCandidate, CompactStatement as Statement, ParachainDispatchOrigin,
|
Id as ParaId, Chain, DutyRoster, AttestedCandidate, CompactStatement as Statement, ParachainDispatchOrigin,
|
||||||
UpwardMessage, ValidatorId, ActiveParas, CollatorId, Retriable, OmittedValidationData,
|
UpwardMessage, ValidatorId, ActiveParas, CollatorId, Retriable, OmittedValidationData,
|
||||||
CandidateReceipt, GlobalValidationSchedule, AbridgedCandidateReceipt,
|
CandidateReceipt, GlobalValidationData, AbridgedCandidateReceipt,
|
||||||
LocalValidationData, Scheduling, ValidityAttestation, NEW_HEADS_IDENTIFIER, PARACHAIN_KEY_TYPE_ID,
|
LocalValidationData, Scheduling, ValidityAttestation, NEW_HEADS_IDENTIFIER, PARACHAIN_KEY_TYPE_ID,
|
||||||
ValidatorSignature, SigningContext, HeadData, ValidationCode,
|
ValidatorSignature, SigningContext, HeadData, ValidationCode,
|
||||||
Remark, DownwardMessage
|
Remark, DownwardMessage
|
||||||
@@ -601,7 +601,7 @@ decl_module! {
|
|||||||
|
|
||||||
let mut proceeded = Vec::with_capacity(heads.len());
|
let mut proceeded = Vec::with_capacity(heads.len());
|
||||||
|
|
||||||
let schedule = Self::global_validation_schedule();
|
let schedule = Self::global_validation_data();
|
||||||
|
|
||||||
if !active_parachains.is_empty() {
|
if !active_parachains.is_empty() {
|
||||||
// perform integrity checks before writing to storage.
|
// perform integrity checks before writing to storage.
|
||||||
@@ -1168,9 +1168,9 @@ impl<T: Trait> Module<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the global validation schedule for all parachains.
|
/// Get the global validation schedule for all parachains.
|
||||||
pub fn global_validation_schedule() -> GlobalValidationSchedule {
|
pub fn global_validation_data() -> GlobalValidationData {
|
||||||
let now = <system::Module<T>>::block_number();
|
let now = <system::Module<T>>::block_number();
|
||||||
GlobalValidationSchedule {
|
GlobalValidationData {
|
||||||
max_code_size: T::MaxCodeSize::get(),
|
max_code_size: T::MaxCodeSize::get(),
|
||||||
max_head_data_size: T::MaxHeadDataSize::get(),
|
max_head_data_size: T::MaxHeadDataSize::get(),
|
||||||
block_number: T::BlockNumberConversion::convert(if now.is_zero() {
|
block_number: T::BlockNumberConversion::convert(if now.is_zero() {
|
||||||
@@ -1322,7 +1322,7 @@ impl<T: Trait> Module<T> {
|
|||||||
// check the attestations on these candidates. The candidates should have been checked
|
// check the attestations on these candidates. The candidates should have been checked
|
||||||
// that each candidates' chain ID is valid.
|
// that each candidates' chain ID is valid.
|
||||||
fn check_candidates(
|
fn check_candidates(
|
||||||
schedule: &GlobalValidationSchedule,
|
schedule: &GlobalValidationData,
|
||||||
attested_candidates: &[AttestedCandidate],
|
attested_candidates: &[AttestedCandidate],
|
||||||
active_parachains: &[(ParaId, Option<(CollatorId, Retriable)>)]
|
active_parachains: &[(ParaId, Option<(CollatorId, Retriable)>)]
|
||||||
) -> sp_std::result::Result<IncludedBlocks<T>, sp_runtime::DispatchError> {
|
) -> sp_std::result::Result<IncludedBlocks<T>, sp_runtime::DispatchError> {
|
||||||
@@ -2157,7 +2157,7 @@ mod tests {
|
|||||||
collator: Default::default(),
|
collator: Default::default(),
|
||||||
signature: Default::default(),
|
signature: Default::default(),
|
||||||
pov_block_hash: Default::default(),
|
pov_block_hash: Default::default(),
|
||||||
global_validation: Parachains::global_validation_schedule(),
|
global_validation: Parachains::global_validation_data(),
|
||||||
local_validation: Parachains::current_local_validation_data(¶_id).unwrap(),
|
local_validation: Parachains::current_local_validation_data(¶_id).unwrap(),
|
||||||
commitments: CandidateCommitments::default(),
|
commitments: CandidateCommitments::default(),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1070,7 +1070,7 @@ mod tests {
|
|||||||
collator: collator.public(),
|
collator: collator.public(),
|
||||||
signature: pov_block_hash.using_encoded(|d| collator.sign(d)),
|
signature: pov_block_hash.using_encoded(|d| collator.sign(d)),
|
||||||
pov_block_hash,
|
pov_block_hash,
|
||||||
global_validation: Parachains::global_validation_schedule(),
|
global_validation: Parachains::global_validation_data(),
|
||||||
local_validation: Parachains::current_local_validation_data(&id).unwrap(),
|
local_validation: Parachains::current_local_validation_data(&id).unwrap(),
|
||||||
commitments: CandidateCommitments {
|
commitments: CandidateCommitments {
|
||||||
fees: 0,
|
fees: 0,
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
|||||||
spec_name: create_runtime_str!("kusama"),
|
spec_name: create_runtime_str!("kusama"),
|
||||||
impl_name: create_runtime_str!("parity-kusama"),
|
impl_name: create_runtime_str!("parity-kusama"),
|
||||||
authoring_version: 2,
|
authoring_version: 2,
|
||||||
spec_version: 2019,
|
spec_version: 2020,
|
||||||
impl_version: 0,
|
impl_version: 0,
|
||||||
#[cfg(not(feature = "disable-runtime-api"))]
|
#[cfg(not(feature = "disable-runtime-api"))]
|
||||||
apis: RUNTIME_API_VERSIONS,
|
apis: RUNTIME_API_VERSIONS,
|
||||||
@@ -1115,8 +1115,8 @@ sp_api::impl_runtime_apis! {
|
|||||||
fn active_parachains() -> Vec<(parachain::Id, Option<(parachain::CollatorId, parachain::Retriable)>)> {
|
fn active_parachains() -> Vec<(parachain::Id, Option<(parachain::CollatorId, parachain::Retriable)>)> {
|
||||||
Registrar::active_paras()
|
Registrar::active_paras()
|
||||||
}
|
}
|
||||||
fn global_validation_schedule() -> parachain::GlobalValidationSchedule {
|
fn global_validation_data() -> parachain::GlobalValidationData {
|
||||||
Parachains::global_validation_schedule()
|
Parachains::global_validation_data()
|
||||||
}
|
}
|
||||||
fn local_validation_data(id: parachain::Id) -> Option<parachain::LocalValidationData> {
|
fn local_validation_data(id: parachain::Id) -> Option<parachain::LocalValidationData> {
|
||||||
Parachains::current_local_validation_data(&id)
|
Parachains::current_local_validation_data(&id)
|
||||||
|
|||||||
@@ -19,12 +19,13 @@
|
|||||||
//! 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::{ValidatorId, GlobalValidationData};
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
decl_storage, decl_module, decl_error,
|
decl_storage, decl_module, decl_error,
|
||||||
dispatch::DispatchResult,
|
dispatch::DispatchResult,
|
||||||
weights::{DispatchClass, Weight},
|
weights::{DispatchClass, Weight},
|
||||||
};
|
};
|
||||||
|
use sp_runtime::traits::One;
|
||||||
use codec::{Encode, Decode};
|
use codec::{Encode, Decode};
|
||||||
use system::ensure_root;
|
use system::ensure_root;
|
||||||
|
|
||||||
@@ -219,6 +220,16 @@ impl<T: Trait> Module<T> {
|
|||||||
<Self as Store>::PendingConfig::set(Some(prev));
|
<Self as Store>::PendingConfig::set(Some(prev));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Computes the global validation-data, assuming the context of the parent block.
|
||||||
|
pub(crate) fn global_validation_data() -> GlobalValidationData<T::BlockNumber> {
|
||||||
|
let config = Self::config();
|
||||||
|
GlobalValidationData {
|
||||||
|
max_code_size: config.max_code_size,
|
||||||
|
max_head_data_size: config.max_head_data_size,
|
||||||
|
block_number: <system::Module<T>>::block_number() - One::one(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
use sp_std::prelude::*;
|
use sp_std::prelude::*;
|
||||||
use primitives::v1::{
|
use primitives::v1::{
|
||||||
|
validation_data_hash,
|
||||||
ValidatorId, CandidateCommitments, CandidateDescriptor, ValidatorIndex, Id as ParaId,
|
ValidatorId, CandidateCommitments, CandidateDescriptor, ValidatorIndex, Id as ParaId,
|
||||||
AvailabilityBitfield as AvailabilityBitfield, SignedAvailabilityBitfields, SigningContext,
|
AvailabilityBitfield as AvailabilityBitfield, SignedAvailabilityBitfields, SigningContext,
|
||||||
BackedCandidate, CoreIndex, GroupIndex, CoreAssignment, CommittedCandidateReceipt,
|
BackedCandidate, CoreIndex, GroupIndex, CoreAssignment, CommittedCandidateReceipt,
|
||||||
@@ -145,6 +146,8 @@ decl_error! {
|
|||||||
InvalidBacking,
|
InvalidBacking,
|
||||||
/// Collator did not sign PoV.
|
/// Collator did not sign PoV.
|
||||||
NotCollatorSigned,
|
NotCollatorSigned,
|
||||||
|
/// The validation data hash does not match expected.
|
||||||
|
ValidationDataHashMismatch,
|
||||||
/// Internal error only returned when compiled with debug assertions.
|
/// Internal error only returned when compiled with debug assertions.
|
||||||
InternalError,
|
InternalError,
|
||||||
}
|
}
|
||||||
@@ -399,14 +402,21 @@ impl<T: Trait> Module<T> {
|
|||||||
Error::<T>::CandidateNotInParentContext,
|
Error::<T>::CandidateNotInParentContext,
|
||||||
);
|
);
|
||||||
|
|
||||||
let code_upgrade_allowed = <paras::Module<T>>::last_code_upgrade(para_id, true)
|
// if any, the code upgrade attempt is allowed.
|
||||||
.map_or(
|
let valid_upgrade_attempt =
|
||||||
true,
|
candidate.candidate.commitments.new_validation_code.is_none() ||
|
||||||
|last| last <= relay_parent_number &&
|
<paras::Module<T>>::last_code_upgrade(para_id, true)
|
||||||
relay_parent_number.saturating_sub(last) >= config.validation_upgrade_frequency,
|
.map_or(
|
||||||
);
|
true,
|
||||||
|
|last| last <= relay_parent_number &&
|
||||||
|
relay_parent_number.saturating_sub(last)
|
||||||
|
>= config.validation_upgrade_frequency,
|
||||||
|
);
|
||||||
|
|
||||||
ensure!(code_upgrade_allowed, Error::<T>::PrematureCodeUpgrade);
|
ensure!(
|
||||||
|
valid_upgrade_attempt,
|
||||||
|
Error::<T>::PrematureCodeUpgrade,
|
||||||
|
);
|
||||||
ensure!(
|
ensure!(
|
||||||
candidate.descriptor().check_collator_signature().is_ok(),
|
candidate.descriptor().check_collator_signature().is_ok(),
|
||||||
Error::<T>::NotCollatorSigned,
|
Error::<T>::NotCollatorSigned,
|
||||||
@@ -423,6 +433,32 @@ impl<T: Trait> Module<T> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// this should never fail because the para is registered
|
||||||
|
let (global_validation_data, local_validation_data) = (
|
||||||
|
<configuration::Module<T>>::global_validation_data(),
|
||||||
|
match <paras::Module<T>>::local_validation_data(para_id) {
|
||||||
|
Some(l) => l,
|
||||||
|
None => {
|
||||||
|
// We don't want to error out here because it will
|
||||||
|
// brick the relay-chain. So we return early without
|
||||||
|
// doing anything.
|
||||||
|
return Ok(Vec::new());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected = validation_data_hash(
|
||||||
|
&global_validation_data,
|
||||||
|
&local_validation_data,
|
||||||
|
);
|
||||||
|
|
||||||
|
ensure!(
|
||||||
|
expected == candidate.descriptor().validation_data_hash,
|
||||||
|
Error::<T>::ValidationDataHashMismatch,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
ensure!(
|
ensure!(
|
||||||
<PendingAvailability<T>>::get(¶_id).is_none() &&
|
<PendingAvailability<T>>::get(¶_id).is_none() &&
|
||||||
<PendingAvailabilityCommitments>::get(¶_id).is_none(),
|
<PendingAvailabilityCommitments>::get(¶_id).is_none(),
|
||||||
@@ -686,6 +722,7 @@ mod tests {
|
|||||||
let payload = primitives::v1::collator_signature_payload(
|
let payload = primitives::v1::collator_signature_payload(
|
||||||
&candidate.descriptor.relay_parent,
|
&candidate.descriptor.relay_parent,
|
||||||
&candidate.descriptor.para_id,
|
&candidate.descriptor.para_id,
|
||||||
|
&candidate.descriptor.validation_data_hash,
|
||||||
&candidate.descriptor.pov_hash,
|
&candidate.descriptor.pov_hash,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -814,6 +851,7 @@ mod tests {
|
|||||||
head_data: HeadData,
|
head_data: HeadData,
|
||||||
pov_hash: Hash,
|
pov_hash: Hash,
|
||||||
relay_parent: Hash,
|
relay_parent: Hash,
|
||||||
|
validation_data_hash: Hash,
|
||||||
new_validation_code: Option<ValidationCode>,
|
new_validation_code: Option<ValidationCode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -824,6 +862,7 @@ mod tests {
|
|||||||
para_id: self.para_id,
|
para_id: self.para_id,
|
||||||
pov_hash: self.pov_hash,
|
pov_hash: self.pov_hash,
|
||||||
relay_parent: self.relay_parent,
|
relay_parent: self.relay_parent,
|
||||||
|
validation_data_hash: self.validation_data_hash,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
commitments: CandidateCommitments {
|
commitments: CandidateCommitments {
|
||||||
@@ -835,6 +874,12 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_vdata_hash(para_id: ParaId) -> Option<Hash> {
|
||||||
|
let global_validation_data = Configuration::global_validation_data();
|
||||||
|
let local_validation_data = Paras::local_validation_data(para_id)?;
|
||||||
|
Some(validation_data_hash(&global_validation_data, &local_validation_data))
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn collect_pending_cleans_up_pending() {
|
fn collect_pending_cleans_up_pending() {
|
||||||
let chain_a = ParaId::from(1);
|
let chain_a = ParaId::from(1);
|
||||||
@@ -1261,6 +1306,7 @@ mod tests {
|
|||||||
para_id: chain_a,
|
para_id: chain_a,
|
||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([1; 32]),
|
pov_hash: Hash::from([1; 32]),
|
||||||
|
validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
collator_sign_candidate(
|
collator_sign_candidate(
|
||||||
@@ -1276,11 +1322,14 @@ mod tests {
|
|||||||
BackingKind::Threshold,
|
BackingKind::Threshold,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(Inclusion::process_candidates(
|
assert_eq!(
|
||||||
vec![backed],
|
Inclusion::process_candidates(
|
||||||
vec![chain_b_assignment.clone()],
|
vec![backed],
|
||||||
&group_validators,
|
vec![chain_b_assignment.clone()],
|
||||||
).is_err());
|
&group_validators,
|
||||||
|
),
|
||||||
|
Err(Error::<Test>::UnscheduledCandidate.into()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// candidates out of order.
|
// candidates out of order.
|
||||||
@@ -1289,12 +1338,14 @@ mod tests {
|
|||||||
para_id: chain_a,
|
para_id: chain_a,
|
||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([1; 32]),
|
pov_hash: Hash::from([1; 32]),
|
||||||
|
validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
let mut candidate_b = TestCandidateBuilder {
|
let mut candidate_b = TestCandidateBuilder {
|
||||||
para_id: chain_b,
|
para_id: chain_b,
|
||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([2; 32]),
|
pov_hash: Hash::from([2; 32]),
|
||||||
|
validation_data_hash: make_vdata_hash(chain_b).unwrap(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
|
|
||||||
@@ -1324,11 +1375,15 @@ mod tests {
|
|||||||
BackingKind::Threshold,
|
BackingKind::Threshold,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(Inclusion::process_candidates(
|
// out-of-order manifests as unscheduled.
|
||||||
vec![backed_b, backed_a],
|
assert_eq!(
|
||||||
vec![chain_a_assignment.clone(), chain_b_assignment.clone()],
|
Inclusion::process_candidates(
|
||||||
&group_validators,
|
vec![backed_b, backed_a],
|
||||||
).is_err());
|
vec![chain_a_assignment.clone(), chain_b_assignment.clone()],
|
||||||
|
&group_validators,
|
||||||
|
),
|
||||||
|
Err(Error::<Test>::UnscheduledCandidate.into()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// candidate not backed.
|
// candidate not backed.
|
||||||
@@ -1337,6 +1392,7 @@ mod tests {
|
|||||||
para_id: chain_a,
|
para_id: chain_a,
|
||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([1; 32]),
|
pov_hash: Hash::from([1; 32]),
|
||||||
|
validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
collator_sign_candidate(
|
collator_sign_candidate(
|
||||||
@@ -1352,11 +1408,14 @@ mod tests {
|
|||||||
BackingKind::Lacking,
|
BackingKind::Lacking,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(Inclusion::process_candidates(
|
assert_eq!(
|
||||||
vec![backed],
|
Inclusion::process_candidates(
|
||||||
vec![chain_a_assignment.clone()],
|
vec![backed],
|
||||||
&group_validators,
|
vec![chain_a_assignment.clone()],
|
||||||
).is_err());
|
&group_validators,
|
||||||
|
),
|
||||||
|
Err(Error::<Test>::InsufficientBacking.into()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// candidate not in parent context.
|
// candidate not in parent context.
|
||||||
@@ -1368,6 +1427,7 @@ mod tests {
|
|||||||
para_id: chain_a,
|
para_id: chain_a,
|
||||||
relay_parent: wrong_parent_hash,
|
relay_parent: wrong_parent_hash,
|
||||||
pov_hash: Hash::from([1; 32]),
|
pov_hash: Hash::from([1; 32]),
|
||||||
|
validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
collator_sign_candidate(
|
collator_sign_candidate(
|
||||||
@@ -1383,11 +1443,14 @@ mod tests {
|
|||||||
BackingKind::Threshold,
|
BackingKind::Threshold,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(Inclusion::process_candidates(
|
assert_eq!(
|
||||||
vec![backed],
|
Inclusion::process_candidates(
|
||||||
vec![chain_a_assignment.clone()],
|
vec![backed],
|
||||||
&group_validators,
|
vec![chain_a_assignment.clone()],
|
||||||
).is_err());
|
&group_validators,
|
||||||
|
),
|
||||||
|
Err(Error::<Test>::CandidateNotInParentContext.into()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// candidate has wrong collator.
|
// candidate has wrong collator.
|
||||||
@@ -1396,6 +1459,7 @@ mod tests {
|
|||||||
para_id: thread_a,
|
para_id: thread_a,
|
||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([1; 32]),
|
pov_hash: Hash::from([1; 32]),
|
||||||
|
validation_data_hash: make_vdata_hash(thread_a).unwrap(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
|
|
||||||
@@ -1413,15 +1477,18 @@ mod tests {
|
|||||||
BackingKind::Threshold,
|
BackingKind::Threshold,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(Inclusion::process_candidates(
|
assert_eq!(
|
||||||
vec![backed],
|
Inclusion::process_candidates(
|
||||||
vec![
|
vec![backed],
|
||||||
chain_a_assignment.clone(),
|
vec![
|
||||||
chain_b_assignment.clone(),
|
chain_a_assignment.clone(),
|
||||||
thread_a_assignment.clone(),
|
chain_b_assignment.clone(),
|
||||||
],
|
thread_a_assignment.clone(),
|
||||||
&group_validators,
|
],
|
||||||
).is_err());
|
&group_validators,
|
||||||
|
),
|
||||||
|
Err(Error::<Test>::WrongCollator.into()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// candidate not well-signed by collator.
|
// candidate not well-signed by collator.
|
||||||
@@ -1430,6 +1497,7 @@ mod tests {
|
|||||||
para_id: thread_a,
|
para_id: thread_a,
|
||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([1; 32]),
|
pov_hash: Hash::from([1; 32]),
|
||||||
|
validation_data_hash: make_vdata_hash(thread_a).unwrap(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
|
|
||||||
@@ -1450,11 +1518,14 @@ mod tests {
|
|||||||
BackingKind::Threshold,
|
BackingKind::Threshold,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(Inclusion::process_candidates(
|
assert_eq!(
|
||||||
vec![backed],
|
Inclusion::process_candidates(
|
||||||
vec![thread_a_assignment.clone()],
|
vec![backed],
|
||||||
&group_validators,
|
vec![thread_a_assignment.clone()],
|
||||||
).is_err());
|
&group_validators,
|
||||||
|
),
|
||||||
|
Err(Error::<Test>::NotCollatorSigned.into()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// para occupied - reject.
|
// para occupied - reject.
|
||||||
@@ -1463,6 +1534,7 @@ mod tests {
|
|||||||
para_id: chain_a,
|
para_id: chain_a,
|
||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([1; 32]),
|
pov_hash: Hash::from([1; 32]),
|
||||||
|
validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
|
|
||||||
@@ -1489,11 +1561,14 @@ mod tests {
|
|||||||
});
|
});
|
||||||
<PendingAvailabilityCommitments>::insert(&chain_a, candidate.commitments);
|
<PendingAvailabilityCommitments>::insert(&chain_a, candidate.commitments);
|
||||||
|
|
||||||
assert!(Inclusion::process_candidates(
|
assert_eq!(
|
||||||
vec![backed],
|
Inclusion::process_candidates(
|
||||||
vec![chain_a_assignment.clone()],
|
vec![backed],
|
||||||
&group_validators,
|
vec![chain_a_assignment.clone()],
|
||||||
).is_err());
|
&group_validators,
|
||||||
|
),
|
||||||
|
Err(Error::<Test>::CandidateScheduledBeforeParaFree.into()),
|
||||||
|
);
|
||||||
|
|
||||||
<PendingAvailability<Test>>::remove(&chain_a);
|
<PendingAvailability<Test>>::remove(&chain_a);
|
||||||
<PendingAvailabilityCommitments>::remove(&chain_a);
|
<PendingAvailabilityCommitments>::remove(&chain_a);
|
||||||
@@ -1505,6 +1580,7 @@ mod tests {
|
|||||||
para_id: chain_a,
|
para_id: chain_a,
|
||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([1; 32]),
|
pov_hash: Hash::from([1; 32]),
|
||||||
|
validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
|
|
||||||
@@ -1524,11 +1600,14 @@ mod tests {
|
|||||||
BackingKind::Threshold,
|
BackingKind::Threshold,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(Inclusion::process_candidates(
|
assert_eq!(
|
||||||
vec![backed],
|
Inclusion::process_candidates(
|
||||||
vec![chain_a_assignment.clone()],
|
vec![backed],
|
||||||
&group_validators,
|
vec![chain_a_assignment.clone()],
|
||||||
).is_err());
|
&group_validators,
|
||||||
|
),
|
||||||
|
Err(Error::<Test>::CandidateScheduledBeforeParaFree.into()),
|
||||||
|
);
|
||||||
|
|
||||||
<PendingAvailabilityCommitments>::remove(&chain_a);
|
<PendingAvailabilityCommitments>::remove(&chain_a);
|
||||||
}
|
}
|
||||||
@@ -1540,6 +1619,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]),
|
||||||
new_validation_code: Some(vec![5, 6, 7, 8].into()),
|
new_validation_code: Some(vec![5, 6, 7, 8].into()),
|
||||||
|
validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
|
|
||||||
@@ -1564,11 +1644,47 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(Paras::last_code_upgrade(chain_a, true), Some(10));
|
assert_eq!(Paras::last_code_upgrade(chain_a, true), Some(10));
|
||||||
|
|
||||||
assert!(Inclusion::process_candidates(
|
assert_eq!(
|
||||||
vec![backed],
|
Inclusion::process_candidates(
|
||||||
vec![thread_a_assignment.clone()],
|
vec![backed],
|
||||||
&group_validators,
|
vec![chain_a_assignment.clone()],
|
||||||
).is_err());
|
&group_validators,
|
||||||
|
),
|
||||||
|
Err(Error::<Test>::PrematureCodeUpgrade.into()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bad validation data hash - reject
|
||||||
|
{
|
||||||
|
let mut candidate = TestCandidateBuilder {
|
||||||
|
para_id: chain_a,
|
||||||
|
relay_parent: System::parent_hash(),
|
||||||
|
pov_hash: Hash::from([1; 32]),
|
||||||
|
validation_data_hash: [42u8; 32].into(),
|
||||||
|
..Default::default()
|
||||||
|
}.build();
|
||||||
|
|
||||||
|
collator_sign_candidate(
|
||||||
|
Sr25519Keyring::One,
|
||||||
|
&mut candidate,
|
||||||
|
);
|
||||||
|
|
||||||
|
let backed = back_candidate(
|
||||||
|
candidate,
|
||||||
|
&validators,
|
||||||
|
group_validators(GroupIndex::from(0)).unwrap().as_ref(),
|
||||||
|
&signing_context,
|
||||||
|
BackingKind::Threshold,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Inclusion::process_candidates(
|
||||||
|
vec![backed],
|
||||||
|
vec![chain_a_assignment.clone()],
|
||||||
|
&group_validators,
|
||||||
|
),
|
||||||
|
Err(Error::<Test>::ValidationDataHashMismatch.into()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1634,6 +1750,7 @@ mod tests {
|
|||||||
para_id: chain_a,
|
para_id: chain_a,
|
||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([1; 32]),
|
pov_hash: Hash::from([1; 32]),
|
||||||
|
validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
collator_sign_candidate(
|
collator_sign_candidate(
|
||||||
@@ -1645,6 +1762,7 @@ mod tests {
|
|||||||
para_id: chain_b,
|
para_id: chain_b,
|
||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([2; 32]),
|
pov_hash: Hash::from([2; 32]),
|
||||||
|
validation_data_hash: make_vdata_hash(chain_b).unwrap(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
collator_sign_candidate(
|
collator_sign_candidate(
|
||||||
@@ -1656,6 +1774,7 @@ mod tests {
|
|||||||
para_id: thread_a,
|
para_id: thread_a,
|
||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
pov_hash: Hash::from([3; 32]),
|
pov_hash: Hash::from([3; 32]),
|
||||||
|
validation_data_hash: make_vdata_hash(thread_a).unwrap(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.build();
|
}.build();
|
||||||
collator_sign_candidate(
|
collator_sign_candidate(
|
||||||
@@ -1746,6 +1865,91 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_include_candidate_with_ok_code_upgrade() {
|
||||||
|
let chain_a = ParaId::from(1);
|
||||||
|
|
||||||
|
let paras = vec![(chain_a, true)];
|
||||||
|
let validators = vec![
|
||||||
|
Sr25519Keyring::Alice,
|
||||||
|
Sr25519Keyring::Bob,
|
||||||
|
Sr25519Keyring::Charlie,
|
||||||
|
Sr25519Keyring::Dave,
|
||||||
|
Sr25519Keyring::Ferdie,
|
||||||
|
];
|
||||||
|
let validator_public = validator_pubkeys(&validators);
|
||||||
|
|
||||||
|
new_test_ext(genesis_config(paras)).execute_with(|| {
|
||||||
|
Validators::set(validator_public.clone());
|
||||||
|
CurrentSessionIndex::set(5);
|
||||||
|
|
||||||
|
run_to_block(5, |_| None);
|
||||||
|
|
||||||
|
let signing_context = SigningContext {
|
||||||
|
parent_hash: System::parent_hash(),
|
||||||
|
session_index: 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
let group_validators = |group_index: GroupIndex| match group_index {
|
||||||
|
group_index if group_index == GroupIndex::from(0) => Some(vec![0, 1, 2, 3, 4]),
|
||||||
|
_ => panic!("Group index out of bounds for 1 parachain"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let chain_a_assignment = CoreAssignment {
|
||||||
|
core: CoreIndex::from(0),
|
||||||
|
para_id: chain_a,
|
||||||
|
kind: AssignmentKind::Parachain,
|
||||||
|
group_idx: GroupIndex::from(0),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut candidate_a = TestCandidateBuilder {
|
||||||
|
para_id: chain_a,
|
||||||
|
relay_parent: System::parent_hash(),
|
||||||
|
pov_hash: Hash::from([1; 32]),
|
||||||
|
validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||||
|
new_validation_code: Some(vec![1, 2, 3].into()),
|
||||||
|
..Default::default()
|
||||||
|
}.build();
|
||||||
|
collator_sign_candidate(
|
||||||
|
Sr25519Keyring::One,
|
||||||
|
&mut candidate_a,
|
||||||
|
);
|
||||||
|
|
||||||
|
let backed_a = back_candidate(
|
||||||
|
candidate_a.clone(),
|
||||||
|
&validators,
|
||||||
|
group_validators(GroupIndex::from(0)).unwrap().as_ref(),
|
||||||
|
&signing_context,
|
||||||
|
BackingKind::Threshold,
|
||||||
|
);
|
||||||
|
|
||||||
|
let occupied_cores = Inclusion::process_candidates(
|
||||||
|
vec![backed_a],
|
||||||
|
vec![
|
||||||
|
chain_a_assignment.clone(),
|
||||||
|
],
|
||||||
|
&group_validators,
|
||||||
|
).expect("candidates scheduled, in order, and backed");
|
||||||
|
|
||||||
|
assert_eq!(occupied_cores, vec![CoreIndex::from(0)]);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
<PendingAvailability<Test>>::get(&chain_a),
|
||||||
|
Some(CandidatePendingAvailability {
|
||||||
|
core: CoreIndex::from(0),
|
||||||
|
descriptor: candidate_a.descriptor,
|
||||||
|
availability_votes: default_availability_votes(),
|
||||||
|
relay_parent_number: System::block_number() - 1,
|
||||||
|
backed_in_number: System::block_number(),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
<PendingAvailabilityCommitments>::get(&chain_a),
|
||||||
|
Some(candidate_a.commitments),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn session_change_wipes_and_updates_session_info() {
|
fn session_change_wipes_and_updates_session_info() {
|
||||||
let chain_a = ParaId::from(1);
|
let chain_a = ParaId::from(1);
|
||||||
|
|||||||
@@ -25,9 +25,9 @@
|
|||||||
|
|
||||||
use sp_std::prelude::*;
|
use sp_std::prelude::*;
|
||||||
use sp_std::marker::PhantomData;
|
use sp_std::marker::PhantomData;
|
||||||
use sp_runtime::traits::One;
|
use sp_runtime::traits::{One, BlakeTwo256, Hash as HashT, Saturating};
|
||||||
use primitives::v1::{
|
use primitives::v1::{
|
||||||
Id as ParaId, ValidationCode, HeadData,
|
Id as ParaId, ValidationCode, HeadData, LocalValidationData,
|
||||||
};
|
};
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
decl_storage, decl_module, decl_error,
|
decl_storage, decl_module, decl_error,
|
||||||
@@ -536,6 +536,37 @@ impl<T: Trait> Module<T> {
|
|||||||
|
|
||||||
Self::past_code_meta(&id).most_recent_change()
|
Self::past_code_meta(&id).most_recent_change()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compute the local-validation data based on the head of the para. This assumes the
|
||||||
|
/// relay-parent is the parent of the current block.
|
||||||
|
pub(crate) fn local_validation_data(para_id: ParaId) -> Option<LocalValidationData<T::BlockNumber>> {
|
||||||
|
let relay_parent_number = <system::Module<T>>::block_number() - One::one();
|
||||||
|
|
||||||
|
let config = <configuration::Module<T>>::config();
|
||||||
|
let freq = config.validation_upgrade_frequency;
|
||||||
|
let delay = config.validation_upgrade_delay;
|
||||||
|
|
||||||
|
let last_code_upgrade = Self::last_code_upgrade(para_id, true);
|
||||||
|
let can_upgrade_code = last_code_upgrade.map_or(
|
||||||
|
true,
|
||||||
|
|l| { l <= relay_parent_number && relay_parent_number.saturating_sub(l) >= freq },
|
||||||
|
);
|
||||||
|
|
||||||
|
let code_upgrade_allowed = if can_upgrade_code {
|
||||||
|
Some(relay_parent_number + delay)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(LocalValidationData {
|
||||||
|
parent_head: Self::para_head(¶_id)?,
|
||||||
|
balance: 0,
|
||||||
|
validation_code_hash: BlakeTwo256::hash_of(
|
||||||
|
&Self::current_code(¶_id)?
|
||||||
|
),
|
||||||
|
code_upgrade_allowed,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -18,12 +18,12 @@
|
|||||||
//! functions.
|
//! functions.
|
||||||
|
|
||||||
use primitives::v1::{
|
use primitives::v1::{
|
||||||
ValidatorId, ValidatorIndex, GroupRotationInfo, CoreState, GlobalValidationSchedule,
|
ValidatorId, ValidatorIndex, GroupRotationInfo, CoreState, GlobalValidationData,
|
||||||
Id as ParaId, OccupiedCoreAssumption, LocalValidationData, SessionIndex, ValidationCode,
|
Id as ParaId, OccupiedCoreAssumption, LocalValidationData, SessionIndex, ValidationCode,
|
||||||
CommittedCandidateReceipt, ScheduledCore, OccupiedCore, CoreOccupied, CoreIndex,
|
CommittedCandidateReceipt, ScheduledCore, OccupiedCore, CoreOccupied, CoreIndex,
|
||||||
GroupIndex, CandidateEvent,
|
GroupIndex, CandidateEvent,
|
||||||
};
|
};
|
||||||
use sp_runtime::traits::{One, BlakeTwo256, Hash as HashT, Saturating, Zero};
|
use sp_runtime::traits::Zero;
|
||||||
use frame_support::debug;
|
use frame_support::debug;
|
||||||
use crate::{initializer, inclusion, scheduler, configuration, paras};
|
use crate::{initializer, inclusion, scheduler, configuration, paras};
|
||||||
|
|
||||||
@@ -160,16 +160,11 @@ pub fn availability_cores<T: initializer::Trait>() -> Vec<CoreState<T::BlockNumb
|
|||||||
core_states
|
core_states
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation for the `global_validation_schedule` function of the runtime API.
|
/// Implementation for the `global_validation_data` function of the runtime API.
|
||||||
pub fn global_validation_schedule<T: initializer::Trait>()
|
pub fn global_validation_data<T: initializer::Trait>()
|
||||||
-> GlobalValidationSchedule<T::BlockNumber>
|
-> GlobalValidationData<T::BlockNumber>
|
||||||
{
|
{
|
||||||
let config = <configuration::Module<T>>::config();
|
<configuration::Module<T>>::global_validation_data()
|
||||||
GlobalValidationSchedule {
|
|
||||||
max_code_size: config.max_code_size,
|
|
||||||
max_head_data_size: config.max_head_data_size,
|
|
||||||
block_number: <system::Module<T>>::block_number() - One::one(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation for the `local_validation_data` function of the runtime API.
|
/// Implementation for the `local_validation_data` function of the runtime API.
|
||||||
@@ -177,46 +172,19 @@ pub fn local_validation_data<T: initializer::Trait>(
|
|||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
assumption: OccupiedCoreAssumption,
|
assumption: OccupiedCoreAssumption,
|
||||||
) -> Option<LocalValidationData<T::BlockNumber>> {
|
) -> Option<LocalValidationData<T::BlockNumber>> {
|
||||||
let construct = || {
|
|
||||||
let relay_parent_number = <system::Module<T>>::block_number() - One::one();
|
|
||||||
|
|
||||||
let config = <configuration::Module<T>>::config();
|
|
||||||
let freq = config.validation_upgrade_frequency;
|
|
||||||
let delay = config.validation_upgrade_delay;
|
|
||||||
|
|
||||||
let last_code_upgrade = <paras::Module<T>>::last_code_upgrade(para_id, true)?;
|
|
||||||
let can_upgrade_code = last_code_upgrade <= relay_parent_number
|
|
||||||
&& relay_parent_number.saturating_sub(last_code_upgrade) >= freq;
|
|
||||||
|
|
||||||
let code_upgrade_allowed = if can_upgrade_code {
|
|
||||||
Some(relay_parent_number + delay)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(LocalValidationData {
|
|
||||||
parent_head: <paras::Module<T>>::para_head(¶_id)?,
|
|
||||||
balance: 0,
|
|
||||||
validation_code_hash: BlakeTwo256::hash_of(
|
|
||||||
&<paras::Module<T>>::current_code(¶_id)?
|
|
||||||
),
|
|
||||||
code_upgrade_allowed,
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
match assumption {
|
match assumption {
|
||||||
OccupiedCoreAssumption::Included => {
|
OccupiedCoreAssumption::Included => {
|
||||||
<inclusion::Module<T>>::force_enact(para_id);
|
<inclusion::Module<T>>::force_enact(para_id);
|
||||||
construct()
|
<paras::Module<T>>::local_validation_data(para_id)
|
||||||
}
|
}
|
||||||
OccupiedCoreAssumption::TimedOut => {
|
OccupiedCoreAssumption::TimedOut => {
|
||||||
construct()
|
<paras::Module<T>>::local_validation_data(para_id)
|
||||||
}
|
}
|
||||||
OccupiedCoreAssumption::Free => {
|
OccupiedCoreAssumption::Free => {
|
||||||
if <inclusion::Module<T>>::pending_availability(para_id).is_some() {
|
if <inclusion::Module<T>>::pending_availability(para_id).is_some() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
construct()
|
<paras::Module<T>>::local_validation_data(para_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
|||||||
spec_name: create_runtime_str!("polkadot"),
|
spec_name: create_runtime_str!("polkadot"),
|
||||||
impl_name: create_runtime_str!("parity-polkadot"),
|
impl_name: create_runtime_str!("parity-polkadot"),
|
||||||
authoring_version: 0,
|
authoring_version: 0,
|
||||||
spec_version: 19,
|
spec_version: 20,
|
||||||
impl_version: 0,
|
impl_version: 0,
|
||||||
#[cfg(not(feature = "disable-runtime-api"))]
|
#[cfg(not(feature = "disable-runtime-api"))]
|
||||||
apis: RUNTIME_API_VERSIONS,
|
apis: RUNTIME_API_VERSIONS,
|
||||||
@@ -1256,8 +1256,8 @@ sp_api::impl_runtime_apis! {
|
|||||||
fn active_parachains() -> Vec<(parachain::Id, Option<(parachain::CollatorId, parachain::Retriable)>)> {
|
fn active_parachains() -> Vec<(parachain::Id, Option<(parachain::CollatorId, parachain::Retriable)>)> {
|
||||||
Registrar::active_paras()
|
Registrar::active_paras()
|
||||||
}
|
}
|
||||||
fn global_validation_schedule() -> parachain::GlobalValidationSchedule {
|
fn global_validation_data() -> parachain::GlobalValidationData {
|
||||||
Parachains::global_validation_schedule()
|
Parachains::global_validation_data()
|
||||||
}
|
}
|
||||||
fn local_validation_data(id: parachain::Id) -> Option<parachain::LocalValidationData> {
|
fn local_validation_data(id: parachain::Id) -> Option<parachain::LocalValidationData> {
|
||||||
Parachains::current_local_validation_data(&id)
|
Parachains::current_local_validation_data(&id)
|
||||||
|
|||||||
@@ -676,8 +676,8 @@ sp_api::impl_runtime_apis! {
|
|||||||
fn active_parachains() -> Vec<(parachain::Id, Option<(parachain::CollatorId, parachain::Retriable)>)> {
|
fn active_parachains() -> Vec<(parachain::Id, Option<(parachain::CollatorId, parachain::Retriable)>)> {
|
||||||
Registrar::active_paras()
|
Registrar::active_paras()
|
||||||
}
|
}
|
||||||
fn global_validation_schedule() -> parachain::GlobalValidationSchedule {
|
fn global_validation_data() -> parachain::GlobalValidationData {
|
||||||
Parachains::global_validation_schedule()
|
Parachains::global_validation_data()
|
||||||
}
|
}
|
||||||
fn local_validation_data(id: parachain::Id) -> Option<parachain::LocalValidationData> {
|
fn local_validation_data(id: parachain::Id) -> Option<parachain::LocalValidationData> {
|
||||||
Parachains::current_local_validation_data(&id)
|
Parachains::current_local_validation_data(&id)
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
|||||||
spec_name: create_runtime_str!("westend"),
|
spec_name: create_runtime_str!("westend"),
|
||||||
impl_name: create_runtime_str!("parity-westend"),
|
impl_name: create_runtime_str!("parity-westend"),
|
||||||
authoring_version: 2,
|
authoring_version: 2,
|
||||||
spec_version: 39,
|
spec_version: 40,
|
||||||
impl_version: 0,
|
impl_version: 0,
|
||||||
#[cfg(not(feature = "disable-runtime-api"))]
|
#[cfg(not(feature = "disable-runtime-api"))]
|
||||||
apis: RUNTIME_API_VERSIONS,
|
apis: RUNTIME_API_VERSIONS,
|
||||||
@@ -897,8 +897,8 @@ sp_api::impl_runtime_apis! {
|
|||||||
fn active_parachains() -> Vec<(parachain::Id, Option<(parachain::CollatorId, parachain::Retriable)>)> {
|
fn active_parachains() -> Vec<(parachain::Id, Option<(parachain::CollatorId, parachain::Retriable)>)> {
|
||||||
Registrar::active_paras()
|
Registrar::active_paras()
|
||||||
}
|
}
|
||||||
fn global_validation_schedule() -> parachain::GlobalValidationSchedule {
|
fn global_validation_data() -> parachain::GlobalValidationData {
|
||||||
Parachains::global_validation_schedule()
|
Parachains::global_validation_data()
|
||||||
}
|
}
|
||||||
fn local_validation_data(id: parachain::Id) -> Option<parachain::LocalValidationData> {
|
fn local_validation_data(id: parachain::Id) -> Option<parachain::LocalValidationData> {
|
||||||
Parachains::current_local_validation_data(&id)
|
Parachains::current_local_validation_data(&id)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
use polkadot_erasure_coding as erasure;
|
use polkadot_erasure_coding as erasure;
|
||||||
use polkadot_primitives::v0::{
|
use polkadot_primitives::v0::{
|
||||||
CollationInfo, PoVBlock, LocalValidationData, GlobalValidationSchedule, OmittedValidationData,
|
CollationInfo, PoVBlock, LocalValidationData, GlobalValidationData, OmittedValidationData,
|
||||||
AvailableData, FeeSchedule, CandidateCommitments, ErasureChunk, ParachainHost,
|
AvailableData, FeeSchedule, CandidateCommitments, ErasureChunk, ParachainHost,
|
||||||
Id as ParaId, AbridgedCandidateReceipt, ValidationCode,
|
Id as ParaId, AbridgedCandidateReceipt, ValidationCode,
|
||||||
};
|
};
|
||||||
@@ -95,7 +95,7 @@ impl FullOutput {
|
|||||||
/// validation are needed, call `full_output`. Otherwise, safely drop this value.
|
/// validation are needed, call `full_output`. Otherwise, safely drop this value.
|
||||||
pub struct ValidatedCandidate<'a> {
|
pub struct ValidatedCandidate<'a> {
|
||||||
pov_block: &'a PoVBlock,
|
pov_block: &'a PoVBlock,
|
||||||
global_validation: &'a GlobalValidationSchedule,
|
global_validation: &'a GlobalValidationData,
|
||||||
local_validation: &'a LocalValidationData,
|
local_validation: &'a LocalValidationData,
|
||||||
upward_messages: Vec<UpwardMessage>,
|
upward_messages: Vec<UpwardMessage>,
|
||||||
fees: Balance,
|
fees: Balance,
|
||||||
@@ -189,7 +189,7 @@ pub fn validate<'a>(
|
|||||||
collation: &'a CollationInfo,
|
collation: &'a CollationInfo,
|
||||||
pov_block: &'a PoVBlock,
|
pov_block: &'a PoVBlock,
|
||||||
local_validation: &'a LocalValidationData,
|
local_validation: &'a LocalValidationData,
|
||||||
global_validation: &'a GlobalValidationSchedule,
|
global_validation: &'a GlobalValidationData,
|
||||||
validation_code: &ValidationCode,
|
validation_code: &ValidationCode,
|
||||||
) -> Result<ValidatedCandidate<'a>, Error> {
|
) -> Result<ValidatedCandidate<'a>, Error> {
|
||||||
if collation.head_data.0.len() > global_validation.max_head_data_size as _ {
|
if collation.head_data.0.len() > global_validation.max_head_data_size as _ {
|
||||||
@@ -249,7 +249,7 @@ pub fn validate<'a>(
|
|||||||
|
|
||||||
/// Extracts validation parameters from a Polkadot runtime API for a specific parachain.
|
/// Extracts validation parameters from a Polkadot runtime API for a specific parachain.
|
||||||
pub fn validation_params<P>(api: &P, relay_parent: Hash, para_id: ParaId)
|
pub fn validation_params<P>(api: &P, relay_parent: Hash, para_id: ParaId)
|
||||||
-> Result<(LocalValidationData, GlobalValidationSchedule, ValidationCode), Error>
|
-> Result<(LocalValidationData, GlobalValidationData, ValidationCode), Error>
|
||||||
where
|
where
|
||||||
P: ProvideRuntimeApi<Block>,
|
P: ProvideRuntimeApi<Block>,
|
||||||
P::Api: ParachainHost<Block, Error = sp_blockchain::Error>,
|
P::Api: ParachainHost<Block, Error = sp_blockchain::Error>,
|
||||||
@@ -261,7 +261,7 @@ where
|
|||||||
let local_validation = api.local_validation_data(&relay_parent, para_id)?
|
let local_validation = api.local_validation_data(&relay_parent, para_id)?
|
||||||
.ok_or_else(|| Error::InactiveParachain(para_id))?;
|
.ok_or_else(|| Error::InactiveParachain(para_id))?;
|
||||||
|
|
||||||
let global_validation = api.global_validation_schedule(&relay_parent)?;
|
let global_validation = api.global_validation_data(&relay_parent)?;
|
||||||
let validation_code = api.parachain_code(&relay_parent, para_id)?
|
let validation_code = api.parachain_code(&relay_parent, para_id)?
|
||||||
.ok_or_else(|| Error::InactiveParachain(para_id))?;
|
.ok_or_else(|| Error::InactiveParachain(para_id))?;
|
||||||
|
|
||||||
|
|||||||
@@ -547,7 +547,7 @@ mod tests {
|
|||||||
use availability_store::ErasureNetworking;
|
use availability_store::ErasureNetworking;
|
||||||
use polkadot_primitives::v0::{
|
use polkadot_primitives::v0::{
|
||||||
PoVBlock, AbridgedCandidateReceipt, ErasureChunk, ValidatorIndex,
|
PoVBlock, AbridgedCandidateReceipt, ErasureChunk, ValidatorIndex,
|
||||||
CollationInfo, DutyRoster, GlobalValidationSchedule, LocalValidationData,
|
CollationInfo, DutyRoster, GlobalValidationData, LocalValidationData,
|
||||||
Retriable, CollatorId, BlockData, Chain, AvailableData, SigningContext, ValidationCode,
|
Retriable, CollatorId, BlockData, Chain, AvailableData, SigningContext, ValidationCode,
|
||||||
};
|
};
|
||||||
use runtime_primitives::traits::Block as BlockT;
|
use runtime_primitives::traits::Block as BlockT;
|
||||||
@@ -697,7 +697,7 @@ mod tests {
|
|||||||
fn validators(&self) -> Vec<ValidatorId> { self.validators.clone() }
|
fn validators(&self) -> Vec<ValidatorId> { self.validators.clone() }
|
||||||
fn duty_roster(&self) -> DutyRoster { self.duty_roster.clone() }
|
fn duty_roster(&self) -> DutyRoster { self.duty_roster.clone() }
|
||||||
fn active_parachains() -> Vec<(ParaId, Option<(CollatorId, Retriable)>)> { vec![(ParaId::from(1), None)] }
|
fn active_parachains() -> Vec<(ParaId, Option<(CollatorId, Retriable)>)> { vec![(ParaId::from(1), None)] }
|
||||||
fn global_validation_schedule() -> GlobalValidationSchedule { Default::default() }
|
fn global_validation_data() -> GlobalValidationData { Default::default() }
|
||||||
fn local_validation_data(_: ParaId) -> Option<LocalValidationData> { None }
|
fn local_validation_data(_: ParaId) -> Option<LocalValidationData> { None }
|
||||||
fn parachain_code(_: ParaId) -> Option<ValidationCode> { None }
|
fn parachain_code(_: ParaId) -> Option<ValidationCode> { None }
|
||||||
fn get_heads(_: Vec<<Block as BlockT>::Extrinsic>) -> Option<Vec<AbridgedCandidateReceipt>> {
|
fn get_heads(_: Vec<<Block as BlockT>::Extrinsic>) -> Option<Vec<AbridgedCandidateReceipt>> {
|
||||||
|
|||||||
Reference in New Issue
Block a user