hypercore 11.12.2 → 11.13.1

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.
@@ -679,6 +679,7 @@ class MerkleTree {
679
679
  // TODO: we could prop use a read batch here and do this in blocks of X for perf
680
680
  while (!ite.contains(head) && !(await hasTreeNode(session.storage, ite.index))) {
681
681
  cnt++
682
+ if (cnt >= 1024) throw ASSERTION('Bad arguments to missingNodes index=' + index + ' at length=' + length)
682
683
  ite.parent()
683
684
  }
684
685
 
@@ -742,6 +743,7 @@ function getByteOffsetBatch (roots, index, rx) {
742
743
  if ((index & 1) === 1) index = flat.leftSpan(index)
743
744
 
744
745
  let head = 0
746
+ let cnt = 0
745
747
 
746
748
  const promises = []
747
749
 
@@ -756,6 +758,8 @@ function getByteOffsetBatch (roots, index, rx) {
756
758
  const ite = flat.iterator(node.index)
757
759
 
758
760
  while (ite.index !== index) {
761
+ if (++cnt >= 1024) throw ASSERTION('Bad getByteOffsetSession index=' + index)
762
+
759
763
  if (index < ite.index) {
760
764
  ite.leftChild()
761
765
  } else {
@@ -930,8 +934,10 @@ async function seekTrustedTree (session, root, bytes, padding) {
930
934
  if (!bytes) return root
931
935
 
932
936
  const ite = flat.iterator(root)
937
+ let cnt = 0
933
938
 
934
939
  while ((ite.index & 1) !== 0) {
940
+ if (++cnt >= 1024) throw ASSERTION('Bad seekTrusted bytes=' + bytes + ', paddding=' + padding)
935
941
  const l = await getTreeNodeFromStorage(session.storage, ite.leftChild())
936
942
 
937
943
  if (l) {
@@ -972,11 +978,13 @@ async function seekUntrustedTree (session, root, bytes, padding) {
972
978
 
973
979
  function seekProof (session, rx, seekRoot, root, p) {
974
980
  const ite = flat.iterator(seekRoot)
981
+ let cnt = 0
975
982
 
976
983
  p.seek = []
977
984
  p.seek.push(getTreeNodeOrError(rx, ite.index))
978
985
 
979
986
  while (ite.index !== root) {
987
+ if (++cnt >= 1024) throw ASSERTION('Bad seekProof seekRoot=' + seekRoot + ', root=' + root)
980
988
  ite.sibling()
981
989
  p.seek.push(getTreeNodeOrError(rx, ite.index))
982
990
  ite.parent()
@@ -987,11 +995,13 @@ function blockAndSeekProof (session, rx, node, seek, seekRoot, root, p) {
987
995
  if (!node) return seekProof(session, rx, seekRoot, root, p)
988
996
 
989
997
  const ite = flat.iterator(node.index)
998
+ let cnt = 0
990
999
 
991
1000
  p.node = []
992
1001
  if (!node.value) p.node.push(getTreeNodeOrError(rx, ite.index))
993
1002
 
994
1003
  while (ite.index !== root) {
1004
+ if (++cnt >= 1024) throw ASSERTION('Bad blockAndSeekProof seekRoot=' + seekRoot + ', root=' + root)
995
1005
  ite.sibling()
996
1006
 
997
1007
  if (seek && ite.contains(seekRoot) && ite.index !== seekRoot) {
@@ -1017,10 +1027,13 @@ function upgradeProof (session, rx, node, seek, from, to, subTree, p) {
1017
1027
 
1018
1028
  const root = ite.index
1019
1029
  const target = from - 2
1030
+ let cnt = 0
1020
1031
 
1021
1032
  ite.seek(target)
1022
1033
 
1023
1034
  while (ite.index !== root) {
1035
+ if (++cnt >= 1024) throw ASSERTION('Bad upgradeProof target=' + target + ', root=' + root)
1036
+
1024
1037
  ite.sibling()
1025
1038
  if (ite.index > target) {
1026
1039
  if (p.node === null && p.seek === null && ite.contains(subTree)) {
@@ -1064,10 +1077,12 @@ function additionalUpgradeProof (session, rx, from, to, p) {
1064
1077
 
1065
1078
  const root = ite.index
1066
1079
  const target = from - 2
1080
+ let cnt = 0
1067
1081
 
1068
1082
  ite.seek(target)
1069
1083
 
1070
1084
  while (ite.index !== root) {
1085
+ if (++cnt >= 1024) throw ASSERTION('Bad arguments to additionalUpgradeProof root=' + root + ' target=' + target)
1071
1086
  ite.sibling()
1072
1087
  if (ite.index > target) {
1073
1088
  p.additionalUpgrade.push(getTreeNodeOrError(rx, ite.index))
package/lib/messages.js CHANGED
@@ -514,13 +514,20 @@ wire.data = {
514
514
  wire.noData = {
515
515
  preencode (state, m) {
516
516
  c.uint.preencode(state, m.request)
517
+ c.uint.preencode(state, m.reason ? 1 : 0)
518
+ if (m.reason) c.uint.preencode(state, m.reason)
517
519
  },
518
520
  encode (state, m) {
519
521
  c.uint.encode(state, m.request)
522
+ c.uint.encode(state, m.reason ? 1 : 0)
523
+ if (m.reason) c.uint.encode(state, m.reason)
520
524
  },
521
525
  decode (state, m) {
526
+ const request = c.uint.decode(state)
527
+ const flags = state.start < state.end ? c.uint.decode(state) : 0
522
528
  return {
523
- request: c.uint.decode(state)
529
+ request,
530
+ reason: flags & 1 ? c.uint.decode(state) : 0
524
531
  }
525
532
  }
526
533
  }
package/lib/replicator.js CHANGED
@@ -44,6 +44,11 @@ const MAX_REMOTE_SEGMENTS = 2048
44
44
 
45
45
  const MAX_RANGES = 64
46
46
 
47
+ const NOT_AVAILABLE = 1
48
+ const INVALID_REQUEST = 2
49
+ const MAX_INVALID_REQUESTS = 64
50
+ const MAX_BACKOFFS = MAX_INVALID_REQUESTS / 2
51
+
47
52
  const PRIORITY = {
48
53
  NORMAL: 0,
49
54
  HIGH: 1,
@@ -407,7 +412,8 @@ class Peer {
407
412
  wireExtension: { tx: 0, rx: 0 },
408
413
  hotswaps: 0,
409
414
  invalidData: 0,
410
- invalidRequests: 0
415
+ invalidRequests: 0,
416
+ backoffs: 0
411
417
  }
412
418
 
413
419
  this.receiverQueue = new ReceiverQueue()
@@ -730,9 +736,13 @@ class Peer {
730
736
  return new ProofRequest(msg, proof, block, manifest)
731
737
  } catch (err) {
732
738
  batch.destroy()
733
- this.stats.invalidRequests++
734
- this.replicator.stats.invalidRequests++
735
- throw err
739
+
740
+ this.replicator._oninvalidrequest(err, msg, this)
741
+
742
+ if (this.stats.invalidRequests >= MAX_INVALID_REQUESTS) throw err
743
+
744
+ await backoff(this.stats.invalidRequests)
745
+ return null
736
746
  }
737
747
  }
738
748
 
@@ -791,6 +801,11 @@ class Peer {
791
801
  ? await this._getProof(batch, msg)
792
802
  : new ProofRequest(msg, null, null, null)
793
803
 
804
+ if (req === null) {
805
+ this.wireNoData.send({ request: msg.id, reason: INVALID_REQUEST })
806
+ return
807
+ }
808
+
794
809
  batch.tryFlush()
795
810
 
796
811
  await this._fulfillRequest(req)
@@ -819,7 +834,7 @@ class Peer {
819
834
  return
820
835
  }
821
836
 
822
- this.wireNoData.send({ request: req.msg.id })
837
+ this.wireNoData.send({ request: req.msg.id, reason: NOT_AVAILABLE })
823
838
  return
824
839
  }
825
840
 
@@ -904,7 +919,7 @@ class Peer {
904
919
  if (isBlockRequest(req)) this.replicator._unmarkInflight(req.block.index)
905
920
 
906
921
  this.paused = true
907
- this.replicator._oninvalid(err, req, data, this)
922
+ this.replicator._oninvaliddata(err, req, data, this)
908
923
  return
909
924
  }
910
925
 
@@ -913,7 +928,7 @@ class Peer {
913
928
 
914
929
  try {
915
930
  if (!matchingRequest(req, data) || !(await this.core.verify(data, this))) {
916
- this.replicator._onnodata(this, req)
931
+ this.replicator._onnodata(this, req, 0)
917
932
  return
918
933
  }
919
934
  } catch (err) {
@@ -935,8 +950,8 @@ class Peer {
935
950
  }
936
951
 
937
952
  this.paused = true
938
- this.replicator._onnodata(this, req)
939
- this.replicator._oninvalid(err, req, data, this)
953
+ this.replicator._onnodata(this, req, 0)
954
+ this.replicator._oninvaliddata(err, req, data, this)
940
955
  return
941
956
  } finally {
942
957
  if (isBlockRequest(req)) this.replicator._markProcessed(req.block.index)
@@ -950,13 +965,12 @@ class Peer {
950
965
  }
951
966
  }
952
967
 
953
- onnodata ({ request }) {
968
+ onnodata ({ request, reason }) {
954
969
  const req = request > 0 ? this.replicator._inflight.get(request) : null
955
-
956
970
  if (req === null || req.peer !== this) return
957
971
 
958
972
  this._onrequestroundtrip(req)
959
- this.replicator._onnodata(this, req)
973
+ this.replicator._onnodata(this, req, reason)
960
974
  }
961
975
 
962
976
  _onrequestroundtrip (req) {
@@ -1505,7 +1519,8 @@ module.exports = class Replicator {
1505
1519
  wireExtension: { tx: 0, rx: 0 },
1506
1520
  hotswaps: 0,
1507
1521
  invalidData: 0,
1508
- invalidRequests: 0
1522
+ invalidRequests: 0,
1523
+ backoffs: 0
1509
1524
  }
1510
1525
 
1511
1526
  this._attached = new Set()
@@ -2086,7 +2101,16 @@ module.exports = class Replicator {
2086
2101
  }
2087
2102
  }
2088
2103
 
2089
- _onnodata (peer, req) {
2104
+ _onnodata (peer, req, reason) {
2105
+ if (reason === INVALID_REQUEST) {
2106
+ peer.stats.backoffs++
2107
+ this.stats.backoffs++
2108
+
2109
+ if (peer.stats.backoffs >= MAX_BACKOFFS) {
2110
+ peer.paused = true
2111
+ }
2112
+ }
2113
+
2090
2114
  this._clearRequest(peer, req)
2091
2115
  this.updateAll()
2092
2116
  }
@@ -2547,7 +2571,7 @@ module.exports = class Replicator {
2547
2571
  }
2548
2572
  }
2549
2573
 
2550
- _oninvalid (err, req, res, from) {
2574
+ _oninvaliddata (err, req, res, from) {
2551
2575
  const sessions = this.core.monitors
2552
2576
 
2553
2577
  this.stats.invalidData++
@@ -2556,6 +2580,16 @@ module.exports = class Replicator {
2556
2580
  sessions[i].emit('verification-error', err, req, res, from)
2557
2581
  }
2558
2582
  }
2583
+
2584
+ _oninvalidrequest (err, req, from) {
2585
+ const sessions = this.core.monitors
2586
+
2587
+ from.stats.invalidRequests++
2588
+ this.stats.invalidRequests++
2589
+ for (let i = 0; i < sessions.length; i++) {
2590
+ sessions[i].emit('invalid-request', err, req, from)
2591
+ }
2592
+ }
2559
2593
  }
2560
2594
 
2561
2595
  function matchingRequest (req, data) {
@@ -2707,3 +2741,8 @@ function incrementRx (stats1, stats2) {
2707
2741
  }
2708
2742
 
2709
2743
  function noop () {}
2744
+
2745
+ function backoff (times) {
2746
+ const sleep = times < 2 ? 200 : times < 5 ? 500 : times < 40 ? 1000 : 5000
2747
+ return new Promise(resolve => setTimeout(resolve, sleep))
2748
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore",
3
- "version": "11.12.2",
3
+ "version": "11.13.1",
4
4
  "description": "Hypercore is a secure, distributed append-only log",
5
5
  "main": "index.js",
6
6
  "scripts": {