Skip to content

Commit 6f38a7a

Browse files
committed
fixes for CausalReference + a couple of passing tests
1 parent 806ed7c commit 6f38a7a

File tree

2 files changed

+118
-21
lines changed

2 files changed

+118
-21
lines changed

src/data/collections/causal/CausalReference.ts

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { Timestamps } from 'util/timestamps';
33

44
import { Identity } from '../../identity';
55
import { Hash, HashedObject, MutableObject, MutationOp, MutableContentEvents, ClassRegistry } from '../../model';
6-
import { RefUpdateOp } from '../mutable/MutableReference';
76

87
import { Authorizer } from '../../model/causal/Authorization';
98
import { Verification } from '../../model/causal/Authorization';
@@ -26,9 +25,10 @@ function sig(op: CausalRefUpdateOp<any>) {
2625
// the following should return -1 if u2 comes after u1;
2726

2827
function compareUpdateSigs(u1: UpdateSig, u2: UpdateSig) {
28+
2929
if (u2.sequence > u1.sequence) {
3030
return -1;
31-
} else if (u1.sequence < u2.sequence) {
31+
} else if (u1.sequence > u2.sequence) {
3232
return 1;
3333
} else { // u2.sequence === u1.sequence
3434
if (Timestamps.after(u2.timestamp, u1.timestamp)) {
@@ -54,7 +54,7 @@ class CausalReference<T> extends BaseCausalCollection<T> {
5454
_largestSequence?: number;
5555

5656
constructor(config?: CausalCollectionConfig) {
57-
super([CausalRefUpdateOp.className], config);
57+
super([CausalRefUpdateOp.className], {...config, supportsUndo: true});
5858

5959
this.setRandomId();
6060

@@ -104,34 +104,33 @@ class CausalReference<T> extends BaseCausalCollection<T> {
104104

105105
let mutated = false;
106106

107-
if (op instanceof RefUpdateOp) {
107+
if (op instanceof CausalRefUpdateOp) {
108+
109+
//console.log('processing sequence ' + op.sequence + ', valid=' + valid)
108110

109111
const up = sig(op);
110112

111113
let idx: number; // the position of op in the array
112114

113-
if (!this._allAppliedOps.has(up.opHash)) {
115+
// find the right place for the op in the array:
116+
const length = this._causallyOrderedUpdates.length
117+
idx = length;
114118

115-
// if the op has not been applied, we find the right place for it:
116-
const length = this._causallyOrderedUpdates.length
117-
idx = length;
119+
while (idx>0 && compareUpdateSigs(this._causallyOrderedUpdates[idx-1], up) > 0) {
120+
idx=idx-1;
121+
}
118122

119-
while (idx>0 && compareUpdateSigs(this._causallyOrderedUpdates[idx-1], up) > 0) {
120-
idx=idx-1;
121-
}
123+
// and then insert it there, if it was not there already:
122124

123-
// and then insert it there:
125+
// NOTE: since the compare above failed, upds[idx-1] <= up
126+
if (idx===0 || this._causallyOrderedUpdates[idx-1].opHash !== up.opHash) {
127+
// upds[idx-1] < up => insert in position idx
124128
this._causallyOrderedUpdates.splice(idx, 0, up);
125129
} else {
126-
127-
// else, we just go through the array until we find it
128-
idx = length-1;
129-
130-
while (idx>0 && this._causallyOrderedUpdates[idx-1].opHash !== up.opHash) {
131-
idx=idx-1;
132-
}
130+
// upds[idx-1] === up => use old position idx-1
131+
idx = idx-1;
133132
}
134-
133+
135134
let newValueIdx: number|undefined;
136135
let newValueOp: CausalRefUpdateOp<T>|undefined;
137136

@@ -148,13 +147,14 @@ class CausalReference<T> extends BaseCausalCollection<T> {
148147
if (this._latestValidIdx === idx) {
149148
// the current value has been invalidated, look for the next-best
150149

151-
let nextValueIdx = length;
150+
let nextValueIdx = length-1;
152151

153152
while (nextValueIdx>=0 && !this.isValidOp(this._causallyOrderedUpdates[nextValueIdx].opHash)) {
154153
nextValueIdx=nextValueIdx-1;
155154
}
156155

157156
if (nextValueIdx >= 0) {
157+
158158
newValueIdx = nextValueIdx;
159159
newValueOp = await this.loadOp(this._causallyOrderedUpdates[nextValueIdx].opHash) as CausalRefUpdateOp<T>;
160160
} else {
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { describeProxy } from 'config';
2+
import { RNGImpl } from 'crypto/random';
3+
import { Identity, RSAKeyPair } from 'data/identity';
4+
import { CausalReference, CausalSet } from 'data/collections';
5+
6+
import { Store } from 'storage/store';
7+
import { IdbBackend } from 'storage/backends';
8+
9+
describeProxy('[CRF] Causal references', () => {
10+
11+
test('[CRF01] Causal reference set', async (done) => {
12+
13+
let r = new CausalReference<string>({acceptedTypes: ['string']});
14+
15+
expect (r.getValue()).toBeUndefined();
16+
17+
await r.setValue('hi');
18+
19+
expect (r.getValue() === 'hi').toBeTruthy();
20+
21+
await r.setValue('bye');
22+
23+
expect (r.getValue() === 'bye').toBeTruthy();
24+
25+
done();
26+
});
27+
28+
test('[CRF02] Causal reference undo', async (done) => {
29+
30+
let store = new Store(new IdbBackend('CRF02 - ' + new RNGImpl().randomHexString(128)));
31+
32+
let kp0 = await RSAKeyPair.generate(2048);
33+
let i0 = Identity.fromKeyPair({}, kp0);
34+
35+
await store.save(kp0);
36+
await store.save(i0);
37+
38+
let kp1 = await RSAKeyPair.generate(2048);
39+
let i1 = Identity.fromKeyPair({}, kp1);
40+
41+
await store.save(kp1);
42+
await store.save(i1);
43+
44+
45+
let mutWriters = new CausalSet<Identity>({writer: i0, acceptedTypes: [Identity.className]});
46+
let ref = new CausalReference<string>({mutableWriters: mutWriters});
47+
48+
await store.save(mutWriters);
49+
await store.save(ref);
50+
51+
const check = await ref.canSetValue('hi', i1);
52+
53+
expect(check).toBeFalsy();
54+
55+
await mutWriters.add(i1, i0);
56+
await mutWriters.save();
57+
58+
const recheck = await ref.canSetValue('hi', i1);
59+
60+
expect(recheck).toBeTruthy();
61+
62+
await ref.setValue('1', i1);
63+
await ref.save();
64+
65+
expect (ref.getValue()).toEqual('1');
66+
67+
await ref.setValue('2', i1);
68+
await ref.save();
69+
70+
expect (ref.getValue()).toEqual('2');
71+
72+
let mutWritersClone = await store.load(mutWriters.hash()) as CausalSet<Identity>;
73+
74+
await ref.setValue('3', i1);
75+
await ref.save();
76+
77+
expect (ref.getValue()).toEqual('3');
78+
79+
await ref.setValue('4', i1);
80+
await ref.save();
81+
82+
expect (ref.getValue()).toEqual('4');
83+
84+
await mutWritersClone.delete(i1, i0);
85+
86+
await mutWritersClone.save();
87+
88+
console.log('FINAL LOADING!')
89+
90+
let refClone = await store.load(ref.hash()) as CausalReference<string>;
91+
92+
expect (refClone.getValue()).toEqual('2');
93+
94+
done();
95+
});
96+
97+
});

0 commit comments

Comments
 (0)