hypercore 10.0.0-alpha.3 → 10.0.0-alpha.32

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,11 @@
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 b4a = require('b4a')
5
+ const caps = require('./caps')
4
6
 
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])
7
+ const BLANK_HASH = b4a.alloc(32)
8
+ const OLD_TREE = b4a.from([5, 2, 87, 2, 0, 0, 40, 7, 66, 76, 65, 75, 69, 50, 98])
7
9
 
8
10
  class NodeQueue {
9
11
  constructor (nodes, extra = null) {
@@ -56,11 +58,11 @@ class MerkleTreeBatch {
56
58
  }
57
59
 
58
60
  signable (hash = this.hash()) {
59
- return signable(hash, this.length, this.fork)
61
+ return caps.treeSignable(hash, this.length, this.fork)
60
62
  }
61
63
 
62
- signedBy (key) {
63
- return this.signature !== null && this.tree.crypto.verify(this.signable(), this.signature, key)
64
+ signableLegacy (hash = this.hash()) {
65
+ return caps.treeSignableLegacy(hash, this.length, this.fork)
64
66
  }
65
67
 
66
68
  append (buf) {
@@ -212,9 +214,9 @@ class ReorgBatch extends MerkleTreeBatch {
212
214
  if (this.want === null) return true
213
215
 
214
216
  const nodes = []
215
- const root = verifyBlock(proof, this.tree.crypto, nodes)
217
+ const root = verifyTree(proof, this.tree.crypto, nodes)
216
218
 
217
- if (root === null || !root.hash.equals(this.diff.hash)) return false
219
+ if (root === null || !b4a.equals(root.hash, this.diff.hash)) return false
218
220
 
219
221
  this.nodes.push(...nodes)
220
222
  return this._update(nodes)
@@ -232,7 +234,7 @@ class ReorgBatch extends MerkleTreeBatch {
232
234
  if (!left) break
233
235
 
234
236
  const existing = await this.tree.get(left.index, false)
235
- if (!existing || !existing.hash.equals(left.hash)) {
237
+ if (!existing || !b4a.equals(existing.hash, left.hash)) {
236
238
  diff = left
237
239
  } else {
238
240
  diff = n.get(ite.sibling())
@@ -246,6 +248,8 @@ class ReorgBatch extends MerkleTreeBatch {
246
248
  }
247
249
 
248
250
  _updateDiffRoot (diff) {
251
+ if (this.want === null) return true
252
+
249
253
  const spans = flat.spans(diff.index)
250
254
  const start = spans[0] / 2
251
255
  const end = Math.min(this.treeLength, spans[1] / 2 + 1)
@@ -272,11 +276,15 @@ class ReorgBatch extends MerkleTreeBatch {
272
276
  }
273
277
 
274
278
  class ByteSeeker {
275
- constructor (tree, bytes) {
279
+ constructor (tree, bytes, padding = 0) {
276
280
  this.tree = tree
277
281
  this.bytes = bytes
278
- this.start = bytes >= tree.byteLength ? tree.length : 0
279
- this.end = bytes < tree.byteLength ? tree.length : 0
282
+ this.padding = padding
283
+
284
+ const size = tree.byteLength - (tree.length * padding)
285
+
286
+ this.start = bytes >= size ? tree.length : 0
287
+ this.end = bytes < size ? tree.length : 0
280
288
  }
281
289
 
282
290
  nodes () {
@@ -287,12 +295,12 @@ class ByteSeeker {
287
295
  if (!bytes) return [0, 0]
288
296
 
289
297
  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
- }
298
+ let size = node.size
299
+ if (this.padding > 0) size -= this.padding * flat.countLeaves(node.index)
293
300
 
294
- if (bytes > node.size) {
295
- bytes -= node.size
301
+ if (bytes === size) return [flat.rightSpan(node.index) + 2, 0]
302
+ if (bytes > size) {
303
+ bytes -= size
296
304
  continue
297
305
  }
298
306
 
@@ -301,9 +309,12 @@ class ByteSeeker {
301
309
  while ((ite.index & 1) !== 0) {
302
310
  const l = await this.tree.get(ite.leftChild(), false)
303
311
  if (l) {
304
- if (l.size === bytes) return [ite.rightSpan() + 2, 0]
305
- if (l.size > bytes) continue
306
- bytes -= l.size
312
+ let size = l.size
313
+ if (this.padding > 0) size -= this.padding * ite.countLeaves()
314
+
315
+ if (size === bytes) return [ite.rightSpan() + 2, 0]
316
+ if (size > bytes) continue
317
+ bytes -= size
307
318
  ite.sibling()
308
319
  } else {
309
320
  ite.parent()
@@ -347,7 +358,7 @@ module.exports = class MerkleTree {
347
358
  }
348
359
 
349
360
  addNode (node) {
350
- if (node.size === 0 && node.hash.equals(BLANK_HASH)) node = blankNode(node.index)
361
+ if (node.size === 0 && b4a.equals(node.hash, BLANK_HASH)) node = blankNode(node.index)
351
362
  this.unflushed.set(node.index, node)
352
363
  }
353
364
 
@@ -355,8 +366,8 @@ module.exports = class MerkleTree {
355
366
  return new MerkleTreeBatch(this)
356
367
  }
357
368
 
358
- seek (bytes) {
359
- return new ByteSeeker(this, bytes)
369
+ seek (bytes, padding) {
370
+ return new ByteSeeker(this, bytes, padding)
360
371
  }
361
372
 
362
373
  hash () {
@@ -364,11 +375,33 @@ module.exports = class MerkleTree {
364
375
  }
365
376
 
366
377
  signable (hash = this.hash()) {
367
- return signable(hash, this.length, this.fork)
378
+ return caps.treeSignable(hash, this.length, this.fork)
368
379
  }
369
380
 
370
- signedBy (key) {
371
- return this.signature !== null && this.crypto.verify(this.signable(), this.signature, key)
381
+ getRoots (length) {
382
+ const indexes = flat.fullRoots(2 * length)
383
+ const roots = new Array(indexes.length)
384
+
385
+ for (let i = 0; i < indexes.length; i++) {
386
+ roots[i] = this.get(indexes[i], true)
387
+ }
388
+
389
+ return Promise.all(roots)
390
+ }
391
+
392
+ async upgradeable (length) {
393
+ const indexes = flat.fullRoots(2 * length)
394
+ const roots = new Array(indexes.length)
395
+
396
+ for (let i = 0; i < indexes.length; i++) {
397
+ roots[i] = this.get(indexes[i], false)
398
+ }
399
+
400
+ for (const node of await Promise.all(roots)) {
401
+ if (node === null) return false
402
+ }
403
+
404
+ return true
372
405
  }
373
406
 
374
407
  get (index, error = true) {
@@ -433,17 +466,23 @@ module.exports = class MerkleTree {
433
466
  // TODO: write neighbors together etc etc
434
467
  // TODO: bench loading a full disk page and copy to that instead
435
468
  return new Promise((resolve, reject) => {
436
- const slab = Buffer.allocUnsafe(40 * this.flushing.size)
469
+ const slab = b4a.allocUnsafe(40 * this.flushing.size)
437
470
 
438
471
  let error = null
439
472
  let missing = this.flushing.size + 1
440
473
  let offset = 0
441
474
 
442
475
  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)
476
+ const state = {
477
+ start: 0,
478
+ end: 40,
479
+ buffer: slab.subarray(offset, offset += 40)
480
+ }
481
+
482
+ c.uint64.encode(state, node.size)
483
+ c.raw.encode(state, node.hash)
484
+
485
+ this.storage.write(node.index * 40, state.buffer, done)
447
486
  }
448
487
 
449
488
  done(null)
@@ -510,8 +549,8 @@ module.exports = class MerkleTree {
510
549
 
511
550
  let unverified = null
512
551
 
513
- if (proof.block || proof.seek) {
514
- unverified = verifyBlock(proof, this.crypto, batch.nodes)
552
+ if (proof.block || proof.hash || proof.seek) {
553
+ unverified = verifyTree(proof, this.crypto, batch.nodes)
515
554
  }
516
555
 
517
556
  if (!verifyUpgrade(proof, unverified, batch)) {
@@ -520,7 +559,7 @@ module.exports = class MerkleTree {
520
559
 
521
560
  for (const root of batch.roots) {
522
561
  const existing = await this.get(root.index, false)
523
- if (existing && existing.hash.equals(root.hash)) continue
562
+ if (existing && b4a.equals(existing.hash, root.hash)) continue
524
563
  batch._updateDiffRoot(root)
525
564
  break
526
565
  }
@@ -538,7 +577,7 @@ module.exports = class MerkleTree {
538
577
  async verify (proof) {
539
578
  const batch = new MerkleTreeBatch(this)
540
579
 
541
- let unverified = verifyBlock(proof, this.crypto, batch.nodes)
580
+ let unverified = verifyTree(proof, this.crypto, batch.nodes)
542
581
 
543
582
  if (proof.upgrade) {
544
583
  if (verifyUpgrade(proof, unverified, batch)) {
@@ -548,7 +587,7 @@ module.exports = class MerkleTree {
548
587
 
549
588
  if (unverified) {
550
589
  const verified = await this.get(unverified.index)
551
- if (!verified.hash.equals(unverified.hash)) {
590
+ if (!b4a.equals(verified.hash, unverified.hash)) {
552
591
  throw new Error('Invalid checksum at node ' + unverified.index)
553
592
  }
554
593
  }
@@ -556,89 +595,102 @@ module.exports = class MerkleTree {
556
595
  return batch
557
596
  }
558
597
 
559
- async proof ({ block, seek, upgrade }) {
598
+ async proof ({ block, hash, seek, upgrade }) {
560
599
  // Important that this does not throw inbetween making the promise arrays
561
600
  // and finalise being called, otherwise there will be lingering promises in the background
562
601
 
563
- const signature = this.signature
564
602
  const fork = this.fork
603
+ const signature = this.signature
565
604
  const head = 2 * this.length
566
605
  const from = upgrade ? upgrade.start * 2 : 0
567
606
  const to = upgrade ? from + upgrade.length * 2 : head
607
+ const node = normalizeIndexed(block, hash)
568
608
 
569
609
  if (from >= to || to > head) {
570
610
  throw new Error('Invalid upgrade')
571
611
  }
572
- if (seek && block && upgrade && block.index * 2 >= from) {
573
- throw new Error('Cannot both do a seek and block request when upgrading')
612
+ if (seek && upgrade && node !== null && node.index >= from) {
613
+ throw new Error('Cannot both do a seek and block/hash request when upgrading')
574
614
  }
575
615
 
576
616
  let subTree = head
577
617
 
578
618
  const p = {
579
- block: null,
619
+ node: null,
580
620
  seek: null,
581
621
  upgrade: null,
582
622
  additionalUpgrade: null
583
623
  }
584
624
 
585
- if (block && (!upgrade || block.index < upgrade.start)) {
586
- subTree = nodesToRoot(2 * block.index, block.nodes, to)
625
+ if (node !== null && (!upgrade || node.lastIndex < upgrade.start)) {
626
+ subTree = nodesToRoot(node.index, node.nodes, to)
587
627
  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
628
+ blockAndSeekProof(this, node, seek, seekRoot, subTree, p)
629
+ } else if ((node || seek) && upgrade) {
630
+ subTree = seek ? await seekFromHead(this, to, seek.bytes) : node.index
591
631
  }
592
632
 
593
633
  if (upgrade) {
594
- upgradeProof(this, block, seek, from, to, subTree, p)
634
+ upgradeProof(this, node, seek, from, to, subTree, p)
595
635
  if (head > to) additionalUpgradeProof(this, to, head, p)
596
636
  }
597
637
 
598
- try {
599
- const result = { fork, block: null, seek: null, upgrade: null }
600
-
601
- if (block) {
602
- const nodes = await Promise.all(p.block)
638
+ const [pNode, pSeek, pUpgrade, pAdditional] = await settleProof(p)
639
+ const result = { fork, block: null, hash: null, seek: null, upgrade: null }
603
640
 
604
- result.block = {
605
- index: block.index,
606
- value: null,
607
- nodes
608
- }
641
+ if (block) {
642
+ result.block = {
643
+ index: block.index,
644
+ value: null, // populated upstream, alloc it here for simplicity
645
+ nodes: pNode
646
+ }
647
+ } else if (hash) {
648
+ result.hash = {
649
+ index: hash.index,
650
+ nodes: pNode
609
651
  }
610
- if (seek && p.seek !== null) {
611
- const nodes = await Promise.all(p.seek)
652
+ }
612
653
 
613
- result.seek = {
614
- bytes: seek.bytes,
615
- nodes
616
- }
654
+ if (seek && pSeek !== null) {
655
+ result.seek = {
656
+ bytes: seek.bytes,
657
+ nodes: pSeek
617
658
  }
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
- }
659
+ }
660
+
661
+ if (upgrade) {
662
+ result.upgrade = {
663
+ start: upgrade.start,
664
+ length: upgrade.length,
665
+ nodes: pUpgrade,
666
+ additionalNodes: pAdditional || [],
667
+ signature
629
668
  }
669
+ }
630
670
 
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
671
+ return result
672
+ }
673
+
674
+ // Successor to .nodes()
675
+ async missingNodes (index) {
676
+ const head = 2 * this.length
677
+ const ite = flat.iterator(index)
678
+
679
+ // See iterator.rightSpan()
680
+ const iteRightSpan = ite.index + ite.factor / 2 - 1
681
+ // If the index is not in the current tree, we do not know how many missing nodes there are...
682
+ if (iteRightSpan >= head) return 0
683
+
684
+ let cnt = 0
685
+ while (!ite.contains(head) && (await this.get(ite.index, false)) === null) {
686
+ cnt++
687
+ ite.parent()
639
688
  }
689
+
690
+ return cnt
640
691
  }
641
692
 
693
+ // Deprecated
642
694
  async nodes (index) {
643
695
  const head = 2 * this.length
644
696
  const ite = flat.iterator(index)
@@ -693,7 +745,7 @@ module.exports = class MerkleTree {
693
745
  await new Promise((resolve, reject) => {
694
746
  storage.read(0, OLD_TREE.length, (err, buf) => {
695
747
  if (err) return resolve()
696
- if (buf.equals(OLD_TREE)) return reject(new Error('Storage contains an incompatible merkle tree'))
748
+ if (b4a.equals(buf, OLD_TREE)) return reject(new Error('Storage contains an incompatible merkle tree'))
697
749
  resolve()
698
750
  })
699
751
  })
@@ -713,8 +765,14 @@ module.exports = class MerkleTree {
713
765
 
714
766
  // All the methods needed for proof verification
715
767
 
716
- function verifyBlock ({ block, seek }, crypto, nodes) {
717
- if (!block && (!seek || !seek.nodes.length)) return null
768
+ function verifyTree ({ block, hash, seek }, crypto, nodes) {
769
+ const untrustedNode = block
770
+ ? { index: 2 * block.index, value: block.value, nodes: block.nodes }
771
+ : hash
772
+ ? { index: hash.index, value: null, nodes: hash.nodes }
773
+ : null
774
+
775
+ if (untrustedNode === null && (!seek || !seek.nodes.length)) return null
718
776
 
719
777
  let root = null
720
778
 
@@ -734,12 +792,12 @@ function verifyBlock ({ block, seek }, crypto, nodes) {
734
792
  }
735
793
  }
736
794
 
737
- if (!block) return root
795
+ if (untrustedNode === null) return root
738
796
 
739
- const ite = flat.iterator(2 * block.index)
740
- const blockHash = block.value && blockNode(crypto, ite.index, block.value)
797
+ const ite = flat.iterator(untrustedNode.index)
798
+ const blockHash = untrustedNode.value && blockNode(crypto, ite.index, untrustedNode.value)
741
799
 
742
- const q = new NodeQueue(block.nodes, root)
800
+ const q = new NodeQueue(untrustedNode.nodes, root)
743
801
 
744
802
  root = blockHash || q.shift(ite.index)
745
803
  nodes.push(root)
@@ -888,13 +946,13 @@ function seekProof (tree, seekRoot, root, p) {
888
946
  }
889
947
  }
890
948
 
891
- function blockAndSeekProof (tree, block, seek, seekRoot, root, p) {
892
- if (!block) return seekProof(tree, seekRoot, root, p)
949
+ function blockAndSeekProof (tree, node, seek, seekRoot, root, p) {
950
+ if (!node) return seekProof(tree, seekRoot, root, p)
893
951
 
894
- const ite = flat.iterator(2 * block.index)
952
+ const ite = flat.iterator(node.index)
895
953
 
896
- p.block = []
897
- if (!block.value) p.block.push(tree.get(ite.index))
954
+ p.node = []
955
+ if (!node.value) p.node.push(tree.get(ite.index))
898
956
 
899
957
  while (ite.index !== root) {
900
958
  ite.sibling()
@@ -902,14 +960,14 @@ function blockAndSeekProof (tree, block, seek, seekRoot, root, p) {
902
960
  if (seek && ite.contains(seekRoot) && ite.index !== seekRoot) {
903
961
  seekProof(tree, seekRoot, ite.index, p)
904
962
  } else {
905
- p.block.push(tree.get(ite.index))
963
+ p.node.push(tree.get(ite.index))
906
964
  }
907
965
 
908
966
  ite.parent()
909
967
  }
910
968
  }
911
969
 
912
- function upgradeProof (tree, block, seek, from, to, subTree, p) {
970
+ function upgradeProof (tree, node, seek, from, to, subTree, p) {
913
971
  if (from === 0) p.upgrade = []
914
972
 
915
973
  for (const ite = flat.iterator(0); ite.fullRoot(to); ite.nextTree()) {
@@ -928,8 +986,8 @@ function upgradeProof (tree, block, seek, from, to, subTree, p) {
928
986
  while (ite.index !== root) {
929
987
  ite.sibling()
930
988
  if (ite.index > target) {
931
- if (p.block === null && p.seek === null && ite.contains(subTree)) {
932
- blockAndSeekProof(tree, block, seek, subTree, ite.index, p)
989
+ if (p.node === null && p.seek === null && ite.contains(subTree)) {
990
+ blockAndSeekProof(tree, node, seek, subTree, ite.index, p)
933
991
  } else {
934
992
  p.upgrade.push(tree.get(ite.index))
935
993
  }
@@ -946,8 +1004,8 @@ function upgradeProof (tree, block, seek, from, to, subTree, p) {
946
1004
 
947
1005
  // if the subtree included is a child of this tree, include that one
948
1006
  // 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)
1007
+ if (p.node === null && p.seek === null && ite.contains(subTree)) {
1008
+ blockAndSeekProof(tree, node, seek, subTree, ite.index, p)
951
1009
  continue
952
1010
  }
953
1011
 
@@ -1038,10 +1096,10 @@ function getStoredNode (storage, index, error) {
1038
1096
  return
1039
1097
  }
1040
1098
 
1041
- const hash = data.slice(8)
1042
- const size = uint64le.decode(data, 0)
1099
+ const hash = data.subarray(8)
1100
+ const size = c.decode(c.uint64, data)
1043
1101
 
1044
- if (size === 0 && Buffer.compare(hash, BLANK_HASH) === 0) {
1102
+ if (size === 0 && b4a.compare(hash, BLANK_HASH) === 0) {
1045
1103
  if (error) reject(new Error('Could not load node: ' + index))
1046
1104
  else resolve(null)
1047
1105
  return
@@ -1087,10 +1145,27 @@ function log2 (n) {
1087
1145
  return res
1088
1146
  }
1089
1147
 
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
1148
+ function normalizeIndexed (block, hash) {
1149
+ if (block) return { value: true, index: block.index * 2, nodes: block.nodes, lastIndex: block.index }
1150
+ if (hash) return { value: false, index: hash.index, nodes: hash.nodes, lastIndex: flat.rightSpan(hash.index) / 2 }
1151
+ return null
1152
+ }
1153
+
1154
+ async function settleProof (p) {
1155
+ const result = [
1156
+ p.node && Promise.all(p.node),
1157
+ p.seek && Promise.all(p.seek),
1158
+ p.upgrade && Promise.all(p.upgrade),
1159
+ p.additionalUpgrade && Promise.all(p.additionalUpgrade)
1160
+ ]
1161
+
1162
+ try {
1163
+ return await Promise.all(result)
1164
+ } catch (err) {
1165
+ if (p.node) await Promise.allSettled(p.node)
1166
+ if (p.seek) await Promise.allSettled(p.seek)
1167
+ if (p.upgrade) await Promise.allSettled(p.upgrade)
1168
+ if (p.additionalUpgrade) await Promise.allSettled(p.additionalUpgrade)
1169
+ throw err
1170
+ }
1096
1171
  }