mirror of https://github.com/waku-org/js-waku.git
chore: segregate basic access to fields and more advanced logic
Move basic access to ENR fields (with conversion) to `RawEnr` `ENR` inherits from `RawEnr` and add a layer of logic.
This commit is contained in:
parent
6dbcde041a
commit
81ad14cad3
|
@ -1,28 +1,21 @@
|
||||||
import type { PeerId } from "@libp2p/interface-peer-id";
|
import type { PeerId } from "@libp2p/interface-peer-id";
|
||||||
import type { PeerInfo } from "@libp2p/interface-peer-info";
|
import type { PeerInfo } from "@libp2p/interface-peer-info";
|
||||||
import type { Multiaddr } from "@multiformats/multiaddr";
|
import type { Multiaddr } from "@multiformats/multiaddr";
|
||||||
import {
|
|
||||||
convertToBytes,
|
|
||||||
convertToString,
|
|
||||||
} from "@multiformats/multiaddr/convert";
|
|
||||||
import type {
|
import type {
|
||||||
ENRKey,
|
ENRKey,
|
||||||
ENRValue,
|
ENRValue,
|
||||||
IEnr,
|
IEnr,
|
||||||
NodeId,
|
NodeId,
|
||||||
SequenceNumber,
|
SequenceNumber,
|
||||||
Waku2,
|
|
||||||
} from "@waku/interfaces";
|
} from "@waku/interfaces";
|
||||||
import { bytesToUtf8 } from "@waku/utils";
|
|
||||||
import debug from "debug";
|
import debug from "debug";
|
||||||
|
|
||||||
import { ERR_INVALID_ID } from "./constants.js";
|
import { ERR_INVALID_ID } from "./constants.js";
|
||||||
import { keccak256, verifySignature } from "./crypto.js";
|
import { keccak256, verifySignature } from "./crypto.js";
|
||||||
import { locationMultiaddrFromEnrFields } from "./get_multiaddr.js";
|
import { locationMultiaddrFromEnrFields } from "./get_multiaddr.js";
|
||||||
import { decodeMultiaddrs, encodeMultiaddrs } from "./multiaddrs_codec.js";
|
|
||||||
import { createPeerIdFromPublicKey } from "./peer_id.js";
|
import { createPeerIdFromPublicKey } from "./peer_id.js";
|
||||||
|
import { RawEnr } from "./raw_enr.js";
|
||||||
import * as v4 from "./v4.js";
|
import * as v4 from "./v4.js";
|
||||||
import { decodeWaku2, encodeWaku2 } from "./waku2_codec.js";
|
|
||||||
|
|
||||||
const log = debug("waku:enr");
|
const log = debug("waku:enr");
|
||||||
|
|
||||||
|
@ -37,22 +30,10 @@ export enum TransportProtocolPerIpVersion {
|
||||||
UDP6 = "udp6",
|
UDP6 = "udp6",
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ENR extends Map<ENRKey, ENRValue> implements IEnr {
|
export class ENR extends RawEnr implements IEnr {
|
||||||
public static readonly RECORD_PREFIX = "enr:";
|
public static readonly RECORD_PREFIX = "enr:";
|
||||||
public seq: SequenceNumber;
|
|
||||||
public signature?: Uint8Array;
|
|
||||||
public peerId?: PeerId;
|
public peerId?: PeerId;
|
||||||
|
|
||||||
private constructor(
|
|
||||||
kvs: Record<ENRKey, ENRValue> = {},
|
|
||||||
seq: SequenceNumber = BigInt(1),
|
|
||||||
signature?: Uint8Array
|
|
||||||
) {
|
|
||||||
super(Object.entries(kvs));
|
|
||||||
this.seq = seq;
|
|
||||||
this.signature = signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
static async create(
|
static async create(
|
||||||
kvs: Record<ENRKey, ENRValue> = {},
|
kvs: Record<ENRKey, ENRValue> = {},
|
||||||
seq: SequenceNumber = BigInt(1),
|
seq: SequenceNumber = BigInt(1),
|
||||||
|
@ -70,26 +51,6 @@ export class ENR extends Map<ENRKey, ENRValue> implements IEnr {
|
||||||
|
|
||||||
return enr;
|
return enr;
|
||||||
}
|
}
|
||||||
set(k: ENRKey, v: ENRValue): this {
|
|
||||||
this.signature = undefined;
|
|
||||||
this.seq++;
|
|
||||||
return super.set(k, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
get id(): string {
|
|
||||||
const id = this.get("id");
|
|
||||||
if (!id) throw new Error("id not found.");
|
|
||||||
return bytesToUtf8(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
get publicKey(): Uint8Array | undefined {
|
|
||||||
switch (this.id) {
|
|
||||||
case "v4":
|
|
||||||
return this.get("secp256k1");
|
|
||||||
default:
|
|
||||||
throw new Error(ERR_INVALID_ID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get nodeId(): NodeId | undefined {
|
get nodeId(): NodeId | undefined {
|
||||||
switch (this.id) {
|
switch (this.id) {
|
||||||
|
@ -99,150 +60,6 @@ export class ENR extends Map<ENRKey, ENRValue> implements IEnr {
|
||||||
throw new Error(ERR_INVALID_ID);
|
throw new Error(ERR_INVALID_ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get ip(): string | undefined {
|
|
||||||
const raw = this.get("ip");
|
|
||||||
if (raw) {
|
|
||||||
return convertToString("ip4", raw) as string;
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set ip(ip: string | undefined) {
|
|
||||||
if (ip) {
|
|
||||||
this.set("ip", convertToBytes("ip4", ip));
|
|
||||||
} else {
|
|
||||||
this.delete("ip");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get tcp(): number | undefined {
|
|
||||||
const raw = this.get("tcp");
|
|
||||||
if (raw) {
|
|
||||||
return Number(convertToString("tcp", raw));
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set tcp(port: number | undefined) {
|
|
||||||
if (port === undefined) {
|
|
||||||
this.delete("tcp");
|
|
||||||
} else {
|
|
||||||
this.set("tcp", convertToBytes("tcp", port.toString(10)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get udp(): number | undefined {
|
|
||||||
const raw = this.get("udp");
|
|
||||||
if (raw) {
|
|
||||||
return Number(convertToString("udp", raw));
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set udp(port: number | undefined) {
|
|
||||||
if (port === undefined) {
|
|
||||||
this.delete("udp");
|
|
||||||
} else {
|
|
||||||
this.set("udp", convertToBytes("udp", port.toString(10)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get ip6(): string | undefined {
|
|
||||||
const raw = this.get("ip6");
|
|
||||||
if (raw) {
|
|
||||||
return convertToString("ip6", raw) as string;
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set ip6(ip: string | undefined) {
|
|
||||||
if (ip) {
|
|
||||||
this.set("ip6", convertToBytes("ip6", ip));
|
|
||||||
} else {
|
|
||||||
this.delete("ip6");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get tcp6(): number | undefined {
|
|
||||||
const raw = this.get("tcp6");
|
|
||||||
if (raw) {
|
|
||||||
return Number(convertToString("tcp", raw));
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set tcp6(port: number | undefined) {
|
|
||||||
if (port === undefined) {
|
|
||||||
this.delete("tcp6");
|
|
||||||
} else {
|
|
||||||
this.set("tcp6", convertToBytes("tcp", port.toString(10)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get udp6(): number | undefined {
|
|
||||||
const raw = this.get("udp6");
|
|
||||||
if (raw) {
|
|
||||||
return Number(convertToString("udp", raw));
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set udp6(port: number | undefined) {
|
|
||||||
if (port === undefined) {
|
|
||||||
this.delete("udp6");
|
|
||||||
} else {
|
|
||||||
this.set("udp6", convertToBytes("udp", port.toString(10)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the `multiaddrs` field from ENR.
|
|
||||||
*
|
|
||||||
* This field is used to store multiaddresses that cannot be stored with the current ENR pre-defined keys.
|
|
||||||
* These can be a multiaddresses that include encapsulation (e.g. wss) or do not use `ip4` nor `ip6` for the host
|
|
||||||
* address (e.g. `dns4`, `dnsaddr`, etc)..
|
|
||||||
*
|
|
||||||
* If the peer information only contains information that can be represented with the ENR pre-defined keys
|
|
||||||
* (ip, tcp, etc) then the usage of { @link getLocationMultiaddr } should be preferred.
|
|
||||||
*
|
|
||||||
* The multiaddresses stored in this field are expected to be location multiaddresses, ie, peer id less.
|
|
||||||
*/
|
|
||||||
get multiaddrs(): Multiaddr[] | undefined {
|
|
||||||
const raw = this.get("multiaddrs");
|
|
||||||
|
|
||||||
if (raw) return decodeMultiaddrs(raw);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the `multiaddrs` field on the ENR.
|
|
||||||
*
|
|
||||||
* This field is used to store multiaddresses that cannot be stored with the current ENR pre-defined keys.
|
|
||||||
* These can be a multiaddresses that include encapsulation (e.g. wss) or do not use `ip4` nor `ip6` for the host
|
|
||||||
* address (e.g. `dns4`, `dnsaddr`, etc)..
|
|
||||||
*
|
|
||||||
* If the peer information only contains information that can be represented with the ENR pre-defined keys
|
|
||||||
* (ip, tcp, etc) then the usage of { @link setLocationMultiaddr } should be preferred.
|
|
||||||
* The multiaddresses stored in this field must be location multiaddresses,
|
|
||||||
* ie, without a peer id.
|
|
||||||
*/
|
|
||||||
set multiaddrs(multiaddrs: Multiaddr[] | undefined) {
|
|
||||||
if (multiaddrs === undefined) {
|
|
||||||
this.delete("multiaddrs");
|
|
||||||
} else {
|
|
||||||
const multiaddrsBuf = encodeMultiaddrs(multiaddrs);
|
|
||||||
this.set("multiaddrs", multiaddrsBuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getLocationMultiaddr: (
|
getLocationMultiaddr: (
|
||||||
protocol: TransportProtocol | TransportProtocolPerIpVersion
|
protocol: TransportProtocol | TransportProtocolPerIpVersion
|
||||||
) => Multiaddr | undefined = locationMultiaddrFromEnrFields.bind({}, this);
|
) => Multiaddr | undefined = locationMultiaddrFromEnrFields.bind({}, this);
|
||||||
|
@ -330,28 +147,6 @@ export class ENR extends Map<ENRKey, ENRValue> implements IEnr {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the `waku2` field from ENR.
|
|
||||||
*/
|
|
||||||
get waku2(): Waku2 | undefined {
|
|
||||||
const raw = this.get("waku2");
|
|
||||||
if (raw) return decodeWaku2(raw[0]);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the `waku2` field on the ENR.
|
|
||||||
*/
|
|
||||||
set waku2(waku2: Waku2 | undefined) {
|
|
||||||
if (waku2 === undefined) {
|
|
||||||
this.delete("waku2");
|
|
||||||
} else {
|
|
||||||
const byte = encodeWaku2(waku2);
|
|
||||||
this.set("waku2", new Uint8Array([byte]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
verify(data: Uint8Array, signature: Uint8Array): boolean {
|
verify(data: Uint8Array, signature: Uint8Array): boolean {
|
||||||
if (!this.get("id") || this.id !== "v4") {
|
if (!this.get("id") || this.id !== "v4") {
|
||||||
throw new Error(ERR_INVALID_ID);
|
throw new Error(ERR_INVALID_ID);
|
||||||
|
|
|
@ -0,0 +1,212 @@
|
||||||
|
import type { Multiaddr } from "@multiformats/multiaddr";
|
||||||
|
import {
|
||||||
|
convertToBytes,
|
||||||
|
convertToString,
|
||||||
|
} from "@multiformats/multiaddr/convert";
|
||||||
|
import type { ENRKey, ENRValue, SequenceNumber, Waku2 } from "@waku/interfaces";
|
||||||
|
import { bytesToUtf8 } from "@waku/utils";
|
||||||
|
|
||||||
|
import { ERR_INVALID_ID } from "./constants.js";
|
||||||
|
import { decodeMultiaddrs, encodeMultiaddrs } from "./multiaddrs_codec.js";
|
||||||
|
import { decodeWaku2, encodeWaku2 } from "./waku2_codec.js";
|
||||||
|
|
||||||
|
export class RawEnr extends Map<ENRKey, ENRValue> {
|
||||||
|
public seq: SequenceNumber;
|
||||||
|
public signature?: Uint8Array;
|
||||||
|
|
||||||
|
protected constructor(
|
||||||
|
kvs: Record<ENRKey, ENRValue> = {},
|
||||||
|
seq: SequenceNumber = BigInt(1),
|
||||||
|
signature?: Uint8Array
|
||||||
|
) {
|
||||||
|
super(Object.entries(kvs));
|
||||||
|
this.seq = seq;
|
||||||
|
this.signature = signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
set(k: ENRKey, v: ENRValue): this {
|
||||||
|
this.signature = undefined;
|
||||||
|
this.seq++;
|
||||||
|
return super.set(k, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
get id(): string {
|
||||||
|
const id = this.get("id");
|
||||||
|
if (!id) throw new Error("id not found.");
|
||||||
|
return bytesToUtf8(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
get publicKey(): Uint8Array | undefined {
|
||||||
|
switch (this.id) {
|
||||||
|
case "v4":
|
||||||
|
return this.get("secp256k1");
|
||||||
|
default:
|
||||||
|
throw new Error(ERR_INVALID_ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get ip(): string | undefined {
|
||||||
|
const raw = this.get("ip");
|
||||||
|
if (raw) {
|
||||||
|
return convertToString("ip4", raw) as string;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set ip(ip: string | undefined) {
|
||||||
|
if (ip) {
|
||||||
|
this.set("ip", convertToBytes("ip4", ip));
|
||||||
|
} else {
|
||||||
|
this.delete("ip");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get tcp(): number | undefined {
|
||||||
|
const raw = this.get("tcp");
|
||||||
|
if (raw) {
|
||||||
|
return Number(convertToString("tcp", raw));
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set tcp(port: number | undefined) {
|
||||||
|
if (port === undefined) {
|
||||||
|
this.delete("tcp");
|
||||||
|
} else {
|
||||||
|
this.set("tcp", convertToBytes("tcp", port.toString(10)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get udp(): number | undefined {
|
||||||
|
const raw = this.get("udp");
|
||||||
|
if (raw) {
|
||||||
|
return Number(convertToString("udp", raw));
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set udp(port: number | undefined) {
|
||||||
|
if (port === undefined) {
|
||||||
|
this.delete("udp");
|
||||||
|
} else {
|
||||||
|
this.set("udp", convertToBytes("udp", port.toString(10)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get ip6(): string | undefined {
|
||||||
|
const raw = this.get("ip6");
|
||||||
|
if (raw) {
|
||||||
|
return convertToString("ip6", raw) as string;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set ip6(ip: string | undefined) {
|
||||||
|
if (ip) {
|
||||||
|
this.set("ip6", convertToBytes("ip6", ip));
|
||||||
|
} else {
|
||||||
|
this.delete("ip6");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get tcp6(): number | undefined {
|
||||||
|
const raw = this.get("tcp6");
|
||||||
|
if (raw) {
|
||||||
|
return Number(convertToString("tcp", raw));
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set tcp6(port: number | undefined) {
|
||||||
|
if (port === undefined) {
|
||||||
|
this.delete("tcp6");
|
||||||
|
} else {
|
||||||
|
this.set("tcp6", convertToBytes("tcp", port.toString(10)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get udp6(): number | undefined {
|
||||||
|
const raw = this.get("udp6");
|
||||||
|
if (raw) {
|
||||||
|
return Number(convertToString("udp", raw));
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set udp6(port: number | undefined) {
|
||||||
|
if (port === undefined) {
|
||||||
|
this.delete("udp6");
|
||||||
|
} else {
|
||||||
|
this.set("udp6", convertToBytes("udp", port.toString(10)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the `multiaddrs` field from ENR.
|
||||||
|
*
|
||||||
|
* This field is used to store multiaddresses that cannot be stored with the current ENR pre-defined keys.
|
||||||
|
* These can be a multiaddresses that include encapsulation (e.g. wss) or do not use `ip4` nor `ip6` for the host
|
||||||
|
* address (e.g. `dns4`, `dnsaddr`, etc)..
|
||||||
|
*
|
||||||
|
* If the peer information only contains information that can be represented with the ENR pre-defined keys
|
||||||
|
* (ip, tcp, etc) then the usage of { @link getLocationMultiaddr } should be preferred.
|
||||||
|
*
|
||||||
|
* The multiaddresses stored in this field are expected to be location multiaddresses, ie, peer id less.
|
||||||
|
*/
|
||||||
|
get multiaddrs(): Multiaddr[] | undefined {
|
||||||
|
const raw = this.get("multiaddrs");
|
||||||
|
|
||||||
|
if (raw) return decodeMultiaddrs(raw);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the `multiaddrs` field on the ENR.
|
||||||
|
*
|
||||||
|
* This field is used to store multiaddresses that cannot be stored with the current ENR pre-defined keys.
|
||||||
|
* These can be a multiaddresses that include encapsulation (e.g. wss) or do not use `ip4` nor `ip6` for the host
|
||||||
|
* address (e.g. `dns4`, `dnsaddr`, etc)..
|
||||||
|
*
|
||||||
|
* If the peer information only contains information that can be represented with the ENR pre-defined keys
|
||||||
|
* (ip, tcp, etc) then the usage of { @link setLocationMultiaddr } should be preferred.
|
||||||
|
* The multiaddresses stored in this field must be location multiaddresses,
|
||||||
|
* ie, without a peer id.
|
||||||
|
*/
|
||||||
|
set multiaddrs(multiaddrs: Multiaddr[] | undefined) {
|
||||||
|
if (multiaddrs === undefined) {
|
||||||
|
this.delete("multiaddrs");
|
||||||
|
} else {
|
||||||
|
const multiaddrsBuf = encodeMultiaddrs(multiaddrs);
|
||||||
|
this.set("multiaddrs", multiaddrsBuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the `waku2` field from ENR.
|
||||||
|
*/
|
||||||
|
get waku2(): Waku2 | undefined {
|
||||||
|
const raw = this.get("waku2");
|
||||||
|
if (raw) return decodeWaku2(raw[0]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the `waku2` field on the ENR.
|
||||||
|
*/
|
||||||
|
set waku2(waku2: Waku2 | undefined) {
|
||||||
|
if (waku2 === undefined) {
|
||||||
|
this.delete("waku2");
|
||||||
|
} else {
|
||||||
|
const byte = encodeWaku2(waku2);
|
||||||
|
this.set("waku2", new Uint8Array([byte]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue