Files
pezkuwi-fellows/stale/0138-invulnerable-collator-election.html
T
2025-11-18 01:15:24 +00:00

428 lines
37 KiB
HTML

<!DOCTYPE HTML>
<html lang="en" class="polkadot" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>RFC-0138: Election mechanism for invulnerable collators on system chains - 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/0150-voting-while-delegating.html">RFC-150: Allow Voting While Delegating</a></li><li class="chapter-item expanded "><a href="../proposed/0154-multi-slot-aura.html">RFC-0154: AURA Multi-Slot Collation </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="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">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" class="active">RFC-0138: Election mechanism for invulnerable collators on system chains</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/RFC-114 Adjust Tipper Track Confirmation Periods.html">RFC-114: Adjust Tipper Track Confirmation Periods</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/pull/138">(source)</a></p>
<p><strong>Table of Contents</strong></p>
<ul>
<li><a href="#rfc-0138-election-mechanism-for-invulnerable-collators-on-system-chains">RFC-0138: Election mechanism for invulnerable collators on system chains</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="#proposal">Proposal</a></li>
<li><a href="#how-it-works">How it works</a></li>
<li><a href="#motivations-behind-the-particularities-of-this-mechanism">Motivations behind the particularities of this mechanism</a></li>
<li><a href="#corner-cases">Corner cases</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-ergonomics-and-compatibility">Performance, Ergonomics, and Compatibility</a>
<ul>
<li><a href="#performance">Performance</a></li>
<li><a href="#ergonomics">Ergonomics</a></li>
<li><a href="#compatibility">Compatibility</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-0138-election-mechanism-for-invulnerable-collators-on-system-chains"><a class="header" href="#rfc-0138-election-mechanism-for-invulnerable-collators-on-system-chains">RFC-0138: Election mechanism for invulnerable collators on system chains</a></h1>
<div class="table-wrapper"><table><thead><tr><th></th><th></th></tr></thead><tbody>
<tr><td><strong>Start Date</strong></td><td>28 January 2025</td></tr>
<tr><td><strong>Description</strong></td><td>Mechanism for electing invulnerable collators on system chains.</td></tr>
<tr><td><strong>Authors</strong></td><td>George Pisaltu</td></tr>
</tbody></table>
</div>
<h2 id="summary"><a class="header" href="#summary">Summary</a></h2>
<p>The current election mechanism for permissionless collators on system chains was introduced in
<a href="https://github.com/polkadot-fellows/RFCs/blob/main/text/0007-system-collator-selection.md">RFC-7</a>.
This RFC proposes a mechanism to facilitate replacements in the invulnerable sets of system chains
by breaking down barriers that exist today.</p>
<h2 id="motivation"><a class="header" href="#motivation">Motivation</a></h2>
<p>Following RFC-7 and the <a href="https://github.com/paritytech/polkadot-sdk/pull/1340">introduction of the collator election
mechanism</a>, anyone can now collate on a system
chain on the permissionless slots, but the invulnerable set has been a contentious issue among
current collators on system chains as the path towards an invulnerable slot is almost impossible to
pursue. From a technical standpoint, nothing is preventing a permissionless collator, or anyone for
that matter, from submitting a referendum to remove one collator from the invulnerable set and add
themselves in their place. However, as it quickly becomes obvious, such a referendum would be very
difficult to pass under normal circumstances.</p>
<p>The first reason this would be contentious is that there is no significant difference between
collators with good performance. There is no reasonable way to keep track of arbitrary data on-chain
which could clearly and consistently distinguish between one collator or another. Collators that
perform well propose blocks when they are supposed to and that is what is being tracked on-chain.
Any other metrics for performance are arbitrary as far as the runtime logic is concerned and should
be reasoned upon by humans using public discussion and a referendum.</p>
<p>The second reason for this is the inherently social aspect of this action. Even just proposing the
referendum would be perceived as an attack on a specific collator in the set, singling them out,
when in reality the proposer likely just wants to be part of the set and doesn't necessarily care
who is kicked. In order to consolidate their position, the other invulnerables will rally behind the
one that was challenged and the bid to replace one invulnerable will probably fail.</p>
<p>Existing invulnerables have a vested interest in protecting any other invulnerable from such attacks
so that they themselves would be protected if need be. The existing collator set has already
demonstrated that they can work together and subvert the free market mechanism offered by the
runtime when they agreed to not outbid each other on permissionless slots after the new collator
selection mechanism was introduced.</p>
<p>The existing invulnerable set on a given system chain are there for a reason; they have demonstrated
reliability in the past and were rewarded by governance with invulnerable slots and a bounty to
cover their expenses. This means they have a solid reputation and a strong say in governance over
matters related to collation. The optics of a permissionless collator actively challenging an
invulnerable, even when it's justified, combined with the support of other invulnerables, make the
invulnerable set de facto immutable.</p>
<p>While there should be strong guarantees of stability for invulnerables, they should not be a closed
circle. The aim of this RFC is to provide a clear, reasonable, fair, and socially acceptable path
for a permissionless collator with a proven track record to become an invulnerable while preserving
the stability of the invulnerable set of a system parachain.</p>
<h2 id="stakeholders"><a class="header" href="#stakeholders">Stakeholders</a></h2>
<ul>
<li>Infrastructure providers (people who run validator/collator nodes)</li>
<li>Polkadot Treasury</li>
</ul>
<h2 id="explanation"><a class="header" href="#explanation">Explanation</a></h2>
<h3 id="proposal"><a class="header" href="#proposal">Proposal</a></h3>
<p>This RFC proposes a periodic, mandatory, round-robin, two-round election mechanism for
invulnerables.</p>
<h3 id="how-it-works"><a class="header" href="#how-it-works">How it works</a></h3>
<p>The election should be implemented on top of the current logic in the <code>collator-selection</code> pallet.
In this mechanism, candidates would register for the first round of the next election by placing
deposits.</p>
<p>When the period between elections passes, the first round of the election starts with every
candidate that registered, excluding the incumbent, as an option on the ballot. Votes should be
expressed using tokens which should not be available for other transactions while the election is
ongoing in order to introduce some opportunity cost to voting. After a certain amount of time
passes, the election closes and the candidate who wins the first round of the election advances to
the second and final round of the election. The deposits held for voting in the first round must be
released before the second round.</p>
<p>In the second round of the election, the winner of the first round has the chance to replace the
invulnerable currently holding the slot. A referendum is submitted to replace the incumbent with the
winner of the first round of the election, turning the second round of the election into a
<code>conviction-voting</code> compatible referendum. If the referendum fails, the incumbent keeps their slot.</p>
<p>The period between elections should be configurable at the <code>collator-selection</code> pallet level. A full
election cycle ends when the pallet held an election for every single invulnerable slot. To qualify
for the ballot, candidates must have been collating for at least one period from a permissionless
slot or be the incumbent.</p>
<h3 id="motivations-behind-the-particularities-of-this-mechanism"><a class="header" href="#motivations-behind-the-particularities-of-this-mechanism">Motivations behind the particularities of this mechanism</a></h3>
<ul>
<li>Round-robin - It is not desirable to allow any election of the entire invulnerable set at once
because the main purpose of invulnerables is to ensure the stability, reliability and liveness of
the parachain. It is safer to change them one by one and, in case mistakes happen, governance has
time to react without endangering the liveness of any chain.</li>
<li>Two-round voting - it's useful to separate the election process into two distinct steps: the
first, less important step of determining the challenger at the pallet level through deposits; the
second, more important step of actually trying to replace the invulnerable by referendum, which is
the same mechanism the invulnerable used to acquire the slot in the first place. It is not so
important who is trying to replace the incumbent as long as they meet the requirements and they
have a clear way to get to the second round of the election. </li>
<li>Mandatory - The runtime, not any particular individual, is actively pushing the invulnerables to
convince people that they not only deserve to keep their invulnerable slots, but that they deserve
it more than any of the other candidates that registered; the rules of the chain enforce this
mechanism so no blame or ill-intent can be attributed to other individuals.</li>
<li>Periodic - In order to provide a reasonable path towards an invulnerable slot, no seat can be
permanent and should be challenged periodically.</li>
<li>Ballot qualification - Any invulnerable collator must have a proven track record as a collator, so
allowing only current permissionless collators to run against the current invulnerable minimizes
the chance of human error by restricting the number of incompatible choices.</li>
</ul>
<h3 id="corner-cases"><a class="header" href="#corner-cases">Corner cases</a></h3>
<ul>
<li>If no candidate registers for an election, the slot will become empty, unless the number of
collators is lower than the minimum number allowed by the pallet configuration, defined in
<code>MinEligibleCollators</code>.</li>
<li>In case of equality for the first and second positions, the candidate that registered first wins the election.</li>
<li>In case no collator registers or qualifies for the first round of the election, the incumbent is
automatically granted the win and gets to keep the invulnerable slot.</li>
</ul>
<h2 id="drawbacks"><a class="header" href="#drawbacks">Drawbacks</a></h2>
<p>The first major drawback of this proposal is that it would put more responsibility on governance by
having people vote regularly in order to maintain the invulnerable collator set on each chain. Today
the <code>collator-selection</code> pallet employs a fire-and-forget system where the invulnerables are chosen
once by governance vote. Although in theory governance can always intervene to elect new
invulnerables, for the reasons stated in this RFC this is not the case in practice. Moving away from
this system means more action is needed from governance to ensure the stability of the invulnerable
collator sets on each system chain, which automatically increases the probability of errors.
However, governance is the ultimate source of truth on-chain and there is a lot more at stake in the
hands of governance than the invulnerable collator sets on system chains, so I think this risk is
acceptable.</p>
<p>The second drawback of this proposal is the imperfect voting mechanism. Probably the simplest and
most fair voting system for this scenario would have been First Past the Post, where all candidates
participate in a single election round and the candidate with the most votes wins the election
outright. However, the downside of such a system is the technical complexity behind running such an
election on-chain. This election mechanism would require a multiple choice referendum implementation
in the <code>collator-selection</code> pallet or at the system level somewhere else (e.g. on the Collectives
chain), which would be a mix between the <code>conviction-voting</code> and <code>staking</code> pallets and would
possibly communicate with all system chains via XCM. While this voting system could be useful in
other contexts as well, I don't think it's worth conditioning the invulnerable collator redesign on
a separate implementation of the multiple choice voting system when the Two-Round proposed achieves
the objectives of this RFC.</p>
<h2 id="testing-security-and-privacy"><a class="header" href="#testing-security-and-privacy">Testing, Security, and Privacy</a></h2>
<p>All election mechanisms as well as corner cases can be covered with unit tests.</p>
<h2 id="performance-ergonomics-and-compatibility"><a class="header" href="#performance-ergonomics-and-compatibility">Performance, Ergonomics, and Compatibility</a></h2>
<h3 id="performance"><a class="header" href="#performance">Performance</a></h3>
<p>The chain will have to run extrinsics to start and end elections periodically, but the impact in
terms of weight and PoV size is negligible.</p>
<h3 id="ergonomics"><a class="header" href="#ergonomics">Ergonomics</a></h3>
<p>The invulnerables will be the most affected group, as they will have to now compete in elections
periodically to secure their spots. Permissionless candidates will now have a clear, though not
guaranteed, path towards becoming an invulnerable, at least for a period of time.</p>
<h3 id="compatibility"><a class="header" href="#compatibility">Compatibility</a></h3>
<p>Any changes to the election mechanism of invulnerables should be compatible with the current
invulnerable set interaction with the collator set chosen at the session boundary. The current
invulnerable set for each chain can be grandfathered in when upgrading the <code>collator-selection</code>
pallet version.</p>
<h2 id="prior-art-and-references"><a class="header" href="#prior-art-and-references">Prior Art and References</a></h2>
<p>This RFC builds on RFC-7, which introduced the election mechanism for system chain collators.</p>
<h2 id="unresolved-questions"><a class="header" href="#unresolved-questions">Unresolved Questions</a></h2>
<ul>
<li>How long should the period between individual elections be? How long should the full election
cycle be?
<ul>
<li>There should be a bit more than one month between individual elections, so that if there are 5
invulnerables on system chains, a full election cycle would take 6 months.</li>
</ul>
</li>
<li>How long should the voting stay open?
<ul>
<li>It probably should just be a fixed period (e.g. 1 week) or maybe it can be the entire period
before the next election begins.</li>
</ul>
</li>
</ul>
<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 main spinoff of this RFC might be a multiple choice poll implementation in a separate pallet to
hold a First Past the Post election instead of the Two-Round System proposed, which would prompt a
migration to the new voting system within the <code>collator-selection</code> pallet. Additionally, a more
complex solution where the voting for all system chains happens in a single place which then sends
XCM responses with election results back to system chains can be implemented in the next iteration
of this RFC.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../stale/0124-extrinsic-version-5.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="../stale/0152-decentralized-convex-preference-coretime-market-for-polkadot.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="../stale/0124-extrinsic-version-5.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="../stale/0152-decentralized-convex-preference-coretime-market-for-polkadot.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>