diff --git a/node/core/backing/src/lib.rs b/node/core/backing/src/lib.rs index 4a70555d08a2..e9a1afd5f8b5 100644 --- a/node/core/backing/src/lib.rs +++ b/node/core/backing/src/lib.rs @@ -772,7 +772,7 @@ async fn handle_active_leaves_update( state: &mut State, ) -> Result<(), Error> { enum LeafHasProspectiveParachains { - Enabled(Result, ImplicitViewFetchError>), + Enabled(Result), Disabled, } @@ -788,8 +788,8 @@ async fn handle_active_leaves_update( leaf, match mode { ProspectiveParachainsMode::Disabled => LeafHasProspectiveParachains::Disabled, - ProspectiveParachainsMode::Enabled => LeafHasProspectiveParachains::Enabled( - state.implicit_view.activate_leaf(ctx.sender(), leaf_hash).await, + ProspectiveParachainsMode::Enabled { .. } => LeafHasProspectiveParachains::Enabled( + state.implicit_view.activate_leaf(ctx.sender(), leaf_hash).await.map(|_| mode), ), }, )) @@ -824,7 +824,7 @@ async fn handle_active_leaves_update( // Get relay parents which might be fresh but might be known already // that are explicit or implicit from the new active leaf. - let fresh_relay_parents = match res { + let (fresh_relay_parents, leaf_mode) = match res { None => return Ok(()), Some((leaf, LeafHasProspectiveParachains::Disabled)) => { // defensive in this case - for enabled, this manifests as an error. @@ -844,9 +844,9 @@ async fn handle_active_leaves_update( }, ); - vec![leaf.hash] + (vec![leaf.hash], ProspectiveParachainsMode::Disabled) }, - Some((leaf, LeafHasProspectiveParachains::Enabled(Ok(_)))) => { + Some((leaf, LeafHasProspectiveParachains::Enabled(Ok(prospective_parachains_mode)))) => { let fresh_relay_parents = state.implicit_view.known_allowed_relay_parents_under(&leaf.hash, None); @@ -907,13 +907,10 @@ async fn handle_active_leaves_update( state.per_leaf.insert( leaf.hash, - ActiveLeafState { - prospective_parachains_mode: ProspectiveParachainsMode::Enabled, - seconded_at_depth, - }, + ActiveLeafState { prospective_parachains_mode, seconded_at_depth }, ); - match fresh_relay_parents { + let fresh_relay_parent = match fresh_relay_parents { Some(f) => f.to_vec(), None => { gum::warn!( @@ -924,7 +921,8 @@ async fn handle_active_leaves_update( vec![leaf.hash] }, - } + }; + (fresh_relay_parent, prospective_parachains_mode) }, Some((leaf, LeafHasProspectiveParachains::Enabled(Err(e)))) => { gum::debug!( @@ -951,7 +949,7 @@ async fn handle_active_leaves_update( // subsystem that it is an ancestor of a leaf which // has prospective parachains enabled and that the // block itself did. - ProspectiveParachainsMode::Enabled + leaf_mode }, Some(l) => l.prospective_parachains_mode, }; @@ -1061,7 +1059,7 @@ async fn construct_per_relay_parent_state( let table_context = TableContext { groups, validators, validator }; let table_config = TableConfig { allow_multiple_seconded: match mode { - ProspectiveParachainsMode::Enabled => true, + ProspectiveParachainsMode::Enabled { .. } => true, ProspectiveParachainsMode::Disabled => false, }, }; diff --git a/node/core/backing/src/tests/mod.rs b/node/core/backing/src/tests/mod.rs index dff05c7b76f0..4e6577fa0d7a 100644 --- a/node/core/backing/src/tests/mod.rs +++ b/node/core/backing/src/tests/mod.rs @@ -23,6 +23,7 @@ use assert_matches::assert_matches; use futures::{future, Future}; use polkadot_node_primitives::{BlockData, InvalidCandidate, SignedFullStatement, Statement}; use polkadot_node_subsystem::{ + errors::RuntimeApiError, jaeger, messages::{ AllMessages, CollatorProtocolMessage, RuntimeApiMessage, RuntimeApiRequest, @@ -44,7 +45,8 @@ use std::collections::HashMap; mod prospective_parachains; -const API_VERSION_PROSPECTIVE_DISABLED: u32 = 2; +const ASYNC_BACKING_DISABLED_ERROR: RuntimeApiError = + RuntimeApiError::NotSupported { runtime_api_name: "test-runtime" }; fn validator_pubkeys(val_ids: &[Sr25519Keyring]) -> Vec { val_ids.iter().map(|v| v.public().into()).collect() @@ -242,14 +244,12 @@ async fn test_startup(virtual_overseer: &mut VirtualOverseer, test_state: &TestS )))) .await; - // Prospective parachains mode is temporarily defined by the Runtime API version. - // Disable it for the test leaf. assert_matches!( virtual_overseer.recv().await, AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::Version(tx)) + RuntimeApiMessage::Request(parent, RuntimeApiRequest::StagingAsyncBackingParameters(tx)) ) if parent == test_state.relay_parent => { - tx.send(Ok(API_VERSION_PROSPECTIVE_DISABLED)).unwrap(); + tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)).unwrap(); } ); diff --git a/node/core/backing/src/tests/prospective_parachains.rs b/node/core/backing/src/tests/prospective_parachains.rs index 86ef1e069977..4d68fd99f798 100644 --- a/node/core/backing/src/tests/prospective_parachains.rs +++ b/node/core/backing/src/tests/prospective_parachains.rs @@ -17,11 +17,15 @@ //! Tests for the backing subsystem with enabled prospective parachains. use polkadot_node_subsystem::{messages::ChainApiMessage, TimeoutExt}; -use polkadot_primitives::v2::{BlockNumber, Header, OccupiedCore}; +use polkadot_primitives::{ + v2::{BlockNumber, Header, OccupiedCore}, + vstaging as vstaging_primitives, +}; use super::*; -const API_VERSION_PROSPECTIVE_ENABLED: u32 = RuntimeApiRequest::VALIDITY_CONSTRAINTS; +const ASYNC_BACKING_PARAMETERS: vstaging_primitives::AsyncBackingParameters = + vstaging_primitives::AsyncBackingParameters { max_candidate_depth: 4, allowed_ancestry_len: 3 }; struct TestLeaf { activated: ActivatedLeaf, @@ -52,9 +56,9 @@ async fn activate_leaf( assert_matches!( virtual_overseer.recv().await, AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::Version(tx)) + RuntimeApiMessage::Request(parent, RuntimeApiRequest::StagingAsyncBackingParameters(tx)) ) if parent == leaf_hash => { - tx.send(Ok(API_VERSION_PROSPECTIVE_ENABLED)).unwrap(); + tx.send(Ok(ASYNC_BACKING_PARAMETERS)).unwrap(); } ); diff --git a/node/core/prospective-parachains/src/lib.rs b/node/core/prospective-parachains/src/lib.rs index effa87c3e032..35a9422efc84 100644 --- a/node/core/prospective-parachains/src/lib.rs +++ b/node/core/prospective-parachains/src/lib.rs @@ -41,7 +41,7 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_util::{ inclusion_emulator::staging::{Constraints, RelayChainBlockInfo}, - runtime::prospective_parachains_mode, + runtime::{prospective_parachains_mode, ProspectiveParachainsMode}, }; use polkadot_primitives::vstaging::{ BlockNumber, CandidateHash, CommittedCandidateReceipt, CoreState, Hash, Id as ParaId, @@ -58,18 +58,6 @@ mod fragment_tree; const LOG_TARGET: &str = "parachain::prospective-parachains"; -// The maximum depth the subsystem will allow. 'depth' is defined as the -// amount of blocks between the para head in a relay-chain block's state -// and a candidate with a particular relay-parent. -// -// This value is chosen mostly for reasons of resource-limitation. -// Without it, a malicious validator group could create arbitrarily long, -// useless prospective parachains and DoS honest nodes. -const MAX_DEPTH: usize = 4; - -// The maximum ancestry we support. -const MAX_ANCESTRY: usize = 5; - struct RelayBlockViewData { // Scheduling info for paras and upcoming paras. fragment_trees: HashMap, @@ -171,7 +159,8 @@ async fn handle_active_leaves_update( let mode = prospective_parachains_mode(ctx.sender(), hash) .await .map_err(JfyiError::Runtime)?; - if !mode.is_enabled() { + + let ProspectiveParachainsMode::Enabled { max_candidate_depth, allowed_ancestry_len } = mode else { gum::trace!( target: LOG_TARGET, block_hash = ?hash, @@ -180,7 +169,7 @@ async fn handle_active_leaves_update( // Not a part of any allowed ancestry. return Ok(()) - } + }; let scheduled_paras = fetch_upcoming_paras(&mut *ctx, hash).await?; @@ -200,7 +189,7 @@ async fn handle_active_leaves_update( Some(info) => info, }; - let ancestry = fetch_ancestry(&mut *ctx, hash, MAX_ANCESTRY).await?; + let ancestry = fetch_ancestry(&mut *ctx, hash, allowed_ancestry_len).await?; // Find constraints. let mut fragment_trees = HashMap::new(); @@ -230,7 +219,7 @@ async fn handle_active_leaves_update( para, block_info.clone(), constraints, - MAX_DEPTH, + max_candidate_depth, ancestry.iter().cloned(), ) .expect("ancestors are provided in reverse order and correctly; qed"); @@ -627,6 +616,10 @@ async fn fetch_ancestry( relay_hash: Hash, ancestors: usize, ) -> JfyiErrorResult> { + if ancestors == 0 { + return Ok(Vec::new()) + } + let (tx, rx) = oneshot::channel(); ctx.send_message(ChainApiMessage::Ancestors { hash: relay_hash, diff --git a/node/core/provisioner/src/lib.rs b/node/core/provisioner/src/lib.rs index ce32f9a943f4..fbf78416cb70 100644 --- a/node/core/provisioner/src/lib.rs +++ b/node/core/provisioner/src/lib.rs @@ -692,7 +692,7 @@ async fn select_candidates( sender: &mut impl overseer::ProvisionerSenderTrait, ) -> Result, Error> { let selected_candidates = match prospective_parachains_mode { - ProspectiveParachainsMode::Enabled => + ProspectiveParachainsMode::Enabled { .. } => request_backable_candidates(availability_cores, bitfields, relay_parent, sender).await?, ProspectiveParachainsMode::Disabled => select_candidate_hashes_from_tracked( diff --git a/node/core/provisioner/src/tests.rs b/node/core/provisioner/src/tests.rs index 4b34905b77ca..b0c69b54f007 100644 --- a/node/core/provisioner/src/tests.rs +++ b/node/core/provisioner/src/tests.rs @@ -350,7 +350,7 @@ mod select_candidates { AllMessages::ProspectiveParachains( ProspectiveParachainsMessage::GetBackableCandidate(.., tx), ) => match prospective_parachains_mode { - ProspectiveParachainsMode::Enabled => { + ProspectiveParachainsMode::Enabled { .. } => { let _ = tx.send(candidates.next()); }, ProspectiveParachainsMode::Disabled => @@ -572,7 +572,8 @@ mod select_candidates { let expected_candidates: Vec<_> = [1, 4, 7, 8, 10].iter().map(|&idx| candidates[idx].clone()).collect(); // Expect prospective parachains subsystem requests. - let prospective_parachains_mode = ProspectiveParachainsMode::Enabled; + let prospective_parachains_mode = + ProspectiveParachainsMode::Enabled { max_candidate_depth: 0, allowed_ancestry_len: 0 }; let expected_backed = expected_candidates .iter() @@ -587,7 +588,16 @@ mod select_candidates { .collect(); test_harness( - |r| mock_overseer(r, expected_backed, ProspectiveParachainsMode::Enabled), + |r| { + mock_overseer( + r, + expected_backed, + ProspectiveParachainsMode::Enabled { + max_candidate_depth: 0, + allowed_ancestry_len: 0, + }, + ) + }, |mut tx: TestSubsystemSender| async move { let result = select_candidates( &mock_cores, diff --git a/node/core/runtime-api/src/cache.rs b/node/core/runtime-api/src/cache.rs index 651a921e6a5b..c7ac97e9449b 100644 --- a/node/core/runtime-api/src/cache.rs +++ b/node/core/runtime-api/src/cache.rs @@ -53,6 +53,7 @@ const VERSION_CACHE_SIZE: usize = 4 * 1024; const DISPUTES_CACHE_SIZE: usize = 64 * 1024; const STAGING_VALIDITY_CONSTRAINTS_CACHE_SIZE: usize = 10 * 1024; +const STAGING_ASYNC_BACKING_PARAMETERS_CACHE_SIZE: usize = 10 * 1024; struct ResidentSizeOf(T); @@ -120,15 +121,16 @@ pub(crate) struct RequestResultCache { (Hash, ParaId, OccupiedCoreAssumption), ResidentSizeOf>, >, - - staging_validity_constraints: - MemoryLruCache<(Hash, ParaId), ResidentSizeOf>>, - version: MemoryLruCache>, disputes: MemoryLruCache< Hash, ResidentSizeOf)>>, >, + + staging_validity_constraints: + MemoryLruCache<(Hash, ParaId), ResidentSizeOf>>, + staging_async_backing_parameters: + MemoryLruCache>, } impl Default for RequestResultCache { @@ -155,13 +157,15 @@ impl Default for RequestResultCache { on_chain_votes: MemoryLruCache::new(ON_CHAIN_VOTES_CACHE_SIZE), pvfs_require_precheck: MemoryLruCache::new(PVFS_REQUIRE_PRECHECK_SIZE), validation_code_hash: MemoryLruCache::new(VALIDATION_CODE_HASH_CACHE_SIZE), + version: MemoryLruCache::new(VERSION_CACHE_SIZE), + disputes: MemoryLruCache::new(DISPUTES_CACHE_SIZE), staging_validity_constraints: MemoryLruCache::new( STAGING_VALIDITY_CONSTRAINTS_CACHE_SIZE, ), - - version: MemoryLruCache::new(VERSION_CACHE_SIZE), - disputes: MemoryLruCache::new(DISPUTES_CACHE_SIZE), + staging_async_backing_parameters: MemoryLruCache::new( + STAGING_ASYNC_BACKING_PARAMETERS_CACHE_SIZE, + ), } } } @@ -420,21 +424,6 @@ impl RequestResultCache { self.validation_code_hash.insert(key, ResidentSizeOf(value)); } - pub(crate) fn staging_validity_constraints( - &mut self, - key: (Hash, ParaId), - ) -> Option<&Option> { - self.staging_validity_constraints.get(&key).map(|v| &v.0) - } - - pub(crate) fn cache_staging_validity_constraints( - &mut self, - key: (Hash, ParaId), - value: Option, - ) { - self.staging_validity_constraints.insert(key, ResidentSizeOf(value)); - } - pub(crate) fn version(&mut self, relay_parent: &Hash) -> Option<&u32> { self.version.get(&relay_parent).map(|v| &v.0) } @@ -457,6 +446,36 @@ impl RequestResultCache { ) { self.disputes.insert(relay_parent, ResidentSizeOf(value)); } + + pub(crate) fn staging_validity_constraints( + &mut self, + key: (Hash, ParaId), + ) -> Option<&Option> { + self.staging_validity_constraints.get(&key).map(|v| &v.0) + } + + pub(crate) fn cache_staging_validity_constraints( + &mut self, + key: (Hash, ParaId), + value: Option, + ) { + self.staging_validity_constraints.insert(key, ResidentSizeOf(value)); + } + + pub(crate) fn staging_async_backing_parameters( + &mut self, + key: &Hash, + ) -> Option<&vstaging_primitives::AsyncBackingParameters> { + self.staging_async_backing_parameters.get(&key).map(|v| &v.0) + } + + pub(crate) fn cache_staging_async_backing_parameters( + &mut self, + key: Hash, + value: vstaging_primitives::AsyncBackingParameters, + ) { + self.staging_async_backing_parameters.insert(key, ResidentSizeOf(value)); + } } pub(crate) enum RequestResult { @@ -491,9 +510,9 @@ pub(crate) enum RequestResult { // This is a request with side-effects and no result, hence (). SubmitPvfCheckStatement(Hash, PvfCheckStatement, ValidatorSignature, ()), ValidationCodeHash(Hash, ParaId, OccupiedCoreAssumption, Option), - - StagingValidityConstraints(Hash, ParaId, Option), - Version(Hash, u32), Disputes(Hash, Vec<(SessionIndex, CandidateHash, DisputeState)>), + + StagingValidityConstraints(Hash, ParaId, Option), + StagingAsyncBackingParameters(Hash, vstaging_primitives::AsyncBackingParameters), } diff --git a/node/core/runtime-api/src/lib.rs b/node/core/runtime-api/src/lib.rs index a6d71f351a6a..c354db35fd26 100644 --- a/node/core/runtime-api/src/lib.rs +++ b/node/core/runtime-api/src/lib.rs @@ -151,15 +151,16 @@ where ValidationCodeHash(relay_parent, para_id, assumption, hash) => self .requests_cache .cache_validation_code_hash((relay_parent, para_id, assumption), hash), - - StagingValidityConstraints(relay_parent, para_id, constraints) => self - .requests_cache - .cache_staging_validity_constraints((relay_parent, para_id), constraints), - Version(relay_parent, version) => self.requests_cache.cache_version(relay_parent, version), Disputes(relay_parent, disputes) => self.requests_cache.cache_disputes(relay_parent, disputes), + + StagingValidityConstraints(relay_parent, para_id, constraints) => self + .requests_cache + .cache_staging_validity_constraints((relay_parent, para_id), constraints), + StagingAsyncBackingParameters(relay_parent, params) => + self.requests_cache.cache_staging_async_backing_parameters(relay_parent, params), } } @@ -261,11 +262,14 @@ where Request::ValidationCodeHash(para, assumption, sender) => query!(validation_code_hash(para, assumption), sender) .map(|sender| Request::ValidationCodeHash(para, assumption, sender)), + Request::Disputes(sender) => + query!(disputes(), sender).map(|sender| Request::Disputes(sender)), Request::StagingValidityConstraints(para, sender) => query!(staging_validity_constraints(para), sender) .map(|sender| Request::StagingValidityConstraints(para, sender)), - Request::Disputes(sender) => - query!(disputes(), sender).map(|sender| Request::Disputes(sender)), + Request::StagingAsyncBackingParameters(sender) => + query!(staging_async_backing_parameters(), sender) + .map(|sender| Request::StagingAsyncBackingParameters(sender)), } } @@ -508,10 +512,23 @@ where }, Request::ValidationCodeHash(para, assumption, sender) => query!(ValidationCodeHash, validation_code_hash(para, assumption), ver = 2, sender), - Request::StagingValidityConstraints(para, sender) => { - query!(StagingValidityConstraints, staging_validity_constraints(para), ver = 2, sender) - }, Request::Disputes(sender) => query!(Disputes, disputes(), ver = Request::DISPUTES_RUNTIME_REQUIREMENT, sender), + Request::StagingValidityConstraints(para, sender) => { + query!( + StagingValidityConstraints, + staging_validity_constraints(para), + ver = Request::VALIDITY_CONSTRAINTS, + sender + ) + }, + Request::StagingAsyncBackingParameters(sender) => { + query!( + StagingAsyncBackingParameters, + staging_async_backing_parameters(), + ver = Request::VALIDITY_CONSTRAINTS, + sender + ) + }, } } diff --git a/node/network/collator-protocol/src/collator_side/mod.rs b/node/network/collator-protocol/src/collator_side/mod.rs index 3a9a32587bd1..55537628fb8a 100644 --- a/node/network/collator-protocol/src/collator_side/mod.rs +++ b/node/network/collator-protocol/src/collator_side/mod.rs @@ -57,7 +57,7 @@ use polkadot_primitives::v2::{ GroupIndex, Hash, Id as ParaId, SessionIndex, }; -use super::{LOG_TARGET, MAX_CANDIDATE_DEPTH}; +use super::LOG_TARGET; use crate::{ error::{log_error, Error, FatalError, Result}, modify_reputation, @@ -345,7 +345,7 @@ async fn distribute_collation( let collations_limit = match relay_parent_mode { ProspectiveParachainsMode::Disabled => 1, - ProspectiveParachainsMode::Enabled => MAX_CANDIDATE_DEPTH + 1, + ProspectiveParachainsMode::Enabled { max_candidate_depth, .. } => max_candidate_depth + 1, }; if per_relay_parent.collations.len() >= collations_limit { @@ -455,7 +455,7 @@ async fn distribute_collation( .iter() .filter(|(_, PeerData { view: v, .. })| match relay_parent_mode { ProspectiveParachainsMode::Disabled => v.contains(&candidate_relay_parent), - ProspectiveParachainsMode::Enabled => v.iter().any(|block_hash| { + ProspectiveParachainsMode::Enabled { .. } => v.iter().any(|block_hash| { state .implicit_view .known_allowed_relay_parents_under(block_hash, Some(id)) @@ -1063,7 +1063,7 @@ async fn handle_peer_view_change( .map(|per_relay_parent| per_relay_parent.prospective_parachains_mode) { Some(ProspectiveParachainsMode::Disabled) => std::slice::from_ref(&added), - Some(ProspectiveParachainsMode::Enabled) => state + Some(ProspectiveParachainsMode::Enabled { .. }) => state .implicit_view .known_allowed_relay_parents_under(&added, state.collating_on) .unwrap_or_default(), @@ -1209,7 +1209,7 @@ where state .per_relay_parent .entry(*block_hash) - .or_insert_with(|| PerRelayParent::new(ProspectiveParachainsMode::Enabled)); + .or_insert_with(|| PerRelayParent::new(mode)); } } } @@ -1345,7 +1345,7 @@ pub(crate) async fn run( (ProspectiveParachainsMode::Disabled, VersionedCollationRequest::V1(_)) => { per_relay_parent.collations.values().next() }, - (ProspectiveParachainsMode::Enabled, VersionedCollationRequest::VStaging(req)) => { + (ProspectiveParachainsMode::Enabled { .. }, VersionedCollationRequest::VStaging(req)) => { per_relay_parent.collations.get(&req.payload.candidate_hash) }, _ => { diff --git a/node/network/collator-protocol/src/collator_side/tests/mod.rs b/node/network/collator-protocol/src/collator_side/tests/mod.rs index 99baea31c016..470b78cd3ab3 100644 --- a/node/network/collator-protocol/src/collator_side/tests/mod.rs +++ b/node/network/collator-protocol/src/collator_side/tests/mod.rs @@ -37,6 +37,7 @@ use polkadot_node_network_protocol::{ }; use polkadot_node_primitives::BlockData; use polkadot_node_subsystem::{ + errors::RuntimeApiError, jaeger, messages::{AllMessages, RuntimeApiMessage, RuntimeApiRequest}, ActivatedLeaf, ActiveLeavesUpdate, LeafStatus, @@ -51,7 +52,8 @@ use polkadot_primitives_test_helpers::TestCandidateBuilder; mod prospective_parachains; -const API_VERSION_PROSPECTIVE_DISABLED: u32 = 2; +const ASYNC_BACKING_DISABLED_ERROR: RuntimeApiError = + RuntimeApiError::NotSupported { runtime_api_name: "test-runtime" }; #[derive(Clone)] struct TestState { @@ -193,10 +195,10 @@ impl TestState { overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( relay_parent, - RuntimeApiRequest::Version(tx) + RuntimeApiRequest::StagingAsyncBackingParameters(tx) )) => { assert_eq!(relay_parent, self.relay_parent); - tx.send(Ok(API_VERSION_PROSPECTIVE_DISABLED)).unwrap(); + tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)).unwrap(); } ); } @@ -324,10 +326,10 @@ async fn setup_system(virtual_overseer: &mut VirtualOverseer, test_state: &TestS overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( relay_parent, - RuntimeApiRequest::Version(tx) + RuntimeApiRequest::StagingAsyncBackingParameters(tx) )) => { assert_eq!(relay_parent, test_state.relay_parent); - tx.send(Ok(API_VERSION_PROSPECTIVE_DISABLED)).unwrap(); + tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)).unwrap(); } ); } diff --git a/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs b/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs index d98db5b8eb82..8fe75e3c28ca 100644 --- a/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs +++ b/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs @@ -19,9 +19,13 @@ use super::*; use polkadot_node_subsystem::messages::{ChainApiMessage, ProspectiveParachainsMessage}; -use polkadot_primitives::v2::{Header, OccupiedCore}; +use polkadot_primitives::{ + v2::{Header, OccupiedCore}, + vstaging as vstaging_primitives, +}; -const ALLOWED_ANCESTRY: u32 = 3; +const ASYNC_BACKING_PARAMETERS: vstaging_primitives::AsyncBackingParameters = + vstaging_primitives::AsyncBackingParameters { max_candidate_depth: 4, allowed_ancestry_len: 3 }; fn get_parent_hash(hash: Hash) -> Hash { Hash::from_low_u64_be(hash.to_low_u64_be() + 1) @@ -51,14 +55,14 @@ async fn update_view( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( parent, - RuntimeApiRequest::Version(tx), + RuntimeApiRequest::StagingAsyncBackingParameters(tx), )) => { - tx.send(Ok(RuntimeApiRequest::VALIDITY_CONSTRAINTS)).unwrap(); + tx.send(Ok(ASYNC_BACKING_PARAMETERS)).unwrap(); (parent, new_view.get(&parent).copied().expect("Unknown parent requested")) } ); - let min_number = leaf_number.saturating_sub(ALLOWED_ANCESTRY); + let min_number = leaf_number.saturating_sub(ASYNC_BACKING_PARAMETERS.allowed_ancestry_len); assert_matches!( overseer_recv(virtual_overseer).await, @@ -318,7 +322,7 @@ fn distribute_collation_up_to_limit() { // Activated leaf is `a`, but the collation will be based on `b`. update_view(virtual_overseer, &test_state, vec![(head_a, head_a_num)], 1).await; - for i in 0..(MAX_CANDIDATE_DEPTH + 1) { + for i in 0..(ASYNC_BACKING_PARAMETERS.max_candidate_depth + 1) { let pov = PoV { block_data: BlockData(vec![i as u8]) }; let parent_head_data_hash = Hash::repeat_byte(0xAA); let candidate = TestCandidateBuilder { diff --git a/node/network/collator-protocol/src/lib.rs b/node/network/collator-protocol/src/lib.rs index ca5bf5e297c6..b349a15db47a 100644 --- a/node/network/collator-protocol/src/lib.rs +++ b/node/network/collator-protocol/src/lib.rs @@ -47,15 +47,6 @@ mod validator_side; const LOG_TARGET: &'static str = "parachain::collator-protocol"; -/// The maximum depth a candidate can occupy for any relay parent. -/// 'depth' is defined as the amount of blocks between the para -/// head in a relay-chain block's state and a candidate with a -/// particular relay-parent. -/// -/// This value is only used for limiting the number of candidates -/// we accept and distribute per relay parent. -const MAX_CANDIDATE_DEPTH: usize = 4; - /// A collator eviction policy - how fast to evict collators which are inactive. #[derive(Debug, Clone, Copy)] pub struct CollatorEvictionPolicy { diff --git a/node/network/collator-protocol/src/validator_side/collation.rs b/node/network/collator-protocol/src/validator_side/collation.rs index a18397e09051..a60cd172cf44 100644 --- a/node/network/collator-protocol/src/validator_side/collation.rs +++ b/node/network/collator-protocol/src/validator_side/collation.rs @@ -37,7 +37,7 @@ use polkadot_primitives::v2::{ CandidateHash, CandidateReceipt, CollatorId, Hash, Id as ParaId, PersistedValidationData, }; -use crate::{error::SecondingError, LOG_TARGET, MAX_CANDIDATE_DEPTH}; +use crate::{error::SecondingError, LOG_TARGET}; /// Candidate supplied with a para head it's built on top of. #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] @@ -258,7 +258,13 @@ impl Collations { relay_parent_mode: ProspectiveParachainsMode, ) -> bool { let seconded_limit = - if relay_parent_mode.is_enabled() { MAX_CANDIDATE_DEPTH + 1 } else { 1 }; + if let ProspectiveParachainsMode::Enabled { max_candidate_depth, .. } = + relay_parent_mode + { + max_candidate_depth + 1 + } else { + 1 + }; self.seconded_count < seconded_limit } } diff --git a/node/network/collator-protocol/src/validator_side/mod.rs b/node/network/collator-protocol/src/validator_side/mod.rs index a6ef8d45bffc..0f2bc2ef670c 100644 --- a/node/network/collator-protocol/src/validator_side/mod.rs +++ b/node/network/collator-protocol/src/validator_side/mod.rs @@ -66,7 +66,7 @@ use polkadot_primitives::v2::{ use crate::error::{Error, FetchError, Result, SecondingError}; -use super::{modify_reputation, tick_stream, LOG_TARGET, MAX_CANDIDATE_DEPTH}; +use super::{modify_reputation, tick_stream, LOG_TARGET}; mod collation; mod metrics; @@ -274,7 +274,10 @@ impl PeerData { .advertisements .insert(on_relay_parent, HashSet::from_iter(candidate_hash)); }, - (ProspectiveParachainsMode::Enabled, Some(candidate_hash)) => { + ( + ProspectiveParachainsMode::Enabled { max_candidate_depth, .. }, + Some(candidate_hash), + ) => { if state .advertisements .get(&on_relay_parent) @@ -284,7 +287,7 @@ impl PeerData { } let candidates = state.advertisements.entry(on_relay_parent).or_default(); - if candidates.len() >= MAX_CANDIDATE_DEPTH + 1 { + if candidates.len() >= max_candidate_depth + 1 { return Err(InsertAdvertisementError::PeerLimitReached) } candidates.insert(candidate_hash); @@ -461,7 +464,7 @@ fn is_relay_parent_in_implicit_view( ) -> bool { match relay_parent_mode { ProspectiveParachainsMode::Disabled => active_leaves.contains_key(relay_parent), - ProspectiveParachainsMode::Enabled => active_leaves.iter().any(|(hash, mode)| { + ProspectiveParachainsMode::Enabled { .. } => active_leaves.iter().any(|(hash, mode)| { mode.is_enabled() && implicit_view .known_allowed_relay_parents_under(hash, Some(para_id)) @@ -1277,8 +1280,7 @@ where .unwrap_or_default(); for block_hash in allowed_ancestry { if let Entry::Vacant(entry) = state.per_relay_parent.entry(*block_hash) { - let mut per_relay_parent = - PerRelayParent::new(ProspectiveParachainsMode::Enabled); + let mut per_relay_parent = PerRelayParent::new(mode); assign_incoming( sender, &mut per_relay_parent.assignment, @@ -1763,7 +1765,7 @@ async fn kick_off_seconding( let pvd = match (relay_parent_mode, collation_event.1.prospective_candidate) { ( - ProspectiveParachainsMode::Enabled, + ProspectiveParachainsMode::Enabled { .. }, Some(ProspectiveCandidate { parent_head_data_hash, .. }), ) => request_prospective_validation_data( diff --git a/node/network/collator-protocol/src/validator_side/tests/mod.rs b/node/network/collator-protocol/src/validator_side/tests/mod.rs index 3499c8639a6d..ae728e033fe1 100644 --- a/node/network/collator-protocol/src/validator_side/tests/mod.rs +++ b/node/network/collator-protocol/src/validator_side/tests/mod.rs @@ -29,7 +29,10 @@ use polkadot_node_network_protocol::{ ObservedRole, }; use polkadot_node_primitives::BlockData; -use polkadot_node_subsystem::messages::{AllMessages, RuntimeApiMessage, RuntimeApiRequest}; +use polkadot_node_subsystem::{ + errors::RuntimeApiError, + messages::{AllMessages, RuntimeApiMessage, RuntimeApiRequest}, +}; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::TimeoutExt; use polkadot_primitives::v2::{ @@ -45,7 +48,8 @@ mod prospective_parachains; const ACTIVITY_TIMEOUT: Duration = Duration::from_millis(500); const DECLARE_TIMEOUT: Duration = Duration::from_millis(25); -const API_VERSION_PROSPECTIVE_DISABLED: u32 = 2; +const ASYNC_BACKING_DISABLED_ERROR: RuntimeApiError = + RuntimeApiError::NotSupported { runtime_api_name: "test-runtime" }; fn dummy_pvd() -> PersistedValidationData { PersistedValidationData { @@ -280,7 +284,7 @@ async fn assert_candidate_backing_second( tx.send(Ok(Some(pvd.clone()))).unwrap(); } ), - ProspectiveParachainsMode::Enabled => assert_matches!( + ProspectiveParachainsMode::Enabled { .. } => assert_matches!( msg, AllMessages::ProspectiveParachains( ProspectiveParachainsMessage::GetProspectiveValidationData(request, tx), @@ -430,15 +434,18 @@ async fn advertise_collation( .await; } -async fn assert_runtime_version_request(virtual_overseer: &mut VirtualOverseer, hash: Hash) { +async fn assert_async_backing_parameters_request( + virtual_overseer: &mut VirtualOverseer, + hash: Hash, +) { assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( relay_parent, - RuntimeApiRequest::Version(tx) + RuntimeApiRequest::StagingAsyncBackingParameters(tx) )) => { assert_eq!(relay_parent, hash); - tx.send(Ok(API_VERSION_PROSPECTIVE_DISABLED)).unwrap(); + tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)).unwrap(); } ); } @@ -462,7 +469,8 @@ fn act_on_advertisement() { ) .await; - assert_runtime_version_request(&mut virtual_overseer, test_state.relay_parent).await; + assert_async_backing_parameters_request(&mut virtual_overseer, test_state.relay_parent) + .await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; let peer_b = PeerId::random(); @@ -511,7 +519,8 @@ fn act_on_advertisement_vstaging() { ) .await; - assert_runtime_version_request(&mut virtual_overseer, test_state.relay_parent).await; + assert_async_backing_parameters_request(&mut virtual_overseer, test_state.relay_parent) + .await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; let peer_b = PeerId::random(); @@ -564,7 +573,8 @@ fn collator_reporting_works() { ) .await; - assert_runtime_version_request(&mut virtual_overseer, test_state.relay_parent).await; + assert_async_backing_parameters_request(&mut virtual_overseer, test_state.relay_parent) + .await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; @@ -682,7 +692,7 @@ fn fetch_one_collation_at_a_time() { // Iter over view since the order may change due to sorted invariant. for hash in our_view.iter() { - assert_runtime_version_request(&mut virtual_overseer, *hash).await; + assert_async_backing_parameters_request(&mut virtual_overseer, *hash).await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; } @@ -780,7 +790,7 @@ fn fetches_next_collation() { .await; for hash in our_view.iter() { - assert_runtime_version_request(&mut virtual_overseer, *hash).await; + assert_async_backing_parameters_request(&mut virtual_overseer, *hash).await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; } @@ -899,7 +909,8 @@ fn reject_connection_to_next_group() { ) .await; - assert_runtime_version_request(&mut virtual_overseer, test_state.relay_parent).await; + assert_async_backing_parameters_request(&mut virtual_overseer, test_state.relay_parent) + .await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; let peer_b = PeerId::random(); @@ -951,7 +962,7 @@ fn fetch_next_collation_on_invalid_collation() { .await; for hash in our_view.iter() { - assert_runtime_version_request(&mut virtual_overseer, *hash).await; + assert_async_backing_parameters_request(&mut virtual_overseer, *hash).await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; } @@ -1062,7 +1073,7 @@ fn inactive_disconnected() { ) .await; - assert_runtime_version_request(&mut virtual_overseer, hash_a).await; + assert_async_backing_parameters_request(&mut virtual_overseer, hash_a).await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; let peer_b = PeerId::random(); @@ -1117,7 +1128,7 @@ fn activity_extends_life() { .await; for hash in our_view.iter() { - assert_runtime_version_request(&mut virtual_overseer, *hash).await; + assert_async_backing_parameters_request(&mut virtual_overseer, *hash).await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; } @@ -1191,7 +1202,8 @@ fn disconnect_if_no_declare() { ) .await; - assert_runtime_version_request(&mut virtual_overseer, test_state.relay_parent).await; + assert_async_backing_parameters_request(&mut virtual_overseer, test_state.relay_parent) + .await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; let peer_b = PeerId::random(); @@ -1230,7 +1242,8 @@ fn disconnect_if_wrong_declare() { ) .await; - assert_runtime_version_request(&mut virtual_overseer, test_state.relay_parent).await; + assert_async_backing_parameters_request(&mut virtual_overseer, test_state.relay_parent) + .await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; let peer_b = PeerId::random(); @@ -1293,7 +1306,8 @@ fn view_change_clears_old_collators() { ) .await; - assert_runtime_version_request(&mut virtual_overseer, test_state.relay_parent).await; + assert_async_backing_parameters_request(&mut virtual_overseer, test_state.relay_parent) + .await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; let peer_b = PeerId::random(); @@ -1318,7 +1332,7 @@ fn view_change_clears_old_collators() { .await; test_state.group_rotation_info = test_state.group_rotation_info.bump_rotation(); - assert_runtime_version_request(&mut virtual_overseer, hash_b).await; + assert_async_backing_parameters_request(&mut virtual_overseer, hash_b).await; respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; assert_collator_disconnect(&mut virtual_overseer, peer_b.clone()).await; diff --git a/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs b/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs index 3b25f9203fc9..ebaf18f050e0 100644 --- a/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs +++ b/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs @@ -19,12 +19,16 @@ use super::*; use polkadot_node_subsystem::messages::ChainApiMessage; -use polkadot_primitives::v2::{ - BlockNumber, CandidateCommitments, CommittedCandidateReceipt, Header, SigningContext, - ValidatorId, +use polkadot_primitives::{ + v2::{ + BlockNumber, CandidateCommitments, CommittedCandidateReceipt, Header, SigningContext, + ValidatorId, + }, + vstaging as vstaging_primitives, }; -const ALLOWED_ANCESTRY: u32 = 3; +const ASYNC_BACKING_PARAMETERS: vstaging_primitives::AsyncBackingParameters = + vstaging_primitives::AsyncBackingParameters { max_candidate_depth: 4, allowed_ancestry_len: 3 }; fn get_parent_hash(hash: Hash) -> Hash { Hash::from_low_u64_be(hash.to_low_u64_be() + 1) @@ -96,9 +100,9 @@ async fn update_view( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( parent, - RuntimeApiRequest::Version(tx), + RuntimeApiRequest::StagingAsyncBackingParameters(tx), )) => { - tx.send(Ok(RuntimeApiRequest::VALIDITY_CONSTRAINTS)).unwrap(); + tx.send(Ok(ASYNC_BACKING_PARAMETERS)).unwrap(); (parent, new_view.get(&parent).copied().expect("Unknown parent requested")) } ); @@ -112,7 +116,7 @@ async fn update_view( ) .await; - let min_number = leaf_number.saturating_sub(ALLOWED_ANCESTRY); + let min_number = leaf_number.saturating_sub(ASYNC_BACKING_PARAMETERS.allowed_ancestry_len); assert_matches!( overseer_recv(virtual_overseer).await, @@ -416,7 +420,7 @@ fn second_multiple_candidates_per_relay_parent() { ) .await; - for i in 0..(MAX_CANDIDATE_DEPTH + 1) { + for i in 0..(ASYNC_BACKING_PARAMETERS.max_candidate_depth + 1) { let mut candidate = dummy_candidate_receipt_bad_sig(head_c, Some(Default::default())); candidate.descriptor.para_id = test_state.chain_ids[0]; candidate.descriptor.relay_parent = head_c; @@ -476,7 +480,10 @@ fn second_multiple_candidates_per_relay_parent() { head_c, test_state.chain_ids[0], &pov, - ProspectiveParachainsMode::Enabled, + ProspectiveParachainsMode::Enabled { + max_candidate_depth: ASYNC_BACKING_PARAMETERS.max_candidate_depth as _, + allowed_ancestry_len: ASYNC_BACKING_PARAMETERS.allowed_ancestry_len as _, + }, ) .await; diff --git a/node/subsystem-types/src/messages.rs b/node/subsystem-types/src/messages.rs index e51cd9689c79..e71aff6478a8 100644 --- a/node/subsystem-types/src/messages.rs +++ b/node/subsystem-types/src/messages.rs @@ -707,11 +707,15 @@ pub enum RuntimeApiRequest { OccupiedCoreAssumption, RuntimeApiSender>, ), + /// Returns all on-chain disputes at given block number. Available in `v3`. + Disputes(RuntimeApiSender)>>), /// Get the validity constraints of the given para. /// This is a staging API that will not be available on production runtimes. StagingValidityConstraints(ParaId, RuntimeApiSender>), - /// Returns all on-chain disputes at given block number. Available in `v3`. - Disputes(RuntimeApiSender)>>), + /// Get candidate's acceptance limitations for asynchronous backing for a relay parent. + /// + /// If it's not supported by the Runtime, the async backing is said to be disabled. + StagingAsyncBackingParameters(RuntimeApiSender), } impl RuntimeApiRequest { diff --git a/node/subsystem-types/src/runtime_client.rs b/node/subsystem-types/src/runtime_client.rs index 65f0cff00262..31aacd3b00b8 100644 --- a/node/subsystem-types/src/runtime_client.rs +++ b/node/subsystem-types/src/runtime_client.rs @@ -199,6 +199,12 @@ pub trait RuntimeApiSubsystemClient { para_id: Id, ) -> Result, ApiError>; + /// Returns candidate's acceptance limitations for asynchronous backing for a relay parent. + async fn staging_async_backing_parameters( + &self, + at: Hash, + ) -> Result; + // === BABE API === /// Returns information regarding the current epoch. @@ -397,4 +403,12 @@ where ) -> Result, ApiError> { self.runtime_api().staging_validity_constraints(&BlockId::Hash(at), para_id) } + + /// Returns candidate's acceptance limitations for asynchronous backing for a relay parent. + async fn staging_async_backing_parameters( + &self, + at: Hash, + ) -> Result { + self.runtime_api().staging_async_backing_parameters(&BlockId::Hash(at)) + } } diff --git a/node/subsystem-util/src/lib.rs b/node/subsystem-util/src/lib.rs index 68fdad77895d..63353d7e6269 100644 --- a/node/subsystem-util/src/lib.rs +++ b/node/subsystem-util/src/lib.rs @@ -40,12 +40,15 @@ pub use polkadot_node_metrics::{metrics, Metronome}; use futures::channel::{mpsc, oneshot}; use parity_scale_codec::Encode; -use polkadot_primitives::v2::{ - AuthorityDiscoveryId, CandidateEvent, CommittedCandidateReceipt, CoreState, EncodeAs, - GroupIndex, GroupRotationInfo, Hash, Id as ParaId, OccupiedCoreAssumption, - PersistedValidationData, ScrapedOnChainVotes, SessionIndex, SessionInfo, Signed, - SigningContext, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, - ValidatorSignature, +use polkadot_primitives::{ + v2::{ + AuthorityDiscoveryId, CandidateEvent, CommittedCandidateReceipt, CoreState, EncodeAs, + GroupIndex, GroupRotationInfo, Hash, Id as ParaId, OccupiedCoreAssumption, + PersistedValidationData, ScrapedOnChainVotes, SessionIndex, SessionInfo, Signed, + SigningContext, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, + ValidatorSignature, + }, + vstaging as vstaging_primitives, }; pub use rand; use sp_application_crypto::AppKey; @@ -211,6 +214,7 @@ specialize_requests! { fn request_validation_code_hash(para_id: ParaId, assumption: OccupiedCoreAssumption) -> Option; ValidationCodeHash; fn request_on_chain_votes() -> Option; FetchOnChainVotes; + fn request_staging_async_backing_parameters() -> vstaging_primitives::AsyncBackingParameters; StagingAsyncBackingParameters; } /// From the given set of validators, find the first key we can sign with, if any. diff --git a/node/subsystem-util/src/runtime/mod.rs b/node/subsystem-util/src/runtime/mod.rs index 4a2e3c0f4224..699efabe2de1 100644 --- a/node/subsystem-util/src/runtime/mod.rs +++ b/node/subsystem-util/src/runtime/mod.rs @@ -26,19 +26,22 @@ use sp_core::crypto::ByteArray; use sp_keystore::{CryptoStore, SyncCryptoStorePtr}; use polkadot_node_subsystem::{ - messages::{RuntimeApiMessage, RuntimeApiRequest}, - overseer, SubsystemSender, + errors::RuntimeApiError, messages::RuntimeApiMessage, overseer, SubsystemSender, }; -use polkadot_primitives::v2::{ - CandidateEvent, CoreState, EncodeAs, GroupIndex, GroupRotationInfo, Hash, IndexedVec, - OccupiedCore, ScrapedOnChainVotes, SessionIndex, SessionInfo, Signed, SigningContext, - UncheckedSigned, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, +use polkadot_primitives::{ + v2::{ + CandidateEvent, CoreState, EncodeAs, GroupIndex, GroupRotationInfo, Hash, IndexedVec, + OccupiedCore, ScrapedOnChainVotes, SessionIndex, SessionInfo, Signed, SigningContext, + UncheckedSigned, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, + }, + vstaging as vstaging_primitives, }; use crate::{ request_availability_cores, request_candidate_events, request_on_chain_votes, - request_runtime_api_version, request_session_index_for_child, request_session_info, - request_validation_code_by_hash, request_validator_groups, + request_session_index_for_child, request_session_info, + request_staging_async_backing_parameters, request_validation_code_by_hash, + request_validator_groups, }; /// Errors that can happen on runtime fetches. @@ -358,13 +361,21 @@ pub enum ProspectiveParachainsMode { /// v2 runtime API: no prospective parachains. Disabled, /// vstaging runtime API: prospective parachains. - Enabled, + Enabled { + /// The maximum number of para blocks between the para head in a relay parent + /// and a new candidate. Restricts nodes from building arbitrary long chains + /// and spamming other validators. + max_candidate_depth: usize, + /// How many ancestors of a relay parent are allowed to build candidates on top + /// of. + allowed_ancestry_len: usize, + }, } impl ProspectiveParachainsMode { /// Returns `true` if mode is enabled, `false` otherwise. pub fn is_enabled(&self) -> bool { - matches!(self, ProspectiveParachainsMode::Enabled) + matches!(self, ProspectiveParachainsMode::Enabled { .. }) } } @@ -377,21 +388,28 @@ pub async fn prospective_parachains_mode( where Sender: SubsystemSender, { - let version = recv_runtime(request_runtime_api_version(relay_parent, sender).await).await?; + let result = + recv_runtime(request_staging_async_backing_parameters(relay_parent, sender).await).await; + + if let Err(error::Error::RuntimeRequest(RuntimeApiError::NotSupported { runtime_api_name })) = + &result + { + gum::trace!( + target: LOG_TARGET, + ?relay_parent, + "Prospective parachains are disabled, {} is not supported by the current Runtime API", + runtime_api_name, + ); - if version >= RuntimeApiRequest::VALIDITY_CONSTRAINTS { - Ok(ProspectiveParachainsMode::Enabled) - } else { - if version < 2 { - gum::warn!( - target: LOG_TARGET, - ?relay_parent, - "Runtime API version is {}, it is expected to be at least 2. Prospective parachains are disabled", - version - ); - } Ok(ProspectiveParachainsMode::Disabled) + } else { + let vstaging_primitives::AsyncBackingParameters { + max_candidate_depth, + allowed_ancestry_len, + } = result?; + Ok(ProspectiveParachainsMode::Enabled { + max_candidate_depth: max_candidate_depth as _, + allowed_ancestry_len: allowed_ancestry_len as _, + }) } } - -// TODO [now] : a way of getting all [`ContextLimitations`] from runtime. diff --git a/primitives/src/runtime_api.rs b/primitives/src/runtime_api.rs index d54ec6919d55..ee041438d6b9 100644 --- a/primitives/src/runtime_api.rs +++ b/primitives/src/runtime_api.rs @@ -216,12 +216,19 @@ sp_api::decl_runtime_apis! { #[changed_in(2)] fn session_info(index: sp_staking::SessionIndex) -> Option; + /// Returns all onchain disputes. + #[api_version(3)] + fn disputes() -> Vec<(v2::SessionIndex, v2::CandidateHash, v2::DisputeState)>; + + /***** Asynchronous backing *****/ + /// Returns the base constraints of the given para, if they exist. /// This is a staging method! Do not use on production runtimes! + #[api_version(99)] fn staging_validity_constraints(_: ppp::Id) -> Option; - /// Returns all onchain disputes. - #[api_version(3)] - fn disputes() -> Vec<(v2::SessionIndex, v2::CandidateHash, v2::DisputeState)>; + /// Returns candidate's acceptance limitations for asynchronous backing for a relay parent. + #[api_version(99)] + fn staging_async_backing_parameters() -> vstaging::AsyncBackingParameters; } } diff --git a/primitives/src/vstaging/mod.rs b/primitives/src/vstaging/mod.rs index 16bfc085570a..9834eb3eac2c 100644 --- a/primitives/src/vstaging/mod.rs +++ b/primitives/src/vstaging/mod.rs @@ -30,6 +30,23 @@ use parity_util_mem::MallocSizeOf; /// Useful type alias for Para IDs. pub type ParaId = Id; +/// Candidate's acceptance limitations for asynchronous backing per relay parent. +#[derive(RuntimeDebug, Copy, Clone, PartialEq, Encode, Decode, TypeInfo)] +#[cfg_attr(feature = "std", derive(MallocSizeOf, serde::Serialize, serde::Deserialize))] +pub struct AsyncBackingParameters { + /// The maximum number of para blocks between the para head in a relay parent + /// and a new candidate. Restricts nodes from building arbitrary long chains + /// and spamming other validators. + /// + /// When async backing is disabled, the only valid value is 0. + pub max_candidate_depth: u32, + /// How many ancestors of a relay parent are allowed to build candidates on top + /// of. + /// + /// When async backing is disabled, the only valid value is 0. + pub allowed_ancestry_len: u32, +} + /// Constraints on inbound HRMP channels. #[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)] #[cfg_attr(feature = "std", derive(MallocSizeOf))] diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index 902ea7bdcae7..94e6d5110d99 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -1460,7 +1460,7 @@ pub type Executive = frame_executive::Executive< pallet_democracy::migrations::v1::Migration, pallet_multisig::migrations::v1::MigrateToV1, // "Properly migrate weights to v2" - parachains_configuration::migration::v3::MigrateToV3, + parachains_configuration::migration::v4::MigrateToV4, pallet_election_provider_multi_phase::migrations::v1::MigrateToV1, pallet_fast_unstake::migrations::v1::MigrateToV1, ), @@ -1690,10 +1690,6 @@ sp_api::impl_runtime_apis! { { parachains_runtime_api_impl::validation_code_hash::(para_id, assumption) } - - fn staging_validity_constraints(_: ParaId) -> Option { - unimplemented!("Staging API not implemented"); - } } impl beefy_primitives::BeefyApi for Runtime { diff --git a/runtime/parachains/src/configuration.rs b/runtime/parachains/src/configuration.rs index 2ebaff1b8282..d1e65af4444f 100644 --- a/runtime/parachains/src/configuration.rs +++ b/runtime/parachains/src/configuration.rs @@ -22,7 +22,10 @@ use crate::shared; use frame_support::{pallet_prelude::*, weights::constants::WEIGHT_PER_MILLIS}; use frame_system::pallet_prelude::*; use parity_scale_codec::{Decode, Encode}; -use primitives::v2::{Balance, SessionIndex, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE}; +use primitives::{ + v2::{Balance, SessionIndex, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE}, + vstaging::AsyncBackingParameters, +}; use sp_runtime::traits::Zero; use sp_std::prelude::*; @@ -117,6 +120,8 @@ pub struct HostConfiguration { * The parameters that are not essential, but still may be of interest for parachains. */ + /// Asynchronous backing parameters. + pub async_backing_parameters: AsyncBackingParameters, /// The maximum POV block size, in bytes. pub max_pov_size: u32, /// The maximum size of a message that can be put in a downward message queue. @@ -246,6 +251,10 @@ pub struct HostConfiguration { impl> Default for HostConfiguration { fn default() -> Self { Self { + async_backing_parameters: AsyncBackingParameters { + max_candidate_depth: 0, + allowed_ancestry_len: 0, + }, group_rotation_frequency: 1u32.into(), chain_availability_period: 1u32.into(), thread_availability_period: 1u32.into(), @@ -518,6 +527,23 @@ pub mod pallet { #[pallet::call] impl Pallet { + /// Set the asynchronous backing parameters. + #[pallet::weight(( + T::WeightInfo::set_config_with_option_u32(), // The same size in bytes. + DispatchClass::Operational, + ))] + pub fn set_async_backing_parameters( + origin: OriginFor, + max_candidate_depth: u32, + allowed_ancestry_len: u32, + ) -> DispatchResult { + ensure_root(origin)?; + Self::schedule_config_update(|config| { + config.async_backing_parameters = + AsyncBackingParameters { max_candidate_depth, allowed_ancestry_len }; + }) + } + /// Set the validation upgrade cooldown. #[pallet::weight(( T::WeightInfo::set_config_with_block_number(), diff --git a/runtime/parachains/src/configuration/migration.rs b/runtime/parachains/src/configuration/migration.rs index d87c98f6ae78..d3b50181266c 100644 --- a/runtime/parachains/src/configuration/migration.rs +++ b/runtime/parachains/src/configuration/migration.rs @@ -17,27 +17,23 @@ //! A module that is responsible for migration of storage. use crate::configuration::{self, Config, Pallet, Store, MAX_POV_SIZE}; -use frame_support::{ - pallet_prelude::*, - traits::StorageVersion, - weights::{OldWeight, Weight}, -}; +use frame_support::{pallet_prelude::*, traits::StorageVersion, weights::Weight}; use frame_system::pallet_prelude::BlockNumberFor; +use primitives::vstaging::AsyncBackingParameters; /// The current storage version. /// /// v0-v1: /// v1-v2: /// v2-v3: -pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(3); +/// v3-v4: ... +pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); -pub mod v3 { +pub mod v4 { use super::*; - use frame_support::traits::OnRuntimeUpgrade; + use frame_support::{traits::OnRuntimeUpgrade, weights::constants::WEIGHT_PER_MILLIS}; use primitives::v2::{Balance, SessionIndex}; - // Copied over from configuration.rs @ de9e147695b9f1be8bd44e07861a31e483c8343a and removed - // all the comments, and changed the Weight struct to OldWeight #[derive(parity_scale_codec::Encode, parity_scale_codec::Decode, Debug)] pub struct OldHostConfiguration { pub max_code_size: u32, @@ -51,7 +47,7 @@ pub mod v3 { pub validation_upgrade_delay: BlockNumber, pub max_pov_size: u32, pub max_downward_message_size: u32, - pub ump_service_total_weight: OldWeight, + pub ump_service_total_weight: Weight, pub hrmp_max_parachain_outbound_channels: u32, pub hrmp_max_parathread_outbound_channels: u32, pub hrmp_sender_deposit: Balance, @@ -79,7 +75,7 @@ pub mod v3 { pub zeroth_delay_tranche_width: u32, pub needed_approvals: u32, pub relay_vrf_modulo_samples: u32, - pub ump_max_individual_weight: OldWeight, + pub ump_max_individual_weight: Weight, pub pvf_checking_enabled: bool, pub pvf_voting_ttl: SessionIndex, pub minimum_validation_upgrade_delay: BlockNumber, @@ -93,7 +89,7 @@ pub mod v3 { thread_availability_period: 1u32.into(), no_show_slots: 1u32.into(), validation_upgrade_cooldown: Default::default(), - validation_upgrade_delay: Default::default(), + validation_upgrade_delay: 2u32.into(), code_retention_period: Default::default(), max_code_size: Default::default(), max_pov_size: Default::default(), @@ -114,7 +110,7 @@ pub mod v3 { max_upward_queue_count: Default::default(), max_upward_queue_size: Default::default(), max_downward_message_size: Default::default(), - ump_service_total_weight: OldWeight(Default::default()), + ump_service_total_weight: Default::default(), max_upward_message_size: Default::default(), max_upward_message_num_per_candidate: Default::default(), hrmp_sender_deposit: Default::default(), @@ -127,9 +123,8 @@ pub mod v3 { hrmp_max_parachain_outbound_channels: Default::default(), hrmp_max_parathread_outbound_channels: Default::default(), hrmp_max_message_num_per_candidate: Default::default(), - ump_max_individual_weight: OldWeight( - frame_support::weights::constants::WEIGHT_PER_MILLIS.ref_time() * 20, - ), + ump_max_individual_weight: (20u64 * WEIGHT_PER_MILLIS) + .set_proof_size(MAX_POV_SIZE as u64), pvf_checking_enabled: false, pvf_voting_ttl: 2u32.into(), minimum_validation_upgrade_delay: 2.into(), @@ -137,35 +132,39 @@ pub mod v3 { } } - pub struct MigrateToV3(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for MigrateToV3 { + pub struct MigrateToV4(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV4 { fn on_runtime_upgrade() -> Weight { - if StorageVersion::get::>() == 2 { - let weight_consumed = migrate_to_v3::(); + if StorageVersion::get::>() == 3 { + let mut weight_consumed = migrate_to_v4::(); - log::info!(target: configuration::LOG_TARGET, "MigrateToV3 executed successfully"); + log::info!(target: configuration::LOG_TARGET, "MigrateToV4 executed successfully"); STORAGE_VERSION.put::>(); + weight_consumed += T::DbWeight::get().reads_writes(1, 1); weight_consumed } else { - log::warn!(target: configuration::LOG_TARGET, "MigrateToV3 should be removed."); + log::warn!(target: configuration::LOG_TARGET, "MigrateToV4 should be removed."); T::DbWeight::get().reads(1) } } } } -fn migrate_to_v3() -> Weight { +fn migrate_to_v4() -> Weight { // Unusual formatting is justified: // - make it easier to verify that fields assign what they supposed to assign. // - this code is transient and will be removed after all migrations are done. // - this code is important enough to optimize for legibility sacrificing consistency. #[rustfmt::skip] let translate = - |pre: v3::OldHostConfiguration>| -> + |pre: v4::OldHostConfiguration>| -> configuration::HostConfiguration> { super::HostConfiguration { +// Default values are zeroes, thus it's ensured allowed ancestry never crosses the upgrade block. +async_backing_parameters : AsyncBackingParameters { max_candidate_depth: 0, allowed_ancestry_len: 0 }, + max_code_size : pre.max_code_size, max_head_data_size : pre.max_head_data_size, max_upward_queue_count : pre.max_upward_queue_count, @@ -207,9 +206,8 @@ relay_vrf_modulo_samples : pre.relay_vrf_modulo_samples, pvf_checking_enabled : pre.pvf_checking_enabled, pvf_voting_ttl : pre.pvf_voting_ttl, minimum_validation_upgrade_delay : pre.minimum_validation_upgrade_delay, - -ump_service_total_weight: Weight::from_ref_time(pre.ump_service_total_weight.0).set_proof_size(MAX_POV_SIZE as u64), -ump_max_individual_weight: Weight::from_ref_time(pre.ump_max_individual_weight.0).set_proof_size(MAX_POV_SIZE as u64), +ump_service_total_weight : pre.ump_service_total_weight, +ump_max_individual_weight :pre.ump_max_individual_weight, } }; @@ -234,31 +232,31 @@ mod tests { use crate::mock::{new_test_ext, Test}; #[test] - fn v2_deserialized_from_actual_data() { - // Fetched at Kusama 14,703,780 (0x3b2c305d01bd4adf1973d32a2d55ca1260a55eea8dfb3168e317c57f2841fdf1) + fn v3_deserialized_from_actual_data() { + // Fetched at Westend 13,327,763 (0x3b2c305d01bd4adf1973d32a2d55ca1260a55eea8dfb3168e317c57f2841fdf1) // // This exceeds the maximal line width length, but that's fine, since this is not code and // doesn't need to be read and also leaving it as one line allows to easily copy it. - let raw_config = hex_literal::hex!["0000a000005000000a00000000c8000000c800000a0000000a000000100e0000580200000000500000c8000000e87648170000001e00000000000000005039278c0400000000000000000000005039278c0400000000000000000000e8030000009001001e00000000000000009001008070000000000000000000000a0000000a0000000a00000001000000010500000001c8000000060000005802000002000000580200000200000059000000000000001e0000002800000000c817a804000000000200000014000000"]; + let raw_config = hex_literal::hex!["00005000005000000a00000000c8000000c800000a0000000a000000c8000000640000000000500000c800000700e8764817020040010a0000000000000000c0220fca950300000000000000000000c0220fca9503000000000000000000e8030000009001000a00000000000000009001008070000000000000000000000a000000050000000500000001000000010500000001c80000000600000058020000020000005802000002000000280000000000000002000000010000000700c817a8040200400100020000000f000000"]; - let v2 = - v3::OldHostConfiguration::::decode(&mut &raw_config[..]) + let v3 = + v4::OldHostConfiguration::::decode(&mut &raw_config[..]) .unwrap(); // We check only a sample of the values here. If we missed any fields or messed up data types // that would skew all the fields coming after. - assert_eq!(v2.max_code_size, 10_485_760); - assert_eq!(v2.validation_upgrade_cooldown, 3600); - assert_eq!(v2.max_pov_size, 5_242_880); - assert_eq!(v2.hrmp_channel_max_message_size, 102_400); - assert_eq!(v2.dispute_max_spam_slots, 2); - assert_eq!(v2.n_delay_tranches, 89); - assert_eq!(v2.ump_max_individual_weight, OldWeight(20_000_000_000)); - assert_eq!(v2.minimum_validation_upgrade_delay, 20); + assert_eq!(v3.max_code_size, 5_242_880); + assert_eq!(v3.validation_upgrade_cooldown, 200); + assert_eq!(v3.max_pov_size, 5_242_880); + assert_eq!(v3.hrmp_channel_max_message_size, 102_400); + assert_eq!(v3.dispute_max_spam_slots, 2); + assert_eq!(v3.n_delay_tranches, 40); + assert_eq!(v3.ump_max_individual_weight, Weight::from_parts(20_000_000_000, 5_242_880)); + assert_eq!(v3.minimum_validation_upgrade_delay, 15); } #[test] - fn test_migrate_to_v3() { + fn test_migrate_to_v4() { // Host configuration has lots of fields. However, in this migration we add only a couple of // fields. The most important part to check are a couple of the last fields. We also pick // extra fields to check arbitrarily, e.g. depending on their position (i.e. the middle) and @@ -267,8 +265,7 @@ mod tests { // We specify only the picked fields and the rest should be provided by the `Default` // implementation. That implementation is copied over between the two types and should work // fine. - let v2 = v3::OldHostConfiguration:: { - ump_max_individual_weight: OldWeight(0x71616e6f6e0au64), + let v3 = v4::OldHostConfiguration:: { needed_approvals: 69, thread_availability_period: 55, hrmp_recipient_deposit: 1337, @@ -282,61 +279,58 @@ mod tests { // Implant the v2 version in the state. frame_support::storage::unhashed::put_raw( &configuration::ActiveConfig::::hashed_key(), - &v2.encode(), + &v3.encode(), ); - migrate_to_v3::(); + migrate_to_v4::(); - let v3 = configuration::ActiveConfig::::get(); + let v4 = configuration::ActiveConfig::::get(); #[rustfmt::skip] { - assert_eq!(v2.max_code_size , v3.max_code_size); - assert_eq!(v2.max_head_data_size , v3.max_head_data_size); - assert_eq!(v2.max_upward_queue_count , v3.max_upward_queue_count); - assert_eq!(v2.max_upward_queue_size , v3.max_upward_queue_size); - assert_eq!(v2.max_upward_message_size , v3.max_upward_message_size); - assert_eq!(v2.max_upward_message_num_per_candidate , v3.max_upward_message_num_per_candidate); - assert_eq!(v2.hrmp_max_message_num_per_candidate , v3.hrmp_max_message_num_per_candidate); - assert_eq!(v2.validation_upgrade_cooldown , v3.validation_upgrade_cooldown); - assert_eq!(v2.validation_upgrade_delay , v3.validation_upgrade_delay); - assert_eq!(v2.max_pov_size , v3.max_pov_size); - assert_eq!(v2.max_downward_message_size , v3.max_downward_message_size); - assert_eq!(v2.hrmp_max_parachain_outbound_channels , v3.hrmp_max_parachain_outbound_channels); - assert_eq!(v2.hrmp_max_parathread_outbound_channels , v3.hrmp_max_parathread_outbound_channels); - assert_eq!(v2.hrmp_sender_deposit , v3.hrmp_sender_deposit); - assert_eq!(v2.hrmp_recipient_deposit , v3.hrmp_recipient_deposit); - assert_eq!(v2.hrmp_channel_max_capacity , v3.hrmp_channel_max_capacity); - assert_eq!(v2.hrmp_channel_max_total_size , v3.hrmp_channel_max_total_size); - assert_eq!(v2.hrmp_max_parachain_inbound_channels , v3.hrmp_max_parachain_inbound_channels); - assert_eq!(v2.hrmp_max_parathread_inbound_channels , v3.hrmp_max_parathread_inbound_channels); - assert_eq!(v2.hrmp_channel_max_message_size , v3.hrmp_channel_max_message_size); - assert_eq!(v2.code_retention_period , v3.code_retention_period); - assert_eq!(v2.parathread_cores , v3.parathread_cores); - assert_eq!(v2.parathread_retries , v3.parathread_retries); - assert_eq!(v2.group_rotation_frequency , v3.group_rotation_frequency); - assert_eq!(v2.chain_availability_period , v3.chain_availability_period); - assert_eq!(v2.thread_availability_period , v3.thread_availability_period); - assert_eq!(v2.scheduling_lookahead , v3.scheduling_lookahead); - assert_eq!(v2.max_validators_per_core , v3.max_validators_per_core); - assert_eq!(v2.max_validators , v3.max_validators); - assert_eq!(v2.dispute_period , v3.dispute_period); - assert_eq!(v2.dispute_post_conclusion_acceptance_period, v3.dispute_post_conclusion_acceptance_period); - assert_eq!(v2.dispute_max_spam_slots , v3.dispute_max_spam_slots); - assert_eq!(v2.dispute_conclusion_by_time_out_period , v3.dispute_conclusion_by_time_out_period); - assert_eq!(v2.no_show_slots , v3.no_show_slots); - assert_eq!(v2.n_delay_tranches , v3.n_delay_tranches); - assert_eq!(v2.zeroth_delay_tranche_width , v3.zeroth_delay_tranche_width); - assert_eq!(v2.needed_approvals , v3.needed_approvals); - assert_eq!(v2.relay_vrf_modulo_samples , v3.relay_vrf_modulo_samples); - assert_eq!(v2.pvf_checking_enabled , v3.pvf_checking_enabled); - assert_eq!(v2.pvf_voting_ttl , v3.pvf_voting_ttl); - assert_eq!(v2.minimum_validation_upgrade_delay , v3.minimum_validation_upgrade_delay); - - assert_eq!(v2.ump_service_total_weight, OldWeight(v3.ump_service_total_weight.ref_time())); - assert_eq!(v2.ump_max_individual_weight, OldWeight(v3.ump_max_individual_weight.ref_time())); - assert_eq!(v3.ump_service_total_weight.proof_size(), MAX_POV_SIZE as u64); - assert_eq!(v3.ump_max_individual_weight.proof_size(), MAX_POV_SIZE as u64); + assert_eq!(v3.max_code_size , v4.max_code_size); + assert_eq!(v3.max_head_data_size , v4.max_head_data_size); + assert_eq!(v3.max_upward_queue_count , v4.max_upward_queue_count); + assert_eq!(v3.max_upward_queue_size , v4.max_upward_queue_size); + assert_eq!(v3.max_upward_message_size , v4.max_upward_message_size); + assert_eq!(v3.max_upward_message_num_per_candidate , v4.max_upward_message_num_per_candidate); + assert_eq!(v3.hrmp_max_message_num_per_candidate , v4.hrmp_max_message_num_per_candidate); + assert_eq!(v3.validation_upgrade_cooldown , v4.validation_upgrade_cooldown); + assert_eq!(v3.validation_upgrade_delay , v4.validation_upgrade_delay); + assert_eq!(v3.max_pov_size , v4.max_pov_size); + assert_eq!(v3.max_downward_message_size , v4.max_downward_message_size); + assert_eq!(v3.hrmp_max_parachain_outbound_channels , v4.hrmp_max_parachain_outbound_channels); + assert_eq!(v3.hrmp_max_parathread_outbound_channels , v4.hrmp_max_parathread_outbound_channels); + assert_eq!(v3.hrmp_sender_deposit , v4.hrmp_sender_deposit); + assert_eq!(v3.hrmp_recipient_deposit , v4.hrmp_recipient_deposit); + assert_eq!(v3.hrmp_channel_max_capacity , v4.hrmp_channel_max_capacity); + assert_eq!(v3.hrmp_channel_max_total_size , v4.hrmp_channel_max_total_size); + assert_eq!(v3.hrmp_max_parachain_inbound_channels , v4.hrmp_max_parachain_inbound_channels); + assert_eq!(v3.hrmp_max_parathread_inbound_channels , v4.hrmp_max_parathread_inbound_channels); + assert_eq!(v3.hrmp_channel_max_message_size , v4.hrmp_channel_max_message_size); + assert_eq!(v3.code_retention_period , v4.code_retention_period); + assert_eq!(v3.parathread_cores , v4.parathread_cores); + assert_eq!(v3.parathread_retries , v4.parathread_retries); + assert_eq!(v3.group_rotation_frequency , v4.group_rotation_frequency); + assert_eq!(v3.chain_availability_period , v4.chain_availability_period); + assert_eq!(v3.thread_availability_period , v4.thread_availability_period); + assert_eq!(v3.scheduling_lookahead , v4.scheduling_lookahead); + assert_eq!(v3.max_validators_per_core , v4.max_validators_per_core); + assert_eq!(v3.max_validators , v4.max_validators); + assert_eq!(v3.dispute_period , v4.dispute_period); + assert_eq!(v3.dispute_post_conclusion_acceptance_period, v4.dispute_post_conclusion_acceptance_period); + assert_eq!(v3.dispute_max_spam_slots , v4.dispute_max_spam_slots); + assert_eq!(v3.dispute_conclusion_by_time_out_period , v4.dispute_conclusion_by_time_out_period); + assert_eq!(v3.no_show_slots , v4.no_show_slots); + assert_eq!(v3.n_delay_tranches , v4.n_delay_tranches); + assert_eq!(v3.zeroth_delay_tranche_width , v4.zeroth_delay_tranche_width); + assert_eq!(v3.needed_approvals , v4.needed_approvals); + assert_eq!(v3.relay_vrf_modulo_samples , v4.relay_vrf_modulo_samples); + assert_eq!(v3.pvf_checking_enabled , v4.pvf_checking_enabled); + assert_eq!(v3.pvf_voting_ttl , v4.pvf_voting_ttl); + assert_eq!(v3.minimum_validation_upgrade_delay , v4.minimum_validation_upgrade_delay); + assert_eq!(v3.ump_service_total_weight , v4.ump_service_total_weight); + assert_eq!(v3.ump_max_individual_weight , v4.ump_max_individual_weight); }; // ; makes this a statement. `rustfmt::skip` cannot be put on an expression. }); } diff --git a/runtime/parachains/src/configuration/tests.rs b/runtime/parachains/src/configuration/tests.rs index 6f2faf6cb204..e9e6c59f2c27 100644 --- a/runtime/parachains/src/configuration/tests.rs +++ b/runtime/parachains/src/configuration/tests.rs @@ -293,6 +293,10 @@ fn consistency_bypass_works() { fn setting_pending_config_members() { new_test_ext(Default::default()).execute_with(|| { let new_config = HostConfiguration { + async_backing_parameters: AsyncBackingParameters { + max_candidate_depth: 0, + allowed_ancestry_len: 0, + }, validation_upgrade_cooldown: 100, validation_upgrade_delay: 10, code_retention_period: 5, diff --git a/runtime/parachains/src/inclusion/tests.rs b/runtime/parachains/src/inclusion/tests.rs index fe8d96f7d945..550e52a72cb6 100644 --- a/runtime/parachains/src/inclusion/tests.rs +++ b/runtime/parachains/src/inclusion/tests.rs @@ -1913,9 +1913,6 @@ fn check_allowed_relay_parents() { let chain_b = ParaId::from(2); let thread_a = ParaId::from(3); - // The block number of the relay-parent for testing. - const RELAY_PARENT_NUM: BlockNumber = 4; - let paras = vec![ (chain_a, ParaKind::Parachain), (chain_b, ParaKind::Parachain), @@ -1984,10 +1981,25 @@ fn check_allowed_relay_parents() { let relay_parent_c = (3, Hash::repeat_byte(0x3)); let mut allowed_relay_parents = AllowedRelayParentsTracker::default(); - let max_len = RELAY_PARENT_NUM as usize; - allowed_relay_parents.update(relay_parent_a.1, Hash::zero(), relay_parent_a.0, max_len); - allowed_relay_parents.update(relay_parent_b.1, Hash::zero(), relay_parent_b.0, max_len); - allowed_relay_parents.update(relay_parent_c.1, Hash::zero(), relay_parent_c.0, max_len); + let max_ancestry_len = 3; + allowed_relay_parents.update( + relay_parent_a.1, + Hash::zero(), + relay_parent_a.0, + max_ancestry_len, + ); + allowed_relay_parents.update( + relay_parent_b.1, + Hash::zero(), + relay_parent_b.0, + max_ancestry_len, + ); + allowed_relay_parents.update( + relay_parent_c.1, + Hash::zero(), + relay_parent_c.0, + max_ancestry_len, + ); let chain_a_assignment = CoreAssignment { core: CoreIndex::from(0), diff --git a/runtime/parachains/src/paras_inherent/mod.rs b/runtime/parachains/src/paras_inherent/mod.rs index 86e116a2c060..62573a44e8c6 100644 --- a/runtime/parachains/src/paras_inherent/mod.rs +++ b/runtime/parachains/src/paras_inherent/mod.rs @@ -30,8 +30,7 @@ use crate::{ metrics::METRICS, paras, scheduler::{self, CoreAssignment, FreedReason}, - shared::{self, ALLOWED_RELAY_PARENT_LOOKBACK}, - ump, ParaId, + shared, ump, ParaId, }; use bitvec::prelude::BitVec; use frame_support::{ @@ -332,6 +331,7 @@ impl Pallet { ); let now = >::block_number(); + let config = >::config(); // Before anything else, update the allowed relay-parents. { @@ -343,7 +343,7 @@ impl Pallet { parent_hash, parent_storage_root, parent_number, - ALLOWED_RELAY_PARENT_LOOKBACK, + config.async_backing_parameters.allowed_ancestry_len, ); }); } @@ -364,8 +364,6 @@ impl Pallet { .map_err(|_e| Error::::DisputeStatementsUnsortedOrDuplicates)?; let (checked_disputes, total_consumed_weight) = { - // Obtain config params.. - let config = >::config(); let max_spam_slots = config.dispute_max_spam_slots; let post_conclusion_acceptance_period = config.dispute_post_conclusion_acceptance_period; @@ -586,6 +584,7 @@ impl Pallet { disputes.len() ); + let config = >::config(); let parent_hash = >::parent_hash(); let now = >::block_number(); @@ -615,7 +614,7 @@ impl Pallet { parent_hash, parent_storage_root, parent_number, - ALLOWED_RELAY_PARENT_LOOKBACK, + config.async_backing_parameters.allowed_ancestry_len, ); tracker @@ -626,7 +625,6 @@ impl Pallet { log::debug!(target: LOG_TARGET, "Found duplicate statement sets, retaining the first"); } - let config = >::config(); let max_spam_slots = config.dispute_max_spam_slots; let post_conclusion_acceptance_period = config.dispute_post_conclusion_acceptance_period; diff --git a/runtime/parachains/src/runtime_api_impl/vstaging.rs b/runtime/parachains/src/runtime_api_impl/vstaging.rs index 3fe6e2a0b979..eb6c1cf95abc 100644 --- a/runtime/parachains/src/runtime_api_impl/vstaging.rs +++ b/runtime/parachains/src/runtime_api_impl/vstaging.rs @@ -19,7 +19,9 @@ use crate::{configuration, disputes, dmp, hrmp, initializer, paras, shared, ump}; use primitives::{ v2::{CandidateHash, DisputeState, Id as ParaId, SessionIndex}, - vstaging::{Constraints, InboundHrmpLimitations, OutboundHrmpChannelLimitations}, + vstaging::{ + AsyncBackingParameters, Constraints, InboundHrmpLimitations, OutboundHrmpChannelLimitations, + }, }; use sp_std::prelude::*; @@ -33,6 +35,7 @@ pub fn get_session_disputes( pub fn validity_constraints( para_id: ParaId, ) -> Option> { + let config = >::config(); // Async backing is only expected to be enabled with a tracker capacity of 1. // Subsequent configuration update gets applied on new session, which always // clears the buffer. @@ -40,7 +43,10 @@ pub fn validity_constraints( // Thus, minimum relay parent is ensured to have asynchronous backing enabled. let now = >::block_number(); let min_relay_parent_number = >::allowed_relay_parents() - .hypothetical_earliest_block_number(now, shared::ALLOWED_RELAY_PARENT_LOOKBACK); + .hypothetical_earliest_block_number( + now, + config.async_backing_parameters.allowed_ancestry_len, + ); let required_parent = >::para_head(para_id)?; let validation_code_hash = >::current_code_hash(para_id)?; @@ -52,7 +58,6 @@ pub fn validity_constraints( Some(block_num).zip(>::future_code_hash(para_id)) }); - let config = >::config(); let (ump_msg_count, ump_total_bytes) = >::relay_dispatch_queue_size(para_id); let ump_remaining = config.max_upward_queue_count - ump_msg_count; let ump_remaining_bytes = config.max_upward_queue_size - ump_total_bytes; @@ -85,3 +90,8 @@ pub fn validity_constraints( future_validation_code, }) } + +/// Implementation for `StagingAsyncBackingParameters` function from the runtime API +pub fn async_backing_parameters() -> AsyncBackingParameters { + >::config().async_backing_parameters +} diff --git a/runtime/parachains/src/shared.rs b/runtime/parachains/src/shared.rs index cb125d8ef884..28012369ad27 100644 --- a/runtime/parachains/src/shared.rs +++ b/runtime/parachains/src/shared.rs @@ -39,10 +39,6 @@ pub(crate) const SESSION_DELAY: SessionIndex = 2; #[cfg(test)] mod tests; -/// The maximum amount of relay-parent lookback. -// TODO: put this in the configuration module (https://github.com/paritytech/polkadot/issues/4841). -pub const ALLOWED_RELAY_PARENT_LOOKBACK: usize = 4; - /// Information about past relay-parents. #[derive(Encode, Decode, Default, TypeInfo)] pub struct AllowedRelayParentsTracker { @@ -64,22 +60,23 @@ impl AllowedRelayParentsTracker { /// Add a new relay-parent to the allowed relay parents, along with info about the header. - /// Provide a maximum length for the buffer, which will cause old relay-parents to be pruned. + /// Provide a maximum ancestry length for the buffer, which will cause old relay-parents to be pruned. pub(crate) fn update( &mut self, relay_parent: Hash, state_root: Hash, number: BlockNumber, - max_len: usize, + max_ancestry_len: u32, ) { + // + 1 for the most recent block, which is always allowed. + let buffer_size_limit = max_ancestry_len as usize + 1; + self.buffer.push_back((relay_parent, state_root)); self.latest_number = number; - while self.buffer.len() > max_len { + while self.buffer.len() > buffer_size_limit { let _ = self.buffer.pop_front(); } - // if max_len == 0, then latest_number is nonsensical. Otherwise, it's fine. - // We only allow relay parents within the same sessions, the buffer // gets cleared on session changes. } @@ -114,11 +111,11 @@ impl pub(crate) fn hypothetical_earliest_block_number( &self, now: BlockNumber, - max_len: usize, + max_ancestry_len: u32, ) -> BlockNumber { - let allowed_ancestry_len = max_len.saturating_sub(1).min(self.buffer.len()); + let allowed_ancestry_len = max_ancestry_len.min(self.buffer.len() as u32); - now - BlockNumber::from(allowed_ancestry_len as u32) + now - allowed_ancestry_len.into() } } diff --git a/runtime/parachains/src/shared/tests.rs b/runtime/parachains/src/shared/tests.rs index 5594c9420d03..e30dc6a33d07 100644 --- a/runtime/parachains/src/shared/tests.rs +++ b/runtime/parachains/src/shared/tests.rs @@ -32,25 +32,25 @@ fn tracker_earliest_block_number() { // Test it on an empty tracker. let now: u32 = 1; - let max_len = 5; - assert_eq!(tracker.hypothetical_earliest_block_number(now, max_len), now); + let max_ancestry_len = 5; + assert_eq!(tracker.hypothetical_earliest_block_number(now, max_ancestry_len), now); // Push a single block into the tracker, suppose max capacity is 1. - let max_len = 1; - tracker.update(Hash::zero(), Hash::zero(), 0, max_len); - assert_eq!(tracker.hypothetical_earliest_block_number(now, max_len), now); + let max_ancestry_len = 0; + tracker.update(Hash::zero(), Hash::zero(), 0, max_ancestry_len); + assert_eq!(tracker.hypothetical_earliest_block_number(now, max_ancestry_len), now); // Test a greater capacity. - let max_len = 5; + let max_ancestry_len = 4; let now = 4; for i in 1..now { - tracker.update(Hash::zero(), Hash::zero(), i, max_len); - assert_eq!(tracker.hypothetical_earliest_block_number(i + 1, max_len), 0); + tracker.update(Hash::zero(), Hash::zero(), i, max_ancestry_len); + assert_eq!(tracker.hypothetical_earliest_block_number(i + 1, max_ancestry_len), 0); } // Capacity exceeded. - tracker.update(Hash::zero(), Hash::zero(), now, max_len); - assert_eq!(tracker.hypothetical_earliest_block_number(now + 1, max_len), 1); + tracker.update(Hash::zero(), Hash::zero(), now, max_ancestry_len); + assert_eq!(tracker.hypothetical_earliest_block_number(now + 1, max_ancestry_len), 1); } #[test] diff --git a/runtime/polkadot/src/lib.rs b/runtime/polkadot/src/lib.rs index c62d781a9f5b..11fd85c1a573 100644 --- a/runtime/polkadot/src/lib.rs +++ b/runtime/polkadot/src/lib.rs @@ -1616,7 +1616,7 @@ pub type Executive = frame_executive::Executive< pallet_democracy::migrations::v1::Migration, pallet_multisig::migrations::v1::MigrateToV1, // "Properly migrate weights to v2" - parachains_configuration::migration::v3::MigrateToV3, + parachains_configuration::migration::v4::MigrateToV4, pallet_election_provider_multi_phase::migrations::v1::MigrateToV1, pallet_fast_unstake::migrations::v1::MigrateToV1, ), @@ -1847,10 +1847,6 @@ sp_api::impl_runtime_apis! { { parachains_runtime_api_impl::validation_code_hash::(para_id, assumption) } - - fn staging_validity_constraints(_: ParaId) -> Option { - unimplemented!("Staging API not implemented"); - } } impl beefy_primitives::BeefyApi for Runtime { diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index 7c9542d45ceb..d08d3a8bbd45 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -1463,7 +1463,7 @@ pub type Executive = frame_executive::Executive< pallet_democracy::migrations::v1::Migration, pallet_multisig::migrations::v1::MigrateToV1, // "Properly migrate weights to v2" - parachains_configuration::migration::v3::MigrateToV3, + parachains_configuration::migration::v4::MigrateToV4, ), >; /// The payload being signed in transactions. @@ -1608,7 +1608,7 @@ sp_api::impl_runtime_apis! { } } - #[api_version(3)] + #[api_version(99)] impl primitives::runtime_api::ParachainHost for Runtime { fn validators() -> Vec { parachains_runtime_api_impl::validators::() @@ -1711,8 +1711,12 @@ sp_api::impl_runtime_apis! { runtime_parachains::runtime_api_impl::vstaging::get_session_disputes::() } - fn staging_validity_constraints(_: ParaId) -> Option { - unimplemented!("Staging API not implemented"); + fn staging_validity_constraints(para_id: ParaId) -> Option { + runtime_parachains::runtime_api_impl::vstaging::validity_constraints::(para_id) + } + + fn staging_async_backing_parameters() -> primitives::vstaging::AsyncBackingParameters { + runtime_parachains::runtime_api_impl::vstaging::async_backing_parameters::() } } diff --git a/runtime/test-runtime/src/lib.rs b/runtime/test-runtime/src/lib.rs index 08935a1270ac..0210f1ecd8b7 100644 --- a/runtime/test-runtime/src/lib.rs +++ b/runtime/test-runtime/src/lib.rs @@ -916,10 +916,6 @@ sp_api::impl_runtime_apis! { { runtime_impl::validation_code_hash::(para_id, assumption) } - - fn staging_validity_constraints(_: ParaId) -> Option { - unimplemented!("Staging API not implemented"); - } } impl beefy_primitives::BeefyApi for Runtime { diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index d35d94e0f5ab..d69bdd88b2ea 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -1228,7 +1228,7 @@ pub type Executive = frame_executive::Executive< pallet_scheduler::migration::v3::MigrateToV4, pallet_multisig::migrations::v1::MigrateToV1, // "Properly migrate weights to v2" - parachains_configuration::migration::v3::MigrateToV3, + parachains_configuration::migration::v4::MigrateToV4, pallet_election_provider_multi_phase::migrations::v1::MigrateToV1, pallet_fast_unstake::migrations::v1::MigrateToV1, ), @@ -1346,7 +1346,7 @@ sp_api::impl_runtime_apis! { } } - #[api_version(3)] + #[api_version(99)] impl primitives::runtime_api::ParachainHost for Runtime { fn validators() -> Vec { parachains_runtime_api_impl::validators::() @@ -1449,8 +1449,12 @@ sp_api::impl_runtime_apis! { runtime_parachains::runtime_api_impl::vstaging::get_session_disputes::() } - fn staging_validity_constraints(_: ParaId) -> Option { - unimplemented!("Staging API not implemented"); + fn staging_validity_constraints(para_id: ParaId) -> Option { + runtime_parachains::runtime_api_impl::vstaging::validity_constraints::(para_id) + } + + fn staging_async_backing_parameters() -> primitives::vstaging::AsyncBackingParameters { + runtime_parachains::runtime_api_impl::vstaging::async_backing_parameters::() } }