hypercore 10.19.0 → 10.20.0
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 +53 -0
- package/lib/core.js +66 -0
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -82,6 +82,7 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
82
82
|
this.onwait = opts.onwait || null
|
|
83
83
|
this.wait = opts.wait !== false
|
|
84
84
|
this.timeout = opts.timeout || 0
|
|
85
|
+
this._clone = opts.clone || null
|
|
85
86
|
this._readonly = opts.writable === false
|
|
86
87
|
|
|
87
88
|
this.closing = null
|
|
@@ -306,6 +307,14 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
306
307
|
const s = this.sessions[i]
|
|
307
308
|
if (s !== this) s._passCapabilities(this)
|
|
308
309
|
}
|
|
310
|
+
|
|
311
|
+
// copy state over
|
|
312
|
+
if (this._clone) {
|
|
313
|
+
const { from, upgrade } = this._clone
|
|
314
|
+
await from.opening
|
|
315
|
+
await this.core.copyFrom(from.core, upgrade)
|
|
316
|
+
this._clone = null
|
|
317
|
+
}
|
|
309
318
|
}
|
|
310
319
|
|
|
311
320
|
if (!this.auth) this.auth = this.core.defaultAuth
|
|
@@ -458,6 +467,50 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
458
467
|
this.emit('close', true)
|
|
459
468
|
}
|
|
460
469
|
|
|
470
|
+
clone (storage, opts = {}) {
|
|
471
|
+
// TODO: current limitation is no forking
|
|
472
|
+
if ((opts.fork && opts.fork !== 0) || this.fork !== 0) {
|
|
473
|
+
throw BAD_ARGUMENT('Cannot clone a fork')
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
const key = opts.key === undefined ? opts.keyPair ? null : this.key : opts.key
|
|
477
|
+
const keyPair = (opts.auth || opts.keyPair === undefined) ? null : opts.keyPair
|
|
478
|
+
|
|
479
|
+
let auth = this.core.defaultAuth
|
|
480
|
+
if (opts.auth) {
|
|
481
|
+
auth = opts.auth
|
|
482
|
+
} else if (opts.sign && keyPair) {
|
|
483
|
+
auth = Core.createAuth(this.crypto, keyPair, opts)
|
|
484
|
+
} else if (opts.sign) {
|
|
485
|
+
// TODO: dangerous to just update sign?
|
|
486
|
+
auth.sign = opts.sign
|
|
487
|
+
} else if (keyPair && keyPair.secretKey) {
|
|
488
|
+
auth = Core.createAuth(this.crypto, keyPair)
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
const upgrade = opts.upgrade === undefined ? null : opts.upgrade
|
|
492
|
+
|
|
493
|
+
const sparse = opts.sparse === false ? false : this.sparse
|
|
494
|
+
const wait = opts.wait === false ? false : this.wait
|
|
495
|
+
const onwait = opts.onwait === undefined ? this.onwait : opts.onwait
|
|
496
|
+
const timeout = opts.timeout === undefined ? this.timeout : opts.timeout
|
|
497
|
+
|
|
498
|
+
const Clz = this.constructor
|
|
499
|
+
return new Clz(storage, key, {
|
|
500
|
+
...opts,
|
|
501
|
+
sparse,
|
|
502
|
+
wait,
|
|
503
|
+
onwait,
|
|
504
|
+
timeout,
|
|
505
|
+
auth,
|
|
506
|
+
overwrite: true,
|
|
507
|
+
clone: {
|
|
508
|
+
from: this,
|
|
509
|
+
upgrade
|
|
510
|
+
}
|
|
511
|
+
})
|
|
512
|
+
}
|
|
513
|
+
|
|
461
514
|
replicate (isInitiator, opts = {}) {
|
|
462
515
|
// Only limitation here is that ondiscoverykey doesn't work atm when passing a muxer directly,
|
|
463
516
|
// because it doesn't really make a lot of sense.
|
package/lib/core.js
CHANGED
|
@@ -13,6 +13,7 @@ module.exports = class Core {
|
|
|
13
13
|
constructor (header, crypto, oplog, tree, blocks, bitfield, auth, legacy, onupdate, onconflict) {
|
|
14
14
|
this.onupdate = onupdate
|
|
15
15
|
this.onconflict = onconflict
|
|
16
|
+
this.preupdate = null
|
|
16
17
|
this.header = header
|
|
17
18
|
this.crypto = crypto
|
|
18
19
|
this.oplog = oplog
|
|
@@ -174,6 +175,70 @@ module.exports = class Core {
|
|
|
174
175
|
return false
|
|
175
176
|
}
|
|
176
177
|
|
|
178
|
+
async copyFrom (src, signature, auth = this.defaultAuth) {
|
|
179
|
+
this._mutex.lock()
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
let pos = src.bitfield.firstSet(0)
|
|
183
|
+
|
|
184
|
+
while (pos >= 0) {
|
|
185
|
+
const segmentStart = pos
|
|
186
|
+
const segmentEnd = src.bitfield.firstUnset(pos)
|
|
187
|
+
|
|
188
|
+
if (segmentStart < 0) break
|
|
189
|
+
|
|
190
|
+
const segment = []
|
|
191
|
+
|
|
192
|
+
while (pos < segmentEnd) {
|
|
193
|
+
const val = await src.blocks.get(pos++)
|
|
194
|
+
segment.push(val)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const [offset] = await src.tree.byteRange(2 * segmentStart)
|
|
198
|
+
await this.blocks.putBatch(segmentStart, segment, offset)
|
|
199
|
+
|
|
200
|
+
this.bitfield.setRange(segmentStart, segmentEnd, true)
|
|
201
|
+
|
|
202
|
+
pos = src.bitfield.firstSet(segmentEnd + 1)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// TODO: is it an issue to move the nodes directly?
|
|
206
|
+
// TODO: make flat iterator that computes needed nodes
|
|
207
|
+
|
|
208
|
+
for (let i = 0; i <= src.tree.length * 2; i++) {
|
|
209
|
+
const node = await src.tree.get(i, false)
|
|
210
|
+
if (node === null) continue
|
|
211
|
+
|
|
212
|
+
await this.tree.addNode(node)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
await this.tree.flush()
|
|
216
|
+
|
|
217
|
+
this.tree.fork = src.tree.fork
|
|
218
|
+
this.tree.roots = [...src.tree.roots]
|
|
219
|
+
this.tree.length = src.tree.length
|
|
220
|
+
this.tree.byteLength = src.tree.byteLength
|
|
221
|
+
this.tree.signature = null // must provide signature
|
|
222
|
+
|
|
223
|
+
this.tree.signature = signature || auth.sign(this.tree.signable())
|
|
224
|
+
|
|
225
|
+
if (signature && !this._signed(this.tree)) {
|
|
226
|
+
// TODO: how to handle signature failure?
|
|
227
|
+
this.tree.signature = null
|
|
228
|
+
throw INVALID_SIGNATURE('Clone was provided with an invalid signature')
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
this.header.tree.length = this.tree.length
|
|
232
|
+
this.header.tree.rootHash = this.tree.hash()
|
|
233
|
+
this.header.tree.signature = this.tree.signature
|
|
234
|
+
this.header.userData = src.header.userData // should copy?
|
|
235
|
+
|
|
236
|
+
await this._flushOplog()
|
|
237
|
+
} finally {
|
|
238
|
+
this._mutex.unlock()
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
177
242
|
async _flushOplog () {
|
|
178
243
|
// TODO: the apis using this, actually do not need to wait for the bitfields, tree etc to flush
|
|
179
244
|
// as their mutations are already stored in the oplog. We could potentially just run this in the
|
|
@@ -381,6 +446,7 @@ module.exports = class Core {
|
|
|
381
446
|
bitfield
|
|
382
447
|
}
|
|
383
448
|
|
|
449
|
+
if (this.preupdate !== null) await this.preupdate(batch, this.header.signer.publicKey)
|
|
384
450
|
if (bitfield) await this._writeBlock(batch, bitfield.start, value)
|
|
385
451
|
|
|
386
452
|
await this.oplog.append([entry], false)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hypercore",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.20.0",
|
|
4
4
|
"description": "Hypercore is a secure, distributed append-only log",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -64,8 +64,8 @@
|
|
|
64
64
|
"range-parser": "^1.2.1",
|
|
65
65
|
"speedometer": "^1.1.0",
|
|
66
66
|
"standard": "^17.0.0",
|
|
67
|
+
"test-tmp": "^1.0.2",
|
|
67
68
|
"tiny-byte-size": "^1.1.0",
|
|
68
|
-
"tmp-promise": "^3.0.2",
|
|
69
69
|
"udx-native": "^1.6.1"
|
|
70
70
|
}
|
|
71
71
|
}
|