From 09f602f8dedbdb47a8a4f198b5ec2f3dc8e5ad52 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Thu, 23 Jul 2020 15:02:24 -0400 Subject: [PATCH] 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 --- polkadot/collator/src/lib.rs | 10 +- polkadot/network/src/protocol/tests.rs | 4 +- polkadot/node/core/backing/src/lib.rs | 20 +- polkadot/node/primitives/src/lib.rs | 4 +- .../adder/collator/src/main.rs | 4 +- polkadot/primitives/src/v0.rs | 8 +- polkadot/primitives/src/v1.rs | 61 +++- .../src/runtime-api/README.md | 4 +- .../src/runtime/configuration.md | 3 + .../src/runtime/inclusion.md | 1 + .../implementers-guide/src/runtime/paras.md | 1 + .../src/types/availability.md | 4 +- .../implementers-guide/src/types/candidate.md | 19 +- .../src/types/overseer-protocol.md | 2 +- polkadot/runtime/common/src/parachains.rs | 12 +- polkadot/runtime/common/src/registrar.rs | 2 +- polkadot/runtime/kusama/src/lib.rs | 6 +- .../runtime/parachains/src/configuration.rs | 13 +- polkadot/runtime/parachains/src/inclusion.rs | 316 ++++++++++++++---- polkadot/runtime/parachains/src/paras.rs | 35 +- .../parachains/src/runtime_api_impl/v1.rs | 50 +-- polkadot/runtime/polkadot/src/lib.rs | 6 +- polkadot/runtime/test-runtime/src/lib.rs | 4 +- polkadot/runtime/westend/src/lib.rs | 6 +- polkadot/validation/src/pipeline.rs | 10 +- .../validation/src/validation_service/mod.rs | 4 +- 26 files changed, 434 insertions(+), 175 deletions(-) diff --git a/polkadot/collator/src/lib.rs b/polkadot/collator/src/lib.rs index 2e2b330b0c..0b7419c29f 100644 --- a/polkadot/collator/src/lib.rs +++ b/polkadot/collator/src/lib.rs @@ -58,7 +58,7 @@ use sp_core::Pair; use polkadot_primitives::v0::{ BlockId, Hash, Block, DownwardMessage, BlockData, DutyRoster, HeadData, Id as ParaId, - PoVBlock, ValidatorId, CollatorPair, LocalValidationData, GlobalValidationSchedule, + PoVBlock, ValidatorId, CollatorPair, LocalValidationData, GlobalValidationData, Collation, CollationInfo, collator_signature_payload, }; use polkadot_cli::{ @@ -148,7 +148,7 @@ pub trait ParachainContext: Clone { fn produce_candidate( &mut self, relay_parent: Hash, - global_validation: GlobalValidationSchedule, + global_validation: GlobalValidationData, local_validation: LocalValidationData, downward_messages: Vec, ) -> Self::ProduceCandidate; @@ -158,7 +158,7 @@ pub trait ParachainContext: Clone { pub async fn collate

( relay_parent: Hash, local_id: ParaId, - global_validation: GlobalValidationSchedule, + global_validation: GlobalValidationData, local_validation_data: LocalValidationData, downward_messages: Vec, mut para_context: P, @@ -315,7 +315,7 @@ fn build_collator_service( let work = future::lazy(move |_| { 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)) { Some(local_validation) => local_validation, None => return future::Either::Left(future::ok(())), @@ -477,7 +477,7 @@ mod tests { fn produce_candidate( &mut self, _relay_parent: Hash, - _global: GlobalValidationSchedule, + _global: GlobalValidationData, _local_validation: LocalValidationData, _: Vec, ) -> Self::ProduceCandidate { diff --git a/polkadot/network/src/protocol/tests.rs b/polkadot/network/src/protocol/tests.rs index 711906797b..4e7027963c 100644 --- a/polkadot/network/src/protocol/tests.rs +++ b/polkadot/network/src/protocol/tests.rs @@ -21,7 +21,7 @@ use polkadot_primitives::v0::{ Block, Id as ParaId, Chain, DutyRoster, ParachainHost, ValidatorId, Retriable, CollatorId, AbridgedCandidateReceipt, - GlobalValidationSchedule, LocalValidationData, ErasureChunk, SigningContext, + GlobalValidationData, LocalValidationData, ErasureChunk, SigningContext, PoVBlock, BlockData, ValidationCode, }; use polkadot_validation::{SharedTable, TableRouter}; @@ -180,7 +180,7 @@ sp_api::mock_impl_runtime_apis! { Some(ValidationCode(Vec::new())) } - fn global_validation_schedule() -> GlobalValidationSchedule { + fn global_validation_data() -> GlobalValidationData { Default::default() } diff --git a/polkadot/node/core/backing/src/lib.rs b/polkadot/node/core/backing/src/lib.rs index 3d5440968d..4647526fef 100644 --- a/polkadot/node/core/backing/src/lib.rs +++ b/polkadot/node/core/backing/src/lib.rs @@ -606,7 +606,7 @@ impl CandidateBackingJob { with_commitments: impl FnOnce(CandidateCommitments) -> Result, ) -> Result, Error> { let omitted_validation = OmittedValidationData { - global_validation: outputs.global_validation_schedule, + global_validation: outputs.global_validation_data, local_validation: outputs.local_validation_data, }; @@ -773,7 +773,7 @@ mod tests { use futures::{executor, future, Future}; use polkadot_primitives::v1::{ AssignmentKind, BlockData, CandidateCommitments, CollatorId, CoreAssignment, CoreIndex, - LocalValidationData, GlobalValidationSchedule, GroupIndex, HeadData, + LocalValidationData, GlobalValidationData, GroupIndex, HeadData, ValidatorPair, ValidityAttestation, }; use polkadot_subsystem::{ @@ -792,7 +792,7 @@ mod tests { keystore: KeyStorePtr, validators: Vec, validator_public: Vec, - global_validation_schedule: GlobalValidationSchedule, + global_validation_data: GlobalValidationData, local_validation_data: LocalValidationData, roster: SchedulerRoster, head_data: HashMap, @@ -877,7 +877,7 @@ mod tests { validation_code_hash: Default::default(), }; - let global_validation_schedule = GlobalValidationSchedule { + let global_validation_data = GlobalValidationData { max_code_size: 1000, max_head_data_size: 1000, block_number: Default::default(), @@ -891,7 +891,7 @@ mod tests { roster, head_data, local_validation_data, - global_validation_schedule, + global_validation_data, signing_context, relay_parent, } @@ -921,7 +921,7 @@ mod tests { fn make_erasure_root(test: &TestState, pov: PoV) -> Hash { 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(), }; @@ -1048,7 +1048,7 @@ mod tests { ) if pov == pov && &c == candidate.descriptor() => { tx.send(Ok( 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, head_data: expected_head_data.clone(), upward_messages: Vec::new(), @@ -1160,7 +1160,7 @@ mod tests { ) if pov == pov && &c == candidate_a.descriptor() => { tx.send(Ok( 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, head_data: expected_head_data.clone(), upward_messages: Vec::new(), @@ -1281,7 +1281,7 @@ mod tests { ) if pov == pov && &c == candidate_a.descriptor() => { tx.send(Ok( 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, head_data: expected_head_data.clone(), upward_messages: Vec::new(), @@ -1438,7 +1438,7 @@ mod tests { ) if pov == pov && &c == candidate_b.descriptor() => { tx.send(Ok( 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, head_data: expected_head_data.clone(), upward_messages: Vec::new(), diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index 6630199ae5..5064a85158 100644 --- a/polkadot/node/primitives/src/lib.rs +++ b/polkadot/node/primitives/src/lib.rs @@ -24,7 +24,7 @@ use parity_scale_codec::{Decode, Encode}; use polkadot_primitives::v1::{ Hash, CommittedCandidateReceipt, CandidateReceipt, CompactStatement, EncodeAs, Signed, SigningContext, ValidatorIndex, ValidatorId, - UpwardMessage, Balance, ValidationCode, GlobalValidationSchedule, LocalValidationData, + UpwardMessage, Balance, ValidationCode, GlobalValidationData, LocalValidationData, HeadData, }; use polkadot_statement_table::{ @@ -118,7 +118,7 @@ pub struct ValidationOutputs { /// The head-data produced by validation. pub head_data: HeadData, /// The global validation schedule. - pub global_validation_schedule: GlobalValidationSchedule, + pub global_validation_data: GlobalValidationData, /// The local validation data. pub local_validation_data: LocalValidationData, /// Upward messages to the relay chain. diff --git a/polkadot/parachain/test-parachains/adder/collator/src/main.rs b/polkadot/parachain/test-parachains/adder/collator/src/main.rs index ec5b626883..a5d3bb6dc1 100644 --- a/polkadot/parachain/test-parachains/adder/collator/src/main.rs +++ b/polkadot/parachain/test-parachains/adder/collator/src/main.rs @@ -24,7 +24,7 @@ use sp_core::Pair; use codec::{Encode, Decode}; use primitives::v0::{ Hash, DownwardMessage, - HeadData, BlockData, Id as ParaId, LocalValidationData, GlobalValidationSchedule, + HeadData, BlockData, Id as ParaId, LocalValidationData, GlobalValidationData, }; use collator::{ParachainContext, Network, BuildParachainContext, Cli, SubstrateCli}; use parking_lot::Mutex; @@ -58,7 +58,7 @@ impl ParachainContext for AdderContext { fn produce_candidate( &mut self, _relay_parent: Hash, - _global_validation: GlobalValidationSchedule, + _global_validation: GlobalValidationData, local_validation: LocalValidationData, _: Vec, ) -> Self::ProduceCandidate diff --git a/polkadot/primitives/src/v0.rs b/polkadot/primitives/src/v0.rs index e1ec3a5546..3fcb31193a 100644 --- a/polkadot/primitives/src/v0.rs +++ b/polkadot/primitives/src/v0.rs @@ -179,7 +179,7 @@ pub struct DutyRoster { /// These are global parameters that apply to all parachain candidates in a block. #[derive(PartialEq, Eq, Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug, Default))] -pub struct GlobalValidationSchedule { +pub struct GlobalValidationData { /// The maximum code size permitted, in bytes. pub max_code_size: u32, /// The maximum head-data size permitted, in bytes. @@ -278,7 +278,7 @@ pub struct CandidateReceipt { /// The hash of the PoV-block. pub pov_block_hash: H, /// The global validation schedule. - pub global_validation: GlobalValidationSchedule, + pub global_validation: GlobalValidationData, /// The local validation data. pub local_validation: LocalValidationData, /// Commitments made as a result of validation. @@ -352,7 +352,7 @@ impl Ord for CandidateReceipt { #[cfg_attr(feature = "std", derive(Debug, Default))] pub struct OmittedValidationData { /// The global validation schedule. - pub global_validation: GlobalValidationSchedule, + pub global_validation: GlobalValidationData, /// The local validation data. pub local_validation: LocalValidationData, } @@ -762,7 +762,7 @@ sp_api::decl_runtime_apis! { fn active_parachains() -> Vec<(Id, Option<(CollatorId, Retriable)>)>; /// Get the global validation schedule that all parachains should /// be validated under. - fn global_validation_schedule() -> GlobalValidationSchedule; + fn global_validation_data() -> GlobalValidationData; /// Get the local validation data for a particular parachain. fn local_validation_data(id: Id) -> Option; /// Get the given parachain's head code blob. diff --git a/polkadot/primitives/src/v1.rs b/polkadot/primitives/src/v1.rs index 796dd4fb31..5d523fd300 100644 --- a/polkadot/primitives/src/v1.rs +++ b/polkadot/primitives/src/v1.rs @@ -60,14 +60,16 @@ pub const INCLUSION_INHERENT_IDENTIFIER: InherentIdentifier = *b"inclusn0"; pub fn collator_signature_payload>( relay_parent: &H, para_id: &Id, + validation_data_hash: &Hash, pov_hash: &Hash, -) -> [u8; 68] { +) -> [u8; 100] { // 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()); 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 } @@ -75,11 +77,18 @@ pub fn collator_signature_payload>( fn check_collator_signature>( relay_parent: &H, para_id: &Id, + validation_data_hash: &Hash, pov_hash: &Hash, collator: &CollatorId, signature: &CollatorSignature, ) -> 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) { Ok(()) } else { @@ -87,6 +96,14 @@ fn check_collator_signature>( } } +/// Compute the `validation_data_hash` from global & local validation data. +pub fn validation_data_hash( + global: &GlobalValidationData, + local: &LocalValidationData, +) -> Hash { + BlakeTwo256::hash_of(&(global, local)) +} + /// A unique descriptor of the candidate receipt. #[derive(PartialEq, Eq, Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug, Default))] @@ -97,11 +114,16 @@ pub struct CandidateDescriptor { pub relay_parent: H, /// The collator's sr25519 public key. pub collator: CollatorId, - /// Signature on blake2-256 of components of this receipt: - /// The parachain index, the relay parent, and the pov_hash. - pub signature: CollatorSignature, + /// The blake2-256 hash of the validation data. This is extra data derived from + /// relay-chain state which may vary based on bitfields included before the candidate. + /// Thus it cannot be derived entirely from the relay-parent. + pub validation_data_hash: Hash, /// The blake2-256 hash of the pov. 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> CandidateDescriptor { @@ -110,6 +132,7 @@ impl> CandidateDescriptor { check_collator_signature( &self.relay_parent, &self.para_id, + &self.validation_data_hash, &self.pov_hash, &self.collator, &self.signature, @@ -146,7 +169,7 @@ pub struct FullCandidateReceipt { /// The inner candidate receipt. pub inner: CandidateReceipt, /// The global validation schedule. - pub global_validation: GlobalValidationSchedule, + pub global_validation: GlobalValidationData, /// The local validation data. pub local_validation: LocalValidationData, } @@ -232,7 +255,7 @@ pub struct LocalValidationData { /// These are global parameters that apply to all candidates in a block. #[derive(PartialEq, Eq, Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug, Default))] -pub struct GlobalValidationSchedule { +pub struct GlobalValidationData { /// The maximum code size permitted, in bytes. pub max_code_size: u32, /// The maximum head-data size permitted, in bytes. @@ -465,7 +488,7 @@ impl CoreAssignment { #[cfg_attr(feature = "std", derive(PartialEq, Debug))] pub struct OmittedValidationData { /// The global validation schedule. - pub global_validation: GlobalValidationSchedule, + pub global_validation: GlobalValidationData, /// The local validation data. pub local_validation: LocalValidationData, } @@ -636,9 +659,9 @@ sp_api::decl_runtime_apis! { /// cores can have paras assigned to them. fn availability_cores() -> Vec>; - /// 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. - fn global_validation_schedule() -> GlobalValidationSchedule; + fn global_validation_data() -> GlobalValidationData; /// Yields the LocalValidationData for the given ParaId along with an assumption that /// 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.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]), + ); + } } diff --git a/polkadot/roadmap/implementers-guide/src/runtime-api/README.md b/polkadot/roadmap/implementers-guide/src/runtime-api/README.md index 4f36ac5d10..cb8998230d 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime-api/README.md +++ b/polkadot/roadmap/implementers-guide/src/runtime-api/README.md @@ -137,10 +137,10 @@ enum CoreState { ## 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 -fn global_validation_schedule(at: Block) -> GlobalValidationSchedule; +fn global_validation_data(at: Block) -> GlobalValidationData; ``` ## Local Validation Data diff --git a/polkadot/roadmap/implementers-guide/src/runtime/configuration.md b/polkadot/roadmap/implementers-guide/src/runtime/configuration.md index 37e5202429..f1ed5eb508 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/configuration.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/configuration.md @@ -35,6 +35,9 @@ fn update_configuration(f: impl FnOnce(&mut HostConfiguration)) { *pending = Some(x); }) } + +/// Get the GlobalValidationData, assuming the context is the parent block. +fn global_validation_data() -> GlobalValidationData; ``` ## Entry-points diff --git a/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md b/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md index 2387a9244a..e961b78bed 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md @@ -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 `scheduled` is sorted ascending by `CoreIndex`, without duplicates. 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. 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. diff --git a/polkadot/roadmap/implementers-guide/src/runtime/paras.md b/polkadot/roadmap/implementers-guide/src/runtime/paras.md index e80c2d102d..97c49ae167 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/paras.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/paras.md @@ -112,6 +112,7 @@ OutgoingParas: Vec; * `is_parathread(ParaId) -> bool`: Returns true if the para ID references any live parathread. * `last_code_upgrade(id: ParaId, include_future: bool) -> Option`: 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`: Get the LocalValidationData of the given para, assuming the context is the parent block. Returns `None` if the para is not known. ## Finalization diff --git a/polkadot/roadmap/implementers-guide/src/types/availability.md b/polkadot/roadmap/implementers-guide/src/types/availability.md index be42c7a927..3afa8d8df5 100644 --- a/polkadot/roadmap/implementers-guide/src/types/availability.md +++ b/polkadot/roadmap/implementers-guide/src/types/availability.md @@ -26,12 +26,12 @@ struct PoV(Vec); 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 struct OmittedValidationData { /// The global validation schedule. - global_validation: GlobalValidationSchedule, + global_validation: GlobalValidationData, /// The local validation data. local_validation: LocalValidationData, } diff --git a/polkadot/roadmap/implementers-guide/src/types/candidate.md b/polkadot/roadmap/implementers-guide/src/types/candidate.md index 0002851cee..dd69b23380 100644 --- a/polkadot/roadmap/implementers-guide/src/types/candidate.md +++ b/polkadot/roadmap/implementers-guide/src/types/candidate.md @@ -33,7 +33,7 @@ struct CandidateReceipt { ## 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. @@ -42,7 +42,7 @@ However, the Full Candidate Receipt type is useful as a means of avoiding the im struct FullCandidateReceipt { inner: CandidateReceipt, /// The global validation schedule. - global_validation: GlobalValidationSchedule, + global_validation: GlobalValidationData, /// The local validation data. local_validation: LocalValidationData, } @@ -77,16 +77,19 @@ struct CandidateDescriptor { relay_parent: Hash, /// The collator's sr25519 public key. collator: CollatorId, - /// Signature on blake2-256 of components of this receipt: - /// The parachain index, the relay parent, and the pov_hash. - signature: CollatorSignature, + /// The blake2-256 hash of the validation data. These are extra parameters + /// derived from relay-chain state that influence the validity of the block. + validation_data_hash: Hash, /// The blake2-256 hash of the pov-block. 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. @@ -95,7 +98,7 @@ The global validation schedule comprises of information describing the global en /// to fully validate the candidate. /// /// These are global parameters that apply to all candidates in a block. -struct GlobalValidationSchedule { +struct GlobalValidationData { /// The maximum code size permitted, in bytes. max_code_size: u32, /// The maximum head-data size permitted, in bytes. @@ -197,7 +200,7 @@ struct ValidationOutputs { /// The head-data produced by validation. head_data: HeadData, /// The global validation schedule. - global_validation_schedule: GlobalValidationSchedule, + global_validation_data: GlobalValidationData, /// The local validation data. local_validation_data: LocalValidationData, /// Upwards messages to the relay chain. diff --git a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md index f6ff4213fd..d777460176 100644 --- a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md +++ b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md @@ -255,7 +255,7 @@ enum RuntimeApiRequest { /// Get the validation code for a specific para, using the given occupied core assumption. ValidationCode(ParaId, OccupiedCoreAssumption, ResponseChannel>), /// Get the global validation schedule at the state of a given block. - GlobalValidationSchedule(ResponseChannel), + GlobalValidationData(ResponseChannel), /// Get the local validation data for a specific para, with the given occupied core assumption. LocalValidationData( ParaId, diff --git a/polkadot/runtime/common/src/parachains.rs b/polkadot/runtime/common/src/parachains.rs index 2df3669ded..a5d81989aa 100644 --- a/polkadot/runtime/common/src/parachains.rs +++ b/polkadot/runtime/common/src/parachains.rs @@ -41,7 +41,7 @@ use primitives::v0::{ Balance, BlockNumber, Id as ParaId, Chain, DutyRoster, AttestedCandidate, CompactStatement as Statement, ParachainDispatchOrigin, UpwardMessage, ValidatorId, ActiveParas, CollatorId, Retriable, OmittedValidationData, - CandidateReceipt, GlobalValidationSchedule, AbridgedCandidateReceipt, + CandidateReceipt, GlobalValidationData, AbridgedCandidateReceipt, LocalValidationData, Scheduling, ValidityAttestation, NEW_HEADS_IDENTIFIER, PARACHAIN_KEY_TYPE_ID, ValidatorSignature, SigningContext, HeadData, ValidationCode, Remark, DownwardMessage @@ -601,7 +601,7 @@ decl_module! { 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() { // perform integrity checks before writing to storage. @@ -1168,9 +1168,9 @@ impl Module { } /// Get the global validation schedule for all parachains. - pub fn global_validation_schedule() -> GlobalValidationSchedule { + pub fn global_validation_data() -> GlobalValidationData { let now = >::block_number(); - GlobalValidationSchedule { + GlobalValidationData { max_code_size: T::MaxCodeSize::get(), max_head_data_size: T::MaxHeadDataSize::get(), block_number: T::BlockNumberConversion::convert(if now.is_zero() { @@ -1322,7 +1322,7 @@ impl Module { // check the attestations on these candidates. The candidates should have been checked // that each candidates' chain ID is valid. fn check_candidates( - schedule: &GlobalValidationSchedule, + schedule: &GlobalValidationData, attested_candidates: &[AttestedCandidate], active_parachains: &[(ParaId, Option<(CollatorId, Retriable)>)] ) -> sp_std::result::Result, sp_runtime::DispatchError> { @@ -2157,7 +2157,7 @@ mod tests { collator: Default::default(), signature: 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(), commitments: CandidateCommitments::default(), } diff --git a/polkadot/runtime/common/src/registrar.rs b/polkadot/runtime/common/src/registrar.rs index e3b6d5ec12..5493d20839 100644 --- a/polkadot/runtime/common/src/registrar.rs +++ b/polkadot/runtime/common/src/registrar.rs @@ -1070,7 +1070,7 @@ mod tests { collator: collator.public(), signature: pov_block_hash.using_encoded(|d| collator.sign(d)), pov_block_hash, - global_validation: Parachains::global_validation_schedule(), + global_validation: Parachains::global_validation_data(), local_validation: Parachains::current_local_validation_data(&id).unwrap(), commitments: CandidateCommitments { fees: 0, diff --git a/polkadot/runtime/kusama/src/lib.rs b/polkadot/runtime/kusama/src/lib.rs index 7354feb6dd..3e921b433b 100644 --- a/polkadot/runtime/kusama/src/lib.rs +++ b/polkadot/runtime/kusama/src/lib.rs @@ -87,7 +87,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("kusama"), impl_name: create_runtime_str!("parity-kusama"), authoring_version: 2, - spec_version: 2019, + spec_version: 2020, impl_version: 0, #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, @@ -1115,8 +1115,8 @@ sp_api::impl_runtime_apis! { fn active_parachains() -> Vec<(parachain::Id, Option<(parachain::CollatorId, parachain::Retriable)>)> { Registrar::active_paras() } - fn global_validation_schedule() -> parachain::GlobalValidationSchedule { - Parachains::global_validation_schedule() + fn global_validation_data() -> parachain::GlobalValidationData { + Parachains::global_validation_data() } fn local_validation_data(id: parachain::Id) -> Option { Parachains::current_local_validation_data(&id) diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index b977bc119b..6fc9dd4230 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -19,12 +19,13 @@ //! Configuration can change only at session boundaries and is buffered until then. use sp_std::prelude::*; -use primitives::v1::ValidatorId; +use primitives::v1::{ValidatorId, GlobalValidationData}; use frame_support::{ decl_storage, decl_module, decl_error, dispatch::DispatchResult, weights::{DispatchClass, Weight}, }; +use sp_runtime::traits::One; use codec::{Encode, Decode}; use system::ensure_root; @@ -219,6 +220,16 @@ impl Module { ::PendingConfig::set(Some(prev)); } } + + /// Computes the global validation-data, assuming the context of the parent block. + pub(crate) fn global_validation_data() -> GlobalValidationData { + let config = Self::config(); + GlobalValidationData { + max_code_size: config.max_code_size, + max_head_data_size: config.max_head_data_size, + block_number: >::block_number() - One::one(), + } + } } #[cfg(test)] diff --git a/polkadot/runtime/parachains/src/inclusion.rs b/polkadot/runtime/parachains/src/inclusion.rs index 435342cfb8..e6f5ff1a0a 100644 --- a/polkadot/runtime/parachains/src/inclusion.rs +++ b/polkadot/runtime/parachains/src/inclusion.rs @@ -22,6 +22,7 @@ use sp_std::prelude::*; use primitives::v1::{ + validation_data_hash, ValidatorId, CandidateCommitments, CandidateDescriptor, ValidatorIndex, Id as ParaId, AvailabilityBitfield as AvailabilityBitfield, SignedAvailabilityBitfields, SigningContext, BackedCandidate, CoreIndex, GroupIndex, CoreAssignment, CommittedCandidateReceipt, @@ -145,6 +146,8 @@ decl_error! { InvalidBacking, /// Collator did not sign PoV. NotCollatorSigned, + /// The validation data hash does not match expected. + ValidationDataHashMismatch, /// Internal error only returned when compiled with debug assertions. InternalError, } @@ -399,14 +402,21 @@ impl Module { Error::::CandidateNotInParentContext, ); - let code_upgrade_allowed = >::last_code_upgrade(para_id, true) - .map_or( - true, - |last| last <= relay_parent_number && - relay_parent_number.saturating_sub(last) >= config.validation_upgrade_frequency, - ); + // if any, the code upgrade attempt is allowed. + let valid_upgrade_attempt = + candidate.candidate.commitments.new_validation_code.is_none() || + >::last_code_upgrade(para_id, true) + .map_or( + true, + |last| last <= relay_parent_number && + relay_parent_number.saturating_sub(last) + >= config.validation_upgrade_frequency, + ); - ensure!(code_upgrade_allowed, Error::::PrematureCodeUpgrade); + ensure!( + valid_upgrade_attempt, + Error::::PrematureCodeUpgrade, + ); ensure!( candidate.descriptor().check_collator_signature().is_ok(), Error::::NotCollatorSigned, @@ -423,6 +433,32 @@ impl Module { ); } + { + // this should never fail because the para is registered + let (global_validation_data, local_validation_data) = ( + >::global_validation_data(), + match >::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::::ValidationDataHashMismatch, + ); + } + ensure!( >::get(¶_id).is_none() && ::get(¶_id).is_none(), @@ -686,6 +722,7 @@ mod tests { let payload = primitives::v1::collator_signature_payload( &candidate.descriptor.relay_parent, &candidate.descriptor.para_id, + &candidate.descriptor.validation_data_hash, &candidate.descriptor.pov_hash, ); @@ -814,6 +851,7 @@ mod tests { head_data: HeadData, pov_hash: Hash, relay_parent: Hash, + validation_data_hash: Hash, new_validation_code: Option, } @@ -824,6 +862,7 @@ mod tests { para_id: self.para_id, pov_hash: self.pov_hash, relay_parent: self.relay_parent, + validation_data_hash: self.validation_data_hash, ..Default::default() }, commitments: CandidateCommitments { @@ -835,6 +874,12 @@ mod tests { } } + fn make_vdata_hash(para_id: ParaId) -> Option { + 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] fn collect_pending_cleans_up_pending() { let chain_a = ParaId::from(1); @@ -1261,6 +1306,7 @@ mod tests { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::from([1; 32]), + validation_data_hash: make_vdata_hash(chain_a).unwrap(), ..Default::default() }.build(); collator_sign_candidate( @@ -1276,11 +1322,14 @@ mod tests { BackingKind::Threshold, ); - assert!(Inclusion::process_candidates( - vec![backed], - vec![chain_b_assignment.clone()], - &group_validators, - ).is_err()); + assert_eq!( + Inclusion::process_candidates( + vec![backed], + vec![chain_b_assignment.clone()], + &group_validators, + ), + Err(Error::::UnscheduledCandidate.into()), + ); } // candidates out of order. @@ -1289,12 +1338,14 @@ mod tests { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::from([1; 32]), + validation_data_hash: make_vdata_hash(chain_a).unwrap(), ..Default::default() }.build(); let mut candidate_b = TestCandidateBuilder { para_id: chain_b, relay_parent: System::parent_hash(), pov_hash: Hash::from([2; 32]), + validation_data_hash: make_vdata_hash(chain_b).unwrap(), ..Default::default() }.build(); @@ -1324,11 +1375,15 @@ mod tests { BackingKind::Threshold, ); - assert!(Inclusion::process_candidates( - vec![backed_b, backed_a], - vec![chain_a_assignment.clone(), chain_b_assignment.clone()], - &group_validators, - ).is_err()); + // out-of-order manifests as unscheduled. + assert_eq!( + Inclusion::process_candidates( + vec![backed_b, backed_a], + vec![chain_a_assignment.clone(), chain_b_assignment.clone()], + &group_validators, + ), + Err(Error::::UnscheduledCandidate.into()), + ); } // candidate not backed. @@ -1337,6 +1392,7 @@ mod tests { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::from([1; 32]), + validation_data_hash: make_vdata_hash(chain_a).unwrap(), ..Default::default() }.build(); collator_sign_candidate( @@ -1352,11 +1408,14 @@ mod tests { BackingKind::Lacking, ); - assert!(Inclusion::process_candidates( - vec![backed], - vec![chain_a_assignment.clone()], - &group_validators, - ).is_err()); + assert_eq!( + Inclusion::process_candidates( + vec![backed], + vec![chain_a_assignment.clone()], + &group_validators, + ), + Err(Error::::InsufficientBacking.into()), + ); } // candidate not in parent context. @@ -1368,6 +1427,7 @@ mod tests { para_id: chain_a, relay_parent: wrong_parent_hash, pov_hash: Hash::from([1; 32]), + validation_data_hash: make_vdata_hash(chain_a).unwrap(), ..Default::default() }.build(); collator_sign_candidate( @@ -1383,11 +1443,14 @@ mod tests { BackingKind::Threshold, ); - assert!(Inclusion::process_candidates( - vec![backed], - vec![chain_a_assignment.clone()], - &group_validators, - ).is_err()); + assert_eq!( + Inclusion::process_candidates( + vec![backed], + vec![chain_a_assignment.clone()], + &group_validators, + ), + Err(Error::::CandidateNotInParentContext.into()), + ); } // candidate has wrong collator. @@ -1396,6 +1459,7 @@ mod tests { para_id: thread_a, relay_parent: System::parent_hash(), pov_hash: Hash::from([1; 32]), + validation_data_hash: make_vdata_hash(thread_a).unwrap(), ..Default::default() }.build(); @@ -1413,15 +1477,18 @@ mod tests { BackingKind::Threshold, ); - assert!(Inclusion::process_candidates( - vec![backed], - vec![ - chain_a_assignment.clone(), - chain_b_assignment.clone(), - thread_a_assignment.clone(), - ], - &group_validators, - ).is_err()); + assert_eq!( + Inclusion::process_candidates( + vec![backed], + vec![ + chain_a_assignment.clone(), + chain_b_assignment.clone(), + thread_a_assignment.clone(), + ], + &group_validators, + ), + Err(Error::::WrongCollator.into()), + ); } // candidate not well-signed by collator. @@ -1430,6 +1497,7 @@ mod tests { para_id: thread_a, relay_parent: System::parent_hash(), pov_hash: Hash::from([1; 32]), + validation_data_hash: make_vdata_hash(thread_a).unwrap(), ..Default::default() }.build(); @@ -1450,11 +1518,14 @@ mod tests { BackingKind::Threshold, ); - assert!(Inclusion::process_candidates( - vec![backed], - vec![thread_a_assignment.clone()], - &group_validators, - ).is_err()); + assert_eq!( + Inclusion::process_candidates( + vec![backed], + vec![thread_a_assignment.clone()], + &group_validators, + ), + Err(Error::::NotCollatorSigned.into()), + ); } // para occupied - reject. @@ -1463,6 +1534,7 @@ mod tests { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::from([1; 32]), + validation_data_hash: make_vdata_hash(chain_a).unwrap(), ..Default::default() }.build(); @@ -1489,11 +1561,14 @@ mod tests { }); ::insert(&chain_a, candidate.commitments); - assert!(Inclusion::process_candidates( - vec![backed], - vec![chain_a_assignment.clone()], - &group_validators, - ).is_err()); + assert_eq!( + Inclusion::process_candidates( + vec![backed], + vec![chain_a_assignment.clone()], + &group_validators, + ), + Err(Error::::CandidateScheduledBeforeParaFree.into()), + ); >::remove(&chain_a); ::remove(&chain_a); @@ -1505,6 +1580,7 @@ mod tests { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::from([1; 32]), + validation_data_hash: make_vdata_hash(chain_a).unwrap(), ..Default::default() }.build(); @@ -1524,11 +1600,14 @@ mod tests { BackingKind::Threshold, ); - assert!(Inclusion::process_candidates( - vec![backed], - vec![chain_a_assignment.clone()], - &group_validators, - ).is_err()); + assert_eq!( + Inclusion::process_candidates( + vec![backed], + vec![chain_a_assignment.clone()], + &group_validators, + ), + Err(Error::::CandidateScheduledBeforeParaFree.into()), + ); ::remove(&chain_a); } @@ -1540,6 +1619,7 @@ mod tests { relay_parent: System::parent_hash(), pov_hash: Hash::from([1; 32]), new_validation_code: Some(vec![5, 6, 7, 8].into()), + validation_data_hash: make_vdata_hash(chain_a).unwrap(), ..Default::default() }.build(); @@ -1564,11 +1644,47 @@ mod tests { assert_eq!(Paras::last_code_upgrade(chain_a, true), Some(10)); - assert!(Inclusion::process_candidates( - vec![backed], - vec![thread_a_assignment.clone()], - &group_validators, - ).is_err()); + assert_eq!( + Inclusion::process_candidates( + vec![backed], + vec![chain_a_assignment.clone()], + &group_validators, + ), + Err(Error::::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::::ValidationDataHashMismatch.into()), + ); } }); } @@ -1634,6 +1750,7 @@ mod tests { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::from([1; 32]), + validation_data_hash: make_vdata_hash(chain_a).unwrap(), ..Default::default() }.build(); collator_sign_candidate( @@ -1645,6 +1762,7 @@ mod tests { para_id: chain_b, relay_parent: System::parent_hash(), pov_hash: Hash::from([2; 32]), + validation_data_hash: make_vdata_hash(chain_b).unwrap(), ..Default::default() }.build(); collator_sign_candidate( @@ -1656,6 +1774,7 @@ mod tests { para_id: thread_a, relay_parent: System::parent_hash(), pov_hash: Hash::from([3; 32]), + validation_data_hash: make_vdata_hash(thread_a).unwrap(), ..Default::default() }.build(); 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!( + >::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!( + ::get(&chain_a), + Some(candidate_a.commitments), + ); + }); + } + #[test] fn session_change_wipes_and_updates_session_info() { let chain_a = ParaId::from(1); diff --git a/polkadot/runtime/parachains/src/paras.rs b/polkadot/runtime/parachains/src/paras.rs index 0117089f11..2eab9c0546 100644 --- a/polkadot/runtime/parachains/src/paras.rs +++ b/polkadot/runtime/parachains/src/paras.rs @@ -25,9 +25,9 @@ use sp_std::prelude::*; use sp_std::marker::PhantomData; -use sp_runtime::traits::One; +use sp_runtime::traits::{One, BlakeTwo256, Hash as HashT, Saturating}; use primitives::v1::{ - Id as ParaId, ValidationCode, HeadData, + Id as ParaId, ValidationCode, HeadData, LocalValidationData, }; use frame_support::{ decl_storage, decl_module, decl_error, @@ -536,6 +536,37 @@ impl Module { 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> { + let relay_parent_number = >::block_number() - One::one(); + + let config = >::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)] diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/v1.rs b/polkadot/runtime/parachains/src/runtime_api_impl/v1.rs index fa5026dbad..7f4a9093d4 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/v1.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/v1.rs @@ -18,12 +18,12 @@ //! functions. use primitives::v1::{ - ValidatorId, ValidatorIndex, GroupRotationInfo, CoreState, GlobalValidationSchedule, + ValidatorId, ValidatorIndex, GroupRotationInfo, CoreState, GlobalValidationData, Id as ParaId, OccupiedCoreAssumption, LocalValidationData, SessionIndex, ValidationCode, CommittedCandidateReceipt, ScheduledCore, OccupiedCore, CoreOccupied, CoreIndex, GroupIndex, CandidateEvent, }; -use sp_runtime::traits::{One, BlakeTwo256, Hash as HashT, Saturating, Zero}; +use sp_runtime::traits::Zero; use frame_support::debug; use crate::{initializer, inclusion, scheduler, configuration, paras}; @@ -160,16 +160,11 @@ pub fn availability_cores() -> Vec() - -> GlobalValidationSchedule +/// Implementation for the `global_validation_data` function of the runtime API. +pub fn global_validation_data() + -> GlobalValidationData { - let config = >::config(); - GlobalValidationSchedule { - max_code_size: config.max_code_size, - max_head_data_size: config.max_head_data_size, - block_number: >::block_number() - One::one(), - } + >::global_validation_data() } /// Implementation for the `local_validation_data` function of the runtime API. @@ -177,46 +172,19 @@ pub fn local_validation_data( para_id: ParaId, assumption: OccupiedCoreAssumption, ) -> Option> { - let construct = || { - let relay_parent_number = >::block_number() - One::one(); - - let config = >::config(); - let freq = config.validation_upgrade_frequency; - let delay = config.validation_upgrade_delay; - - let last_code_upgrade = >::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: >::para_head(¶_id)?, - balance: 0, - validation_code_hash: BlakeTwo256::hash_of( - &>::current_code(¶_id)? - ), - code_upgrade_allowed, - }) - }; - match assumption { OccupiedCoreAssumption::Included => { >::force_enact(para_id); - construct() + >::local_validation_data(para_id) } OccupiedCoreAssumption::TimedOut => { - construct() + >::local_validation_data(para_id) } OccupiedCoreAssumption::Free => { if >::pending_availability(para_id).is_some() { None } else { - construct() + >::local_validation_data(para_id) } } } diff --git a/polkadot/runtime/polkadot/src/lib.rs b/polkadot/runtime/polkadot/src/lib.rs index e7afcfe16b..f8d8cea3ab 100644 --- a/polkadot/runtime/polkadot/src/lib.rs +++ b/polkadot/runtime/polkadot/src/lib.rs @@ -86,7 +86,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("polkadot"), impl_name: create_runtime_str!("parity-polkadot"), authoring_version: 0, - spec_version: 19, + spec_version: 20, impl_version: 0, #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, @@ -1256,8 +1256,8 @@ sp_api::impl_runtime_apis! { fn active_parachains() -> Vec<(parachain::Id, Option<(parachain::CollatorId, parachain::Retriable)>)> { Registrar::active_paras() } - fn global_validation_schedule() -> parachain::GlobalValidationSchedule { - Parachains::global_validation_schedule() + fn global_validation_data() -> parachain::GlobalValidationData { + Parachains::global_validation_data() } fn local_validation_data(id: parachain::Id) -> Option { Parachains::current_local_validation_data(&id) diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 032efaacfb..65c92aae0c 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -676,8 +676,8 @@ sp_api::impl_runtime_apis! { fn active_parachains() -> Vec<(parachain::Id, Option<(parachain::CollatorId, parachain::Retriable)>)> { Registrar::active_paras() } - fn global_validation_schedule() -> parachain::GlobalValidationSchedule { - Parachains::global_validation_schedule() + fn global_validation_data() -> parachain::GlobalValidationData { + Parachains::global_validation_data() } fn local_validation_data(id: parachain::Id) -> Option { Parachains::current_local_validation_data(&id) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 6d7fdc79f0..f48ee40e53 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -83,7 +83,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westend"), impl_name: create_runtime_str!("parity-westend"), authoring_version: 2, - spec_version: 39, + spec_version: 40, impl_version: 0, #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, @@ -897,8 +897,8 @@ sp_api::impl_runtime_apis! { fn active_parachains() -> Vec<(parachain::Id, Option<(parachain::CollatorId, parachain::Retriable)>)> { Registrar::active_paras() } - fn global_validation_schedule() -> parachain::GlobalValidationSchedule { - Parachains::global_validation_schedule() + fn global_validation_data() -> parachain::GlobalValidationData { + Parachains::global_validation_data() } fn local_validation_data(id: parachain::Id) -> Option { Parachains::current_local_validation_data(&id) diff --git a/polkadot/validation/src/pipeline.rs b/polkadot/validation/src/pipeline.rs index f2a705ba10..663321480c 100644 --- a/polkadot/validation/src/pipeline.rs +++ b/polkadot/validation/src/pipeline.rs @@ -20,7 +20,7 @@ use codec::Encode; use polkadot_erasure_coding as erasure; use polkadot_primitives::v0::{ - CollationInfo, PoVBlock, LocalValidationData, GlobalValidationSchedule, OmittedValidationData, + CollationInfo, PoVBlock, LocalValidationData, GlobalValidationData, OmittedValidationData, AvailableData, FeeSchedule, CandidateCommitments, ErasureChunk, ParachainHost, Id as ParaId, AbridgedCandidateReceipt, ValidationCode, }; @@ -95,7 +95,7 @@ impl FullOutput { /// validation are needed, call `full_output`. Otherwise, safely drop this value. pub struct ValidatedCandidate<'a> { pov_block: &'a PoVBlock, - global_validation: &'a GlobalValidationSchedule, + global_validation: &'a GlobalValidationData, local_validation: &'a LocalValidationData, upward_messages: Vec, fees: Balance, @@ -189,7 +189,7 @@ pub fn validate<'a>( collation: &'a CollationInfo, pov_block: &'a PoVBlock, local_validation: &'a LocalValidationData, - global_validation: &'a GlobalValidationSchedule, + global_validation: &'a GlobalValidationData, validation_code: &ValidationCode, ) -> Result, Error> { 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. pub fn validation_params

(api: &P, relay_parent: Hash, para_id: ParaId) - -> Result<(LocalValidationData, GlobalValidationSchedule, ValidationCode), Error> + -> Result<(LocalValidationData, GlobalValidationData, ValidationCode), Error> where P: ProvideRuntimeApi, P::Api: ParachainHost, @@ -261,7 +261,7 @@ where let local_validation = api.local_validation_data(&relay_parent, 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)? .ok_or_else(|| Error::InactiveParachain(para_id))?; diff --git a/polkadot/validation/src/validation_service/mod.rs b/polkadot/validation/src/validation_service/mod.rs index 7f332f4c0d..11116fcaff 100644 --- a/polkadot/validation/src/validation_service/mod.rs +++ b/polkadot/validation/src/validation_service/mod.rs @@ -547,7 +547,7 @@ mod tests { use availability_store::ErasureNetworking; use polkadot_primitives::v0::{ PoVBlock, AbridgedCandidateReceipt, ErasureChunk, ValidatorIndex, - CollationInfo, DutyRoster, GlobalValidationSchedule, LocalValidationData, + CollationInfo, DutyRoster, GlobalValidationData, LocalValidationData, Retriable, CollatorId, BlockData, Chain, AvailableData, SigningContext, ValidationCode, }; use runtime_primitives::traits::Block as BlockT; @@ -697,7 +697,7 @@ mod tests { fn validators(&self) -> Vec { self.validators.clone() } fn duty_roster(&self) -> DutyRoster { self.duty_roster.clone() } 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 { None } fn parachain_code(_: ParaId) -> Option { None } fn get_heads(_: Vec<::Extrinsic>) -> Option> {