@leofcoin/workers 1.4.12 → 1.4.13
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/CHANGELOG.md +10 -0
- package/package.json +29 -27
- package/src/machine-worker.js +126 -70
- package/tsconfig.json +18 -0
package/CHANGELOG.md
ADDED
package/package.json
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@leofcoin/workers",
|
|
3
|
-
"version": "1.4.
|
|
4
|
-
"description": "Workers used in @leofcoin/chain",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
"
|
|
9
|
-
"./
|
|
10
|
-
"./
|
|
11
|
-
"./
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
"@leofcoin/
|
|
23
|
-
"@leofcoin/
|
|
24
|
-
"@leofcoin/
|
|
25
|
-
"@
|
|
26
|
-
|
|
27
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@leofcoin/workers",
|
|
3
|
+
"version": "1.4.13",
|
|
4
|
+
"description": "Workers used in @leofcoin/chain",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"private": false,
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/workers.js",
|
|
9
|
+
"./machine-worker": "./src/machine-worker.js",
|
|
10
|
+
"./block-worker": "./src/block-worker.js",
|
|
11
|
+
"./transaction-worker": "./src/transaction-worker.js",
|
|
12
|
+
"./pool-worker": "./src/pool-worker.js"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"prettier": "prettier src --config ./../../.prettierrc --write",
|
|
16
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [],
|
|
19
|
+
"author": "",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@leofcoin/addresses": "^1.0.18",
|
|
23
|
+
"@leofcoin/lib": "^1.2.38",
|
|
24
|
+
"@leofcoin/messages": "^1.2.0",
|
|
25
|
+
"@leofcoin/storage": "^3.3.2",
|
|
26
|
+
"@leofcoin/utils": "^1.1.5",
|
|
27
|
+
"@vandeurenglenn/easy-worker": "^1.0.2"
|
|
28
|
+
}
|
|
29
|
+
}
|
package/src/machine-worker.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { BlockMessage, ContractMessage, TransactionMessage } from '@leofcoin/messages'
|
|
2
2
|
import { formatBytes, BigNumber } from '@leofcoin/utils'
|
|
3
|
+
import addresses from '@leofcoin/addresses'
|
|
3
4
|
import bytecodes from '@leofcoin/lib/bytecodes' assert { type: 'json' }
|
|
4
5
|
import EasyWorker from '@vandeurenglenn/easy-worker'
|
|
5
6
|
import { nativeToken } from '@leofcoin/addresses'
|
|
7
|
+
import { randomUUID } from 'crypto'
|
|
8
|
+
import LittlePubSub from '@vandeurenglenn/little-pubsub'
|
|
9
|
+
const pubsub = new LittlePubSub()
|
|
6
10
|
const worker = new EasyWorker()
|
|
7
11
|
|
|
8
12
|
const contractFactoryMessage = bytecodes.contractFactory
|
|
@@ -11,7 +15,6 @@ const nameServiceMessage = bytecodes.nameService
|
|
|
11
15
|
const validatorsMessage = bytecodes.validators
|
|
12
16
|
|
|
13
17
|
const latestTransactions = []
|
|
14
|
-
|
|
15
18
|
let nativeCalls = 0
|
|
16
19
|
let nativeBurns = 0
|
|
17
20
|
let nativeMints = 0
|
|
@@ -30,6 +33,13 @@ globalThis.BigNumber = BigNumber
|
|
|
30
33
|
|
|
31
34
|
let lastBlock = { index: -1, hash: '0x0', previousHash: '0x0' }
|
|
32
35
|
|
|
36
|
+
const debug = (message) => {
|
|
37
|
+
worker.postMessage({
|
|
38
|
+
type: 'debug',
|
|
39
|
+
message
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
|
|
33
43
|
const unique = (arr) =>
|
|
34
44
|
arr.filter((el, pos, arr) => {
|
|
35
45
|
return arr.indexOf(el) == pos
|
|
@@ -49,18 +59,28 @@ const get = ({ contract, method, params }) => {
|
|
|
49
59
|
return result
|
|
50
60
|
}
|
|
51
61
|
|
|
52
|
-
|
|
62
|
+
const resolveContract = (address) => askFor('contract', address)
|
|
63
|
+
|
|
64
|
+
const respond = (id, value) => {
|
|
65
|
+
worker.postMessage({
|
|
66
|
+
type: 'response',
|
|
67
|
+
value,
|
|
68
|
+
id
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
_.runContract = async ({ decoded, hash, encoded }, state) => {
|
|
53
73
|
const params = decoded.constructorParameters
|
|
54
74
|
try {
|
|
55
75
|
const func = new Function(new TextDecoder().decode(decoded.contract))
|
|
56
76
|
const Contract = func()
|
|
57
77
|
|
|
78
|
+
if (state) params.push(state)
|
|
79
|
+
|
|
58
80
|
globalThis.msg = createMessage(decoded.creator)
|
|
59
81
|
contracts[hash] = await new Contract(...params)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
message: `loaded contract: ${hash} size: ${formatBytes(encoded.length)}`
|
|
63
|
-
})
|
|
82
|
+
|
|
83
|
+
debug(`loaded contract: ${hash} size: ${formatBytes(encoded.length)}`)
|
|
64
84
|
} catch (e) {
|
|
65
85
|
console.log(e)
|
|
66
86
|
worker.postMessage({
|
|
@@ -131,11 +151,39 @@ const _executeTransaction = async (transaction) => {
|
|
|
131
151
|
}
|
|
132
152
|
|
|
133
153
|
_.init = async (message) => {
|
|
134
|
-
let {
|
|
135
|
-
console.log({ states })
|
|
136
|
-
|
|
154
|
+
let { peerid, fromState, state } = message
|
|
137
155
|
globalThis.peerid = peerid
|
|
138
156
|
if (fromState) {
|
|
157
|
+
lastBlock = message.lastBlock
|
|
158
|
+
const setState = async (address, state) => {
|
|
159
|
+
const contractBytes = await resolveContract(address)
|
|
160
|
+
const contract = await new ContractMessage(contractBytes)
|
|
161
|
+
|
|
162
|
+
await _.runContract({ hash: address, decoded: contract.decoded, encoded: contract.encoded }, state)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const entries = Object.entries(state)
|
|
166
|
+
if (entries.length > 0) {
|
|
167
|
+
const promises = []
|
|
168
|
+
for (const [address, value] of entries) {
|
|
169
|
+
promises.push(setState(address, value))
|
|
170
|
+
}
|
|
171
|
+
await Promise.all(promises)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const promises = []
|
|
175
|
+
if (!contracts[addresses.contractFactory]) promises.push(setState(addresses.contractFactory))
|
|
176
|
+
if (!contracts[addresses.nameService]) promises.push(setState(addresses.nameService))
|
|
177
|
+
if (!contracts[addresses.validators]) promises.push(setState(addresses.validators))
|
|
178
|
+
if (!contracts[addresses.nativeToken]) promises.push(setState(addresses.nativeToken))
|
|
179
|
+
// contracts = await Promise.all(
|
|
180
|
+
// contracts.map(async (contract) => {
|
|
181
|
+
// contract = await new ContractMessage(new Uint8Array(contract.split(',')))
|
|
182
|
+
// await _.runContract({ decoded: contract.decoded, encoded: contract.encoded, hash: await contract.hash() })
|
|
183
|
+
// return contract
|
|
184
|
+
// })
|
|
185
|
+
// )
|
|
186
|
+
await Promise.all(promises)
|
|
139
187
|
} else {
|
|
140
188
|
contracts = [contractFactoryMessage, nativeTokenMessage, nameServiceMessage, validatorsMessage]
|
|
141
189
|
|
|
@@ -146,67 +194,66 @@ _.init = async (message) => {
|
|
|
146
194
|
return contract
|
|
147
195
|
})
|
|
148
196
|
)
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
// browser env
|
|
160
|
-
pre = './'
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
let _worker = await new EasyWorker(pre + '@leofcoin/workers/block-worker.js', {
|
|
164
|
-
serialization: 'advanced',
|
|
165
|
-
type: 'module'
|
|
166
|
-
})
|
|
167
|
-
blocks = await _worker.once(message.blocks)
|
|
168
|
-
_worker = null
|
|
169
|
-
// blocks = unique(globalThis.blocks ? globalThis : [], blocks)
|
|
170
|
-
// for (let i = 0; i < blocks.length; i++) {
|
|
171
|
-
|
|
172
|
-
// }
|
|
173
|
-
for (const block of blocks) {
|
|
174
|
-
// we only revalidate the latest 24 blocks
|
|
175
|
-
// every 24 blocks a snapshot is taken and stored in state
|
|
176
|
-
// this means contracts will be restored from this state
|
|
177
|
-
// this also means devs NEED to make sure the state can be restored
|
|
178
|
-
// on contract deploy an error will be thrown if state wasn't recoverable
|
|
179
|
-
if (block.index > 24) {
|
|
180
|
-
const transactionCount = blocks[block.index - 1].transactions.length
|
|
181
|
-
latestTransactions.splice(-(transactionCount - 1), latestTransactions.length)
|
|
197
|
+
if (message.blocks?.length > 0) {
|
|
198
|
+
let pre
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
const importee = await import('url')
|
|
202
|
+
const url = importee.default
|
|
203
|
+
if (url) pre = url.fileURLToPath(new URL('.', import.meta.url))
|
|
204
|
+
} catch {
|
|
205
|
+
// browser env
|
|
206
|
+
pre = './'
|
|
182
207
|
}
|
|
183
208
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
209
|
+
let _worker = await new EasyWorker(pre + '@leofcoin/workers/block-worker.js', {
|
|
210
|
+
serialization: 'advanced',
|
|
211
|
+
type: 'module'
|
|
212
|
+
})
|
|
213
|
+
blocks = await _worker.once(message.blocks)
|
|
214
|
+
_worker = null
|
|
215
|
+
// blocks = unique(globalThis.blocks ? globalThis : [], blocks)
|
|
216
|
+
// for (let i = 0; i < blocks.length; i++) {
|
|
217
|
+
|
|
218
|
+
// }
|
|
219
|
+
for (const block of blocks) {
|
|
220
|
+
// we only revalidate the latest 24 blocks
|
|
221
|
+
// every 24 blocks a snapshot is taken and stored in state
|
|
222
|
+
// this means contracts will be restored from this state
|
|
223
|
+
// this also means devs NEED to make sure the state can be restored
|
|
224
|
+
// on contract deploy an error will be thrown if state wasn't recoverable
|
|
225
|
+
if (block.index > 24) {
|
|
226
|
+
const transactionCount = blocks[block.index - 1].transactions.length
|
|
227
|
+
latestTransactions.splice(-(transactionCount - 1), latestTransactions.length)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (!block.loaded && !fromState) {
|
|
231
|
+
const priority = block.transactions.filter((transaction) => transaction.priority)
|
|
232
|
+
if (priority.length > 0)
|
|
233
|
+
await Promise.all(
|
|
234
|
+
priority.sort((a, b) => a.nonce - b.nonce).map((transaction) => _executeTransaction(transaction))
|
|
235
|
+
)
|
|
236
|
+
|
|
187
237
|
await Promise.all(
|
|
188
|
-
|
|
238
|
+
block.transactions
|
|
239
|
+
.filter((transaction) => !transaction.priority)
|
|
240
|
+
.map(async (transaction) => _executeTransaction(transaction))
|
|
189
241
|
)
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
242
|
+
}
|
|
243
|
+
block.loaded = true
|
|
244
|
+
worker.postMessage({
|
|
245
|
+
type: 'debug',
|
|
246
|
+
message: `loaded transactions for block: ${block.blockInfo.hash} @${block.blockInfo.index} ${formatBytes(
|
|
247
|
+
block.blockInfo.size
|
|
248
|
+
)}`
|
|
249
|
+
})
|
|
196
250
|
}
|
|
197
|
-
block.loaded = true
|
|
198
|
-
worker.postMessage({
|
|
199
|
-
type: 'debug',
|
|
200
|
-
message: `loaded transactions for block: ${block.blockInfo.hash} @${block.blockInfo.index} ${formatBytes(
|
|
201
|
-
block.blockInfo.size
|
|
202
|
-
)}`
|
|
203
|
-
})
|
|
204
|
-
}
|
|
205
251
|
|
|
206
|
-
|
|
207
|
-
|
|
252
|
+
if (blocks.length > 0) {
|
|
253
|
+
lastBlock = blocks[blocks.length - 1]
|
|
254
|
+
}
|
|
255
|
+
globalThis.blocks = blocks
|
|
208
256
|
}
|
|
209
|
-
globalThis.blocks = blocks
|
|
210
257
|
}
|
|
211
258
|
|
|
212
259
|
worker.postMessage({ type: 'machine-ready', lastBlock })
|
|
@@ -216,6 +263,7 @@ _.init = async (message) => {
|
|
|
216
263
|
|
|
217
264
|
_.addLoadedBlock = (block) => {
|
|
218
265
|
blocks[block.index - 1] = block
|
|
266
|
+
lastBlock = blocks[blocks.length - 1]
|
|
219
267
|
return true
|
|
220
268
|
}
|
|
221
269
|
|
|
@@ -223,13 +271,17 @@ _.loadBlock = (block) => {
|
|
|
223
271
|
// todo validate here and deprecate addLoadedBlock
|
|
224
272
|
}
|
|
225
273
|
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
274
|
+
const askFor = (question, input) =>
|
|
275
|
+
new Promise((resolve) => {
|
|
276
|
+
const id = randomUUID()
|
|
277
|
+
pubsub.subscribe(id, resolve)
|
|
278
|
+
worker.postMessage({
|
|
279
|
+
type: 'ask',
|
|
280
|
+
question,
|
|
281
|
+
input,
|
|
282
|
+
id
|
|
283
|
+
})
|
|
231
284
|
})
|
|
232
|
-
}
|
|
233
285
|
|
|
234
286
|
const runTask = async (id, taskName, input) => {
|
|
235
287
|
try {
|
|
@@ -245,6 +297,10 @@ const runTask = async (id, taskName, input) => {
|
|
|
245
297
|
}
|
|
246
298
|
|
|
247
299
|
worker.onmessage(({ id, type, input }) => {
|
|
300
|
+
if (pubsub.hasSubscribers(id)) {
|
|
301
|
+
pubsub.publish(id, input)
|
|
302
|
+
return
|
|
303
|
+
}
|
|
248
304
|
switch (type) {
|
|
249
305
|
case 'init':
|
|
250
306
|
runTask(id, 'init', input)
|
|
@@ -286,7 +342,7 @@ worker.onmessage(({ id, type, input }) => {
|
|
|
286
342
|
respond(id, blocks[input - 1])
|
|
287
343
|
break
|
|
288
344
|
case 'lastBlock':
|
|
289
|
-
respond(id,
|
|
345
|
+
respond(id, lastBlock)
|
|
290
346
|
break
|
|
291
347
|
case 'latestTransactions':
|
|
292
348
|
respond(id, latestTransactions)
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "NodeNext",
|
|
4
|
+
"target": "ES2022",
|
|
5
|
+
"outDir": "./exports",
|
|
6
|
+
"moduleResolution": "NodeNext",
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"emitDeclarationOnly": true,
|
|
9
|
+
"declarationDir": "./exports",
|
|
10
|
+
"allowSyntheticDefaultImports": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"allowJs": true,
|
|
13
|
+
"useDefineForClassFields": false,
|
|
14
|
+
"types": ["node"]
|
|
15
|
+
},
|
|
16
|
+
"include": ["./src/**/*"],
|
|
17
|
+
"exclude": ["node_modules"]
|
|
18
|
+
}
|