hypercore 11.16.1 → 11.17.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/README.md +31 -29
- package/index.js +212 -127
- package/lib/audit.js +18 -7
- package/lib/bit-interlude.js +17 -7
- package/lib/bitfield.js +73 -53
- package/lib/caps.js +5 -1
- package/lib/copy-prologue.js +14 -10
- package/lib/core.js +113 -59
- package/lib/default-encryption.js +14 -28
- package/lib/download.js +10 -10
- package/lib/fully-remote-proof.js +3 -3
- package/lib/hotswap-queue.js +5 -5
- package/lib/info.js +4 -4
- package/lib/merkle-tree.js +143 -104
- package/lib/messages.js +163 -143
- package/lib/multisig.js +19 -12
- package/lib/mutex.js +9 -7
- package/lib/receiver-queue.js +6 -6
- package/lib/remote-bitfield.js +30 -32
- package/lib/replicator.js +383 -265
- package/lib/session-state.js +112 -75
- package/lib/streams.js +16 -16
- package/lib/verifier.js +69 -43
- package/package.json +5 -3
package/lib/session-state.js
CHANGED
|
@@ -11,7 +11,7 @@ const Bitfield = require('./bitfield')
|
|
|
11
11
|
const { MerkleTree, MerkleTreeBatch } = require('./merkle-tree')
|
|
12
12
|
|
|
13
13
|
module.exports = class SessionState {
|
|
14
|
-
constructor
|
|
14
|
+
constructor(core, parent, storage, treeInfo, name) {
|
|
15
15
|
this.core = core
|
|
16
16
|
this.index = this.core.sessionStates.push(this) - 1
|
|
17
17
|
|
|
@@ -35,7 +35,9 @@ module.exports = class SessionState {
|
|
|
35
35
|
this.prologue = treeInfo.prologue || null
|
|
36
36
|
this.signature = treeInfo.signature || null
|
|
37
37
|
|
|
38
|
-
this.snapshotCompatLength = this.isSnapshot()
|
|
38
|
+
this.snapshotCompatLength = this.isSnapshot()
|
|
39
|
+
? Math.min(this.length, this.core.state.length)
|
|
40
|
+
: -1
|
|
39
41
|
this.lastTruncation = null
|
|
40
42
|
|
|
41
43
|
this.active = 0
|
|
@@ -46,29 +48,29 @@ module.exports = class SessionState {
|
|
|
46
48
|
this.ref()
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
isSnapshot
|
|
51
|
+
isSnapshot() {
|
|
50
52
|
return this.storage.snapshotted
|
|
51
53
|
}
|
|
52
54
|
|
|
53
|
-
isDefault
|
|
55
|
+
isDefault() {
|
|
54
56
|
return this.core.state === this || this.isAtomicDefault()
|
|
55
57
|
}
|
|
56
58
|
|
|
57
|
-
isAtomicDefault
|
|
59
|
+
isAtomicDefault() {
|
|
58
60
|
return !!this.storage.atom && !!this.parent && this.parent.isDefault()
|
|
59
61
|
}
|
|
60
62
|
|
|
61
|
-
createTreeBatch
|
|
63
|
+
createTreeBatch() {
|
|
62
64
|
return new MerkleTreeBatch(this)
|
|
63
65
|
}
|
|
64
66
|
|
|
65
|
-
addSession
|
|
67
|
+
addSession(s) {
|
|
66
68
|
if (s._stateIndex !== -1) return
|
|
67
69
|
s._stateIndex = this.sessions.push(s) - 1
|
|
68
70
|
if (s.weak === false) this.core.activeSessions++
|
|
69
71
|
}
|
|
70
72
|
|
|
71
|
-
removeSession
|
|
73
|
+
removeSession(s) {
|
|
72
74
|
if (s._stateIndex === -1) return
|
|
73
75
|
const head = this.sessions.pop()
|
|
74
76
|
if (head !== s) this.sessions[(head._stateIndex = s._stateIndex)] = head
|
|
@@ -77,43 +79,43 @@ module.exports = class SessionState {
|
|
|
77
79
|
this.core.checkIfIdle()
|
|
78
80
|
}
|
|
79
81
|
|
|
80
|
-
flushedLength
|
|
82
|
+
flushedLength() {
|
|
81
83
|
if (this.isDefault() || this.isSnapshot()) return this.length
|
|
82
84
|
const deps = this.storage.dependencies
|
|
83
85
|
if (deps.length) return deps[deps.length - 1].length
|
|
84
86
|
return 0
|
|
85
87
|
}
|
|
86
88
|
|
|
87
|
-
signedLength
|
|
89
|
+
signedLength() {
|
|
88
90
|
const l = Math.min(this.flushedLength(), this.core.state.length)
|
|
89
91
|
return this.isSnapshot() && l > this.snapshotCompatLength ? this.snapshotCompatLength : l
|
|
90
92
|
}
|
|
91
93
|
|
|
92
|
-
unref
|
|
94
|
+
unref() {
|
|
93
95
|
if (--this.active > 0) return
|
|
94
96
|
this.close().catch(noop) // technically async, but only for the last db session
|
|
95
97
|
}
|
|
96
98
|
|
|
97
|
-
ref
|
|
99
|
+
ref() {
|
|
98
100
|
this.active++
|
|
99
101
|
return this
|
|
100
102
|
}
|
|
101
103
|
|
|
102
|
-
hash
|
|
104
|
+
hash() {
|
|
103
105
|
return MerkleTree.hash(this)
|
|
104
106
|
}
|
|
105
107
|
|
|
106
|
-
setRoots
|
|
108
|
+
setRoots(roots) {
|
|
107
109
|
this.roots = roots
|
|
108
110
|
this.length = MerkleTree.span(roots) / 2
|
|
109
111
|
this.byteLength = MerkleTree.size(roots)
|
|
110
112
|
}
|
|
111
113
|
|
|
112
|
-
get encryptionFork
|
|
114
|
+
get encryptionFork() {
|
|
113
115
|
return this.core.header.tree.fork
|
|
114
116
|
}
|
|
115
117
|
|
|
116
|
-
async updateSnapshotStorage
|
|
118
|
+
async updateSnapshotStorage(storage) {
|
|
117
119
|
if (!this.atomized || !this.atomized.flushing) return this.treeInfo()
|
|
118
120
|
await this.atomized.flushed()
|
|
119
121
|
|
|
@@ -143,7 +145,14 @@ module.exports = class SessionState {
|
|
|
143
145
|
// dbl check if we are hitting an regression from earler
|
|
144
146
|
for (const root of roots) {
|
|
145
147
|
if (root === null) {
|
|
146
|
-
throw new Error(
|
|
148
|
+
throw new Error(
|
|
149
|
+
'Bad snapshot from atomized session, id = ' +
|
|
150
|
+
this.core.id +
|
|
151
|
+
' length = ' +
|
|
152
|
+
length +
|
|
153
|
+
' fork = ' +
|
|
154
|
+
fork
|
|
155
|
+
)
|
|
147
156
|
}
|
|
148
157
|
}
|
|
149
158
|
|
|
@@ -156,7 +165,7 @@ module.exports = class SessionState {
|
|
|
156
165
|
}
|
|
157
166
|
}
|
|
158
167
|
|
|
159
|
-
treeInfo
|
|
168
|
+
treeInfo() {
|
|
160
169
|
return {
|
|
161
170
|
fork: this.fork,
|
|
162
171
|
roots: this.roots.slice(),
|
|
@@ -166,7 +175,7 @@ module.exports = class SessionState {
|
|
|
166
175
|
}
|
|
167
176
|
}
|
|
168
177
|
|
|
169
|
-
async close
|
|
178
|
+
async close() {
|
|
170
179
|
if (this.index === -1) return
|
|
171
180
|
|
|
172
181
|
this.active = 0
|
|
@@ -188,45 +197,39 @@ module.exports = class SessionState {
|
|
|
188
197
|
return closing
|
|
189
198
|
}
|
|
190
199
|
|
|
191
|
-
async snapshot
|
|
200
|
+
async snapshot() {
|
|
192
201
|
const storage = this.storage.snapshot()
|
|
193
202
|
const treeInfo = await this.updateSnapshotStorage(storage)
|
|
194
203
|
|
|
195
|
-
const s = new SessionState(
|
|
196
|
-
this.core,
|
|
197
|
-
null,
|
|
198
|
-
storage,
|
|
199
|
-
treeInfo,
|
|
200
|
-
this.name
|
|
201
|
-
)
|
|
204
|
+
const s = new SessionState(this.core, null, storage, treeInfo, this.name)
|
|
202
205
|
|
|
203
206
|
return s
|
|
204
207
|
}
|
|
205
208
|
|
|
206
|
-
updateDependency
|
|
209
|
+
updateDependency(tx, length) {
|
|
207
210
|
const dependency = updateDependency(this, length, false)
|
|
208
211
|
if (dependency) tx.setDependency(dependency)
|
|
209
212
|
return dependency
|
|
210
213
|
}
|
|
211
214
|
|
|
212
|
-
_clearActiveBatch
|
|
215
|
+
_clearActiveBatch() {
|
|
213
216
|
this._activeTx = null
|
|
214
217
|
}
|
|
215
218
|
|
|
216
|
-
createWriteBatch
|
|
219
|
+
createWriteBatch() {
|
|
217
220
|
assert(!this._activeTx && !this.storage.snapshotted)
|
|
218
221
|
|
|
219
222
|
this._activeTx = this.storage.write()
|
|
220
223
|
return this._activeTx
|
|
221
224
|
}
|
|
222
225
|
|
|
223
|
-
_unlock
|
|
226
|
+
_unlock() {
|
|
224
227
|
this._clearActiveBatch()
|
|
225
228
|
this.mutex.unlock()
|
|
226
229
|
this.core.checkIfIdle()
|
|
227
230
|
}
|
|
228
231
|
|
|
229
|
-
async flush
|
|
232
|
+
async flush() {
|
|
230
233
|
const tx = this._activeTx
|
|
231
234
|
this._activeTx = null
|
|
232
235
|
|
|
@@ -240,11 +243,11 @@ module.exports = class SessionState {
|
|
|
240
243
|
return true
|
|
241
244
|
}
|
|
242
245
|
|
|
243
|
-
_precommit
|
|
246
|
+
_precommit() {
|
|
244
247
|
this.commiting = true
|
|
245
248
|
}
|
|
246
249
|
|
|
247
|
-
async _commit
|
|
250
|
+
async _commit() {
|
|
248
251
|
await this.mutex.lock()
|
|
249
252
|
|
|
250
253
|
try {
|
|
@@ -258,7 +261,7 @@ module.exports = class SessionState {
|
|
|
258
261
|
}
|
|
259
262
|
}
|
|
260
263
|
|
|
261
|
-
async _oncommit
|
|
264
|
+
async _oncommit(src, bitfield) {
|
|
262
265
|
await this.mutex.lock()
|
|
263
266
|
|
|
264
267
|
try {
|
|
@@ -303,7 +306,7 @@ module.exports = class SessionState {
|
|
|
303
306
|
}
|
|
304
307
|
}
|
|
305
308
|
|
|
306
|
-
async setUserData
|
|
309
|
+
async setUserData(key, value) {
|
|
307
310
|
await this.mutex.lock()
|
|
308
311
|
|
|
309
312
|
try {
|
|
@@ -316,7 +319,7 @@ module.exports = class SessionState {
|
|
|
316
319
|
}
|
|
317
320
|
}
|
|
318
321
|
|
|
319
|
-
async _verifyBlock
|
|
322
|
+
async _verifyBlock(batch, bitfield, value, manifest, from) {
|
|
320
323
|
await this.mutex.lock()
|
|
321
324
|
|
|
322
325
|
try {
|
|
@@ -366,7 +369,7 @@ module.exports = class SessionState {
|
|
|
366
369
|
return true
|
|
367
370
|
}
|
|
368
371
|
|
|
369
|
-
async truncate
|
|
372
|
+
async truncate(length, fork, { signature, keyPair } = {}) {
|
|
370
373
|
if (!keyPair && this.isDefault()) keyPair = this.core.header.keyPair
|
|
371
374
|
|
|
372
375
|
await this.mutex.lock()
|
|
@@ -376,7 +379,10 @@ module.exports = class SessionState {
|
|
|
376
379
|
throw INVALID_OPERATION('Truncation breaks prologue', this.core.discoveryKey)
|
|
377
380
|
}
|
|
378
381
|
if (length > this.length) {
|
|
379
|
-
throw INVALID_OPERATION(
|
|
382
|
+
throw INVALID_OPERATION(
|
|
383
|
+
'Not a truncation, ' + length + ' must be less or equal to ' + this.length,
|
|
384
|
+
this.core.discoveryKey
|
|
385
|
+
)
|
|
380
386
|
}
|
|
381
387
|
|
|
382
388
|
const batch = this.createTreeBatch()
|
|
@@ -393,7 +399,11 @@ module.exports = class SessionState {
|
|
|
393
399
|
const { dependency, tree, roots } = await this._truncate(tx, batch)
|
|
394
400
|
|
|
395
401
|
for (const sessionState of this.core.sessionStates) {
|
|
396
|
-
if (
|
|
402
|
+
if (
|
|
403
|
+
sessionState.isSnapshot() &&
|
|
404
|
+
sessionState.name === this.name &&
|
|
405
|
+
length < sessionState.snapshotCompatLength
|
|
406
|
+
) {
|
|
397
407
|
sessionState.snapshotCompatLength = length
|
|
398
408
|
}
|
|
399
409
|
}
|
|
@@ -414,7 +424,7 @@ module.exports = class SessionState {
|
|
|
414
424
|
}
|
|
415
425
|
}
|
|
416
426
|
|
|
417
|
-
async reorg
|
|
427
|
+
async reorg(batch) {
|
|
418
428
|
await this.mutex.lock()
|
|
419
429
|
|
|
420
430
|
const storage = this.createWriteBatch()
|
|
@@ -440,7 +450,7 @@ module.exports = class SessionState {
|
|
|
440
450
|
}
|
|
441
451
|
}
|
|
442
452
|
|
|
443
|
-
async _truncate
|
|
453
|
+
async _truncate(storage, batch) {
|
|
444
454
|
storage.deleteBlockRange(batch.ancestors, batch.treeLength)
|
|
445
455
|
|
|
446
456
|
assert(batch.commitable(), 'Batch must be commitable')
|
|
@@ -470,7 +480,7 @@ module.exports = class SessionState {
|
|
|
470
480
|
return { dependency, tree, roots: batch.roots }
|
|
471
481
|
}
|
|
472
482
|
|
|
473
|
-
async clear
|
|
483
|
+
async clear(start, end, cleared) {
|
|
474
484
|
await this.mutex.lock()
|
|
475
485
|
|
|
476
486
|
try {
|
|
@@ -484,8 +494,8 @@ module.exports = class SessionState {
|
|
|
484
494
|
|
|
485
495
|
const [left, right] = flat.spans(b)
|
|
486
496
|
const s = left / 2
|
|
487
|
-
const e =
|
|
488
|
-
const has =
|
|
497
|
+
const e = right / 2 + 1
|
|
498
|
+
const has = s <= start && e <= end ? false : this.core.bitfield.hasSet(s, e - s)
|
|
489
499
|
if (has) break
|
|
490
500
|
|
|
491
501
|
tx.deleteTreeNode(a)
|
|
@@ -499,7 +509,7 @@ module.exports = class SessionState {
|
|
|
499
509
|
}
|
|
500
510
|
}
|
|
501
511
|
|
|
502
|
-
if (
|
|
512
|
+
if (end - start === 1) tx.deleteBlock(start)
|
|
503
513
|
else tx.deleteBlockRange(start, end)
|
|
504
514
|
|
|
505
515
|
const dependency = start < this.flushedLength() ? updateDependency(this, start, true) : null
|
|
@@ -520,13 +530,13 @@ module.exports = class SessionState {
|
|
|
520
530
|
}
|
|
521
531
|
}
|
|
522
532
|
|
|
523
|
-
async append
|
|
533
|
+
async append(values, { signature, keyPair, preappend, maxLength = -1 } = {}) {
|
|
524
534
|
if (!keyPair && this.isDefault()) keyPair = this.core.header.keyPair
|
|
525
535
|
|
|
526
536
|
await this.mutex.lock()
|
|
527
537
|
|
|
528
538
|
try {
|
|
529
|
-
if (maxLength >= 0 &&
|
|
539
|
+
if (maxLength >= 0 && this.length + values.length > maxLength) {
|
|
530
540
|
return { length: this.length, byteLength: this.byteLength }
|
|
531
541
|
}
|
|
532
542
|
|
|
@@ -597,7 +607,7 @@ module.exports = class SessionState {
|
|
|
597
607
|
}
|
|
598
608
|
}
|
|
599
609
|
|
|
600
|
-
onappend
|
|
610
|
+
onappend(tree, bitfield, flushed) {
|
|
601
611
|
if (!flushed) this._updateBitfield(bitfield)
|
|
602
612
|
else if (this.isDefault()) this.core.onappend(tree, bitfield)
|
|
603
613
|
|
|
@@ -606,7 +616,7 @@ module.exports = class SessionState {
|
|
|
606
616
|
}
|
|
607
617
|
}
|
|
608
618
|
|
|
609
|
-
ontruncate
|
|
619
|
+
ontruncate(tree, to, from, flushed) {
|
|
610
620
|
const bitfield = { start: to, length: from - to, drop: true }
|
|
611
621
|
|
|
612
622
|
this.lastTruncation = { from, to }
|
|
@@ -615,7 +625,11 @@ module.exports = class SessionState {
|
|
|
615
625
|
else if (this.isDefault()) this.core.ontruncate(tree, bitfield)
|
|
616
626
|
|
|
617
627
|
for (const sessionState of this.core.sessionStates) {
|
|
618
|
-
if (
|
|
628
|
+
if (
|
|
629
|
+
sessionState.isSnapshot() &&
|
|
630
|
+
sessionState.name === this.name &&
|
|
631
|
+
to < sessionState.snapshotCompatLength
|
|
632
|
+
) {
|
|
619
633
|
sessionState.snapshotCompatLength = to
|
|
620
634
|
}
|
|
621
635
|
}
|
|
@@ -625,7 +639,7 @@ module.exports = class SessionState {
|
|
|
625
639
|
}
|
|
626
640
|
}
|
|
627
641
|
|
|
628
|
-
_updateBitfield
|
|
642
|
+
_updateBitfield(bitfield, flushed) {
|
|
629
643
|
if (!bitfield) return
|
|
630
644
|
|
|
631
645
|
const p = this._pendingBitfield
|
|
@@ -633,7 +647,7 @@ module.exports = class SessionState {
|
|
|
633
647
|
|
|
634
648
|
if (b.drop) {
|
|
635
649
|
// truncation must be from end
|
|
636
|
-
if (p &&
|
|
650
|
+
if (p && b.start + b.length !== p.start + p.appends) {
|
|
637
651
|
throw INVALID_OPERATION('Atomic truncations must be contiguous', this.core.discoveryKey)
|
|
638
652
|
}
|
|
639
653
|
|
|
@@ -664,7 +678,7 @@ module.exports = class SessionState {
|
|
|
664
678
|
p.appends += b.length
|
|
665
679
|
}
|
|
666
680
|
|
|
667
|
-
async catchup
|
|
681
|
+
async catchup(length) {
|
|
668
682
|
assert(!this.isDefault(), 'Cannot catchup signed state') // TODO: make this check better
|
|
669
683
|
|
|
670
684
|
await this.mutex.lock()
|
|
@@ -695,7 +709,11 @@ module.exports = class SessionState {
|
|
|
695
709
|
const truncating = sharedLength < origLength
|
|
696
710
|
|
|
697
711
|
for (const node of roots) {
|
|
698
|
-
if (node === null)
|
|
712
|
+
if (node === null)
|
|
713
|
+
throw INVALID_OPERATION(
|
|
714
|
+
'Invalid catchup length, tree nodes not available',
|
|
715
|
+
this.core.discoveryKey
|
|
716
|
+
)
|
|
699
717
|
}
|
|
700
718
|
|
|
701
719
|
const fork = truncating ? this.fork + 1 : this.fork
|
|
@@ -736,7 +754,7 @@ module.exports = class SessionState {
|
|
|
736
754
|
}
|
|
737
755
|
}
|
|
738
756
|
|
|
739
|
-
async _overwrite
|
|
757
|
+
async _overwrite(source, fork, length, treeLength, signature) {
|
|
740
758
|
const blockPromises = []
|
|
741
759
|
const treePromises = []
|
|
742
760
|
const rootPromises = []
|
|
@@ -771,7 +789,10 @@ module.exports = class SessionState {
|
|
|
771
789
|
batch.length = length
|
|
772
790
|
|
|
773
791
|
if (!this.core.verifier.verify(batch, signature)) {
|
|
774
|
-
throw INVALID_SIGNATURE(
|
|
792
|
+
throw INVALID_SIGNATURE(
|
|
793
|
+
'Signature is not valid over committed tree',
|
|
794
|
+
this.core.discoveryKey
|
|
795
|
+
)
|
|
775
796
|
}
|
|
776
797
|
}
|
|
777
798
|
|
|
@@ -848,8 +869,11 @@ module.exports = class SessionState {
|
|
|
848
869
|
return { tree, flushed }
|
|
849
870
|
}
|
|
850
871
|
|
|
851
|
-
async commit
|
|
852
|
-
assert(
|
|
872
|
+
async commit(state, { signature, keyPair, length = state.length, treeLength = -1 } = {}) {
|
|
873
|
+
assert(
|
|
874
|
+
this.isDefault() || (this.parent && this.parent.isDefault()),
|
|
875
|
+
'Can only commit into default state'
|
|
876
|
+
)
|
|
853
877
|
|
|
854
878
|
let srcLocked = false
|
|
855
879
|
await this.mutex.lock()
|
|
@@ -870,7 +894,13 @@ module.exports = class SessionState {
|
|
|
870
894
|
signature = this.core.verifier.sign(batch, keyPair)
|
|
871
895
|
}
|
|
872
896
|
|
|
873
|
-
const { tree, flushed } = await this._overwrite(
|
|
897
|
+
const { tree, flushed } = await this._overwrite(
|
|
898
|
+
state,
|
|
899
|
+
this.fork,
|
|
900
|
+
length,
|
|
901
|
+
treeLength,
|
|
902
|
+
signature
|
|
903
|
+
)
|
|
874
904
|
|
|
875
905
|
// gc blocks from source
|
|
876
906
|
if (treeLength < length) {
|
|
@@ -904,7 +934,7 @@ module.exports = class SessionState {
|
|
|
904
934
|
}
|
|
905
935
|
}
|
|
906
936
|
|
|
907
|
-
async _getTreeHeadAt
|
|
937
|
+
async _getTreeHeadAt(length) {
|
|
908
938
|
if (length === null) return this.treeInfo()
|
|
909
939
|
|
|
910
940
|
const head = getDefaultTree()
|
|
@@ -922,7 +952,7 @@ module.exports = class SessionState {
|
|
|
922
952
|
return head
|
|
923
953
|
}
|
|
924
954
|
|
|
925
|
-
_moveToCore
|
|
955
|
+
_moveToCore(core, truncated, appended) {
|
|
926
956
|
const head = this.core.sessionStates.pop()
|
|
927
957
|
if (head !== this) this.core.sessionStates[(head.index = this.index)] = head
|
|
928
958
|
|
|
@@ -939,7 +969,7 @@ module.exports = class SessionState {
|
|
|
939
969
|
}
|
|
940
970
|
}
|
|
941
971
|
|
|
942
|
-
async moveTo
|
|
972
|
+
async moveTo(core, length) {
|
|
943
973
|
const state = core.state
|
|
944
974
|
|
|
945
975
|
await this.mutex.lock()
|
|
@@ -961,7 +991,11 @@ module.exports = class SessionState {
|
|
|
961
991
|
const resumed = await state.storage.resumeSession(this.name)
|
|
962
992
|
|
|
963
993
|
const truncation = length < this.length ? await truncateAndFlush(this, length) : null
|
|
964
|
-
const treeInfo = truncation
|
|
994
|
+
const treeInfo = truncation
|
|
995
|
+
? truncation.tree
|
|
996
|
+
: resumed
|
|
997
|
+
? null
|
|
998
|
+
: await state._getTreeHeadAt(this.length)
|
|
965
999
|
|
|
966
1000
|
const fork = truncation ? this.fork + 1 : this.fork
|
|
967
1001
|
|
|
@@ -1009,7 +1043,7 @@ module.exports = class SessionState {
|
|
|
1009
1043
|
}
|
|
1010
1044
|
}
|
|
1011
1045
|
|
|
1012
|
-
async createSession
|
|
1046
|
+
async createSession(name, overwrite, atom) {
|
|
1013
1047
|
let storage = null
|
|
1014
1048
|
let treeInfo = null
|
|
1015
1049
|
|
|
@@ -1037,7 +1071,10 @@ module.exports = class SessionState {
|
|
|
1037
1071
|
|
|
1038
1072
|
const head = {
|
|
1039
1073
|
fork: this.fork,
|
|
1040
|
-
roots:
|
|
1074
|
+
roots:
|
|
1075
|
+
length === this.length
|
|
1076
|
+
? this.roots.slice()
|
|
1077
|
+
: await MerkleTree.getRootsFromStorage(storage, length),
|
|
1041
1078
|
length,
|
|
1042
1079
|
prologue: this.prologue,
|
|
1043
1080
|
signature: length === this.length ? this.signature : null
|
|
@@ -1060,13 +1097,13 @@ module.exports = class SessionState {
|
|
|
1060
1097
|
}
|
|
1061
1098
|
}
|
|
1062
1099
|
|
|
1063
|
-
function noop
|
|
1100
|
+
function noop() {}
|
|
1064
1101
|
|
|
1065
|
-
function getBitfieldPage
|
|
1102
|
+
function getBitfieldPage(index) {
|
|
1066
1103
|
return Math.floor(index / Bitfield.BITS_PER_PAGE)
|
|
1067
1104
|
}
|
|
1068
1105
|
|
|
1069
|
-
function fillBitfieldPage
|
|
1106
|
+
function fillBitfieldPage(page, start, end, pageIndex, value) {
|
|
1070
1107
|
const offset = pageIndex * Bitfield.BITS_PER_PAGE
|
|
1071
1108
|
const max = offset + Bitfield.BITS_PER_PAGE
|
|
1072
1109
|
|
|
@@ -1080,7 +1117,7 @@ function fillBitfieldPage (page, start, end, pageIndex, value) {
|
|
|
1080
1117
|
return index
|
|
1081
1118
|
}
|
|
1082
1119
|
|
|
1083
|
-
async function storeBitfieldRange
|
|
1120
|
+
async function storeBitfieldRange(storage, tx, from, to, value) {
|
|
1084
1121
|
if (from >= to) return
|
|
1085
1122
|
|
|
1086
1123
|
const firstPage = getBitfieldPage(from)
|
|
@@ -1109,7 +1146,7 @@ async function storeBitfieldRange (storage, tx, from, to, value) {
|
|
|
1109
1146
|
}
|
|
1110
1147
|
}
|
|
1111
1148
|
|
|
1112
|
-
async function truncateAndFlush
|
|
1149
|
+
async function truncateAndFlush(s, length) {
|
|
1113
1150
|
const batch = s.createTreeBatch()
|
|
1114
1151
|
await MerkleTree.truncate(s, length, batch, s.fork)
|
|
1115
1152
|
const tx = s.createWriteBatch()
|
|
@@ -1125,7 +1162,7 @@ async function truncateAndFlush (s, length) {
|
|
|
1125
1162
|
}
|
|
1126
1163
|
}
|
|
1127
1164
|
|
|
1128
|
-
function updateDependency
|
|
1165
|
+
function updateDependency(state, length, truncated) {
|
|
1129
1166
|
const i = state.storage.findDependencyIndex(length, truncated)
|
|
1130
1167
|
if (i === -1) return null // skip default state and overlays of default
|
|
1131
1168
|
|
|
@@ -1135,7 +1172,7 @@ function updateDependency (state, length, truncated) {
|
|
|
1135
1172
|
}
|
|
1136
1173
|
}
|
|
1137
1174
|
|
|
1138
|
-
function getDefaultTree
|
|
1175
|
+
function getDefaultTree() {
|
|
1139
1176
|
return {
|
|
1140
1177
|
fork: 0,
|
|
1141
1178
|
length: 0,
|
|
@@ -1144,14 +1181,14 @@ function getDefaultTree () {
|
|
|
1144
1181
|
}
|
|
1145
1182
|
}
|
|
1146
1183
|
|
|
1147
|
-
function getCoreHead
|
|
1184
|
+
function getCoreHead(storage) {
|
|
1148
1185
|
const b = storage.read()
|
|
1149
1186
|
const p = b.getHead()
|
|
1150
1187
|
b.tryFlush()
|
|
1151
1188
|
return p
|
|
1152
1189
|
}
|
|
1153
1190
|
|
|
1154
|
-
function isRootIndex
|
|
1191
|
+
function isRootIndex(index, roots) {
|
|
1155
1192
|
for (const node of roots) {
|
|
1156
1193
|
if (node.index === index) return true
|
|
1157
1194
|
}
|
package/lib/streams.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const { Writable, Readable } = require('streamx')
|
|
2
2
|
|
|
3
3
|
class ReadStream extends Readable {
|
|
4
|
-
constructor
|
|
4
|
+
constructor(core, opts = {}) {
|
|
5
5
|
super()
|
|
6
6
|
|
|
7
7
|
this.core = core
|
|
@@ -13,22 +13,22 @@ class ReadStream extends Readable {
|
|
|
13
13
|
this.timeout = opts.timeout || core.timeout
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
_open
|
|
16
|
+
_open(cb) {
|
|
17
17
|
this._openP().then(cb, cb)
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
_read
|
|
20
|
+
_read(cb) {
|
|
21
21
|
this._readP().then(cb, cb)
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
async _openP
|
|
24
|
+
async _openP() {
|
|
25
25
|
if (this.end === -1) await this.core.update()
|
|
26
26
|
else await this.core.ready()
|
|
27
27
|
if (this.snapshot && this.end === -1) this.end = this.core.length
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
async _readP
|
|
31
|
-
const end = this.live ? -1 :
|
|
30
|
+
async _readP() {
|
|
31
|
+
const end = this.live ? -1 : this.end === -1 ? this.core.length : this.end
|
|
32
32
|
if (end >= 0 && this.start >= end) {
|
|
33
33
|
this.push(null)
|
|
34
34
|
return
|
|
@@ -41,16 +41,16 @@ class ReadStream extends Readable {
|
|
|
41
41
|
exports.ReadStream = ReadStream
|
|
42
42
|
|
|
43
43
|
class WriteStream extends Writable {
|
|
44
|
-
constructor
|
|
44
|
+
constructor(core) {
|
|
45
45
|
super()
|
|
46
46
|
this.core = core
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
_writev
|
|
49
|
+
_writev(batch, cb) {
|
|
50
50
|
this._writevP(batch).then(cb, cb)
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
async _writevP
|
|
53
|
+
async _writevP(batch) {
|
|
54
54
|
await this.core.append(batch)
|
|
55
55
|
}
|
|
56
56
|
}
|
|
@@ -58,7 +58,7 @@ class WriteStream extends Writable {
|
|
|
58
58
|
exports.WriteStream = WriteStream
|
|
59
59
|
|
|
60
60
|
class ByteStream extends Readable {
|
|
61
|
-
constructor
|
|
61
|
+
constructor(core, opts = {}) {
|
|
62
62
|
super()
|
|
63
63
|
|
|
64
64
|
this._core = core
|
|
@@ -72,22 +72,22 @@ class ByteStream extends Readable {
|
|
|
72
72
|
this._applyOffset = this._byteOffset > 0
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
_open
|
|
75
|
+
_open(cb) {
|
|
76
76
|
this._openp().then(cb, cb)
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
_read
|
|
79
|
+
_read(cb) {
|
|
80
80
|
this._readp().then(cb, cb)
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
async _openp
|
|
83
|
+
async _openp() {
|
|
84
84
|
if (this._byteLength === -1) {
|
|
85
85
|
await this._core.update()
|
|
86
86
|
this._byteLength = Math.max(this._core.byteLength - this._byteOffset, 0)
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
async _readp
|
|
90
|
+
async _readp() {
|
|
91
91
|
let data = null
|
|
92
92
|
|
|
93
93
|
if (this._byteLength === 0) {
|
|
@@ -118,12 +118,12 @@ class ByteStream extends Readable {
|
|
|
118
118
|
if (this._byteLength === 0) this.push(null)
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
_predownload
|
|
121
|
+
_predownload(index) {
|
|
122
122
|
if (this._range) this._range.destroy()
|
|
123
123
|
this._range = this._core.download({ start: index, end: index + this._prefetch, linear: true })
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
_destroy
|
|
126
|
+
_destroy(cb) {
|
|
127
127
|
if (this._range) this._range.destroy()
|
|
128
128
|
cb(null)
|
|
129
129
|
}
|