Skip to content

Commit

Permalink
refactor: reuse protobuf Vertex definition (#164)
Browse files Browse the repository at this point in the history
Co-authored-by: Oak <[email protected]>
  • Loading branch information
cwkang1998 and d-roak authored Sep 23, 2024
1 parent d2a3a8d commit 552b561
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 47 deletions.
7 changes: 5 additions & 2 deletions packages/blueprints/src/AddWinsSet/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,12 @@ export class AddWinsSet<T> implements CRO {

// in this case is an array of length 2 and there are only two possible operations
resolveConflicts(vertices: Vertex[]): ResolveConflictsType {
// Both must have operations, if not return no-op
if (
vertices[0].operation.type !== vertices[1].operation.type &&
vertices[0].operation.value === vertices[1].operation.value
vertices[0].operation &&
vertices[1].operation &&
vertices[0].operation?.type !== vertices[1].operation?.type &&
vertices[0].operation?.value === vertices[1].operation?.value
) {
return vertices[0].operation.type === "add"
? { action: ActionType.DropRight }
Expand Down
20 changes: 7 additions & 13 deletions packages/object/src/hashgraph/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import * as crypto from "node:crypto";
import { linearizeMultiple } from "../linearize/multipleSemantics.js";
import { linearizePair } from "../linearize/pairSemantics.js";
import { Vertex_Operation as Operation, Vertex } from "../proto/object_pb.js";
import { BitSet } from "./bitset.js";

// Reexporting the Vertex and Operation types from the protobuf file
export { Vertex, Operation };

export type Hash = string;
// biome-ignore lint: value can't be unknown because of protobuf
export type Operation = { type: string; value: any | null };

enum OperationType {
export enum OperationType {
NOP = "-1",
}

Expand All @@ -30,15 +32,6 @@ export type ResolveConflictsType = {
vertices?: Hash[];
};

export interface Vertex {
hash: Hash;
nodeId: string;
// internal Operation type enum converted to number
// -1 for NOP
operation: Operation;
dependencies: Hash[];
}

export class HashGraph {
nodeId: string;
resolveConflicts: (vertices: Vertex[]) => ResolveConflictsType;
Expand Down Expand Up @@ -89,10 +82,11 @@ export class HashGraph {
addToFrontier(operation: Operation): Vertex {
const deps = this.getFrontier();
const hash = computeHash(this.nodeId, operation, deps);

const vertex: Vertex = {
hash,
nodeId: this.nodeId,
operation,
operation: operation ?? { type: OperationType.NOP },
dependencies: deps,
};

Expand Down
23 changes: 7 additions & 16 deletions packages/object/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as crypto from "node:crypto";
import {
type ActionType,
HashGraph,
type Operation,
type ResolveConflictsType,
Expand Down Expand Up @@ -91,10 +90,7 @@ export class TopologyObject implements ITopologyObject {
const serializedVertex = ObjectPb.Vertex.create({
hash: vertex.hash,
nodeId: vertex.nodeId,
operation: {
type: vertex.operation.type,
value: vertex.operation.value,
},
operation: vertex.operation,
dependencies: vertex.dependencies,
});
this.vertices.push(serializedVertex);
Expand All @@ -103,6 +99,11 @@ export class TopologyObject implements ITopologyObject {

merge(vertices: Vertex[]) {
for (const vertex of vertices) {
// Check to avoid manually crafted `undefined` operations
if (!vertex.operation) {
continue;
}

this.hashGraph.addVertex(
vertex.operation,
vertex.dependencies,
Expand All @@ -111,17 +112,7 @@ export class TopologyObject implements ITopologyObject {
}

const operations = this.hashGraph.linearizeOperations();
this.vertices = this.hashGraph.getAllVertices().map((vertex) => {
return {
hash: vertex.hash,
nodeId: vertex.nodeId,
operation: {
type: vertex.operation.type,
value: vertex.operation.value,
},
dependencies: vertex.dependencies,
};
});
this.vertices = this.hashGraph.getAllVertices();

(this.cro as CRO).mergeCallback(operations);
this._notify("merge", this.vertices);
Expand Down
40 changes: 39 additions & 1 deletion packages/object/tests/hashgraph.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { beforeEach, describe, expect, test } from "vitest";
import { AddWinsSet } from "../../blueprints/src/AddWinsSet/index.js";
import { PseudoRandomWinsSet } from "../../blueprints/src/PseudoRandomWinsSet/index.js";
import { TopologyObject } from "../src/index.js";
import { type Operation, OperationType, TopologyObject } from "../src/index.js";

describe("HashGraph for AddWinSet tests", () => {
let obj1: TopologyObject;
Expand Down Expand Up @@ -349,3 +349,41 @@ describe("HashGraph for PseudoRandomWinsSet tests", () => {
expect(linearOps).toEqual([{ type: "add", value: 3 }]);
});
});

describe("HashGraph for undefined operations tests", () => {
let obj1: TopologyObject;
let obj2: TopologyObject;

beforeEach(async () => {
obj1 = new TopologyObject("peer1", new AddWinsSet<number>());
obj2 = new TopologyObject("peer2", new AddWinsSet<number>());
});

test("Test: merge should skip undefined operations", () => {
const cro1 = obj1.cro as AddWinsSet<number>;
const cro2 = obj2.cro as AddWinsSet<number>;

cro1.add(1);
cro2.add(2);

// Set one of the vertice from cro1 to have undefined operation
obj1.hashGraph.getAllVertices()[1].operation = undefined;

obj2.merge(obj1.hashGraph.getAllVertices());

const linearOps = obj2.hashGraph.linearizeOperations();
// Should only have one, since we skipped the undefined operations
expect(linearOps).toEqual([{ type: "add", value: 2 }]);
});

test("Test: addToFrontier with undefined operation return Vertex with NoOp operation", () => {
// Forcefully pass an undefined value
const createdVertex = obj1.hashGraph.addToFrontier(
undefined as unknown as Operation,
);

expect(createdVertex.operation).toEqual({
type: OperationType.NOP,
} as Operation);
});
});
30 changes: 15 additions & 15 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 552b561

Please sign in to comment.