autobee 2.0.0-rc.22 → 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 +23 -47
- package/lib/boot.js +1 -192
- package/lib/fast-forward.js +61 -123
- package/package.json +1 -1
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
|
|
@@ -504,9 +510,20 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
504
510
|
this.emit('error', err)
|
|
505
511
|
}
|
|
506
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
|
+
|
|
507
522
|
async _drain() {
|
|
508
523
|
if (this._updating) await this._updating
|
|
509
524
|
|
|
525
|
+
await this._runPreApply()
|
|
526
|
+
|
|
510
527
|
this.stats.drains++
|
|
511
528
|
|
|
512
529
|
if (this.bootFrom) {
|
|
@@ -626,6 +643,8 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
626
643
|
const hints = await this._applyWakeupHints()
|
|
627
644
|
if (!hints.size) return
|
|
628
645
|
|
|
646
|
+
if (!this._ffEnabled) return
|
|
647
|
+
|
|
629
648
|
// a scheduled fast-forward is applied by the drain before we look again
|
|
630
649
|
if (this.fastForwardTo !== null || this.fastForwarding !== null) return
|
|
631
650
|
if (this._interrupting || this.closing || this.bootFrom) return
|
|
@@ -700,7 +719,7 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
700
719
|
// legacy nodes always inflate, but only indexers carry views - callers
|
|
701
720
|
// that need system info must check op.views
|
|
702
721
|
if (op.version < 3) {
|
|
703
|
-
op = await
|
|
722
|
+
op = await migrations.inflateLegacyOplog(buf, core, target - 1, opts)
|
|
704
723
|
}
|
|
705
724
|
|
|
706
725
|
return {
|
|
@@ -710,49 +729,6 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
710
729
|
}
|
|
711
730
|
}
|
|
712
731
|
|
|
713
|
-
async _inflateLegacyOplog(buf, core, seq, opts = null) {
|
|
714
|
-
const m = encoding.decodeRawOplog(buf)
|
|
715
|
-
|
|
716
|
-
const op = {
|
|
717
|
-
version: m.version,
|
|
718
|
-
timestamp: 0,
|
|
719
|
-
links: m.node.heads,
|
|
720
|
-
batch: { start: 0, end: m.node.batch - 1 },
|
|
721
|
-
views: null,
|
|
722
|
-
optimistic: !!m.optimistic,
|
|
723
|
-
value: m.node.value
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
if (m.digest === null || m.checkpoint === null || !m.checkpoint.system) return op
|
|
727
|
-
|
|
728
|
-
const fetches = []
|
|
729
|
-
|
|
730
|
-
fetches.push(m.digest.pointer ? core.get(seq - m.digest.pointer, opts) : buf)
|
|
731
|
-
fetches.push(
|
|
732
|
-
m.checkpoint.pointer ? core.get(seq - m.checkpoint.system.checkpointer, opts) : buf
|
|
733
|
-
)
|
|
734
|
-
|
|
735
|
-
const [digestNode, checkpointNode] = await Promise.all(fetches)
|
|
736
|
-
// a wait: false get we could not satisfy locally
|
|
737
|
-
if (digestNode === null || checkpointNode === null) return op
|
|
738
|
-
|
|
739
|
-
const { digest } = encoding.decodeRawOplog(digestNode)
|
|
740
|
-
const { checkpoint } = encoding.decodeRawOplog(checkpointNode)
|
|
741
|
-
|
|
742
|
-
if (!checkpoint.system || !checkpoint.system.checkpoint) return op
|
|
743
|
-
|
|
744
|
-
op.views = {
|
|
745
|
-
system: {
|
|
746
|
-
key: digest.key,
|
|
747
|
-
start: 0,
|
|
748
|
-
length: checkpoint.system.checkpoint.length
|
|
749
|
-
},
|
|
750
|
-
flushes: seq
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
return op
|
|
754
|
-
}
|
|
755
|
-
|
|
756
732
|
async _update(changes) {
|
|
757
733
|
this._needsUpdate = false
|
|
758
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
|
-
}
|