@@ -28,6 +28,7 @@ Doc-Page: https://docs.polkadot.com/develop/parachains/deployment/obtain-coretim
2828Doc-Page: https://docs.polkadot.com/develop/parachains/
2929Doc-Page: https://docs.polkadot.com/develop/parachains/install-polkadot-sdk/
3030Doc-Page: https://docs.polkadot.com/develop/parachains/intro-polkadot-sdk/
31+ Doc-Page: https://docs.polkadot.com/develop/parachains/maintenance/asynchronous-backing/
3132Doc-Page: https://docs.polkadot.com/develop/parachains/maintenance/
3233Doc-Page: https://docs.polkadot.com/develop/parachains/maintenance/runtime-metrics-monitoring/
3334Doc-Page: https://docs.polkadot.com/develop/parachains/maintenance/runtime-upgrades/
@@ -5382,6 +5383,355 @@ graph LR
53825383Each stage is covered in detail in its respective guide, walking you through the process from initial setup to final deployment.
53835384--- END CONTENT ---
53845385
5386+ Doc-Content: https://docs.polkadot.com/develop/parachains/maintenance/asynchronous-backing/
5387+ --- BEGIN CONTENT ---
5388+ ---
5389+ title: Asynchronous Backing
5390+ description: Learn how to increase the efficiency and throughput of your parachain by upgrading it to leverage asynchronous backing.
5391+ ---
5392+
5393+ # Upgrade Parachain for Asynchronous Backing Compatibility
5394+
5395+ ## Introduction
5396+
5397+ This guide is relevant for Cumulus based parachain projects started in 2023 or before, whose
5398+ backing process is synchronous where parablocks can only be built on the latest relay chain
5399+ block. Async backing allows collators to build parablocks on older relay chain blocks and create
5400+ pipelines of multiple pending parablocks. This parallel block generation increases efficiency
5401+ and throughput.
5402+
5403+ !!!note
5404+ If starting a new parachain project, please use an async backing compatible template such as
5405+ the [parachain template](https://github.com/paritytech/polkadot-sdk-parachain-template).
5406+ The rollout process for async backing has three phases. Phases 1 and 2 below put new
5407+ infrastructure in place. Then we can simply turn on async backing in phase 3.
5408+
5409+ ## Prerequisite
5410+
5411+ The relay chain needs to have async backing enabled so double-check that the relay chain
5412+ configuration contains the following three parameters (especially when testing locally e.g. with
5413+ zombienet):
5414+
5415+ ```json
5416+ "async_backing_params": {
5417+ "max_candidate_depth": 3,
5418+ "allowed_ancestry_len": 2
5419+ },
5420+ "scheduling_lookahead": 2
5421+ ```
5422+
5423+ !!! warning
5424+ `scheduling_lookahead` must be set to 2, otherwise parachain
5425+ block times will degrade to worse than with sync backing!
5426+
5427+ ## Phase 1 - Update Parachain Runtime
5428+
5429+ This phase involves configuring your parachain's runtime `/runtime/src/lib.rs` to make use of
5430+ async backing system.
5431+
5432+ 1. Establish and ensure constants for `capacity` and `velocity` are both set to 1 in the
5433+ runtime.
5434+ 2. Establish and ensure the constant relay chain slot duration measured in milliseconds equal to
5435+ `6000` in the runtime.
5436+ ```rust
5437+ // Maximum number of blocks simultaneously accepted by the Runtime, not yet included into the
5438+ // relay chain.
5439+ pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1;
5440+ // How many parachain blocks are processed by the relay chain per parent. Limits the number of
5441+ // blocks authored per slot.
5442+ pub const BLOCK_PROCESSING_VELOCITY: u32 = 1;
5443+ // Relay chain slot duration, in milliseconds.
5444+ pub const RELAY_chain_SLOT_DURATION_MILLIS: u32 = 6000;
5445+ ```
5446+
5447+ 3. Establish constants `MILLISECS_PER_BLOCK` and `SLOT_DURATION` if not already present in the
5448+ runtime.
5449+ ```rust
5450+ // `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked
5451+ // up by `pallet_aura` to implement `fn slot_duration()`.
5452+ //
5453+ // Change this to adjust the block time.
5454+ pub const MILLISECS_PER_BLOCK: u64 = 12000;
5455+ pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
5456+ ```
5457+
5458+ 4. Configure `cumulus_pallet_parachain_system` in the runtime.
5459+
5460+ Define a `FixedVelocityConsensusHook` using our capacity, velocity, and relay slot duration
5461+ constants. Use this to set the parachain system `ConsensusHook` property.
5462+
5463+ ```rust
5464+ type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook<
5465+ Runtime,
5466+ RELAY_CHAIN_SLOT_DURATION_MILLIS,
5467+ BLOCK_PROCESSING_VELOCITY,
5468+ UNINCLUDED_SEGMENT_CAPACITY,
5469+ >;
5470+ ```
5471+
5472+ ```rust
5473+ impl cumulus_pallet_parachain_system::Config for Runtime {
5474+ ..
5475+ type ConsensusHook = ConsensusHook;
5476+ ..
5477+ }
5478+ ```
5479+
5480+ Set the parachain system property `CheckAssociatedRelayNumber` to
5481+ `RelayNumberMonotonicallyIncreases`
5482+ ```rust
5483+ impl cumulus_pallet_parachain_system::Config for Runtime {
5484+ ..
5485+ type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases;
5486+ ..
5487+ }
5488+ ```
5489+
5490+ 5. Configure `pallet_aura` in the runtime.
5491+
5492+ Set `AllowMultipleBlocksPerSlot` to `false` (don't worry, we will set it to `true` when we
5493+ activate async backing in phase 3).
5494+
5495+ Define `pallet_aura::SlotDuration` using our constant `SLOT_DURATION`
5496+
5497+ ```rust
5498+ impl pallet_aura::Config for Runtime {
5499+ ..
5500+ type AllowMultipleBlocksPerSlot = ConstBool<false>;
5501+ #[cfg(feature = "experimental")]
5502+ type SlotDuration = ConstU64<SLOT_DURATION>;
5503+ ..
5504+ }
5505+ ```
5506+
5507+ 6. Update `sp_consensus_aura::AuraApi::slot_duration` in `sp_api::impl_runtime_apis` to match
5508+ the constant `SLOT_DURATION`
5509+
5510+ ```rust
5511+ fn impl_slot_duration() -> sp_consensus_aura::SlotDuration {
5512+ sp_consensus_aura::SlotDuration::from_millis(SLOT_DURATION)
5513+ }
5514+ ```
5515+
5516+ 7. Implement the `AuraUnincludedSegmentApi`, which allows the collator client to query its
5517+ runtime to determine whether it should author a block.
5518+
5519+ - Add the dependency `cumulus-primitives-aura` to the `runtime/Cargo.toml` file for your
5520+ runtime
5521+
5522+ ```rust
5523+ ..
5524+ cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false }
5525+ ..
5526+ ```
5527+
5528+ In the same file, add `"cumulus-primitives-aura/std",` to the `std` feature.
5529+
5530+ Inside the `impl_runtime_apis!` block for your runtime, implement the
5531+ `cumulus_primitives_aura::AuraUnincludedSegmentApi` as shown below.
5532+
5533+ ```rust
5534+ fn impl_can_build_upon(
5535+ included_hash: <Block as BlockT>::Hash,
5536+ slot: cumulus_primitives_aura::Slot,
5537+ ) -> bool {
5538+ ConsensusHook::can_build_upon(included_hash, slot)
5539+ }
5540+ ```
5541+
5542+ !!!note
5543+ With a capacity of 1 we have an effective velocity of ½ even when velocity is
5544+ configured to some larger value. This is because capacity will be filled after a single block is
5545+ produced and will only be freed up after that block is included on the relay chain, which takes
5546+ 2 relay blocks to accomplish. Thus with capacity 1 and velocity 1 we get the customary 12 second
5547+ parachain block time.
5548+
5549+ 8. If your `runtime/src/lib.rs` provides a `CheckInherents` type to `register_validate_block`,
5550+ remove it. `FixedVelocityConsensusHook` makes it unnecessary. The following example shows how
5551+ `register_validate_block` should look after removing `CheckInherents`.
5552+
5553+ ```rust
5554+ cumulus_pallet_parachain_system::register_validate_block! {
5555+ Runtime = Runtime,
5556+ BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
5557+ }
5558+ ```
5559+
5560+ ## Phase 2 - Update Parachain Nodes
5561+
5562+ This phase consists of plugging in the new lookahead collator node.
5563+
5564+ 1. Import `cumulus_primitives_core::ValidationCode` to `node/src/service.rs`.
5565+
5566+ ```rust
5567+ use cumulus_primitives_core::{
5568+ relay_chain::{CollatorPair, ValidationCode},
5569+ GetParachainInfo, ParaId,
5570+ };
5571+ ```
5572+
5573+ 2. In `node/src/service.rs`, modify `sc_service::spawn_tasks` to use a clone of `Backend` rather
5574+ than the original
5575+
5576+ ```rust
5577+ sc_service::spawn_tasks(sc_service::SpawnTasksParams {
5578+ ..
5579+ backend: backend.clone(),
5580+ ..
5581+ })?;
5582+ ```
5583+
5584+ 3. Add `backend` as a parameter to `start_consensus()` in `node/src/service.rs`
5585+
5586+ ```rust
5587+ fn start_consensus(
5588+ ..
5589+ backend: Arc<ParachainBackend>,
5590+ ..
5591+ ```
5592+ ```rust
5593+ if validator {
5594+ start_consensus(
5595+ ..
5596+ backend.clone(),
5597+ ..
5598+ )?;
5599+ }
5600+ ```
5601+
5602+ 4. In `node/src/service.rs` import the lookahead collator rather than the basic collator
5603+
5604+ ```rust
5605+ use cumulus_client_consensus_aura::collators::lookahead::{self as aura, Params as AuraParams};
5606+ ```
5607+
5608+ 5. In `start_consensus()` replace the `BasicAuraParams` struct with `AuraParams`
5609+ - Change the struct type from `BasicAuraParams` to `AuraParams`
5610+ - In the `para_client` field, pass in a cloned para client rather than the original
5611+ - Add a `para_backend` parameter after `para_client`, passing in our para backend
5612+ - Provide a `code_hash_provider` closure like that shown below
5613+ - Increase `authoring_duration` from 500 milliseconds to 2000
5614+ ```rust
5615+ let params = AuraParams {
5616+ ..
5617+ para_client: client.clone(),
5618+ para_backend: backend.clone(),
5619+ ..
5620+ code_hash_provider: move |block_hash| {
5621+ client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash())
5622+ },
5623+ ..
5624+ authoring_duration: Duration::from_millis(2000),
5625+ ..
5626+ };
5627+ ```
5628+
5629+ !!!note
5630+ Set `authoring_duration` to whatever you want, taking your own hardware into account.
5631+ But if the backer who should be slower than you due to reading from disk, times out at two
5632+ seconds your candidates will be rejected.
5633+
5634+ 6. In `start_consensus()` replace `basic_aura::run` with `aura::run`
5635+ ```rust
5636+ let fut =
5637+ aura::run::<Block, sp_consensus_aura::sr25519::AuthorityPair, _, _, _, _, _, _, _, _, _>(
5638+ params,
5639+ );
5640+ task_manager.spawn_essential_handle().spawn("aura", None, fut);
5641+ ```
5642+
5643+ ## Phase 3 - Activate Async Backing
5644+
5645+ This phase consists of changes to your parachain's runtime that activate async backing feature.
5646+
5647+ 1. Configure `pallet_aura`, setting `AllowMultipleBlocksPerSlot` to true in
5648+ `runtime/src/lib.rs`.
5649+
5650+ ```rust
5651+ impl pallet_aura::Config for Runtime {
5652+ type AuthorityId = AuraId;
5653+ type DisabledValidators = ();
5654+ type MaxAuthorities = ConstU32<100_000>;
5655+ type AllowMultipleBlocksPerSlot = ConstBool<true>;
5656+ type SlotDuration = ConstU64<SLOT_DURATION>;
5657+ }
5658+ ```
5659+
5660+ 2. Increase the maximum `UNINCLUDED_SEGMENT_CAPACITY` in `runtime/src/lib.rs`.
5661+
5662+ ```rust
5663+ mod async_backing_params {
5664+ /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included
5665+ /// into the relay chain.
5666+ pub(crate) const UNINCLUDED_SEGMENT_CAPACITY: u32 = 3;
5667+ /// How many parachain blocks are processed by the relay chain per parent. Limits the
5668+ /// number of blocks authored per slot.
5669+ pub(crate) const BLOCK_PROCESSING_VELOCITY: u32 = 1;
5670+ /// Relay chain slot duration, in milliseconds.
5671+ pub(crate) const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
5672+ }
5673+ ```
5674+
5675+ 3. Decrease `MILLISECS_PER_BLOCK` to 6000.
5676+
5677+ !!!note
5678+ For a parachain which measures time in terms of its own block number rather than by relay block
5679+ number it may be preferable to increase velocity. Changing block time may cause complications,
5680+ requiring additional changes. See the section "Timing by Block Number".
5681+
5682+ ```rust
5683+ mod block_times {
5684+ /// This determines the average expected block time that we are targeting. Blocks will be
5685+ /// produced at a minimum duration defined by `SLOT_DURATION`. `SLOT_DURATION` is picked up by
5686+ /// `pallet_timestamp` which is in turn picked up by `pallet_aura` to implement `fn
5687+ /// slot_duration()`.
5688+ ///
5689+ /// Change this to adjust the block time.
5690+ pub const MILLI_SECS_PER_BLOCK: u64 = 6000;
5691+
5692+ // NOTE: Currently it is not possible to change the slot duration after the chain has started.
5693+ // Attempting to do so will brick block production.
5694+ pub const SLOT_DURATION: u64 = MILLI_SECS_PER_BLOCK;
5695+ }
5696+ ```
5697+
5698+ 4. Update `MAXIMUM_BLOCK_WEIGHT` to reflect the increased time available for block production.
5699+
5700+ ```rust
5701+ const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(
5702+ WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2),
5703+ cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64,
5704+ );
5705+ ```
5706+
5707+ 5. Add a feature flagged alternative for `MinimumPeriod` in `pallet_timestamp`. The type should
5708+ be `ConstU64<0>` with the feature flag experimental, and `ConstU64<{SLOT_DURATION / 2}>`
5709+ without.
5710+
5711+ ```rust
5712+ impl pallet_timestamp::Config for Runtime {
5713+ ..
5714+ #[cfg(feature = "experimental")]
5715+ type MinimumPeriod = ConstU64<0>;
5716+ #[cfg(not(feature = "experimental"))]
5717+ type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>;
5718+ ..
5719+ }
5720+ ```
5721+
5722+ ## Timing by Block Number
5723+
5724+ With asynchronous backing it will be possible for parachains to opt for a block time of 6
5725+ seconds rather than 12 seconds. But modifying block duration isn't so simple for a parachain
5726+ which was measuring time in terms of its own block number. It could result in expected and
5727+ actual time not matching up, stalling the parachain.
5728+
5729+ One strategy to deal with this issue is to instead rely on relay chain block numbers for timing.
5730+ Relay block number is kept track of by each parachain in `pallet-parachain-system` with the
5731+ storage value `LastRelaychainBlockNumber`. This value can be obtained and used wherever timing
5732+ based on block number is needed.
5733+ --- END CONTENT ---
5734+
53855735Doc-Content: https://docs.polkadot.com/develop/parachains/maintenance/
53865736--- BEGIN CONTENT ---
53875737---
0 commit comments