autobee 2.0.0-rc.21 → 2.0.0-rc.23
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/index.js +25 -50
- package/lib/boot.js +1 -192
- package/lib/fast-forward.js +61 -123
- package/lib/writers.js +9 -1
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -22,6 +22,7 @@ const { ActiveWriters } = require('./lib/writers.js')
|
|
|
22
22
|
const TrustedPeers = require('./lib/trusted.js')
|
|
23
23
|
const ApplyView = require('./lib/apply-view.js')
|
|
24
24
|
const UpdateChanges = require('./lib/updates.js')
|
|
25
|
+
const migrations = require('./lib/migrations')
|
|
25
26
|
|
|
26
27
|
const EMPTY_HEAD = { length: 0, key: null }
|
|
27
28
|
const INTERRUPT = new Error('Apply interrupted')
|
|
@@ -78,13 +79,16 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
78
79
|
this.writers = null
|
|
79
80
|
this.bumping = 0
|
|
80
81
|
|
|
81
|
-
|
|
82
|
+
// fastForward: false disables all fast-forwards - both wakeup and boot
|
|
83
|
+
const fastForward = handlers.fastForward === false ? null : handlers.fastForward || {}
|
|
84
|
+
|
|
85
|
+
this._ffEnabled = fastForward !== null
|
|
82
86
|
|
|
83
87
|
// oplog head to boot from: migrates or fast-forwards depending on its version
|
|
84
|
-
this.bootFrom = fastForward.boot || null
|
|
88
|
+
this.bootFrom = (fastForward && fastForward.boot) || null
|
|
85
89
|
|
|
86
90
|
// conservative (default on): only fast-forward onto a head someone can serve whole
|
|
87
|
-
this._conservativeFF = fastForward.conservative !== false
|
|
91
|
+
this._conservativeFF = !fastForward || fastForward.conservative !== false
|
|
88
92
|
|
|
89
93
|
this.trusted = new TrustedPeers(handlers)
|
|
90
94
|
|
|
@@ -112,6 +116,8 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
112
116
|
this._bootingAll = null
|
|
113
117
|
|
|
114
118
|
this._now = handlers.now || Date.now // overridable for clock-drift tests
|
|
119
|
+
this._preapply = handlers.preapply || null
|
|
120
|
+
this._preApplied = false
|
|
115
121
|
this._hasApply = !!handlers.apply
|
|
116
122
|
this._hasUpdate = !!handlers.update
|
|
117
123
|
this._needsUpdate = false
|
|
@@ -436,9 +442,8 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
436
442
|
async _bootAll() {
|
|
437
443
|
if (!(await this._bootReady())) return
|
|
438
444
|
|
|
439
|
-
for
|
|
440
|
-
|
|
441
|
-
await this.writers.add(node.key)
|
|
445
|
+
for (const head of this.system.heads) {
|
|
446
|
+
await this.writers.add(head.key)
|
|
442
447
|
}
|
|
443
448
|
await this._bump()
|
|
444
449
|
}
|
|
@@ -505,9 +510,20 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
505
510
|
this.emit('error', err)
|
|
506
511
|
}
|
|
507
512
|
|
|
513
|
+
// one-shot user gate: nothing applies until the host has resolved whatever
|
|
514
|
+
// state apply depends on (e.g. legacy views recorded by a migration)
|
|
515
|
+
async _runPreApply() {
|
|
516
|
+
if (this._preapply === null || this._preApplied) return
|
|
517
|
+
|
|
518
|
+
this._preApplied = true
|
|
519
|
+
await this._preapply(this.view)
|
|
520
|
+
}
|
|
521
|
+
|
|
508
522
|
async _drain() {
|
|
509
523
|
if (this._updating) await this._updating
|
|
510
524
|
|
|
525
|
+
await this._runPreApply()
|
|
526
|
+
|
|
511
527
|
this.stats.drains++
|
|
512
528
|
|
|
513
529
|
if (this.bootFrom) {
|
|
@@ -627,6 +643,8 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
627
643
|
const hints = await this._applyWakeupHints()
|
|
628
644
|
if (!hints.size) return
|
|
629
645
|
|
|
646
|
+
if (!this._ffEnabled) return
|
|
647
|
+
|
|
630
648
|
// a scheduled fast-forward is applied by the drain before we look again
|
|
631
649
|
if (this.fastForwardTo !== null || this.fastForwarding !== null) return
|
|
632
650
|
if (this._interrupting || this.closing || this.bootFrom) return
|
|
@@ -701,7 +719,7 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
701
719
|
// legacy nodes always inflate, but only indexers carry views - callers
|
|
702
720
|
// that need system info must check op.views
|
|
703
721
|
if (op.version < 3) {
|
|
704
|
-
op = await
|
|
722
|
+
op = await migrations.inflateLegacyOplog(buf, core, target - 1, opts)
|
|
705
723
|
}
|
|
706
724
|
|
|
707
725
|
return {
|
|
@@ -711,49 +729,6 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
711
729
|
}
|
|
712
730
|
}
|
|
713
731
|
|
|
714
|
-
async _inflateLegacyOplog(buf, core, seq, opts = null) {
|
|
715
|
-
const m = encoding.decodeRawOplog(buf)
|
|
716
|
-
|
|
717
|
-
const op = {
|
|
718
|
-
version: m.version,
|
|
719
|
-
timestamp: 0,
|
|
720
|
-
links: m.node.heads,
|
|
721
|
-
batch: { start: 0, end: m.node.batch - 1 },
|
|
722
|
-
views: null,
|
|
723
|
-
optimistic: !!m.optimistic,
|
|
724
|
-
value: m.node.value
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
if (m.digest === null || m.checkpoint === null || !m.checkpoint.system) return op
|
|
728
|
-
|
|
729
|
-
const fetches = []
|
|
730
|
-
|
|
731
|
-
fetches.push(m.digest.pointer ? core.get(seq - m.digest.pointer, opts) : buf)
|
|
732
|
-
fetches.push(
|
|
733
|
-
m.checkpoint.pointer ? core.get(seq - m.checkpoint.system.checkpointer, opts) : buf
|
|
734
|
-
)
|
|
735
|
-
|
|
736
|
-
const [digestNode, checkpointNode] = await Promise.all(fetches)
|
|
737
|
-
// a wait: false get we could not satisfy locally
|
|
738
|
-
if (digestNode === null || checkpointNode === null) return op
|
|
739
|
-
|
|
740
|
-
const { digest } = encoding.decodeRawOplog(digestNode)
|
|
741
|
-
const { checkpoint } = encoding.decodeRawOplog(checkpointNode)
|
|
742
|
-
|
|
743
|
-
if (!checkpoint.system || !checkpoint.system.checkpoint) return op
|
|
744
|
-
|
|
745
|
-
op.views = {
|
|
746
|
-
system: {
|
|
747
|
-
key: digest.key,
|
|
748
|
-
start: 0,
|
|
749
|
-
length: checkpoint.system.checkpoint.length
|
|
750
|
-
},
|
|
751
|
-
flushes: seq
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
return op
|
|
755
|
-
}
|
|
756
|
-
|
|
757
732
|
async _update(changes) {
|
|
758
733
|
this._needsUpdate = false
|
|
759
734
|
this.bee.update(this._workingBee.root)
|
package/lib/boot.js
CHANGED
|
@@ -1,20 +1,5 @@
|
|
|
1
|
-
const c = require('compact-encoding')
|
|
2
|
-
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
1
|
const encoding = require('./encoding.js')
|
|
8
|
-
const {
|
|
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)
|
|
2
|
+
const { checkAutobaseMigration } = require('./migrations')
|
|
18
3
|
|
|
19
4
|
module.exports = async function boot(
|
|
20
5
|
corestore,
|
|
@@ -153,64 +138,6 @@ module.exports = async function boot(
|
|
|
153
138
|
return result
|
|
154
139
|
}
|
|
155
140
|
|
|
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
|
-
)
|
|
174
|
-
|
|
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')
|
|
178
|
-
|
|
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
|
-
await core.close()
|
|
205
|
-
|
|
206
|
-
return {
|
|
207
|
-
encryptionKey,
|
|
208
|
-
system,
|
|
209
|
-
views: mappedViews,
|
|
210
|
-
catchup: nodes
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
141
|
async function getLocalKey(bootstrap) {
|
|
215
142
|
const [legacy, current] = await Promise.all([
|
|
216
143
|
bootstrap.getUserData('autobase/local'),
|
|
@@ -220,121 +147,3 @@ async function getLocalKey(bootstrap) {
|
|
|
220
147
|
if (current) return current
|
|
221
148
|
return legacy
|
|
222
149
|
}
|
|
223
|
-
|
|
224
|
-
async function getPersistedView(store, view) {
|
|
225
|
-
const core = store.get(view.key)
|
|
226
|
-
await core.ready()
|
|
227
|
-
|
|
228
|
-
const length = core.length
|
|
229
|
-
await core.close()
|
|
230
|
-
|
|
231
|
-
return { key: view.key, length }
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
async function getCatchupHeads(core) {
|
|
235
|
-
const session = core.session({ name: 'batch' })
|
|
236
|
-
await session.ready()
|
|
237
|
-
|
|
238
|
-
const nodes = []
|
|
239
|
-
for (let i = core.length; i < session.length; i++) {
|
|
240
|
-
const node = await session.get(i, { wait: false })
|
|
241
|
-
if (!node) throw new Error('Expect nodes to exist locally')
|
|
242
|
-
|
|
243
|
-
const entry = decodeBlock(node).keys[0]
|
|
244
|
-
if (entry.key[0] !== 0x01) continue
|
|
245
|
-
|
|
246
|
-
const { key, length } = encoding.decodeSystemWriter(entry.key, entry.value)
|
|
247
|
-
if (!length) continue
|
|
248
|
-
nodes.push({ key, length })
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
return nodes
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
async function getWriterBatch(store, head, key, encryptionKey, nodes = []) {
|
|
255
|
-
const batch = []
|
|
256
|
-
|
|
257
|
-
const core = store.get(head.key)
|
|
258
|
-
await core.ready()
|
|
259
|
-
|
|
260
|
-
if (encryptionKey) {
|
|
261
|
-
await core.setEncryption(AutobeeEncryption.getWriterEncryption(key, encryptionKey))
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
let seq = head.length - 1
|
|
265
|
-
const block = await core.get(seq--, { wait: false })
|
|
266
|
-
if (!block) throw new Error('Expect writer node to exist locally')
|
|
267
|
-
|
|
268
|
-
const node = encoding.decodeOplog(block)
|
|
269
|
-
|
|
270
|
-
batch.unshift({ ...head, ...node, from: core })
|
|
271
|
-
|
|
272
|
-
while (seq >= 0) {
|
|
273
|
-
const block = await core.get(seq--, { wait: false })
|
|
274
|
-
if (!block) break
|
|
275
|
-
|
|
276
|
-
const node = encoding.decodeOplog(block)
|
|
277
|
-
if (!node.batch.end) break
|
|
278
|
-
|
|
279
|
-
batch.unshift({ key: head.key, length: seq + 2, from: core, ...node })
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
return batch
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
async function getCoreManifest(store, key) {
|
|
286
|
-
const core = store.get(key)
|
|
287
|
-
await core.ready()
|
|
288
|
-
|
|
289
|
-
const manifest = core.manifest
|
|
290
|
-
await core.close()
|
|
291
|
-
|
|
292
|
-
return manifest
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
function decodeLegacySystemInfo(buffer) {
|
|
296
|
-
const state = { start: 0, end: buffer.length, buffer }
|
|
297
|
-
const version = c.uint.decode(state)
|
|
298
|
-
|
|
299
|
-
state.start--
|
|
300
|
-
|
|
301
|
-
switch (version) {
|
|
302
|
-
case 1:
|
|
303
|
-
return SystemInfoV1.decode(state)
|
|
304
|
-
case 2:
|
|
305
|
-
return SystemInfoV2.decode(state)
|
|
306
|
-
default:
|
|
307
|
-
bail('Expected legacy system info')
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
function deriveNamespace(name, bootstrap, entropy, encryptionKey) {
|
|
312
|
-
const encryptionId = crypto.hash(encryptionKey || EMPTY)
|
|
313
|
-
const version = c.encode(c.uint, INDEX_VERSION)
|
|
314
|
-
|
|
315
|
-
return crypto.hash([
|
|
316
|
-
NS_SIGNER_NAMESPACE,
|
|
317
|
-
version,
|
|
318
|
-
bootstrap,
|
|
319
|
-
encryptionId,
|
|
320
|
-
entropy,
|
|
321
|
-
b4a.from(name)
|
|
322
|
-
])
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
async function findViewByName(store, key, encryptionKey, indexerManifests, views, entropy, name) {
|
|
326
|
-
if (indexerManifests.length === 0) return null
|
|
327
|
-
|
|
328
|
-
const namespace = deriveNamespace(name, key, entropy, encryptionKey)
|
|
329
|
-
|
|
330
|
-
for (const v of views) {
|
|
331
|
-
const manifest = await getCoreManifest(store, v.key)
|
|
332
|
-
if (manifest.signers.length === 0) continue
|
|
333
|
-
|
|
334
|
-
const signer = manifest.signers[0]
|
|
335
|
-
|
|
336
|
-
if (b4a.equals(signer.namespace, namespace)) return v
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
return null
|
|
340
|
-
}
|
package/lib/fast-forward.js
CHANGED
|
@@ -1,23 +1,11 @@
|
|
|
1
1
|
const safetyCatch = require('safety-catch')
|
|
2
2
|
const b4a = require('b4a')
|
|
3
3
|
const Hypercore = require('hypercore')
|
|
4
|
-
const c = require('compact-encoding')
|
|
5
|
-
const crypto = require('hypercore-crypto')
|
|
6
|
-
|
|
7
|
-
const { decodeBlock } = require('hyperbee2/lib/encoding.js')
|
|
8
4
|
|
|
9
5
|
const System = require('./system.js')
|
|
10
|
-
const
|
|
6
|
+
const migrations = require('./migrations')
|
|
11
7
|
const { LEGACY_AUTOBASE_VERSION } = require('./constants.js')
|
|
12
|
-
const { getEncoding } = require('../encoding/spec/autobee')
|
|
13
|
-
|
|
14
|
-
const SystemInfoV1 = getEncoding('@autobase-compat/info-v1')
|
|
15
|
-
const SystemInfoV2 = getEncoding('@autobase-compat/info-v2')
|
|
16
8
|
|
|
17
|
-
const INDEX_VERSION = 1
|
|
18
|
-
const [NS_SIGNER_NAMESPACE] = crypto.namespace('autobase', 1)
|
|
19
|
-
|
|
20
|
-
const EMPTY = b4a.alloc(0)
|
|
21
9
|
const DEFAULT_OP_TIMEOUT = 5_000
|
|
22
10
|
const MIN_FF_GAP = 32
|
|
23
11
|
|
|
@@ -243,7 +231,25 @@ module.exports = class FastForward {
|
|
|
243
231
|
return null
|
|
244
232
|
}
|
|
245
233
|
|
|
246
|
-
|
|
234
|
+
const result = await this._migrate()
|
|
235
|
+
if (result === null || result.autobee === null) return result
|
|
236
|
+
|
|
237
|
+
// an indexer of the newest legacy generation already moved to autobee -
|
|
238
|
+
// fast-forward straight onto its announced head instead of migrating,
|
|
239
|
+
// falling back to the legacy migration if the head cannot be booted
|
|
240
|
+
try {
|
|
241
|
+
this.head = result.autobee
|
|
242
|
+
await this.system.boot(this.head, { timeout: this.timeout })
|
|
243
|
+
if (this.system.version <= LEGACY_AUTOBASE_VERSION) {
|
|
244
|
+
throw new Error('Expected an autobee system')
|
|
245
|
+
}
|
|
246
|
+
} catch (err) {
|
|
247
|
+
safetyCatch(err)
|
|
248
|
+
this.head = result.head
|
|
249
|
+
return { head: result.head, tip: null, migrate: result.migrate }
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// fall through to the plain fast-forward below
|
|
247
253
|
}
|
|
248
254
|
|
|
249
255
|
const promises = []
|
|
@@ -280,47 +286,58 @@ module.exports = class FastForward {
|
|
|
280
286
|
// Upgrade a legacy (pre-AUTOBEE_VERSION) system in place. The system already
|
|
281
287
|
// booted above (coerced to the current struct), but the original v1/v2 struct
|
|
282
288
|
// is needed to recover the indexers/views/entropy, so decode the raw block.
|
|
289
|
+
//
|
|
290
|
+
// A head may be arbitrarily old: an indexer rotation freezes the system core
|
|
291
|
+
// and moves the indexers to a successor. The frozen core cannot reveal its
|
|
292
|
+
// successor (the promotion only lands in its unsigned tail), but the
|
|
293
|
+
// indexers' newest oplog digests stamp the newest system they know - chase
|
|
294
|
+
// those so the migration lands on the newest generation instead of the head
|
|
295
|
+
// we were given.
|
|
283
296
|
async _migrate() {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
await core.ready()
|
|
297
|
+
let head = { key: this.head.key, length: this.head.length }
|
|
298
|
+
const seen = new Set()
|
|
287
299
|
|
|
288
|
-
|
|
289
|
-
|
|
300
|
+
for (let hops = 0; hops < migrations.MAX_MIGRATE_HOPS; hops++) {
|
|
301
|
+
seen.add(b4a.toString(head.key, 'hex'))
|
|
290
302
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
await core.
|
|
303
|
+
const core = this.auto.store.get({ key: head.key, encryption: null })
|
|
304
|
+
this.cores.push(core)
|
|
305
|
+
await core.ready()
|
|
306
|
+
|
|
307
|
+
// setup encryption
|
|
308
|
+
await core.setEncryption(this.auto.getSystemEncryption())
|
|
309
|
+
|
|
310
|
+
// successors are resolved by key only - wait for the replicated length
|
|
311
|
+
if (!head.length) head.length = await migrations.coreLength(core, this.timeout)
|
|
312
|
+
if (!head.length || this.destroyed) return null
|
|
313
|
+
|
|
314
|
+
const info = await migrations.readLegacySystemInfo(core, head.length, {
|
|
294
315
|
timeout: this.timeout,
|
|
295
316
|
activeRequests: this.activeRequests
|
|
296
317
|
})
|
|
297
|
-
)
|
|
298
|
-
assert(node.keys.length > 0, 'bad system block')
|
|
299
|
-
|
|
300
|
-
// Decode system info from hyperbee block using autobee compat
|
|
301
|
-
const info = decodeLegacySystemInfo(node.keys[0].value)
|
|
302
318
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
)
|
|
306
|
-
const entropy =
|
|
307
|
-
info.version > 1 && info.entropy ? info.entropy : indexerManifests[0].signers[0].namespace
|
|
319
|
+
const { legacy, autobee } = await migrations.findNewestSystem(this, info)
|
|
320
|
+
if (this.destroyed) return null
|
|
308
321
|
|
|
309
|
-
|
|
310
|
-
|
|
322
|
+
if (legacy !== null && !seen.has(b4a.toString(legacy, 'hex'))) {
|
|
323
|
+
head = { key: legacy, length: 0 }
|
|
324
|
+
continue
|
|
325
|
+
}
|
|
311
326
|
|
|
312
|
-
|
|
313
|
-
viewProms.push(this.findViewByName(views, indexerManifests, info.views, entropy, name))
|
|
314
|
-
}
|
|
327
|
+
this.head = head
|
|
315
328
|
|
|
316
|
-
|
|
317
|
-
|
|
329
|
+
const views = await migrations.resolveLegacyViews(this, info)
|
|
330
|
+
if (views === null || this.destroyed) return null
|
|
318
331
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
332
|
+
return {
|
|
333
|
+
head,
|
|
334
|
+
tip: null,
|
|
335
|
+
migrate: views,
|
|
336
|
+
autobee: autobee === null ? null : batchToHead(autobee.op.views.system)
|
|
337
|
+
}
|
|
323
338
|
}
|
|
339
|
+
|
|
340
|
+
return null
|
|
324
341
|
}
|
|
325
342
|
|
|
326
343
|
async _resolveLength() {
|
|
@@ -329,47 +346,7 @@ module.exports = class FastForward {
|
|
|
329
346
|
|
|
330
347
|
await core.ready()
|
|
331
348
|
|
|
332
|
-
return coreLength(core, this.timeout)
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
async getCoreManifest(key, length) {
|
|
336
|
-
const core = this.auto.store.get(key)
|
|
337
|
-
this.cores.push(core)
|
|
338
|
-
|
|
339
|
-
await core.ready()
|
|
340
|
-
|
|
341
|
-
try {
|
|
342
|
-
if (!core.manifest) {
|
|
343
|
-
await core.get(length - 1, {
|
|
344
|
-
timeout: this.timeout,
|
|
345
|
-
activeRequests: this.activeRequests
|
|
346
|
-
})
|
|
347
|
-
}
|
|
348
|
-
} catch {
|
|
349
|
-
return null
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
return core.manifest
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
async findViewByName(result, indexerManifests, views, entropy, name) {
|
|
356
|
-
if (indexerManifests.length === 0) return null
|
|
357
|
-
|
|
358
|
-
const namespace = deriveNamespace(name, this.auto.key, entropy, this.auto.encryptionKey)
|
|
359
|
-
|
|
360
|
-
for (const v of views) {
|
|
361
|
-
const manifest = await this.getCoreManifest(v.key, v.length)
|
|
362
|
-
if (!manifest) continue
|
|
363
|
-
|
|
364
|
-
if (manifest.signers.length === 0) continue
|
|
365
|
-
|
|
366
|
-
const signer = manifest.signers[0]
|
|
367
|
-
|
|
368
|
-
if (b4a.equals(signer.namespace, namespace)) {
|
|
369
|
-
result.set(name, v)
|
|
370
|
-
return
|
|
371
|
-
}
|
|
372
|
-
}
|
|
349
|
+
return migrations.coreLength(core, this.timeout)
|
|
373
350
|
}
|
|
374
351
|
|
|
375
352
|
// cancels every read in flight and fails any that come after
|
|
@@ -391,42 +368,3 @@ function batchToHead(b) {
|
|
|
391
368
|
length: b.start + b.length
|
|
392
369
|
}
|
|
393
370
|
}
|
|
394
|
-
|
|
395
|
-
function decodeLegacySystemInfo(buffer) {
|
|
396
|
-
const state = { start: 0, end: buffer.length, buffer }
|
|
397
|
-
const version = c.uint.decode(state)
|
|
398
|
-
|
|
399
|
-
state.start--
|
|
400
|
-
|
|
401
|
-
switch (version) {
|
|
402
|
-
case 1:
|
|
403
|
-
return SystemInfoV1.decode(state)
|
|
404
|
-
case 2:
|
|
405
|
-
return SystemInfoV2.decode(state)
|
|
406
|
-
default:
|
|
407
|
-
return { version }
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
function coreLength(core, timeout) {
|
|
412
|
-
if (core.length) return core.length
|
|
413
|
-
|
|
414
|
-
return new Promise((resolve) => {
|
|
415
|
-
core.on('append', () => resolve(core.length))
|
|
416
|
-
setTimeout(resolve, timeout, 0)
|
|
417
|
-
})
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
function deriveNamespace(name, bootstrap, entropy, encryptionKey) {
|
|
421
|
-
const encryptionId = crypto.hash(encryptionKey || EMPTY)
|
|
422
|
-
const version = c.encode(c.uint, INDEX_VERSION)
|
|
423
|
-
|
|
424
|
-
return crypto.hash([
|
|
425
|
-
NS_SIGNER_NAMESPACE,
|
|
426
|
-
version,
|
|
427
|
-
bootstrap,
|
|
428
|
-
encryptionId,
|
|
429
|
-
entropy,
|
|
430
|
-
b4a.from(name)
|
|
431
|
-
])
|
|
432
|
-
}
|
package/lib/writers.js
CHANGED
|
@@ -633,7 +633,15 @@ class Writer {
|
|
|
633
633
|
const promises = new Array(links.length)
|
|
634
634
|
|
|
635
635
|
for (let i = 0; i < links.length; i++) {
|
|
636
|
-
|
|
636
|
+
const link = links[i]
|
|
637
|
+
|
|
638
|
+
// legacy batch nodes link their own previous node, satisfied by oplog order
|
|
639
|
+
if (link.length < node.length && b4a.equals(link.key, this.core.key)) {
|
|
640
|
+
promises[i] = true
|
|
641
|
+
continue
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
promises[i] = this.system.has(link)
|
|
637
645
|
}
|
|
638
646
|
|
|
639
647
|
const has = await Promise.all(promises)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autobee",
|
|
3
|
-
"version": "2.0.0-rc.
|
|
3
|
+
"version": "2.0.0-rc.23",
|
|
4
4
|
"description": "Bee based autobase",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Holepunch Inc.",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"brittle": "^4.1.0",
|
|
41
|
-
"corestore": "^7.
|
|
41
|
+
"corestore": "^7.12.2",
|
|
42
42
|
"hypercore-crypto": "^3.6.1",
|
|
43
43
|
"lunte": "^1.6.0",
|
|
44
44
|
"prettier": "^3.8.1",
|