#
pezkuwi_sdk_docs/guides/
async_backing_guide.rs

    1//! # Upgrade Teyrchain for Asynchronous Backing Compatibility
    2//!
    3//! This guide is relevant for cumulus based teyrchain projects started in 2023 or before, whose
    4//! backing process is synchronous where parablocks can only be built on the latest Relay Chain
    5//! block. Async Backing allows collators to build parablocks on older Relay Chain blocks and create
    6//! pipelines of multiple pending parablocks. This parallel block generation increases efficiency
    7//! and throughput. For more information on Async backing and its terminology, refer to the document
    8//! on [the Pezkuwi SDK docs.](https://docs.pezkuwichain.io/sdk/master/pezkuwi_sdk_docs/guides/async_backing_guide/index.html)
    9//!
    10//! > If starting a new teyrchain project, please use an async backing compatible template such as
    11//! > the
    12//! > [teyrchain template](https://github.com/pezkuwichain/pezkuwi-sdk/tree/master/templates/teyrchain).
    13//! The rollout process for Async Backing has three phases. Phases 1 and 2 below put new
    14//! infrastructure in place. Then we can simply turn on async backing in phase 3.
    15//!
    16//! ## Prerequisite
    17//!
    18//! The relay chain needs to have async backing enabled so double-check that the relay-chain
    19//! configuration contains the following three parameters (especially when testing locally e.g. with
    20//! zombienet):
    21//!
    22//! ```json
    23//! "async_backing_params": {
    24//!     "max_candidate_depth": 3,
    25//!     "allowed_ancestry_len": 2
    26//! },
    27//! "scheduling_lookahead": 2
    28//! ```
    29//!
    30//! <div class="warning"><code>scheduling_lookahead</code> must be set to 2, otherwise teyrchain
    31//! block times will degrade to worse than with sync backing!</div>
    32//!
    33//! ## Phase 1 - Update Teyrchain Runtime
    34//!
    35//! This phase involves configuring your teyrchain’s runtime `/runtime/src/lib.rs` to make use of
    36//! async backing system.
    37//!
    38//! 1. Establish and ensure constants for `capacity` and `velocity` are both set to 1 in the
    39//!    runtime.
    40//! 2. Establish and ensure the constant relay chain slot duration measured in milliseconds equal to
    41//!    `6000` in the runtime.
    42//! ```rust
    43//! // Maximum number of blocks simultaneously accepted by the Runtime, not yet included into the
    44//! // relay chain.
    45//! pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1;
    46//! // How many teyrchain blocks are processed by the relay chain per parent. Limits the number of
    47//! // blocks authored per slot.
    48//! pub const BLOCK_PROCESSING_VELOCITY: u32 = 1;
    49//! // Relay chain slot duration, in milliseconds.
    50//! pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
    51//! ```
    52//!
    53//! 3. Establish constants `MILLISECS_PER_BLOCK` and `SLOT_DURATION` if not already present in the
    54//!    runtime.
    55//! ```ignore
    56//! // `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked
    57//! // up by `pallet_aura` to implement `fn slot_duration()`.
    58//! //
    59//! // Change this to adjust the block time.
    60//! pub const MILLISECS_PER_BLOCK: u64 = 12000;
    61//! pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
    62//! ```
    63//!
    64//! 4. Configure `cumulus_pallet_teyrchain_system` in the runtime.
    65//!
    66//! - Define a `FixedVelocityConsensusHook` using our capacity, velocity, and relay slot duration
    67//! constants. Use this to set the teyrchain system `ConsensusHook` property.
    68#![doc = docify::embed!("../../templates/teyrchain/runtime/src/lib.rs", ConsensusHook)]
    69//! ```ignore
    70//! impl cumulus_pallet_teyrchain_system::Config for Runtime {
    71//!     ..
    72//!     type ConsensusHook = ConsensusHook;
    73//!     ..
    74//! }
    75//! ```
    76//! - Set the teyrchain system property `CheckAssociatedRelayNumber` to
    77//! `RelayNumberMonotonicallyIncreases`
    78//! ```ignore
    79//! impl cumulus_pallet_teyrchain_system::Config for Runtime {
    80//! 	..
    81//! 	type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases;
    82//! 	..
    83//! }
    84//! ```
    85//!
    86//! 5. Configure `pallet_aura` in the runtime.
    87//!
    88//! - Set `AllowMultipleBlocksPerSlot` to `false` (don't worry, we will set it to `true` when we
    89//! activate async backing in phase 3).
    90//!
    91//! - Define `pallet_aura::SlotDuration` using our constant `SLOT_DURATION`
    92//! ```ignore
    93//! impl pallet_aura::Config for Runtime {
    94//! 	..
    95//! 	type AllowMultipleBlocksPerSlot = ConstBool<false>;
    96//! 	#[cfg(feature = "experimental")]
    97//! 	type SlotDuration = ConstU64<SLOT_DURATION>;
    98//! 	..
    99//! }
    100//! ```
    101//!
    102//! 6. Update `sp_consensus_aura::AuraApi::slot_duration` in `sp_api::impl_runtime_apis` to match
    103//!    the constant `SLOT_DURATION`
    104#![doc = docify::embed!("../../templates/teyrchain/runtime/src/apis.rs", impl_slot_duration)]
    105//!
    106//! 7. Implement the `AuraUnincludedSegmentApi`, which allows the collator client to query its
    107//!    runtime to determine whether it should author a block.
    108//!
    109//!    - Add the dependency `cumulus-primitives-aura` to the `runtime/Cargo.toml` file for your
    110//!      runtime
    111//! ```ignore
    112//! ..
    113//! cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false }
    114//! ..
    115//! ```
    116//!
    117//! - In the same file, add `"cumulus-primitives-aura/std",` to the `std` feature.
    118//!
    119//! - Inside the `impl_runtime_apis!` block for your runtime, implement the
    120//!   `cumulus_primitives_aura::AuraUnincludedSegmentApi` as shown below.
    121#![doc = docify::embed!("../../templates/teyrchain/runtime/src/apis.rs", impl_can_build_upon)]
    122//!
    123//! **Note:** With a capacity of 1 we have an effective velocity of ½ even when velocity is
    124//! configured to some larger value. This is because capacity will be filled after a single block is
    125//! produced and will only be freed up after that block is included on the relay chain, which takes
    126//! 2 relay blocks to accomplish. Thus with capacity 1 and velocity 1 we get the customary 12 second
    127//! teyrchain block time.
    128//!
    129//! 8. If your `runtime/src/lib.rs` provides a `CheckInherents` type to `register_validate_block`,
    130//!    remove it. `FixedVelocityConsensusHook` makes it unnecessary. The following example shows how
    131//!    `register_validate_block` should look after removing `CheckInherents`.
    132#![doc = docify::embed!("../../templates/teyrchain/runtime/src/lib.rs", register_validate_block)]
    133//!
    134//!
    135//! ## Phase 2 - Update Teyrchain Nodes
    136//!
    137//! This phase consists of plugging in the new lookahead collator node.
    138//!
    139//! 1. Import `cumulus_primitives_core::ValidationCode` to `node/src/service.rs`.
    140#![doc = docify::embed!("../../templates/teyrchain/node/src/service.rs", cumulus_primitives)]
    141//!
    142//! 2. In `node/src/service.rs`, modify `sc_service::spawn_tasks` to use a clone of `Backend` rather
    143//!    than the original
    144//! ```ignore
    145//! sc_service::spawn_tasks(sc_service::SpawnTasksParams {
    146//!     ..
    147//!     backend: backend.clone(),
    148//!     ..
    149//! })?;
    150//! ```
    151//!
    152//! 3. Add `backend` as a parameter to `start_consensus()` in `node/src/service.rs`
    153//! ```text
    154//! fn start_consensus(
    155//!     ..
    156//!     backend: Arc<TeyrchainBackend>,
    157//!     ..
    158//! ```
    159//! ```ignore
    160//! if validator {
    161//!   start_consensus(
    162//!     ..
    163//!     backend.clone(),
    164//!     ..
    165//!    )?;
    166//! }
    167//! ```
    168//!
    169//! 4. In `node/src/service.rs` import the lookahead collator rather than the basic collator
    170#![doc = docify::embed!("../../templates/teyrchain/node/src/service.rs", lookahead_collator)]
    171//!
    172//! 5. In `start_consensus()` replace the `BasicAuraParams` struct with `AuraParams`
    173//!    - Change the struct type from `BasicAuraParams` to `AuraParams`
    174//!    - In the `para_client` field, pass in a cloned para client rather than the original
    175//!    - Add a `para_backend` parameter after `para_client`, passing in our para backend
    176//!    - Provide a `code_hash_provider` closure like that shown below
    177//!    - Increase `authoring_duration` from 500 milliseconds to 2000
    178//! ```ignore
    179//! let params = AuraParams {
    180//!     ..
    181//!     para_client: client.clone(),
    182//!     para_backend: backend.clone(),
    183//!     ..
    184//!     code_hash_provider: move |block_hash| {
    185//!         client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash())
    186//!     },
    187//!     ..
    188//!     authoring_duration: Duration::from_millis(2000),
    189//!     ..
    190//! };
    191//! ```
    192//!
    193//! **Note:** Set `authoring_duration` to whatever you want, taking your own hardware into account.
    194//! But if the backer who should be slower than you due to reading from disk, times out at two
    195//! seconds your candidates will be rejected.
    196//!
    197//! 6. In `start_consensus()` replace `basic_aura::run` with `aura::run`
    198//! ```ignore
    199//! let fut =
    200//! aura::run::<Block, sp_consensus_aura::sr25519::AuthorityPair, _, _, _, _, _, _, _, _, _>(
    201//!    params,
    202//! );
    203//! task_manager.spawn_essential_handle().spawn("aura", None, fut);
    204//! ```
    205//!
    206//! ## Phase 3 - Activate Async Backing
    207//!
    208//! This phase consists of changes to your teyrchain’s runtime that activate async backing feature.
    209//!
    210//! 1. Configure `pallet_aura`, setting `AllowMultipleBlocksPerSlot` to true in
    211//!    `runtime/src/lib.rs`.
    212#![doc = docify::embed!("../../templates/teyrchain/runtime/src/configs/mod.rs", aura_config)]
    213//!
    214//! 2. Increase the maximum `UNINCLUDED_SEGMENT_CAPACITY` in `runtime/src/lib.rs`.
    215#![doc = docify::embed!("../../templates/teyrchain/runtime/src/lib.rs", async_backing_params)]
    216//!
    217//! 3. Decrease `MILLISECS_PER_BLOCK` to 6000.
    218//!
    219//! - Note: For a teyrchain which measures time in terms of its own block number rather than by
    220//!   relay block number it may be preferable to increase velocity. Changing block time may cause
    221//!   complications, requiring additional changes. See the section “Timing by Block Number”.
    222#![doc = docify::embed!("../../templates/teyrchain/runtime/src/lib.rs", block_times)]
    223//!
    224//! 4. Update `MAXIMUM_BLOCK_WEIGHT` to reflect the increased time available for block production.
    225#![doc = docify::embed!("../../templates/teyrchain/runtime/src/lib.rs", max_block_weight)]
    226//!
    227//! 5. Add a feature flagged alternative for `MinimumPeriod` in `pallet_timestamp`. The type should
    228//!    be `ConstU64<0>` with the feature flag experimental, and `ConstU64<{SLOT_DURATION / 2}>`
    229//!    without.
    230//! ```ignore
    231//! impl pallet_timestamp::Config for Runtime {
    232//!     ..
    233//!     #[cfg(feature = "experimental")]
    234//!     type MinimumPeriod = ConstU64<0>;
    235//!     #[cfg(not(feature = "experimental"))]
    236//!     type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>;
    237//!     ..
    238//! }
    239//! ```
    240//!
    241//! ## Timing by Block Number
    242//!
    243//! With asynchronous backing it will be possible for teyrchains to opt for a block time of 6
    244//! seconds rather than 12 seconds. But modifying block duration isn’t so simple for a teyrchain
    245//! which was measuring time in terms of its own block number. It could result in expected and
    246//! actual time not matching up, stalling the teyrchain.
    247//!
    248//! One strategy to deal with this issue is to instead rely on relay chain block numbers for timing.
    249//! Relay block number is kept track of by each teyrchain in `pallet-teyrchain-system` with the
    250//! storage value `LastRelayChainBlockNumber`. This value can be obtained and used wherever timing
    251//! based on block number is needed.
    252
    253#![deny(rustdoc::broken_intra_doc_links)]
    254#![deny(rustdoc::private_intra_doc_links)]