From 89454aea4a62521666b136ce1bc0dee789da3bef Mon Sep 17 00:00:00 2001 From: Jan Lewandowski <62848215+JanLewDev@users.noreply.github.com> Date: Fri, 27 Dec 2024 12:16:14 +0100 Subject: [PATCH 1/4] fix: deep cloning state and original drp (#296) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Phạm Xuân Trung <66519569+trungnotchung@users.noreply.github.com> --- packages/object/package.json | 3 ++- packages/object/src/index.ts | 13 ++++--------- pnpm-lock.yaml | 8 ++++++++ 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/object/package.json b/packages/object/package.json index 5ca5dc4e..a9463769 100644 --- a/packages/object/package.json +++ b/packages/object/package.json @@ -27,7 +27,8 @@ "devDependencies": { "@bufbuild/protobuf": "^2.0.0", "benchmark": "^2.1.4", - "tsx": "4.19.1" + "tsx": "4.19.1", + "es-toolkit": "1.30.1" }, "dependencies": { "@ts-drp/logger": "^0.4.4" diff --git a/packages/object/src/index.ts b/packages/object/src/index.ts index 44a231d5..152b1abd 100644 --- a/packages/object/src/index.ts +++ b/packages/object/src/index.ts @@ -13,6 +13,7 @@ import { ObjectSet } from "./utils/objectSet.js"; export * as ObjectPb from "./proto/drp/object/v1/object_pb.js"; export * from "./hashgraph/index.js"; +import { cloneDeep } from "es-toolkit"; export interface IACL { isWriter: (peerId: string) => boolean; @@ -96,10 +97,7 @@ export class DRPObject implements IDRPObject { ); this.subscriptions = []; this.states = new Map([[HashGraph.rootHash, { state: new Map() }]]); - this.originalDRP = Object.create( - Object.getPrototypeOf(drp), - Object.getOwnPropertyDescriptors(structuredClone(drp)), - ); + this.originalDRP = cloneDeep(drp); this.vertices = this.hashGraph.getAllVertices(); } @@ -202,17 +200,14 @@ export class DRPObject implements IDRPObject { ? [] : this.hashGraph.linearizeOperations(lca, subgraph); - const drp = Object.create( - Object.getPrototypeOf(this.originalDRP), - Object.getOwnPropertyDescriptors(structuredClone(this.originalDRP)), - ) as DRP; + const drp = cloneDeep(this.originalDRP); const fetchedState = this.states.get(lca); if (!fetchedState) { throw new Error("State is undefined"); } - const state = structuredClone(fetchedState); + const state = cloneDeep(fetchedState); for (const [key, value] of state.state) { drp[key] = value; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f9bd1f4a..5290bb09 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -289,6 +289,9 @@ importers: benchmark: specifier: ^2.1.4 version: 2.1.4 + es-toolkit: + specifier: 1.30.1 + version: 1.30.1 tsx: specifier: 4.19.1 version: 4.19.1 @@ -2783,6 +2786,9 @@ packages: resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} engines: {node: '>= 0.4'} + es-toolkit@1.30.1: + resolution: {integrity: sha512-ZXflqanzH8BpHkDhFa10bBf6ONDCe84EPUm7SSICGzuuROSluT2ynTPtwn9PcRelMtorCRozSknI/U0MNYp0Uw==} + esbuild@0.21.5: resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} @@ -8047,6 +8053,8 @@ snapshots: dependencies: es-errors: 1.3.0 + es-toolkit@1.30.1: {} + esbuild@0.21.5: optionalDependencies: '@esbuild/aix-ppc64': 0.21.5 From d6e3dfad6e29802ae9b009043449a7e40a737b06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20Xu=C3=A2n=20Trung?= <66519569+trungnotchung@users.noreply.github.com> Date: Sun, 29 Dec 2024 19:19:52 +0700 Subject: [PATCH 2/4] refactor: change nodeId to peerId (#298) --- examples/chat/src/objects/chat.ts | 10 ++++---- examples/grid/src/index.ts | 14 +++++------ .../tests/AddWinsSetWithACL.test.ts | 4 ++-- .../src/proto/drp/object/v1/object_pb.ts | 18 +++++++------- packages/node/src/handlers.ts | 6 ++--- packages/node/src/index.ts | 2 +- packages/node/tests/node.test.ts | 10 ++++---- packages/object/src/hashgraph/index.ts | 24 +++++++++---------- packages/object/src/index.ts | 14 +++++------ .../src/proto/drp/object/v1/object.proto | 2 +- .../src/proto/drp/object/v1/object_pb.ts | 18 +++++++------- packages/object/tests/hashgraph.test.ts | 17 +++++-------- 12 files changed, 67 insertions(+), 72 deletions(-) diff --git a/examples/chat/src/objects/chat.ts b/examples/chat/src/objects/chat.ts index cb75261b..3dce2472 100644 --- a/examples/chat/src/objects/chat.ts +++ b/examples/chat/src/objects/chat.ts @@ -9,22 +9,22 @@ import { export class Chat implements DRP { operations: string[] = ["addMessage"]; semanticsType: SemanticsType = SemanticsType.pair; - // store messages as strings in the format (timestamp, message, nodeId) + // store messages as strings in the format (timestamp, message, peerId) messages: Set; constructor() { this.messages = new Set(); } - addMessage(timestamp: string, message: string, nodeId: string): void { - this._addMessage(timestamp, message, nodeId); + addMessage(timestamp: string, message: string, peerId: string): void { + this._addMessage(timestamp, message, peerId); } private _addMessage( timestamp: string, message: string, - nodeId: string, + peerId: string, ): void { - this.messages.add(`(${timestamp}, ${message}, ${nodeId})`); + this.messages.add(`(${timestamp}, ${message}, ${peerId})`); } getMessages(): Set { diff --git a/examples/grid/src/index.ts b/examples/grid/src/index.ts index a6d121c5..14ef435d 100644 --- a/examples/grid/src/index.ts +++ b/examples/grid/src/index.ts @@ -10,7 +10,7 @@ let peers: string[] = []; let discoveryPeers: string[] = []; let objectPeers: string[] = []; -const formatNodeId = (id: string): string => { +const formatPeerId = (id: string): string => { return `${id.slice(0, 4)}...${id.slice(-4)}`; }; @@ -25,7 +25,7 @@ const hashCode = (str: string): number => { return hash; }; -const getColorForNodeId = (id: string): string => { +const getColorForPeerId = (id: string): string => { if (!colorMap.has(id)) { const hash = hashCode(id); let r = (hash & 0xff0000) >> 16; @@ -64,22 +64,22 @@ const render = () => { } const element_peerId = document.getElementById("peerId"); - element_peerId.innerHTML = `${formatNodeId(node.networkNode.peerId)}`; + element_peerId.innerHTML = `${formatPeerId(node.networkNode.peerId)}`; const element_peers = document.getElementById("peers"); - element_peers.innerHTML = `[${peers.map((peer) => `${formatNodeId(peer)}`).join(", ")}]`; + element_peers.innerHTML = `[${peers.map((peer) => `${formatPeerId(peer)}`).join(", ")}]`; const element_discoveryPeers = ( document.getElementById("discoveryPeers") ); - element_discoveryPeers.innerHTML = `[${discoveryPeers.map((peer) => `${formatNodeId(peer)}`).join(", ")}]`; + element_discoveryPeers.innerHTML = `[${discoveryPeers.map((peer) => `${formatPeerId(peer)}`).join(", ")}]`; const element_objectPeers = ( document.getElementById("objectPeers") ); element_objectPeers.innerHTML = !gridDRP ? "" - : `Your frens in GRID: [${objectPeers.map((peer) => `${formatNodeId(peer)}`).join(", ")}]`; + : `Your frens in GRID: [${objectPeers.map((peer) => `${formatPeerId(peer)}`).join(", ")}]`; if (!gridDRP) return; const users = gridDRP.getUsers(); @@ -179,7 +179,7 @@ async function addUser() { gridDRP.addUser( node.networkNode.peerId, - getColorForNodeId(node.networkNode.peerId), + getColorForPeerId(node.networkNode.peerId), ); render(); } diff --git a/packages/blueprints/tests/AddWinsSetWithACL.test.ts b/packages/blueprints/tests/AddWinsSetWithACL.test.ts index c5025836..c296d9c1 100644 --- a/packages/blueprints/tests/AddWinsSetWithACL.test.ts +++ b/packages/blueprints/tests/AddWinsSetWithACL.test.ts @@ -42,14 +42,14 @@ describe("AccessControl tests with RevokeWins resolution", () => { const vertices = [ { hash: "", - nodeId: "peer1", + peerId: "peer1", operation: { type: "grant", value: "peer3" }, dependencies: [], signature: "", }, { hash: "", - nodeId: "peer2", + peerId: "peer2", operation: { type: "revoke", value: "peer3" }, dependencies: [], signature: "", diff --git a/packages/network/src/proto/drp/object/v1/object_pb.ts b/packages/network/src/proto/drp/object/v1/object_pb.ts index 42039680..3e229e0e 100644 --- a/packages/network/src/proto/drp/object/v1/object_pb.ts +++ b/packages/network/src/proto/drp/object/v1/object_pb.ts @@ -13,7 +13,7 @@ export const protobufPackage = "drp.object.v1"; /** Supposed to be the RIBLT stuff */ export interface Vertex { hash: string; - nodeId: string; + peerId: string; operation: Vertex_Operation | undefined; dependencies: string[]; signature: string; @@ -32,7 +32,7 @@ export interface DRPObjectBase { } function createBaseVertex(): Vertex { - return { hash: "", nodeId: "", operation: undefined, dependencies: [], signature: "" }; + return { hash: "", peerId: "", operation: undefined, dependencies: [], signature: "" }; } export const Vertex: MessageFns = { @@ -40,8 +40,8 @@ export const Vertex: MessageFns = { if (message.hash !== "") { writer.uint32(10).string(message.hash); } - if (message.nodeId !== "") { - writer.uint32(18).string(message.nodeId); + if (message.peerId !== "") { + writer.uint32(18).string(message.peerId); } if (message.operation !== undefined) { Vertex_Operation.encode(message.operation, writer.uint32(26).fork()).join(); @@ -75,7 +75,7 @@ export const Vertex: MessageFns = { break; } - message.nodeId = reader.string(); + message.peerId = reader.string(); continue; } case 3: { @@ -114,7 +114,7 @@ export const Vertex: MessageFns = { fromJSON(object: any): Vertex { return { hash: isSet(object.hash) ? globalThis.String(object.hash) : "", - nodeId: isSet(object.nodeId) ? globalThis.String(object.nodeId) : "", + peerId: isSet(object.peerId) ? globalThis.String(object.peerId) : "", operation: isSet(object.operation) ? Vertex_Operation.fromJSON(object.operation) : undefined, dependencies: globalThis.Array.isArray(object?.dependencies) ? object.dependencies.map((e: any) => globalThis.String(e)) @@ -128,8 +128,8 @@ export const Vertex: MessageFns = { if (message.hash !== "") { obj.hash = message.hash; } - if (message.nodeId !== "") { - obj.nodeId = message.nodeId; + if (message.peerId !== "") { + obj.peerId = message.peerId; } if (message.operation !== undefined) { obj.operation = Vertex_Operation.toJSON(message.operation); @@ -149,7 +149,7 @@ export const Vertex: MessageFns = { fromPartial, I>>(object: I): Vertex { const message = createBaseVertex(); message.hash = object.hash ?? ""; - message.nodeId = object.nodeId ?? ""; + message.peerId = object.peerId ?? ""; message.operation = (object.operation !== undefined && object.operation !== null) ? Vertex_Operation.fromPartial(object.operation) : undefined; diff --git a/packages/node/src/handlers.ts b/packages/node/src/handlers.ts index cffdbf7c..6b6e0b83 100644 --- a/packages/node/src/handlers.ts +++ b/packages/node/src/handlers.ts @@ -215,7 +215,7 @@ export function drpObjectChangesHandler( export async function signGeneratedVertices(node: DRPNode, vertices: Vertex[]) { const signPromises = vertices.map(async (vertex) => { - if (vertex.nodeId !== node.networkNode.peerId || vertex.signature !== "") { + if (vertex.peerId !== node.networkNode.peerId || vertex.signature !== "") { return; } @@ -232,7 +232,7 @@ export async function verifyIncomingVertices( const vertices: Vertex[] = incomingVertices.map((vertex) => { return { hash: vertex.hash, - nodeId: vertex.nodeId, + peerId: vertex.peerId, operation: { type: vertex.operation?.type ?? "", value: vertex.operation?.value, @@ -254,7 +254,7 @@ export async function verifyIncomingVertices( const signature = uint8ArrayFromString(vertex.signature, "base64"); - const publicKey = acl.getPeerKey(vertex.nodeId); + const publicKey = acl.getPeerKey(vertex.peerId); if (!publicKey) { return null; } diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index 706e28ff..a1d801c8 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -100,7 +100,7 @@ export class DRPNode { } async signVertexOperation(vertex: Vertex) { - if (vertex.nodeId !== this.networkNode.peerId) { + if (vertex.peerId !== this.networkNode.peerId) { log.error("::signVertexOperation: Invalid peer id"); return ""; } diff --git a/packages/node/tests/node.test.ts b/packages/node/tests/node.test.ts index b68026d7..06559b27 100644 --- a/packages/node/tests/node.test.ts +++ b/packages/node/tests/node.test.ts @@ -31,7 +31,7 @@ describe("DPRNode with verify and sign signature", () => { const vertices = [ { hash: "hash", - nodeId: "nodeId", + peerId: "peerId", operation: { type: "type", value: "value", @@ -48,7 +48,7 @@ describe("DPRNode with verify and sign signature", () => { const vertices = [ { hash: "hash", - nodeId: drpNode.networkNode.peerId, + peerId: drpNode.networkNode.peerId, operation: { type: "add", value: 1, @@ -65,7 +65,7 @@ describe("DPRNode with verify and sign signature", () => { const vertices = [ { hash: "hash", - nodeId: drpNode.networkNode.peerId, + peerId: drpNode.networkNode.peerId, operation: { type: "add", value: 1, @@ -83,7 +83,7 @@ describe("DPRNode with verify and sign signature", () => { const vertices = [ { hash: "hash", - nodeId: "peer1", + peerId: "peer1", operation: { type: "add", value: 1, @@ -103,7 +103,7 @@ describe("DPRNode with verify and sign signature", () => { const vertices = [ { hash: "hash", - nodeId: drpNode.networkNode.peerId, + peerId: drpNode.networkNode.peerId, operation: { type: "add", value: 1, diff --git a/packages/object/src/hashgraph/index.ts b/packages/object/src/hashgraph/index.ts index ce483fba..af65bd61 100644 --- a/packages/object/src/hashgraph/index.ts +++ b/packages/object/src/hashgraph/index.ts @@ -49,7 +49,7 @@ export type VertexDistance = { }; export class HashGraph { - nodeId: string; + peerId: string; resolveConflicts: (vertices: Vertex[]) => ResolveConflictsType; semanticsType: SemanticsType; @@ -64,7 +64,7 @@ export class HashGraph { ) */ static readonly rootHash: Hash = - "02465e287e3d086f12c6edd856953ca5ad0f01d6707bf8e410b4a601314c1ca5"; + "a65c9cbd875fd3d602adb69a90adb98c4e2c3f26bdf3a2bf597f3548971f2c93"; private arePredecessorsFresh = false; private reachablePredecessors: Map = new Map(); private topoSortedIndex: Map = new Map(); @@ -73,17 +73,17 @@ export class HashGraph { private currentBitsetSize = 1; constructor( - nodeId: string, + peerId: string, resolveConflicts: (vertices: Vertex[]) => ResolveConflictsType, semanticsType: SemanticsType, ) { - this.nodeId = nodeId; + this.peerId = peerId; this.resolveConflicts = resolveConflicts; this.semanticsType = semanticsType; const rootVertex: Vertex = { hash: HashGraph.rootHash, - nodeId: "", + peerId: "", operation: { type: OperationType.NOP, value: null, @@ -101,11 +101,11 @@ export class HashGraph { addToFrontier(operation: Operation): Vertex { const deps = this.getFrontier(); - const hash = computeHash(this.nodeId, operation, deps); + const hash = computeHash(this.peerId, operation, deps); const vertex: Vertex = { hash, - nodeId: this.nodeId, + peerId: this.peerId, operation: operation ?? { type: OperationType.NOP }, dependencies: deps, signature: "", @@ -150,10 +150,10 @@ export class HashGraph { addVertex( operation: Operation, deps: Hash[], - nodeId: string, + peerId: string, signature: string, ): Hash { - const hash = computeHash(nodeId, operation, deps); + const hash = computeHash(peerId, operation, deps); if (this.vertices.has(hash)) { return hash; // Vertex already exists } @@ -166,7 +166,7 @@ export class HashGraph { const vertex: Vertex = { hash, - nodeId, + peerId, operation, dependencies: deps, signature, @@ -503,11 +503,11 @@ export class HashGraph { } function computeHash( - nodeId: string, + peerId: string, operation: Operation, deps: Hash[], ): Hash { - const serialized = JSON.stringify({ operation, deps, nodeId }); + const serialized = JSON.stringify({ operation, deps, peerId }); const hash = crypto.createHash("sha256").update(serialized).digest("hex"); return hash; } diff --git a/packages/object/src/index.ts b/packages/object/src/index.ts index 152b1abd..08c75010 100644 --- a/packages/object/src/index.ts +++ b/packages/object/src/index.ts @@ -57,7 +57,7 @@ export interface DRPObjectConfig { export let log: Logger; export class DRPObject implements IDRPObject { - nodeId: string; + peerId: string; id: string; abi: string; bytecode: Uint8Array; @@ -70,20 +70,20 @@ export class DRPObject implements IDRPObject { subscriptions: DRPObjectCallback[]; constructor( - nodeId: string, + peerId: string, drp: DRP, id?: string, abi?: string, config?: DRPObjectConfig, ) { - this.nodeId = nodeId; + this.peerId = peerId; log = new Logger("drp::object", config?.log_config); this.id = id ?? crypto .createHash("sha256") .update(abi ?? "") - .update(nodeId) + .update(peerId) .update(Math.floor(Math.random() * Number.MAX_VALUE).toString()) .digest("hex"); this.abi = abi ?? ""; @@ -91,7 +91,7 @@ export class DRPObject implements IDRPObject { this.vertices = []; this.drp = drp ? new Proxy(drp, this.proxyDRPHandler()) : null; this.hashGraph = new HashGraph( - nodeId, + peerId, drp?.resolveConflicts?.bind(drp ?? this), drp?.semanticsType, ); @@ -130,7 +130,7 @@ export class DRPObject implements IDRPObject { const serializedVertex = ObjectPb.Vertex.create({ hash: vertex.hash, - nodeId: vertex.nodeId, + peerId: vertex.peerId, operation: vertex.operation, dependencies: vertex.dependencies, }); @@ -154,7 +154,7 @@ export class DRPObject implements IDRPObject { this.hashGraph.addVertex( vertex.operation, vertex.dependencies, - vertex.nodeId, + vertex.peerId, vertex.signature, ); diff --git a/packages/object/src/proto/drp/object/v1/object.proto b/packages/object/src/proto/drp/object/v1/object.proto index ce6f4b65..9af95a91 100644 --- a/packages/object/src/proto/drp/object/v1/object.proto +++ b/packages/object/src/proto/drp/object/v1/object.proto @@ -11,7 +11,7 @@ message Vertex { google.protobuf.Value value = 2; } string hash = 1; - string node_id = 2; + string peer_id = 2; Operation operation = 3; repeated string dependencies = 4; string signature = 5; diff --git a/packages/object/src/proto/drp/object/v1/object_pb.ts b/packages/object/src/proto/drp/object/v1/object_pb.ts index 42039680..3e229e0e 100644 --- a/packages/object/src/proto/drp/object/v1/object_pb.ts +++ b/packages/object/src/proto/drp/object/v1/object_pb.ts @@ -13,7 +13,7 @@ export const protobufPackage = "drp.object.v1"; /** Supposed to be the RIBLT stuff */ export interface Vertex { hash: string; - nodeId: string; + peerId: string; operation: Vertex_Operation | undefined; dependencies: string[]; signature: string; @@ -32,7 +32,7 @@ export interface DRPObjectBase { } function createBaseVertex(): Vertex { - return { hash: "", nodeId: "", operation: undefined, dependencies: [], signature: "" }; + return { hash: "", peerId: "", operation: undefined, dependencies: [], signature: "" }; } export const Vertex: MessageFns = { @@ -40,8 +40,8 @@ export const Vertex: MessageFns = { if (message.hash !== "") { writer.uint32(10).string(message.hash); } - if (message.nodeId !== "") { - writer.uint32(18).string(message.nodeId); + if (message.peerId !== "") { + writer.uint32(18).string(message.peerId); } if (message.operation !== undefined) { Vertex_Operation.encode(message.operation, writer.uint32(26).fork()).join(); @@ -75,7 +75,7 @@ export const Vertex: MessageFns = { break; } - message.nodeId = reader.string(); + message.peerId = reader.string(); continue; } case 3: { @@ -114,7 +114,7 @@ export const Vertex: MessageFns = { fromJSON(object: any): Vertex { return { hash: isSet(object.hash) ? globalThis.String(object.hash) : "", - nodeId: isSet(object.nodeId) ? globalThis.String(object.nodeId) : "", + peerId: isSet(object.peerId) ? globalThis.String(object.peerId) : "", operation: isSet(object.operation) ? Vertex_Operation.fromJSON(object.operation) : undefined, dependencies: globalThis.Array.isArray(object?.dependencies) ? object.dependencies.map((e: any) => globalThis.String(e)) @@ -128,8 +128,8 @@ export const Vertex: MessageFns = { if (message.hash !== "") { obj.hash = message.hash; } - if (message.nodeId !== "") { - obj.nodeId = message.nodeId; + if (message.peerId !== "") { + obj.peerId = message.peerId; } if (message.operation !== undefined) { obj.operation = Vertex_Operation.toJSON(message.operation); @@ -149,7 +149,7 @@ export const Vertex: MessageFns = { fromPartial, I>>(object: I): Vertex { const message = createBaseVertex(); message.hash = object.hash ?? ""; - message.nodeId = object.nodeId ?? ""; + message.peerId = object.peerId ?? ""; message.operation = (object.operation !== undefined && object.operation !== null) ? Vertex_Operation.fromPartial(object.operation) : undefined; diff --git a/packages/object/tests/hashgraph.test.ts b/packages/object/tests/hashgraph.test.ts index abc96fb1..bcf17c81 100644 --- a/packages/object/tests/hashgraph.test.ts +++ b/packages/object/tests/hashgraph.test.ts @@ -432,7 +432,7 @@ describe("HashGraph for PseudoRandomWinsSet tests", () => { const linearOps = obj1.hashGraph.linearizeOperations(); // Pseudo-randomly chosen operation - expect(linearOps).toEqual([{ type: "add", value: 3 }]); + expect(linearOps).toEqual([{ type: "add", value: 5 }]); }); }); @@ -537,17 +537,13 @@ describe("Vertex state tests", () => { drp1.add(4); drp3.add(5); + const hashA4 = obj1.hashGraph.getFrontier()[0]; + const hashC5 = obj3.hashGraph.getFrontier()[0]; + obj1.merge(obj3.hashGraph.getAllVertices()); obj3.merge(obj1.hashGraph.getAllVertices()); - drp1.add(6); - - const hashA4 = - "8e6f4369010528ae3668efce452da04d077e0957955d62d671b90f2934c755fe"; - const hashC5 = - "a8d94f7e2b421be2d5cd1124ca9ddb831e38246065db6e9a32ce493ca9604038"; - const hashA6 = - "cd6a955f0734a09df1bff44c5e0458365d3a26ec7f1cae0df2c0f708b9f100a8"; + const hashA6 = obj1.hashGraph.getFrontier()[0]; const drpState1 = obj1.states.get(hashA4); expect(drpState1?.state.get("state").get(1)).toBe(true); @@ -611,8 +607,7 @@ describe("Vertex state tests", () => { obj3.merge(obj1.hashGraph.getAllVertices()); obj3.merge(obj2.hashGraph.getAllVertices()); - const hashV8 = - "be97d8fe9169800893c28b3d8aaefda517b98936efb069673e0250317b5e4a0b"; + const hashV8 = obj1.hashGraph.getFrontier()[0]; const drpStateV8 = obj1.states.get(hashV8); expect(drpStateV8?.state.get("state").get(1)).toBe(false); expect(drpStateV8?.state.get("state").get(2)).toBe(true); From 87bb51506cb47a1a3efaffc79e3eca4a96357150 Mon Sep 17 00:00:00 2001 From: anhnd350309 <156870690+anhnd350309@users.noreply.github.com> Date: Sun, 29 Dec 2024 19:24:48 +0700 Subject: [PATCH 3/4] feat: add coverage (#290) --- .github/workflows/test.yml | 4 + .gitignore | 2 + package.json | 3 + pnpm-lock.yaml | 310 +++++++++++++++++++++++++++++++++++++ scripts/coverage.ts | 51 ++++++ vite.config.mts | 6 + 6 files changed, 376 insertions(+) create mode 100755 scripts/coverage.ts diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0243c628..8d289976 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,3 +16,7 @@ jobs: run: | pnpm install --no-frozen-lockfile pnpm ci-test + + - shell: bash + run: | + pnpm run coverage diff --git a/.gitignore b/.gitignore index c1165b44..b2c616ea 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ docs/ node_modules/ **/tsconfig.tsbuildinfo +coverage/* +.vscode/* \ No newline at end of file diff --git a/package.json b/package.json index 9bb142a1..6f44c04e 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "build:packages": "pnpm --filter '@ts-drp/*' build", "clean": "pnpm --filter '@ts-drp/*' clean && rm -r node_modules/ docs/", "cli": "tsx ./packages/node/src/run.ts", + "coverage": "pnpm exec ts-node scripts/coverage.ts", "docs": "typedoc", "postinstall": "pnpm build:packages", "proto-gen": "pnpm proto-gen:object && pnpm proto-gen:network", @@ -34,8 +35,10 @@ "@biomejs/biome": "^1.8.3", "@release-it-plugins/workspaces": "^4.2.0", "@types/node": "^22.5.4", + "@vitest/coverage-v8": "2.1.8", "assemblyscript": "^0.27.29", "release-it": "^17.6.0", + "ts-node": "^10.9.2", "ts-proto": "^2.2.4", "tsx": "4.19.1", "typedoc": "^0.26.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5290bb09..8263bd69 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,12 +17,18 @@ importers: '@types/node': specifier: ^22.5.4 version: 22.10.2 + '@vitest/coverage-v8': + specifier: 2.1.8 + version: 2.1.8(vitest@2.1.8(@types/node@22.10.2)(terser@5.37.0)) assemblyscript: specifier: ^0.27.29 version: 0.27.31 release-it: specifier: ^17.6.0 version: 17.10.0(typescript@5.7.2) + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@22.10.2)(typescript@5.7.2) ts-proto: specifier: ^2.2.4 version: 2.6.0 @@ -976,6 +982,9 @@ packages: resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==} engines: {node: '>=6.9.0'} + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@biomejs/biome@1.9.4': resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==} engines: {node: '>=14.21.3'} @@ -1054,6 +1063,10 @@ packages: '@chainsafe/netmask@2.0.0': resolution: {integrity: sha512-I3Z+6SWUoaljh3TBzCnCxjlUyN8tA+NAk5L6m9IxvCf1BENQTePzPMis97CoN/iMW1St3WN+AWCCRp+TTBRiDg==} + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + '@esbuild/aix-ppc64@0.21.5': resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} @@ -1501,6 +1514,10 @@ packages: resolution: {integrity: sha512-BXvGj0ehzrngHTPTDqUoDT3NXL8U0RxUk2zJm2A66RhCEIWdtU1v6GuUqNAgArW4PQ9CinqIWyHdQgdwOj06zQ==} engines: {node: '>=18'} + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + '@isaacs/ttlcache@1.4.1': resolution: {integrity: sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==} engines: {node: '>=12'} @@ -1558,6 +1575,9 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@js-sdsl/ordered-map@4.4.2': resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} @@ -1724,6 +1744,10 @@ packages: '@octokit/types@13.6.2': resolution: {integrity: sha512-WpbZfZUcZU77DrSW4wbsSgTPfKcp286q3ItaIgvSbBpZJlu6mnYXAkjZz6LVZPXkEvLIM8McanyZejKTYUHipA==} + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + '@pnpm/config.env-replace@1.1.0': resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} engines: {node: '>=12.22.0'} @@ -1997,6 +2021,18 @@ packages: '@tootallnate/quickjs-emscripten@0.23.0': resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + '@tsconfig/node10@1.0.11': + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -2066,6 +2102,15 @@ packages: '@ungap/structured-clone@1.2.1': resolution: {integrity: sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==} + '@vitest/coverage-v8@2.1.8': + resolution: {integrity: sha512-2Y7BPlKH18mAZYAW1tYByudlCYrQyl5RGvnnDYJKW5tCiO5qg3KSAy3XAxcxKz900a0ZXxWtKrMuZLe3lKBpJw==} + peerDependencies: + '@vitest/browser': 2.1.8 + vitest: 2.1.8 + peerDependenciesMeta: + '@vitest/browser': + optional: true + '@vitest/expect@2.1.8': resolution: {integrity: sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==} @@ -2103,6 +2148,10 @@ packages: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} + acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + engines: {node: '>=0.4.0'} + acorn@8.14.0: resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} engines: {node: '>=0.4.0'} @@ -2150,6 +2199,9 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -2699,6 +2751,10 @@ packages: devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + diffie-hellman@5.0.3: resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} @@ -2725,6 +2781,9 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -2743,6 +2802,9 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + encodeurl@1.0.2: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} @@ -2942,6 +3004,10 @@ packages: for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + foreground-child@3.3.0: + resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} + engines: {node: '>=14'} + fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} @@ -3011,6 +3077,10 @@ packages: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported @@ -3096,6 +3166,9 @@ packages: hmac-drbg@1.0.1: resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + html-void-elements@3.0.0: resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} @@ -3347,6 +3420,18 @@ packages: resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} engines: {node: '>=8'} + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} + engines: {node: '>=10'} + + istanbul-reports@3.1.7: + resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} + engines: {node: '>=8'} + it-all@3.0.6: resolution: {integrity: sha512-HXZWbxCgQZJfrv5rXvaVeaayXED8nTKx9tj9fpBhmcUJcedVZshMMMqTj0RG2+scGypb9Ut1zd1ifbf3lA8L+Q==} @@ -3418,6 +3503,9 @@ packages: resolution: {integrity: sha512-uWjMtpy5HqhSd/LlrlP3fhYrr7rUfJFFMABv0F5d6n13Q+0glhZthwUKpEAVhDrXY95Tb1RB5lLqqef+QbVNaw==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jest-environment-node@29.7.0: resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -3593,6 +3681,9 @@ packages: loupe@3.1.2: resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -3610,10 +3701,20 @@ packages: magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + magicast@0.3.5: + resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + make-dir@2.1.0: resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} engines: {node: '>=6'} + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} @@ -3781,6 +3882,10 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + mkdirp-classic@0.5.3: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} @@ -4034,6 +4139,9 @@ packages: resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} engines: {node: '>= 14'} + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + package-json@10.0.1: resolution: {integrity: sha512-ua1L4OgXSBdsu1FPb7F3tYH0F48a6kxvod4pLUlGY9COeJAJQNX/sNH2IiEmsxw7lqYiAwrdHMjz1FctOsyDQg==} engines: {node: '>=18'} @@ -4101,6 +4209,10 @@ packages: resolution: {integrity: sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==} engines: {node: '>=0.10.0'} + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + path-type@5.0.0: resolution: {integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==} engines: {node: '>=12'} @@ -4627,6 +4739,10 @@ packages: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + string-width@7.2.0: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} @@ -4702,6 +4818,10 @@ packages: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} + test-exclude@7.0.1: + resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==} + engines: {node: '>=18'} + throat@5.0.0: resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==} @@ -4751,6 +4871,20 @@ packages: trim-lines@3.0.1: resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + ts-poet@6.9.0: resolution: {integrity: sha512-roe6W6MeZmCjRmppyfOURklO5tQFQ6Sg7swURKkwYJvV7dbGCrK28um5+51iW3twdPRKtwarqFAVMU6G1mvnuQ==} @@ -4905,6 +5039,9 @@ packages: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + validate-peer-dependencies@1.2.0: resolution: {integrity: sha512-nd2HUpKc6RWblPZQ2GDuI65sxJ2n/UqZwSBVtj64xlWjMx0m7ZB2m9b2JS3v1f+n9VWH/dd1CMhkHfP6pIdckA==} @@ -5096,6 +5233,10 @@ packages: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + wrap-ansi@9.0.0: resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} engines: {node: '>=18'} @@ -5173,6 +5314,10 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -6035,6 +6180,8 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 + '@bcoe/v8-coverage@0.2.3': {} + '@biomejs/biome@1.9.4': optionalDependencies: '@biomejs/cli-darwin-arm64': 1.9.4 @@ -6129,6 +6276,10 @@ snapshots: dependencies: '@chainsafe/is-ip': 2.0.2 + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + '@esbuild/aix-ppc64@0.21.5': optional: true @@ -6364,6 +6515,15 @@ snapshots: '@inquirer/figures@1.0.9': {} + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + '@isaacs/ttlcache@1.4.1': {} '@istanbuljs/load-nyc-config@1.1.0': @@ -6451,6 +6611,11 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + '@js-sdsl/ordered-map@4.4.2': {} '@leichtgewicht/ip-codec@2.0.5': {} @@ -6876,6 +7041,9 @@ snapshots: dependencies: '@octokit/openapi-types': 22.2.0 + '@pkgjs/parseargs@0.11.0': + optional: true + '@pnpm/config.env-replace@1.1.0': {} '@pnpm/network.ca-file@1.0.2': @@ -7185,6 +7353,14 @@ snapshots: '@tootallnate/quickjs-emscripten@0.23.0': {} + '@tsconfig/node10@1.0.11': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.26.3 @@ -7264,6 +7440,24 @@ snapshots: '@ungap/structured-clone@1.2.1': {} + '@vitest/coverage-v8@2.1.8(vitest@2.1.8(@types/node@22.10.2)(terser@5.37.0))': + dependencies: + '@ampproject/remapping': 2.3.0 + '@bcoe/v8-coverage': 0.2.3 + debug: 4.4.0 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.1.7 + magic-string: 0.30.17 + magicast: 0.3.5 + std-env: 3.8.0 + test-exclude: 7.0.1 + tinyrainbow: 1.2.0 + vitest: 2.1.8(@types/node@22.10.2)(terser@5.37.0) + transitivePeerDependencies: + - supports-color + '@vitest/expect@2.1.8': dependencies: '@vitest/spy': 2.1.8 @@ -7313,6 +7507,10 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 + acorn-walk@8.3.4: + dependencies: + acorn: 8.14.0 + acorn@8.14.0: {} agent-base@7.1.3: {} @@ -7346,6 +7544,8 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + arg@4.1.3: {} + argparse@1.0.10: dependencies: sprintf-js: 1.0.3 @@ -7973,6 +8173,8 @@ snapshots: dependencies: dequal: 2.0.3 + diff@4.0.2: {} + diffie-hellman@5.0.3: dependencies: bn.js: 4.12.1 @@ -8001,6 +8203,8 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 + eastasianwidth@0.2.0: {} + ee-first@1.1.1: {} electron-to-chromium@1.5.75: {} @@ -8021,6 +8225,8 @@ snapshots: emoji-regex@8.0.0: {} + emoji-regex@9.2.2: {} + encodeurl@1.0.2: {} encodeurl@2.0.0: {} @@ -8280,6 +8486,11 @@ snapshots: dependencies: is-callable: 1.2.7 + foreground-child@3.3.0: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + fresh@0.5.2: {} fs-constants@1.0.0: {} @@ -8345,6 +8556,15 @@ snapshots: dependencies: is-glob: 4.0.3 + glob@10.4.5: + dependencies: + foreground-child: 3.3.0 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -8447,6 +8667,8 @@ snapshots: minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 + html-escaper@2.0.2: {} + html-void-elements@3.0.0: {} http-errors@2.0.0: @@ -8668,6 +8890,25 @@ snapshots: transitivePeerDependencies: - supports-color + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@5.0.6: + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + debug: 4.4.0 + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.1.7: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + it-all@3.0.6: {} it-byte-stream@1.1.0: @@ -8778,6 +9019,12 @@ snapshots: - bufferutil - utf-8-validate + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + jest-environment-node@29.7.0: dependencies: '@jest/environment': 29.7.0 @@ -9009,6 +9256,8 @@ snapshots: loupe@3.1.2: {} + lru-cache@10.4.3: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -9023,11 +9272,23 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 + magicast@0.3.5: + dependencies: + '@babel/parser': 7.26.3 + '@babel/types': 7.26.3 + source-map-js: 1.2.1 + make-dir@2.1.0: dependencies: pify: 4.0.1 semver: 5.7.2 + make-dir@4.0.0: + dependencies: + semver: 7.6.3 + + make-error@1.3.6: {} + makeerror@1.0.12: dependencies: tmpl: 1.0.5 @@ -9316,6 +9577,8 @@ snapshots: minimist@1.2.8: {} + minipass@7.1.2: {} + mkdirp-classic@0.5.3: {} mkdirp@0.5.6: @@ -9587,6 +9850,8 @@ snapshots: degenerator: 5.0.1 netmask: 2.0.2 + package-json-from-dist@1.0.1: {} + package-json@10.0.1: dependencies: ky: 1.7.4 @@ -9651,6 +9916,11 @@ snapshots: dependencies: path-root-regex: 0.1.2 + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + path-type@5.0.0: {} pathe@1.1.2: {} @@ -10307,6 +10577,12 @@ snapshots: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + string-width@7.2.0: dependencies: emoji-regex: 10.4.0 @@ -10390,6 +10666,12 @@ snapshots: glob: 7.2.3 minimatch: 3.1.2 + test-exclude@7.0.1: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 10.4.5 + minimatch: 9.0.5 + throat@5.0.0: {} through2@2.0.5: @@ -10427,6 +10709,24 @@ snapshots: trim-lines@3.0.1: {} + ts-node@10.9.2(@types/node@22.10.2)(typescript@5.7.2): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.10.2 + acorn: 8.14.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.7.2 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + ts-poet@6.9.0: dependencies: dprint-node: 1.0.8 @@ -10579,6 +10879,8 @@ snapshots: utils-merge@1.0.1: {} + v8-compile-cache-lib@3.0.1: {} + validate-peer-dependencies@1.2.0: dependencies: resolve-package-path: 3.1.0 @@ -10767,6 +11069,12 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + wrap-ansi@9.0.0: dependencies: ansi-styles: 6.2.1 @@ -10816,6 +11124,8 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yn@3.1.1: {} + yocto-queue@0.1.0: {} yoctocolors-cjs@2.1.2: {} diff --git a/scripts/coverage.ts b/scripts/coverage.ts new file mode 100755 index 00000000..1e7a5fa1 --- /dev/null +++ b/scripts/coverage.ts @@ -0,0 +1,51 @@ +import * as fs from "node:fs"; +import path from "node:path"; +const lcovPath = path.resolve("./coverage/lcov.info"); +const threshold = 20; // Set your desired threshold + +function parseCoverage(lcovFilePath: string): number { + if (!fs.existsSync(lcovFilePath)) { + throw new Error(`File not found: ${lcovFilePath}`); + } + + const lcovData = fs.readFileSync(lcovFilePath, "utf-8"); + const totalLinesMatch = lcovData.match(/LF:(\d+)/g); + const coveredLinesMatch = lcovData.match(/LH:(\d+)/g); + + if (!totalLinesMatch || !coveredLinesMatch) { + throw new Error("Coverage data is missing or invalid in lcov.info"); + } + + const totalLines = totalLinesMatch + .map((line) => Number.parseInt(line.split(":")[1], 10)) + .reduce((sum, value) => sum + value, 0); + + const coveredLines = coveredLinesMatch + .map((line) => Number.parseInt(line.split(":")[1], 10)) + .reduce((sum, value) => sum + value, 0); + + return (coveredLines / totalLines) * 100; +} + +try { + const coveragePercentage = parseCoverage(lcovPath); + console.log(`Total Coverage: ${coveragePercentage.toFixed(2)}%`); + + if (coveragePercentage < threshold) { + console.error( + `Coverage (${coveragePercentage.toFixed( + 2, + )}%) is below the threshold (${threshold}%).`, + ); + process.exit(1); // Exit with an error code if threshold is not met + } else { + console.log( + `Coverage (${coveragePercentage.toFixed( + 2, + )}%) meets the threshold (${threshold}%).`, + ); + } +} catch (error) { + console.error(`Error: ${(error as Error).message}`); + process.exit(1); // Exit with an error code for any script failure +} diff --git a/vite.config.mts b/vite.config.mts index 50bab196..137a7dcc 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -5,5 +5,11 @@ export default defineConfig({ plugins: [tsconfigPaths()], test: { exclude: ["**/node_modules"], + coverage: { + enabled: true, + reporter: ["text", "lcov"], + include: ["packages/**/*.{ts,tsx}"], + exclude: ["**/node_modules/**", "**/__tests__/**", "**/tests/**"], + }, }, }); From 4220e726c88f125ee78bdca4c3871572d1f2dbf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ph=E1=BA=A1m=20Xu=C3=A2n=20Trung?= <66519569+trungnotchung@users.noreply.github.com> Date: Sun, 29 Dec 2024 19:28:48 +0700 Subject: [PATCH 4/4] fix: sign vertex hash instead of vertex operation (#300) Co-authored-by: Oak --- packages/node/src/handlers.ts | 8 +++----- packages/node/src/index.ts | 6 ++---- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/node/src/handlers.ts b/packages/node/src/handlers.ts index 6b6e0b83..de6fa2f8 100644 --- a/packages/node/src/handlers.ts +++ b/packages/node/src/handlers.ts @@ -219,7 +219,7 @@ export async function signGeneratedVertices(node: DRPNode, vertices: Vertex[]) { return; } - await node.signVertexOperation(vertex); + await node.signVertex(vertex); }); await Promise.all(signPromises); @@ -260,9 +260,7 @@ export async function verifyIncomingVertices( } const publicKeyBytes = uint8ArrayFromString(publicKey, "base64"); - const operationData = uint8ArrayFromString( - JSON.stringify(vertex.operation), - ); + const data = uint8ArrayFromString(vertex.hash); try { const cryptoKey = await crypto.subtle.importKey( @@ -277,7 +275,7 @@ export async function verifyIncomingVertices( { name: "Ed25519" }, cryptoKey, signature, - operationData, + data, ); return isValid ? vertex : null; diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index a1d801c8..9aa54354 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -99,13 +99,11 @@ export class DRPNode { operations.syncObject(this, id, peerId); } - async signVertexOperation(vertex: Vertex) { + async signVertex(vertex: Vertex) { if (vertex.peerId !== this.networkNode.peerId) { log.error("::signVertexOperation: Invalid peer id"); return ""; } - vertex.signature = await this.networkNode.sign( - JSON.stringify(vertex.operation), - ); + vertex.signature = await this.networkNode.sign(vertex.hash); } }