hypercore 11.0.20 → 11.0.22

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
@@ -247,19 +247,6 @@ class Hypercore extends EventEmitter {
247
247
  this.core.replicator.updateActivity(this._active ? 1 : -1)
248
248
  }
249
249
 
250
- _setupSession (parent) {
251
- if (!this.keyPair) this.keyPair = parent.keyPair
252
-
253
- const s = parent.state
254
-
255
- if (s) {
256
- const shouldSnapshot = this.snapshotted && !s.isSnapshot()
257
- this.state = shouldSnapshot ? s.snapshot() : s.ref()
258
- }
259
-
260
- if (this.snapshotted && this.core && !this._snapshot) this._updateSnapshot()
261
- }
262
-
263
250
  async _open (storage, key, opts) {
264
251
  const preload = opts.preload || (opts.parent && opts.parent.preload)
265
252
 
@@ -339,7 +326,18 @@ class Hypercore extends EventEmitter {
339
326
 
340
327
  if (parent) {
341
328
  if (parent._stateIndex === -1) await parent.ready()
342
- this._setupSession(parent)
329
+ if (!this.keyPair) this.keyPair = parent.keyPair
330
+
331
+ const ps = parent.state
332
+
333
+ if (ps) {
334
+ const shouldSnapshot = this.snapshotted && !ps.isSnapshot()
335
+ this.state = shouldSnapshot ? await ps.snapshot() : ps.ref()
336
+ }
337
+
338
+ if (this.snapshotted && this.core && !this._snapshot) {
339
+ this._updateSnapshot()
340
+ }
343
341
  }
344
342
 
345
343
  if (opts.exclusive && opts.writable !== false) {
@@ -24,6 +24,7 @@ module.exports = class SessionState {
24
24
  this.lingers = null
25
25
 
26
26
  this.parent = parent
27
+ this.atomized = null
27
28
  this.mutex = new Mutex()
28
29
 
29
30
  this.blocks = blocks
@@ -122,6 +123,33 @@ module.exports = class SessionState {
122
123
  return MerkleTree.size(this.roots)
123
124
  }
124
125
 
126
+ async getFlushedTreeInfo (storage) {
127
+ if (!this.atomized || !this.atomized.flushing) return this.treeInfo()
128
+ await this.atomized.flushed()
129
+
130
+ let rx = storage.read()
131
+ const headPromise = rx.getHead()
132
+ const authPromise = rx.getAuth()
133
+
134
+ rx.tryFlush()
135
+ const [head, auth] = await Promise.all([headPromise, authPromise])
136
+
137
+ rx = storage.read()
138
+ const rootPromises = []
139
+ for (const r of flat.fullRoots(head.length * 2)) {
140
+ rootPromises.push(rx.getTreeNode(r))
141
+ }
142
+
143
+ rx.tryFlush()
144
+ return {
145
+ fork: head.fork,
146
+ roots: await Promise.all(rootPromises),
147
+ length: head.length,
148
+ prologue: auth.manifest && auth.manifest.prologue,
149
+ signature: head.signature
150
+ }
151
+ }
152
+
125
153
  treeInfo () {
126
154
  return {
127
155
  fork: this.fork,
@@ -137,6 +165,7 @@ module.exports = class SessionState {
137
165
 
138
166
  this.active = 0
139
167
  this.mutex.destroy(new Error('Closed')).catch(noop)
168
+ if (this.parent && this.parent.atomized) this.parent.atomized = null
140
169
 
141
170
  const closing = this.storage.close()
142
171
 
@@ -153,14 +182,16 @@ module.exports = class SessionState {
153
182
  return closing
154
183
  }
155
184
 
156
- snapshot () {
185
+ async snapshot () {
186
+ const storage = this.storage.snapshot()
187
+
157
188
  const s = new SessionState(
158
189
  this.core,
159
190
  null,
160
- this.storage.snapshot(),
191
+ storage,
161
192
  this.blocks,
162
- this.tree.clone(),
163
- this.treeInfo(),
193
+ this.tree.clone(storage),
194
+ await this.getFlushedTreeInfo(storage),
164
195
  this.name
165
196
  )
166
197
 
@@ -214,46 +245,62 @@ module.exports = class SessionState {
214
245
  }
215
246
  }
216
247
 
217
- _commit () {
218
- const bitfield = this._pendingBitfield
219
- this._pendingBitfield = null
248
+ _precommit () {
249
+ this.commiting = true
250
+ }
251
+
252
+ async _commit () {
253
+ await this.mutex.lock()
220
254
 
221
- return this.parent._oncommit(this, bitfield)
255
+ try {
256
+ const bitfield = this._pendingBitfield
257
+ this._pendingBitfield = null
258
+ await this.parent._oncommit(this, bitfield)
259
+ } finally {
260
+ this.commiting = false
261
+ this.mutex.unlock()
262
+ }
222
263
  }
223
264
 
224
265
  async _oncommit (src, bitfield) {
225
- const currLength = this.length
266
+ await this.mutex.lock()
226
267
 
227
- this.fork = src.fork
228
- this.length = src.length
229
- this.roots = src.roots.slice()
230
- this.signature = src.signature
268
+ try {
269
+ const currLength = this.length
231
270
 
232
- const tree = {
233
- fork: this.fork,
234
- length: this.length,
235
- rootHash: this.hash(),
236
- signature: this.signature
237
- }
271
+ this.fork = src.fork
272
+ this.length = src.length
273
+ this.roots = src.roots.slice()
274
+ this.signature = src.signature
238
275
 
239
- const rx = src.storage.read()
240
- const dependencyPromise = rx.getDependency()
276
+ const tree = {
277
+ fork: this.fork,
278
+ length: this.length,
279
+ rootHash: this.hash(),
280
+ signature: this.signature
281
+ }
241
282
 
242
- rx.tryFlush()
283
+ const rx = src.storage.read()
284
+ const dependencyPromise = rx.getDependency()
243
285
 
244
- const dependency = await dependencyPromise
245
- if (dependency && dependency.length > this.flushedLength()) {
246
- this.storage.updateDependencyLength(dependency.length, false, true)
247
- }
286
+ rx.tryFlush()
248
287
 
249
- const truncated = bitfield ? bitfield.truncated : -1
288
+ const dependency = await dependencyPromise
289
+ if (dependency && dependency.length > this.flushedLength()) {
290
+ this.storage.updateDependencyLength(dependency.length, false, true)
291
+ }
250
292
 
251
- if (truncated !== -1 && truncated < currLength) {
252
- this.ontruncate(tree, truncated, currLength, true)
253
- if (!bitfield || bitfield.length === 0) return
254
- }
293
+ const truncated = bitfield ? bitfield.truncated : -1
294
+
295
+ if (truncated !== -1 && truncated < currLength) {
296
+ this.ontruncate(tree, truncated, currLength, true)
297
+ if (!bitfield || bitfield.length === 0) return
298
+ }
255
299
 
256
- this.onappend(tree, bitfield, true)
300
+ this.onappend(tree, bitfield, true)
301
+ } finally {
302
+ this.mutex.unlock()
303
+ }
257
304
  }
258
305
 
259
306
  flushed () {
@@ -587,7 +634,6 @@ module.exports = class SessionState {
587
634
 
588
635
  try {
589
636
  if (length < this.length) throw INVALID_OPERATION('Can not catchup back in time')
590
- if (length === this.length) return
591
637
 
592
638
  const origLength = this.length
593
639
 
@@ -641,14 +687,12 @@ module.exports = class SessionState {
641
687
  this.storage.updateDependencyLength(sharedLength, true)
642
688
  this.storage.updateDependencyLength(length, false)
643
689
 
644
- const bitfield = { start: sharedLength, length: tree.length - sharedLength, drop: false }
645
-
646
690
  this.fork = tree.fork
647
691
  this.roots = roots
648
692
  this.length = tree.length
649
693
 
650
694
  if (truncating) this.ontruncate(tree, sharedLength, origLength, flushed)
651
- if (sharedLength < length) this.onappend(tree, bitfield, flushed)
695
+ if (sharedLength < length) this.onappend(tree, null, flushed)
652
696
  } finally {
653
697
  this.mutex.unlock()
654
698
  }
@@ -803,6 +847,7 @@ module.exports = class SessionState {
803
847
  srcLocked = true
804
848
 
805
849
  if (!(await this.core._validateCommit(state, treeLength))) return null
850
+ if (this.length > length) return null
806
851
 
807
852
  if (this.length < length && !signature) {
808
853
  if (!keyPair) keyPair = this.core.header.keyPair
@@ -968,6 +1013,10 @@ module.exports = class SessionState {
968
1013
  }
969
1014
  }
970
1015
 
1016
+ if (this.atomized && atom) {
1017
+ throw new Error('Session already atomized')
1018
+ }
1019
+
971
1020
  const tree = new MerkleTree(storage)
972
1021
 
973
1022
  const head = {
@@ -988,7 +1037,10 @@ module.exports = class SessionState {
988
1037
  atom ? this.name : name
989
1038
  )
990
1039
 
991
- if (atom) atom.onflush(state._commit.bind(state))
1040
+ if (atom) {
1041
+ this.atomized = atom
1042
+ atom.onflush(state._commit.bind(state))
1043
+ }
992
1044
 
993
1045
  return state
994
1046
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore",
3
- "version": "11.0.20",
3
+ "version": "11.0.22",
4
4
  "description": "Hypercore is a secure, distributed append-only log",
5
5
  "main": "index.js",
6
6
  "scripts": {