hypercore 10.0.0-alpha.5 → 10.0.0-alpha.52

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,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
 
@@ -272,11 +277,15 @@ class ReorgBatch extends MerkleTreeBatch {
272
277
  }
273
278
 
274
279
  class ByteSeeker {
275
- constructor (tree, bytes) {
280
+ constructor (tree, bytes, padding = 0) {
276
281
  this.tree = tree
277
282
  this.bytes = bytes
278
- this.start = bytes >= tree.byteLength ? tree.length : 0
279
- this.end = bytes < tree.byteLength ? tree.length : 0
283
+ this.padding = padding
284
+
285
+ const size = tree.byteLength - (tree.length * padding)
286
+
287
+ this.start = bytes >= size ? tree.length : 0
288
+ this.end = bytes < size ? tree.length : 0
280
289
  }
281
290
 
282
291
  nodes () {
@@ -287,12 +296,12 @@ class ByteSeeker {
287
296
  if (!bytes) return [0, 0]
288
297
 
289
298
  for (const node of this.tree.roots) { // all async ticks happen once we find the root so safe
290
- if (bytes === node.size) {
291
- return [flat.rightSpan(node.index) + 2, 0]
292
- }
299
+ let size = node.size
300
+ if (this.padding > 0) size -= this.padding * flat.countLeaves(node.index)
293
301
 
294
- if (bytes > node.size) {
295
- bytes -= node.size
302
+ if (bytes === size) return [flat.rightSpan(node.index) + 2, 0]
303
+ if (bytes > size) {
304
+ bytes -= size
296
305
  continue
297
306
  }
298
307
 
@@ -301,9 +310,12 @@ class ByteSeeker {
301
310
  while ((ite.index & 1) !== 0) {
302
311
  const l = await this.tree.get(ite.leftChild(), false)
303
312
  if (l) {
304
- if (l.size === bytes) return [ite.rightSpan() + 2, 0]
305
- if (l.size > bytes) continue
306
- bytes -= l.size
313
+ let size = l.size
314
+ if (this.padding > 0) size -= this.padding * ite.countLeaves()
315
+
316
+ if (size === bytes) return [ite.rightSpan() + 2, 0]
317
+ if (size > bytes) continue
318
+ bytes -= size
307
319
  ite.sibling()
308
320
  } else {
309
321
  ite.parent()
@@ -341,13 +353,14 @@ module.exports = class MerkleTree {
341
353
 
342
354
  this.storage = storage
343
355
  this.unflushed = new Map()
356
+ this.cache = new Xache({ maxSize: TREE_CACHE })
344
357
  this.flushing = null
345
358
  this.truncated = false
346
359
  this.truncateTo = 0
347
360
  }
348
361
 
349
362
  addNode (node) {
350
- 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)
351
364
  this.unflushed.set(node.index, node)
352
365
  }
353
366
 
@@ -355,8 +368,8 @@ module.exports = class MerkleTree {
355
368
  return new MerkleTreeBatch(this)
356
369
  }
357
370
 
358
- seek (bytes) {
359
- return new ByteSeeker(this, bytes)
371
+ seek (bytes, padding) {
372
+ return new ByteSeeker(this, bytes, padding)
360
373
  }
361
374
 
362
375
  hash () {
@@ -364,14 +377,39 @@ module.exports = class MerkleTree {
364
377
  }
365
378
 
366
379
  signable (hash = this.hash()) {
367
- return signable(hash, this.length, this.fork)
380
+ return caps.treeSignable(hash, this.length, this.fork)
368
381
  }
369
382
 
370
- signedBy (key) {
371
- 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
372
407
  }
373
408
 
374
409
  get (index, error = true) {
410
+ const c = this.cache.get(index)
411
+ if (c) return c
412
+
375
413
  let node = this.unflushed.get(index)
376
414
 
377
415
  if (this.flushing !== null && node === undefined) {
@@ -391,7 +429,7 @@ module.exports = class MerkleTree {
391
429
  return Promise.resolve(node)
392
430
  }
393
431
 
394
- return getStoredNode(this.storage, index, error)
432
+ return getStoredNode(this.storage, index, this.cache, error)
395
433
  }
396
434
 
397
435
  async flush () {
@@ -433,17 +471,23 @@ module.exports = class MerkleTree {
433
471
  // TODO: write neighbors together etc etc
434
472
  // TODO: bench loading a full disk page and copy to that instead
435
473
  return new Promise((resolve, reject) => {
436
- const slab = Buffer.allocUnsafe(40 * this.flushing.size)
474
+ const slab = b4a.allocUnsafe(40 * this.flushing.size)
437
475
 
438
476
  let error = null
439
477
  let missing = this.flushing.size + 1
440
478
  let offset = 0
441
479
 
442
480
  for (const node of this.flushing.values()) {
443
- const b = slab.slice(offset, offset += 40)
444
- uint64le.encode(node.size, b, 0)
445
- node.hash.copy(b, 8)
446
- 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)
447
491
  }
448
492
 
449
493
  done(null)
@@ -458,6 +502,7 @@ module.exports = class MerkleTree {
458
502
  }
459
503
 
460
504
  clear () {
505
+ this.cache = new Xache({ maxSize: this.cache.maxSize })
461
506
  this.truncated = true
462
507
  this.truncateTo = 0
463
508
  this.roots = []
@@ -510,8 +555,8 @@ module.exports = class MerkleTree {
510
555
 
511
556
  let unverified = null
512
557
 
513
- if (proof.block || proof.seek) {
514
- unverified = verifyBlock(proof, this.crypto, batch.nodes)
558
+ if (proof.block || proof.hash || proof.seek) {
559
+ unverified = verifyTree(proof, this.crypto, batch.nodes)
515
560
  }
516
561
 
517
562
  if (!verifyUpgrade(proof, unverified, batch)) {
@@ -520,7 +565,7 @@ module.exports = class MerkleTree {
520
565
 
521
566
  for (const root of batch.roots) {
522
567
  const existing = await this.get(root.index, false)
523
- if (existing && existing.hash.equals(root.hash)) continue
568
+ if (existing && b4a.equals(existing.hash, root.hash)) continue
524
569
  batch._updateDiffRoot(root)
525
570
  break
526
571
  }
@@ -538,7 +583,7 @@ module.exports = class MerkleTree {
538
583
  async verify (proof) {
539
584
  const batch = new MerkleTreeBatch(this)
540
585
 
541
- let unverified = verifyBlock(proof, this.crypto, batch.nodes)
586
+ let unverified = verifyTree(proof, this.crypto, batch.nodes)
542
587
 
543
588
  if (proof.upgrade) {
544
589
  if (verifyUpgrade(proof, unverified, batch)) {
@@ -548,7 +593,7 @@ module.exports = class MerkleTree {
548
593
 
549
594
  if (unverified) {
550
595
  const verified = await this.get(unverified.index)
551
- if (!verified.hash.equals(unverified.hash)) {
596
+ if (!b4a.equals(verified.hash, unverified.hash)) {
552
597
  throw new Error('Invalid checksum at node ' + unverified.index)
553
598
  }
554
599
  }
@@ -556,89 +601,102 @@ module.exports = class MerkleTree {
556
601
  return batch
557
602
  }
558
603
 
559
- async proof ({ block, seek, upgrade }) {
604
+ async proof ({ block, hash, seek, upgrade }) {
560
605
  // Important that this does not throw inbetween making the promise arrays
561
606
  // and finalise being called, otherwise there will be lingering promises in the background
562
607
 
563
- const signature = this.signature
564
608
  const fork = this.fork
609
+ const signature = this.signature
565
610
  const head = 2 * this.length
566
611
  const from = upgrade ? upgrade.start * 2 : 0
567
612
  const to = upgrade ? from + upgrade.length * 2 : head
613
+ const node = normalizeIndexed(block, hash)
568
614
 
569
615
  if (from >= to || to > head) {
570
616
  throw new Error('Invalid upgrade')
571
617
  }
572
- if (seek && block && upgrade && block.index * 2 >= from) {
573
- 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')
574
620
  }
575
621
 
576
622
  let subTree = head
577
623
 
578
624
  const p = {
579
- block: null,
625
+ node: null,
580
626
  seek: null,
581
627
  upgrade: null,
582
628
  additionalUpgrade: null
583
629
  }
584
630
 
585
- if (block && (!upgrade || block.index < upgrade.start)) {
586
- 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)
587
633
  const seekRoot = seek ? await seekUntrustedTree(this, subTree, seek.bytes) : head
588
- blockAndSeekProof(this, block, seek, seekRoot, subTree, p)
589
- } else if ((block || seek) && upgrade) {
590
- 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
591
637
  }
592
638
 
593
639
  if (upgrade) {
594
- upgradeProof(this, block, seek, from, to, subTree, p)
640
+ upgradeProof(this, node, seek, from, to, subTree, p)
595
641
  if (head > to) additionalUpgradeProof(this, to, head, p)
596
642
  }
597
643
 
598
- try {
599
- const result = { fork, block: null, seek: null, upgrade: null }
600
-
601
- if (block) {
602
- 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 }
603
646
 
604
- result.block = {
605
- index: block.index,
606
- value: null,
607
- nodes
608
- }
647
+ if (block) {
648
+ result.block = {
649
+ index: block.index,
650
+ value: null, // populated upstream, alloc it here for simplicity
651
+ nodes: pNode
609
652
  }
610
- if (seek && p.seek !== null) {
611
- const nodes = await Promise.all(p.seek)
653
+ } else if (hash) {
654
+ result.hash = {
655
+ index: hash.index,
656
+ nodes: pNode
657
+ }
658
+ }
612
659
 
613
- result.seek = {
614
- bytes: seek.bytes,
615
- nodes
616
- }
660
+ if (seek && pSeek !== null) {
661
+ result.seek = {
662
+ bytes: seek.bytes,
663
+ nodes: pSeek
617
664
  }
618
- if (upgrade) {
619
- const nodes = await Promise.all(p.upgrade)
620
- const additionalNodes = await Promise.all(p.additionalUpgrade || [])
621
-
622
- result.upgrade = {
623
- start: upgrade.start,
624
- length: upgrade.length,
625
- nodes,
626
- additionalNodes,
627
- signature
628
- }
665
+ }
666
+
667
+ if (upgrade) {
668
+ result.upgrade = {
669
+ start: upgrade.start,
670
+ length: upgrade.length,
671
+ nodes: pUpgrade,
672
+ additionalNodes: pAdditional || [],
673
+ signature
629
674
  }
675
+ }
630
676
 
631
- return result
632
- } catch (err) {
633
- // Make sure we await all pending p so don't have background async state...
634
- if (p.seek !== null) await Promise.allSettled(p.seek)
635
- if (p.block !== null) await Promise.allSettled(p.block)
636
- if (p.upgrade !== null) await Promise.allSettled(p.upgrade)
637
- if (p.additionalUpgrade !== null) await Promise.allSettled(p.additionalUpgrade)
638
- 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()
639
694
  }
695
+
696
+ return cnt
640
697
  }
641
698
 
699
+ // Deprecated
642
700
  async nodes (index) {
643
701
  const head = 2 * this.length
644
702
  const ite = flat.iterator(index)
@@ -693,7 +751,7 @@ module.exports = class MerkleTree {
693
751
  await new Promise((resolve, reject) => {
694
752
  storage.read(0, OLD_TREE.length, (err, buf) => {
695
753
  if (err) return resolve()
696
- 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'))
697
755
  resolve()
698
756
  })
699
757
  })
@@ -704,7 +762,7 @@ module.exports = class MerkleTree {
704
762
 
705
763
  const roots = []
706
764
  for (const index of flat.fullRoots(2 * length)) {
707
- roots.push(await getStoredNode(storage, index, true))
765
+ roots.push(await getStoredNode(storage, index, null, true))
708
766
  }
709
767
 
710
768
  return new MerkleTree(storage, roots, opts.fork || 0, opts.signature || null)
@@ -713,8 +771,14 @@ module.exports = class MerkleTree {
713
771
 
714
772
  // All the methods needed for proof verification
715
773
 
716
- function verifyBlock ({ block, seek }, crypto, nodes) {
717
- 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
718
782
 
719
783
  let root = null
720
784
 
@@ -734,12 +798,12 @@ function verifyBlock ({ block, seek }, crypto, nodes) {
734
798
  }
735
799
  }
736
800
 
737
- if (!block) return root
801
+ if (untrustedNode === null) return root
738
802
 
739
- const ite = flat.iterator(2 * block.index)
740
- 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)
741
805
 
742
- const q = new NodeQueue(block.nodes, root)
806
+ const q = new NodeQueue(untrustedNode.nodes, root)
743
807
 
744
808
  root = blockHash || q.shift(ite.index)
745
809
  nodes.push(root)
@@ -888,13 +952,13 @@ function seekProof (tree, seekRoot, root, p) {
888
952
  }
889
953
  }
890
954
 
891
- function blockAndSeekProof (tree, block, seek, seekRoot, root, p) {
892
- 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)
893
957
 
894
- const ite = flat.iterator(2 * block.index)
958
+ const ite = flat.iterator(node.index)
895
959
 
896
- p.block = []
897
- if (!block.value) p.block.push(tree.get(ite.index))
960
+ p.node = []
961
+ if (!node.value) p.node.push(tree.get(ite.index))
898
962
 
899
963
  while (ite.index !== root) {
900
964
  ite.sibling()
@@ -902,14 +966,14 @@ function blockAndSeekProof (tree, block, seek, seekRoot, root, p) {
902
966
  if (seek && ite.contains(seekRoot) && ite.index !== seekRoot) {
903
967
  seekProof(tree, seekRoot, ite.index, p)
904
968
  } else {
905
- p.block.push(tree.get(ite.index))
969
+ p.node.push(tree.get(ite.index))
906
970
  }
907
971
 
908
972
  ite.parent()
909
973
  }
910
974
  }
911
975
 
912
- function upgradeProof (tree, block, seek, from, to, subTree, p) {
976
+ function upgradeProof (tree, node, seek, from, to, subTree, p) {
913
977
  if (from === 0) p.upgrade = []
914
978
 
915
979
  for (const ite = flat.iterator(0); ite.fullRoot(to); ite.nextTree()) {
@@ -928,8 +992,8 @@ function upgradeProof (tree, block, seek, from, to, subTree, p) {
928
992
  while (ite.index !== root) {
929
993
  ite.sibling()
930
994
  if (ite.index > target) {
931
- if (p.block === null && p.seek === null && ite.contains(subTree)) {
932
- 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)
933
997
  } else {
934
998
  p.upgrade.push(tree.get(ite.index))
935
999
  }
@@ -946,8 +1010,8 @@ function upgradeProof (tree, block, seek, from, to, subTree, p) {
946
1010
 
947
1011
  // if the subtree included is a child of this tree, include that one
948
1012
  // instead of a dup node
949
- if (p.block === null && p.seek === null && ite.contains(subTree)) {
950
- 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)
951
1015
  continue
952
1016
  }
953
1017
 
@@ -1029,7 +1093,7 @@ function blankNode (index) {
1029
1093
 
1030
1094
  // Storage methods
1031
1095
 
1032
- function getStoredNode (storage, index, error) {
1096
+ function getStoredNode (storage, index, cache, error) {
1033
1097
  return new Promise((resolve, reject) => {
1034
1098
  storage.read(40 * index, 40, (err, data) => {
1035
1099
  if (err) {
@@ -1038,16 +1102,18 @@ function getStoredNode (storage, index, error) {
1038
1102
  return
1039
1103
  }
1040
1104
 
1041
- const hash = data.slice(8)
1042
- const size = uint64le.decode(data, 0)
1105
+ const hash = data.subarray(8)
1106
+ const size = c.decode(c.uint64, data)
1043
1107
 
1044
- if (size === 0 && Buffer.compare(hash, BLANK_HASH) === 0) {
1108
+ if (size === 0 && b4a.compare(hash, BLANK_HASH) === 0) {
1045
1109
  if (error) reject(new Error('Could not load node: ' + index))
1046
1110
  else resolve(null)
1047
1111
  return
1048
1112
  }
1049
1113
 
1050
- resolve({ index, size, hash })
1114
+ const node = { index, size, hash }
1115
+ if (cache !== null) cache.set(index, node)
1116
+ resolve(node)
1051
1117
  })
1052
1118
  })
1053
1119
  }
@@ -1066,7 +1132,7 @@ async function autoLength (storage) {
1066
1132
  if (!nodes) return 0
1067
1133
  const ite = flat.iterator(nodes - 1)
1068
1134
  let index = nodes - 1
1069
- while (await getStoredNode(storage, ite.parent(), false)) index = ite.index
1135
+ while (await getStoredNode(storage, ite.parent(), null, false)) index = ite.index
1070
1136
  return flat.rightSpan(index) / 2 + 1
1071
1137
  }
1072
1138
 
@@ -1087,10 +1153,27 @@ function log2 (n) {
1087
1153
  return res
1088
1154
  }
1089
1155
 
1090
- function signable (hash, length, fork) {
1091
- const buf = Buffer.alloc(48)
1092
- hash.copy(buf)
1093
- uint64le.encode(length, buf, 32)
1094
- uint64le.encode(fork, buf, 40)
1095
- 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
+ }
1096
1179
  }