@leofcoin/workers 1.4.7 → 1.4.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leofcoin/workers",
3
- "version": "1.4.7",
3
+ "version": "1.4.8",
4
4
  "description": "Workers used in @leofcoin/chain",
5
5
  "type": "module",
6
6
  "exports": {
@@ -24,7 +24,7 @@ const run = async (blocks) => {
24
24
  console.log(`loaded block: ${hash} @${index} ${formatBytes(size)}`)
25
25
  // todo we don't want this, need shared state
26
26
  block.decoded.transactions = block.decoded.transactions.sort((a, b) => a.nonce - b.nonce)
27
- resolve({ ...block.decoded, blockInfo: { hash, size, index } })
27
+ resolve({ ...block.decoded, hash, blockInfo: { hash, size, index } })
28
28
  })
29
29
  )
30
30
  )
@@ -9,6 +9,9 @@ const contractFactoryMessage = bytecodes.contractFactory
9
9
  const nativeTokenMessage = bytecodes.nativeToken
10
10
  const nameServiceMessage = bytecodes.nameService
11
11
  const validatorsMessage = bytecodes.validators
12
+
13
+ const latestTransactions = []
14
+
12
15
  let nativeCalls = 0
13
16
  let nativeBurns = 0
14
17
  let nativeMints = 0
@@ -19,8 +22,13 @@ let totalBurnAmount = 0
19
22
  let totalMintAmount = 0
20
23
  let totalTransferAmount = 0
21
24
 
25
+ let blocks = []
26
+ let contracts = {}
27
+ const _ = {}
28
+
22
29
  globalThis.BigNumber = BigNumber
23
- globalThis.contracts = {}
30
+
31
+ let lastBlock = { index: 0, hash: '0x0', previousHash: '0x0' }
24
32
 
25
33
  const unique = (arr) =>
