@waku/enr 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -2
- package/bundle/index.js +5367 -5359
- package/dist/.tsbuildinfo +1 -0
- package/dist/creator.d.ts +7 -0
- package/dist/creator.js +26 -0
- package/dist/creator.js.map +1 -0
- package/dist/crypto.d.ts +0 -7
- package/dist/crypto.js +1 -7
- package/dist/crypto.js.map +1 -1
- package/dist/decoder.d.ts +5 -0
- package/dist/decoder.js +62 -0
- package/dist/decoder.js.map +1 -0
- package/dist/encoder.d.ts +7 -0
- package/dist/encoder.js +38 -0
- package/dist/encoder.js.map +1 -0
- package/dist/enr.d.ts +19 -68
- package/dist/enr.js +43 -336
- package/dist/enr.js.map +1 -1
- package/dist/get_multiaddr.d.ts +3 -0
- package/dist/get_multiaddr.js +31 -0
- package/dist/get_multiaddr.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/peer_id.d.ts +4 -0
- package/dist/peer_id.js +25 -0
- package/dist/peer_id.js.map +1 -0
- package/dist/raw_enr.d.ts +56 -0
- package/dist/raw_enr.js +142 -0
- package/dist/raw_enr.js.map +1 -0
- package/dist/v4.js +1 -1
- package/dist/v4.js.map +1 -1
- package/package.json +39 -28
- package/src/creator.ts +36 -0
- package/src/crypto.ts +1 -9
- package/src/decoder.ts +84 -0
- package/src/encoder.ts +50 -0
- package/src/enr.ts +50 -411
- package/src/get_multiaddr.ts +47 -0
- package/src/index.ts +3 -1
- package/src/peer_id.ts +34 -0
- package/src/raw_enr.ts +204 -0
- package/src/v4.ts +1 -2
- package/dist/keypair/index.d.ts +0 -8
- package/dist/keypair/index.js +0 -53
- package/dist/keypair/index.js.map +0 -1
- package/dist/keypair/secp256k1.d.ts +0 -13
- package/dist/keypair/secp256k1.js +0 -57
- package/dist/keypair/secp256k1.js.map +0 -1
- package/dist/keypair/types.d.ts +0 -13
- package/dist/keypair/types.js +0 -7
- package/dist/keypair/types.js.map +0 -1
- package/src/keypair/index.ts +0 -76
- package/src/keypair/secp256k1.ts +0 -69
- package/src/keypair/types.ts +0 -14
package/dist/raw_enr.js
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
import { convertToBytes, convertToString, } from "@multiformats/multiaddr/convert";
|
2
|
+
import { bytesToUtf8 } from "@waku/utils/bytes";
|
3
|
+
import { ERR_INVALID_ID } from "./constants.js";
|
4
|
+
import { decodeMultiaddrs, encodeMultiaddrs } from "./multiaddrs_codec.js";
|
5
|
+
import { decodeWaku2, encodeWaku2 } from "./waku2_codec.js";
|
6
|
+
export class RawEnr extends Map {
|
7
|
+
constructor(kvs = {}, seq = BigInt(1), signature) {
|
8
|
+
super(Object.entries(kvs));
|
9
|
+
this.seq = seq;
|
10
|
+
this.signature = signature;
|
11
|
+
}
|
12
|
+
set(k, v) {
|
13
|
+
this.signature = undefined;
|
14
|
+
this.seq++;
|
15
|
+
return super.set(k, v);
|
16
|
+
}
|
17
|
+
get id() {
|
18
|
+
const id = this.get("id");
|
19
|
+
if (!id)
|
20
|
+
throw new Error("id not found.");
|
21
|
+
return bytesToUtf8(id);
|
22
|
+
}
|
23
|
+
get publicKey() {
|
24
|
+
switch (this.id) {
|
25
|
+
case "v4":
|
26
|
+
return this.get("secp256k1");
|
27
|
+
default:
|
28
|
+
throw new Error(ERR_INVALID_ID);
|
29
|
+
}
|
30
|
+
}
|
31
|
+
get ip() {
|
32
|
+
return getStringValue(this, "ip", "ip4");
|
33
|
+
}
|
34
|
+
set ip(ip) {
|
35
|
+
setStringValue(this, "ip", "ip4", ip);
|
36
|
+
}
|
37
|
+
get tcp() {
|
38
|
+
return getNumberAsStringValue(this, "tcp", "tcp");
|
39
|
+
}
|
40
|
+
set tcp(port) {
|
41
|
+
setNumberAsStringValue(this, "tcp", "tcp", port);
|
42
|
+
}
|
43
|
+
get udp() {
|
44
|
+
return getNumberAsStringValue(this, "udp", "udp");
|
45
|
+
}
|
46
|
+
set udp(port) {
|
47
|
+
setNumberAsStringValue(this, "udp", "udp", port);
|
48
|
+
}
|
49
|
+
get ip6() {
|
50
|
+
return getStringValue(this, "ip6", "ip6");
|
51
|
+
}
|
52
|
+
set ip6(ip) {
|
53
|
+
setStringValue(this, "ip6", "ip6", ip);
|
54
|
+
}
|
55
|
+
get tcp6() {
|
56
|
+
return getNumberAsStringValue(this, "tcp6", "tcp");
|
57
|
+
}
|
58
|
+
set tcp6(port) {
|
59
|
+
setNumberAsStringValue(this, "tcp6", "tcp", port);
|
60
|
+
}
|
61
|
+
get udp6() {
|
62
|
+
return getNumberAsStringValue(this, "udp6", "udp");
|
63
|
+
}
|
64
|
+
set udp6(port) {
|
65
|
+
setNumberAsStringValue(this, "udp6", "udp", port);
|
66
|
+
}
|
67
|
+
/**
|
68
|
+
* Get the `multiaddrs` field from ENR.
|
69
|
+
*
|
70
|
+
* This field is used to store multiaddresses that cannot be stored with the current ENR pre-defined keys.
|
71
|
+
* These can be a multiaddresses that include encapsulation (e.g. wss) or do not use `ip4` nor `ip6` for the host
|
72
|
+
* address (e.g. `dns4`, `dnsaddr`, etc)..
|
73
|
+
*
|
74
|
+
* If the peer information only contains information that can be represented with the ENR pre-defined keys
|
75
|
+
* (ip, tcp, etc) then the usage of { @link ENR.getLocationMultiaddr } should be preferred.
|
76
|
+
*
|
77
|
+
* The multiaddresses stored in this field are expected to be location multiaddresses, ie, peer id less.
|
78
|
+
*/
|
79
|
+
get multiaddrs() {
|
80
|
+
const raw = this.get("multiaddrs");
|
81
|
+
if (raw)
|
82
|
+
return decodeMultiaddrs(raw);
|
83
|
+
return;
|
84
|
+
}
|
85
|
+
/**
|
86
|
+
* Set the `multiaddrs` field on the ENR.
|
87
|
+
*
|
88
|
+
* This field is used to store multiaddresses that cannot be stored with the current ENR pre-defined keys.
|
89
|
+
* These can be a multiaddresses that include encapsulation (e.g. wss) or do not use `ip4` nor `ip6` for the host
|
90
|
+
* address (e.g. `dns4`, `dnsaddr`, etc)..
|
91
|
+
*
|
92
|
+
* If the peer information only contains information that can be represented with the ENR pre-defined keys
|
93
|
+
* (ip, tcp, etc) then the usage of { @link ENR.setLocationMultiaddr } should be preferred.
|
94
|
+
* The multiaddresses stored in this field must be location multiaddresses,
|
95
|
+
* ie, without a peer id.
|
96
|
+
*/
|
97
|
+
set multiaddrs(multiaddrs) {
|
98
|
+
deleteUndefined(this, "multiaddrs", multiaddrs, encodeMultiaddrs);
|
99
|
+
}
|
100
|
+
/**
|
101
|
+
* Get the `waku2` field from ENR.
|
102
|
+
*/
|
103
|
+
get waku2() {
|
104
|
+
const raw = this.get("waku2");
|
105
|
+
if (raw)
|
106
|
+
return decodeWaku2(raw[0]);
|
107
|
+
return;
|
108
|
+
}
|
109
|
+
/**
|
110
|
+
* Set the `waku2` field on the ENR.
|
111
|
+
*/
|
112
|
+
set waku2(waku2) {
|
113
|
+
deleteUndefined(this, "waku2", waku2, (w) => new Uint8Array([encodeWaku2(w)]));
|
114
|
+
}
|
115
|
+
}
|
116
|
+
function getStringValue(map, key, proto) {
|
117
|
+
const raw = map.get(key);
|
118
|
+
if (!raw)
|
119
|
+
return;
|
120
|
+
return convertToString(proto, raw);
|
121
|
+
}
|
122
|
+
function getNumberAsStringValue(map, key, proto) {
|
123
|
+
const raw = map.get(key);
|
124
|
+
if (!raw)
|
125
|
+
return;
|
126
|
+
return Number(convertToString(proto, raw));
|
127
|
+
}
|
128
|
+
function setStringValue(map, key, proto, value) {
|
129
|
+
deleteUndefined(map, key, value, convertToBytes.bind({}, proto));
|
130
|
+
}
|
131
|
+
function setNumberAsStringValue(map, key, proto, value) {
|
132
|
+
setStringValue(map, key, proto, value?.toString(10));
|
133
|
+
}
|
134
|
+
function deleteUndefined(map, key, value, transform) {
|
135
|
+
if (value !== undefined) {
|
136
|
+
map.set(key, transform(value));
|
137
|
+
}
|
138
|
+
else {
|
139
|
+
map.delete(key);
|
140
|
+
}
|
141
|
+
}
|
142
|
+
//# sourceMappingURL=raw_enr.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"raw_enr.js","sourceRoot":"","sources":["../src/raw_enr.ts"],"names":[],"mappings":"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"}
|
package/dist/v4.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import * as secp from "@noble/secp256k1";
|
2
|
-
import { bytesToHex } from "@waku/
|
2
|
+
import { bytesToHex } from "@waku/utils/bytes";
|
3
3
|
import { keccak256 } from "./crypto.js";
|
4
4
|
export async function sign(privKey, msg) {
|
5
5
|
return secp.sign(keccak256(msg), privKey, {
|
package/dist/v4.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"v4.js","sourceRoot":"","sources":["../src/v4.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAC;
|
1
|
+
{"version":3,"file":"v4.js","sourceRoot":"","sources":["../src/v4.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAC;AAEzC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,MAAM,CAAC,KAAK,UAAU,IAAI,CACxB,OAAmB,EACnB,GAAe;IAEf,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE;QACxC,GAAG,EAAE,KAAK;KACX,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,MAAkB;IACvC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7C,MAAM,kBAAkB,GAAG,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAEvD,OAAO,UAAU,CAAC,SAAS,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@waku/enr",
|
3
|
-
"version": "0.0.
|
3
|
+
"version": "0.0.6",
|
4
4
|
"description": "ENR (EIP-778) for Waku",
|
5
5
|
"types": "./dist/index.d.ts",
|
6
6
|
"module": "./dist/index.js",
|
@@ -37,7 +37,7 @@
|
|
37
37
|
"build:bundle": "rollup --config rollup.config.js",
|
38
38
|
"fix": "run-s fix:*",
|
39
39
|
"fix:prettier": "prettier . --write",
|
40
|
-
"fix:lint": "eslint src
|
40
|
+
"fix:lint": "eslint src *.js --fix",
|
41
41
|
"check": "run-s check:*",
|
42
42
|
"check:lint": "eslint src --ext .ts",
|
43
43
|
"check:prettier": "prettier . --list-different",
|
@@ -53,38 +53,49 @@
|
|
53
53
|
"node": ">=16"
|
54
54
|
},
|
55
55
|
"dependencies": {
|
56
|
-
"@ethersproject/rlp": "^5.
|
57
|
-
"@libp2p/crypto": "^1.0.
|
58
|
-
"@libp2p/
|
59
|
-
"@
|
60
|
-
"@
|
61
|
-
"@
|
62
|
-
"@waku/byte-utils": "*",
|
63
|
-
"chai": "^4.3.6",
|
56
|
+
"@ethersproject/rlp": "^5.7.0",
|
57
|
+
"@libp2p/crypto": "^1.0.14",
|
58
|
+
"@libp2p/peer-id": "^2.0.2",
|
59
|
+
"@multiformats/multiaddr": "^11.4.0",
|
60
|
+
"@noble/secp256k1": "^1.7.1",
|
61
|
+
"@waku/utils": "0.0.2",
|
64
62
|
"debug": "^4.3.4",
|
65
63
|
"js-sha3": "^0.8.0"
|
66
64
|
},
|
67
65
|
"devDependencies": {
|
68
|
-
"@
|
69
|
-
"
|
70
|
-
"@libp2p/peer-id-factory": "^
|
71
|
-
"@rollup/plugin-commonjs": "^
|
72
|
-
"@rollup/plugin-json": "^
|
73
|
-
"@rollup/plugin-node-resolve": "^
|
74
|
-
"@
|
75
|
-
"@
|
76
|
-
"
|
77
|
-
"eslint": "^
|
78
|
-
"
|
66
|
+
"@libp2p/interface-peer-id": "^2.0.1",
|
67
|
+
"@libp2p/interface-peer-info": "^1.0.8",
|
68
|
+
"@libp2p/peer-id-factory": "^2.0.1",
|
69
|
+
"@rollup/plugin-commonjs": "^24.0.1",
|
70
|
+
"@rollup/plugin-json": "^6.0.0",
|
71
|
+
"@rollup/plugin-node-resolve": "^15.0.1",
|
72
|
+
"@types/chai": "^4.3.4",
|
73
|
+
"@types/mocha": "^10.0.1",
|
74
|
+
"@typescript-eslint/eslint-plugin": "^5.54.1",
|
75
|
+
"@typescript-eslint/parser": "^5.51.0",
|
76
|
+
"@waku/build-utils": "*",
|
77
|
+
"@waku/interfaces": "0.0.8",
|
78
|
+
"chai": "^4.3.7",
|
79
|
+
"cspell": "^6.28.0",
|
80
|
+
"eslint": "^8.35.0",
|
81
|
+
"eslint-config-prettier": "^8.6.0",
|
79
82
|
"eslint-plugin-eslint-comments": "^3.2.0",
|
80
|
-
"eslint-plugin-functional": "^
|
81
|
-
"eslint-plugin-import": "^2.
|
82
|
-
"eslint-plugin-prettier": "^4.
|
83
|
+
"eslint-plugin-functional": "^5.0.4",
|
84
|
+
"eslint-plugin-import": "^2.27.5",
|
85
|
+
"eslint-plugin-prettier": "^4.2.1",
|
86
|
+
"karma": "^6.4.1",
|
87
|
+
"karma-chrome-launcher": "^3.1.1",
|
88
|
+
"karma-mocha": "^2.0.1",
|
89
|
+
"karma-webpack": "^5.0.0",
|
90
|
+
"mocha": "^10.2.0",
|
83
91
|
"npm-run-all": "^4.1.5",
|
84
|
-
"prettier": "^2.
|
85
|
-
"
|
86
|
-
"
|
87
|
-
"
|
92
|
+
"prettier": "^2.8.4",
|
93
|
+
"process": "^0.11.10",
|
94
|
+
"puppeteer": "^19.7.2",
|
95
|
+
"rollup": "^3.15.0",
|
96
|
+
"ts-loader": "^9.4.2",
|
97
|
+
"typescript": "^4.9.5",
|
98
|
+
"uint8arrays": "^4.0.3"
|
88
99
|
},
|
89
100
|
"typedoc": {
|
90
101
|
"entryPoint": "./src/index.ts"
|
package/src/creator.ts
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
import { PeerId } from "@libp2p/interface-peer-id";
|
2
|
+
import type { ENRKey, ENRValue } from "@waku/interfaces";
|
3
|
+
import { utf8ToBytes } from "@waku/utils/bytes";
|
4
|
+
|
5
|
+
import { compressPublicKey } from "./crypto.js";
|
6
|
+
import { ENR } from "./enr.js";
|
7
|
+
import { getPublicKeyFromPeerId } from "./peer_id.js";
|
8
|
+
|
9
|
+
export class EnrCreator {
|
10
|
+
static fromPublicKey(
|
11
|
+
publicKey: Uint8Array,
|
12
|
+
kvs: Record<ENRKey, ENRValue> = {}
|
13
|
+
): Promise<ENR> {
|
14
|
+
// EIP-778 specifies that the key must be in compressed format, 33 bytes
|
15
|
+
if (publicKey.length !== 33) {
|
16
|
+
publicKey = compressPublicKey(publicKey);
|
17
|
+
}
|
18
|
+
return ENR.create({
|
19
|
+
...kvs,
|
20
|
+
id: utf8ToBytes("v4"),
|
21
|
+
secp256k1: publicKey,
|
22
|
+
});
|
23
|
+
}
|
24
|
+
|
25
|
+
static async fromPeerId(
|
26
|
+
peerId: PeerId,
|
27
|
+
kvs: Record<ENRKey, ENRValue> = {}
|
28
|
+
): Promise<ENR> {
|
29
|
+
switch (peerId.type) {
|
30
|
+
case "secp256k1":
|
31
|
+
return EnrCreator.fromPublicKey(getPublicKeyFromPeerId(peerId), kvs);
|
32
|
+
default:
|
33
|
+
throw new Error();
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
package/src/crypto.ts
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
import * as secp from "@noble/secp256k1";
|
2
|
-
import { concat } from "@waku/
|
2
|
+
import { concat } from "@waku/utils/bytes";
|
3
3
|
import sha3 from "js-sha3";
|
4
4
|
|
5
|
-
export const randomBytes = secp.utils.randomBytes;
|
6
|
-
|
7
|
-
/**
|
8
|
-
* Return the public key for the given private key, to be used for asymmetric
|
9
|
-
* encryption.
|
10
|
-
*/
|
11
|
-
export const getPublicKey = secp.getPublicKey;
|
12
|
-
|
13
5
|
/**
|
14
6
|
* ECDSA Sign a message with the given private key.
|
15
7
|
*
|
package/src/decoder.ts
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
import * as RLP from "@ethersproject/rlp";
|
2
|
+
import type { ENRKey, ENRValue } from "@waku/interfaces";
|
3
|
+
import { bytesToHex, bytesToUtf8, hexToBytes } from "@waku/utils/bytes";
|
4
|
+
import { log } from "debug";
|
5
|
+
import { fromString } from "uint8arrays/from-string";
|
6
|
+
|
7
|
+
import { ENR } from "./enr.js";
|
8
|
+
|
9
|
+
export class EnrDecoder {
|
10
|
+
static fromString(encoded: string): Promise<ENR> {
|
11
|
+
if (!encoded.startsWith(ENR.RECORD_PREFIX)) {
|
12
|
+
throw new Error(
|
13
|
+
`"string encoded ENR must start with '${ENR.RECORD_PREFIX}'`
|
14
|
+
);
|
15
|
+
}
|
16
|
+
return EnrDecoder.fromRLP(fromString(encoded.slice(4), "base64url"));
|
17
|
+
}
|
18
|
+
|
19
|
+
static fromRLP(encoded: Uint8Array): Promise<ENR> {
|
20
|
+
const decoded = RLP.decode(encoded).map(hexToBytes);
|
21
|
+
return fromValues(decoded);
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
async function fromValues(values: Uint8Array[]): Promise<ENR> {
|
26
|
+
const { signature, seq, kvs } = checkValues(values);
|
27
|
+
|
28
|
+
const obj: Record<ENRKey, ENRValue> = {};
|
29
|
+
for (let i = 0; i < kvs.length; i += 2) {
|
30
|
+
try {
|
31
|
+
obj[bytesToUtf8(kvs[i])] = kvs[i + 1];
|
32
|
+
} catch (e) {
|
33
|
+
log("Failed to decode ENR key to UTF-8, skipping it", kvs[i], e);
|
34
|
+
}
|
35
|
+
}
|
36
|
+
const _seq = decodeSeq(seq);
|
37
|
+
|
38
|
+
const enr = await ENR.create(obj, _seq, signature);
|
39
|
+
checkSignature(seq, kvs, enr, signature);
|
40
|
+
return enr;
|
41
|
+
}
|
42
|
+
|
43
|
+
function decodeSeq(seq: Uint8Array): bigint {
|
44
|
+
// If seq is an empty array, translate as value 0
|
45
|
+
if (!seq.length) return BigInt(0);
|
46
|
+
|
47
|
+
return BigInt("0x" + bytesToHex(seq));
|
48
|
+
}
|
49
|
+
|
50
|
+
function checkValues(values: Uint8Array[]): {
|
51
|
+
signature: Uint8Array;
|
52
|
+
seq: Uint8Array;
|
53
|
+
kvs: Uint8Array[];
|
54
|
+
} {
|
55
|
+
if (!Array.isArray(values)) {
|
56
|
+
throw new Error("Decoded ENR must be an array");
|
57
|
+
}
|
58
|
+
if (values.length % 2 !== 0) {
|
59
|
+
throw new Error("Decoded ENR must have an even number of elements");
|
60
|
+
}
|
61
|
+
const [signature, seq, ...kvs] = values;
|
62
|
+
if (!signature || Array.isArray(signature)) {
|
63
|
+
throw new Error("Decoded ENR invalid signature: must be a byte array");
|
64
|
+
}
|
65
|
+
if (!seq || Array.isArray(seq)) {
|
66
|
+
throw new Error(
|
67
|
+
"Decoded ENR invalid sequence number: must be a byte array"
|
68
|
+
);
|
69
|
+
}
|
70
|
+
|
71
|
+
return { signature, seq, kvs };
|
72
|
+
}
|
73
|
+
|
74
|
+
function checkSignature(
|
75
|
+
seq: Uint8Array,
|
76
|
+
kvs: Uint8Array[],
|
77
|
+
enr: ENR,
|
78
|
+
signature: Uint8Array
|
79
|
+
): void {
|
80
|
+
const rlpEncodedBytes = hexToBytes(RLP.encode([seq, ...kvs]));
|
81
|
+
if (!enr.verify(rlpEncodedBytes, signature)) {
|
82
|
+
throw new Error("Unable to verify ENR signature");
|
83
|
+
}
|
84
|
+
}
|
package/src/encoder.ts
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
import * as RLP from "@ethersproject/rlp";
|
2
|
+
import type { ENRKey, ENRValue } from "@waku/interfaces";
|
3
|
+
import { hexToBytes, utf8ToBytes } from "@waku/utils/bytes";
|
4
|
+
import { toString } from "uint8arrays/to-string";
|
5
|
+
|
6
|
+
import { ERR_NO_SIGNATURE, MAX_RECORD_SIZE } from "./constants.js";
|
7
|
+
import { ENR } from "./enr.js";
|
8
|
+
|
9
|
+
export class EnrEncoder {
|
10
|
+
static async toValues(
|
11
|
+
enr: ENR,
|
12
|
+
privateKey?: Uint8Array
|
13
|
+
): Promise<(ENRKey | ENRValue | number[])[]> {
|
14
|
+
// sort keys and flatten into [k, v, k, v, ...]
|
15
|
+
const content: Array<ENRKey | ENRValue | number[]> = Array.from(enr.keys())
|
16
|
+
.sort((a, b) => a.localeCompare(b))
|
17
|
+
.map((k) => [k, enr.get(k)] as [ENRKey, ENRValue])
|
18
|
+
.map(([k, v]) => [utf8ToBytes(k), v])
|
19
|
+
.flat();
|
20
|
+
content.unshift(new Uint8Array([Number(enr.seq)]));
|
21
|
+
if (privateKey) {
|
22
|
+
content.unshift(
|
23
|
+
await enr.sign(hexToBytes(RLP.encode(content)), privateKey)
|
24
|
+
);
|
25
|
+
} else {
|
26
|
+
if (!enr.signature) {
|
27
|
+
throw new Error(ERR_NO_SIGNATURE);
|
28
|
+
}
|
29
|
+
content.unshift(enr.signature);
|
30
|
+
}
|
31
|
+
return content;
|
32
|
+
}
|
33
|
+
|
34
|
+
static async toBytes(enr: ENR, privateKey?: Uint8Array): Promise<Uint8Array> {
|
35
|
+
const encoded = hexToBytes(
|
36
|
+
RLP.encode(await EnrEncoder.toValues(enr, privateKey))
|
37
|
+
);
|
38
|
+
if (encoded.length >= MAX_RECORD_SIZE) {
|
39
|
+
throw new Error("ENR must be less than 300 bytes");
|
40
|
+
}
|
41
|
+
return encoded;
|
42
|
+
}
|
43
|
+
|
44
|
+
static async toString(enr: ENR, privateKey?: Uint8Array): Promise<string> {
|
45
|
+
return (
|
46
|
+
ENR.RECORD_PREFIX +
|
47
|
+
toString(await EnrEncoder.toBytes(enr, privateKey), "base64url")
|
48
|
+
);
|
49
|
+
}
|
50
|
+
}
|