Skip to content

Commit

Permalink
Merge branch 'main' into feat/replace-eddsa-with-ecdsa
Browse files Browse the repository at this point in the history
  • Loading branch information
trungnotchung committed Feb 19, 2025
2 parents 7c1c187 + 2c51957 commit 6e79d89
Show file tree
Hide file tree
Showing 8 changed files with 309 additions and 732 deletions.
1 change: 1 addition & 0 deletions packages/network/src/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ export class DRPNetworkNode {
...(this._config?.announce_addresses ? { announce: this._config.announce_addresses } : {}),
},
connectionManager: {
dialTimeout: 60_000,
addressSorter: this._sortAddresses,
},
connectionEncrypters: [noise()],
Expand Down
21 changes: 13 additions & 8 deletions packages/object/src/hashgraph/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,16 +166,20 @@ export class HashGraph {

dfsTopologicalSortIterative(origin: Hash, subgraph: ObjectSet<Hash>): Hash[] {
const visited = new ObjectSet<Hash>();
const result: Hash[] = [];
const stack: Hash[] = [origin];
const result: Hash[] = Array(subgraph.size);
const stack: Hash[] = Array(subgraph.size);
const processing = new ObjectSet<Hash>();
let resultIndex = subgraph.size - 1;
let stackIndex = 0;
stack[stackIndex] = origin;

while (stack.length > 0) {
const node = stack[stack.length - 1];
while (resultIndex >= 0) {
const node = stack[stackIndex];

if (visited.has(node)) {
stack.pop();
result.push(node);
result[resultIndex] = node;
stackIndex--;
resultIndex--;
processing.delete(node);
continue;
}
Expand All @@ -188,13 +192,14 @@ export class HashGraph {
for (const neighbor of neighbors.sort()) {
if (processing.has(neighbor)) throw new Error("Graph contains a cycle!");
if (subgraph.has(neighbor) && !visited.has(neighbor)) {
stack.push(neighbor);
stackIndex++;
stack[stackIndex] = neighbor;
}
}
}
}

return result.reverse();
return result;
}

/* Topologically sort the vertices in the whole hashgraph or the past of a given vertex. */
Expand Down
169 changes: 63 additions & 106 deletions packages/object/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,9 @@ export class DRPObject implements DRPObjectBase {
if (callerName?.startsWith("DRPObject.resolveConflicts")) {
return Reflect.apply(applyTarget, thisArg, args);
}
if (!callerName?.startsWith("Proxy.")) obj.callFn(fullPropKey, args, vertexType);
if (!callerName?.startsWith("Proxy.")) {
return obj.callFn(fullPropKey, args, vertexType);
}
return Reflect.apply(applyTarget, thisArg, args);
},
});
Expand All @@ -160,70 +162,56 @@ export class DRPObject implements DRPObjectBase {
if (!this.hashGraph) {
throw new Error("Hashgraph is undefined");
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let preOperationDRP: any;
if (drpType === DrpType.ACL) {
preOperationDRP = this._computeObjectACL(this.hashGraph.getFrontier());
} else {
preOperationDRP = this._computeDRP(this.hashGraph.getFrontier());
}
const drp = cloneDeep(preOperationDRP);

const isACL = drpType === DrpType.ACL;
const vertexDependencies = this.hashGraph.getFrontier();
const vertexOperation = { drpType, opType: fn, value: args };
const preComputeLca = this.computeLCA(vertexDependencies);
const now = Date.now();
const preOperationDRP = isACL
? this._computeObjectACL(vertexDependencies)
: this._computeDRP(vertexDependencies);

const clonedDRP = cloneDeep(preOperationDRP);
let appliedOperationResult = undefined;
try {
this._applyOperation(drp, { opType: fn, value: args, drpType });
appliedOperationResult = this._applyOperation(clonedDRP, vertexOperation);
} catch (e) {
log.error(`::drpObject::callFn: ${e}`);
return;
}

let stateChanged = false;
for (const key of Object.keys(preOperationDRP)) {
if (!deepEqual(preOperationDRP[key], drp[key])) {
stateChanged = true;
break;
}
return appliedOperationResult;
}

const stateChanged = Object.keys(preOperationDRP).some(
(key) => !deepEqual(preOperationDRP[key], clonedDRP[key])
);
if (!stateChanged) {
return;
return appliedOperationResult;
}

const vertexTimestamp = Date.now();
const vertexOperation = { drpType: drpType, opType: fn, value: args };
const vertexDependencies = this.hashGraph.getFrontier();
const [drp, acl] = isACL
? [this._computeDRP(vertexDependencies, preComputeLca), clonedDRP as ACL]
: [clonedDRP as DRP, this._computeObjectACL(vertexDependencies, preComputeLca)];

const vertex = ObjectPb.Vertex.create({
hash: computeHash(this.peerId, vertexOperation, vertexDependencies, vertexTimestamp),
hash: computeHash(this.peerId, vertexOperation, vertexDependencies, now),
peerId: this.peerId,
operation: vertexOperation,
dependencies: vertexDependencies,
timestamp: vertexTimestamp,
timestamp: now,
});
this.hashGraph.addToFrontier(vertex);

if (drpType === DrpType.DRP) {
this._setObjectACLState(vertex, undefined);
this._setDRPState(vertex, undefined, this._getDRPState(drp));
} else {
this._setObjectACLState(vertex, undefined, this._getDRPState(drp));
this._setDRPState(vertex, undefined);
}
this._initializeFinalityState(vertex.hash);
this.hashGraph.addToFrontier(vertex);
this._setDRPState(vertex, preComputeLca, this._getDRPState(drp));
this._setObjectACLState(vertex, preComputeLca, this._getDRPState(acl));
this._initializeFinalityState(vertex.hash, acl);

this.vertices.push(vertex);
this._notify("callFn", [vertex]);
}

/* Merges the vertices into the hashgraph
* Returns a tuple with a boolean indicating if there were
* missing vertices and an array with the missing vertices
*/
merge(vertices: Vertex[]): [merged: boolean, missing: string[]] {
if (!this.hashGraph) {
throw new Error("Hashgraph is undefined");
}
if (!this.drp) {
return this._mergeWithoutDrp(vertices);
}
return this._mergeWithDrp(vertices);
if (!isACL) Object.assign(this.drp as DRP, clonedDRP);
else Object.assign(this.acl as ObjectACL, clonedDRP);

return appliedOperationResult;
}

validateVertex(vertex: Vertex) {
Expand Down Expand Up @@ -260,9 +248,15 @@ export class DRPObject implements DRPObjectBase {
}
}

/* Merges the vertices into the hashgraph using DRP
/* Merges the vertices into the hashgraph
* Returns a tuple with a boolean indicating if there were
* missing vertices and an array with the missing vertices
*/
private _mergeWithDrp(vertices: Vertex[]): [merged: boolean, missing: string[]] {
merge(vertices: Vertex[]): [merged: boolean, missing: string[]] {
if (!this.hashGraph) {
throw new Error("Hashgraph is undefined");
}

const missing: Hash[] = [];
const newVertices: Vertex[] = [];
for (const vertex of vertices) {
Expand All @@ -275,17 +269,24 @@ export class DRPObject implements DRPObjectBase {
this.validateVertex(vertex);
const preComputeLca = this.computeLCA(vertex.dependencies);

if (vertex.operation.drpType === DrpType.DRP) {
const drp = this._computeDRP(vertex.dependencies, preComputeLca, vertex.operation);
this._setObjectACLState(vertex, preComputeLca);
if (this.drp) {
const drp = this._computeDRP(
vertex.dependencies,
preComputeLca,
vertex.operation.drpType === DrpType.DRP ? vertex.operation : undefined
);
this._setDRPState(vertex, preComputeLca, this._getDRPState(drp));
} else {
const acl = this._computeObjectACL(vertex.dependencies, preComputeLca, vertex.operation);
this._setObjectACLState(vertex, preComputeLca, this._getDRPState(acl));
this._setDRPState(vertex, preComputeLca);
}

const acl = this._computeObjectACL(
vertex.dependencies,
preComputeLca,
vertex.operation.drpType === DrpType.ACL ? vertex.operation : undefined
);
this._setObjectACLState(vertex, preComputeLca, this._getDRPState(acl));

this.hashGraph.addVertex(vertex);
this._initializeFinalityState(vertex.hash);
this._initializeFinalityState(vertex.hash, acl);
newVertices.push(vertex);
} catch (_) {
missing.push(vertex.hash);
Expand All @@ -294,39 +295,12 @@ export class DRPObject implements DRPObjectBase {

this.vertices = this.hashGraph.getAllVertices();
this._updateObjectACLState();
this._updateDRPState();
if (this.drp) this._updateDRPState();
this._notify("merge", newVertices);

return [missing.length === 0, missing];
}

/* Merges the vertices into the hashgraph without using DRP
*/
private _mergeWithoutDrp(vertices: Vertex[]): [merged: boolean, missing: string[]] {
const missing = [];
for (const vertex of vertices) {
if (!vertex.operation || this.hashGraph.vertices.has(vertex.hash)) {
continue;
}

try {
this.validateVertex(vertex);
this.hashGraph.addVertex({
hash: vertex.hash,
operation: vertex.operation,
dependencies: vertex.dependencies,
peerId: vertex.peerId,
timestamp: vertex.timestamp,
signature: vertex.signature,
});
} catch (_) {
missing.push(vertex.hash);
}
}

return [missing.length === 0, missing];
}

subscribe(callback: DRPObjectCallback) {
this.subscriptions.push(callback);
}
Expand All @@ -338,29 +312,12 @@ export class DRPObject implements DRPObjectBase {
}

// initialize the attestation store for the given vertex hash
private _initializeFinalityState(hash: Hash) {
if (!this.acl || !this.originalObjectACL) {
throw new Error("ObjectACL is undefined");
}
const fetchedState = this.aclStates.get(hash);
if (fetchedState !== undefined) {
const state = cloneDeep(fetchedState);
const acl = cloneDeep(this.originalObjectACL);

for (const entry of state.state) {
acl[entry.key] = entry.value;
}
// signer set equals writer set
this.finalityStore.initializeState(hash, acl.query_getFinalitySigners());
}
private _initializeFinalityState(hash: Hash, acl: ACL) {
this.finalityStore.initializeState(hash, acl.query_getFinalitySigners());
}

// check if the given peer has write permission
private _checkWriterPermission(peerId: string, deps: Hash[]): boolean {
if (!this.drp) {
return (this.acl as ACL).query_isWriter(peerId);
}

const acl = this._computeObjectACL(deps);
return (acl as ACL).query_isWriter(peerId);
}
Expand All @@ -385,7 +342,7 @@ export class DRPObject implements DRPObjectBase {
}

try {
target[methodName](...value);
return target[methodName](...value);
} catch (e) {
throw new Error(`Error while applying operation ${opType}: ${e}`);
}
Expand Down Expand Up @@ -432,7 +389,7 @@ export class DRPObject implements DRPObjectBase {
vertexDependencies: Hash[],
preCompute?: LcaAndOperations,
vertexOperation?: Operation
): DRP {
): ACL {
if (!this.acl || !this.originalObjectACL) {
throw new Error("ObjectACL is undefined");
}
Expand Down
1 change: 0 additions & 1 deletion packages/object/src/linearize/pairSemantics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,5 @@ export function linearizePairSemantics(
}
}
}

return result;
}
9 changes: 9 additions & 0 deletions packages/object/src/utils/objectSet.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
export class ObjectSet<T extends string | number | symbol> {
set: { [key in T]: boolean };
size: number;

constructor(iterable: Iterable<T> = []) {
this.set = {} as { [key in T]: boolean };
this.size = 0;
for (const item of iterable) {
this.set[item] = true;
this.size++;
}
}

add(item: T): void {
if (this.has(item)) return;

this.set[item] = true;
this.size++;
}

delete(item: T): void {
if (!this.has(item)) return;

delete this.set[item];
this.size--;
}

has(item: T): boolean {
Expand Down
4 changes: 3 additions & 1 deletion packages/object/tests/actiontypes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ describe("Test: ActionTypes (Nop and Swap)", () => {
addMul.add(5);
drp.merge(drp2.vertices);
drp2.merge(drp.vertices);

addMul.mul(5);
addMul.add(5);
addMul2.add(5);
Expand All @@ -99,8 +98,11 @@ describe("Test: ActionTypes (Nop and Swap)", () => {
expect(addMul2.query_value()).toBe(75);

addMul2.mul(2);
vi.setSystemTime(new Date(Date.UTC(1998, 11, 24)));
addMul2.add(2);
vi.setSystemTime(new Date(Date.UTC(1998, 11, 25)));
addMul.add(3);
vi.setSystemTime(new Date(Date.UTC(1998, 11, 26)));
addMul.mul(3);
drp.merge(drp2.vertices);
drp2.merge(drp.vertices);
Expand Down
Loading

0 comments on commit 6e79d89

Please sign in to comment.