hypercore 10.38.2 → 11.0.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/lib/verifier.js CHANGED
@@ -1,4 +1,4 @@
1
- const defaultCrypto = require('hypercore-crypto')
1
+ const crypto = require('hypercore-crypto')
2
2
  const b4a = require('b4a')
3
3
  const c = require('compact-encoding')
4
4
  const flat = require('flat-tree')
@@ -10,11 +10,10 @@ const multisig = require('./multisig')
10
10
  const caps = require('./caps')
11
11
 
12
12
  class Signer {
13
- constructor (crypto, manifestHash, version, index, { signature = 'ed25519', publicKey, namespace = caps.DEFAULT_NAMESPACE } = {}) {
13
+ constructor (manifestHash, version, index, { signature = 'ed25519', publicKey, namespace = caps.DEFAULT_NAMESPACE } = {}) {
14
14
  if (!publicKey) throw BAD_ARGUMENT('public key is required for a signer')
15
15
  if (signature !== 'ed25519') throw BAD_ARGUMENT('Only Ed25519 signatures are supported')
16
16
 
17
- this.crypto = crypto
18
17
  this.manifestHash = manifestHash
19
18
  this.version = version
20
19
  this.signer = index
@@ -28,31 +27,31 @@ class Signer {
28
27
  }
29
28
 
30
29
  verify (batch, signature) {
31
- return this.crypto.verify(batch.signable(this._ctx()), signature, this.publicKey)
30
+ return crypto.verify(batch.signable(this._ctx()), signature, this.publicKey)
32
31
  }
33
32
 
34
33
  sign (batch, keyPair) {
35
- return this.crypto.sign(batch.signable(this._ctx()), keyPair.secretKey)
34
+ return crypto.sign(batch.signable(this._ctx()), keyPair.secretKey)
36
35
  }
37
36
  }
38
37
 
39
38
  class CompatSigner extends Signer {
40
- constructor (crypto, index, signer, legacy) {
41
- super(crypto, null, 0, index, signer)
39
+ constructor (index, signer, legacy) {
40
+ super(null, 0, index, signer)
42
41
  this.legacy = legacy
43
42
  }
44
43
 
45
44
  verify (batch, signature) {
46
- return this.crypto.verify(batch.signableCompat(this.legacy), signature, this.publicKey)
45
+ return crypto.verify(batch.signableCompat(this.legacy), signature, this.publicKey)
47
46
  }
48
47
 
49
48
  sign (batch, keyPair) {
50
- return this.crypto.sign(batch.signableCompat(this.legacy), keyPair.secretKey)
49
+ return crypto.sign(batch.signableCompat(this.legacy), keyPair.secretKey)
51
50
  }
52
51
  }
53
52
 
54
53
  module.exports = class Verifier {
55
- constructor (manifestHash, manifest, { compat = isCompat(manifestHash, manifest), crypto = defaultCrypto, legacy = false } = {}) {
54
+ constructor (manifestHash, manifest, { compat = isCompat(manifestHash, manifest), legacy = false } = {}) {
56
55
  const self = this
57
56
 
58
57
  this.manifestHash = manifestHash
@@ -67,8 +66,8 @@ module.exports = class Verifier {
67
66
 
68
67
  function createSigner (signer, index) {
69
68
  return self.compat
70
- ? new CompatSigner(crypto, index, signer, legacy)
71
- : new Signer(crypto, manifestHash, self.version, index, signer)
69
+ ? new CompatSigner(index, signer, legacy)
70
+ : new Signer(manifestHash, self.version, index, signer)
72
71
  }
73
72
  }
74
73
 
@@ -164,6 +163,14 @@ module.exports = class Verifier {
164
163
  return manifestHash(manifest)
165
164
  }
166
165
 
166
+ static encodeManifest (manifest) {
167
+ return c.encode(m.manifest, manifest)
168
+ }
169
+
170
+ static decodeManifest (manifest) {
171
+ return c.decode(m.manifest, manifest)
172
+ }
173
+
167
174
  static defaultSignerManifest (publicKey) {
168
175
  return {
169
176
  version: 1,
@@ -293,7 +300,7 @@ function manifestHash (manifest) {
293
300
  state.buffer = b4a.allocUnsafe(state.end)
294
301
  c.raw.encode(state, caps.MANIFEST)
295
302
  m.manifest.encode(state, manifest)
296
- return defaultCrypto.hash(state.buffer)
303
+ return crypto.hash(state.buffer)
297
304
  }
298
305
 
299
306
  function proofToVersion1 (proof) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore",
3
- "version": "10.38.2",
3
+ "version": "11.0.0",
4
4
  "description": "Hypercore is a secure, distributed append-only log",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -52,6 +52,7 @@
52
52
  "hypercore-crypto": "^3.2.1",
53
53
  "hypercore-errors": "^1.2.0",
54
54
  "hypercore-id-encoding": "^1.2.0",
55
+ "hypercore-storage": "^1.0.0",
55
56
  "is-options": "^1.0.1",
56
57
  "protomux": "^3.5.0",
57
58
  "quickbit-universal": "^2.2.0",
@@ -61,7 +62,6 @@
61
62
  "sodium-universal": "^4.0.0",
62
63
  "streamx": "^2.12.4",
63
64
  "unslab": "^1.3.0",
64
- "xache": "^1.1.0",
65
65
  "z32": "^1.0.0"
66
66
  },
67
67
  "devDependencies": {
package/lib/batch.js DELETED
@@ -1,431 +0,0 @@
1
- const { BLOCK_NOT_AVAILABLE, SESSION_CLOSED } = require('hypercore-errors')
2
- const EventEmitter = require('events')
3
- const c = require('compact-encoding')
4
- const b4a = require('b4a')
5
- const safetyCatch = require('safety-catch')
6
-
7
- module.exports = class HypercoreBatch extends EventEmitter {
8
- constructor (session, checkoutLength, autoClose, restore, clear) {
9
- super()
10
-
11
- this.session = session
12
- this.opened = false
13
- this.closed = false
14
- this.opening = null
15
- this.closing = null
16
- this.writable = true // always writable...
17
- this.autoClose = autoClose
18
- this.restore = restore
19
- this.fork = 0
20
-
21
- this._appends = []
22
- this._appendsActual = null
23
- this._checkoutLength = checkoutLength
24
- this._byteLength = 0
25
- this._sessionLength = 0
26
- this._sessionByteLength = 0
27
- this._sessionBatch = null
28
- this._cachedBatch = null
29
- this._flushing = null
30
- this._clear = clear
31
-
32
- this.opening = this._open()
33
- this.opening.catch(safetyCatch)
34
- }
35
-
36
- get id () {
37
- return this.session.id
38
- }
39
-
40
- get key () {
41
- return this.session.key
42
- }
43
-
44
- get discoveryKey () {
45
- return this.session.discoveryKey
46
- }
47
-
48
- get indexedLength () {
49
- return Math.min(this._sessionLength, this.session.core === null ? 0 : this.session.core.tree.length)
50
- }
51
-
52
- get flushedLength () {
53
- return this._sessionLength
54
- }
55
-
56
- get indexedByteLength () {
57
- return this._sessionByteLength
58
- }
59
-
60
- get length () {
61
- return this._sessionLength + this._appends.length
62
- }
63
-
64
- get byteLength () {
65
- return this._sessionByteLength + this._byteLength
66
- }
67
-
68
- get core () {
69
- return this.session.core
70
- }
71
-
72
- get manifest () {
73
- return this.session.manifest
74
- }
75
-
76
- ready () {
77
- return this.opening
78
- }
79
-
80
- async _open () {
81
- await this.session.ready()
82
-
83
- if (this._clear) this._checkoutLength = this.core.tree.length
84
-
85
- if (this._checkoutLength !== -1) {
86
- const batch = await this.session.core.tree.restoreBatch(this._checkoutLength)
87
- batch.treeLength = this._checkoutLength
88
- this._sessionLength = batch.length
89
- this._sessionByteLength = batch.byteLength
90
- this._sessionBatch = batch
91
- if (this._clear) await this.core.clearBatch()
92
- } else {
93
- const last = this.restore ? this.session.core.bitfield.findFirst(false, this.session.length) : 0
94
-
95
- if (last > this.session.length) {
96
- const batch = await this.session.core.tree.restoreBatch(last)
97
- this._sessionLength = batch.length
98
- this._sessionByteLength = batch.byteLength - this.session.padding * batch.length
99
- this._sessionBatch = batch
100
- } else {
101
- this._sessionLength = this.session.length
102
- this._sessionByteLength = this.session.byteLength
103
- this._sessionBatch = this.session.createTreeBatch()
104
- }
105
- }
106
-
107
- this._appendsActual = this.session.encryption ? [] : this._appends
108
- this.fork = this.session.fork
109
- this.opened = true
110
- this.emit('ready')
111
- }
112
-
113
- async has (index) {
114
- if (this.opened === false) await this.ready()
115
- if (index >= this._sessionLength) return index < this.length
116
- return this.session.has(index)
117
- }
118
-
119
- async update (opts) {
120
- if (this.opened === false) await this.ready()
121
- await this.session.update(opts)
122
- }
123
-
124
- treeHash () {
125
- return this._sessionBatch.hash()
126
- }
127
-
128
- setUserData (key, value, opts) {
129
- return this.session.setUserData(key, value, opts)
130
- }
131
-
132
- getUserData (key, opts) {
133
- return this.session.getUserData(key, opts)
134
- }
135
-
136
- async info (opts) {
137
- const session = this.session
138
- const info = await session.info(opts)
139
-
140
- info.length = this._sessionLength
141
-
142
- if (info.contiguousLength >= info.length) {
143
- info.contiguousLength = info.length += this._appends.length
144
- } else {
145
- info.length += this._appends.length
146
- }
147
-
148
- info.byteLength = this._sessionByteLength + this._byteLength
149
-
150
- return info
151
- }
152
-
153
- async seek (bytes, opts = {}) {
154
- if (this.opened === false) await this.opening
155
- if (this.closing) throw SESSION_CLOSED()
156
-
157
- if (bytes < this._sessionByteLength) return await this.session.seek(bytes, { ...opts, tree: this._sessionBatch })
158
-
159
- bytes -= this._sessionByteLength
160
-
161
- let i = 0
162
-
163
- for (const blk of this._appends) {
164
- if (bytes < blk.byteLength) return [this._sessionLength + i, bytes]
165
- i++
166
- bytes -= blk.byteLength
167
- }
168
-
169
- if (bytes === 0) return [this._sessionLength + i, 0]
170
-
171
- throw BLOCK_NOT_AVAILABLE()
172
- }
173
-
174
- async get (index, opts = {}) {
175
- if (this.opened === false) await this.opening
176
- if (this.closing) throw SESSION_CLOSED()
177
-
178
- const length = this._sessionLength
179
-
180
- if (index < length) {
181
- return this.session.get(index, { ...opts, tree: this._sessionBatch })
182
- }
183
-
184
- if (opts && opts.raw) {
185
- return this._appendsActual[index - length] || null
186
- }
187
-
188
- const buffer = this._appends[index - length] || null
189
- if (!buffer) throw BLOCK_NOT_AVAILABLE()
190
-
191
- const encoding = (opts && opts.valueEncoding && c.from(opts.valueEncoding)) || this.session.valueEncoding
192
- if (!encoding) return buffer
193
-
194
- return c.decode(encoding, buffer)
195
- }
196
-
197
- async _waitForFlush () {
198
- // wait for any pending flush...
199
- while (this._flushing) {
200
- await this._flushing
201
- await Promise.resolve() // yield in case a new flush is queued
202
- }
203
- }
204
-
205
- async restoreBatch (length, blocks) {
206
- if (this.opened === false) await this.opening
207
- if (length >= this._sessionLength) return this.createTreeBatch(length, blocks)
208
- return this.session.core.tree.restoreBatch(length)
209
- }
210
-
211
- _catchupBatch (clone) {
212
- if (this._cachedBatch === null) this._cachedBatch = this._sessionBatch.clone()
213
-
214
- if (this.length > this._cachedBatch.length) {
215
- const offset = this._cachedBatch.length - this._sessionBatch.length
216
-
217
- for (let i = offset; i < this._appendsActual.length; i++) {
218
- this._cachedBatch.append(this._appendsActual[i])
219
- }
220
- }
221
-
222
- return clone ? this._cachedBatch.clone() : this._cachedBatch
223
- }
224
-
225
- createTreeBatch (length, opts = {}) {
226
- if (Array.isArray(opts)) opts = { blocks: opts }
227
-
228
- const { blocks = [], clone = true } = opts
229
- if (!length && length !== 0) length = this.length + blocks.length
230
-
231
- const maxLength = this.length + blocks.length
232
- const b = this._catchupBatch(clone || (blocks.length > 0 || length !== this.length))
233
- const len = Math.min(length, this.length)
234
-
235
- if (len < this._sessionLength || length > maxLength) return null
236
- if (len < b.length) b.checkout(len, this._sessionBatch.roots)
237
-
238
- for (let i = 0; i < length - len; i++) {
239
- b.append(this._appendsActual === this._appends ? blocks[i] : this._encrypt(b.length, blocks[i]))
240
- }
241
-
242
- return b
243
- }
244
-
245
- async truncate (newLength = 0, opts = {}) {
246
- if (this.opened === false) await this.opening
247
- if (this.closing) throw SESSION_CLOSED()
248
-
249
- // wait for any pending flush... (prop needs a lock)
250
- await this._waitForFlush()
251
-
252
- if (typeof opts === 'number') opts = { fork: opts }
253
- const { fork = this.fork + 1, force = false } = opts
254
-
255
- this._cachedBatch = null
256
-
257
- const length = this._sessionLength
258
- if (newLength < length) {
259
- if (!force) throw new Error('Cannot truncate committed blocks')
260
- this._appends.length = 0
261
- this._byteLength = 0
262
- await this.session.truncate(newLength, { fork, force: true, ...opts })
263
- this._sessionLength = this.session.length
264
- this._sessionByteLength = this.session.byteLength
265
- this._sessionBatch = this.session.createTreeBatch()
266
- } else {
267
- for (let i = newLength - length; i < this._appends.length; i++) this._byteLength -= this._appends[i].byteLength
268
- this._appends.length = newLength - length
269
- }
270
-
271
- this.fork = fork
272
-
273
- this.emit('truncate', newLength, this.fork)
274
- }
275
-
276
- async append (blocks) {
277
- const session = this.session
278
-
279
- if (this.opened === false) await this.opening
280
- if (this.closing) throw SESSION_CLOSED()
281
-
282
- // wait for any pending flush... (prop needs a lock)
283
- await this._waitForFlush()
284
-
285
- blocks = Array.isArray(blocks) ? blocks : [blocks]
286
-
287
- const buffers = session.encodeBatch !== null
288
- ? session.encodeBatch(blocks)
289
- : new Array(blocks.length)
290
-
291
- if (session.encodeBatch === null) {
292
- for (let i = 0; i < blocks.length; i++) {
293
- const buffer = this._encode(session.valueEncoding, blocks[i])
294
- buffers[i] = buffer
295
- this._byteLength += buffer.byteLength
296
- }
297
- }
298
- if (this._appends !== this._appendsActual) {
299
- for (let i = 0; i < buffers.length; i++) {
300
- this._appendsActual.push(this._encrypt(this._sessionLength + this._appendsActual.length, buffers[i]))
301
- }
302
- }
303
-
304
- for (const b of buffers) this._appends.push(b)
305
-
306
- const info = { length: this.length, byteLength: this.byteLength }
307
- this.emit('append')
308
-
309
- return info
310
- }
311
-
312
- _encode (enc, val) {
313
- const state = { start: 0, end: 0, buffer: null }
314
-
315
- if (b4a.isBuffer(val)) {
316
- if (state.start === 0) return val
317
- state.end += val.byteLength
318
- } else if (enc) {
319
- enc.preencode(state, val)
320
- } else {
321
- val = b4a.from(val)
322
- if (state.start === 0) return val
323
- state.end += val.byteLength
324
- }
325
-
326
- state.buffer = b4a.allocUnsafe(state.end)
327
-
328
- if (enc) enc.encode(state, val)
329
- else state.buffer.set(val, state.start)
330
-
331
- return state.buffer
332
- }
333
-
334
- _encrypt (index, buffer) {
335
- const block = b4a.allocUnsafe(buffer.byteLength + 8)
336
- block.set(buffer, 8)
337
- this.session.encryption.encrypt(index, block, this.fork)
338
- return block
339
- }
340
-
341
- async flush (opts = {}) {
342
- if (this.opened === false) await this.opening
343
- if (this.closing) throw SESSION_CLOSED()
344
-
345
- const { length = this.length, keyPair = this.session.keyPair, signature = null, pending = !signature && !keyPair } = opts
346
-
347
- while (this._flushing) await this._flushing
348
- this._flushing = this._flush(length, keyPair, signature, pending)
349
-
350
- let flushed = false
351
-
352
- try {
353
- flushed = await this._flushing
354
- } finally {
355
- this._flushing = null
356
- }
357
-
358
- if (this.autoClose) await this.close()
359
-
360
- return flushed
361
- }
362
-
363
- async _flush (length, keyPair, signature, pending) { // TODO: make this safe to interact with a parallel truncate...
364
- if (this._sessionBatch.fork !== this.session.fork) return false // no truncs supported atm
365
-
366
- if (this.session.replicator._upgrade) {
367
- for (const req of this.session.replicator._upgrade.inflight) {
368
- // yield to the remote inflight upgrade, TODO: if the remote upgrade fails, retry flushing...
369
- if (req.upgrade && (req.upgrade.start + req.upgrade.length) > length) {
370
- return false
371
- }
372
- }
373
- }
374
-
375
- const flushingLength = Math.min(length - this._sessionLength, this._appends.length)
376
- if (flushingLength <= 0) {
377
- if (this._sessionLength > this.core.tree.length && length > this.core.tree.length && !pending) {
378
- const batch = await this.restoreBatch(length)
379
- const info = await this.core.insertBatch(batch, [], { keyPair, signature, pending, treeLength: length })
380
- return info !== null
381
- }
382
- return true
383
- }
384
-
385
- const batch = this.createTreeBatch(this._sessionLength + flushingLength)
386
- if (batch === null) return false
387
-
388
- const info = await this.core.insertBatch(batch, this._appendsActual, { keyPair, signature, pending, treeLength: this._sessionLength })
389
- if (info === null) return false
390
-
391
- const delta = info.byteLength - this._sessionByteLength
392
- const newBatch = info.length !== this.session.length ? await this.session.core.tree.restoreBatch(info.length) : this.session.createTreeBatch()
393
-
394
- this._sessionLength = info.length
395
- this._sessionByteLength = info.byteLength
396
- this._sessionBatch = newBatch
397
-
398
- if (this._cachedBatch !== null) this._cachedBatch.prune(info.length)
399
-
400
- const same = this._appends === this._appendsActual
401
-
402
- this._appends = this._appends.slice(flushingLength)
403
- this._appendsActual = same ? this._appends : this._appendsActual.slice(flushingLength)
404
- this._byteLength -= delta
405
-
406
- this.emit('flush')
407
-
408
- return true
409
- }
410
-
411
- close () {
412
- if (!this.closing) this.closing = this._close()
413
- return this.closing
414
- }
415
-
416
- async _close () {
417
- this._clearAppends()
418
-
419
- await this.session.close()
420
-
421
- this.closed = true
422
- this.emit('close')
423
- }
424
-
425
- _clearAppends () {
426
- this._appends = []
427
- this._appendsActual = []
428
- this._byteLength = 0
429
- this.fork = 0
430
- }
431
- }
package/lib/big-header.js DELETED
@@ -1,55 +0,0 @@
1
- const c = require('compact-encoding')
2
- const { oplog } = require('./messages')
3
-
4
- module.exports = class BigHeader {
5
- constructor (storage) {
6
- this.storage = storage
7
- }
8
-
9
- async load (external) {
10
- const buf = await new Promise((resolve, reject) => {
11
- this.storage.read(external.start, external.length, (err, buf) => {
12
- if (err) return reject(err)
13
- resolve(buf)
14
- })
15
- })
16
-
17
- const header = c.decode(oplog.header, buf)
18
- header.external = external
19
- return header
20
- }
21
-
22
- async flush (header) {
23
- const external = header.external || { start: 0, length: 0 }
24
- header.external = null
25
-
26
- const buf = c.encode(oplog.header, header)
27
-
28
- let start = 0
29
- if (buf.byteLength > external.start) {
30
- start = external.start + external.length
31
- const rem = start & 4095
32
- if (rem > 0) start += (4096 - rem)
33
- }
34
-
35
- header.external = { start, length: buf.byteLength }
36
-
37
- await new Promise((resolve, reject) => {
38
- this.storage.write(start, buf, (err) => {
39
- if (err) return reject(err)
40
- resolve()
41
- })
42
- })
43
-
44
- return header
45
- }
46
-
47
- close () {
48
- return new Promise((resolve, reject) => {
49
- this.storage.close((err) => {
50
- if (err) return reject(err)
51
- resolve()
52
- })
53
- })
54
- }
55
- }