mirror of
https://github.com/pezkuwichain/pezkuwi-fellows.git
synced 2026-05-30 23:01:03 +00:00
670 lines
43 KiB
HTML
670 lines
43 KiB
HTML
|
|
<!DOCTYPE HTML>
|
|
<html lang="en" class="polkadot" dir="ltr">
|
|
<head>
|
|
<!-- Book generated using mdBook -->
|
|
<meta charset="UTF-8">
|
|
<title>RFC-0126: Introduce XCQ(Cross Consensus Query) - 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="chapter-item expanded "><a href="../new/0135-compressed-blob-prefixes.html">RFC-0135: Compressed Blob Prefixes</a></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/0004-remove-unnecessary-allocator-usage.html">RFC-0004: Remove the host-side runtime memory allocator</a></li><li class="chapter-item expanded "><a href="../proposed/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="../proposed/0125-xcm-asset-metadata.html">RFC-0125: XCM Asset Metadata</a></li><li class="chapter-item expanded "><a href="../proposed/0126-introduce-xcq.html" class="active">RFC-0126: Introduce XCQ(Cross Consensus Query)</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/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="spacer"></li><li class="chapter-item expanded affix "><li class="part-title">Stale</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/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/0015-market-design-revisit.html">RFC-0015: Market Design Revisit</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/0121-iterable-referenda-tracks.html">RFC-0121: Iterable Referenda Tracks</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/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></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/126">(source)</a></p>
|
|
<p><strong>Table of Contents</strong></p>
|
|
<ul>
|
|
<li><a href="#rfc-0126-introduce-xcqcross-consensus-query">RFC-0126: Introduce XCQ(Cross Consensus Query)</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="#xcq-runtime-api">XCQ Runtime API</a></li>
|
|
<li><a href="#xcq-executor">XCQ Executor</a></li>
|
|
<li><a href="#xcq-extension">XCQ Extension</a></li>
|
|
<li><a href="#xcq-program-structure">XCQ Program Structure</a></li>
|
|
<li><a href="#xcq-program-execution-flow">XCQ Program Execution Flow</a></li>
|
|
<li><a href="#xcm-integration">XCM integration</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#drawbacks">Drawbacks</a>
|
|
<ul>
|
|
<li><a href="#performance-issues">Performance issues</a></li>
|
|
<li><a href="#user-experience-issues">User experience issues</a></li>
|
|
</ul>
|
|
</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-0126-introduce-xcqcross-consensus-query"><a class="header" href="#rfc-0126-introduce-xcqcross-consensus-query">RFC-0126: Introduce XCQ(Cross Consensus Query)</a></h1>
|
|
<div class="table-wrapper"><table><thead><tr><th></th><th></th></tr></thead><tbody>
|
|
<tr><td><strong>Start Date</strong></td><td>Oct 25 2024</td></tr>
|
|
<tr><td><strong>Description</strong></td><td>Introduce XCQ (Cross Consensus Query)</td></tr>
|
|
<tr><td><strong>Authors</strong></td><td>Bryan Chen, Jiyuan Zheng</td></tr>
|
|
</tbody></table>
|
|
</div>
|
|
<h2 id="summary"><a class="header" href="#summary">Summary</a></h2>
|
|
<p>This proposal introduces XCQ (Cross Consensus Query), which aims to serve as an intermediary layer between different chain runtime implementations and tools/UIs, to provide a unified interface for cross-chain queries.
|
|
<code>XCQ</code> abstracts away concrete implementations across chains and supports custom query computations.</p>
|
|
<p>Use cases benefiting from <code>XCQ</code> include:</p>
|
|
<ul>
|
|
<li>XCM bridge UI:
|
|
<ul>
|
|
<li>Query asset balances</li>
|
|
<li>Query XCM weight and fee from hop and dest chains</li>
|
|
</ul>
|
|
</li>
|
|
<li>Wallets:
|
|
<ul>
|
|
<li>Query asset balances</li>
|
|
<li>Query weights and fees for operations across chains</li>
|
|
</ul>
|
|
</li>
|
|
<li>Universal dApp that supports all the parachains:
|
|
<ul>
|
|
<li>Perform Feature discovery</li>
|
|
<li>Query pallet-specific features</li>
|
|
<li>Construct extrinsics by querying pallet index, call index, etc</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h2 id="motivation"><a class="header" href="#motivation">Motivation</a></h2>
|
|
<p>In Substrate, runtime APIs facilitate off-chain clients in reading the state of the consensus system.
|
|
However, different chains may expose different APIs for a similar query or have varying data types, such as doing custom transformations on direct data, or differing <code>AccountId</code> types.
|
|
This diversity also extends to client-side, which may require custom computations over runtime APIs in various use cases.
|
|
Therefore, tools and UI developers often access storage directly and reimplement custom computations to convert data into user-friendly representations, leading to duplicated code between Rust runtime logic and UI JS/TS logic.
|
|
This duplication increases workload and potential for bugs.</p>
|
|
<p>Therefore, a system is needed to serve as an intermediary layer between concrete chain runtime implementations and tools/UIs, to provide a unified interface for cross-chain queries.</p>
|
|
<h2 id="stakeholders"><a class="header" href="#stakeholders">Stakeholders</a></h2>
|
|
<ul>
|
|
<li>Runtime Developers</li>
|
|
<li>Tools/UI Developers</li>
|
|
</ul>
|
|
<h2 id="explanation"><a class="header" href="#explanation">Explanation</a></h2>
|
|
<p>The overall query pattern of XCQ consists of three components:</p>
|
|
<ul>
|
|
<li>Runtime: View-functions across different pallets are amalgamated through an extension-based system.</li>
|
|
<li>XCQ query: Custom computations over view-function results are encapsulated via PolkaVM programs.</li>
|
|
<li>XCQ query arguments: Query arguments like accounts to be queried are also passed together with the query program.</li>
|
|
</ul>
|
|
<h3 id="xcq-runtime-api"><a class="header" href="#xcq-runtime-api">XCQ Runtime API</a></h3>
|
|
<p>The runtime API for off-chain query usage includes two methods:</p>
|
|
<ul>
|
|
<li><code>execute_query</code>: Executes the query and returns the result. It takes the query, input, and weight limit as arguments.
|
|
The query is the query program in PolkaVM program binary format.
|
|
The input is the query arguments that is SCALE-encoded.
|
|
The weight limit is the maximum weight allowed for the query execution.</li>
|
|
<li><code>metadata</code>: Return metadata of supported extensions (introduced in later section) and methods, serving as a feature discovery functionality.
|
|
The representation and encoding mechanism is similar to the <a href="https://github.com/paritytech/frame-metadata/"><code>frame-metadata</code></a>, using <code>scale-info</code>.</li>
|
|
</ul>
|
|
<h4 id="example-xcq-runtime-api"><a class="header" href="#example-xcq-runtime-api">Example XCQ Runtime API</a></h4>
|
|
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
</span><span class="boring">fn main() {
|
|
</span>decl_runtime_apis! {
|
|
pub trait XcqApi {
|
|
fn execute_query(query: Vec<u8>, input: Vec<u8>, weight_limit: u64) -> XcqResult;
|
|
fn metadata() -> Vec<u8>;
|
|
}
|
|
}
|
|
type XcqResult = Result<XcqResponse, XcqError>;
|
|
type XcqResponse = Vec<u8>;
|
|
enum XcqError {
|
|
Custom(String),
|
|
}
|
|
<span class="boring">}</span></code></pre></pre>
|
|
<h4 id="example-metadata-before-scale-encoded"><a class="header" href="#example-metadata-before-scale-encoded">Example Metadata (before SCALE-encoded)</a></h4>
|
|
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
</span><span class="boring">fn main() {
|
|
</span>pub struct Metadata {
|
|
pub types: PortableRegistry,
|
|
pub extensions: Vec<ExtensionMetadata<PortableForm>>,
|
|
}
|
|
<span class="boring">}</span></code></pre></pre>
|
|
<h3 id="xcq-executor"><a class="header" href="#xcq-executor">XCQ Executor</a></h3>
|
|
<p>An XCQ executor is a runtime module that executes XCQ queries.
|
|
It has a core method <code>execute</code> that takes a PolkaVM program binary,
|
|
method name of the exported functions in the PolkaVM program, input arguments, and weight limit that the PolkaVM program can consume.</p>
|
|
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
</span><span class="boring">fn main() {
|
|
</span>pub fn execute(
|
|
&mut self,
|
|
raw_blob: &[u8],
|
|
method: &str,
|
|
input: &[u8],
|
|
weight_limit: u64,
|
|
) -> Result<Vec<u8>, XcqExecutorError> {...}
|
|
<span class="boring">}</span></code></pre></pre>
|
|
<h3 id="xcq-extension"><a class="header" href="#xcq-extension">XCQ Extension</a></h3>
|
|
<p>An extension-based design is essential for several reasons:</p>
|
|
<ul>
|
|
<li>Different chains may have different data types for semantically similar queries, making it challenging to standardize function calls across them.
|
|
An extension-based design with optional associated types allows these diverse data types to be specified and utilized effectively.</li>
|
|
<li>Function calls distributed across various pallets can be amalgamated into a single extension, simplifying the development process and ensuring a more cohesive and maintainable codebase.</li>
|
|
<li>New functionalities can be added without upgrading the core part of the XCQ.</li>
|
|
<li>Ensure the core part is in a minimal scope.</li>
|
|
</ul>
|
|
<p>Essential components of an XCQ extension system include:</p>
|
|
<ul>
|
|
<li>
|
|
<p>A hash-based extension id generation mechanism for addressing and versioning . The hash value derives from the extension name and its method sets. Any update to an extension is treated as a new extension.</p>
|
|
</li>
|
|
<li>
|
|
<p><code>decl_extension</code> macro: Defines an extension as a Rust trait with optional associated types.</p>
|
|
</li>
|
|
</ul>
|
|
<p><strong>Example usage</strong>:</p>
|
|
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
</span><span class="boring">fn main() {
|
|
</span>use xcq_extension::decl_extension;
|
|
|
|
pub trait Config {
|
|
type AssetId: Codec;
|
|
type AccountId: Codec;
|
|
type Balance: Codec;
|
|
}
|
|
decl_extension! {
|
|
pub trait ExtensionFungibles {
|
|
type Config: Config;
|
|
fn total_supply(asset: <Self::Config as Config>::AssetId) -> <Self::Config as Config>::Balance;
|
|
fn balance(asset: <Self::Config as Config>::AssetId, who: <Self::Config as Config>::AccountId) -> <Self::Config as Config>::Balance;
|
|
}
|
|
}
|
|
<span class="boring">}</span></code></pre></pre>
|
|
<ul>
|
|
<li><code>impl_extensions</code> macro: Generates extension implementations and extension-level metadata.</li>
|
|
</ul>
|
|
<p><strong>Example Usage</strong>:</p>
|
|
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
</span><span class="boring">fn main() {
|
|
</span>// ExtensionImpl is an aggregate struct to impl different extensions
|
|
struct ExtensionImpl;
|
|
impl extension_fungibles::Config for ExtensionImpl {
|
|
type AssetId = u32;
|
|
type AccountId = [u8; 32];
|
|
type Balance = u64;
|
|
}
|
|
impl_extensions! {
|
|
impl extension_core::ExtensionCore for ExtensionImpl {
|
|
type Config = ExtensionImpl;
|
|
fn has_extension(id: <Self::Config as extension_core::Config>::ExtensionId) -> bool {
|
|
matches!(id, 0 | 1)
|
|
}
|
|
}
|
|
|
|
impl extension_fungibles::ExtensionFungibles for ExtensionImpl {
|
|
type Config = ExtensionImpl;
|
|
#[allow(unused_variables)]
|
|
fn total_supply(asset: <Self::Config as extension_fungibles::Config>::AssetId) -> <Self::Config as extension_fungibles::Config>::Balance {
|
|
200
|
|
}
|
|
#[allow(unused_variables)]
|
|
fn balance(asset: <Self::Config as extension_fungibles::Config>::AssetId, who: <Self::Config as extension_fungibles::Config>::AccountId) -> <Self::Config as extension_fungibles::Config>::Balance {
|
|
100
|
|
}
|
|
}
|
|
}
|
|
<span class="boring">}</span></code></pre></pre>
|
|
<ul>
|
|
<li><code>ExtensionExecutor</code>: Connects extension implementations and <code>xcq-executor</code>.
|
|
All methods of all extensions that a chain supports are amalgamated into a single <code>host_call</code> entry.
|
|
Then this entry is registered as a typed function entry in PolkaVM Linker within the <code>xcq-executor</code>.
|
|
Given the extension ID and call data encoded in SCALE format, call requests from the guest XCQ program are dispatched to corresponding extensions:</li>
|
|
</ul>
|
|
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
</span><span class="boring">fn main() {
|
|
</span>linker
|
|
.define_typed(
|
|
"host_call",
|
|
move |caller: Caller<'_, Self::UserData>,
|
|
extension_id: u64,
|
|
call_ptr: u32,
|
|
call_len: u32|
|
|
-> Result<u64, ExtensionError> {
|
|
...
|
|
});
|
|
<span class="boring">}</span></code></pre></pre>
|
|
<ul>
|
|
<li><code>PermissionController</code>: Filters guest XCQ program calling requests, useful for host chains to disable some queries by filtering invoking sources.</li>
|
|
</ul>
|
|
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
</span><span class="boring">fn main() {
|
|
</span>pub trait PermissionController {
|
|
fn is_allowed(extension_id: ExtensionIdTy, call: &[u8], source: InvokeSource) -> bool;
|
|
}
|
|
#[derive(Copy, Clone)]
|
|
pub enum InvokeSource {
|
|
RuntimeAPI,
|
|
XCM,
|
|
Extrinsic,
|
|
Runtime,
|
|
}
|
|
<span class="boring">}</span></code></pre></pre>
|
|
<h3 id="xcq-program-structure"><a class="header" href="#xcq-program-structure">XCQ Program Structure</a></h3>
|
|
<p>An XCQ program is structured as a PolkaVM program with the following key components:</p>
|
|
<ul>
|
|
<li>
|
|
<p>Imported Functions:</p>
|
|
<ul>
|
|
<li>
|
|
<p><code>host_call</code>: Dispatches call requests to the XCQ Extension Executor.</p>
|
|
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
</span><span class="boring">fn main() {
|
|
</span>#[polkavm_derive::polkavm_import]
|
|
extern "C" {
|
|
fn host_call(extension_id: u64, call_ptr: u32, call_len: u32) -> u64;
|
|
}
|
|
<span class="boring">}</span></code></pre></pre>
|
|
<p>Results are SCALE-encoded bytes, with the pointer address (lower 32 bits) and length (higher 32 bits) packed into a u64.</p>
|
|
</li>
|
|
<li>
|
|
<p><code>return_ty</code>: Returns the type of the function call result.</p>
|
|
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
</span><span class="boring">fn main() {
|
|
</span>#[polkavm_derive::polkavm_import]
|
|
extern "C" {
|
|
fn return_ty(extension_id: u64, call_index: u32) -> u64;
|
|
}
|
|
<span class="boring">}</span></code></pre></pre>
|
|
<p>Results are SCALE-encoded bytes, with the pointer address and length packed similarly to <code>host_call</code>.</p>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<p>Exported Functions:</p>
|
|
<ul>
|
|
<li><code>main</code>: The entry point of the XCQ program. It performs type checking, arguments and results passing and executes the query.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h3 id="xcq-program-execution-flow"><a class="header" href="#xcq-program-execution-flow">XCQ Program Execution Flow</a></h3>
|
|
<p>The interaction between an XCQ program and the XCQ Extension Executor follows these steps:</p>
|
|
<ol>
|
|
<li>
|
|
<p>Program Loading: The Executor loads the PolkaVM program binary.</p>
|
|
</li>
|
|
<li>
|
|
<p>Environment Setup: The Executor configures the PolkaVM environment, registering host functions like <code>host_call</code> and <code>return_ty</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p>Main Function Execution: The Executor calls the program's <code>main</code> function, passing serialized query arguments.</p>
|
|
</li>
|
|
<li>
|
|
<p>Program Execution:</p>
|
|
<ol>
|
|
<li>Type Checking: The program uses the <code>return_ty</code> function to ensure compatibility with supported chain extensions.</li>
|
|
<li>Query Execution: The program executes the query using <code>host_call</code> and performs custom computations.</li>
|
|
<li>Result Serialization: The program serializes the result, writes it to shared memory, and returns the pointer and length to the executor.</li>
|
|
</ol>
|
|
</li>
|
|
<li>
|
|
<p>Result Retrieval: The Executor reads the result from shared memory and returns it to the caller.</p>
|
|
</li>
|
|
</ol>
|
|
<h3 id="xcm-integration"><a class="header" href="#xcm-integration">XCM integration</a></h3>
|
|
<p>The integration of XCQ into XCM is achieved by adding a new instruction to XCM, as well as a new variant of the <code>Response</code> type in <code>QueryResponse</code> message.:</p>
|
|
<ul>
|
|
<li>A new <code>ReportQuery</code> instruction</li>
|
|
</ul>
|
|
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
</span><span class="boring">fn main() {
|
|
</span>ReportQuery {
|
|
query: SizeLimitedXcq,
|
|
weight_limit: WeightLimit,
|
|
info: QueryResponseInfo,
|
|
}
|
|
<span class="boring">}</span></code></pre></pre>
|
|
<p>Report to a given destination the results of an XCQ query. After query, a <code>QueryResponse</code> message of type <code>XcqResult</code> will be sent to the described destination.</p>
|
|
<p>Operands:</p>
|
|
<ul>
|
|
<li>
|
|
<p><code>query: SizeLimitedXcq</code> has a size limit(2MB)</p>
|
|
<ul>
|
|
<li><code>program: Vec<u8></code>: A pre-built PVM program binary.</li>
|
|
<li><code>input: Vec<u8></code>: The arguments of the program.</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<p><code>weight_limit: WeightLimit</code>: The maximum weight that the query should take. <code>WeightLimit</code> is an enum that can specify either <code>Limit(Weight)</code> or <code>Unlimited</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p><code>info: QueryResponseInfo</code>: Information for making the response.</p>
|
|
<ul>
|
|
<li><code>destination: Location</code>: The destination to which the query response message should be sent.</li>
|
|
<li><code>query_id: Compact<QueryId></code>: The <code>query_id</code> field of the <code>QueryResponse</code> message</li>
|
|
<li><code>max_weight: Weight</code>: The <code>max_weight</code> field of the <code>QueryResponse</code> message</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<p>Add a new variant to the <code>Response</code> type in <code>QueryResponse</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>XcqResult = 6 (XcqResult)</code>
|
|
<code>XcqResult</code> is a enum</p>
|
|
<ul>
|
|
<li><code>Ok = 0 (Vec<u8>)</code>: XCQ executes successfully with a SCALE-encoded response.</li>
|
|
<li><code>Err = 1 (ErrorCode)</code>: XCQ fails with an error code.
|
|
<code>ErrorCode</code> is a enum</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<p><code>ExceedMaxWeight = 0</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>MemoryAllocationError = 1</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>MemoryAccessError = 2</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>CallError = 3</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>OtherPVMError = 4</code></p>
|
|
</li>
|
|
</ul>
|
|
<h4 id="errors"><a class="header" href="#errors">Errors</a></h4>
|
|
<ul>
|
|
<li><code>BadOrigin</code></li>
|
|
<li><code>DestinationUnsupported</code></li>
|
|
</ul>
|
|
<h2 id="drawbacks"><a class="header" href="#drawbacks">Drawbacks</a></h2>
|
|
<h3 id="performance-issues"><a class="header" href="#performance-issues">Performance issues</a></h3>
|
|
<ul>
|
|
<li>XCQ Query Program Size: The size of XCQ query programs should be optimized to ensure efficient storage and transmission via XCMP/HRMP.
|
|
Some strategies to address this issue include:
|
|
<ul>
|
|
<li>Exploring modular program structures that allow for separate storage and transmission of core logic and supporting elements. PolkaVM supports splitting the program into multiple modules.</li>
|
|
<li>Establishing guidelines for optimizing dynamic memory usage within query programs</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h3 id="user-experience-issues"><a class="header" href="#user-experience-issues">User experience issues</a></h3>
|
|
<ul>
|
|
<li>Debugging: Currently, there is no full-fledged debuggers for PolkaVM programs. The only debugging approach is to set the PolkaVM backend in interpreter mode and then log the operations at the assembly level, which is too low-level to debug efficiently.</li>
|
|
<li>Gas computation: According to <a href="https://github.com/koute/polkavm/issues/17">this issue</a>, the gas cost model of PolkaVM is not accurate for now.</li>
|
|
</ul>
|
|
<h2 id="testing-security-and-privacy"><a class="header" href="#testing-security-and-privacy">Testing, Security, and Privacy</a></h2>
|
|
<ul>
|
|
<li>
|
|
<p>Testing:</p>
|
|
<ul>
|
|
<li>A comprehensive test suite should be developed to cover various scenarios:
|
|
<ul>
|
|
<li>Positive test cases:
|
|
<ul>
|
|
<li>Basic queries with various extensions, data types, return values, custom computations, etc.</li>
|
|
<li>Accurate conversion between given weight limit and the gas limit of PolkaVM</li>
|
|
</ul>
|
|
</li>
|
|
<li>Negative test cases:
|
|
<ul>
|
|
<li>Queries exceeding weight limits</li>
|
|
<li>Invoking queries from unauthorized sources</li>
|
|
</ul>
|
|
</li>
|
|
<li>Edge cases:
|
|
<ul>
|
|
<li>Queries with minimal or maximum allowed input sizes</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li>Integration tests to ensure proper interaction with off-chain wallets/UI and on-chain XCM, including the aforementioned use cases in <strong>Motivation</strong> section.</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<p>Security:</p>
|
|
<ul>
|
|
<li>The XCQ system must enforce a strict read-only policy for all query operations. A mechanism should be implemented to prevent any state-changing operations within XCQ queries. For example, perform a final rollback in <code>frame_support::storage::with_transaction</code> to ensure the storage won't be changed.</li>
|
|
<li>Clear guidelines and best practices should be provided for parachain developers to ensure secure implementation.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<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>It's a new functionality, which doesn't modify the existing implementations.</p>
|
|
<h3 id="ergonomics"><a class="header" href="#ergonomics">Ergonomics</a></h3>
|
|
<p>The proposal facilitate the wallets and dApps developers. Developers no longer need to examine every concrete implementation to support conceptually similar operations across different chains. Additionally, they gain a more modular development experience through encapsulating custom computations over the exposed APIs in PolkaVM programs.</p>
|
|
<h3 id="compatibility"><a class="header" href="#compatibility">Compatibility</a></h3>
|
|
<p>The proposal defines new apis, which doesn't break compatibility with existing interfaces.</p>
|
|
<h2 id="prior-art-and-references"><a class="header" href="#prior-art-and-references">Prior Art and References</a></h2>
|
|
<p>There are several discussions related to the proposal, including:</p>
|
|
<ul>
|
|
<li><a href="https://forum.polkadot.network/t/wasm-view-functions/1045">https://forum.polkadot.network/t/wasm-view-functions/1045</a> is the original discussion about having a mechanism to avoid code duplications between the runtime and front-ends/wallets. In the original design, the custom computations are compiled as a wasm function.</li>
|
|
<li><a href="https://github.com/paritytech/polkadot-sdk/issues/216">https://github.com/paritytech/polkadot-sdk/issues/216</a> is the issue tracking the <code>view functions</code> implementation in runtime implementations</li>
|
|
<li><a href="https://github.com/paritytech/polkadot-sdk/pull/4722">https://github.com/paritytech/polkadot-sdk/pull/4722</a> is the on-going <code>view function</code> pull request. It works at pallet level. If two chains use two different pallets to provide similar functionalities, like pallet-assets and pallet-erc20, we still need to have different codes to support. Therefore, it doesn't conflict with XCQ, and can be utilized by XCQ.</li>
|
|
</ul>
|
|
<h2 id="unresolved-questions"><a class="header" href="#unresolved-questions">Unresolved Questions</a></h2>
|
|
<ul>
|
|
<li>The metadata of the XCQ extensions can be integrated into <code>frame-metadata</code>'s <code>CustomMetadata</code> field, but the trade-offs (i.e. compatibility between versions) need examination.</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>
|
|
|
|
</main>
|
|
|
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
<!-- Mobile navigation buttons -->
|
|
<a rel="prev" href="../proposed/0125-xcm-asset-metadata.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/0001-agile-coretime.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="../proposed/0125-xcm-asset-metadata.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/0001-agile-coretime.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>
|