hypercore 10.37.0 → 10.37.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/batch.js +25 -8
- package/lib/merkle-tree.js +62 -0
- package/lib/remote-bitfield.js +5 -1
- package/package.json +1 -1
package/lib/batch.js
CHANGED
|
@@ -25,6 +25,7 @@ module.exports = class HypercoreBatch extends EventEmitter {
|
|
|
25
25
|
this._sessionLength = 0
|
|
26
26
|
this._sessionByteLength = 0
|
|
27
27
|
this._sessionBatch = null
|
|
28
|
+
this._cachedBatch = null
|
|
28
29
|
this._flushing = null
|
|
29
30
|
this._clear = clear
|
|
30
31
|
|
|
@@ -207,20 +208,32 @@ module.exports = class HypercoreBatch extends EventEmitter {
|
|
|
207
208
|
return this.session.core.tree.restoreBatch(length)
|
|
208
209
|
}
|
|
209
210
|
|
|
210
|
-
|
|
211
|
+
_catchupBatch (clone) {
|
|
212
|
+
if (this._cachedBatch === null) this._cachedBatch = this._sessionBatch.clone()
|
|
213
|
+
|
|
214
|
+
if (this.length > this._cachedBatch.length) {
|
|
215
|
+
const offset = this._cachedBatch.length - this._sessionBatch.length
|
|
216
|
+
|
|
217
|
+
for (let i = offset; i < this._appendsActual.length; i++) {
|
|
218
|
+
this._cachedBatch.append(this._appendsActual[i])
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return clone ? this._cachedBatch.clone() : this._cachedBatch
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
createTreeBatch (length, opts = {}) {
|
|
226
|
+
if (Array.isArray(opts)) opts = { blocks: opts }
|
|
227
|
+
|
|
228
|
+
const { blocks = [], clone = true } = opts
|
|
211
229
|
if (!length && length !== 0) length = this.length + blocks.length
|
|
212
230
|
|
|
213
231
|
const maxLength = this.length + blocks.length
|
|
214
|
-
const b = this.
|
|
232
|
+
const b = this._catchupBatch(clone || (blocks.length > 0 || length !== this.length))
|
|
215
233
|
const len = Math.min(length, this.length)
|
|
216
234
|
|
|
217
235
|
if (len < this._sessionLength || length > maxLength) return null
|
|
218
|
-
|
|
219
|
-
for (let i = 0; i < len - this._sessionLength; i++) {
|
|
220
|
-
b.append(this._appendsActual[i])
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
if (len < this.length) return b
|
|
236
|
+
if (len < b.length) b.checkout(len, this._sessionBatch.roots)
|
|
224
237
|
|
|
225
238
|
for (let i = 0; i < length - len; i++) {
|
|
226
239
|
b.append(this._appendsActual === this._appends ? blocks[i] : this._encrypt(b.length, blocks[i]))
|
|
@@ -239,6 +252,8 @@ module.exports = class HypercoreBatch extends EventEmitter {
|
|
|
239
252
|
if (typeof opts === 'number') opts = { fork: opts }
|
|
240
253
|
const { fork = this.fork + 1, force = false } = opts
|
|
241
254
|
|
|
255
|
+
this._cachedBatch = null
|
|
256
|
+
|
|
242
257
|
const length = this._sessionLength
|
|
243
258
|
if (newLength < length) {
|
|
244
259
|
if (!force) throw new Error('Cannot truncate committed blocks')
|
|
@@ -380,6 +395,8 @@ module.exports = class HypercoreBatch extends EventEmitter {
|
|
|
380
395
|
this._sessionByteLength = info.byteLength
|
|
381
396
|
this._sessionBatch = newBatch
|
|
382
397
|
|
|
398
|
+
if (this._cachedBatch !== null) this._cachedBatch.prune(info.length)
|
|
399
|
+
|
|
383
400
|
const same = this._appends === this._appendsActual
|
|
384
401
|
|
|
385
402
|
this._appends = this._appends.slice(flushingLength)
|
package/lib/merkle-tree.js
CHANGED
|
@@ -57,6 +57,68 @@ class MerkleTreeBatch {
|
|
|
57
57
|
this.upgraded = false
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
checkout (length, additionalRoots) {
|
|
61
|
+
const roots = []
|
|
62
|
+
let r = 0
|
|
63
|
+
|
|
64
|
+
const head = 2 * length - 2
|
|
65
|
+
const gaps = new Set()
|
|
66
|
+
const all = new Map()
|
|
67
|
+
|
|
68
|
+
// additional roots is so the original roots can be passed (we mutate the array in appendRoot)
|
|
69
|
+
if (additionalRoots) {
|
|
70
|
+
for (const node of additionalRoots) all.set(node.index, node)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
for (const node of this.nodes) all.set(node.index, node)
|
|
74
|
+
|
|
75
|
+
for (const index of flat.fullRoots(head + 2)) {
|
|
76
|
+
const left = flat.leftSpan(index)
|
|
77
|
+
if (left !== 0) gaps.add(left - 1)
|
|
78
|
+
|
|
79
|
+
if (r < this.roots.length && this.roots[r].index === index) {
|
|
80
|
+
roots.push(this.roots[r++])
|
|
81
|
+
continue
|
|
82
|
+
}
|
|
83
|
+
const node = all.get(index)
|
|
84
|
+
if (!node) throw new BAD_ARGUMENT('root missing for given length')
|
|
85
|
+
roots.push(node)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
this.roots = roots
|
|
89
|
+
this.length = length
|
|
90
|
+
this.byteLength = totalSize(roots)
|
|
91
|
+
this.hashCached = null
|
|
92
|
+
this.signature = null
|
|
93
|
+
|
|
94
|
+
for (let i = 0; i < this.nodes.length; i++) {
|
|
95
|
+
const index = this.nodes[i].index
|
|
96
|
+
if (index <= head && !gaps.has(index)) continue
|
|
97
|
+
const last = this.nodes.pop()
|
|
98
|
+
if (i < this.nodes.length) this.nodes[i--] = last
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
prune (length) {
|
|
103
|
+
if (length === 0) return
|
|
104
|
+
|
|
105
|
+
const head = 2 * length - 2
|
|
106
|
+
const gaps = new Set()
|
|
107
|
+
|
|
108
|
+
// TODO: make a function for this in flat-tree
|
|
109
|
+
for (const index of flat.fullRoots(head + 2)) {
|
|
110
|
+
const left = flat.leftSpan(index)
|
|
111
|
+
if (left !== 0) gaps.add(left - 1)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
for (let i = 0; i < this.nodes.length; i++) {
|
|
115
|
+
const index = this.nodes[i].index
|
|
116
|
+
if (index > head || gaps.has(index)) continue
|
|
117
|
+
const last = this.nodes.pop()
|
|
118
|
+
if (i < this.nodes.length) this.nodes[i--] = last
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
60
122
|
clone () {
|
|
61
123
|
const b = new MerkleTreeBatch(this.tree)
|
|
62
124
|
|
package/lib/remote-bitfield.js
CHANGED
|
@@ -230,7 +230,11 @@ module.exports = class RemoteBitfield {
|
|
|
230
230
|
i++
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
-
|
|
233
|
+
// For the val === false case, we always return at least
|
|
234
|
+
// the 'position', also if nothing was found
|
|
235
|
+
return val
|
|
236
|
+
? -1
|
|
237
|
+
: Math.max(position, this._maxSegments * BITS_PER_SEGMENT)
|
|
234
238
|
}
|
|
235
239
|
|
|
236
240
|
firstSet (position) {
|