@@ -161,7 +161,8 @@ export function decodeTxt(encoded: string): ENRData {
161161
162162// IP / Protocol
163163
164- export type Protocol = "udp" | "tcp" | "udp4" | "udp6" | "tcp4" | "tcp6" ;
164+ /** Protocols automagically supported by this library */
165+ export type Protocol = "udp" | "tcp" | "quic" | "udp4" | "udp6" | "tcp4" | "tcp6" | "quic4" | "quic6" ;
165166
166167export function getIPValue ( kvs : ReadonlyMap < ENRKey , ENRValue > , key : string , multifmtStr : string ) : string | undefined {
167168 const raw = kvs . get ( key ) ;
@@ -191,6 +192,57 @@ export function portToBuf(port: number): Uint8Array {
191192 return buf ;
192193}
193194
195+ export function parseLocationMultiaddr ( ma : Multiaddr ) : {
196+ family : 4 | 6 ;
197+ ip : Uint8Array ;
198+ protoName : "udp" | "tcp" | "quic" ;
199+ protoVal : Uint8Array ;
200+ } {
201+ const protoNames = ma . protoNames ( ) ;
202+ const tuples = ma . tuples ( ) ;
203+ let family : 4 | 6 ;
204+ let protoName : "udp" | "tcp" | "quic" ;
205+
206+ if ( protoNames [ 0 ] === "ip4" ) {
207+ family = 4 ;
208+ } else if ( protoNames [ 0 ] === "ip6" ) {
209+ family = 6 ;
210+ } else {
211+ throw new Error ( "Invalid multiaddr: must start with ip4 or ip6" ) ;
212+ }
213+ if ( tuples [ 0 ] [ 1 ] == null ) {
214+ throw new Error ( "Invalid multiaddr: ip address is missing" ) ;
215+ }
216+ const ip = tuples [ 0 ] [ 1 ] ;
217+
218+ if ( protoNames [ 1 ] === "udp" ) {
219+ protoName = "udp" ;
220+ } else if ( protoNames [ 1 ] === "tcp" ) {
221+ protoName = "tcp" ;
222+ } else {
223+ throw new Error ( "Invalid multiaddr: must have udp or tcp protocol" ) ;
224+ }
225+ if ( tuples [ 1 ] [ 1 ] == null ) {
226+ throw new Error ( "Invalid multiaddr: udp or tcp port is missing" ) ;
227+ }
228+ const protoVal = tuples [ 1 ] [ 1 ] ;
229+
230+ if ( protoNames . length === 3 ) {
231+ if ( protoNames [ 2 ] === "quic-v1" ) {
232+ if ( protoName !== "udp" ) {
233+ throw new Error ( "Invalid multiaddr: quic protocol must be used with udp" ) ;
234+ }
235+ protoName = "quic" ;
236+ } else {
237+ throw new Error ( "Invalid multiaddr: unknown protocol" ) ;
238+ }
239+ } else if ( protoNames . length > 2 ) {
240+ throw new Error ( "Invalid multiaddr: unknown protocol" ) ;
241+ }
242+
243+ return { family, ip, protoName, protoVal } ;
244+ }
245+
194246// Classes
195247
196248export abstract class BaseENR {
@@ -228,6 +280,9 @@ export abstract class BaseENR {
228280 get udp ( ) : number | undefined {
229281 return getProtocolValue ( this . kvs , "udp" ) ;
230282 }
283+ get quic ( ) : number | undefined {
284+ return getProtocolValue ( this . kvs , "quic" ) ;
285+ }
231286 get ip6 ( ) : string | undefined {
232287 return getIPValue ( this . kvs , "ip6" , "ip6" ) ;
233288 }
@@ -237,13 +292,19 @@ export abstract class BaseENR {
237292 get udp6 ( ) : number | undefined {
238293 return getProtocolValue ( this . kvs , "udp6" ) ;
239294 }
295+ get quic6 ( ) : number | undefined {
296+ return getProtocolValue ( this . kvs , "quic6" ) ;
297+ }
240298 getLocationMultiaddr ( protocol : Protocol ) : Multiaddr | undefined {
241299 if ( protocol === "udp" ) {
242300 return this . getLocationMultiaddr ( "udp4" ) || this . getLocationMultiaddr ( "udp6" ) ;
243301 }
244302 if ( protocol === "tcp" ) {
245303 return this . getLocationMultiaddr ( "tcp4" ) || this . getLocationMultiaddr ( "tcp6" ) ;
246304 }
305+ if ( protocol === "quic" ) {
306+ return this . getLocationMultiaddr ( "quic4" ) || this . getLocationMultiaddr ( "quic6" ) ;
307+ }
247308 const isIpv6 = protocol . endsWith ( "6" ) ;
248309 const ipVal = this . kvs . get ( isIpv6 ? "ip6" : "ip" ) ;
249310 if ( ! ipVal ) {
@@ -252,13 +313,17 @@ export abstract class BaseENR {
252313
253314 const isUdp = protocol . startsWith ( "udp" ) ;
254315 const isTcp = protocol . startsWith ( "tcp" ) ;
316+ const isQuic = protocol . startsWith ( "quic" ) ;
255317 let protoName , protoVal ;
256318 if ( isUdp ) {
257319 protoName = "udp" ;
258320 protoVal = isIpv6 ? this . kvs . get ( "udp6" ) : this . kvs . get ( "udp" ) ;
259321 } else if ( isTcp ) {
260322 protoName = "tcp" ;
261323 protoVal = isIpv6 ? this . kvs . get ( "tcp6" ) : this . kvs . get ( "tcp" ) ;
324+ } else if ( isQuic ) {
325+ protoName = "udp" ;
326+ protoVal = isIpv6 ? this . kvs . get ( "quic6" ) : this . kvs . get ( "quic" ) ;
262327 } else {
263328 return undefined ;
264329 }
@@ -282,7 +347,11 @@ export abstract class BaseENR {
282347 maBuf . set ( protoBuf , 1 + ipByteLen ) ;
283348 maBuf . set ( protoVal , 1 + ipByteLen + protoBuf . length ) ;
284349
285- return multiaddr ( maBuf ) ;
350+ const ma = multiaddr ( maBuf ) ;
351+ if ( isQuic ) {
352+ return ma . encapsulate ( "/quic-v1" ) ;
353+ }
354+ return ma ;
286355 }
287356 async getFullMultiaddr ( protocol : Protocol ) : Promise < Multiaddr | undefined > {
288357 const locationMultiaddr = this . getLocationMultiaddr ( protocol ) ;
@@ -504,6 +573,16 @@ export class SignableENR extends BaseENR {
504573 this . set ( "udp" , portToBuf ( port ) ) ;
505574 }
506575 }
576+ get quic ( ) : number | undefined {
577+ return getProtocolValue ( this . kvs , "quic" ) ;
578+ }
579+ set quic ( port : number | undefined ) {
580+ if ( port === undefined ) {
581+ this . delete ( "quic" ) ;
582+ } else {
583+ this . set ( "quic" , portToBuf ( port ) ) ;
584+ }
585+ }
507586 get ip6 ( ) : string | undefined {
508587 return getIPValue ( this . kvs , "ip6" , "ip6" ) ;
509588 }
@@ -534,23 +613,25 @@ export class SignableENR extends BaseENR {
534613 this . set ( "udp6" , portToBuf ( port ) ) ;
535614 }
536615 }
537- setLocationMultiaddr ( multiaddr : Multiaddr ) : void {
538- const protoNames = multiaddr . protoNames ( ) ;
539- if ( protoNames . length !== 2 && protoNames [ 1 ] !== "udp" && protoNames [ 1 ] !== "tcp" ) {
540- throw new Error ( "Invalid multiaddr" ) ;
541- }
542- const tuples = multiaddr . tuples ( ) ;
543- if ( ! tuples [ 0 ] [ 1 ] || ! tuples [ 1 ] [ 1 ] ) {
544- throw new Error ( "Invalid multiaddr" ) ;
616+ get quic6 ( ) : number | undefined {
617+ return getProtocolValue ( this . kvs , "quic6" ) ;
618+ }
619+ set quic6 ( port : number | undefined ) {
620+ if ( port === undefined ) {
621+ this . delete ( "quic6" ) ;
622+ } else {
623+ this . set ( "quic6" , portToBuf ( port ) ) ;
545624 }
625+ }
626+ setLocationMultiaddr ( multiaddr : Multiaddr ) : void {
627+ const { family, ip, protoName, protoVal } = parseLocationMultiaddr ( multiaddr ) ;
546628
547- // IPv4
548- if ( tuples [ 0 ] [ 0 ] === 4 ) {
549- this . set ( "ip" , tuples [ 0 ] [ 1 ] ) ;
550- this . set ( protoNames [ 1 ] , tuples [ 1 ] [ 1 ] ) ;
629+ if ( family === 4 ) {
630+ this . set ( "ip" , ip ) ;
631+ this . set ( protoName , protoVal ) ;
551632 } else {
552- this . set ( "ip6" , tuples [ 0 ] [ 1 ] ) ;
553- this . set ( protoNames [ 1 ] + "6" , tuples [ 1 ] [ 1 ] ) ;
633+ this . set ( "ip6" , ip ) ;
634+ this . set ( protoName + "6" , protoVal ) ;
554635 }
555636 }
556637
0 commit comments