hypercore 11.16.2 → 11.18.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/README.md +31 -29
- package/index.js +153 -155
- package/lib/audit.js +17 -6
- package/lib/bit-interlude.js +17 -7
- package/lib/bitfield.js +72 -52
- package/lib/caps.js +5 -1
- package/lib/copy-prologue.js +14 -10
- package/lib/core.js +109 -56
- package/lib/default-encryption.js +14 -28
- package/lib/download.js +10 -10
- package/lib/fully-remote-proof.js +3 -3
- package/lib/hotswap-queue.js +5 -5
- package/lib/info.js +4 -4
- package/lib/inspect.js +50 -0
- package/lib/merkle-tree.js +143 -104
- package/lib/messages.js +163 -143
- package/lib/multisig.js +19 -12
- package/lib/mutex.js +9 -7
- package/lib/receiver-queue.js +6 -6
- package/lib/remote-bitfield.js +30 -32
- package/lib/replicator.js +383 -265
- package/lib/session-state.js +112 -75
- package/lib/streams.js +16 -16
- package/lib/verifier.js +69 -43
- package/package.json +5 -3
package/index.js
CHANGED
|
@@ -10,6 +10,7 @@ const id = require('hypercore-id-encoding')
|
|
|
10
10
|
const safetyCatch = require('safety-catch')
|
|
11
11
|
const unslab = require('unslab')
|
|
12
12
|
|
|
13
|
+
const inspect = require('./lib/inspect')
|
|
13
14
|
const Core = require('./lib/core')
|
|
14
15
|
const Info = require('./lib/info')
|
|
15
16
|
const Download = require('./lib/download')
|
|
@@ -29,14 +30,14 @@ const {
|
|
|
29
30
|
DECODING_ERROR
|
|
30
31
|
} = require('hypercore-errors')
|
|
31
32
|
|
|
32
|
-
const
|
|
33
|
+
const inspectSymbol = Symbol.for('nodejs.util.inspect.custom')
|
|
33
34
|
|
|
34
35
|
// Hypercore actually does not have any notion of max/min block sizes
|
|
35
36
|
// but we enforce 15mb to ensure smooth replication (each block is transmitted atomically)
|
|
36
37
|
const MAX_SUGGESTED_BLOCK_SIZE = 15 * 1024 * 1024
|
|
37
38
|
|
|
38
39
|
class Hypercore extends EventEmitter {
|
|
39
|
-
constructor
|
|
40
|
+
constructor(storage, key, opts) {
|
|
40
41
|
super()
|
|
41
42
|
|
|
42
43
|
if (isOptions(storage) && !storage.db) {
|
|
@@ -96,75 +97,37 @@ class Hypercore extends EventEmitter {
|
|
|
96
97
|
this.on('newListener', maybeAddMonitor)
|
|
97
98
|
}
|
|
98
99
|
|
|
99
|
-
[
|
|
100
|
-
|
|
101
|
-
if (typeof opts.indentationLvl === 'number') {
|
|
102
|
-
while (indent.length < opts.indentationLvl) indent += ' '
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
let peers = ''
|
|
106
|
-
const min = Math.min(this.peers.length, 5)
|
|
107
|
-
|
|
108
|
-
for (let i = 0; i < min; i++) {
|
|
109
|
-
const peer = this.peers[i]
|
|
110
|
-
|
|
111
|
-
peers += indent + ' Peer(\n'
|
|
112
|
-
peers += indent + ' remotePublicKey: ' + opts.stylize(toHex(peer.remotePublicKey), 'string') + '\n'
|
|
113
|
-
peers += indent + ' remoteLength: ' + opts.stylize(peer.remoteLength, 'number') + '\n'
|
|
114
|
-
peers += indent + ' remoteFork: ' + opts.stylize(peer.remoteFork, 'number') + '\n'
|
|
115
|
-
peers += indent + ' remoteCanUpgrade: ' + opts.stylize(peer.remoteCanUpgrade, 'boolean') + '\n'
|
|
116
|
-
peers += indent + ' )' + '\n'
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (this.peers.length > 5) {
|
|
120
|
-
peers += indent + ' ... and ' + (this.peers.length - 5) + ' more\n'
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (peers) peers = '[\n' + peers + indent + ' ]'
|
|
124
|
-
else peers = '[ ' + opts.stylize(0, 'number') + ' ]'
|
|
125
|
-
|
|
126
|
-
return this.constructor.name + '(\n' +
|
|
127
|
-
indent + ' id: ' + opts.stylize(this.id, 'string') + '\n' +
|
|
128
|
-
indent + ' key: ' + opts.stylize(toHex(this.key), 'string') + '\n' +
|
|
129
|
-
indent + ' discoveryKey: ' + opts.stylize(toHex(this.discoveryKey), 'string') + '\n' +
|
|
130
|
-
indent + ' opened: ' + opts.stylize(this.opened, 'boolean') + '\n' +
|
|
131
|
-
indent + ' closed: ' + opts.stylize(this.closed, 'boolean') + '\n' +
|
|
132
|
-
indent + ' snapshotted: ' + opts.stylize(this.snapshotted, 'boolean') + '\n' +
|
|
133
|
-
indent + ' writable: ' + opts.stylize(this.writable, 'boolean') + '\n' +
|
|
134
|
-
indent + ' length: ' + opts.stylize(this.length, 'number') + '\n' +
|
|
135
|
-
indent + ' fork: ' + opts.stylize(this.fork, 'number') + '\n' +
|
|
136
|
-
indent + ' sessions: [ ' + opts.stylize(this.sessions.length, 'number') + ' ]\n' +
|
|
137
|
-
indent + ' activeRequests: [ ' + opts.stylize(this.activeRequests.length, 'number') + ' ]\n' +
|
|
138
|
-
indent + ' peers: ' + peers + '\n' +
|
|
139
|
-
indent + ')'
|
|
100
|
+
[inspectSymbol](depth, opts) {
|
|
101
|
+
return inspect(this, depth, opts)
|
|
140
102
|
}
|
|
141
103
|
|
|
142
104
|
static MAX_SUGGESTED_BLOCK_SIZE = MAX_SUGGESTED_BLOCK_SIZE
|
|
143
105
|
|
|
144
106
|
static DefaultEncryption = DefaultEncryption
|
|
145
107
|
|
|
146
|
-
static key
|
|
147
|
-
if (b4a.isBuffer(manifest))
|
|
108
|
+
static key(manifest, { compat, version, namespace } = {}) {
|
|
109
|
+
if (b4a.isBuffer(manifest))
|
|
110
|
+
manifest = { version, signers: [{ publicKey: manifest, namespace }] }
|
|
148
111
|
return compat ? manifest.signers[0].publicKey : manifestHash(createManifest(manifest))
|
|
149
112
|
}
|
|
150
113
|
|
|
151
|
-
static discoveryKey
|
|
114
|
+
static discoveryKey(key) {
|
|
152
115
|
return crypto.discoveryKey(key)
|
|
153
116
|
}
|
|
154
117
|
|
|
155
|
-
static blockEncryptionKey
|
|
118
|
+
static blockEncryptionKey(key, encryptionKey) {
|
|
156
119
|
return DefaultEncryption.blockEncryptionKey(key, encryptionKey)
|
|
157
120
|
}
|
|
158
121
|
|
|
159
|
-
static getProtocolMuxer
|
|
122
|
+
static getProtocolMuxer(stream) {
|
|
160
123
|
return stream.noiseStream.userData
|
|
161
124
|
}
|
|
162
125
|
|
|
163
|
-
static createCore
|
|
126
|
+
static createCore(storage, opts) {
|
|
164
127
|
return new Core(Hypercore.defaultStorage(storage), { autoClose: false, ...opts })
|
|
165
128
|
}
|
|
166
129
|
|
|
167
|
-
static createProtocolStream
|
|
130
|
+
static createProtocolStream(isInitiator, opts = {}) {
|
|
168
131
|
let outerStream = Protomux.isProtomux(isInitiator)
|
|
169
132
|
? isInitiator.stream
|
|
170
133
|
: isStream(isInitiator)
|
|
@@ -197,22 +160,26 @@ class Hypercore extends EventEmitter {
|
|
|
197
160
|
return outerStream
|
|
198
161
|
}
|
|
199
162
|
|
|
200
|
-
static defaultStorage
|
|
163
|
+
static defaultStorage(storage, opts = {}) {
|
|
201
164
|
if (CoreStorage.isCoreStorage(storage)) return storage
|
|
202
165
|
|
|
203
166
|
const directory = storage
|
|
204
167
|
return new CoreStorage(directory, opts)
|
|
205
168
|
}
|
|
206
169
|
|
|
207
|
-
static clearRequests
|
|
170
|
+
static clearRequests(session, err) {
|
|
208
171
|
return Replicator.clearRequests(session, err)
|
|
209
172
|
}
|
|
210
173
|
|
|
211
|
-
snapshot
|
|
174
|
+
snapshot(opts) {
|
|
212
175
|
return this.session({ ...opts, snapshot: true })
|
|
213
176
|
}
|
|
214
177
|
|
|
215
|
-
|
|
178
|
+
compact() {
|
|
179
|
+
return this.core.compact()
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
session(opts = {}) {
|
|
216
183
|
if (this.closing) {
|
|
217
184
|
// This makes the closing logic a lot easier. If this turns out to be a problem
|
|
218
185
|
// in practice, open an issue and we'll try to make a solution for it.
|
|
@@ -243,13 +210,13 @@ class Hypercore extends EventEmitter {
|
|
|
243
210
|
return s
|
|
244
211
|
}
|
|
245
212
|
|
|
246
|
-
async setEncryptionKey
|
|
213
|
+
async setEncryptionKey(key, opts) {
|
|
247
214
|
if (!this.opened) await this.opening
|
|
248
215
|
const encryption = this._getEncryptionProvider({ key, block: !!(opts && opts.block) })
|
|
249
216
|
return this.setEncryption(encryption)
|
|
250
217
|
}
|
|
251
218
|
|
|
252
|
-
async setEncryption
|
|
219
|
+
async setEncryption(encryption) {
|
|
253
220
|
if (!this.opened) await this.opening
|
|
254
221
|
|
|
255
222
|
if (encryption === null) {
|
|
@@ -264,11 +231,11 @@ class Hypercore extends EventEmitter {
|
|
|
264
231
|
this.encryption = encryption
|
|
265
232
|
}
|
|
266
233
|
|
|
267
|
-
setKeyPair
|
|
234
|
+
setKeyPair(keyPair) {
|
|
268
235
|
this.keyPair = keyPair
|
|
269
236
|
}
|
|
270
237
|
|
|
271
|
-
setActive
|
|
238
|
+
setActive(bool) {
|
|
272
239
|
const active = !!bool
|
|
273
240
|
if (active === this._active || this.closing) return
|
|
274
241
|
this._active = active
|
|
@@ -276,7 +243,7 @@ class Hypercore extends EventEmitter {
|
|
|
276
243
|
this.core.replicator.updateActivity(this._active ? 1 : -1)
|
|
277
244
|
}
|
|
278
245
|
|
|
279
|
-
async _open
|
|
246
|
+
async _open(storage, key, opts) {
|
|
280
247
|
const preload = opts.preload || (opts.parent && opts.parent.preload)
|
|
281
248
|
|
|
282
249
|
if (preload) {
|
|
@@ -324,7 +291,7 @@ class Hypercore extends EventEmitter {
|
|
|
324
291
|
if (this.core.closing) this.close().catch(safetyCatch)
|
|
325
292
|
}
|
|
326
293
|
|
|
327
|
-
_removeSession
|
|
294
|
+
_removeSession() {
|
|
328
295
|
if (this._sessionIndex === -1) return
|
|
329
296
|
const head = this.sessions.pop()
|
|
330
297
|
if (head !== this) this.sessions[(head._sessionIndex = this._sessionIndex)] = head
|
|
@@ -332,7 +299,7 @@ class Hypercore extends EventEmitter {
|
|
|
332
299
|
if (this.ongc !== null) this.ongc(this)
|
|
333
300
|
}
|
|
334
301
|
|
|
335
|
-
async _openSession
|
|
302
|
+
async _openSession(opts) {
|
|
336
303
|
if (this.core.opened === false) await this.core.ready()
|
|
337
304
|
|
|
338
305
|
if (this.keyPair === null) this.keyPair = opts.keyPair || this.core.header.keyPair
|
|
@@ -388,10 +355,18 @@ class Hypercore extends EventEmitter {
|
|
|
388
355
|
}
|
|
389
356
|
|
|
390
357
|
if (this.state && checkout !== -1) {
|
|
391
|
-
if (!opts.name && !opts.atom)
|
|
392
|
-
|
|
358
|
+
if (!opts.name && !opts.atom)
|
|
359
|
+
throw ASSERTION('Checkouts must be named or atomized', this.discoveryKey)
|
|
360
|
+
if (checkout > this.state.length)
|
|
361
|
+
throw ASSERTION(
|
|
362
|
+
`Invalid checkout ${checkout} for ${opts.name}, length is ${this.state.length}`,
|
|
363
|
+
this.discoveryKey
|
|
364
|
+
)
|
|
393
365
|
if (this.state.prologue && checkout < this.state.prologue.length) {
|
|
394
|
-
throw ASSERTION(
|
|
366
|
+
throw ASSERTION(
|
|
367
|
+
`Invalid checkout ${checkout} for ${opts.name}, prologue length is ${this.state.prologue.length}`,
|
|
368
|
+
this.discoveryKey
|
|
369
|
+
)
|
|
395
370
|
}
|
|
396
371
|
if (checkout < this.state.length) await this.state.truncate(checkout, this.fork)
|
|
397
372
|
}
|
|
@@ -425,11 +400,11 @@ class Hypercore extends EventEmitter {
|
|
|
425
400
|
this.opened = true
|
|
426
401
|
}
|
|
427
402
|
|
|
428
|
-
get replicator
|
|
403
|
+
get replicator() {
|
|
429
404
|
return this.core === null ? null : this.core.replicator
|
|
430
405
|
}
|
|
431
406
|
|
|
432
|
-
_getSnapshot
|
|
407
|
+
_getSnapshot() {
|
|
433
408
|
return {
|
|
434
409
|
length: this.state.length,
|
|
435
410
|
byteLength: this.state.byteLength,
|
|
@@ -437,33 +412,33 @@ class Hypercore extends EventEmitter {
|
|
|
437
412
|
}
|
|
438
413
|
}
|
|
439
414
|
|
|
440
|
-
_updateSnapshot
|
|
415
|
+
_updateSnapshot() {
|
|
441
416
|
const prev = this._snapshot
|
|
442
|
-
const next = this._snapshot = this._getSnapshot()
|
|
417
|
+
const next = (this._snapshot = this._getSnapshot())
|
|
443
418
|
|
|
444
419
|
if (!prev) return true
|
|
445
420
|
return prev.length !== next.length || prev.fork !== next.fork
|
|
446
421
|
}
|
|
447
422
|
|
|
448
|
-
_isWritable
|
|
423
|
+
_isWritable() {
|
|
449
424
|
if (this._readonly) return false
|
|
450
425
|
if (this.state && !this.state.isDefault()) return true
|
|
451
426
|
return !!(this.keyPair && this.keyPair.secretKey)
|
|
452
427
|
}
|
|
453
428
|
|
|
454
|
-
close
|
|
429
|
+
close({ error } = {}) {
|
|
455
430
|
if (this.closing) return this.closing
|
|
456
431
|
|
|
457
432
|
this.closing = this._close(error || null)
|
|
458
433
|
return this.closing
|
|
459
434
|
}
|
|
460
435
|
|
|
461
|
-
clearRequests
|
|
436
|
+
clearRequests(activeRequests, error) {
|
|
462
437
|
if (!activeRequests.length) return
|
|
463
438
|
if (this.core) this.core.replicator.clearRequests(activeRequests, error)
|
|
464
439
|
}
|
|
465
440
|
|
|
466
|
-
async _close
|
|
441
|
+
async _close(error) {
|
|
467
442
|
if (this.opened === false) {
|
|
468
443
|
try {
|
|
469
444
|
await this.opening
|
|
@@ -511,14 +486,14 @@ class Hypercore extends EventEmitter {
|
|
|
511
486
|
this.emit('close')
|
|
512
487
|
}
|
|
513
488
|
|
|
514
|
-
async commit
|
|
489
|
+
async commit(session, opts) {
|
|
515
490
|
await this.ready()
|
|
516
491
|
await session.ready()
|
|
517
492
|
|
|
518
493
|
return this.state.commit(session.state, { keyPair: this.keyPair, ...opts })
|
|
519
494
|
}
|
|
520
495
|
|
|
521
|
-
replicate
|
|
496
|
+
replicate(isInitiator, opts = {}) {
|
|
522
497
|
// Only limitation here is that ondiscoverykey doesn't work atm when passing a muxer directly,
|
|
523
498
|
// because it doesn't really make a lot of sense.
|
|
524
499
|
if (Protomux.isProtomux(isInitiator)) return this._attachToMuxer(isInitiator)
|
|
@@ -535,11 +510,16 @@ class Hypercore extends EventEmitter {
|
|
|
535
510
|
return protocolStream
|
|
536
511
|
}
|
|
537
512
|
|
|
538
|
-
_isAttached
|
|
539
|
-
return
|
|
513
|
+
_isAttached(stream) {
|
|
514
|
+
return (
|
|
515
|
+
stream.userData &&
|
|
516
|
+
this.core &&
|
|
517
|
+
this.core.replicator &&
|
|
518
|
+
this.core.replicator.attached(stream.userData)
|
|
519
|
+
)
|
|
540
520
|
}
|
|
541
521
|
|
|
542
|
-
_attachToMuxer
|
|
522
|
+
_attachToMuxer(mux) {
|
|
543
523
|
if (this.opened) {
|
|
544
524
|
this.core.replicator.attachTo(mux)
|
|
545
525
|
} else {
|
|
@@ -549,55 +529,55 @@ class Hypercore extends EventEmitter {
|
|
|
549
529
|
return mux
|
|
550
530
|
}
|
|
551
531
|
|
|
552
|
-
get id
|
|
532
|
+
get id() {
|
|
553
533
|
return this.core === null ? null : this.core.id
|
|
554
534
|
}
|
|
555
535
|
|
|
556
|
-
get key
|
|
536
|
+
get key() {
|
|
557
537
|
return this.core === null ? null : this.core.key
|
|
558
538
|
}
|
|
559
539
|
|
|
560
|
-
get discoveryKey
|
|
540
|
+
get discoveryKey() {
|
|
561
541
|
return this.core === null ? null : this.core.discoveryKey
|
|
562
542
|
}
|
|
563
543
|
|
|
564
|
-
get manifest
|
|
544
|
+
get manifest() {
|
|
565
545
|
return this.core === null ? null : this.core.manifest
|
|
566
546
|
}
|
|
567
547
|
|
|
568
|
-
get length
|
|
548
|
+
get length() {
|
|
569
549
|
if (this._snapshot) return this._snapshot.length
|
|
570
550
|
return this.opened === false ? 0 : this.state.length
|
|
571
551
|
}
|
|
572
552
|
|
|
573
|
-
get signedLength
|
|
553
|
+
get signedLength() {
|
|
574
554
|
return this.opened === false ? 0 : this.state.signedLength()
|
|
575
555
|
}
|
|
576
556
|
|
|
577
557
|
/**
|
|
578
558
|
* Deprecated. Use `const { byteLength } = await core.info()`.
|
|
579
559
|
*/
|
|
580
|
-
get byteLength
|
|
560
|
+
get byteLength() {
|
|
581
561
|
if (this.opened === false) return 0
|
|
582
562
|
if (this._snapshot) return this._snapshot.byteLength
|
|
583
|
-
return this.state.byteLength -
|
|
563
|
+
return this.state.byteLength - this.state.length * this.padding
|
|
584
564
|
}
|
|
585
565
|
|
|
586
|
-
get contiguousLength
|
|
566
|
+
get contiguousLength() {
|
|
587
567
|
if (this.opened === false) return 0
|
|
588
568
|
return Math.min(this.core.state.length, this.core.header.hints.contiguousLength)
|
|
589
569
|
}
|
|
590
570
|
|
|
591
|
-
get contiguousByteLength
|
|
571
|
+
get contiguousByteLength() {
|
|
592
572
|
return 0
|
|
593
573
|
}
|
|
594
574
|
|
|
595
|
-
get fork
|
|
575
|
+
get fork() {
|
|
596
576
|
if (this.opened === false) return 0
|
|
597
577
|
return this.state.fork
|
|
598
578
|
}
|
|
599
579
|
|
|
600
|
-
get padding
|
|
580
|
+
get padding() {
|
|
601
581
|
if (this.encryption && this.key && this.manifest) {
|
|
602
582
|
return this.encryption.padding(this.core, this.length)
|
|
603
583
|
}
|
|
@@ -605,24 +585,24 @@ class Hypercore extends EventEmitter {
|
|
|
605
585
|
return 0
|
|
606
586
|
}
|
|
607
587
|
|
|
608
|
-
get peers
|
|
588
|
+
get peers() {
|
|
609
589
|
return this.opened === false ? [] : this.core.replicator.peers
|
|
610
590
|
}
|
|
611
591
|
|
|
612
|
-
get globalCache
|
|
592
|
+
get globalCache() {
|
|
613
593
|
return this.opened === false ? null : this.core.globalCache
|
|
614
594
|
}
|
|
615
595
|
|
|
616
|
-
ready
|
|
596
|
+
ready() {
|
|
617
597
|
return this.opening
|
|
618
598
|
}
|
|
619
599
|
|
|
620
|
-
async setUserData
|
|
600
|
+
async setUserData(key, value) {
|
|
621
601
|
if (this.opened === false) await this.opening
|
|
622
602
|
await this.state.setUserData(key, value)
|
|
623
603
|
}
|
|
624
604
|
|
|
625
|
-
async getUserData
|
|
605
|
+
async getUserData(key) {
|
|
626
606
|
if (this.opened === false) await this.opening
|
|
627
607
|
const batch = this.state.storage.read()
|
|
628
608
|
const p = batch.getUserData(key)
|
|
@@ -630,7 +610,7 @@ class Hypercore extends EventEmitter {
|
|
|
630
610
|
return p
|
|
631
611
|
}
|
|
632
612
|
|
|
633
|
-
transferSession
|
|
613
|
+
transferSession(core) {
|
|
634
614
|
// todo: validate we can move
|
|
635
615
|
|
|
636
616
|
if (this.weak === false) {
|
|
@@ -652,7 +632,7 @@ class Hypercore extends EventEmitter {
|
|
|
652
632
|
this.emit('migrate', this.key)
|
|
653
633
|
}
|
|
654
634
|
|
|
655
|
-
findingPeers
|
|
635
|
+
findingPeers() {
|
|
656
636
|
this._findingPeers++
|
|
657
637
|
if (this.core !== null && !this.closing) this.core.replicator.findingPeers++
|
|
658
638
|
|
|
@@ -668,13 +648,13 @@ class Hypercore extends EventEmitter {
|
|
|
668
648
|
}
|
|
669
649
|
}
|
|
670
650
|
|
|
671
|
-
async info
|
|
651
|
+
async info(opts) {
|
|
672
652
|
if (this.opened === false) await this.opening
|
|
673
653
|
|
|
674
654
|
return Info.from(this, opts)
|
|
675
655
|
}
|
|
676
656
|
|
|
677
|
-
async update
|
|
657
|
+
async update(opts) {
|
|
678
658
|
if (this.opened === false) await this.opening
|
|
679
659
|
if (this.closing !== null) return false
|
|
680
660
|
if (this.snapshotted) return false
|
|
@@ -705,7 +685,7 @@ class Hypercore extends EventEmitter {
|
|
|
705
685
|
return true
|
|
706
686
|
}
|
|
707
687
|
|
|
708
|
-
async seek
|
|
688
|
+
async seek(bytes, opts) {
|
|
709
689
|
if (this.opened === false) await this.opening
|
|
710
690
|
if (!isValidIndex(bytes)) throw ASSERTION('seek is invalid', this.discoveryKey)
|
|
711
691
|
|
|
@@ -726,7 +706,8 @@ class Hypercore extends EventEmitter {
|
|
|
726
706
|
const offset = await s.update()
|
|
727
707
|
if (offset) return offset
|
|
728
708
|
|
|
729
|
-
if (this.closing !== null)
|
|
709
|
+
if (this.closing !== null)
|
|
710
|
+
throw SESSION_CLOSED('cannot seek on a closed session', this.discoveryKey)
|
|
730
711
|
|
|
731
712
|
if (!this._shouldWait(opts, this.wait)) return null
|
|
732
713
|
|
|
@@ -743,9 +724,10 @@ class Hypercore extends EventEmitter {
|
|
|
743
724
|
}
|
|
744
725
|
}
|
|
745
726
|
|
|
746
|
-
async has
|
|
727
|
+
async has(start, end = start + 1) {
|
|
747
728
|
if (this.opened === false) await this.opening
|
|
748
|
-
if (!isValidIndex(start) || !isValidIndex(end))
|
|
729
|
+
if (!isValidIndex(start) || !isValidIndex(end))
|
|
730
|
+
throw ASSERTION('has range is invalid', this.discoveryKey)
|
|
749
731
|
|
|
750
732
|
if (this.state.isDefault()) {
|
|
751
733
|
if (end === start + 1) return this.core.bitfield.get(start)
|
|
@@ -770,16 +752,18 @@ class Hypercore extends EventEmitter {
|
|
|
770
752
|
count++
|
|
771
753
|
}
|
|
772
754
|
|
|
773
|
-
return count ===
|
|
755
|
+
return count === end - start
|
|
774
756
|
}
|
|
775
757
|
|
|
776
|
-
async get
|
|
758
|
+
async get(index, opts) {
|
|
777
759
|
if (this.opened === false) await this.opening
|
|
778
760
|
if (!isValidIndex(index)) throw ASSERTION('block index is invalid', this.discoveryKey)
|
|
779
761
|
|
|
780
|
-
if (this.closing !== null)
|
|
762
|
+
if (this.closing !== null)
|
|
763
|
+
throw SESSION_CLOSED('cannot get on a closed session', this.discoveryKey)
|
|
781
764
|
|
|
782
|
-
const encoding =
|
|
765
|
+
const encoding =
|
|
766
|
+
(opts && opts.valueEncoding && c.from(opts.valueEncoding)) || this.valueEncoding
|
|
783
767
|
|
|
784
768
|
if (this.onseq !== null) this.onseq(index, this)
|
|
785
769
|
|
|
@@ -800,18 +784,20 @@ class Hypercore extends EventEmitter {
|
|
|
800
784
|
return this._decode(encoding, block, index)
|
|
801
785
|
}
|
|
802
786
|
|
|
803
|
-
async clear
|
|
787
|
+
async clear(start, end = start + 1, opts) {
|
|
804
788
|
if (this.opened === false) await this.opening
|
|
805
|
-
if (this.closing !== null)
|
|
789
|
+
if (this.closing !== null)
|
|
790
|
+
throw SESSION_CLOSED('cannot clear on a closed session', this.discoveryKey)
|
|
806
791
|
|
|
807
792
|
if (typeof end === 'object') {
|
|
808
793
|
opts = end
|
|
809
794
|
end = start + 1
|
|
810
795
|
}
|
|
811
796
|
|
|
812
|
-
if (!isValidIndex(start) || !isValidIndex(end))
|
|
797
|
+
if (!isValidIndex(start) || !isValidIndex(end))
|
|
798
|
+
throw ASSERTION('clear range is invalid', this.discoveryKey)
|
|
813
799
|
|
|
814
|
-
const cleared =
|
|
800
|
+
const cleared = opts && opts.diff ? { blocks: 0 } : null
|
|
815
801
|
|
|
816
802
|
if (start >= end) return cleared
|
|
817
803
|
if (start >= this.length) return cleared
|
|
@@ -821,17 +807,18 @@ class Hypercore extends EventEmitter {
|
|
|
821
807
|
return cleared
|
|
822
808
|
}
|
|
823
809
|
|
|
824
|
-
async purge
|
|
810
|
+
async purge() {
|
|
825
811
|
await this._closeAllSessions(null)
|
|
826
812
|
await this.core.purge()
|
|
827
813
|
}
|
|
828
814
|
|
|
829
|
-
async _get
|
|
815
|
+
async _get(index, opts) {
|
|
830
816
|
const block = await readBlock(this.state.storage.read(), index)
|
|
831
817
|
|
|
832
818
|
if (block !== null) return block
|
|
833
819
|
|
|
834
|
-
if (this.closing !== null)
|
|
820
|
+
if (this.closing !== null)
|
|
821
|
+
throw SESSION_CLOSED('cannot get on a closed session', this.discoveryKey)
|
|
835
822
|
|
|
836
823
|
// snapshot should check if core has block
|
|
837
824
|
if (this._snapshot !== null) {
|
|
@@ -876,7 +863,7 @@ class Hypercore extends EventEmitter {
|
|
|
876
863
|
return maybeUnslab(replicatedBlock)
|
|
877
864
|
}
|
|
878
865
|
|
|
879
|
-
_shouldWait
|
|
866
|
+
_shouldWait(opts, defaultValue) {
|
|
880
867
|
if (opts) {
|
|
881
868
|
if (opts.wait === false) return false
|
|
882
869
|
if (opts.wait === true) return true
|
|
@@ -884,33 +871,33 @@ class Hypercore extends EventEmitter {
|
|
|
884
871
|
return defaultValue
|
|
885
872
|
}
|
|
886
873
|
|
|
887
|
-
createReadStream
|
|
874
|
+
createReadStream(opts) {
|
|
888
875
|
return new ReadStream(this, opts)
|
|
889
876
|
}
|
|
890
877
|
|
|
891
|
-
createWriteStream
|
|
878
|
+
createWriteStream() {
|
|
892
879
|
return new WriteStream(this)
|
|
893
880
|
}
|
|
894
881
|
|
|
895
|
-
createByteStream
|
|
882
|
+
createByteStream(opts) {
|
|
896
883
|
return new ByteStream(this, opts)
|
|
897
884
|
}
|
|
898
885
|
|
|
899
|
-
download
|
|
886
|
+
download(range) {
|
|
900
887
|
return new Download(this, range)
|
|
901
888
|
}
|
|
902
889
|
|
|
903
890
|
// TODO: get rid of this / deprecate it?
|
|
904
|
-
undownload
|
|
891
|
+
undownload(range) {
|
|
905
892
|
range.destroy(null)
|
|
906
893
|
}
|
|
907
894
|
|
|
908
895
|
// TODO: get rid of this / deprecate it?
|
|
909
|
-
cancel
|
|
896
|
+
cancel(request) {
|
|
910
897
|
// Do nothing for now
|
|
911
898
|
}
|
|
912
899
|
|
|
913
|
-
async truncate
|
|
900
|
+
async truncate(newLength = 0, opts = {}) {
|
|
914
901
|
if (this.opened === false) await this.opening
|
|
915
902
|
|
|
916
903
|
const {
|
|
@@ -921,7 +908,8 @@ class Hypercore extends EventEmitter {
|
|
|
921
908
|
|
|
922
909
|
const isDefault = this.state === this.core.state
|
|
923
910
|
const writable = !this._readonly && !!(signature || (keyPair && keyPair.secretKey))
|
|
924
|
-
if (isDefault && writable === false && (newLength > 0 || fork !== this.state.fork))
|
|
911
|
+
if (isDefault && writable === false && (newLength > 0 || fork !== this.state.fork))
|
|
912
|
+
throw SESSION_NOT_WRITABLE('cannot append to a non-writable core', this.discoveryKey)
|
|
925
913
|
|
|
926
914
|
await this.state.truncate(newLength, fork, { keyPair, signature })
|
|
927
915
|
|
|
@@ -929,16 +917,18 @@ class Hypercore extends EventEmitter {
|
|
|
929
917
|
if (this.state === this.core.state) this.core.replicator.updateAll()
|
|
930
918
|
}
|
|
931
919
|
|
|
932
|
-
async append
|
|
920
|
+
async append(blocks, opts = {}) {
|
|
933
921
|
if (this.opened === false) await this.opening
|
|
934
922
|
|
|
935
923
|
const isDefault = this.state === this.core.state
|
|
936
924
|
const defaultKeyPair = this.state.name === null ? this.keyPair : null
|
|
937
925
|
|
|
938
926
|
const { keyPair = defaultKeyPair, signature = null, maxLength } = opts
|
|
939
|
-
const writable =
|
|
927
|
+
const writable =
|
|
928
|
+
!isDefault || !!signature || !!(keyPair && keyPair.secretKey) || opts.writable === true
|
|
940
929
|
|
|
941
|
-
if (this._readonly || writable === false)
|
|
930
|
+
if (this._readonly || writable === false)
|
|
931
|
+
throw SESSION_NOT_WRITABLE('cannot append to a readonly core', this.discoveryKey)
|
|
942
932
|
|
|
943
933
|
blocks = Array.isArray(blocks) ? blocks : [blocks]
|
|
944
934
|
|
|
@@ -953,14 +943,17 @@ class Hypercore extends EventEmitter {
|
|
|
953
943
|
}
|
|
954
944
|
for (const b of buffers) {
|
|
955
945
|
if (b.byteLength > MAX_SUGGESTED_BLOCK_SIZE) {
|
|
956
|
-
throw BAD_ARGUMENT(
|
|
946
|
+
throw BAD_ARGUMENT(
|
|
947
|
+
'Appended block exceeds the maximum suggested block size',
|
|
948
|
+
this.discoveryKey
|
|
949
|
+
)
|
|
957
950
|
}
|
|
958
951
|
}
|
|
959
952
|
|
|
960
953
|
return this.state.append(buffers, { keyPair, signature, preappend, maxLength })
|
|
961
954
|
}
|
|
962
955
|
|
|
963
|
-
async signable
|
|
956
|
+
async signable(length = -1, fork = -1) {
|
|
964
957
|
if (this.opened === false) await this.opening
|
|
965
958
|
if (length === -1) length = this.length
|
|
966
959
|
if (fork === -1) fork = this.fork
|
|
@@ -968,7 +961,7 @@ class Hypercore extends EventEmitter {
|
|
|
968
961
|
return caps.treeSignable(this.key, await this.treeHash(length), length, fork)
|
|
969
962
|
}
|
|
970
963
|
|
|
971
|
-
async treeHash
|
|
964
|
+
async treeHash(length = -1) {
|
|
972
965
|
if (this.opened === false) await this.opening
|
|
973
966
|
if (length === -1) length = this.length
|
|
974
967
|
|
|
@@ -976,7 +969,12 @@ class Hypercore extends EventEmitter {
|
|
|
976
969
|
return crypto.tree(roots)
|
|
977
970
|
}
|
|
978
971
|
|
|
979
|
-
async
|
|
972
|
+
async missingNodes(index) {
|
|
973
|
+
if (this.opened === false) await this.opening
|
|
974
|
+
return await MerkleTree.missingNodes(this.core.state, 2 * index, this.core.state.length)
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
async proof(opts) {
|
|
980
978
|
if (this.opened === false) await this.opening
|
|
981
979
|
const rx = this.state.storage.read()
|
|
982
980
|
const promise = MerkleTree.proof(this.state, rx, opts)
|
|
@@ -984,14 +982,14 @@ class Hypercore extends EventEmitter {
|
|
|
984
982
|
return promise
|
|
985
983
|
}
|
|
986
984
|
|
|
987
|
-
async verifyFullyRemote
|
|
985
|
+
async verifyFullyRemote(proof) {
|
|
988
986
|
if (this.opened === false) await this.opening
|
|
989
987
|
const batch = await MerkleTree.verifyFullyRemote(this.state, proof)
|
|
990
988
|
await this.core._verifyBatchUpgrade(batch, proof.manifest)
|
|
991
989
|
return batch
|
|
992
990
|
}
|
|
993
991
|
|
|
994
|
-
registerExtension
|
|
992
|
+
registerExtension(name, handlers = {}) {
|
|
995
993
|
if (this.extensions.has(name)) {
|
|
996
994
|
const ext = this.extensions.get(name)
|
|
997
995
|
ext.handlers = handlers
|
|
@@ -1005,23 +1003,23 @@ class Hypercore extends EventEmitter {
|
|
|
1005
1003
|
handlers,
|
|
1006
1004
|
encoding: c.from(handlers.encoding || c.buffer),
|
|
1007
1005
|
session: this,
|
|
1008
|
-
send
|
|
1006
|
+
send(message, peer) {
|
|
1009
1007
|
const buffer = c.encode(this.encoding, message)
|
|
1010
1008
|
peer.extension(name, buffer)
|
|
1011
1009
|
},
|
|
1012
|
-
broadcast
|
|
1010
|
+
broadcast(message) {
|
|
1013
1011
|
const buffer = c.encode(this.encoding, message)
|
|
1014
1012
|
for (const peer of this.session.peers) {
|
|
1015
1013
|
peer.extension(name, buffer)
|
|
1016
1014
|
}
|
|
1017
1015
|
},
|
|
1018
|
-
destroy
|
|
1016
|
+
destroy() {
|
|
1019
1017
|
for (const peer of this.session.peers) {
|
|
1020
1018
|
if (peer.extensions.get(name) === ext) peer.extensions.delete(name)
|
|
1021
1019
|
}
|
|
1022
1020
|
this.session.extensions.delete(name)
|
|
1023
1021
|
},
|
|
1024
|
-
_onmessage
|
|
1022
|
+
_onmessage(state, peer) {
|
|
1025
1023
|
const m = this.encoding.decode(state)
|
|
1026
1024
|
if (this.handlers.onmessage) this.handlers.onmessage(m, peer)
|
|
1027
1025
|
}
|
|
@@ -1039,7 +1037,7 @@ class Hypercore extends EventEmitter {
|
|
|
1039
1037
|
return ext
|
|
1040
1038
|
}
|
|
1041
1039
|
|
|
1042
|
-
_encode
|
|
1040
|
+
_encode(enc, val) {
|
|
1043
1041
|
const state = { start: this.padding, end: this.padding, buffer: null }
|
|
1044
1042
|
|
|
1045
1043
|
if (b4a.isBuffer(val)) {
|
|
@@ -1061,7 +1059,7 @@ class Hypercore extends EventEmitter {
|
|
|
1061
1059
|
return state.buffer
|
|
1062
1060
|
}
|
|
1063
1061
|
|
|
1064
|
-
_decode
|
|
1062
|
+
_decode(enc, block, index) {
|
|
1065
1063
|
if (this.encryption) block = block.subarray(this.encryption.padding(this.core, index))
|
|
1066
1064
|
try {
|
|
1067
1065
|
if (enc) return c.decode(enc, block)
|
|
@@ -1071,7 +1069,7 @@ class Hypercore extends EventEmitter {
|
|
|
1071
1069
|
return block
|
|
1072
1070
|
}
|
|
1073
1071
|
|
|
1074
|
-
_getEncryptionProvider
|
|
1072
|
+
_getEncryptionProvider(e) {
|
|
1075
1073
|
if (isEncryptionProvider(e)) return e
|
|
1076
1074
|
if (!e || !e.key) return null
|
|
1077
1075
|
return new DefaultEncryption(e.key, this.key, { block: e.block, compat: this.core.compat })
|
|
@@ -1080,15 +1078,11 @@ class Hypercore extends EventEmitter {
|
|
|
1080
1078
|
|
|
1081
1079
|
module.exports = Hypercore
|
|
1082
1080
|
|
|
1083
|
-
function isStream
|
|
1081
|
+
function isStream(s) {
|
|
1084
1082
|
return typeof s === 'object' && s && typeof s.pipe === 'function'
|
|
1085
1083
|
}
|
|
1086
1084
|
|
|
1087
|
-
function
|
|
1088
|
-
return buf && b4a.toString(buf, 'hex')
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
async function preappend (blocks) {
|
|
1085
|
+
async function preappend(blocks) {
|
|
1092
1086
|
const offset = this.state.length
|
|
1093
1087
|
const fork = this.state.encryptionFork
|
|
1094
1088
|
|
|
@@ -1097,26 +1091,30 @@ async function preappend (blocks) {
|
|
|
1097
1091
|
}
|
|
1098
1092
|
}
|
|
1099
1093
|
|
|
1100
|
-
function isValidIndex
|
|
1094
|
+
function isValidIndex(index) {
|
|
1101
1095
|
return index === 0 || index > 0
|
|
1102
1096
|
}
|
|
1103
1097
|
|
|
1104
|
-
function maybeUnslab
|
|
1098
|
+
function maybeUnslab(block) {
|
|
1105
1099
|
// Unslab only when it takes up less then half the slab
|
|
1106
1100
|
return block !== null && 2 * block.byteLength < block.buffer.byteLength ? unslab(block) : block
|
|
1107
1101
|
}
|
|
1108
1102
|
|
|
1109
|
-
function checkSnapshot
|
|
1110
|
-
if (index >= snapshot.state.snapshotCompatLength)
|
|
1103
|
+
function checkSnapshot(snapshot, index) {
|
|
1104
|
+
if (index >= snapshot.state.snapshotCompatLength)
|
|
1105
|
+
throw SNAPSHOT_NOT_AVAILABLE(
|
|
1106
|
+
`snapshot at index ${index} not available (max compat length ${snapshot.state.snapshotCompatLength})`,
|
|
1107
|
+
snapshot.discoveryKey
|
|
1108
|
+
)
|
|
1111
1109
|
}
|
|
1112
1110
|
|
|
1113
|
-
function readBlock
|
|
1111
|
+
function readBlock(rx, index) {
|
|
1114
1112
|
const promise = rx.getBlock(index)
|
|
1115
1113
|
rx.tryFlush()
|
|
1116
1114
|
return promise
|
|
1117
1115
|
}
|
|
1118
1116
|
|
|
1119
|
-
function initOnce
|
|
1117
|
+
function initOnce(session, storage, key, opts) {
|
|
1120
1118
|
if (storage === null) storage = opts.storage || null
|
|
1121
1119
|
if (key === null) key = opts.key || null
|
|
1122
1120
|
|
|
@@ -1139,7 +1137,7 @@ function initOnce (session, storage, key, opts) {
|
|
|
1139
1137
|
})
|
|
1140
1138
|
}
|
|
1141
1139
|
|
|
1142
|
-
function maybeAddMonitor
|
|
1140
|
+
function maybeAddMonitor(name) {
|
|
1143
1141
|
if (name === 'append' || name === 'truncate') return
|
|
1144
1142
|
if (this._monitorIndex >= 0 || this.closing) return
|
|
1145
1143
|
|
|
@@ -1150,21 +1148,21 @@ function maybeAddMonitor (name) {
|
|
|
1150
1148
|
}
|
|
1151
1149
|
}
|
|
1152
1150
|
|
|
1153
|
-
function isSessionMoved
|
|
1151
|
+
function isSessionMoved(err) {
|
|
1154
1152
|
return err.code === 'SESSION_MOVED'
|
|
1155
1153
|
}
|
|
1156
1154
|
|
|
1157
|
-
function getEncryptionOption
|
|
1155
|
+
function getEncryptionOption(opts) {
|
|
1158
1156
|
// old style, supported for now but will go away
|
|
1159
1157
|
if (opts.encryptionKey) return { key: opts.encryptionKey, block: !!opts.isBlockKey }
|
|
1160
1158
|
if (!opts.encryption) return null
|
|
1161
1159
|
return b4a.isBuffer(opts.encryption) ? { key: opts.encryption } : opts.encryption
|
|
1162
1160
|
}
|
|
1163
1161
|
|
|
1164
|
-
function isEncryptionProvider
|
|
1162
|
+
function isEncryptionProvider(e) {
|
|
1165
1163
|
return e && isFunction(e.padding) && isFunction(e.encrypt) && isFunction(e.decrypt)
|
|
1166
1164
|
}
|
|
1167
1165
|
|
|
1168
|
-
function isFunction
|
|
1166
|
+
function isFunction(fn) {
|
|
1169
1167
|
return !!fn && typeof fn === 'function'
|
|
1170
1168
|
}
|