|
1 | | -TODO |
| 1 | +--- |
| 2 | +title: Asynchronous Backing |
| 3 | +description: Understand how asynchronous backing pipelines parachain block production, the protocol changes it introduces on the Relay Chain, and how parachains participate safely and efficiently. |
| 4 | +categories: Polkadot Protocol |
| 5 | +--- |
| 6 | + |
| 7 | +# Asynchronous Backing |
| 8 | + |
| 9 | +## Introduction |
| 10 | + |
| 11 | +Parachain blocks secured by the Polkadot relay chain are processed through a mulit-step pipeline called the [Inclusion Pipeline](#inclusion-pipeline). |
| 12 | + |
| 13 | +Asynchronous backing (often shortened to **_Async Backing_**) decouples the steps of this pipeline which enables parallel processing. Specifically, it allows for the generation and backing steps to kick off for a given parablock *before its parent block completes the pipeline*. |
| 14 | + |
| 15 | +The introduction of this technique improves throughput of the Polkadot network and lays the foundation for many blocks of the same parachain to be processed in parallel via [Elastic Scaling](/reference/parachains/consensus/elastic-scaling){target=\_blank}. |
| 16 | + |
| 17 | +## How Async Backing Works |
| 18 | + |
| 19 | +Before diving into *asynchronous* backing, it is helpful to first review each component of the pipeline. |
| 20 | + |
| 21 | +### Inclusion Pipeline |
| 22 | + |
| 23 | +```mermaid |
| 24 | +%%{init: {"flowchart": {"nodeSpacing": 40, "rankSpacing": 60}}}%% |
| 25 | +flowchart LR |
| 26 | + %% Keep the pipeline on one row (container is hidden) |
| 27 | + subgraph Row[" "] |
| 28 | + direction LR |
| 29 | + G["Generation"] --> B["Backing"] --> I["Inclusion"] |
| 30 | + end |
| 31 | + style Row fill:none,stroke:none |
| 32 | +
|
| 33 | + %% Context: plain text (no box) pointing to both G and B |
| 34 | + C["Context"]:::nobox |
| 35 | + C -.-> G |
| 36 | + C -.-> B |
| 37 | +
|
| 38 | + classDef nobox fill:none,stroke:none,color:inherit; |
| 39 | +``` |
| 40 | +**Context**: Context of state is provided as input in order for collators and validators to build a parablock during the generation and backing stages, respectively. This context is provided by two sources: |
| 41 | + |
| 42 | +* **Relay Parent**: The relay chain block which a given parablock is anchored to. Note that the relay parent of a parablock and the relay block including that parablock are always different. This context source lives on the relay chain. |
| 43 | + |
| 44 | +* **Unincluded Segments**: Chains of candidate parablocks that have yet to be included in the relay chain, i.e. they can contain parablocks at any stage pre-inclusion. The core functionality that asynchronous backing brings is the ability to build on these unincluded segments of block ancestors rather than building only on ancestors included in the relay chain state. This context source lives on the collators. |
| 45 | + |
| 46 | +**Generation**: Collators *execute* their blockchain's core functionality to generate a new block, producing a [candidate receipt](), which is passed to validators selected for backing. |
| 47 | + |
| 48 | +**Backing**: A subset of active validators verify if the parablock follows the state transition rules of the parachain and sign *Proof of Validity* (PoV) statements that can have a positive or negative outcome. With enough positive statements, the block is backed and included in the relay chain, but is still pending approval. |
| 49 | + |
| 50 | +**Inclusion**: Validators gossip [erasure code chunks]() and put the parablock through the final [approval process]() before a parablock is considered *included* in the relay chain. |
| 51 | + |
| 52 | +### Sync VS. Async |
| 53 | + |
| 54 | +In the synchronous scenario, both the collators and validators draw context from the Relay Parent of the prior parablock, which lives on the relay chain. This makes the Backing and Generation steps tightly coupled to the prior parablock completing the inclusion pipeline. As a result, one parablock can be processed every other relay blocks. |
| 55 | + |
| 56 | +```mermaid |
| 57 | +--- |
| 58 | + displayMode: compact |
| 59 | + config: |
| 60 | + themeCSS: " |
| 61 | + #item1 { fill: #4f2eb7; stroke: #000; } \n |
| 62 | + #item2 { fill: #ffc62a; stroke: #000; } \n |
| 63 | + #item3 { fill: #4faff9; stroke: #000; } \n |
| 64 | + #r { fill: #eb4172; stroke: #000; } \n |
| 65 | + #p1padTop { fill:none;stroke:none;opacity:0; } \n |
| 66 | + text.taskText[id^=p1padTop] { fill: none !important; color: #000 !important; } \n |
| 67 | +
|
| 68 | +
|
| 69 | + /* Default inside task text: white */ \n |
| 70 | + .taskText { fill: #fff !important; color: #fff !important; font-weight: 700; font-size: 18px; } \n |
| 71 | +
|
| 72 | + /* Outside labels and section titles: black */ \n |
| 73 | + .taskTextOutside, .sectionTitle { fill: #000 !important; color: #000 !important; font-weight: 700; font-size: 18px; } \n |
| 74 | +
|
| 75 | + /* Inside text for #r items: black */ \n |
| 76 | + text.taskText[id^=r] { fill: #fff !important; color: #000 !important; } \n |
| 77 | + " |
| 78 | + themeVariables: |
| 79 | + sectionBkgColor: '#fff' |
| 80 | + gantt: |
| 81 | + numberSectionStyles: 1 |
| 82 | + barHeight: 70 |
| 83 | + gridLineStartPadding: 100 |
| 84 | +--- |
| 85 | +%%{init: {"gantt": {"barHeight": 70 }}}%% |
| 86 | +gantt |
| 87 | + dateFormat YYYY |
| 88 | + axisFormat %y |
| 89 | + %% this next line doesn't recognise 'decade' or 'year', but will silently ignore |
| 90 | + tickInterval '10year' |
| 91 | +
|
| 92 | + R1 : r, 1905, 1907 |
| 93 | + R2 : r, 1911, 1913 |
| 94 | + R3 : r, 1917, 1919 |
| 95 | + R4 : r, 1923, 1925 |
| 96 | +
|
| 97 | + SPACING : p1padTop, 1905, 1907 |
| 98 | + SPACING : p1padTop, 1911, 1913 |
| 99 | + SPACING : p1padTop, 1917, 1919 |
| 100 | + SPACING : p1padTop, 1923, 1925 |
| 101 | +
|
| 102 | + section P1 |
| 103 | + X : item1, 1900, 1901 |
| 104 | + Backing : item2, 1901, 1906 |
| 105 | + Inclusion : item3, 1906, 1912 |
| 106 | +
|
| 107 | + section P2 |
| 108 | + X : item1, 1912, 1913 |
| 109 | + Backing : item2, 1913, 1918 |
| 110 | + Inclusion : item3, 1918, 1924 |
| 111 | +``` |
| 112 | + |
| 113 | +In the asynchronous scenario, where both the collators and validators have access to Unincluded Segments as an additional context source, the Backing and Generation steps are no longer coupled to the prior block completing the full inclusion pipeline. Instead, the prior parablock only needs to complete the generation step and be added to the Unincluded Segments before the next parablock can begin the Backing and Generation steps. |
| 114 | + |
| 115 | +This results in one parablock being processed *every* relay block, and allows for more time to execute during the Generation step (0.5s --> 2s). |
| 116 | + |
| 117 | +```mermaid |
| 118 | +--- |
| 119 | + displayMode: compact |
| 120 | + config: |
| 121 | + themeCSS: " |
| 122 | + #item1 { fill: #4f2eb7; stroke: #000; } \n |
| 123 | + #item2 { fill: #ffc62a; stroke: #000; } \n |
| 124 | + #item3 { fill: #4faff9; stroke: #000; } \n |
| 125 | + #r { fill: #eb4172; stroke: #000; } \n |
| 126 | + #p1padTop { fill:none;stroke:none;opacity:0; } \n |
| 127 | + text.taskText[id^=p1padTop] { fill: none !important; color: #000 !important; } \n |
| 128 | +
|
| 129 | +
|
| 130 | + /* Default inside task text: white */ \n |
| 131 | + .taskText { fill: #fff !important; color: #fff !important; font-weight: 700; font-size: 18px; } \n |
| 132 | +
|
| 133 | + /* Outside labels and section titles: black */ \n |
| 134 | + .taskTextOutside, .sectionTitle { fill: #000 !important; color: #000 !important; font-weight: 700; font-size: 18px; } \n |
| 135 | +
|
| 136 | + /* Inside text for #r items: black */ \n |
| 137 | + text.taskText[id^=r] { fill: #fff !important; } \n |
| 138 | + " |
| 139 | + themeVariables: |
| 140 | + sectionBkgColor: '#fff' |
| 141 | + gantt: |
| 142 | + numberSectionStyles: 1 |
| 143 | + barHeight: 70 |
| 144 | + gridLineStartPadding: 100 |
| 145 | +--- |
| 146 | +%%{init: {"gantt": {"barHeight": 70 }}}%% |
| 147 | +gantt |
| 148 | + dateFormat YYYY |
| 149 | + axisFormat %y |
| 150 | + %% this next line doesn't recognise 'decade' or 'year', but will silently ignore |
| 151 | + tickInterval '10year' |
| 152 | +
|
| 153 | + R1 : r, 1905, 1907 |
| 154 | + R2 : r, 1911, 1913 |
| 155 | + R3 : r, 1917, 1919 |
| 156 | + R4 : r, 1923, 1925 |
| 157 | + R5 : r, 1929, 1931 |
| 158 | +
|
| 159 | + SPACING : p1padTop, 1905, 1907 |
| 160 | + SPACING : p1padTop, 1911, 1913 |
| 161 | + SPACING : p1padTop, 1917, 1919 |
| 162 | + SPACING : p1padTop, 1923, 1925 |
| 163 | + SPACING : p1padTop, 1929, 1931 |
| 164 | +
|
| 165 | + section P1 |
| 166 | + X : item1, 1900, 1902 |
| 167 | + Backing : item2, 1902, 1912 |
| 168 | + Inclusion : item3, 1912, 1918 |
| 169 | +
|
| 170 | + section P2 |
| 171 | + X : item1, 1906, 1908 |
| 172 | + Backing : item2, 1908, 1918 |
| 173 | + Inclusion : item3, 1918, 1924 |
| 174 | + |
| 175 | + section P3 |
| 176 | + X : item1, 1912, 1914 |
| 177 | + Backing : item2, 1914, 1924 |
| 178 | + Inclusion : item3, 1924, 1930 |
| 179 | +
|
| 180 | + section P4 |
| 181 | + X : item1, 1918, 1920 |
| 182 | + Backing : item2, 1920, 1930 |
| 183 | +``` |
| 184 | + |
| 185 | +### Compute Advantage |
| 186 | +Below is a table showing the main advantages of asynchronous over synchronous backing. |
| 187 | + |
| 188 | +| | Sync Backing | Async Backing | Async Backing Advantage | |
| 189 | +| ------------------------------------ | ------------ | ------------ | ----------------------------------------- | |
| 190 | +| **Parablocks included every** | 12 seconds | 6 seconds | **2x** more parablocks included | |
| 191 | +| **Parablock maximum execution time** | 0.5 seconds | 2 seconds | **4x** more execution time in a parablock | |
| 192 | +| **Total Computer Gain (per core)** | | | **8x Compute Throughput** | |
| 193 | + |
| 194 | +## Configurations |
| 195 | +The following configurations can be set by onchain governance: |
| 196 | + |
| 197 | +* [`max_candidate_depth`](https://github.com/paritytech/polkadot-sdk/blob/f204e3264f945c33b4cea18a49f7232c180b07c5/polkadot/primitives/src/vstaging/mod.rs#L49): the number of parachain blocks a collator can produce that are not yet included in the relay chain. |
| 198 | +* [`allowed_ancestry_len`](https://github.com/paritytech/polkadot-sdk/blob/f204e3264f945c33b4cea18a49f7232c180b07c5/polkadot/primitives/src/vstaging/mod.rs#L54): the oldest relay chain parent a parachain block can be built on top of. |
0 commit comments