hypercore 10.0.0-alpha.5 → 10.0.0-alpha.50
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 +68 -5
- package/index.js +594 -173
- package/lib/bitfield.js +9 -5
- package/lib/block-encryption.js +68 -0
- package/lib/block-store.js +3 -1
- package/lib/caps.js +32 -0
- package/lib/core.js +88 -27
- package/lib/errors.js +50 -0
- package/lib/merkle-tree.js +186 -113
- package/lib/messages.js +249 -168
- package/lib/oplog.js +4 -3
- package/lib/replicator.js +1385 -616
- package/lib/streams.js +56 -0
- package/package.json +18 -9
- package/.github/workflows/test-node.yml +0 -23
- package/CHANGELOG.md +0 -37
- package/UPGRADE.md +0 -9
- package/examples/announce.js +0 -19
- package/examples/basic.js +0 -10
- package/examples/http.js +0 -123
- package/examples/lookup.js +0 -20
- package/lib/extensions.js +0 -76
- package/lib/protocol.js +0 -524
- package/lib/random-iterator.js +0 -46
- package/test/basic.js +0 -78
- package/test/bitfield.js +0 -71
- package/test/core.js +0 -290
- package/test/encodings.js +0 -18
- package/test/extension.js +0 -71
- package/test/helpers/index.js +0 -23
- package/test/merkle-tree.js +0 -518
- package/test/mutex.js +0 -137
- package/test/oplog.js +0 -399
- package/test/preload.js +0 -72
- package/test/replicate.js +0 -333
- package/test/sessions.js +0 -173
- package/test/user-data.js +0 -47
package/lib/bitfield.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// TODO: needs massive improvements obvs
|
|
2
2
|
|
|
3
3
|
const BigSparseArray = require('big-sparse-array')
|
|
4
|
+
const b4a = require('b4a')
|
|
4
5
|
|
|
5
6
|
class FixedBitfield {
|
|
6
7
|
constructor (index, bitfield) {
|
|
@@ -40,8 +41,9 @@ module.exports = class Bitfield {
|
|
|
40
41
|
this.pages = new BigSparseArray()
|
|
41
42
|
this.unflushed = []
|
|
42
43
|
this.storage = storage
|
|
44
|
+
this.resumed = !!(buf && buf.byteLength >= 4)
|
|
43
45
|
|
|
44
|
-
const all =
|
|
46
|
+
const all = this.resumed
|
|
45
47
|
? new Uint32Array(buf.buffer, buf.byteOffset, Math.floor(buf.byteLength / 4))
|
|
46
48
|
: new Uint32Array(1024)
|
|
47
49
|
|
|
@@ -92,8 +94,10 @@ module.exports = class Bitfield {
|
|
|
92
94
|
clear () {
|
|
93
95
|
return new Promise((resolve, reject) => {
|
|
94
96
|
this.storage.del(0, Infinity, (err) => {
|
|
95
|
-
if (err) reject(err)
|
|
96
|
-
|
|
97
|
+
if (err) return reject(err)
|
|
98
|
+
this.pages = new BigSparseArray()
|
|
99
|
+
this.unflushed = []
|
|
100
|
+
resolve()
|
|
97
101
|
})
|
|
98
102
|
})
|
|
99
103
|
}
|
|
@@ -116,9 +120,9 @@ module.exports = class Bitfield {
|
|
|
116
120
|
let error = null
|
|
117
121
|
|
|
118
122
|
for (const page of this.unflushed) {
|
|
119
|
-
const
|
|
123
|
+
const buf = b4a.from(page.bitfield.buffer, page.bitfield.byteOffset, page.bitfield.byteLength)
|
|
120
124
|
page.dirty = false
|
|
121
|
-
this.storage.write(page.index * 4096,
|
|
125
|
+
this.storage.write(page.index * 4096, buf, done)
|
|
122
126
|
}
|
|
123
127
|
|
|
124
128
|
function done (err) {
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const sodium = require('sodium-universal')
|
|
2
|
+
const c = require('compact-encoding')
|
|
3
|
+
const b4a = require('b4a')
|
|
4
|
+
|
|
5
|
+
const nonce = b4a.alloc(sodium.crypto_stream_NONCEBYTES)
|
|
6
|
+
|
|
7
|
+
module.exports = class BlockEncryption {
|
|
8
|
+
constructor (encryptionKey, hypercoreKey) {
|
|
9
|
+
const subKeys = b4a.alloc(2 * sodium.crypto_stream_KEYBYTES)
|
|
10
|
+
|
|
11
|
+
this.key = encryptionKey
|
|
12
|
+
this.blockKey = subKeys.subarray(0, sodium.crypto_stream_KEYBYTES)
|
|
13
|
+
this.blindingKey = subKeys.subarray(sodium.crypto_stream_KEYBYTES)
|
|
14
|
+
this.padding = 8
|
|
15
|
+
|
|
16
|
+
sodium.crypto_generichash(this.blockKey, encryptionKey, hypercoreKey)
|
|
17
|
+
sodium.crypto_generichash(this.blindingKey, this.blockKey)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
encrypt (index, block, fork) {
|
|
21
|
+
const padding = block.subarray(0, this.padding)
|
|
22
|
+
block = block.subarray(this.padding)
|
|
23
|
+
|
|
24
|
+
c.uint64.encode({ start: 0, end: 8, buffer: padding }, fork)
|
|
25
|
+
c.uint64.encode({ start: 0, end: 8, buffer: nonce }, index)
|
|
26
|
+
|
|
27
|
+
// Zero out any previous padding.
|
|
28
|
+
nonce.fill(0, 8, 8 + padding.byteLength)
|
|
29
|
+
|
|
30
|
+
// Blind the fork ID, possibly risking reusing the nonce on a reorg of the
|
|
31
|
+
// Hypercore. This is fine as the blinding is best-effort and the latest
|
|
32
|
+
// fork ID shared on replication anyway.
|
|
33
|
+
sodium.crypto_stream_xor(
|
|
34
|
+
padding,
|
|
35
|
+
padding,
|
|
36
|
+
nonce,
|
|
37
|
+
this.blindingKey
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
nonce.set(padding, 8)
|
|
41
|
+
|
|
42
|
+
// The combination of a (blinded) fork ID and a block index is unique for a
|
|
43
|
+
// given Hypercore and is therefore a valid nonce for encrypting the block.
|
|
44
|
+
sodium.crypto_stream_xor(
|
|
45
|
+
block,
|
|
46
|
+
block,
|
|
47
|
+
nonce,
|
|
48
|
+
this.blockKey
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
decrypt (index, block) {
|
|
53
|
+
const padding = block.subarray(0, this.padding)
|
|
54
|
+
block = block.subarray(this.padding)
|
|
55
|
+
|
|
56
|
+
c.uint64.encode({ start: 0, end: 8, buffer: nonce }, index)
|
|
57
|
+
|
|
58
|
+
nonce.set(padding, 8)
|
|
59
|
+
|
|
60
|
+
// Decrypt the block using the blinded fork ID.
|
|
61
|
+
sodium.crypto_stream_xor(
|
|
62
|
+
block,
|
|
63
|
+
block,
|
|
64
|
+
nonce,
|
|
65
|
+
this.blockKey
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
}
|
package/lib/block-store.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const b4a = require('b4a')
|
|
2
|
+
|
|
1
3
|
module.exports = class BlockStore {
|
|
2
4
|
constructor (storage, tree) {
|
|
3
5
|
this.storage = storage
|
|
@@ -15,7 +17,7 @@ module.exports = class BlockStore {
|
|
|
15
17
|
|
|
16
18
|
putBatch (i, batch, offset) {
|
|
17
19
|
if (batch.length === 0) return Promise.resolve()
|
|
18
|
-
return this.put(i, batch.length === 1 ? batch[0] :
|
|
20
|
+
return this.put(i, batch.length === 1 ? batch[0] : b4a.concat(batch), offset)
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
clear () {
|
package/lib/caps.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const crypto = require('hypercore-crypto')
|
|
2
|
+
const sodium = require('sodium-universal')
|
|
3
|
+
const b4a = require('b4a')
|
|
4
|
+
const c = require('compact-encoding')
|
|
5
|
+
|
|
6
|
+
// TODO: rename this to "crypto" and move everything hashing related etc in here
|
|
7
|
+
// Also lets move the tree stuff from hypercore-crypto here
|
|
8
|
+
|
|
9
|
+
const [TREE, REPLICATE_INITIATOR, REPLICATE_RESPONDER] = crypto.namespace('hypercore', 3)
|
|
10
|
+
|
|
11
|
+
exports.replicate = function (isInitiator, key, handshakeHash) {
|
|
12
|
+
const out = b4a.allocUnsafe(32)
|
|
13
|
+
sodium.crypto_generichash_batch(out, [isInitiator ? REPLICATE_INITIATOR : REPLICATE_RESPONDER, key], handshakeHash)
|
|
14
|
+
return out
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
exports.treeSignable = function (hash, length, fork) {
|
|
18
|
+
const state = { start: 0, end: 80, buffer: b4a.allocUnsafe(80) }
|
|
19
|
+
c.raw.encode(state, TREE)
|
|
20
|
+
c.raw.encode(state, hash)
|
|
21
|
+
c.uint64.encode(state, length)
|
|
22
|
+
c.uint64.encode(state, fork)
|
|
23
|
+
return state.buffer
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
exports.treeSignableLegacy = function (hash, length, fork) {
|
|
27
|
+
const state = { start: 0, end: 48, buffer: b4a.allocUnsafe(48) }
|
|
28
|
+
c.raw.encode(state, hash)
|
|
29
|
+
c.uint64.encode(state, length)
|
|
30
|
+
c.uint64.encode(state, fork)
|
|
31
|
+
return state.buffer
|
|
32
|
+
}
|
package/lib/core.js
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
const hypercoreCrypto = require('hypercore-crypto')
|
|
2
|
+
const b4a = require('b4a')
|
|
2
3
|
const Oplog = require('./oplog')
|
|
3
4
|
const Mutex = require('./mutex')
|
|
4
5
|
const MerkleTree = require('./merkle-tree')
|
|
5
6
|
const BlockStore = require('./block-store')
|
|
6
7
|
const Bitfield = require('./bitfield')
|
|
7
|
-
const {
|
|
8
|
+
const { BAD_ARGUMENT, STORAGE_EMPTY, STORAGE_CONFLICT, INVALID_SIGNATURE } = require('./errors')
|
|
9
|
+
const m = require('./messages')
|
|
8
10
|
|
|
9
11
|
module.exports = class Core {
|
|
10
|
-
constructor (header, crypto, oplog, tree, blocks, bitfield,
|
|
12
|
+
constructor (header, crypto, oplog, tree, blocks, bitfield, auth, legacy, onupdate, oncontigupdate) {
|
|
11
13
|
this.onupdate = onupdate
|
|
14
|
+
this.oncontigupdate = oncontigupdate
|
|
12
15
|
this.header = header
|
|
13
16
|
this.crypto = crypto
|
|
14
17
|
this.oplog = oplog
|
|
15
18
|
this.tree = tree
|
|
16
19
|
this.blocks = blocks
|
|
17
20
|
this.bitfield = bitfield
|
|
18
|
-
this.
|
|
21
|
+
this.defaultAuth = auth
|
|
19
22
|
this.truncating = 0
|
|
20
23
|
|
|
21
24
|
this._maxOplogSize = 65536
|
|
@@ -23,6 +26,9 @@ module.exports = class Core {
|
|
|
23
26
|
this._verifies = null
|
|
24
27
|
this._verifiesFlushed = null
|
|
25
28
|
this._mutex = new Mutex()
|
|
29
|
+
this._legacy = legacy
|
|
30
|
+
|
|
31
|
+
this._updateContiguousLength(header.contiguousLength)
|
|
26
32
|
}
|
|
27
33
|
|
|
28
34
|
static async open (storage, opts = {}) {
|
|
@@ -49,27 +55,46 @@ module.exports = class Core {
|
|
|
49
55
|
}
|
|
50
56
|
}
|
|
51
57
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
static createAuth (crypto, { publicKey, secretKey }, opts = {}) {
|
|
59
|
+
if (secretKey && !crypto.validateKeyPair({ publicKey, secretKey })) {
|
|
60
|
+
throw BAD_ARGUMENT('Invalid key pair')
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const sign = opts.sign
|
|
64
|
+
? opts.sign
|
|
65
|
+
: secretKey
|
|
66
|
+
? (signable) => crypto.sign(signable, secretKey)
|
|
67
|
+
: undefined
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
sign,
|
|
71
|
+
verify (signable, signature) {
|
|
72
|
+
return crypto.verify(signable, signature, publicKey)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
56
75
|
}
|
|
57
76
|
|
|
58
77
|
static async resume (oplogFile, treeFile, bitfieldFile, dataFile, opts) {
|
|
59
|
-
|
|
78
|
+
let overwrite = opts.overwrite === true
|
|
79
|
+
|
|
80
|
+
const force = opts.force === true
|
|
60
81
|
const createIfMissing = opts.createIfMissing !== false
|
|
61
82
|
const crypto = opts.crypto || hypercoreCrypto
|
|
62
83
|
|
|
63
84
|
const oplog = new Oplog(oplogFile, {
|
|
64
|
-
headerEncoding:
|
|
65
|
-
entryEncoding:
|
|
85
|
+
headerEncoding: m.oplog.header,
|
|
86
|
+
entryEncoding: m.oplog.entry
|
|
66
87
|
})
|
|
67
88
|
|
|
68
89
|
let { header, entries } = await oplog.open()
|
|
69
90
|
|
|
70
|
-
if (
|
|
91
|
+
if (force && opts.keyPair && header && header.signer && !b4a.equals(header.signer.publicKey, opts.keyPair.publicKey)) {
|
|
92
|
+
overwrite = true
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!header || overwrite) {
|
|
71
96
|
if (!createIfMissing) {
|
|
72
|
-
throw
|
|
97
|
+
throw STORAGE_EMPTY('No Hypercore is stored here')
|
|
73
98
|
}
|
|
74
99
|
|
|
75
100
|
header = {
|
|
@@ -84,14 +109,15 @@ module.exports = class Core {
|
|
|
84
109
|
signer: opts.keyPair || crypto.keyPair(),
|
|
85
110
|
hints: {
|
|
86
111
|
reorgs: []
|
|
87
|
-
}
|
|
112
|
+
},
|
|
113
|
+
contiguousLength: 0
|
|
88
114
|
}
|
|
89
115
|
|
|
90
116
|
await oplog.flush(header)
|
|
91
117
|
}
|
|
92
118
|
|
|
93
|
-
if (opts.keyPair && !header.signer.publicKey
|
|
94
|
-
throw
|
|
119
|
+
if (opts.keyPair && !b4a.equals(header.signer.publicKey, opts.keyPair.publicKey)) {
|
|
120
|
+
throw STORAGE_CONFLICT('Another Hypercore is stored here')
|
|
95
121
|
}
|
|
96
122
|
|
|
97
123
|
const tree = await MerkleTree.open(treeFile, { crypto, ...header.tree })
|
|
@@ -102,9 +128,13 @@ module.exports = class Core {
|
|
|
102
128
|
await tree.clear()
|
|
103
129
|
await blocks.clear()
|
|
104
130
|
await bitfield.clear()
|
|
131
|
+
entries = []
|
|
132
|
+
} else if (bitfield.resumed && header.tree.length === 0) {
|
|
133
|
+
// If this was an old bitfield, reset it since it loads based on disk size atm (TODO: change that)
|
|
134
|
+
await bitfield.clear()
|
|
105
135
|
}
|
|
106
136
|
|
|
107
|
-
const
|
|
137
|
+
const auth = opts.auth || this.createAuth(crypto, header.signer)
|
|
108
138
|
|
|
109
139
|
for (const e of entries) {
|
|
110
140
|
if (e.userData) {
|
|
@@ -118,7 +148,7 @@ module.exports = class Core {
|
|
|
118
148
|
}
|
|
119
149
|
|
|
120
150
|
if (e.bitfield) {
|
|
121
|
-
bitfield.setRange(e.bitfield.start, e.bitfield.length)
|
|
151
|
+
bitfield.setRange(e.bitfield.start, e.bitfield.length, !e.bitfield.drop)
|
|
122
152
|
}
|
|
123
153
|
|
|
124
154
|
if (e.treeUpgrade) {
|
|
@@ -135,7 +165,7 @@ module.exports = class Core {
|
|
|
135
165
|
}
|
|
136
166
|
}
|
|
137
167
|
|
|
138
|
-
return new this(header, crypto, oplog, tree, blocks, bitfield,
|
|
168
|
+
return new this(header, crypto, oplog, tree, blocks, bitfield, auth, !!opts.legacy, opts.onupdate || noop, opts.oncontigupdate || noop)
|
|
139
169
|
}
|
|
140
170
|
|
|
141
171
|
_shouldFlush () {
|
|
@@ -166,6 +196,17 @@ module.exports = class Core {
|
|
|
166
196
|
await this.blocks.put(index, value, byteOffset)
|
|
167
197
|
}
|
|
168
198
|
|
|
199
|
+
_updateContiguousLength (index, length = 0) {
|
|
200
|
+
if (index === this.header.contiguousLength) {
|
|
201
|
+
let i = this.header.contiguousLength + length
|
|
202
|
+
|
|
203
|
+
while (this.bitfield.get(i)) i++
|
|
204
|
+
|
|
205
|
+
this.header.contiguousLength = i
|
|
206
|
+
this.oncontigupdate()
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
169
210
|
async userData (key, value) {
|
|
170
211
|
// TODO: each oplog append can set user data, so we should have a way
|
|
171
212
|
// to just hitch a ride on one of the other ongoing appends?
|
|
@@ -176,7 +217,7 @@ module.exports = class Core {
|
|
|
176
217
|
|
|
177
218
|
for (const u of this.header.userData) {
|
|
178
219
|
if (u.key !== key) continue
|
|
179
|
-
if (value &&
|
|
220
|
+
if (value && b4a.equals(u.value, value)) return
|
|
180
221
|
empty = false
|
|
181
222
|
break
|
|
182
223
|
}
|
|
@@ -200,13 +241,13 @@ module.exports = class Core {
|
|
|
200
241
|
}
|
|
201
242
|
}
|
|
202
243
|
|
|
203
|
-
async truncate (length, fork,
|
|
244
|
+
async truncate (length, fork, auth = this.defaultAuth) {
|
|
204
245
|
this.truncating++
|
|
205
246
|
await this._mutex.lock()
|
|
206
247
|
|
|
207
248
|
try {
|
|
208
249
|
const batch = await this.tree.truncate(length, fork)
|
|
209
|
-
batch.signature = await sign(batch.signable())
|
|
250
|
+
batch.signature = await auth.sign(batch.signable())
|
|
210
251
|
await this._truncate(batch, null)
|
|
211
252
|
} finally {
|
|
212
253
|
this.truncating--
|
|
@@ -214,17 +255,19 @@ module.exports = class Core {
|
|
|
214
255
|
}
|
|
215
256
|
}
|
|
216
257
|
|
|
217
|
-
async append (values,
|
|
258
|
+
async append (values, auth = this.defaultAuth, hooks = {}) {
|
|
218
259
|
await this._mutex.lock()
|
|
219
260
|
|
|
220
261
|
try {
|
|
262
|
+
if (hooks.preappend) await hooks.preappend(values)
|
|
263
|
+
|
|
221
264
|
if (!values.length) return this.tree.length
|
|
222
265
|
|
|
223
266
|
const batch = this.tree.batch()
|
|
224
267
|
for (const val of values) batch.append(val)
|
|
225
268
|
|
|
226
269
|
const hash = batch.hash()
|
|
227
|
-
batch.signature = await sign(batch.signable(hash))
|
|
270
|
+
batch.signature = await auth.sign(this._legacy ? batch.signableLegacy(hash) : batch.signable(hash))
|
|
228
271
|
|
|
229
272
|
const entry = {
|
|
230
273
|
userData: null,
|
|
@@ -243,6 +286,8 @@ module.exports = class Core {
|
|
|
243
286
|
this.bitfield.setRange(batch.ancestors, batch.length - batch.ancestors, true)
|
|
244
287
|
batch.commit()
|
|
245
288
|
|
|
289
|
+
this.header.contiguousLength = batch.length
|
|
290
|
+
this.oncontigupdate()
|
|
246
291
|
this.header.tree.length = batch.length
|
|
247
292
|
this.header.tree.rootHash = hash
|
|
248
293
|
this.header.tree.signature = batch.signature
|
|
@@ -256,11 +301,16 @@ module.exports = class Core {
|
|
|
256
301
|
}
|
|
257
302
|
}
|
|
258
303
|
|
|
304
|
+
_signed (batch, hash, auth = this.defaultAuth) {
|
|
305
|
+
const signable = this._legacy ? batch.signableLegacy(hash) : batch.signable(hash)
|
|
306
|
+
return auth.verify(signable, batch.signature)
|
|
307
|
+
}
|
|
308
|
+
|
|
259
309
|
async _verifyExclusive ({ batch, bitfield, value, from }) {
|
|
260
310
|
// TODO: move this to tree.js
|
|
261
311
|
const hash = batch.hash()
|
|
262
|
-
if (!batch.signature || !this.
|
|
263
|
-
throw
|
|
312
|
+
if (!batch.signature || !this._signed(batch, hash)) {
|
|
313
|
+
throw INVALID_SIGNATURE('Proof contains an invalid signature')
|
|
264
314
|
}
|
|
265
315
|
|
|
266
316
|
await this._mutex.lock()
|
|
@@ -279,7 +329,11 @@ module.exports = class Core {
|
|
|
279
329
|
|
|
280
330
|
await this.oplog.append([entry], false)
|
|
281
331
|
|
|
282
|
-
if (bitfield)
|
|
332
|
+
if (bitfield) {
|
|
333
|
+
this.bitfield.set(bitfield.start, true)
|
|
334
|
+
this._updateContiguousLength(bitfield.start, bitfield.length)
|
|
335
|
+
}
|
|
336
|
+
|
|
283
337
|
batch.commit()
|
|
284
338
|
|
|
285
339
|
this.header.tree.fork = batch.fork
|
|
@@ -333,8 +387,13 @@ module.exports = class Core {
|
|
|
333
387
|
continue
|
|
334
388
|
}
|
|
335
389
|
|
|
336
|
-
if (bitfield)
|
|
390
|
+
if (bitfield) {
|
|
391
|
+
this.bitfield.set(bitfield.start, true)
|
|
392
|
+
this._updateContiguousLength(bitfield.start, bitfield.length)
|
|
393
|
+
}
|
|
394
|
+
|
|
337
395
|
batch.commit()
|
|
396
|
+
|
|
338
397
|
this.onupdate(0, bitfield, value, from)
|
|
339
398
|
}
|
|
340
399
|
|
|
@@ -415,6 +474,8 @@ module.exports = class Core {
|
|
|
415
474
|
|
|
416
475
|
const appended = batch.length > batch.ancestors
|
|
417
476
|
|
|
477
|
+
this.header.contiguousLength = Math.min(batch.ancestors, this.header.contiguousLength)
|
|
478
|
+
this.oncontigupdate()
|
|
418
479
|
this.header.tree.fork = batch.fork
|
|
419
480
|
this.header.tree.length = batch.length
|
|
420
481
|
this.header.tree.rootHash = batch.hash()
|
package/lib/errors.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module.exports = class HypercoreError extends Error {
|
|
2
|
+
constructor (msg, code, fn = HypercoreError) {
|
|
3
|
+
super(`${code}: ${msg}`)
|
|
4
|
+
this.code = code
|
|
5
|
+
|
|
6
|
+
if (Error.captureStackTrace) {
|
|
7
|
+
Error.captureStackTrace(this, fn)
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
get name () {
|
|
12
|
+
return 'HypercoreError'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
static BAD_ARGUMENT (msg) {
|
|
16
|
+
return new HypercoreError(msg, 'BAD_ARGUMENT', HypercoreError.BAD_ARGUMENT)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static STORAGE_EMPTY (msg) {
|
|
20
|
+
return new HypercoreError(msg, 'STORAGE_EMPTY', HypercoreError.STORAGE_EMPTY)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static STORAGE_CONFLICT (msg) {
|
|
24
|
+
return new HypercoreError(msg, 'STORAGE_CONFLICT', HypercoreError.STORAGE_CONFLICT)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static INVALID_SIGNATURE (msg) {
|
|
28
|
+
return new HypercoreError(msg, 'INVALID_SIGNATURE', HypercoreError.INVALID_SIGNATURE)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static INVALID_CAPABILITY (msg) {
|
|
32
|
+
return new HypercoreError(msg, 'INVALID_CAPABILITY', HypercoreError.INVALID_CAPABILITY)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static SNAPSHOT_NOT_AVAILABLE (msg = 'Snapshot is not available') {
|
|
36
|
+
return new HypercoreError(msg, 'SNAPSHOT_NOT_AVAILABLE', HypercoreError.SNAPSHOT_NOT_AVAILABLE)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static REQUEST_CANCELLED (msg = 'Request was cancelled') {
|
|
40
|
+
return new HypercoreError(msg, 'REQUEST_CANCELLED', HypercoreError.REQUEST_CANCELLED)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static SESSION_NOT_WRITABLE (msg = 'Session is not writable') {
|
|
44
|
+
return new HypercoreError(msg, 'SESSION_NOT_WRITABLE', HypercoreError.SESSION_NOT_WRITABLE)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static SESSION_CLOSED (msg = 'Session is closed') {
|
|
48
|
+
return new HypercoreError(msg, 'SESSION_CLOSED', HypercoreError.SESSION_CLOSED)
|
|
49
|
+
}
|
|
50
|
+
}
|