diff --git a/packages/object/src/index.ts b/packages/object/src/index.ts index b4d952bf..2b0aced2 100644 --- a/packages/object/src/index.ts +++ b/packages/object/src/index.ts @@ -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); }, }); @@ -160,36 +162,35 @@ 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 isACL = drpType === DrpType.ACL; + const vertexDependencies = this.hashGraph.getFrontier(); + const preOperationDRP = isACL + ? this._computeObjectACL(vertexDependencies) + : this._computeDRP(vertexDependencies); + const drp = cloneDeep(preOperationDRP); + let appliedOperationResult = undefined; try { - this._applyOperation(drp, { opType: fn, value: args, drpType }); + appliedOperationResult = this._applyOperation(drp, { + opType: fn, + value: args, + drpType, + }); } 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], drp[key]) + ); if (!stateChanged) { - return; + return appliedOperationResult; } const vertexTimestamp = Date.now(); const vertexOperation = { drpType: drpType, opType: fn, value: args }; - const vertexDependencies = this.hashGraph.getFrontier(); const vertex = ObjectPb.Vertex.create({ hash: computeHash(this.peerId, vertexOperation, vertexDependencies, vertexTimestamp), peerId: this.peerId, @@ -197,8 +198,8 @@ export class DRPObject implements DRPObjectBase { dependencies: vertexDependencies, timestamp: vertexTimestamp, }); - this.hashGraph.addToFrontier(vertex); + this.hashGraph.addToFrontier(vertex); if (drpType === DrpType.DRP) { this._setObjectACLState(vertex, undefined); this._setDRPState(vertex, undefined, this._getDRPState(drp)); @@ -210,6 +211,11 @@ export class DRPObject implements DRPObjectBase { this.vertices.push(vertex); this._notify("callFn", [vertex]); + + if (!isACL) Object.assign(this.drp as DRP, drp); + else Object.assign(this.acl as ObjectACL, drp); + + return appliedOperationResult; } /* Merges the vertices into the hashgraph @@ -385,7 +391,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}`); } diff --git a/packages/object/tests/drpobject.test.ts b/packages/object/tests/drpobject.test.ts index 38d70e22..99faca18 100644 --- a/packages/object/tests/drpobject.test.ts +++ b/packages/object/tests/drpobject.test.ts @@ -1,7 +1,9 @@ import { SetDRP } from "@ts-drp/blueprints/src/index.js"; import { beforeEach, describe, expect, it, test, vi } from "vitest"; -import { DRPObject, ObjectACL } from "../src/index.js"; +import { SemanticsType } from "../dist/src/hashgraph/index.js"; +import { ActionType } from "../dist/src/hashgraph/index.js"; +import { DRP, DRPObject, ObjectACL, ResolveConflictsType, Vertex } from "../src/index.js"; const acl = new ObjectACL({ admins: new Map([ @@ -70,6 +72,46 @@ describe("Drp Object should be able to change state value", () => { }); }); +describe("Test for duplicate call issue", () => { + let counter = 0; + + class CounterDRP implements DRP { + semanticsType = SemanticsType.pair; + + private _counter: number; + + constructor() { + this._counter = 0; + } + + test() { + this._counter++; + counter++; + return this._counter; + } + + resolveConflicts(_: Vertex[]): ResolveConflictsType { + return { action: ActionType.Nop }; + } + } + + test("Detect duplicate call", () => { + const obj = new DRPObject({ + peerId: "", + publicCredential: { + ed25519PublicKey: "cred", + blsPublicKey: "cred", + }, + drp: new CounterDRP(), + }); + + const testDRP = obj.drp as CounterDRP; + expect(testDRP).toBeDefined(); + const ret = testDRP.test(); + expect(ret).toBe(counter); + }); +}); + describe("Merging vertices tests", () => { let obj1: DRPObject; let obj2: DRPObject;