hypercore 11.13.3 → 11.13.4
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 +21 -21
- package/lib/core.js +9 -9
- package/lib/replicator.js +15 -5
- package/lib/session-state.js +7 -7
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -178,7 +178,7 @@ class Hypercore extends EventEmitter {
|
|
|
178
178
|
noiseStream = new NoiseSecretStream(isInitiator, null, opts)
|
|
179
179
|
outerStream = noiseStream.rawStream
|
|
180
180
|
}
|
|
181
|
-
if (!noiseStream) throw BAD_ARGUMENT('Invalid stream')
|
|
181
|
+
if (!noiseStream) throw BAD_ARGUMENT('Invalid stream', this.discoveryKey)
|
|
182
182
|
|
|
183
183
|
if (!noiseStream.userData) {
|
|
184
184
|
const protocol = Protomux.from(noiseStream)
|
|
@@ -211,10 +211,10 @@ class Hypercore extends EventEmitter {
|
|
|
211
211
|
if (this.closing) {
|
|
212
212
|
// This makes the closing logic a lot easier. If this turns out to be a problem
|
|
213
213
|
// in practice, open an issue and we'll try to make a solution for it.
|
|
214
|
-
throw SESSION_CLOSED('Cannot make sessions on a closing core')
|
|
214
|
+
throw SESSION_CLOSED('Cannot make sessions on a closing core', this.discoveryKey)
|
|
215
215
|
}
|
|
216
216
|
if (opts.checkout !== undefined && !opts.name && !opts.atom) {
|
|
217
|
-
throw ASSERTION('Checkouts are only supported on atoms or named sessions')
|
|
217
|
+
throw ASSERTION('Checkouts are only supported on atoms or named sessions', this.discoveryKey)
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
const wait = opts.wait === false ? false : this.wait
|
|
@@ -253,7 +253,7 @@ class Hypercore extends EventEmitter {
|
|
|
253
253
|
}
|
|
254
254
|
|
|
255
255
|
if (!isEncryptionProvider(encryption)) {
|
|
256
|
-
throw ASSERTION('Provider does not satisfy HypercoreEncryption interface')
|
|
256
|
+
throw ASSERTION('Provider does not satisfy HypercoreEncryption interface', this.discoveryKey)
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
this.encryption = encryption
|
|
@@ -383,10 +383,10 @@ class Hypercore extends EventEmitter {
|
|
|
383
383
|
}
|
|
384
384
|
|
|
385
385
|
if (this.state && checkout !== -1) {
|
|
386
|
-
if (!opts.name && !opts.atom) throw ASSERTION('Checkouts must be named or atomized')
|
|
387
|
-
if (checkout > this.state.length) throw ASSERTION('Invalid checkout ' + checkout + ' for ' + opts.name + ', length is ' + this.state.length)
|
|
386
|
+
if (!opts.name && !opts.atom) throw ASSERTION('Checkouts must be named or atomized', this.discoveryKey)
|
|
387
|
+
if (checkout > this.state.length) throw ASSERTION('Invalid checkout ' + checkout + ' for ' + opts.name + ', length is ' + this.state.length, this.discoveryKey)
|
|
388
388
|
if (this.state.prologue && checkout < this.state.prologue.length) {
|
|
389
|
-
throw ASSERTION('Invalid checkout ' + checkout + ' for ' + opts.name + ', prologue length is ' + this.state.prologue.length)
|
|
389
|
+
throw ASSERTION('Invalid checkout ' + checkout + ' for ' + opts.name + ', prologue length is ' + this.state.prologue.length, this.discoveryKey)
|
|
390
390
|
}
|
|
391
391
|
if (checkout < this.state.length) await this.state.truncate(checkout, this.fork)
|
|
392
392
|
}
|
|
@@ -697,7 +697,7 @@ class Hypercore extends EventEmitter {
|
|
|
697
697
|
|
|
698
698
|
async seek (bytes, opts) {
|
|
699
699
|
if (this.opened === false) await this.opening
|
|
700
|
-
if (!isValidIndex(bytes)) throw ASSERTION('seek is invalid')
|
|
700
|
+
if (!isValidIndex(bytes)) throw ASSERTION('seek is invalid', this.discoveryKey)
|
|
701
701
|
|
|
702
702
|
const activeRequests = (opts && opts.activeRequests) || this.activeRequests
|
|
703
703
|
|
|
@@ -716,7 +716,7 @@ class Hypercore extends EventEmitter {
|
|
|
716
716
|
const offset = await s.update()
|
|
717
717
|
if (offset) return offset
|
|
718
718
|
|
|
719
|
-
if (this.closing !== null) throw SESSION_CLOSED()
|
|
719
|
+
if (this.closing !== null) throw SESSION_CLOSED('cannot seek on a closed session', this.discoveryKey)
|
|
720
720
|
|
|
721
721
|
if (!this._shouldWait(opts, this.wait)) return null
|
|
722
722
|
|
|
@@ -735,7 +735,7 @@ class Hypercore extends EventEmitter {
|
|
|
735
735
|
|
|
736
736
|
async has (start, end = start + 1) {
|
|
737
737
|
if (this.opened === false) await this.opening
|
|
738
|
-
if (!isValidIndex(start) || !isValidIndex(end)) throw ASSERTION('has range is invalid')
|
|
738
|
+
if (!isValidIndex(start) || !isValidIndex(end)) throw ASSERTION('has range is invalid', this.discoveryKey)
|
|
739
739
|
|
|
740
740
|
if (this.state.isDefault()) {
|
|
741
741
|
if (end === start + 1) return this.core.bitfield.get(start)
|
|
@@ -765,9 +765,9 @@ class Hypercore extends EventEmitter {
|
|
|
765
765
|
|
|
766
766
|
async get (index, opts) {
|
|
767
767
|
if (this.opened === false) await this.opening
|
|
768
|
-
if (!isValidIndex(index)) throw ASSERTION('block index is invalid')
|
|
768
|
+
if (!isValidIndex(index)) throw ASSERTION('block index is invalid', this.discoveryKey)
|
|
769
769
|
|
|
770
|
-
if (this.closing !== null) throw SESSION_CLOSED()
|
|
770
|
+
if (this.closing !== null) throw SESSION_CLOSED('cannot get on a closed session', this.discoveryKey)
|
|
771
771
|
|
|
772
772
|
const encoding = (opts && opts.valueEncoding && c.from(opts.valueEncoding)) || this.valueEncoding
|
|
773
773
|
|
|
@@ -792,14 +792,14 @@ class Hypercore extends EventEmitter {
|
|
|
792
792
|
|
|
793
793
|
async clear (start, end = start + 1, opts) {
|
|
794
794
|
if (this.opened === false) await this.opening
|
|
795
|
-
if (this.closing !== null) throw SESSION_CLOSED()
|
|
795
|
+
if (this.closing !== null) throw SESSION_CLOSED('cannot clear on a closed session', this.discoveryKey)
|
|
796
796
|
|
|
797
797
|
if (typeof end === 'object') {
|
|
798
798
|
opts = end
|
|
799
799
|
end = start + 1
|
|
800
800
|
}
|
|
801
801
|
|
|
802
|
-
if (!isValidIndex(start) || !isValidIndex(end)) throw ASSERTION('clear range is invalid')
|
|
802
|
+
if (!isValidIndex(start) || !isValidIndex(end)) throw ASSERTION('clear range is invalid', this.discoveryKey)
|
|
803
803
|
|
|
804
804
|
const cleared = (opts && opts.diff) ? { blocks: 0 } : null
|
|
805
805
|
|
|
@@ -821,7 +821,7 @@ class Hypercore extends EventEmitter {
|
|
|
821
821
|
|
|
822
822
|
if (block !== null) return block
|
|
823
823
|
|
|
824
|
-
if (this.closing !== null) throw SESSION_CLOSED()
|
|
824
|
+
if (this.closing !== null) throw SESSION_CLOSED('cannot get on a closed session', this.discoveryKey)
|
|
825
825
|
|
|
826
826
|
// snapshot should check if core has block
|
|
827
827
|
if (this._snapshot !== null) {
|
|
@@ -911,7 +911,7 @@ class Hypercore extends EventEmitter {
|
|
|
911
911
|
|
|
912
912
|
const isDefault = this.state === this.core.state
|
|
913
913
|
const writable = !this._readonly && !!(signature || (keyPair && keyPair.secretKey))
|
|
914
|
-
if (isDefault && writable === false && (newLength > 0 || fork !== this.state.fork)) throw SESSION_NOT_WRITABLE()
|
|
914
|
+
if (isDefault && writable === false && (newLength > 0 || fork !== this.state.fork)) throw SESSION_NOT_WRITABLE('cannot append to a non-writable core', this.discoveryKey)
|
|
915
915
|
|
|
916
916
|
await this.state.truncate(newLength, fork, { keyPair, signature })
|
|
917
917
|
|
|
@@ -928,7 +928,7 @@ class Hypercore extends EventEmitter {
|
|
|
928
928
|
const { keyPair = defaultKeyPair, signature = null, maxLength } = opts
|
|
929
929
|
const writable = !isDefault || !!signature || !!(keyPair && keyPair.secretKey) || opts.writable === true
|
|
930
930
|
|
|
931
|
-
if (this._readonly || writable === false) throw SESSION_NOT_WRITABLE()
|
|
931
|
+
if (this._readonly || writable === false) throw SESSION_NOT_WRITABLE('cannot append to a readonly core', this.discoveryKey)
|
|
932
932
|
|
|
933
933
|
blocks = Array.isArray(blocks) ? blocks : [blocks]
|
|
934
934
|
|
|
@@ -943,7 +943,7 @@ class Hypercore extends EventEmitter {
|
|
|
943
943
|
}
|
|
944
944
|
for (const b of buffers) {
|
|
945
945
|
if (b.byteLength > MAX_SUGGESTED_BLOCK_SIZE) {
|
|
946
|
-
throw BAD_ARGUMENT('Appended block exceeds the maximum suggested block size')
|
|
946
|
+
throw BAD_ARGUMENT('Appended block exceeds the maximum suggested block size', this.discoveryKey)
|
|
947
947
|
}
|
|
948
948
|
}
|
|
949
949
|
|
|
@@ -1055,8 +1055,8 @@ class Hypercore extends EventEmitter {
|
|
|
1055
1055
|
if (this.encryption) block = block.subarray(this.encryption.padding(this.core, index))
|
|
1056
1056
|
try {
|
|
1057
1057
|
if (enc) return c.decode(enc, block)
|
|
1058
|
-
} catch {
|
|
1059
|
-
throw DECODING_ERROR()
|
|
1058
|
+
} catch (err) {
|
|
1059
|
+
throw DECODING_ERROR(err.message, this.discoveryKey)
|
|
1060
1060
|
}
|
|
1061
1061
|
return block
|
|
1062
1062
|
}
|
|
@@ -1097,7 +1097,7 @@ function maybeUnslab (block) {
|
|
|
1097
1097
|
}
|
|
1098
1098
|
|
|
1099
1099
|
function checkSnapshot (snapshot, index) {
|
|
1100
|
-
if (index >= snapshot.state.snapshotCompatLength) throw SNAPSHOT_NOT_AVAILABLE()
|
|
1100
|
+
if (index >= snapshot.state.snapshotCompatLength) throw SNAPSHOT_NOT_AVAILABLE(`snapshot at index ${index} not available (max compat length ${snapshot.state.snapshotCompatLength})`, snapshot.discoveryKey)
|
|
1101
1101
|
}
|
|
1102
1102
|
|
|
1103
1103
|
function readBlock (rx, index) {
|
package/lib/core.js
CHANGED
|
@@ -146,17 +146,17 @@ module.exports = class Core {
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
if (!header && (opts.discoveryKey && !(opts.key || opts.manifest))) {
|
|
149
|
-
throw STORAGE_EMPTY('No Hypercore is stored here')
|
|
149
|
+
throw STORAGE_EMPTY('No Hypercore is stored here', this.discoveryKey)
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
if (!header || overwrite) {
|
|
153
153
|
if (!createIfMissing) {
|
|
154
|
-
throw STORAGE_EMPTY('No Hypercore is stored here')
|
|
154
|
+
throw STORAGE_EMPTY('No Hypercore is stored here', this.discoveryKey)
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
if (compat) {
|
|
158
158
|
if (opts.key && opts.keyPair && !b4a.equals(opts.key, opts.keyPair.publicKey)) {
|
|
159
|
-
throw BAD_ARGUMENT('Key must match publicKey when in compat mode')
|
|
159
|
+
throw BAD_ARGUMENT('Key must match publicKey when in compat mode', this.discoveryKey)
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
|
|
@@ -216,14 +216,14 @@ module.exports = class Core {
|
|
|
216
216
|
if (opts.manifest) {
|
|
217
217
|
// if we provide a manifest and no key, verify that the stored key is the same
|
|
218
218
|
if (!opts.key && !Verifier.isValidManifest(header.key, Verifier.createManifest(opts.manifest))) {
|
|
219
|
-
throw STORAGE_CONFLICT('Manifest does not hash to provided key')
|
|
219
|
+
throw STORAGE_CONFLICT('Manifest does not hash to provided key', this.discoveryKey)
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
if (!header.manifest) header.manifest = opts.manifest
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
if (opts.key && !b4a.equals(header.key, opts.key)) {
|
|
226
|
-
throw STORAGE_CONFLICT('Another Hypercore is stored here')
|
|
226
|
+
throw STORAGE_CONFLICT('Another Hypercore is stored here', this.discoveryKey)
|
|
227
227
|
}
|
|
228
228
|
|
|
229
229
|
// if we signalled compat, but already now this core isn't disable it
|
|
@@ -298,7 +298,7 @@ module.exports = class Core {
|
|
|
298
298
|
|
|
299
299
|
try {
|
|
300
300
|
if (manifest && this.header.manifest === null) {
|
|
301
|
-
if (!Verifier.isValidManifest(this.header.key, manifest)) throw INVALID_CHECKSUM('Manifest hash does not match')
|
|
301
|
+
if (!Verifier.isValidManifest(this.header.key, manifest)) throw INVALID_CHECKSUM('Manifest hash does not match', this.discoveryKey)
|
|
302
302
|
|
|
303
303
|
const tx = this.state.createWriteBatch()
|
|
304
304
|
this._setManifest(tx, Verifier.createManifest(manifest), null)
|
|
@@ -385,13 +385,13 @@ module.exports = class Core {
|
|
|
385
385
|
if (!manifest) manifest = Verifier.defaultSignerManifest(this.header.key)
|
|
386
386
|
|
|
387
387
|
if (!manifest || !(Verifier.isValidManifest(this.header.key, manifest) || Verifier.isCompat(this.header.key, manifest))) {
|
|
388
|
-
throw INVALID_SIGNATURE('Proof contains an invalid manifest') // TODO: proper error type
|
|
388
|
+
throw INVALID_SIGNATURE('Proof contains an invalid manifest', this.discoveryKey) // TODO: proper error type
|
|
389
389
|
}
|
|
390
390
|
}
|
|
391
391
|
|
|
392
392
|
const verifier = this.verifier || new Verifier(this.header.key, Verifier.createManifest(manifest), { legacy: this._legacy })
|
|
393
393
|
if (!verifier.verify(batch, batch.signature)) {
|
|
394
|
-
throw INVALID_SIGNATURE('Proof contains an invalid signature')
|
|
394
|
+
throw INVALID_SIGNATURE('Proof contains an invalid signature', this.discoveryKey)
|
|
395
395
|
}
|
|
396
396
|
|
|
397
397
|
return manifest
|
|
@@ -451,7 +451,7 @@ module.exports = class Core {
|
|
|
451
451
|
|
|
452
452
|
// if we got a manifest AND its strictly a non compat one, lets store it
|
|
453
453
|
if (manifest && this.header.manifest === null) {
|
|
454
|
-
if (!Verifier.isValidManifest(this.header.key, manifest)) throw INVALID_CHECKSUM('Manifest hash does not match')
|
|
454
|
+
if (!Verifier.isValidManifest(this.header.key, manifest)) throw INVALID_CHECKSUM('Manifest hash does not match', this.discoveryKey)
|
|
455
455
|
this._setManifest(tx, manifest, null)
|
|
456
456
|
}
|
|
457
457
|
|
package/lib/replicator.js
CHANGED
|
@@ -1325,6 +1325,8 @@ class Peer {
|
|
|
1325
1325
|
}
|
|
1326
1326
|
|
|
1327
1327
|
_requestRange (r) {
|
|
1328
|
+
if (this.syncsProcessing > 0) return false
|
|
1329
|
+
|
|
1328
1330
|
const { length, fork } = this.core.state
|
|
1329
1331
|
|
|
1330
1332
|
if (r.blocks) {
|
|
@@ -1343,31 +1345,39 @@ class Peer {
|
|
|
1343
1345
|
return false
|
|
1344
1346
|
}
|
|
1345
1347
|
|
|
1346
|
-
|
|
1348
|
+
// if we can upgrade the remote, or the remote is ahead, then all the remotes blocks are valid
|
|
1349
|
+
// otherwise truncate to the last length the remote has acked for us
|
|
1350
|
+
const maxLocalLength = this.canUpgrade || this.remoteLength >= this.core.state.length
|
|
1351
|
+
? this.core.state.length
|
|
1352
|
+
: fork === this.lastUpgradableFork ? Math.min(this.lastUpgradableLength, this.core.state.length) : 0
|
|
1353
|
+
|
|
1354
|
+
const end = Math.min(maxLocalLength, Math.min(r.end === -1 ? this.remoteLength : r.end, this.remoteLength))
|
|
1347
1355
|
if (end <= r.start || fork !== this.remoteFork) return false
|
|
1348
1356
|
|
|
1349
1357
|
const len = end - r.start
|
|
1350
1358
|
const off = r.start + (r.linear ? 0 : Math.floor(Math.random() * len))
|
|
1351
1359
|
|
|
1352
1360
|
let i = off
|
|
1361
|
+
// should be way less than this, but this is worst case upper bound for the skiplist
|
|
1362
|
+
let tries = this.inflight
|
|
1353
1363
|
|
|
1354
|
-
|
|
1364
|
+
do {
|
|
1355
1365
|
i = this._findNext(i)
|
|
1356
1366
|
if (i === -1 || i >= end) break
|
|
1357
1367
|
|
|
1358
1368
|
if (this._requestRangeBlock(i, length)) return true
|
|
1359
1369
|
i++
|
|
1360
|
-
}
|
|
1370
|
+
} while (tries-- > 0)
|
|
1361
1371
|
|
|
1362
1372
|
i = r.start
|
|
1363
1373
|
|
|
1364
|
-
|
|
1374
|
+
do {
|
|
1365
1375
|
i = this._findNext(i)
|
|
1366
1376
|
if (i === -1 || i >= off) break
|
|
1367
1377
|
|
|
1368
1378
|
if (this._requestRangeBlock(i, length)) return true
|
|
1369
1379
|
i++
|
|
1370
|
-
}
|
|
1380
|
+
} while (tries-- > 0)
|
|
1371
1381
|
|
|
1372
1382
|
this._maybeWant(r.start, len)
|
|
1373
1383
|
return false
|
package/lib/session-state.js
CHANGED
|
@@ -373,10 +373,10 @@ module.exports = class SessionState {
|
|
|
373
373
|
|
|
374
374
|
try {
|
|
375
375
|
if (this.prologue && length < this.prologue.length) {
|
|
376
|
-
throw INVALID_OPERATION('Truncation breaks prologue')
|
|
376
|
+
throw INVALID_OPERATION('Truncation breaks prologue', this.core.discoveryKey)
|
|
377
377
|
}
|
|
378
378
|
if (length > this.length) {
|
|
379
|
-
throw INVALID_OPERATION('Not a truncation, ' + length + ' must be less or equal to ' + this.length)
|
|
379
|
+
throw INVALID_OPERATION('Not a truncation, ' + length + ' must be less or equal to ' + this.length, this.core.discoveryKey)
|
|
380
380
|
}
|
|
381
381
|
|
|
382
382
|
const batch = this.createTreeBatch()
|
|
@@ -531,7 +531,7 @@ module.exports = class SessionState {
|
|
|
531
531
|
|
|
532
532
|
// only multisig can have prologue so signature is always present
|
|
533
533
|
if (this.prologue && batch.length < this.prologue.length) {
|
|
534
|
-
throw INVALID_OPERATION('Append is not consistent with prologue')
|
|
534
|
+
throw INVALID_OPERATION('Append is not consistent with prologue', this.core.discoveryKey)
|
|
535
535
|
}
|
|
536
536
|
|
|
537
537
|
if (!signature && keyPair) signature = this.core.verifier.sign(batch, keyPair)
|
|
@@ -618,7 +618,7 @@ module.exports = class SessionState {
|
|
|
618
618
|
if (b.drop) {
|
|
619
619
|
// truncation must be from end
|
|
620
620
|
if (p && (b.start + b.length !== p.start + p.appends)) {
|
|
621
|
-
throw INVALID_OPERATION('Atomic truncations must be contiguous')
|
|
621
|
+
throw INVALID_OPERATION('Atomic truncations must be contiguous', this.core.discoveryKey)
|
|
622
622
|
}
|
|
623
623
|
|
|
624
624
|
// actual truncation
|
|
@@ -642,7 +642,7 @@ module.exports = class SessionState {
|
|
|
642
642
|
}
|
|
643
643
|
|
|
644
644
|
if (b.start !== p.start + p.appends) {
|
|
645
|
-
throw INVALID_OPERATION('Atomic operations must be contiguous')
|
|
645
|
+
throw INVALID_OPERATION('Atomic operations must be contiguous', this.core.discoveryKey)
|
|
646
646
|
}
|
|
647
647
|
|
|
648
648
|
p.appends += b.length
|
|
@@ -679,7 +679,7 @@ module.exports = class SessionState {
|
|
|
679
679
|
const truncating = sharedLength < origLength
|
|
680
680
|
|
|
681
681
|
for (const node of roots) {
|
|
682
|
-
if (node === null) throw INVALID_OPERATION('Invalid catchup length, tree nodes not available')
|
|
682
|
+
if (node === null) throw INVALID_OPERATION('Invalid catchup length, tree nodes not available', this.core.discoveryKey)
|
|
683
683
|
}
|
|
684
684
|
|
|
685
685
|
const fork = truncating ? this.fork + 1 : this.fork
|
|
@@ -755,7 +755,7 @@ module.exports = class SessionState {
|
|
|
755
755
|
batch.length = length
|
|
756
756
|
|
|
757
757
|
if (!this.core.verifier.verify(batch, signature)) {
|
|
758
|
-
throw INVALID_SIGNATURE('Signature is not valid over committed tree')
|
|
758
|
+
throw INVALID_SIGNATURE('Signature is not valid over committed tree', this.core.discoveryKey)
|
|
759
759
|
}
|
|
760
760
|
}
|
|
761
761
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hypercore",
|
|
3
|
-
"version": "11.13.
|
|
3
|
+
"version": "11.13.4",
|
|
4
4
|
"description": "Hypercore is a secure, distributed append-only log",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"fast-fifo": "^1.3.0",
|
|
51
51
|
"flat-tree": "^1.9.0",
|
|
52
52
|
"hypercore-crypto": "^3.2.1",
|
|
53
|
-
"hypercore-errors": "^1.
|
|
53
|
+
"hypercore-errors": "^1.5.0",
|
|
54
54
|
"hypercore-id-encoding": "^1.2.0",
|
|
55
55
|
"hypercore-storage": "^1.0.0",
|
|
56
56
|
"is-options": "^1.0.1",
|