hypercore 10.24.0 → 10.24.2
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 +5 -2
- package/lib/batch.js +66 -13
- package/lib/core.js +4 -4
- package/lib/manifest.js +4 -0
- package/lib/merkle-tree.js +4 -4
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -135,7 +135,7 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
static key (manifest, { compat } = {}) {
|
|
138
|
-
return compat ? manifest.signer.publicKey : manifestHash(manifest)
|
|
138
|
+
return compat ? manifest.signer.publicKey : manifestHash(createManifest(manifest))
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
static discoveryKey (key) {
|
|
@@ -960,6 +960,9 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
960
960
|
async append (blocks, opts = {}) {
|
|
961
961
|
if (this._batch && this !== this._batch.session) throw BATCH_UNFLUSHED()
|
|
962
962
|
|
|
963
|
+
// if a batched append, run unlocked as it already locked...
|
|
964
|
+
const lock = !this._batch
|
|
965
|
+
|
|
963
966
|
if (this.opened === false) await this.opening
|
|
964
967
|
|
|
965
968
|
const { keyPair = this.keyPair, signature = null } = opts
|
|
@@ -979,7 +982,7 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
979
982
|
}
|
|
980
983
|
}
|
|
981
984
|
|
|
982
|
-
return this.core.append(buffers, { keyPair, signature, preappend })
|
|
985
|
+
return this.core.append(buffers, { lock, keyPair, signature, preappend })
|
|
983
986
|
}
|
|
984
987
|
|
|
985
988
|
async treeHash (length) {
|
package/lib/batch.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const { BLOCK_NOT_AVAILABLE, SESSION_CLOSED } = require('hypercore-errors')
|
|
2
2
|
const EventEmitter = require('events')
|
|
3
3
|
const c = require('compact-encoding')
|
|
4
|
+
const b4a = require('b4a')
|
|
4
5
|
|
|
5
6
|
module.exports = class HypercoreBatch extends EventEmitter {
|
|
6
7
|
constructor (session, autoClose) {
|
|
@@ -19,6 +20,7 @@ module.exports = class HypercoreBatch extends EventEmitter {
|
|
|
19
20
|
this._byteLength = 0
|
|
20
21
|
this._sessionLength = 0
|
|
21
22
|
this._sessionByteLength = 0
|
|
23
|
+
this._sessionBatch = null
|
|
22
24
|
this._flushing = null
|
|
23
25
|
|
|
24
26
|
this.opening = this.ready().catch(noop)
|
|
@@ -65,6 +67,7 @@ module.exports = class HypercoreBatch extends EventEmitter {
|
|
|
65
67
|
if (this.opened) return
|
|
66
68
|
this._sessionLength = this.session.length
|
|
67
69
|
this._sessionByteLength = this.session.byteLength
|
|
70
|
+
this._sessionBatch = this.session.createTreeBatch()
|
|
68
71
|
this.fork = this.session.fork
|
|
69
72
|
this.opened = true
|
|
70
73
|
this.emit('ready')
|
|
@@ -149,7 +152,7 @@ module.exports = class HypercoreBatch extends EventEmitter {
|
|
|
149
152
|
if (!length && length !== 0) length = this.length + blocks.length
|
|
150
153
|
|
|
151
154
|
const maxLength = this.length + blocks.length
|
|
152
|
-
const b = this.
|
|
155
|
+
const b = this._sessionBatch.clone()
|
|
153
156
|
const len = Math.min(length, this.length)
|
|
154
157
|
|
|
155
158
|
if (len < this._sessionLength || length > maxLength) return null
|
|
@@ -185,6 +188,7 @@ module.exports = class HypercoreBatch extends EventEmitter {
|
|
|
185
188
|
await this.session.truncate(newLength, { fork, force: true, ...opts })
|
|
186
189
|
this._sessionLength = this.session.length
|
|
187
190
|
this._sessionByteLength = this.session.byteLength
|
|
191
|
+
this._sessionBatch = this.session.createTreeBatch()
|
|
188
192
|
} else {
|
|
189
193
|
for (let i = newLength - length; i < this._appends.length; i++) this._byteLength -= this._appends[i].byteLength
|
|
190
194
|
this._appends.length = newLength - length
|
|
@@ -230,34 +234,83 @@ module.exports = class HypercoreBatch extends EventEmitter {
|
|
|
230
234
|
if (this.opened === false) await this.opening
|
|
231
235
|
if (this.closing) throw SESSION_CLOSED()
|
|
232
236
|
|
|
233
|
-
const { length = this.
|
|
237
|
+
const { length = this.length, keyPair = this.session.keyPair, signature = null } = opts
|
|
234
238
|
|
|
235
239
|
while (this._flushing) await this._flushing
|
|
236
240
|
this._flushing = this._flush(length, keyPair, signature)
|
|
237
241
|
|
|
242
|
+
let flushed = false
|
|
243
|
+
|
|
238
244
|
try {
|
|
239
|
-
await this._flushing
|
|
245
|
+
flushed = await this._flushing
|
|
240
246
|
} finally {
|
|
241
247
|
this._flushing = null
|
|
242
248
|
}
|
|
243
249
|
|
|
244
250
|
if (this.autoClose) await this.close()
|
|
251
|
+
|
|
252
|
+
return flushed
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
async _catchup () {
|
|
256
|
+
if (this.core.tree.length === this._sessionLength) return true
|
|
257
|
+
|
|
258
|
+
const batchLength = this._sessionLength + this._appends.length
|
|
259
|
+
|
|
260
|
+
if (this.core.tree.length > batchLength) return false
|
|
261
|
+
|
|
262
|
+
const b = this.createTreeBatch()
|
|
263
|
+
|
|
264
|
+
for (const root of this.core.tree.roots) {
|
|
265
|
+
const batchRoot = await b.get(root.index)
|
|
266
|
+
|
|
267
|
+
if (batchRoot === null) continue // in the shared tree
|
|
268
|
+
if (batchRoot.size !== root.size || !b4a.equals(batchRoot.hash, root.hash)) {
|
|
269
|
+
// TODO: type this error
|
|
270
|
+
throw new Error('Batch is uncommitable due to a conflict at ' + root.index)
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const offset = this._sessionLength + this._appends.length - this.core.tree.length
|
|
275
|
+
for (let i = 0; i < offset; i++) this._byteLength -= this._appends[i]
|
|
276
|
+
|
|
277
|
+
this._sessionLength = this.session.length
|
|
278
|
+
this._sessionByteLength = this.session.byteLength
|
|
279
|
+
this._sessionBatch = this.session.createTreeBatch()
|
|
280
|
+
|
|
281
|
+
if (offset) this._appends = this._appends.slice(this._appends.length - offset)
|
|
282
|
+
|
|
283
|
+
return true
|
|
245
284
|
}
|
|
246
285
|
|
|
247
286
|
async _flush (length, keyPair, signature) { // TODO: make this safe to interact with a parallel truncate...
|
|
248
|
-
if (this._appends.length === 0) return
|
|
287
|
+
if (this._appends.length === 0) return true
|
|
288
|
+
if (!(await this._catchup())) return false
|
|
289
|
+
|
|
290
|
+
await this.core._mutex.lock()
|
|
249
291
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
const delta = info.byteLength - this._sessionByteLength
|
|
292
|
+
try {
|
|
293
|
+
const flushingLength = Math.min(length - this._sessionLength, this._appends.length)
|
|
294
|
+
if (flushingLength <= 0) return true
|
|
254
295
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
296
|
+
const blocks = flushingLength < this._appends.length ? this._appends.slice(0, flushingLength) : this._appends
|
|
297
|
+
|
|
298
|
+
const info = await this.session.append(blocks, { keyPair, signature })
|
|
299
|
+
const delta = info.byteLength - this._sessionByteLength
|
|
300
|
+
|
|
301
|
+
this._sessionLength = info.length
|
|
302
|
+
this._sessionByteLength = info.byteLength
|
|
303
|
+
this._sessionBatch = this.session.createTreeBatch()
|
|
304
|
+
|
|
305
|
+
this._appends = this._appends.slice(flushingLength)
|
|
306
|
+
this._byteLength -= delta
|
|
307
|
+
|
|
308
|
+
this.emit('flush')
|
|
309
|
+
} finally {
|
|
310
|
+
this.core._mutex.unlock()
|
|
311
|
+
}
|
|
259
312
|
|
|
260
|
-
|
|
313
|
+
return true
|
|
261
314
|
}
|
|
262
315
|
|
|
263
316
|
close () {
|
package/lib/core.js
CHANGED
|
@@ -432,8 +432,8 @@ module.exports = class Core {
|
|
|
432
432
|
})
|
|
433
433
|
}
|
|
434
434
|
|
|
435
|
-
async append (values, { signature, keyPair = this.header.keyPair, preappend } = {}) {
|
|
436
|
-
await this._mutex.lock()
|
|
435
|
+
async append (values, { lock, signature, keyPair = this.header.keyPair, preappend } = {}) {
|
|
436
|
+
if (lock) await this._mutex.lock()
|
|
437
437
|
|
|
438
438
|
// upsert compat manifest
|
|
439
439
|
if (this.verifier === null && keyPair) this.setManifest(null, keyPair)
|
|
@@ -479,7 +479,7 @@ module.exports = class Core {
|
|
|
479
479
|
|
|
480
480
|
return { length: batch.length, byteLength }
|
|
481
481
|
} finally {
|
|
482
|
-
this._mutex.unlock()
|
|
482
|
+
if (lock) this._mutex.unlock()
|
|
483
483
|
}
|
|
484
484
|
}
|
|
485
485
|
|
|
@@ -494,7 +494,7 @@ module.exports = class Core {
|
|
|
494
494
|
|
|
495
495
|
const verifier = this.verifier || createVerifier(manifest, { compat: isCompat(this.header.key, manifest), crypto: this.crypto, legacy: this._legacy })
|
|
496
496
|
|
|
497
|
-
if (!
|
|
497
|
+
if (!verifier.verify(batch, batch.signature)) {
|
|
498
498
|
throw INVALID_SIGNATURE('Proof contains an invalid signature')
|
|
499
499
|
}
|
|
500
500
|
|
package/lib/manifest.js
CHANGED
|
@@ -44,6 +44,7 @@ class CompatVerifier {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
verify (batch, signature) {
|
|
47
|
+
if (!signature) return false
|
|
47
48
|
return this.crypto.verify(batch.signableCompat(this.legacy), signature, this.publicKey)
|
|
48
49
|
}
|
|
49
50
|
}
|
|
@@ -63,6 +64,7 @@ class SingleVerifier {
|
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
verify (batch, signature) {
|
|
67
|
+
if (!signature) return false
|
|
66
68
|
return this.crypto.verify(batch.signable(this.namespace), signature, this.publicKey)
|
|
67
69
|
}
|
|
68
70
|
}
|
|
@@ -82,6 +84,8 @@ class MultiVerifier {
|
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
verify (batch, signature) {
|
|
87
|
+
if (!signature) return false
|
|
88
|
+
|
|
85
89
|
const inputs = multisig.inflate(signature)
|
|
86
90
|
|
|
87
91
|
if (inputs.length < this.quorum) return false
|
package/lib/merkle-tree.js
CHANGED
|
@@ -92,14 +92,14 @@ class MerkleTreeBatch {
|
|
|
92
92
|
return null
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
if (index < this.treeLength * 2) {
|
|
96
|
-
return this.tree.get(index)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
95
|
for (const n of this.nodes) {
|
|
100
96
|
if (n.index === index) return n
|
|
101
97
|
}
|
|
102
98
|
|
|
99
|
+
if (index < this.treeLength * 2) {
|
|
100
|
+
return this.tree.get(index)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
103
|
return null
|
|
104
104
|
}
|
|
105
105
|
|