@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 ADDED
@@ -0,0 +1,10 @@
1
+ # @leofcoin/workers
2
+
3
+ ## 1.4.13
4
+
5
+ ### Patch Changes
6
+
7
+ - c24054d: State it
8
+ - Updated dependencies [c24054d]
9
+ - @leofcoin/addresses@1.0.18
10
+ - @leofcoin/lib@1.2.38
package/package.json CHANGED
@@ -1,27 +1,29 @@
1
- {
2
- "name": "@leofcoin/workers",
3
- "version": "1.4.12",
4
- "description": "Workers used in @leofcoin/chain",
5
- "type": "module",
6
- "exports": {
7
- ".": "./src/workers.js",
8
- "./machine-worker": "./src/machine-worker.js",
9
- "./block-worker": "./src/block-worker.js",
10
- "./transaction-worker": "./src/transaction-worker.js",
11
- "./pool-worker": "./src/pool-worker.js"
12
- },
13
- "scripts": {
14
- "prettier": "prettier src --config ./../../.prettierrc --write",
15
- "test": "echo \"Error: no test specified\" && exit 1"
16
- },
17
- "keywords": [],
18
- "author": "",
19
- "license": "MIT",
20
- "dependencies": {
21
- "@leofcoin/lib": "^1.2.3",
22
- "@leofcoin/messages": "^1.2.0",
23
- "@leofcoin/storage": "^3.3.2",
24
- "@leofcoin/utils": "^1.1.5",
25
- "@vandeurenglenn/easy-worker": "^1.0.2"
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
+ }
@@ -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
- _.runContract = async ({ decoded, hash, encoded }) => {
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
- worker.postMessage({
61
- type: 'debug',
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 { contracts, peerid, fromState, states } = message
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
- if (message.blocks?.length > 0) {
152
- let pre
153
-
154
- try {
155
- const importee = await import('url')
156
- const url = importee.default
157
- if (url) pre = url.fileURLToPath(new URL('.', import.meta.url))
158
- } catch {
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
- if (!block.loaded && !fromState) {
185
- const priority = block.transactions.filter((transaction) => transaction.priority)
186
- if (priority.length > 0)
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
- priority.sort((a, b) => a.nonce - b.nonce).map((transaction) => _executeTransaction(transaction))
238
+ block.transactions
239
+ .filter((transaction) => !transaction.priority)
240
+ .map(async (transaction) => _executeTransaction(transaction))
189
241
  )
190
-
191
- await Promise.all(
192
- block.transactions
193
- .filter((transaction) => !transaction.priority)
194
- .map(async (transaction) => _executeTransaction(transaction))
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
- if (blocks.length > 0) {
207
- lastBlock = blocks[blocks.length - 1]
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 respond = (id, value) => {
227
- worker.postMessage({
228
- type: 'response',
229
- value,
230
- id
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, blocks[blocks.length - 1] || lastBlock)
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
+ }