Files
rfc-index/vac/raw/sds.html
2025-12-22 15:08:29 +00:00

685 lines
59 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE HTML>
<html lang="en" class="ayu" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>SDS - Vac RFC</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<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="../../custom.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 ? "navy" : "ayu";
</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('ayu')
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="../../index.html">Introduction</a></li><li class="chapter-item expanded "><a href="../../vac/index.html"><strong aria-hidden="true">1.</strong> Vac</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../vac/1/coss.html"><strong aria-hidden="true">1.1.</strong> 1/COSS</a></li><li class="chapter-item expanded "><a href="../../vac/2/mvds.html"><strong aria-hidden="true">1.2.</strong> 2/MVDS</a></li><li class="chapter-item expanded "><a href="../../vac/3/remote-log.html"><strong aria-hidden="true">1.3.</strong> 3/Remote Log</a></li><li class="chapter-item expanded "><a href="../../vac/4/mvds-meta.html"><strong aria-hidden="true">1.4.</strong> 4/MVDS Meta</a></li><li class="chapter-item expanded "><a href="../../vac/25/libp2p-dns-discovery.html"><strong aria-hidden="true">1.5.</strong> 25/Libp2p DNS Discovery</a></li><li class="chapter-item expanded "><a href="../../vac/32/rln-v1.html"><strong aria-hidden="true">1.6.</strong> 32/RLN-V1</a></li><li class="chapter-item expanded "><a href="../../vac/raw/index.html"><strong aria-hidden="true">1.7.</strong> Raw</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../vac/raw/consensus-hashgraphlike.html"><strong aria-hidden="true">1.7.1.</strong> Consensus Hashgraphlike</a></li><li class="chapter-item expanded "><a href="../../vac/raw/decentralized-messaging-ethereum.html"><strong aria-hidden="true">1.7.2.</strong> Decentralized Messaging Ethereum</a></li><li class="chapter-item expanded "><a href="../../vac/raw/eth-mls-offchain.html"><strong aria-hidden="true">1.7.3.</strong> ETH MLS Offchain</a></li><li class="chapter-item expanded "><a href="../../vac/raw/eth-mls-onchain.html"><strong aria-hidden="true">1.7.4.</strong> ETH MLS Onchain</a></li><li class="chapter-item expanded "><a href="../../vac/raw/deleted/eth-secpm.html"><strong aria-hidden="true">1.7.5.</strong> ETH SecPM</a></li><li class="chapter-item expanded "><a href="../../vac/raw/gossipsub-tor-push.html"><strong aria-hidden="true">1.7.6.</strong> Gossipsub Tor Push</a></li><li class="chapter-item expanded "><a href="../../vac/raw/logos-capability-discovery.html"><strong aria-hidden="true">1.7.7.</strong> Logos Capability Discovery</a></li><li class="chapter-item expanded "><a href="../../vac/raw/mix.html"><strong aria-hidden="true">1.7.8.</strong> Mix</a></li><li class="chapter-item expanded "><a href="../../vac/raw/noise-x3dh-double-ratchet.html"><strong aria-hidden="true">1.7.9.</strong> Noise X3DH Double Ratchet</a></li><li class="chapter-item expanded "><a href="../../vac/raw/rln-interep-spec.html"><strong aria-hidden="true">1.7.10.</strong> RLN Interep Spec</a></li><li class="chapter-item expanded "><a href="../../vac/raw/rln-stealth-commitments.html"><strong aria-hidden="true">1.7.11.</strong> RLN Stealth Commitments</a></li><li class="chapter-item expanded "><a href="../../vac/raw/rln-v2.html"><strong aria-hidden="true">1.7.12.</strong> RLN-V2</a></li><li class="chapter-item expanded "><a href="../../vac/raw/sds.html" class="active"><strong aria-hidden="true">1.7.13.</strong> SDS</a></li></ol></li><li class="chapter-item expanded "><a href="../../vac/template.html"><strong aria-hidden="true">1.8.</strong> Template</a></li></ol></li><li class="chapter-item expanded "><a href="../../waku/index.html"><strong aria-hidden="true">2.</strong> Waku</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../waku/standards/core/index.html"><strong aria-hidden="true">2.1.</strong> Standards - Core</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../waku/standards/core/10/waku2.html"><strong aria-hidden="true">2.1.1.</strong> 10/Waku2</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/11/relay.html"><strong aria-hidden="true">2.1.2.</strong> 11/Relay</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/12/filter.html"><strong aria-hidden="true">2.1.3.</strong> 12/Filter</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/13/store.html"><strong aria-hidden="true">2.1.4.</strong> 13/Store</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/14/message.html"><strong aria-hidden="true">2.1.5.</strong> 14/Message</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/15/bridge.html"><strong aria-hidden="true">2.1.6.</strong> 15/Bridge</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/17/rln-relay.html"><strong aria-hidden="true">2.1.7.</strong> 17/RLN Relay</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/19/lightpush.html"><strong aria-hidden="true">2.1.8.</strong> 19/Lightpush</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/31/enr.html"><strong aria-hidden="true">2.1.9.</strong> 31/ENR</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/33/discv5.html"><strong aria-hidden="true">2.1.10.</strong> 33/Discv5</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/34/peer-exchange.html"><strong aria-hidden="true">2.1.11.</strong> 34/Peer Exchange</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/36/bindings-api.html"><strong aria-hidden="true">2.1.12.</strong> 36/Bindings API</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/64/network.html"><strong aria-hidden="true">2.1.13.</strong> 64/Network</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/66/metadata.html"><strong aria-hidden="true">2.1.14.</strong> 66/Metadata</a></li></ol></li><li class="chapter-item expanded "><a href="../../waku/standards/application/index.html"><strong aria-hidden="true">2.2.</strong> Standards - Application</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../waku/standards/application/20/toy-eth-pm.html"><strong aria-hidden="true">2.2.1.</strong> 20/Toy ETH PM</a></li><li class="chapter-item expanded "><a href="../../waku/standards/application/26/payload.html"><strong aria-hidden="true">2.2.2.</strong> 26/Payload</a></li><li class="chapter-item expanded "><a href="../../waku/standards/application/53/x3dh.html"><strong aria-hidden="true">2.2.3.</strong> 53/X3DH</a></li><li class="chapter-item expanded "><a href="../../waku/standards/application/54/x3dh-sessions.html"><strong aria-hidden="true">2.2.4.</strong> 54/X3DH Sessions</a></li></ol></li><li class="chapter-item expanded "><a href="../../waku/standards/legacy/index.html"><strong aria-hidden="true">2.3.</strong> Standards - Legacy</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../waku/standards/legacy/6/waku1.html"><strong aria-hidden="true">2.3.1.</strong> 6/Waku1</a></li><li class="chapter-item expanded "><a href="../../waku/standards/legacy/7/data.html"><strong aria-hidden="true">2.3.2.</strong> 7/Data</a></li><li class="chapter-item expanded "><a href="../../waku/standards/legacy/8/mail.html"><strong aria-hidden="true">2.3.3.</strong> 8/Mail</a></li><li class="chapter-item expanded "><a href="../../waku/standards/legacy/9/rpc.html"><strong aria-hidden="true">2.3.4.</strong> 9/RPC</a></li></ol></li><li class="chapter-item expanded "><a href="../../waku/informational/index.html"><strong aria-hidden="true">2.4.</strong> Informational</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../waku/informational/22/toy-chat.html"><strong aria-hidden="true">2.4.1.</strong> 22/Toy Chat</a></li><li class="chapter-item expanded "><a href="../../waku/informational/23/topics.html"><strong aria-hidden="true">2.4.2.</strong> 23/Topics</a></li><li class="chapter-item expanded "><a href="../../waku/informational/27/peers.html"><strong aria-hidden="true">2.4.3.</strong> 27/Peers</a></li><li class="chapter-item expanded "><a href="../../waku/informational/29/config.html"><strong aria-hidden="true">2.4.4.</strong> 29/Config</a></li><li class="chapter-item expanded "><a href="../../waku/informational/30/adaptive-nodes.html"><strong aria-hidden="true">2.4.5.</strong> 30/Adaptive Nodes</a></li></ol></li><li class="chapter-item expanded "><a href="../../waku/deprecated/index.html"><strong aria-hidden="true">2.5.</strong> Deprecated</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../waku/deprecated/5/waku0.html"><strong aria-hidden="true">2.5.1.</strong> 5/Waku0</a></li><li class="chapter-item expanded "><a href="../../waku/deprecated/16/rpc.html"><strong aria-hidden="true">2.5.2.</strong> 16/RPC</a></li><li class="chapter-item expanded "><a href="../../waku/deprecated/18/swap.html"><strong aria-hidden="true">2.5.3.</strong> 18/Swap</a></li><li class="chapter-item expanded "><a href="../../waku/deprecated/fault-tolerant-store.html"><strong aria-hidden="true">2.5.4.</strong> Fault Tolerant Store</a></li></ol></li></ol></li><li class="chapter-item expanded "><a href="../../nomos/index.html"><strong aria-hidden="true">3.</strong> Nomos</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../nomos/raw/index.html"><strong aria-hidden="true">3.1.</strong> Raw</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../nomos/raw/nomosda-encoding.html"><strong aria-hidden="true">3.1.1.</strong> NomosDA Encoding</a></li><li class="chapter-item expanded "><a href="../../nomos/raw/nomosda-network.html"><strong aria-hidden="true">3.1.2.</strong> NomosDA Network</a></li><li class="chapter-item expanded "><a href="../../nomos/raw/p2p-hardware-requirements.html"><strong aria-hidden="true">3.1.3.</strong> P2P Hardware Requirements</a></li><li class="chapter-item expanded "><a href="../../nomos/raw/p2p-nat-solution.html"><strong aria-hidden="true">3.1.4.</strong> P2P NAT Solution</a></li><li class="chapter-item expanded "><a href="../../nomos/raw/p2p-network-bootstrapping.html"><strong aria-hidden="true">3.1.5.</strong> P2P Network Bootstrapping</a></li><li class="chapter-item expanded "><a href="../../nomos/raw/p2p-network.html"><strong aria-hidden="true">3.1.6.</strong> P2P Network</a></li><li class="chapter-item expanded "><a href="../../nomos/raw/sdp.html"><strong aria-hidden="true">3.1.7.</strong> SDP</a></li></ol></li><li class="chapter-item expanded "><a href="../../nomos/deprecated/index.html"><strong aria-hidden="true">3.2.</strong> Deprecated</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../nomos/deprecated/claro.html"><strong aria-hidden="true">3.2.1.</strong> Claro</a></li></ol></li></ol></li><li class="chapter-item expanded "><a href="../../codex/index.html"><strong aria-hidden="true">4.</strong> Codex</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../codex/raw/index.html"><strong aria-hidden="true">4.1.</strong> Raw</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../codex/raw/codex-block-exchange.html"><strong aria-hidden="true">4.1.1.</strong> Block Exchange</a></li><li class="chapter-item expanded "><a href="../../codex/raw/codex-marketplace.html"><strong aria-hidden="true">4.1.2.</strong> Marketplace</a></li></ol></li></ol></li><li class="chapter-item expanded "><a href="../../status/index.html"><strong aria-hidden="true">5.</strong> Status</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../status/24/curation.html"><strong aria-hidden="true">5.1.</strong> 24/Curation</a></li><li class="chapter-item expanded "><a href="../../status/28/featuring.html"><strong aria-hidden="true">5.2.</strong> 28/Featuring</a></li><li class="chapter-item expanded "><a href="../../status/55/1to1-chat.html"><strong aria-hidden="true">5.3.</strong> 55/1-to-1 Chat</a></li><li class="chapter-item expanded "><a href="../../status/56/communities.html"><strong aria-hidden="true">5.4.</strong> 56/Communities</a></li><li class="chapter-item expanded "><a href="../../status/61/community-history-service.html"><strong aria-hidden="true">5.5.</strong> 61/Community History Service</a></li><li class="chapter-item expanded "><a href="../../status/62/payloads.html"><strong aria-hidden="true">5.6.</strong> 62/Payloads</a></li><li class="chapter-item expanded "><a href="../../status/63/keycard-usage.html"><strong aria-hidden="true">5.7.</strong> 63/Keycard Usage</a></li><li class="chapter-item expanded "><a href="../../status/65/account-address.html"><strong aria-hidden="true">5.8.</strong> 65/Account Address</a></li><li class="chapter-item expanded "><a href="../../status/71/push-notification-server.html"><strong aria-hidden="true">5.9.</strong> 71/Push Notification Server</a></li><li class="chapter-item expanded "><a href="../../status/raw/index.html"><strong aria-hidden="true">5.10.</strong> Raw</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../status/raw/simple-scaling.html"><strong aria-hidden="true">5.10.1.</strong> Simple Scaling</a></li><li class="chapter-item expanded "><a href="../../status/raw/status-app-protocols.html"><strong aria-hidden="true">5.10.2.</strong> Status App Protocols</a></li><li class="chapter-item expanded "><a href="../../status/raw/status-mvds.html"><strong aria-hidden="true">5.10.3.</strong> Status MVDS</a></li><li class="chapter-item expanded "><a href="../../status/raw/url-data.html"><strong aria-hidden="true">5.10.4.</strong> URL Data</a></li><li class="chapter-item expanded "><a href="../../status/raw/url-scheme.html"><strong aria-hidden="true">5.10.5.</strong> URL Scheme</a></li></ol></li><li class="chapter-item expanded "><a href="../../status/deprecated/index.html"><strong aria-hidden="true">5.11.</strong> Deprecated</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../status/deprecated/3rd-party.html"><strong aria-hidden="true">5.11.1.</strong> 3rd Party</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/account.html"><strong aria-hidden="true">5.11.2.</strong> Account</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/client.html"><strong aria-hidden="true">5.11.3.</strong> Client</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/dapp-browser-API-usage.html"><strong aria-hidden="true">5.11.4.</strong> Dapp Browser API Usage</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/eips.html"><strong aria-hidden="true">5.11.5.</strong> EIPs</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/ethereum-usage.html"><strong aria-hidden="true">5.11.6.</strong> Ethereum Usage</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/group-chat.html"><strong aria-hidden="true">5.11.7.</strong> Group Chat</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/IPFS-gateway-for-sticker-Pack.html"><strong aria-hidden="true">5.11.8.</strong> IPFS Gateway for Sticker Pack</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/keycard-usage-for-wallet-and-chat-keys.html"><strong aria-hidden="true">5.11.9.</strong> Keycard Usage for Wallet and Chat Keys</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/notifications.html"><strong aria-hidden="true">5.11.10.</strong> Notifications</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/payloads.html"><strong aria-hidden="true">5.11.11.</strong> Payloads</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/push-notification-server.html"><strong aria-hidden="true">5.11.12.</strong> Push Notification Server</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/secure-transport.html"><strong aria-hidden="true">5.11.13.</strong> Secure Transport</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/waku-mailserver.html"><strong aria-hidden="true">5.11.14.</strong> Waku Mailserver</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/waku-usage.html"><strong aria-hidden="true">5.11.15.</strong> Waku Usage</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/whisper-mailserver.html"><strong aria-hidden="true">5.11.16.</strong> Whisper Mailserver</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/whisper-usage.html"><strong aria-hidden="true">5.11.17.</strong> Whisper Usage</a></li></ol></li></ol></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</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="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">Vac RFC</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>
<a href="https://github.com/vacp2p/rfc-index" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></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>
<h1 id="sds"><a class="header" href="#sds">SDS</a></h1>
<div class="table-wrapper"><table><thead><tr><th>Field</th><th>Value</th></tr></thead><tbody>
<tr><td>Name</td><td>Scalable Data Sync protocol for distributed logs</td></tr>
<tr><td>Status</td><td>raw</td></tr>
<tr><td>Editor</td><td>Hanno Cornelius <a href="mailto:hanno@status.im">hanno@status.im</a></td></tr>
<tr><td>Contributors</td><td>Akhil Peddireddy <a href="mailto:akhil@status.im">akhil@status.im</a></td></tr>
</tbody></table>
</div><!-- timeline:start -->
<h2 id="timeline"><a class="header" href="#timeline">Timeline</a></h2>
<ul>
<li><strong>2025-12-22</strong><a href="https://github.com/vacp2p/rfc-index/blob/0f1855edcf68ef982c4ce478b67d660809aa9830/docs/vac/raw/sds.md"><code>0f1855e</code></a> — Chore/fix headers (#239)</li>
<li><strong>2025-12-22</strong><a href="https://github.com/vacp2p/rfc-index/blob/b1a578393edf8487ccc97a5f25b25af9bf41efb3/docs/vac/raw/sds.md"><code>b1a5783</code></a> — Chore/mdbook updates (#237)</li>
<li><strong>2025-12-18</strong><a href="https://github.com/vacp2p/rfc-index/blob/d03e699084774ebecef9c6d4662498907c5e2080/docs/vac/raw/sds.md"><code>d03e699</code></a> — ci: add mdBook configuration (#233)</li>
<li><strong>2025-10-24</strong><a href="https://github.com/vacp2p/rfc-index/blob/69802377a8c1df53659ac05c7aa93543be4b3e4a/vac/raw/sds.md"><code>6980237</code></a> — Fix Linting Errors (#204)</li>
<li><strong>2025-10-13</strong><a href="https://github.com/vacp2p/rfc-index/blob/171e934d6186a5952f0458bbe42c966859fe2a31/vac/raw/sds.md"><code>171e934</code></a> — docs: add SDS-Repair extension (#176)</li>
<li><strong>2025-10-02</strong><a href="https://github.com/vacp2p/rfc-index/blob/6672c5bedf5a08d3045d3b7d23d2b7a2e5d3aa2f/vac/raw/sds.md"><code>6672c5b</code></a> — docs: update lamport timestamps to uint64, pegged to current time (#196)</li>
<li><strong>2025-09-15</strong><a href="https://github.com/vacp2p/rfc-index/blob/b1da70386edb15303fb8aa587b8a5da784a2d644/vac/raw/sds.md"><code>b1da703</code></a> — fix: use milliseconds for Lamport timestamp initialization (#179)</li>
<li><strong>2025-08-22</strong><a href="https://github.com/vacp2p/rfc-index/blob/3505da6bd66d2830e5711deb0b5c2b4de9212a4d/vac/raw/sds.md"><code>3505da6</code></a> — sds lint fix (#177)</li>
<li><strong>2025-08-19</strong><a href="https://github.com/vacp2p/rfc-index/blob/536d31b5b7641bd451cf35b94e8de1aa8a6c9f64/vac/raw/sds.md"><code>536d31b</code></a> — docs: re-add sender ID to messages (#170)</li>
<li><strong>2025-03-07</strong><a href="https://github.com/vacp2p/rfc-index/blob/8ee2a6d6b232838d83374c35e2413f84436ecf64/vac/raw/sds.md"><code>8ee2a6d</code></a> — docs: add optional retrieval hint to causal history in sds (#130)</li>
<li><strong>2025-02-20</strong><a href="https://github.com/vacp2p/rfc-index/blob/235c1d5aa676d8278036003d4493c7c32afc033b/vac/raw/sds.md"><code>235c1d5</code></a> — docs: clarify receiving sync messages (#131)</li>
<li><strong>2025-02-18</strong><a href="https://github.com/vacp2p/rfc-index/blob/718245979fd1c67d04d1eab7ea31a4aad6dbc1d2/vac/raw/sds.md"><code>7182459</code></a> — docs: update sds sync message requirements (#129)</li>
<li><strong>2025-01-28</strong><a href="https://github.com/vacp2p/rfc-index/blob/7a01711ffc5b50186e111bc2f4fa2e4b02b26bf3/vac/raw/sds.md"><code>7a01711</code></a> — fix(sds): remove optional from causal history field in Message protobuf (#123)</li>
<li><strong>2024-12-17</strong><a href="https://github.com/vacp2p/rfc-index/blob/08b363d67e34277e7881a20e36f788978cb0f93c/vac/raw/sds.md"><code>08b363d</code></a> — Update SDS.md: Remove Errors (#115)</li>
<li><strong>2024-11-28</strong><a href="https://github.com/vacp2p/rfc-index/blob/bee78c40b9a94ed4c40fe6ba2505b6b0654206b4/vac/raw/sds.md"><code>bee78c4</code></a> — docs: add SDS protocol for scalable e2e reliability (#108)</li>
</ul>
<!-- timeline:end -->
<h2 id="abstract"><a class="header" href="#abstract">Abstract</a></h2>
<p>This specification introduces the Scalable Data Sync (SDS) protocol
to achieve end-to-end reliability
when consolidating distributed logs in a decentralized manner.
The protocol is designed for a peer-to-peer (p2p) topology
where an append-only log is maintained by each member of a group of nodes
who may individually append new entries to their local log at any time and
is interested in merging new entries from other nodes in real-time or close to real-time
while maintaining a consistent order.
The outcome of the log consolidation procedure is
that all nodes in the group eventually reflect in their own logs
the same entries in the same order.
The protocol aims to scale to very large groups.</p>
<h2 id="motivation"><a class="header" href="#motivation">Motivation</a></h2>
<p>A common application that fits this model is a p2p group chat (or group communication),
where the participants act as log nodes
and the group conversation is modelled as the consolidated logs
maintained on each node.
The problem of end-to-end reliability can then be stated as
ensuring that all participants eventually see the same sequence of messages
in the same causal order,
despite the challenges of network latency, message loss,
and scalability present in any communications transport layer.
The rest of this document will assume the terminology of a group communication:
log nodes being the <em>participants</em> in the group chat
and the logged entries being the <em>messages</em> exchanged between participants.</p>
<h2 id="design-assumptions"><a class="header" href="#design-assumptions">Design Assumptions</a></h2>
<p>We make the following simplifying assumptions for a proposed reliability protocol:</p>
<ul>
<li><strong>Broadcast routing:</strong>
Messages are broadcast disseminated by the underlying transport.
The selected transport takes care of routing messages
to all participants of the communication.</li>
<li><strong>Store nodes:</strong>
There are high-availability caches (a.k.a. Store nodes)
from which missed messages can be retrieved.
These caches maintain the full history of all messages that have been broadcast.
This is an optional element in the protocol design,
but improves scalability by reducing direct interactions between participants.</li>
<li><strong>Message ID:</strong>
Each message has a globally unique, immutable ID (or hash).
Messages can be requested from the high-availability caches or
other participants using the corresponding message ID.</li>
<li><strong>Participant ID:</strong>
Each participant has a globally unique, immutable ID
visible to other participants in the communication.</li>
<li><strong>Sender ID:</strong>
The <strong>Participant ID</strong> of the original sender of a message,
often coupled with a <strong>Message ID</strong>.</li>
</ul>
<h2 id="wire-protocol"><a class="header" href="#wire-protocol">Wire protocol</a></h2>
<p>The keywords “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”,
“SHOULD NOT”, “RECOMMENDED”, “MAY”, and
“OPTIONAL” in this document are to be interpreted as described in <a href="https://www.ietf.org/rfc/rfc2119.txt">2119</a>.</p>
<h3 id="message"><a class="header" href="#message">Message</a></h3>
<p>Messages MUST adhere to the following meta structure:</p>
<pre><code class="language-protobuf">syntax = "proto3";
message HistoryEntry {
string message_id = 1; // Unique identifier of the SDS message, as defined in `Message`
optional bytes retrieval_hint = 2; // Optional information to help remote parties retrieve this SDS message; For example, A Waku deterministic message hash or routing payload hash
optional string sender_id = 3; // Participant ID of original message sender. Only populated if using optional SDS Repair extension
}
message Message {
string sender_id = 1; // Participant ID of the message sender
string message_id = 2; // Unique identifier of the message
string channel_id = 3; // Identifier of the channel to which the message belongs
optional uint64 lamport_timestamp = 10; // Logical timestamp for causal ordering in channel
repeated HistoryEntry causal_history = 11; // List of preceding message IDs that this message causally depends on. Generally 2 or 3 message IDs are included.
optional bytes bloom_filter = 12; // Bloom filter representing received message IDs in channel
repeated HistoryEntry repair_request = 13; // Capped list of history entries missing from sender's causal history. Only populated if using the optional SDS Repair extension.
optional bytes content = 20; // Actual content of the message
}
</code></pre>
<p>The sending participant MUST include its own globally unique identifier in the <code>sender_id</code> field.
In addition, it MUST include a globally unique identifier for the message in the <code>message_id</code> field,
likely based on a message hash.
The <code>channel_id</code> field MUST be set to the identifier of the channel of group communication
that is being synchronized.
For simple group communications without individual channels,
the <code>channel_id</code> SHOULD be set to <code>0</code>.
The <code>lamport_timestamp</code>, <code>causal_history</code> and
<code>bloom_filter</code> fields MUST be set according to the <a href="#protocol-steps">protocol steps</a>
set out below.
These fields MAY be left unset in the case of <a href="#ephemeral-messages">ephemeral messages</a>.
The message <code>content</code> MAY be left empty for <a href="#periodic-sync-message">periodic sync messages</a>,
otherwise it MUST contain the application-level content</p>
<blockquote>
<p><strong><em>Note:</em></strong> Close readers may notice that,
outside of filtering messages originating from the sender itself,
the <code>sender_id</code> field is not used for much.
Its importance is expected to increase once a p2p retrieval mechanism is added to SDS,
as is planned for the protocol.</p>
</blockquote>
<h3 id="participant-state"><a class="header" href="#participant-state">Participant state</a></h3>
<p>Each participant MUST maintain:</p>
<ul>
<li>A Lamport timestamp for each channel of communication,
initialized to current epoch time in millisecond resolution.
The Lamport timestamp is increased as described in the <a href="#protocol-steps">protocol steps</a>
to maintain a logical ordering of events while staying close to the current epoch time.
This allows the messages from new joiners to be correctly ordered with other recent messages,
without these new participants first having to synchronize past messages to discover the current Lamport timestamp.</li>
<li>A bloom filter for received message IDs per channel.
The bloom filter SHOULD be rolled over and
recomputed once it reaches a predefined capacity of message IDs.
Furthermore,
it SHOULD be designed to minimize false positives through an optimal selection of
size and hash functions.</li>
<li>A buffer for unacknowledged outgoing messages</li>
<li>A buffer for incoming messages with unmet causal dependencies</li>
<li>A local log (or history) for each channel,
containing all message IDs in the communication channel,
ordered by Lamport timestamp.</li>
</ul>
<p>Messages in the unacknowledged outgoing buffer can be in one of three states:</p>
<ol>
<li><strong>Unacknowledged</strong> - there has been no acknowledgement of message receipt
by any participant in the channel</li>
<li><strong>Possibly acknowledged</strong> - there has been ambiguous indication that the message
has been <em>possibly</em> received by at least one participant in the channel</li>
<li><strong>Acknowledged</strong> - there has been sufficient indication that the message
has been received by at least some of the participants in the channel.
This state will also remove the message from the outgoing buffer.</li>
</ol>
<h3 id="protocol-steps"><a class="header" href="#protocol-steps">Protocol Steps</a></h3>
<p>For each channel of communication,
participants MUST follow these protocol steps to populate and interpret
the <code>lamport_timestamp</code>, <code>causal_history</code> and <code>bloom_filter</code> fields.</p>
<h4 id="send-message"><a class="header" href="#send-message">Send Message</a></h4>
<p>Before broadcasting a message:</p>
<ul>
<li>the participant MUST set its local Lamport timestamp
to the maximum between the current value + <code>1</code>
and the current epoch time in milliseconds.
In other words the local Lamport timestamp is set to <code>max(timeNowInMs, current_lamport_timestamp + 1)</code>.</li>
<li>the participant MUST include the increased Lamport timestamp in the message's <code>lamport_timestamp</code> field.</li>
<li>the participant MUST determine the preceding few message IDs in the local history
and include these in an ordered list in the <code>causal_history</code> field.
The number of message IDs to include in the <code>causal_history</code> depends on the application.
We recommend a causal history of two message IDs.</li>
<li>the participant MAY include a <code>retrieval_hint</code> in the <code>HistoryEntry</code>
for each message ID in the <code>causal_history</code> field.
This is an application-specific field to facilitate retrieval of messages,
e.g. from high-availability caches.</li>
<li>the participant MUST include the current <code>bloom_filter</code>
state in the broadcast message.</li>
</ul>
<p>After broadcasting a message,
the message MUST be added to the participants buffer
of unacknowledged outgoing messages.</p>
<h4 id="receive-message"><a class="header" href="#receive-message">Receive Message</a></h4>
<p>Upon receiving a message,</p>
<ul>
<li>the participant SHOULD ignore the message if it has a <code>sender_id</code> matching its own.</li>
<li>the participant MAY deduplicate the message by comparing its <code>message_id</code> to previously received message IDs.</li>
<li>the participant MUST <a href="#review-ack-status">review the ACK status</a> of messages
in its unacknowledged outgoing buffer
using the received message's causal history and bloom filter.</li>
<li>if the message has a populated <code>content</code> field,
the participant MUST include the received message ID in its local bloom filter.</li>
<li>the participant MUST verify that all causal dependencies are met
for the received message.
Dependencies are met if the message IDs in the <code>causal_history</code> of the received message
appear in the local history of the receiving participant.</li>
</ul>
<p>If all dependencies are met and the message has a populated <code>content</code> field,
the participant MUST <a href="#deliver-message">deliver the message</a>.
If dependencies are unmet,
the participant MUST add the message to the incoming buffer of messages
with unmet causal dependencies.</p>
<h4 id="deliver-message"><a class="header" href="#deliver-message">Deliver Message</a></h4>
<p>Triggered by the <a href="#receive-message">Receive Message</a> procedure.</p>
<p>If the received messages Lamport timestamp is greater than the participant's
local Lamport timestamp,
the participant MUST update its local Lamport timestamp to match the received message.
The participant MUST insert the message ID into its local log,
based on Lamport timestamp.
If one or more message IDs with the same Lamport timestamp already exists,
the participant MUST follow the <a href="#resolve-conflicts">Resolve Conflicts</a> procedure.</p>
<h4 id="resolve-conflicts"><a class="header" href="#resolve-conflicts">Resolve Conflicts</a></h4>
<p>Triggered by the <a href="#deliver-message">Deliver Message</a> procedure.</p>
<p>The participant MUST order messages with the same Lamport timestamp
in ascending order of message ID.
If the message ID is implemented as a hash of the message,
this means the message with the lowest hash would precede
other messages with the same Lamport timestamp in the local log.</p>
<h4 id="review-ack-status"><a class="header" href="#review-ack-status">Review ACK Status</a></h4>
<p>Triggered by the <a href="#receive-message">Receive Message</a> procedure.</p>
<p>For each message in the unacknowledged outgoing buffer,
based on the received <code>bloom_filter</code> and <code>causal_history</code>:</p>
<ul>
<li>the participant MUST mark all messages in the received <code>causal_history</code> as <strong>acknowledged</strong>.</li>
<li>the participant MUST mark all messages included in the <code>bloom_filter</code>
as <strong>possibly acknowledged</strong>.
If a message appears as <strong>possibly acknowledged</strong> in multiple received bloom filters,
the participant MAY mark it as acknowledged based on probabilistic grounds,
taking into account the bloom filter size and hash number.</li>
</ul>
<h4 id="periodic-incoming-buffer-sweep"><a class="header" href="#periodic-incoming-buffer-sweep">Periodic Incoming Buffer Sweep</a></h4>
<p>The participant MUST periodically check causal dependencies for each message
in the incoming buffer.
For each message in the incoming buffer:</p>
<ul>
<li>the participant MAY attempt to retrieve missing dependencies from the Store node
(high-availability cache) or other peers.
It MAY use the application-specific <code>retrieval_hint</code> in the <code>HistoryEntry</code> to facilitate retrieval.</li>
<li>if all dependencies of a message are met,
the participant MUST proceed to <a href="#deliver-message">deliver the message</a>.</li>
</ul>
<p>If a message's causal dependencies have failed to be met
after a predetermined amount of time,
the participant MAY mark them as <strong>irretrievably lost</strong>.</p>
<h4 id="periodic-outgoing-buffer-sweep"><a class="header" href="#periodic-outgoing-buffer-sweep">Periodic Outgoing Buffer Sweep</a></h4>
<p>The participant MUST rebroadcast <strong>unacknowledged</strong> outgoing messages
after a set period.
The participant SHOULD use distinct resend periods for <strong>unacknowledged</strong> and
<strong>possibly acknowledged</strong> messages,
prioritizing <strong>unacknowledged</strong> messages.</p>
<h4 id="periodic-sync-message"><a class="header" href="#periodic-sync-message">Periodic Sync Message</a></h4>
<p>For each channel of communication,
participants SHOULD periodically send sync messages to maintain state.
These sync messages:</p>
<ul>
<li>MUST be sent with empty content</li>
<li>MUST include a Lamport timestamp increased to <code>max(timeNowInMs, current_lamport_timestamp + 1)</code>,
where <code>timeNowInMs</code> is the current epoch time in milliseconds.</li>
<li>MUST include causal history and bloom filter according to regular message rules</li>
<li>MUST NOT be added to the unacknowledged outgoing buffer</li>
<li>MUST NOT be included in causal histories of subsequent messages</li>
<li>MUST NOT be included in bloom filters</li>
<li>MUST NOT be added to the local log</li>
</ul>
<p>Since sync messages are not persisted,
they MAY have non-unique message IDs without impacting the protocol.
To avoid network activity bursts in large groups,
a participant MAY choose to only send periodic sync messages
if no other messages have been broadcast in the channel after a random backoff period.</p>
<p>Participants MUST process the causal history and bloom filter of these sync messages
following the same steps as regular messages,
but MUST NOT persist the sync messages themselves.</p>
<h4 id="ephemeral-messages"><a class="header" href="#ephemeral-messages">Ephemeral Messages</a></h4>
<p>Participants MAY choose to send short-lived messages for which no synchronization
or reliability is required.
These messages are termed <em>ephemeral</em>.</p>
<p>Ephemeral messages SHOULD be sent with <code>lamport_timestamp</code>, <code>causal_history</code>, and
<code>bloom_filter</code> unset.
Ephemeral messages SHOULD NOT be added to the unacknowledged outgoing buffer
after broadcast.
Upon reception,
ephemeral messages SHOULD be delivered immediately without buffering for causal dependencies
or including in the local log.</p>
<h3 id="sds-repair-sds-r"><a class="header" href="#sds-repair-sds-r">SDS Repair (SDS-R)</a></h3>
<p>SDS Repair (SDS-R) is an optional extension module for SDS,
allowing participants in a communication to collectively repair any gaps in causal history (missing messages)
preferably over a limited time window.
Since SDS-R acts as coordinated rebroadcasting of missing messages,
which involves all participants of the communication,
it is most appropriate in a limited use case for repairing relatively recent missed dependencies.
It is not meant to replace mechanisms for long-term consistency,
such as peer-to-peer syncing or the use of a high-availability centralised cache (Store node).</p>
<h4 id="sds-r-message-fields"><a class="header" href="#sds-r-message-fields">SDS-R message fields</a></h4>
<p>SDS-R adds the following fields to SDS messages:</p>
<ul>
<li><code>sender_id</code> in <code>HistoryEntry</code>:
the original message sender's participant ID.
This is used to determine the group of participants who will respond to a repair request.</li>
<li><code>repair_request</code> in <code>Message</code>:
a capped list of history entries missing for the message sender
and for which it's requesting a repair.</li>
</ul>
<h4 id="sds-r-participant-state"><a class="header" href="#sds-r-participant-state">SDS-R participant state</a></h4>
<p>SDS-R adds the following to each participant state:</p>
<ul>
<li>
<p>Outgoing <strong>repair request buffer</strong>:
a list of locally missing <code>HistoryEntry</code>s
each mapped to a future request timestamp, <code>T_req</code>,
after which this participant will request a repair if at that point the missing dependency has not been repaired yet.
<code>T_req</code> is computed as a pseudorandom backoff from the timestamp when the dependency was detected missing.
<a href="#determine-t_req">Determining <code>T_req</code></a> is described below.
We RECOMMEND that the outgoing repair request buffer be chronologically ordered in ascending order of <code>T_req</code>.</p>
</li>
<li>
<p>Incoming <strong>repair request buffer</strong>:
a list of locally available <code>HistoryEntry</code>s
that were requested for repair by a remote participant
AND for which this participant might be an eligible responder,
each mapped to a future response timestamp, <code>T_resp</code>,
after which this participant will rebroadcast the corresponding requested <code>Message</code> if at that point no other participant had rebroadcast the <code>Message</code>.
<code>T_resp</code> is computed as a pseudorandom backoff from the timestamp when the repair was first requested.
<a href="#determine-t_resp">Determining <code>T_resp</code></a> is described below.
We describe below how a participant can <a href="#determine-response-group">determine if they're an eligible responder</a> for a specific repair request.</p>
</li>
<li>
<p>Augmented local history log:
for each message ID kept in the local log for which the participant could be a repair responder,
the full SDS <code>Message</code> must be cached rather than just the message ID,
in case this participant is called upon to rebroadcast the message.
We describe below how a participant can <a href="#determine-response-group">determine if they're an eligible responder</a> for a specific message.</p>
</li>
</ul>
<p><strong><em>Note:</em></strong> The required state can likely be significantly reduced in future by simply requiring that a responding participant should <em>reconstruct</em> the original <code>Message</code> when rebroadcasting, rather than the simpler, but heavier,
requirement of caching the entire received <code>Message</code> content in local history.</p>
<h4 id="sds-r-global-state"><a class="header" href="#sds-r-global-state">SDS-R global state</a></h4>
<p>For a specific channel (that is, within a specific SDS-controlled communication)
the following SDS-R configuration state SHOULD be common for all participants in the conversation:</p>
<ul>
<li><code>T_min</code>: the <em>minimum</em> time period to wait before a missing causal entry can be repaired.
We RECOMMEND a value of at least 30 seconds.</li>
<li><code>T_max</code>: the <em>maximum</em> time period over which missing causal entries can be repaired.
We RECOMMEND a value of between 120 and 600 seconds.</li>
</ul>
<p>Furthermore, to avoid a broadcast storm with multiple participants responding to a repair request,
participants in a single channel MAY be divided into discrete response groups.
Participants will only respond to a repair request if they are in the response group for that request.
The global <code>num_response_groups</code> variable configures the number of response groups for this communication.
Its use is described below.
A reasonable default value for <code>num_response_groups</code> is one response group for every <code>128</code> participants.
In other words, if the (roughly) expected number of participants is expressed as <code>num_participants</code>, then
<code>num_response_groups = num_participants div 128 + 1</code>.
In other words, if there are fewer than 128 participants in a communication,
they will all belong to the same response group.</p>
<p>We RECOMMEND that the global state variables <code>T_min</code>, <code>T_max</code> and <code>num_response_groups</code>
be set <em>statically</em> for a specific SDS-R application,
based on expected number of group participants and volume of traffic.</p>
<p><strong><em>Note:</em></strong> Future versions of this protocol will recommend dynamic global SDS-R variables,
based on the current number of participants.</p>
<h4 id="sds-r-send-message"><a class="header" href="#sds-r-send-message">SDS-R send message</a></h4>
<p>SDS-R adds the following steps when sending a message:</p>
<p>Before broadcasting a message,</p>
<ul>
<li>the participant SHOULD populate the <code>repair_request</code> field in the message
with <em>eligible</em> entries from the outgoing repair request buffer.
An entry is eligible to be included in a <code>repair_request</code>
if its corresponding request timestamp, <code>T_req</code>, has expired (in other words,
<code>T_req &lt;= current_time</code>).
The maximum number of repair request entries to include is up to the application.
We RECOMMEND that this quota be filled by the eligible entries from the outgoing repair request buffer with the lowest <code>T_req</code>.
We RECOMMEND a maximum of 3 entries.
If there are no eligible entries in the buffer,
this optional field MUST be left unset.</li>
</ul>
<h4 id="sds-r-receive-message"><a class="header" href="#sds-r-receive-message">SDS-R receive message</a></h4>
<p>On receiving a message,</p>
<ul>
<li>the participant MUST remove entries matching the received message ID from its <em>outgoing</em> repair request buffer.
This ensures that the participant does not request repairs for dependencies that have now been met.</li>
<li>the participant MUST remove entries matching the received message ID from its <em>incoming</em> repair request buffer.
This ensures that the participant does not respond to repair requests that another participant has already responded to.</li>
<li>the participant SHOULD add any unmet causal dependencies to its outgoing repair request buffer against a unique <code>T_req</code> timestamp for that entry.
It MUST compute the <code>T_req</code> for each such HistoryEntry according to the steps outlined in <a href="#determine-t_req"><em>Determine T_req</em></a>.</li>
<li>for each item in the <code>repair_request</code> field:
<ul>
<li>the participant MUST remove entries matching the repair message ID from its own outgoing repair request buffer.
This limits the number of participants that will request a common missing dependency.</li>
<li>if the participant has the requested <code>Message</code> in its local history <em>and</em> is an eligible responder for the repair request,
it SHOULD add the request to its incoming repair request buffer against a unique <code>T_resp</code> timestamp for that entry.
It MUST compute the <code>T_resp</code> for each such repair request according to the steps outlined in <a href="#determine-t_resp"><em>Determine T_resp</em></a>.
It MUST determine if it's an eligible responder for a repair request according to the steps outlined in <a href="#determine-response-group"><em>Determine response group</em></a>.</li>
</ul>
</li>
</ul>
<h4 id="determine-t_req"><a class="header" href="#determine-t_req">Determine T_req</a></h4>
<p>A participant determines the repair request timestamp, <code>T_req</code>,
for a missing <code>HistoryEntry</code> as follows:</p>
<pre><code class="language-text">T_req = current_time + hash(participant_id, message_id) % (T_max - T_min) + T_min
</code></pre>
<p>where <code>current_time</code> is the current timestamp,
<code>participant_id</code> is the participant's <em>own</em> participant ID
(not the <code>sender_id</code> in the missing <code>HistoryEntry</code>),
<code>message_id</code> is the missing <code>HistoryEntry</code>'s message ID,
and <code>T_min</code> and <code>T_max</code> are as set out in <a href="#sds-r-global-state">SDS-R global state</a>.</p>
<p>This allows <code>T_req</code> to be pseudorandomly and linearly distributed as a backoff of between <code>T_min</code> and <code>T_max</code> from current time.</p>
<blockquote>
<p><strong><em>Note:</em></strong> placing <code>T_req</code> values on an exponential backoff curve will likely be more appropriate and is left for a future improvement.</p>
</blockquote>
<h4 id="determine-t_resp"><a class="header" href="#determine-t_resp">Determine T_resp</a></h4>
<p>A participant determines the repair response timestamp, <code>T_resp</code>,
for a <code>HistoryEntry</code> that it could repair as follows:</p>
<pre><code class="language-text">distance = hash(participant_id) XOR hash(sender_id)
T_resp = current_time + distance*hash(message_id) % T_max
</code></pre>
<p>where <code>current_time</code> is the current timestamp,
<code>participant_id</code> is the participant's <em>own</em> (local) participant ID,
<code>sender_id</code> is the requested <code>HistoryEntry</code> sender ID,
<code>message_id</code> is the requested <code>HistoryEntry</code> message ID,
and <code>T_max</code> is as set out in <a href="#sds-r-global-state">SDS-R global state</a>.</p>
<p>We first calculate the logical <code>distance</code> between the local <code>participant_id</code> and
the original <code>sender_id</code>.
If this participant is the original sender, the <code>distance</code> will be <code>0</code>.
It should then be clear that the original participant will have a response backoff time of <code>0</code>,
making it the most likely responder.
The <code>T_resp</code> values for other eligible participants will be pseudorandomly and
linearly distributed as a backoff of up to <code>T_max</code> from current time.</p>
<blockquote>
<p><strong><em>Note:</em></strong> placing <code>T_resp</code> values on an exponential backoff curve will likely be more appropriate and
is left for a future improvement.</p>
</blockquote>
<h4 id="determine-response-group"><a class="header" href="#determine-response-group">Determine response group</a></h4>
<p>Given a message with <code>sender_id</code> and <code>message_id</code>,
a participant with <code>participant_id</code> is in the response group for that message if</p>
<pre><code class="language-text">hash(participant_id, message_id) % num_response_groups == hash(sender_id, message_id) % num_response_groups
</code></pre>
<p>where <code>num_response_groups</code> is as set out in <a href="#sds-r-global-state">SDS-R global state</a>.
This ensures that a participant will always be in the response group for its own published messages.
It also allows participants to determine immediately on first reception of a message or
a history entry if they are in the associated response group.</p>
<h4 id="sds-r-incoming-repair-request-buffer-sweep"><a class="header" href="#sds-r-incoming-repair-request-buffer-sweep">SDS-R incoming repair request buffer sweep</a></h4>
<p>An SDS-R participant MUST periodically check if there are any incoming requests in the <strong>incoming</strong> repair request buffer* that is due for a response.
For each item in the buffer,
the participant SHOULD broadcast the corresponding <code>Message</code> from local history
if its corresponding response timestamp, <code>T_resp</code>, has expired
(in other words, <code>T_resp &lt;= current_time</code>).</p>
<h4 id="sds-r-periodic-sync-message"><a class="header" href="#sds-r-periodic-sync-message">SDS-R Periodic Sync Message</a></h4>
<p>If the participant is due to send a periodic sync message,
it SHOULD send the message according to <a href="#sds-r-send-message">SDS-R send message</a>
if there are any eligible items in the outgoing repair request buffer,
regardless of whether other participants have also recently broadcast a Periodic Sync message.</p>
<h2 id="copyright"><a class="header" href="#copyright">Copyright</a></h2>
<p>Copyright and related rights waived via <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a>.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../../vac/raw/rln-v2.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="../../vac/template.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="../../vac/raw/rln-v2.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="../../vac/template.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 -->
<script src="../../scripts/rfc-index.js"></script>
</div>
</body>
</html>