autobee 2.0.0-rc.9 → 2.0.0

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.
@@ -1,5 +1,4 @@
1
1
  const ID = require('hypercore-id-encoding')
2
- const b4a = require('b4a')
3
2
 
4
3
  class ApplyCalls {
5
4
  constructor(auto) {
@@ -35,15 +34,15 @@ class ApplyCalls {
35
34
  if (typeof key === 'string') key = ID.decode(key)
36
35
  // no witness needed for genesis
37
36
  const isGenesis = !this.applying
38
- return this.auto.system.addWriter(key, { weight, isGenesis })
37
+ const coord = this.applying
38
+ ? { key: this.applying[0].key, length: this.applying[0].length }
39
+ : null
40
+ const carrier = this.applying ? this.applying[0].weight : -1
41
+ return this.auto.system.addWriter(key, { weight, isGenesis, coord, carrier })
39
42
  }
40
43
 
41
44
  ackWriter(key) {
42
45
  if (typeof key === 'string') key = ID.decode(key)
43
- // acking an optimistic node means we owe it a linking node
44
- if (this.applying && this.applying[0].optimistic && !b4a.equals(key, this.auto.local.key)) {
45
- this.auto._ackRequired = true
46
- }
47
46
  return this.auto.system.ackWriter(key)
48
47
  }
49
48
 
@@ -0,0 +1,25 @@
1
+ module.exports = class ApplyView {
2
+ constructor(bee, auto) {
3
+ this.bee = bee
4
+ this.auto = auto
5
+ this.view = ApplyView.open(bee, auto)
6
+ }
7
+
8
+ static open(bee, auto) {
9
+ return auto._handlers.open ? auto._handlers.open(bee, auto) : bee
10
+ }
11
+
12
+ static close(view, auto) {
13
+ if (!auto._handlers.close) return Promise.resolve()
14
+ return auto._handlers.close(view)
15
+ }
16
+
17
+ apply(userBatch) {
18
+ return this.auto._handlers.apply(userBatch, this.view, this.auto._host)
19
+ }
20
+
21
+ async close() {
22
+ await ApplyView.close(this.view, this.auto)
23
+ await this.bee.close()
24
+ }
25
+ }
package/lib/boot.js CHANGED
@@ -1,20 +1,6 @@
1
- const c = require('compact-encoding')
2
1
  const b4a = require('b4a')
3
- const crypto = require('hypercore-crypto')
4
- const { AutobeeEncryption } = require('autobee-encryption')
5
- const { decodeBlock } = require('hyperbee2/lib/encoding.js')
6
-
7
2
  const encoding = require('./encoding.js')
8
- const { assert, bail } = require('./asserts.js')
9
-
10
- const { getEncoding } = require('../encoding/spec/autobee')
11
-
12
- const SystemInfoV1 = getEncoding('@autobase-compat/info-v1')
13
- const SystemInfoV2 = getEncoding('@autobase-compat/info-v2')
14
-
15
- const EMPTY = b4a.alloc(0)
16
- const INDEX_VERSION = 1
17
- const [NS_SIGNER_NAMESPACE] = crypto.namespace('autobase', 1)
3
+ const { checkAutobaseMigration } = require('./migrations.js')
18
4
 
19
5
  module.exports = async function boot(
20
6
  corestore,
@@ -109,7 +95,7 @@ module.exports = async function boot(
109
95
  await result.bootstrap.setUserData('autobee/local', result.local.key)
110
96
  await result.local.setUserData('referrer', result.key)
111
97
 
112
- result.migration = await checkAutobaseMigration(
98
+ result.migration = await migrateWithFallback(
113
99
  corestore,
114
100
  result.local,
115
101
  result.bootstrap,
@@ -153,59 +139,20 @@ module.exports = async function boot(
153
139
  return result
154
140
  }
155
141
 
156
- async function checkAutobaseMigration(store, local, bootstrap, legacyViews) {
157
- const bootRecord = await local.getUserData('autobase/boot')
158
- if (!bootRecord) return null
159
-
160
- const { key } = encoding.decodeAutobaseBootRecord(bootRecord)
161
- const core = store.get({ key: key, encryption: null })
162
- await core.ready()
163
-
164
- const system = { key, length: core.length }
165
-
166
- // setup encryption
167
- const encryptionKey = await local.getUserData('autobase/encryption')
168
- await AutobeeEncryption.setSystemEncryption(bootstrap.key, encryptionKey, core)
169
-
170
- const catchup = await getCatchupHeads(core)
171
- const nodes = await Promise.all(
172
- catchup.map((n) => getWriterBatch(store, n, bootstrap.key, encryptionKey))
173
- )
142
+ // the bootstrap pointer names the rotated-to writer, whose legacy boot record
143
+ // can be unusable. the namespace local still carries the pre-rotation record,
144
+ // which points at the last system core that was actually signed
145
+ async function migrateWithFallback(corestore, local, bootstrap, legacyViews) {
146
+ try {
147
+ return await checkAutobaseMigration(corestore, local, bootstrap, legacyViews)
148
+ } catch (err) {
149
+ const prev = corestore.get({ name: 'local', active: false })
150
+ await prev.ready()
174
151
 
175
- // Decode hyperbee block using hyperbee2 compat
176
- const node = decodeBlock(await core.get(core.length - 1))
177
- assert(node.keys.length > 0, 'bad system block')
152
+ if (b4a.equals(prev.key, local.key)) throw err
153
+ if (!(await prev.getUserData('autobase/boot'))) throw err
178
154
 
179
- // Decode system info from hyperbee block using autobee compat
180
- const info = decodeLegacySystemInfo(node.keys[0].value)
181
-
182
- const indexerManifests = await Promise.all(
183
- info.indexers.map((idx) => getCoreManifest(store, idx.key))
184
- )
185
- const views = await Promise.all(info.views.map((v) => getPersistedView(store, v)))
186
- const entropy =
187
- info.version > 1 && info.entropy ? info.entropy : indexerManifests[0].signers[0].namespace
188
-
189
- const mappedViews = new Map()
190
- for (const name of legacyViews) {
191
- const v = await findViewByName(
192
- store,
193
- bootstrap.key,
194
- encryptionKey,
195
- indexerManifests,
196
- views,
197
- entropy,
198
- name
199
- )
200
-
201
- mappedViews.set(name, v)
202
- }
203
-
204
- return {
205
- encryptionKey,
206
- system,
207
- views: mappedViews,
208
- catchup: nodes
155
+ return checkAutobaseMigration(corestore, prev, bootstrap, legacyViews)
209
156
  }
210
157
  }
211
158
 
@@ -218,118 +165,3 @@ async function getLocalKey(bootstrap) {
218
165
  if (current) return current
219
166
  return legacy
220
167
  }
221
-
222
- async function getPersistedView(store, view) {
223
- const core = store.get(view.key)
224
- await core.ready()
225
-
226
- const length = core.length
227
- await core.close()
228
-
229
- return { key: view.key, length }
230
- }
231
-
232
- async function getCatchupHeads(core) {
233
- const session = core.session({ name: 'batch' })
234
- await session.ready()
235
-
236
- const nodes = []
237
- for (let i = core.length; i < session.length; i++) {
238
- const node = await session.get(i, { wait: false })
239
- if (!node) throw new Error('Expect nodes to exist locally')
240
-
241
- const entry = decodeBlock(node).keys[0]
242
- if (entry.key[0] !== 0x01) continue
243
-
244
- const { key, length } = encoding.decodeSystemWriter(entry.key, entry.value)
245
- nodes.push({ key, length })
246
- }
247
-
248
- return nodes
249
- }
250
-
251
- async function getWriterBatch(store, head, key, encryptionKey, nodes = []) {
252
- const batch = []
253
-
254
- const core = store.get(head.key)
255
- await core.ready()
256
-
257
- await core.setEncryption(AutobeeEncryption.getWriterEncryption(key, encryptionKey))
258
-
259
- let seq = head.length - 1
260
- const block = await core.get(seq--, { wait: false })
261
- if (!block) throw new Error('Expect writer node to exist locally')
262
-
263
- const node = encoding.decodeOplog(block)
264
-
265
- batch.unshift({ ...head, ...node, from: core })
266
-
267
- while (seq >= 0) {
268
- const block = await core.get(seq--, { wait: false })
269
- if (!block) break
270
-
271
- const node = encoding.decodeOplog(block)
272
- if (!node.batch.end) break
273
-
274
- batch.unshift({ key: head.key, length: seq + 2, from: core, ...node })
275
- }
276
-
277
- return batch
278
- }
279
-
280
- async function getCoreManifest(store, key) {
281
- const core = store.get(key)
282
- await core.ready()
283
-
284
- const manifest = core.manifest
285
- await core.close()
286
-
287
- return manifest
288
- }
289
-
290
- function decodeLegacySystemInfo(buffer) {
291
- const state = { start: 0, end: buffer.length, buffer }
292
- const version = c.uint.decode(state)
293
-
294
- state.start--
295
-
296
- switch (version) {
297
- case 1:
298
- return SystemInfoV1.decode(state)
299
- case 2:
300
- return SystemInfoV2.decode(state)
301
- default:
302
- bail('Expected legacy system info')
303
- }
304
- }
305
-
306
- function deriveNamespace(name, bootstrap, entropy, encryptionKey) {
307
- const encryptionId = crypto.hash(encryptionKey || EMPTY)
308
- const version = c.encode(c.uint, INDEX_VERSION)
309
-
310
- return crypto.hash([
311
- NS_SIGNER_NAMESPACE,
312
- version,
313
- bootstrap,
314
- encryptionId,
315
- entropy,
316
- b4a.from(name)
317
- ])
318
- }
319
-
320
- async function findViewByName(store, key, encryptionKey, indexerManifests, views, entropy, name) {
321
- if (indexerManifests.length === 0) return null
322
-
323
- const namespace = deriveNamespace(name, key, entropy, encryptionKey)
324
-
325
- for (const v of views) {
326
- const manifest = await getCoreManifest(store, v.key)
327
- if (manifest.signers.length === 0) continue
328
-
329
- const signer = manifest.signers[0]
330
-
331
- if (b4a.equals(signer.namespace, namespace)) return v
332
- }
333
-
334
- return null
335
- }
package/lib/constants.js CHANGED
@@ -1,16 +1,13 @@
1
- const crypto = require('hypercore-crypto')
2
-
3
1
  const LEGACY_OPLOG_VERSION = 2
4
- const OPLOG_VERSION = 3
2
+ const OPLOG_VERSION = 4
5
3
  const LEGACY_AUTOBASE_VERSION = 2
6
4
  const AUTOBEE_VERSION = 3
7
-
8
- const [NS_WITNESS] = crypto.namespace('autobee-witness', 1)
5
+ const DEFAULT_OP_TIMEOUT = 5000
9
6
 
10
7
  module.exports = {
11
8
  LEGACY_OPLOG_VERSION,
12
9
  OPLOG_VERSION,
13
10
  LEGACY_AUTOBASE_VERSION,
14
11
  AUTOBEE_VERSION,
15
- NS_WITNESS
12
+ DEFAULT_OP_TIMEOUT
16
13
  }
package/lib/encoding.js CHANGED
@@ -12,6 +12,7 @@ const SystemInfo = getEncoding('@autobee/system-info')
12
12
  const SystemWriter = getEncoding('@autobee/system-writer')
13
13
  const ManifestData = getEncoding('@autobee/manifest-data')
14
14
  const AutobaseBootRecord = getEncoding('@autobase-compat/boot-record')
15
+ const MigratedHead = getEncoding('@autobee/migrated-head')
15
16
 
16
17
  exports.OPLOG_VERSION = OPLOG_VERSION
17
18
 
@@ -21,13 +22,23 @@ exports.ManifestData = ManifestData
21
22
  exports.encodeBootRecord = encodeBootRecord
22
23
  exports.decodeBootRecord = decodeBootRecord
23
24
 
25
+ exports.encodeMigratedHead = encodeMigratedHead
26
+ exports.decodeMigratedHead = decodeMigratedHead
27
+
24
28
  exports.encodePreviousDrain = encodePreviousDrain
25
29
  exports.decodePreviousDrain = decodePreviousDrain
26
30
 
27
31
  exports.decodeAutobaseBootRecord = decodeAutobaseBootRecord
28
32
 
33
+ exports.encodeSystemGrantKey = encodeSystemGrantKey
34
+ exports.encodeSystemGrantHint = encodeSystemGrantHint
35
+ exports.decodeSystemGrantHint = decodeSystemGrantHint
36
+ exports.encodeSystemPendingKey = encodeSystemPendingKey
37
+ exports.decodeSystemPendingKey = decodeSystemPendingKey
38
+ exports.encodeSystemPendingRange = encodeSystemPendingRange
39
+ exports.encodeSystemPending = encodeSystemPending
40
+ exports.decodeSystemPending = decodeSystemPending
29
41
  exports.encodeSystemWriterKey = encodeSystemWriterKey
30
- exports.encodeSystemIndexerKey = encodeSystemIndexerKey
31
42
  exports.encodeSystemWriter = encodeSystemWriter
32
43
  exports.decodeSystemWriter = decodeSystemWriter
33
44
 
@@ -39,6 +50,14 @@ function decodeBootRecord(value) {
39
50
  return c.decode(Link, value)
40
51
  }
41
52
 
53
+ function encodeMigratedHead(m) {
54
+ return c.encode(MigratedHead, m)
55
+ }
56
+
57
+ function decodeMigratedHead(value) {
58
+ return c.decode(MigratedHead, value)
59
+ }
60
+
42
61
  function encodePreviousDrain(d) {
43
62
  return c.encode(c.uint, d)
44
63
  }
@@ -59,13 +78,57 @@ function encodeSystemWriterKey(key) {
59
78
  return buf
60
79
  }
61
80
 
62
- function encodeSystemIndexerKey(key) {
81
+ function encodeSystemPendingKey(key) {
82
+ const buf = b4a.allocUnsafe(33)
83
+ buf[0] = 5
84
+ buf.set(key, 1)
85
+ return buf
86
+ }
87
+
88
+ function decodeSystemPendingKey(buf) {
89
+ return buf.subarray(1, 33)
90
+ }
91
+
92
+ function encodeSystemPendingRange() {
93
+ return { gte: b4a.from([5]), lt: b4a.from([6]) }
94
+ }
95
+
96
+ function encodeSystemPending(entry) {
97
+ return c.encode(c.uint, entry.weight)
98
+ }
99
+
100
+ function decodeSystemPending(value) {
101
+ return { weight: c.decode(c.uint, value) }
102
+ }
103
+
104
+ function encodeSystemGrantKey(key) {
63
105
  const buf = b4a.allocUnsafe(33)
64
- buf[0] = 2
106
+ buf[0] = 4
65
107
  buf.set(key, 1)
66
108
  return buf
67
109
  }
68
110
 
111
+ function encodeSystemGrantHint(hint) {
112
+ const state = { start: 0, end: 0, buffer: null }
113
+ c.fixed32.preencode(state, hint.key)
114
+ c.uint.preencode(state, hint.length)
115
+ c.uint.preencode(state, hint.weight)
116
+ state.buffer = b4a.alloc(state.end)
117
+ c.fixed32.encode(state, hint.key)
118
+ c.uint.encode(state, hint.length)
119
+ c.uint.encode(state, hint.weight)
120
+ return state.buffer
121
+ }
122
+
123
+ function decodeSystemGrantHint(value) {
124
+ const state = { start: 0, end: value.byteLength, buffer: value }
125
+ return {
126
+ key: c.fixed32.decode(state),
127
+ length: c.uint.decode(state),
128
+ weight: c.uint.decode(state)
129
+ }
130
+ }
131
+
69
132
  function encodeSystemWriter(m) {
70
133
  return c.encode(SystemWriter, m)
71
134
  }
@@ -107,6 +170,9 @@ function decodeOplog(buf) {
107
170
  links: m.node.heads,
108
171
  batch: { start: 0, end: m.node.batch - 1 },
109
172
  views: null,
173
+ trusted: null,
174
+ witness: null,
175
+ approvals: null,
110
176
  optimistic: !!m.optimistic,
111
177
  value: m.node.value
112
178
  }
@@ -153,6 +219,9 @@ function createValue(value, opts = {}) {
153
219
  links,
154
220
  batch: null,
155
221
  views,
222
+ trusted: null,
223
+ witness: null,
224
+ approvals: null,
156
225
  optimistic,
157
226
  value
158
227
  }