hypercore 10.38.1 → 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/README.md +13 -30
- package/index.js +390 -442
- package/lib/audit.js +33 -41
- package/lib/bit-interlude.js +174 -0
- package/lib/bitfield.js +79 -87
- package/lib/block-store.js +12 -50
- package/lib/copy-prologue.js +236 -0
- package/lib/core.js +413 -746
- package/lib/download.js +42 -4
- package/lib/merkle-tree.js +263 -406
- package/lib/multisig.js +9 -6
- package/lib/mutex.js +4 -0
- package/lib/remote-bitfield.js +9 -9
- package/lib/replicator.js +247 -177
- package/lib/session-state.js +949 -0
- package/lib/verifier.js +20 -13
- package/package.json +2 -2
- package/lib/batch.js +0 -431
- package/lib/big-header.js +0 -55
- package/lib/oplog.js +0 -228
package/lib/oplog.js
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
const cenc = require('compact-encoding')
|
|
2
|
-
const b4a = require('b4a')
|
|
3
|
-
const { crc32 } = require('crc-universal')
|
|
4
|
-
const { OPLOG_CORRUPT, OPLOG_HEADER_OVERFLOW, WRITE_FAILED } = require('hypercore-errors')
|
|
5
|
-
|
|
6
|
-
module.exports = class Oplog {
|
|
7
|
-
constructor (storage, { pageSize = 4096, headerEncoding = cenc.raw, entryEncoding = cenc.raw, readonly = false } = {}) {
|
|
8
|
-
this.storage = storage
|
|
9
|
-
this.headerEncoding = headerEncoding
|
|
10
|
-
this.entryEncoding = entryEncoding
|
|
11
|
-
this.readonly = readonly
|
|
12
|
-
this.flushed = false
|
|
13
|
-
this.byteLength = 0
|
|
14
|
-
this.length = 0
|
|
15
|
-
|
|
16
|
-
this._headers = [1, 0]
|
|
17
|
-
this._pageSize = pageSize
|
|
18
|
-
this._entryOffset = pageSize * 2
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
_addHeader (state, len, headerBit, partialBit) {
|
|
22
|
-
// add the uint header (frame length and flush info)
|
|
23
|
-
state.start = state.start - len - 4
|
|
24
|
-
cenc.uint32.encode(state, (len << 2) | headerBit | partialBit)
|
|
25
|
-
|
|
26
|
-
// crc32 the length + header-bit + content and prefix it
|
|
27
|
-
state.start -= 8
|
|
28
|
-
cenc.uint32.encode(state, crc32(state.buffer.subarray(state.start + 4, state.start + 8 + len)))
|
|
29
|
-
state.start += len + 4
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
_decodeEntry (state, enc) {
|
|
33
|
-
if (state.end - state.start < 8) return null
|
|
34
|
-
const cksum = cenc.uint32.decode(state)
|
|
35
|
-
const l = cenc.uint32.decode(state)
|
|
36
|
-
const length = l >>> 2
|
|
37
|
-
const headerBit = l & 1
|
|
38
|
-
const partialBit = l & 2
|
|
39
|
-
|
|
40
|
-
if (state.end - state.start < length) return null
|
|
41
|
-
|
|
42
|
-
const end = state.start + length
|
|
43
|
-
|
|
44
|
-
if (crc32(state.buffer.subarray(state.start - 4, end)) !== cksum) {
|
|
45
|
-
return null
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const result = { header: headerBit, partial: partialBit !== 0, byteLength: length + 8, message: null }
|
|
49
|
-
|
|
50
|
-
try {
|
|
51
|
-
result.message = enc.decode({ start: state.start, end, buffer: state.buffer })
|
|
52
|
-
} catch {
|
|
53
|
-
return null
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
state.start = end
|
|
57
|
-
|
|
58
|
-
return result
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async open () {
|
|
62
|
-
const buffer = await this._readAll() // TODO: stream the oplog in on load maybe?
|
|
63
|
-
const state = { start: 0, end: buffer.byteLength, buffer }
|
|
64
|
-
const result = { header: null, entries: [] }
|
|
65
|
-
|
|
66
|
-
this.byteLength = 0
|
|
67
|
-
this.length = 0
|
|
68
|
-
|
|
69
|
-
const h1 = this._decodeEntry(state, this.headerEncoding)
|
|
70
|
-
state.start = this._pageSize
|
|
71
|
-
|
|
72
|
-
const h2 = this._decodeEntry(state, this.headerEncoding)
|
|
73
|
-
state.start = this._entryOffset
|
|
74
|
-
|
|
75
|
-
if (!h1 && !h2) {
|
|
76
|
-
// reset state...
|
|
77
|
-
this.flushed = false
|
|
78
|
-
this._headers[0] = 1
|
|
79
|
-
this._headers[1] = 0
|
|
80
|
-
|
|
81
|
-
if (buffer.byteLength >= this._entryOffset) {
|
|
82
|
-
throw OPLOG_CORRUPT()
|
|
83
|
-
}
|
|
84
|
-
return result
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
this.flushed = true
|
|
88
|
-
|
|
89
|
-
if (h1 && !h2) {
|
|
90
|
-
this._headers[0] = h1.header
|
|
91
|
-
this._headers[1] = h1.header
|
|
92
|
-
} else if (!h1 && h2) {
|
|
93
|
-
this._headers[0] = (h2.header + 1) & 1
|
|
94
|
-
this._headers[1] = h2.header
|
|
95
|
-
} else {
|
|
96
|
-
this._headers[0] = h1.header
|
|
97
|
-
this._headers[1] = h2.header
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const header = (this._headers[0] + this._headers[1]) & 1
|
|
101
|
-
const decoded = []
|
|
102
|
-
|
|
103
|
-
result.header = header ? h2.message : h1.message
|
|
104
|
-
|
|
105
|
-
while (true) {
|
|
106
|
-
const entry = this._decodeEntry(state, this.entryEncoding)
|
|
107
|
-
if (!entry) break
|
|
108
|
-
if (entry.header !== header) break
|
|
109
|
-
|
|
110
|
-
decoded.push(entry)
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
while (decoded.length > 0 && decoded[decoded.length - 1].partial) decoded.pop()
|
|
114
|
-
|
|
115
|
-
for (const e of decoded) {
|
|
116
|
-
result.entries.push(e.message)
|
|
117
|
-
this.byteLength += e.byteLength
|
|
118
|
-
this.length++
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const size = this.byteLength + this._entryOffset
|
|
122
|
-
|
|
123
|
-
if (size === buffer.byteLength) return result
|
|
124
|
-
|
|
125
|
-
await new Promise((resolve, reject) => {
|
|
126
|
-
if (this.readonly) return resolve()
|
|
127
|
-
this.storage.truncate(size, err => {
|
|
128
|
-
if (err) return reject(err)
|
|
129
|
-
resolve()
|
|
130
|
-
})
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
return result
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
_readAll () {
|
|
137
|
-
return new Promise((resolve, reject) => {
|
|
138
|
-
this.storage.open(err => {
|
|
139
|
-
if (err && err.code !== 'ENOENT') return reject(err)
|
|
140
|
-
if (err) return resolve(b4a.alloc(0))
|
|
141
|
-
this.storage.stat((err, stat) => {
|
|
142
|
-
if (err && err.code !== 'ENOENT') return reject(err)
|
|
143
|
-
this.storage.read(0, stat.size, (err, buf) => {
|
|
144
|
-
if (err) return reject(err)
|
|
145
|
-
resolve(buf)
|
|
146
|
-
})
|
|
147
|
-
})
|
|
148
|
-
})
|
|
149
|
-
})
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
flush (header) {
|
|
153
|
-
const state = { start: 8, end: 8, buffer: null }
|
|
154
|
-
const i = this._headers[0] === this._headers[1] ? 1 : 0
|
|
155
|
-
const bit = (this._headers[i] + 1) & 1
|
|
156
|
-
|
|
157
|
-
this.headerEncoding.preencode(state, header)
|
|
158
|
-
if (state.end > this._pageSize) throw OPLOG_HEADER_OVERFLOW()
|
|
159
|
-
state.buffer = b4a.allocUnsafe(state.end)
|
|
160
|
-
this.headerEncoding.encode(state, header)
|
|
161
|
-
this._addHeader(state, state.end - 8, bit, 0)
|
|
162
|
-
|
|
163
|
-
return this._writeHeaderAndTruncate(i, bit, state.buffer)
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
_writeHeaderAndTruncate (i, bit, buf) {
|
|
167
|
-
return new Promise((resolve, reject) => {
|
|
168
|
-
this.storage.write(i === 0 ? 0 : this._pageSize, buf, err => {
|
|
169
|
-
if (err) return reject(err)
|
|
170
|
-
|
|
171
|
-
this.storage.truncate(this._entryOffset, err => {
|
|
172
|
-
if (err) return reject(err)
|
|
173
|
-
|
|
174
|
-
this._headers[i] = bit
|
|
175
|
-
this.byteLength = 0
|
|
176
|
-
this.length = 0
|
|
177
|
-
this.flushed = true
|
|
178
|
-
|
|
179
|
-
resolve()
|
|
180
|
-
})
|
|
181
|
-
})
|
|
182
|
-
})
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
append (batch, atomic = true) {
|
|
186
|
-
if (!Array.isArray(batch)) batch = [batch]
|
|
187
|
-
|
|
188
|
-
const state = { start: 0, end: batch.length * 8, buffer: null }
|
|
189
|
-
const bit = (this._headers[0] + this._headers[1]) & 1
|
|
190
|
-
|
|
191
|
-
for (let i = 0; i < batch.length; i++) {
|
|
192
|
-
this.entryEncoding.preencode(state, batch[i])
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
state.buffer = b4a.allocUnsafe(state.end)
|
|
196
|
-
|
|
197
|
-
for (let i = 0; i < batch.length; i++) {
|
|
198
|
-
const start = state.start += 8 // space for header
|
|
199
|
-
const partial = (atomic && i < batch.length - 1) ? 2 : 0
|
|
200
|
-
this.entryEncoding.encode(state, batch[i])
|
|
201
|
-
this._addHeader(state, state.start - start, bit, partial)
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
return this._append(state.buffer, batch.length)
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
close () {
|
|
208
|
-
return new Promise((resolve, reject) => {
|
|
209
|
-
this.storage.close(err => {
|
|
210
|
-
if (err) return reject(err)
|
|
211
|
-
resolve()
|
|
212
|
-
})
|
|
213
|
-
})
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
_append (buf, count) {
|
|
217
|
-
return new Promise((resolve, reject) => {
|
|
218
|
-
this.storage.write(this._entryOffset + this.byteLength, buf, err => {
|
|
219
|
-
if (err) return reject(WRITE_FAILED(err.message))
|
|
220
|
-
|
|
221
|
-
this.byteLength += buf.byteLength
|
|
222
|
-
this.length += count
|
|
223
|
-
|
|
224
|
-
resolve()
|
|
225
|
-
})
|
|
226
|
-
})
|
|
227
|
-
}
|
|
228
|
-
}
|