hypercore 10.0.0-alpha.7 → 10.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.
package/lib/errors.js ADDED
@@ -0,0 +1,50 @@
1
+ module.exports = class HypercoreError extends Error {
2
+ constructor (msg, code, fn = HypercoreError) {
3
+ super(`${code}: ${msg}`)
4
+ this.code = code
5
+
6
+ if (Error.captureStackTrace) {
7
+ Error.captureStackTrace(this, fn)
8
+ }
9
+ }
10
+
11
+ get name () {
12
+ return 'HypercoreError'
13
+ }
14
+
15
+ static BAD_ARGUMENT (msg) {
16
+ return new HypercoreError(msg, 'BAD_ARGUMENT', HypercoreError.BAD_ARGUMENT)
17
+ }
18
+
19
+ static STORAGE_EMPTY (msg) {
20
+ return new HypercoreError(msg, 'STORAGE_EMPTY', HypercoreError.STORAGE_EMPTY)
21
+ }
22
+
23
+ static STORAGE_CONFLICT (msg) {
24
+ return new HypercoreError(msg, 'STORAGE_CONFLICT', HypercoreError.STORAGE_CONFLICT)
25
+ }
26
+
27
+ static INVALID_SIGNATURE (msg) {
28
+ return new HypercoreError(msg, 'INVALID_SIGNATURE', HypercoreError.INVALID_SIGNATURE)
29
+ }
30
+
31
+ static INVALID_CAPABILITY (msg) {
32
+ return new HypercoreError(msg, 'INVALID_CAPABILITY', HypercoreError.INVALID_CAPABILITY)
33
+ }
34
+
35
+ static SNAPSHOT_NOT_AVAILABLE (msg = 'Snapshot is not available') {
36
+ return new HypercoreError(msg, 'SNAPSHOT_NOT_AVAILABLE', HypercoreError.SNAPSHOT_NOT_AVAILABLE)
37
+ }
38
+
39
+ static REQUEST_CANCELLED (msg = 'Request was cancelled') {
40
+ return new HypercoreError(msg, 'REQUEST_CANCELLED', HypercoreError.REQUEST_CANCELLED)
41
+ }
42
+
43
+ static SESSION_NOT_WRITABLE (msg = 'Session is not writable') {
44
+ return new HypercoreError(msg, 'SESSION_NOT_WRITABLE', HypercoreError.SESSION_NOT_WRITABLE)
45
+ }
46
+
47
+ static SESSION_CLOSED (msg = 'Session is closed') {
48
+ return new HypercoreError(msg, 'SESSION_CLOSED', HypercoreError.SESSION_CLOSED)
49
+ }
50
+ }
package/lib/info.js ADDED
@@ -0,0 +1,23 @@
1
+ module.exports = class Info {
2
+ constructor (opts = {}) {
3
+ this.length = opts.length || 0
4
+ this.contiguousLength = opts.contiguousLength || 0
5
+ this.byteLength = opts.byteLength || 0
6
+ this.padding = opts.padding || 0
7
+ }
8
+
9
+ static async from (core, padding, snapshot) {
10
+ return new Info({
11
+ key: core.key,
12
+ length: snapshot
13
+ ? snapshot.length
14
+ : core.tree.length,
15
+ contiguousLength: core.header.contiguousLength,
16
+ byteLength: snapshot
17
+ ? snapshot.byteLength
18
+ : (core.tree.byteLength - (core.tree.length * padding)),
19
+ fork: core.tree.fork,
20
+ padding
21
+ })
22
+ }
23
+ }
@@ -1,9 +1,13 @@
1
1
  const flat = require('flat-tree')
2
2
  const crypto = require('hypercore-crypto')
3
- const uint64le = require('uint64le')
3
+ const c = require('compact-encoding')
4
+ const Xache = require('xache')
5
+ const b4a = require('b4a')
6
+ const caps = require('./caps')
4
7
 
