autobee 2.0.0-rc.2 → 2.0.0-rc.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -1
- package/encoding/compat.js +1 -1
- package/encoding/legacy.js +3 -3
- package/encoding/spec/autobee/index.js +104 -22
- package/encoding/spec/autobee/schema.json +63 -1
- package/index.js +392 -197
- package/lib/apply-calls.js +5 -0
- package/lib/apply-view.js +25 -0
- package/lib/boot.js +6 -1
- package/lib/encoding.js +12 -0
- package/lib/{reboot.js → fast-forward.js} +213 -19
- package/lib/system.js +38 -62
- package/lib/topo.js +121 -18
- package/lib/trusted.js +44 -0
- package/lib/updates.js +1 -38
- package/lib/writers.js +90 -15
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -78,7 +78,10 @@ Options:
|
|
|
78
78
|
encryptionKey: Buffer, // 32-byte key to encrypt all data at rest
|
|
79
79
|
encrypted: false, // set true if using encryptionKey
|
|
80
80
|
keyPair: { publicKey, secretKey }, // custom signing key pair for the local writer
|
|
81
|
-
optimistic: true
|
|
81
|
+
optimistic: true, // allow optimistic writes from unknown writers
|
|
82
|
+
isTrusted (key, reference) {}, // do we trust this writer, see Fast-forward
|
|
83
|
+
mostRecentTrusted (target, reference) {}, // the head we vouch for, see Fast-forward
|
|
84
|
+
fastForward: {} // see Fast-forward
|
|
82
85
|
}
|
|
83
86
|
```
|
|
84
87
|
|
|
@@ -222,6 +225,50 @@ Create an anchor node. Returns `{ key, length }`. Anchors are used to create a v
|
|
|
222
225
|
|
|
223
226
|
`true` if the system has not yet processed any nodes. Use this to bootstrap the first writer.
|
|
224
227
|
|
|
228
|
+
### Fast-forward
|
|
229
|
+
|
|
230
|
+
Fast-forward only ever deals in oplog heads — `{ key, length }` of a writer's core, never a system head.
|
|
231
|
+
|
|
232
|
+
Each flush stamps the head you vouch for into your own oplog, and peers read those stamps out of the writers they wake up on, so trust travels with the log.
|
|
233
|
+
|
|
234
|
+
#### `isTrusted(key, reference)`
|
|
235
|
+
|
|
236
|
+
Return whether `key` is a writer you trust, judged against the `reference` view.
|
|
237
|
+
|
|
238
|
+
Positive answers are cached until an undo rewinds the view, and the default is `true` unless you supply `mostRecentTrusted`, in which case it is `false`.
|
|
239
|
+
|
|
240
|
+
#### `mostRecentTrusted(target, reference)`
|
|
241
|
+
|
|
242
|
+
Return the oplog head you most recently vouched for, given the `target` view being considered.
|
|
243
|
+
|
|
244
|
+
Called at flush time to stamp your own oplog (with your view as `target` and a `null` reference), and again per candidate during discovery.
|
|
245
|
+
|
|
246
|
+
#### `fastForward.boot`
|
|
247
|
+
|
|
248
|
+
```js
|
|
249
|
+
{
|
|
250
|
+
head: { key, length }, // oplog head to boot from
|
|
251
|
+
legacy: { key, length }, // pre-2.0 pointer, see below
|
|
252
|
+
bootCondition (target, reference) {} // optional gate on the view we would land on
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Pass one of `head` or `legacy`, not both.
|
|
257
|
+
|
|
258
|
+
Without `bootCondition` this is a single attempt that gives up if the head cannot be read; with one it parks until the condition is satisfied, which today means indefinitely if it never is.
|
|
259
|
+
|
|
260
|
+
`legacy` is for records written before boot heads were oplog heads: the key is a _system_ head and a `0` length is resolved from the core. It boots ungated - `bootCondition` does not apply - and will be removed, so don't reach for it. A bare `{ key, length }` in place of the whole struct means the same thing, older still.
|
|
261
|
+
|
|
262
|
+
#### `fastForward.conservative`
|
|
263
|
+
|
|
264
|
+
Defaults to `true`: only fast-forward onto a head a connected peer can serve whole.
|
|
265
|
+
|
|
266
|
+
The check covers the oplog head only, not the system and view cores the fast-forward then reads.
|
|
267
|
+
|
|
268
|
+
#### `await db.moveTo(head)`
|
|
269
|
+
|
|
270
|
+
Fast-forward onto an oplog head, ignoring the usual distance and conservative checks. Resolves `{ to, from }`.
|
|
271
|
+
|
|
225
272
|
### Encryption
|
|
226
273
|
|
|
227
274
|
Pass an `encryptionKey` to encrypt all writer cores and the view at rest.
|
package/encoding/compat.js
CHANGED
package/encoding/legacy.js
CHANGED
|
@@ -153,18 +153,18 @@ const Node = {
|
|
|
153
153
|
preencode(state, m) {
|
|
154
154
|
Clock.preencode(state, m.heads)
|
|
155
155
|
c.uint.preencode(state, m.batch)
|
|
156
|
-
c.
|
|
156
|
+
c.optionalBuffer.preencode(state, m.value)
|
|
157
157
|
},
|
|
158
158
|
encode(state, m) {
|
|
159
159
|
Clock.encode(state, m.heads)
|
|
160
160
|
c.uint.encode(state, m.batch)
|
|
161
|
-
c.
|
|
161
|
+
c.optionalBuffer.encode(state, m.value)
|
|
162
162
|
},
|
|
163
163
|
decode(state, m) {
|
|
164
164
|
return {
|
|
165
165
|
heads: Clock.decode(state),
|
|
166
166
|
batch: c.uint.decode(state),
|
|
167
|
-
value: c.
|
|
167
|
+
value: c.optionalBuffer.decode(state)
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
}
|
|
@@ -97,8 +97,9 @@ const encoding4 = {
|
|
|
97
97
|
// @autobase-compat/boot-record
|
|
98
98
|
const encoding5 = {
|
|
99
99
|
preencode(state, m) {
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
const v = m.version ?? 3
|
|
101
|
+
c.uint.preencode(state, v)
|
|
102
|
+
switch (v) {
|
|
102
103
|
case 0:
|
|
103
104
|
encoding3.preencode(state, m)
|
|
104
105
|
break
|
|
@@ -112,8 +113,9 @@ const encoding5 = {
|
|
|
112
113
|
}
|
|
113
114
|
},
|
|
114
115
|
encode(state, m) {
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
const v = m.version ?? 3
|
|
117
|
+
c.uint.encode(state, v)
|
|
118
|
+
switch (v) {
|
|
117
119
|
case 0:
|
|
118
120
|
encoding3.encode(state, m)
|
|
119
121
|
break
|
|
@@ -236,17 +238,17 @@ const encoding9 = {
|
|
|
236
238
|
preencode(state, m) {
|
|
237
239
|
encoding1.preencode(state, m.heads)
|
|
238
240
|
c.uint.preencode(state, m.batch)
|
|
239
|
-
c.
|
|
241
|
+
c.optionalBuffer.preencode(state, m.value)
|
|
240
242
|
},
|
|
241
243
|
encode(state, m) {
|
|
242
244
|
encoding1.encode(state, m.heads)
|
|
243
245
|
c.uint.encode(state, m.batch)
|
|
244
|
-
c.
|
|
246
|
+
c.optionalBuffer.encode(state, m.value)
|
|
245
247
|
},
|
|
246
248
|
decode(state) {
|
|
247
249
|
const r0 = encoding1.decode(state)
|
|
248
250
|
const r1 = c.uint.decode(state)
|
|
249
|
-
const r2 = c.
|
|
251
|
+
const r2 = c.optionalBuffer.decode(state)
|
|
250
252
|
|
|
251
253
|
return {
|
|
252
254
|
heads: r0,
|
|
@@ -496,8 +498,9 @@ const encoding18 = {
|
|
|
496
498
|
// @autobee/system-info
|
|
497
499
|
const encoding19 = {
|
|
498
500
|
preencode(state, m) {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
+
const v = m.version ?? 3
|
|
502
|
+
c.uint.preencode(state, v)
|
|
503
|
+
switch (v) {
|
|
501
504
|
case 0:
|
|
502
505
|
case 1:
|
|
503
506
|
encoding15.preencode(state, m)
|
|
@@ -513,8 +516,9 @@ const encoding19 = {
|
|
|
513
516
|
}
|
|
514
517
|
},
|
|
515
518
|
encode(state, m) {
|
|
516
|
-
|
|
517
|
-
|
|
519
|
+
const v = m.version ?? 3
|
|
520
|
+
c.uint.encode(state, v)
|
|
521
|
+
switch (v) {
|
|
518
522
|
case 0:
|
|
519
523
|
case 1:
|
|
520
524
|
encoding15.encode(state, m)
|
|
@@ -603,8 +607,9 @@ const encoding20 = {
|
|
|
603
607
|
// @autobee/system-writer
|
|
604
608
|
const encoding21 = {
|
|
605
609
|
preencode(state, m) {
|
|
606
|
-
|
|
607
|
-
|
|
610
|
+
const v = m.version ?? 4
|
|
611
|
+
c.uint.preencode(state, v)
|
|
612
|
+
switch (v) {
|
|
608
613
|
case 0:
|
|
609
614
|
case 1:
|
|
610
615
|
case 2:
|
|
@@ -619,8 +624,9 @@ const encoding21 = {
|
|
|
619
624
|
}
|
|
620
625
|
},
|
|
621
626
|
encode(state, m) {
|
|
622
|
-
|
|
623
|
-
|
|
627
|
+
const v = m.version ?? 4
|
|
628
|
+
c.uint.encode(state, v)
|
|
629
|
+
switch (v) {
|
|
624
630
|
case 0:
|
|
625
631
|
case 1:
|
|
626
632
|
case 2:
|
|
@@ -850,15 +856,28 @@ const encoding29_7 = c.array(c.frame(encoding28))
|
|
|
850
856
|
// @autobee/oplog-message-v3
|
|
851
857
|
const encoding29 = {
|
|
852
858
|
preencode(state, m) {
|
|
859
|
+
let flags =
|
|
860
|
+
(m.batch ? 1 : 0) |
|
|
861
|
+
(m.views ? 2 : 0) |
|
|
862
|
+
(m.optimistic ? 8 : 0) |
|
|
863
|
+
(m.value ? 16 : 0) |
|
|
864
|
+
(m.witness ? 32 : 0) |
|
|
865
|
+
(m.attestations ? 64 : 0) |
|
|
866
|
+
(m.trusted ? 128 : 0)
|
|
867
|
+
if (m.views) {
|
|
868
|
+
flags |= m.views.view ? 4 : 0
|
|
869
|
+
}
|
|
870
|
+
|
|
853
871
|
c.uint.preencode(state, m.timestamp)
|
|
854
872
|
encoding29_1.preencode(state, m.links)
|
|
855
|
-
state
|
|
873
|
+
c.uint.preencode(state, flags)
|
|
856
874
|
|
|
857
875
|
if (m.batch) encoding24.preencode(state, m.batch)
|
|
858
876
|
if (m.views) encoding25_inline.preencode(state, m.views)
|
|
859
877
|
if (m.value) c.buffer.preencode(state, m.value)
|
|
860
878
|
if (m.witness) encoding29_6.preencode(state, m.witness)
|
|
861
879
|
if (m.attestations) encoding29_7.preencode(state, m.attestations)
|
|
880
|
+
if (m.trusted) encoding29_8.preencode(state, m.trusted)
|
|
862
881
|
},
|
|
863
882
|
encode(state, m) {
|
|
864
883
|
let flags =
|
|
@@ -867,7 +886,8 @@ const encoding29 = {
|
|
|
867
886
|
(m.optimistic ? 8 : 0) |
|
|
868
887
|
(m.value ? 16 : 0) |
|
|
869
888
|
(m.witness ? 32 : 0) |
|
|
870
|
-
(m.attestations ? 64 : 0)
|
|
889
|
+
(m.attestations ? 64 : 0) |
|
|
890
|
+
(m.trusted ? 128 : 0)
|
|
871
891
|
if (m.views) {
|
|
872
892
|
flags |= m.views.view ? 4 : 0
|
|
873
893
|
}
|
|
@@ -881,6 +901,7 @@ const encoding29 = {
|
|
|
881
901
|
if (m.value) c.buffer.encode(state, m.value)
|
|
882
902
|
if (m.witness) encoding29_6.encode(state, m.witness)
|
|
883
903
|
if (m.attestations) encoding29_7.encode(state, m.attestations)
|
|
904
|
+
if (m.trusted) encoding29_8.encode(state, m.trusted)
|
|
884
905
|
},
|
|
885
906
|
decode(state) {
|
|
886
907
|
const v = c.uint.decode(state)
|
|
@@ -897,7 +918,8 @@ const encoding29 = {
|
|
|
897
918
|
optimistic: (flags & 8) !== 0,
|
|
898
919
|
value: (flags & 16) !== 0 ? c.buffer.decode(state) : null,
|
|
899
920
|
witness: (flags & 32) !== 0 ? encoding29_6.decode(state) : null,
|
|
900
|
-
attestations: (flags & 64) !== 0 ? encoding29_7.decode(state) : null
|
|
921
|
+
attestations: (flags & 64) !== 0 ? encoding29_7.decode(state) : null,
|
|
922
|
+
trusted: (flags & 128) !== 0 ? encoding29_8.decode(state) : null
|
|
901
923
|
}
|
|
902
924
|
}
|
|
903
925
|
}
|
|
@@ -905,8 +927,9 @@ const encoding29 = {
|
|
|
905
927
|
// @autobee/oplog
|
|
906
928
|
const encoding30 = {
|
|
907
929
|
preencode(state, m) {
|
|
908
|
-
|
|
909
|
-
|
|
930
|
+
const v = m.version ?? 3
|
|
931
|
+
c.uint.preencode(state, v)
|
|
932
|
+
switch (v) {
|
|
910
933
|
case 0:
|
|
911
934
|
encoding12.preencode(state, m)
|
|
912
935
|
break
|
|
@@ -924,8 +947,9 @@ const encoding30 = {
|
|
|
924
947
|
}
|
|
925
948
|
},
|
|
926
949
|
encode(state, m) {
|
|
927
|
-
|
|
928
|
-
|
|
950
|
+
const v = m.version ?? 3
|
|
951
|
+
c.uint.encode(state, v)
|
|
952
|
+
switch (v) {
|
|
929
953
|
case 0:
|
|
930
954
|
encoding12.encode(state, m)
|
|
931
955
|
break
|
|
@@ -999,12 +1023,66 @@ const encoding31 = {
|
|
|
999
1023
|
}
|
|
1000
1024
|
}
|
|
1001
1025
|
|
|
1026
|
+
// @autobee/trusted-head
|
|
1027
|
+
const encoding32 = {
|
|
1028
|
+
preencode(state, m) {
|
|
1029
|
+
c.fixed32.preencode(state, m.key)
|
|
1030
|
+
c.uint.preencode(state, m.length)
|
|
1031
|
+
c.uint.preencode(state, m.flushes)
|
|
1032
|
+
},
|
|
1033
|
+
encode(state, m) {
|
|
1034
|
+
c.fixed32.encode(state, m.key)
|
|
1035
|
+
c.uint.encode(state, m.length)
|
|
1036
|
+
c.uint.encode(state, m.flushes)
|
|
1037
|
+
},
|
|
1038
|
+
decode(state) {
|
|
1039
|
+
const r0 = c.fixed32.decode(state)
|
|
1040
|
+
const r1 = c.uint.decode(state)
|
|
1041
|
+
const r2 = c.uint.decode(state)
|
|
1042
|
+
|
|
1043
|
+
return {
|
|
1044
|
+
key: r0,
|
|
1045
|
+
length: r1,
|
|
1046
|
+
flushes: r2
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
// @autobee/migrated-head
|
|
1052
|
+
const encoding33 = {
|
|
1053
|
+
preencode(state, m) {
|
|
1054
|
+
encoding22.preencode(state, m.system)
|
|
1055
|
+
state.end++ // flags are fixed size
|
|
1056
|
+
|
|
1057
|
+
if (m.view) encoding22.preencode(state, m.view)
|
|
1058
|
+
},
|
|
1059
|
+
encode(state, m) {
|
|
1060
|
+
const flags = m.view ? 1 : 0
|
|
1061
|
+
|
|
1062
|
+
encoding22.encode(state, m.system)
|
|
1063
|
+
c.uint8.encode(state, flags)
|
|
1064
|
+
|
|
1065
|
+
if (m.view) encoding22.encode(state, m.view)
|
|
1066
|
+
},
|
|
1067
|
+
decode(state) {
|
|
1068
|
+
const r0 = encoding22.decode(state)
|
|
1069
|
+
const flags = c.uint8.decode(state)
|
|
1070
|
+
|
|
1071
|
+
return {
|
|
1072
|
+
system: r0,
|
|
1073
|
+
view: (flags & 1) !== 0 ? encoding22.decode(state) : null
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1002
1078
|
// @autobee/system-info-v3.heads, deferred due to recusive use
|
|
1003
1079
|
const encoding18_3 = c.array(encoding22)
|
|
1004
1080
|
// @autobee/system-info-v3.indexers, deferred due to recusive use
|
|
1005
1081
|
const encoding18_4 = encoding18_3
|
|
1006
1082
|
// @autobee/oplog-message-v3.links, deferred due to recusive use
|
|
1007
1083
|
const encoding29_1 = encoding18_3
|
|
1084
|
+
// @autobee/oplog-message-v3.trusted, deferred due to recusive use
|
|
1085
|
+
const encoding29_8 = c.array(c.frame(encoding32))
|
|
1008
1086
|
|
|
1009
1087
|
function setVersion(v) {
|
|
1010
1088
|
version = v
|
|
@@ -1093,6 +1171,10 @@ function getEncoding(name) {
|
|
|
1093
1171
|
return encoding30
|
|
1094
1172
|
case '@autobee/manifest-data':
|
|
1095
1173
|
return encoding31
|
|
1174
|
+
case '@autobee/trusted-head':
|
|
1175
|
+
return encoding32
|
|
1176
|
+
case '@autobee/migrated-head':
|
|
1177
|
+
return encoding33
|
|
1096
1178
|
default:
|
|
1097
1179
|
throw new Error('Encoder not found ' + name)
|
|
1098
1180
|
}
|
|
@@ -194,7 +194,7 @@
|
|
|
194
194
|
{
|
|
195
195
|
"name": "value",
|
|
196
196
|
"required": true,
|
|
197
|
-
"type": "
|
|
197
|
+
"type": "optionalBuffer",
|
|
198
198
|
"version": 1
|
|
199
199
|
}
|
|
200
200
|
]
|
|
@@ -750,6 +750,12 @@
|
|
|
750
750
|
"array": true,
|
|
751
751
|
"type": "@autobee/attestation",
|
|
752
752
|
"version": 1
|
|
753
|
+
},
|
|
754
|
+
{
|
|
755
|
+
"name": "trusted",
|
|
756
|
+
"array": true,
|
|
757
|
+
"type": "@autobee/trusted-head",
|
|
758
|
+
"version": 1
|
|
753
759
|
}
|
|
754
760
|
]
|
|
755
761
|
},
|
|
@@ -804,6 +810,62 @@
|
|
|
804
810
|
"version": 1
|
|
805
811
|
}
|
|
806
812
|
]
|
|
813
|
+
},
|
|
814
|
+
{
|
|
815
|
+
"name": "trusted-head",
|
|
816
|
+
"namespace": "autobee",
|
|
817
|
+
"compact": false,
|
|
818
|
+
"flagsPosition": -1,
|
|
819
|
+
"fields": [
|
|
820
|
+
{
|
|
821
|
+
"name": "key",
|
|
822
|
+
"required": true,
|
|
823
|
+
"type": "fixed32",
|
|
824
|
+
"version": 1
|
|
825
|
+
},
|
|
826
|
+
{
|
|
827
|
+
"name": "length",
|
|
828
|
+
"required": true,
|
|
829
|
+
"type": "uint",
|
|
830
|
+
"version": 1
|
|
831
|
+
},
|
|
832
|
+
{
|
|
833
|
+
"name": "flushes",
|
|
834
|
+
"required": true,
|
|
835
|
+
"type": "uint",
|
|
836
|
+
"version": 1
|
|
837
|
+
}
|
|
838
|
+
]
|
|
839
|
+
},
|
|
840
|
+
{
|
|
841
|
+
"name": "migrated-head",
|
|
842
|
+
"namespace": "autobee",
|
|
843
|
+
"compact": true,
|
|
844
|
+
"flagsPosition": 1,
|
|
845
|
+
"fields": [
|
|
846
|
+
{
|
|
847
|
+
"name": "system",
|
|
848
|
+
"required": true,
|
|
849
|
+
"type": "@autobee/link",
|
|
850
|
+
"version": 1
|
|
851
|
+
},
|
|
852
|
+
{
|
|
853
|
+
"name": "view",
|
|
854
|
+
"required": false,
|
|
855
|
+
"type": "@autobee/link",
|
|
856
|
+
"version": 1
|
|
857
|
+
}
|
|
858
|
+
]
|
|
859
|
+
}
|
|
860
|
+
],
|
|
861
|
+
"namespaces": [
|
|
862
|
+
{
|
|
863
|
+
"name": "autobee",
|
|
864
|
+
"external": "../../legacy.js"
|
|
865
|
+
},
|
|
866
|
+
{
|
|
867
|
+
"name": "autobase-compat",
|
|
868
|
+
"external": "../../legacy.js"
|
|
807
869
|
}
|
|
808
870
|
]
|
|
809
871
|
}
|