polkadot_sdk_docs/guides/enable_elastic_scaling.rs
1//! # Enable elastic scaling for a parachain
2//!
3//! <div class="warning">This guide assumes full familiarity with Asynchronous Backing and its
4//! terminology, as defined in <a href="https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/guides/async_backing_guide/index.html">the Polkadot SDK Docs</a>.
5//! </div>
6//!
7//! ## Quick introduction to Elastic Scaling
8//!
9//! [Elastic scaling](https://www.parity.io/blog/polkadot-web3-cloud) is a feature that enables parachains (rollups) to use multiple cores.
10//! Parachains can adjust their usage of core resources on the fly to increase TPS and decrease
11//! latency.
12//!
13//! ### When do you need Elastic Scaling?
14//!
15//! Depending on their use case, applications might have an increased need for the following:
16//! - compute (CPU weight)
17//! - bandwidth (proof size)
18//! - lower latency (block time)
19//!
20//! ### High throughput (TPS) and lower latency
21//!
22//! If the main bottleneck is the CPU, then your parachain needs to maximize the compute usage of
23//! each core while also achieving a lower latency.
24//! 3 cores provide the best balance between CPU, bandwidth and latency: up to 6s of execution,
25//! 5MB/s of DA bandwidth and fast block time of just 2 seconds.
26//!
27//! ### High bandwidth
28//!
29//! Useful for applications that are bottlenecked by bandwidth.
30//! By using 6 cores, applications can make use of up to 6s of compute, 10MB/s of bandwidth
31//! while also achieving 1 second block times.
32//!
33//! ### Ultra low latency
34//!
35//! When latency is the primary requirement, Elastic scaling is currently the only solution. The
36//! caveat is the efficiency of core time usage decreases as more cores are used.
37//!
38//! For example, using 12 cores enables fast transaction confirmations with 500ms blocks and up to
39//! 20 MB/s of DA bandwidth.
40//!
41//! ## Dependencies
42//!
43//! Prerequisites: Polkadot-SDK `2509` or newer.
44//!
45//! To ensure the security and reliability of your chain when using this feature you need the
46//! following:
47//! - An omni-node based collator. This has already become the default choice for collators.
48//! - UMP signal support.
49//! [RFC103](https://github.com/polkadot-fellows/RFCs/blob/main/text/0103-introduce-core-index-commitment.md).
50//! This is mandatory protection against PoV replay attacks.
51//! - Enabling the relay parent offset feature. This is required to ensure the parachain block times
52//! and transaction in-block confidence are not negatively affected by relay chain forks. Read
53//! [`crate::guides::handling_parachain_forks`] for more information.
54//! - Block production configuration adjustments.
55//!
56//! ### Upgrade to Polkadot Omni node
57//!
58//! Your collators need to run `polkadot-parachain` or `polkadot-omni-node` with the `--authoring
59//! slot-based` CLI argument.
60//! To avoid potential issues and get best performance it is recommeneded to always run the
61//! latest release on all of the collators.
62//!
63//! Further information about omni-node and how to upgrade is available:
64//! - [high level docs](https://docs.polkadot.com/develop/toolkit/parachains/polkadot-omni-node/)
65//! - [`crate::reference_docs::omni_node`]
66//!
67//! ### Enable UMP signals
68//!
69//! The only required change for the runtime is enabling the `experimental-ump-signals` feature of
70//! the `parachain-system` pallet:
71//! `cumulus-pallet-parachain-system = { workspace = true, features = ["experimental-ump-signals"]
72//! }`
73//!
74//! You can find more technical details about UMP signals and their usage for elastic scaling
75//! [here](https://github.com/polkadot-fellows/RFCs/blob/main/text/0103-introduce-core-index-commitment.md).
76//!
77//! ### Enable the relay parent offset feature
78//!
79//! It is recommended to use an offset of `1`, which is sufficient to eliminate any issues
80//! with relay chain forks.
81//!
82//! Configure the relay parent offset like this:
83//! ```ignore
84//! /// Build with an offset of 1 behind the relay chain best block.
85//! const RELAY_PARENT_OFFSET: u32 = 1;
86//!
87//! impl cumulus_pallet_parachain_system::Config for Runtime {
88//! // ...
89//! type RelayParentOffset = ConstU32<RELAY_PARENT_OFFSET>;
90//! }
91//! ```
92//!
93//! Implement the runtime API to retrieve the offset on the client side.
94//! ```ignore
95//! impl cumulus_primitives_core::RelayParentOffsetApi<Block> for Runtime {
96//! fn relay_parent_offset() -> u32 {
97//! RELAY_PARENT_OFFSET
98//! }
99//! }
100//! ```
101//!
102//! ### Block production configuration
103//!
104//! This configuration directly controls the minimum block time and maximum number of cores
105//! the parachain can use.
106//!
107//! Example configuration for a 3 core parachain:
108//! ```ignore
109//! /// The upper limit of how many parachain blocks are processed by the relay chain per
110//! /// parent. Limits the number of blocks authored per slot. This determines the minimum
111//! /// block time of the parachain:
112//! /// `RELAY_CHAIN_SLOT_DURATION_MILLIS/BLOCK_PROCESSING_VELOCITY`
113//! const BLOCK_PROCESSING_VELOCITY: u32 = 3;
114//!
115//! /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included
116//! /// into the relay chain.
117//! const UNINCLUDED_SEGMENT_CAPACITY: u32 = (2 + RELAY_PARENT_OFFSET) *
118//! BLOCK_PROCESSING_VELOCITY + 1;
119//!
120//! /// Relay chain slot duration, in milliseconds.
121//! const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
122//!
123//! type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook<
124//! Runtime,
125//! RELAY_CHAIN_SLOT_DURATION_MILLIS,
126//! BLOCK_PROCESSING_VELOCITY,
127//! UNINCLUDED_SEGMENT_CAPACITY,
128//! >;
129//!
130//! ```
131//!
132//! ## Current limitations
133//!
134//! ### Maximum execution time per relay chain block.
135//!
136//! Since parachain block authoring is sequential, the next block can only be built after
137//! the previous one has been imported.
138//! At present, a core allows up to 2 seconds of execution per relay chain block.
139//!
140//! If we assume a 6s parachain slot, and each block takes the full 2 seconds to execute,
141//! the parachain will not be able to fully utilize the compute resources of all 3 cores.
142//!
143//! If the collator hardware is faster, it can author and import full blocks more quickly,
144//! making it possible to utilize even more than 3 cores efficiently.
145//!
146//! #### Why?
147//!
148//! Within a 6-second parachain slot, collators can author multiple parachain blocks.
149//! Before building the first block in a slot, the new block author must import the last
150//! block produced by the previous author.
151//! If the import of the last block is not completed before the next relay chain slot starts,
152//! the new author will build on its parent (assuming it was imported). This will create a fork
153//! which degrades the parachain block confidence and block times.
154//!
155//! This means that, on reference hardware, a parachain with a slot time of 6s can
156//! effectively utilize up to 4 seconds of execution per relay chain block, because it needs to
157//! ensure the next block author has enough time to import the last block.
158//! Hardware with higher single-core performance can enable a parachain to fully utilize more
159//! cores.
160//!
161//! ### Fixed factor scaling.
162//!
163//! For true elasticity, a parachain needs to acquire more cores when needed in an automated
164//! manner. This functionality is not yet available in the SDK, thus acquiring additional
165//! on-demand or bulk cores has to be managed externally.