Skip to content

Commit ac885ff

Browse files
committed
add basics of ebt replication
1 parent 8908759 commit ac885ff

File tree

1 file changed

+154
-0
lines changed

1 file changed

+154
-0
lines changed

index.html

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ <h2 id="toc">Contents</h2>
5454
<div><a href="#structure">Structure</a></div>
5555
<div><a href="#message-format">Message format</a></div>
5656
<div><a href="#createHistoryStream">createHistoryStream</a></div>
57+
<div><a href="#ebt-replication">EBT replication</a></div>
5758
</div>
5859
</div>
5960
<div class="section">
@@ -1086,6 +1087,159 @@ <h5>Implementations</h5>
10861087
}</code></pre>
10871088
</div>
10881089
</figure>
1090+
<!-- ebt documentation -->
1091+
<h3 id="ebt-replication">Epidemic Broadcast Tree (EBT) Replication</h3>
1092+
<aside class="impl kicker">
1093+
<img class="icon" src="img/impl.png" alt=""/>
1094+
<h5>Implementations</h5>
1095+
<div class="lang">JS</div>
1096+
<div><a href="https://github.com/ssbc/epidemic-broadcast-trees/blob/master/index.js">epidemic-broadcast-trees</a></div>
1097+
<div class="vs"><a href="https://github.com/ssbc/ssb-ebt/blob/master/index.js">ssb-ebt</a></div>
1098+
<div class="lang">Go</div>
1099+
<div class="vs"><a href="https://github.com/planetary-social/scuttlego/tree/main/service/domain/replication/ebt">ebt</a></div>
1100+
</aside>
1101+
<p>In addition to classic replication using <i>createHistoryStream</i>, some Scuttlebutt clients implement a more efficient form of replication known as <i>Epidemic broadcast tree replication</i>. This is often referred to by the abbreviation <i>EBT</i>. The implementation of EBT used in Scuttlebutt is loosely based on the push-lazy-push multicast tree protocol, more commonly known as the <i>Plumtree</i> protocol [1].</p>
1102+
<h4 id="session-initiation">Session Initiation</h4>
1103+
<p>An EBT session may be initiated once two peers have completed the secret handshake and have established their respective box streams. The peer who acted as the client during the secret handshake takes on the role of the requester, sending an <i>["ebt", "replicate"]</i> request to the connected peer.</p>
1104+
<figure class="request-response">
1105+
<div class="request">
1106+
<div class="header">
1107+
<span class="key">Request number</span><span class="value">1</span>
1108+
<span class="key">Body type</span><span class="value">JSON</span>
1109+
<span class="key">Stream</span><span class="value">Yes</span>
1110+
<span class="key">End/err</span><span class="value">No</span>
1111+
</div>
1112+
<pre><code>{
1113+
"name": ["ebt", "replicate"],
1114+
"type": "duplex",
1115+
"args": [
1116+
{
1117+
"version": 3,
1118+
"format": "classic"
1119+
}
1120+
]
1121+
}</code></pre>
1122+
</div>
1123+
<img class="request-arrow" src="img/arrow.png" alt=""/>
1124+
</figure>
1125+
<p>The peer who acted as the server during the secret handshake takes on the role of the responder. After having received the replicate request, the responder must first validate the arguments to ensure that the version is 3 and the format is "classic". If either of those values are incorrect, the responder terminates the stream with an error.</p>
1126+
<h4 id="vector-clocks">Vector Clocks</h4>
1127+
<p>The responder then sends a vector clock (also known as a "note" or "control message") to the requester. The vector clock takes the form of a JSON object with one or more key-value pairs. The key of each pair specifies a Scuttlebutt feed identified by the @-prefixed public key of the author. The value of each pair is a signed integer encoding a replicate flag, a receive flag and a feed sequence number.
1128+
<figure class="request-response">
1129+
<img class="response-arrow" src="img/arrow.png" alt=""/>
1130+
<div class="response">
1131+
<div class="header">
1132+
<span class="key">Request number</span><span class="value">-1</span>
1133+
<span class="key">Body type</span><span class="value">JSON</span>
1134+
<span class="key">Stream</span><span class="value">Yes</span>
1135+
<span class="key">End/err</span><span class="value">No</span>
1136+
</div>
1137+
<pre><code>{
1138+
"@qK93G/R9R5J2fiqK+kxV72HqqPUcss+rth8rACcYr4s=.ed25519": 450,
1139+
"@L/g6qZQE/2FdO2UhSJ0uyDiZb5LjJLatM/d8MN+INSM=.ed25519": 12,
1140+
"@fGHFd8rUgoznX/qS/1U7HPF3vnirbSyfaaWlS8cCWR0=.ed25519": 1,
1141+
"@HEqy940T6uB+T+d9Jaa58aNfRzLx9eRWqkZljBmnkmk=.ed25519": -1
1142+
}</code></pre>
1143+
</div>
1144+
</figure>
1145+
<p>The requester should terminate the stream with an error if any of the received feed identifiers or encoded values are malformed. If the received vector clock is valid, the requester can proceed with decoding the values.</p>
1146+
<p>The value in each key-value pair of a vector clock encodes a maximum of three data points: a replicate flag, a receive flag and a sequence number. A negative value (usually -1) signals that the responder does not wish to replicate the associated feed, neither sending nor receiving messages. In this scenario, the replicate flag is set to false and both the receive flag and sequence number are irrelevant.</p>
1147+
<p>A positive value signals that the responder wishes to replicate the associated feed. If the value is positive it should be decoded as follows. First, the JSON number should be parsed and converted to a signed integer. Then, the rightmost (lowest order) bit of the number should be interpreted as a binary flag with 0 equal to true and 1 equal to false. This flag is referred to as the receive flag. Next, a sign-extending right shift (also called arithmetic right shift) by 1 bit should be performed on the binary number, therefore discarding the rightmost (lowest order) bit. The remaining number should then be interpreted as a sequence number for the associated feed.</p>
1148+
<p>If the receive flag is set to true, the peer who sent the vector clock wishes to receive messages for the associated feed. The decoded sequence number defines the latest message held by the peer for that feed.</p>
1149+
<p>Encoding of a vector clock value involves reversing the steps outlined above. If the peer does not wish to replicate a feed, the value is simply set to -1. Otherwise, the latest sequence number of the associated feed should be stored as a signed integer and an arithmetic left shift should be performed. The rightmost (lowest order) bit should then be set according to the replicate flag as described previously.</p>
1150+
<table class="clock-values">
1151+
<thead>
1152+
<tr>
1153+
<th rowspan="2">Encoded</th>
1154+
<th colspan="3">Decoded</th>
1155+
</tr>
1156+
<tr>
1157+
<th>Replicate flag</th>
1158+
<th>Receive flag</th>
1159+
<th>Sequence</th>
1160+
</tr>
1161+
</thead>
1162+
<tbody>
1163+
<tr>
1164+
<td>-1</td>
1165+
<td>False</td>
1166+
<td>Irrelevant</td>
1167+
<td>Irrelevant</td>
1168+
</tr>
1169+
<tr>
1170+
<td>0</td>
1171+
<td>True</td>
1172+
<td>True</td>
1173+
<td>0</td>
1174+
</tr>
1175+
<tr>
1176+
<td>1</td>
1177+
<td>True</td>
1178+
<td>False</td>
1179+
<td>0</td>
1180+
</tr>
1181+
<tr>
1182+
<td>2</td>
1183+
<td>True</td>
1184+
<td>True</td>
1185+
<td>1</td>
1186+
</tr>
1187+
<tr>
1188+
<td>3</td>
1189+
<td>True</td>
1190+
<td>False</td>
1191+
<td>1</td>
1192+
</tr>
1193+
</tbody>
1194+
</table>
1195+
<p>The requester then sends their own vector clock to the responder. At this point, the initial exchange of vector clocks is complete and both peers can begin freely sending messages.</p>
1196+
<aside class="kicker" style="align-self: start; position: relative; top: 58px;">
1197+
<p>The same request number is used for all requests occurring between a pair of peers over the course of a single EBT session.</p>
1198+
</aside>
1199+
<figure class="request-response">
1200+
<div class="request">
1201+
<div class="header">
1202+
<span class="key">Request number</span><span class="value">1</span>
1203+
<span class="key">Body type</span><span class="value">JSON</span>
1204+
<span class="key">Stream</span><span class="value">Yes</span>
1205+
<span class="key">End/err</span><span class="value">No</span>
1206+
</div>
1207+
<pre><code>{
1208+
"@fGHFd8rUgoznX/qS/1U7HPF3vnirbSyfaaWlS8cCWR0=.ed25519": 62,
1209+
"@qK93G/R9R5J2fiqK+kxV72HqqPUcss+rth8rACcYr4s=.ed25519": -1,
1210+
"@L/g6qZQE/2FdO2UhSJ0uyDiZb5LjJLatM/d8MN+INSM=.ed25519": 10
1211+
}</code></pre>
1212+
</div>
1213+
<img class="request-arrow" src="img/arrow.png" alt=""/>
1214+
</figure>
1215+
<p>Messages are sent in exactly the same way as when responding to a <i>createHistoryStream</i> request.
1216+
<figure class="request-response">
1217+
<img class="response-arrow" src="img/arrow.png" alt=""/>
1218+
<div class="response">
1219+
<div class="header">
1220+
<span class="key">Request number</span><span class="value">-1</span>
1221+
<span class="key">Body type</span><span class="value">JSON</span>
1222+
<span class="key">Stream</span><span class="value">Yes</span>
1223+
<span class="key">End/err</span><span class="value">No</span>
1224+
</div>
1225+
<pre><code>{
1226+
"previous": "%GvRqbiZFY0cNyGRD4QwjeMQvnrjz9vMPBsT5JdWrcW0=.sha256",
1227+
"author": "@L/g6qZQE/2FdO2UhSJ0uyDiZb5LjJLatM/d8MN+INSM=.ed25519",
1228+
"sequence": 5,
1229+
"timestamp": 1698824093970,
1230+
"hash": "sha256",
1231+
"content": {
1232+
"type": "contact",
1233+
"contact": "@fGHFd8rUgoznX/qS/1U7HPF3vnirbSyfaaWlS8cCWR0=.ed25519",
1234+
"blocking": false,
1235+
"following": true
1236+
},
1237+
"signature": "8+VQ7sbv0fnD8ZnbunJ19fyvtcwSpHvhlWUakj32nU4woFNNpI
1238+
qpvkAJ4GMGJdYHoqc8C7asPXPa+wMzbPR1Cw==.sig.ed25519"
1239+
}</code></pre>
1240+
</div>
1241+
</figure>
1242+
<p>[1] Joao Leitao, Jose Pereira and Luis Rodrigues. 2007. Epidemic Broadcast Trees. In <i>2007 26th IEEE International Symposium on Reliable Distributed Systems (SRDS 2007)</i>, 301-310. https://doi.org/10.1109/SRDS.2007.27</p>
10891243
<!-- metafeeds documentation -->
10901244
<h2 id="metafeeds">Metafeeds</h2>
10911245
<div>

0 commit comments

Comments
 (0)