hypercore 10.28.11 → 10.29.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 +23 -19
- package/lib/messages.js +8 -4
- package/lib/replicator.js +39 -19
- package/package.json +1 -1
package/lib/merkle-tree.js
CHANGED
|
@@ -345,8 +345,7 @@ class ByteSeeker {
|
|
|
345
345
|
if (!bytes) return [0, 0]
|
|
346
346
|
|
|
347
347
|
for (const node of this.tree.roots) { // all async ticks happen once we find the root so safe
|
|
348
|
-
|
|
349
|
-
if (this.padding > 0) size -= this.padding * flat.countLeaves(node.index)
|
|
348
|
+
const size = getUnpaddedSize(node, this.padding, null)
|
|
350
349
|
|
|
351
350
|
if (bytes === size) return [flat.rightSpan(node.index) + 2, 0]
|
|
352
351
|
if (bytes > size) {
|
|
@@ -359,8 +358,7 @@ class ByteSeeker {
|
|
|
359
358
|
while ((ite.index & 1) !== 0) {
|
|
360
359
|
const l = await this.tree.get(ite.leftChild(), false)
|
|
361
360
|
if (l) {
|
|
362
|
-
|
|
363
|
-
if (this.padding > 0) size -= this.padding * ite.countLeaves()
|
|
361
|
+
const size = getUnpaddedSize(l, this.padding, ite)
|
|
364
362
|
|
|
365
363
|
if (size === bytes) return [ite.rightSpan() + 2, 0]
|
|
366
364
|
if (size > bytes) continue
|
|
@@ -875,20 +873,21 @@ function verifyUpgrade ({ fork, upgrade }, blockRoot, batch) {
|
|
|
875
873
|
return q.extra === null
|
|
876
874
|
}
|
|
877
875
|
|
|
878
|
-
async function seekFromHead (tree, head, bytes) {
|
|
876
|
+
async function seekFromHead (tree, head, bytes, padding) {
|
|
879
877
|
const roots = flat.fullRoots(head)
|
|
880
878
|
|
|
881
879
|
for (let i = 0; i < roots.length; i++) {
|
|
882
880
|
const root = roots[i]
|
|
883
881
|
const node = await tree.get(root)
|
|
882
|
+
const size = getUnpaddedSize(node, padding, null)
|
|
884
883
|
|
|
885
|
-
if (bytes ===
|
|
886
|
-
if (bytes >
|
|
887
|
-
bytes -=
|
|
884
|
+
if (bytes === size) return root
|
|
885
|
+
if (bytes > size) {
|
|
886
|
+
bytes -= size
|
|
888
887
|
continue
|
|
889
888
|
}
|
|
890
889
|
|
|
891
|
-
return seekTrustedTree(tree, root, bytes)
|
|
890
|
+
return seekTrustedTree(tree, root, bytes, padding)
|
|
892
891
|
}
|
|
893
892
|
|
|
894
893
|
return head
|
|
@@ -896,7 +895,7 @@ async function seekFromHead (tree, head, bytes) {
|
|
|
896
895
|
|
|
897
896
|
// trust that bytes are within the root tree and find the block at bytes
|
|
898
897
|
|
|
899
|
-
async function seekTrustedTree (tree, root, bytes) {
|
|
898
|
+
async function seekTrustedTree (tree, root, bytes, padding) {
|
|
900
899
|
if (!bytes) return root
|
|
901
900
|
|
|
902
901
|
const ite = flat.iterator(root)
|
|
@@ -904,9 +903,10 @@ async function seekTrustedTree (tree, root, bytes) {
|
|
|
904
903
|
while ((ite.index & 1) !== 0) {
|
|
905
904
|
const l = await tree.get(ite.leftChild(), false)
|
|
906
905
|
if (l) {
|
|
907
|
-
|
|
908
|
-
if (
|
|
909
|
-
bytes
|
|
906
|
+
const size = getUnpaddedSize(l, padding, ite)
|
|
907
|
+
if (size === bytes) return ite.index
|
|
908
|
+
if (size > bytes) continue
|
|
909
|
+
bytes -= size
|
|
910
910
|
ite.sibling()
|
|
911
911
|
} else {
|
|
912
912
|
ite.parent()
|
|
@@ -919,8 +919,8 @@ async function seekTrustedTree (tree, root, bytes) {
|
|
|
919
919
|
|
|
920
920
|
// try to find the block at bytes without trusting that is *is* within the root passed
|
|
921
921
|
|
|
922
|
-
async function seekUntrustedTree (tree, root, bytes) {
|
|
923
|
-
const offset = await tree.byteOffset(root)
|
|
922
|
+
async function seekUntrustedTree (tree, root, bytes, padding) {
|
|
923
|
+
const offset = await tree.byteOffset(root) - (padding ? padding * flat.leftSpan(root) / 2 : 0)
|
|
924
924
|
|
|
925
925
|
if (offset > bytes) throw INVALID_OPERATION('Invalid seek')
|
|
926
926
|
if (offset === bytes) return root
|
|
@@ -929,9 +929,9 @@ async function seekUntrustedTree (tree, root, bytes) {
|
|
|
929
929
|
|
|
930
930
|
const node = await tree.get(root)
|
|
931
931
|
|
|
932
|
-
if (node
|
|
932
|
+
if (getUnpaddedSize(node, padding, null) <= bytes) throw INVALID_OPERATION('Invalid seek')
|
|
933
933
|
|
|
934
|
-
return seekTrustedTree(tree, root, bytes)
|
|
934
|
+
return seekTrustedTree(tree, root, bytes, padding)
|
|
935
935
|
}
|
|
936
936
|
|
|
937
937
|
// Below is proof production, ie, construct proofs to verify a request
|
|
@@ -1212,10 +1212,10 @@ async function generateProof (tree, block, hash, seek, upgrade) {
|
|
|
1212
1212
|
|
|
1213
1213
|
if (node !== null && (!upgrade || node.lastIndex < upgrade.start)) {
|
|
1214
1214
|
subTree = nodesToRoot(node.index, node.nodes, to)
|
|
1215
|
-
const seekRoot = seek ? await seekUntrustedTree(tree, subTree, seek.bytes) : head
|
|
1215
|
+
const seekRoot = seek ? await seekUntrustedTree(tree, subTree, seek.bytes, seek.padding) : head
|
|
1216
1216
|
blockAndSeekProof(tree, node, seek, seekRoot, subTree, p)
|
|
1217
1217
|
} else if ((node || seek) && upgrade) {
|
|
1218
|
-
subTree = seek ? await seekFromHead(tree, to, seek.bytes) : node.index
|
|
1218
|
+
subTree = seek ? await seekFromHead(tree, to, seek.bytes, seek.padding) : node.index
|
|
1219
1219
|
}
|
|
1220
1220
|
|
|
1221
1221
|
if (upgrade) {
|
|
@@ -1257,3 +1257,7 @@ async function generateProof (tree, block, hash, seek, upgrade) {
|
|
|
1257
1257
|
|
|
1258
1258
|
return result
|
|
1259
1259
|
}
|
|
1260
|
+
|
|
1261
|
+
function getUnpaddedSize (node, padding, ite) {
|
|
1262
|
+
return padding === 0 ? node.size : node.size - padding * (ite ? ite.countLeaves() : flat.countLeaves(node.index))
|
|
1263
|
+
}
|
package/lib/messages.js
CHANGED
|
@@ -165,16 +165,17 @@ const wire = exports.wire = {}
|
|
|
165
165
|
|
|
166
166
|
wire.handshake = {
|
|
167
167
|
preencode (state, m) {
|
|
168
|
-
c.uint.preencode(state,
|
|
168
|
+
c.uint.preencode(state, 1)
|
|
169
169
|
c.fixed32.preencode(state, m.capability)
|
|
170
170
|
},
|
|
171
171
|
encode (state, m) {
|
|
172
|
-
c.uint.encode(state, 0)
|
|
172
|
+
c.uint.encode(state, m.seeks ? 1 : 0)
|
|
173
173
|
c.fixed32.encode(state, m.capability)
|
|
174
174
|
},
|
|
175
175
|
decode (state) {
|
|
176
|
-
c.uint.decode(state)
|
|
176
|
+
const flags = c.uint.decode(state)
|
|
177
177
|
return {
|
|
178
|
+
seeks: (flags & 1) !== 0,
|
|
178
179
|
capability: c.fixed32.decode(state)
|
|
179
180
|
}
|
|
180
181
|
}
|
|
@@ -200,13 +201,16 @@ const requestBlock = {
|
|
|
200
201
|
const requestSeek = {
|
|
201
202
|
preencode (state, s) {
|
|
202
203
|
c.uint.preencode(state, s.bytes)
|
|
204
|
+
c.uint.preencode(state, s.padding)
|
|
203
205
|
},
|
|
204
206
|
encode (state, s) {
|
|
205
207
|
c.uint.encode(state, s.bytes)
|
|
208
|
+
c.uint.encode(state, s.padding)
|
|
206
209
|
},
|
|
207
210
|
decode (state) {
|
|
208
211
|
return {
|
|
209
|
-
bytes: c.uint.decode(state)
|
|
212
|
+
bytes: c.uint.decode(state),
|
|
213
|
+
padding: c.uint.decode(state)
|
|
210
214
|
}
|
|
211
215
|
}
|
|
212
216
|
}
|
package/lib/replicator.js
CHANGED
|
@@ -269,6 +269,7 @@ class Peer {
|
|
|
269
269
|
this.stream = protomux.stream
|
|
270
270
|
this.protomux = protomux
|
|
271
271
|
this.remotePublicKey = this.stream.remotePublicKey
|
|
272
|
+
this.remoteSupportsSeeks = false
|
|
272
273
|
|
|
273
274
|
this.paused = false
|
|
274
275
|
|
|
@@ -389,7 +390,7 @@ class Peer {
|
|
|
389
390
|
})
|
|
390
391
|
}
|
|
391
392
|
|
|
392
|
-
onopen ({ capability }) {
|
|
393
|
+
onopen ({ seeks, capability }) {
|
|
393
394
|
const expected = caps.replicate(this.stream.isInitiator === false, this.replicator.key, this.stream.handshakeHash)
|
|
394
395
|
|
|
395
396
|
if (b4a.equals(capability, expected) !== true) { // TODO: change this to a rejection instead, less leakage
|
|
@@ -398,6 +399,7 @@ class Peer {
|
|
|
398
399
|
|
|
399
400
|
if (this.remoteOpened === true) return
|
|
400
401
|
this.remoteOpened = true
|
|
402
|
+
this.remoteSupportsSeeks = seeks
|
|
401
403
|
|
|
402
404
|
this.protomux.cork()
|
|
403
405
|
|
|
@@ -811,6 +813,9 @@ class Peer {
|
|
|
811
813
|
}
|
|
812
814
|
|
|
813
815
|
_requestSeek (s) {
|
|
816
|
+
// if replicator is updating the seeks etc, bail and wait for it to drain
|
|
817
|
+
if (this.replicator._updatesPending > 0) return false
|
|
818
|
+
|
|
814
819
|
const { length, fork } = this.core.tree
|
|
815
820
|
|
|
816
821
|
if (fork !== this.remoteFork) return false
|
|
@@ -821,7 +826,7 @@ class Peer {
|
|
|
821
826
|
// We need an upgrade for the seek, if non can be provided, skip
|
|
822
827
|
if (req === null) return false
|
|
823
828
|
|
|
824
|
-
req.seek = { bytes: s.seeker.padding
|
|
829
|
+
req.seek = this.remoteSupportsSeeks ? { bytes: s.seeker.bytes, padding: s.seeker.padding } : null
|
|
825
830
|
|
|
826
831
|
s.inflight.push(req)
|
|
827
832
|
this._send(req)
|
|
@@ -849,9 +854,10 @@ class Peer {
|
|
|
849
854
|
if (h.inflight.length > 0) continue
|
|
850
855
|
|
|
851
856
|
const req = this._makeRequest(false, h.priority)
|
|
857
|
+
const nodes = flatTree.depth(s.seeker.start + s.seeker.end - 1)
|
|
852
858
|
|
|
853
|
-
req.hash = { index: 2 * index, nodes
|
|
854
|
-
req.seek = { bytes: s.seeker.padding
|
|
859
|
+
req.hash = { index: 2 * index, nodes }
|
|
860
|
+
req.seek = this.remoteSupportsSeeks ? { bytes: s.seeker.bytes, padding: s.seeker.padding } : null
|
|
855
861
|
|
|
856
862
|
s.inflight.push(req)
|
|
857
863
|
h.inflight.push(req)
|
|
@@ -1059,23 +1065,30 @@ class Peer {
|
|
|
1059
1065
|
this.inflight++
|
|
1060
1066
|
this.replicator._inflight.add(req)
|
|
1061
1067
|
|
|
1062
|
-
if (req.upgrade !== null && req.fork === fork) {
|
|
1063
|
-
const u = this.replicator._addUpgrade()
|
|
1064
|
-
u.inflight.push(req)
|
|
1065
|
-
}
|
|
1066
|
-
|
|
1067
1068
|
try {
|
|
1068
1069
|
if (req.block !== null && req.fork === fork) {
|
|
1069
1070
|
req.block.nodes = await this.core.tree.missingNodes(2 * req.block.index)
|
|
1070
1071
|
}
|
|
1071
|
-
if (req.hash !== null && req.fork === fork) {
|
|
1072
|
+
if (req.hash !== null && req.fork === fork && req.hash.nodes === 0) {
|
|
1072
1073
|
req.hash.nodes = await this.core.tree.missingNodes(req.hash.index)
|
|
1074
|
+
|
|
1075
|
+
// nodes === 0, we already have it, bail
|
|
1076
|
+
if (req.hash.nodes === 0 && (req.hash.index & 1) === 0) {
|
|
1077
|
+
this.inflight--
|
|
1078
|
+
this.replicator._resolveHashLocally(this, req)
|
|
1079
|
+
return
|
|
1080
|
+
}
|
|
1073
1081
|
}
|
|
1074
1082
|
} catch (err) {
|
|
1075
1083
|
this.stream.destroy(err)
|
|
1076
1084
|
return
|
|
1077
1085
|
}
|
|
1078
1086
|
|
|
1087
|
+
if (req.upgrade !== null && req.fork === fork) {
|
|
1088
|
+
const u = this.replicator._addUpgrade()
|
|
1089
|
+
u.inflight.push(req)
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1079
1092
|
this.wireRequest.send(req)
|
|
1080
1093
|
}
|
|
1081
1094
|
}
|
|
@@ -1186,7 +1199,7 @@ module.exports = class Replicator {
|
|
|
1186
1199
|
for (const peer of this.peers) peer.signalUpgrade()
|
|
1187
1200
|
if (this._blocks.isEmpty() === false) this._resolveBlocksLocally()
|
|
1188
1201
|
if (this._upgrade !== null) this._resolveUpgradeRequest(null)
|
|
1189
|
-
if (this._ranges.length !== 0 || this._seeks.length !== 0) this._updateNonPrimary()
|
|
1202
|
+
if (this._ranges.length !== 0 || this._seeks.length !== 0) this._updateNonPrimary(true)
|
|
1190
1203
|
}
|
|
1191
1204
|
|
|
1192
1205
|
// Called externally when a conflict has been detected and verified
|
|
@@ -1270,7 +1283,7 @@ module.exports = class Replicator {
|
|
|
1270
1283
|
|
|
1271
1284
|
// Trigger this to see if this is already resolved...
|
|
1272
1285
|
// Also auto compresses the range based on local bitfield
|
|
1273
|
-
this._updateNonPrimary()
|
|
1286
|
+
this._updateNonPrimary(true)
|
|
1274
1287
|
|
|
1275
1288
|
return ref
|
|
1276
1289
|
}
|
|
@@ -1420,6 +1433,12 @@ module.exports = class Replicator {
|
|
|
1420
1433
|
this._queued.push(b)
|
|
1421
1434
|
}
|
|
1422
1435
|
|
|
1436
|
+
_resolveHashLocally (peer, req) {
|
|
1437
|
+
this._removeInflight(req.id)
|
|
1438
|
+
this._resolveBlockRequest(this._hashes, req.hash.index / 2, null, req)
|
|
1439
|
+
this.updatePeer(peer)
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1423
1442
|
// Runs in the background - not allowed to throw
|
|
1424
1443
|
async _resolveBlocksLocally () {
|
|
1425
1444
|
// TODO: check if fork compat etc. Requires that we pass down truncation info
|
|
@@ -1528,7 +1547,7 @@ module.exports = class Replicator {
|
|
|
1528
1547
|
}
|
|
1529
1548
|
|
|
1530
1549
|
// "slow" updates here - async but not allowed to ever throw
|
|
1531
|
-
async _updateNonPrimary () {
|
|
1550
|
+
async _updateNonPrimary (updateAll) {
|
|
1532
1551
|
// Check if running, if so skip it and the running one will issue another update for us (debounce)
|
|
1533
1552
|
while (++this._updatesPending === 1) {
|
|
1534
1553
|
for (let i = 0; i < this._ranges.length; i++) {
|
|
@@ -1564,13 +1583,13 @@ module.exports = class Replicator {
|
|
|
1564
1583
|
else s.resolve(res)
|
|
1565
1584
|
}
|
|
1566
1585
|
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
// No additional updates scheduled - return
|
|
1570
|
-
if (--this._updatesPending === 0) return
|
|
1586
|
+
// No additional updates scheduled - break
|
|
1587
|
+
if (--this._updatesPending === 0) break
|
|
1571
1588
|
// Debounce the additional updates - continue
|
|
1572
1589
|
this._updatesPending = 0
|
|
1573
1590
|
}
|
|
1591
|
+
|
|
1592
|
+
if (this._inflight.idle || updateAll) this.updateAll()
|
|
1574
1593
|
}
|
|
1575
1594
|
|
|
1576
1595
|
_maybeResolveIfAvailableRanges () {
|
|
@@ -1641,8 +1660,8 @@ module.exports = class Replicator {
|
|
|
1641
1660
|
this._manifestPeer = null
|
|
1642
1661
|
}
|
|
1643
1662
|
|
|
1644
|
-
if (this._seeks.length > 0 || this._ranges.length > 0) this._updateNonPrimary()
|
|
1645
|
-
|
|
1663
|
+
if (this._seeks.length > 0 || this._ranges.length > 0) this._updateNonPrimary(this._seeks.length > 0)
|
|
1664
|
+
this.updatePeer(peer)
|
|
1646
1665
|
}
|
|
1647
1666
|
|
|
1648
1667
|
_onwant (peer, start, length) {
|
|
@@ -1921,6 +1940,7 @@ module.exports = class Replicator {
|
|
|
1921
1940
|
const stream = protomux.stream
|
|
1922
1941
|
|
|
1923
1942
|
peer.channel.open({
|
|
1943
|
+
seeks: true,
|
|
1924
1944
|
capability: caps.replicate(stream.isInitiator, this.key, stream.handshakeHash)
|
|
1925
1945
|
})
|
|
1926
1946
|
|