Skip to content

Commit 22ffcf5

Browse files
committed
chore!: extract encoder code
Separation of concerns by moving encoding logic in new class.
1 parent 130c49b commit 22ffcf5

File tree

4 files changed

+63
-58
lines changed

4 files changed

+63
-58
lines changed

packages/enr/src/encoder.ts

+50
Original file line numberDiff line numberDiff line change
@@ -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";
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+
}

packages/enr/src/enr.spec.ts

+11-10
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { equals } from "uint8arrays/equals";
99
import { ERR_INVALID_ID } from "./constants.js";
1010
import { EnrCreator } from "./creator.js";
1111
import { EnrDecoder } from "./decoder.js";
12+
import { EnrEncoder } from "./encoder.js";
1213
import { ENR } from "./enr.js";
1314
import { getPrivateKeyFromPeerId } from "./peer_id.js";
1415

@@ -34,7 +35,7 @@ describe("ENR", function () {
3435
lightPush: false,
3536
};
3637

37-
const txt = await enr.encodeTxt(privateKey);
38+
const txt = await EnrEncoder.toString(enr, privateKey);
3839
const enr2 = await EnrDecoder.fromString(txt);
3940

4041
if (!enr.signature) throw "enr.signature is undefined";
@@ -113,7 +114,7 @@ describe("ENR", function () {
113114
enr.setLocationMultiaddr(multiaddr("/ip4/18.223.219.100/udp/9000"));
114115

115116
enr.set("id", new Uint8Array([0]));
116-
const txt = await enr.encodeTxt(privateKey);
117+
const txt = await EnrEncoder.toString(enr, privateKey);
117118

118119
await EnrDecoder.fromString(txt);
119120
assert.fail("Expect error here");
@@ -199,7 +200,7 @@ describe("ENR", function () {
199200
record = await EnrCreator.fromPublicKey(secp.getPublicKey(privateKey));
200201
record.setLocationMultiaddr(multiaddr("/ip4/127.0.0.1/udp/30303"));
201202
record.seq = seq;
202-
await record.encodeTxt(privateKey);
203+
await EnrEncoder.toString(record, privateKey);
203204
});
204205

205206
it("should properly compute the node id", () => {
@@ -209,7 +210,7 @@ describe("ENR", function () {
209210
});
210211

211212
it("should encode/decode to RLP encoding", async function () {
212-
const encoded = await record.encode(privateKey);
213+
const encoded = await EnrEncoder.toBytes(record, privateKey);
213214
const decoded = await EnrDecoder.fromRLP(encoded);
214215

215216
record.forEach((value, key) => {
@@ -403,7 +404,7 @@ describe("ENR", function () {
403404
it("should set field with all protocols disabled", async () => {
404405
enr.waku2 = waku2Protocols;
405406

406-
const txt = await enr.encodeTxt(privateKey);
407+
const txt = await EnrEncoder.toString(enr, privateKey);
407408
const decoded = (await EnrDecoder.fromString(txt)).waku2!;
408409

409410
expect(decoded.relay).to.equal(false);
@@ -419,7 +420,7 @@ describe("ENR", function () {
419420
waku2Protocols.lightPush = true;
420421

421422
enr.waku2 = waku2Protocols;
422-
const txt = await enr.encodeTxt(privateKey);
423+
const txt = await EnrEncoder.toString(enr, privateKey);
423424
const decoded = (await EnrDecoder.fromString(txt)).waku2!;
424425

425426
expect(decoded.relay).to.equal(true);
@@ -432,7 +433,7 @@ describe("ENR", function () {
432433
waku2Protocols.relay = true;
433434

434435
enr.waku2 = waku2Protocols;
435-
const txt = await enr.encodeTxt(privateKey);
436+
const txt = await EnrEncoder.toString(enr, privateKey);
436437
const decoded = (await EnrDecoder.fromString(txt)).waku2!;
437438

438439
expect(decoded.relay).to.equal(true);
@@ -445,7 +446,7 @@ describe("ENR", function () {
445446
waku2Protocols.store = true;
446447

447448
enr.waku2 = waku2Protocols;
448-
const txt = await enr.encodeTxt(privateKey);
449+
const txt = await EnrEncoder.toString(enr, privateKey);
449450
const decoded = (await EnrDecoder.fromString(txt)).waku2!;
450451

451452
expect(decoded.relay).to.equal(false);
@@ -458,7 +459,7 @@ describe("ENR", function () {
458459
waku2Protocols.filter = true;
459460

460461
enr.waku2 = waku2Protocols;
461-
const txt = await enr.encodeTxt(privateKey);
462+
const txt = await EnrEncoder.toString(enr, privateKey);
462463
const decoded = (await EnrDecoder.fromString(txt)).waku2!;
463464

464465
expect(decoded.relay).to.equal(false);
@@ -471,7 +472,7 @@ describe("ENR", function () {
471472
waku2Protocols.lightPush = true;
472473

473474
enr.waku2 = waku2Protocols;
474-
const txt = await enr.encodeTxt(privateKey);
475+
const txt = await EnrEncoder.toString(enr, privateKey);
475476
const decoded = (await EnrDecoder.fromString(txt)).waku2!;
476477

477478
expect(decoded.relay).to.equal(false);

packages/enr/src/enr.ts

+2-47
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import * as RLP from "@ethersproject/rlp";
21
import type { PeerId } from "@libp2p/interface-peer-id";
32
import type { Multiaddr } from "@multiformats/multiaddr";
43
import {
@@ -13,15 +12,10 @@ import type {
1312
SequenceNumber,
1413
Waku2,
1514
} from "@waku/interfaces";
16-
import { bytesToUtf8, hexToBytes, utf8ToBytes } from "@waku/utils";
15+
import { bytesToUtf8 } from "@waku/utils";
1716
import debug from "debug";
18-
import { toString } from "uint8arrays/to-string";
1917

20-
import {
21-
ERR_INVALID_ID,
22-
ERR_NO_SIGNATURE,
23-
MAX_RECORD_SIZE,
24-
} from "./constants.js";
18+
import { ERR_INVALID_ID } from "./constants.js";
2519
import { keccak256, verifySignature } from "./crypto.js";
2620
import { multiaddrFromFields } from "./multiaddr_from_fields.js";
2721
import { decodeMultiaddrs, encodeMultiaddrs } from "./multiaddrs_codec.js";
@@ -380,43 +374,4 @@ export class ENR extends Map<ENRKey, ENRValue> implements IEnr {
380374
}
381375
return this.signature;
382376
}
383-
384-
async encodeToValues(
385-
privateKey?: Uint8Array
386-
): Promise<(ENRKey | ENRValue | number[])[]> {
387-
// sort keys and flatten into [k, v, k, v, ...]
388-
const content: Array<ENRKey | ENRValue | number[]> = Array.from(this.keys())
389-
.sort((a, b) => a.localeCompare(b))
390-
.map((k) => [k, this.get(k)] as [ENRKey, ENRValue])
391-
.map(([k, v]) => [utf8ToBytes(k), v])
392-
.flat();
393-
content.unshift(new Uint8Array([Number(this.seq)]));
394-
if (privateKey) {
395-
content.unshift(
396-
await this.sign(hexToBytes(RLP.encode(content)), privateKey)
397-
);
398-
} else {
399-
if (!this.signature) {
400-
throw new Error(ERR_NO_SIGNATURE);
401-
}
402-
content.unshift(this.signature);
403-
}
404-
return content;
405-
}
406-
407-
async encode(privateKey?: Uint8Array): Promise<Uint8Array> {
408-
const encoded = hexToBytes(
409-
RLP.encode(await this.encodeToValues(privateKey))
410-
);
411-
if (encoded.length >= MAX_RECORD_SIZE) {
412-
throw new Error("ENR must be less than 300 bytes");
413-
}
414-
return encoded;
415-
}
416-
417-
async encodeTxt(privateKey?: Uint8Array): Promise<string> {
418-
return (
419-
ENR.RECORD_PREFIX + toString(await this.encode(privateKey), "base64url")
420-
);
421-
}
422377
}

packages/interfaces/src/enr.ts

-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,5 @@ export interface IEnr extends Map<ENRKey, ENRValue> {
3333
multiaddrs?: Multiaddr[];
3434
waku2?: Waku2;
3535

36-
encode(privateKey?: Uint8Array): Promise<Uint8Array>;
3736
getFullMultiaddrs(): Multiaddr[];
3837
}

0 commit comments

Comments
 (0)