Files
pezkuwi-fellows/approved/0103-introduce-core-index-commitment.html
T
2025-10-23 01:13:07 +00:00

503 lines
42 KiB
HTML

<!DOCTYPE HTML>
<html lang="en" class="polkadot" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>RFC-0103: Introduce a CoreIndex commitment and a SessionIndex field in candidate receipts - Polkadot Fellowship RFCs</title>
<!-- Custom HTML head -->
<meta name="description" content="An online book of RFCs approved or proposed within the Polkadot Fellowship.">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="../favicon.svg">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<link rel="stylesheet" href="../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<link rel="stylesheet" href="../theme/polkadot.css">
</head>
<body class="sidebar-visible no-js">
<div id="body-container">
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "polkadot" : "polkadot";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('polkadot')
html.classList.add(theme);
var body = document.querySelector('body');
body.classList.remove('no-js')
body.classList.add('js');
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var body = document.querySelector('body');
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
body.classList.remove('sidebar-visible');
body.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded affix "><a href="../introduction.html">Introduction</a></li><li class="spacer"></li><li class="chapter-item expanded affix "><li class="part-title">Newly Proposed</li><li class="spacer"></li><li class="chapter-item expanded affix "><li class="part-title">Proposed</li><li class="chapter-item expanded "><a href="../proposed/0145-remove-unnecessary-allocator-usage.html">RFC-0145: Remove the host-side runtime memory allocator</a></li><li class="chapter-item expanded "><a href="../proposed/0155-pUSD.html">RFC-0155: pUSD (Polkadot USD over-collateralised debt token)</a></li><li class="chapter-item expanded "><a href="../proposed/0156-bls-signatures.html">RFC-0156: Add BLS12-381 Host Functions</a></li><li class="chapter-item expanded "><a href="../proposed/RFC-114 Adjust Tipper Track Confirmation Periods.html">RFC-114: Adjust Tipper Track Confirmation Periods</a></li><li class="spacer"></li><li class="chapter-item expanded affix "><li class="part-title">Approved</li><li class="chapter-item expanded "><a href="../approved/0001-agile-coretime.html">RFC-1: Agile Coretime</a></li><li class="chapter-item expanded "><a href="../approved/0005-coretime-interface.html">RFC-5: Coretime Interface</a></li><li class="chapter-item expanded "><a href="../approved/0007-system-collator-selection.html">RFC-0007: System Collator Selection</a></li><li class="chapter-item expanded "><a href="../approved/0008-parachain-bootnodes-dht.html">RFC-0008: Store parachain bootnodes in relay chain DHT</a></li><li class="chapter-item expanded "><a href="../approved/0009-improved-net-light-client-requests.html">RFC-0009: Improved light client requests networking protocol</a></li><li class="chapter-item expanded "><a href="../approved/0010-burn-coretime-revenue.html">RFC-0010: Burn Coretime Revenue</a></li><li class="chapter-item expanded "><a href="../approved/0012-process-for-adding-new-collectives.html">RFC-0012: Process for Adding New System Collectives</a></li><li class="chapter-item expanded "><a href="../approved/0013-prepare-blockbuilder-and-core-runtime-apis-for-mbms.html">RFC-0013: Prepare Core runtime API for MBMs</a></li><li class="chapter-item expanded "><a href="../approved/0014-improve-locking-mechanism-for-parachains.html">RFC-0014: Improve locking mechanism for parachains</a></li><li class="chapter-item expanded "><a href="../approved/0017-coretime-market-redesign.html">RFC-0017: Coretime Market Redesign</a></li><li class="chapter-item expanded "><a href="../approved/0022-adopt-encointer-runtime.html">RFC-0022: Adopt Encointer Runtime</a></li><li class="chapter-item expanded "><a href="../approved/0026-sassafras-consensus.html">RFC-0026: Sassafras Consensus Protocol</a></li><li class="chapter-item expanded "><a href="../approved/0032-minimal-relay.html">RFC-0032: Minimal Relay</a></li><li class="chapter-item expanded "><a href="../approved/0042-extrinsics-state-version.html">RFC-0042: Add System version that replaces StateVersion on RuntimeVersion</a></li><li class="chapter-item expanded "><a href="../approved/0043-storage-proof-size-hostfunction.html">RFC-0043: Introduce storage_proof_size Host Function for Improved Parachain Block Utilization</a></li><li class="chapter-item expanded "><a href="../approved/0045-nft-deposits-asset-hub.html">RFC-0045: Lowering NFT Deposits on Asset Hub</a></li><li class="chapter-item expanded "><a href="../approved/0047-assignment-of-availability-chunks.html">RFC-0047: Assignment of availability chunks to validators</a></li><li class="chapter-item expanded "><a href="../approved/0048-session-keys-runtime-api.html">RFC-0048: Generate ownership proof for SessionKeys</a></li><li class="chapter-item expanded "><a href="../approved/0050-fellowship-salaries.html">RFC-0050: Fellowship Salaries</a></li><li class="chapter-item expanded "><a href="../approved/0056-one-transaction-per-notification.html">RFC-0056: Enforce only one transaction per notification</a></li><li class="chapter-item expanded "><a href="../approved/0059-nodes-capabilities-discovery.html">RFC-0059: Add a discovery mechanism for nodes based on their capabilities</a></li><li class="chapter-item expanded "><a href="../approved/0078-merkleized-metadata.html">RFC-0078: Merkleized Metadata</a></li><li class="chapter-item expanded "><a href="../approved/0084-general-transaction-extrinsic-format.html">RFC-0084: General transactions in extrinsic format</a></li><li class="chapter-item expanded "><a href="../approved/0091-dht-record-creation-time.html">RFC-0091: DHT Authority discovery record creation time</a></li><li class="chapter-item expanded "><a href="../approved/0097-unbonding_queue.html">RFC-0097: Unbonding Queue</a></li><li class="chapter-item expanded "><a href="../approved/0099-transaction-extension-version.html">RFC-0099: Introduce a transaction extension version</a></li><li class="chapter-item expanded "><a href="../approved/0100-xcm-multi-type-asset-transfer.html">RFC-0100: New XCM instruction: InitiateAssetsTransfer</a></li><li class="chapter-item expanded "><a href="../approved/0101-xcm-transact-remove-max-weight-param.html">RFC-0101: XCM Transact remove require_weight_at_most parameter</a></li><li class="chapter-item expanded "><a href="../approved/0103-introduce-core-index-commitment.html" class="active">RFC-0103: Introduce a CoreIndex commitment and a SessionIndex field in candidate receipts</a></li><li class="chapter-item expanded "><a href="../approved/0105-xcm-improved-fee-mechanism.html">RFC-0105: XCM improved fee mechanism</a></li><li class="chapter-item expanded "><a href="../approved/0107-xcm-execution-hints.html">RFC-0107: XCM Execution hints</a></li><li class="chapter-item expanded "><a href="../approved/0108-xcm-remove-testnet-ids.html">RFC-0108: Remove XCM testnet NetworkIds</a></li><li class="chapter-item expanded "><a href="../approved/0122-alias-origin-on-asset-transfers.html">RFC-0122: Asset transfers can alias XCM origin on destination to original origin</a></li><li class="chapter-item expanded "><a href="../approved/0123-pending-code-as-storage-location-for-runtime-upgrades.html">RFC-0123: Introduce :pending_code as intermediate storage key for the runtime code</a></li><li class="chapter-item expanded "><a href="../approved/0125-xcm-asset-metadata.html">RFC-0125: XCM Asset Metadata</a></li><li class="chapter-item expanded "><a href="../approved/0126-introduce-pvq.html">RFC-0126: Introduce PVQ (PolkaVM Query)</a></li><li class="chapter-item expanded "><a href="../approved/0135-compressed-blob-prefixes.html">RFC-0135: Compressed Blob Prefixes</a></li><li class="chapter-item expanded "><a href="../approved/0139-faster-erasure-coding.html">RFC-0139: Faster Erasure Coding</a></li><li class="chapter-item expanded "><a href="../approved/0146-deflationary-fee-proposal.html">RFC-0146: Deflationary Transaction Fee Model for the Relay Chain and its System Parachains</a></li><li class="chapter-item expanded "><a href="../approved/0149-rfc-1-renewal-adjustment.html">RFC-0149: Renewal Adjustment</a></li><li class="spacer"></li><li class="chapter-item expanded affix "><li class="part-title">Stale</li><li class="chapter-item expanded "><a href="../stale/0000-pre-elves_soft.html">RFC-0000: Pre-ELVES soft concensus</a></li><li class="chapter-item expanded "><a href="../stale/0000-rewards.html">RFC-0000: Validator Rewards</a></li><li class="chapter-item expanded "><a href="../stale/0004-remove-unnecessary-allocator-usage.html">RFC-0004: Remove the host-side runtime memory allocator</a></li><li class="chapter-item expanded "><a href="../stale/0006-dynamic-pricing-for-bulk-coretime-sales.html">RFC-0006: Dynamic Pricing for Bulk Coretime Sales</a></li><li class="chapter-item expanded "><a href="../stale/0034-xcm-absolute-location-account-derivation.html">RFC-34: XCM Absolute Location Account Derivation</a></li><li class="chapter-item expanded "><a href="../stale/0035-conviction-voting-delegation-modifications.html"> RFC-0035: Conviction Voting Delegation Modifications</a></li><li class="chapter-item expanded "><a href="../stale/0044-rent-based-registration.html">RFC-0044: Rent based registration model</a></li><li class="chapter-item expanded "><a href="../stale/0054-remove-heap-pages.html">RFC-0054: Remove the concept of "heap pages" from the client</a></li><li class="chapter-item expanded "><a href="../stale/0070-x-track-kusamanetwork.html">RFC-0070: X Track for @kusamanetwork</a></li><li class="chapter-item expanded "><a href="../stale/0073-referedum-deposit-track.html">RFC-0073: Decision Deposit Referendum Track</a></li><li class="chapter-item expanded "><a href="../stale/0074-stateful-multisig-pallet.html">RFC-0074: Stateful Multisig Pallet</a></li><li class="chapter-item expanded "><a href="../stale/0077-increase-max-length-of-identity-pgp-fingerprint-value.html">RFC-0077: Increase maximum length of identity PGP fingerprint values from 20 bytes</a></li><li class="chapter-item expanded "><a href="../stale/0088-broker-pallet-slashable-deposit-purchaser-reputation-reserved-cores.html">RFC-0088: Add slashable locked deposit, purchaser reputation, and reserved cores for on-chain identities to broker pallet</a></li><li class="chapter-item expanded "><a href="../stale/00xx-secondary-marketplace-for-regions.html">RFC-0001: Secondary Market for Regions</a></li><li class="chapter-item expanded "><a href="../stale/00xx-smart-contracts-coretime-chain.html">RFC-0002: Smart Contracts on the Coretime Chain</a></li><li class="chapter-item expanded "><a href="../stale/0102-offchain-parachain-runtime-upgrades.html">RFC-0000: Feature Name Here</a></li><li class="chapter-item expanded "><a href="../stale/0106-xcm-remove-fees-mode.html">RFC-0106: Remove XCM fees mode</a></li><li class="chapter-item expanded "><a href="../stale/0111-pure-proxy-replication.html">RFC-0111: Pure Proxy Replication</a></li><li class="chapter-item expanded "><a href="../stale/0112-compress-state-response-message-in-state-sync.html">RFC-0112: Compress the State Response Message in State Sync</a></li><li class="chapter-item expanded "><a href="../stale/0114-secp256r1-hostfunction.html">RFC-0114: Introduce secp256r1_ecdsa_verify_prehashed Host Function to verify NIST-P256 elliptic curve signatures</a></li><li class="chapter-item expanded "><a href="../stale/0117-unbrick-collective.html">RFC-0117: The Unbrick Collective</a></li><li class="chapter-item expanded "><a href="../stale/0120-referenda-confirmation-by-candle-mechanism.html">RFC-0120: Referenda Confirmation by Candle Mechanism</a></li><li class="chapter-item expanded "><a href="../stale/0124-extrinsic-version-5.html">RFC-0124: Extrinsic version 5</a></li><li class="chapter-item expanded "><a href="../stale/0138-invulnerable-collator-election.html">RFC-0138: Election mechanism for invulnerable collators on system chains</a></li><li class="chapter-item expanded "><a href="../stale/0150-voting-while-delegating.html">RFC-150: Allow Voting While Delegating</a></li><li class="chapter-item expanded "><a href="../stale/0152-decentralized-convex-preference-coretime-market-for-polkadot.html">RFC-0152: Decentralized Convex-Preference Coretime Market for Polkadot</a></li><li class="chapter-item expanded "><a href="../stale/0154-multi-slot-aura.html">RFC-0154: AURA Multi-Slot Collation </a></li><li class="chapter-item expanded "><a href="../stale/TODO-stale-nomination-reward-curve.html">RFC-TODO: Stale Nomination Reward Curve</a></li><li class="chapter-item expanded "><a href="../stale/xxxx-improve-the-security-of-proof-of-possession.html">RFC-XXXX: Adding customized mandatory context to proof of possession statement</a></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<!-- Track and set sidebar scroll position -->
<script>
var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
sidebarScrollbox.addEventListener('click', function(e) {
if (e.target.tagName === 'A') {
sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
}
}, { passive: true });
var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
sessionStorage.removeItem('sidebar-scroll');
if (sidebarScrollTop) {
// preserve sidebar scroll position when navigating via links within sidebar
sidebarScrollbox.scrollTop = sidebarScrollTop;
} else {
// scroll sidebar to current active section when navigating via "next/previous chapter" buttons
var activeSection = document.querySelector('#sidebar .active');
if (activeSection) {
activeSection.scrollIntoView({ block: 'center' });
}
}
</script>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="polkadot">Polkadot</button></li>
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Polkadot Fellowship RFCs</h1>
<div class="right-buttons">
<a href="../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<p><a href="https://github.com/polkadot-fellows/RFCs/blob/main/text/0103-introduce-core-index-commitment.md">(source)</a></p>
<p><strong>Table of Contents</strong></p>
<ul>
<li><a href="#rfc-0103--introduce-a-coreindex-commitment-and-a-sessionindex-field-in-candidate-receipts">RFC-0103: Introduce a <code>CoreIndex</code> commitment and a <code>SessionIndex</code> field in candidate receipts</a>
<ul>
<li><a href="#summary">Summary</a></li>
<li><a href="#motivation">Motivation</a></li>
<li><a href="#stakeholders">Stakeholders</a></li>
<li><a href="#explanation">Explanation</a>
<ul>
<li><a href="#reclaiming-unused-space-in-the-descriptor">Reclaiming unused space in the descriptor</a></li>
<li><a href="#ump-transport">UMP transport</a></li>
<li><a href="#polkadot-primitive-changes">Polkadot Primitive changes</a></li>
<li><a href="#backwards-compatibility">Backwards compatibility</a></li>
<li><a href="#parachain-block-validation">Parachain block validation</a></li>
<li><a href="#on-chain-backing">On-chain backing</a></li>
</ul>
</li>
<li><a href="#drawbacks">Drawbacks</a></li>
<li><a href="#testing-security-and-privacy">Testing, Security, and Privacy</a></li>
<li><a href="#performance">Performance</a></li>
<li><a href="#ergonomics">Ergonomics</a></li>
<li><a href="#compatibility">Compatibility</a>
<ul>
<li><a href="#relay-chain-runtime">Relay chain runtime</a></li>
<li><a href="#validators">Validators</a></li>
<li><a href="#tooling">Tooling</a></li>
</ul>
</li>
<li><a href="#prior-art-and-references">Prior Art and References</a></li>
<li><a href="#unresolved-questions">Unresolved Questions</a></li>
<li><a href="#future-directions-and-related-material">Future Directions and Related Material</a></li>
</ul>
</li>
</ul>
<h1 id="rfc-0103--introduce-a-coreindex-commitment-and-a-sessionindex-field-in-candidate-receipts"><a class="header" href="#rfc-0103--introduce-a-coreindex-commitment-and-a-sessionindex-field-in-candidate-receipts">RFC-0103: Introduce a <code>CoreIndex</code> commitment and a <code>SessionIndex</code> field in candidate receipts</a></h1>
<div class="table-wrapper"><table><thead><tr><th></th><th></th></tr></thead><tbody>
<tr><td><strong>Start Date</strong></td><td>15 July 2024</td></tr>
<tr><td><strong>Description</strong></td><td>Constrain parachain block validity to a specific core and session</td></tr>
<tr><td><strong>Authors</strong></td><td>Andrei Sandu</td></tr>
</tbody></table>
</div>
<h2 id="summary"><a class="header" href="#summary">Summary</a></h2>
<p>Elastic scaling is not resilient against griefing attacks without a way for a PoV (Proof of Validity)
to commit to the particular core index it was intended for. This RFC proposes a way to include
core index information in the candidate commitments and the <code>CandidateDescriptor</code> data structure
in a backward compatible way. Additionally, it proposes the addition of a <code>SessionIndex</code> field in
the <code>CandidateDescriptor</code> to make dispute resolution more secure and robust.</p>
<h2 id="motivation"><a class="header" href="#motivation">Motivation</a></h2>
<p>This RFC proposes a way to solve two different problems:</p>
<ol>
<li>For Elastic Scaling, it prevents anyone who has acquired a valid collation to DoS the parachain
by providing the same collation to all backing groups assigned to the parachain. This can
happen before the next valid parachain block is authored and will prevent the chain of
candidates from being formed, reducing the throughput of the parachain to a single core.</li>
<li>The dispute protocol relies on validators trusting the session index provided by other
validators when initiating and participating in disputes. It is used to look up validator keys
and check dispute vote signatures. By adding a <code>SessionIndex</code> in the <code>CandidateDescriptor</code>,
validators no longer have to trust the <code>Sessionindex</code> provided by the validator raising a
dispute. The dispute may concern a relay chain block not yet imported by a
validator. In this case, validators can safely assume the session index refers to the session
the candidate has appeared in, otherwise, the chain would have rejected the candidate.</li>
</ol>
<h2 id="stakeholders"><a class="header" href="#stakeholders">Stakeholders</a></h2>
<ul>
<li>Polkadot core developers.</li>
<li>Cumulus node developers.</li>
<li>Tooling, block explorer developers.</li>
</ul>
<p>This approach and alternatives have been considered and discussed in <a href="https://github.com/polkadot-fellows/RFCs/issues/92">this issue</a>.</p>
<h2 id="explanation"><a class="header" href="#explanation">Explanation</a></h2>
<p>The approach proposed below was chosen primarily because it minimizes the number of breaking
changes, the complexity and takes less implementation and testing time. The proposal is to change
the existing primitives while keeping binary compatibility with the older versions. We repurpose
unused fields to introduce core index and a session index information in the <code>CandidateDescriptor</code>
and extend the UMP to transport non-XCM messages.</p>
<h3 id="reclaiming-unused-space-in-the-descriptor"><a class="header" href="#reclaiming-unused-space-in-the-descriptor">Reclaiming unused space in the descriptor</a></h3>
<p>The <code>CandidateDescriptor</code> includes <code>collator</code> and <code>signature</code> fields. The collator
includes a signature on the following descriptor fields: parachain id, relay parent, validation
data hash, validation code hash, and the PoV hash.</p>
<p>However, in practice, having a collator signature in the receipt on the relay chain does not
provide any benefits as there is no mechanism to punish or reward collators that have provided
bad parachain blocks.</p>
<p>This proposal aims to remove the collator signature and all the logic that checks the collator
signatures of candidate receipts. We use the first 7 reclaimed bytes to represent the version,
the core, session index, and fill the rest with zeroes. So, there is no change in the layout
and length of the receipt. The new primitive is binary-compatible with the old one.</p>
<h3 id="ump-transport"><a class="header" href="#ump-transport">UMP transport</a></h3>
<p><a href="https://github.com/paritytech/polkadot-sdk/blob/b5029eb4fd6c7ffd8164b2fe12b71bad0c59c9f2/polkadot/primitives/src/v7/mod.rs#L682">CandidateCommitments</a>
remains unchanged as we will store scale encoded <code>UMPSignal</code> messages directly in the parachain
UMP queue by outputting them in <a href="https://github.com/paritytech/polkadot-sdk/blob/b5029eb4fd6c7ffd8164b2fe12b71bad0c59c9f2/polkadot/primitives/src/v7/mod.rs#L684">upward_messages</a>.</p>
<p>The UMP queue layout is changed to allow the relay chain to receive both the XCM messages and
<code>UMPSignal</code> messages. An empty message (empty <code>Vec&lt;u8&gt;</code>) is used to mark the end of XCM messages and
the start of <code>UMPSignal</code> messages. The <code>UMPSignal</code> is optional and can be omitted by parachains
not using elastic scaling.</p>
<p>This way of representing the new messages has been chosen over introducing an enum wrapper to
minimize breaking changes of XCM message decoding in tools like Subscan for example.</p>
<p>Example:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>[ XCM message1, XCM message2, ..., EMPTY message, UMPSignal::SelectCore ]
<span class="boring">}</span></code></pre></pre>
<h4 id="umpsignal-messages"><a class="header" href="#umpsignal-messages"><code>UMPSignal</code> messages</a></h4>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>/// The selector that determines the core index.
pub struct CoreSelector(pub u8);
/// The offset in the relay chain claim queue.
///
/// The state of the claim queue is given by the relay chain block
/// that is used as context for the `PoV`.
pub struct ClaimQueueOffset(pub u8);
/// Signals sent by a parachain to the relay chain.
pub enum UMPSignal {
/// A message sent by a parachain to select the core the candidate is committed to.
/// Relay chain validators, in particular backers, use the `CoreSelector` and `ClaimQueueOffset`
/// to compute the index of the core the candidate has committed to.
SelectCore(CoreSelector, ClaimQueueOffset),
}
<span class="boring">}</span></code></pre></pre>
<p>The <code>CoreSelector</code> together with the <code>ClaimQueueOffset</code> are used to index the claim queue. This way
the validators can compute the <code>CoreIndex</code> and ensure that the collator put the correct <code>CoreIndex</code>
into the <code>CandidateDescriptor</code>.</p>
<p><strong>Example:</strong></p>
<p><code>cq_offset = 1</code> and <code>core_selector = 3</code></p>
<p>The table below represents a snapshot of the claim queue:</p>
<div class="table-wrapper"><table><thead><tr><th style="text-align: center"></th><th style="text-align: center">offset = 0</th><th style="text-align: center">offset = 1</th><th style="text-align: center">offset = 2</th></tr></thead><tbody>
<tr><td style="text-align: center">Core 1</td><td style="text-align: center"><strong>Para A</strong></td><td style="text-align: center"><strong>Para A</strong></td><td style="text-align: center"><strong>Para A</strong></td></tr>
<tr><td style="text-align: center">Core 2</td><td style="text-align: center"><strong>Para A</strong></td><td style="text-align: center">Para B</td><td style="text-align: center"><strong>Para A</strong></td></tr>
<tr><td style="text-align: center">Core 3</td><td style="text-align: center">Para B</td><td style="text-align: center"><strong>Para A</strong></td><td style="text-align: center"><strong>Para A</strong></td></tr>
</tbody></table>
</div>
<p>The purpose of <code>ClaimQueueOffset</code> is to select the column from the above table.
For <code>cq_offset = 1</code> we get <code>[Para A, Para B, Para A]</code> and use as input to create
a sorted vec with the cores A is assigned to: <code>[Core 1, Core 3]</code> and call it <code>para_assigned_cores</code>.
We use <code>core_selector</code> and determine the committed core index is <code>Core 3</code> like this:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let committed_core_index = para_assigned_cores[core_selector % para_assigned_cores.len()];
<span class="boring">}</span></code></pre></pre>
<h3 id="polkadot-primitive-changes"><a class="header" href="#polkadot-primitive-changes">Polkadot Primitive changes</a></h3>
<h4 id="new-candidatedescriptor"><a class="header" href="#new-candidatedescriptor">New <a href="https://github.com/paritytech/polkadot-sdk/blob/b5029eb4fd6c7ffd8164b2fe12b71bad0c59c9f2/polkadot/primitives/src/v7/mod.rs#L512">CandidateDescriptor</a></a></h4>
<ul>
<li>reclaim 32 bytes from <code>collator: CollatorId</code> and 64 bytes from <code>signature: CollatorSignature</code>
and rename to <code>reserved1</code> and <code>reserved2</code> fields.</li>
<li>take 1 bytes from <code>reserved1</code> for a new <code>version: u8</code> field.</li>
<li>take 2 bytes from <code>reserved1</code> for a new <code>core_index: u16</code> field.</li>
<li>take 4 bytes from <code>reserved1</code> for a new <code>session_index: u32</code> field.</li>
<li>the remaining <code>reserved1</code> and <code>reserved2</code> fields are zeroed</li>
</ul>
<p>The new primitive will look like this:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>pub struct CandidateDescriptorV2&lt;H = Hash&gt; {
/// The ID of the para this is a candidate for.
para_id: ParaId,
/// The hash of the relay-chain block this is executed in the context of.
relay_parent: H,
/// Version field. The raw value here is not exposed, instead, it is used
/// to determine the `CandidateDescriptorVersion`
version: InternalVersion,
/// The core index where the candidate is backed.
core_index: u16,
/// The session in which the candidate is backed.
session_index: SessionIndex,
/// Reserved bytes.
reserved1: [u8; 25],
/// The blake2-256 hash of the persisted validation data. This is extra data derived from
/// relay-chain state which may vary based on bitfields included before the candidate.
/// Thus it cannot be derived entirely from the relay parent.
persisted_validation_data_hash: Hash,
/// The blake2-256 hash of the PoV.
pov_hash: Hash,
/// The root of a block's erasure encoding Merkle tree.
erasure_root: Hash,
/// Reserved bytes.
reserved2: [u8; 64],
/// Hash of the para header that is being generated by this candidate.
para_head: Hash,
/// The blake2-256 hash of the validation code bytes.
validation_code_hash: ValidationCodeHash,
}
<span class="boring">}</span></code></pre></pre>
<p>In future format versions, parts of the <code>reserved1</code> and <code>reserved2</code> bytes can be used to include
additional information in the descriptor.</p>
<h3 id="backwards-compatibility"><a class="header" href="#backwards-compatibility">Backwards compatibility</a></h3>
<p>Two flavors of candidate receipts are used in network protocols, runtime and node
implementation:</p>
<ul>
<li><code>CommittedCandidateReceipt</code> which includes the <code>CandidateDescriptor</code> and the <code>CandidateCommitments</code></li>
<li><code>CandidateReceipt</code> which includes the <code>CandidateDescriptor</code> and just a hash of the commitments</li>
</ul>
<p>We want to support both the old and new versions in the runtime and node, so the implementation must
be able to detect the version of a given candidate receipt.</p>
<p>The version of the descriptor is detected by checking the reserved fields.
If they are not zeroed, it means it is a version 1 descriptor. Otherwise the <code>version</code> field
is used further to determine the version. It should be <code>0</code> for version 2 descriptors. If it is not
the descriptor has an unknown version and should be considered invalid.</p>
<h3 id="parachain-block-validation"><a class="header" href="#parachain-block-validation">Parachain block validation</a></h3>
<p>If the candidate descriptor is version 1, there are no changes.</p>
<p>Backers must check the validity of <code>core_index</code> and <code>session_index</code> fields.
A candidate must not be backed if any of the following are true:</p>
<ul>
<li>the <code>core_index</code> in the descriptor does not match the core the backer is assigned to</li>
<li>the <code>session_index</code> is not equal to the session index the candidate is backed in</li>
<li>the <code>core_index</code> in the descriptor does not match the one determined by the
<code>UMPSignal::SelectCore</code> message</li>
</ul>
<h3 id="on-chain-backing"><a class="header" href="#on-chain-backing">On-chain backing</a></h3>
<p>If the candidate descriptor is version 1, there are no changes.</p>
<p>For version 2 descriptors the runtime will determine the <code>core_index</code> using the same inputs
as backers did off-chain. It currently stores the claim queue at the newest allowed
relay parent corresponding to the claim queue offset <code>0</code>. The runtime needs to be changed to store
a claim queue snapshot at all allowed relay parents.</p>
<h2 id="drawbacks"><a class="header" href="#drawbacks">Drawbacks</a></h2>
<p>The only drawback is that further additions to the descriptor are limited to the amount of
remaining unused space.</p>
<h2 id="testing-security-and-privacy"><a class="header" href="#testing-security-and-privacy">Testing, Security, and Privacy</a></h2>
<p>Standard testing (unit tests, CI zombienet tests) for functionality and mandatory security audit
to ensure the implementation does not introduce any new security issues.</p>
<p>Backward compatibility of the implementation will be tested on testnets (Versi and Westend).</p>
<p>There is no impact on privacy.</p>
<h2 id="performance"><a class="header" href="#performance">Performance</a></h2>
<p>Overall performance will be improved by not checking the collator signatures in runtime and nodes.
The impact on the UMP queue and candidate receipt processing is negligible.</p>
<p>The <code>ClaimQueueOffset</code> along with the relay parent choice allows parachains to optimize their
block production for either throughput or lower XCM message processing latency. A value of <code>0</code>
with the newest relay parent provides the best latency while picking older relay parents avoids
re-orgs.</p>
<h2 id="ergonomics"><a class="header" href="#ergonomics">Ergonomics</a></h2>
<p>It is mandatory for elastic parachains to switch to the new receipt format and commit to a
core by sending the <code>UMPSignal::SelectCore</code> message. It is optional but desired that all
parachains switch to the new receipts for providing the session index for disputes.</p>
<p>The implementation of this RFC itself must not introduce any breaking changes for the parachain
runtime or collator nodes.</p>
<h2 id="compatibility"><a class="header" href="#compatibility">Compatibility</a></h2>
<p>The proposed changes are not fully backward compatible, because older validators verify the
collator signature of candidate descriptors.</p>
<p>Additional care must be taken before enabling the new descriptors by waiting for at least
<code>2/3 + 1</code> validators to upgrade. Validators that have not upgraded will not back candidates
using the new descriptor format and will also initiate disputes against these candidates.</p>
<h3 id="relay-chain-runtime"><a class="header" href="#relay-chain-runtime">Relay chain runtime</a></h3>
<p>The first step is to remove collator signature checking logic in the runtime but keep the node
side collator signature checks.</p>
<p>The runtime must be upgraded to support the new primitives before any collator or node is allowed
to use the new candidate receipts format.</p>
<h3 id="validators"><a class="header" href="#validators">Validators</a></h3>
<p>To ensure a smooth launch, a new node feature is required.
The feature acts as a signal for supporting the new candidate receipts on the node side and can
only be safely enabled if at least <code>2/3 + 1</code> of the validators are upgraded. Node implementations
need to decode the new candidate descriptor once the feature is enabled otherwise they might
raise disputes and get slashed.</p>
<p>Once the feature is enabled, the validators will skip checking the collator signature when
processing the candidate receipts and verify the <code>CoreIndex</code> and <code>SessionIndex</code> fields if
present in the receipt.</p>
<p>No new implementation of networking protocol versions for collation and validation is required.</p>
<h3 id="tooling"><a class="header" href="#tooling">Tooling</a></h3>
<p>Any tooling that decodes UMP XCM messages needs an update to support or ignore the new UMP
messages, but they should be fine to decode the regular XCM messages that come before the
separator.</p>
<h2 id="prior-art-and-references"><a class="header" href="#prior-art-and-references">Prior Art and References</a></h2>
<p>Forum discussion about a new <code>CandidateReceipt</code> format:
<a href="https://forum.polkadot.network/t/pre-rfc-discussion-candidate-receipt-format-v2/3738">https://forum.polkadot.network/t/pre-rfc-discussion-candidate-receipt-format-v2/3738</a></p>
<h2 id="unresolved-questions"><a class="header" href="#unresolved-questions">Unresolved Questions</a></h2>
<p>N/A</p>
<h2 id="future-directions-and-related-material"><a class="header" href="#future-directions-and-related-material">Future Directions and Related Material</a></h2>
<p>The implementation is extensible and future-proof to some extent. With minimal or no breaking
changes, additional fields can be added in the candidate descriptor until the reserved space is
exhausted</p>
<p>At this point, there is a simple way to determine the version of the receipt, by testing for zeroed
reserved bytes in the descriptor. Future versions of the receipt can be implemented and identified
by using the <code>version</code> field of the descriptor introduced in this RFC.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../approved/0101-xcm-transact-remove-max-weight-param.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../approved/0105-xcm-improved-fee-mechanism.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../approved/0101-xcm-transact-remove-max-weight-param.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../approved/0105-xcm-improved-fee-mechanism.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>