mirror of https://github.com/waku-org/js-waku.git
chore!: extract encoder code
Separation of concerns by moving encoding logic in new class.
This commit is contained in:
parent
130c49b636
commit
22ffcf571a
|
@ -0,0 +1,50 @@
|
|||
import * as RLP from "@ethersproject/rlp";
|
||||
import type { ENRKey, ENRValue } from "@waku/interfaces";
|
||||
import { hexToBytes, utf8ToBytes } from "@waku/utils";
|
||||
import { toString } from "uint8arrays/to-string";
|
||||
|
||||
import { ERR_NO_SIGNATURE, MAX_RECORD_SIZE } from "./constants.js";
|
||||
import { ENR } from "./enr.js";
|
||||
|
||||
export class EnrEncoder {
|
||||
static async toValues(
|
||||
enr: ENR,
|
||||
privateKey?: Uint8Array
|
||||
): Promise<(ENRKey | ENRValue | number[])[]> {
|
||||
// sort keys and flatten into [k, v, k, v, ...]
|
||||
const content: Array<ENRKey | ENRValue | number[]> = Array.from(enr.keys())
|
||||
.sort((a, b) => a.localeCompare(b))
|
||||
.map((k) => [k, enr.get(k)] as [ENRKey, ENRValue])
|
||||
.map(([k, v]) => [utf8ToBytes(k), v])
|
||||
.flat();
|
||||
content.unshift(new Uint8Array([Number(enr.seq)]));
|
||||
if (privateKey) {
|
||||
content.unshift(
|
||||
await enr.sign(hexToBytes(RLP.encode(content)), privateKey)
|
||||
);
|
||||
} else {
|
||||
if (!enr.signature) {
|
||||
throw new Error(ERR_NO_SIGNATURE);
|
||||
}
|
||||
content.unshift(enr.signature);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
static async toBytes(enr: ENR, privateKey?: Uint8Array): Promise<Uint8Array> {
|
||||
const encoded = hexToBytes(
|
||||
RLP.encode(await EnrEncoder.toValues(enr, privateKey))
|
||||
);
|
||||
if (encoded.length >= MAX_RECORD_SIZE) {
|
||||
throw new Error("ENR must be less than 300 bytes");
|
||||
}
|
||||
return encoded;
|
||||
}
|
||||
|
||||
static async toString(enr: ENR, privateKey?: Uint8Array): Promise<string> {
|
||||
return (
|
||||
ENR.RECORD_PREFIX +
|
||||
toString(await EnrEncoder.toBytes(enr, privateKey), "base64url")
|
||||
);
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ import { equals } from "uint8arrays/equals";
|
|||
import { ERR_INVALID_ID } from "./constants.js";
|
||||
import { EnrCreator } from "./creator.js";
|
||||
import { EnrDecoder } from "./decoder.js";
|
||||
import { EnrEncoder } from "./encoder.js";
|
||||
import { ENR } from "./enr.js";
|
||||
import { getPrivateKeyFromPeerId } from "./peer_id.js";
|
||||
|
||||
|
@ -34,7 +35,7 @@ describe("ENR", function () {
|
|||
lightPush: false,
|
||||
};
|
||||
|
||||
const txt = await enr.encodeTxt(privateKey);
|
||||
const txt = await EnrEncoder.toString(enr, privateKey);
|
||||
const enr2 = await EnrDecoder.fromString(txt);
|
||||
|
||||
if (!enr.signature) throw "enr.signature is undefined";
|
||||
|
@ -113,7 +114,7 @@ describe("ENR", function () {
|
|||
enr.setLocationMultiaddr(multiaddr("/ip4/18.223.219.100/udp/9000"));
|
||||
|
||||
enr.set("id", new Uint8Array([0]));
|
||||
const txt = await enr.encodeTxt(privateKey);
|
||||
const txt = await EnrEncoder.toString(enr, privateKey);
|
||||
|
||||
await EnrDecoder.fromString(txt);
|
||||
assert.fail("Expect error here");
|
||||
|
@ -199,7 +200,7 @@ describe("ENR", function () {
|
|||
record = await EnrCreator.fromPublicKey(secp.getPublicKey(privateKey));
|
||||
record.setLocationMultiaddr(multiaddr("/ip4/127.0.0.1/udp/30303"));
|
||||
record.seq = seq;
|
||||
await record.encodeTxt(privateKey);
|
||||
await EnrEncoder.toString(record, privateKey);
|
||||
});
|
||||
|
||||
it("should properly compute the node id", () => {
|
||||
|
@ -209,7 +210,7 @@ describe("ENR", function () {
|
|||
});
|
||||
|
||||
it("should encode/decode to RLP encoding", async function () {
|
||||
const encoded = await record.encode(privateKey);
|
||||
const encoded = await EnrEncoder.toBytes(record, privateKey);
|
||||
const decoded = await EnrDecoder.fromRLP(encoded);
|
||||
|
||||
record.forEach((value, key) => {
|
||||
|
@ -403,7 +404,7 @@ describe("ENR", function () {
|
|||
it("should set field with all protocols disabled", async () => {
|
||||
enr.waku2 = waku2Protocols;
|
||||
|
||||
const txt = await enr.encodeTxt(privateKey);
|
||||
const txt = await EnrEncoder.toString(enr, privateKey);
|
||||
const decoded = (await EnrDecoder.fromString(txt)).waku2!;
|
||||
|
||||
expect(decoded.relay).to.equal(false);
|
||||
|
@ -419,7 +420,7 @@ describe("ENR", function () {
|
|||
waku2Protocols.lightPush = true;
|
||||
|
||||
enr.waku2 = waku2Protocols;
|
||||
const txt = await enr.encodeTxt(privateKey);
|
||||
const txt = await EnrEncoder.toString(enr, privateKey);
|
||||
const decoded = (await EnrDecoder.fromString(txt)).waku2!;
|
||||
|
||||
expect(decoded.relay).to.equal(true);
|
||||
|
@ -432,7 +433,7 @@ describe("ENR", function () {
|
|||
waku2Protocols.relay = true;
|
||||
|
||||
enr.waku2 = waku2Protocols;
|
||||
const txt = await enr.encodeTxt(privateKey);
|
||||
const txt = await EnrEncoder.toString(enr, privateKey);
|
||||
const decoded = (await EnrDecoder.fromString(txt)).waku2!;
|
||||
|
||||
expect(decoded.relay).to.equal(true);
|
||||
|
@ -445,7 +446,7 @@ describe("ENR", function () {
|
|||
waku2Protocols.store = true;
|
||||
|
||||
enr.waku2 = waku2Protocols;
|
||||
const txt = await enr.encodeTxt(privateKey);
|
||||
const txt = await EnrEncoder.toString(enr, privateKey);
|
||||
const decoded = (await EnrDecoder.fromString(txt)).waku2!;
|
||||
|
||||
expect(decoded.relay).to.equal(false);
|
||||
|
@ -458,7 +459,7 @@ describe("ENR", function () {
|
|||
waku2Protocols.filter = true;
|
||||
|
||||
enr.waku2 = waku2Protocols;
|
||||
const txt = await enr.encodeTxt(privateKey);
|
||||
const txt = await EnrEncoder.toString(enr, privateKey);
|
||||
const decoded = (await EnrDecoder.fromString(txt)).waku2!;
|
||||
|
||||
expect(decoded.relay).to.equal(false);
|
||||
|
@ -471,7 +472,7 @@ describe("ENR", function () {
|
|||
waku2Protocols.lightPush = true;
|
||||
|
||||
enr.waku2 = waku2Protocols;
|
||||
const txt = await enr.encodeTxt(privateKey);
|
||||
const txt = await EnrEncoder.toString(enr, privateKey);
|
||||
const decoded = (await EnrDecoder.fromString(txt)).waku2!;
|
||||
|
||||
expect(decoded.relay).to.equal(false);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import * as RLP from "@ethersproject/rlp";
|
||||
import type { PeerId } from "@libp2p/interface-peer-id";
|
||||
import type { Multiaddr } from "@multiformats/multiaddr";
|
||||
import {
|
||||
|
@ -13,15 +12,10 @@ import type {
|
|||
SequenceNumber,
|
||||
Waku2,
|
||||
} from "@waku/interfaces";
|
||||
import { bytesToUtf8, hexToBytes, utf8ToBytes } from "@waku/utils";
|
||||
import { bytesToUtf8 } from "@waku/utils";
|
||||
import debug from "debug";
|
||||
import { toString } from "uint8arrays/to-string";
|
||||
|
||||
import {
|
||||
ERR_INVALID_ID,
|
||||
ERR_NO_SIGNATURE,
|
||||
MAX_RECORD_SIZE,
|
||||
} from "./constants.js";
|
||||
import { ERR_INVALID_ID } from "./constants.js";
|
||||
import { keccak256, verifySignature } from "./crypto.js";
|
||||
import { multiaddrFromFields } from "./multiaddr_from_fields.js";
|
||||
import { decodeMultiaddrs, encodeMultiaddrs } from "./multiaddrs_codec.js";
|
||||
|
@ -380,43 +374,4 @@ export class ENR extends Map<ENRKey, ENRValue> implements IEnr {
|
|||
}
|
||||
return this.signature;
|
||||
}
|
||||
|
||||
async encodeToValues(
|
||||
privateKey?: Uint8Array
|
||||
): Promise<(ENRKey | ENRValue | number[])[]> {
|
||||
// sort keys and flatten into [k, v, k, v, ...]
|
||||
const content: Array<ENRKey | ENRValue | number[]> = Array.from(this.keys())
|
||||
.sort((a, b) => a.localeCompare(b))
|
||||
.map((k) => [k, this.get(k)] as [ENRKey, ENRValue])
|
||||
.map(([k, v]) => [utf8ToBytes(k), v])
|
||||
.flat();
|
||||
content.unshift(new Uint8Array([Number(this.seq)]));
|
||||
if (privateKey) {
|
||||
content.unshift(
|
||||
await this.sign(hexToBytes(RLP.encode(content)), privateKey)
|
||||
);
|
||||
} else {
|
||||
if (!this.signature) {
|
||||
throw new Error(ERR_NO_SIGNATURE);
|
||||
}
|
||||
content.unshift(this.signature);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
async encode(privateKey?: Uint8Array): Promise<Uint8Array> {
|
||||
const encoded = hexToBytes(
|
||||
RLP.encode(await this.encodeToValues(privateKey))
|
||||
);
|
||||
if (encoded.length >= MAX_RECORD_SIZE) {
|
||||
throw new Error("ENR must be less than 300 bytes");
|
||||
}
|
||||
return encoded;
|
||||
}
|
||||
|
||||
async encodeTxt(privateKey?: Uint8Array): Promise<string> {
|
||||
return (
|
||||
ENR.RECORD_PREFIX + toString(await this.encode(privateKey), "base64url")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,5 @@ export interface IEnr extends Map<ENRKey, ENRValue> {
|
|||
multiaddrs?: Multiaddr[];
|
||||
waku2?: Waku2;
|
||||
|
||||
encode(privateKey?: Uint8Array): Promise<Uint8Array>;
|
||||
getFullMultiaddrs(): Multiaddr[];
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue