Asynchronous backing PR (#2300)

* Update substrate & polkadot

* min changes to make async backing compile

* (async backing) parachain-system: track limitations for unincluded blocks (#2438)

* unincluded segment draft

* read para head from storage proof

* read_para_head -> read_included_para_head

* Provide pub interface

* add errors

* fix unincluded segment update

* BlockTracker -> Ancestor

* add a dmp limit

* Read para head depending on the storage switch

* doc comments

* storage items docs

* add a sanity check on block initialize

* Check watermark

* append to the segment on block finalize

* Move segment update into set_validation_data

* Resolve para head todo

* option watermark

* fix comment

* Drop dmq check

* fix weight

* doc-comments on inherent invariant

* Remove TODO

* add todo

* primitives tests

* pallet tests

* doc comments

* refactor unincluded segment length into a ConsensusHook (#2501)

* refactor unincluded segment length into a ConsensusHook

* add docs

* refactor bandwidth_out calculation

Co-authored-by: Chris Sosnin <48099298+slumber@users.noreply.github.com>

* test for limits from impl

* fmt

* make tests compile

* update comment

* uncomment test

* fix collator test by adding parent to state proof

* patch HRMP watermark rules for unincluded segment

* get consensus-common tests to pass, using unincluded segment

* fix unincluded segment tests

* get all tests passing

* fmt

* rustdoc CI

* aura-ext: limit the number of authored blocks per slot (#2551)

* aura_ext consensus hook

* reverse dependency

* include weight into hook

* fix tests

* remove stray println

Co-authored-by: Chris Sosnin <48099298+slumber@users.noreply.github.com>

* fix test warning

* fix doc link

---------

Co-authored-by: Chris Sosnin <48099298+slumber@users.noreply.github.com>
Co-authored-by: Chris Sosnin <chris125_@live.com>

* parachain-system: ignore go ahead signal once upgrade is processed (#2594)

* handle goahead signal for unincluded segment

* doc comment

* add test

* parachain-system: drop processed messages from inherent data (#2590)

* implement `drop_processed_messages`

* drop messages based on relay parent number

* adjust tests

* drop changes to mqc

* fix comment

* drop test

* drop more dead code

* clippy

* aura-ext: check slot in consensus hook and remove all `CheckInherents` logic (#2658)

* aura-ext: check slot in consensus hook

* convert relay chain slot

* Make relay chain slot duration generic

* use fixed velocity hook for pallets with aura

* purge timestamp inherent

* fix warning

* adjust runtime tests

* fix slots in tests

* Make `xcm-emulator` test pass for new consensus hook (#2722)

* add pallets on_initialize

* tests pass

* add AuraExt on_init

* ".git/.scripts/commands/fmt/fmt.sh"

---------

Co-authored-by: command-bot <>

---------

Co-authored-by: Ignacio Palacios <ignacio.palacios.santos@gmail.com>

* update polkadot git refs

* CollationGenerationConfig closure is now optional (#2772)

* CollationGenerationConfig closure is now optional

* fix test

* propagate network-protocol-staging feature (#2899)

* Feature Flagging Consensus Hook Type Parameter (#2911)

* First pass

* fmt

* Added as default feature in tomls

* Changed to direct dependency feature

* Dealing with clippy error

* Update pallets/parachain-system/src/lib.rs

Co-authored-by: asynchronous rob <rphmeier@gmail.com>

---------

Co-authored-by: asynchronous rob <rphmeier@gmail.com>

* fmt

* bump deps and remove warning

* parachain-system: update RelevantMessagingState according to the unincluded segment (#2948)

* mostly address 2471 with a bug introduced

* adjust relevant messaging state after computing total

* fmt

* max -> min

* fix test implementation of xcmp source

* add test

* fix test message sending logic

* fix + test

* add more to unincluded segment test

* fmt

---------

Co-authored-by: Chris Sosnin <chris125_@live.com>

* Integrate new Aura / Parachain Consensus Logic in Parachain-Template / Polkadot-Parachain (#2864)

* add a comment

* refactor client/service utilities

* deprecate start_collator

* update parachain-template

* update test-service in the same way

* update polkadot-parachain crate

* fmt

* wire up new SubmitCollation message

* some runtime utilities for implementing unincluded segment runtime APIs

* allow parachains to configure their level of sybil-resistance when starting the network

* make aura-ext compile

* update to specify sybil resistance levels

* fmt

* specify relay chain slot duration in milliseconds

* update Aura to explicitly produce Send futures

also, make relay_chain_slot_duration a Duration

* add authoring duration to basic collator and document params

* integrate new basic collator into parachain-template

* remove assert_send used for testing

* basic-aura: only author when parent included

* update polkadot-parachain-bin

* fmt

* some fixes

* fixes

* add a RelayNumberMonotonicallyIncreases

* add a utility function for initializing subsystems

* some logging for timestamp adjustment

* fmt

* some fixes for lookahead collator

* add a log

* update `find_potential_parents` to account for sessions

* bound the loop

* restore & deprecate old start_collator and start_full_node functions.

* remove unnecessary await calls

* fix warning

* clippy

* more clippy

* remove unneeded logic

* ci

* update comment

Co-authored-by: Marcin S. <marcin@bytedude.com>

* (async backing) restore `CheckInherents` for backwards-compatibility (#2977)

* bring back timestamp

* Restore CheckInherents

* revert to empty CheckInherents

* make CheckInherents optional

* attempt

* properly end system blocks

* add some more comments

* ignore failing system parachain tests

* update refs after main feature branch merge

* comment out the offending tests because CI runs ignored tests

* fix warnings

* fmt

* revert to polkadot master

* cargo update -p polkadot-primitives -p sp-io

---------

Co-authored-by: asynchronous rob <rphmeier@gmail.com>
Co-authored-by: Ignacio Palacios <ignacio.palacios.santos@gmail.com>
Co-authored-by: Bradley Olson <34992650+BradleyOlson64@users.noreply.github.com>
Co-authored-by: Marcin S. <marcin@bytedude.com>
Co-authored-by: eskimor <eskimor@users.noreply.github.com>
Co-authored-by: Andronik <write@reusable.software>
This commit is contained in:
Chris Sosnin
2023-08-18 19:57:34 +03:00
committed by GitHub
parent 4f699c70a4
commit 6ef1117685
105 changed files with 4707 additions and 2359 deletions
+421 -364
View File
File diff suppressed because it is too large Load Diff
@@ -41,8 +41,8 @@ sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", d
sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
# Polkadot dependencies
xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false }
xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false }
xcm = { git = "https://github.com/paritytech/polkadot", default-features = false , branch = "master" }
xcm-builder = { git = "https://github.com/paritytech/polkadot", default-features = false , branch = "master" }
[dev-dependencies]
bp-test-utils = { path = "../../primitives/test-utils" }
@@ -26,8 +26,8 @@ sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", d
# Polkadot Dependencies
xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false }
xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false }
xcm = { git = "https://github.com/paritytech/polkadot", default-features = false , branch = "master" }
xcm-builder = { git = "https://github.com/paritytech/polkadot", default-features = false , branch = "master" }
[dev-dependencies]
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" }
@@ -21,7 +21,7 @@ sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", d
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
# Polkadot Dependencies
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false }
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false , branch = "master" }
[features]
default = ["std"]
+1
View File
@@ -42,3 +42,4 @@ polkadot-node-subsystem-test-helpers = { git = "https://github.com/paritytech/po
# Cumulus
cumulus-test-client = { path = "../../test/client" }
cumulus-test-runtime = { path = "../../test/runtime" }
cumulus-test-relay-sproof-builder = { path = "../../test/relay-sproof-builder" }
+64 -8
View File
@@ -26,7 +26,8 @@ use sp_core::traits::SpawnNamed;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use cumulus_client_consensus_common::ParachainConsensus;
use polkadot_node_primitives::{CollationResult, MaybeCompressedPoV};
use polkadot_node_primitives::{CollationGenerationConfig, CollationResult, MaybeCompressedPoV};
use polkadot_node_subsystem::messages::{CollationGenerationMessage, CollatorProtocolMessage};
use polkadot_overseer::Handle as OverseerHandle;
use polkadot_primitives::{CollatorPair, Id as ParaId};
@@ -200,7 +201,7 @@ pub mod relay_chain_driven {
let config = CollationGenerationConfig {
key,
para_id,
collator: Box::new(move |relay_parent, validation_data| {
collator: Some(Box::new(move |relay_parent, validation_data| {
// Cloning the channel on each usage effectively makes the channel
// unbounded. The channel is actually bounded by the block production
// and consensus systems of Polkadot, which limits the amount of possible
@@ -218,7 +219,7 @@ pub mod relay_chain_driven {
this_rx.await.ok().flatten()
})
}),
})),
};
overseer_handle
@@ -233,6 +234,31 @@ pub mod relay_chain_driven {
}
}
/// Initialize the collation-related subsystems on the relay-chain side.
///
/// This must be done prior to collation, and does not set up any callback for collation.
/// For callback-driven collators, use the [`relay_chain_driven`] module.
pub async fn initialize_collator_subsystems(
overseer_handle: &mut OverseerHandle,
key: CollatorPair,
para_id: ParaId,
) {
overseer_handle
.send_msg(
CollationGenerationMessage::Initialize(CollationGenerationConfig {
key,
para_id,
collator: None,
}),
"StartCollator",
)
.await;
overseer_handle
.send_msg(CollatorProtocolMessage::CollateOn(para_id), "StartCollator")
.await;
}
/// Parameters for [`start_collator`].
pub struct StartCollatorParams<Block: BlockT, RA, BS, Spawner> {
pub para_id: ParaId,
@@ -246,7 +272,24 @@ pub struct StartCollatorParams<Block: BlockT, RA, BS, Spawner> {
}
/// Start the collator.
#[deprecated = "Collators should run consensus futures which handle this logic internally"]
pub async fn start_collator<Block, RA, BS, Spawner>(
params: StartCollatorParams<Block, RA, BS, Spawner>,
) where
Block: BlockT,
BS: BlockBackend<Block> + Send + Sync + 'static,
Spawner: SpawnNamed + Clone + Send + Sync + 'static,
RA: ProvideRuntimeApi<Block> + Send + Sync + 'static,
RA::Api: CollectCollationInfo<Block>,
{
// This never needed to be asynchronous, but shouldn't be changed due to backcompat.
#[allow(deprecated)]
start_collator_sync(params);
}
/// Start the collator in a synchronous function.
#[deprecated = "Collators should run consensus futures which handle this logic internally"]
pub fn start_collator_sync<Block, RA, BS, Spawner>(
StartCollatorParams {
para_id,
block_status,
@@ -269,9 +312,8 @@ pub async fn start_collator<Block, RA, BS, Spawner>(
let collator = Collator::new(collator_service, parachain_consensus);
let mut request_stream = relay_chain_driven::init(key, para_id, overseer_handle).await;
let collation_future = Box::pin(async move {
let mut request_stream = relay_chain_driven::init(key, para_id, overseer_handle).await;
while let Some(request) = request_stream.next().await {
let collation = collator
.clone()
@@ -298,11 +340,14 @@ mod tests {
Client, ClientBlockImportExt, DefaultTestClientBuilderExt, InitBlockBuilder,
TestClientBuilder, TestClientBuilderExt,
};
use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
use cumulus_test_runtime::{Block, Header};
use futures::{channel::mpsc, executor::block_on, StreamExt};
use polkadot_node_primitives::CollationGenerationConfig;
use polkadot_node_subsystem::messages::CollationGenerationMessage;
use polkadot_node_subsystem_test_helpers::ForwardSubsystem;
use polkadot_overseer::{dummy::dummy_overseer_builder, HeadSupportsParachains};
use polkadot_primitives::HeadData;
use sp_consensus::BlockOrigin;
use sp_core::{testing::TaskExecutor, Pair};
use sp_runtime::traits::BlakeTwo256;
@@ -330,10 +375,14 @@ mod tests {
_: PHash,
validation_data: &PersistedValidationData,
) -> Option<ParachainCandidate<Block>> {
let mut sproof = RelayStateSproofBuilder::default();
sproof.included_para_head = Some(HeadData(parent.encode()));
sproof.para_id = cumulus_test_runtime::PARACHAIN_ID.into();
let builder = self.client.init_block_builder_at(
parent.hash(),
Some(validation_data.clone()),
Default::default(),
sproof,
);
let (block, _, proof) = builder.build().expect("Creates block").into_inner();
@@ -368,6 +417,7 @@ mod tests {
spawner.spawn("overseer", None, overseer.run().then(|_| async {}).boxed());
#[allow(deprecated)]
let collator_start = start_collator(StartCollatorParams {
runtime_api: client.clone(),
block_status: client.clone(),
@@ -384,13 +434,19 @@ mod tests {
.0
.expect("message should be send by `start_collator` above.");
let CollationGenerationMessage::Initialize(config) = msg;
let collator_fn = match msg {
CollationGenerationMessage::Initialize(CollationGenerationConfig {
collator: Some(c),
..
}) => c,
_ => panic!("unexpected message or no collator fn"),
};
let validation_data =
PersistedValidationData { parent_head: header.encode().into(), ..Default::default() };
let relay_parent = Default::default();
let collation = block_on((config.collator)(relay_parent, &validation_data))
let collation = block_on(collator_fn(relay_parent, &validation_data))
.expect("Collation is build")
.collation;
+1
View File
@@ -45,4 +45,5 @@ cumulus-client-collator = { path = "../../collator" }
# Polkadot
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-node-subsystem = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-overseer = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+32 -14
View File
@@ -55,7 +55,7 @@ use sp_runtime::{
};
use sp_state_machine::StorageChanges;
use sp_timestamp::Timestamp;
use std::{convert::TryFrom, error::Error, sync::Arc, time::Duration};
use std::{convert::TryFrom, error::Error, time::Duration};
/// Parameters for instantiating a [`Collator`].
pub struct Params<BI, CIDP, RClient, Proposer, CS> {
@@ -64,7 +64,7 @@ pub struct Params<BI, CIDP, RClient, Proposer, CS> {
/// The block import handle.
pub block_import: BI,
/// An interface to the relay-chain client.
pub relay_client: Arc<RClient>,
pub relay_client: RClient,
/// The keystore handle used for accessing parachain key material.
pub keystore: KeystorePtr,
/// The identifier of the parachain within the relay-chain.
@@ -81,12 +81,12 @@ pub struct Params<BI, CIDP, RClient, Proposer, CS> {
pub struct Collator<Block, P, BI, CIDP, RClient, Proposer, CS> {
create_inherent_data_providers: CIDP,
block_import: BI,
relay_client: Arc<RClient>,
relay_client: RClient,
keystore: KeystorePtr,
para_id: ParaId,
proposer: Proposer,
collator_service: CS,
_marker: std::marker::PhantomData<(Block, P)>,
_marker: std::marker::PhantomData<(Block, Box<dyn Fn(P) + Send + Sync + 'static>)>,
}
impl<Block, P, BI, CIDP, RClient, Proposer, CS> Collator<Block, P, BI, CIDP, RClient, Proposer, CS>
@@ -123,7 +123,7 @@ where
validation_data: &PersistedValidationData,
parent_hash: Block::Hash,
timestamp: impl Into<Option<Timestamp>>,
) -> Result<(ParachainInherentData, InherentData), Box<dyn Error>> {
) -> Result<(ParachainInherentData, InherentData), Box<dyn Error + Send + Sync + 'static>> {
let paras_inherent_data = ParachainInherentData::create_at(
relay_parent,
&self.relay_client,
@@ -143,7 +143,7 @@ where
let mut other_inherent_data = self
.create_inherent_data_providers
.create_inherent_data_providers(parent_hash, ())
.map_err(|e| e as Box<dyn Error>)
.map_err(|e| e as Box<dyn Error + Send + Sync + 'static>)
.await?
.create_inherent_data()
.await
@@ -172,7 +172,8 @@ where
inherent_data: (ParachainInherentData, InherentData),
proposal_duration: Duration,
max_pov_size: usize,
) -> Result<(Collation, ParachainBlockData<Block>, Block::Hash), Box<dyn Error>> {
) -> Result<(Collation, ParachainBlockData<Block>, Block::Hash), Box<dyn Error + Send + 'static>>
{
let mut digest = additional_pre_digest.into().unwrap_or_default();
digest.push(slot_claim.pre_digest.clone());
@@ -187,14 +188,15 @@ where
Some(max_pov_size),
)
.await
.map_err(|e| Box::new(e))?;
.map_err(|e| Box::new(e) as Box<dyn Error + Send>)?;
let sealed_importable = seal::<_, P>(
proposal.block,
proposal.storage_changes,
&slot_claim.author_pub,
&self.keystore,
)?;
)
.map_err(|e| e as Box<dyn Error + Send>)?;
let post_hash = sealed_importable.post_hash();
let block = Block::new(
@@ -206,7 +208,10 @@ where
.clone(),
);
self.block_import.import_block(sealed_importable).await?;
self.block_import
.import_block(sealed_importable)
.map_err(|e| Box::new(e) as Box<dyn Error + Send>)
.await?;
if let Some((collation, block_data)) = self.collator_service.build_collation(
parent_header,
@@ -231,7 +236,8 @@ where
Ok((collation, block_data, post_hash))
} else {
Err("Unable to produce collation".to_string().into())
Err(Box::<dyn Error + Send + Sync>::from("Unable to produce collation")
as Box<dyn Error + Send>)
}
}
@@ -285,7 +291,7 @@ pub async fn claim_slot<B, C, P>(
parent_hash: B::Hash,
relay_parent_header: &PHeader,
slot_duration: SlotDuration,
relay_chain_slot_duration: SlotDuration,
relay_chain_slot_duration: Duration,
keystore: &KeystorePtr,
) -> Result<Option<SlotClaim<P::Public>>, Box<dyn Error>>
where
@@ -304,7 +310,19 @@ where
relay_parent_header,
relay_chain_slot_duration,
) {
Some((_, t)) => (Slot::from_timestamp(t, slot_duration), t),
Some((r_s, t)) => {
let our_slot = Slot::from_timestamp(t, slot_duration);
tracing::debug!(
target: crate::LOG_TARGET,
relay_slot = ?r_s,
para_slot = ?our_slot,
timestamp = ?t,
?slot_duration,
?relay_chain_slot_duration,
"Adjusted relay-chain slot to parachain slot"
);
(our_slot, t)
},
None => return Ok(None),
};
@@ -326,7 +344,7 @@ pub fn seal<B: BlockT, P>(
storage_changes: StorageChanges<HashingFor<B>>,
author_pub: &P::Public,
keystore: &KeystorePtr,
) -> Result<BlockImportParams<B>, Box<dyn Error>>
) -> Result<BlockImportParams<B>, Box<dyn Error + Send + Sync + 'static>>
where
P: Pair,
P::Signature: Codec + TryFrom<Vec<u8>>,
@@ -51,26 +51,44 @@ use crate::collator as collator_util;
/// Parameters for [`run`].
pub struct Params<BI, CIDP, Client, RClient, SO, Proposer, CS> {
/// Inherent data providers. Only non-consensus inherent data should be provided, i.e.
/// the timestamp, slot, and paras inherents should be omitted, as they are set by this
/// collator.
pub create_inherent_data_providers: CIDP,
/// Used to actually import blocks.
pub block_import: BI,
/// The underlying para client.
pub para_client: Arc<Client>,
pub relay_client: Arc<RClient>,
/// A handle to the relay-chain client.
pub relay_client: RClient,
/// A chain synchronization oracle.
pub sync_oracle: SO,
/// The underlying keystore, which should contain Aura consensus keys.
pub keystore: KeystorePtr,
pub key: CollatorPair,
/// The collator key used to sign collations before submitting to validators.
pub collator_key: CollatorPair,
/// The para's ID.
pub para_id: ParaId,
/// A handle to the relay-chain client's "Overseer" or task orchestrator.
pub overseer_handle: OverseerHandle,
/// The length of slots in this chain.
pub slot_duration: SlotDuration,
pub relay_chain_slot_duration: SlotDuration,
/// The length of slots in the relay chain.
pub relay_chain_slot_duration: Duration,
/// The underlying block proposer this should call into.
pub proposer: Proposer,
/// The generic collator service used to plug into this consensus engine.
pub collator_service: CS,
/// The amount of time to spend authoring each block.
pub authoring_duration: Duration,
}
/// Run bare Aura consensus as a relay-chain-driven collator.
pub async fn run<Block, P, BI, CIDP, Client, RClient, SO, Proposer, CS>(
pub fn run<Block, P, BI, CIDP, Client, RClient, SO, Proposer, CS>(
params: Params<BI, CIDP, Client, RClient, SO, Proposer, CS>,
) where
Block: BlockT,
) -> impl Future<Output = ()> + Send + 'static
where
Block: BlockT + Send,
Client: ProvideRuntimeApi<Block>
+ BlockOf
+ AuxStore
@@ -80,18 +98,20 @@ pub async fn run<Block, P, BI, CIDP, Client, RClient, SO, Proposer, CS>(
+ Sync
+ 'static,
Client::Api: AuraApi<Block, P::Public> + CollectCollationInfo<Block>,
RClient: RelayChainInterface,
CIDP: CreateInherentDataProviders<Block, ()> + 'static,
RClient: RelayChainInterface + Send + Clone + 'static,
CIDP: CreateInherentDataProviders<Block, ()> + Send + 'static,
CIDP::InherentDataProviders: Send,
BI: BlockImport<Block> + ParachainBlockImportMarker + Send + Sync + 'static,
SO: SyncOracle + Send + Sync + Clone + 'static,
Proposer: ProposerInterface<Block>,
CS: CollatorServiceInterface<Block>,
Proposer: ProposerInterface<Block> + Send + Sync + 'static,
CS: CollatorServiceInterface<Block> + Send + Sync + 'static,
P: Pair,
P::Public: AppPublic + Member,
P::Public: AppPublic + Member + Codec,
P::Signature: TryFrom<Vec<u8>> + Member + Codec,
{
async move {
let mut collation_requests = cumulus_client_collator::relay_chain_driven::init(
params.key,
params.collator_key,
params.para_id,
params.overseer_handle,
)
@@ -180,10 +200,7 @@ pub async fn run<Block, P, BI, CIDP, Client, RClient, SO, Proposer, CS>(
&claim,
None,
(parachain_inherent_data, other_inherent_data),
// TODO [https://github.com/paritytech/cumulus/issues/2439]
// We should call out to a pluggable interface that provides
// the proposal duration.
Duration::from_millis(500),
params.authoring_duration,
// Set the block limit to 50% of the maximum PoV size.
//
// TODO: If we got benchmarking that includes the proof size,
@@ -197,3 +214,4 @@ pub async fn run<Block, P, BI, CIDP, Client, RClient, SO, Proposer, CS>(
request.complete(Some(CollationResult { collation, result_sender }));
}
}
}
@@ -43,6 +43,8 @@ use cumulus_primitives_core::{
};
use cumulus_relay_chain_interface::RelayChainInterface;
use polkadot_node_primitives::SubmitCollationParams;
use polkadot_node_subsystem::messages::CollationGenerationMessage;
use polkadot_overseer::Handle as OverseerHandle;
use polkadot_primitives::{CollatorPair, Id as ParaId, OccupiedCoreAssumption};
@@ -65,28 +67,48 @@ use std::{convert::TryFrom, sync::Arc, time::Duration};
use crate::collator::{self as collator_util, SlotClaim};
/// Parameters for [`run`].
pub struct Params<BI, CIDP, Client, Backend, RClient, SO, Proposer, CS> {
pub struct Params<BI, CIDP, Client, Backend, RClient, CHP, SO, Proposer, CS> {
/// Inherent data providers. Only non-consensus inherent data should be provided, i.e.
/// the timestamp, slot, and paras inherents should be omitted, as they are set by this
/// collator.
pub create_inherent_data_providers: CIDP,
/// Used to actually import blocks.
pub block_import: BI,
/// The underlying para client.
pub para_client: Arc<Client>,
/// The para client's backend, used to access the database.
pub para_backend: Arc<Backend>,
pub relay_client: Arc<RClient>,
/// A handle to the relay-chain client.
pub relay_client: RClient,
/// A validation code hash provider, used to get the current validation code hash.
pub code_hash_provider: CHP,
/// A chain synchronization oracle.
pub sync_oracle: SO,
/// The underlying keystore, which should contain Aura consensus keys.
pub keystore: KeystorePtr,
pub key: CollatorPair,
/// The collator key used to sign collations before submitting to validators.
pub collator_key: CollatorPair,
/// The para's ID.
pub para_id: ParaId,
/// A handle to the relay-chain client's "Overseer" or task orchestrator.
pub overseer_handle: OverseerHandle,
/// The length of slots in this chain.
pub slot_duration: SlotDuration,
pub relay_chain_slot_duration: SlotDuration,
/// The length of slots in the relay chain.
pub relay_chain_slot_duration: Duration,
/// The underlying block proposer this should call into.
pub proposer: Proposer,
/// The generic collator service used to plug into this consensus engine.
pub collator_service: CS,
/// The amount of time to spend authoring each block.
pub authoring_duration: Duration,
}
/// Run async-backing-friendly Aura.
pub async fn run<Block, P, BI, CIDP, Client, Backend, RClient, SO, Proposer, CS>(
params: Params<BI, CIDP, Client, Backend, RClient, SO, Proposer, CS>,
) where
pub fn run<Block, P, BI, CIDP, Client, Backend, RClient, CHP, SO, Proposer, CS>(
mut params: Params<BI, CIDP, Client, Backend, RClient, CHP, SO, Proposer, CS>,
) -> impl Future<Output = ()> + Send + 'static
where
Block: BlockT,
Client: ProvideRuntimeApi<Block>
+ BlockOf
@@ -98,15 +120,17 @@ pub async fn run<Block, P, BI, CIDP, Client, Backend, RClient, SO, Proposer, CS>
+ 'static,
Client::Api:
AuraApi<Block, P::Public> + CollectCollationInfo<Block> + AuraUnincludedSegmentApi<Block>,
Backend: sp_blockchain::Backend<Block>,
RClient: RelayChainInterface,
Backend: sc_client_api::Backend<Block> + 'static,
RClient: RelayChainInterface + Clone + 'static,
CIDP: CreateInherentDataProviders<Block, ()> + 'static,
CIDP::InherentDataProviders: Send,
BI: BlockImport<Block> + ParachainBlockImportMarker + Send + Sync + 'static,
SO: SyncOracle + Send + Sync + Clone + 'static,
Proposer: ProposerInterface<Block>,
CS: CollatorServiceInterface<Block>,
Proposer: ProposerInterface<Block> + Send + Sync + 'static,
CS: CollatorServiceInterface<Block> + Send + Sync + 'static,
CHP: consensus_common::ValidationCodeHashProvider<Block::Hash> + Send + 'static,
P: Pair,
P::Public: AppPublic + Member,
P::Public: AppPublic + Member + Codec,
P::Signature: TryFrom<Vec<u8>> + Member + Codec,
{
// This is an arbitrary value which is likely guaranteed to exceed any reasonable
@@ -117,7 +141,16 @@ pub async fn run<Block, P, BI, CIDP, Client, Backend, RClient, SO, Proposer, CS>
// rules specified by the parachain's runtime and thus will never be too deep.
const PARENT_SEARCH_DEPTH: usize = 10;
let mut import_notifications = match params.relay_client.import_notification_stream().await {
async move {
cumulus_client_collator::initialize_collator_subsystems(
&mut params.overseer_handle,
params.collator_key,
params.para_id,
)
.await;
let mut import_notifications = match params.relay_client.import_notification_stream().await
{
Ok(s) => s,
Err(err) => {
tracing::error!(
@@ -169,7 +202,19 @@ pub async fn run<Block, P, BI, CIDP, Client, Backend, RClient, SO, Proposer, CS>
params.relay_chain_slot_duration,
) {
None => continue,
Some((_, t)) => (Slot::from_timestamp(t, params.slot_duration), t),
Some((r_s, t)) => {
let our_slot = Slot::from_timestamp(t, params.slot_duration);
tracing::debug!(
target: crate::LOG_TARGET,
relay_slot = ?r_s,
para_slot = ?our_slot,
timestamp = ?t,
slot_duration = ?params.slot_duration,
relay_chain_slot_duration = ?params.relay_chain_slot_duration,
"Adjusted relay-chain slot to parachain slot"
);
(our_slot, t)
},
};
let parent_search_params = ParentSearchParams {
@@ -180,7 +225,8 @@ pub async fn run<Block, P, BI, CIDP, Client, Backend, RClient, SO, Proposer, CS>
ignore_alternative_branches: true,
};
let potential_parents = cumulus_client_consensus_common::find_potential_parents::<Block>(
let potential_parents =
cumulus_client_consensus_common::find_potential_parents::<Block>(
parent_search_params,
&*params.para_backend,
&params.relay_client,
@@ -233,12 +279,23 @@ pub async fn run<Block, P, BI, CIDP, Client, Backend, RClient, SO, Proposer, CS>
// at any block, so we need to re-claim our slot every time.
let mut parent_hash = initial_parent.hash;
let mut parent_header = initial_parent.header;
loop {
let overseer_handle = &mut params.overseer_handle;
// This needs to change to support elastic scaling, but for continuously
// scheduled chains this ensures that the backlog will grow steadily.
for n_built in 0..2 {
let slot_claim = match can_build_upon(parent_hash).await {
None => break,
Some(c) => c,
};
tracing::debug!(
target: crate::LOG_TARGET,
?relay_parent,
unincluded_segment_len = initial_parent.depth + n_built,
"Slot claimed. Building"
);
let validation_data = PersistedValidationData {
parent_head: parent_header.encode().into(),
relay_parent_number: *relay_parent_header.number(),
@@ -264,6 +321,15 @@ pub async fn run<Block, P, BI, CIDP, Client, Backend, RClient, SO, Proposer, CS>
Ok(x) => x,
};
let validation_code_hash = match params.code_hash_provider.code_hash_at(parent_hash)
{
None => {
tracing::error!(target: crate::LOG_TARGET, ?parent_hash, "Could not fetch validation code hash");
break
},
Some(v) => v,
};
match collator
.collate(
&parent_header,
@@ -279,16 +345,33 @@ pub async fn run<Block, P, BI, CIDP, Client, Backend, RClient, SO, Proposer, CS>
)
.await
{
Ok((_collation, block_data, new_block_hash)) => {
parent_hash = new_block_hash;
parent_header = block_data.into_header();
Ok((collation, block_data, new_block_hash)) => {
// Here we are assuming that the import logic protects against equivocations
// and provides sybil-resistance, as it should.
collator.collator_service().announce_block(new_block_hash, None);
// TODO [https://github.com/paritytech/polkadot/issues/5056]:
// announce collation to relay-chain validators.
// Send a submit-collation message to the collation generation subsystem,
// which then distributes this to validators.
//
// Here we are assuming that the leaf is imported, as we've gotten an
// import notification.
overseer_handle
.send_msg(
CollationGenerationMessage::SubmitCollation(
SubmitCollationParams {
relay_parent,
collation,
parent_head: parent_header.encode().into(),
validation_code_hash,
result_sender: None,
},
),
"SubmitCollation",
)
.await;
parent_hash = new_block_hash;
parent_header = block_data.into_header();
},
Err(err) => {
tracing::error!(target: crate::LOG_TARGET, ?err);
@@ -298,6 +381,7 @@ pub async fn run<Block, P, BI, CIDP, Client, Backend, RClient, SO, Proposer, CS>
}
}
}
}
// Checks if we own the slot at the given block and whether there
// is space in the unincluded segment.
@@ -324,7 +408,9 @@ where
// be legal. Skipping the runtime API query here allows us to seamlessly run this
// collator against chains which have not yet upgraded their runtime.
if parent_hash != included_block {
runtime_api.can_build_upon(parent_hash, included_block, slot).ok()?;
if !runtime_api.can_build_upon(parent_hash, included_block, slot).ok()? {
return None
}
}
Some(SlotClaim::unchecked::<P>(author_pub, slot, timestamp))
+3
View File
@@ -76,6 +76,7 @@ impl<B, CIDP, W> Clone for AuraConsensus<B, CIDP, W> {
}
/// Parameters of [`AuraConsensus::build`].
#[deprecated = "Use the `aura::collators::basic` collator instead"]
pub struct BuildAuraConsensusParams<PF, BI, CIDP, Client, BS, SO> {
pub proposer_factory: PF,
pub create_inherent_data_providers: CIDP,
@@ -98,6 +99,8 @@ where
CIDP::InherentDataProviders: InherentDataProviderExt,
{
/// Create a new boxed instance of AURA consensus.
#[allow(deprecated)]
#[deprecated = "Use the `aura::collators::basic` collator instead"]
pub fn build<P, Client, BI, SO, PF, BS, Error>(
BuildAuraConsensusParams {
proposer_factory,
@@ -43,3 +43,4 @@ sp-tracing = { git = "https://github.com/paritytech/substrate", branch = "master
# Cumulus
cumulus-test-client = { path = "../../../test/client" }
cumulus-test-relay-sproof-builder = { path = "../../../test/relay-sproof-builder" }
+38 -9
View File
@@ -16,7 +16,7 @@
use codec::Decode;
use polkadot_primitives::{
Block as PBlock, Hash as PHash, Header as PHeader, PersistedValidationData,
Block as PBlock, Hash as PHash, Header as PHeader, PersistedValidationData, ValidationCodeHash,
};
use cumulus_primitives_core::{
@@ -25,13 +25,14 @@ use cumulus_primitives_core::{
};
use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface};
use sc_client_api::Backend;
use sc_client_api::{Backend, HeaderBackend};
use sc_consensus::{shared_data::SharedData, BlockImport, ImportResult};
use sp_consensus_slots::{Slot, SlotDuration};
use sp_blockchain::Backend as BlockchainBackend;
use sp_consensus_slots::Slot;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use sp_timestamp::Timestamp;
use std::sync::Arc;
use std::{sync::Arc, time::Duration};
mod level_monitor;
mod parachain_consensus;
@@ -45,6 +46,21 @@ pub use level_monitor::{LevelLimit, MAX_LEAVES_PER_LEVEL_SENSIBLE_DEFAULT};
pub mod import_queue;
/// Provides the hash of validation code used for authoring/execution of blocks at a given
/// hash.
pub trait ValidationCodeHashProvider<Hash> {
fn code_hash_at(&self, at: Hash) -> Option<ValidationCodeHash>;
}
impl<F, Hash> ValidationCodeHashProvider<Hash> for F
where
F: Fn(Hash) -> Option<ValidationCodeHash>,
{
fn code_hash_at(&self, at: Hash) -> Option<ValidationCodeHash> {
(self)(at)
}
}
/// The result of [`ParachainConsensus::produce_candidate`].
pub struct ParachainCandidate<B> {
/// The block that was built for this candidate.
@@ -237,22 +253,35 @@ pub struct PotentialParent<B: BlockT> {
/// pending parachain block (when `max_depth` >= 1), or all of the following hold:
/// * its parent is a potential parent
/// * its relay-parent is within `ancestry_lookback` of the targeted relay-parent.
/// * its relay-parent is within the same session as the targeted relay-parent.
/// * the block number is within `max_depth` blocks of the included block
pub async fn find_potential_parents<B: BlockT>(
params: ParentSearchParams,
client: &impl sp_blockchain::Backend<B>,
client: &impl Backend<B>,
relay_client: &impl RelayChainInterface,
) -> Result<Vec<PotentialParent<B>>, RelayChainError> {
// 1. Build up the ancestry record of the relay chain to compare against.
let rp_ancestry = {
let mut ancestry = Vec::with_capacity(params.ancestry_lookback + 1);
let mut current_rp = params.relay_parent;
let mut required_session = None;
while ancestry.len() <= params.ancestry_lookback {
let header = match relay_client.header(RBlockId::hash(current_rp)).await? {
None => break,
Some(h) => h,
};
let session = relay_client.session_index_for_child(current_rp).await?;
if let Some(required_session) = required_session {
// Respect the relay-chain rule not to cross session boundaries.
if session != required_session {
break
}
} else {
required_session = Some(session);
}
ancestry.push((current_rp, *header.state_root()));
current_rp = *header.parent_hash();
@@ -339,7 +368,7 @@ pub async fn find_potential_parents<B: BlockT>(
}
// push children onto search frontier.
for child in client.children(hash).ok().into_iter().flatten() {
for child in client.blockchain().children(hash).ok().into_iter().flatten() {
let aligned_with_pending = parent_aligned_with_pending &&
if child_depth == 1 {
pending_hash.as_ref().map_or(true, |h| &child == h)
@@ -351,7 +380,7 @@ pub async fn find_potential_parents<B: BlockT>(
continue
}
let header = match client.header(child) {
let header = match client.blockchain().header(child) {
Ok(Some(h)) => h,
Ok(None) => continue,
Err(_) => continue,
@@ -372,12 +401,12 @@ pub async fn find_potential_parents<B: BlockT>(
/// Get the relay-parent slot and timestamp from a header.
pub fn relay_slot_and_timestamp(
relay_parent_header: &PHeader,
relay_chain_slot_duration: SlotDuration,
relay_chain_slot_duration: Duration,
) -> Option<(Slot, Timestamp)> {
sc_consensus_babe::find_pre_digest::<PBlock>(relay_parent_header)
.map(|babe_pre_digest| {
let slot = babe_pre_digest.slot();
let t = Timestamp::new(relay_chain_slot_duration.as_millis() * *slot);
let t = Timestamp::new(relay_chain_slot_duration.as_millis() as u64 * *slot);
(slot, t)
})
+53 -20
View File
@@ -28,9 +28,11 @@ use cumulus_test_client::{
runtime::{Block, Hash, Header},
Backend, Client, InitBlockBuilder, TestClientBuilder, TestClientBuilderExt,
};
use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
use futures::{channel::mpsc, executor::block_on, select, FutureExt, Stream, StreamExt};
use futures_timer::Delay;
use sc_client_api::{blockchain::Backend as _, Backend as _, UsageProvider};
use polkadot_primitives::HeadData;
use sc_client_api::{Backend as _, UsageProvider};
use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy};
use sp_consensus::{BlockOrigin, BlockStatus};
use std::{
@@ -213,17 +215,36 @@ impl RelayChainInterface for Relaychain {
}
}
fn sproof_with_best_parent(client: &Client) -> RelayStateSproofBuilder {
let best_hash = client.chain_info().best_hash;
sproof_with_parent_by_hash(client, best_hash)
}
fn sproof_with_parent_by_hash(client: &Client, hash: PHash) -> RelayStateSproofBuilder {
let header = client.header(hash).ok().flatten().expect("No header for parent block");
sproof_with_parent(HeadData(header.encode()))
}
fn sproof_with_parent(parent: HeadData) -> RelayStateSproofBuilder {
let mut x = RelayStateSproofBuilder::default();
x.para_id = cumulus_test_client::runtime::PARACHAIN_ID.into();
x.included_para_head = Some(parent);
x
}
fn build_block<B: InitBlockBuilder>(
builder: &B,
sproof: RelayStateSproofBuilder,
at: Option<Hash>,
timestamp: Option<u64>,
) -> Block {
let builder = match at {
Some(at) => match timestamp {
Some(ts) => builder.init_block_builder_with_timestamp(at, None, Default::default(), ts),
None => builder.init_block_builder_at(at, None, Default::default()),
Some(ts) => builder.init_block_builder_with_timestamp(at, None, sproof, ts),
None => builder.init_block_builder_at(at, None, sproof),
},
None => builder.init_block_builder(None, Default::default()),
None => builder.init_block_builder(None, sproof),
};
let mut block = builder.build().unwrap().block;
@@ -264,22 +285,27 @@ fn import_block_sync<I: BlockImport<Block>>(
block_on(import_block(importer, block, origin, import_as_best));
}
fn build_and_import_block_ext<B: InitBlockBuilder, I: BlockImport<Block>>(
builder: &B,
fn build_and_import_block_ext<I: BlockImport<Block>>(
client: &Client,
origin: BlockOrigin,
import_as_best: bool,
importer: &mut I,
at: Option<Hash>,
timestamp: Option<u64>,
) -> Block {
let block = build_block(builder, at, timestamp);
let sproof = match at {
None => sproof_with_best_parent(client),
Some(at) => sproof_with_parent_by_hash(client, at),
};
let block = build_block(client, sproof, at, timestamp);
import_block_sync(importer, block.clone(), origin, import_as_best);
block
}
fn build_and_import_block(mut client: Arc<Client>, import_as_best: bool) -> Block {
build_and_import_block_ext(
&*client.clone(),
&client.clone(),
BlockOrigin::Own,
import_as_best,
&mut client,
@@ -341,7 +367,12 @@ fn follow_new_best_with_dummy_recovery_works() {
Some(recovery_chan_tx),
);
let block = build_block(&*client, None, None);
let sproof = {
let best = client.chain_info().best_hash;
let header = client.header(best).ok().flatten().expect("No header for best");
sproof_with_parent(HeadData(header.encode()))
};
let block = build_block(&*client, sproof, None, None);
let block_clone = block.clone();
let client_clone = client.clone();
@@ -427,7 +458,8 @@ fn follow_finalized_does_not_stop_on_unknown_block() {
let block = build_and_import_block(client.clone(), false);
let unknown_block = {
let block_builder = client.init_block_builder_at(block.hash(), None, Default::default());
let sproof = sproof_with_parent_by_hash(&client, block.hash());
let block_builder = client.init_block_builder_at(block.hash(), None, sproof);
block_builder.build().unwrap().block
};
@@ -476,7 +508,8 @@ fn follow_new_best_sets_best_after_it_is_imported() {
let block = build_and_import_block(client.clone(), false);
let unknown_block = {
let block_builder = client.init_block_builder_at(block.hash(), None, Default::default());
let sproof = sproof_with_parent_by_hash(&client, block.hash());
let block_builder = client.init_block_builder_at(block.hash(), None, sproof);
block_builder.build().unwrap().block
};
@@ -599,7 +632,7 @@ fn prune_blocks_on_level_overflow() {
);
let block0 = build_and_import_block_ext(
&*client,
&client,
BlockOrigin::NetworkInitialSync,
true,
&mut para_import,
@@ -611,7 +644,7 @@ fn prune_blocks_on_level_overflow() {
let blocks1 = (0..LEVEL_LIMIT)
.map(|i| {
build_and_import_block_ext(
&*client,
&client,
if i == 1 { BlockOrigin::NetworkInitialSync } else { BlockOrigin::Own },
i == 1,
&mut para_import,
@@ -625,7 +658,7 @@ fn prune_blocks_on_level_overflow() {
let blocks2 = (0..2)
.map(|i| {
build_and_import_block_ext(
&*client,
&client,
BlockOrigin::Own,
false,
&mut para_import,
@@ -653,7 +686,7 @@ fn prune_blocks_on_level_overflow() {
assert_eq!(best, blocks1[1].header.hash());
let block13 = build_and_import_block_ext(
&*client,
&client,
BlockOrigin::Own,
false,
&mut para_import,
@@ -672,7 +705,7 @@ fn prune_blocks_on_level_overflow() {
assert_eq!(leaves, expected);
let block14 = build_and_import_block_ext(
&*client,
&client,
BlockOrigin::Own,
false,
&mut para_import,
@@ -710,7 +743,7 @@ fn restore_limit_monitor() {
);
let block00 = build_and_import_block_ext(
&*client,
&client,
BlockOrigin::NetworkInitialSync,
true,
&mut para_import,
@@ -722,7 +755,7 @@ fn restore_limit_monitor() {
let blocks1 = (0..LEVEL_LIMIT + 1)
.map(|i| {
build_and_import_block_ext(
&*client,
&client,
if i == 1 { BlockOrigin::NetworkInitialSync } else { BlockOrigin::Own },
i == 1,
&mut para_import,
@@ -736,7 +769,7 @@ fn restore_limit_monitor() {
let _ = (0..LEVEL_LIMIT)
.map(|i| {
build_and_import_block_ext(
&*client,
&client,
BlockOrigin::Own,
false,
&mut para_import,
@@ -770,7 +803,7 @@ fn restore_limit_monitor() {
std::mem::drop(monitor);
let block13 = build_and_import_block_ext(
&*client,
&client,
BlockOrigin::Own,
false,
&mut para_import,
@@ -22,7 +22,7 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master
sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" }
# Polkadot
polkadot-cli = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false, features = ["cli"] }
polkadot-cli = { git = "https://github.com/paritytech/polkadot", default-features = false, features = ["cli"] , branch = "master" }
polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "master" }
# Cumulus
@@ -41,3 +41,6 @@ metered = { package = "prioritized-metered-channel", version = "0.2.0" }
# Cumulus
cumulus-test-service = { path = "../../test/service" }
[features]
network-protocol-staging = ["polkadot-service/network-protocol-staging"]
@@ -43,3 +43,6 @@ tracing = "0.1.37"
async-trait = "0.1.73"
futures = "0.3.28"
tokio = { version = "1.32.0", features = ["macros"] }
[features]
network-protocol-staging = ["polkadot-node-network-protocol/network-protocol-staging"]
@@ -21,7 +21,10 @@ use cumulus_relay_chain_rpc_interface::RelayChainRpcClient;
use futures::{Stream, StreamExt};
use polkadot_core_primitives::{Block, BlockNumber, Hash, Header};
use polkadot_overseer::RuntimeApiSubsystemClient;
use polkadot_primitives::slashing;
use polkadot_primitives::{
slashing,
vstaging::{AsyncBackingParams, BackingState},
};
use sc_authority_discovery::{AuthorityDiscovery, Error as AuthorityDiscoveryError};
use sp_api::{ApiError, RuntimeApiInfo};
@@ -334,6 +337,18 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient {
.parachain_host_submit_report_dispute_lost(at, dispute_proof, key_ownership_proof)
.await?)
}
async fn staging_async_backing_params(&self, at: Hash) -> Result<AsyncBackingParams, ApiError> {
Ok(self.rpc_client.parachain_host_staging_async_backing_params(at).await?)
}
async fn staging_para_backing_state(
&self,
at: Hash,
para_id: cumulus_primitives_core::ParaId,
) -> Result<Option<BackingState>, ApiError> {
Ok(self.rpc_client.parachain_host_staging_para_backing_state(at, para_id).await?)
}
}
#[async_trait::async_trait]
@@ -29,8 +29,8 @@ use polkadot_node_core_runtime_api::RuntimeApiSubsystem;
use polkadot_node_network_protocol::{
peer_set::PeerSetProtocolNames,
request_response::{
v1::{AvailableDataFetchingRequest, CollationFetchingRequest},
IncomingRequestReceiver, ReqProtocolNames,
v1::{self, AvailableDataFetchingRequest},
vstaging, IncomingRequestReceiver, ReqProtocolNames,
},
};
use polkadot_node_subsystem_util::metrics::{prometheus::Registry, Metrics};
@@ -60,8 +60,11 @@ pub(crate) struct CollatorOverseerGenArgs<'a> {
pub sync_oracle: Box<dyn sp_consensus::SyncOracle + Send>,
/// Underlying authority discovery service.
pub authority_discovery_service: AuthorityDiscoveryService,
/// Receiver for collation request protocol
pub collation_req_receiver: IncomingRequestReceiver<CollationFetchingRequest>,
/// Receiver for collation request protocol v1.
pub collation_req_receiver_v1: IncomingRequestReceiver<v1::CollationFetchingRequest>,
/// Receiver for collation request protocol vstaging.
pub collation_req_receiver_vstaging:
IncomingRequestReceiver<vstaging::CollationFetchingRequest>,
/// Receiver for availability request protocol
pub available_data_req_receiver: IncomingRequestReceiver<AvailableDataFetchingRequest>,
/// Prometheus registry, commonly used for production systems, less so for test.
@@ -83,7 +86,8 @@ fn build_overseer(
network_service,
sync_oracle,
authority_discovery_service,
collation_req_receiver,
collation_req_receiver_v1,
collation_req_receiver_vstaging,
available_data_req_receiver,
registry,
spawner,
@@ -112,12 +116,13 @@ fn build_overseer(
.chain_api(DummySubsystem)
.collation_generation(CollationGenerationSubsystem::new(Metrics::register(registry)?))
.collator_protocol({
let side = ProtocolSide::Collator(
network_service.local_peer_id(),
let side = ProtocolSide::Collator {
peer_id: network_service.local_peer_id(),
collator_pair,
collation_req_receiver,
Metrics::register(registry)?,
);
request_receiver_v1: collation_req_receiver_v1,
request_receiver_vstaging: collation_req_receiver_vstaging,
metrics: Metrics::register(registry)?,
};
CollatorProtocolSubsystem::new(side)
})
.network_bridge_rx(NetworkBridgeRxSubsystem::new(
@@ -141,6 +146,7 @@ fn build_overseer(
spawner.clone(),
))
.statement_distribution(DummySubsystem)
.prospective_parachains(DummySubsystem)
.approval_distribution(DummySubsystem)
.approval_voting(DummySubsystem)
.gossip_support(DummySubsystem)
@@ -22,7 +22,9 @@ use network::build_collator_network;
use polkadot_network_bridge::{peer_sets_info, IsAuthority};
use polkadot_node_network_protocol::{
peer_set::PeerSetProtocolNames,
request_response::{v1, IncomingRequest, IncomingRequestReceiver, Protocol, ReqProtocolNames},
request_response::{
v1, vstaging, IncomingRequest, IncomingRequestReceiver, Protocol, ReqProtocolNames,
},
};
use polkadot_node_subsystem_util::metrics::prometheus::Registry;
@@ -148,7 +150,7 @@ async fn new_minimal_relay_chain(
}
let request_protocol_names = ReqProtocolNames::new(genesis_hash, config.chain_spec.fork_id());
let (collation_req_receiver, available_data_req_receiver) =
let (collation_req_receiver_v1, collation_req_receiver_vstaging, available_data_req_receiver) =
build_request_response_protocol_receivers(&request_protocol_names, &mut net_config);
let best_header = relay_chain_rpc_client
@@ -177,7 +179,8 @@ async fn new_minimal_relay_chain(
network_service: network.clone(),
sync_oracle,
authority_discovery_service,
collation_req_receiver,
collation_req_receiver_v1,
collation_req_receiver_vstaging,
available_data_req_receiver,
registry: prometheus_registry.as_ref(),
spawner: task_manager.spawn_handle(),
@@ -199,9 +202,13 @@ fn build_request_response_protocol_receivers(
config: &mut FullNetworkConfiguration,
) -> (
IncomingRequestReceiver<v1::CollationFetchingRequest>,
IncomingRequestReceiver<vstaging::CollationFetchingRequest>,
IncomingRequestReceiver<v1::AvailableDataFetchingRequest>,
) {
let (collation_req_receiver, cfg) =
let (collation_req_receiver_v1, cfg) =
IncomingRequest::get_config_receiver(request_protocol_names);
config.add_request_response_protocol(cfg);
let (collation_req_receiver_vstaging, cfg) =
IncomingRequest::get_config_receiver(request_protocol_names);
config.add_request_response_protocol(cfg);
let (available_data_req_receiver, cfg) =
@@ -209,5 +216,5 @@ fn build_request_response_protocol_receivers(
config.add_request_response_protocol(cfg);
let cfg = Protocol::ChunkFetchingV1.get_outbound_only_config(request_protocol_names);
config.add_request_response_protocol(cfg);
(collation_req_receiver, available_data_req_receiver)
(collation_req_receiver_v1, collation_req_receiver_vstaging, available_data_req_receiver)
}
@@ -30,7 +30,9 @@ use sp_storage::StorageKey;
use cumulus_primitives_core::{
relay_chain::{
slashing, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash,
slashing,
vstaging::{AsyncBackingParams, BackingState},
BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash,
CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo,
Hash as RelayHash, Header as RelayHeader, InboundHrmpMessage, OccupiedCoreAssumption,
PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode,
@@ -508,6 +510,33 @@ impl RelayChainRpcClient {
.await
}
#[allow(missing_docs)]
pub async fn parachain_host_staging_async_backing_params(
&self,
at: RelayHash,
) -> Result<AsyncBackingParams, RelayChainError> {
self.call_remote_runtime_function(
"ParachainHost_staging_async_backing_params",
at,
None::<()>,
)
.await
}
#[allow(missing_docs)]
pub async fn parachain_host_staging_para_backing_state(
&self,
at: RelayHash,
para_id: ParaId,
) -> Result<Option<BackingState>, RelayChainError> {
self.call_remote_runtime_function(
"ParachainHost_staging_para_backing_state",
at,
Some(para_id),
)
.await
}
/// Get a stream of all imported relay chain headers
pub fn get_imported_heads_stream(&self) -> Result<Receiver<RelayHeader>, RelayChainError> {
self.ws_client.get_imported_heads_stream()
+6
View File
@@ -39,3 +39,9 @@ cumulus-primitives-core = { path = "../../primitives/core" }
cumulus-relay-chain-interface = { path = "../relay-chain-interface" }
cumulus-relay-chain-inprocess-interface = { path = "../relay-chain-inprocess-interface" }
cumulus-relay-chain-minimal-node = { path = "../relay-chain-minimal-node" }
[features]
network-protocol-staging = [
"cumulus-relay-chain-minimal-node/network-protocol-staging",
"cumulus-relay-chain-inprocess-interface/network-protocol-staging"
]
+186 -80
View File
@@ -20,7 +20,7 @@
use cumulus_client_cli::CollatorOptions;
use cumulus_client_consensus_common::ParachainConsensus;
use cumulus_client_network::RequireSecondedInBlockAnnounce;
use cumulus_client_network::{AssumeSybilResistance, RequireSecondedInBlockAnnounce};
use cumulus_client_pov_recovery::{PoVRecovery, RecoveryDelayRange, RecoveryHandle};
use cumulus_primitives_core::{CollectCollationInfo, ParaId};
use cumulus_relay_chain_inprocess_interface::build_inprocess_relay_chain;
@@ -56,7 +56,18 @@ use std::{sync::Arc, time::Duration};
const RECOVERY_CHAN_SIZE: usize = 8;
const LOG_TARGET_SYNC: &str = "sync::cumulus";
/// Parameters given to [`start_collator`].
/// A hint about how long the node should wait before attempting to recover missing block data
/// from the data availability layer.
pub enum DARecoveryProfile {
/// Collators use an aggressive recovery profile by default.
Collator,
/// Full nodes use a passive recovery profile by default, as they are not direct
/// victims of withholding attacks.
FullNode,
/// Provide an explicit recovery profile.
Other(RecoveryDelayRange),
}
pub struct StartCollatorParams<'a, Block: BlockT, BS, Client, RCInterface, Spawner> {
pub block_status: Arc<BS>,
pub client: Arc<Client>,
@@ -73,11 +84,39 @@ pub struct StartCollatorParams<'a, Block: BlockT, BS, Client, RCInterface, Spawn
pub sync_service: Arc<SyncingService<Block>>,
}
/// Parameters given to [`start_relay_chain_tasks`].
pub struct StartRelayChainTasksParams<'a, Block: BlockT, Client, RCInterface> {
pub client: Arc<Client>,
pub announce_block: Arc<dyn Fn(Block::Hash, Option<Vec<u8>>) + Send + Sync>,
pub para_id: ParaId,
pub relay_chain_interface: RCInterface,
pub task_manager: &'a mut TaskManager,
pub da_recovery_profile: DARecoveryProfile,
pub import_queue: Box<dyn ImportQueueService<Block>>,
pub relay_chain_slot_duration: Duration,
pub recovery_handle: Box<dyn RecoveryHandle>,
pub sync_service: Arc<SyncingService<Block>>,
}
/// Parameters given to [`start_full_node`].
pub struct StartFullNodeParams<'a, Block: BlockT, Client, RCInterface> {
pub para_id: ParaId,
pub client: Arc<Client>,
pub relay_chain_interface: RCInterface,
pub task_manager: &'a mut TaskManager,
pub announce_block: Arc<dyn Fn(Block::Hash, Option<Vec<u8>>) + Send + Sync>,
pub relay_chain_slot_duration: Duration,
pub import_queue: Box<dyn ImportQueueService<Block>>,
pub recovery_handle: Box<dyn RecoveryHandle>,
pub sync_service: Arc<SyncingService<Block>>,
}
/// Start a collator node for a parachain.
///
/// A collator is similar to a validator in a normal blockchain.
/// It is responsible for producing blocks and sending the blocks to a
/// parachain validator for validation and inclusion into the relay chain.
#[deprecated = "use start_relay_chain_tasks instead"]
pub async fn start_collator<'a, Block, BS, Client, Backend, RCInterface, Spawner>(
StartCollatorParams {
block_status,
@@ -113,41 +152,24 @@ where
RCInterface: RelayChainInterface + Clone + 'static,
Backend: BackendT<Block> + 'static,
{
let (recovery_chan_tx, recovery_chan_rx) = mpsc::channel(RECOVERY_CHAN_SIZE);
let consensus = cumulus_client_consensus_common::run_parachain_consensus(
para_id,
client.clone(),
relay_chain_interface.clone(),
announce_block.clone(),
Some(recovery_chan_tx),
);
task_manager
.spawn_essential_handle()
.spawn_blocking("cumulus-consensus", None, consensus);
let pov_recovery = PoVRecovery::new(
recovery_handle,
// We want that collators wait at maximum the relay chain slot duration before starting
// to recover blocks. Additionally, we wait at least half the slot time to give the
// relay chain the chance to increase availability.
RecoveryDelayRange { min: relay_chain_slot_duration / 2, max: relay_chain_slot_duration },
client.clone(),
import_queue,
relay_chain_interface.clone(),
para_id,
recovery_chan_rx,
sync_service,
);
task_manager
.spawn_essential_handle()
.spawn("cumulus-pov-recovery", None, pov_recovery.run());
let overseer_handle = relay_chain_interface
.overseer_handle()
.map_err(|e| sc_service::Error::Application(Box::new(e)))?;
start_relay_chain_tasks(StartRelayChainTasksParams {
client: client.clone(),
announce_block: announce_block.clone(),
para_id,
task_manager,
da_recovery_profile: DARecoveryProfile::Collator,
relay_chain_interface,
import_queue,
relay_chain_slot_duration,
recovery_handle,
sync_service,
})?;
#[allow(deprecated)]
cumulus_client_collator::start_collator(cumulus_client_collator::StartCollatorParams {
runtime_api: client,
block_status,
@@ -163,23 +185,101 @@ where
Ok(())
}
/// Parameters given to [`start_full_node`].
pub struct StartFullNodeParams<'a, Block: BlockT, Client, RCInterface> {
pub para_id: ParaId,
pub client: Arc<Client>,
pub relay_chain_interface: RCInterface,
pub task_manager: &'a mut TaskManager,
pub announce_block: Arc<dyn Fn(Block::Hash, Option<Vec<u8>>) + Send + Sync>,
pub relay_chain_slot_duration: Duration,
pub import_queue: Box<dyn ImportQueueService<Block>>,
pub recovery_handle: Box<dyn RecoveryHandle>,
pub sync_service: Arc<SyncingService<Block>>,
/// Start necessary consensus tasks related to the relay chain.
///
/// Parachain nodes need to track the state of the relay chain and use the
/// relay chain's data availability service to fetch blocks if they don't
/// arrive via the normal p2p layer (i.e. when authors withhold their blocks deliberately).
///
/// This function spawns work for those side tasks.
pub fn start_relay_chain_tasks<Block, Client, Backend, RCInterface>(
StartRelayChainTasksParams {
client,
announce_block,
para_id,
task_manager,
da_recovery_profile,
relay_chain_interface,
import_queue,
relay_chain_slot_duration,
recovery_handle,
sync_service,
}: StartRelayChainTasksParams<Block, Client, RCInterface>,
) -> sc_service::error::Result<()>
where
Block: BlockT,
Client: Finalizer<Block, Backend>
+ UsageProvider<Block>
+ Send
+ Sync
+ BlockBackend<Block>
+ BlockchainEvents<Block>
+ 'static,
for<'a> &'a Client: BlockImport<Block>,
Backend: BackendT<Block> + 'static,
RCInterface: RelayChainInterface + Clone + 'static,
{
let (recovery_chan_tx, recovery_chan_rx) = mpsc::channel(RECOVERY_CHAN_SIZE);
let consensus = cumulus_client_consensus_common::run_parachain_consensus(
para_id,
client.clone(),
relay_chain_interface.clone(),
announce_block.clone(),
Some(recovery_chan_tx),
);
task_manager
.spawn_essential_handle()
.spawn_blocking("cumulus-consensus", None, consensus);
let da_recovery_profile = match da_recovery_profile {
DARecoveryProfile::Collator => {
// We want that collators wait at maximum the relay chain slot duration before starting
// to recover blocks. Additionally, we wait at least half the slot time to give the
// relay chain the chance to increase availability.
RecoveryDelayRange {
min: relay_chain_slot_duration / 2,
max: relay_chain_slot_duration,
}
},
DARecoveryProfile::FullNode => {
// Full nodes should at least wait 2.5 minutes (assuming 6 seconds slot duration) and
// in maximum 5 minutes before starting to recover blocks. Collators should already
// start the recovery way before full nodes try to recover a certain block and then
// share the block with the network using "the normal way". Full nodes are just the
// "last resort" for block recovery.
RecoveryDelayRange {
min: relay_chain_slot_duration * 25,
max: relay_chain_slot_duration * 50,
}
},
DARecoveryProfile::Other(profile) => profile,
};
let pov_recovery = PoVRecovery::new(
recovery_handle,
da_recovery_profile,
client.clone(),
import_queue,
relay_chain_interface.clone(),
para_id,
recovery_chan_rx,
sync_service,
);
task_manager
.spawn_essential_handle()
.spawn("cumulus-pov-recovery", None, pov_recovery.run());
Ok(())
}
/// Start a full node for a parachain.
///
/// A full node will only sync the given parachain and will follow the
/// tip of the chain.
#[deprecated = "use start_relay_chain_tasks instead"]
pub fn start_full_node<Block, Client, Backend, RCInterface>(
StartFullNodeParams {
client,
@@ -206,44 +306,26 @@ where
Backend: BackendT<Block> + 'static,
RCInterface: RelayChainInterface + Clone + 'static,
{
let (recovery_chan_tx, recovery_chan_rx) = mpsc::channel(RECOVERY_CHAN_SIZE);
let consensus = cumulus_client_consensus_common::run_parachain_consensus(
para_id,
client.clone(),
relay_chain_interface.clone(),
announce_block,
Some(recovery_chan_tx),
);
task_manager
.spawn_essential_handle()
.spawn_blocking("cumulus-consensus", None, consensus);
let pov_recovery = PoVRecovery::new(
recovery_handle,
// Full nodes should at least wait 2.5 minutes (assuming 6 seconds slot duration) and
// in maximum 5 minutes before starting to recover blocks. Collators should already start
// the recovery way before full nodes try to recover a certain block and then share the
// block with the network using "the normal way". Full nodes are just the "last resort"
// for block recovery.
RecoveryDelayRange {
min: relay_chain_slot_duration * 25,
max: relay_chain_slot_duration * 50,
},
start_relay_chain_tasks(StartRelayChainTasksParams {
client,
import_queue,
announce_block,
task_manager,
relay_chain_interface,
para_id,
recovery_chan_rx,
relay_chain_slot_duration,
import_queue,
recovery_handle,
sync_service,
);
da_recovery_profile: DARecoveryProfile::FullNode,
})
}
task_manager
.spawn_essential_handle()
.spawn("cumulus-pov-recovery", None, pov_recovery.run());
Ok(())
/// Re-exports of old parachain consensus loop start logic.
#[deprecated = "This is old consensus architecture only for backwards compatibility \
and will be removed in the future"]
pub mod old_consensus {
#[allow(deprecated)]
pub use cumulus_client_collator::{start_collator, start_collator_sync, StartCollatorParams};
}
/// Prepare the parachain's node configuration
@@ -285,6 +367,20 @@ pub async fn build_relay_chain_interface(
}
}
/// The expected level of collator sybil-resistance on the network. This is used to
/// configure the type of metadata passed alongside block announcements on the network.
pub enum CollatorSybilResistance {
/// There is a collator-selection protocol which provides sybil-resistance,
/// such as Aura. Sybil-resistant collator-selection protocols are able to
/// operate more efficiently.
Resistant,
/// There is no collator-selection protocol providing sybil-resistance.
/// In situations such as "free-for-all" collators, the network is unresistant
/// and needs to attach more metadata to block announcements, relying on relay-chain
/// validators to avoid handling unbounded numbers of blocks.
Unresistant,
}
/// Parameters given to [`build_network`].
pub struct BuildNetworkParams<
'a,
@@ -308,6 +404,7 @@ pub struct BuildNetworkParams<
pub relay_chain_interface: RCInterface,
pub spawn_handle: SpawnTaskHandle,
pub import_queue: IQ,
pub sybil_resistance_level: CollatorSybilResistance,
}
/// Build the network service, the network status sinks and an RPC sender.
@@ -321,6 +418,7 @@ pub async fn build_network<'a, Block, Client, RCInterface, IQ>(
spawn_handle,
relay_chain_interface,
import_queue,
sybil_resistance_level,
}: BuildNetworkParams<'a, Block, Client, RCInterface, IQ>,
) -> sc_service::error::Result<(
Arc<NetworkService<Block, Block::Hash>>,
@@ -361,9 +459,17 @@ where
_ => None,
};
let block_announce_validator = match sybil_resistance_level {
CollatorSybilResistance::Resistant => {
let block_announce_validator = AssumeSybilResistance::allow_seconded_messages();
Box::new(block_announce_validator) as Box<_>
},
CollatorSybilResistance::Unresistant => {
let block_announce_validator =
RequireSecondedInBlockAnnounce::new(relay_chain_interface, para_id);
let block_announce_validator_builder = move |_| Box::new(block_announce_validator) as Box<_>;
Box::new(block_announce_validator) as Box<_>
},
};
sc_service::build_network(sc_service::BuildNetworkParams {
config: parachain_config,
@@ -372,7 +478,7 @@ where
transaction_pool,
spawn_handle,
import_queue,
block_announce_validator_builder: Some(Box::new(block_announce_validator_builder)),
block_announce_validator_builder: Some(Box::new(move |_| block_announce_validator)),
warp_sync_params,
})
}
+5
View File
@@ -13,11 +13,15 @@ scale-info = { version = "2.9.0", default-features = false, features = ["derive"
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
pallet-aura = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
pallet-timestamp= { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-application-crypto = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-consensus-aura = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
# Cumulus
cumulus-pallet-parachain-system = { path = "../parachain-system", default-features = false }
[dev-dependencies]
# Cumulus
@@ -35,5 +39,6 @@ std = [
"sp-consensus-aura/std",
"sp-runtime/std",
"sp-std/std",
"cumulus-pallet-parachain-system/std",
]
try-runtime = ["frame-support/try-runtime"]
@@ -0,0 +1,123 @@
// Copyright 2023 Parity Technologies (UK) Ltd.
// This file is part of Cumulus.
// Cumulus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Cumulus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
//! The definition of a [`FixedVelocityConsensusHook`] for consensus logic to manage
//! block velocity.
//!
//! The velocity `V` refers to the rate of block processing by the relay chain.
use super::{pallet, Aura};
use cumulus_pallet_parachain_system::{
self as parachain_system,
consensus_hook::{ConsensusHook, UnincludedSegmentCapacity},
relay_state_snapshot::RelayChainStateProof,
};
use frame_support::pallet_prelude::*;
use sp_consensus_aura::{Slot, SlotDuration};
use sp_std::{marker::PhantomData, num::NonZeroU32};
/// A consensus hook for a fixed block processing velocity and unincluded segment capacity.
///
/// Relay chain slot duration must be provided in milliseconds.
pub struct FixedVelocityConsensusHook<
T,
const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32,
const V: u32,
const C: u32,
>(PhantomData<T>);
impl<
T: pallet::Config,
const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32,
const V: u32,
const C: u32,
> ConsensusHook for FixedVelocityConsensusHook<T, RELAY_CHAIN_SLOT_DURATION_MILLIS, V, C>
where
<T as pallet_timestamp::Config>::Moment: Into<u64>,
{
// Validates the number of authored blocks within the slot with respect to the `V + 1` limit.
fn on_state_proof(state_proof: &RelayChainStateProof) -> (Weight, UnincludedSegmentCapacity) {
// Ensure velocity is non-zero.
let velocity = V.max(1);
let relay_chain_slot = state_proof.read_slot().expect("failed to read relay chain slot");
let (slot, authored) = pallet::Pallet::<T>::slot_info()
.expect("slot info is inserted on block initialization");
// Convert relay chain timestamp.
let relay_chain_timestamp =
u64::from(RELAY_CHAIN_SLOT_DURATION_MILLIS).saturating_mul(*relay_chain_slot);
let para_slot_duration = SlotDuration::from_millis(Aura::<T>::slot_duration().into());
let para_slot_from_relay =
Slot::from_timestamp(relay_chain_timestamp.into(), para_slot_duration);
// Perform checks.
assert_eq!(slot, para_slot_from_relay, "slot number mismatch");
if authored > velocity + 1 {
panic!("authored blocks limit is reached for the slot")
}
let weight = T::DbWeight::get().reads(1);
(
weight,
NonZeroU32::new(sp_std::cmp::max(C, 1))
.expect("1 is the minimum value and non-zero; qed")
.into(),
)
}
}
impl<
T: pallet::Config + parachain_system::Config,
const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32,
const V: u32,
const C: u32,
> FixedVelocityConsensusHook<T, RELAY_CHAIN_SLOT_DURATION_MILLIS, V, C>
{
/// Whether it is legal to extend the chain, assuming the given block is the most
/// recently included one as-of the relay parent that will be built against, and
/// the given slot.
///
/// This should be consistent with the logic the runtime uses when validating blocks to
/// avoid issues.
///
/// When the unincluded segment is empty, i.e. `included_hash == at`, where at is the block
/// whose state we are querying against, this must always return `true` as long as the slot
/// is more recent than the included block itself.
pub fn can_build_upon(included_hash: T::Hash, new_slot: Slot) -> bool {
let velocity = V.max(1);
let (last_slot, authored_so_far) = match pallet::Pallet::<T>::slot_info() {
None => return true,
Some(x) => x,
};
let size_after_included =
parachain_system::Pallet::<T>::unincluded_segment_size_after(included_hash);
// can never author when the unincluded segment is full.
if size_after_included >= C {
return false
}
if last_slot == new_slot {
authored_so_far < velocity + 1
} else {
// disallow slot from moving backwards.
last_slot < new_slot
}
}
}
+24 -2
View File
@@ -29,7 +29,6 @@
//! cumulus_pallet_parachain_system::register_validate_block! {
//! Runtime = Runtime,
//! BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
//! CheckInherents = CheckInherents,
//! }
//! ```
@@ -37,9 +36,12 @@
use frame_support::traits::{ExecuteBlock, FindAuthor};
use sp_application_crypto::RuntimeAppPublic;
use sp_consensus_aura::digests::CompatibleDigestItem;
use sp_consensus_aura::{digests::CompatibleDigestItem, Slot};
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
pub mod consensus_hook;
pub use consensus_hook::FixedVelocityConsensusHook;
type Aura<T> = pallet_aura::Pallet<T>;
pub use pallet::*;
@@ -68,6 +70,19 @@ pub mod pallet {
// Fetch the authorities once to get them into the storage proof of the PoV.
Authorities::<T>::get();
let new_slot = Aura::<T>::current_slot();
let (new_slot, authored) = match SlotInfo::<T>::get() {
Some((slot, authored)) if slot == new_slot => (slot, authored + 1),
Some((slot, _)) if slot < new_slot => (new_slot, 1),
Some(..) => {
panic!("slot moved backwards")
},
None => (new_slot, 1),
};
SlotInfo::<T>::put((new_slot, authored));
T::DbWeight::get().reads_writes(2, 1)
}
}
@@ -84,6 +99,13 @@ pub mod pallet {
ValueQuery,
>;
/// Current slot paired with a number of authored blocks.
///
/// Updated on each block initialization.
#[pallet::storage]
#[pallet::getter(fn slot_info)]
pub(crate) type SlotInfo<T: Config> = StorageValue<_, (Slot, u32), OptionQuery>;
#[pallet::genesis_config]
#[derive(frame_support::DefaultNoBound)]
pub struct GenesisConfig<T: Config> {
@@ -37,6 +37,7 @@ cumulus-primitives-core = { path = "../../primitives/core", default-features = f
cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent", default-features = false }
[dev-dependencies]
assert_matches = "1.5"
hex-literal = "0.4.1"
lazy_static = "1.4"
@@ -78,3 +79,5 @@ runtime-benchmarks = [
]
try-runtime = ["frame-support/try-runtime"]
parameterized-consensus-hook = []
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
use proc_macro2::{Span, TokenStream};
use proc_macro2::Span;
use proc_macro_crate::{crate_name, FoundCrate};
use syn::{
parse::{Parse, ParseStream},
@@ -31,7 +31,7 @@ mod keywords {
struct Input {
runtime: Path,
block_executor: Path,
check_inherents: Path,
check_inherents: Option<Path>,
}
impl Parse for Input {
@@ -59,7 +59,7 @@ impl Parse for Input {
}
}
while runtime.is_none() || block_executor.is_none() || check_inherents.is_none() {
while !input.is_empty() || runtime.is_none() || block_executor.is_none() {
let lookahead = input.lookahead1();
if lookahead.peek(keywords::Runtime) {
@@ -73,15 +73,10 @@ impl Parse for Input {
}
}
let rest = input.parse::<TokenStream>()?;
if !rest.is_empty() {
return Err(Error::new(rest.span(), "Unexpected input data"))
}
Ok(Self {
runtime: runtime.expect("Everything is parsed before; qed"),
block_executor: block_executor.expect("Everything is parsed before; qed"),
check_inherents: check_inherents.expect("Everything is parsed before; qed"),
check_inherents,
})
}
}
@@ -97,7 +92,7 @@ fn crate_() -> Result<Ident, Error> {
#[proc_macro]
pub fn register_validate_block(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let Input { runtime, check_inherents, block_executor } = match syn::parse(input) {
let Input { runtime, block_executor, check_inherents } = match syn::parse(input) {
Ok(t) => t,
Err(e) => return e.into_compile_error().into(),
};
@@ -107,6 +102,17 @@ pub fn register_validate_block(input: proc_macro::TokenStream) -> proc_macro::To
Err(e) => return e.into_compile_error().into(),
};
let check_inherents = match check_inherents {
Some(_check_inherents) => {
quote::quote! { #_check_inherents }
},
None => {
quote::quote! {
#crate_::DummyCheckInherents<<#runtime as #crate_::validate_block::GetRuntimeBlockType>::RuntimeBlock>
}
},
};
if cfg!(not(feature = "std")) {
quote::quote! {
#[doc(hidden)]
@@ -0,0 +1,109 @@
// Copyright 2023 Parity Technologies (UK) Ltd.
// This file is part of Cumulus.
// Cumulus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Cumulus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
//! The definition of a [`ConsensusHook`] trait for consensus logic to manage the backlog
//! of parachain blocks ready to submit to the relay chain, as well as some basic implementations.
use super::relay_state_snapshot::RelayChainStateProof;
use frame_support::weights::Weight;
use sp_std::num::NonZeroU32;
/// The possible capacity of the unincluded segment.
#[derive(Clone)]
pub struct UnincludedSegmentCapacity(UnincludedSegmentCapacityInner);
impl UnincludedSegmentCapacity {
pub(crate) fn get(&self) -> u32 {
match self.0 {
UnincludedSegmentCapacityInner::ExpectParentIncluded => 1,
UnincludedSegmentCapacityInner::Value(v) => v.get(),
}
}
pub(crate) fn is_expecting_included_parent(&self) -> bool {
match self.0 {
UnincludedSegmentCapacityInner::ExpectParentIncluded => true,
UnincludedSegmentCapacityInner::Value(_) => false,
}
}
}
#[derive(Clone)]
pub(crate) enum UnincludedSegmentCapacityInner {
ExpectParentIncluded,
Value(NonZeroU32),
}
impl From<NonZeroU32> for UnincludedSegmentCapacity {
fn from(value: NonZeroU32) -> Self {
UnincludedSegmentCapacity(UnincludedSegmentCapacityInner::Value(value))
}
}
/// The consensus hook for dealing with the unincluded segment.
///
/// Higher-level and user-configurable consensus logic is more informed about the
/// desired unincluded segment length, as well as any rules for adapting it dynamically
/// according to the relay-chain state.
pub trait ConsensusHook {
/// This hook is called partway through the `set_validation_data` inherent in parachain-system.
///
/// The hook is allowed to panic if customized consensus rules aren't met and is required
/// to return a maximum capacity for the unincluded segment with weight consumed.
fn on_state_proof(state_proof: &RelayChainStateProof) -> (Weight, UnincludedSegmentCapacity);
}
/// A special consensus hook for handling the migration to asynchronous backing gracefully,
/// even if collators haven't been updated to provide the last included parent in the state
/// proof yet.
///
/// This behaves as though the parent is included, even if the relay chain state proof doesn't
/// contain the included para head. If the para head is present in the state proof, this does ensure
/// the parent is included.
pub struct ExpectParentIncluded;
impl ConsensusHook for ExpectParentIncluded {
fn on_state_proof(_state_proof: &RelayChainStateProof) -> (Weight, UnincludedSegmentCapacity) {
(
Weight::zero(),
UnincludedSegmentCapacity(UnincludedSegmentCapacityInner::ExpectParentIncluded),
)
}
}
/// A consensus hook for a fixed unincluded segment length. This hook does nothing but
/// set the capacity of the unincluded segment to the constant N.
///
/// Since it is illegal to provide an unincluded segment length of 0, this sets a minimum of
/// 1.
pub struct FixedCapacityUnincludedSegment<const N: u32>;
impl<const N: u32> ConsensusHook for FixedCapacityUnincludedSegment<N> {
fn on_state_proof(_state_proof: &RelayChainStateProof) -> (Weight, UnincludedSegmentCapacity) {
(
Weight::zero(),
NonZeroU32::new(sp_std::cmp::max(N, 1))
.expect("1 is the minimum value and non-zero; qed")
.into(),
)
}
}
/// A fixed-capacity unincluded segment hook, which requires that the parent block is
/// included prior to the current block being authored.
///
/// This is a simple type alias around a fixed-capacity unincluded segment with a size of 1.
pub type RequireParentIncluded = FixedCapacityUnincludedSegment<1>;
+390 -23
View File
@@ -58,12 +58,22 @@ use sp_std::{cmp, collections::btree_map::BTreeMap, prelude::*};
use xcm::latest::XcmHash;
pub mod migration;
mod relay_state_snapshot;
#[macro_use]
pub mod validate_block;
#[cfg(test)]
mod tests;
mod unincluded_segment;
pub mod consensus_hook;
pub mod relay_state_snapshot;
#[macro_use]
pub mod validate_block;
use unincluded_segment::{
Ancestor, HrmpChannelUpdate, HrmpWatermarkUpdate, OutboundBandwidthLimits, SegmentTracker,
UsedBandwidth,
};
pub use consensus_hook::{ConsensusHook, ExpectParentIncluded};
/// Register the `validate_block` function that is used by parachains to validate blocks on a
/// validator.
///
@@ -136,6 +146,23 @@ impl CheckAssociatedRelayNumber for AnyRelayNumber {
fn check_associated_relay_number(_: RelayChainBlockNumber, _: RelayChainBlockNumber) {}
}
/// Provides an implementation of [`CheckAssociatedRelayNumber`].
///
/// It will ensure that the associated relay block number monotonically increases between Parachain
/// blocks. This should be used when asynchronous backing is enabled.
pub struct RelayNumberMonotonicallyIncreases;
impl CheckAssociatedRelayNumber for RelayNumberMonotonicallyIncreases {
fn check_associated_relay_number(
current: RelayChainBlockNumber,
previous: RelayChainBlockNumber,
) {
if current < previous {
panic!("Relay chain block number needs to monotonically increase between Parachain blocks!")
}
}
}
/// Information needed when a new runtime binary is submitted and needs to be authorized before
/// replacing the current runtime.
#[derive(Decode, Encode, Default, PartialEq, Eq, MaxEncodedLen, TypeInfo)]
@@ -193,6 +220,22 @@ pub mod pallet {
/// Something that can check the associated relay parent block number.
type CheckAssociatedRelayNumber: CheckAssociatedRelayNumber;
/// An entry-point for higher-level logic to manage the backlog of unincluded parachain
/// blocks and authorship rights for those blocks.
///
/// Typically, this should be a hook tailored to the collator-selection/consensus mechanism
/// that is used for this chain.
///
/// However, to maintain the same behavior as prior to asynchronous backing, provide the
/// [`consensus_hook::ExpectParentIncluded`] here. This is only necessary in the case
/// that collators aren't expected to have node versions that supply the included block
/// in the relay-chain state proof.
///
/// This config type is only available when the `parameterized-consensus-hook` crate feature
/// is activated.
#[cfg(feature = "parameterized-consensus-hook")]
type ConsensusHook: ConsensusHook;
}
#[pallet::hooks]
@@ -200,6 +243,7 @@ pub mod pallet {
fn on_finalize(_: BlockNumberFor<T>) {
<DidSetValidationCode<T>>::kill();
<UpgradeRestrictionSignal<T>>::kill();
let relay_upgrade_go_ahead = <UpgradeGoAhead<T>>::take();
assert!(
<ValidationData<T>>::exists(),
@@ -216,8 +260,12 @@ pub mod pallet {
return
},
};
let relevant_messaging_state = match Self::relevant_messaging_state() {
Some(ok) => ok,
// Before updating the relevant messaging state, we need to extract
// the total bandwidth limits for the purpose of updating the unincluded
// segment.
let total_bandwidth_out = match Self::relevant_messaging_state() {
Some(s) => OutboundBandwidthLimits::from_relay_chain_state(&s),
None => {
debug_assert!(
false,
@@ -228,35 +276,57 @@ pub mod pallet {
},
};
<PendingUpwardMessages<T>>::mutate(|up| {
let queue_size = relevant_messaging_state.relay_dispatch_queue_remaining_capacity;
// After this point, the `RelevantMessagingState` in storage reflects the
// unincluded segment.
Self::adjust_egress_bandwidth_limits();
let available_capacity = cmp::min(
queue_size.remaining_count,
host_config.max_upward_message_num_per_candidate.into(),
let (ump_msg_count, ump_total_bytes) = <PendingUpwardMessages<T>>::mutate(|up| {
let (available_capacity, available_size) = match Self::relevant_messaging_state() {
Some(limits) => (
limits.relay_dispatch_queue_remaining_capacity.remaining_count,
limits.relay_dispatch_queue_remaining_capacity.remaining_size,
),
None => {
debug_assert!(
false,
"relevant messaging state is promised to be set until `on_finalize`; \
qed",
);
let available_size = queue_size.remaining_size;
return (0, 0)
},
};
let available_capacity =
cmp::min(available_capacity, host_config.max_upward_message_num_per_candidate);
// Count the number of messages we can possibly fit in the given constraints, i.e.
// available_capacity and available_size.
let num = up
let (num, total_size) = up
.iter()
.scan((available_capacity as usize, available_size as usize), |state, msg| {
let (cap_left, size_left) = *state;
match (cap_left.checked_sub(1), size_left.checked_sub(msg.len())) {
(Some(new_cap), Some(new_size)) => {
.scan((0u32, 0u32), |state, msg| {
let (cap_used, size_used) = *state;
let new_cap = cap_used.saturating_add(1);
let new_size = size_used.saturating_add(msg.len() as u32);
match available_capacity
.checked_sub(new_cap)
.and(available_size.checked_sub(new_size))
{
Some(_) => {
*state = (new_cap, new_size);
Some(())
Some(*state)
},
_ => None,
}
})
.count();
.last()
.unwrap_or_default();
// TODO: #274 Return back messages that do not longer fit into the queue.
UpwardMessages::<T>::put(&up[..num]);
*up = up.split_off(num);
UpwardMessages::<T>::put(&up[..num as usize]);
*up = up.split_off(num as usize);
(num, total_size)
});
// Sending HRMP messages is a little bit more involved. There are the following
@@ -272,12 +342,54 @@ pub mod pallet {
.hrmp_max_message_num_per_candidate
.min(<AnnouncedHrmpMessagesPerCandidate<T>>::take()) as usize;
// Note: this internally calls the `GetChannelInfo` implementation for this
// pallet, which draws on the `RelevantMessagingState`. That in turn has
// been adjusted above to reflect the correct limits in all channels.
let outbound_messages =
T::OutboundXcmpMessageSource::take_outbound_messages(maximum_channels)
.into_iter()
.map(|(recipient, data)| OutboundHrmpMessage { recipient, data })
.collect::<Vec<_>>();
// Update the unincluded segment length; capacity checks were done previously in
// `set_validation_data`, so this can be done unconditionally.
{
let hrmp_outgoing = outbound_messages
.iter()
.map(|msg| {
(
msg.recipient,
HrmpChannelUpdate { msg_count: 1, total_bytes: msg.data.len() as u32 },
)
})
.collect();
let used_bandwidth =
UsedBandwidth { ump_msg_count, ump_total_bytes, hrmp_outgoing };
let mut aggregated_segment =
AggregatedUnincludedSegment::<T>::get().unwrap_or_default();
let consumed_go_ahead_signal =
if aggregated_segment.consumed_go_ahead_signal().is_some() {
// Some ancestor within the segment already processed this signal --
// validated during inherent creation.
None
} else {
relay_upgrade_go_ahead
};
// The bandwidth constructed was ensured to satisfy relay chain constraints.
let ancestor = Ancestor::new_unchecked(used_bandwidth, consumed_go_ahead_signal);
let watermark = HrmpWatermark::<T>::get();
let watermark_update =
HrmpWatermarkUpdate::new(watermark, LastRelayChainBlockNumber::<T>::get());
aggregated_segment
.append(&ancestor, watermark_update, &total_bandwidth_out)
.expect("unincluded segment limits exceeded");
AggregatedUnincludedSegment::<T>::put(aggregated_segment);
// Check in `on_initialize` guarantees there's space for this block.
UnincludedSegment::<T>::append(ancestor);
}
HrmpOutboundMessages::<T>::put(outbound_messages);
}
@@ -292,6 +404,22 @@ pub mod pallet {
weight += T::DbWeight::get().writes(1);
}
// The parent hash was unknown during block finalization. Update it here.
{
<UnincludedSegment<T>>::mutate(|chain| {
if let Some(ancestor) = chain.last_mut() {
let parent = frame_system::Pallet::<T>::parent_hash();
// Ancestor is the latest finalized block, thus current parent is
// its output head.
ancestor.replace_para_head_hash(parent);
}
});
weight += T::DbWeight::get().reads_writes(1, 1);
// Weight used during finalization.
weight += T::DbWeight::get().reads_writes(3, 2);
}
// Remove the validation from the old block.
ValidationData::<T>::kill();
ProcessedDownwardMessages::<T>::kill();
@@ -332,6 +460,12 @@ pub mod pallet {
4 + hrmp_max_message_num_per_candidate as u64,
);
// Weight for adjusting the unincluded segment in `on_finalize`.
weight += T::DbWeight::get().reads_writes(6, 3);
// Always try to read `UpgradeGoAhead` in `on_finalize`.
weight += T::DbWeight::get().reads(1);
weight
}
}
@@ -360,6 +494,15 @@ pub mod pallet {
"ValidationData must be updated only once in a block",
);
// TODO: This is more than zero, but will need benchmarking to figure out what.
let mut total_weight = Weight::zero();
// NOTE: the inherent data is expected to be unique, even if this block is built
// in the context of the same relay parent as the previous one. In particular,
// the inherent shouldn't contain messages that were already processed by any of the
// ancestors.
//
// This invariant should be upheld by the `ProvideInherent` implementation.
let ParachainInherentData {
validation_data: vfp,
relay_chain_state,
@@ -381,6 +524,13 @@ pub mod pallet {
)
.expect("Invalid relay chain state proof");
// Update the desired maximum capacity according to the consensus hook.
#[cfg(feature = "parameterized-consensus-hook")]
let (consensus_hook_weight, capacity) = T::ConsensusHook::on_state_proof(&relay_state_proof);
#[cfg(not(feature = "parameterized-consensus-hook"))]
let (consensus_hook_weight, capacity) = ExpectParentIncluded::on_state_proof(&relay_state_proof);
total_weight += consensus_hook_weight;
total_weight += Self::maybe_drop_included_ancestors(&relay_state_proof, capacity);
// Deposit a log indicating the relay-parent storage root.
// TODO: remove this in favor of the relay-parent's hash after
// https://github.com/paritytech/cumulus/issues/303
@@ -397,7 +547,19 @@ pub mod pallet {
let upgrade_go_ahead_signal = relay_state_proof
.read_upgrade_go_ahead_signal()
.expect("Invalid upgrade go ahead signal");
let upgrade_signal_in_segment = AggregatedUnincludedSegment::<T>::get()
.as_ref()
.and_then(SegmentTracker::consumed_go_ahead_signal);
if let Some(signal_in_segment) = upgrade_signal_in_segment.as_ref() {
// Unincluded ancestor consuming upgrade signal is still within the segment,
// sanity check that it matches with the signal from relay chain.
assert_eq!(upgrade_go_ahead_signal, Some(*signal_in_segment));
}
match upgrade_go_ahead_signal {
Some(_signal) if upgrade_signal_in_segment.is_some() => {
// Do nothing, processing logic was executed by unincluded ancestor.
},
Some(relay_chain::UpgradeGoAhead::GoAhead) => {
assert!(
<PendingValidationCode<T>>::exists(),
@@ -422,10 +584,12 @@ pub mod pallet {
.read_upgrade_restriction_signal()
.expect("Invalid upgrade restriction signal"),
);
<UpgradeGoAhead<T>>::put(upgrade_go_ahead_signal);
let host_config = relay_state_proof
.read_abridged_host_configuration()
.expect("Invalid host configuration in relay chain state proof");
let relevant_messaging_state = relay_state_proof
.read_messaging_state_snapshot(&host_config)
.expect("Invalid messaging state in relay chain state proof");
@@ -437,8 +601,6 @@ pub mod pallet {
<T::OnSystemEvent as OnSystemEvent>::on_validation_data(&vfp);
// TODO: This is more than zero, but will need benchmarking to figure out what.
let mut total_weight = Weight::zero();
total_weight += Self::process_inbound_downward_messages(
relevant_messaging_state.dmq_mqc_head,
downward_messages,
@@ -547,6 +709,23 @@ pub mod pallet {
Unauthorized,
}
/// Latest included block descendants the runtime accepted. In other words, these are
/// ancestors of the currently executing block which have not been included in the observed
/// relay-chain state.
///
/// The segment length is limited by the capacity returned from the [`ConsensusHook`] configured
/// in the pallet.
#[pallet::storage]
pub(super) type UnincludedSegment<T: Config> =
StorageValue<_, Vec<Ancestor<T::Hash>>, ValueQuery>;
/// Storage field that keeps track of bandwidth used by the unincluded segment along with the
/// latest the latest HRMP watermark. Used for limiting the acceptance of new blocks with
/// respect to relay chain constraints.
#[pallet::storage]
pub(super) type AggregatedUnincludedSegment<T: Config> =
StorageValue<_, SegmentTracker<T::Hash>, OptionQuery>;
/// In case of a scheduled upgrade, this storage field contains the validation code to be
/// applied.
///
@@ -592,6 +771,15 @@ pub mod pallet {
pub(super) type UpgradeRestrictionSignal<T: Config> =
StorageValue<_, Option<relay_chain::UpgradeRestriction>, ValueQuery>;
/// Optional upgrade go-ahead signal from the relay-chain.
///
/// This storage item is a mirror of the corresponding value for the current parachain from the
/// relay-chain. This value is ephemeral which means it doesn't hit the storage. This value is
/// set after the inherent.
#[pallet::storage]
pub(super) type UpgradeGoAhead<T: Config> =
StorageValue<_, Option<relay_chain::UpgradeGoAhead>, ValueQuery>;
/// The state proof for the last relay parent block.
///
/// This field is meant to be updated each block with the validation data inherent. Therefore,
@@ -702,11 +890,13 @@ pub mod pallet {
cumulus_primitives_parachain_inherent::INHERENT_IDENTIFIER;
fn create_inherent(data: &InherentData) -> Option<Self::Call> {
let data: ParachainInherentData =
let mut data: ParachainInherentData =
data.get_data(&Self::INHERENT_IDENTIFIER).ok().flatten().expect(
"validation function params are always injected into inherent data; qed",
);
Self::drop_processed_messages_from_inherent(&mut data);
Some(Call::set_validation_data { data })
}
@@ -769,6 +959,18 @@ impl<T: Config> Pallet<T> {
Ok(actual_hash)
}
/// Get the unincluded segment size after the given hash.
///
/// If the unincluded segment doesn't contain the given hash, this returns the
/// length of the entire unincluded segment.
///
/// This is intended to be used for determining how long the unincluded segment _would be_
/// in runtime APIs related to authoring.
pub fn unincluded_segment_size_after(included_hash: T::Hash) -> u32 {
let segment = UnincludedSegment::<T>::get();
crate::unincluded_segment::size_after_included(included_hash, &segment)
}
}
impl<T: Config> GetChannelInfo for Pallet<T> {
@@ -822,6 +1024,37 @@ impl<T: Config> GetChannelInfo for Pallet<T> {
}
impl<T: Config> Pallet<T> {
/// Updates inherent data to only contain messages that weren't already processed
/// by the runtime based on last relay chain block number.
///
/// This method doesn't check for mqc heads mismatch.
fn drop_processed_messages_from_inherent(para_inherent: &mut ParachainInherentData) {
let ParachainInherentData { downward_messages, horizontal_messages, .. } = para_inherent;
// Last relay chain block number. Any message with sent-at block number less
// than or equal to this value is assumed to be processed previously.
let last_relay_block_number = LastRelayChainBlockNumber::<T>::get();
// DMQ.
let dmq_processed_num = downward_messages
.iter()
.take_while(|message| message.sent_at <= last_relay_block_number)
.count();
downward_messages.drain(..dmq_processed_num);
// HRMP.
for horizontal in horizontal_messages.values_mut() {
let horizontal_processed_num = horizontal
.iter()
.take_while(|message| message.sent_at <= last_relay_block_number)
.count();
horizontal.drain(..horizontal_processed_num);
}
// If MQC doesn't match after dropping messages, the runtime will panic when creating
// inherent.
}
/// Process all inbound downward messages relayed by the collator.
///
/// Checks if the sequence of the messages is valid, dispatches them and communicates the
@@ -966,6 +1199,122 @@ impl<T: Config> Pallet<T> {
weight_used
}
/// Drop blocks from the unincluded segment with respect to the latest parachain head.
fn maybe_drop_included_ancestors(
relay_state_proof: &RelayChainStateProof,
capacity: consensus_hook::UnincludedSegmentCapacity,
) -> Weight {
let mut weight_used = Weight::zero();
// If the unincluded segment length is nonzero, then the parachain head must be present.
let para_head =
relay_state_proof.read_included_para_head().ok().map(|h| T::Hashing::hash(&h.0));
let unincluded_segment_len = <UnincludedSegment<T>>::decode_len().unwrap_or(0);
weight_used += T::DbWeight::get().reads(1);
// Clean up unincluded segment if nonempty.
let included_head = match (para_head, capacity.is_expecting_included_parent()) {
(Some(h), true) => {
assert_eq!(
h,
frame_system::Pallet::<T>::parent_hash(),
"expected parent to be included"
);
h
},
(Some(h), false) => h,
(None, true) => {
// All this logic is essentially a workaround to support collators which
// might still not provide the included block with the state proof.
frame_system::Pallet::<T>::parent_hash()
},
(None, false) => panic!("included head not present in relay storage proof"),
};
let new_len = {
let para_head_hash = included_head;
let dropped: Vec<Ancestor<T::Hash>> = <UnincludedSegment<T>>::mutate(|chain| {
// Drop everything up to (inclusive) the block with an included para head, if
// present.
let idx = chain
.iter()
.position(|block| {
let head_hash = block
.para_head_hash()
.expect("para head hash is updated during block initialization; qed");
head_hash == &para_head_hash
})
.map_or(0, |idx| idx + 1); // inclusive.
chain.drain(..idx).collect()
});
weight_used += T::DbWeight::get().reads_writes(1, 1);
let new_len = unincluded_segment_len - dropped.len();
if !dropped.is_empty() {
<AggregatedUnincludedSegment<T>>::mutate(|agg| {
let agg = agg.as_mut().expect(
"dropped part of the segment wasn't empty, hence value exists; qed",
);
for block in dropped {
agg.subtract(&block);
}
});
weight_used += T::DbWeight::get().reads_writes(1, 1);
}
new_len as u32
};
// Current block validity check: ensure there is space in the unincluded segment.
//
// If this fails, the parachain needs to wait for ancestors to be included before
// a new block is allowed.
assert!(new_len < capacity.get(), "no space left for the block in the unincluded segment");
weight_used
}
/// This adjusts the `RelevantMessagingState` according to the bandwidth limits in the
/// unincluded segment.
//
// Reads: 2
// Writes: 1
fn adjust_egress_bandwidth_limits() {
let unincluded_segment = match AggregatedUnincludedSegment::<T>::get() {
None => return,
Some(s) => s,
};
<RelevantMessagingState<T>>::mutate(|messaging_state| {
let messaging_state = match messaging_state {
None => return,
Some(s) => s,
};
let used_bandwidth = unincluded_segment.used_bandwidth();
let channels = &mut messaging_state.egress_channels;
for (para_id, used) in used_bandwidth.hrmp_outgoing.iter() {
let i = match channels.binary_search_by_key(para_id, |item| item.0) {
Ok(i) => i,
Err(_) => continue, // indicates channel closed.
};
let c = &mut channels[i].1;
c.total_size = (c.total_size + used.total_bytes).min(c.max_total_size);
c.msg_count = (c.msg_count + used.msg_count).min(c.max_capacity);
}
let upward_capacity = &mut messaging_state.relay_dispatch_queue_remaining_capacity;
upward_capacity.remaining_count =
upward_capacity.remaining_count.saturating_sub(used_bandwidth.ump_msg_count);
upward_capacity.remaining_size =
upward_capacity.remaining_size.saturating_sub(used_bandwidth.ump_total_bytes);
});
}
/// Put a new validation function into a particular location where polkadot
/// monitors for updates. Calling this function notifies polkadot that a new
/// upgrade has been scheduled.
@@ -1157,6 +1506,10 @@ impl<T: Config> UpwardMessageSender for Pallet<T> {
}
/// Something that can check the inherents of a block.
#[cfg_attr(
feature = "parameterized-consensus-hook",
deprecated = "consider switching to `cumulus-pallet-parachain-system::ConsensusHook`"
)]
pub trait CheckInherents<Block: BlockT> {
/// Check all inherents of the block.
///
@@ -1168,6 +1521,20 @@ pub trait CheckInherents<Block: BlockT> {
) -> frame_support::inherent::CheckInherentsResult;
}
/// Struct that always returns `Ok` on inherents check, needed for backwards-compatibility.
#[doc(hidden)]
pub struct DummyCheckInherents<Block>(sp_std::marker::PhantomData<Block>);
#[allow(deprecated)]
impl<Block: BlockT> CheckInherents<Block> for DummyCheckInherents<Block> {
fn check_inherents(
_: &Block,
_: &RelayChainStateProof,
) -> frame_support::inherent::CheckInherentsResult {
sp_inherents::CheckInherentsResult::new()
}
}
/// Something that should be informed about system related events.
///
/// This includes events like [`on_validation_data`](Self::on_validation_data) that is being
@@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
//! Relay chain state proof provides means for accessing part of relay chain storage for reads.
use codec::{Decode, Encode};
use cumulus_primitives_core::{
relay_chain, AbridgedHostConfiguration, AbridgedHrmpChannel, ParaId,
@@ -94,6 +96,8 @@ pub enum Error {
HrmpEgressChannelIndex(ReadEntryErr),
/// The channel identified by the sender and receiver cannot be extracted.
HrmpChannel(ParaId, ParaId, ReadEntryErr),
/// The latest included parachain head cannot be extracted.
ParaHead(ReadEntryErr),
}
#[derive(Debug)]
@@ -280,6 +284,15 @@ impl RelayChainStateProof {
.map_err(Error::Config)
}
/// Read latest included parachain [head data](`relay_chain::HeadData`) from the relay chain
/// state proof.
///
/// Returns an error if anything failed at reading or decoding.
pub fn read_included_para_head(&self) -> Result<relay_chain::HeadData, Error> {
read_entry(&self.trie_backend, &relay_chain::well_known_keys::para_head(self.para_id), None)
.map_err(Error::ParaHead)
}
/// Read the [`Slot`](relay_chain::Slot) from the relay chain state proof.
///
/// The slot is slot of the relay chain block this state proof was extracted from.
+515 -33
View File
@@ -29,7 +29,10 @@ use frame_support::{
traits::{OnFinalize, OnInitialize},
weights::Weight,
};
use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin};
use frame_system::{
pallet_prelude::{BlockNumberFor, HeaderFor},
RawOrigin,
};
use hex_literal::hex;
use relay_chain::HrmpChannelId;
use sp_core::{blake2_256, H256};
@@ -37,10 +40,12 @@ use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup},
BuildStorage, DispatchErrorWithPostInfo,
};
use sp_std::{collections::vec_deque::VecDeque, num::NonZeroU32};
use sp_version::RuntimeVersion;
use std::cell::RefCell;
use crate as parachain_system;
use crate::consensus_hook::UnincludedSegmentCapacity;
type Block = frame_system::mocking::MockBlock<Test>;
@@ -102,7 +107,8 @@ impl Config for Test {
type ReservedDmpWeight = ReservedDmpWeight;
type XcmpMessageHandler = SaveIntoThreadLocal;
type ReservedXcmpWeight = ReservedXcmpWeight;
type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases;
type CheckAssociatedRelayNumber = AnyRelayNumber;
type ConsensusHook = TestConsensusHook;
}
pub struct FromThreadLocal;
@@ -112,6 +118,16 @@ std::thread_local! {
static HANDLED_DMP_MESSAGES: RefCell<Vec<(relay_chain::BlockNumber, Vec<u8>)>> = RefCell::new(Vec::new());
static HANDLED_XCMP_MESSAGES: RefCell<Vec<(ParaId, relay_chain::BlockNumber, Vec<u8>)>> = RefCell::new(Vec::new());
static SENT_MESSAGES: RefCell<Vec<(ParaId, Vec<u8>)>> = RefCell::new(Vec::new());
static CONSENSUS_HOOK: RefCell<Box<dyn Fn(&RelayChainStateProof) -> (Weight, UnincludedSegmentCapacity)>>
= RefCell::new(Box::new(|_| (Weight::zero(), NonZeroU32::new(1).unwrap().into())));
}
pub struct TestConsensusHook;
impl ConsensusHook for TestConsensusHook {
fn on_state_proof(s: &RelayChainStateProof) -> (Weight, UnincludedSegmentCapacity) {
CONSENSUS_HOOK.with(|f| f.borrow_mut()(s))
}
}
fn send_message(dest: ParaId, message: Vec<u8>) {
@@ -121,15 +137,28 @@ fn send_message(dest: ParaId, message: Vec<u8>) {
impl XcmpMessageSource for FromThreadLocal {
fn take_outbound_messages(maximum_channels: usize) -> Vec<(ParaId, Vec<u8>)> {
let mut ids = std::collections::BTreeSet::<ParaId>::new();
let mut taken = 0;
let mut taken_messages = 0;
let mut taken_bytes = 0;
let mut result = Vec::new();
SENT_MESSAGES.with(|ms| {
ms.borrow_mut().retain(|m| {
let status = <Pallet<Test> as GetChannelInfo>::get_channel_status(m.0);
let ready = matches!(status, ChannelStatus::Ready(..));
if ready && !ids.contains(&m.0) && taken < maximum_channels {
let (max_size_now, max_size_ever) = match status {
ChannelStatus::Ready(now, ever) => (now, ever),
ChannelStatus::Closed => return false, // drop message
ChannelStatus::Full => return true, // keep message queued.
};
let msg_len = m.1.len();
if !ids.contains(&m.0) &&
taken_messages < maximum_channels &&
msg_len <= max_size_ever &&
taken_bytes + msg_len <= max_size_now
{
ids.insert(m.0);
taken += 1;
taken_messages += 1;
taken_bytes += msg_len;
result.push(m.clone());
false
} else {
@@ -222,9 +251,13 @@ struct BlockTests {
ran: bool,
relay_sproof_builder_hook:
Option<Box<dyn Fn(&BlockTests, RelayChainBlockNumber, &mut RelayStateSproofBuilder)>>,
persisted_validation_data_hook: Option<Box<dyn Fn(&BlockTests, &mut PersistedValidationData)>>,
inherent_data_hook:
Option<Box<dyn Fn(&BlockTests, RelayChainBlockNumber, &mut ParachainInherentData)>>,
inclusion_delay: Option<usize>,
relay_block_number: Option<Box<dyn Fn(&BlockNumberFor<Test>) -> RelayChainBlockNumber>>,
included_para_head: Option<relay_chain::HeadData>,
pending_blocks: VecDeque<relay_chain::HeadData>,
}
impl BlockTests {
@@ -269,11 +302,11 @@ impl BlockTests {
self
}
fn with_validation_data<F>(mut self, f: F) -> Self
fn with_relay_block_number<F>(mut self, f: F) -> Self
where
F: 'static + Fn(&BlockTests, &mut PersistedValidationData),
F: 'static + Fn(&BlockNumberFor<Test>) -> RelayChainBlockNumber,
{
self.persisted_validation_data_hook = Some(Box::new(f));
self.relay_block_number = Some(Box::new(f));
self
}
@@ -285,10 +318,27 @@ impl BlockTests {
self
}
fn with_inclusion_delay(mut self, inclusion_delay: usize) -> Self {
self.inclusion_delay.replace(inclusion_delay);
self
}
fn run(&mut self) {
self.ran = true;
wasm_ext().execute_with(|| {
let mut parent_head_data = {
let header = HeaderFor::<Test>::new_from_number(0);
relay_chain::HeadData(header.encode())
};
self.included_para_head = Some(parent_head_data.clone());
for BlockTest { n, within_block, after_block } in self.tests.iter() {
let relay_parent_number = self
.relay_block_number
.as_ref()
.map(|f| f(n))
.unwrap_or(*n as RelayChainBlockNumber);
// clear pending updates, as applicable
if let Some(upgrade_block) = self.pending_upgrade {
if n >= &upgrade_block.into() {
@@ -297,24 +347,27 @@ impl BlockTests {
}
// begin initialization
let parent_hash = BlakeTwo256::hash(&parent_head_data.0);
System::reset_events();
System::initialize(n, &Default::default(), &Default::default());
System::initialize(n, &parent_hash, &Default::default());
// now mess with the storage the way validate_block does
let mut sproof_builder = RelayStateSproofBuilder::default();
sproof_builder.included_para_head = self
.included_para_head
.clone()
.unwrap_or_else(|| parent_head_data.clone())
.into();
if let Some(ref hook) = self.relay_sproof_builder_hook {
hook(self, *n as RelayChainBlockNumber, &mut sproof_builder);
hook(self, relay_parent_number, &mut sproof_builder);
}
let (relay_parent_storage_root, relay_chain_state) =
sproof_builder.into_state_root_and_proof();
let mut vfp = PersistedValidationData {
relay_parent_number: *n as RelayChainBlockNumber,
let vfp = PersistedValidationData {
relay_parent_number,
relay_parent_storage_root,
..Default::default()
};
if let Some(ref hook) = self.persisted_validation_data_hook {
hook(self, &mut vfp);
}
<ValidationData<Test>>::put(&vfp);
NewValidationCode::<Test>::kill();
@@ -330,7 +383,7 @@ impl BlockTests {
horizontal_messages: Default::default(),
};
if let Some(ref hook) = self.inherent_data_hook {
hook(self, *n as RelayChainBlockNumber, &mut system_inherent_data);
hook(self, relay_parent_number, &mut system_inherent_data);
}
inherent_data
.put_data(
@@ -356,7 +409,23 @@ impl BlockTests {
}
// clean up
System::finalize();
let header = System::finalize();
let head_data = relay_chain::HeadData(header.encode());
parent_head_data = head_data.clone();
match self.inclusion_delay {
Some(delay) if delay > 0 => {
self.pending_blocks.push_back(head_data);
if self.pending_blocks.len() > delay {
let included = self.pending_blocks.pop_front().unwrap();
self.included_para_head.replace(included);
}
},
_ => {
self.included_para_head.replace(head_data);
},
}
if let Some(after_block) = after_block {
after_block();
}
@@ -379,6 +448,427 @@ fn block_tests_run_on_drop() {
BlockTests::new().add(123, || panic!("if this test passes, block tests run properly"));
}
#[test]
fn test_xcmp_source_keeps_messages() {
let recipient = ParaId::from(400);
CONSENSUS_HOOK.with(|c| {
*c.borrow_mut() = Box::new(|_| (Weight::zero(), NonZeroU32::new(3).unwrap().into()))
});
BlockTests::new()
.with_inclusion_delay(2)
.with_relay_sproof_builder(move |_, block_number, sproof| {
sproof.host_config.hrmp_max_message_num_per_candidate = 10;
let channel = sproof.upsert_outbound_channel(recipient);
channel.max_total_size = 10;
channel.max_message_size = 10;
// Only fit messages starting from 3rd block.
channel.max_capacity = if block_number < 3 { 0 } else { 1 };
})
.add(1, || {})
.add_with_post_test(
2,
move || {
send_message(recipient, b"22".to_vec());
},
move || {
let v = HrmpOutboundMessages::<Test>::get();
assert!(v.is_empty());
},
)
.add_with_post_test(
3,
move || {},
move || {
// Not discarded.
let v = HrmpOutboundMessages::<Test>::get();
assert_eq!(v, vec![OutboundHrmpMessage { recipient, data: b"22".to_vec() }]);
},
);
}
#[test]
fn unincluded_segment_works() {
CONSENSUS_HOOK.with(|c| {
*c.borrow_mut() = Box::new(|_| (Weight::zero(), NonZeroU32::new(10).unwrap().into()))
});
BlockTests::new()
.with_inclusion_delay(1)
.add_with_post_test(
123,
|| {},
|| {
let segment = <UnincludedSegment<Test>>::get();
assert_eq!(segment.len(), 1);
assert!(<AggregatedUnincludedSegment<Test>>::get().is_some());
},
)
.add_with_post_test(
124,
|| {},
|| {
let segment = <UnincludedSegment<Test>>::get();
assert_eq!(segment.len(), 2);
},
)
.add_with_post_test(
125,
|| {},
|| {
let segment = <UnincludedSegment<Test>>::get();
// Block 123 was popped from the segment, the len is still 2.
assert_eq!(segment.len(), 2);
},
);
}
#[test]
#[should_panic = "no space left for the block in the unincluded segment"]
fn unincluded_segment_is_limited() {
CONSENSUS_HOOK.with(|c| {
*c.borrow_mut() = Box::new(|_| (Weight::zero(), NonZeroU32::new(1).unwrap().into()))
});
BlockTests::new()
.with_inclusion_delay(2)
.add_with_post_test(
123,
|| {},
|| {
let segment = <UnincludedSegment<Test>>::get();
assert_eq!(segment.len(), 1);
assert!(<AggregatedUnincludedSegment<Test>>::get().is_some());
},
)
.add(124, || {}); // The previous block wasn't included yet, should panic in `create_inherent`.
}
#[test]
fn unincluded_code_upgrade_handles_signal() {
CONSENSUS_HOOK.with(|c| {
*c.borrow_mut() = Box::new(|_| (Weight::zero(), NonZeroU32::new(2).unwrap().into()))
});
BlockTests::new()
.with_inclusion_delay(1)
.with_relay_sproof_builder(|_, block_number, builder| {
if block_number > 123 && block_number <= 125 {
builder.upgrade_go_ahead = Some(relay_chain::UpgradeGoAhead::GoAhead);
}
})
.add(123, || {
assert_ok!(System::set_code(RawOrigin::Root.into(), Default::default()));
})
.add_with_post_test(
124,
|| {},
|| {
assert!(
!<PendingValidationCode<Test>>::exists(),
"validation function must have been unset"
);
},
)
.add_with_post_test(
125,
|| {
// The signal is present in relay state proof and ignored.
// Block that processed the signal is still not included.
},
|| {
let segment = <UnincludedSegment<Test>>::get();
assert_eq!(segment.len(), 2);
let aggregated_segment =
<AggregatedUnincludedSegment<Test>>::get().expect("segment is non-empty");
assert_eq!(
aggregated_segment.consumed_go_ahead_signal(),
Some(relay_chain::UpgradeGoAhead::GoAhead)
);
},
)
.add_with_post_test(
126,
|| {},
|| {
let aggregated_segment =
<AggregatedUnincludedSegment<Test>>::get().expect("segment is non-empty");
// Block that processed the signal is included.
assert!(aggregated_segment.consumed_go_ahead_signal().is_none());
},
);
}
#[test]
fn unincluded_code_upgrade_scheduled_after_go_ahead() {
CONSENSUS_HOOK.with(|c| {
*c.borrow_mut() = Box::new(|_| (Weight::zero(), NonZeroU32::new(2).unwrap().into()))
});
BlockTests::new()
.with_inclusion_delay(1)
.with_relay_sproof_builder(|_, block_number, builder| {
if block_number > 123 && block_number <= 125 {
builder.upgrade_go_ahead = Some(relay_chain::UpgradeGoAhead::GoAhead);
}
})
.add(123, || {
assert_ok!(System::set_code(RawOrigin::Root.into(), Default::default()));
})
.add_with_post_test(
124,
|| {},
|| {
assert!(
!<PendingValidationCode<Test>>::exists(),
"validation function must have been unset"
);
// The previous go-ahead signal was processed, schedule another upgrade.
assert_ok!(System::set_code(RawOrigin::Root.into(), Default::default()));
},
)
.add_with_post_test(
125,
|| {
// The signal is present in relay state proof and ignored.
// Block that processed the signal is still not included.
},
|| {
let segment = <UnincludedSegment<Test>>::get();
assert_eq!(segment.len(), 2);
let aggregated_segment =
<AggregatedUnincludedSegment<Test>>::get().expect("segment is non-empty");
assert_eq!(
aggregated_segment.consumed_go_ahead_signal(),
Some(relay_chain::UpgradeGoAhead::GoAhead)
);
},
)
.add_with_post_test(
126,
|| {},
|| {
assert!(<PendingValidationCode<Test>>::exists(), "upgrade is pending");
},
);
}
#[test]
fn inherent_processed_messages_are_ignored() {
CONSENSUS_HOOK.with(|c| {
*c.borrow_mut() = Box::new(|_| (Weight::zero(), NonZeroU32::new(2).unwrap().into()))
});
lazy_static::lazy_static! {
static ref DMQ_MSG: InboundDownwardMessage = InboundDownwardMessage {
sent_at: 3,
msg: b"down".to_vec(),
};
static ref XCMP_MSG_1: InboundHrmpMessage = InboundHrmpMessage {
sent_at: 2,
data: b"h1".to_vec(),
};
static ref XCMP_MSG_2: InboundHrmpMessage = InboundHrmpMessage {
sent_at: 3,
data: b"h2".to_vec(),
};
static ref EXPECTED_PROCESSED_DMQ: Vec<(RelayChainBlockNumber, Vec<u8>)> = vec![
(DMQ_MSG.sent_at, DMQ_MSG.msg.clone())
];
static ref EXPECTED_PROCESSED_XCMP: Vec<(ParaId, RelayChainBlockNumber, Vec<u8>)> = vec![
(ParaId::from(200), XCMP_MSG_1.sent_at, XCMP_MSG_1.data.clone()),
(ParaId::from(200), XCMP_MSG_2.sent_at, XCMP_MSG_2.data.clone()),
];
}
BlockTests::new()
.with_inclusion_delay(1)
.with_relay_block_number(|block_number| 3.max(*block_number as RelayChainBlockNumber))
.with_relay_sproof_builder(|_, relay_block_num, sproof| match relay_block_num {
3 => {
sproof.dmq_mqc_head =
Some(MessageQueueChain::default().extend_downward(&DMQ_MSG).head());
sproof.upsert_inbound_channel(ParaId::from(200)).mqc_head = Some(
MessageQueueChain::default()
.extend_hrmp(&XCMP_MSG_1)
.extend_hrmp(&XCMP_MSG_2)
.head(),
);
},
_ => unreachable!(),
})
.with_inherent_data(|_, relay_block_num, data| match relay_block_num {
3 => {
data.downward_messages.push(DMQ_MSG.clone());
data.horizontal_messages
.insert(ParaId::from(200), vec![XCMP_MSG_1.clone(), XCMP_MSG_2.clone()]);
},
_ => unreachable!(),
})
.add(1, || {
// Don't drop processed messages for this test.
HANDLED_DMP_MESSAGES.with(|m| {
let m = m.borrow();
assert_eq!(&*m, EXPECTED_PROCESSED_DMQ.as_slice());
});
HANDLED_XCMP_MESSAGES.with(|m| {
let m = m.borrow_mut();
assert_eq!(&*m, EXPECTED_PROCESSED_XCMP.as_slice());
});
})
.add(2, || {})
.add(3, || {
HANDLED_DMP_MESSAGES.with(|m| {
let m = m.borrow();
assert_eq!(&*m, EXPECTED_PROCESSED_DMQ.as_slice());
});
HANDLED_XCMP_MESSAGES.with(|m| {
let m = m.borrow_mut();
assert_eq!(&*m, EXPECTED_PROCESSED_XCMP.as_slice());
});
});
}
#[test]
fn hrmp_outbound_respects_used_bandwidth() {
let recipient = ParaId::from(400);
CONSENSUS_HOOK.with(|c| {
*c.borrow_mut() = Box::new(|_| (Weight::zero(), NonZeroU32::new(3).unwrap().into()))
});
BlockTests::new()
.with_inclusion_delay(2)
.with_relay_sproof_builder(move |_, block_number, sproof| {
sproof.host_config.hrmp_max_message_num_per_candidate = 10;
let channel = sproof.upsert_outbound_channel(recipient);
channel.max_capacity = 2;
channel.max_total_size = 4;
channel.max_message_size = 10;
// states:
// [relay_chain][unincluded_segment] + [message_queue]
// 2: []["2"] + ["2222"]
// 3: []["2", "3"] + ["2222"]
// 4: []["2", "3"] + ["2222", "444", "4"]
// 5: ["2"]["3"] + ["2222", "444", "4"]
// 6: ["2", "3"][] + ["2222", "444", "4"]
// 7: ["3"]["444"] + ["2222", "4"]
// 8: []["444", "4"] + ["2222"]
//
// 2 tests max bytes - there is message space but no byte space.
// 4 tests max capacity - there is byte space but no message space
match block_number {
5 => {
// 2 included.
// one message added
channel.msg_count = 1;
channel.total_size = 1;
},
6 => {
// 3 included.
// one message added
channel.msg_count = 2;
channel.total_size = 2;
},
7 => {
// 4 included.
// one message drained.
channel.msg_count = 1;
channel.total_size = 1;
},
8 => {
// 5 included. no messages added, one drained.
channel.msg_count = 0;
channel.total_size = 0;
},
_ => {
channel.msg_count = 0;
channel.total_size = 0;
},
}
})
.add(1, || {})
.add_with_post_test(
2,
move || {
send_message(recipient, b"2".to_vec());
send_message(recipient, b"2222".to_vec());
},
move || {
let v = HrmpOutboundMessages::<Test>::get();
assert_eq!(v, vec![OutboundHrmpMessage { recipient, data: b"2".to_vec() }]);
},
)
.add_with_post_test(
3,
move || {
send_message(recipient, b"3".to_vec());
},
move || {
let v = HrmpOutboundMessages::<Test>::get();
assert_eq!(v, vec![OutboundHrmpMessage { recipient, data: b"3".to_vec() }]);
},
)
.add_with_post_test(
4,
move || {
send_message(recipient, b"444".to_vec());
send_message(recipient, b"4".to_vec());
},
move || {
// Queue has byte capacity but not message capacity.
let v = HrmpOutboundMessages::<Test>::get();
assert!(v.is_empty());
},
)
.add_with_post_test(
5,
|| {},
move || {
// 1 is included here, channel not drained yet. nothing fits.
let v = HrmpOutboundMessages::<Test>::get();
assert!(v.is_empty());
},
)
.add_with_post_test(
6,
|| {},
move || {
// 2 is included here. channel is totally full.
let v = HrmpOutboundMessages::<Test>::get();
assert!(v.is_empty());
},
)
.add_with_post_test(
7,
|| {},
move || {
// 3 is included here. One message was drained out. The 3-byte message
// finally fits
let v = HrmpOutboundMessages::<Test>::get();
// This line relies on test implementation of [`XcmpMessageSource`].
assert_eq!(v, vec![OutboundHrmpMessage { recipient, data: b"444".to_vec() }]);
},
)
.add_with_post_test(
8,
|| {},
move || {
// 4 is included here. Relay-chain side of the queue is empty,
let v = HrmpOutboundMessages::<Test>::get();
// This line relies on test implementation of [`XcmpMessageSource`].
assert_eq!(v, vec![OutboundHrmpMessage { recipient, data: b"4".to_vec() }]);
},
);
}
#[test]
fn events() {
BlockTests::new()
@@ -522,7 +1012,10 @@ fn send_upward_message_num_per_candidate() {
)
.add_with_post_test(
2,
|| { /* do nothing within block */ },
|| {
assert_eq!(UnincludedSegment::<Test>::get().len(), 0);
/* do nothing within block */
},
|| {
let v = UpwardMessages::<Test>::get();
assert_eq!(v, vec![b"message 2".to_vec()]);
@@ -786,7 +1279,7 @@ fn receive_hrmp() {
};
static ref MSG_2: InboundHrmpMessage = InboundHrmpMessage {
sent_at: 1,
sent_at: 2,
data: b"2".to_vec(),
};
@@ -863,8 +1356,8 @@ fn receive_hrmp() {
assert_eq!(
&*m,
&[
(ParaId::from(300), 1, b"2".to_vec()),
(ParaId::from(200), 2, b"4".to_vec()),
(ParaId::from(300), 2, b"2".to_vec()),
(ParaId::from(300), 2, b"3".to_vec()),
]
);
@@ -956,17 +1449,6 @@ fn receive_hrmp_after_pause() {
});
}
#[test]
#[should_panic = "Relay chain block number needs to strictly increase between Parachain blocks!"]
fn test() {
BlockTests::new()
.with_validation_data(|_, data| {
data.relay_parent_number = 1;
})
.add(1, || {})
.add(2, || {});
}
#[test]
fn upgrade_version_checks_should_work() {
let test_data = vec![
@@ -0,0 +1,856 @@
// Copyright 2023 Parity Technologies (UK) Ltd.
// This file is part of Cumulus.
// Cumulus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Cumulus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
//! Primitives used for tracking message queues constraints in an unincluded block segment
//! of the parachain.
//!
//! Unincluded segment describes a chain of latest included block descendants, which are not yet
//! sent to relay chain.
use super::relay_state_snapshot::{MessagingStateSnapshot, RelayDispatchQueueRemainingCapacity};
use codec::{Decode, Encode};
use cumulus_primitives_core::{relay_chain, ParaId};
use frame_support::RuntimeDebug;
use scale_info::TypeInfo;
use sp_std::{collections::btree_map::BTreeMap, marker::PhantomData};
/// Constraints on outbound HRMP channel.
#[derive(Clone, RuntimeDebug)]
pub struct HrmpOutboundLimits {
/// The maximum bytes that can be written to the channel.
pub bytes_remaining: u32,
/// The maximum messages that can be written to the channel.
pub messages_remaining: u32,
}
/// Limits on outbound message bandwidth.
#[derive(Clone, RuntimeDebug)]
pub struct OutboundBandwidthLimits {
/// The amount of UMP messages remaining.
pub ump_messages_remaining: u32,
/// The amount of UMP bytes remaining.
pub ump_bytes_remaining: u32,
/// The limitations of all registered outbound HRMP channels.
pub hrmp_outgoing: BTreeMap<ParaId, HrmpOutboundLimits>,
}
impl OutboundBandwidthLimits {
/// Creates new limits from the messaging state and upward message queue maximums fetched
/// from the host configuration.
///
/// These will be the total bandwidth limits across the entire unincluded segment.
pub fn from_relay_chain_state(messaging_state: &MessagingStateSnapshot) -> Self {
let RelayDispatchQueueRemainingCapacity { remaining_count, remaining_size } =
messaging_state.relay_dispatch_queue_remaining_capacity;
let hrmp_outgoing = messaging_state
.egress_channels
.iter()
.map(|(id, channel)| {
(
*id,
HrmpOutboundLimits {
bytes_remaining: channel.max_total_size.saturating_sub(channel.total_size),
messages_remaining: channel.max_capacity.saturating_sub(channel.msg_count),
},
)
})
.collect();
Self {
ump_messages_remaining: remaining_count,
ump_bytes_remaining: remaining_size,
hrmp_outgoing,
}
}
}
/// The error type for updating bandwidth used by a segment.
#[derive(RuntimeDebug)]
pub enum BandwidthUpdateError {
/// Too many messages submitted to HRMP channel.
HrmpMessagesOverflow {
/// Parachain id of the recipient.
recipient: ParaId,
/// The amount of remaining messages in the capacity of the channel.
messages_remaining: u32,
/// The amount of messages submitted to the channel.
messages_submitted: u32,
},
/// Too many bytes submitted to HRMP channel.
HrmpBytesOverflow {
/// Parachain id of the recipient.
recipient: ParaId,
/// The amount of remaining bytes in the capacity of the channel.
bytes_remaining: u32,
/// The amount of bytes submitted to the channel.
bytes_submitted: u32,
},
/// Too many messages submitted to UMP queue.
UmpMessagesOverflow {
/// The amount of remaining messages in the capacity of UMP.
messages_remaining: u32,
/// The amount of messages submitted to UMP.
messages_submitted: u32,
},
/// Too many bytes submitted to UMP.
UmpBytesOverflow {
/// The amount of remaining bytes in the capacity of UMP.
bytes_remaining: u32,
/// The amount of bytes submitted to UMP.
bytes_submitted: u32,
},
/// Invalid HRMP watermark.
InvalidHrmpWatermark {
/// HRMP watermark submitted by the candidate.
submitted: relay_chain::BlockNumber,
/// Latest tracked HRMP watermark.
latest: relay_chain::BlockNumber,
},
/// Upgrade signal sent by relay chain was already processed by
/// some ancestor from the segment.
UpgradeGoAheadAlreadyProcessed,
}
/// The number of messages and size in bytes submitted to HRMP channel.
#[derive(RuntimeDebug, Default, Copy, Clone, Encode, Decode, TypeInfo)]
pub struct HrmpChannelUpdate {
/// The amount of messages submitted to the channel.
pub msg_count: u32,
/// The amount of bytes submitted to the channel.
pub total_bytes: u32,
}
impl HrmpChannelUpdate {
/// Returns `true` if the update is empty, `false` otherwise.
fn is_empty(&self) -> bool {
self.msg_count == 0 && self.total_bytes == 0
}
/// Tries to append another update, respecting given bandwidth limits.
fn append(
&self,
other: &Self,
recipient: ParaId,
limits: &OutboundBandwidthLimits,
) -> Result<Self, BandwidthUpdateError> {
let limits = limits
.hrmp_outgoing
.get(&recipient)
.expect("limit for declared hrmp channel must be present; qed");
let mut new = *self;
new.msg_count = new.msg_count.saturating_add(other.msg_count);
if new.msg_count > limits.messages_remaining {
return Err(BandwidthUpdateError::HrmpMessagesOverflow {
recipient,
messages_remaining: limits.messages_remaining,
messages_submitted: new.msg_count,
})
}
new.total_bytes = new.total_bytes.saturating_add(other.total_bytes);
if new.total_bytes > limits.bytes_remaining {
return Err(BandwidthUpdateError::HrmpBytesOverflow {
recipient,
bytes_remaining: limits.bytes_remaining,
bytes_submitted: new.total_bytes,
})
}
Ok(new)
}
/// Subtracts previously added channel update.
fn subtract(&mut self, other: &Self) {
self.msg_count -= other.msg_count;
self.total_bytes -= other.total_bytes;
}
}
/// Bandwidth used by a parachain block(s).
///
/// This struct can be created with pub items, however, it should
/// never hit the storage directly to avoid bypassing limitations checks.
#[derive(Default, Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
pub struct UsedBandwidth {
/// The amount of UMP messages sent.
pub ump_msg_count: u32,
/// The amount of UMP bytes sent.
pub ump_total_bytes: u32,
/// Outbound HRMP channels updates.
pub hrmp_outgoing: BTreeMap<ParaId, HrmpChannelUpdate>,
}
impl UsedBandwidth {
/// Tries to append another update, respecting given bandwidth limits.
fn append(
&self,
other: &Self,
limits: &OutboundBandwidthLimits,
) -> Result<Self, BandwidthUpdateError> {
let mut new = self.clone();
new.ump_msg_count = new.ump_msg_count.saturating_add(other.ump_msg_count);
if new.ump_msg_count > limits.ump_messages_remaining {
return Err(BandwidthUpdateError::UmpMessagesOverflow {
messages_remaining: limits.ump_messages_remaining,
messages_submitted: new.ump_msg_count,
})
}
new.ump_total_bytes = new.ump_total_bytes.saturating_add(other.ump_total_bytes);
if new.ump_total_bytes > limits.ump_bytes_remaining {
return Err(BandwidthUpdateError::UmpBytesOverflow {
bytes_remaining: limits.ump_bytes_remaining,
bytes_submitted: new.ump_total_bytes,
})
}
for (id, channel) in other.hrmp_outgoing.iter() {
let current = new.hrmp_outgoing.entry(*id).or_default();
*current = current.append(channel, *id, limits)?;
}
Ok(new)
}
/// Subtracts previously added bandwidth update.
fn subtract(&mut self, other: &Self) {
self.ump_msg_count -= other.ump_msg_count;
self.ump_total_bytes -= other.ump_total_bytes;
for (id, channel) in other.hrmp_outgoing.iter() {
let entry = self
.hrmp_outgoing
.get_mut(id)
.expect("entry's been inserted earlier with `append`; qed");
entry.subtract(channel);
}
self.hrmp_outgoing.retain(|_, channel| !channel.is_empty());
}
}
/// Ancestor of the block being currently executed, not yet included
/// into the relay chain.
#[derive(Encode, Decode, TypeInfo, RuntimeDebug)]
pub struct Ancestor<H> {
/// Bandwidth used by this block.
used_bandwidth: UsedBandwidth,
/// Output head data hash of this block. This may be optional in case the head data has not
/// yet been posted on chain, but should be updated during initialization of the next block.
para_head_hash: Option<H>,
/// Optional go-ahead signal sent by the relay-chain this ancestor has processed.
consumed_go_ahead_signal: Option<relay_chain::UpgradeGoAhead>,
}
impl<H> Ancestor<H> {
/// Creates new ancestor without validating the bandwidth used.
pub fn new_unchecked(
used_bandwidth: UsedBandwidth,
consumed_go_ahead_signal: Option<relay_chain::UpgradeGoAhead>,
) -> Self {
Self { used_bandwidth, para_head_hash: None, consumed_go_ahead_signal }
}
/// Returns [`UsedBandwidth`] of this block.
pub fn used_bandwidth(&self) -> &UsedBandwidth {
&self.used_bandwidth
}
/// Returns hashed [output head data](`relay_chain::HeadData`) of this block.
pub fn para_head_hash(&self) -> Option<&H> {
self.para_head_hash.as_ref()
}
/// Set para head hash of this block.
pub fn replace_para_head_hash(&mut self, para_head_hash: H) {
self.para_head_hash.replace(para_head_hash);
}
}
/// An update to the HRMP watermark. This is always a relay-chain block number,
/// but the two variants have different semantic meanings.
pub enum HrmpWatermarkUpdate {
/// An update to the HRMP watermark where the new value is set to be equal to the
/// relay-parent's block number, i.e. the "head" of the relay chain.
/// This is always legal.
Head(relay_chain::BlockNumber),
/// An update to the HRMP watermark where the new value falls into the "trunk" of the
/// relay-chain. In this case, the watermark must be greater than the previous value.
Trunk(relay_chain::BlockNumber),
}
impl HrmpWatermarkUpdate {
/// Create a new update based on the desired watermark value and the current
/// relay-parent number.
pub fn new(
watermark: relay_chain::BlockNumber,
relay_parent_number: relay_chain::BlockNumber,
) -> Self {
// Hard constrain the watermark to the relay-parent number.
if watermark >= relay_parent_number {
HrmpWatermarkUpdate::Head(relay_parent_number)
} else {
HrmpWatermarkUpdate::Trunk(watermark)
}
}
}
/// Struct that keeps track of bandwidth used by the unincluded part of the chain
/// along with the latest HRMP watermark.
#[derive(Default, Encode, Decode, TypeInfo, RuntimeDebug)]
pub struct SegmentTracker<H> {
/// Bandwidth used by the segment.
used_bandwidth: UsedBandwidth,
/// The mark which specifies the block number up to which all inbound HRMP messages are
/// processed.
hrmp_watermark: Option<relay_chain::BlockNumber>,
/// Optional go-ahead signal sent by the relay-chain some ancestor from the segment has
/// processed. Only single block is allowed to have this set within the whole segment.
consumed_go_ahead_signal: Option<relay_chain::UpgradeGoAhead>,
/// `H` is the type of para head hash.
phantom_data: PhantomData<H>,
}
impl<H> SegmentTracker<H> {
/// Tries to append another block to the tracker, respecting given bandwidth limits.
/// In practice, the bandwidth limits supplied should be the total allowed within the
/// block.
pub fn append(
&mut self,
block: &Ancestor<H>,
new_watermark: HrmpWatermarkUpdate,
limits: &OutboundBandwidthLimits,
) -> Result<(), BandwidthUpdateError> {
if self.consumed_go_ahead_signal.is_some() && block.consumed_go_ahead_signal.is_some() {
return Err(BandwidthUpdateError::UpgradeGoAheadAlreadyProcessed)
}
if let Some(watermark) = self.hrmp_watermark.as_ref() {
if let HrmpWatermarkUpdate::Trunk(new) = new_watermark {
if &new <= watermark {
return Err(BandwidthUpdateError::InvalidHrmpWatermark {
submitted: new,
latest: *watermark,
})
}
}
}
self.used_bandwidth = self.used_bandwidth.append(block.used_bandwidth(), limits)?;
if let Some(consumed) = block.consumed_go_ahead_signal.as_ref() {
self.consumed_go_ahead_signal.replace(*consumed);
}
self.hrmp_watermark.replace(match new_watermark {
HrmpWatermarkUpdate::Trunk(w) | HrmpWatermarkUpdate::Head(w) => w,
});
Ok(())
}
/// Removes previously added block from the tracker.
pub fn subtract(&mut self, block: &Ancestor<H>) {
self.used_bandwidth.subtract(block.used_bandwidth());
if let Some(consumed) = block.consumed_go_ahead_signal.as_ref() {
// This is the same signal stored in the tracker.
let signal_in_segment = self.consumed_go_ahead_signal.take();
assert_eq!(signal_in_segment, Some(*consumed));
}
// Watermark doesn't need to be updated since the is always dropped
// from the tail of the segment.
}
/// Return a reference to the used bandwidth across the entire segment.
pub fn used_bandwidth(&self) -> &UsedBandwidth {
&self.used_bandwidth
}
/// Return go ahead signal consumed by some ancestor in a segment, if any.
pub fn consumed_go_ahead_signal(&self) -> Option<relay_chain::UpgradeGoAhead> {
self.consumed_go_ahead_signal
}
}
pub(crate) fn size_after_included<H: PartialEq>(included_hash: H, segment: &[Ancestor<H>]) -> u32 {
let pivot = segment
.iter()
.position(|ancestor| ancestor.para_head_hash() == Some(&included_hash))
.map(|p| p + 1)
.unwrap_or(0);
(segment.len() - pivot) as u32
}
#[cfg(test)]
mod tests {
use super::*;
use assert_matches::assert_matches;
#[test]
fn outbound_limits_constructed_correctly() {
let para_a = ParaId::from(0);
let para_a_channel = relay_chain::AbridgedHrmpChannel {
max_message_size: 15,
// Msg count capacity left is 2.
msg_count: 5,
max_capacity: 7,
// Bytes capacity left is 10.
total_size: 50,
max_total_size: 60,
mqc_head: None,
};
let para_b = ParaId::from(1);
let para_b_channel = relay_chain::AbridgedHrmpChannel {
max_message_size: 15,
// Msg count capacity left is 10.
msg_count: 40,
max_capacity: 50,
// Bytes capacity left is 0.
total_size: 500,
max_total_size: 500,
mqc_head: None,
};
let relay_dispatch_queue_remaining_capacity =
RelayDispatchQueueRemainingCapacity { remaining_count: 1, remaining_size: 50 };
let messaging_state = MessagingStateSnapshot {
dmq_mqc_head: relay_chain::Hash::zero(),
relay_dispatch_queue_remaining_capacity,
ingress_channels: Vec::new(),
egress_channels: vec![(para_a, para_a_channel), (para_b, para_b_channel)],
};
let limits = OutboundBandwidthLimits::from_relay_chain_state(&messaging_state);
// UMP.
assert_eq!(limits.ump_messages_remaining, 1);
assert_eq!(limits.ump_bytes_remaining, 50);
// HRMP.
let para_a_limits = limits.hrmp_outgoing.get(&para_a).expect("channel must be present");
let para_b_limits = limits.hrmp_outgoing.get(&para_b).expect("channel must be present");
assert_eq!(para_a_limits.bytes_remaining, 10);
assert_eq!(para_a_limits.messages_remaining, 2);
assert_eq!(para_b_limits.bytes_remaining, 0);
assert_eq!(para_b_limits.messages_remaining, 10);
}
#[test]
fn hrmp_msg_count_limits() {
let para_0 = ParaId::from(0);
let para_0_limits = HrmpOutboundLimits { bytes_remaining: u32::MAX, messages_remaining: 5 };
let para_1 = ParaId::from(1);
let para_1_limits = HrmpOutboundLimits { bytes_remaining: u32::MAX, messages_remaining: 3 };
let hrmp_outgoing = [(para_0, para_0_limits), (para_1, para_1_limits)].into();
let limits = OutboundBandwidthLimits {
ump_messages_remaining: 0,
ump_bytes_remaining: 0,
hrmp_outgoing,
};
let mut hrmp_update = HrmpChannelUpdate::default();
assert!(hrmp_update.is_empty());
for _ in 0..5 {
hrmp_update = hrmp_update
.append(&HrmpChannelUpdate { msg_count: 1, total_bytes: 10 }, para_0, &limits)
.expect("update is within the limits");
}
assert_matches!(
hrmp_update.append(
&HrmpChannelUpdate { msg_count: 1, total_bytes: 10 },
para_0,
&limits,
),
Err(BandwidthUpdateError::HrmpMessagesOverflow {
recipient,
messages_remaining,
messages_submitted,
}) if recipient == para_0 && messages_remaining == 5 && messages_submitted == 6
);
let mut hrmp_update = HrmpChannelUpdate::default();
hrmp_update = hrmp_update
.append(&HrmpChannelUpdate { msg_count: 2, total_bytes: 10 }, para_1, &limits)
.expect("update is within the limits");
assert_matches!(
hrmp_update.append(
&HrmpChannelUpdate { msg_count: 3, total_bytes: 10 },
para_1,
&limits,
),
Err(BandwidthUpdateError::HrmpMessagesOverflow {
recipient,
messages_remaining,
messages_submitted,
}) if recipient == para_1 && messages_remaining == 3 && messages_submitted == 5
);
}
#[test]
fn hrmp_bytes_limits() {
let para_0 = ParaId::from(0);
let para_0_limits =
HrmpOutboundLimits { bytes_remaining: 25, messages_remaining: u32::MAX };
let hrmp_outgoing = [(para_0, para_0_limits)].into();
let limits = OutboundBandwidthLimits {
ump_messages_remaining: 0,
ump_bytes_remaining: 0,
hrmp_outgoing,
};
let mut hrmp_update = HrmpChannelUpdate::default();
assert!(hrmp_update.is_empty());
for _ in 0..5 {
hrmp_update = hrmp_update
.append(&HrmpChannelUpdate { msg_count: 1, total_bytes: 4 }, para_0, &limits)
.expect("update is within the limits");
}
assert_matches!(
hrmp_update.append(
&HrmpChannelUpdate { msg_count: 1, total_bytes: 6 },
para_0,
&limits,
),
Err(BandwidthUpdateError::HrmpBytesOverflow {
recipient,
bytes_remaining,
bytes_submitted,
}) if recipient == para_0 && bytes_remaining == 25 && bytes_submitted == 26
);
}
#[test]
fn hrmp_limits_with_segment() {
let create_used_hrmp =
|hrmp_outgoing| UsedBandwidth { ump_msg_count: 0, ump_total_bytes: 0, hrmp_outgoing };
let para_0 = ParaId::from(0);
let para_0_limits = HrmpOutboundLimits { bytes_remaining: 30, messages_remaining: 10 };
let para_1 = ParaId::from(1);
let para_1_limits = HrmpOutboundLimits { bytes_remaining: 20, messages_remaining: 3 };
let hrmp_outgoing = [(para_0, para_0_limits), (para_1, para_1_limits)].into();
let limits = OutboundBandwidthLimits {
ump_messages_remaining: 0,
ump_bytes_remaining: 0,
hrmp_outgoing,
};
let mut segment = SegmentTracker::default();
let para_0_update = HrmpChannelUpdate { msg_count: 1, total_bytes: 6 };
let ancestor_0 = Ancestor {
used_bandwidth: create_used_hrmp([(para_0, para_0_update)].into()),
para_head_hash: None::<relay_chain::Hash>,
consumed_go_ahead_signal: None,
};
segment
.append(&ancestor_0, HrmpWatermarkUpdate::Trunk(0), &limits)
.expect("update is within the limits");
for watermark in 1..5 {
let ancestor = Ancestor {
used_bandwidth: create_used_hrmp([(para_0, para_0_update)].into()),
para_head_hash: None::<relay_chain::Hash>,
consumed_go_ahead_signal: None,
};
segment
.append(&ancestor, HrmpWatermarkUpdate::Trunk(watermark), &limits)
.expect("update is within the limits");
}
let para_0_update = HrmpChannelUpdate { msg_count: 1, total_bytes: 1 };
let ancestor_5 = Ancestor {
used_bandwidth: create_used_hrmp([(para_0, para_0_update)].into()),
para_head_hash: None::<relay_chain::Hash>,
consumed_go_ahead_signal: None,
};
assert_matches!(
segment.append(&ancestor_5, HrmpWatermarkUpdate::Trunk(5), &limits),
Err(BandwidthUpdateError::HrmpBytesOverflow {
recipient,
bytes_remaining,
bytes_submitted,
}) if recipient == para_0 && bytes_remaining == 30 && bytes_submitted == 31
);
// Remove the first ancestor from the segment to make space.
segment.subtract(&ancestor_0);
segment
.append(&ancestor_5, HrmpWatermarkUpdate::Trunk(5), &limits)
.expect("update is within the limits");
let para_1_update = HrmpChannelUpdate { msg_count: 3, total_bytes: 10 };
let ancestor = Ancestor {
used_bandwidth: create_used_hrmp([(para_1, para_1_update)].into()),
para_head_hash: None::<relay_chain::Hash>,
consumed_go_ahead_signal: None,
};
segment
.append(&ancestor, HrmpWatermarkUpdate::Trunk(6), &limits)
.expect("update is within the limits");
assert_matches!(
segment.append(&ancestor, HrmpWatermarkUpdate::Trunk(7), &limits),
Err(BandwidthUpdateError::HrmpMessagesOverflow {
recipient,
messages_remaining,
messages_submitted,
}) if recipient == para_1 && messages_remaining == 3 && messages_submitted == 6
);
}
#[test]
fn ump_limits_with_segment() {
let create_used_ump = |(ump_msg_count, ump_total_bytes)| UsedBandwidth {
ump_msg_count,
ump_total_bytes,
hrmp_outgoing: BTreeMap::default(),
};
let limits = OutboundBandwidthLimits {
ump_messages_remaining: 5,
ump_bytes_remaining: 50,
hrmp_outgoing: BTreeMap::default(),
};
let mut segment = SegmentTracker::default();
let ancestor_0 = Ancestor {
used_bandwidth: create_used_ump((1, 10)),
para_head_hash: None::<relay_chain::Hash>,
consumed_go_ahead_signal: None,
};
segment
.append(&ancestor_0, HrmpWatermarkUpdate::Trunk(0), &limits)
.expect("update is within the limits");
for watermark in 1..4 {
let ancestor = Ancestor {
used_bandwidth: create_used_ump((1, 10)),
para_head_hash: None::<relay_chain::Hash>,
consumed_go_ahead_signal: None,
};
segment
.append(&ancestor, HrmpWatermarkUpdate::Trunk(watermark), &limits)
.expect("update is within the limits");
}
let ancestor_4 = Ancestor {
used_bandwidth: create_used_ump((1, 30)),
para_head_hash: None::<relay_chain::Hash>,
consumed_go_ahead_signal: None,
};
assert_matches!(
segment.append(&ancestor_4, HrmpWatermarkUpdate::Trunk(4), &limits),
Err(BandwidthUpdateError::UmpBytesOverflow {
bytes_remaining,
bytes_submitted,
}) if bytes_remaining == 50 && bytes_submitted == 70
);
let ancestor = Ancestor {
used_bandwidth: create_used_ump((1, 5)),
para_head_hash: None::<relay_chain::Hash>,
consumed_go_ahead_signal: None,
};
segment
.append(&ancestor, HrmpWatermarkUpdate::Trunk(4), &limits)
.expect("update is within the limits");
assert_matches!(
segment.append(&ancestor, HrmpWatermarkUpdate::Trunk(5), &limits),
Err(BandwidthUpdateError::UmpMessagesOverflow {
messages_remaining,
messages_submitted,
}) if messages_remaining == 5 && messages_submitted == 6
);
}
#[test]
fn segment_hrmp_watermark() {
let mut segment = SegmentTracker::default();
let ancestor = Ancestor {
used_bandwidth: UsedBandwidth::default(),
para_head_hash: None::<relay_chain::Hash>,
consumed_go_ahead_signal: None,
};
let limits = OutboundBandwidthLimits {
ump_messages_remaining: 0,
ump_bytes_remaining: 0,
hrmp_outgoing: BTreeMap::default(),
};
segment
.append(&ancestor, HrmpWatermarkUpdate::Head(0), &limits)
.expect("nothing to compare the watermark with in default segment");
assert_matches!(
segment.append(&ancestor, HrmpWatermarkUpdate::Trunk(0), &limits),
Err(BandwidthUpdateError::InvalidHrmpWatermark {
submitted,
latest,
}) if submitted == 0 && latest == 0
);
for watermark in 1..5 {
segment
.append(&ancestor, HrmpWatermarkUpdate::Trunk(watermark), &limits)
.expect("hrmp watermark is valid");
}
for watermark in 0..5 {
assert_matches!(
segment.append(&ancestor, HrmpWatermarkUpdate::Trunk(watermark), &limits),
Err(BandwidthUpdateError::InvalidHrmpWatermark {
submitted,
latest,
}) if submitted == watermark && latest == 4
);
}
segment
.append(&ancestor, HrmpWatermarkUpdate::Head(4), &limits)
.expect("head updates always valid");
}
#[test]
fn segment_drops_empty_hrmp_channels() {
let create_used_hrmp =
|hrmp_outgoing| UsedBandwidth { ump_msg_count: 0, ump_total_bytes: 0, hrmp_outgoing };
let para_0 = ParaId::from(0);
let para_0_limits =
HrmpOutboundLimits { bytes_remaining: u32::MAX, messages_remaining: u32::MAX };
let para_1 = ParaId::from(1);
let para_1_limits =
HrmpOutboundLimits { bytes_remaining: u32::MAX, messages_remaining: u32::MAX };
let hrmp_outgoing = [(para_0, para_0_limits), (para_1, para_1_limits)].into();
let limits = OutboundBandwidthLimits {
ump_messages_remaining: 0,
ump_bytes_remaining: 0,
hrmp_outgoing,
};
let mut segment = SegmentTracker::default();
let para_0_update = HrmpChannelUpdate { msg_count: 1, total_bytes: 1 };
let ancestor_0 = Ancestor {
used_bandwidth: create_used_hrmp([(para_0, para_0_update)].into()),
para_head_hash: None::<relay_chain::Hash>,
consumed_go_ahead_signal: None,
};
segment
.append(&ancestor_0, HrmpWatermarkUpdate::Head(0), &limits)
.expect("update is within the limits");
let para_1_update = HrmpChannelUpdate { msg_count: 3, total_bytes: 10 };
let ancestor_1 = Ancestor {
used_bandwidth: create_used_hrmp([(para_1, para_1_update)].into()),
para_head_hash: None::<relay_chain::Hash>,
consumed_go_ahead_signal: None,
};
segment
.append(&ancestor_1, HrmpWatermarkUpdate::Head(1), &limits)
.expect("update is within the limits");
assert_eq!(segment.used_bandwidth.hrmp_outgoing.len(), 2);
segment.subtract(&ancestor_0);
assert_eq!(segment.used_bandwidth.hrmp_outgoing.len(), 1);
segment.subtract(&ancestor_1);
assert_eq!(segment.used_bandwidth.hrmp_outgoing.len(), 0);
}
#[test]
fn segment_go_ahead_signal_is_unique() {
let limits = OutboundBandwidthLimits {
ump_messages_remaining: 0,
ump_bytes_remaining: 0,
hrmp_outgoing: BTreeMap::default(),
};
let mut segment = SegmentTracker::default();
let ancestor_0 = Ancestor {
used_bandwidth: UsedBandwidth::default(),
para_head_hash: None::<relay_chain::Hash>,
consumed_go_ahead_signal: Some(relay_chain::UpgradeGoAhead::GoAhead),
};
segment
.append(&ancestor_0, HrmpWatermarkUpdate::Head(0), &limits)
.expect("update is within the limits");
let ancestor_1 = Ancestor {
used_bandwidth: UsedBandwidth::default(),
para_head_hash: None::<relay_chain::Hash>,
consumed_go_ahead_signal: None,
};
segment
.append(&ancestor_1, HrmpWatermarkUpdate::Head(1), &limits)
.expect("update is within the limits");
let ancestor_2 = Ancestor {
used_bandwidth: UsedBandwidth::default(),
para_head_hash: None::<relay_chain::Hash>,
consumed_go_ahead_signal: Some(relay_chain::UpgradeGoAhead::Abort),
};
assert_matches!(
segment.append(&ancestor_2, HrmpWatermarkUpdate::Head(2), &limits),
Err(BandwidthUpdateError::UpgradeGoAheadAlreadyProcessed)
);
segment.subtract(&ancestor_0);
segment
.append(&ancestor_2, HrmpWatermarkUpdate::Head(1), &limits)
.expect("update is within the limits");
}
#[test]
fn size_after_included_works() {
let segment = vec![
Ancestor {
used_bandwidth: Default::default(),
para_head_hash: Some("a"),
consumed_go_ahead_signal: None,
},
Ancestor {
used_bandwidth: Default::default(),
para_head_hash: Some("b"),
consumed_go_ahead_signal: None,
},
Ancestor {
used_bandwidth: Default::default(),
para_head_hash: Some("c"),
consumed_go_ahead_signal: None,
},
];
assert_eq!(size_after_included("a", &segment), 2,);
assert_eq!(size_after_included("b", &segment), 1,);
assert_eq!(size_after_included("c", &segment), 0,);
assert_eq!(size_after_included("d", &segment), 3,);
assert_eq!(size_after_included("x", &[]), 0,);
}
}
@@ -18,7 +18,9 @@ use codec::{Decode, DecodeAll, Encode};
use cumulus_primitives_core::{ParachainBlockData, PersistedValidationData};
use cumulus_test_client::{
generate_extrinsic,
runtime::{Block, Hash, Header, TestPalletCall, UncheckedExtrinsic, WASM_BINARY},
runtime::{
self as test_runtime, Block, Hash, Header, TestPalletCall, UncheckedExtrinsic, WASM_BINARY,
},
transfer, BlockData, BuildParachainBlockData, Client, DefaultTestClientBuilderExt, HeadData,
InitBlockBuilder, TestClientBuilder, TestClientBuilderExt, ValidationParams,
};
@@ -76,8 +78,10 @@ fn build_block_with_witness(
client: &Client,
extra_extrinsics: Vec<UncheckedExtrinsic>,
parent_head: Header,
sproof_builder: RelayStateSproofBuilder,
mut sproof_builder: RelayStateSproofBuilder,
) -> TestBlockData {
sproof_builder.para_id = test_runtime::PARACHAIN_ID.into();
sproof_builder.included_para_head = Some(HeadData(parent_head.encode()));
let (relay_parent_storage_root, _) = sproof_builder.clone().into_state_root_and_proof();
let mut validation_data = PersistedValidationData {
relay_parent_number: 1,
@@ -221,36 +225,6 @@ fn validate_block_fails_on_invalid_validation_data() {
}
}
#[test]
fn check_inherent_fails_on_validate_block_as_expected() {
sp_tracing::try_init_simple();
if env::var("RUN_TEST").is_ok() {
let (client, parent_head) = create_test_client();
let TestBlockData { block, validation_data } = build_block_with_witness(
&client,
Vec::new(),
parent_head.clone(),
RelayStateSproofBuilder { current_slot: 1337.into(), ..Default::default() },
);
call_validate_block(parent_head, block, validation_data.relay_parent_storage_root)
.unwrap_err();
} else {
let output = Command::new(env::current_exe().unwrap())
.args(["check_inherent_fails_on_validate_block_as_expected", "--", "--nocapture"])
.env("RUN_TEST", "1")
.output()
.expect("Runs the test");
assert!(output.status.success());
assert!(
dbg!(String::from_utf8(output.stderr).unwrap()).contains("Checking inherents failed")
);
}
}
#[test]
fn check_inherents_are_unsigned_and_before_all_other_extrinsics() {
sp_tracing::try_init_simple();
+1
View File
@@ -111,6 +111,7 @@ impl cumulus_pallet_parachain_system::Config for Test {
type XcmpMessageHandler = XcmpQueue;
type ReservedXcmpWeight = ();
type CheckAssociatedRelayNumber = AnyRelayNumber;
type ConsensusHook = cumulus_pallet_parachain_system::consensus_hook::ExpectParentIncluded;
}
parameter_types! {
+7 -1
View File
@@ -54,14 +54,16 @@ substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate
try-runtime-cli = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
# Polkadot
polkadot-cli = { git = "https://github.com/paritytech/polkadot", branch = "master", features = ["rococo-native"] }
polkadot-cli = { git = "https://github.com/paritytech/polkadot", features = ["rococo-native"] , branch = "master" }
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" }
xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
# Cumulus
cumulus-client-cli = { path = "../../client/cli" }
cumulus-client-collator = { path = "../../client/collator" }
cumulus-client-consensus-aura = { path = "../../client/consensus/aura" }
cumulus-client-consensus-common = { path = "../../client/consensus/common" }
cumulus-client-consensus-proposer = { path = "../../client/consensus/proposer" }
cumulus-client-service = { path = "../../client/service" }
cumulus-primitives-core = { path = "../../primitives/core" }
cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" }
@@ -81,3 +83,7 @@ try-runtime = [
"try-runtime-cli/try-runtime",
"parachain-template-runtime/try-runtime"
]
network-protocol-staging = [
"polkadot-cli/network-protocol-staging",
"cumulus-client-service/network-protocol-staging"
]
+80 -99
View File
@@ -5,19 +5,21 @@ use std::{sync::Arc, time::Duration};
use cumulus_client_cli::CollatorOptions;
// Local Runtime Types
use parachain_template_runtime::{opaque::Block, RuntimeApi};
use parachain_template_runtime::{
opaque::{Block, Hash},
RuntimeApi,
};
// Cumulus Imports
use cumulus_client_consensus_aura::{AuraConsensus, BuildAuraConsensusParams, SlotProportion};
use cumulus_client_consensus_common::{
ParachainBlockImport as TParachainBlockImport, ParachainConsensus,
};
use cumulus_client_collator::service::CollatorService;
use cumulus_client_consensus_common::ParachainBlockImport as TParachainBlockImport;
use cumulus_client_consensus_proposer::Proposer;
use cumulus_client_service::{
build_network, build_relay_chain_interface, prepare_node_config, start_collator,
start_full_node, BuildNetworkParams, StartCollatorParams, StartFullNodeParams,
build_network, build_relay_chain_interface, prepare_node_config, start_relay_chain_tasks,
BuildNetworkParams, CollatorSybilResistance, DARecoveryProfile, StartRelayChainTasksParams,
};
use cumulus_primitives_core::ParaId;
use cumulus_relay_chain_interface::RelayChainInterface;
use cumulus_primitives_core::{relay_chain::CollatorPair, ParaId};
use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface};
// Substrate Imports
use frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE;
@@ -176,7 +178,6 @@ async fn start_node_impl(
.await
.map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?;
let force_authoring = parachain_config.force_authoring;
let validator = parachain_config.role.is_authority();
let prometheus_registry = parachain_config.prometheus_registry().cloned();
let transaction_pool = params.transaction_pool.clone();
@@ -192,6 +193,7 @@ async fn start_node_impl(
spawn_handle: task_manager.spawn_handle(),
relay_chain_interface: relay_chain_interface.clone(),
import_queue: params.import_queue,
sybil_resistance_level: CollatorSybilResistance::Resistant, // because of Aura
})
.await?;
@@ -280,8 +282,25 @@ async fn start_node_impl(
.overseer_handle()
.map_err(|e| sc_service::Error::Application(Box::new(e)))?;
start_relay_chain_tasks(StartRelayChainTasksParams {
client: client.clone(),
announce_block: announce_block.clone(),
para_id,
relay_chain_interface: relay_chain_interface.clone(),
task_manager: &mut task_manager,
da_recovery_profile: if validator {
DARecoveryProfile::Collator
} else {
DARecoveryProfile::FullNode
},
import_queue: import_queue_service,
relay_chain_slot_duration,
recovery_handle: Box::new(overseer_handle.clone()),
sync_service: sync_service.clone(),
})?;
if validator {
let parachain_consensus = build_consensus(
start_consensus(
client.clone(),
block_import,
prometheus_registry.as_ref(),
@@ -291,42 +310,12 @@ async fn start_node_impl(
transaction_pool,
sync_service.clone(),
params.keystore_container.keystore(),
force_authoring,
relay_chain_slot_duration,
para_id,
collator_key.expect("Command line arguments do not allow this. qed"),
overseer_handle,
announce_block,
)?;
let spawner = task_manager.spawn_handle();
let params = StartCollatorParams {
para_id,
block_status: client.clone(),
announce_block,
client: client.clone(),
task_manager: &mut task_manager,
relay_chain_interface,
spawner,
parachain_consensus,
import_queue: import_queue_service,
collator_key: collator_key.expect("Command line arguments do not allow this. qed"),
relay_chain_slot_duration,
recovery_handle: Box::new(overseer_handle),
sync_service,
};
start_collator(params).await?;
} else {
let params = StartFullNodeParams {
client: client.clone(),
announce_block,
task_manager: &mut task_manager,
para_id,
relay_chain_interface,
relay_chain_slot_duration,
import_queue: import_queue_service,
recovery_handle: Box::new(overseer_handle),
sync_service,
};
start_full_node(params)?;
}
start_network.start_network();
@@ -344,35 +333,27 @@ fn build_import_queue(
) -> Result<sc_consensus::DefaultImportQueue<Block>, sc_service::Error> {
let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?;
cumulus_client_consensus_aura::import_queue::<
Ok(cumulus_client_consensus_aura::equivocation_import_queue::fully_verifying_import_queue::<
sp_consensus_aura::sr25519::AuthorityPair,
_,
_,
_,
_,
_,
>(cumulus_client_consensus_aura::ImportQueueParams {
block_import,
>(
client,
create_inherent_data_providers: move |_, _| async move {
block_import,
move |_, _| async move {
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
let slot =
sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
*timestamp,
slot_duration,
);
Ok((slot, timestamp))
Ok(timestamp)
},
registry: config.prometheus_registry(),
spawner: &task_manager.spawn_essential_handle(),
slot_duration,
&task_manager.spawn_essential_handle(),
config.prometheus_registry(),
telemetry,
})
.map_err(Into::into)
))
}
fn build_consensus(
fn start_consensus(
client: Arc<ParachainClient>,
block_import: ParachainBlockImport,
prometheus_registry: Option<&Registry>,
@@ -382,9 +363,19 @@ fn build_consensus(
transaction_pool: Arc<sc_transaction_pool::FullPool<Block, ParachainClient>>,
sync_oracle: Arc<SyncingService<Block>>,
keystore: KeystorePtr,
force_authoring: bool,
relay_chain_slot_duration: Duration,
para_id: ParaId,
) -> Result<Box<dyn ParachainConsensus<Block>>, sc_service::Error> {
collator_key: CollatorPair,
overseer_handle: OverseerHandle,
announce_block: Arc<dyn Fn(Hash, Option<Vec<u8>>) + Send + Sync>,
) -> Result<(), sc_service::Error> {
use cumulus_client_consensus_aura::collators::basic::{
self as basic_aura, Params as BasicAuraParams,
};
// NOTE: because we use Aura here explicitly, we can use `CollatorSybilResistance::Resistant`
// when starting the network.
let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?;
let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording(
@@ -395,50 +386,40 @@ fn build_consensus(
telemetry.clone(),
);
let params = BuildAuraConsensusParams {
proposer_factory,
create_inherent_data_providers: move |_, (relay_parent, validation_data)| {
let relay_chain_interface = relay_chain_interface.clone();
async move {
let parachain_inherent =
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(
relay_parent,
&relay_chain_interface,
&validation_data,
para_id,
)
.await;
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
let proposer = Proposer::new(proposer_factory);
let slot =
sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
*timestamp,
slot_duration,
let collator_service = CollatorService::new(
client.clone(),
Arc::new(task_manager.spawn_handle()),
announce_block,
client.clone(),
);
let parachain_inherent = parachain_inherent.ok_or_else(|| {
Box::<dyn std::error::Error + Send + Sync>::from(
"Failed to create parachain inherent",
)
})?;
Ok((slot, timestamp, parachain_inherent))
}
},
let params = BasicAuraParams {
create_inherent_data_providers: move |_, ()| async move { Ok(()) },
block_import,
para_client: client,
backoff_authoring_blocks: Option::<()>::None,
relay_client: relay_chain_interface,
sync_oracle,
keystore,
force_authoring,
collator_key,
para_id,
overseer_handle,
slot_duration,
// We got around 500ms for proposing
block_proposal_slot_portion: SlotProportion::new(1f32 / 24f32),
// And a maximum of 750ms if slots are skipped
max_block_proposal_slot_portion: Some(SlotProportion::new(1f32 / 16f32)),
telemetry,
relay_chain_slot_duration,
proposer,
collator_service,
// Very limited proposal time.
authoring_duration: Duration::from_millis(500),
};
Ok(AuraConsensus::build::<sp_consensus_aura::sr25519::AuthorityPair, _, _, _, _, _, _>(params))
let fut =
basic_aura::run::<Block, sp_consensus_aura::sr25519::AuthorityPair, _, _, _, _, _, _, _>(
params,
);
task_manager.spawn_essential_handle().spawn("aura", None, fut);
Ok(())
}
/// Start a parachain node.
@@ -63,12 +63,11 @@ xcm-executor = { git = "https://github.com/paritytech/polkadot", default-feature
# Cumulus
cumulus-pallet-aura-ext = { path = "../../pallets/aura-ext", default-features = false }
cumulus-pallet-dmp-queue = { path = "../../pallets/dmp-queue", default-features = false }
cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system", default-features = false }
cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] }
cumulus-pallet-session-benchmarking = {path = "../../pallets/session-benchmarking", default-features = false, version = "3.0.0"}
cumulus-pallet-xcm = { path = "../../pallets/xcm", default-features = false }
cumulus-pallet-xcmp-queue = { path = "../../pallets/xcmp-queue", default-features = false }
cumulus-primitives-core = { path = "../../primitives/core", default-features = false }
cumulus-primitives-timestamp = { path = "../../primitives/timestamp", default-features = false }
cumulus-primitives-utility = { path = "../../primitives/utility", default-features = false }
pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false }
parachain-info = { path = "../../parachains/pallets/parachain-info", default-features = false }
@@ -87,7 +86,6 @@ std = [
"cumulus-pallet-xcm/std",
"cumulus-pallet-xcmp-queue/std",
"cumulus-primitives-core/std",
"cumulus-primitives-timestamp/std",
"cumulus-primitives-utility/std",
"frame-executive/std",
"frame-support/std",
+21 -25
View File
@@ -152,7 +152,10 @@ impl WeightToFeePolynomial for WeightToFee {
/// to even the core data structures.
pub mod opaque {
use super::*;
use sp_runtime::{generic, traits::BlakeTwo256};
use sp_runtime::{
generic,
traits::{BlakeTwo256, Hash as HashT},
};
pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;
/// Opaque block header type.
@@ -161,6 +164,8 @@ pub mod opaque {
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
/// Opaque block identifier type.
pub type BlockId = generic::BlockId<Block>;
/// Opaque block hash type.
pub type Hash = <BlakeTwo256 as HashT>::Output;
}
impl_opaque_keys! {
@@ -220,6 +225,15 @@ const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(
cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64,
);
/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included
/// into the relay chain.
const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1;
/// How many parachain blocks are processed by the relay chain per parent. Limits the
/// number of blocks authored per slot.
const BLOCK_PROCESSING_VELOCITY: u32 = 1;
/// Relay chain slot duration, in milliseconds.
const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
/// The version information used to identify this runtime when compiled natively.
#[cfg(feature = "std")]
pub fn native_version() -> NativeVersion {
@@ -376,6 +390,12 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type XcmpMessageHandler = XcmpQueue;
type ReservedXcmpWeight = ReservedXcmpWeight;
type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases;
type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook<
Runtime,
RELAY_CHAIN_SLOT_DURATION_MILLIS,
BLOCK_PROCESSING_VELOCITY,
UNINCLUDED_SEGMENT_CAPACITY,
>;
}
impl parachain_info::Config for Runtime {}
@@ -722,31 +742,7 @@ impl_runtime_apis! {
}
}
struct CheckInherents;
impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
fn check_inherents(
block: &Block,
relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
) -> sp_inherents::CheckInherentsResult {
let relay_chain_slot = relay_state_proof
.read_slot()
.expect("Could not read the relay chain slot from the proof");
let inherent_data =
cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
relay_chain_slot,
sp_std::time::Duration::from_secs(6),
)
.create_inherent_data()
.expect("Could not create the timestamp inherent data");
inherent_data.check_extrinsics(block)
}
}
cumulus_pallet_parachain_system::register_validate_block! {
Runtime = Runtime,
BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
CheckInherents = CheckInherents,
}
@@ -126,71 +126,72 @@ fn send_transact_native_from_system_para_to_relay_fails() {
/// Parachain should be able to send XCM paying its fee with sufficient asset
/// in the System Parachain
#[test]
#[ignore]
fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() {
let para_sovereign_account = AssetHubKusama::sovereign_account_id_of(
AssetHubKusama::sibling_location_of(PenpalKusamaA::para_id()),
);
// let para_sovereign_account = AssetHubKusama::sovereign_account_id_of(
// AssetHubKusama::sibling_location_of(PenpalKusamaA::para_id()),
// );
// Force create and mint assets for Parachain's sovereign account
AssetHubKusama::force_create_and_mint_asset(
ASSET_ID,
ASSET_MIN_BALANCE,
true,
para_sovereign_account.clone(),
ASSET_MIN_BALANCE * 1000000000,
);
// // Force create and mint assets for Parachain's sovereign account
// AssetHubKusama::force_create_and_mint_asset(
// ASSET_ID,
// ASSET_MIN_BALANCE,
// true,
// para_sovereign_account.clone(),
// ASSET_MIN_BALANCE * 1000000000,
// );
// We just need a call that can pass the `SafeCallFilter`
// Call values are not relevant
let call = AssetHubKusama::force_create_asset_call(
ASSET_ID,
para_sovereign_account.clone(),
true,
ASSET_MIN_BALANCE,
);
// // We just need a call that can pass the `SafeCallFilter`
// // Call values are not relevant
// let call = AssetHubKusama::force_create_asset_call(
// ASSET_ID,
// para_sovereign_account.clone(),
// true,
// ASSET_MIN_BALANCE,
// );
let origin_kind = OriginKind::SovereignAccount;
let fee_amount = ASSET_MIN_BALANCE * 1000000;
let native_asset =
(X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), fee_amount).into();
// let origin_kind = OriginKind::SovereignAccount;
// let fee_amount = ASSET_MIN_BALANCE * 1000000;
// let native_asset =
// (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), fee_amount).into();
let root_origin = <PenpalKusamaA as Chain>::RuntimeOrigin::root();
let system_para_destination =
PenpalKusamaA::sibling_location_of(AssetHubKusama::para_id()).into();
let xcm = xcm_transact_paid_execution(
call,
origin_kind,
native_asset,
para_sovereign_account.clone(),
);
// let root_origin = <PenpalKusamaA as Chain>::RuntimeOrigin::root();
// let system_para_destination =
// PenpalKusamaA::sibling_location_of(AssetHubKusama::para_id()).into();
// let xcm = xcm_transact_paid_execution(
// call,
// origin_kind,
// native_asset,
// para_sovereign_account.clone(),
// );
PenpalKusamaA::execute_with(|| {
assert_ok!(<PenpalKusamaA as PenpalKusamaAPallet>::PolkadotXcm::send(
root_origin,
bx!(system_para_destination),
bx!(xcm),
));
// PenpalKusamaA::execute_with(|| {
// assert_ok!(<PenpalKusamaA as PenpalKusamaAPallet>::PolkadotXcm::send(
// root_origin,
// bx!(system_para_destination),
// bx!(xcm),
// ));
PenpalKusamaA::assert_xcm_pallet_sent();
});
// PenpalKusamaA::assert_xcm_pallet_sent();
// });
AssetHubKusama::execute_with(|| {
type RuntimeEvent = <AssetHubKusama as Chain>::RuntimeEvent;
// AssetHubKusama::execute_with(|| {
// type RuntimeEvent = <AssetHubKusama as Chain>::RuntimeEvent;
AssetHubKusama::assert_xcmp_queue_success(Some(Weight::from_parts(2_176_414_000, 203_593)));
// AssetHubKusama::assert_xcmp_queue_success(Some(Weight::from_parts(2_176_414_000, 203_593)));
assert_expected_events!(
AssetHubKusama,
vec![
RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => {
asset_id: *asset_id == ASSET_ID,
owner: *owner == para_sovereign_account,
balance: *balance == fee_amount,
},
RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, .. }) => {
asset_id: *asset_id == ASSET_ID,
},
]
);
});
// assert_expected_events!(
// AssetHubKusama,
// vec![
// RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => {
// asset_id: *asset_id == ASSET_ID,
// owner: *owner == para_sovereign_account,
// balance: *balance == fee_amount,
// },
// RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, .. }) => {
// asset_id: *asset_id == ASSET_ID,
// },
// ]
// );
// });
}
@@ -129,74 +129,75 @@ fn send_transact_native_from_system_para_to_relay_fails() {
/// Parachain should be able to send XCM paying its fee with sufficient asset
/// in the System Parachain
#[test]
#[ignore]
fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() {
let para_sovereign_account = AssetHubPolkadot::sovereign_account_id_of(
AssetHubPolkadot::sibling_location_of(PenpalPolkadotA::para_id()),
);
// let para_sovereign_account = AssetHubPolkadot::sovereign_account_id_of(
// AssetHubPolkadot::sibling_location_of(PenpalPolkadotA::para_id()),
// );
// Force create and mint assets for Parachain's sovereign account
AssetHubPolkadot::force_create_and_mint_asset(
ASSET_ID,
ASSET_MIN_BALANCE,
true,
para_sovereign_account.clone(),
ASSET_MIN_BALANCE * 1000000000,
);
// // Force create and mint assets for Parachain's sovereign account
// AssetHubPolkadot::force_create_and_mint_asset(
// ASSET_ID,
// ASSET_MIN_BALANCE,
// true,
// para_sovereign_account.clone(),
// ASSET_MIN_BALANCE * 1000000000,
// );
// We just need a call that can pass the `SafeCallFilter`
// Call values are not relevant
let call = AssetHubPolkadot::force_create_asset_call(
ASSET_ID,
para_sovereign_account.clone(),
true,
ASSET_MIN_BALANCE,
);
// // We just need a call that can pass the `SafeCallFilter`
// // Call values are not relevant
// let call = AssetHubPolkadot::force_create_asset_call(
// ASSET_ID,
// para_sovereign_account.clone(),
// true,
// ASSET_MIN_BALANCE,
// );
let origin_kind = OriginKind::SovereignAccount;
let fee_amount = ASSET_MIN_BALANCE * 1000000;
let native_asset =
(X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), fee_amount).into();
// let origin_kind = OriginKind::SovereignAccount;
// let fee_amount = ASSET_MIN_BALANCE * 1000000;
// let native_asset =
// (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), fee_amount).into();
let root_origin = <PenpalPolkadotA as Chain>::RuntimeOrigin::root();
let system_para_destination =
PenpalPolkadotA::sibling_location_of(AssetHubPolkadot::para_id()).into();
let xcm = xcm_transact_paid_execution(
call,
origin_kind,
native_asset,
para_sovereign_account.clone(),
);
// let root_origin = <PenpalPolkadotA as Chain>::RuntimeOrigin::root();
// let system_para_destination =
// PenpalPolkadotA::sibling_location_of(AssetHubPolkadot::para_id()).into();
// let xcm = xcm_transact_paid_execution(
// call,
// origin_kind,
// native_asset,
// para_sovereign_account.clone(),
// );
PenpalPolkadotA::execute_with(|| {
assert_ok!(<PenpalPolkadotA as PenpalPolkadotAPallet>::PolkadotXcm::send(
root_origin,
bx!(system_para_destination),
bx!(xcm),
));
// PenpalPolkadotA::execute_with(|| {
// assert_ok!(<PenpalPolkadotA as PenpalPolkadotAPallet>::PolkadotXcm::send(
// root_origin,
// bx!(system_para_destination),
// bx!(xcm),
// ));
PenpalPolkadotA::assert_xcm_pallet_sent();
});
// PenpalPolkadotA::assert_xcm_pallet_sent();
// });
AssetHubPolkadot::execute_with(|| {
type RuntimeEvent = <AssetHubPolkadot as Chain>::RuntimeEvent;
// AssetHubPolkadot::execute_with(|| {
// type RuntimeEvent = <AssetHubPolkadot as Chain>::RuntimeEvent;
AssetHubPolkadot::assert_xcmp_queue_success(Some(Weight::from_parts(
2_176_414_000,
203_593,
)));
// AssetHubPolkadot::assert_xcmp_queue_success(Some(Weight::from_parts(
// 2_176_414_000,
// 203_593,
// )));
assert_expected_events!(
AssetHubPolkadot,
vec![
RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => {
asset_id: *asset_id == ASSET_ID,
owner: *owner == para_sovereign_account,
balance: *balance == fee_amount,
},
RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, .. }) => {
asset_id: *asset_id == ASSET_ID,
},
]
);
});
// assert_expected_events!(
// AssetHubPolkadot,
// vec![
// RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => {
// asset_id: *asset_id == ASSET_ID,
// owner: *owner == para_sovereign_account,
// balance: *balance == fee_amount,
// },
// RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, .. }) => {
// asset_id: *asset_id == ASSET_ID,
// },
// ]
// );
// });
}
@@ -68,74 +68,75 @@ fn send_transact_sudo_from_relay_to_system_para_works() {
/// Parachain should be able to send XCM paying its fee with sufficient asset
/// in the System Parachain
#[test]
#[ignore]
fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() {
let para_sovereign_account = AssetHubWestend::sovereign_account_id_of(
AssetHubWestend::sibling_location_of(PenpalWestendA::para_id()),
);
// let para_sovereign_account = AssetHubWestend::sovereign_account_id_of(
// AssetHubWestend::sibling_location_of(PenpalWestendA::para_id()),
// );
// Force create and mint assets for Parachain's sovereign account
AssetHubWestend::force_create_and_mint_asset(
ASSET_ID,
ASSET_MIN_BALANCE,
true,
para_sovereign_account.clone(),
ASSET_MIN_BALANCE * 1000000000,
);
// // Force create and mint assets for Parachain's sovereign account
// AssetHubWestend::force_create_and_mint_asset(
// ASSET_ID,
// ASSET_MIN_BALANCE,
// true,
// para_sovereign_account.clone(),
// ASSET_MIN_BALANCE * 1000000000,
// );
// We just need a call that can pass the `SafeCallFilter`
// Call values are not relevant
let call = AssetHubWestend::force_create_asset_call(
ASSET_ID,
para_sovereign_account.clone(),
true,
ASSET_MIN_BALANCE,
);
// // We just need a call that can pass the `SafeCallFilter`
// // Call values are not relevant
// let call = AssetHubWestend::force_create_asset_call(
// ASSET_ID,
// para_sovereign_account.clone(),
// true,
// ASSET_MIN_BALANCE,
// );
let origin_kind = OriginKind::SovereignAccount;
let fee_amount = ASSET_MIN_BALANCE * 1000000;
let native_asset =
(X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), fee_amount).into();
// let origin_kind = OriginKind::SovereignAccount;
// let fee_amount = ASSET_MIN_BALANCE * 1000000;
// let native_asset =
// (X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), fee_amount).into();
let root_origin = <PenpalWestendA as Chain>::RuntimeOrigin::root();
let system_para_destination =
PenpalWestendA::sibling_location_of(AssetHubWestend::para_id()).into();
let xcm = xcm_transact_paid_execution(
call,
origin_kind,
native_asset,
para_sovereign_account.clone(),
);
// let root_origin = <PenpalWestendA as Chain>::RuntimeOrigin::root();
// let system_para_destination =
// PenpalWestendA::sibling_location_of(AssetHubWestend::para_id()).into();
// let xcm = xcm_transact_paid_execution(
// call,
// origin_kind,
// native_asset,
// para_sovereign_account.clone(),
// );
PenpalWestendA::execute_with(|| {
assert_ok!(<PenpalWestendA as PenpalWestendAPallet>::PolkadotXcm::send(
root_origin,
bx!(system_para_destination),
bx!(xcm),
));
// PenpalWestendA::execute_with(|| {
// assert_ok!(<PenpalWestendA as PenpalWestendAPallet>::PolkadotXcm::send(
// root_origin,
// bx!(system_para_destination),
// bx!(xcm),
// ));
PenpalWestendA::assert_xcm_pallet_sent();
});
// PenpalWestendA::assert_xcm_pallet_sent();
// });
AssetHubWestend::execute_with(|| {
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
// AssetHubWestend::execute_with(|| {
// type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
AssetHubWestend::assert_xcmp_queue_success(Some(Weight::from_parts(
2_176_414_000,
203_593,
)));
// AssetHubWestend::assert_xcmp_queue_success(Some(Weight::from_parts(
// 2_176_414_000,
// 203_593,
// )));
assert_expected_events!(
AssetHubWestend,
vec![
RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => {
asset_id: *asset_id == ASSET_ID,
owner: *owner == para_sovereign_account,
balance: *balance == fee_amount,
},
RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, .. }) => {
asset_id: *asset_id == ASSET_ID,
},
]
);
});
// assert_expected_events!(
// AssetHubWestend,
// vec![
// RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => {
// asset_id: *asset_id == ASSET_ID,
// owner: *owner == para_sovereign_account,
// balance: *balance == fee_amount,
// },
// RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, .. }) => {
// asset_id: *asset_id == ASSET_ID,
// },
// ]
// );
// });
}
@@ -14,86 +14,85 @@
// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
use crate::*;
#[test]
#[ignore]
fn example() {
// Init tests variables
// XcmPallet send arguments
let sudo_origin = <Rococo as Chain>::RuntimeOrigin::root();
let destination = Rococo::child_location_of(BridgeHubRococo::para_id()).into();
let weight_limit = WeightLimit::Unlimited;
let check_origin = None;
// // Init tests variables
// // XcmPallet send arguments
// let sudo_origin = <Rococo as Chain>::RuntimeOrigin::root();
// let destination = Rococo::child_location_of(BridgeHubRococo::para_id()).into();
// let weight_limit = WeightLimit::Unlimited;
// let check_origin = None;
let remote_xcm = Xcm(vec![ClearOrigin]);
// let remote_xcm = Xcm(vec![ClearOrigin]);
let xcm = VersionedXcm::from(Xcm(vec![
UnpaidExecution { weight_limit, check_origin },
ExportMessage {
network: WococoId,
destination: X1(Parachain(AssetHubWococo::para_id().into())),
xcm: remote_xcm,
},
]));
// let xcm = VersionedXcm::from(Xcm(vec![
// UnpaidExecution { weight_limit, check_origin },
// ExportMessage {
// network: WococoId,
// destination: X1(Parachain(AssetHubWococo::para_id().into())),
// xcm: remote_xcm,
// },
// ]));
//Rococo Global Consensus
// Send XCM message from Relay Chain to Bridge Hub source Parachain
Rococo::execute_with(|| {
assert_ok!(<Rococo as RococoPallet>::XcmPallet::send(
sudo_origin,
bx!(destination),
bx!(xcm),
));
// //Rococo Global Consensus
// // Send XCM message from Relay Chain to Bridge Hub source Parachain
// Rococo::execute_with(|| {
// assert_ok!(<Rococo as RococoPallet>::XcmPallet::send(
// sudo_origin,
// bx!(destination),
// bx!(xcm),
// ));
type RuntimeEvent = <Rococo as Chain>::RuntimeEvent;
// type RuntimeEvent = <Rococo as Chain>::RuntimeEvent;
assert_expected_events!(
Rococo,
vec![
RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {},
]
);
});
// Receive XCM message in Bridge Hub source Parachain
BridgeHubRococo::execute_with(|| {
type RuntimeEvent = <BridgeHubRococo as Chain>::RuntimeEvent;
// assert_expected_events!(
// Rococo,
// vec![
// RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {},
// ]
// );
// });
// // Receive XCM message in Bridge Hub source Parachain
// BridgeHubRococo::execute_with(|| {
// type RuntimeEvent = <BridgeHubRococo as Chain>::RuntimeEvent;
assert_expected_events!(
BridgeHubRococo,
vec![
RuntimeEvent::DmpQueue(cumulus_pallet_dmp_queue::Event::ExecutedDownward {
outcome: Outcome::Complete(_),
..
}) => {},
RuntimeEvent::BridgeWococoMessages(pallet_bridge_messages::Event::MessageAccepted {
lane_id: LaneId([0, 0, 0, 1]),
nonce: 1,
}) => {},
]
);
});
// assert_expected_events!(
// BridgeHubRococo,
// vec![
// RuntimeEvent::DmpQueue(cumulus_pallet_dmp_queue::Event::ExecutedDownward {
// outcome: Outcome::Complete(_),
// ..
// }) => {},
// RuntimeEvent::BridgeWococoMessages(pallet_bridge_messages::Event::MessageAccepted {
// lane_id: LaneId([0, 0, 0, 1]),
// nonce: 1,
// }) => {},
// ]
// );
// });
// Wococo GLobal Consensus
// Receive XCM message in Bridge Hub target Parachain
BridgeHubWococo::execute_with(|| {
type RuntimeEvent = <BridgeHubWococo as Chain>::RuntimeEvent;
// // Wococo GLobal Consensus
// // Receive XCM message in Bridge Hub target Parachain
// BridgeHubWococo::execute_with(|| {
// type RuntimeEvent = <BridgeHubWococo as Chain>::RuntimeEvent;
assert_expected_events!(
BridgeHubWococo,
vec![
RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {},
]
);
});
// Receive embeded XCM message within `ExportMessage` in Parachain destination
AssetHubWococo::execute_with(|| {
type RuntimeEvent = <AssetHubWococo as Chain>::RuntimeEvent;
// assert_expected_events!(
// BridgeHubWococo,
// vec![
// RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {},
// ]
// );
// });
// // Receive embeded XCM message within `ExportMessage` in Parachain destination
// AssetHubWococo::execute_with(|| {
// type RuntimeEvent = <AssetHubWococo as Chain>::RuntimeEvent;
assert_expected_events!(
AssetHubWococo,
vec![
RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Fail { .. }) => {},
]
);
});
// assert_expected_events!(
// AssetHubWococo,
// vec![
// RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Fail { .. }) => {},
// ]
// );
// });
}
@@ -16,62 +16,54 @@
//! Integration tests concerning the Fellowship.
use crate::*;
use collectives_polkadot_runtime::fellowship::FellowshipSalaryPaymaster;
use frame_support::traits::{
fungibles::{Create, Mutate},
tokens::Pay,
};
use sp_core::crypto::Ss58Codec;
use xcm_emulator::TestExt;
#[test]
#[ignore]
fn pay_salary() {
let asset_id: u32 = 1984;
let pay_from: AccountId =
<AccountId as Ss58Codec>::from_string("13w7NdvSR1Af8xsQTArDtZmVvjE8XhWNdL4yed3iFHrUNCnS")
.unwrap();
let pay_to = Polkadot::account_id_of(ALICE);
let pay_amount = 9000;
// let asset_id: u32 = 1984;
// let pay_from: AccountId =
// <AccountId as Ss58Codec>::from_string("13w7NdvSR1Af8xsQTArDtZmVvjE8XhWNdL4yed3iFHrUNCnS")
// .unwrap();
// let pay_to = Polkadot::account_id_of(ALICE);
// let pay_amount = 9000;
AssetHubPolkadot::execute_with(|| {
type AssetHubAssets = <AssetHubPolkadot as AssetHubPolkadotPallet>::Assets;
// AssetHubPolkadot::execute_with(|| {
// type AssetHubAssets = <AssetHubPolkadot as AssetHubPolkadotPallet>::Assets;
assert_ok!(<AssetHubAssets as Create<_>>::create(
asset_id,
pay_to.clone(),
true,
pay_amount / 2
));
assert_ok!(<AssetHubAssets as Mutate<_>>::mint_into(asset_id, &pay_from, pay_amount * 2));
});
// assert_ok!(<AssetHubAssets as Create<_>>::create(
// asset_id,
// pay_to.clone(),
// true,
// pay_amount / 2
// ));
// assert_ok!(<AssetHubAssets as Mutate<_>>::mint_into(asset_id, &pay_from, pay_amount * 2));
// });
Collectives::execute_with(|| {
type RuntimeEvent = <Collectives as Chain>::RuntimeEvent;
// Collectives::execute_with(|| {
// type RuntimeEvent = <Collectives as Chain>::RuntimeEvent;
assert_ok!(FellowshipSalaryPaymaster::pay(&pay_to, (), pay_amount));
assert_expected_events!(
Collectives,
vec![
RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {},
]
);
});
// assert_ok!(FellowshipSalaryPaymaster::pay(&pay_to, (), pay_amount));
// assert_expected_events!(
// Collectives,
// vec![
// RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {},
// ]
// );
// });
AssetHubPolkadot::execute_with(|| {
type RuntimeEvent = <AssetHubPolkadot as Chain>::RuntimeEvent;
// AssetHubPolkadot::execute_with(|| {
// type RuntimeEvent = <AssetHubPolkadot as Chain>::RuntimeEvent;
assert_expected_events!(
AssetHubPolkadot,
vec![
RuntimeEvent::Assets(pallet_assets::Event::Transferred { asset_id: id, from, to, amount }) => {
asset_id: id == &asset_id,
from: from == &pay_from,
to: to == &pay_to,
amount: amount == &pay_amount,
},
RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) => {},
]
);
});
// assert_expected_events!(
// AssetHubPolkadot,
// vec![
// RuntimeEvent::Assets(pallet_assets::Event::Transferred { asset_id: id, from, to, amount }) =>
// { asset_id: id == &asset_id,
// from: from == &pay_from,
// to: to == &pay_to,
// amount: amount == &pay_amount,
// },
// RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) => {},
// ]
// );
// });
}
@@ -29,7 +29,7 @@ beefy-primitives = { package = "sp-consensus-beefy", git = "https://github.com/p
# Polkadot
polkadot-core-primitives = { default-features = false, git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-parachain = { default-features = false, git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-service = { default-features = false, git = "https://github.com/paritytech/polkadot", branch = "master", features = ["full-node"] }
polkadot-service = { default-features = false, git = "https://github.com/paritytech/polkadot", features = ["full-node"] , branch = "master" }
polkadot-primitives = { default-features = false, git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-runtime = { git = "https://github.com/paritytech/polkadot", branch = "master" }
@@ -10,7 +10,10 @@ pub use constants::{
PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD,
};
use frame_support::{
assert_ok, instances::Instance1, parameter_types, sp_tracing, traits::fungibles::Inspect,
assert_ok,
instances::Instance1,
parameter_types, sp_tracing,
traits::{fungibles::Inspect, Hooks},
};
pub use impls::{RococoWococoMessageHandler, WococoRococoMessageHandler};
pub use parachains_common::{AccountId, Balance};
@@ -117,7 +120,9 @@ decl_test_parachains! {
// Polkadot Parachains
pub struct AssetHubPolkadot {
genesis = asset_hub_polkadot::genesis(),
on_init = (),
on_init = {
asset_hub_polkadot_runtime::AuraExt::on_initialize(1);
},
runtime = asset_hub_polkadot_runtime,
core = {
XcmpMessageHandler: asset_hub_polkadot_runtime::XcmpQueue,
@@ -133,7 +138,9 @@ decl_test_parachains! {
},
pub struct Collectives {
genesis = collectives::genesis(),
on_init = (),
on_init = {
collectives_polkadot_runtime::AuraExt::on_initialize(1);
},
runtime = collectives_polkadot_runtime,
core = {
XcmpMessageHandler: collectives_polkadot_runtime::XcmpQueue,
@@ -148,7 +155,9 @@ decl_test_parachains! {
},
pub struct BridgeHubPolkadot {
genesis = bridge_hub_polkadot::genesis(),
on_init = (),
on_init = {
bridge_hub_polkadot_runtime::AuraExt::on_initialize(1);
},
runtime = bridge_hub_polkadot_runtime,
core = {
XcmpMessageHandler: bridge_hub_polkadot_runtime::XcmpQueue,
@@ -162,7 +171,9 @@ decl_test_parachains! {
},
pub struct PenpalPolkadotA {
genesis = penpal::genesis(penpal::PARA_ID_A),
on_init = (),
on_init = {
penpal_runtime::AuraExt::on_initialize(1);
},
runtime = penpal_runtime,
core = {
XcmpMessageHandler: penpal_runtime::XcmpQueue,
@@ -177,7 +188,9 @@ decl_test_parachains! {
},
pub struct PenpalPolkadotB {
genesis = penpal::genesis(penpal::PARA_ID_B),
on_init = (),
on_init = {
penpal_runtime::AuraExt::on_initialize(1);
},
runtime = penpal_runtime,
core = {
XcmpMessageHandler: penpal_runtime::XcmpQueue,
@@ -193,7 +206,9 @@ decl_test_parachains! {
// Kusama Parachains
pub struct AssetHubKusama {
genesis = asset_hub_kusama::genesis(),
on_init = (),
on_init = {
asset_hub_kusama_runtime::AuraExt::on_initialize(1);
},
runtime = asset_hub_kusama_runtime,
core = {
XcmpMessageHandler: asset_hub_kusama_runtime::XcmpQueue,
@@ -210,7 +225,9 @@ decl_test_parachains! {
},
pub struct BridgeHubKusama {
genesis = bridge_hub_kusama::genesis(),
on_init = (),
on_init = {
bridge_hub_kusama_runtime::AuraExt::on_initialize(1);
},
runtime = bridge_hub_kusama_runtime,
core = {
XcmpMessageHandler: bridge_hub_kusama_runtime::XcmpQueue,
@@ -224,7 +241,9 @@ decl_test_parachains! {
},
pub struct PenpalKusamaA {
genesis = penpal::genesis(penpal::PARA_ID_A),
on_init = (),
on_init = {
penpal_runtime::AuraExt::on_initialize(1);
},
runtime = penpal_runtime,
core = {
XcmpMessageHandler: penpal_runtime::XcmpQueue,
@@ -239,7 +258,9 @@ decl_test_parachains! {
},
pub struct PenpalKusamaB {
genesis = penpal::genesis(penpal::PARA_ID_B),
on_init = (),
on_init = {
penpal_runtime::AuraExt::on_initialize(1);
},
runtime = penpal_runtime,
core = {
XcmpMessageHandler: penpal_runtime::XcmpQueue,
@@ -255,7 +276,9 @@ decl_test_parachains! {
// Westend Parachains
pub struct AssetHubWestend {
genesis = asset_hub_westend::genesis(),
on_init = (),
on_init = {
asset_hub_westend_runtime::AuraExt::on_initialize(1);
},
runtime = asset_hub_westend_runtime,
core = {
XcmpMessageHandler: asset_hub_westend_runtime::XcmpQueue,
@@ -274,7 +297,9 @@ decl_test_parachains! {
},
pub struct PenpalWestendA {
genesis = penpal::genesis(penpal::PARA_ID_A),
on_init = (),
on_init = {
penpal_runtime::AuraExt::on_initialize(1);
},
runtime = penpal_runtime,
core = {
XcmpMessageHandler: penpal_runtime::XcmpQueue,
@@ -290,7 +315,9 @@ decl_test_parachains! {
// Rococo Parachains
pub struct BridgeHubRococo {
genesis = bridge_hub_rococo::genesis(),
on_init = (),
on_init = {
bridge_hub_rococo_runtime::AuraExt::on_initialize(1);
},
runtime = bridge_hub_rococo_runtime,
core = {
XcmpMessageHandler: bridge_hub_rococo_runtime::XcmpQueue,
@@ -306,7 +333,9 @@ decl_test_parachains! {
// AssetHubRococo (aka Rockmine/Rockmine2) mirrors AssetHubKusama
pub struct AssetHubRococo {
genesis = asset_hub_kusama::genesis(),
on_init = (),
on_init = {
asset_hub_polkadot_runtime::AuraExt::on_initialize(1);
},
runtime = asset_hub_kusama_runtime,
core = {
XcmpMessageHandler: asset_hub_kusama_runtime::XcmpQueue,
@@ -322,7 +351,9 @@ decl_test_parachains! {
// Wococo Parachains
pub struct BridgeHubWococo {
genesis = bridge_hub_rococo::genesis(),
on_init = (),
on_init = {
bridge_hub_rococo_runtime::AuraExt::on_initialize(1);
},
runtime = bridge_hub_rococo_runtime,
core = {
XcmpMessageHandler: bridge_hub_rococo_runtime::XcmpQueue,
@@ -336,7 +367,9 @@ decl_test_parachains! {
},
pub struct AssetHubWococo {
genesis = asset_hub_polkadot::genesis(),
on_init = (),
on_init = {
asset_hub_polkadot_runtime::AuraExt::on_initialize(1);
},
runtime = asset_hub_polkadot_runtime,
core = {
XcmpMessageHandler: asset_hub_polkadot_runtime::XcmpQueue,
@@ -351,7 +384,9 @@ decl_test_parachains! {
},
pub struct PenpalRococoA {
genesis = penpal::genesis(penpal::PARA_ID_A),
on_init = (),
on_init = {
penpal_runtime::AuraExt::on_initialize(1);
},
runtime = penpal_runtime,
core = {
XcmpMessageHandler: penpal_runtime::XcmpQueue,
@@ -53,7 +53,7 @@ sp-weights = { git = "https://github.com/paritytech/substrate", default-features
# Polkadot
kusama-runtime-constants = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false, optional = true }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", default-features = false, optional = true , branch = "master" }
polkadot-core-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
@@ -64,12 +64,11 @@ xcm-executor = { git = "https://github.com/paritytech/polkadot", default-feature
# Cumulus
cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false }
cumulus-pallet-dmp-queue = { path = "../../../../pallets/dmp-queue", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] }
cumulus-pallet-session-benchmarking = {path = "../../../../pallets/session-benchmarking", default-features = false, version = "3.0.0"}
cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false }
cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false }
cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false }
cumulus-primitives-timestamp = { path = "../../../../primitives/timestamp", default-features = false }
cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false }
pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false }
parachain-info = { path = "../../../pallets/parachain-info", default-features = false }
@@ -83,7 +82,9 @@ asset-test-utils = { path = "../test-utils"}
substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
[features]
default = [ "std" ]
default = [
"std",
]
# When enabled the `state_version` is set to `1`.
# This means that the chain will start using the new state format. The migration is lazy, so
# it requires to write a storage value to use the new state format. To migrate all the other
@@ -195,7 +196,6 @@ std = [
"cumulus-pallet-xcm/std",
"cumulus-pallet-xcmp-queue/std",
"cumulus-primitives-core/std",
"cumulus-primitives-timestamp/std",
"cumulus-primitives-utility/std",
"pallet-collator-selection/std",
"parachain-info/std",
@@ -104,3 +104,15 @@ pub mod fee {
}
}
}
/// Consensus-related.
pub mod consensus {
/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included
/// into the relay chain.
pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1;
/// How many parachain blocks are processed by the relay chain per parent. Limits the
/// number of blocks authored per slot.
pub const BLOCK_PROCESSING_VELOCITY: u32 = 1;
/// Relay chain slot duration, in milliseconds.
pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
}
@@ -47,7 +47,7 @@ use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
use codec::{Decode, Encode, MaxEncodedLen};
use constants::{currency::*, fee::WeightToFee};
use constants::{consensus::*, currency::*, fee::WeightToFee};
use frame_support::{
construct_runtime,
dispatch::DispatchClass,
@@ -537,6 +537,12 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type XcmpMessageHandler = XcmpQueue;
type ReservedXcmpWeight = ReservedXcmpWeight;
type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases;
type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook<
Runtime,
RELAY_CHAIN_SLOT_DURATION_MILLIS,
BLOCK_PROCESSING_VELOCITY,
UNINCLUDED_SEGMENT_CAPACITY,
>;
}
impl parachain_info::Config for Runtime {}
@@ -1229,33 +1235,9 @@ impl_runtime_apis! {
}
}
struct CheckInherents;
impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
fn check_inherents(
block: &Block,
relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
) -> sp_inherents::CheckInherentsResult {
let relay_chain_slot = relay_state_proof
.read_slot()
.expect("Could not read the relay chain slot from the proof");
let inherent_data =
cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
relay_chain_slot,
sp_std::time::Duration::from_secs(6),
)
.create_inherent_data()
.expect("Could not create the timestamp inherent data");
inherent_data.check_extrinsics(block)
}
}
cumulus_pallet_parachain_system::register_validate_block! {
Runtime = Runtime,
BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
CheckInherents = CheckInherents,
}
#[cfg(feature = "state-trie-version-1")]
@@ -23,11 +23,11 @@ use asset_hub_kusama_runtime::xcm_config::{
pub use asset_hub_kusama_runtime::{
constants::fee::WeightToFee,
xcm_config::{CheckingAccount, ForeignCreatorsSovereignAccountOf, XcmConfig},
AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance,
MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, RuntimeCall,
RuntimeEvent, SessionKeys, System, TrustBackedAssetsInstance,
AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets,
ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime,
RuntimeCall, RuntimeEvent, SessionKeys, System, TrustBackedAssetsInstance,
};
use asset_test_utils::{CollatorSessionKeys, ExtBuilder, RuntimeHelper};
use asset_test_utils::{CollatorSessionKeys, ExtBuilder};
use codec::{Decode, Encode};
use cumulus_primitives_utility::ChargeWeightInFungibles;
use frame_support::{
@@ -46,6 +46,8 @@ const SOME_ASSET_ADMIN: [u8; 32] = [5u8; 32];
type AssetIdForTrustBackedAssetsConvert =
assets_common::AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation>;
type RuntimeHelper = asset_test_utils::RuntimeHelper<Runtime, AllPalletsWithoutSystem>;
fn collator_session_keys() -> CollatorSessionKeys<Runtime> {
CollatorSessionKeys::new(
AccountId::from(ALICE),
@@ -69,7 +71,7 @@ fn test_asset_xcm_trader() {
let minimum_asset_balance = 3333333_u128;
let local_asset_id = 1;
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
local_asset_id.into(),
AccountId::from(ALICE).into(),
true,
@@ -78,7 +80,7 @@ fn test_asset_xcm_trader() {
// We first mint enough asset for the account to exist for assets
assert_ok!(Assets::mint(
RuntimeHelper::<Runtime>::origin_of(AccountId::from(ALICE)),
RuntimeHelper::origin_of(AccountId::from(ALICE)),
local_asset_id.into(),
AccountId::from(ALICE).into(),
minimum_asset_balance
@@ -89,7 +91,7 @@ fn test_asset_xcm_trader() {
AssetIdForTrustBackedAssetsConvert::convert_back(&local_asset_id).unwrap();
// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));
RuntimeHelper::run_to_block(2, AccountId::from(ALICE));
// We are going to buy 4e9 weight
let bought = Weight::from_parts(4_000_000_000u64, 0);
@@ -148,7 +150,7 @@ fn test_asset_xcm_trader_with_refund() {
// We need root origin to create a sufficient asset
// We set existential deposit to be identical to the one for Balances first
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
1.into(),
AccountId::from(ALICE).into(),
true,
@@ -157,7 +159,7 @@ fn test_asset_xcm_trader_with_refund() {
// We first mint enough asset for the account to exist for assets
assert_ok!(Assets::mint(
RuntimeHelper::<Runtime>::origin_of(AccountId::from(ALICE)),
RuntimeHelper::origin_of(AccountId::from(ALICE)),
1.into(),
AccountId::from(ALICE).into(),
ExistentialDeposit::get()
@@ -167,7 +169,7 @@ fn test_asset_xcm_trader_with_refund() {
let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));
RuntimeHelper::run_to_block(2, AccountId::from(ALICE));
// We are going to buy 4e9 weight
let bought = Weight::from_parts(4_000_000_000u64, 0);
@@ -228,7 +230,7 @@ fn test_asset_xcm_trader_refund_not_possible_since_amount_less_than_ed() {
// We need root origin to create a sufficient asset
// We set existential deposit to be identical to the one for Balances first
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
1.into(),
AccountId::from(ALICE).into(),
true,
@@ -239,7 +241,7 @@ fn test_asset_xcm_trader_refund_not_possible_since_amount_less_than_ed() {
let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));
RuntimeHelper::run_to_block(2, AccountId::from(ALICE));
// We are going to buy small amount
let bought = Weight::from_parts(500_000_000u64, 0);
@@ -280,7 +282,7 @@ fn test_that_buying_ed_refund_does_not_refund() {
// We need root origin to create a sufficient asset
// We set existential deposit to be identical to the one for Balances first
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
1.into(),
AccountId::from(ALICE).into(),
true,
@@ -291,7 +293,7 @@ fn test_that_buying_ed_refund_does_not_refund() {
let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));
RuntimeHelper::run_to_block(2, AccountId::from(ALICE));
// We are gonna buy ED
let bought = Weight::from_parts(ExistentialDeposit::get().try_into().unwrap(), 0);
@@ -345,7 +347,7 @@ fn test_asset_xcm_trader_not_possible_for_non_sufficient_assets() {
// Create a non-sufficient asset with specific existential deposit
let minimum_asset_balance = 1_000_000_u128;
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
1.into(),
AccountId::from(ALICE).into(),
false,
@@ -354,7 +356,7 @@ fn test_asset_xcm_trader_not_possible_for_non_sufficient_assets() {
// We first mint enough asset for the account to exist for assets
assert_ok!(Assets::mint(
RuntimeHelper::<Runtime>::origin_of(AccountId::from(ALICE)),
RuntimeHelper::origin_of(AccountId::from(ALICE)),
1.into(),
AccountId::from(ALICE).into(),
minimum_asset_balance
@@ -364,7 +366,7 @@ fn test_asset_xcm_trader_not_possible_for_non_sufficient_assets() {
let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));
RuntimeHelper::run_to_block(2, AccountId::from(ALICE));
// We are going to buy 4e9 weight
let bought = Weight::from_parts(4_000_000_000u64, 0);
@@ -428,7 +430,7 @@ fn test_assets_balances_api_works() {
// We need root origin to create a sufficient asset
let minimum_asset_balance = 3333333_u128;
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
local_asset_id.into(),
AccountId::from(ALICE).into(),
true,
@@ -437,7 +439,7 @@ fn test_assets_balances_api_works() {
// We first mint enough asset for the account to exist for assets
assert_ok!(Assets::mint(
RuntimeHelper::<Runtime>::origin_of(AccountId::from(ALICE)),
RuntimeHelper::origin_of(AccountId::from(ALICE)),
local_asset_id.into(),
AccountId::from(ALICE).into(),
minimum_asset_balance
@@ -446,7 +448,7 @@ fn test_assets_balances_api_works() {
// create foreign asset
let foreign_asset_minimum_asset_balance = 3333333_u128;
assert_ok!(ForeignAssets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
foreign_asset_id_multilocation,
AccountId::from(SOME_ASSET_ADMIN).into(),
false,
@@ -455,7 +457,7 @@ fn test_assets_balances_api_works() {
// We first mint enough asset for the account to exist for assets
assert_ok!(ForeignAssets::mint(
RuntimeHelper::<Runtime>::origin_of(AccountId::from(SOME_ASSET_ADMIN)),
RuntimeHelper::origin_of(AccountId::from(SOME_ASSET_ADMIN)),
foreign_asset_id_multilocation,
AccountId::from(ALICE).into(),
6 * foreign_asset_minimum_asset_balance
@@ -502,6 +504,7 @@ fn test_assets_balances_api_works() {
asset_test_utils::include_teleports_for_native_asset_works!(
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
CheckingAccount,
WeightToFee,
@@ -525,6 +528,7 @@ asset_test_utils::include_teleports_for_native_asset_works!(
asset_test_utils::include_teleports_for_foreign_assets_works!(
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
CheckingAccount,
WeightToFee,
@@ -50,7 +50,7 @@ sp-weights = { git = "https://github.com/paritytech/substrate", default-features
# Polkadot
pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false, optional = true }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", default-features = false, optional = true , branch = "master" }
polkadot-core-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
@@ -62,12 +62,11 @@ xcm-executor = { git = "https://github.com/paritytech/polkadot", default-feature
# Cumulus
cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false }
cumulus-pallet-dmp-queue = { path = "../../../../pallets/dmp-queue", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] }
cumulus-pallet-session-benchmarking = { path = "../../../../pallets/session-benchmarking", default-features = false, version = "3.0.0" }
cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false }
cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false }
cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false }
cumulus-primitives-timestamp = { path = "../../../../primitives/timestamp", default-features = false }
cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false }
pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false }
parachain-info = { path = "../../../pallets/parachain-info", default-features = false }
@@ -82,7 +81,9 @@ asset-test-utils = { path = "../test-utils"}
substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
[features]
default = [ "std" ]
default = [
"std",
]
runtime-benchmarks = [
"hex-literal",
"frame-benchmarking/runtime-benchmarks",
@@ -181,7 +182,6 @@ std = [
"cumulus-pallet-xcm/std",
"cumulus-pallet-xcmp-queue/std",
"cumulus-primitives-core/std",
"cumulus-primitives-timestamp/std",
"cumulus-primitives-utility/std",
"pallet-collator-selection/std",
"parachain-info/std",
@@ -105,3 +105,15 @@ pub mod fee {
}
}
}
/// Consensus-related.
pub mod consensus {
/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included
/// into the relay chain.
pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1;
/// How many parachain blocks are processed by the relay chain per parent. Limits the
/// number of blocks authored per slot.
pub const BLOCK_PROCESSING_VELOCITY: u32 = 1;
/// Relay chain slot duration, in milliseconds.
pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
}
@@ -82,7 +82,7 @@ use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
use codec::{Decode, Encode, MaxEncodedLen};
use constants::{currency::*, fee::WeightToFee};
use constants::{consensus::*, currency::*, fee::WeightToFee};
use frame_support::{
construct_runtime,
dispatch::DispatchClass,
@@ -551,6 +551,12 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type XcmpMessageHandler = XcmpQueue;
type ReservedXcmpWeight = ReservedXcmpWeight;
type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases;
type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook<
Runtime,
RELAY_CHAIN_SLOT_DURATION_MILLIS,
BLOCK_PROCESSING_VELOCITY,
UNINCLUDED_SEGMENT_CAPACITY,
>;
}
impl parachain_info::Config for Runtime {}
@@ -1211,33 +1217,9 @@ impl_runtime_apis! {
}
}
struct CheckInherents;
impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
fn check_inherents(
block: &Block,
relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
) -> sp_inherents::CheckInherentsResult {
let relay_chain_slot = relay_state_proof
.read_slot()
.expect("Could not read the relay chain slot from the proof");
let inherent_data =
cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
relay_chain_slot,
sp_std::time::Duration::from_secs(6),
)
.create_inherent_data()
.expect("Could not create the timestamp inherent data");
inherent_data.check_extrinsics(block)
}
}
cumulus_pallet_parachain_system::register_validate_block! {
Runtime = Runtime,
BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
CheckInherents = CheckInherents,
}
#[cfg(test)]
@@ -22,11 +22,12 @@ use asset_hub_polkadot_runtime::xcm_config::{
ForeignCreatorsSovereignAccountOf, TrustBackedAssetsPalletLocation, XcmConfig,
};
pub use asset_hub_polkadot_runtime::{
constants::fee::WeightToFee, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets,
ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime,
RuntimeCall, RuntimeEvent, SessionKeys, System, TrustBackedAssetsInstance,
constants::fee::WeightToFee, AllPalletsWithoutSystem, AssetDeposit, Assets, Balances,
ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase,
MetadataDepositPerByte, ParachainSystem, Runtime, RuntimeCall, RuntimeEvent, SessionKeys,
System, TrustBackedAssetsInstance,
};
use asset_test_utils::{CollatorSessionKeys, ExtBuilder, RuntimeHelper};
use asset_test_utils::{CollatorSessionKeys, ExtBuilder};
use codec::{Decode, Encode};
use cumulus_primitives_utility::ChargeWeightInFungibles;
use frame_support::{
@@ -47,6 +48,8 @@ const SOME_ASSET_ADMIN: [u8; 32] = [5u8; 32];
type AssetIdForTrustBackedAssetsConvert =
assets_common::AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation>;
type RuntimeHelper = asset_test_utils::RuntimeHelper<Runtime, AllPalletsWithoutSystem>;
fn collator_session_keys() -> CollatorSessionKeys<Runtime> {
CollatorSessionKeys::new(
AccountId::from(ALICE),
@@ -70,7 +73,7 @@ fn test_asset_xcm_trader() {
let minimum_asset_balance = 333333333_u128;
let local_asset_id = 1;
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
local_asset_id.into(),
AccountId::from(ALICE).into(),
true,
@@ -79,7 +82,7 @@ fn test_asset_xcm_trader() {
// We first mint enough asset for the account to exist for assets
assert_ok!(Assets::mint(
RuntimeHelper::<Runtime>::origin_of(AccountId::from(ALICE)),
RuntimeHelper::origin_of(AccountId::from(ALICE)),
local_asset_id.into(),
AccountId::from(ALICE).into(),
minimum_asset_balance
@@ -90,7 +93,7 @@ fn test_asset_xcm_trader() {
AssetIdForTrustBackedAssetsConvert::convert_back(&local_asset_id).unwrap();
// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));
RuntimeHelper::run_to_block(2, AccountId::from(ALICE));
// We are going to buy 400e9 weight
// Because of the ED being higher in kusama's asset hub
@@ -152,7 +155,7 @@ fn test_asset_xcm_trader_with_refund() {
// We need root origin to create a sufficient asset
// We set existential deposit to be identical to the one for Balances first
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
1.into(),
AccountId::from(ALICE).into(),
true,
@@ -161,7 +164,7 @@ fn test_asset_xcm_trader_with_refund() {
// We first mint enough asset for the account to exist for assets
assert_ok!(Assets::mint(
RuntimeHelper::<Runtime>::origin_of(AccountId::from(ALICE)),
RuntimeHelper::origin_of(AccountId::from(ALICE)),
1.into(),
AccountId::from(ALICE).into(),
ExistentialDeposit::get()
@@ -171,7 +174,7 @@ fn test_asset_xcm_trader_with_refund() {
let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));
RuntimeHelper::run_to_block(2, AccountId::from(ALICE));
// We are going to buy 400e9 weight
// Because of the ED being higher in kusama's asset hub
@@ -235,7 +238,7 @@ fn test_asset_xcm_trader_refund_not_possible_since_amount_less_than_ed() {
// We need root origin to create a sufficient asset
// We set existential deposit to be identical to the one for Balances first
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
1.into(),
AccountId::from(ALICE).into(),
true,
@@ -246,7 +249,7 @@ fn test_asset_xcm_trader_refund_not_possible_since_amount_less_than_ed() {
let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));
RuntimeHelper::run_to_block(2, AccountId::from(ALICE));
// We are going to buy 50e9 weight
// Because of the ED being higher in kusama's asset hub
@@ -290,7 +293,7 @@ fn test_that_buying_ed_refund_does_not_refund() {
// We need root origin to create a sufficient asset
// We set existential deposit to be identical to the one for Balances first
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
1.into(),
AccountId::from(ALICE).into(),
true,
@@ -301,7 +304,7 @@ fn test_that_buying_ed_refund_does_not_refund() {
let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));
RuntimeHelper::run_to_block(2, AccountId::from(ALICE));
// We are gonna buy ED
let bought = Weight::from_parts(ExistentialDeposit::get().try_into().unwrap(), 0);
@@ -355,7 +358,7 @@ fn test_asset_xcm_trader_not_possible_for_non_sufficient_assets() {
// Create a non-sufficient asset
let minimum_asset_balance = 1_000_000_u128;
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
1.into(),
AccountId::from(ALICE).into(),
false,
@@ -364,7 +367,7 @@ fn test_asset_xcm_trader_not_possible_for_non_sufficient_assets() {
// We first mint enough asset for the account to exist for assets
assert_ok!(Assets::mint(
RuntimeHelper::<Runtime>::origin_of(AccountId::from(ALICE)),
RuntimeHelper::origin_of(AccountId::from(ALICE)),
1.into(),
AccountId::from(ALICE).into(),
minimum_asset_balance
@@ -374,7 +377,7 @@ fn test_asset_xcm_trader_not_possible_for_non_sufficient_assets() {
let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));
RuntimeHelper::run_to_block(2, AccountId::from(ALICE));
// We are going to buy 400e9 weight
// Because of the ED being higher in kusama's asset hub
@@ -441,7 +444,7 @@ fn test_assets_balances_api_works() {
// We need root origin to create a sufficient asset
let minimum_asset_balance = 3333333_u128;
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
local_asset_id.into(),
AccountId::from(ALICE).into(),
true,
@@ -450,7 +453,7 @@ fn test_assets_balances_api_works() {
// We first mint enough asset for the account to exist for assets
assert_ok!(Assets::mint(
RuntimeHelper::<Runtime>::origin_of(AccountId::from(ALICE)),
RuntimeHelper::origin_of(AccountId::from(ALICE)),
local_asset_id.into(),
AccountId::from(ALICE).into(),
minimum_asset_balance
@@ -459,7 +462,7 @@ fn test_assets_balances_api_works() {
// create foreign asset
let foreign_asset_minimum_asset_balance = 3333333_u128;
assert_ok!(ForeignAssets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
foreign_asset_id_multilocation,
AccountId::from(SOME_ASSET_ADMIN).into(),
false,
@@ -468,7 +471,7 @@ fn test_assets_balances_api_works() {
// We first mint enough asset for the account to exist for assets
assert_ok!(ForeignAssets::mint(
RuntimeHelper::<Runtime>::origin_of(AccountId::from(SOME_ASSET_ADMIN)),
RuntimeHelper::origin_of(AccountId::from(SOME_ASSET_ADMIN)),
foreign_asset_id_multilocation,
AccountId::from(ALICE).into(),
6 * foreign_asset_minimum_asset_balance
@@ -515,6 +518,7 @@ fn test_assets_balances_api_works() {
asset_test_utils::include_teleports_for_native_asset_works!(
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
CheckingAccount,
WeightToFee,
@@ -538,6 +542,7 @@ asset_test_utils::include_teleports_for_native_asset_works!(
asset_test_utils::include_teleports_for_foreign_assets_works!(
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
CheckingAccount,
WeightToFee,
@@ -53,7 +53,7 @@ primitive-types = { version = "0.12.1", default-features = false, features = ["c
# Polkadot
pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false, optional = true }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", default-features = false, optional = true , branch = "master" }
polkadot-core-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
@@ -65,12 +65,11 @@ xcm-executor = { git = "https://github.com/paritytech/polkadot", default-feature
# Cumulus
cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false }
cumulus-pallet-dmp-queue = { path = "../../../../pallets/dmp-queue", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] }
cumulus-pallet-session-benchmarking = {path = "../../../../pallets/session-benchmarking", default-features = false, version = "3.0.0"}
cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false }
cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false }
cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false }
cumulus-primitives-timestamp = { path = "../../../../primitives/timestamp", default-features = false }
cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false }
pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false }
parachain-info = { path = "../../../pallets/parachain-info", default-features = false }
@@ -85,7 +84,9 @@ asset-test-utils = { path = "../test-utils"}
substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
[features]
default = [ "std" ]
default = [
"std",
]
runtime-benchmarks = [
"hex-literal",
"frame-benchmarking/runtime-benchmarks",
@@ -190,7 +191,6 @@ std = [
"cumulus-pallet-xcm/std",
"cumulus-pallet-xcmp-queue/std",
"cumulus-primitives-core/std",
"cumulus-primitives-timestamp/std",
"cumulus-primitives-utility/std",
"pallet-collator-selection/std",
"parachain-info/std",
@@ -107,3 +107,15 @@ pub mod fee {
}
}
}
/// Consensus-related.
pub mod consensus {
/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included
/// into the relay chain.
pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1;
/// How many parachain blocks are processed by the relay chain per parent. Limits the
/// number of blocks authored per slot.
pub const BLOCK_PROCESSING_VELOCITY: u32 = 1;
/// Relay chain slot duration, in milliseconds.
pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
}
@@ -36,7 +36,7 @@ use assets_common::{
AssetIdForTrustBackedAssetsConvert,
};
use codec::{Decode, Encode, MaxEncodedLen};
use constants::{currency::*, fee::WeightToFee};
use constants::{consensus::*, currency::*, fee::WeightToFee};
use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases;
use frame_support::{
construct_runtime,
@@ -590,6 +590,12 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type XcmpMessageHandler = XcmpQueue;
type ReservedXcmpWeight = ReservedXcmpWeight;
type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases;
type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook<
Runtime,
RELAY_CHAIN_SLOT_DURATION_MILLIS,
BLOCK_PROCESSING_VELOCITY,
UNINCLUDED_SEGMENT_CAPACITY,
>;
}
impl parachain_info::Config for Runtime {}
@@ -1345,33 +1351,9 @@ impl_runtime_apis! {
}
}
struct CheckInherents;
impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
fn check_inherents(
block: &Block,
relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
) -> sp_inherents::CheckInherentsResult {
let relay_chain_slot = relay_state_proof
.read_slot()
.expect("Could not read the relay chain slot from the proof");
let inherent_data =
cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
relay_chain_slot,
sp_std::time::Duration::from_secs(6),
)
.create_inherent_data()
.expect("Could not create the timestamp inherent data");
inherent_data.check_extrinsics(block)
}
}
cumulus_pallet_parachain_system::register_validate_block! {
Runtime = Runtime,
BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
CheckInherents = CheckInherents,
}
pub mod migrations {
@@ -20,18 +20,19 @@
pub use asset_hub_westend_runtime::{
constants::fee::WeightToFee,
xcm_config::{CheckingAccount, TrustBackedAssetsPalletLocation, XcmConfig},
AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance,
ParachainSystem, Runtime, SessionKeys, System, TrustBackedAssetsInstance,
AllowMultiAssetPools, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets,
ForeignAssetsInstance, ParachainSystem, Runtime, SessionKeys, System,
TrustBackedAssetsInstance,
};
use asset_hub_westend_runtime::{
xcm_config::{
AssetFeeAsExistentialDepositMultiplierFeeCharger, ForeignCreatorsSovereignAccountOf,
WestendLocation,
},
AllowMultiAssetPools, LiquidityWithdrawalFee, MetadataDepositBase, MetadataDepositPerByte,
AllPalletsWithoutSystem, LiquidityWithdrawalFee, MetadataDepositBase, MetadataDepositPerByte,
RuntimeCall, RuntimeEvent,
};
use asset_test_utils::{CollatorSessionKeys, ExtBuilder, RuntimeHelper, XcmReceivedFrom};
use asset_test_utils::{CollatorSessionKeys, ExtBuilder, XcmReceivedFrom};
use codec::{Decode, DecodeLimit, Encode};
use cumulus_primitives_utility::ChargeWeightInFungibles;
use frame_support::{
@@ -57,6 +58,8 @@ const SOME_ASSET_ADMIN: [u8; 32] = [5u8; 32];
type AssetIdForTrustBackedAssetsConvert =
assets_common::AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation>;
type RuntimeHelper = asset_test_utils::RuntimeHelper<Runtime, AllPalletsWithoutSystem>;
fn collator_session_keys() -> CollatorSessionKeys<Runtime> {
CollatorSessionKeys::new(
AccountId::from(ALICE),
@@ -80,7 +83,7 @@ fn test_asset_xcm_trader() {
let minimum_asset_balance = 3333333_u128;
let local_asset_id = 1;
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
local_asset_id.into(),
AccountId::from(ALICE).into(),
true,
@@ -89,7 +92,7 @@ fn test_asset_xcm_trader() {
// We first mint enough asset for the account to exist for assets
assert_ok!(Assets::mint(
RuntimeHelper::<Runtime>::origin_of(AccountId::from(ALICE)),
RuntimeHelper::origin_of(AccountId::from(ALICE)),
local_asset_id.into(),
AccountId::from(ALICE).into(),
minimum_asset_balance
@@ -100,7 +103,7 @@ fn test_asset_xcm_trader() {
AssetIdForTrustBackedAssetsConvert::convert_back(&local_asset_id).unwrap();
// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));
RuntimeHelper::run_to_block(2, AccountId::from(ALICE));
// We are going to buy 4e9 weight
let bought = Weight::from_parts(4_000_000_000u64, 0);
@@ -159,7 +162,7 @@ fn test_asset_xcm_trader_with_refund() {
// We need root origin to create a sufficient asset
// We set existential deposit to be identical to the one for Balances first
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
1.into(),
AccountId::from(ALICE).into(),
true,
@@ -168,7 +171,7 @@ fn test_asset_xcm_trader_with_refund() {
// We first mint enough asset for the account to exist for assets
assert_ok!(Assets::mint(
RuntimeHelper::<Runtime>::origin_of(AccountId::from(ALICE)),
RuntimeHelper::origin_of(AccountId::from(ALICE)),
1.into(),
AccountId::from(ALICE).into(),
ExistentialDeposit::get()
@@ -178,7 +181,7 @@ fn test_asset_xcm_trader_with_refund() {
let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));
RuntimeHelper::run_to_block(2, AccountId::from(ALICE));
// We are going to buy 4e9 weight
let bought = Weight::from_parts(4_000_000_000u64, 0);
@@ -238,7 +241,7 @@ fn test_asset_xcm_trader_refund_not_possible_since_amount_less_than_ed() {
// We need root origin to create a sufficient asset
// We set existential deposit to be identical to the one for Balances first
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
1.into(),
AccountId::from(ALICE).into(),
true,
@@ -249,7 +252,7 @@ fn test_asset_xcm_trader_refund_not_possible_since_amount_less_than_ed() {
let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));
RuntimeHelper::run_to_block(2, AccountId::from(ALICE));
// We are going to buy 5e9 weight
let bought = Weight::from_parts(500_000_000u64, 0);
@@ -290,7 +293,7 @@ fn test_that_buying_ed_refund_does_not_refund() {
// We need root origin to create a sufficient asset
// We set existential deposit to be identical to the one for Balances first
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
1.into(),
AccountId::from(ALICE).into(),
true,
@@ -301,7 +304,7 @@ fn test_that_buying_ed_refund_does_not_refund() {
let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));
RuntimeHelper::run_to_block(2, AccountId::from(ALICE));
let bought = Weight::from_parts(500_000_000u64, 0);
@@ -354,7 +357,7 @@ fn test_asset_xcm_trader_not_possible_for_non_sufficient_assets() {
// Create a non-sufficient asset with specific existential deposit
let minimum_asset_balance = 1_000_000_u128;
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
1.into(),
AccountId::from(ALICE).into(),
false,
@@ -363,7 +366,7 @@ fn test_asset_xcm_trader_not_possible_for_non_sufficient_assets() {
// We first mint enough asset for the account to exist for assets
assert_ok!(Assets::mint(
RuntimeHelper::<Runtime>::origin_of(AccountId::from(ALICE)),
RuntimeHelper::origin_of(AccountId::from(ALICE)),
1.into(),
AccountId::from(ALICE).into(),
minimum_asset_balance
@@ -373,7 +376,7 @@ fn test_asset_xcm_trader_not_possible_for_non_sufficient_assets() {
let ctx = XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
// Set Alice as block author, who will receive fees
RuntimeHelper::<Runtime>::run_to_block(2, Some(AccountId::from(ALICE)));
RuntimeHelper::run_to_block(2, AccountId::from(ALICE));
// We are going to buy 4e9 weight
let bought = Weight::from_parts(4_000_000_000u64, 0);
@@ -437,7 +440,7 @@ fn test_assets_balances_api_works() {
// We need root origin to create a sufficient asset
let minimum_asset_balance = 3333333_u128;
assert_ok!(Assets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
local_asset_id.into(),
AccountId::from(ALICE).into(),
true,
@@ -446,7 +449,7 @@ fn test_assets_balances_api_works() {
// We first mint enough asset for the account to exist for assets
assert_ok!(Assets::mint(
RuntimeHelper::<Runtime>::origin_of(AccountId::from(ALICE)),
RuntimeHelper::origin_of(AccountId::from(ALICE)),
local_asset_id.into(),
AccountId::from(ALICE).into(),
minimum_asset_balance
@@ -455,7 +458,7 @@ fn test_assets_balances_api_works() {
// create foreign asset
let foreign_asset_minimum_asset_balance = 3333333_u128;
assert_ok!(ForeignAssets::force_create(
RuntimeHelper::<Runtime>::root_origin(),
RuntimeHelper::root_origin(),
foreign_asset_id_multilocation,
AccountId::from(SOME_ASSET_ADMIN).into(),
false,
@@ -464,7 +467,7 @@ fn test_assets_balances_api_works() {
// We first mint enough asset for the account to exist for assets
assert_ok!(ForeignAssets::mint(
RuntimeHelper::<Runtime>::origin_of(AccountId::from(SOME_ASSET_ADMIN)),
RuntimeHelper::origin_of(AccountId::from(SOME_ASSET_ADMIN)),
foreign_asset_id_multilocation,
AccountId::from(ALICE).into(),
6 * foreign_asset_minimum_asset_balance
@@ -511,6 +514,7 @@ fn test_assets_balances_api_works() {
asset_test_utils::include_teleports_for_native_asset_works!(
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
CheckingAccount,
WeightToFee,
@@ -534,6 +538,7 @@ asset_test_utils::include_teleports_for_native_asset_works!(
asset_test_utils::include_teleports_for_foreign_assets_works!(
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
CheckingAccount,
WeightToFee,
@@ -658,7 +663,7 @@ fn plain_receive_teleported_asset_works() {
.map(xcm::v3::Xcm::<RuntimeCall>::try_from).expect("failed").expect("failed");
let outcome =
XcmExecutor::<XcmConfig>::execute_xcm(Parent, maybe_msg, message_id, RuntimeHelper::<Runtime>::xcm_max_weight(XcmReceivedFrom::Parent));
XcmExecutor::<XcmConfig>::execute_xcm(Parent, maybe_msg, message_id, RuntimeHelper::xcm_max_weight(XcmReceivedFrom::Parent));
assert_eq!(outcome.ensure_complete(), Ok(()));
})
}
@@ -21,7 +21,7 @@ sp-std = { git = "https://github.com/paritytech/substrate", default-features = f
sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
# Cumulus
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] }
cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false }
cumulus-pallet-dmp-queue = { path = "../../../../pallets/dmp-queue", default-features = false }
pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false }
@@ -18,13 +18,14 @@
use codec::Encode;
use frame_support::{
assert_noop, assert_ok,
traits::{fungibles::InspectEnumerable, Get, OriginTrait},
traits::{fungibles::InspectEnumerable, Get, OnFinalize, OnInitialize, OriginTrait},
weights::Weight,
};
use parachains_common::Balance;
use frame_system::pallet_prelude::BlockNumberFor;
use parachains_common::{AccountId, Balance};
use parachains_runtimes_test_utils::{
assert_metadata, assert_total, AccountIdOf, BalanceOf, CollatorSessionKeys, ExtBuilder,
RuntimeHelper, ValidatorIdOf, XcmReceivedFrom,
ValidatorIdOf, XcmReceivedFrom,
};
use sp_runtime::{
traits::{MaybeEquivalence, StaticLookup, Zero},
@@ -33,6 +34,9 @@ use sp_runtime::{
use xcm::latest::prelude::*;
use xcm_executor::{traits::ConvertLocation, XcmExecutor};
type RuntimeHelper<Runtime, AllPalletsWithoutSystem = ()> =
parachains_runtimes_test_utils::RuntimeHelper<Runtime, AllPalletsWithoutSystem>;
// Re-export test_case from `parachains-runtimes-test-utils`
pub use parachains_runtimes_test_utils::test_cases::change_storage_constant_by_governance_works;
@@ -40,6 +44,7 @@ pub use parachains_runtimes_test_utils::test_cases::change_storage_constant_by_g
/// and can teleport it back and to the other parachains
pub fn teleports_for_native_asset_works<
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
CheckingAccount,
WeightToFee,
@@ -62,6 +67,8 @@ pub fn teleports_for_native_asset_works<
+ pallet_collator_selection::Config
+ cumulus_pallet_parachain_system::Config
+ cumulus_pallet_xcmp_queue::Config,
AllPalletsWithoutSystem:
OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
AccountIdOf<Runtime>: Into<[u8; 32]>,
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
BalanceOf<Runtime>: From<Balance> + Into<u128>,
@@ -84,6 +91,13 @@ pub fn teleports_for_native_asset_works<
.with_para_id(runtime_para_id.into())
.build()
.execute_with(|| {
let mut alice = [0u8; 32];
alice[0] = 1;
let included_head = RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::run_to_block(
2,
AccountId::from(alice),
);
// check Balances before
assert_eq!(<pallet_balances::Pallet<Runtime>>::free_balance(&target_account), 0.into());
assert_eq!(
@@ -166,6 +180,8 @@ pub fn teleports_for_native_asset_works<
dest_beneficiary,
(native_asset_id, native_asset_to_teleport_away.into()),
None,
included_head.clone(),
&alice,
));
// check balances
assert_eq!(
@@ -211,6 +227,8 @@ pub fn teleports_for_native_asset_works<
dest_beneficiary,
(native_asset_id, native_asset_to_teleport_away.into()),
Some((runtime_para_id, other_para_id)),
included_head,
&alice,
));
// check balances
@@ -240,6 +258,7 @@ pub fn teleports_for_native_asset_works<
macro_rules! include_teleports_for_native_asset_works(
(
$runtime:path,
$all_pallets_without_system:path,
$xcm_config:path,
$checking_account:path,
$weight_to_fee:path,
@@ -257,6 +276,7 @@ macro_rules! include_teleports_for_native_asset_works(
$crate::test_cases::teleports_for_native_asset_works::<
$runtime,
$all_pallets_without_system,
$xcm_config,
$checking_account,
$weight_to_fee,
@@ -277,6 +297,7 @@ macro_rules! include_teleports_for_native_asset_works(
/// chain
pub fn teleports_for_foreign_assets_works<
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
CheckingAccount,
WeightToFee,
@@ -302,6 +323,8 @@ pub fn teleports_for_foreign_assets_works<
+ cumulus_pallet_parachain_system::Config
+ cumulus_pallet_xcmp_queue::Config
+ pallet_assets::Config<ForeignAssetsPalletInstance>,
AllPalletsWithoutSystem:
OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
AccountIdOf<Runtime>: Into<[u8; 32]>,
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
BalanceOf<Runtime>: From<Balance>,
@@ -363,6 +386,13 @@ pub fn teleports_for_foreign_assets_works<
.with_tracing()
.build()
.execute_with(|| {
let mut alice = [0u8; 32];
alice[0] = 1;
let included_head = RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::run_to_block(
2,
AccountId::from(alice),
);
// checks target_account before
assert_eq!(
<pallet_balances::Pallet<Runtime>>::free_balance(&target_account),
@@ -514,6 +544,8 @@ pub fn teleports_for_foreign_assets_works<
dest_beneficiary,
(foreign_asset_id_multilocation, asset_to_teleport_away),
Some((runtime_para_id, foreign_para_id)),
included_head,
&alice,
));
// check balances
@@ -558,6 +590,7 @@ pub fn teleports_for_foreign_assets_works<
macro_rules! include_teleports_for_foreign_assets_works(
(
$runtime:path,
$all_pallets_without_system:path,
$xcm_config:path,
$checking_account:path,
$weight_to_fee:path,
@@ -578,6 +611,7 @@ macro_rules! include_teleports_for_foreign_assets_works(
$crate::test_cases::teleports_for_foreign_assets_works::<
$runtime,
$all_pallets_without_system,
$xcm_config,
$checking_account,
$weight_to_fee,
@@ -49,7 +49,7 @@ sp-version = { git = "https://github.com/paritytech/substrate", default-features
# Polkadot
kusama-runtime-constants = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false, optional = true }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", default-features = false, optional = true , branch = "master" }
polkadot-core-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
@@ -60,12 +60,11 @@ xcm-executor = { git = "https://github.com/paritytech/polkadot", default-feature
# Cumulus
cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false }
cumulus-pallet-dmp-queue = { path = "../../../../pallets/dmp-queue", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] }
cumulus-pallet-session-benchmarking = {path = "../../../../pallets/session-benchmarking", default-features = false, version = "3.0.0"}
cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false }
cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false }
cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false }
cumulus-primitives-timestamp = { path = "../../../../primitives/timestamp", default-features = false }
cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false }
pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false }
parachain-info = { path = "../../../../parachains/pallets/parachain-info", default-features = false }
@@ -89,7 +88,6 @@ std = [
"cumulus-pallet-xcm/std",
"cumulus-pallet-xcmp-queue/std",
"cumulus-primitives-core/std",
"cumulus-primitives-timestamp/std",
"cumulus-primitives-utility/std",
"frame-executive/std",
"frame-support/std",
@@ -103,3 +103,15 @@ pub mod fee {
}
}
}
/// Consensus-related.
pub mod consensus {
/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included
/// into the relay chain.
pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1;
/// How many parachain blocks are processed by the relay chain per parent. Limits the
/// number of blocks authored per slot.
pub const BLOCK_PROCESSING_VELOCITY: u32 = 1;
/// Relay chain slot duration, in milliseconds.
pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
}
@@ -41,7 +41,7 @@ use sp_std::prelude::*;
use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
use constants::{currency::*, fee::WeightToFee};
use constants::{consensus::*, currency::*, fee::WeightToFee};
use frame_support::{
construct_runtime,
dispatch::DispatchClass,
@@ -281,6 +281,12 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type XcmpMessageHandler = XcmpQueue;
type ReservedXcmpWeight = ReservedXcmpWeight;
type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases;
type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook<
Runtime,
RELAY_CHAIN_SLOT_DURATION_MILLIS,
BLOCK_PROCESSING_VELOCITY,
UNINCLUDED_SEGMENT_CAPACITY,
>;
}
impl parachain_info::Config for Runtime {}
@@ -772,31 +778,7 @@ impl_runtime_apis! {
}
}
struct CheckInherents;
impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
fn check_inherents(
block: &Block,
relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
) -> sp_inherents::CheckInherentsResult {
let relay_chain_slot = relay_state_proof
.read_slot()
.expect("Could not read the relay chain slot from the proof");
let inherent_data =
cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
relay_chain_slot,
sp_std::time::Duration::from_secs(6),
)
.create_inherent_data()
.expect("Could not create the timestamp inherent data");
inherent_data.check_extrinsics(block)
}
}
cumulus_pallet_parachain_system::register_validate_block! {
Runtime = Runtime,
BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
CheckInherents = CheckInherents,
}
@@ -15,8 +15,8 @@
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
pub use bridge_hub_kusama_runtime::{
constants::fee::WeightToFee, xcm_config::XcmConfig, Balances, ExistentialDeposit,
ParachainSystem, PolkadotXcm, Runtime, RuntimeEvent, SessionKeys,
constants::fee::WeightToFee, xcm_config::XcmConfig, AllPalletsWithoutSystem, Balances,
ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeEvent, SessionKeys,
};
use codec::Decode;
use frame_support::parameter_types;
@@ -30,6 +30,7 @@ parameter_types! {
bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!(
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
CheckingAccount,
WeightToFee,
@@ -49,7 +49,7 @@ sp-version = { git = "https://github.com/paritytech/substrate", default-features
# Polkadot
polkadot-runtime-constants = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false, optional = true }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", default-features = false, optional = true , branch = "master" }
polkadot-core-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
@@ -60,12 +60,11 @@ xcm-executor = { git = "https://github.com/paritytech/polkadot", default-feature
# Cumulus
cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false }
cumulus-pallet-dmp-queue = { path = "../../../../pallets/dmp-queue", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] }
cumulus-pallet-session-benchmarking = {path = "../../../../pallets/session-benchmarking", default-features = false, version = "3.0.0"}
cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false }
cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false }
cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false }
cumulus-primitives-timestamp = { path = "../../../../primitives/timestamp", default-features = false }
cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false }
pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false }
parachain-info = { path = "../../../../parachains/pallets/parachain-info", default-features = false }
@@ -89,7 +88,6 @@ std = [
"cumulus-pallet-xcm/std",
"cumulus-pallet-xcmp-queue/std",
"cumulus-primitives-core/std",
"cumulus-primitives-timestamp/std",
"cumulus-primitives-utility/std",
"frame-executive/std",
"frame-support/std",
@@ -103,3 +103,15 @@ pub mod fee {
}
}
}
/// Consensus-related.
pub mod consensus {
/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included
/// into the relay chain.
pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1;
/// How many parachain blocks are processed by the relay chain per parent. Limits the
/// number of blocks authored per slot.
pub const BLOCK_PROCESSING_VELOCITY: u32 = 1;
/// Relay chain slot duration, in milliseconds.
pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
}
@@ -41,7 +41,7 @@ use sp_std::prelude::*;
use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
use constants::{currency::*, fee::WeightToFee};
use constants::{consensus::*, currency::*, fee::WeightToFee};
use frame_support::{
construct_runtime,
dispatch::DispatchClass,
@@ -281,6 +281,12 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type XcmpMessageHandler = XcmpQueue;
type ReservedXcmpWeight = ReservedXcmpWeight;
type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases;
type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook<
Runtime,
RELAY_CHAIN_SLOT_DURATION_MILLIS,
BLOCK_PROCESSING_VELOCITY,
UNINCLUDED_SEGMENT_CAPACITY,
>;
}
impl parachain_info::Config for Runtime {}
@@ -772,31 +778,7 @@ impl_runtime_apis! {
}
}
struct CheckInherents;
impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
fn check_inherents(
block: &Block,
relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
) -> sp_inherents::CheckInherentsResult {
let relay_chain_slot = relay_state_proof
.read_slot()
.expect("Could not read the relay chain slot from the proof");
let inherent_data =
cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
relay_chain_slot,
sp_std::time::Duration::from_secs(6),
)
.create_inherent_data()
.expect("Could not create the timestamp inherent data");
inherent_data.check_extrinsics(block)
}
}
cumulus_pallet_parachain_system::register_validate_block! {
Runtime = Runtime,
BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
CheckInherents = CheckInherents,
}
@@ -15,8 +15,8 @@
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
pub use bridge_hub_polkadot_runtime::{
constants::fee::WeightToFee, xcm_config::XcmConfig, Balances, ExistentialDeposit,
ParachainSystem, PolkadotXcm, Runtime, RuntimeEvent, SessionKeys,
constants::fee::WeightToFee, xcm_config::XcmConfig, AllPalletsWithoutSystem, Balances,
ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeEvent, SessionKeys,
};
use codec::Decode;
use frame_support::parameter_types;
@@ -30,6 +30,7 @@ parameter_types! {
bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!(
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
CheckingAccount,
WeightToFee,
@@ -49,7 +49,7 @@ sp-version = { git = "https://github.com/paritytech/substrate", default-features
# Polkadot
rococo-runtime-constants = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false, optional = true }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", default-features = false, optional = true , branch = "master" }
polkadot-core-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
@@ -60,12 +60,11 @@ xcm-executor = { git = "https://github.com/paritytech/polkadot", default-feature
# Cumulus
cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false }
cumulus-pallet-dmp-queue = { path = "../../../../pallets/dmp-queue", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] }
cumulus-pallet-session-benchmarking = {path = "../../../../pallets/session-benchmarking", default-features = false, version = "3.0.0"}
cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false }
cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false }
cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false }
cumulus-primitives-timestamp = { path = "../../../../primitives/timestamp", default-features = false }
cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false }
pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false }
parachain-info = { path = "../../../../parachains/pallets/parachain-info", default-features = false }
@@ -120,7 +119,6 @@ std = [
"cumulus-pallet-xcm/std",
"cumulus-pallet-xcmp-queue/std",
"cumulus-primitives-core/std",
"cumulus-primitives-timestamp/std",
"cumulus-primitives-utility/std",
"frame-benchmarking/std",
"frame-executive/std",
@@ -105,3 +105,15 @@ pub mod fee {
}
}
}
/// Consensus-related.
pub mod consensus {
/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included
/// into the relay chain.
pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1;
/// How many parachain blocks are processed by the relay chain per parent. Limits the
/// number of blocks authored per slot.
pub const BLOCK_PROCESSING_VELOCITY: u32 = 1;
/// Relay chain slot duration, in milliseconds.
pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
}
@@ -28,7 +28,7 @@ pub mod constants;
mod weights;
pub mod xcm_config;
use constants::currency::*;
use constants::{consensus::*, currency::*};
use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases;
use sp_api::impl_runtime_apis;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
@@ -299,6 +299,12 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type XcmpMessageHandler = XcmpQueue;
type ReservedXcmpWeight = ReservedXcmpWeight;
type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases;
type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook<
Runtime,
RELAY_CHAIN_SLOT_DURATION_MILLIS,
BLOCK_PROCESSING_VELOCITY,
UNINCLUDED_SEGMENT_CAPACITY,
>;
}
impl parachain_info::Config for Runtime {}
@@ -1223,33 +1229,9 @@ impl_runtime_apis! {
}
}
struct CheckInherents;
impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
fn check_inherents(
block: &Block,
relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
) -> sp_inherents::CheckInherentsResult {
let relay_chain_slot = relay_state_proof
.read_slot()
.expect("Could not read the relay chain slot from the proof");
let inherent_data =
cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
relay_chain_slot,
sp_std::time::Duration::from_secs(6),
)
.create_inherent_data()
.expect("Could not create the timestamp inherent data");
inherent_data.check_extrinsics(block)
}
}
cumulus_pallet_parachain_system::register_validate_block! {
Runtime = Runtime,
BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
CheckInherents = CheckInherents,
}
#[cfg(test)]
@@ -21,9 +21,9 @@ use bridge_hub_rococo_runtime::{
bridge_hub_rococo_config, bridge_hub_wococo_config,
constants::fee::WeightToFee,
xcm_config::{RelayNetwork, XcmConfig},
BridgeRejectObsoleteHeadersAndMessages, DeliveryRewardInBalance, Executive, ExistentialDeposit,
ParachainSystem, PolkadotXcm, RequiredStakeForStakeAndSlash, Runtime, RuntimeCall,
RuntimeEvent, SessionKeys, SignedExtra, UncheckedExtrinsic,
AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, DeliveryRewardInBalance,
Executive, ExistentialDeposit, ParachainSystem, PolkadotXcm, RequiredStakeForStakeAndSlash,
Runtime, RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra, UncheckedExtrinsic,
};
use codec::{Decode, Encode};
use frame_support::parameter_types;
@@ -106,6 +106,7 @@ mod bridge_hub_rococo_tests {
bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!(
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
CheckingAccount,
WeightToFee,
@@ -199,6 +200,7 @@ mod bridge_hub_rococo_tests {
fn message_dispatch_routing_works() {
bridge_hub_test_utils::test_cases::message_dispatch_routing_works::<
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
ParachainSystem,
WithBridgeHubWococoMessagesInstance,
@@ -228,6 +230,7 @@ mod bridge_hub_rococo_tests {
fn relayed_incoming_message_works() {
bridge_hub_test_utils::test_cases::relayed_incoming_message_works::<
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
ParachainSystem,
BridgeGrandpaWococoInstance,
@@ -248,6 +251,7 @@ mod bridge_hub_rococo_tests {
pub fn complex_relay_extrinsic_works() {
bridge_hub_test_utils::test_cases::complex_relay_extrinsic_works::<
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
ParachainSystem,
BridgeGrandpaWococoInstance,
@@ -281,6 +285,7 @@ mod bridge_hub_wococo_tests {
bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!(
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
CheckingAccount,
WeightToFee,
@@ -374,6 +379,7 @@ mod bridge_hub_wococo_tests {
fn message_dispatch_routing_works() {
bridge_hub_test_utils::test_cases::message_dispatch_routing_works::<
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
ParachainSystem,
WithBridgeHubRococoMessagesInstance,
@@ -403,6 +409,7 @@ mod bridge_hub_wococo_tests {
fn relayed_incoming_message_works() {
bridge_hub_test_utils::test_cases::relayed_incoming_message_works::<
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
ParachainSystem,
BridgeGrandpaRococoInstance,
@@ -423,6 +430,7 @@ mod bridge_hub_wococo_tests {
pub fn complex_relay_extrinsic_works() {
bridge_hub_test_utils::test_cases::complex_relay_extrinsic_works::<
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
ParachainSystem,
BridgeGrandpaRococoInstance,
@@ -26,15 +26,16 @@ pallet-session = { git = "https://github.com/paritytech/substrate", default-feat
# Cumulus
asset-test-utils = { path = "../../assets/test-utils"}
cumulus-pallet-dmp-queue = { path = "../../../../pallets/dmp-queue", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] }
cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false }
pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false }
parachain-info = { path = "../../../../parachains/pallets/parachain-info", default-features = false }
parachains-common = { path = "../../../../parachains/common", default-features = false }
parachains-runtimes-test-utils = { path = "../../test-utils", default-features = false }
# Polkadot
pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false, optional = true }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", default-features = false, optional = true , branch = "master" }
xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
xcm-builder = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
@@ -80,6 +81,7 @@ std = [
"pallet-bridge-relayers/std",
"parachain-info/std",
"parachains-runtimes-test-utils/std",
"parachains-common/std",
"cumulus-pallet-parachain-system/std",
"cumulus-pallet-xcmp-queue/std",
"pallet-xcm/std",
@@ -36,13 +36,14 @@ use bridge_runtime_common::{
use codec::Encode;
use frame_support::{
assert_ok,
traits::{Get, OriginTrait, PalletInfoAccess},
traits::{Get, OnFinalize, OnInitialize, OriginTrait, PalletInfoAccess},
};
use frame_system::pallet_prelude::{BlockNumberFor, HeaderFor};
use pallet_bridge_grandpa::BridgedHeader;
use parachains_common::AccountId;
use parachains_runtimes_test_utils::{
mock_open_hrmp_channel, AccountIdOf, BalanceOf, CollatorSessionKeys, ExtBuilder, RuntimeHelper,
ValidatorIdOf, XcmReceivedFrom,
mock_open_hrmp_channel, AccountIdOf, BalanceOf, CollatorSessionKeys, ExtBuilder, ValidatorIdOf,
XcmReceivedFrom,
};
use sp_core::H256;
use sp_keyring::AccountKeyring::*;
@@ -54,6 +55,9 @@ use xcm_executor::XcmExecutor;
// Re-export test_case from assets
pub use asset_test_utils::include_teleports_for_native_asset_works;
type RuntimeHelper<Runtime, AllPalletsWithoutSystem = ()> =
parachains_runtimes_test_utils::RuntimeHelper<Runtime, AllPalletsWithoutSystem>;
// Re-export test_case from `parachains-runtimes-test-utils`
pub use parachains_runtimes_test_utils::test_cases::change_storage_constant_by_governance_works;
@@ -210,6 +214,7 @@ pub fn handle_export_message_from_system_parachain_to_outbound_queue_works<
/// 2. to Sibling parachain
pub fn message_dispatch_routing_works<
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
HrmpChannelOpener,
MessagesPalletInstance,
@@ -237,6 +242,10 @@ pub fn message_dispatch_routing_works<
+ cumulus_pallet_parachain_system::Config
+ cumulus_pallet_xcmp_queue::Config
+ pallet_bridge_messages::Config<MessagesPalletInstance, InboundPayload = XcmAsPlainPayload>,
AllPalletsWithoutSystem:
OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
<Runtime as frame_system::Config>::AccountId:
Into<<<Runtime as frame_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
XcmConfig: xcm_executor::Config,
MessagesPalletInstance: 'static,
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
@@ -258,6 +267,13 @@ pub fn message_dispatch_routing_works<
.with_tracing()
.build()
.execute_with(|| {
let mut alice = [0u8; 32];
alice[0] = 1;
let included_head = RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::run_to_block(
2,
AccountId::from(alice),
);
// 1. this message is sent from other global consensus with destination of this Runtime relay chain (UMP)
let bridging_message =
test_data::simulate_message_exporter_on_bridged_chain::<BridgedNetwork, RuntimeNetwork>(
@@ -299,7 +315,7 @@ pub fn message_dispatch_routing_works<
.count(), 0);
// 2.1. WITH hrmp channel -> Ok
mock_open_hrmp_channel::<Runtime, HrmpChannelOpener>(runtime_para_id.into(), sibling_parachain_id.into());
mock_open_hrmp_channel::<Runtime, HrmpChannelOpener>(runtime_para_id.into(), sibling_parachain_id.into(), included_head, &alice);
let result = <<Runtime as pallet_bridge_messages::Config<MessagesPalletInstance>>::MessageDispatch>::dispatch(
DispatchMessage {
key: MessageKey { lane_id: expected_lane_id, nonce: 1 },
@@ -320,7 +336,7 @@ pub fn message_dispatch_routing_works<
/// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer,
/// with proofs (finality, para heads, message) independently submitted.
pub fn relayed_incoming_message_works<Runtime, XcmConfig, HrmpChannelOpener, GPI, PPI, MPI, MB>(
pub fn relayed_incoming_message_works<Runtime, AllPalletsWithoutSystem, XcmConfig, HrmpChannelOpener, GPI, PPI, MPI, MB>(
collator_session_key: CollatorSessionKeys<Runtime>,
runtime_para_id: u32,
bridged_para_id: u32,
@@ -340,6 +356,8 @@ pub fn relayed_incoming_message_works<Runtime, XcmConfig, HrmpChannelOpener, GPI
+ pallet_bridge_grandpa::Config<GPI>
+ pallet_bridge_parachains::Config<PPI>
+ pallet_bridge_messages::Config<MPI, InboundPayload = XcmAsPlainPayload>,
AllPalletsWithoutSystem: OnInitialize<BlockNumberFor<Runtime>>
+ OnFinalize<BlockNumberFor<Runtime>>,
GPI: 'static,
PPI: 'static,
MPI: 'static,
@@ -370,9 +388,18 @@ pub fn relayed_incoming_message_works<Runtime, XcmConfig, HrmpChannelOpener, GPI
.with_tracing()
.build()
.execute_with(|| {
let mut alice = [0u8; 32];
alice[0] = 1;
let included_head = RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::run_to_block(
2,
AccountId::from(alice),
);
mock_open_hrmp_channel::<Runtime, HrmpChannelOpener>(
runtime_para_id.into(),
sibling_parachain_id.into(),
included_head,
&alice,
);
// start with bridged chain block#0
@@ -516,7 +543,7 @@ pub fn relayed_incoming_message_works<Runtime, XcmConfig, HrmpChannelOpener, GPI
/// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer,
/// with proofs (finality, para heads, message) batched together in signed extrinsic.
/// Also verifies relayer transaction signed extensions work as intended.
pub fn complex_relay_extrinsic_works<Runtime, XcmConfig, HrmpChannelOpener, GPI, PPI, MPI, MB>(
pub fn complex_relay_extrinsic_works<Runtime, AllPalletsWithoutSystem, XcmConfig, HrmpChannelOpener, GPI, PPI, MPI, MB>(
collator_session_key: CollatorSessionKeys<Runtime>,
runtime_para_id: u32,
bridged_para_id: u32,
@@ -545,6 +572,8 @@ pub fn complex_relay_extrinsic_works<Runtime, XcmConfig, HrmpChannelOpener, GPI,
+ pallet_bridge_parachains::Config<PPI>
+ pallet_bridge_messages::Config<MPI, InboundPayload = XcmAsPlainPayload>
+ pallet_bridge_relayers::Config,
AllPalletsWithoutSystem: OnInitialize<BlockNumberFor<Runtime>>
+ OnFinalize<BlockNumberFor<Runtime>>,
GPI: 'static,
PPI: 'static,
MPI: 'static,
@@ -588,6 +617,13 @@ pub fn complex_relay_extrinsic_works<Runtime, XcmConfig, HrmpChannelOpener, GPI,
.with_tracing()
.build()
.execute_with(|| {
let mut alice = [0u8; 32];
alice[0] = 1;
let included_head = RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::run_to_block(
2,
AccountId::from(alice),
);
let zero: BlockNumberFor<Runtime> = 0u32.into();
let genesis_hash = frame_system::Pallet::<Runtime>::block_hash(zero);
let mut header: HeaderFor<Runtime> = bp_test_utils::test_header(1u32.into());
@@ -597,6 +633,8 @@ pub fn complex_relay_extrinsic_works<Runtime, XcmConfig, HrmpChannelOpener, GPI,
mock_open_hrmp_channel::<Runtime, HrmpChannelOpener>(
runtime_para_id.into(),
sibling_parachain_id.into(),
included_head,
&alice,
);
// start with bridged chain block#0
@@ -64,12 +64,11 @@ xcm-executor = { git = "https://github.com/paritytech/polkadot", default-feature
# Cumulus
cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false }
cumulus-pallet-dmp-queue = { path = "../../../../pallets/dmp-queue", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] }
cumulus-pallet-session-benchmarking = { path = "../../../../pallets/session-benchmarking", default-features = false, version = "3.0.0" }
cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false }
cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false }
cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false }
cumulus-primitives-timestamp = { path = "../../../../primitives/timestamp", default-features = false }
cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false }
pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false }
parachain-info = { path = "../../../pallets/parachain-info", default-features = false }
@@ -82,7 +81,9 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran
sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
[features]
default = [ "std" ]
default = [
"std",
]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
@@ -184,7 +185,6 @@ std = [
"cumulus-pallet-xcm/std",
"cumulus-pallet-xcmp-queue/std",
"cumulus-primitives-core/std",
"cumulus-primitives-timestamp/std",
"cumulus-primitives-utility/std",
"pallet-collator-selection/std",
"parachain-info/std",
@@ -122,3 +122,15 @@ pub mod fee {
}
}
}
/// Consensus-related.
pub mod consensus {
/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included
/// into the relay chain.
pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1;
/// How many parachain blocks are processed by the relay chain per parent. Limits the
/// number of blocks authored per slot.
pub const BLOCK_PROCESSING_VELOCITY: u32 = 1;
/// Relay chain slot duration, in milliseconds.
pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
}
@@ -64,7 +64,7 @@ use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
use codec::{Decode, Encode, MaxEncodedLen};
use constants::{currency::*, fee::WeightToFee};
use constants::{consensus::*, currency::*, fee::WeightToFee};
use frame_support::{
construct_runtime,
dispatch::DispatchClass,
@@ -368,6 +368,12 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type XcmpMessageHandler = XcmpQueue;
type ReservedXcmpWeight = ReservedXcmpWeight;
type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases;
type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook<
Runtime,
RELAY_CHAIN_SLOT_DURATION_MILLIS,
BLOCK_PROCESSING_VELOCITY,
UNINCLUDED_SEGMENT_CAPACITY,
>;
}
impl parachain_info::Config for Runtime {}
@@ -894,31 +900,7 @@ impl_runtime_apis! {
}
}
struct CheckInherents;
impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
fn check_inherents(
block: &Block,
relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
) -> sp_inherents::CheckInherentsResult {
let relay_chain_slot = relay_state_proof
.read_slot()
.expect("Could not read the relay chain slot from the proof");
let inherent_data =
cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
relay_chain_slot,
sp_std::time::Duration::from_secs(6),
)
.create_inherent_data()
.expect("Could not create the timestamp inherent data");
inherent_data.check_extrinsics(block)
}
}
cumulus_pallet_parachain_system::register_validate_block! {
Runtime = Runtime,
BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
CheckInherents = CheckInherents,
}
@@ -63,12 +63,11 @@ xcm-executor = { git = "https://github.com/paritytech/polkadot", default-feature
# Cumulus
cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false }
cumulus-pallet-dmp-queue = { path = "../../../../pallets/dmp-queue", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] }
cumulus-pallet-session-benchmarking = { path = "../../../../pallets/session-benchmarking", default-features = false }
cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false }
cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false }
cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false }
cumulus-primitives-timestamp = { path = "../../../../primitives/timestamp", default-features = false }
cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false }
pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false }
parachain-info = { path = "../../../pallets/parachain-info", default-features = false }
@@ -128,7 +127,6 @@ std = [
"cumulus-pallet-xcm/std",
"cumulus-pallet-xcmp-queue/std",
"cumulus-primitives-core/std",
"cumulus-primitives-timestamp/std",
"cumulus-primitives-utility/std",
"substrate-wasm-builder",
]
@@ -107,3 +107,15 @@ pub mod fee {
}
}
}
/// Consensus-related.
pub mod consensus {
/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included
/// into the relay chain.
pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1;
/// How many parachain blocks are processed by the relay chain per parent. Limits the
/// number of blocks authored per slot.
pub const BLOCK_PROCESSING_VELOCITY: u32 = 1;
/// Relay chain slot duration, in milliseconds.
pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
}
@@ -45,7 +45,7 @@ use sp_std::prelude::*;
use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
use constants::{currency::*, fee::WeightToFee};
use constants::{consensus::*, currency::*, fee::WeightToFee};
use frame_support::{
construct_runtime,
dispatch::DispatchClass,
@@ -274,6 +274,12 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type XcmpMessageHandler = XcmpQueue;
type ReservedXcmpWeight = ReservedXcmpWeight;
type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases;
type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook<
Runtime,
RELAY_CHAIN_SLOT_DURATION_MILLIS,
BLOCK_PROCESSING_VELOCITY,
UNINCLUDED_SEGMENT_CAPACITY,
>;
}
impl pallet_insecure_randomness_collective_flip::Config for Runtime {}
@@ -688,31 +694,7 @@ impl_runtime_apis! {
}
}
struct CheckInherents;
impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
fn check_inherents(
block: &Block,
relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
) -> sp_inherents::CheckInherentsResult {
let relay_chain_slot = relay_state_proof
.read_slot()
.expect("Could not read the relay chain slot from the proof");
let inherent_data =
cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
relay_chain_slot,
sp_std::time::Duration::from_secs(6),
)
.create_inherent_data()
.expect("Could not create the timestamp inherent data");
inherent_data.check_extrinsics(block)
}
}
cumulus_pallet_parachain_system::register_validate_block! {
Runtime = Runtime,
BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
CheckInherents = CheckInherents,
}
@@ -35,7 +35,7 @@ xcm-builder = { git = "https://github.com/paritytech/polkadot", default-features
xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
# Cumulus
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] }
cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false }
cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false }
parachain-info = { path = "../../../pallets/parachain-info", default-features = false }
@@ -45,7 +45,9 @@ parachains-common = { path = "../../../common", default-features = false }
substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
[features]
default = [ "std" ]
default = [
"std",
]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
@@ -179,6 +179,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type XcmpMessageHandler = ();
type ReservedXcmpWeight = ();
type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases;
type ConsensusHook = cumulus_pallet_parachain_system::consensus_hook::ExpectParentIncluded;
}
impl parachain_info::Config for Runtime {}
@@ -397,19 +398,7 @@ impl_runtime_apis! {
}
}
struct CheckInherents;
impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
fn check_inherents(
_: &Block,
_: &cumulus_pallet_parachain_system::RelayChainStateProof,
) -> sp_inherents::CheckInherentsResult {
sp_inherents::CheckInherentsResult::new()
}
}
cumulus_pallet_parachain_system::register_validate_block! {
Runtime = Runtime,
BlockExecutor = Executive,
CheckInherents = CheckInherents,
}
@@ -26,7 +26,7 @@ sp-transaction-pool = { git = "https://github.com/paritytech/substrate", default
sp-version = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
# Cumulus
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] }
cumulus-pallet-solo-to-para = { path = "../../../../pallets/solo-to-para", default-features = false }
parachain-info = { path = "../../../pallets/parachain-info", default-features = false }
parachains-common = { path = "../../../common", default-features = false }
@@ -36,7 +36,9 @@ cumulus-primitives-core = { path = "../../../../primitives/core", default-featur
substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
[features]
default = [ "std" ]
default = [
"std",
]
std = [
"codec/std",
"scale-info/std",
@@ -175,6 +175,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type XcmpMessageHandler = ();
type ReservedXcmpWeight = ();
type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases;
type ConsensusHook = cumulus_pallet_parachain_system::consensus_hook::ExpectParentIncluded;
}
impl parachain_info::Config for Runtime {}
@@ -313,19 +314,7 @@ impl_runtime_apis! {
}
}
struct CheckInherents;
impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
fn check_inherents(
_: &Block,
_: &cumulus_pallet_parachain_system::RelayChainStateProof,
) -> sp_inherents::CheckInherentsResult {
sp_inherents::CheckInherentsResult::new()
}
}
cumulus_pallet_parachain_system::register_validate_block! {
Runtime = Runtime,
BlockExecutor = Executive,
CheckInherents = CheckInherents,
}
@@ -30,7 +30,7 @@ xcm-builder = { git = "https://github.com/paritytech/polkadot", default-features
xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
# Cumulus
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] }
cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false }
cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false }
parachain-info = { path = "../../../pallets/parachain-info", default-features = false }
@@ -40,7 +40,9 @@ parachains-common = { path = "../../../common", default-features = false }
substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
[features]
default = [ "std" ]
default = [
"std",
]
std = [
"codec/std",
"scale-info/std",
@@ -178,6 +178,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type XcmpMessageHandler = ();
type ReservedXcmpWeight = ();
type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases;
type ConsensusHook = cumulus_pallet_parachain_system::consensus_hook::ExpectParentIncluded;
}
impl parachain_info::Config for Runtime {}
@@ -343,19 +344,7 @@ impl_runtime_apis! {
}
}
struct CheckInherents;
impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
fn check_inherents(
_: &Block,
_: &cumulus_pallet_parachain_system::RelayChainStateProof,
) -> sp_inherents::CheckInherentsResult {
sp_inherents::CheckInherentsResult::new()
}
}
cumulus_pallet_parachain_system::register_validate_block! {
Runtime = Runtime,
BlockExecutor = Executive,
CheckInherents = CheckInherents,
}
@@ -21,7 +21,7 @@ sp-std = { git = "https://github.com/paritytech/substrate", default-features = f
sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
# Cumulus
cumulus-pallet-parachain-system = { path = "../../../pallets/parachain-system", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] }
cumulus-pallet-xcmp-queue = { path = "../../../pallets/xcmp-queue", default-features = false }
cumulus-pallet-dmp-queue = { path = "../../../pallets/dmp-queue", default-features = false }
pallet-collator-selection = { path = "../../../pallets/collator-selection", default-features = false }
@@ -15,21 +15,26 @@
use sp_std::marker::PhantomData;
use codec::DecodeLimit;
use cumulus_primitives_core::{AbridgedHrmpChannel, ParaId, PersistedValidationData};
use codec::{Decode, DecodeLimit};
use cumulus_primitives_core::{
relay_chain::Slot, AbridgedHrmpChannel, ParaId, PersistedValidationData,
};
use cumulus_primitives_parachain_inherent::ParachainInherentData;
use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
use frame_support::{
dispatch::{DispatchResult, RawOrigin, UnfilteredDispatchable},
inherent::{InherentData, ProvideInherent},
traits::OriginTrait,
traits::{OnFinalize, OnInitialize, OriginTrait},
weights::Weight,
};
use parachains_common::AccountId;
use polkadot_parachain::primitives::{HrmpChannelId, RelayChainBlockNumber, XcmpMessageFormat};
use sp_consensus_aura::AURA_ENGINE_ID;
use frame_system::pallet_prelude::{BlockNumberFor, HeaderFor};
use parachains_common::{AccountId, SLOT_DURATION};
use polkadot_parachain::primitives::{
HeadData, HrmpChannelId, RelayChainBlockNumber, XcmpMessageFormat,
};
use sp_consensus_aura::{SlotDuration, AURA_ENGINE_ID};
use sp_core::Encode;
use sp_runtime::{BuildStorage, Digest, DigestItem};
use sp_runtime::{traits::Header, BuildStorage, Digest, DigestItem};
use xcm::{
latest::{MultiAsset, MultiLocation, XcmContext, XcmHash},
prelude::*,
@@ -207,36 +212,46 @@ impl<
}
}
pub struct RuntimeHelper<Runtime>(PhantomData<Runtime>);
pub struct RuntimeHelper<Runtime, AllPalletsWithoutSystem>(
PhantomData<(Runtime, AllPalletsWithoutSystem)>,
);
/// Utility function that advances the chain to the desired block number.
/// If an author is provided, that author information is injected to all the blocks in the meantime.
impl<Runtime: frame_system::Config> RuntimeHelper<Runtime>
impl<Runtime: frame_system::Config, AllPalletsWithoutSystem>
RuntimeHelper<Runtime, AllPalletsWithoutSystem>
where
AccountIdOf<Runtime>:
Into<<<Runtime as frame_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
AllPalletsWithoutSystem:
OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
{
pub fn run_to_block(n: u32, author: Option<AccountId>) {
while frame_system::Pallet::<Runtime>::block_number() < n.into() {
pub fn run_to_block(n: u32, author: AccountId) -> HeaderFor<Runtime> {
let mut last_header = None;
loop {
let block_number = frame_system::Pallet::<Runtime>::block_number();
if block_number >= n.into() {
break
}
// Set the new block number and author
match author {
Some(ref author) => {
let pre_digest = Digest {
logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, author.encode())],
};
// Inherent is not created at every block, don't finalize parachain
// system to avoid panicking.
let header = frame_system::Pallet::<Runtime>::finalize();
let pre_digest =
Digest { logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, author.encode())] };
frame_system::Pallet::<Runtime>::reset_events();
let next_block_number = block_number + 1u32.into();
frame_system::Pallet::<Runtime>::initialize(
&(frame_system::Pallet::<Runtime>::block_number() + 1u32.into()),
&frame_system::Pallet::<Runtime>::parent_hash(),
&next_block_number,
&header.hash(),
&pre_digest,
);
},
None => {
frame_system::Pallet::<Runtime>::set_block_number(
frame_system::Pallet::<Runtime>::block_number() + 1u32.into(),
);
},
}
AllPalletsWithoutSystem::on_initialize(next_block_number);
last_header = Some(header);
}
last_header.expect("run_to_block empty block range")
}
pub fn root_origin() -> <Runtime as frame_system::Config>::RuntimeOrigin {
@@ -250,7 +265,9 @@ where
}
}
impl<XcmConfig: xcm_executor::Config> RuntimeHelper<XcmConfig> {
impl<XcmConfig: xcm_executor::Config, AllPalletsWithoutSystem>
RuntimeHelper<XcmConfig, AllPalletsWithoutSystem>
{
pub fn do_transfer(
from: MultiLocation,
to: MultiLocation,
@@ -267,13 +284,19 @@ impl<XcmConfig: xcm_executor::Config> RuntimeHelper<XcmConfig> {
}
}
impl<Runtime: pallet_xcm::Config + cumulus_pallet_parachain_system::Config> RuntimeHelper<Runtime> {
impl<
Runtime: pallet_xcm::Config + cumulus_pallet_parachain_system::Config,
AllPalletsWithoutSystem,
> RuntimeHelper<Runtime, AllPalletsWithoutSystem>
{
pub fn do_teleport_assets<HrmpChannelOpener>(
origin: <Runtime as frame_system::Config>::RuntimeOrigin,
dest: MultiLocation,
beneficiary: MultiLocation,
(asset, amount): (MultiLocation, u128),
open_hrmp_channel: Option<(u32, u32)>,
included_head: HeaderFor<Runtime>,
slot_digest: &[u8],
) -> DispatchResult
where
HrmpChannelOpener: frame_support::inherent::ProvideInherent<
@@ -285,6 +308,8 @@ impl<Runtime: pallet_xcm::Config + cumulus_pallet_parachain_system::Config> Runt
mock_open_hrmp_channel::<Runtime, HrmpChannelOpener>(
source_para_id.into(),
target_para_id.into(),
included_head,
slot_digest,
);
}
@@ -299,8 +324,10 @@ impl<Runtime: pallet_xcm::Config + cumulus_pallet_parachain_system::Config> Runt
}
}
impl<Runtime: cumulus_pallet_dmp_queue::Config + cumulus_pallet_parachain_system::Config>
RuntimeHelper<Runtime>
impl<
Runtime: cumulus_pallet_dmp_queue::Config + cumulus_pallet_parachain_system::Config,
AllPalletsWithoutSystem,
> RuntimeHelper<Runtime, AllPalletsWithoutSystem>
{
pub fn execute_as_governance(call: Vec<u8>, require_weight_at_most: Weight) -> Outcome {
// prepare xcm as governance will do
@@ -329,7 +356,9 @@ pub enum XcmReceivedFrom {
Sibling,
}
impl<ParachainSystem: cumulus_pallet_parachain_system::Config> RuntimeHelper<ParachainSystem> {
impl<ParachainSystem: cumulus_pallet_parachain_system::Config, AllPalletsWithoutSystem>
RuntimeHelper<ParachainSystem, AllPalletsWithoutSystem>
{
pub fn xcm_max_weight(from: XcmReceivedFrom) -> Weight {
use frame_support::traits::Get;
match from {
@@ -339,7 +368,9 @@ impl<ParachainSystem: cumulus_pallet_parachain_system::Config> RuntimeHelper<Par
}
}
impl<Runtime: frame_system::Config + pallet_xcm::Config> RuntimeHelper<Runtime> {
impl<Runtime: frame_system::Config + pallet_xcm::Config, AllPalletsWithoutSystem>
RuntimeHelper<Runtime, AllPalletsWithoutSystem>
{
pub fn assert_pallet_xcm_event_outcome(
unwrap_pallet_xcm_event: &Box<dyn Fn(Vec<u8>) -> Option<pallet_xcm::Event<Runtime>>>,
assert_outcome: fn(Outcome),
@@ -357,7 +388,11 @@ impl<Runtime: frame_system::Config + pallet_xcm::Config> RuntimeHelper<Runtime>
}
}
impl<Runtime: frame_system::Config + cumulus_pallet_xcmp_queue::Config> RuntimeHelper<Runtime> {
impl<
Runtime: frame_system::Config + cumulus_pallet_xcmp_queue::Config,
AllPalletsWithoutSystem,
> RuntimeHelper<Runtime, AllPalletsWithoutSystem>
{
pub fn xcmp_queue_message_sent(
unwrap_xcmp_queue_event: Box<
dyn Fn(Vec<u8>) -> Option<cumulus_pallet_xcmp_queue::Event<Runtime>>,
@@ -400,18 +435,35 @@ pub fn assert_total<Fungibles, AccountId>(
assert_eq!(Fungibles::active_issuance(asset_id.into()), expected_active_issuance.into());
}
/// Helper function which emulates opening HRMP channel which is needed for `XcmpQueue` to pass
/// Helper function which emulates opening HRMP channel which is needed for `XcmpQueue` to pass.
///
/// Calls parachain-system's `create_inherent` in case the channel hasn't been opened before, and
/// thus requires additional parameters for validating it: latest included parachain head and
/// parachain AuRa-slot.
///
/// AuRa consensus hook expects pallets to be initialized, before calling this function make sure to
/// `run_to_block` at least once.
pub fn mock_open_hrmp_channel<
C: cumulus_pallet_parachain_system::Config,
T: ProvideInherent<Call = cumulus_pallet_parachain_system::Call<C>>,
>(
sender: ParaId,
recipient: ParaId,
included_head: HeaderFor<C>,
mut slot_digest: &[u8],
) {
const RELAY_CHAIN_SLOT_DURATION: SlotDuration = SlotDuration::from_millis(6000);
let slot = Slot::decode(&mut slot_digest).expect("failed to decode digest");
// Convert para slot to relay chain.
let timestamp = slot.saturating_mul(SLOT_DURATION);
let relay_slot = Slot::from_timestamp(timestamp.into(), RELAY_CHAIN_SLOT_DURATION);
let n = 1_u32;
let mut sproof_builder = RelayStateSproofBuilder {
para_id: sender,
included_para_head: Some(HeadData(included_head.encode())),
hrmp_egress_channel_index: Some(vec![recipient]),
current_slot: relay_slot,
..Default::default()
};
sproof_builder.hrmp_channels.insert(
@@ -458,8 +510,8 @@ pub fn mock_open_hrmp_channel<
.expect("dispatch succeeded");
}
impl<HrmpChannelSource: cumulus_primitives_core::XcmpMessageSource>
RuntimeHelper<HrmpChannelSource>
impl<HrmpChannelSource: cumulus_primitives_core::XcmpMessageSource, AllPalletsWithoutSystem>
RuntimeHelper<HrmpChannelSource, AllPalletsWithoutSystem>
{
pub fn take_xcm(sent_to_para_id: ParaId) -> Option<VersionedXcm<()>> {
match HrmpChannelSource::take_outbound_messages(10)[..] {
@@ -16,10 +16,13 @@
//! Module contains predefined test-case scenarios for `Runtime` with common functionality.
use crate::{AccountIdOf, CollatorSessionKeys, ExtBuilder, RuntimeHelper, ValidatorIdOf};
use crate::{AccountIdOf, CollatorSessionKeys, ExtBuilder, ValidatorIdOf};
use codec::Encode;
use frame_support::{assert_ok, traits::Get};
type RuntimeHelper<Runtime, AllPalletsWithoutSystem = ()> =
crate::RuntimeHelper<Runtime, AllPalletsWithoutSystem>;
/// Test-case makes sure that `Runtime` can change storage constant via governance-like call
pub fn change_storage_constant_by_governance_works<Runtime, StorageConstant, StorageConstantType>(
collator_session_key: CollatorSessionKeys<Runtime>,
@@ -63,12 +63,11 @@ xcm-executor = { git = "https://github.com/paritytech/polkadot", default-feature
# Cumulus
cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false }
cumulus-pallet-dmp-queue = { path = "../../../../pallets/dmp-queue", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] }
cumulus-pallet-session-benchmarking = {path = "../../../../pallets/session-benchmarking", default-features = false, version = "3.0.0"}
cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false }
cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false }
cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false }
cumulus-primitives-timestamp = { path = "../../../../primitives/timestamp", default-features = false }
cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false }
pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false }
parachain-info = { path = "../../../../parachains/pallets/parachain-info", default-features = false }
@@ -88,7 +87,6 @@ std = [
"cumulus-pallet-xcm/std",
"cumulus-pallet-xcmp-queue/std",
"cumulus-primitives-core/std",
"cumulus-primitives-timestamp/std",
"cumulus-primitives-utility/std",
"frame-executive/std",
"frame-support/std",
@@ -271,6 +271,15 @@ const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(
cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64,
);
/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included
/// into the relay chain.
const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1;
/// How many parachain blocks are processed by the relay chain per parent. Limits the
/// number of blocks authored per slot.
const BLOCK_PROCESSING_VELOCITY: u32 = 1;
/// Relay chain slot duration, in milliseconds.
const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
/// The version information used to identify this runtime when compiled natively.
#[cfg(feature = "std")]
pub fn native_version() -> NativeVersion {
@@ -457,6 +466,12 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type XcmpMessageHandler = XcmpQueue;
type ReservedXcmpWeight = ReservedXcmpWeight;
type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases;
type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook<
Runtime,
RELAY_CHAIN_SLOT_DURATION_MILLIS,
BLOCK_PROCESSING_VELOCITY,
UNINCLUDED_SEGMENT_CAPACITY,
>;
}
impl parachain_info::Config for Runtime {}
@@ -816,31 +831,7 @@ impl_runtime_apis! {
}
}
struct CheckInherents;
impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
fn check_inherents(
block: &Block,
relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
) -> sp_inherents::CheckInherentsResult {
let relay_chain_slot = relay_state_proof
.read_slot()
.expect("Could not read the relay chain slot from the proof");
let inherent_data =
cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
relay_chain_slot,
sp_std::time::Duration::from_secs(6),
)
.create_inherent_data()
.expect("Could not create the timestamp inherent data");
inherent_data.check_extrinsics(block)
}
}
cumulus_pallet_parachain_system::register_validate_block! {
Runtime = Runtime,
BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
CheckInherents = CheckInherents,
}
@@ -44,12 +44,11 @@ xcm-executor = { git = "https://github.com/paritytech/polkadot", default-feature
# Cumulus
cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false }
cumulus-pallet-dmp-queue = { path = "../../../../pallets/dmp-queue", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false }
cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] }
cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false }
cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false }
cumulus-ping = { path = "../../../pallets/ping", default-features = false }
cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false }
cumulus-primitives-timestamp = { path = "../../../../primitives/timestamp", default-features = false }
cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false }
parachains-common = { path = "../../../common", default-features = false }
parachain-info = { path = "../../../pallets/parachain-info", default-features = false }
@@ -58,7 +57,9 @@ parachain-info = { path = "../../../pallets/parachain-info", default-features =
substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
[features]
default = [ "std" ]
default = [
"std",
]
std = [
"codec/std",
"scale-info/std",
@@ -95,7 +96,6 @@ std = [
"cumulus-pallet-xcmp-queue/std",
"cumulus-ping/std",
"cumulus-primitives-core/std",
"cumulus-primitives-timestamp/std",
"cumulus-primitives-utility/std",
"parachain-info/std",
"parachains-common/std",
@@ -144,6 +144,15 @@ const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(
cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64,
);
/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included
/// into the relay chain.
const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1;
/// How many parachain blocks are processed by the relay chain per parent. Limits the
/// number of blocks authored per slot.
const BLOCK_PROCESSING_VELOCITY: u32 = 1;
/// Relay chain slot duration, in milliseconds.
const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
parameter_types! {
pub const BlockHashCount: BlockNumber = 250;
pub const Version: RuntimeVersion = VERSION;
@@ -271,6 +280,12 @@ impl cumulus_pallet_parachain_system::Config for Runtime {
type XcmpMessageHandler = XcmpQueue;
type ReservedXcmpWeight = ReservedXcmpWeight;
type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases;
type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook<
Runtime,
RELAY_CHAIN_SLOT_DURATION_MILLIS,
BLOCK_PROCESSING_VELOCITY,
UNINCLUDED_SEGMENT_CAPACITY,
>;
}
impl parachain_info::Config for Runtime {}
@@ -781,31 +796,7 @@ impl_runtime_apis! {
}
}
struct CheckInherents;
impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
fn check_inherents(
block: &Block,
relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
) -> sp_inherents::CheckInherentsResult {
let relay_chain_slot = relay_state_proof
.read_slot()
.expect("Could not read the relay chain slot from the proof");
let inherent_data =
cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
relay_chain_slot,
sp_std::time::Duration::from_secs(6),
)
.create_inherent_data()
.expect("Could not create the timestamp inherent data");
inherent_data.check_extrinsics(block)
}
}
cumulus_pallet_parachain_system::register_validate_block! {
Runtime = Runtime,
BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
CheckInherents = CheckInherents,
}
+3 -1
View File
@@ -75,16 +75,18 @@ substrate-state-trie-migration-rpc = { git = "https://github.com/paritytech/subs
# Polkadot
# Use rococo-native as this is currently the default "local" relay chain
polkadot-cli = { git = "https://github.com/paritytech/polkadot", branch = "master", features = ["rococo-native"] }
polkadot-cli = { git = "https://github.com/paritytech/polkadot", features = ["rococo-native"] , branch = "master" }
polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" }
polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "master" }
xcm = { git = "https://github.com/paritytech/polkadot", branch = "master" }
# Cumulus
cumulus-client-cli = { path = "../client/cli" }
cumulus-client-collator = { path = "../client/collator" }
cumulus-client-consensus-aura = { path = "../client/consensus/aura" }
cumulus-client-consensus-relay-chain = { path = "../client/consensus/relay-chain" }
cumulus-client-consensus-common = { path = "../client/consensus/common" }
cumulus-client-consensus-proposer = { path = "../client/consensus/proposer" }
cumulus-client-service = { path = "../client/service" }
cumulus-primitives-core = { path = "../primitives/core" }
cumulus-primitives-parachain-inherent = { path = "../primitives/parachain-inherent" }
+256 -319
View File
@@ -16,19 +16,25 @@
use codec::Codec;
use cumulus_client_cli::CollatorOptions;
use cumulus_client_consensus_aura::{AuraConsensus, BuildAuraConsensusParams, SlotProportion};
use cumulus_client_collator::service::CollatorService;
use cumulus_client_consensus_aura::collators::basic::{
self as basic_aura, Params as BasicAuraParams,
};
use cumulus_client_consensus_common::{
ParachainBlockImport as TParachainBlockImport, ParachainCandidate, ParachainConsensus,
};
use cumulus_client_consensus_proposer::Proposer;
#[allow(deprecated)]
use cumulus_client_service::old_consensus;
use cumulus_client_service::{
build_network, build_relay_chain_interface, prepare_node_config, start_collator,
start_full_node, BuildNetworkParams, StartCollatorParams, StartFullNodeParams,
build_network, build_relay_chain_interface, prepare_node_config, start_relay_chain_tasks,
BuildNetworkParams, CollatorSybilResistance, DARecoveryProfile, StartRelayChainTasksParams,
};
use cumulus_primitives_core::{
relay_chain::{Hash as PHash, PersistedValidationData},
ParaId,
};
use cumulus_relay_chain_interface::RelayChainInterface;
use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface};
use sp_core::Pair;
use jsonrpsee::RpcModule;
@@ -54,6 +60,8 @@ use sp_runtime::{app_crypto::AppCrypto, traits::Header as HeaderT};
use std::{marker::PhantomData, sync::Arc, time::Duration};
use substrate_prometheus_endpoint::Registry;
use polkadot_primitives::CollatorPair;
#[cfg(not(feature = "runtime-benchmarks"))]
type HostFunctions = sp_io::SubstrateHostFunctions;
@@ -325,14 +333,15 @@ where
/// This is the actual implementation that is abstract over the executor and the runtime api for
/// shell nodes.
#[sc_tracing::logging::prefix_logs_with("Parachain")]
async fn start_shell_node_impl<RuntimeApi, RB, BIQ, BIC>(
async fn start_shell_node_impl<RuntimeApi, RB, BIQ, SC>(
parachain_config: Configuration,
polkadot_config: Configuration,
collator_options: CollatorOptions,
sybil_resistance_level: CollatorSybilResistance,
para_id: ParaId,
rpc_ext_builder: RB,
build_import_queue: BIQ,
build_consensus: BIC,
start_consensus: SC,
hwbench: Option<sc_sysinfo::HwBench>,
) -> sc_service::error::Result<(TaskManager, Arc<ParachainClient<RuntimeApi>>)>
where
@@ -353,7 +362,7 @@ where
Option<TelemetryHandle>,
&TaskManager,
) -> Result<sc_consensus::DefaultImportQueue<Block>, sc_service::Error>,
BIC: FnOnce(
SC: FnOnce(
Arc<ParachainClient<RuntimeApi>>,
ParachainBlockImport<RuntimeApi>,
Option<&Registry>,
@@ -363,8 +372,12 @@ where
Arc<sc_transaction_pool::FullPool<Block, ParachainClient<RuntimeApi>>>,
Arc<SyncingService<Block>>,
KeystorePtr,
bool,
) -> Result<Box<dyn ParachainConsensus<Block>>, sc_service::Error>,
Duration,
ParaId,
CollatorPair,
OverseerHandle,
Arc<dyn Fn(Hash, Option<Vec<u8>>) + Send + Sync>,
) -> Result<(), sc_service::Error>,
{
let parachain_config = prepare_node_config(parachain_config);
@@ -387,7 +400,6 @@ where
.await
.map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?;
let force_authoring = parachain_config.force_authoring;
let validator = parachain_config.role.is_authority();
let prometheus_registry = parachain_config.prometheus_registry().cloned();
let transaction_pool = params.transaction_pool.clone();
@@ -404,6 +416,7 @@ where
spawn_handle: task_manager.spawn_handle(),
relay_chain_interface: relay_chain_interface.clone(),
import_queue: params.import_queue,
sybil_resistance_level,
})
.await?;
@@ -452,8 +465,25 @@ where
.overseer_handle()
.map_err(|e| sc_service::Error::Application(Box::new(e)))?;
start_relay_chain_tasks(StartRelayChainTasksParams {
client: client.clone(),
announce_block: announce_block.clone(),
para_id,
relay_chain_interface: relay_chain_interface.clone(),
task_manager: &mut task_manager,
da_recovery_profile: if validator {
DARecoveryProfile::Collator
} else {
DARecoveryProfile::FullNode
},
import_queue: import_queue_service,
relay_chain_slot_duration,
recovery_handle: Box::new(overseer_handle.clone()),
sync_service: sync_service.clone(),
})?;
if validator {
let parachain_consensus = build_consensus(
start_consensus(
client.clone(),
block_import,
prometheus_registry.as_ref(),
@@ -463,42 +493,12 @@ where
transaction_pool,
sync_service.clone(),
params.keystore_container.keystore(),
force_authoring,
relay_chain_slot_duration,
para_id,
collator_key.expect("Command line arguments do not allow this. qed"),
overseer_handle,
announce_block,
)?;
let spawner = task_manager.spawn_handle();
let params = StartCollatorParams {
para_id,
block_status: client.clone(),
announce_block,
client: client.clone(),
task_manager: &mut task_manager,
relay_chain_interface,
spawner,
parachain_consensus,
import_queue: import_queue_service,
collator_key: collator_key.expect("Command line arguments do not allow this. qed"),
relay_chain_slot_duration,
recovery_handle: Box::new(overseer_handle),
sync_service,
};
start_collator(params).await?;
} else {
let params = StartFullNodeParams {
client: client.clone(),
announce_block,
task_manager: &mut task_manager,
para_id,
relay_chain_interface,
relay_chain_slot_duration,
import_queue: import_queue_service,
recovery_handle: Box::new(overseer_handle),
sync_service,
};
start_full_node(params)?;
}
start_network.start_network();
@@ -510,14 +510,15 @@ where
///
/// This is the actual implementation that is abstract over the executor and the runtime api.
#[sc_tracing::logging::prefix_logs_with("Parachain")]
async fn start_node_impl<RuntimeApi, RB, BIQ, BIC>(
async fn start_node_impl<RuntimeApi, RB, BIQ, SC>(
parachain_config: Configuration,
polkadot_config: Configuration,
collator_options: CollatorOptions,
sybil_resistance_level: CollatorSybilResistance,
para_id: ParaId,
_rpc_ext_builder: RB,
build_import_queue: BIQ,
build_consensus: BIC,
start_consensus: SC,
hwbench: Option<sc_sysinfo::HwBench>,
) -> sc_service::error::Result<(TaskManager, Arc<ParachainClient<RuntimeApi>>)>
where
@@ -539,7 +540,7 @@ where
Option<TelemetryHandle>,
&TaskManager,
) -> Result<sc_consensus::DefaultImportQueue<Block>, sc_service::Error>,
BIC: FnOnce(
SC: FnOnce(
Arc<ParachainClient<RuntimeApi>>,
ParachainBlockImport<RuntimeApi>,
Option<&Registry>,
@@ -549,8 +550,12 @@ where
Arc<sc_transaction_pool::FullPool<Block, ParachainClient<RuntimeApi>>>,
Arc<SyncingService<Block>>,
KeystorePtr,
bool,
) -> Result<Box<dyn ParachainConsensus<Block>>, sc_service::Error>,
Duration,
ParaId,
CollatorPair,
OverseerHandle,
Arc<dyn Fn(Hash, Option<Vec<u8>>) + Send + Sync>,
) -> Result<(), sc_service::Error>,
{
let parachain_config = prepare_node_config(parachain_config);
@@ -572,7 +577,6 @@ where
.await
.map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?;
let force_authoring = parachain_config.force_authoring;
let validator = parachain_config.role.is_authority();
let prometheus_registry = parachain_config.prometheus_registry().cloned();
let transaction_pool = params.transaction_pool.clone();
@@ -589,6 +593,7 @@ where
spawn_handle: task_manager.spawn_handle(),
relay_chain_interface: relay_chain_interface.clone(),
import_queue: params.import_queue,
sybil_resistance_level,
})
.await?;
@@ -649,8 +654,26 @@ where
let overseer_handle = relay_chain_interface
.overseer_handle()
.map_err(|e| sc_service::Error::Application(Box::new(e)))?;
start_relay_chain_tasks(StartRelayChainTasksParams {
client: client.clone(),
announce_block: announce_block.clone(),
para_id,
relay_chain_interface: relay_chain_interface.clone(),
task_manager: &mut task_manager,
da_recovery_profile: if validator {
DARecoveryProfile::Collator
} else {
DARecoveryProfile::FullNode
},
import_queue: import_queue_service,
relay_chain_slot_duration,
recovery_handle: Box::new(overseer_handle.clone()),
sync_service: sync_service.clone(),
})?;
if validator {
let parachain_consensus = build_consensus(
start_consensus(
client.clone(),
block_import,
prometheus_registry.as_ref(),
@@ -660,42 +683,12 @@ where
transaction_pool,
sync_service.clone(),
params.keystore_container.keystore(),
force_authoring,
relay_chain_slot_duration,
para_id,
collator_key.expect("Command line arguments do not allow this. qed"),
overseer_handle,
announce_block,
)?;
let spawner = task_manager.spawn_handle();
let params = StartCollatorParams {
para_id,
block_status: client.clone(),
announce_block,
client: client.clone(),
task_manager: &mut task_manager,
relay_chain_interface: relay_chain_interface.clone(),
spawner,
parachain_consensus,
import_queue: import_queue_service,
collator_key: collator_key.expect("Command line arguments do not allow this. qed"),
relay_chain_slot_duration,
recovery_handle: Box::new(overseer_handle),
sync_service,
};
start_collator(params).await?;
} else {
let params = StartFullNodeParams {
client: client.clone(),
announce_block,
task_manager: &mut task_manager,
para_id,
relay_chain_interface,
relay_chain_slot_duration,
import_queue: import_queue_service,
recovery_handle: Box::new(overseer_handle),
sync_service,
};
start_full_node(params)?;
}
start_network.start_network();
@@ -756,6 +749,7 @@ pub async fn start_rococo_parachain_node(
parachain_config,
polkadot_config,
collator_options,
CollatorSybilResistance::Resistant, // Aura
para_id,
|_| Ok(RpcModule::new(())),
rococo_parachain_build_import_queue,
@@ -768,7 +762,11 @@ pub async fn start_rococo_parachain_node(
transaction_pool,
sync_oracle,
keystore,
force_authoring| {
relay_chain_slot_duration,
para_id,
collator_key,
overseer_handle,
announce_block| {
let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?;
let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording(
@@ -778,53 +776,47 @@ pub async fn start_rococo_parachain_node(
prometheus_registry,
telemetry.clone(),
);
let proposer = Proposer::new(proposer_factory);
Ok(AuraConsensus::build::<sp_consensus_aura::sr25519::AuthorityPair, _, _, _, _, _, _>(
BuildAuraConsensusParams {
proposer_factory,
create_inherent_data_providers: move |_, (relay_parent, validation_data)| {
let relay_chain_interface = relay_chain_interface.clone();
async move {
let parachain_inherent =
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(
relay_parent,
&relay_chain_interface,
&validation_data,
para_id,
).await;
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
let slot =
sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
*timestamp,
slot_duration,
let collator_service = CollatorService::new(
client.clone(),
Arc::new(task_manager.spawn_handle()),
announce_block,
client.clone(),
);
let parachain_inherent = parachain_inherent.ok_or_else(|| {
Box::<dyn std::error::Error + Send + Sync>::from(
"Failed to create parachain inherent",
)
})?;
Ok((slot, timestamp, parachain_inherent))
}
},
let params = BasicAuraParams {
create_inherent_data_providers: move |_, ()| async move { Ok(()) },
block_import,
para_client: client,
backoff_authoring_blocks: Option::<()>::None,
relay_client: relay_chain_interface,
sync_oracle,
keystore,
force_authoring,
collator_key,
para_id,
overseer_handle,
slot_duration,
// We got around 500ms for proposing
block_proposal_slot_portion: SlotProportion::new(1f32 / 24f32),
// And a maximum of 750ms if slots are skipped
max_block_proposal_slot_portion: Some(SlotProportion::new(1f32 / 16f32)),
telemetry,
},
))
relay_chain_slot_duration,
proposer,
collator_service,
// Very limited proposal time.
authoring_duration: Duration::from_millis(500),
};
let fut = basic_aura::run::<
Block,
sp_consensus_aura::sr25519::AuthorityPair,
_,
_,
_,
_,
_,
_,
_,
>(params);
task_manager.spawn_essential_handle().spawn("aura", None, fut);
Ok(())
},
hwbench,
)
@@ -880,6 +872,7 @@ where
parachain_config,
polkadot_config,
collator_options,
CollatorSybilResistance::Unresistant, // free-for-all consensus
para_id,
|_| Ok(RpcModule::new(())),
shell_build_import_queue,
@@ -890,18 +883,22 @@ where
task_manager,
relay_chain_interface,
transaction_pool,
_,
_,
_| {
_sync_oracle,
_keystore,
_relay_chain_slot_duration,
para_id,
collator_key,
overseer_handle,
announce_block| {
let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording(
task_manager.spawn_handle(),
client,
client.clone(),
transaction_pool,
prometheus_registry,
telemetry,
);
Ok(cumulus_client_consensus_relay_chain::build_relay_chain_consensus(
let free_for_all = cumulus_client_consensus_relay_chain::build_relay_chain_consensus(
cumulus_client_consensus_relay_chain::BuildRelayChainConsensusParams {
para_id,
proposer_factory,
@@ -926,7 +923,24 @@ where
}
},
},
))
);
let spawner = task_manager.spawn_handle();
// Required for free-for-all consensus
#[allow(deprecated)]
old_consensus::start_collator_sync(old_consensus::StartCollatorParams {
para_id,
block_status: client.clone(),
announce_block,
overseer_handle,
spawner,
key: collator_key,
parachain_consensus: free_for_all,
runtime_api: client.clone(),
});
Ok(())
},
hwbench,
)
@@ -1127,6 +1141,7 @@ where
parachain_config,
polkadot_config,
collator_options,
CollatorSybilResistance::Resistant, // Aura
para_id,
|_| Ok(RpcModule::new(())),
aura_build_import_queue::<_, AuraId>,
@@ -1139,123 +1154,52 @@ where
transaction_pool,
sync_oracle,
keystore,
force_authoring| {
let spawn_handle = task_manager.spawn_handle();
let client2 = client.clone();
let block_import2 = block_import.clone();
let transaction_pool2 = transaction_pool.clone();
let telemetry2 = telemetry.clone();
let prometheus_registry2 = prometheus_registry.map(|r| (*r).clone());
let relay_chain_for_aura = relay_chain_interface.clone();
let aura_consensus = BuildOnAccess::Uninitialized(Some(Box::new(move || {
let slot_duration =
cumulus_client_consensus_aura::slot_duration(&*client2).unwrap();
let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording(
spawn_handle,
client2.clone(),
transaction_pool2,
prometheus_registry2.as_ref(),
telemetry2.clone(),
);
AuraConsensus::build::<<AuraId as AppCrypto>::Pair, _, _, _, _, _, _>(
BuildAuraConsensusParams {
proposer_factory,
create_inherent_data_providers:
move |_, (relay_parent, validation_data)| {
let relay_chain_for_aura = relay_chain_for_aura.clone();
async move {
let parachain_inherent =
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(
relay_parent,
&relay_chain_for_aura,
&validation_data,
relay_chain_slot_duration,
para_id,
).await;
let timestamp =
sp_timestamp::InherentDataProvider::from_system_time();
let slot =
sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
*timestamp,
slot_duration,
);
let parachain_inherent =
parachain_inherent.ok_or_else(|| {
Box::<dyn std::error::Error + Send + Sync>::from(
"Failed to create parachain inherent",
)
})?;
Ok((slot, timestamp, parachain_inherent))
}
},
block_import: block_import2,
para_client: client2,
backoff_authoring_blocks: Option::<()>::None,
sync_oracle,
keystore,
force_authoring,
slot_duration,
// We got around 500ms for proposing
block_proposal_slot_portion: SlotProportion::new(1f32 / 24f32),
// And a maximum of 750ms if slots are skipped
max_block_proposal_slot_portion: Some(SlotProportion::new(1f32 / 16f32)),
telemetry: telemetry2,
},
)
})));
collator_key,
overseer_handle,
announce_block| {
let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?;
let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording(
task_manager.spawn_handle(),
client.clone(),
transaction_pool,
prometheus_registry,
telemetry,
telemetry.clone(),
);
let proposer = Proposer::new(proposer_factory);
let collator_service = CollatorService::new(
client.clone(),
Arc::new(task_manager.spawn_handle()),
announce_block,
client.clone(),
);
let relay_chain_consensus =
cumulus_client_consensus_relay_chain::build_relay_chain_consensus(
cumulus_client_consensus_relay_chain::BuildRelayChainConsensusParams {
para_id,
proposer_factory,
let params = BasicAuraParams {
create_inherent_data_providers: move |_, ()| async move { Ok(()) },
block_import,
relay_chain_interface: relay_chain_interface.clone(),
create_inherent_data_providers:
move |_, (relay_parent, validation_data)| {
let relay_chain_interface = relay_chain_interface.clone();
async move {
let parachain_inherent =
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(
relay_parent,
&relay_chain_interface,
&validation_data,
para_client: client,
relay_client: relay_chain_interface,
sync_oracle,
keystore,
collator_key,
para_id,
).await;
let parachain_inherent =
parachain_inherent.ok_or_else(|| {
Box::<dyn std::error::Error + Send + Sync>::from(
"Failed to create parachain inherent",
)
})?;
Ok(parachain_inherent)
}
},
},
);
overseer_handle,
slot_duration,
relay_chain_slot_duration,
proposer,
collator_service,
// Very limited proposal time.
authoring_duration: Duration::from_millis(500),
};
let parachain_consensus = Box::new(WaitForAuraConsensus {
client,
aura_consensus: Arc::new(Mutex::new(aura_consensus)),
relay_chain_consensus: Arc::new(Mutex::new(relay_chain_consensus)),
_phantom: PhantomData,
});
let fut =
basic_aura::run::<Block, <AuraId as AppCrypto>::Pair, _, _, _, _, _, _, _>(params);
task_manager.spawn_essential_handle().spawn("aura", None, fut);
Ok(parachain_consensus)
Ok(())
},
hwbench,
)
@@ -1263,14 +1207,15 @@ where
}
#[sc_tracing::logging::prefix_logs_with("Parachain")]
async fn start_contracts_rococo_node_impl<RuntimeApi, RB, BIQ, BIC>(
async fn start_contracts_rococo_node_impl<RuntimeApi, RB, BIQ, SC>(
parachain_config: Configuration,
polkadot_config: Configuration,
collator_options: CollatorOptions,
sybil_resistance_level: CollatorSybilResistance,
para_id: ParaId,
_rpc_ext_builder: RB,
build_import_queue: BIQ,
build_consensus: BIC,
start_consensus: SC,
hwbench: Option<sc_sysinfo::HwBench>,
) -> sc_service::error::Result<(TaskManager, Arc<ParachainClient<RuntimeApi>>)>
where
@@ -1292,7 +1237,7 @@ where
Option<TelemetryHandle>,
&TaskManager,
) -> Result<sc_consensus::DefaultImportQueue<Block>, sc_service::Error>,
BIC: FnOnce(
SC: FnOnce(
Arc<ParachainClient<RuntimeApi>>,
ParachainBlockImport<RuntimeApi>,
Option<&Registry>,
@@ -1302,8 +1247,12 @@ where
Arc<sc_transaction_pool::FullPool<Block, ParachainClient<RuntimeApi>>>,
Arc<SyncingService<Block>>,
KeystorePtr,
bool,
) -> Result<Box<dyn ParachainConsensus<Block>>, sc_service::Error>,
Duration,
ParaId,
CollatorPair,
OverseerHandle,
Arc<dyn Fn(Hash, Option<Vec<u8>>) + Send + Sync>,
) -> Result<(), sc_service::Error>,
{
let parachain_config = prepare_node_config(parachain_config);
@@ -1325,7 +1274,6 @@ where
.await
.map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?;
let force_authoring = parachain_config.force_authoring;
let validator = parachain_config.role.is_authority();
let prometheus_registry = parachain_config.prometheus_registry().cloned();
let transaction_pool = params.transaction_pool.clone();
@@ -1342,6 +1290,7 @@ where
spawn_handle: task_manager.spawn_handle(),
relay_chain_interface: relay_chain_interface.clone(),
import_queue: params.import_queue,
sybil_resistance_level,
})
.await?;
@@ -1401,8 +1350,26 @@ where
let overseer_handle = relay_chain_interface
.overseer_handle()
.map_err(|e| sc_service::Error::Application(Box::new(e)))?;
start_relay_chain_tasks(StartRelayChainTasksParams {
client: client.clone(),
announce_block: announce_block.clone(),
para_id,
relay_chain_interface: relay_chain_interface.clone(),
task_manager: &mut task_manager,
da_recovery_profile: if validator {
DARecoveryProfile::Collator
} else {
DARecoveryProfile::FullNode
},
import_queue: import_queue_service,
relay_chain_slot_duration,
recovery_handle: Box::new(overseer_handle.clone()),
sync_service: sync_service.clone(),
})?;
if validator {
let parachain_consensus = build_consensus(
start_consensus(
client.clone(),
block_import,
prometheus_registry.as_ref(),
@@ -1412,42 +1379,12 @@ where
transaction_pool,
sync_service.clone(),
params.keystore_container.keystore(),
force_authoring,
relay_chain_slot_duration,
para_id,
collator_key.expect("Command line arguments do not allow this. qed"),
overseer_handle,
announce_block,
)?;
let spawner = task_manager.spawn_handle();
let params = StartCollatorParams {
para_id,
block_status: client.clone(),
announce_block,
client: client.clone(),
task_manager: &mut task_manager,
relay_chain_interface,
spawner,
parachain_consensus,
import_queue: import_queue_service,
collator_key: collator_key.expect("Command line arguments do not allow this. qed"),
relay_chain_slot_duration,
recovery_handle: Box::new(overseer_handle),
sync_service,
};
start_collator(params).await?;
} else {
let params = StartFullNodeParams {
client: client.clone(),
announce_block,
task_manager: &mut task_manager,
para_id,
relay_chain_interface,
relay_chain_slot_duration,
import_queue: import_queue_service,
recovery_handle: Box::new(overseer_handle),
sync_service,
};
start_full_node(params)?;
}
start_network.start_network();
@@ -1508,6 +1445,7 @@ pub async fn start_contracts_rococo_node(
parachain_config,
polkadot_config,
collator_options,
CollatorSybilResistance::Resistant, // Aura
para_id,
|_| Ok(RpcModule::new(())),
contracts_rococo_build_import_queue,
@@ -1520,7 +1458,11 @@ pub async fn start_contracts_rococo_node(
transaction_pool,
sync_oracle,
keystore,
force_authoring| {
relay_chain_slot_duration,
para_id,
collator_key,
overseer_handle,
announce_block| {
let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?;
let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording(
@@ -1530,52 +1472,47 @@ pub async fn start_contracts_rococo_node(
prometheus_registry,
telemetry.clone(),
);
let proposer = Proposer::new(proposer_factory);
Ok(AuraConsensus::build::<sp_consensus_aura::sr25519::AuthorityPair, _, _, _, _, _, _>(
BuildAuraConsensusParams {
proposer_factory,
create_inherent_data_providers: move |_, (relay_parent, validation_data)| {
let relay_chain_interface = relay_chain_interface.clone();
async move {
let parachain_inherent =
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(
relay_parent,
&relay_chain_interface,
&validation_data,
para_id,
).await;
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
let slot =
sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
*timestamp,
slot_duration,
let collator_service = CollatorService::new(
client.clone(),
Arc::new(task_manager.spawn_handle()),
announce_block,
client.clone(),
);
let parachain_inherent = parachain_inherent.ok_or_else(|| {
Box::<dyn std::error::Error + Send + Sync>::from(
"Failed to create parachain inherent",
)
})?;
Ok((slot, timestamp, parachain_inherent))
}
},
let params = BasicAuraParams {
create_inherent_data_providers: move |_, ()| async move { Ok(()) },
block_import,
para_client: client,
backoff_authoring_blocks: Option::<()>::None,
relay_client: relay_chain_interface,
sync_oracle,
keystore,
force_authoring,
collator_key,
para_id,
overseer_handle,
slot_duration,
// We got around 500ms for proposing
block_proposal_slot_portion: SlotProportion::new(1f32 / 24f32),
// And a maximum of 750ms if slots are skipped
max_block_proposal_slot_portion: Some(SlotProportion::new(1f32 / 16f32)),
telemetry,
},
))
relay_chain_slot_duration,
proposer,
collator_service,
// Very limited proposal time.
authoring_duration: Duration::from_millis(500),
};
let fut = basic_aura::run::<
Block,
sp_consensus_aura::sr25519::AuthorityPair,
_,
_,
_,
_,
_,
_,
_,
>(params);
task_manager.spawn_essential_handle().spawn("aura", None, fut);
Ok(())
},
hwbench,
)
@@ -109,6 +109,7 @@ async fn collect_relay_storage_proof(
relay_well_known_keys::hrmp_egress_channel_index(para_id),
relay_well_known_keys::upgrade_go_ahead_signal(para_id),
relay_well_known_keys::upgrade_restriction_signal(para_id),
relay_well_known_keys::para_head(para_id),
];
relevant_keys.extend(ingress_channels.into_iter().map(|sender| {
relay_well_known_keys::hrmp_channels(HrmpChannelId { sender, recipient: para_id })
-12
View File
@@ -17,18 +17,6 @@ sp-timestamp = { git = "https://github.com/paritytech/substrate", default-featur
# Cumulus
cumulus-primitives-core = { path = "../core", default-features = false }
[dev-dependencies]
# Substrate
sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" }
# Cumulus
cumulus-test-client = { path = "../../test/client" }
cumulus-test-relay-sproof-builder = { path = "../../test/relay-sproof-builder" }
[features]
default = [ "std" ]
std = [
-124
View File
@@ -68,127 +68,3 @@ impl InherentDataProvider {
inherent_data.put_data(INHERENT_IDENTIFIER, &data)
}
}
#[cfg(test)]
mod tests {
use super::*;
use codec::{Decode, Encode};
use cumulus_primitives_core::{relay_chain::Hash as PHash, PersistedValidationData};
use cumulus_test_client::{
runtime::{Block, Header, WASM_BINARY},
BlockData, BuildParachainBlockData, Client, ClientBlockImportExt, ExecutorResult, HeadData,
InitBlockBuilder, ParachainBlockData, TestClientBuilder, TestClientBuilderExt,
ValidationParams,
};
use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use std::{env, process::Command, str::FromStr};
const SLOT_DURATION: u64 = 6000;
fn call_validate_block(
parent_head: Header,
block_data: ParachainBlockData,
relay_parent_storage_root: PHash,
) -> ExecutorResult<Header> {
cumulus_test_client::validate_block(
ValidationParams {
block_data: BlockData(block_data.encode()),
parent_head: HeadData(parent_head.encode()),
relay_parent_number: 1,
relay_parent_storage_root,
},
WASM_BINARY.expect("You need to build the WASM binaries to run the tests!"),
)
.map(|v| Header::decode(&mut &v.head_data.0[..]).expect("Decodes `Header`."))
}
fn build_block(
client: &Client,
hash: <Block as BlockT>::Hash,
timestamp: u64,
relay_chain_slot: Slot,
) -> (ParachainBlockData, PHash) {
let sproof_builder =
RelayStateSproofBuilder { current_slot: relay_chain_slot, ..Default::default() };
let parent_header = client.header(hash).ok().flatten().expect("Genesis header exists");
let relay_parent_storage_root = sproof_builder.clone().into_state_root_and_proof().0;
let validation_data = PersistedValidationData {
relay_parent_number: 1,
parent_head: parent_header.encode().into(),
..Default::default()
};
let block = client
.init_block_builder_with_timestamp(
hash,
Some(validation_data),
sproof_builder,
timestamp,
)
.build_parachain_block(*parent_header.state_root());
(block, relay_parent_storage_root)
}
#[test]
fn check_timestamp_inherent_works() {
sp_tracing::try_init_simple();
let relay_chain_slot = 2;
if env::var("RUN_TEST").is_ok() {
let mut client = TestClientBuilder::default().build();
let timestamp = u64::from_str(&env::var("TIMESTAMP").expect("TIMESTAMP is set"))
.expect("TIMESTAMP is a valid `u64`");
let block =
build_block(&client, client.chain_info().genesis_hash, SLOT_DURATION, 1.into())
.0
.into_block();
futures::executor::block_on(
client.import(sp_consensus::BlockOrigin::Own, block.clone()),
)
.unwrap();
let hashof1 = block.hash();
let (block, relay_chain_root) =
build_block(&client, hashof1, timestamp, relay_chain_slot.into());
let header = call_validate_block(
client.header(hashof1).ok().flatten().expect("Genesis header exists"),
block.clone(),
relay_chain_root,
)
.expect("Calls validate block");
assert_eq!(block.header(), &header);
} else {
let slot_timestamp = relay_chain_slot * SLOT_DURATION;
for (timestamp, res) in &[
(slot_timestamp, true),
(slot_timestamp - 500, true),
(slot_timestamp + 500, true),
(slot_timestamp * 10, false),
] {
let output = Command::new(env::current_exe().unwrap())
.args(["check_timestamp_inherent_works", "--", "--nocapture"])
.env("RUN_TEST", "1")
.env("TIMESTAMP", timestamp.to_string())
.output()
.expect("Runs the test");
if !res {
assert!(String::from_utf8(output.stderr)
.unwrap()
.contains("Checking inherents failed"));
}
assert!(dbg!(output.status.success()) == *res);
}
}
}
}
+27 -3
View File
@@ -46,6 +46,7 @@ pub struct RelayStateSproofBuilder {
pub current_epoch: u64,
pub randomness: relay_chain::Hash,
pub additional_key_values: Vec<(Vec<u8>, Vec<u8>)>,
pub included_para_head: Option<relay_chain::HeadData>,
}
impl Default for RelayStateSproofBuilder {
@@ -73,6 +74,7 @@ impl Default for RelayStateSproofBuilder {
current_epoch: 0u64,
randomness: relay_chain::Hash::default(),
additional_key_values: vec![],
included_para_head: None,
}
}
}
@@ -90,9 +92,28 @@ impl RelayStateSproofBuilder {
in_index.insert(idx, sender);
}
self.hrmp_channels
.entry(relay_chain::HrmpChannelId { sender, recipient: self.para_id })
.or_insert_with(|| AbridgedHrmpChannel {
self.upsert_channel(relay_chain::HrmpChannelId { sender, recipient: self.para_id })
}
/// Returns a mutable reference to HRMP channel metadata for a channel (`self.para_id`,
/// `recipient`).
///
/// If there is no channel, a new default one is created.
///
/// It also updates the `hrmp_egress_channel_index`, creating it if needed.
pub fn upsert_outbound_channel(&mut self, recipient: ParaId) -> &mut AbridgedHrmpChannel {
let in_index = self.hrmp_egress_channel_index.get_or_insert_with(Vec::new);
if let Err(idx) = in_index.binary_search(&recipient) {
in_index.insert(idx, recipient);
}
self.upsert_channel(relay_chain::HrmpChannelId { sender: self.para_id, recipient })
}
/// Creates a new default entry in the hrmp channels mapping if not exists, and returns mutable
/// reference to it.
fn upsert_channel(&mut self, id: relay_chain::HrmpChannelId) -> &mut AbridgedHrmpChannel {
self.hrmp_channels.entry(id).or_insert_with(|| AbridgedHrmpChannel {
max_capacity: 0,
max_total_size: 0,
max_message_size: 0,
@@ -126,6 +147,9 @@ impl RelayStateSproofBuilder {
dmq_mqc_head.encode(),
);
}
if let Some(para_head) = self.included_para_head {
insert(relay_chain::well_known_keys::para_head(self.para_id), para_head.encode());
}
if let Some(relay_dispatch_queue_remaining_capacity) =
self.relay_dispatch_queue_remaining_capacity
{
@@ -8,7 +8,7 @@ build = "build.rs"
[dependencies]
# Polkadot
polkadot-node-core-pvf = { git = "https://github.com/paritytech/polkadot", branch = "master", features = ["test-utils"] }
polkadot-node-core-pvf = { git = "https://github.com/paritytech/polkadot", features = ["test-utils"] , branch = "master" }
[build-dependencies]
toml = "0.7.6"
+4 -4
View File
@@ -31,15 +31,16 @@ sp-transaction-pool = { git = "https://github.com/paritytech/substrate", default
sp-version = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
# Cumulus
cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system", default-features = false }
cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system", default-features = false, features = ["parameterized-consensus-hook",] }
cumulus-primitives-core = { path = "../../primitives/core", default-features = false }
cumulus-primitives-timestamp = { path = "../../primitives/timestamp", default-features = false }
[build-dependencies]
substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" , optional = true }
[features]
default = [ "std" ]
default = [
"std",
]
std = [
"codec/std",
"scale-info/std",
@@ -66,7 +67,6 @@ std = [
"sp-version/std",
"cumulus-pallet-parachain-system/std",
"cumulus-primitives-core/std",
"cumulus-primitives-timestamp/std",
"substrate-wasm-builder",
]
increment-spec-version = []

Some files were not shown because too many files have changed in this diff Show More