Skip to content

Commit 0762325

Browse files
committed
multistream-select-v2: Initial draft
1 parent 69c4fdf commit 0762325

File tree

1 file changed

+265
-0
lines changed

1 file changed

+265
-0
lines changed
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
# Multistream Select V2
2+
3+
| Lifecycle Stage | Maturity | Status | Latest Revision |
4+
| --------------- | ------------- | ------ | --------------- |
5+
| 1A | Working Draft | Active | r1, 2025-11-13 |
6+
7+
Authors: [@raulk], [@marcopolo]
8+
9+
Interest Group: [@ppopth]
10+
11+
[@marcopolo]: https://github.com/marcopolo
12+
[@ppopth]: https://github.com/ppopth
13+
[@raulk]: https://github.com/raulk
14+
15+
## Terminology
16+
17+
Server: The endpoint advertising its supported protocol strings.
18+
19+
Client: The endpoint receiving the advertisement and using protocol string
20+
abbreviations when opening streams.
21+
22+
Abbreviation Tree: The tree data structure that determines the abbreviation to
23+
use for a given protocol string.
24+
25+
Note, A peer can behave as both a client and server. For the purpose of defining
26+
this protocol, it's useful to focus on the client/server interaction.
27+
28+
## Abbreviation Tree
29+
30+
A list of protocol strings are abbreviated by creating a minimal hash prefix
31+
tree.
32+
33+
### Construction
34+
35+
Each protocol string is hashed and inserted into the tree as shallowly as
36+
possible. Each node in the tree has 256 leaf branches representing a byte of the
37+
hash (2^8). If multiple protocol strings share a common byte prefix, they are
38+
distinguished the next level down the tree.
39+
40+
Each protocol string in the tree has a tombstone bit associated with it. This is
41+
set to true if the protocol is currently not supported (but was previously).
42+
43+
A node in the tree may contain a value as well as children. This only happens
44+
when introducing a new supported protocol introduces a conflict. This does not
45+
happen on initial construction.
46+
47+
### Example
48+
49+
```txt
50+
(root)
51+
|
52+
+-- 0xaa -> "/some-protocol/a/v1"
53+
|
54+
+-- 0xbb -> "/some-protocol/b/v1"
55+
|
56+
+-- 0xcc
57+
| |
58+
| +-- 0x01 -> "/some-protocol/c/v1"
59+
| |
60+
| +-- 0x02 -> "/some-protocol/c'/v1"
61+
|
62+
+-- 0xdd -> "/some-protocol/d/v1" tombstone=true
63+
```
64+
65+
### Inserting a New Protocol String
66+
67+
The protocol string is inserted into the tree as shallowly as possible. If there
68+
is a conflict, the protocol string should be inserted one level down and
69+
duplicate the conflicting protocol string to the new level if it is not
70+
tombstoned. The conflicting protocol string MUST not removed from its original
71+
position as it may still be referenced.
72+
73+
#### Example
74+
75+
Using the initial example as the initial state and we add three new protocol
76+
strings:
77+
78+
1. `"/new-protocol/foo"` that hashes to `0xaa02`. This example highlights a
79+
conflict with an existing protocol string.
80+
2. `"/new-protocol/bar"` that hashes to `0xee...`. This example highlights no
81+
conflicts and inserting shallowly.
82+
3. `"/new-protocol/d"` that hashes to `0xdd02`. This example highlights a
83+
conflict with a tombstoned protocol string.
84+
85+
```txt
86+
(root)
87+
|
88+
+-- 0xaa -> "/some-protocol/a/v1"
89+
| |
90+
| +-- 0x01 -> "/some-protocol/a/v1"
91+
| |
92+
| +-- 0x02 -> "/new-protocol/foo"
93+
|
94+
+-- 0xbb -> "/some-protocol/b/v1"
95+
|
96+
+-- 0xcc
97+
| |
98+
| +-- 0x01 -> "/some-protocol/c/v1"
99+
| |
100+
| +-- 0x02 -> "/some-protocol/c'/v1"
101+
|
102+
+-- 0xdd -> "/some-protocol/d/v1" tombstone=true
103+
| |
104+
| +-- 0xdd01 -> "/new-protocol/d"
105+
|
106+
+-- 0xee -> "/new-protocol/bar"
107+
```
108+
109+
### Removing a Protocol String
110+
111+
For each instance of the protocol string in the tree, the tombstone bit is set
112+
to true. The protocol string MUST not be removed from the tree as that could
113+
lead to inconsistencies if a new protocol string is introduced with the same
114+
prefix hash.
115+
116+
#### Example
117+
118+
Using the initial example as the initial state and we remove protocol
119+
string `"/some-protocol/b/v1"`.
120+
121+
```txt
122+
(root)
123+
|
124+
+-- 0xaa -> "/some-protocol/a/v1"
125+
|
126+
+-- 0xbb -> "/some-protocol/b/v1" tombstone=true
127+
|
128+
+-- 0xcc
129+
| |
130+
| +-- 0x01 -> "/some-protocol/c/v1"
131+
| |
132+
| +-- 0x02 -> "/some-protocol/c'/v1"
133+
|
134+
+-- 0xdd -> "/some-protocol/d/v1" tombstone=true
135+
```
136+
137+
### Reintroducing a previously removed protocol string
138+
139+
For each instance of the protocol string in the tree, the tombstone bit should
140+
be set to false. The protocol string should then be inserted into the tree as if
141+
inserting a new protocol string. If the protocol string is already present as a
142+
leaf node, no changes are required.
143+
144+
#### Example
145+
146+
Using the example for removing a protocol string as the initial state. We
147+
reintroduce protocol string `"/some-protocol/b/v1"`.
148+
149+
```txt
150+
(root)
151+
|
152+
+-- 0xaa -> "/some-protocol/a/v1"
153+
|
154+
+-- 0xbb -> "/some-protocol/b/v1"
155+
|
156+
+-- 0xcc
157+
| |
158+
| +-- 0x01 -> "/some-protocol/c/v1"
159+
| |
160+
| +-- 0x02 -> "/some-protocol/c'/v1"
161+
|
162+
+-- 0xdd -> "/some-protocol/d/v1" tombstone=true
163+
```
164+
165+
#### Example with a new leaf node
166+
167+
If the tombstoned protocol string is no longer at a leaf position we need to
168+
insert a new protocol string, as well as untombstoning the existing protocol
169+
string.
170+
171+
Initial State:
172+
173+
```txt
174+
(root)
175+
|
176+
+-- 0xaa -> "/some-protocol/a/v1"
177+
|
178+
+-- 0xbb -> "/some-protocol/b/v1" tombstone=true
179+
| |
180+
| +-- 0x02 -> "/some-protocol/b'/v1"
181+
|
182+
+-- 0xcc
183+
| |
184+
| +-- 0x01 -> "/some-protocol/c/v1"
185+
| |
186+
| +-- 0x02 -> "/some-protocol/c'/v1"
187+
|
188+
+-- 0xdd -> "/some-protocol/d/v1" tombstone=true
189+
```
190+
191+
After reintroducing `"/some-protocol/b/v1"`:
192+
193+
```txt
194+
(root)
195+
|
196+
+-- 0xaa -> "/some-protocol/a/v1"
197+
|
198+
+-- 0xbb -> "/some-protocol/b/v1"
199+
| |
200+
| +-- 0x01 -> "/some-protocol/b/v1"
201+
| |
202+
| +-- 0x02 -> "/some-protocol/b'/v1"
203+
|
204+
+-- 0xcc
205+
| |
206+
| +-- 0x01 -> "/some-protocol/c/v1"
207+
| |
208+
| +-- 0x02 -> "/some-protocol/c'/v1"
209+
|
210+
+-- 0xdd -> "/some-protocol/d/v1" tombstone=true
211+
```
212+
213+
## Limits
214+
215+
Implementations SHOULD limit the number of protocol strings they track
216+
(including tombstoned protocol strings).
217+
218+
## Mapping Algorithm
219+
220+
A mapping algorithm maps a protocol string to byte array. This byte array is
221+
used for the abbreviation tree.
222+
223+
SHA256 MUST be used for the mapping algorithm.
224+
225+
TODO: Do we want to consider faster keyed hashes? Risks complicating
226+
implementations.
227+
228+
TODO: Do we need a hash function at all? Would an index into the list of a
229+
server's protocols work instead?
230+
231+
## Initial Server Client Exchange
232+
233+
When a client connects to a server, the server shares all the state necessary to
234+
create an abbreviation tree it can use to communicate with the server. Namely:
235+
the list of supported protocol strings, and the list of previously supported
236+
protocol strings (tombstoned protocol strings).
237+
238+
The client's abbreviation tree will differ from the server's abbreviation tree
239+
only in that protocol strings will only exist at leaf nodes in the client's
240+
abbreviation tree. This is because non-leaf protocol strings only occur when
241+
adding a protocol string to an existing tree.
242+
243+
# Multistream Select V2
244+
245+
## Wire Format
246+
247+
TODO define the wire format of multistream select v2.
248+
249+
## Client opening a new stream
250+
251+
A client identifies the protocol string it wishes to use on a stream by the
252+
minimal hash prefix as determined by the abbreviate stream.
253+
254+
## Server accepting a new stream
255+
256+
The server identifies the protocol string by looking up the minimal hash prefix
257+
in the tree.
258+
259+
## Version Negotiation
260+
261+
Multistream Select V2 does not support negotiating different protocols on a
262+
single stream like Multistream Select V1 does. A client specifies what protocol
263+
they would like to use for a stream and MAY start sending protocol immediately.
264+
If the server does not support this protocol, it MUST close the stream with
265+
error code (TODO specify this).

0 commit comments

Comments
 (0)