26
34
  arr.filter((el, pos, arr) => {
@@ -31,7 +39,7 @@ const has = (address) => {
31
39
  return contracts[address] ? true : false
32
40
  }
33
41
 
34
- const get = (contract, method, params) => {
42
+ const get = ({ contract, method, params }) => {
35
43
  let result
36
44
  if (params?.length > 0) {
37
45
  result = contracts[contract][method](...params)
@@ -41,7 +49,7 @@ const get = (contract, method, params) => {
41
49
  return result
42
50
  }
43
51
 
44
- const runContract = async ({ decoded, hash, encoded }) => {
52
+ _.runContract = async ({ decoded, hash, encoded }) => {
45
53
  const params = decoded.constructorParameters
46
54
  try {
47
55
  const func = new Function(new TextDecoder().decode(decoded.contract))
@@ -63,7 +71,7 @@ const runContract = async ({ decoded, hash, encoded }) => {
63
71
  }
64
72
  }
65
73
 
66
- const execute = async (contract, method, params) => {
74
+ _.execute = async ({ contract, method, params }) => {
67
75
  try {
68
76
  let result
69
77
  // don't execute the method on a proxy
@@ -88,26 +96,25 @@ const execute = async (contract, method, params) => {
88
96
  const createMessage = (sender = globalThis.peerid) => {
89
97
  return {
90
98
  sender,
91
- call: execute,
99
+ call: _.execute,
92
100
  staticCall: get
93
101
  }
94
102
  }
95
103
 
96
- const _init = async ({ contracts, blocks, peerid }) => {
104
+ _.init = async (message) => {
105
+ let { contracts, peerid } = message
97
106
  globalThis.peerid = peerid
98
107
  contracts = [contractFactoryMessage, nativeTokenMessage, nameServiceMessage, validatorsMessage]
99
108
 
100
109
  contracts = await Promise.all(
101
110
  contracts.map(async (contract) => {
102
111
  contract = await new ContractMessage(new Uint8Array(contract.split(',')))
103
- await runContract({ decoded: contract.decoded, encoded: contract.encoded, hash: await contract.hash() })
112
+ await _.runContract({ decoded: contract.decoded, encoded: contract.encoded, hash: await contract.hash() })
104
113
  return contract
105
114
  })
106
115
  )
107
116
 
108
- let lastBlock = { hash: '0x0' }
109
-
110
- if (blocks?.length > 0) {
117
+ if (message.blocks?.length > 0) {
111
118
  let pre
112
119
 
113
120
  try {
@@ -123,68 +130,65 @@ const _init = async ({ contracts, blocks, peerid }) => {
123
130
  serialization: 'advanced',
124
131
  type: 'module'
125
132
  })
126
- blocks = await _worker.once(blocks)
133
+ blocks = await _worker.once(message.blocks)
127
134
  _worker = null
128
135
  // blocks = unique(globalThis.blocks ? globalThis : [], blocks)
129
136
  // for (let i = 0; i < blocks.length; i++) {
130
137
 
131
138
  // }
132
139
  for (const block of blocks) {
133
- try {
134
- await Promise.all(
135
- block.transactions.map(async (transaction) => {
136
- if (!block.loaded) {
140
+ // we only revalidate the latest 24 blocks
141
+ // every 24 blocks a snapshot is taken and stored in state
142
+ // this means contracts will be restored from this state
143
+ // this also means devs NEED to make sure the state can be restored
144
+ // on contract deploy an error will be thrown if state wasn't recoverable
145
+ if (block.index > 24) {
146
+ const transactionCount = blocks[block.index - 1].transactions.length
147
+ latestTransactions.splice(-(transactionCount - 1), latestTransactions.length)
148
+ }
149
+ await Promise.all(
150
+ block.transactions.map(async (transaction) => {
151
+ if (!block.loaded) {
152
+ const hash = await new TransactionMessage(transaction).hash()
153
+ if (latestTransactions.includes(hash)) {
154
+ throw new Error(`double transaction found: ${hash} in block ${block.index}`)
155
+ } else {
156
+ latestTransactions.push(hash)
137
157
  const { from, to, method, params, nonce } = transaction
138
158
  globalThis.msg = createMessage(from)
139
159
 
140
- try {
141
- await execute(to, method, params)
142
- if (to === nativeToken) {
143
- nativeCalls += 1
144
- if (method === 'burn') nativeBurns += 1
145
- if (method === 'mint') nativeMints += 1
146
- if (method === 'transfer') nativeTransfers += 1
147
- }
148
- totalTransactions += 1
149
-
150
- worker.postMessage({
151
- type: 'transactionLoaded',
152
- result: {
153
- hash: await new TransactionMessage(transaction).hash(),
154
- from,
155
- nonce: String(nonce)
156
- }
157
- })
158
- } catch (error) {
159
- throw error
160
+ await _.execute({ contract: to, method, params })
161
+ if (to === nativeToken) {
162
+ nativeCalls += 1
163
+ if (method === 'burn') nativeBurns += 1
164
+ if (method === 'mint') nativeMints += 1
165
+ if (method === 'transfer') nativeTransfers += 1
160
166
  }
167
+ totalTransactions += 1
168
+
169
+ worker.postMessage({
170
+ type: 'transactionLoaded',
171
+ result: {
172
+ hash,
173
+ from,
174
+ nonce: String(nonce)
175
+ }
176
+ })
161
177
  }
162
- })
163
- )
164
- block.loaded = true
165
- worker.postMessage({
166
- type: 'debug',
167
- message: `loaded transactions for block: ${block.blockInfo.hash} @${block.blockInfo.index} ${formatBytes(
168
- block.blockInfo.size
169
- )}`
170
- })
171
- } catch (error) {
172
- worker.postMessage({
173
- type: 'error',
174
- message: error.message
178
+ }
175
179
  })
176
- }
180
+ )
181
+ block.loaded = true
182
+ worker.postMessage({
183
+ type: 'debug',
184
+ message: `loaded transactions for block: ${block.blockInfo.hash} @${block.blockInfo.index} ${formatBytes(
185
+ block.blockInfo.size
186
+ )}`
187
+ })
177
188
  }
178
189
 
179
190
  if (blocks.length > 0) {
180
191
  lastBlock = blocks[blocks.length - 1]
181
- // todo blocks already loaded as blockmessage so use it!
182
- lastBlock = await new BlockMessage(lastBlock)
183
-
184
- lastBlock = {
185
- ...lastBlock.decoded,
186
- hash: await lastBlock.hash()
187
- }
188
192
  }
189
193
  globalThis.blocks = blocks
190
194
  }
@@ -194,113 +198,94 @@ const _init = async ({ contracts, blocks, peerid }) => {
194
198
  // worker.postMessage({blocks});
195
199
  }
196
200
 
197
- const tasks = async (e) => {
198
- const id = e.id
199
- if (e.type === 'init') {
200
- try {
201
- await _init(e.input)
202
- } catch (e) {
203
- worker.postMessage({
204
- type: 'initError',
205
- message: e.message,
206
- id
207
- })
208
- }
209
- } else if (e.type === 'nativeCalls') {
210
- worker.postMessage({
211
- type: 'response',
212
- value: nativeCalls,
213
- id
214
- })
215
- } else if (e.type === 'nativeBurns') {
216
- worker.postMessage({
217
- type: 'response',
218
- value: nativeBurns,
219
- id
220
- })
221
- } else if (e.type === 'nativeMints') {
222
- worker.postMessage({
223
- type: 'response',
224
- value: nativeMints,
225
- id
226
- })
227
- } else if (e.type === 'nativeTransfers') {
228
- worker.postMessage({
229
- type: 'response',
230
- value: nativeTransfers,
231
- id
232
- })
233
- } else if (e.type === 'totalTransfers') {
201
+ _.addLoadedBlock = (block) => {
202
+ blocks[block.index - 1] = block
203
+ return true
204
+ }
205
+
206
+ _.loadBlock = (block) => {
207
+ // todo validate here and deprecate addLoadedBlock
208
+ }
209
+
210
+ const respond = (id, value) => {
211
+ worker.postMessage({
212
+ type: 'response',
213
+ value,
214
+ id
215
+ })
216
+ }
217
+
218
+ const runTask = async (id, taskName, input) => {
219
+ try {
220
+ const result = await _[taskName](input)
221
+ respond(id, result)
222
+ } catch (e) {
234
223
  worker.postMessage({
235
- type: 'response',
236
- value: totalTransfers,
224
+ type: `${taskName}Error`,
225
+ message: e.message,
237
226
  id
238
227
  })
239
228
  }
240
- if (e.type === 'has') {
241
- try {
242
- const value = await has(e.input.address)
243
- worker.postMessage({
244
- type: 'response',
245
- id,
246
- value
247
- })
248
- } catch (error) {
249
- worker.postMessage({
250
- type: 'hasError',
251
- message: error.message,
252
- id
253
- })
254
- }
255
- }
256
- if (e.type === 'run') {
257
- try {
258
- const value = await runContract(e.input)
259
- worker.postMessage({
260
- type: 'response',
261
- id,
262
- value
263
- })
264
- } catch (e) {
265
- worker.postMessage({
266
- type: 'runError',
267
- message: e.message,
268
- id
269
- })
270
- }
271
- }
272
- if (e.type === 'get') {
273
- try {
274
- const value = await get(e.input.contract, e.input.method, e.input.params)
275
- worker.postMessage({
276
- type: 'response',
277
- id,
278
- value
279
- })
280
- } catch (e) {
281
- worker.postMessage({
282
- type: 'fetchError',
283
- message: e.message,
284
- id
285
- })
286
- }
287
- }
288
- if (e.type === 'execute') {
289
- try {
290
- const value = await execute(e.input.contract, e.input.method, e.input.params)
291
- worker.postMessage({
292
- type: 'response',
293
- id,
294
- value
295
- })
296
- } catch (e) {
297
- worker.postMessage({
298
- type: 'executionError',
299
- message: e.message,
300
- id
301
- })
302
- }
303
- }
304
229
  }
305
230
 
306
- worker.onmessage((data) => tasks(data))
231
+ worker.onmessage(({ id, type, input }) => {
232
+ switch (type) {
233
+ case 'init':
234
+ runTask(id, 'init', input)
235
+ break
236
+ case 'run':
237
+ runTask(id, 'runContract', input)
238
+ break
239
+ case 'execute':
240
+ runTask(id, 'execute', input)
241
+ break
242
+ case 'addLoadedBlock':
243
+ runTask(id, 'addLoadedBlock', input)
244
+ break
245
+ case 'nativeCalls':
246
+ respond(id, nativeCalls)
247
+ break
248
+ case 'contracts':
249
+ respond(id, contracts)
250
+ break
251
+ case 'nativeMints':
252
+ respond(id, nativeMints)
253
+ break
254
+ case 'nativeBurns':
255
+ respond(id, nativeBurns)
256
+ break
257
+ case 'nativeTransfers':
258
+ respond(id, nativeTransfers)
259
+ break
260
+ case 'totalTransfers':
261
+ respond(id, totalTransfers)
262
+ break
263
+ case 'totalBlocks':
264
+ respond(id, blocks.length)
265
+ break
266
+ case 'blocks':
267
+ respond(id, input ? blocks.slice(input.from, input.to) : blocks)
268
+ break
269
+ case 'block':
270
+ respond(id, blocks[input - 1])
271
+ break
272
+ case 'lastBlock':
273
+ respond(id, blocks[blocks.length - 1])
274
+ break
275
+ case 'latestTransactions':
276
+ respond(id, latestTransactions)
277
+ break
278
+ case 'totalTransactions':
279
+ respond(id, totalTransactions)
280
+ break
281
+ case 'has':
282
+ respond(id, has(input.address))
283
+ break
284
+ case 'get':
285
+ respond(id, get(input))
286
+ break
287
+ default:
288
+ console.log(`machine-worker: unsupported taskType: ${type}`)
289
+ break
290
+ }
291
+ })