hypercore 11.0.1 → 11.0.3

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 CHANGED
@@ -207,7 +207,7 @@ class Hypercore extends EventEmitter {
207
207
  }
208
208
 
209
209
  const wait = opts.wait === false ? false : this.wait
210
- const writable = opts.writable === false ? false : !this._readonly
210
+ const writable = opts.writable === undefined ? !this._readonly : opts.writable === true
211
211
  const onwait = opts.onwait === undefined ? this.onwait : opts.onwait
212
212
  const timeout = opts.timeout === undefined ? this.timeout : opts.timeout
213
213
  const weak = opts.weak === undefined ? this.weak : opts.weak
@@ -245,7 +245,6 @@ class Hypercore extends EventEmitter {
245
245
 
246
246
  _setupSession (parent) {
247
247
  if (!this.keyPair) this.keyPair = parent.keyPair
248
- this.writable = this._isWritable()
249
248
 
250
249
  const s = parent.state
251
250
 
@@ -341,13 +340,13 @@ class Hypercore extends EventEmitter {
341
340
  }
342
341
 
343
342
  const parent = opts.parent || this.core
343
+ const checkout = opts.checkout === undefined ? -1 : opts.checkout
344
344
 
345
345
  if (opts.atom) {
346
- this.state = await parent.state.createSession(null, -1, false, opts.atom)
346
+ this.state = await parent.state.createSession(null, checkout, false, opts.atom)
347
347
  } else if (opts.name) {
348
348
  // todo: need to make named sessions safe before ready
349
349
  // atm we always copy the state in passCapabilities
350
- const checkout = opts.checkout === undefined ? -1 : opts.checkout
351
350
  const state = this.state
352
351
 
353
352
  this.state = await parent.state.createSession(opts.name, checkout, !!opts.overwrite, null)
@@ -360,6 +359,8 @@ class Hypercore extends EventEmitter {
360
359
  this.state = this.core.state.ref()
361
360
  }
362
361
 
362
+ this.writable = this._isWritable()
363
+
363
364
  if (this.snapshotted && this.core) this._updateSnapshot()
364
365
 
365
366
  this.state.addSession(this)
@@ -404,8 +405,9 @@ class Hypercore extends EventEmitter {
404
405
  }
405
406
 
406
407
  _isWritable () {
407
- if (this.draft) return true
408
- return !this._readonly && !!(this.keyPair && this.keyPair.secretKey)
408
+ if (this._readonly) return false
409
+ if (this.state && !this.state.isDefault()) return true
410
+ return !!(this.keyPair && this.keyPair.secretKey)
409
411
  }
410
412
 
411
413
  close ({ error } = {}) {
@@ -126,7 +126,7 @@ async function flushBatch (prologue, src, dst, batch) {
126
126
  }
127
127
 
128
128
  for (const { key, value } of userData) {
129
- tx.setUserData(key, value)
129
+ tx.putUserData(key, value)
130
130
  }
131
131
 
132
132
  let upgraded = batch.first && !head
package/lib/core.js CHANGED
@@ -8,7 +8,7 @@ const BlockStore = require('./block-store')
8
8
  const BitInterlude = require('./bit-interlude')
9
9
  const Bitfield = require('./bitfield')
10
10
  const RemoteBitfield = require('./remote-bitfield')
11
- const { BAD_ARGUMENT, STORAGE_EMPTY, STORAGE_CONFLICT, INVALID_OPERATION, INVALID_SIGNATURE, INVALID_CHECKSUM } = require('hypercore-errors')
11
+ const { BAD_ARGUMENT, STORAGE_EMPTY, STORAGE_CONFLICT, INVALID_SIGNATURE, INVALID_CHECKSUM } = require('hypercore-errors')
12
12
  const Verifier = require('./verifier')
13
13
  const audit = require('./audit')
14
14
  const copyPrologue = require('./copy-prologue')
@@ -374,21 +374,23 @@ module.exports = class Core {
374
374
 
375
375
  async _validateCommit (state, treeLength) {
376
376
  if (this.state.length > state.length) {
377
- throw new Error('Invalid commit: partial commit') // TODO: partial commit in the future if possible
377
+ return false // TODO: partial commit in the future if possible
378
378
  }
379
379
 
380
380
  if (this.state.length > treeLength) {
381
381
  for (const root of this.state.roots) {
382
382
  const batchRoot = await state.tree.get(root.index)
383
383
  if (batchRoot.size !== root.size || !b4a.equals(batchRoot.hash, root.hash)) {
384
- throw new Error('Invalid commit: tree conflict')
384
+ return false
385
385
  }
386
386
  }
387
387
  }
388
388
 
389
389
  if (this.verifier === null) {
390
- throw INVALID_OPERATION('Cannot commit without manifest') // easier to assert than upsert
390
+ return false // easier to assert than upsert
391
391
  }
392
+
393
+ return true
392
394
  }
393
395
 
394
396
  _verifyBatchUpgrade (batch, manifest) {
package/lib/multisig.js CHANGED
@@ -21,7 +21,7 @@ function inflate (data) {
21
21
  }
22
22
 
23
23
  async function partialSignature (core, signer, from, to = core.state.length, signature = core.state.signature) {
24
- if (from > core.tree.length) return null
24
+ if (from > core.state.length) return null
25
25
  const nodes = to <= from ? null : await upgradeNodes(core, from, to)
26
26
 
27
27
  if (signature.byteLength !== 64) signature = c.decode(multiSignature, signature).proofs[0].signature
@@ -35,10 +35,10 @@ async function partialSignature (core, signer, from, to = core.state.length, sig
35
35
  }
36
36
 
37
37
  async function upgradeNodes (core, from, to) {
38
- const batch = core.storage.read()
38
+ const rx = core.state.storage.read()
39
39
  const treeBatch = core.state.createTreeBatch()
40
- const p = await core.tree.proof(batch, treeBatch, { upgrade: { start: from, length: to - from } })
41
- batch.tryFlush()
40
+ const p = await core.state.tree.proof(rx, treeBatch, { upgrade: { start: from, length: to - from } })
41
+ rx.tryFlush()
42
42
  return (await p.settle()).upgrade.nodes
43
43
  }
44
44
 
@@ -35,6 +35,7 @@ module.exports = class SessionState {
35
35
  const deps = this.storage.dependencies
36
36
  this.dependencyLength = deps.length ? deps[deps.length - 1].length : Infinity
37
37
 
38
+ if (treeInfo.length < this.dependencyLength) this.dependencyLength = treeInfo.length
38
39
  if (treeInfo.roots.length) this.setRoots(treeInfo.roots)
39
40
 
40
41
  this.snapshotCompatLength = this.isSnapshot() ? this.length : -1
@@ -109,7 +110,8 @@ module.exports = class SessionState {
109
110
  fork: this.fork,
110
111
  roots: this.roots.slice(),
111
112
  length: this.length,
112
- prologue: this.prologue
113
+ prologue: this.prologue,
114
+ signature: this.signature
113
115
  }
114
116
  }
115
117
 
@@ -144,11 +146,11 @@ module.exports = class SessionState {
144
146
  return s
145
147
  }
146
148
 
147
- updateDependency (storage, length) {
149
+ updateDependency (tx, length) {
148
150
  const dependency = updateDependency(this, length)
149
151
  if (dependency) {
150
152
  this.dependencyLength = dependency.length
151
- storage.setDependency(dependency)
153
+ tx.setDependency(dependency)
152
154
  }
153
155
 
154
156
  return dependency
@@ -202,6 +204,8 @@ module.exports = class SessionState {
202
204
  }
203
205
 
204
206
  async _oncommit (src, bitfield) {
207
+ const currLength = this.length
208
+
205
209
  this.fork = src.fork
206
210
  this.length = src.length
207
211
  this.roots = src.roots.slice()
@@ -214,6 +218,10 @@ module.exports = class SessionState {
214
218
  signature: this.signature
215
219
  }
216
220
 
221
+ if (src.dependencyLength > this.dependencyLength) {
222
+ this.storage.updateDependencyLength(src.dependencyLength)
223
+ }
224
+
217
225
  // handle migration
218
226
  if (src.core !== this.core) {
219
227
  this.prologue = src.prologue
@@ -229,11 +237,16 @@ module.exports = class SessionState {
229
237
  this._moveToCore(src.core)
230
238
  }
231
239
 
232
- if (!bitfield || !bitfield.drop) {
233
- this.onappend(tree, bitfield, true)
234
- } else {
235
- this.ontruncate(tree, bitfield.start, bitfield.start + bitfield.length, true)
240
+ const truncated = (bitfield && bitfield.truncated !== -1)
241
+ ? bitfield.truncated
242
+ : src.dependencyLength
243
+
244
+ if (truncated < currLength) {
245
+ this.ontruncate(tree, truncated, currLength, true)
246
+ if (!bitfield || bitfield.length === 0) return
236
247
  }
248
+
249
+ this.onappend(tree, bitfield, true)
237
250
  }
238
251
 
239
252
  flushed () {
@@ -511,22 +524,40 @@ module.exports = class SessionState {
511
524
  }
512
525
 
513
526
  _updateBitfield (bitfield, flushed) {
527
+ if (!bitfield) return
528
+
514
529
  const p = this._pendingBitfield
530
+ const b = bitfield
515
531
 
516
- if (p === null) {
517
- if (bitfield) this._pendingBitfield = bitfield
532
+ if (b.drop) {
533
+ if (p === null) {
534
+ this._pendingBitfield = { truncated: b.start, start: b.start, length: 0, drop: false }
535
+ return
536
+ }
537
+
538
+ if (p.drop) {
539
+ if (p.truncated !== b.start + b.length) throw INVALID_OPERATION('Atomic truncations must be contiguous')
540
+ p.truncated = b.start
541
+ return
542
+ }
543
+
544
+ if (b.start < p.start) throw INVALID_OPERATION('Atomic truncations must be contiguous')
545
+ p.length = b.start - p.start
546
+
547
+ if (p.length === 0) this._pendingBitfield = null
518
548
  return
519
549
  }
520
550
 
521
- if (p.drop) {
522
- const from = bitfield.start + bitfield.length
523
- if (!bitfield.drop || p.start !== from) throw INVALID_OPERATION('Atomic truncations must be contiguous')
551
+ if (p === null) {
552
+ this._pendingBitfield = { truncated: -1, start: b.start, length: b.length, drop: false }
553
+ return
554
+ }
524
555
 
525
- p.length += bitfield.length
526
- p.start = bitfield.start
527
- } else {
528
- p.length = bitfield.start + bitfield.length - p.start
556
+ if (b.start !== p.start + p.length) {
557
+ throw INVALID_OPERATION('Atomic operations must be contiguous')
529
558
  }
559
+
560
+ p.length += b.length
530
561
  }
531
562
 
532
563
  async _overwrite (source, fork, length, treeLength, signature, isDependent, shallow) {
@@ -670,7 +701,7 @@ module.exports = class SessionState {
670
701
  await state.mutex.lock()
671
702
  srcLocked = true
672
703
 
673
- await this.core._validateCommit(state, treeLength)
704
+ if (!(await this.core._validateCommit(state, treeLength))) return null
674
705
 
675
706
  if (this.length < length && !signature) {
676
707
  if (!keyPair) keyPair = this.core.header.keyPair
@@ -729,6 +760,8 @@ module.exports = class SessionState {
729
760
  head.fork = this.fork
730
761
  head.rootHash = rootHash
731
762
 
763
+ if (length === this.length) head.signature = this.signature
764
+
732
765
  return head
733
766
  }
734
767
 
@@ -739,6 +772,10 @@ module.exports = class SessionState {
739
772
  this.core = core
740
773
  this.index = this.core.sessionStates.push(this) - 1
741
774
 
775
+ // storage was updated
776
+ const deps = this.storage.dependencies
777
+ this.dependencyLength = deps[deps.length - 1].length
778
+
742
779
  for (let i = this.sessions.length - 1; i >= 0; i--) this.sessions[i].transferSession(this.core)
743
780
  }
744
781
 
@@ -831,7 +868,8 @@ module.exports = class SessionState {
831
868
  fork: this.fork,
832
869
  roots: length === this.length ? this.roots.slice() : await tree.getRoots(length),
833
870
  length,
834
- prologue: this.prologue
871
+ prologue: this.prologue,
872
+ signature: length === this.length ? this.signature : null
835
873
  }
836
874
 
837
875
  const state = new SessionState(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore",
3
- "version": "11.0.1",
3
+ "version": "11.0.3",
4
4
  "description": "Hypercore is a secure, distributed append-only log",
5
5
  "main": "index.js",
6
6
  "scripts": {