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.
- package/lib/merkle-tree.js +15 -0
- package/lib/messages.js +8 -1
- package/lib/replicator.js +54 -15
- package/package.json +1 -1
package/lib/merkle-tree.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
734
|
-
this.replicator.
|
|
735
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
+
}
|