hypercore 11.0.29 → 11.0.30

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 CHANGED
@@ -14,8 +14,10 @@ const Core = require('./lib/core')
14
14
  const BlockEncryption = require('./lib/block-encryption')
15
15
  const Info = require('./lib/info')
16
16
  const Download = require('./lib/download')
17
+ const caps = require('./lib/caps')
17
18
  const { manifestHash, createManifest } = require('./lib/verifier')
18
19
  const { ReadStream, WriteStream, ByteStream } = require('./lib/streams')
20
+ const { MerkleTree } = require('./lib/merkle-tree')
19
21
  const {
20
22
  ASSERTION,
21
23
  BAD_ARGUMENT,
@@ -617,24 +619,6 @@ class Hypercore extends EventEmitter {
617
619
  this.emit('migrate', this.key)
618
620
  }
619
621
 
620
- createTreeBatch () {
621
- return this.state.createTreeBatch()
622
- }
623
-
624
- async restoreBatch (length, additionalBlocks = []) {
625
- if (this.opened === false) await this.opening
626
- const batch = this.state.createTreeBatch()
627
-
628
- if (length > batch.length + additionalBlocks.length) {
629
- throw BAD_ARGUMENT('Insufficient additional blocks were passed')
630
- }
631
-
632
- let i = 0
633
- while (batch.length < length) batch.append(additionalBlocks[i++])
634
-
635
- return length < batch.length ? batch.restore(length) : batch
636
- }
637
-
638
622
  findingPeers () {
639
623
  this._findingPeers++
640
624
  if (this.core !== null && !this.closing) this.core.replicator.findingPeers++
@@ -692,8 +676,7 @@ class Hypercore extends EventEmitter {
692
676
  if (this.opened === false) await this.opening
693
677
  if (!isValidIndex(bytes)) throw ASSERTION('seek is invalid')
694
678
 
695
- const tree = (opts && opts.tree) || this.state.core.tree
696
- const s = tree.seek(this.state, bytes, this.padding)
679
+ const s = MerkleTree.seek(this.state, bytes, this.padding)
697
680
 
698
681
  const offset = await s.update()
699
682
  if (offset) return offset
@@ -800,8 +783,6 @@ class Hypercore extends EventEmitter {
800
783
  }
801
784
 
802
785
  async _get (index, opts) {
803
- if (this.core.isFlushing) await this.core.flushed()
804
-
805
786
  const block = await readBlock(this.state.storage.read(), index)
806
787
 
807
788
  if (block !== null) return block
@@ -935,16 +916,30 @@ class Hypercore extends EventEmitter {
935
916
  return this.state.append(buffers, { keyPair, signature, preappend })
936
917
  }
937
918
 
938
- async treeHash (length) {
939
- if (length === undefined) {
940
- await this.ready()
941
- length = this.state.length
942
- }
919
+ async signable (length = -1, fork = -1) {
920
+ if (this.opened === false) await this.opening
921
+ if (length === -1) length = this.length
922
+ if (fork === -1) fork = this.fork
943
923
 
944
- const roots = await this.state.tree.getRoots(length)
924
+ return caps.treeSignable(this.key, await this.treeHash(length), length, fork)
925
+ }
926
+
927
+ async treeHash (length = -1) {
928
+ if (this.opened === false) await this.opening
929
+ if (length === -1) length = this.length
930
+
931
+ const roots = await MerkleTree.getRoots(this.state, length)
945
932
  return crypto.tree(roots)
946
933
  }
947
934
 
935
+ async proof (opts) {
936
+ if (this.opened === false) await this.opening
937
+ const rx = this.state.storage.read()
938
+ const promise = MerkleTree.proof(this.state, rx)
939
+ rx.tryFlush()
940
+ return promise
941
+ }
942
+
948
943
  registerExtension (name, handlers = {}) {
949
944
  if (this.extensions.has(name)) {
950
945
  const ext = this.extensions.get(name)
@@ -14,7 +14,7 @@ module.exports = copyPrologue
14
14
  async function copyPrologue (src, dst) {
15
15
  const prologue = dst.header.manifest.prologue
16
16
 
17
- if (src.tree.length < prologue.length || prologue.length === 0) return
17
+ if (src.length < prologue.length || prologue.length === 0) return
18
18
 
19
19
  const stack = []
20
20
  const roots = flat.fullRoots(prologue.length * 2)
package/lib/core.js CHANGED
@@ -4,7 +4,6 @@ const unslab = require('unslab')
4
4
  const z32 = require('z32')
5
5
  const Mutex = require('./mutex')
6
6
  const { MerkleTree, ReorgBatch } = require('./merkle-tree')
7
- const BlockStore = require('./block-store')
8
7
  const BitInterlude = require('./bit-interlude')
9
8
  const Bitfield = require('./bitfield')
10
9
  const RemoteBitfield = require('./remote-bitfield')
@@ -35,8 +34,6 @@ module.exports = class Core {
35
34
  this.preupdate = null
36
35
  this.header = null
37
36
  this.compat = false
38
- this.tree = null
39
- this.blocks = null
40
37
  this.bitfield = null
41
38
  this.verifier = null
42
39
  this.truncating = 0
@@ -54,9 +51,6 @@ module.exports = class Core {
54
51
  this.closed = false
55
52
 
56
53
  this._manifestFlushed = false
57
- this._onflush = null
58
- this._flushing = null
59
- this._activeBatch = null
60
54
  this._bitfield = null
61
55
  this._verifies = null
62
56
  this._verifiesFlushed = null
@@ -239,22 +233,20 @@ module.exports = class Core {
239
233
 
240
234
  const prologue = header.manifest ? header.manifest.prologue : null
241
235
 
242
- const tree = await MerkleTree.open(storage)
243
236
  const bitfield = await Bitfield.open(storage, header.tree.length)
244
- const blocks = new BlockStore(storage)
245
237
 
246
238
  const treeInfo = {
247
239
  fork: header.tree.fork,
248
240
  length: header.tree.length,
249
241
  signature: header.tree.signature,
250
- roots: header.tree.length ? await tree.getRoots(header.tree.length) : [],
242
+ roots: header.tree.length ? await MerkleTree.getRootsFromStorage(storage, header.tree.length) : [],
251
243
  prologue
252
244
  }
253
245
 
254
246
  if (overwrite) {
255
247
  const tx = storage.write()
256
- tree.clear(tx)
257
- blocks.clear(tx)
248
+ tx.deleteTreeNodeRange(0, -1)
249
+ tx.deleteBlockRange(0, -1)
258
250
  bitfield.clear(tx)
259
251
  await tx.flush()
260
252
  }
@@ -282,11 +274,9 @@ module.exports = class Core {
282
274
  this.storage = storage
283
275
  this.header = header
284
276
  this.compat = compat
285
- this.tree = tree
286
- this.blocks = blocks
287
277
  this.bitfield = bitfield
288
278
  this.verifier = verifier
289
- this.state = new SessionState(this, null, storage, this.blocks, tree, treeInfo, null)
279
+ this.state = new SessionState(this, null, storage, treeInfo, null)
290
280
 
291
281
  if (this.key === null) this.key = this.header.key
292
282
  if (this.discoveryKey === null) this.discoveryKey = crypto.discoveryKey(this.key)
@@ -323,8 +313,7 @@ module.exports = class Core {
323
313
 
324
314
  const tx = this.state.createWriteBatch()
325
315
  this._setManifest(tx, Verifier.createManifest(manifest), null)
326
-
327
- if (await this.state.flush(tx)) this.replicator.onupgrade()
316
+ await this.state.flush()
328
317
  }
329
318
  } finally {
330
319
  this.state._unlock()
@@ -377,10 +366,6 @@ module.exports = class Core {
377
366
  }
378
367
  }
379
368
 
380
- get isFlushing () {
381
- return !!(this._flushing || this.state._activeBatch)
382
- }
383
-
384
369
  flushed () {
385
370
  return this.state.flushed()
386
371
  }
@@ -392,7 +377,7 @@ module.exports = class Core {
392
377
 
393
378
  if (this.state.length > treeLength) {
394
379
  for (const root of this.state.roots) {
395
- const batchRoot = await state.tree.get(root.index)
380
+ const batchRoot = await MerkleTree.get(state, root.index)
396
381
  if (batchRoot.size !== root.size || !b4a.equals(batchRoot.hash, root.hash)) {
397
382
  return false
398
383
  }
@@ -487,7 +472,7 @@ module.exports = class Core {
487
472
 
488
473
  const ranges = bits.flush(tx, this.bitfield)
489
474
 
490
- await this.state.flush(tx)
475
+ await this.state.flush()
491
476
 
492
477
  for (const { start, end, value } of ranges) {
493
478
  this._setBitfieldRanges(start, end, value)
@@ -514,7 +499,7 @@ module.exports = class Core {
514
499
  return false
515
500
  }
516
501
 
517
- const batch = this.tree.verifyFullyRemote(proof, this.state)
502
+ const batch = MerkleTree.verifyFullyRemote(this.state, proof)
518
503
 
519
504
  try {
520
505
  this._verifyBatchUpgrade(batch, proof.manifest)
@@ -530,13 +515,13 @@ module.exports = class Core {
530
515
  this._setManifest(tx, proof.manifest, null)
531
516
  }
532
517
 
533
- await this.state.flush(tx)
518
+ await this.state.flush()
534
519
  } finally {
535
520
  this.state.mutex.unlock()
536
521
  }
537
522
 
538
523
  const remoteTreeHash = crypto.tree(proof.upgrade.nodes)
539
- const localTreeHash = crypto.tree(await this.tree.getRoots(proof.upgrade.length))
524
+ const localTreeHash = crypto.tree(await MerkleTree.getRootsFromStorage(this.storage, proof.upgrade.length))
540
525
 
541
526
  if (b4a.equals(localTreeHash, remoteTreeHash)) return false
542
527
 
@@ -545,8 +530,8 @@ module.exports = class Core {
545
530
  }
546
531
 
547
532
  async verifyReorg (proof) {
548
- const batch = new ReorgBatch(this.tree, this.state)
549
- await this.tree.reorg(proof, batch)
533
+ const batch = new ReorgBatch(this.state)
534
+ await MerkleTree.reorg(this.state, proof, batch)
550
535
  this._verifyBatchUpgrade(batch, proof.manifest)
551
536
  return batch
552
537
  }
@@ -557,7 +542,7 @@ module.exports = class Core {
557
542
  // but this is easy atm (and the above layer will just retry)
558
543
  if (proof.fork !== this.state.fork) return false
559
544
 
560
- const batch = await this.tree.verify(proof, this.state)
545
+ const batch = await MerkleTree.verify(this.state, proof)
561
546
  if (!batch.commitable()) return false
562
547
 
563
548
  const value = (proof.block && proof.block.value) || null
@@ -36,7 +36,7 @@ class NodeQueue {
36
36
  }
37
37
 
38
38
  class MerkleTreeBatch {
39
- constructor (tree, session) {
39
+ constructor (session) {
40
40
  this.fork = session.fork
41
41
  this.roots = [...session.roots]
42
42
  this.length = session.length
@@ -50,8 +50,7 @@ class MerkleTreeBatch {
50
50
  this.truncated = false
51
51
  this.treeLength = session.length
52
52
  this.treeFork = session.fork
53
- this.tree = tree
54
- this.storage = tree.storage
53
+ this.storage = session.storage
55
54
  this.session = session
56
55
  this.nodes = []
57
56
  this.upgraded = false
@@ -120,7 +119,7 @@ class MerkleTreeBatch {
120
119
  }
121
120
 
122
121
  clone () {
123
- const b = new MerkleTreeBatch(this.tree, this.session)
122
+ const b = new MerkleTreeBatch(this.session)
124
123
 
125
124
  b.fork = this.fork
126
125
  b.roots = [...this.roots]
@@ -158,11 +157,12 @@ class MerkleTreeBatch {
158
157
  if (n.index === index) return n
159
158
  }
160
159
 
161
- return this.tree.get(index, error)
160
+ return MerkleTree.get(this.session, index, error)
162
161
  }
163
162
 
163
+ // deprecated, use sssion proof instead
164
164
  proof (batch, { block, hash, seek, upgrade }) {
165
- return generateProof(batch, this, block, hash, seek, upgrade)
165
+ return generateProof(this.session, batch, block, hash, seek, upgrade)
166
166
  }
167
167
 
168
168
  verifyUpgrade (proof) {
@@ -287,7 +287,7 @@ class MerkleTreeBatch {
287
287
  async restore (length) {
288
288
  if (length === this.length) return this
289
289
 
290
- const roots = unslabNodes(await this.tree.getRoots(length))
290
+ const roots = unslabNodes(await MerkleTree.getRootsFromStorage(this.storage, length))
291
291
 
292
292
  this.roots = roots
293
293
  this.length = length
@@ -301,8 +301,8 @@ class MerkleTreeBatch {
301
301
  }
302
302
 
303
303
  class ReorgBatch extends MerkleTreeBatch {
304
- constructor (tree, session) {
305
- super(tree, session)
304
+ constructor (session) {
305
+ super(session)
306
306
 
307
307
  this.roots = []
308
308
  this.length = 0
@@ -347,7 +347,7 @@ class ReorgBatch extends MerkleTreeBatch {
347
347
  const left = n.get(ite.leftChild())
348
348
  if (!left) break
349
349
 
350
- const existing = await this.tree.get(left.index, false)
350
+ const existing = await MerkleTree.get(this.session, left.index, false)
351
351
  if (!existing || !b4a.equals(existing.hash, left.hash)) {
352
352
  diff = left
353
353
  } else {
@@ -387,16 +387,15 @@ class ReorgBatch extends MerkleTreeBatch {
387
387
  }
388
388
 
389
389
  class ByteSeeker {
390
- constructor (tree, session, bytes, padding = 0) {
391
- this.tree = tree
390
+ constructor (session, bytes, padding = 0) {
392
391
  this.session = session
393
392
  this.bytes = bytes
394
393
  this.padding = padding
395
394
 
396
- const size = tree.byteLength - (tree.length * padding)
395
+ const size = session.byteLength - (session.length * padding)
397
396
 
398
- this.start = bytes >= size ? tree.length : 0
399
- this.end = bytes < size ? tree.length : 0
397
+ this.start = bytes >= size ? session.length : 0
398
+ this.end = bytes < size ? session.length : 0
400
399
  }
401
400
 
402
401
  async _seek (bytes) {
@@ -414,7 +413,7 @@ class ByteSeeker {
414
413
  const ite = flat.iterator(node.index)
415
414
 
416
415
  while ((ite.index & 1) !== 0) {
417
- const l = await this.tree.get(ite.leftChild(), false)
416
+ const l = await MerkleTree.get(this.session, ite.leftChild(), false)
418
417
 
419
418
  if (l) {
420
419
  const size = getUnpaddedSize(l, this.padding, ite)
@@ -449,9 +448,9 @@ class ByteSeeker {
449
448
  }
450
449
 
451
450
  class TreeProof {
452
- constructor (tree, block, hash, seek, upgrade) {
453
- this.fork = tree.fork
454
- this.signature = tree.signature
451
+ constructor (session, block, hash, seek, upgrade) {
452
+ this.fork = session.fork
453
+ this.signature = session.signature
455
454
 
456
455
  this.block = block
457
456
  this.hash = hash
@@ -508,10 +507,6 @@ class TreeProof {
508
507
  }
509
508
 
510
509
  class MerkleTree {
511
- constructor (storage) {
512
- this.storage = storage
513
- }
514
-
515
510
  static hash (s) {
516
511
  return unslab(crypto.tree(s.roots))
517
512
  }
@@ -528,14 +523,14 @@ class MerkleTree {
528
523
  return totalSpan(roots)
529
524
  }
530
525
 
531
- clone (storage) {
532
- return new MerkleTree(storage)
526
+ static getRoots (session, length) {
527
+ return MerkleTree.getRootsFromStorage(session.storage, length)
533
528
  }
534
529
 
535
- getRoots (length) {
530
+ static getRootsFromStorage (storage, length) {
536
531
  const indexes = flat.fullRoots(2 * length)
537
532
  const roots = new Array(indexes.length)
538
- const readBatch = this.storage.read()
533
+ const readBatch = storage.read()
539
534
 
540
535
  for (let i = 0; i < indexes.length; i++) {
541
536
  roots[i] = readBatch.getTreeNode(indexes[i], true)
@@ -546,7 +541,7 @@ class MerkleTree {
546
541
  return Promise.all(roots)
547
542
  }
548
543
 
549
- getNeededNodes (length, start, end) {
544
+ static getNeededNodes (session, length, start, end) {
550
545
  const nodes = new Map()
551
546
  const head = length * 2
552
547
 
@@ -555,7 +550,7 @@ class MerkleTree {
555
550
 
556
551
  while (true) {
557
552
  if (nodes.has(ite.index)) break
558
- nodes.set(ite.index, this.get(ite.index, true))
553
+ nodes.set(ite.index, this.get(session, ite.index, true))
559
554
 
560
555
  const sibling = ite.sibling()
561
556
 
@@ -563,17 +558,17 @@ class MerkleTree {
563
558
  if (ite.contains(head)) break
564
559
 
565
560
  if (nodes.has(sibling)) break
566
- nodes.set(sibling, this.get(sibling, true))
561
+ nodes.set(sibling, this.get(session, sibling, true))
567
562
  }
568
563
  }
569
564
 
570
565
  return Promise.all([...nodes.values()])
571
566
  }
572
567
 
573
- async upgradeable (length) {
568
+ static async upgradeable (session, length) {
574
569
  const indexes = flat.fullRoots(2 * length)
575
570
  const roots = new Array(indexes.length)
576
- const readBatch = this.storage.read()
571
+ const readBatch = session.storage.read()
577
572
 
578
573
  for (let i = 0; i < indexes.length; i++) {
579
574
  roots[i] = readBatch.getTreeNode(indexes[i], false)
@@ -588,24 +583,17 @@ class MerkleTree {
588
583
  return true
589
584
  }
590
585
 
591
- seek (session, bytes, padding) {
592
- return new ByteSeeker(this, session, bytes, padding)
586
+ static seek (session, bytes, padding) {
587
+ return new ByteSeeker(session, bytes, padding)
593
588
  }
594
589
 
595
- get (index, error = true, readBatch = null) {
590
+ static get (session, index, error = true, readBatch = null) {
596
591
  if (readBatch) return readBatch.getTreeNode(index, error)
597
592
 
598
- return getTreeNode(this.storage, index, error)
593
+ return getTreeNode(session.storage, index, error)
599
594
  }
600
595
 
601
- clear (tx) {
602
- this.truncated = true
603
- this.truncateTo = 0
604
-
605
- return tx.deleteTreeNodeRange(0, -1)
606
- }
607
-
608
- async truncate (length, batch, fork = batch.fork) {
596
+ static async truncate (session, length, batch, fork = batch.fork) {
609
597
  const head = length * 2
610
598
  const fullRoots = flat.fullRoots(head)
611
599
 
@@ -614,7 +602,7 @@ class MerkleTree {
614
602
  if (i < batch.roots.length && batch.roots[i].index === root) continue
615
603
 
616
604
  while (batch.roots.length > i) batch.roots.pop()
617
- batch.roots.push(unslabNode(await this.get(root)))
605
+ batch.roots.push(unslabNode(await this.get(session, root)))
618
606
  }
619
607
 
620
608
  while (batch.roots.length > fullRoots.length) {
@@ -630,7 +618,7 @@ class MerkleTree {
630
618
  return batch
631
619
  }
632
620
 
633
- async reorg (proof, batch) {
621
+ static async reorg (session, proof, batch) {
634
622
  let unverified = null
635
623
 
636
624
  if (proof.block || proof.hash || proof.seek) {
@@ -642,7 +630,7 @@ class MerkleTree {
642
630
  }
643
631
 
644
632
  for (const root of batch.roots) {
645
- const existing = await this.get(root.index, false)
633
+ const existing = await MerkleTree.get(session, root.index, false)
646
634
  if (existing && b4a.equals(existing.hash, root.hash)) continue
647
635
  batch._updateDiffRoot(root)
648
636
  break
@@ -658,9 +646,9 @@ class MerkleTree {
658
646
  return batch
659
647
  }
660
648
 
661
- verifyFullyRemote (proof, session) {
649
+ static verifyFullyRemote (session, proof) {
662
650
  // TODO: impl this less hackishly
663
- const batch = new MerkleTreeBatch(this, session)
651
+ const batch = new MerkleTreeBatch(session)
664
652
 
665
653
  batch.fork = proof.fork
666
654
  batch.roots = []
@@ -679,8 +667,8 @@ class MerkleTree {
679
667
  return batch
680
668
  }
681
669
 
682
- async verify (proof, session) {
683
- const batch = new MerkleTreeBatch(this, session)
670
+ static async verify (session, proof) {
671
+ const batch = new MerkleTreeBatch(session)
684
672
 
685
673
  let unverified = verifyTree(proof, batch.nodes)
686
674
 
@@ -691,7 +679,7 @@ class MerkleTree {
691
679
  }
692
680
 
693
681
  if (unverified) {
694
- const verified = await this.get(unverified.index)
682
+ const verified = await MerkleTree.get(session, unverified.index)
695
683
  if (!b4a.equals(verified.hash, unverified.hash)) {
696
684
  throw INVALID_CHECKSUM('Invalid checksum at node ' + unverified.index)
697
685
  }
@@ -700,12 +688,11 @@ class MerkleTree {
700
688
  return batch
701
689
  }
702
690
 
703
- proof (rx, batch, { block, hash, seek, upgrade }) {
704
- return generateProof(rx, batch, block, hash, seek, upgrade)
691
+ static proof (session, rx, { block, hash, seek, upgrade }) {
692
+ return generateProof(session, rx, block, hash, seek, upgrade)
705
693
  }
706
694
 
707
- // Successor to .nodes()
708
- async missingNodes (index, length) {
695
+ static async missingNodes (session, index, length) {
709
696
  const head = 2 * length
710
697
  const ite = flat.iterator(index)
711
698
 
@@ -716,7 +703,7 @@ class MerkleTree {
716
703
 
717
704
  let cnt = 0
718
705
  // TODO: we could prop use a read batch here and do this in blocks of X for perf
719
- while (!ite.contains(head) && !(await hasTreeNode(this.storage, ite.index))) {
706
+ while (!ite.contains(head) && !(await hasTreeNode(session.storage, ite.index))) {
720
707
  cnt++
721
708
  ite.parent()
722
709
  }
@@ -724,27 +711,16 @@ class MerkleTree {
724
711
  return cnt
725
712
  }
726
713
 
727
- // Deprecated
728
- async nodes (index) {
729
- const head = 2 * this.length
730
- const ite = flat.iterator(index)
731
-
732
- let cnt = 0
733
- while (!ite.contains(head) && (await this.get(ite.index, false)) === null) {
734
- cnt++
735
- ite.parent()
736
- }
737
-
738
- return cnt
714
+ static byteOffset (session, index) {
715
+ return getByteOffsetSession(session, index, null)
739
716
  }
740
717
 
741
- static async open (storage, length, opts = {}) {
742
- const roots = []
743
- for (const index of flat.fullRoots(2 * length)) {
744
- roots.push(unslabNode(await getTreeNode(storage, index, true)))
745
- }
746
-
747
- return new MerkleTree(storage, roots, opts.fork || 0, opts.signature || null, opts.prologue || null)
718
+ static byteRange (session, index) {
719
+ const rx = session.storage.read()
720
+ const offset = getByteOffsetSession(session, index, rx)
721
+ const size = getNodeSize(index, rx)
722
+ rx.tryFlush()
723
+ return Promise.all([offset, size])
748
724
  }
749
725
  }
750
726
 
@@ -758,14 +734,44 @@ async function getNodeSize (index, readBatch) {
758
734
  return (await readBatch.getTreeNode(index, true)).size
759
735
  }
760
736
 
761
- function getByteOffsetTree (tree, index, readBatch) {
737
+ async function getByteOffsetSession (session, index, readBatch) {
738
+ if (index === 2 * session.length) return session.byteLength
739
+
740
+ const treeNodes = readBatch === null
741
+ ? await getByteOffsetBatchFlush(session.roots, index, session.storage.read())
742
+ : await getByteOffsetBatch(session.roots, index, readBatch)
743
+
744
+ let offset = 0
745
+ for (const node of treeNodes) offset += node.size
746
+
747
+ return offset
748
+ }
749
+
750
+ async function getByteOffset (tree, index, readBatch) {
751
+ if (index === 2 * tree.length) return tree.byteLength
752
+
753
+ const treeNodes = await getByteOffsetBatch(tree.roots, index, readBatch)
754
+
755
+ let offset = 0
756
+ for (const node of treeNodes) offset += node.size
757
+
758
+ return offset
759
+ }
760
+
761
+ function getByteOffsetBatchFlush (roots, index, readBatch) {
762
+ const treeNodes = getByteOffsetBatch(roots, index, readBatch)
763
+ readBatch.tryFlush()
764
+ return treeNodes
765
+ }
766
+
767
+ function getByteOffsetBatch (roots, index, readBatch) {
762
768
  if ((index & 1) === 1) index = flat.leftSpan(index)
763
769
 
764
770
  let head = 0
765
771
 
766
772
  const promises = []
767
773
 
768
- for (const node of tree.roots) { // all async ticks happen once we find the root so safe
774
+ for (const node of roots) { // all async ticks happen once we find the root so safe
769
775
  head += 2 * ((node.index - head) + 1)
770
776
 
771
777
  if (index >= head) {
@@ -779,7 +785,7 @@ function getByteOffsetTree (tree, index, readBatch) {
779
785
  if (index < ite.index) {
780
786
  ite.leftChild()
781
787
  } else {
782
- promises.push(tree.get(ite.leftChild(), true, readBatch))
788
+ promises.push(readBatch.getTreeNode(ite.leftChild(), true))
783
789
  ite.sibling()
784
790
  }
785
791
  }
@@ -790,17 +796,6 @@ function getByteOffsetTree (tree, index, readBatch) {
790
796
  throw ASSERTION('Failed to find offset')
791
797
  }
792
798
 
793
- async function getByteOffset (tree, index, readBatch) {
794
- if (index === 2 * tree.length) return tree.byteLength
795
-
796
- const treeNodes = await getByteOffsetTree(tree, index, readBatch)
797
-
798
- let offset = 0
799
- for (const node of treeNodes) offset += node.size
800
-
801
- return offset
802
- }
803
-
804
799
  function getByteRange (tree, index, readBatch) {
805
800
  const head = 2 * tree.length
806
801
  if (((index & 1) === 0 ? index : flat.rightSpan(index)) >= head) {
@@ -935,12 +930,13 @@ function verifyUpgrade ({ fork, upgrade }, blockRoot, batch) {
935
930
  return q.extra === null
936
931
  }
937
932
 
938
- async function seekFromHead (tree, head, bytes, padding) {
933
+ async function seekFromHead (session, head, bytes, padding) {
939
934
  const roots = flat.fullRoots(head)
940
935
 
941
936
  for (let i = 0; i < roots.length; i++) {
942
937
  const root = roots[i]
943
- const node = await tree.get(root, true)
938
+ const node = await MerkleTree.get(session, root, false)
939
+ if (node === null) throw new Error('Tree node missing')
944
940
  const size = getUnpaddedSize(node, padding, null)
945
941
 
946
942
  if (bytes === size) return root
@@ -949,7 +945,7 @@ async function seekFromHead (tree, head, bytes, padding) {
949
945
  continue
950
946
  }
951
947
 
952
- return seekTrustedTree(tree, root, bytes, padding)
948
+ return seekTrustedTree(session, root, bytes, padding)
953
949
  }
954
950
 
955
951
  return head
@@ -957,13 +953,13 @@ async function seekFromHead (tree, head, bytes, padding) {
957
953
 
958
954
  // trust that bytes are within the root tree and find the block at bytes
959
955
 
960
- async function seekTrustedTree (tree, root, bytes, padding) {
956
+ async function seekTrustedTree (session, root, bytes, padding) {
961
957
  if (!bytes) return root
962
958
 
963
959
  const ite = flat.iterator(root)
964
960
 
965
961
  while ((ite.index & 1) !== 0) {
966
- const l = await tree.get(ite.leftChild(), false)
962
+ const l = await MerkleTree.get(session, ite.leftChild(), false)
967
963
 
968
964
  if (l) {
969
965
  const size = getUnpaddedSize(l, padding, ite)
@@ -982,60 +978,61 @@ async function seekTrustedTree (tree, root, bytes, padding) {
982
978
 
983
979
  // try to find the block at bytes without trusting that is *is* within the root passed
984
980
 
985
- async function seekUntrustedTree (tree, root, bytes, padding) {
986
- const offset = await tree.byteOffset(root) - (padding ? padding * flat.leftSpan(root) / 2 : 0)
981
+ async function seekUntrustedTree (session, root, bytes, padding) {
982
+ const offset = await getByteOffsetSession(session, root, null) - (padding ? padding * flat.leftSpan(root) / 2 : 0)
987
983
 
988
984
  if (offset > bytes) throw INVALID_OPERATION('Invalid seek')
989
985
  if (offset === bytes) return root
990
986
 
991
987
  bytes -= offset
992
988
 
993
- const node = await tree.get(root, true)
989
+ const node = await MerkleTree.get(session, root, false)
990
+ if (node === null) throw new Error('Tree node missing')
994
991
 
995
992
  if (getUnpaddedSize(node, padding, null) <= bytes) throw INVALID_OPERATION('Invalid seek')
996
993
 
997
- return seekTrustedTree(tree, root, bytes, padding)
994
+ return seekTrustedTree(session, root, bytes, padding)
998
995
  }
999
996
 
1000
997
  // Below is proof production, ie, construct proofs to verify a request
1001
998
  // Note, that all these methods are sync as we can statically infer which nodes
1002
999
  // are needed for the remote to verify given they arguments they passed us
1003
1000
 
1004
- function seekProof (tree, batch, seekRoot, root, p) {
1001
+ function seekProof (session, batch, seekRoot, root, p) {
1005
1002
  const ite = flat.iterator(seekRoot)
1006
1003
 
1007
1004
  p.seek = []
1008
- p.seek.push(tree.get(ite.index, true, batch))
1005
+ p.seek.push(MerkleTree.get(session, ite.index, true, batch))
1009
1006
 
1010
1007
  while (ite.index !== root) {
1011
1008
  ite.sibling()
1012
- p.seek.push(tree.get(ite.index, true, batch))
1009
+ p.seek.push(MerkleTree.get(session, ite.index, true, batch))
1013
1010
  ite.parent()
1014
1011
  }
1015
1012
  }
1016
1013
 
1017
- function blockAndSeekProof (tree, batch, node, seek, seekRoot, root, p) {
1018
- if (!node) return seekProof(tree, batch, seekRoot, root, p)
1014
+ function blockAndSeekProof (session, batch, node, seek, seekRoot, root, p) {
1015
+ if (!node) return seekProof(session, batch, seekRoot, root, p)
1019
1016
 
1020
1017
  const ite = flat.iterator(node.index)
1021
1018
 
1022
1019
  p.node = []
1023
- if (!node.value) p.node.push(tree.get(ite.index, true, batch))
1020
+ if (!node.value) p.node.push(MerkleTree.get(session, ite.index, true, batch))
1024
1021
 
1025
1022
  while (ite.index !== root) {
1026
1023
  ite.sibling()
1027
1024
 
1028
1025
  if (seek && ite.contains(seekRoot) && ite.index !== seekRoot) {
1029
- seekProof(tree, batch, seekRoot, ite.index, p)
1026
+ seekProof(session, batch, seekRoot, ite.index, p)
1030
1027
  } else {
1031
- p.node.push(tree.get(ite.index, true, batch))
1028
+ p.node.push(MerkleTree.get(session, ite.index, true, batch))
1032
1029
  }
1033
1030
 
1034
1031
  ite.parent()
1035
1032
  }
1036
1033
  }
1037
1034
 
1038
- function upgradeProof (tree, batch, node, seek, from, to, subTree, p) {
1035
+ function upgradeProof (session, batch, node, seek, from, to, subTree, p) {
1039
1036
  if (from === 0) p.upgrade = []
1040
1037
 
1041
1038
  for (const ite = flat.iterator(0); ite.fullRoot(to); ite.nextTree()) {
@@ -1055,7 +1052,7 @@ function upgradeProof (tree, batch, node, seek, from, to, subTree, p) {
1055
1052
  ite.sibling()
1056
1053
  if (ite.index > target) {
1057
1054
  if (p.node === null && p.seek === null && ite.contains(subTree)) {
1058
- blockAndSeekProof(tree, batch, node, seek, subTree, ite.index, p)
1055
+ blockAndSeekProof(session, batch, node, seek, subTree, ite.index, p)
1059
1056
  } else {
1060
1057
  p.upgrade.push(batch.getTreeNode(ite.index, true))
1061
1058
  }
@@ -1073,16 +1070,16 @@ function upgradeProof (tree, batch, node, seek, from, to, subTree, p) {
1073
1070
  // if the subtree included is a child of this tree, include that one
1074
1071
  // instead of a dup node
1075
1072
  if (p.node === null && p.seek === null && ite.contains(subTree)) {
1076
- blockAndSeekProof(tree, batch, node, seek, subTree, ite.index, p)
1073
+ blockAndSeekProof(session, batch, node, seek, subTree, ite.index, p)
1077
1074
  continue
1078
1075
  }
1079
1076
 
1080
1077
  // add root (can be optimised since the root might be in tree.roots)
1081
- p.upgrade.push(tree.get(ite.index, true, batch))
1078
+ p.upgrade.push(MerkleTree.get(session, ite.index, true, batch))
1082
1079
  }
1083
1080
  }
1084
1081
 
1085
- function additionalUpgradeProof (tree, batch, from, to, p) {
1082
+ function additionalUpgradeProof (session, batch, from, to, p) {
1086
1083
  if (from === 0) p.additionalUpgrade = []
1087
1084
 
1088
1085
  for (const ite = flat.iterator(0); ite.fullRoot(to); ite.nextTree()) {
@@ -1101,7 +1098,7 @@ function additionalUpgradeProof (tree, batch, from, to, p) {
1101
1098
  while (ite.index !== root) {
1102
1099
  ite.sibling()
1103
1100
  if (ite.index > target) {
1104
- p.additionalUpgrade.push(tree.get(ite.index, true, batch))
1101
+ p.additionalUpgrade.push(MerkleTree.get(session, ite.index, true, batch))
1105
1102
  }
1106
1103
  ite.parent()
1107
1104
  }
@@ -1114,7 +1111,7 @@ function additionalUpgradeProof (tree, batch, from, to, p) {
1114
1111
  }
1115
1112
 
1116
1113
  // add root (can be optimised since the root is in tree.roots)
1117
- p.additionalUpgrade.push(tree.get(ite.index, true, batch))
1114
+ p.additionalUpgrade.push(MerkleTree.get(session, ite.index, true, batch))
1118
1115
  }
1119
1116
  }
1120
1117
 
@@ -1200,22 +1197,22 @@ async function settleProof (p) {
1200
1197
  }
1201
1198
 
1202
1199
  // tree can be either the merkle tree or a merkle tree batch
1203
- async function generateProof (readBatch, tree, block, hash, seek, upgrade) {
1200
+ async function generateProof (session, readBatch, block, hash, seek, upgrade) {
1204
1201
  // Important that this does not throw inbetween making the promise arrays
1205
1202
  // and finalise being called, otherwise there will be lingering promises in the background
1206
1203
 
1207
- if (tree.prologue && upgrade) {
1208
- upgrade.start = upgrade.start < tree.prologue.length ? 0 : upgrade.start
1209
- upgrade.length = upgrade.start < tree.prologue.length ? tree.prologue.length : upgrade.length
1204
+ if (session.prologue && upgrade) {
1205
+ upgrade.start = upgrade.start < session.prologue.length ? 0 : upgrade.start
1206
+ upgrade.length = upgrade.start < session.prologue.length ? session.prologue.length : upgrade.length
1210
1207
  }
1211
1208
 
1212
- const head = 2 * tree.length
1209
+ const head = 2 * session.length
1213
1210
  const from = upgrade ? upgrade.start * 2 : 0
1214
1211
  const to = upgrade ? from + upgrade.length * 2 : head
1215
1212
  const node = normalizeIndexed(block, hash)
1216
1213
 
1217
1214
  // can't do anything as we have no data...
1218
- if (head === 0) return new TreeProof(tree, null, null, null, null)
1215
+ if (head === 0) return new TreeProof(session, null, null, null, null)
1219
1216
 
1220
1217
  if (from >= to || to > head) {
1221
1218
  throw INVALID_OPERATION('Invalid upgrade')
@@ -1226,19 +1223,19 @@ async function generateProof (readBatch, tree, block, hash, seek, upgrade) {
1226
1223
 
1227
1224
  let subTree = head
1228
1225
 
1229
- const p = new TreeProof(tree, block, hash, seek, upgrade)
1226
+ const p = new TreeProof(session, block, hash, seek, upgrade)
1230
1227
 
1231
1228
  if (node !== null && (!upgrade || node.lastIndex < upgrade.start)) {
1232
1229
  subTree = nodesToRoot(node.index, node.nodes, to)
1233
- const seekRoot = seek ? await seekUntrustedTree(tree, subTree, seek.bytes, seek.padding) : head
1234
- blockAndSeekProof(tree, readBatch, node, seek, seekRoot, subTree, p.pending)
1230
+ const seekRoot = seek ? await seekUntrustedTree(session, subTree, seek.bytes, seek.padding) : head
1231
+ blockAndSeekProof(session, readBatch, node, seek, seekRoot, subTree, p.pending)
1235
1232
  } else if ((node || seek) && upgrade) {
1236
- subTree = seek ? await seekFromHead(tree, to, seek.bytes, seek.padding) : node.index
1233
+ subTree = seek ? await seekFromHead(session, to, seek.bytes, seek.padding) : node.index
1237
1234
  }
1238
1235
 
1239
1236
  if (upgrade) {
1240
- upgradeProof(tree, readBatch, node, seek, from, to, subTree, p.pending)
1241
- if (head > to) additionalUpgradeProof(tree, readBatch, to, head, p.pending)
1237
+ upgradeProof(session, readBatch, node, seek, from, to, subTree, p.pending)
1238
+ if (head > to) additionalUpgradeProof(session, readBatch, to, head, p.pending)
1242
1239
  }
1243
1240
 
1244
1241
  return p
package/lib/multisig.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const c = require('compact-encoding')
2
2
  const b4a = require('b4a')
3
3
  const flat = require('flat-tree')
4
+ const { MerkleTree } = require('./merkle-tree')
4
5
  const { multiSignature, multiSignaturev0 } = require('./messages')
5
6
 
6
7
  module.exports = {
@@ -36,8 +37,7 @@ async function partialSignature (core, signer, from, to = core.state.length, sig
36
37
 
37
38
  async function upgradeNodes (core, from, to) {
38
39
  const rx = core.state.storage.read()
39
- const treeBatch = core.state.createTreeBatch()
40
- const p = await core.state.tree.proof(rx, treeBatch, { upgrade: { start: from, length: to - from } })
40
+ const p = await MerkleTree.proof(core.state, rx, { upgrade: { start: from, length: to - from } })
41
41
  rx.tryFlush()
42
42
  return (await p.settle()).upgrade.nodes
43
43
  }
package/lib/replicator.js CHANGED
@@ -19,7 +19,7 @@
19
19
  - Which blocks does the Peer have available (tracked in remoteBitfield)
20
20
  - Which blocks are you actively looking for from this peer (tracked in missingBlocks)
21
21
  - How many blocks are currently inflight (tracked in inflight)
22
- The Peer uses this information to decide which blocks to request form the peer in response to _requestRange requests and the like.
22
+ The Peer uses this information to decide which blocks to request from the peer in response to _requestRange requests and the like.
23
23
  */
24
24
 
25
25
  const b4a = require('b4a')
@@ -29,6 +29,7 @@ const flatTree = require('flat-tree')
29
29
  const ReceiverQueue = require('./receiver-queue')
30
30
  const HotswapQueue = require('./hotswap-queue')
31
31
  const RemoteBitfield = require('./remote-bitfield')
32
+ const { MerkleTree } = require('./merkle-tree')
32
33
  const { REQUEST_CANCELLED, REQUEST_TIMEOUT, INVALID_CAPABILITY, SNAPSHOT_NOT_AVAILABLE } = require('hypercore-errors')
33
34
  const m = require('./messages')
34
35
  const caps = require('./caps')
@@ -676,7 +677,7 @@ class Peer {
676
677
 
677
678
  try {
678
679
  // Rely on caching to make sure this is cheap...
679
- const canUpgrade = await this.core.tree.upgradeable(remoteLength)
680
+ const canUpgrade = await MerkleTree.upgradeable(this.core.state, remoteLength)
680
681
 
681
682
  if (remoteFork !== this.core.state.fork) return false
682
683
 
@@ -696,12 +697,11 @@ class Peer {
696
697
  return new ProofRequest(msg, null, null, null)
697
698
  }
698
699
 
699
- block = this.core.blocks.get(batch, index)
700
+ block = batch.getBlock(index)
700
701
  }
701
702
 
702
703
  const manifest = (msg.manifest && !this.core.compat) ? this.core.header.manifest : null
703
- const treeBatch = this.core.state.createTreeBatch()
704
- const proof = await this.core.tree.proof(batch, treeBatch, msg)
704
+ const proof = await MerkleTree.proof(this.core.state, batch, msg)
705
705
 
706
706
  return new ProofRequest(msg, proof, block, manifest)
707
707
  }
@@ -1404,11 +1404,11 @@ class Peer {
1404
1404
 
1405
1405
  try {
1406
1406
  if (req.block !== null && req.fork === fork) {
1407
- req.block.nodes = await this.core.tree.missingNodes(2 * req.block.index, this.core.state.length)
1407
+ req.block.nodes = await MerkleTree.missingNodes(this.core.state, 2 * req.block.index, this.core.state.length)
1408
1408
  if (req.priority === PRIORITY.CANCELLED) return
1409
1409
  }
1410
1410
  if (req.hash !== null && req.fork === fork && req.hash.nodes === 0) {
1411
- req.hash.nodes = await this.core.tree.missingNodes(req.hash.index, this.core.state.length)
1411
+ req.hash.nodes = await MerkleTree.missingNodes(this.core.state, req.hash.index, this.core.state.length)
1412
1412
  if (req.priority === PRIORITY.CANCELLED) return
1413
1413
 
1414
1414
  // nodes === 0, we already have it, bail
@@ -1442,7 +1442,7 @@ module.exports = class Replicator {
1442
1442
  this.allowFork = allowFork
1443
1443
  this.ondownloading = null // optional external hook for monitoring downloading status
1444
1444
  this.peers = []
1445
- this.findingPeers = 0 // updateable from the outside
1445
+ this.findingPeers = 0 // updatable from the outside
1446
1446
  this.destroyed = false
1447
1447
  this.downloading = false
1448
1448
  this.activeSessions = 0
@@ -1856,7 +1856,7 @@ module.exports = class Replicator {
1856
1856
 
1857
1857
  async _resolveLocalBlock (b, reader, resolved) {
1858
1858
  try {
1859
- b.resolve(await this.core.blocks.get(reader, b.index))
1859
+ b.resolve(await reader.getBlock(b.index))
1860
1860
  } catch (err) {
1861
1861
  b.reject(err)
1862
1862
  return
@@ -2538,7 +2538,7 @@ function clampRange (core, r) {
2538
2538
  if (r.blocks === null) {
2539
2539
  const start = core.bitfield.firstUnset(r.start)
2540
2540
 
2541
- if (r.end === -1) r.start = start === -1 ? core.tree.length : start
2541
+ if (r.end === -1) r.start = start === -1 ? core.state.length : start
2542
2542
  else if (start === -1 || start >= r.end) r.start = r.end
2543
2543
  else {
2544
2544
  r.start = start
@@ -11,7 +11,7 @@ const Bitfield = require('./bitfield')
11
11
  const { MerkleTree, MerkleTreeBatch } = require('./merkle-tree')
12
12
 
13
13
  module.exports = class SessionState {
14
- constructor (core, parent, storage, blocks, tree, treeInfo, name) {
14
+ constructor (core, parent, storage, treeInfo, name) {
15
15
  this.core = core
16
16
  this.index = this.core.sessionStates.push(this) - 1
17
17
 
@@ -27,26 +27,20 @@ module.exports = class SessionState {
27
27
  this.atomized = null
28
28
  this.mutex = new Mutex()
29
29
 
30
- this.blocks = blocks
31
- this.tree = tree
32
-
33
30
  this.treeFork = -1 // only updated if truncated below dependency
34
31
 
35
32
  // merkle state
36
- this.roots = []
37
- this.length = 0
33
+ this.roots = treeInfo.roots.length ? treeInfo.roots : []
38
34
  this.fork = treeInfo.fork || 0
35
+ this.length = MerkleTree.span(this.roots) / 2
36
+ this.byteLength = MerkleTree.size(this.roots)
39
37
  this.prologue = treeInfo.prologue || null
40
38
  this.signature = treeInfo.signature || null
41
39
 
42
- if (treeInfo.roots.length) this.setRoots(treeInfo.roots)
43
-
44
40
  this.snapshotCompatLength = this.isSnapshot() ? Math.min(this.length, this.core.state.length) : -1
45
41
 
46
42
  this.active = 0
47
43
 
48
- this._onflush = null
49
- this._flushing = null
50
44
  this._activeTx = null
51
45
  this._pendingBitfield = null
52
46
 
@@ -66,7 +60,7 @@ module.exports = class SessionState {
66
60
  }
67
61
 
68
62
  createTreeBatch () {
69
- return new MerkleTreeBatch(this.tree, this)
63
+ return new MerkleTreeBatch(this)
70
64
  }
71
65
 
72
66
  addSession (s) {
@@ -113,16 +107,13 @@ module.exports = class SessionState {
113
107
  setRoots (roots) {
114
108
  this.roots = roots
115
109
  this.length = MerkleTree.span(roots) / 2
110
+ this.byteLength = MerkleTree.size(roots)
116
111
  }
117
112
 
118
113
  get encryptionFork () {
119
114
  return this.treeFork === -1 ? this.core.header.tree.fork : this.treeFork
120
115
  }
121
116
 
122
- get byteLength () {
123
- return MerkleTree.size(this.roots)
124
- }
125
-
126
117
  async getFlushedTreeInfo (storage) {
127
118
  if (!this.atomized || !this.atomized.flushing) return this.treeInfo()
128
119
  await this.atomized.flushed()
@@ -203,8 +194,6 @@ module.exports = class SessionState {
203
194
  this.core,
204
195
  null,
205
196
  storage,
206
- this.blocks,
207
- this.tree.clone(storage),
208
197
  treeInfo,
209
198
  this.name
210
199
  )
@@ -215,19 +204,10 @@ module.exports = class SessionState {
215
204
  updateDependency (tx, length) {
216
205
  const dependency = updateDependency(this, length, false)
217
206
  if (dependency) tx.setDependency(dependency)
218
-
219
207
  return dependency
220
208
  }
221
209
 
222
- _clearActiveBatch (err) {
223
- if (!this._activeTx) return
224
- this._activeTx = null
225
-
226
- if (this._onflush) this._onflush(err)
227
-
228
- this._onflush = null
229
- this._flushing = null
230
-
210
+ _clearActiveBatch () {
231
211
  this._activeTx = null
232
212
  }
233
213
 
@@ -238,7 +218,7 @@ module.exports = class SessionState {
238
218
  return this._activeTx
239
219
  }
240
220
 
241
- _unlock (lock) {
221
+ _unlock () {
242
222
  this._clearActiveBatch()
243
223
  this.mutex.unlock()
244
224
  this.core.checkIfIdle()
@@ -248,12 +228,8 @@ module.exports = class SessionState {
248
228
  const tx = this._activeTx
249
229
  this._activeTx = null
250
230
 
251
- const flushing = tx.flush()
252
-
253
231
  try {
254
- if (!this._flushing) this._flushing = flushing
255
-
256
- return flushing
232
+ return await tx.flush()
257
233
  } finally {
258
234
  this._clearActiveBatch()
259
235
  }
@@ -284,6 +260,7 @@ module.exports = class SessionState {
284
260
 
285
261
  this.fork = src.fork
286
262
  this.length = src.length
263
+ this.byteLength = src.byteLength
287
264
  this.roots = src.roots.slice()
288
265
  this.signature = src.signature
289
266
 
@@ -314,21 +291,10 @@ module.exports = class SessionState {
314
291
  this.onappend(tree, bitfield, true)
315
292
  } finally {
316
293
  this.mutex.unlock()
294
+ this.core.checkIfIdle()
317
295
  }
318
296
  }
319
297
 
320
- flushed () {
321
- if (!this._activeTx) return
322
-
323
- if (this._flushing) return this._flushing
324
-
325
- this._flushing = new Promise(resolve => {
326
- this._onflush = resolve
327
- })
328
-
329
- return this._flushing
330
- }
331
-
332
298
  async setUserData (key, value) {
333
299
  await this.mutex.lock()
334
300
 
@@ -350,7 +316,9 @@ module.exports = class SessionState {
350
316
  const tx = this.createWriteBatch()
351
317
  this.updating = true
352
318
 
353
- if (bitfield) this.blocks.put(tx, bitfield.start, value)
319
+ if (bitfield) {
320
+ tx.putBlock(bitfield.start, value)
321
+ }
354
322
 
355
323
  if (bitfield && this.isDefault()) {
356
324
  await storeBitfieldRange(this.storage, tx, bitfield.start, bitfield.start + 1, true)
@@ -375,6 +343,7 @@ module.exports = class SessionState {
375
343
  if (batch.upgraded) {
376
344
  this.roots = batch.roots
377
345
  this.length = batch.length
346
+ this.byteLength = batch.byteLength
378
347
  this.fork = batch.fork
379
348
  this.signature = batch.signature
380
349
 
@@ -400,7 +369,7 @@ module.exports = class SessionState {
400
369
 
401
370
  try {
402
371
  const batch = this.createTreeBatch()
403
- await this.tree.truncate(length, batch, fork)
372
+ await MerkleTree.truncate(this, length, batch, fork)
404
373
 
405
374
  if (!signature && keyPair && length > 0) signature = this.core.verifier.sign(batch, keyPair)
406
375
  if (signature) batch.signature = signature
@@ -422,6 +391,7 @@ module.exports = class SessionState {
422
391
 
423
392
  this.fork = tree.fork
424
393
  this.length = tree.length
394
+ this.byteLength = MerkleTree.size(roots)
425
395
  this.roots = roots
426
396
  this.signature = tree.signature
427
397
 
@@ -447,6 +417,7 @@ module.exports = class SessionState {
447
417
 
448
418
  this.fork = batch.fork
449
419
  this.length = batch.length
420
+ this.byteLength = batch.byteLength
450
421
  this.roots = batch.roots
451
422
  this.signature = batch.signature
452
423
 
@@ -501,7 +472,7 @@ module.exports = class SessionState {
501
472
  }
502
473
  }
503
474
 
504
- this.blocks.clear(tx, start, end)
475
+ tx.deleteBlockRange(start, end)
505
476
 
506
477
  const dependency = start < this.flushedLength() ? updateDependency(this, start, true) : null
507
478
 
@@ -563,7 +534,9 @@ module.exports = class SessionState {
563
534
 
564
535
  if (this.isDefault()) await storeBitfieldRange(this.storage, tx, batch.ancestors, batch.length, true)
565
536
 
566
- this.blocks.putBatch(tx, this.length, values)
537
+ for (let i = 0; i < values.length; i++) {
538
+ tx.putBlock(this.length + i, values[i])
539
+ }
567
540
 
568
541
  const bitfield = {
569
542
  drop: false,
@@ -576,6 +549,7 @@ module.exports = class SessionState {
576
549
  this.fork = batch.fork
577
550
  this.roots = batch.roots
578
551
  this.length = batch.length
552
+ this.byteLength = batch.byteLength
579
553
  this.signature = batch.signature
580
554
 
581
555
  this.onappend(tree, bitfield, flushed)
@@ -717,6 +691,7 @@ module.exports = class SessionState {
717
691
  this.fork = tree.fork
718
692
  this.roots = roots
719
693
  this.length = tree.length
694
+ this.byteLength = MerkleTree.size(roots)
720
695
 
721
696
  if (truncating) this.ontruncate(tree, sharedLength, origLength, flushed)
722
697
  if (sharedLength < length) this.onappend(tree, null, flushed)
@@ -819,7 +794,7 @@ module.exports = class SessionState {
819
794
  signature
820
795
  }
821
796
 
822
- const upgraded = treeLength < this.length || this.length < length || tree.fork !== this.tree.fork
797
+ const upgraded = treeLength < this.length || this.length < length || tree.fork !== this.fork
823
798
 
824
799
  if (upgraded) tx.setHead(tree)
825
800
 
@@ -828,6 +803,7 @@ module.exports = class SessionState {
828
803
  this.fork = tree.fork
829
804
  this.roots = roots
830
805
  this.length = length
806
+ this.byteLength = MerkleTree.size(roots)
831
807
  this.signature = signature
832
808
 
833
809
  return { tree, flushed }
@@ -861,7 +837,7 @@ module.exports = class SessionState {
861
837
  if (treeLength < length) {
862
838
  const tx = state.createWriteBatch()
863
839
 
864
- state.blocks.clear(tx, treeLength, length)
840
+ tx.deleteBlockRange(treeLength, length)
865
841
  const dependency = state.updateDependency(tx, length)
866
842
 
867
843
  await state.flush(tx)
@@ -896,7 +872,7 @@ module.exports = class SessionState {
896
872
 
897
873
  head.length = length
898
874
 
899
- const roots = await this.tree.getRoots(length)
875
+ const roots = await MerkleTree.getRootsFromStorage(this.storage, length)
900
876
  const rootHash = crypto.tree(roots)
901
877
 
902
878
  head.fork = this.fork
@@ -952,19 +928,23 @@ module.exports = class SessionState {
952
928
 
953
929
  // todo: validate treeInfo
954
930
 
931
+ let storage = null
932
+
955
933
  if (resumed) {
956
- this.storage = resumed
934
+ storage = resumed
957
935
  } else {
958
936
  treeInfo.fork = fork
959
- this.storage = await state.storage.createSession(this.name, treeInfo)
937
+ storage = await state.storage.createSession(this.name, treeInfo)
960
938
  }
961
939
 
962
- this.tree = new MerkleTree(this.storage)
940
+ const roots = await MerkleTree.getRootsFromStorage(storage, length)
963
941
 
942
+ this.storage = storage
964
943
  this.prologue = state.prologue
965
944
  this.fork = fork
966
945
  this.length = length
967
- this.roots = await this.tree.getRoots(length)
946
+ this.byteLength = MerkleTree.size(roots)
947
+ this.roots = roots
968
948
 
969
949
  if (truncation) {
970
950
  const { dependency } = truncation
@@ -1016,11 +996,9 @@ module.exports = class SessionState {
1016
996
  throw new Error('Session already atomized')
1017
997
  }
1018
998
 
1019
- const tree = new MerkleTree(storage)
1020
-
1021
999
  const head = {
1022
1000
  fork: this.fork,
1023
- roots: length === this.length ? this.roots.slice() : await tree.getRoots(length),
1001
+ roots: length === this.length ? this.roots.slice() : await MerkleTree.getRootsFromStorage(storage, length),
1024
1002
  length,
1025
1003
  prologue: this.prologue,
1026
1004
  signature: length === this.length ? this.signature : null
@@ -1030,8 +1008,6 @@ module.exports = class SessionState {
1030
1008
  this.core,
1031
1009
  atom ? this : null,
1032
1010
  storage,
1033
- this.core.blocks,
1034
- tree,
1035
1011
  head,
1036
1012
  atom ? this.name : name
1037
1013
  )
@@ -1094,7 +1070,7 @@ async function storeBitfieldRange (storage, tx, from, to, value) {
1094
1070
 
1095
1071
  async function truncateAndFlush (s, length) {
1096
1072
  const batch = s.createTreeBatch()
1097
- await s.tree.truncate(length, batch, s.tree.fork)
1073
+ await MerkleTree.truncate(s, length, batch, s.fork)
1098
1074
  const tx = s.createWriteBatch()
1099
1075
 
1100
1076
  const info = await s._truncate(tx, batch)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore",
3
- "version": "11.0.29",
3
+ "version": "11.0.30",
4
4
  "description": "Hypercore is a secure, distributed append-only log",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -1,25 +0,0 @@
1
- module.exports = class BlockStore {
2
- constructor (storage) {
3
- this.storage = storage
4
- }
5
-
6
- async get (rx, i) {
7
- return rx.getBlock(i)
8
- }
9
-
10
- put (tx, i, data) {
11
- tx.putBlock(i, data)
12
- }
13
-
14
- putBatch (tx, i, blocks) {
15
- if (blocks.length === 0) return Promise.resolve()
16
-
17
- for (let j = 0; j < blocks.length; j++) {
18
- tx.putBlock(i + j, blocks[j])
19
- }
20
- }
21
-
22
- clear (tx, start = 0, end = -1) {
23
- tx.deleteBlockRange(start, end)
24
- }
25
- }