5
- const BLANK_HASH = Buffer.alloc(32)
6
- const OLD_TREE = Buffer.from([5, 2, 87, 2, 0, 0, 40, 7, 66, 76, 65, 75, 69, 50, 98])
8
+ const BLANK_HASH = b4a.alloc(32)
9
+ const OLD_TREE = b4a.from([5, 2, 87, 2, 0, 0, 40, 7, 66, 76, 65, 75, 69, 50, 98])
10
+ const TREE_CACHE = 128 // speeds up linear scans by A LOT
7
11
 
8
12
  class NodeQueue {
9
13
  constructor (nodes, extra = null) {
@@ -56,11 +60,11 @@ class MerkleTreeBatch {
56
60
  }
57
61
 
58
62
  signable (hash = this.hash()) {
59
- return signable(hash, this.length, this.fork)
63
+ return caps.treeSignable(hash, this.length, this.fork)
60
64
  }
61
65
 
62
- signedBy (key) {
63
- return this.signature !== null && this.tree.crypto.verify(this.signable(), this.signature, key)
66
+ signableLegacy (hash = this.hash()) {
67
+ return caps.treeSignableLegacy(hash, this.length, this.fork)
64
68
  }
65
69
 
66
70
  append (buf) {
@@ -138,6 +142,7 @@ class MerkleTreeBatch {
138
142
  : this.ancestors
139
143
 
140
144
  this.tree.truncated = true
145
+ this.tree.cache = new Xache({ maxSize: this.tree.cache.maxSize })
141
146
  truncateMap(this.tree.unflushed, this.ancestors)
142
147
  if (this.tree.flushing !== null) truncateMap(this.tree.flushing, this.ancestors)
143
148
  }
@@ -212,9 +217,9 @@ class ReorgBatch extends MerkleTreeBatch {
212
217
  if (this.want === null) return true
213
218
 
214
219
  const nodes = []
215
- const root = verifyBlock(proof, this.tree.crypto, nodes)
220
+ const root = verifyTree(proof, this.tree.crypto, nodes)
216
221
 
217
- if (root === null || !root.hash.equals(this.diff.hash)) return false
222
+ if (root === null || !b4a.equals(root.hash, this.diff.hash)) return false
218
223
 
219
224
  this.nodes.push(...nodes)
220
225
  return this._update(nodes)
@@ -226,13 +231,14 @@ class ReorgBatch extends MerkleTreeBatch {
226
231
 
227
232
  let diff = null
228
233
  const ite = flat.iterator(this.diff.index)
234
+ const startingDiff = this.diff
229
235
 
230
236
  while ((ite.index & 1) !== 0) {
231
237
  const left = n.get(ite.leftChild())
232
238
  if (!left) break
233
239
 
234
240
  const existing = await this.tree.get(left.index, false)
235
- if (!existing || !existing.hash.equals(left.hash)) {
241
+ if (!existing || !b4a.equals(existing.hash, left.hash)) {
236
242
  diff = left
237
243
  } else {
238
244
  diff = n.get(ite.sibling())
@@ -241,20 +247,19 @@ class ReorgBatch extends MerkleTreeBatch {
241
247
 
242
248
  if ((this.diff.index & 1) === 0) return true
243
249
  if (diff === null) return false
250
+ if (startingDiff !== this.diff) return false
244
251
 
245
252
  return this._updateDiffRoot(diff)
246
253
  }
247
254
 
248
255
  _updateDiffRoot (diff) {
256
+ if (this.want === null) return true
257
+
249
258
  const spans = flat.spans(diff.index)
250
259
  const start = spans[0] / 2
251
260
  const end = Math.min(this.treeLength, spans[1] / 2 + 1)
252
261
  const len = end - start
253
262
 
254
- if (this.diff !== null && len >= this.want.end - this.want.start) {
255
- return false
256
- }
257
-
258
263
  this.ancestors = start
259
264
  this.diff = diff
260
265
 
@@ -348,13 +353,14 @@ module.exports = class MerkleTree {
348
353
 
349
354
  this.storage = storage
350
355
  this.unflushed = new Map()
356
+ this.cache = new Xache({ maxSize: TREE_CACHE })
351
357
  this.flushing = null
352
358
  this.truncated = false
353
359
  this.truncateTo = 0
354
360
  }
355
361
 
356
362
  addNode (node) {
357
- if (node.size === 0 && node.hash.equals(BLANK_HASH)) node = blankNode(node.index)
363
+ if (node.size === 0 && b4a.equals(node.hash, BLANK_HASH)) node = blankNode(node.index)
358
364
  this.unflushed.set(node.index, node)
359
365
  }
360
366
 
@@ -371,14 +377,39 @@ module.exports = class MerkleTree {
371
377
  }
372
378
 
373
379
  signable (hash = this.hash()) {
374
- return signable(hash, this.length, this.fork)
380
+ return caps.treeSignable(hash, this.length, this.fork)
375
381
  }
376
382
 
377
- signedBy (key) {
378
- return this.signature !== null && this.crypto.verify(this.signable(), this.signature, key)
383
+ getRoots (length) {
384
+ const indexes = flat.fullRoots(2 * length)
385
+ const roots = new Array(indexes.length)
386
+
387
+ for (let i = 0; i < indexes.length; i++) {
388
+ roots[i] = this.get(indexes[i], true)
389
+ }
390
+
391
+ return Promise.all(roots)
392
+ }
393
+
394
+ async upgradeable (length) {
395
+ const indexes = flat.fullRoots(2 * length)
396
+ const roots = new Array(indexes.length)
397
+
398
+ for (let i = 0; i < indexes.length; i++) {
399
+ roots[i] = this.get(indexes[i], false)
400
+ }
401
+
402
+ for (const node of await Promise.all(roots)) {
403
+ if (node === null) return false
404
+ }
405
+
406
+ return true
379
407
  }
380
408
 
381
409
  get (index, error = true) {
410
+ const c = this.cache.get(index)
411
+ if (c) return c
412
+
382
413
  let node = this.unflushed.get(index)
383
414
 
384
415
  if (this.flushing !== null && node === undefined) {
@@ -398,7 +429,7 @@ module.exports = class MerkleTree {
398
429
  return Promise.resolve(node)
399
430
  }
400
431
 
401
- return getStoredNode(this.storage, index, error)
432
+ return getStoredNode(this.storage, index, this.cache, error)
402
433
  }
403
434
 
404
435
  async flush () {
@@ -440,17 +471,23 @@ module.exports = class MerkleTree {
440
471
  // TODO: write neighbors together etc etc
441
472
  // TODO: bench loading a full disk page and copy to that instead
442
473
  return new Promise((resolve, reject) => {
443
- const slab = Buffer.allocUnsafe(40 * this.flushing.size)
474
+ const slab = b4a.allocUnsafe(40 * this.flushing.size)
444
475
 
445
476
  let error = null
446
477
  let missing = this.flushing.size + 1
447
478
  let offset = 0
448
479
 
449
480
  for (const node of this.flushing.values()) {
450
- const b = slab.slice(offset, offset += 40)
451
- uint64le.encode(node.size, b, 0)
452
- node.hash.copy(b, 8)
453
- this.storage.write(node.index * 40, b, done)
481
+ const state = {
482
+ start: 0,
483
+ end: 40,
484
+ buffer: slab.subarray(offset, offset += 40)
485
+ }
486
+
487
+ c.uint64.encode(state, node.size)
488
+ c.raw.encode(state, node.hash)
489
+
490
+ this.storage.write(node.index * 40, state.buffer, done)
454
491
  }
455
492
 
456
493
  done(null)
@@ -465,6 +502,7 @@ module.exports = class MerkleTree {
465
502
  }
466
503
 
467
504
  clear () {
505
+ this.cache = new Xache({ maxSize: this.cache.maxSize })
468
506
  this.truncated = true
469
507
  this.truncateTo = 0
470
508
  this.roots = []
@@ -517,8 +555,8 @@ module.exports = class MerkleTree {
517
555
 
518
556
  let unverified = null
519
557
 
520
- if (proof.block || proof.seek) {
521
- unverified = verifyBlock(proof, this.crypto, batch.nodes)
558
+ if (proof.block || proof.hash || proof.seek) {
559
+ unverified = verifyTree(proof, this.crypto, batch.nodes)
522
560
  }
523
561
 
524
562
  if (!verifyUpgrade(proof, unverified, batch)) {
@@ -527,7 +565,7 @@ module.exports = class MerkleTree {
527
565
 
528
566
  for (const root of batch.roots) {
529
567
  const existing = await this.get(root.index, false)
530
- if (existing && existing.hash.equals(root.hash)) continue
568
+ if (existing && b4a.equals(existing.hash, root.hash)) continue
531
569
  batch._updateDiffRoot(root)
532
570
  break
533
571
  }
@@ -545,7 +583,7 @@ module.exports = class MerkleTree {
545
583
  async verify (proof) {
546
584
  const batch = new MerkleTreeBatch(this)
547
585
 
548
- let unverified = verifyBlock(proof, this.crypto, batch.nodes)
586
+ let unverified = verifyTree(proof, this.crypto, batch.nodes)
549
587
 
550
588
  if (proof.upgrade) {
551
589
  if (verifyUpgrade(proof, unverified, batch)) {
@@ -555,7 +593,7 @@ module.exports = class MerkleTree {
555
593
 
556
594
  if (unverified) {
557
595
  const verified = await this.get(unverified.index)
558
- if (!verified.hash.equals(unverified.hash)) {
596
+ if (!b4a.equals(verified.hash, unverified.hash)) {
559
597
  throw new Error('Invalid checksum at node ' + unverified.index)
560
598
  }
561
599
  }
@@ -563,89 +601,102 @@ module.exports = class MerkleTree {
563
601
  return batch
564
602
  }
565
603
 
566
- async proof ({ block, seek, upgrade }) {
604
+ async proof ({ block, hash, seek, upgrade }) {
567
605
  // Important that this does not throw inbetween making the promise arrays
568
606
  // and finalise being called, otherwise there will be lingering promises in the background
569
607
 
570
- const signature = this.signature
571
608
  const fork = this.fork
609
+ const signature = this.signature
572
610
  const head = 2 * this.length
573
611
  const from = upgrade ? upgrade.start * 2 : 0
574
612
  const to = upgrade ? from + upgrade.length * 2 : head
613
+ const node = normalizeIndexed(block, hash)
575
614
 
576
615
  if (from >= to || to > head) {
577
616
  throw new Error('Invalid upgrade')
578
617
  }
579
- if (seek && block && upgrade && block.index * 2 >= from) {
580
- throw new Error('Cannot both do a seek and block request when upgrading')
618
+ if (seek && upgrade && node !== null && node.index >= from) {
619
+ throw new Error('Cannot both do a seek and block/hash request when upgrading')
581
620
  }
582
621
 
583
622
  let subTree = head
584
623
 
585
624
  const p = {
586
- block: null,
625
+ node: null,
587
626
  seek: null,
588
627
  upgrade: null,
589
628
  additionalUpgrade: null
590
629
  }
591
630
 
592
- if (block && (!upgrade || block.index < upgrade.start)) {
593
- subTree = nodesToRoot(2 * block.index, block.nodes, to)
631
+ if (node !== null && (!upgrade || node.lastIndex < upgrade.start)) {
632
+ subTree = nodesToRoot(node.index, node.nodes, to)
594
633
  const seekRoot = seek ? await seekUntrustedTree(this, subTree, seek.bytes) : head
595
- blockAndSeekProof(this, block, seek, seekRoot, subTree, p)
596
- } else if ((block || seek) && upgrade) {
597
- subTree = seek ? await seekFromHead(this, to, seek.bytes) : 2 * block.index
634
+ blockAndSeekProof(this, node, seek, seekRoot, subTree, p)
635
+ } else if ((node || seek) && upgrade) {
636
+ subTree = seek ? await seekFromHead(this, to, seek.bytes) : node.index
598
637
  }
599
638
 
600
639
  if (upgrade) {
601
- upgradeProof(this, block, seek, from, to, subTree, p)
640
+ upgradeProof(this, node, seek, from, to, subTree, p)
602
641
  if (head > to) additionalUpgradeProof(this, to, head, p)
603
642
  }
604
643
 
605
- try {
606
- const result = { fork, block: null, seek: null, upgrade: null }
607
-
608
- if (block) {
609
- const nodes = await Promise.all(p.block)
644
+ const [pNode, pSeek, pUpgrade, pAdditional] = await settleProof(p)
645
+ const result = { fork, block: null, hash: null, seek: null, upgrade: null }
610
646
 
611
- result.block = {
612
- index: block.index,
613
- value: null,
614
- nodes
615
- }
647
+ if (block) {
648
+ result.block = {
649
+ index: block.index,
650
+ value: null, // populated upstream, alloc it here for simplicity
651
+ nodes: pNode
652
+ }
653
+ } else if (hash) {
654
+ result.hash = {
655
+ index: hash.index,
656
+ nodes: pNode
616
657
  }
617
- if (seek && p.seek !== null) {
618
- const nodes = await Promise.all(p.seek)
658
+ }
619
659
 
620
- result.seek = {
621
- bytes: seek.bytes,
622
- nodes
623
- }
660
+ if (seek && pSeek !== null) {
661
+ result.seek = {
662
+ bytes: seek.bytes,
663
+ nodes: pSeek
624
664
  }
625
- if (upgrade) {
626
- const nodes = await Promise.all(p.upgrade)
627
- const additionalNodes = await Promise.all(p.additionalUpgrade || [])
628
-
629
- result.upgrade = {
630
- start: upgrade.start,
631
- length: upgrade.length,
632
- nodes,
633
- additionalNodes,
634
- signature
635
- }
665
+ }
666
+
667
+ if (upgrade) {
668
+ result.upgrade = {
669
+ start: upgrade.start,
670
+ length: upgrade.length,
671
+ nodes: pUpgrade,
672
+ additionalNodes: pAdditional || [],
673
+ signature
636
674
  }
675
+ }
637
676
 
638
- return result
639
- } catch (err) {
640
- // Make sure we await all pending p so don't have background async state...
641
- if (p.seek !== null) await Promise.allSettled(p.seek)
642
- if (p.block !== null) await Promise.allSettled(p.block)
643
- if (p.upgrade !== null) await Promise.allSettled(p.upgrade)
644
- if (p.additionalUpgrade !== null) await Promise.allSettled(p.additionalUpgrade)
645
- throw err
677
+ return result
678
+ }
679
+
680
+ // Successor to .nodes()
681
+ async missingNodes (index) {
682
+ const head = 2 * this.length
683
+ const ite = flat.iterator(index)
684
+
685
+ // See iterator.rightSpan()
686
+ const iteRightSpan = ite.index + ite.factor / 2 - 1
687
+ // If the index is not in the current tree, we do not know how many missing nodes there are...
688
+ if (iteRightSpan >= head) return 0
689
+
690
+ let cnt = 0
691
+ while (!ite.contains(head) && (await this.get(ite.index, false)) === null) {
692
+ cnt++
693
+ ite.parent()
646
694
  }
695
+
696
+ return cnt
647
697
  }
648
698
 
699
+ // Deprecated
649
700
  async nodes (index) {
650
701
  const head = 2 * this.length
651
702
  const ite = flat.iterator(index)
@@ -700,7 +751,7 @@ module.exports = class MerkleTree {
700
751
  await new Promise((resolve, reject) => {
701
752
  storage.read(0, OLD_TREE.length, (err, buf) => {
702
753
  if (err) return resolve()
703
- if (buf.equals(OLD_TREE)) return reject(new Error('Storage contains an incompatible merkle tree'))
754
+ if (b4a.equals(buf, OLD_TREE)) return reject(new Error('Storage contains an incompatible merkle tree'))
704
755
  resolve()
705
756
  })
706
757
  })
@@ -711,7 +762,7 @@ module.exports = class MerkleTree {
711
762
 
712
763
  const roots = []
713
764
  for (const index of flat.fullRoots(2 * length)) {
714
- roots.push(await getStoredNode(storage, index, true))
765
+ roots.push(await getStoredNode(storage, index, null, true))
715
766
  }
716
767
 
717
768
  return new MerkleTree(storage, roots, opts.fork || 0, opts.signature || null)
@@ -720,8 +771,14 @@ module.exports = class MerkleTree {
720
771
 
721
772
  // All the methods needed for proof verification
722
773
 
723
- function verifyBlock ({ block, seek }, crypto, nodes) {
724
- if (!block && (!seek || !seek.nodes.length)) return null
774
+ function verifyTree ({ block, hash, seek }, crypto, nodes) {
775
+ const untrustedNode = block
776
+ ? { index: 2 * block.index, value: block.value, nodes: block.nodes }
777
+ : hash
778
+ ? { index: hash.index, value: null, nodes: hash.nodes }
779
+ : null
780
+
781
+ if (untrustedNode === null && (!seek || !seek.nodes.length)) return null
725
782
 
726
783
  let root = null
727
784
 
@@ -741,12 +798,12 @@ function verifyBlock ({ block, seek }, crypto, nodes) {
741
798
  }
742
799
  }
743
800
 
744
- if (!block) return root
801
+ if (untrustedNode === null) return root
745
802
 
746
- const ite = flat.iterator(2 * block.index)
747
- const blockHash = block.value && blockNode(crypto, ite.index, block.value)
803
+ const ite = flat.iterator(untrustedNode.index)
804
+ const blockHash = untrustedNode.value && blockNode(crypto, ite.index, untrustedNode.value)
748
805
 
749
- const q = new NodeQueue(block.nodes, root)
806
+ const q = new NodeQueue(untrustedNode.nodes, root)
750
807
 
751
808
  root = blockHash || q.shift(ite.index)
752
809
  nodes.push(root)
@@ -895,13 +952,13 @@ function seekProof (tree, seekRoot, root, p) {
895
952
  }
896
953
  }
897
954
 
898
- function blockAndSeekProof (tree, block, seek, seekRoot, root, p) {
899
- if (!block) return seekProof(tree, seekRoot, root, p)
955
+ function blockAndSeekProof (tree, node, seek, seekRoot, root, p) {
956
+ if (!node) return seekProof(tree, seekRoot, root, p)
900
957
 
901
- const ite = flat.iterator(2 * block.index)
958
+ const ite = flat.iterator(node.index)
902
959
 
903
- p.block = []
904
- if (!block.value) p.block.push(tree.get(ite.index))
960
+ p.node = []
961
+ if (!node.value) p.node.push(tree.get(ite.index))
905
962
 
906
963
  while (ite.index !== root) {
907
964
  ite.sibling()
@@ -909,14 +966,14 @@ function blockAndSeekProof (tree, block, seek, seekRoot, root, p) {
909
966
  if (seek && ite.contains(seekRoot) && ite.index !== seekRoot) {
910
967
  seekProof(tree, seekRoot, ite.index, p)
911
968
  } else {
912
- p.block.push(tree.get(ite.index))
969
+ p.node.push(tree.get(ite.index))
913
970
  }
914
971
 
915
972
  ite.parent()
916
973
  }
917
974
  }
918
975
 
919
- function upgradeProof (tree, block, seek, from, to, subTree, p) {
976
+ function upgradeProof (tree, node, seek, from, to, subTree, p) {
920
977
  if (from === 0) p.upgrade = []
921
978
 
922
979
  for (const ite = flat.iterator(0); ite.fullRoot(to); ite.nextTree()) {
@@ -935,8 +992,8 @@ function upgradeProof (tree, block, seek, from, to, subTree, p) {
935
992
  while (ite.index !== root) {
936
993
  ite.sibling()
937
994
  if (ite.index > target) {
938
- if (p.block === null && p.seek === null && ite.contains(subTree)) {
939
- blockAndSeekProof(tree, block, seek, subTree, ite.index, p)
995
+ if (p.node === null && p.seek === null && ite.contains(subTree)) {
996
+ blockAndSeekProof(tree, node, seek, subTree, ite.index, p)
940
997
  } else {
941
998
  p.upgrade.push(tree.get(ite.index))
942
999
  }
@@ -953,8 +1010,8 @@ function upgradeProof (tree, block, seek, from, to, subTree, p) {
953
1010
 
954
1011
  // if the subtree included is a child of this tree, include that one
955
1012
  // instead of a dup node
956
- if (p.block === null && p.seek === null && ite.contains(subTree)) {
957
- blockAndSeekProof(tree, block, seek, subTree, ite.index, p)
1013
+ if (p.node === null && p.seek === null && ite.contains(subTree)) {
1014
+ blockAndSeekProof(tree, node, seek, subTree, ite.index, p)
958
1015
  continue
959
1016
  }
960
1017
 
@@ -1036,7 +1093,7 @@ function blankNode (index) {
1036
1093
 
1037
1094
  // Storage methods
1038
1095
 
1039
- function getStoredNode (storage, index, error) {
1096
+ function getStoredNode (storage, index, cache, error) {
1040
1097
  return new Promise((resolve, reject) => {
1041
1098
  storage.read(40 * index, 40, (err, data) => {
1042
1099
  if (err) {
@@ -1045,16 +1102,18 @@ function getStoredNode (storage, index, error) {
1045
1102
  return
1046
1103
  }
1047
1104
 
1048
- const hash = data.slice(8)
1049
- const size = uint64le.decode(data, 0)
1105
+ const hash = data.subarray(8)
1106
+ const size = c.decode(c.uint64, data)
1050
1107
 
1051
- if (size === 0 && Buffer.compare(hash, BLANK_HASH) === 0) {
1108
+ if (size === 0 && b4a.compare(hash, BLANK_HASH) === 0) {
1052
1109
  if (error) reject(new Error('Could not load node: ' + index))
1053
1110
  else resolve(null)
1054
1111
  return
1055
1112
  }
1056
1113
 
1057
- resolve({ index, size, hash })
1114
+ const node = { index, size, hash }
1115
+ if (cache !== null) cache.set(index, node)
1116
+ resolve(node)
1058
1117
  })
1059
1118
  })
1060
1119
  }
@@ -1073,7 +1132,7 @@ async function autoLength (storage) {
1073
1132
  if (!nodes) return 0
1074
1133
  const ite = flat.iterator(nodes - 1)
1075
1134
  let index = nodes - 1
1076
- while (await getStoredNode(storage, ite.parent(), false)) index = ite.index
1135
+ while (await getStoredNode(storage, ite.parent(), null, false)) index = ite.index
1077
1136
  return flat.rightSpan(index) / 2 + 1
1078
1137
  }
1079
1138
 
@@ -1094,10 +1153,27 @@ function log2 (n) {
1094
1153
  return res
1095
1154
  }
1096
1155
 
1097
- function signable (hash, length, fork) {
1098
- const buf = Buffer.alloc(48)
1099
- hash.copy(buf)
1100
- uint64le.encode(length, buf, 32)
1101
- uint64le.encode(fork, buf, 40)
1102
- return buf
1156
+ function normalizeIndexed (block, hash) {
1157
+ if (block) return { value: true, index: block.index * 2, nodes: block.nodes, lastIndex: block.index }
1158
+ if (hash) return { value: false, index: hash.index, nodes: hash.nodes, lastIndex: flat.rightSpan(hash.index) / 2 }
1159
+ return null
1160
+ }
1161
+
1162
+ async function settleProof (p) {
1163
+ const result = [
1164
+ p.node && Promise.all(p.node),
1165
+ p.seek && Promise.all(p.seek),
1166
+ p.upgrade && Promise.all(p.upgrade),
1167
+ p.additionalUpgrade && Promise.all(p.additionalUpgrade)
1168
+ ]
1169
+
1170
+ try {
1171
+ return await Promise.all(result)
1172
+ } catch (err) {
1173
+ if (p.node) await Promise.allSettled(p.node)
1174
+ if (p.seek) await Promise.allSettled(p.seek)
1175
+ if (p.upgrade) await Promise.allSettled(p.upgrade)
1176
+ if (p.additionalUpgrade) await Promise.allSettled(p.additionalUpgrade)
1177
+ throw err
1178
+ }
1103
1179
  }