Skip to content

Commit dad8349

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

1 file changed

Lines changed: 251 additions & 0 deletions

File tree

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
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. The conflicting
70+
protocol string MUST not removed from its original position as it may still
71+
be referenced.
72+
73+
#### Example
74+
75+
Using the initial example as the initial state and we add two new protocol
76+
strings. `"/new-protocol/foo"` that hashes to `0xaa02` , and
77+
`"/new-protocol/bar"` that hashes to `0xee...` .
78+
79+
```txt
80+
(root)
81+
|
82+
+-- 0xaa -> "/some-protocol/a/v1"
83+
| |
84+
| +-- 0x01 -> "/some-protocol/a/v1"
85+
| |
86+
| +-- 0x02 -> "/new-protocol/foo"
87+
|
88+
+-- 0xbb -> "/some-protocol/b/v1"
89+
|
90+
+-- 0xcc
91+
| |
92+
| +-- 0x01 -> "/some-protocol/c/v1"
93+
| |
94+
| +-- 0x02 -> "/some-protocol/c'/v1"
95+
|
96+
+-- 0xdd -> "/some-protocol/d/v1" tombstone=true
97+
|
98+
+-- 0xee -> "/new-protocol/bar"
99+
```
100+
101+
### Removing a Protocol String
102+
103+
For each instance of the protocol string in the tree, the tombstone bit is set
104+
to true. The protocol string MUST not be removed from the tree as that could
105+
lead to inconsistencies if a new protocol string is introduced with the same
106+
prefix hash.
107+
108+
#### Example
109+
110+
Using the initial example as the initial state and we add remove protocol
111+
string `"/some-protocol/b/v1"`.
112+
113+
```txt
114+
(root)
115+
|
116+
+-- 0xaa -> "/some-protocol/a/v1"
117+
|
118+
+-- 0xbb -> "/some-protocol/b/v1" tombstone=true
119+
|
120+
+-- 0xcc
121+
| |
122+
| +-- 0x01 -> "/some-protocol/c/v1"
123+
| |
124+
| +-- 0x02 -> "/some-protocol/c'/v1"
125+
|
126+
+-- 0xdd -> "/some-protocol/d/v1" tombstone=true
127+
```
128+
129+
### Reintroducing a previously removed protocol string
130+
131+
For each instance of the protocol string in the tree, the tombstone bit should
132+
be set to false. The protocol string should then be inserted into the tree as if
133+
inserting a new protocol string. If the protocol string is already present as a
134+
leaf node, no changes are required.
135+
136+
#### Example
137+
138+
Using the example for removing a protocol string as the initial state. We
139+
reintroduce protocol string `"/some-protocol/b/v1"`.
140+
141+
```txt
142+
(root)
143+
|
144+
+-- 0xaa -> "/some-protocol/a/v1"
145+
|
146+
+-- 0xbb -> "/some-protocol/b/v1"
147+
|
148+
+-- 0xcc
149+
| |
150+
| +-- 0x01 -> "/some-protocol/c/v1"
151+
| |
152+
| +-- 0x02 -> "/some-protocol/c'/v1"
153+
|
154+
+-- 0xdd -> "/some-protocol/d/v1" tombstone=true
155+
```
156+
157+
#### Example with a new leaf node
158+
159+
If the tombstoned protocol string is no longer at a leaf position we need to
160+
insert a new protocol string, as well as untombstoning the existing protocol
161+
string.
162+
163+
Initial State:
164+
165+
```txt
166+
(root)
167+
|
168+
+-- 0xaa -> "/some-protocol/a/v1"
169+
|
170+
+-- 0xbb -> "/some-protocol/b/v1" tombstone=true
171+
| |
172+
| +-- 0x02 -> "/some-protocol/b'/v1"
173+
|
174+
+-- 0xcc
175+
| |
176+
| +-- 0x01 -> "/some-protocol/c/v1"
177+
| |
178+
| +-- 0x02 -> "/some-protocol/c'/v1"
179+
|
180+
+-- 0xdd -> "/some-protocol/d/v1" tombstone=true
181+
```
182+
183+
After reintroducing `"/some-protocol/b/v1"`:
184+
185+
```txt
186+
(root)
187+
|
188+
+-- 0xaa -> "/some-protocol/a/v1"
189+
|
190+
+-- 0xbb -> "/some-protocol/b/v1"
191+
| |
192+
| +-- 0x01 -> "/some-protocol/b/v1"
193+
| |
194+
| +-- 0x02 -> "/some-protocol/b'/v1"
195+
|
196+
+-- 0xcc
197+
| |
198+
| +-- 0x01 -> "/some-protocol/c/v1"
199+
| |
200+
| +-- 0x02 -> "/some-protocol/c'/v1"
201+
|
202+
+-- 0xdd -> "/some-protocol/d/v1" tombstone=true
203+
```
204+
205+
## Limits
206+
207+
Implementations SHOULD limit the number of protocol strings they track
208+
(including tombstoned protocol strings).
209+
210+
## Hashing Algorithm
211+
212+
SHA256 MUST be used.
213+
214+
TODO: do we want to consider faster keyed hashes? Risks complicating
215+
implementations.
216+
217+
## Initial Server Client Exchange
218+
219+
When a client connects to a server, the server shares all the state necessary to
220+
create an abbreviation tree it can use to communicate with the server. Namely:
221+
the list of supported protocol strings, and the list of previously supported
222+
protocol strings (tombstoned protocol strings).
223+
224+
The client's abbreviation tree will differ from the server's abbreviation tree
225+
only in that protocol strings will only exist at leaf nodes. This is because
226+
non-leaf protocol strings only occur when adding a protocol string to an
227+
existing tree.
228+
229+
# Multistream Select V2
230+
231+
## Wire Format
232+
233+
TODO define the wire format of multistream select v2.
234+
235+
## Client opening a new stream
236+
237+
A client identifies the protocol string it wishes to use on a stream by the
238+
minimal hash prefix as determined by the abbreviate stream.
239+
240+
## Server accepting a new stream
241+
242+
The server identifies the protocol string by looking up the minimal hash prefix
243+
in the tree.
244+
245+
## Version Negotiation
246+
247+
Multistream Select V2 does not support negotiating different protocols on a
248+
single stream like Multistream Select V1 does. A client specifies what protocol
249+
they would like to use for a stream and MAY start sending protocol immediately.
250+
If the server does not support this protocol, it MUST close the stream with
251+
error code (TODO specify this).

0 commit comments

Comments
 (0)