@leofcoin/chain 1.9.18 → 1.9.20

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/exports/chain.js CHANGED
@@ -1,89 +1,64 @@
1
- import { createDebugger } from '@vandeurenglenn/debug'
2
- import { jsonStringifyBigInt, jsonParseBigInt, formatBytes, parseUnits, formatUnits } from '@leofcoin/utils'
3
- import {
4
- TransactionMessage,
5
- BlockMessage,
6
- ContractMessage,
7
- LastBlockMessage,
8
- PrevoteMessage,
9
- PrecommitMessage,
10
- ProposalMessage,
11
- BWMessage,
12
- StateMessage,
13
- BWRequestMessage
14
- } from '@leofcoin/messages'
15
- import addresses, { contractFactory } from '@leofcoin/addresses'
16
- import {
17
- calculateFee,
18
- createContractMessage,
19
- signTransaction,
20
- contractFactoryMessage,
21
- nativeTokenMessage,
22
- validatorsMessage,
23
- nameServiceMessage
24
- } from '@leofcoin/lib'
25
- import semver from 'semver'
26
- import { randombytes } from '@leofcoin/crypto'
27
- import EasyWorker from '@vandeurenglenn/easy-worker'
28
- import {
29
- ContractDeploymentError,
30
- ExecutionError,
31
- isResolveError,
32
- ResolveError,
33
- isExecutionError
34
- } from '@leofcoin/errors'
35
- import { P as PROTOCOL_VERSION, R as REACHED_ONE_ZERO_ZERO } from './constants-C83ZCYKa.js'
36
- import '@leofcoin/networks'
1
+ import { createDebugger } from '@vandeurenglenn/debug';
2
+ import { jsonStringifyBigInt, jsonParseBigInt, formatBytes, parseUnits, formatUnits } from '@leofcoin/utils';
3
+ import { TransactionMessage, BlockMessage, ContractMessage, LastBlockMessage, PrevoteMessage, PrecommitMessage, ProposalMessage, BWMessage, StateMessage, BWRequestMessage } from '@leofcoin/messages';
4
+ import addresses, { contractFactory } from '@leofcoin/addresses';
5
+ import { calculateFee, createContractMessage, signTransaction, contractFactoryMessage, nativeTokenMessage, validatorsMessage, nameServiceMessage } from '@leofcoin/lib';
6
+ import semver from 'semver';
7
+ import { randombytes } from '@leofcoin/crypto';
8
+ import EasyWorker from '@vandeurenglenn/easy-worker';
9
+ import { ContractDeploymentError, ExecutionError, isResolveError, ResolveError, isExecutionError } from '@leofcoin/errors';
10
+ import { P as PROTOCOL_VERSION, R as REACHED_ONE_ZERO_ZERO } from './constants-C83ZCYKa.js';
11
+ import '@leofcoin/networks';
37
12
 
38
- const limit = 1800
39
- const transactionLimit = 2500
40
- const requestTimeout = 3e4
41
- const syncTimeout = 3e4
13
+ const limit = 1800;
14
+ const transactionLimit = 2500;
15
+ const requestTimeout = 3e4;
16
+ const syncTimeout = 3e4;
42
17
  class Protocol {
43
18
  constructor(config) {
44
- this.resolveTimeout = 1e4
45
- if (config?.resolveTimeout) this.resolveTimeout = config.resolveTimeout
19
+ this.resolveTimeout = 1e4;
20
+ if (config?.resolveTimeout) this.resolveTimeout = config.resolveTimeout;
46
21
  }
47
22
  get limit() {
48
- return limit
23
+ return limit;
49
24
  }
50
25
  get transactionLimit() {
51
- return transactionLimit
26
+ return transactionLimit;
52
27
  }
53
28
  get requestTimeout() {
54
- return requestTimeout
29
+ return requestTimeout;
55
30
  }
56
31
  get syncTimeout() {
57
- return syncTimeout
32
+ return syncTimeout;
58
33
  }
59
34
  }
60
35
 
61
36
  class Transaction extends Protocol {
62
- #pendingNonces = /* @__PURE__ */ new Map()
63
- #maxPendingNonce = /* @__PURE__ */ new Map()
37
+ #pendingNonces = /* @__PURE__ */ new Map();
38
+ #maxPendingNonce = /* @__PURE__ */ new Map();
64
39
  constructor(config) {
65
- super(config)
40
+ super(config);
66
41
  }
67
42
  addPendingNonce(address, nonce) {
68
43
  if (!this.#pendingNonces.has(address)) {
69
- this.#pendingNonces.set(address, /* @__PURE__ */ new Set())
44
+ this.#pendingNonces.set(address, /* @__PURE__ */ new Set());
70
45
  }
71
- this.#pendingNonces.get(address).add(nonce)
72
- const currentMax = this.#maxPendingNonce.get(address) ?? -1
46
+ this.#pendingNonces.get(address).add(nonce);
47
+ const currentMax = this.#maxPendingNonce.get(address) ?? -1;
73
48
  if (nonce > currentMax) {
74
- this.#maxPendingNonce.set(address, nonce)
49
+ this.#maxPendingNonce.set(address, nonce);
75
50
  }
76
51
  }
77
52
  removePendingNonce(address, nonce) {
78
53
  if (this.#pendingNonces.has(address)) {
79
- this.#pendingNonces.get(address).delete(nonce)
54
+ this.#pendingNonces.get(address).delete(nonce);
80
55
  }
81
56
  }
82
57
  getPendingNonces(address) {
83
- return this.#pendingNonces.get(address) || /* @__PURE__ */ new Set()
58
+ return this.#pendingNonces.get(address) || /* @__PURE__ */ new Set();
84
59
  }
85
60
  getMaxPendingNonce(address) {
86
- return this.#maxPendingNonce.get(address) ?? -1
61
+ return this.#maxPendingNonce.get(address) ?? -1;
87
62
  }
88
63
  /**
89
64
  *
@@ -92,23 +67,23 @@ class Transaction extends Protocol {
92
67
  */
93
68
  async getTransactions(transactions) {
94
69
  return new Promise(async (resolve, reject) => {
95
- let size = 0
96
- const _transactions = []
97
- const MAX_BLOCK_TX_BYTES = 786432
70
+ let size = 0;
71
+ const _transactions = [];
72
+ const MAX_BLOCK_TX_BYTES = 786432;
98
73
  await Promise.all(
99
74
  transactions.map(async (tx) => {
100
- tx = await new TransactionMessage(tx)
101
- const newSize = size + tx.encoded.length
75
+ tx = await new TransactionMessage(tx);
76
+ const newSize = size + tx.encoded.length;
102
77
  if (newSize <= MAX_BLOCK_TX_BYTES) {
103
- size = newSize
104
- _transactions.push({ ...tx.decoded, hash: await tx.hash() })
78
+ size = newSize;
79
+ _transactions.push({ ...tx.decoded, hash: await tx.hash() });
105
80
  } else {
106
- resolve(_transactions)
81
+ resolve(_transactions);
107
82
  }
108
83
  })
109
- )
110
- return resolve(_transactions)
111
- })
84
+ );
85
+ return resolve(_transactions);
86
+ });
112
87
  }
113
88
  /**
114
89
  *
@@ -116,8 +91,8 @@ class Transaction extends Protocol {
116
91
  * @returns {TransactionMessage}
117
92
  */
118
93
  async promiseTransactions(transactions) {
119
- transactions = await Promise.all(transactions.map((tx) => new TransactionMessage(tx.encoded || tx)))
120
- return transactions
94
+ transactions = await Promise.all(transactions.map((tx) => new TransactionMessage(tx.encoded || tx)));
95
+ return transactions;
121
96
  }
122
97
  /**
123
98
  *
@@ -127,13 +102,12 @@ class Transaction extends Protocol {
127
102
  async promiseTransactionsContent(transactions) {
128
103
  transactions = await Promise.all(
129
104
  transactions.map(
130
- (tx) =>
131
- new Promise(async (resolve, reject) => {
132
- resolve({ ...tx.decoded, hash: await tx.hash() })
133
- })
105
+ (tx) => new Promise(async (resolve, reject) => {
106
+ resolve({ ...tx.decoded, hash: await tx.hash() });
107
+ })
134
108
  )
135
- )
136
- return transactions
109
+ );
110
+ return transactions;
137
111
  }
138
112
  /**
139
113
  * When a nonce isn't found for an address fallback to just checking the transactionnPoolStore
@@ -141,32 +115,32 @@ class Transaction extends Protocol {
141
115
  * @returns {Number} nonce
142
116
  */
143
117
  async #getNonceFallback(address) {
144
- let transactions = await globalThis.transactionPoolStore.values()
145
- transactions = await this.promiseTransactions(transactions)
146
- transactions = transactions.filter((tx) => tx.decoded.from === address)
147
- transactions = await this.promiseTransactionsContent(transactions)
148
- if (this.lastBlock?.hash && transactions.length === 0 && this.lastBlock.hash !== '0x0') {
149
- let block
118
+ let transactions = await globalThis.transactionPoolStore.values();
119
+ transactions = await this.promiseTransactions(transactions);
120
+ transactions = transactions.filter((tx) => tx.decoded.from === address);
121
+ transactions = await this.promiseTransactionsContent(transactions);
122
+ if (this.lastBlock?.hash && transactions.length === 0 && this.lastBlock.hash !== "0x0") {
123
+ let block;
150
124
  try {
151
- block = await globalThis.peernet.get(this.lastBlock.hash, 'block')
125
+ block = await globalThis.peernet.get(this.lastBlock.hash, "block");
152
126
  } catch (error) {
153
- block = void 0
127
+ block = void 0;
154
128
  }
155
- if (block === void 0) return []
156
- block = await new BlockMessage(block)
157
- transactions = transactions.filter((tx) => tx.from === address)
158
- while (transactions.length === 0 && block.decoded.index !== 0 && block.decoded.previousHash !== '0x0') {
159
- block = await globalThis.blockStore.get(block.decoded.previousHash)
160
- block = await new BlockMessage(block)
161
- transactions = block.decoded.transactions.filter((tx) => tx.from === address)
129
+ if (block === void 0) return [];
130
+ block = await new BlockMessage(block);
131
+ transactions = transactions.filter((tx) => tx.from === address);
132
+ while (transactions.length === 0 && block.decoded.index !== 0 && block.decoded.previousHash !== "0x0") {
133
+ block = await globalThis.blockStore.get(block.decoded.previousHash);
134
+ block = await new BlockMessage(block);
135
+ transactions = block.decoded.transactions.filter((tx) => tx.from === address);
162
136
  }
163
137
  }
164
- if (transactions.length === 0) return 0
165
- let maxNonce = 0
138
+ if (transactions.length === 0) return 0;
139
+ let maxNonce = 0;
166
140
  for (const tx of transactions) {
167
- if (tx.nonce > maxNonce) maxNonce = tx.nonce
141
+ if (tx.nonce > maxNonce) maxNonce = tx.nonce;
168
142
  }
169
- return maxNonce
143
+ return maxNonce;
170
144
  }
171
145
  /**
172
146
  * Get amount of transactions by address
@@ -175,126 +149,126 @@ class Transaction extends Protocol {
175
149
  */
176
150
  async getNonce(address) {
177
151
  try {
178
- if (!(await globalThis.accountsStore.has(address))) {
179
- const nonce2 = await this.#getNonceFallback(address)
180
- await globalThis.accountsStore.put(address, new TextEncoder().encode(String(nonce2)))
152
+ if (!await globalThis.accountsStore.has(address)) {
153
+ const nonce2 = await this.#getNonceFallback(address);
154
+ await globalThis.accountsStore.put(address, new TextEncoder().encode(String(nonce2)));
181
155
  }
182
156
  } catch (error) {
183
- const nonce2 = await this.#getNonceFallback(address)
184
- await globalThis.accountsStore.put(address, new TextEncoder().encode(String(nonce2)))
157
+ const nonce2 = await this.#getNonceFallback(address);
158
+ await globalThis.accountsStore.put(address, new TextEncoder().encode(String(nonce2)));
185
159
  }
186
- let nonce = await globalThis.accountsStore.get(address)
187
- nonce = Number(new TextDecoder().decode(nonce))
188
- const maxPending = this.getMaxPendingNonce(address)
160
+ let nonce = await globalThis.accountsStore.get(address);
161
+ nonce = Number(new TextDecoder().decode(nonce));
162
+ const maxPending = this.getMaxPendingNonce(address);
189
163
  if (maxPending > nonce) {
190
- return maxPending
164
+ return maxPending;
191
165
  }
192
- return nonce
166
+ return nonce;
193
167
  }
194
168
  async validateNonce(address, nonce) {
195
- let committedNonce
169
+ let committedNonce;
196
170
  try {
197
171
  if (await globalThis.accountsStore.has(address)) {
198
- const raw = await globalThis.accountsStore.get(address)
199
- committedNonce = Number(new TextDecoder().decode(raw))
172
+ const raw = await globalThis.accountsStore.get(address);
173
+ committedNonce = Number(new TextDecoder().decode(raw));
200
174
  } else {
201
- committedNonce = await this.#getNonceFallback(address)
175
+ committedNonce = await this.#getNonceFallback(address);
202
176
  }
203
177
  } catch {
204
- committedNonce = 0
178
+ committedNonce = 0;
205
179
  }
206
- if (committedNonce >= nonce) throw new Error(`a transaction with the same nonce already exists`)
207
- const pendingNonces = this.getPendingNonces(address)
208
- if (pendingNonces.has(nonce)) throw new Error(`a transaction with the same nonce already exists`)
180
+ if (committedNonce >= nonce) throw new Error(`a transaction with the same nonce already exists`);
181
+ const pendingNonces = this.getPendingNonces(address);
182
+ if (pendingNonces.has(nonce)) throw new Error(`a transaction with the same nonce already exists`);
209
183
  }
210
184
  isTransactionMessage(message) {
211
- if (message instanceof TransactionMessage) return true
212
- return false
185
+ if (message instanceof TransactionMessage) return true;
186
+ return false;
213
187
  }
214
188
  async createTransactionMessage(transaction, signature) {
215
- return new TransactionMessage({ ...transaction, signature })
189
+ return new TransactionMessage({ ...transaction, signature });
216
190
  }
217
191
  async createTransaction(transaction) {
218
192
  return {
219
193
  ...transaction,
220
194
  timestamp: transaction.timestamp || Date.now(),
221
- nonce: transaction.nonce || (await this.getNonce(transaction.from)) + 1
222
- }
195
+ nonce: transaction.nonce || await this.getNonce(transaction.from) + 1
196
+ };
223
197
  }
224
198
  async sendTransaction(message) {
225
- if (!this.isTransactionMessage(message)) message = await new TransactionMessage(message)
226
- if (!message.decoded.signature) throw new Error(`transaction not signed`)
227
- if (message.decoded.nonce === void 0) throw new Error(`nonce required`)
228
- await this.validateNonce(message.decoded.from, message.decoded.nonce)
229
- const hash = await message.hash()
199
+ if (!this.isTransactionMessage(message)) message = await new TransactionMessage(message);
200
+ if (!message.decoded.signature) throw new Error(`transaction not signed`);
201
+ if (message.decoded.nonce === void 0) throw new Error(`nonce required`);
202
+ await this.validateNonce(message.decoded.from, message.decoded.nonce);
203
+ const hash = await message.hash();
230
204
  try {
231
- let data
205
+ let data;
232
206
  const wait = new Promise(async (resolve, reject) => {
233
207
  if (pubsub.hasSubscribers(`transaction.completed.${hash}`)) {
234
- const result = pubsub.getValue(`transaction.completed.${hash}`)
235
- if (result.status !== 'fulfilled') {
236
- await transactionPoolStore.delete(hash)
208
+ const result = pubsub.getValue(`transaction.completed.${hash}`);
209
+ if (result.status !== "fulfilled") {
210
+ await transactionPoolStore.delete(hash);
237
211
  }
238
- result.status === 'fulfilled' ? resolve(result.hash) : reject({ hash: result.hash, error: result.error })
212
+ result.status === "fulfilled" ? resolve(result.hash) : reject({ hash: result.hash, error: result.error });
239
213
  } else {
240
214
  const completed = async (result) => {
241
- if (result.status !== 'fulfilled') {
242
- await transactionPoolStore.delete(hash)
215
+ if (result.status !== "fulfilled") {
216
+ await transactionPoolStore.delete(hash);
243
217
  }
244
- result.status === 'fulfilled' ? resolve(result.hash) : reject({ hash: result.hash, error: result.error })
218
+ result.status === "fulfilled" ? resolve(result.hash) : reject({ hash: result.hash, error: result.error });
245
219
  setTimeout(async () => {
246
- pubsub.unsubscribe(`transaction.completed.${hash}`, completed)
247
- }, 1e4)
248
- }
249
- pubsub.subscribe(`transaction.completed.${hash}`, completed)
220
+ pubsub.unsubscribe(`transaction.completed.${hash}`, completed);
221
+ }, 1e4);
222
+ };
223
+ pubsub.subscribe(`transaction.completed.${hash}`, completed);
250
224
  }
251
- })
252
- await globalThis.transactionPoolStore.put(hash, message.encoded)
253
- this.addPendingNonce(message.decoded.from, message.decoded.nonce)
225
+ });
226
+ await globalThis.transactionPoolStore.put(hash, message.encoded);
227
+ this.addPendingNonce(message.decoded.from, message.decoded.nonce);
254
228
  try {
255
- peernet.publish('add-transaction', message.encoded)
229
+ peernet.publish("add-transaction", message.encoded);
256
230
  } catch (publishError) {
257
- console.warn('peernet publish failed: add-transaction', publishError?.message ?? publishError)
231
+ console.warn("peernet publish failed: add-transaction", publishError?.message ?? publishError);
258
232
  }
259
- const fee = await calculateFee(message.decoded)
260
- return { hash, data, fee, wait, message }
233
+ const fee = await calculateFee(message.decoded);
234
+ return { hash, data, fee, wait, message };
261
235
  } catch (error) {
262
- console.log('remo')
263
- await transactionPoolStore.delete(hash)
264
- this.removePendingNonce(message.decoded.from, message.decoded.nonce)
265
- throw error
236
+ console.log("remo");
237
+ await transactionPoolStore.delete(hash);
238
+ this.removePendingNonce(message.decoded.from, message.decoded.nonce);
239
+ throw error;
266
240
  }
267
241
  }
268
242
  }
269
243
 
270
244
  const isDerivedFrom = (derivedClass, baseClass) => {
271
- if (!derivedClass || !baseClass) return false
272
- let proto = Object.getPrototypeOf(derivedClass)
245
+ if (!derivedClass || !baseClass) return false;
246
+ let proto = Object.getPrototypeOf(derivedClass);
273
247
  while (proto) {
274
- if (proto === baseClass) return true
275
- proto = Object.getPrototypeOf(proto)
248
+ if (proto === baseClass) return true;
249
+ proto = Object.getPrototypeOf(proto);
276
250
  }
277
- return false
278
- }
251
+ return false;
252
+ };
279
253
  const parseContractInheritance = (contractCode) => {
280
- const classMatch = contractCode.match(/class\s+(\w+)(?:\s+extends\s+(\w+))?/)
254
+ const classMatch = contractCode.match(/class\s+(\w+)(?:\s+extends\s+(\w+))?/);
281
255
  if (!classMatch) {
282
- return { className: null, baseClass: null, hasInheritance: false }
256
+ return { className: null, baseClass: null, hasInheritance: false };
283
257
  }
284
258
  return {
285
259
  className: classMatch[1],
286
260
  baseClass: classMatch[2] || null,
287
261
  hasInheritance: !!classMatch[2]
288
- }
289
- }
262
+ };
263
+ };
290
264
 
291
265
  class ContractRegistry {
292
266
  constructor() {
293
- this.baseContracts = /* @__PURE__ */ new Map()
267
+ this.baseContracts = /* @__PURE__ */ new Map();
294
268
  // hash -> ContractMessage
295
- this.contractNames = /* @__PURE__ */ new Map()
269
+ this.contractNames = /* @__PURE__ */ new Map();
296
270
  // name -> hash
297
- this.contractDependencies = /* @__PURE__ */ new Map()
271
+ this.contractDependencies = /* @__PURE__ */ new Map();
298
272
  }
299
273
  /**
300
274
  * Register a base contract that can be reused
@@ -304,13 +278,13 @@ class ContractRegistry {
304
278
  * @returns The contract hash
305
279
  */
306
280
  async registerBaseContract(name, message) {
307
- const hash = await message.hash()
308
- this.baseContracts.set(hash, message)
309
- this.contractNames.set(name, hash)
281
+ const hash = await message.hash();
282
+ this.baseContracts.set(hash, message);
283
+ this.contractNames.set(name, hash);
310
284
  if (globalThis.contractStore) {
311
- await globalThis.contractStore.put(hash, message.encoded)
285
+ await globalThis.contractStore.put(hash, message.encoded);
312
286
  }
313
- return hash
287
+ return hash;
314
288
  }
315
289
  /**
316
290
  * Register a name for a contract hash in the nameService
@@ -320,10 +294,9 @@ class ContractRegistry {
320
294
  * @param signer The wallet to sign the transaction
321
295
  */
322
296
  async registerNameInNameService(name, hash, chain, signer) {
323
- ;({
297
+ ({
324
298
  from: await signer.address,
325
- to: addresses.nameService
326
- })
299
+ to: addresses.nameService});
327
300
  }
328
301
  /**
329
302
  * Get a base contract by name
@@ -332,11 +305,11 @@ class ContractRegistry {
332
305
  * @returns The contract message or undefined
333
306
  */
334
307
  getBaseContract(name) {
335
- const hash = this.contractNames.get(name)
308
+ const hash = this.contractNames.get(name);
336
309
  if (hash) {
337
- return this.baseContracts.get(hash)
310
+ return this.baseContracts.get(hash);
338
311
  }
339
- return void 0
312
+ return void 0;
340
313
  }
341
314
  /**
342
315
  * Get a base contract by hash
@@ -344,7 +317,7 @@ class ContractRegistry {
344
317
  * @returns The contract message or undefined
345
318
  */
346
319
  getBaseContractByHash(hash) {
347
- return this.baseContracts.get(hash)
320
+ return this.baseContracts.get(hash);
348
321
  }
349
322
  /**
350
323
  * Resolve a name to a hash (first local, then nameService)
@@ -352,7 +325,7 @@ class ContractRegistry {
352
325
  * @returns The contract hash or undefined
353
326
  */
354
327
  resolveNameToHash(name) {
355
- return this.contractNames.get(name)
328
+ return this.contractNames.get(name);
356
329
  }
357
330
  /**
358
331
  * Register contract dependencies (inheritance chain)
@@ -360,7 +333,7 @@ class ContractRegistry {
360
333
  * @param dependencies Array of base contract hashes this contract depends on
361
334
  */
362
335
  registerDependencies(contractHash, dependencies) {
363
- this.contractDependencies.set(contractHash, dependencies)
336
+ this.contractDependencies.set(contractHash, dependencies);
364
337
  }
365
338
  /**
366
339
  * Get all dependencies for a contract
@@ -368,7 +341,7 @@ class ContractRegistry {
368
341
  * @returns Array of dependency hashes
369
342
  */
370
343
  getDependencies(contractHash) {
371
- return this.contractDependencies.get(contractHash) || []
344
+ return this.contractDependencies.get(contractHash) || [];
372
345
  }
373
346
  /**
374
347
  * Check if all dependencies for a contract are available
@@ -376,27 +349,27 @@ class ContractRegistry {
376
349
  * @returns true if all dependencies are available
377
350
  */
378
351
  async areDependenciesAvailable(contractHash) {
379
- const dependencies = this.getDependencies(contractHash)
380
- if (dependencies.length === 0) return true
352
+ const dependencies = this.getDependencies(contractHash);
353
+ if (dependencies.length === 0) return true;
381
354
  for (const depHash of dependencies) {
382
355
  try {
383
356
  if (globalThis.contractStore) {
384
- await globalThis.contractStore.get(depHash)
357
+ await globalThis.contractStore.get(depHash);
385
358
  } else {
386
- return false
359
+ return false;
387
360
  }
388
361
  } catch {
389
- return false
362
+ return false;
390
363
  }
391
364
  }
392
- return true
365
+ return true;
393
366
  }
394
367
  /**
395
368
  * Get all registered contract hashes
396
369
  * @returns Array of contract hashes
397
370
  */
398
371
  getBaseContractHashes() {
399
- return Array.from(this.baseContracts.keys())
372
+ return Array.from(this.baseContracts.keys());
400
373
  }
401
374
  /**
402
375
  * Get hash for a registered name
@@ -404,7 +377,7 @@ class ContractRegistry {
404
377
  * @returns The hash or undefined
405
378
  */
406
379
  getHashForName(name) {
407
- return this.contractNames.get(name)
380
+ return this.contractNames.get(name);
408
381
  }
409
382
  /**
410
383
  * Analyze contract code and extract inheritance information
@@ -412,7 +385,7 @@ class ContractRegistry {
412
385
  * @returns Inheritance information
413
386
  */
414
387
  analyzeContract(contractCode) {
415
- return parseContractInheritance(contractCode)
388
+ return parseContractInheritance(contractCode);
416
389
  }
417
390
  /**
418
391
  * Build a complete contract by combining base contracts
@@ -421,35 +394,35 @@ class ContractRegistry {
421
394
  * @returns Combined contract code
422
395
  */
423
396
  async buildContract(contractCode, baseContractIdentifiers = []) {
424
- let combinedCode = ''
397
+ let combinedCode = "";
425
398
  for (const identifier of baseContractIdentifiers) {
426
- let baseContract = await this.getBaseContract(identifier)
399
+ let baseContract = await this.getBaseContract(identifier);
427
400
  if (!baseContract) {
428
- baseContract = this.getBaseContractByHash(identifier)
401
+ baseContract = this.getBaseContractByHash(identifier);
429
402
  }
430
403
  if (baseContract) {
431
- const decoded = baseContract.decoded
404
+ const decoded = baseContract.decoded;
432
405
  combinedCode += `// Base contract: ${identifier}
433
- `
434
- combinedCode += decoded.contract + '\n\n'
406
+ `;
407
+ combinedCode += decoded.contract + "\n\n";
435
408
  }
436
409
  }
437
- combinedCode += contractCode
438
- return combinedCode
410
+ combinedCode += contractCode;
411
+ return combinedCode;
439
412
  }
440
413
  /**
441
414
  * Clear all registered contracts
442
415
  */
443
416
  clear() {
444
- this.baseContracts.clear()
445
- this.contractDependencies.clear()
417
+ this.baseContracts.clear();
418
+ this.contractDependencies.clear();
446
419
  }
447
420
  /**
448
421
  * Get all registered base contract names
449
422
  * @returns Array of base contract names
450
423
  */
451
424
  getBaseContractNames() {
452
- return Array.from(this.contractNames.keys())
425
+ return Array.from(this.contractNames.keys());
453
426
  }
454
427
  /**
455
428
  * Get name for a hash if registered
@@ -458,16 +431,16 @@ class ContractRegistry {
458
431
  */
459
432
  getNameForHash(hash) {
460
433
  for (const [name, h] of this.contractNames.entries()) {
461
- if (h === hash) return name
434
+ if (h === hash) return name;
462
435
  }
463
- return void 0
436
+ return void 0;
464
437
  }
465
438
  }
466
- const contractRegistry = new ContractRegistry()
439
+ const contractRegistry = new ContractRegistry();
467
440
 
468
441
  class Contract extends Transaction {
469
442
  constructor(config) {
470
- super(config)
443
+ super(config);
471
444
  }
472
445
  /**
473
446
  *
@@ -477,7 +450,7 @@ class Contract extends Transaction {
477
450
  * @returns lib.createContractMessage
478
451
  */
479
452
  async createContractMessage(creator, contract, constructorParameters = []) {
480
- return createContractMessage(creator, contract, constructorParameters)
453
+ return createContractMessage(creator, contract, constructorParameters);
481
454
  }
482
455
  /**
483
456
  *
@@ -487,8 +460,8 @@ class Contract extends Transaction {
487
460
  * @returns {Address}
488
461
  */
489
462
  async createContractAddress(creator, contract, constructorParameters = []) {
490
- contract = await this.createContractMessage(creator, contract, constructorParameters)
491
- return contract.hash()
463
+ contract = await this.createContractMessage(creator, contract, constructorParameters);
464
+ return contract.hash();
492
465
  }
493
466
  /**
494
467
  *
@@ -497,8 +470,8 @@ class Contract extends Transaction {
497
470
  * @returns
498
471
  */
499
472
  async deployContract(signer, contract, constructorParameters = []) {
500
- const message = await createContractMessage(await signer.address, contract, constructorParameters)
501
- return this.deployContractMessage(signer, message)
473
+ const message = await createContractMessage(await signer.address, contract, constructorParameters);
474
+ return this.deployContractMessage(signer, message);
502
475
  }
503
476
  /**
504
477
  * Register a base contract for reuse by other contracts
@@ -509,15 +482,15 @@ class Contract extends Transaction {
509
482
  * @returns {Promise<string>} The contract hash
510
483
  */
511
484
  async registerBaseContract(name, contract, constructorParameters = []) {
512
- const creator = addresses.contractFactory
513
- const message = await createContractMessage(creator, contract, [])
514
- const hash = await contractRegistry.registerBaseContract(name, message)
485
+ const creator = addresses.contractFactory;
486
+ const message = await createContractMessage(creator, contract, []);
487
+ const hash = await contractRegistry.registerBaseContract(name, message);
515
488
  try {
516
- await globalThis.contractStore.put(hash, message.encoded)
489
+ await globalThis.contractStore.put(hash, message.encoded);
517
490
  } catch (error) {
518
- throw error
491
+ throw error;
519
492
  }
520
- return hash
493
+ return hash;
521
494
  }
522
495
  /**
523
496
  * Deploy a contract with optional base contracts for inheritance
@@ -529,38 +502,38 @@ class Contract extends Transaction {
529
502
  */
530
503
  async deployDerivedContract(signer, contract, baseContractIdentifier, constructorParameters = []) {
531
504
  if (baseContractIdentifier) {
532
- const baseContract = contractRegistry.getBaseContract(baseContractIdentifier)
505
+ const baseContract = contractRegistry.getBaseContract(baseContractIdentifier);
533
506
  if (!baseContract) {
534
507
  throw new Error(
535
508
  `Base contract '${baseContractIdentifier}' not found. Register it first using registerBaseContract.`
536
- )
509
+ );
537
510
  }
538
511
  }
539
- const inheritanceInfo = parseContractInheritance(contract)
540
- const message = await createContractMessage(await signer.address, contract, constructorParameters)
512
+ const inheritanceInfo = parseContractInheritance(contract);
513
+ const message = await createContractMessage(await signer.address, contract, constructorParameters);
541
514
  if (inheritanceInfo.hasInheritance && inheritanceInfo.baseClass && baseContractIdentifier) {
542
- const baseHash = contractRegistry.getHashForName(inheritanceInfo.baseClass)
515
+ const baseHash = contractRegistry.getHashForName(inheritanceInfo.baseClass);
543
516
  if (baseHash) {
544
- const contractHash = await message.hash()
545
- contractRegistry.registerDependencies(contractHash, [baseHash])
517
+ const contractHash = await message.hash();
518
+ contractRegistry.registerDependencies(contractHash, [baseHash]);
546
519
  }
547
520
  }
548
- return this.deployContractMessage(signer, message)
521
+ return this.deployContractMessage(signer, message);
549
522
  }
550
523
  async deployContractMessage(signer, message) {
551
524
  try {
552
- await globalThis.contractStore.put(await message.hash(), message.encoded)
525
+ await globalThis.contractStore.put(await message.hash(), message.encoded);
553
526
  } catch (error) {
554
- throw error
527
+ throw error;
555
528
  }
556
529
  let transaction = {
557
530
  from: await signer.address,
558
531
  to: addresses.contractFactory,
559
- method: 'registerContract',
532
+ method: "registerContract",
560
533
  params: [await message.hash()]
561
- }
562
- transaction = await signTransaction(await this.createTransaction(transaction), signer)
563
- return this.sendTransaction(transaction)
534
+ };
535
+ transaction = await signTransaction(await this.createTransaction(transaction), signer);
536
+ return this.sendTransaction(transaction);
564
537
  }
565
538
  /**
566
539
  * Check if a class is derived from another class
@@ -569,7 +542,7 @@ class Contract extends Transaction {
569
542
  * @returns true if derivedClass extends baseClass
570
543
  */
571
544
  isDerivedFrom(derivedClass, baseClass) {
572
- return isDerivedFrom(derivedClass, baseClass)
545
+ return isDerivedFrom(derivedClass, baseClass);
573
546
  }
574
547
  /**
575
548
  * Parse contract code to extract inheritance information
@@ -577,25 +550,25 @@ class Contract extends Transaction {
577
550
  * @returns Inheritance information
578
551
  */
579
552
  parseContractInheritance(contractCode) {
580
- return parseContractInheritance(contractCode)
553
+ return parseContractInheritance(contractCode);
581
554
  }
582
555
  /**
583
556
  * Get the contract registry instance
584
557
  * @returns {ContractRegistry} The contract registry
585
558
  */
586
559
  getRegistry() {
587
- return contractRegistry
560
+ return contractRegistry;
588
561
  }
589
562
  }
590
563
 
591
- const debug$2 = createDebugger('leofcoin/machine')
564
+ const debug$2 = createDebugger("leofcoin/machine");
592
565
  class Machine {
593
566
  constructor(blocks) {
594
567
  this.states = {
595
568
  states: {},
596
569
  lastBlock: {
597
570
  index: -1,
598
- hash: ''
571
+ hash: ""
599
572
  },
600
573
  accounts: {},
601
574
  info: {
@@ -609,159 +582,156 @@ class Machine {
609
582
  totalTransactions: BigInt(0),
610
583
  totalBlocks: BigInt(0)
611
584
  }
612
- }
613
- this.wantList = []
585
+ };
586
+ this.wantList = [];
614
587
  this.ready = new Promise((resolve) => {
615
- this.readyResolve = resolve
616
- })
617
- this.init(blocks)
588
+ this.readyResolve = resolve;
589
+ });
590
+ this.init(blocks);
618
591
  }
619
592
  init(blocks) {
620
- return this.#init(blocks)
593
+ return this.#init(blocks);
621
594
  }
622
595
  async #onmessage(data) {
623
596
  switch (data.type) {
624
- case 'transactionLoaded': {
625
- const { from, nonce, hash } = data.result
626
- ;(await transactionPoolStore.has(hash)) && (await transactionPoolStore.delete(hash))
597
+ case "transactionLoaded": {
598
+ const { from, nonce, hash } = data.result;
599
+ await transactionPoolStore.has(hash) && await transactionPoolStore.delete(hash);
627
600
  try {
628
- const _nonce = await accountsStore.get(from)
629
- if (nonce > _nonce) await accountsStore.put(from, nonce)
601
+ const _nonce = await accountsStore.get(from);
602
+ if (nonce > _nonce) await accountsStore.put(from, nonce);
630
603
  } catch (error) {
631
- await accountsStore.put(from, nonce)
604
+ await accountsStore.put(from, nonce);
632
605
  }
633
- break
606
+ break;
634
607
  }
635
- case 'contractError': {
636
- console.warn(data.error)
637
- console.warn(`contract error: ${data.hash}`)
638
- await contractStore.delete(data.hash)
639
- break
608
+ case "contractError": {
609
+ console.warn(data.error);
610
+ console.warn(`contract error: ${data.hash}`);
611
+ await contractStore.delete(data.hash);
612
+ break;
640
613
  }
641
- case 'initError': {
642
- console.error(`init error: ${data.message}`)
643
- break
614
+ case "initError": {
615
+ console.error(`init error: ${data.message}`);
616
+ break;
644
617
  }
645
- case 'executeError': {
646
- pubsub.publish(data.id, { error: data.message })
647
- break
618
+ case "executeError": {
619
+ pubsub.publish(data.id, { error: data.message });
620
+ break;
648
621
  }
649
- case 'debug': {
650
- if (data.message.includes('loaded transactions for block:')) {
651
- pubsub.publish('block-loaded', data.message.replace('loaded transactions for block: ', '').split(' @')[0])
622
+ case "debug": {
623
+ if (data.message.includes("loaded transactions for block:")) {
624
+ pubsub.publish("block-loaded", data.message.replace("loaded transactions for block: ", "").split(" @")[0]);
652
625
  }
653
- break
626
+ break;
654
627
  }
655
- case 'error': {
656
- console.error(data.message)
657
- break
628
+ case "error": {
629
+ console.error(data.message);
630
+ break;
658
631
  }
659
- case 'machine-ready': {
660
- pubsub.publish('machine.ready', true)
661
- break
632
+ case "machine-ready": {
633
+ pubsub.publish("machine.ready", true);
634
+ break;
662
635
  }
663
- case 'response': {
664
- pubsub.publish(data.id, data.value || false)
665
- break
636
+ case "response": {
637
+ pubsub.publish(data.id, data.value || false);
638
+ break;
666
639
  }
667
- case 'addToWantList': {
668
- this.wantList.push(data.hash)
640
+ case "addToWantList": {
641
+ this.wantList.push(data.hash);
669
642
  }
670
- case 'ask': {
671
- if (data.question === 'contract' || data.question === 'transaction') {
643
+ case "ask": {
644
+ if (data.question === "contract" || data.question === "transaction") {
672
645
  try {
673
- const input = await peernet.get(data.input, data.question)
646
+ const input = await peernet.get(data.input, data.question);
674
647
  if (input === void 0) {
675
- this.worker.postMessage({ id: data.id, error: `could not get ${data.question} @${data.input}` })
676
- this.wantList.push(data.input)
648
+ this.worker.postMessage({ id: data.id, error: `could not get ${data.question} @${data.input}` });
649
+ this.wantList.push(data.input);
677
650
  } else {
678
- this.worker.postMessage({ id: data.id, input })
651
+ this.worker.postMessage({ id: data.id, input });
679
652
  }
680
653
  } catch (error) {
681
- console.error(error)
682
- this.worker.postMessage({ id: data.id, error: `could not get ${data.question} @${data.input}` })
683
- this.wantList.push(data.input)
654
+ console.error(error);
655
+ this.worker.postMessage({ id: data.id, error: `could not get ${data.question} @${data.input}` });
656
+ this.wantList.push(data.input);
684
657
  }
685
- } else if (data.question === 'peers') {
658
+ } else if (data.question === "peers") {
686
659
  this.worker.postMessage({
687
660
  id: data.id,
688
661
  input: peernet.connections ? Object.entries(peernet.connections).map(([id, peer]) => peer.toJSON()) : []
689
- })
662
+ });
690
663
  } else {
691
- this.worker.postMessage({ id: data.id, input: data.input })
664
+ this.worker.postMessage({ id: data.id, input: data.input });
692
665
  }
693
666
  }
694
667
  }
695
668
  }
696
669
  async updateState() {
697
670
  try {
698
- const lastBlock = await this.lastBlock
699
- const lastBlockIndex = Number(lastBlock.index)
700
- const statesLastBlockIndex = Number(this.states.lastBlock.index)
701
- if (
702
- lastBlockIndex > statesLastBlockIndex ||
703
- (lastBlock.hash !== this.states.lastBlock.hash && Number(lastBlockIndex) === 0)
704
- ) {
705
- const blocks = (await this.blocks).slice(statesLastBlockIndex)
706
- let transactions = []
671
+ const lastBlock = await this.lastBlock;
672
+ const lastBlockIndex = Number(lastBlock.index);
673
+ const statesLastBlockIndex = Number(this.states.lastBlock.index);
674
+ if (lastBlockIndex > statesLastBlockIndex || lastBlock.hash !== this.states.lastBlock.hash && Number(lastBlockIndex) === 0) {
675
+ const blocks = (await this.blocks).slice(statesLastBlockIndex);
676
+ let transactions = [];
707
677
  for (const block of blocks) {
708
- if (block?.transactions) transactions = [...transactions, ...block.transactions]
678
+ if (block?.transactions) transactions = [...transactions, ...block.transactions];
709
679
  }
710
680
  transactions = await Promise.all(
711
681
  transactions.map(async (transaction) => new TransactionMessage(await transactionStore.get(transaction)))
712
- )
682
+ );
713
683
  const contractsToGet = transactions.reduce((set, current) => {
714
- const contract = current.decoded.to
715
- if (!set.includes(contract)) set.push(contract)
716
- return set
717
- }, [])
718
- const state = {}
719
- if (!contractsToGet.includes(addresses.contractFactory)) contractsToGet.push(addresses.contractFactory)
720
- if (!contractsToGet.includes(addresses.nativeToken)) contractsToGet.push(addresses.nativeToken)
721
- if (!contractsToGet.includes(addresses.nameService)) contractsToGet.push(addresses.nameService)
722
- if (!contractsToGet.includes(addresses.validators)) contractsToGet.push(addresses.validators)
684
+ const contract = current.decoded.to;
685
+ if (!set.includes(contract)) set.push(contract);
686
+ return set;
687
+ }, []);
688
+ const state = {};
689
+ if (!contractsToGet.includes(addresses.contractFactory)) contractsToGet.push(addresses.contractFactory);
690
+ if (!contractsToGet.includes(addresses.nativeToken)) contractsToGet.push(addresses.nativeToken);
691
+ if (!contractsToGet.includes(addresses.nameService)) contractsToGet.push(addresses.nameService);
692
+ if (!contractsToGet.includes(addresses.validators)) contractsToGet.push(addresses.validators);
723
693
  await Promise.all(
724
694
  contractsToGet.map(async (contract) => {
725
- const value = await this.#askWorker('get', { contract, method: 'state', params: [] })
726
- state[contract] = value
695
+ const value = await this.#askWorker("get", { contract, method: "state", params: [] });
696
+ state[contract] = value;
727
697
  })
728
- )
729
- let accounts = {}
698
+ );
699
+ let accounts = {};
730
700
  try {
731
- const promises = []
701
+ const promises = [];
732
702
  for (const address of await accountsStore.keys()) {
733
703
  promises.push(async () => {
734
- accounts[address] = await accountsStore.get(address)
735
- })
704
+ accounts[address] = await accountsStore.get(address);
705
+ });
736
706
  }
737
- await Promise.all(promises)
707
+ await Promise.all(promises);
738
708
  } catch (error) {
739
- const promises = []
709
+ const promises = [];
740
710
  for (const transaction of transactions.reverse()) {
741
- const { from, to, amount, nonce } = transaction.decoded.data
711
+ const { from, to, amount, nonce } = transaction.decoded.data;
742
712
  if (!accounts[from]) {
743
- accounts[from] = nonce
713
+ accounts[from] = nonce;
744
714
  promises.push(async () => {
745
- await accountsStore.put(from, nonce)
746
- })
715
+ await accountsStore.put(from, nonce);
716
+ });
747
717
  }
748
718
  }
749
- await Promise.all(promises)
719
+ await Promise.all(promises);
750
720
  }
751
721
  const sortedStringify = (obj, replacer) => {
752
- const sorted = {}
753
- const keys = Object.keys(obj).sort()
722
+ const sorted = {};
723
+ const keys = Object.keys(obj).sort();
754
724
  for (const key of keys) {
755
- sorted[key] = obj[key]
725
+ sorted[key] = obj[key];
756
726
  }
757
- return JSON.stringify(sorted, replacer)
758
- }
727
+ return JSON.stringify(sorted, replacer);
728
+ };
759
729
  const tasks = [
760
- stateStore.put('lastBlock', sortedStringify(await this.lastBlock, jsonStringifyBigInt)),
761
- stateStore.put('states', sortedStringify(state, jsonStringifyBigInt)),
762
- stateStore.put('accounts', sortedStringify(accounts, jsonStringifyBigInt)),
730
+ stateStore.put("lastBlock", sortedStringify(await this.lastBlock, jsonStringifyBigInt)),
731
+ stateStore.put("states", sortedStringify(state, jsonStringifyBigInt)),
732
+ stateStore.put("accounts", sortedStringify(accounts, jsonStringifyBigInt)),
763
733
  stateStore.put(
764
- 'info',
734
+ "info",
765
735
  sortedStringify(
766
736
  {
767
737
  nativeBurnAmount: await this.totalBurnAmount,
@@ -779,53 +749,53 @@ class Machine {
779
749
  )
780
750
  )
781
751
  // accountsStore.clear()
782
- ]
783
- await Promise.all(tasks)
752
+ ];
753
+ await Promise.all(tasks);
784
754
  }
785
755
  } catch (error) {
786
- console.error(error)
756
+ console.error(error);
787
757
  }
788
758
  }
789
759
  async #init(blocks) {
790
760
  return new Promise(async (resolve) => {
791
761
  const machineReady = async () => {
792
- pubsub.unsubscribe('machine.ready', machineReady)
793
- await this.updateState()
794
- resolve(this)
795
- }
796
- pubsub.subscribe('machine.ready', machineReady)
797
- let pre
762
+ pubsub.unsubscribe("machine.ready", machineReady);
763
+ await this.updateState();
764
+ resolve(this);
765
+ };
766
+ pubsub.subscribe("machine.ready", machineReady);
767
+ let pre;
798
768
  try {
799
- const importee = await import('url')
800
- const url = importee.default
801
- if (url) pre = url.fileURLToPath(new URL('.', import.meta.url))
769
+ const importee = await import('url');
770
+ const url = importee.default;
771
+ if (url) pre = url.fileURLToPath(new URL(".", import.meta.url));
802
772
  } catch {
803
- pre = './'
804
- }
805
- this.worker = await new EasyWorker(pre + 'workers/machine-worker.js', {
806
- serialization: 'advanced',
807
- type: 'module'
808
- })
809
- this.worker.onmessage(this.#onmessage.bind(this))
810
- let rawLastBlock
811
- let rawStates
812
- let rawAccounts
813
- let rawInfo
814
- if (await stateStore.has('lastBlock')) {
815
- const decoder = new TextDecoder()
816
- const decode = (param) => decoder.decode(param)
817
- rawLastBlock = decode(await stateStore.get('lastBlock'))
818
- this.states.lastBlock = JSON.parse(rawLastBlock, jsonParseBigInt)
773
+ pre = "./";
774
+ }
775
+ this.worker = await new EasyWorker(pre + "workers/machine-worker.js", {
776
+ serialization: "advanced",
777
+ type: "module"
778
+ });
779
+ this.worker.onmessage(this.#onmessage.bind(this));
780
+ let rawLastBlock;
781
+ let rawStates;
782
+ let rawAccounts;
783
+ let rawInfo;
784
+ if (await stateStore.has("lastBlock")) {
785
+ const decoder = new TextDecoder();
786
+ const decode = (param) => decoder.decode(param);
787
+ rawLastBlock = decode(await stateStore.get("lastBlock"));
788
+ this.states.lastBlock = JSON.parse(rawLastBlock, jsonParseBigInt);
819
789
  try {
820
- rawStates = decode(await stateStore.get('states'))
821
- rawAccounts = decode(await stateStore.get('accounts'))
822
- rawInfo = decode(await stateStore.get('info'))
823
- this.states.states = JSON.parse(rawStates, jsonParseBigInt)
824
- this.states.accounts = JSON.parse(rawAccounts, jsonParseBigInt)
825
- this.states.info = JSON.parse(rawInfo, jsonParseBigInt)
790
+ rawStates = decode(await stateStore.get("states"));
791
+ rawAccounts = decode(await stateStore.get("accounts"));
792
+ rawInfo = decode(await stateStore.get("info"));
793
+ this.states.states = JSON.parse(rawStates, jsonParseBigInt);
794
+ this.states.accounts = JSON.parse(rawAccounts, jsonParseBigInt);
795
+ this.states.info = JSON.parse(rawInfo, jsonParseBigInt);
826
796
  } catch (error) {
827
- console.error(error)
828
- this.states.accounts = {}
797
+ console.error(error);
798
+ this.states.accounts = {};
829
799
  this.states.info = {
830
800
  nativeCalls: BigInt(0),
831
801
  nativeMints: BigInt(0),
@@ -836,13 +806,13 @@ class Machine {
836
806
  totalTransferAmount: BigInt(0),
837
807
  totalTransactions: BigInt(0),
838
808
  totalBlocks: BigInt(0)
839
- }
840
- rawInfo = JSON.stringify(this.states.info, jsonStringifyBigInt)
841
- await stateStore.put('info', new TextEncoder().encode(rawInfo))
809
+ };
810
+ rawInfo = JSON.stringify(this.states.info, jsonStringifyBigInt);
811
+ await stateStore.put("info", new TextEncoder().encode(rawInfo));
842
812
  }
843
813
  }
844
814
  const message = {
845
- type: 'init',
815
+ type: "init",
846
816
  input: {
847
817
  blocks,
848
818
  fromState: this.states.lastBlock?.index >= 0,
@@ -852,31 +822,31 @@ class Machine {
852
822
  // @ts-ignore
853
823
  peerid: peernet.peerId
854
824
  }
855
- }
856
- this.worker.postMessage(message)
857
- this.readyResolve(this)
858
- })
825
+ };
826
+ this.worker.postMessage(message);
827
+ this.readyResolve(this);
828
+ });
859
829
  }
860
830
  async #runContract(contractMessage) {
861
- const hash = await contractMessage.hash()
831
+ const hash = await contractMessage.hash();
862
832
  return new Promise((resolve, reject) => {
863
- const id = randombytes(20).toString('hex')
833
+ const id = randombytes(20).toString("hex");
864
834
  const onmessage = (message) => {
865
- pubsub.unsubscribe(id, onmessage)
866
- if (message?.error) reject(message.error)
867
- else resolve(message)
868
- }
869
- pubsub.subscribe(id, onmessage)
835
+ pubsub.unsubscribe(id, onmessage);
836
+ if (message?.error) reject(message.error);
837
+ else resolve(message);
838
+ };
839
+ pubsub.subscribe(id, onmessage);
870
840
  this.worker.postMessage({
871
- type: 'run',
841
+ type: "run",
872
842
  id,
873
843
  input: {
874
844
  decoded: contractMessage.decoded,
875
845
  encoded: contractMessage.encoded,
876
846
  hash
877
847
  }
878
- })
879
- })
848
+ });
849
+ });
880
850
  }
881
851
  /**
882
852
  *
@@ -887,40 +857,40 @@ class Machine {
887
857
  */
888
858
  async execute(contract, method, parameters) {
889
859
  try {
890
- if (contract === contractFactory && method === 'registerContract') {
891
- if (await this.has(parameters[0])) throw new Error(`duplicate contract @${parameters[0]}`)
892
- let message
893
- if (!(await globalThis.contractStore.has(parameters[0]))) {
894
- message = await peernet.get(parameters[0], 'contract')
895
- if (!message) throw new Error(`contract ${parameters[0]} not available`)
896
- message = await new ContractMessage(message)
897
- await globalThis.contractStore.put(await message.hash(), message.encoded)
860
+ if (contract === contractFactory && method === "registerContract") {
861
+ if (await this.has(parameters[0])) throw new Error(`duplicate contract @${parameters[0]}`);
862
+ let message;
863
+ if (!await globalThis.contractStore.has(parameters[0])) {
864
+ message = await peernet.get(parameters[0], "contract");
865
+ if (!message) throw new Error(`contract ${parameters[0]} not available`);
866
+ message = await new ContractMessage(message);
867
+ await globalThis.contractStore.put(await message.hash(), message.encoded);
898
868
  }
899
869
  if (!message) {
900
- message = await globalThis.contractStore.get(parameters[0])
901
- message = await new ContractMessage(message)
870
+ message = await globalThis.contractStore.get(parameters[0]);
871
+ message = await new ContractMessage(message);
902
872
  }
903
- if (!(await this.has(await message.hash()))) await this.#runContract(message)
873
+ if (!await this.has(await message.hash())) await this.#runContract(message);
904
874
  }
905
875
  } catch (error) {
906
876
  throw new ContractDeploymentError(`contract deployment failed for ${parameters[0]}
907
- ${error.message}`)
877
+ ${error.message}`);
908
878
  }
909
879
  return new Promise((resolve, reject) => {
910
- const id = randombytes(20).toString('hex')
880
+ const id = randombytes(20).toString("hex");
911
881
  const timeout = setTimeout(() => {
912
- pubsub.unsubscribe(id, onmessage)
913
- reject(new Error(`Machine.execute timeout for ${contract}.${method}`))
914
- }, 3e4)
882
+ pubsub.unsubscribe(id, onmessage);
883
+ reject(new Error(`Machine.execute timeout for ${contract}.${method}`));
884
+ }, 3e4);
915
885
  const onmessage = (message) => {
916
- clearTimeout(timeout)
917
- pubsub.unsubscribe(id, onmessage)
918
- if (message?.error) reject(new ExecutionError(message.error))
919
- else resolve(message)
920
- }
921
- pubsub.subscribe(id, onmessage)
886
+ clearTimeout(timeout);
887
+ pubsub.unsubscribe(id, onmessage);
888
+ if (message?.error) reject(new ExecutionError(message.error));
889
+ else resolve(message);
890
+ };
891
+ pubsub.subscribe(id, onmessage);
922
892
  this.worker.postMessage({
923
- type: 'execute',
893
+ type: "execute",
924
894
  id,
925
895
  input: {
926
896
  to: contract,
@@ -928,764 +898,753 @@ ${error.message}`)
928
898
  method,
929
899
  params: parameters
930
900
  }
931
- })
932
- })
901
+ });
902
+ });
933
903
  }
934
904
  get(contract, method, parameters) {
935
905
  return new Promise((resolve, reject) => {
936
- const id = randombytes(20).toString()
906
+ const id = randombytes(20).toString();
937
907
  const timeout = setTimeout(() => {
938
- pubsub.unsubscribe(id, onmessage)
939
- reject(new Error(`Machine.get timeout for ${contract}.${method}`))
940
- }, 3e4)
908
+ pubsub.unsubscribe(id, onmessage);
909
+ reject(new Error(`Machine.get timeout for ${contract}.${method}`));
910
+ }, 3e4);
941
911
  const onmessage = (message) => {
942
- clearTimeout(timeout)
943
- pubsub.unsubscribe(id, onmessage)
944
- resolve(message)
945
- }
946
- pubsub.subscribe(id, onmessage)
912
+ clearTimeout(timeout);
913
+ pubsub.unsubscribe(id, onmessage);
914
+ resolve(message);
915
+ };
916
+ pubsub.subscribe(id, onmessage);
947
917
  this.worker.postMessage({
948
- type: 'get',
918
+ type: "get",
949
919
  id,
950
920
  input: {
951
921
  contract,
952
922
  method,
953
923
  params: parameters
954
924
  }
955
- })
956
- })
925
+ });
926
+ });
957
927
  }
958
928
  async has(address) {
959
929
  return new Promise((resolve, reject) => {
960
- const id = randombytes(20).toString('hex')
930
+ const id = randombytes(20).toString("hex");
961
931
  const timeout = setTimeout(() => {
962
- pubsub.unsubscribe(id, onmessage)
963
- reject(new Error(`Machine.has timeout for ${address}`))
964
- }, 1e4)
932
+ pubsub.unsubscribe(id, onmessage);
933
+ reject(new Error(`Machine.has timeout for ${address}`));
934
+ }, 1e4);
965
935
  const onmessage = (message) => {
966
- clearTimeout(timeout)
967
- pubsub.unsubscribe(id, onmessage)
968
- if (message?.error) reject(message.error)
969
- else resolve(message)
970
- }
971
- pubsub.subscribe(id, onmessage)
936
+ clearTimeout(timeout);
937
+ pubsub.unsubscribe(id, onmessage);
938
+ if (message?.error) reject(message.error);
939
+ else resolve(message);
940
+ };
941
+ pubsub.subscribe(id, onmessage);
972
942
  this.worker.postMessage({
973
- type: 'has',
943
+ type: "has",
974
944
  id,
975
945
  input: {
976
946
  address
977
947
  }
978
- })
979
- })
948
+ });
949
+ });
980
950
  }
981
951
  #askWorker(type, input) {
982
952
  return new Promise((resolve, reject) => {
983
- const id = randombytes(20).toString('hex')
953
+ const id = randombytes(20).toString("hex");
984
954
  const timeout = setTimeout(() => {
985
- pubsub.unsubscribe(id, onmessage)
986
- reject(new Error(`Machine.#askWorker timeout for ${type}`))
987
- }, 3e4)
955
+ pubsub.unsubscribe(id, onmessage);
956
+ reject(new Error(`Machine.#askWorker timeout for ${type}`));
957
+ }, 3e4);
988
958
  const onmessage = (message) => {
989
- clearTimeout(timeout)
990
- pubsub.unsubscribe(id, onmessage)
991
- if (message?.error) reject(message.error)
992
- else resolve(message)
993
- }
994
- pubsub.subscribe(id, onmessage)
959
+ clearTimeout(timeout);
960
+ pubsub.unsubscribe(id, onmessage);
961
+ if (message?.error) reject(message.error);
962
+ else resolve(message);
963
+ };
964
+ pubsub.subscribe(id, onmessage);
995
965
  this.worker.postMessage({
996
966
  type,
997
967
  id,
998
968
  input
999
- })
1000
- })
969
+ });
970
+ });
1001
971
  }
1002
972
  get contracts() {
1003
- return this.#askWorker('contracts')
973
+ return this.#askWorker("contracts");
1004
974
  }
1005
975
  get totalContracts() {
1006
- return this.#askWorker('totalContracts')
976
+ return this.#askWorker("totalContracts");
1007
977
  }
1008
978
  get nativeCalls() {
1009
- return this.#askWorker('nativeCalls')
979
+ return this.#askWorker("nativeCalls");
1010
980
  }
1011
981
  get nativeMints() {
1012
- return this.#askWorker('nativeMints')
982
+ return this.#askWorker("nativeMints");
1013
983
  }
1014
984
  get nativeBurns() {
1015
- return this.#askWorker('nativeBurns')
985
+ return this.#askWorker("nativeBurns");
1016
986
  }
1017
987
  get nativeTransfers() {
1018
- return this.#askWorker('nativeTransfers')
988
+ return this.#askWorker("nativeTransfers");
1019
989
  }
1020
990
  get totalBurnAmount() {
1021
- return this.#askWorker('totalBurnAmount')
991
+ return this.#askWorker("totalBurnAmount");
1022
992
  }
1023
993
  get totalMintAmount() {
1024
- return this.#askWorker('totalMintAmount')
994
+ return this.#askWorker("totalMintAmount");
1025
995
  }
1026
996
  get totalTransferAmount() {
1027
- return this.#askWorker('totalTransferAmount')
997
+ return this.#askWorker("totalTransferAmount");
1028
998
  }
1029
999
  get totalTransactions() {
1030
- return this.#askWorker('totalTransactions')
1000
+ return this.#askWorker("totalTransactions");
1031
1001
  }
1032
1002
  get totalBlocks() {
1033
- return this.#askWorker('totalBlocks')
1003
+ return this.#askWorker("totalBlocks");
1034
1004
  }
1035
1005
  get blocks() {
1036
- return this.getBlocks()
1006
+ return this.getBlocks();
1037
1007
  }
1038
1008
  get lastBlock() {
1039
- return this.#askWorker('lastBlock').catch((error) => {
1040
- debug$2('lastBlock fallback after worker timeout:', error?.message ?? error)
1041
- return this.states.lastBlock
1042
- })
1009
+ return this.#askWorker("lastBlock").catch((error) => {
1010
+ debug$2("lastBlock fallback after worker timeout:", error?.message ?? error);
1011
+ return this.states.lastBlock;
1012
+ });
1043
1013
  }
1044
1014
  get lastBlockHeight() {
1045
- return this.#askWorker('lastBlockHeight').catch((error) => {
1046
- debug$2('lastBlockHeight fallback after worker timeout:', error?.message ?? error)
1047
- return Number(this.states.lastBlock?.index ?? 0)
1048
- })
1015
+ return this.#askWorker("lastBlockHeight").catch((error) => {
1016
+ debug$2("lastBlockHeight fallback after worker timeout:", error?.message ?? error);
1017
+ return Number(this.states.lastBlock?.index ?? 0);
1018
+ });
1049
1019
  }
1050
1020
  getBlocks(from, to) {
1051
- return this.#askWorker('blocks', { from, to })
1021
+ return this.#askWorker("blocks", { from, to });
1052
1022
  }
1053
1023
  getBlock(index) {
1054
- return this.#askWorker('block', index)
1024
+ return this.#askWorker("block", index);
1055
1025
  }
1056
1026
  async addLoadedBlock(block) {
1057
- debug$2(`adding loaded block: ${block.index}@${block.hash}`)
1058
- if (block.decoded) block = { ...block.decoded, hash: await block.hash() }
1059
- return this.#askWorker('addLoadedBlock', JSON.stringify(block, jsonStringifyBigInt))
1027
+ debug$2(`adding loaded block: ${block.index}@${block.hash}`);
1028
+ if (block.decoded) block = { ...block.decoded, hash: await block.hash() };
1029
+ return this.#askWorker("addLoadedBlock", JSON.stringify(block, jsonStringifyBigInt));
1060
1030
  }
1061
1031
  async latestTransactions() {
1062
- return this.#askWorker('latestTransactions')
1032
+ return this.#askWorker("latestTransactions");
1063
1033
  }
1064
1034
  async delete(hash) {
1065
- return globalThis.contractStore.delete(hash)
1035
+ return globalThis.contractStore.delete(hash);
1066
1036
  }
1067
1037
  /**
1068
1038
  *
1069
1039
  * @returns Promise
1070
1040
  */
1071
1041
  async deleteAll() {
1072
- let hashes = await globalThis.contractStore.keys()
1073
- hashes = Object.keys(hashes).map((hash) => this.delete(hash))
1074
- return Promise.all(hashes)
1042
+ let hashes = await globalThis.contractStore.keys();
1043
+ hashes = Object.keys(hashes).map((hash) => this.delete(hash));
1044
+ return Promise.all(hashes);
1075
1045
  }
1076
1046
  }
1077
1047
 
1078
1048
  class Jobber {
1079
1049
  constructor(timeout) {
1080
- this.busy = false
1081
- this.timeout = timeout
1050
+ this.busy = false;
1051
+ this.timeout = timeout;
1082
1052
  }
1083
1053
  add(fn) {
1084
- this.busy = true
1054
+ this.busy = true;
1085
1055
  return new Promise(async (resolve, reject) => {
1086
1056
  const timeout = setTimeout(() => {
1087
- reject('timeout')
1088
- }, this.timeout)
1057
+ reject("timeout");
1058
+ }, this.timeout);
1089
1059
  this.destroy = () => {
1090
- clearTimeout(timeout)
1091
- this.busy = false
1092
- resolve('stopped')
1093
- }
1060
+ clearTimeout(timeout);
1061
+ this.busy = false;
1062
+ resolve("stopped");
1063
+ };
1094
1064
  try {
1095
- const result = await fn()
1096
- clearTimeout(timeout)
1097
- this.busy = false
1098
- resolve(result)
1065
+ const result = await fn();
1066
+ clearTimeout(timeout);
1067
+ this.busy = false;
1068
+ resolve(result);
1099
1069
  } catch (error) {
1100
- clearTimeout(timeout)
1101
- reject(error)
1070
+ clearTimeout(timeout);
1071
+ reject(error);
1102
1072
  }
1103
- })
1073
+ });
1104
1074
  }
1105
1075
  }
1106
1076
 
1107
- const debug$1 = createDebugger('leofcoin/state')
1077
+ const debug$1 = createDebugger("leofcoin/state");
1108
1078
  class State extends Contract {
1109
1079
  constructor(config) {
1110
- super(config)
1111
- this.#lastResolvedTime = 0
1112
- this.#resolving = false
1113
- this.#resolveErrorCount = 0
1114
- this.#chainState = 'loading'
1115
- this.#syncErrorCount = 0
1116
- this.#blockHashMap = /* @__PURE__ */ new Map()
1117
- this.#chainSyncing = false
1118
- this.#blocks = []
1119
- this.knownBlocks = []
1120
- this.#totalSize = 0
1121
- this.#loaded = false
1122
- this.#resolvingHashes = /* @__PURE__ */ new Set()
1123
- this._wantList = []
1080
+ super(config);
1081
+ this.#lastResolvedTime = 0;
1082
+ this.#resolving = false;
1083
+ this.#resolveErrorCount = 0;
1084
+ this.#chainState = "loading";
1085
+ this.#syncErrorCount = 0;
1086
+ this.#blockHashMap = /* @__PURE__ */ new Map();
1087
+ this.#chainSyncing = false;
1088
+ this.#blocks = [];
1089
+ this.knownBlocks = [];
1090
+ this.#totalSize = 0;
1091
+ this.#loaded = false;
1092
+ this.#resolvingHashes = /* @__PURE__ */ new Set();
1093
+ this._wantList = [];
1124
1094
  this.#chainStateHandler = () => {
1125
- return new globalThis.peernet.protos['peernet-response']({
1095
+ return new globalThis.peernet.protos["peernet-response"]({
1126
1096
  response: this.#chainState
1127
- })
1128
- }
1097
+ });
1098
+ };
1129
1099
  this.#lastBlockHandler = async () => {
1130
- return new globalThis.peernet.protos['peernet-response']({
1100
+ return new globalThis.peernet.protos["peernet-response"]({
1131
1101
  response: new LastBlockMessage(await this.lastBlock).encoded
1132
- })
1133
- }
1102
+ });
1103
+ };
1134
1104
  this.#knownBlocksHandler = async () => {
1135
- return new globalThis.peernet.protos['peernet-response']({
1105
+ return new globalThis.peernet.protos["peernet-response"]({
1136
1106
  response: { blocks: await globalThis.blockStore.keys() }
1137
- })
1138
- }
1139
- this.#loadBlockTransactions = (transactions) =>
1140
- Promise.all(
1141
- transactions.map(async (transaction) => new TransactionMessage(await peernet.get(transaction, 'transaction')))
1142
- )
1107
+ });
1108
+ };
1109
+ this.#loadBlockTransactions = (transactions) => Promise.all(
1110
+ transactions.map(async (transaction) => new TransactionMessage(await peernet.get(transaction, "transaction")))
1111
+ );
1143
1112
  this.#getLastTransactions = async () => {
1144
- let lastTransactions = (
1145
- await Promise.all(
1146
- (
1147
- await this.blocks
1148
- )
1149
- .filter((block) => block.loaded)
1150
- .slice(-24)
1151
- .map((block) => this.#loadBlockTransactions(block.transactions))
1152
- )
1153
- ).reduce((all, transactions) => [...all, ...transactions], [])
1154
- return Promise.all(lastTransactions.map((transaction) => transaction.hash()))
1155
- }
1156
- }
1157
- #resolveErrored
1158
- #lastResolvedTime
1159
- #lastResolved
1160
- #resolving
1161
- #resolveErrorCount
1162
- #syncState
1163
- #chainState
1164
- #lastBlockInQue
1165
- #syncErrorCount
1166
- #blockHashMap
1167
- #chainSyncing
1168
- #blocks
1169
- #totalSize
1170
- #machine
1171
- #loaded
1172
- #resolvingHashes
1113
+ let lastTransactions = (await Promise.all(
1114
+ (await this.blocks).filter((block) => block.loaded).slice(-24).map((block) => this.#loadBlockTransactions(block.transactions))
1115
+ )).reduce((all, transactions) => [...all, ...transactions], []);
1116
+ return Promise.all(lastTransactions.map((transaction) => transaction.hash()));
1117
+ };
1118
+ }
1119
+ #resolveErrored;
1120
+ #lastResolvedTime;
1121
+ #lastResolved;
1122
+ #resolving;
1123
+ #resolveErrorCount;
1124
+ #syncState;
1125
+ #chainState;
1126
+ #lastBlockInQue;
1127
+ #syncErrorCount;
1128
+ #blockHashMap;
1129
+ #chainSyncing;
1130
+ #blocks;
1131
+ #totalSize;
1132
+ #machine;
1133
+ #loaded;
1134
+ #resolvingHashes;
1173
1135
  /**
1174
1136
  * contains transactions we need before we can successfully load
1175
1137
  */
1176
1138
  get wantList() {
1177
- return this.#machine?.wantList ?? this._wantList
1139
+ return this.#machine?.wantList ?? this._wantList;
1178
1140
  }
1179
1141
  get state() {
1180
1142
  return {
1181
1143
  sync: this.#syncState,
1182
1144
  chain: this.#chainState
1183
- }
1145
+ };
1184
1146
  }
1185
1147
  get blockHashMap() {
1186
- return this.#blockHashMap.entries()
1148
+ return this.#blockHashMap.entries();
1187
1149
  }
1188
1150
  get loaded() {
1189
- return this.#loaded
1151
+ return this.#loaded;
1190
1152
  }
1191
1153
  get resolving() {
1192
- return this.#resolving
1154
+ return this.#resolving;
1193
1155
  }
1194
1156
  get contracts() {
1195
- return this.#machine.contracts
1157
+ return this.#machine.contracts;
1196
1158
  }
1197
1159
  get totalContracts() {
1198
- return this.#machine.totalContracts
1160
+ return this.#machine.totalContracts;
1199
1161
  }
1200
1162
  get nativeCalls() {
1201
- return this.#machine.nativeCalls
1163
+ return this.#machine.nativeCalls;
1202
1164
  }
1203
1165
  get nativeMints() {
1204
- return this.#machine.nativeMints
1166
+ return this.#machine.nativeMints;
1205
1167
  }
1206
1168
  get nativeBurns() {
1207
- return this.#machine.nativeBurns
1169
+ return this.#machine.nativeBurns;
1208
1170
  }
1209
1171
  get nativeTransfers() {
1210
- return this.#machine.nativeTransfers
1172
+ return this.#machine.nativeTransfers;
1211
1173
  }
1212
1174
  get totalBurnAmouint() {
1213
- return this.#machine.totalBurnAmount
1175
+ return this.#machine.totalBurnAmount;
1214
1176
  }
1215
1177
  get totalMintAmount() {
1216
- return this.#machine.totalMintAmount
1178
+ return this.#machine.totalMintAmount;
1217
1179
  }
1218
1180
  get totalTransferAmount() {
1219
- return this.#machine.totalTransferAmount
1181
+ return this.#machine.totalTransferAmount;
1220
1182
  }
1221
1183
  get totalTransactions() {
1222
- return this.#machine.totalTransactions
1184
+ return this.#machine.totalTransactions;
1223
1185
  }
1224
1186
  get totalBlocks() {
1225
- return this.#machine.totalBlocks
1187
+ return this.#machine.totalBlocks;
1226
1188
  }
1227
1189
  get blocks() {
1228
- return this.getBlocks()
1190
+ return this.getBlocks();
1229
1191
  }
1230
1192
  get lastBlock() {
1231
- return this.#machine ? this.#machine.lastBlock : { index: 0, hash: '0x0', previousHash: '0x0' }
1193
+ return this.#machine ? this.#machine.lastBlock : { index: 0, hash: "0x0", previousHash: "0x0" };
1232
1194
  }
1233
1195
  get lastBlockHeight() {
1234
- return this.#machine ? this.#machine.lastBlockHeight : 0
1196
+ return this.#machine ? this.#machine.lastBlockHeight : 0;
1235
1197
  }
1236
1198
  getBlock(index) {
1237
- return this.#machine.getBlock(index)
1199
+ return this.#machine.getBlock(index);
1238
1200
  }
1239
1201
  getBlocks(from, to) {
1240
- return this.#machine.getBlocks(from, to)
1202
+ return this.#machine.getBlocks(from, to);
1241
1203
  }
1242
1204
  get totalSize() {
1243
- return this.#totalSize
1205
+ return this.#totalSize;
1244
1206
  }
1245
1207
  get machine() {
1246
- return this.#machine
1208
+ return this.#machine;
1247
1209
  }
1248
1210
  async clearPool() {
1249
- await globalThis.transactionPoolStore.clear()
1211
+ await globalThis.transactionPoolStore.clear();
1250
1212
  }
1251
1213
  /**
1252
1214
  * drastic measurement, removes everything!
1253
1215
  */
1254
1216
  async clearAll() {
1255
- await globalThis.accountsStore.clear()
1256
- await globalThis.chainStore.clear()
1257
- await globalThis.blockStore.clear()
1258
- await globalThis.transactionStore.clear()
1259
- await globalThis.stateStore.clear()
1260
- await globalThis.transactionPoolStore.clear()
1261
- }
1262
- #chainStateHandler
1263
- #lastBlockHandler
1264
- #knownBlocksHandler
1217
+ await globalThis.accountsStore.clear();
1218
+ await globalThis.chainStore.clear();
1219
+ await globalThis.blockStore.clear();
1220
+ await globalThis.transactionStore.clear();
1221
+ await globalThis.stateStore.clear();
1222
+ await globalThis.transactionPoolStore.clear();
1223
+ }
1224
+ #chainStateHandler;
1225
+ #lastBlockHandler;
1226
+ #knownBlocksHandler;
1265
1227
  async init() {
1266
- console.log('State init start')
1267
- this.jobber = new Jobber(this.resolveTimeout)
1268
- await globalThis.peernet.addRequestHandler('lastBlock', this.#lastBlockHandler)
1269
- await globalThis.peernet.addRequestHandler('knownBlocks', this.#knownBlocksHandler)
1270
- await globalThis.peernet.addRequestHandler('chainState', this.#chainStateHandler)
1271
- let localBlockHash
1272
- let blockMessage
1273
- let localBlock
1274
- console.log('State init before try-catch')
1228
+ console.log("State init start");
1229
+ this.jobber = new Jobber(this.resolveTimeout);
1230
+ await globalThis.peernet.addRequestHandler("lastBlock", this.#lastBlockHandler);
1231
+ await globalThis.peernet.addRequestHandler("knownBlocks", this.#knownBlocksHandler);
1232
+ await globalThis.peernet.addRequestHandler("chainState", this.#chainStateHandler);
1233
+ let localBlockHash;
1234
+ let blockMessage;
1235
+ let localBlock;
1236
+ console.log("State init before try-catch");
1275
1237
  try {
1276
- const rawBlock = await globalThis.chainStore.has('lastBlock')
1277
- console.log('State init after has lastBlock check')
1238
+ const rawBlock = await globalThis.chainStore.has("lastBlock");
1239
+ console.log("State init after has lastBlock check");
1278
1240
  if (rawBlock) {
1279
- console.log('State init after has lastBlock found')
1280
- console.log(rawBlock)
1281
- localBlockHash = new TextDecoder().decode(await globalThis.chainStore.get('lastBlock'))
1282
- console.log(localBlockHash)
1283
- if (localBlockHash !== '0x0') {
1284
- blockMessage = await globalThis.blockStore.get(localBlockHash)
1285
- console.log(blockMessage)
1286
- blockMessage = await new BlockMessage(blockMessage)
1287
- localBlock = { ...blockMessage.decoded, hash: localBlockHash }
1241
+ console.log("State init after has lastBlock found");
1242
+ console.log(rawBlock);
1243
+ localBlockHash = new TextDecoder().decode(await globalThis.chainStore.get("lastBlock"));
1244
+ console.log(localBlockHash);
1245
+ if (localBlockHash !== "0x0") {
1246
+ blockMessage = await globalThis.blockStore.get(localBlockHash);
1247
+ console.log(blockMessage);
1248
+ blockMessage = await new BlockMessage(blockMessage);
1249
+ localBlock = { ...blockMessage.decoded, hash: localBlockHash };
1288
1250
  }
1289
- console.log('State init after localBlock set')
1251
+ console.log("State init after localBlock set");
1290
1252
  } else {
1291
- localBlock = { index: 0, hash: '0x0', previousHash: '0x0' }
1253
+ localBlock = { index: 0, hash: "0x0", previousHash: "0x0" };
1292
1254
  }
1293
1255
  } catch {
1294
- console.log('e')
1295
- console.log('State init middle')
1296
- localBlock = { index: 0, hash: '0x0', previousHash: '0x0' }
1256
+ console.log("e");
1257
+ console.log("State init middle");
1258
+ localBlock = { index: 0, hash: "0x0", previousHash: "0x0" };
1297
1259
  }
1298
- console.log('State init middle')
1260
+ console.log("State init middle");
1299
1261
  try {
1300
- console.log('fetching known blocks from blockStore')
1301
- this.knownBlocks = await blockStore.keys()
1262
+ console.log("fetching known blocks from blockStore");
1263
+ this.knownBlocks = await blockStore.keys();
1302
1264
  } catch (error) {
1303
- console.log('no local known blocks found')
1265
+ console.log("no local known blocks found");
1304
1266
  }
1305
1267
  try {
1306
- if (localBlock?.hash && localBlock.hash !== '0x0') {
1268
+ if (localBlock?.hash && localBlock.hash !== "0x0") {
1307
1269
  try {
1308
- if (!(await globalThis.stateStore.has('lastBlock'))) {
1309
- await this.resolveBlocks()
1270
+ if (!await globalThis.stateStore.has("lastBlock")) {
1271
+ await this.resolveBlocks();
1310
1272
  }
1311
1273
  } catch {
1312
- await this.resolveBlocks()
1274
+ await this.resolveBlocks();
1313
1275
  }
1314
1276
  } else {
1315
- await this.resolveBlocks()
1277
+ await this.resolveBlocks();
1316
1278
  }
1317
- const machine = new Machine(this.#blocks)
1318
- console.log(machine)
1319
- await machine.ready
1320
- this.#machine = machine
1321
- const lastBlock = await this.#machine.lastBlock
1322
- if (lastBlock.hash !== '0x0') {
1323
- this.updateState(new BlockMessage(lastBlock))
1279
+ const machine = new Machine(this.#blocks);
1280
+ console.log(machine);
1281
+ await machine.ready;
1282
+ this.#machine = machine;
1283
+ const lastBlock = await this.#machine.lastBlock;
1284
+ if (lastBlock.hash !== "0x0") {
1285
+ this.updateState(new BlockMessage(lastBlock));
1324
1286
  }
1325
- this.#loaded = true
1287
+ this.#loaded = true;
1326
1288
  } catch (error) {
1327
- console.log('e')
1289
+ console.log("e");
1328
1290
  if (isResolveError(error)) {
1329
- console.error(error)
1291
+ console.error(error);
1330
1292
  }
1331
- console.log(error)
1293
+ console.log(error);
1332
1294
  }
1333
1295
  }
1334
1296
  async updateState(message) {
1335
1297
  try {
1336
- const hash = await message.hash()
1337
- await globalThis.chainStore.put('lastBlock', hash)
1338
- globalThis.pubsub.publish('lastBlock', message.encoded)
1298
+ const hash = await message.hash();
1299
+ await globalThis.chainStore.put("lastBlock", hash);
1300
+ globalThis.pubsub.publish("lastBlock", message.encoded);
1339
1301
  if (!this.#machine) {
1340
- const machine = new Machine(this.#blocks)
1341
- console.log(machine)
1342
- await machine.ready
1343
- this.#machine = machine
1302
+ const machine = new Machine(this.#blocks);
1303
+ console.log(machine);
1304
+ await machine.ready;
1305
+ this.#machine = machine;
1344
1306
  }
1345
- await this.#machine.updateState()
1307
+ await this.#machine.updateState();
1346
1308
  } catch (error) {
1347
- console.error(error)
1309
+ console.error(error);
1348
1310
  }
1349
1311
  }
1350
1312
  getLatestBlock() {
1351
- return this.#getLatestBlock()
1313
+ return this.#getLatestBlock();
1352
1314
  }
1353
1315
  async getAndPutBlock(hash) {
1354
- let block = await globalThis.peernet.get(hash, 'block')
1316
+ let block = await globalThis.peernet.get(hash, "block");
1355
1317
  if (block !== void 0) {
1356
1318
  if (!(block instanceof Uint8Array)) {
1357
- block = new Uint8Array(Object.values(block))
1319
+ block = new Uint8Array(Object.values(block));
1358
1320
  }
1359
- block = await new BlockMessage(block)
1360
- const { index } = block.decoded
1361
- if (this.#blocks[index] && this.#blocks[index].hash !== block.hash) throw `invalid block ${hash} @${index}`
1362
- if (!(await globalThis.peernet.has(hash))) await globalThis.peernet.put(hash, block.encoded, 'block')
1321
+ block = await new BlockMessage(block);
1322
+ const { index } = block.decoded;
1323
+ if (this.#blocks[index] && this.#blocks[index].hash !== block.hash) throw `invalid block ${hash} @${index}`;
1324
+ if (!await globalThis.peernet.has(hash)) await globalThis.peernet.put(hash, block.encoded, "block");
1363
1325
  }
1364
- return block
1326
+ return block;
1365
1327
  }
1366
1328
  async #resolveTransactions(transactions) {
1367
1329
  await Promise.all(
1368
- transactions
1369
- .filter((hash) => Boolean(hash))
1370
- .map(async (hash) => {
1371
- const exists = await transactionStore.has(hash)
1372
- if (!exists) {
1373
- const data = await peernet.get(hash, 'transaction')
1374
- if (!data) throw new Error(`missing transaction data for ${hash}`)
1375
- await transactionStore.put(hash, data)
1376
- }
1377
- const inPool = await transactionPoolStore.has(hash)
1378
- if (inPool) await transactionPoolStore.delete(hash)
1379
- })
1380
- )
1330
+ transactions.filter((hash) => Boolean(hash)).map(async (hash) => {
1331
+ const exists = await transactionStore.has(hash);
1332
+ if (!exists) {
1333
+ const data = await peernet.get(hash, "transaction");
1334
+ if (!data) throw new Error(`missing transaction data for ${hash}`);
1335
+ await transactionStore.put(hash, data);
1336
+ }
1337
+ const inPool = await transactionPoolStore.has(hash);
1338
+ if (inPool) await transactionPoolStore.delete(hash);
1339
+ })
1340
+ );
1381
1341
  }
1382
1342
  async #resolveBlock(hash) {
1383
- let index = this.#blockHashMap.get(hash)
1384
- let localHash = '0x0'
1343
+ let index = this.#blockHashMap.get(hash);
1344
+ let localHash = "0x0";
1385
1345
  try {
1386
- localHash = await globalThis.stateStore.get('lastBlock')
1346
+ localHash = await globalThis.stateStore.get("lastBlock");
1387
1347
  } catch (error) {
1388
- debug$1('no local state found')
1348
+ debug$1("no local state found");
1389
1349
  }
1390
1350
  if (this.#blocks[index]) {
1391
- const previousHash = this.#blocks[index].previousHash
1392
- if (previousHash === localHash) return
1393
- if (previousHash !== '0x0') {
1394
- return this.resolveBlock(previousHash)
1351
+ const previousHash = this.#blocks[index].previousHash;
1352
+ if (previousHash === localHash) return;
1353
+ if (previousHash !== "0x0") {
1354
+ return this.resolveBlock(previousHash);
1395
1355
  } else {
1396
- return
1356
+ return;
1397
1357
  }
1398
1358
  }
1399
1359
  try {
1400
- const block = await this.getAndPutBlock(hash)
1401
- const promises = []
1402
- if (block.decoded.previousHash !== '0x0' && block.decoded.previousHash !== localHash) {
1403
- promises.push(this.resolveBlock(block.decoded.previousHash))
1404
- }
1405
- promises.push(this.#resolveTransactions(block.decoded.transactions))
1406
- await Promise.all(promises)
1407
- index = block.decoded.index
1408
- const size = block.encoded.length > 0 ? block.encoded.length : block.encoded.byteLength
1409
- this.#totalSize += size
1410
- this.#blocks[index] = { hash, ...block.decoded }
1411
- this.#blockHashMap.set(hash, index)
1412
- debug$1(`resolved block: ${hash} @${index} ${formatBytes(size)}`)
1413
- globalThis.pubsub.publish('block-resolved', { hash, index })
1414
- this.#lastResolved = this.#blocks[index]
1415
- this.#lastResolvedTime = Date.now()
1360
+ const block = await this.getAndPutBlock(hash);
1361
+ const promises = [];
1362
+ if (block.decoded.previousHash !== "0x0" && block.decoded.previousHash !== localHash) {
1363
+ promises.push(this.resolveBlock(block.decoded.previousHash));
1364
+ }
1365
+ promises.push(this.#resolveTransactions(block.decoded.transactions));
1366
+ await Promise.all(promises);
1367
+ index = block.decoded.index;
1368
+ const size = block.encoded.length > 0 ? block.encoded.length : block.encoded.byteLength;
1369
+ this.#totalSize += size;
1370
+ this.#blocks[index] = { hash, ...block.decoded };
1371
+ this.#blockHashMap.set(hash, index);
1372
+ debug$1(`resolved block: ${hash} @${index} ${formatBytes(size)}`);
1373
+ globalThis.pubsub.publish("block-resolved", { hash, index });
1374
+ this.#lastResolved = this.#blocks[index];
1375
+ this.#lastResolvedTime = Date.now();
1416
1376
  } catch (error) {
1417
- throw new ResolveError(`block: ${hash}@${index}`, { cause: error })
1377
+ throw new ResolveError(`block: ${hash}@${index}`, { cause: error });
1418
1378
  }
1419
- return
1379
+ return;
1420
1380
  }
1421
1381
  async resolveBlock(hash) {
1422
- if (!hash) throw new Error(`expected hash, got: ${hash}`)
1423
- if (hash === '0x0') return
1424
- if (this.#resolvingHashes.has(hash)) return
1425
- this.#resolvingHashes.add(hash)
1426
- const isEntering = this.#resolvingHashes.size === 1
1427
- this.#resolving = true
1382
+ if (!hash) throw new Error(`expected hash, got: ${hash}`);
1383
+ if (hash === "0x0") return;
1384
+ if (this.#resolvingHashes.has(hash)) return;
1385
+ this.#resolvingHashes.add(hash);
1386
+ const isEntering = this.#resolvingHashes.size === 1;
1387
+ this.#resolving = true;
1428
1388
  try {
1429
1389
  if (isEntering) {
1430
- if (this.jobber.busy && this.jobber.destroy) await this.jobber.destroy()
1431
- await this.jobber.add(() => this.#resolveBlock(hash))
1390
+ if (this.jobber.busy && this.jobber.destroy) await this.jobber.destroy();
1391
+ await this.jobber.add(() => this.#resolveBlock(hash));
1432
1392
  } else {
1433
- await this.#resolveBlock(hash)
1393
+ await this.#resolveBlock(hash);
1434
1394
  }
1435
1395
  try {
1436
- const lastBlockHash = await globalThis.stateStore.get('lastBlock')
1396
+ const lastBlockHash = await globalThis.stateStore.get("lastBlock");
1437
1397
  if (lastBlockHash === hash) {
1438
- this.#resolveErrored = false
1439
- return
1398
+ this.#resolveErrored = false;
1399
+ return;
1440
1400
  }
1441
- } catch (error) {}
1401
+ } catch (error) {
1402
+ }
1442
1403
  } catch (error) {
1443
- console.log({ error })
1444
- this.#resolveErrorCount += 1
1404
+ console.log({ error });
1405
+ this.#resolveErrorCount += 1;
1445
1406
  if (this.#resolveErrorCount < 3) {
1446
- this.#resolvingHashes.delete(hash)
1447
- return this.resolveBlock(hash)
1407
+ this.#resolvingHashes.delete(hash);
1408
+ return this.resolveBlock(hash);
1448
1409
  }
1449
- this.#resolveErrorCount = 0
1450
- this.wantList.push(hash)
1451
- throw new ResolveError(`block: ${hash}`, { cause: error })
1410
+ this.#resolveErrorCount = 0;
1411
+ this.wantList.push(hash);
1412
+ throw new ResolveError(`block: ${hash}`, { cause: error });
1452
1413
  } finally {
1453
- this.#resolvingHashes.delete(hash)
1454
- if (this.#resolvingHashes.size === 0) this.#resolving = false
1414
+ this.#resolvingHashes.delete(hash);
1415
+ if (this.#resolvingHashes.size === 0) this.#resolving = false;
1455
1416
  }
1456
1417
  }
1457
1418
  async resolveBlocks() {
1458
1419
  if (this.#chainSyncing || this.#resolving) {
1459
- debug$1('Already syncing or resolving, skipping resolveBlocks()')
1460
- return
1420
+ debug$1("Already syncing or resolving, skipping resolveBlocks()");
1421
+ return;
1461
1422
  }
1462
1423
  try {
1463
1424
  if (this.jobber.busy && this.jobber.destroy) {
1464
- await this.jobber.destroy()
1425
+ await this.jobber.destroy();
1465
1426
  }
1466
1427
  } catch (error) {
1467
- console.error(error)
1428
+ console.error(error);
1468
1429
  }
1469
1430
  try {
1470
- const localBlock = await globalThis.chainStore.get('lastBlock')
1471
- const hash = new TextDecoder().decode(localBlock)
1472
- if (hash && hash !== '0x0') {
1473
- debug$1(`Resolving blocks from hash: ${hash}`)
1474
- await this.resolveBlock(hash)
1431
+ const localBlock = await globalThis.chainStore.get("lastBlock");
1432
+ const hash = new TextDecoder().decode(localBlock);
1433
+ if (hash && hash !== "0x0") {
1434
+ debug$1(`Resolving blocks from hash: ${hash}`);
1435
+ await this.resolveBlock(hash);
1475
1436
  }
1476
1437
  } catch (error) {
1477
- console.log(error)
1478
- this.#chainSyncing = false
1479
- this.#syncState = 'errored'
1480
- this.#resolveErrored = true
1481
- return this.restoreChain()
1438
+ console.log(error);
1439
+ this.#chainSyncing = false;
1440
+ this.#syncState = "errored";
1441
+ this.#resolveErrored = true;
1442
+ return this.restoreChain();
1482
1443
  }
1483
1444
  }
1484
1445
  async restoreChain() {
1485
1446
  try {
1486
- const { hash } = await this.#getLatestBlock()
1487
- await globalThis.chainStore.put('lastBlock', hash)
1488
- if (hash && hash !== '0x0') {
1489
- await this.resolveBlock(hash)
1447
+ const { hash } = await this.#getLatestBlock();
1448
+ await globalThis.chainStore.put("lastBlock", hash);
1449
+ if (hash && hash !== "0x0") {
1450
+ await this.resolveBlock(hash);
1490
1451
  }
1491
1452
  } catch (error) {
1492
- console.log(error)
1493
- this.#resolveErrored = true
1494
- this.#resolveErrorCount += 1
1495
- this.#resolving = false
1496
- return this.restoreChain()
1453
+ console.log(error);
1454
+ this.#resolveErrored = true;
1455
+ this.#resolveErrorCount += 1;
1456
+ this.#resolving = false;
1457
+ return this.restoreChain();
1497
1458
  }
1498
1459
  }
1499
1460
  async syncChain(lastBlock) {
1500
- console.log('check if can sync')
1501
- if (!this.shouldSync) return
1502
- console.log('starting sync')
1503
- this.#syncState = 'syncing'
1504
- this.#chainSyncing = true
1461
+ console.log("check if can sync");
1462
+ if (!this.shouldSync) return;
1463
+ console.log("starting sync");
1464
+ this.#syncState = "syncing";
1465
+ this.#chainSyncing = true;
1505
1466
  try {
1506
1467
  if (this.jobber.busy && this.jobber.destroy) {
1507
- await this.jobber.destroy()
1468
+ await this.jobber.destroy();
1508
1469
  }
1509
1470
  } catch (error) {
1510
- console.error(error)
1471
+ console.error(error);
1511
1472
  }
1512
- if (!lastBlock) lastBlock = await this.#getLatestBlock()
1513
- if (globalThis.peernet.peers.length === 0) return 'connectionless'
1473
+ if (!lastBlock) lastBlock = await this.#getLatestBlock();
1474
+ if (globalThis.peernet.peers.length === 0) return "connectionless";
1514
1475
  try {
1515
- await this.#syncChain(lastBlock)
1476
+ await this.#syncChain(lastBlock);
1516
1477
  } catch (error) {
1517
- this.#syncErrorCount += 1
1518
- if (this.#syncErrorCount < 3) return this.syncChain(lastBlock)
1519
- this.#syncErrorCount = 0
1520
- this.#chainSyncing = false
1521
- this.#syncState = 'errored'
1522
- return this.#syncState
1523
- }
1524
- if (lastBlock.index === this.#lastBlockInQue?.index) this.#lastBlockInQue = void 0
1525
- this.#syncErrorCount = 0
1526
- this.#chainSyncing = false
1527
- if (this.#lastBlockInQue) return this.syncChain(this.#lastBlockInQue)
1528
- this.#syncState = 'synced'
1529
- return this.#syncState
1478
+ this.#syncErrorCount += 1;
1479
+ if (this.#syncErrorCount < 3) return this.syncChain(lastBlock);
1480
+ this.#syncErrorCount = 0;
1481
+ this.#chainSyncing = false;
1482
+ this.#syncState = "errored";
1483
+ return this.#syncState;
1484
+ }
1485
+ if (lastBlock.index === this.#lastBlockInQue?.index) this.#lastBlockInQue = void 0;
1486
+ this.#syncErrorCount = 0;
1487
+ this.#chainSyncing = false;
1488
+ if (this.#lastBlockInQue) return this.syncChain(this.#lastBlockInQue);
1489
+ this.#syncState = "synced";
1490
+ return this.#syncState;
1530
1491
  }
1531
1492
  async #syncChain(lastBlock) {
1532
1493
  try {
1533
- const localBlock = await this.lastBlock
1534
- const localIndex = localBlock ? Number(localBlock.index) : -1
1535
- const remoteIndex = Number(lastBlock.index)
1536
- const remoteBlockHash = lastBlock.hash
1537
- let localStateHash = '0x0'
1494
+ const localBlock = await this.lastBlock;
1495
+ const localIndex = localBlock ? Number(localBlock.index) : -1;
1496
+ const remoteIndex = Number(lastBlock.index);
1497
+ const remoteBlockHash = lastBlock.hash;
1498
+ let localStateHash = "0x0";
1538
1499
  try {
1539
- localStateHash = new TextDecoder().decode(await globalThis.chainStore.get('lastBlock'))
1500
+ localStateHash = new TextDecoder().decode(await globalThis.chainStore.get("lastBlock"));
1540
1501
  } catch (error) {
1541
- debug$1(`No local state hash found: ${error}`)
1502
+ debug$1(`No local state hash found: ${error}`);
1542
1503
  }
1543
- debug$1(`Local block height: ${localIndex}, remote block height: ${remoteIndex}`)
1544
- debug$1(`Local state hash: ${localStateHash}, remote block hash: ${remoteBlockHash}`)
1545
- if (remoteBlockHash === '0x0') {
1546
- debug$1(`Remote block hash is 0x0, skipping sync`)
1547
- return
1504
+ debug$1(`Local block height: ${localIndex}, remote block height: ${remoteIndex}`);
1505
+ debug$1(`Local state hash: ${localStateHash}, remote block hash: ${remoteBlockHash}`);
1506
+ if (remoteBlockHash === "0x0") {
1507
+ debug$1(`Remote block hash is 0x0, skipping sync`);
1508
+ return;
1548
1509
  }
1549
1510
  if (localIndex > remoteIndex) {
1550
- debug$1(`Local index ${localIndex} is ahead of remote ${remoteIndex}, skipping sync`)
1551
- return
1511
+ debug$1(`Local index ${localIndex} is ahead of remote ${remoteIndex}, skipping sync`);
1512
+ return;
1552
1513
  }
1553
- const MAX_REORG_DEPTH = 6
1554
- const reorgDepth = localIndex - remoteIndex
1514
+ const MAX_REORG_DEPTH = 6;
1515
+ const reorgDepth = localIndex - remoteIndex;
1555
1516
  if (reorgDepth > 0 && reorgDepth > MAX_REORG_DEPTH) {
1556
1517
  console.warn(
1557
1518
  `[consensus-safety] Peer proposing reorg depth of ${reorgDepth} blocks (limit is ${MAX_REORG_DEPTH}). Rejecting to prevent DoS.`
1558
- )
1559
- throw new Error(`Excessive reorg depth: ${reorgDepth} blocks (max ${MAX_REORG_DEPTH})`)
1519
+ );
1520
+ throw new Error(`Excessive reorg depth: ${reorgDepth} blocks (max ${MAX_REORG_DEPTH})`);
1560
1521
  }
1561
1522
  if (localStateHash !== remoteBlockHash) {
1562
1523
  if (this.wantList.length > 0) {
1563
- debug$1(`Fetching ${this.wantList.length} blocks before resolving`)
1524
+ debug$1(`Fetching ${this.wantList.length} blocks before resolving`);
1564
1525
  const getBatch = async (batch) => {
1565
1526
  const blocks2 = await Promise.all(
1566
- batch.map((hash) =>
1567
- this.getAndPutBlock(hash).catch((e) => {
1568
- console.warn(`failed to fetch block ${hash}`, e)
1527
+ batch.map(
1528
+ (hash) => this.getAndPutBlock(hash).catch((e) => {
1529
+ console.warn(`failed to fetch block ${hash}`, e);
1569
1530
  })
1570
1531
  )
1571
- )
1572
- const transactions = blocks2
1573
- .filter((block) => Boolean(block))
1574
- .flatMap((block) => block.decoded.transactions)
1575
- return this.#resolveTransactions(transactions)
1576
- }
1532
+ );
1533
+ const transactions = blocks2.filter((block) => Boolean(block)).flatMap((block) => block.decoded.transactions);
1534
+ return this.#resolveTransactions(transactions);
1535
+ };
1577
1536
  for (let i = 0; i < this.wantList.length; i += 50) {
1578
- const batch = this.wantList.slice(i, i + 50)
1579
- await getBatch(batch)
1537
+ const batch = this.wantList.slice(i, i + 50);
1538
+ await getBatch(batch);
1580
1539
  }
1581
1540
  }
1582
- debug$1(`Resolving remote block: ${remoteBlockHash} @${remoteIndex} (differs from local state)`)
1583
- await this.resolveBlock(remoteBlockHash)
1584
- const blocksSynced = remoteIndex - localIndex
1585
- debug$1(`Resolved ${blocksSynced} new block(s)`)
1586
- const blocks = this.#blocks
1587
- debug$1(`Loading blocks from index ${localIndex + 1} to ${remoteIndex}`)
1588
- const start = localIndex + 1
1541
+ debug$1(`Resolving remote block: ${remoteBlockHash} @${remoteIndex} (differs from local state)`);
1542
+ await this.resolveBlock(remoteBlockHash);
1543
+ const blocksSynced = remoteIndex - localIndex;
1544
+ debug$1(`Resolved ${blocksSynced} new block(s)`);
1545
+ const blocks = this.#blocks;
1546
+ debug$1(`Loading blocks from index ${localIndex + 1} to ${remoteIndex}`);
1547
+ const start = localIndex + 1;
1589
1548
  if (this.#machine && blocks.length > start) {
1590
- await this.#loadBlocks(blocks.slice(start))
1549
+ await this.#loadBlocks(blocks.slice(start));
1591
1550
  }
1592
1551
  if (blocks.length > 0) {
1593
- await this.updateState(new BlockMessage(blocks[blocks.length - 1]))
1552
+ await this.updateState(new BlockMessage(blocks[blocks.length - 1]));
1594
1553
  }
1595
1554
  } else {
1596
- debug$1(`Block already in local state. Remote hash: ${remoteBlockHash} matches local state`)
1555
+ debug$1(`Block already in local state. Remote hash: ${remoteBlockHash} matches local state`);
1597
1556
  }
1598
1557
  } catch (error) {
1599
- console.log(error)
1600
- throw error
1558
+ console.log(error);
1559
+ throw error;
1601
1560
  }
1602
1561
  }
1603
1562
  async #getLatestBlock() {
1604
- let promises = []
1605
- const connectedPeers = Object.values(globalThis.peernet.connections || {}).filter((peer) => peer.connected)
1606
- let compatiblePeerCount = 0
1607
- let data = await new globalThis.peernet.protos['peernet-request']({
1608
- request: 'lastBlock'
1609
- })
1610
- let node = await globalThis.peernet.prepareMessage(data)
1563
+ let promises = [];
1564
+ const connectedPeers = Object.values(globalThis.peernet.connections || {}).filter((peer) => peer.connected);
1565
+ let compatiblePeerCount = 0;
1566
+ let data = await new globalThis.peernet.protos["peernet-request"]({
1567
+ request: "lastBlock"
1568
+ });
1569
+ let node = await globalThis.peernet.prepareMessage(data);
1611
1570
  for (const id in globalThis.peernet.connections) {
1612
- const peer = globalThis.peernet.connections[id]
1571
+ const peer = globalThis.peernet.connections[id];
1613
1572
  if (peer.connected && this.isVersionCompatible(peer.version)) {
1614
- compatiblePeerCount += 1
1573
+ compatiblePeerCount += 1;
1615
1574
  const task = async () => {
1616
1575
  try {
1617
- const result = await peer.request(node.encoded)
1618
- const resultType = result instanceof Uint8Array ? `bytes:${result.length}` : typeof result
1619
- debug$1(`lastBlock result type: ${resultType}`)
1620
- console.log({ result })
1621
- return { result: new LastBlockMessage(result), peer }
1576
+ const result = await peer.request(node.encoded);
1577
+ const resultType = result instanceof Uint8Array ? `bytes:${result.length}` : typeof result;
1578
+ debug$1(`lastBlock result type: ${resultType}`);
1579
+ console.log({ result });
1580
+ return { result: new LastBlockMessage(result), peer };
1622
1581
  } catch (error) {
1623
- const peerId = peer?.peerId || peer?.id || peer?.address || 'unknown'
1624
- debug$1(`lastBlock request failed: ${peerId}:`, error?.message ?? error)
1625
- throw error
1582
+ const peerId = peer?.peerId || peer?.id || peer?.address || "unknown";
1583
+ debug$1(`lastBlock request failed: ${peerId}:`, error?.message ?? error);
1584
+ throw error;
1626
1585
  }
1627
- }
1628
- promises.push(task())
1586
+ };
1587
+ promises.push(task());
1629
1588
  }
1630
1589
  }
1631
1590
  if (connectedPeers.length > 0 && compatiblePeerCount === 0) {
1632
1591
  throw new ResolveError(
1633
1592
  `latestBlock: no compatible peers found for local version ${this.version} among ${connectedPeers.length} connected peers`
1634
- )
1593
+ );
1635
1594
  }
1636
- console.log({ promises })
1637
- promises = await this.promiseRequests(promises)
1595
+ console.log({ promises });
1596
+ promises = await this.promiseRequests(promises);
1638
1597
  if (compatiblePeerCount > 0 && promises.length === 0) {
1639
- throw new ResolveError('latestBlock: no responses from compatible peers')
1640
- }
1641
- console.log({ promises })
1642
- let latest = { index: 0, hash: '0x0', previousHash: '0x0' }
1643
- promises = promises.sort((a, b) => b.index - a.index)
1644
- if (promises.length > 0) latest = promises[0].value
1645
- debug$1(`Latest block from peers: ${latest.hash} @${latest.index}`)
1646
- if (latest.hash && latest.hash !== '0x0') {
1647
- let message = await globalThis.peernet.get(latest.hash, 'block')
1648
- message = await new BlockMessage(message)
1649
- const hash = await message.hash()
1650
- if (hash !== latest.hash) throw new Error('invalid block @getLatestBlock')
1651
- latest = { ...message.decoded, hash }
1652
- const peer = promises[0].peer
1598
+ throw new ResolveError("latestBlock: no responses from compatible peers");
1599
+ }
1600
+ console.log({ promises });
1601
+ let latest = { index: 0, hash: "0x0", previousHash: "0x0" };
1602
+ promises = promises.sort((a, b) => b.index - a.index);
1603
+ if (promises.length > 0) latest = promises[0].value;
1604
+ debug$1(`Latest block from peers: ${latest.hash} @${latest.index}`);
1605
+ if (latest.hash && latest.hash !== "0x0") {
1606
+ let message = await globalThis.peernet.get(latest.hash, "block");
1607
+ message = await new BlockMessage(message);
1608
+ const hash = await message.hash();
1609
+ if (hash !== latest.hash) throw new Error("invalid block @getLatestBlock");
1610
+ latest = { ...message.decoded, hash };
1611
+ const peer = promises[0].peer;
1653
1612
  if (peer.connected && this.isVersionCompatible(peer.version)) {
1654
- let data2 = await new globalThis.peernet.protos['peernet-request']({
1655
- request: 'knownBlocks'
1656
- })
1657
- let node2 = await globalThis.peernet.prepareMessage(data2)
1613
+ let data2 = await new globalThis.peernet.protos["peernet-request"]({
1614
+ request: "knownBlocks"
1615
+ });
1616
+ let node2 = await globalThis.peernet.prepareMessage(data2);
1658
1617
  try {
1659
- let message2 = await peer.request(node2.encode())
1660
- message2 = await new globalThis.peernet.protos['peernet-response'](message2)
1661
- const MAX_WANTLIST_SIZE = 1e3
1662
- const incoming = message2.decoded.response.blocks.filter((block) => !this.knownBlocks.includes(block))
1663
- const remaining = MAX_WANTLIST_SIZE - this.wantList.length
1664
- if (remaining > 0) this.wantList.push(...incoming.slice(0, remaining))
1618
+ let message2 = await peer.request(node2.encode());
1619
+ message2 = await new globalThis.peernet.protos["peernet-response"](message2);
1620
+ const MAX_WANTLIST_SIZE = 1e3;
1621
+ const incoming = message2.decoded.response.blocks.filter((block) => !this.knownBlocks.includes(block));
1622
+ const remaining = MAX_WANTLIST_SIZE - this.wantList.length;
1623
+ if (remaining > 0) this.wantList.push(...incoming.slice(0, remaining));
1665
1624
  } catch (error) {
1666
- const peerId = peer?.peerId || peer?.id || peer?.address || 'unknown'
1667
- debug$1(`knownBlocks request failed: ${peerId}:`, error?.message ?? error)
1668
- throw error
1625
+ const peerId = peer?.peerId || peer?.id || peer?.address || "unknown";
1626
+ debug$1(`knownBlocks request failed: ${peerId}:`, error?.message ?? error);
1627
+ throw error;
1669
1628
  }
1670
1629
  }
1671
1630
  }
1672
- return latest
1631
+ return latest;
1673
1632
  }
1674
- #loadBlockTransactions
1675
- #getLastTransactions
1633
+ #loadBlockTransactions;
1634
+ #getLastTransactions;
1676
1635
  // todo throw error
1677
1636
  async #_executeTransaction(transaction) {
1678
1637
  try {
1679
- await this.#machine.execute(transaction.decoded.to, transaction.decoded.method, transaction.decoded.params)
1638
+ await this.#machine.execute(transaction.decoded.to, transaction.decoded.method, transaction.decoded.params);
1680
1639
  } catch (error) {
1681
- console.log(error)
1682
- await globalThis.transactionPoolStore.delete(await transaction.hash())
1683
- console.log('removing invalid transaction')
1640
+ console.log(error);
1641
+ await globalThis.transactionPoolStore.delete(await transaction.hash());
1642
+ console.log("removing invalid transaction");
1684
1643
  if (isExecutionError(error)) {
1685
- console.log(error)
1644
+ console.log(error);
1686
1645
  }
1687
- console.log(error)
1688
- return false
1646
+ console.log(error);
1647
+ return false;
1689
1648
  }
1690
1649
  }
1691
1650
  /**
@@ -1693,518 +1652,515 @@ class State extends Contract {
1693
1652
  * @param {Block[]} blocks
1694
1653
  */
1695
1654
  async #loadBlocks(blocks) {
1696
- this.#chainState = 'loading'
1697
- const poolTransactionKeys = new Set(await globalThis.transactionPoolStore.keys())
1698
- debug$1(`pool transactions: ${poolTransactionKeys.size}`)
1699
- debug$1(`loading ${blocks.length} blocks`)
1655
+ this.#chainState = "loading";
1656
+ const poolTransactionKeys = new Set(await globalThis.transactionPoolStore.keys());
1657
+ debug$1(`pool transactions: ${poolTransactionKeys.size}`);
1658
+ debug$1(`loading ${blocks.length} blocks`);
1700
1659
  for (const block of blocks) {
1701
1660
  if (block && !block.loaded) {
1702
1661
  try {
1703
- debug$1(`loading block: ${Number(block.index)} ${block.hash}`)
1704
- let transactions = await this.#loadBlockTransactions(block.transactions || [])
1705
- debug$1(`loading transactions: ${transactions.length} for block ${block.index}`)
1706
- let priority = []
1662
+ debug$1(`loading block: ${Number(block.index)} ${block.hash}`);
1663
+ let transactions = await this.#loadBlockTransactions(block.transactions || []);
1664
+ debug$1(`loading transactions: ${transactions.length} for block ${block.index}`);
1665
+ let priority = [];
1707
1666
  for (const transaction of transactions) {
1708
- const hash = await transaction.hash()
1709
- if (transaction.decoded.priority) priority.push(transaction)
1710
- if (poolTransactionKeys.has(hash)) await globalThis.transactionPoolStore.delete(hash)
1667
+ const hash = await transaction.hash();
1668
+ if (transaction.decoded.priority) priority.push(transaction);
1669
+ if (poolTransactionKeys.has(hash)) await globalThis.transactionPoolStore.delete(hash);
1711
1670
  }
1712
1671
  if (priority.length > 0) {
1713
- debug$1(`executing ${priority.length} priority transactions for block ${block.index}`)
1714
- priority = priority.sort((a, b) => a.nonce - b.nonce)
1672
+ debug$1(`executing ${priority.length} priority transactions for block ${block.index}`);
1673
+ priority = priority.sort((a, b) => a.nonce - b.nonce);
1715
1674
  for (const transaction of priority) {
1716
- await this.#_executeTransaction(transaction)
1675
+ await this.#_executeTransaction(transaction);
1717
1676
  }
1718
1677
  }
1719
- transactions = transactions.filter((transaction) => !transaction.decoded.priority)
1720
- debug$1(`executing ${transactions.length} transactions for block ${block.index}`)
1721
- await Promise.all(transactions.map((transaction) => this.#_executeTransaction(transaction)))
1722
- this.#blocks[block.index].loaded = true
1723
- debug$1(`executed transactions for block ${block.index}`)
1724
- if (Number(block.index) === 0) this.#loaded = true
1725
- await this.#machine.addLoadedBlock(block)
1726
- debug$1(`loaded block: ${block.hash} @${Number(block.index)}`)
1727
- globalThis.pubsub.publish('block-loaded', { ...block })
1678
+ transactions = transactions.filter((transaction) => !transaction.decoded.priority);
1679
+ debug$1(`executing ${transactions.length} transactions for block ${block.index}`);
1680
+ await Promise.all(transactions.map((transaction) => this.#_executeTransaction(transaction)));
1681
+ this.#blocks[block.index].loaded = true;
1682
+ debug$1(`executed transactions for block ${block.index}`);
1683
+ if (Number(block.index) === 0) this.#loaded = true;
1684
+ await this.#machine.addLoadedBlock(block);
1685
+ debug$1(`loaded block: ${block.hash} @${Number(block.index)}`);
1686
+ globalThis.pubsub.publish("block-loaded", { ...block });
1728
1687
  } catch (error) {
1729
- console.error(error)
1688
+ console.error(error);
1730
1689
  for (const transaction of block.transactions) {
1731
- this.wantList.push(transaction)
1690
+ this.wantList.push(transaction);
1732
1691
  }
1733
1692
  }
1734
1693
  }
1735
1694
  }
1736
- this.#chainState = 'loaded'
1737
- return true
1695
+ this.#chainState = "loaded";
1696
+ return true;
1738
1697
  }
1739
1698
  promiseRequests(promises) {
1740
1699
  return new Promise(async (resolve, reject) => {
1741
1700
  const timeout = setTimeout(() => {
1742
- resolve([{ index: 0, hash: '0x0' }])
1743
- debug$1('sync timed out')
1744
- }, this.requestTimeout)
1745
- console.log({ promises })
1746
- promises = await Promise.allSettled(promises)
1747
- console.log({ promises })
1748
- promises = promises.filter(({ status }) => status === 'fulfilled')
1749
- clearTimeout(timeout)
1701
+ resolve([{ index: 0, hash: "0x0" }]);
1702
+ debug$1("sync timed out");
1703
+ }, this.requestTimeout);
1704
+ console.log({ promises });
1705
+ promises = await Promise.allSettled(promises);
1706
+ console.log({ promises });
1707
+ promises = promises.filter(({ status }) => status === "fulfilled");
1708
+ clearTimeout(timeout);
1750
1709
  if (promises.length > 0) {
1751
1710
  promises = promises.map(async ({ value }) => {
1752
- const node = await new globalThis.peernet.protos['peernet-response'](value.result)
1753
- return { value: node.decoded.response, peer: value.peer }
1754
- })
1755
- promises = await Promise.all(promises)
1756
- resolve(promises)
1711
+ const node = await new globalThis.peernet.protos["peernet-response"](value.result);
1712
+ return { value: node.decoded.response, peer: value.peer };
1713
+ });
1714
+ promises = await Promise.all(promises);
1715
+ resolve(promises);
1757
1716
  } else {
1758
- resolve([])
1717
+ resolve([]);
1759
1718
  }
1760
- })
1719
+ });
1761
1720
  }
1762
1721
  get canSync() {
1763
- if (this.#chainSyncing) return false
1764
- return true
1722
+ if (this.#chainSyncing) return false;
1723
+ return true;
1765
1724
  }
1766
1725
  get shouldSync() {
1767
- if (this.#chainSyncing) return false
1726
+ if (this.#chainSyncing) return false;
1768
1727
  const compatiblePeers = Object.values(globalThis.peernet.connections || {}).filter(
1769
1728
  (peer) => peer.connected && this.isVersionCompatible(peer.version)
1770
- )
1729
+ );
1771
1730
  if (compatiblePeers.length === 0) {
1772
- debug$1('No compatible peers available for sync')
1773
- return false
1774
- }
1775
- if (
1776
- !this.#chainSyncing ||
1777
- this.#resolveErrored ||
1778
- this.#syncState === 'errored' ||
1779
- this.#syncState === 'connectionless' ||
1780
- this.#lastResolvedTime + this.resolveTimeout > Date.now()
1781
- )
1782
- return true
1783
- return false
1731
+ debug$1("No compatible peers available for sync");
1732
+ return false;
1733
+ }
1734
+ if (!this.#chainSyncing || this.#resolveErrored || this.#syncState === "errored" || this.#syncState === "connectionless" || this.#lastResolvedTime + this.resolveTimeout > Date.now())
1735
+ return true;
1736
+ return false;
1784
1737
  }
1785
1738
  async #waitForPeers(timeoutMs = 3e4) {
1786
1739
  return new Promise((resolve) => {
1787
1740
  const checkPeers = () => {
1788
1741
  const peers = Object.values(globalThis.peernet.connections || {}).filter(
1789
1742
  (peer) => peer.connected && this.isVersionCompatible(peer.version)
1790
- )
1743
+ );
1791
1744
  if (peers.length > 0) {
1792
- resolve(true)
1745
+ resolve(true);
1793
1746
  }
1794
- }
1795
- checkPeers()
1796
- const interval = setInterval(checkPeers, 1e3)
1747
+ };
1748
+ checkPeers();
1749
+ const interval = setInterval(checkPeers, 1e3);
1797
1750
  setTimeout(() => {
1798
- clearInterval(interval)
1799
- resolve(false)
1800
- }, timeoutMs)
1801
- })
1751
+ clearInterval(interval);
1752
+ resolve(false);
1753
+ }, timeoutMs);
1754
+ });
1802
1755
  }
1803
1756
  async triggerSync() {
1804
- const latest = await this.#getLatestBlock()
1805
- return this.syncChain(latest)
1757
+ const latest = await this.#getLatestBlock();
1758
+ return this.syncChain(latest);
1806
1759
  }
1807
1760
  async triggerLoad() {
1808
1761
  if (this.#blocks?.length > 0) {
1809
- const machine = new Machine(this.#blocks)
1810
- console.log(machine)
1811
- await machine.ready
1812
- this.#machine = machine
1762
+ const machine = new Machine(this.#blocks);
1763
+ console.log(machine);
1764
+ await machine.ready;
1765
+ this.#machine = machine;
1813
1766
  }
1814
1767
  }
1815
1768
  }
1816
1769
 
1817
1770
  class VersionControl extends State {
1818
1771
  constructor(config) {
1819
- super(config)
1772
+ super(config);
1820
1773
  }
1821
- #currentVersion = PROTOCOL_VERSION
1822
- #reachedOneZeroZero = REACHED_ONE_ZERO_ZERO
1774
+ #currentVersion = PROTOCOL_VERSION;
1775
+ #reachedOneZeroZero = REACHED_ONE_ZERO_ZERO;
1823
1776
  async #setCurrentVersion() {
1824
- this.version = this.#currentVersion
1825
- await globalThis.chainStore.put('version', this.version)
1777
+ this.version = this.#currentVersion;
1778
+ await globalThis.chainStore.put("version", this.version);
1826
1779
  }
1827
1780
  async init() {
1828
- super.init && (await super.init())
1781
+ super.init && await super.init();
1829
1782
  try {
1830
- const version = await globalThis.chainStore.get('version')
1831
- const storedVersion = new TextDecoder().decode(version)
1832
- console.log(storedVersion, this.#currentVersion)
1833
- this.version = this.#currentVersion
1834
- console.warn('the reachedZeroZero flag is set to false, this will clear all data on every start if above v1.0.0')
1835
- if (semver.compare(storedVersion, '1.0.0') === 1 && !this.#reachedOneZeroZero) {
1836
- console.warn('clearing all data because we are below v1.0.0')
1837
- await this.clearAll()
1783
+ const version = await globalThis.chainStore.get("version");
1784
+ const storedVersion = new TextDecoder().decode(version);
1785
+ console.log(storedVersion, this.#currentVersion);
1786
+ this.version = this.#currentVersion;
1787
+ console.warn("the reachedZeroZero flag is set to false, this will clear all data on every start if above v1.0.0");
1788
+ if (semver.compare(storedVersion, "1.0.0") === 1 && !this.#reachedOneZeroZero) {
1789
+ console.warn("clearing all data because we are below v1.0.0");
1790
+ await this.clearAll();
1838
1791
  }
1839
1792
  if (storedVersion !== this.#currentVersion) {
1840
- console.log(`Version mismatch: stored=${storedVersion}, current=${this.#currentVersion}. Updating...`)
1841
- await globalThis.chainStore.put('version', this.version)
1793
+ console.log(`Version mismatch: stored=${storedVersion}, current=${this.#currentVersion}. Updating...`);
1794
+ await globalThis.chainStore.put("version", this.version);
1842
1795
  }
1843
1796
  } catch (e) {
1844
- console.log(e)
1845
- return this.#setCurrentVersion()
1797
+ console.log(e);
1798
+ return this.#setCurrentVersion();
1846
1799
  }
1847
1800
  }
1848
1801
  isVersionCompatible(peerVersion) {
1849
- if (!peerVersion || !this.version) return false
1850
- const [peerMajor, peerMinor] = peerVersion.split('.')
1851
- const [localMajor, localMinor] = this.version.split('.')
1852
- return peerMajor === localMajor && peerMinor === localMinor
1802
+ if (!peerVersion || !this.version) return false;
1803
+ const [peerMajor, peerMinor] = peerVersion.split(".");
1804
+ const [localMajor, localMinor] = this.version.split(".");
1805
+ return peerMajor === localMajor && peerMinor === localMinor;
1853
1806
  }
1854
1807
  }
1855
1808
 
1856
1809
  class ConnectionMonitor {
1857
- #isMonitoring = false
1858
- #checkInterval = null
1859
- #reconnectDelay = 5e3
1860
- #reconnectTimer = null
1861
- #healthCheckInterval = 6e4
1862
- #version
1863
- #lastHealthCheckAt = 0
1864
- #reconnecting = false
1810
+ #isMonitoring = false;
1811
+ #checkInterval = null;
1812
+ #reconnectDelay = 5e3;
1813
+ #reconnectTimer = null;
1814
+ #healthCheckInterval = 6e4;
1815
+ #version;
1816
+ #lastHealthCheckAt = 0;
1817
+ #reconnecting = false;
1865
1818
  // event handlers to remove later
1866
- #onOnline = null
1867
- #onVisibilityChange = null
1868
- #onSigcont = null
1869
- #onPeerConnected = null
1819
+ #onOnline = null;
1820
+ #onVisibilityChange = null;
1821
+ #onSigcont = null;
1822
+ #onPeerConnected = null;
1870
1823
  get isMonitoring() {
1871
- return this.#isMonitoring
1824
+ return this.#isMonitoring;
1872
1825
  }
1873
1826
  get connectedPeers() {
1874
- return Object.values(globalThis.peernet?.connections || {}).filter((peer) => peer.connected)
1827
+ return Object.values(globalThis.peernet?.connections || {}).filter((peer) => peer.connected);
1875
1828
  }
1876
1829
  get compatiblePeers() {
1877
1830
  return this.connectedPeers.filter((peer) => {
1878
- if (!peer.version || !this.#version) return false
1879
- const [peerMajor, peerMinor] = peer.version.split('.')
1880
- const [localMajor, localMinor] = this.#version.split('.')
1881
- return peerMajor === localMajor && peerMinor === localMinor
1882
- })
1831
+ if (!peer.version || !this.#version) return false;
1832
+ const [peerMajor, peerMinor] = peer.version.split(".");
1833
+ const [localMajor, localMinor] = this.#version.split(".");
1834
+ return peerMajor === localMajor && peerMinor === localMinor;
1835
+ });
1883
1836
  }
1884
1837
  get disconnectedPeers() {
1885
- return Object.values(globalThis.peernet?.connections || {}).filter((peer) => !peer.connected)
1838
+ return Object.values(globalThis.peernet?.connections || {}).filter((peer) => !peer.connected);
1886
1839
  }
1887
1840
  start(version) {
1888
- this.#version = version
1889
- console.log(`\u{1F517} Connection Monitor initialized for version: ${this.#version}`)
1890
- if (this.#isMonitoring) return
1891
- this.#isMonitoring = true
1892
- console.log('\u{1F504} Starting connection monitor...')
1893
- if (typeof window !== 'undefined' && typeof document !== 'undefined') {
1841
+ this.#version = version;
1842
+ console.log(`\u{1F517} Connection Monitor initialized for version: ${this.#version}`);
1843
+ if (this.#isMonitoring) return;
1844
+ this.#isMonitoring = true;
1845
+ console.log("\u{1F504} Starting connection monitor...");
1846
+ if (typeof window !== "undefined" && typeof document !== "undefined") {
1894
1847
  this.#onOnline = () => {
1895
- console.log('\u{1F310} Network online \u2014 attempting restore')
1896
- void this.#restoreNetwork()
1897
- }
1898
- window.addEventListener('online', this.#onOnline)
1848
+ console.log("\u{1F310} Network online \u2014 attempting restore");
1849
+ void this.#restoreNetwork();
1850
+ };
1851
+ window.addEventListener("online", this.#onOnline);
1899
1852
  this.#onVisibilityChange = () => {
1900
- if (document.visibilityState === 'visible') {
1901
- console.log('\u{1F4A1} Visibility regained')
1853
+ if (document.visibilityState === "visible") {
1854
+ console.log("\u{1F4A1} Visibility regained");
1902
1855
  if (this.connectedPeers.length === 0) {
1903
- console.log('\u{1F4A1} Visibility regained \u2014 attempting restore')
1904
- void this.#restoreNetwork()
1856
+ console.log("\u{1F4A1} Visibility regained \u2014 attempting restore");
1857
+ void this.#restoreNetwork();
1905
1858
  }
1906
1859
  }
1907
- }
1908
- document.addEventListener('visibilitychange', this.#onVisibilityChange)
1860
+ };
1861
+ document.addEventListener("visibilitychange", this.#onVisibilityChange);
1909
1862
  }
1910
- if (typeof process !== 'undefined' && typeof process.on === 'function') {
1863
+ if (typeof process !== "undefined" && typeof process.on === "function") {
1911
1864
  this.#onSigcont = () => {
1912
- console.log('\u{1F514} Process resumed (SIGCONT) \u2014 attempting restore')
1913
- void this.#restoreNetwork()
1914
- }
1865
+ console.log("\u{1F514} Process resumed (SIGCONT) \u2014 attempting restore");
1866
+ void this.#restoreNetwork();
1867
+ };
1915
1868
  try {
1916
- process.on('SIGCONT', this.#onSigcont)
1917
- } catch (e) {}
1869
+ process.on("SIGCONT", this.#onSigcont);
1870
+ } catch (e) {
1871
+ }
1918
1872
  }
1919
- this.#lastHealthCheckAt = Date.now()
1873
+ this.#lastHealthCheckAt = Date.now();
1920
1874
  this.#checkInterval = setInterval(() => {
1921
- this.#healthCheck()
1922
- }, this.#healthCheckInterval)
1875
+ this.#healthCheck();
1876
+ }, this.#healthCheckInterval);
1923
1877
  this.#onPeerConnected = () => {
1924
1878
  if (this.#reconnectTimer) {
1925
- clearTimeout(this.#reconnectTimer)
1926
- this.#reconnectTimer = null
1879
+ clearTimeout(this.#reconnectTimer);
1880
+ this.#reconnectTimer = null;
1927
1881
  }
1928
- this.#reconnecting = false
1929
- this.#reconnectDelay = 5e3
1930
- }
1931
- globalThis.pubsub?.subscribe('peer:connected', this.#onPeerConnected)
1882
+ this.#reconnecting = false;
1883
+ this.#reconnectDelay = 5e3;
1884
+ };
1885
+ globalThis.pubsub?.subscribe("peer:connected", this.#onPeerConnected);
1932
1886
  }
1933
1887
  stop() {
1934
- if (!this.#isMonitoring) return
1935
- this.#isMonitoring = false
1888
+ if (!this.#isMonitoring) return;
1889
+ this.#isMonitoring = false;
1936
1890
  if (this.#checkInterval) {
1937
- clearInterval(this.#checkInterval)
1938
- this.#checkInterval = null
1891
+ clearInterval(this.#checkInterval);
1892
+ this.#checkInterval = null;
1939
1893
  }
1940
- if (typeof window !== 'undefined') {
1894
+ if (typeof window !== "undefined") {
1941
1895
  if (this.#onOnline) {
1942
- window.removeEventListener('online', this.#onOnline)
1943
- this.#onOnline = null
1896
+ window.removeEventListener("online", this.#onOnline);
1897
+ this.#onOnline = null;
1944
1898
  }
1945
1899
  if (this.#onVisibilityChange) {
1946
- document.removeEventListener('visibilitychange', this.#onVisibilityChange)
1947
- this.#onVisibilityChange = null
1900
+ document.removeEventListener("visibilitychange", this.#onVisibilityChange);
1901
+ this.#onVisibilityChange = null;
1948
1902
  }
1949
1903
  }
1950
- if (typeof process !== 'undefined' && typeof process.removeListener === 'function' && this.#onSigcont) {
1904
+ if (typeof process !== "undefined" && typeof process.removeListener === "function" && this.#onSigcont) {
1951
1905
  try {
1952
- process.removeListener('SIGCONT', this.#onSigcont)
1953
- } catch (e) {}
1954
- this.#onSigcont = null
1906
+ process.removeListener("SIGCONT", this.#onSigcont);
1907
+ } catch (e) {
1908
+ }
1909
+ this.#onSigcont = null;
1955
1910
  }
1956
1911
  if (this.#onPeerConnected) {
1957
- globalThis.pubsub?.unsubscribe('peer:connected', this.#onPeerConnected)
1958
- this.#onPeerConnected = null
1912
+ globalThis.pubsub?.unsubscribe("peer:connected", this.#onPeerConnected);
1913
+ this.#onPeerConnected = null;
1959
1914
  }
1960
1915
  if (this.#reconnectTimer) {
1961
- clearTimeout(this.#reconnectTimer)
1962
- this.#reconnectTimer = null
1916
+ clearTimeout(this.#reconnectTimer);
1917
+ this.#reconnectTimer = null;
1963
1918
  }
1964
- console.log('\u23F9\uFE0F Connection monitor stopped')
1919
+ console.log("\u23F9\uFE0F Connection monitor stopped");
1965
1920
  }
1966
1921
  async #healthCheck() {
1967
- const now = Date.now()
1968
- const expectedNext = this.#lastHealthCheckAt + this.#healthCheckInterval
1969
- const drift = now - expectedNext
1970
- this.#lastHealthCheckAt = now
1922
+ const now = Date.now();
1923
+ const expectedNext = this.#lastHealthCheckAt + this.#healthCheckInterval;
1924
+ const drift = now - expectedNext;
1925
+ this.#lastHealthCheckAt = now;
1971
1926
  if (drift > 5e3) {
1972
- console.log(`\u23F0 Detected timer drift of ${drift}ms (likely system sleep) \u2014 attempting restore`)
1973
- void this.#restoreNetwork()
1927
+ console.log(`\u23F0 Detected timer drift of ${drift}ms (likely system sleep) \u2014 attempting restore`);
1928
+ void this.#restoreNetwork();
1974
1929
  }
1975
- const connectedPeers = this.connectedPeers
1976
- const compatiblePeers = this.compatiblePeers
1977
- const disconnectedPeers = this.disconnectedPeers
1930
+ const connectedPeers = this.connectedPeers;
1931
+ const compatiblePeers = this.compatiblePeers;
1932
+ const disconnectedPeers = this.disconnectedPeers;
1978
1933
  console.log(
1979
1934
  `\u{1F50D} Health check: ${connectedPeers.length} connected, ${compatiblePeers.length} compatible, ${disconnectedPeers.length} negotiating`
1980
- )
1935
+ );
1981
1936
  if (connectedPeers.length === 0 && disconnectedPeers.length === 0) {
1982
- console.warn('\u26A0\uFE0F No peer connections detected \u2014 attempting reconnection')
1983
- await this.#attemptReconnection()
1937
+ console.warn("\u26A0\uFE0F No peer connections detected \u2014 attempting reconnection");
1938
+ await this.#attemptReconnection();
1984
1939
  } else if (compatiblePeers.length === 0 && connectedPeers.length > 0) {
1985
- console.warn('\u26A0\uFE0F No compatible peers found \u2014 attempting reconnection')
1986
- await this.#attemptReconnection()
1940
+ console.warn("\u26A0\uFE0F No compatible peers found \u2014 attempting reconnection");
1941
+ await this.#attemptReconnection();
1987
1942
  }
1988
- globalThis.pubsub?.publish('connection-status', {
1943
+ globalThis.pubsub?.publish("connection-status", {
1989
1944
  connected: connectedPeers.length,
1990
1945
  compatible: compatiblePeers.length,
1991
1946
  healthy: compatiblePeers.length > 0
1992
- })
1947
+ });
1993
1948
  }
1994
1949
  // lightweight TCP probe to detect internet connectivity in Node.js
1995
1950
  async #isOnLine(timeout = 1500) {
1996
1951
  if (navigator?.onLine !== void 0) {
1997
- return navigator.onLine
1952
+ return navigator.onLine;
1998
1953
  }
1999
1954
  return new Promise(async (resolve) => {
2000
1955
  try {
2001
- const net = await import('net')
2002
- const socket = new net.Socket()
2003
- let finished = false
1956
+ const net = await import('net');
1957
+ const socket = new net.Socket();
1958
+ let finished = false;
2004
1959
  const finish = (val) => {
2005
- if (finished) return
2006
- finished = true
1960
+ if (finished) return;
1961
+ finished = true;
2007
1962
  try {
2008
- socket.destroy()
2009
- } catch (e) {}
2010
- resolve(val)
2011
- }
2012
- socket.setTimeout(timeout)
2013
- socket.once('connect', () => finish(true))
2014
- socket.once('error', () => finish(false))
2015
- socket.once('timeout', () => finish(false))
2016
- socket.connect(53, '1.1.1.1')
1963
+ socket.destroy();
1964
+ } catch (e) {
1965
+ }
1966
+ resolve(val);
1967
+ };
1968
+ socket.setTimeout(timeout);
1969
+ socket.once("connect", () => finish(true));
1970
+ socket.once("error", () => finish(false));
1971
+ socket.once("timeout", () => finish(false));
1972
+ socket.connect(53, "1.1.1.1");
2017
1973
  } catch (e) {
2018
- resolve(false)
1974
+ resolve(false);
2019
1975
  }
2020
- })
1976
+ });
2021
1977
  }
2022
1978
  // Called on visibility/online/resume events
2023
1979
  async #restoreNetwork() {
2024
1980
  if (this.#reconnecting) {
2025
- console.log('\u{1F501} Reconnection already in progress, skipping')
2026
- return
1981
+ console.log("\u{1F501} Reconnection already in progress, skipping");
1982
+ return;
2027
1983
  }
2028
- this.#reconnecting = true
1984
+ this.#reconnecting = true;
2029
1985
  if (this.connectedPeers.length > 0) {
2030
- console.log('\u2705 Already connected to peers, skipping restoration')
2031
- this.#reconnecting = false
2032
- return
1986
+ console.log("\u2705 Already connected to peers, skipping restoration");
1987
+ this.#reconnecting = false;
1988
+ return;
2033
1989
  }
2034
- console.log('\u{1F501} Restoring network')
1990
+ console.log("\u{1F501} Restoring network");
2035
1991
  try {
2036
- const online = await this.#isOnLine(1500)
1992
+ const online = await this.#isOnLine(1500);
2037
1993
  if (!online) {
2038
- console.warn('\u26A0\uFE0F No internet detected, skipping restore')
2039
- this.#reconnecting = false
2040
- return
1994
+ console.warn("\u26A0\uFE0F No internet detected, skipping restore");
1995
+ this.#reconnecting = false;
1996
+ return;
2041
1997
  }
2042
1998
  } catch (e) {
2043
- console.warn('\u26A0\uFE0F Online probe failed, proceeding with restore', e?.message || e)
1999
+ console.warn("\u26A0\uFE0F Online probe failed, proceeding with restore", e?.message || e);
2044
2000
  }
2045
2001
  try {
2046
- console.log('\u{1F504} Attempting network restoration...')
2002
+ console.log("\u{1F504} Attempting network restoration...");
2047
2003
  if (globalThis.peernet?.client?.reinit) {
2048
- console.log(' \u2192 Trying client.reinit()')
2004
+ console.log(" \u2192 Trying client.reinit()");
2049
2005
  try {
2050
- await globalThis.peernet.client.reinit()
2051
- console.log(' \u2705 client.reinit() succeeded')
2006
+ await globalThis.peernet.client.reinit();
2007
+ console.log(" \u2705 client.reinit() succeeded");
2052
2008
  } catch (e) {
2053
- console.warn(' \u26A0\uFE0F client.reinit() failed:', e?.message || e)
2009
+ console.warn(" \u26A0\uFE0F client.reinit() failed:", e?.message || e);
2054
2010
  }
2055
2011
  }
2056
2012
  if (globalThis.peernet?.start) {
2057
- console.log(' \u2192 Trying peernet.start()')
2013
+ console.log(" \u2192 Trying peernet.start()");
2058
2014
  try {
2059
- await globalThis.peernet.start()
2060
- console.log(' \u2705 peernet.start() succeeded')
2015
+ await globalThis.peernet.start();
2016
+ console.log(" \u2705 peernet.start() succeeded");
2061
2017
  } catch (e) {
2062
- console.warn(' \u26A0\uFE0F peernet.start() failed:', e?.message || e)
2018
+ console.warn(" \u26A0\uFE0F peernet.start() failed:", e?.message || e);
2063
2019
  }
2064
2020
  }
2065
2021
  try {
2066
- const networkName = globalThis.peernet?.network
2067
- if (networkName && typeof networkName === 'string') {
2068
- const { default: networks } = await import('@leofcoin/networks')
2069
- const [mainKey, subKey] = networkName.split(':')
2070
- const networkConfig = networks?.[mainKey]?.[subKey]
2022
+ const networkName = globalThis.peernet?.network;
2023
+ if (networkName && typeof networkName === "string") {
2024
+ const { default: networks } = await import('@leofcoin/networks');
2025
+ const [mainKey, subKey] = networkName.split(":");
2026
+ const networkConfig = networks?.[mainKey]?.[subKey];
2071
2027
  if (networkConfig?.stars && Array.isArray(networkConfig.stars)) {
2072
- console.log(' \u2192 Attempting to dial star servers:', networkConfig.stars.join(', '))
2028
+ console.log(" \u2192 Attempting to dial star servers:", networkConfig.stars.join(", "));
2073
2029
  for (const star of networkConfig.stars) {
2074
2030
  try {
2075
- if (globalThis.peernet?.client && 'dial' in globalThis.peernet.client) {
2076
- await globalThis.peernet.client.dial(star)
2077
- console.log(` \u2705 Connected to star server: ${star}`)
2031
+ if (globalThis.peernet?.client && "dial" in globalThis.peernet.client) {
2032
+ await globalThis.peernet.client.dial(star);
2033
+ console.log(` \u2705 Connected to star server: ${star}`);
2078
2034
  }
2079
2035
  } catch (e) {
2080
- console.warn(` \u26A0\uFE0F Failed to dial ${star}:`, e?.message || e)
2036
+ console.warn(` \u26A0\uFE0F Failed to dial ${star}:`, e?.message || e);
2081
2037
  }
2082
2038
  }
2083
2039
  }
2084
2040
  }
2085
2041
  } catch (e) {
2086
- console.warn(' \u26A0\uFE0F Could not load or dial star servers:', e?.message || e)
2042
+ console.warn(" \u26A0\uFE0F Could not load or dial star servers:", e?.message || e);
2087
2043
  }
2088
- await new Promise((resolve) => setTimeout(resolve, 2e3))
2089
- const connectedAfter = this.connectedPeers.length
2090
- console.log(`\u{1F504} Restoration complete. Connected peers: ${connectedAfter}`)
2044
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
2045
+ const connectedAfter = this.connectedPeers.length;
2046
+ console.log(`\u{1F504} Restoration complete. Connected peers: ${connectedAfter}`);
2091
2047
  } catch (error) {
2092
- console.error('\u274C Network restoration failed:', error?.message || error)
2048
+ console.error("\u274C Network restoration failed:", error?.message || error);
2093
2049
  } finally {
2094
- this.#reconnecting = false
2050
+ this.#reconnecting = false;
2095
2051
  }
2096
2052
  }
2097
2053
  async waitForPeers(timeoutMs = 3e4) {
2098
2054
  return new Promise((resolve) => {
2099
- const startTime = Date.now()
2055
+ const startTime = Date.now();
2100
2056
  const checkPeers = () => {
2101
2057
  if (this.compatiblePeers.length > 0) {
2102
- resolve(true)
2103
- return
2058
+ resolve(true);
2059
+ return;
2104
2060
  }
2105
2061
  if (Date.now() - startTime >= timeoutMs) {
2106
- resolve(false)
2107
- return
2062
+ resolve(false);
2063
+ return;
2108
2064
  }
2109
- setTimeout(checkPeers, 1e3)
2110
- }
2111
- checkPeers()
2112
- })
2065
+ setTimeout(checkPeers, 1e3);
2066
+ };
2067
+ checkPeers();
2068
+ });
2113
2069
  }
2114
2070
  async #attemptReconnection() {
2115
2071
  try {
2116
- await this.#restoreNetwork()
2117
- const hasConnections = this.connectedPeers.length > 0 || this.disconnectedPeers.length > 0
2072
+ await this.#restoreNetwork();
2073
+ const hasConnections = this.connectedPeers.length > 0 || this.disconnectedPeers.length > 0;
2118
2074
  if (hasConnections) {
2119
- console.log('\u2705 Reconnection successful, resetting backoff delay')
2120
- this.#reconnectDelay = 5e3
2075
+ console.log("\u2705 Reconnection successful, resetting backoff delay");
2076
+ this.#reconnectDelay = 5e3;
2121
2077
  } else {
2122
- console.warn('\u26A0\uFE0F Reconnection attempt completed but no peers connected')
2078
+ console.warn("\u26A0\uFE0F Reconnection attempt completed but no peers connected");
2123
2079
  if (this.#reconnectDelay >= 3e4) {
2124
- console.warn('\u26A0\uFE0F Reconnection delay reached maximum, resetting to 5 seconds')
2125
- this.#reconnectDelay = 5e3
2080
+ console.warn("\u26A0\uFE0F Reconnection delay reached maximum, resetting to 5 seconds");
2081
+ this.#reconnectDelay = 5e3;
2126
2082
  } else {
2127
- this.#reconnectDelay = Math.min(this.#reconnectDelay * 1.5, 3e4)
2128
- console.warn(`\u26A0\uFE0F Increasing reconnection delay to ${this.#reconnectDelay} ms`)
2083
+ this.#reconnectDelay = Math.min(this.#reconnectDelay * 1.5, 3e4);
2084
+ console.warn(`\u26A0\uFE0F Increasing reconnection delay to ${this.#reconnectDelay} ms`);
2129
2085
  }
2130
- this.#reconnectTimer = setTimeout(() => this.#attemptReconnection(), this.#reconnectDelay)
2086
+ this.#reconnectTimer = setTimeout(() => this.#attemptReconnection(), this.#reconnectDelay);
2131
2087
  }
2132
2088
  } catch (error) {
2133
- console.error('\u274C Reconnection failed:', error?.message || error)
2089
+ console.error("\u274C Reconnection failed:", error?.message || error);
2134
2090
  if (this.#reconnectDelay >= 3e4) {
2135
- this.#reconnectDelay = 5e3
2091
+ this.#reconnectDelay = 5e3;
2136
2092
  } else {
2137
- this.#reconnectDelay = Math.min(this.#reconnectDelay * 1.5, 3e4)
2093
+ this.#reconnectDelay = Math.min(this.#reconnectDelay * 1.5, 3e4);
2138
2094
  }
2139
- this.#reconnectTimer = setTimeout(() => this.#attemptReconnection(), this.#reconnectDelay)
2095
+ this.#reconnectTimer = setTimeout(() => this.#attemptReconnection(), this.#reconnectDelay);
2140
2096
  }
2141
2097
  }
2142
2098
  }
2143
2099
 
2144
- const debug = createDebugger('leofcoin/chain')
2100
+ const debug = createDebugger("leofcoin/chain");
2145
2101
  class Chain extends VersionControl {
2146
2102
  constructor(config) {
2147
- super(config)
2148
- this.#slotTime = 1e4
2149
- this.#blockTime = 6e3
2103
+ super(config);
2104
+ this.#slotTime = 1e4;
2105
+ this.#blockTime = 6e3;
2150
2106
  // 6 second target block time
2151
- this.#epochLength = 10
2152
- this.utils = {}
2107
+ this.#epochLength = 10;
2108
+ this.utils = {};
2153
2109
  /** {Address[]} */
2154
- this.#validators = []
2110
+ this.#validators = [];
2155
2111
  /** {Boolean} */
2156
- this.#runningEpoch = false
2112
+ this.#runningEpoch = false;
2157
2113
  /** Block height at which current epoch started (for block-based epoch timing) */
2158
- this.#currentEpochStartHeight = 0
2114
+ this.#currentEpochStartHeight = 0;
2159
2115
  /** {Object} Block cache by index for conflict detection: {index: {hash, ...block}} */
2160
- this.#blocks = {}
2161
- this.#participants = []
2162
- this.#participating = false
2163
- this.#jail = /* @__PURE__ */ new Set()
2164
- this.#jailReleaseTimers = /* @__PURE__ */ new Map()
2165
- this.#peerConnectionRetries = /* @__PURE__ */ new Map()
2166
- this.#maxPeerRetries = 5
2167
- this.#peerRetryDelay = 5e3
2116
+ this.#blocks = {};
2117
+ this.#participants = [];
2118
+ this.#participating = false;
2119
+ this.#jail = /* @__PURE__ */ new Set();
2120
+ this.#jailReleaseTimers = /* @__PURE__ */ new Map();
2121
+ this.#peerConnectionRetries = /* @__PURE__ */ new Map();
2122
+ this.#maxPeerRetries = 5;
2123
+ this.#peerRetryDelay = 5e3;
2168
2124
  /** {Map} Peer reputation tracking: {peerId: {score, failures}} */
2169
- this.#peerReputations = /* @__PURE__ */ new Map()
2170
- this.#minPeerScore = -10
2171
- this.#maxPeerFailures = 100
2125
+ this.#peerReputations = /* @__PURE__ */ new Map();
2126
+ this.#minPeerScore = -10;
2127
+ this.#maxPeerFailures = 100;
2172
2128
  // ── Tendermint consensus state ──────────────────────────────────────────────
2173
2129
  /** Current consensus round (increments when proposer is unresponsive) */
2174
- this.#consensusRound = 0
2130
+ this.#consensusRound = 0;
2175
2131
  /** Timer that advances #consensusRound when the proposer doesn't propose in time */
2176
- this.#roundTimer = null
2132
+ this.#roundTimer = null;
2177
2133
  /** prevotes collected per `height:round:blockHash` key */
2178
- this.#prevotes = /* @__PURE__ */ new Map()
2134
+ this.#prevotes = /* @__PURE__ */ new Map();
2179
2135
  /** precommits collected per `height:round:blockHash` key */
2180
- this.#precommits = /* @__PURE__ */ new Map()
2136
+ this.#precommits = /* @__PURE__ */ new Map();
2181
2137
  /** Index of the last block that reached 2f+1 precommits */
2182
- this.#committedHeight = -1
2138
+ this.#committedHeight = -1;
2183
2139
  /** Prevents casting duplicate prevote/precommit per height:round */
2184
- this.#castedVotes = /* @__PURE__ */ new Set()
2140
+ this.#castedVotes = /* @__PURE__ */ new Set();
2185
2141
  this.ready = new Promise((resolve) => {
2186
- this.readyResolve = resolve
2187
- })
2142
+ this.readyResolve = resolve;
2143
+ });
2188
2144
  // ── Tendermint consensus handlers ────────────────────────────────────────
2189
2145
  /**
2190
2146
  * Publish a prevote or precommit. Idempotent — will not cast the same
2191
2147
  * vote twice for the same height:round.
2192
2148
  */
2193
2149
  this.#castVote = async (type, blockHash, index, round) => {
2194
- const voteKey = `${type}:${index}:${round}`
2195
- if (this.#castedVotes.has(voteKey)) return
2196
- this.#castedVotes.add(voteKey)
2197
- const from = peernet.selectedAccount
2198
- const voteData = { blockHash, index: BigInt(index), round: BigInt(round), from }
2199
- const Message = type === 'prevote' ? PrevoteMessage : PrecommitMessage
2200
- const message = new Message(voteData)
2201
- const payload = message.encoded
2150
+ const voteKey = `${type}:${index}:${round}`;
2151
+ if (this.#castedVotes.has(voteKey)) return;
2152
+ this.#castedVotes.add(voteKey);
2153
+ const from = peernet.selectedAccount;
2154
+ const voteData = { blockHash, index: BigInt(index), round: BigInt(round), from };
2155
+ const Message = type === "prevote" ? PrevoteMessage : PrecommitMessage;
2156
+ const message = new Message(voteData);
2157
+ const payload = message.encoded;
2202
2158
  try {
2203
- globalThis.peernet.publish(`consensus:${type}`, payload)
2159
+ globalThis.peernet.publish(`consensus:${type}`, payload);
2204
2160
  } catch (e) {
2205
- debug(`peernet publish failed: consensus:${type}`, e?.message ?? e)
2161
+ debug(`peernet publish failed: consensus:${type}`, e?.message ?? e);
2206
2162
  }
2207
- }
2163
+ };
2208
2164
  /**
2209
2165
  * Phase 2 — receive a block proposal from the designated proposer.
2210
2166
  * Validates the proposer is correct for height/round, fetches + validates
@@ -2212,76 +2168,72 @@ class Chain extends VersionControl {
2212
2168
  */
2213
2169
  this.#handleProposal = async (payload) => {
2214
2170
  try {
2215
- const message = new ProposalMessage(payload)
2216
- const msg = message.decoded
2217
- const { blockHash, index, round, from } = msg
2218
- const validators = await this.#getConsensusValidators(Number(index))
2219
- const expectedProposerIdx = Number((index + round) % BigInt(validators.length))
2171
+ const message = new ProposalMessage(payload);
2172
+ const msg = message.decoded;
2173
+ const { blockHash, index, round, from } = msg;
2174
+ const validators = await this.#getConsensusValidators(Number(index));
2175
+ const expectedProposerIdx = Number((index + round) % BigInt(validators.length));
2220
2176
  if (!validators[expectedProposerIdx] || validators[expectedProposerIdx] !== from) {
2221
- debug(`[consensus] Proposal from wrong proposer at height ${index} round ${round}`)
2222
- return
2177
+ debug(`[consensus] Proposal from wrong proposer at height ${index} round ${round}`);
2178
+ return;
2223
2179
  }
2224
- const localBlock = await this.lastBlock
2225
- const localIndex = localBlock?.index !== void 0 ? localBlock.index : -1n
2180
+ const localBlock = await this.lastBlock;
2181
+ const localIndex = localBlock?.index !== void 0 ? localBlock.index : -1n;
2226
2182
  if (index <= localIndex) {
2227
- debug(`[consensus] Ignoring stale proposal at height ${index} (local: ${localIndex})`)
2228
- return
2183
+ debug(`[consensus] Ignoring stale proposal at height ${index} (local: ${localIndex})`);
2184
+ return;
2229
2185
  }
2230
2186
  try {
2231
- const blockData = await globalThis.peernet.get(blockHash, 'block')
2232
- const blockMessage = await new BlockMessage(blockData)
2233
- const actualHash = await blockMessage.hash()
2187
+ const blockData = await globalThis.peernet.get(blockHash, "block");
2188
+ const blockMessage = await new BlockMessage(blockData);
2189
+ const actualHash = await blockMessage.hash();
2234
2190
  if (actualHash !== blockHash) {
2235
- debug(`[consensus] Block hash mismatch in proposal: expected ${blockHash}, got ${actualHash}`)
2236
- return
2191
+ debug(`[consensus] Block hash mismatch in proposal: expected ${blockHash}, got ${actualHash}`);
2192
+ return;
2237
2193
  }
2238
2194
  } catch (e) {
2239
- debug(`[consensus] Cannot fetch proposed block ${blockHash}:`, e?.message)
2240
- return
2195
+ debug(`[consensus] Cannot fetch proposed block ${blockHash}:`, e?.message);
2196
+ return;
2241
2197
  }
2242
- this.#consensusRound = Number(round)
2198
+ this.#consensusRound = Number(round);
2243
2199
  if (this.#roundTimer) {
2244
- clearTimeout(this.#roundTimer)
2245
- this.#roundTimer = null
2200
+ clearTimeout(this.#roundTimer);
2201
+ this.#roundTimer = null;
2246
2202
  }
2247
2203
  if (validators.includes(peernet.selectedAccount) && !this.#isJailed(peernet.selectedAccount)) {
2248
- await this.#castVote('prevote', blockHash, Number(index), Number(round))
2204
+ await this.#castVote("prevote", blockHash, Number(index), Number(round));
2249
2205
  }
2250
2206
  } catch (e) {
2251
- debug('[consensus] Error handling proposal:', e?.message)
2207
+ debug("[consensus] Error handling proposal:", e?.message);
2252
2208
  }
2253
- }
2209
+ };
2254
2210
  /**
2255
2211
  * Phase 2 — collect prevotes. Once 2f+1 prevotes are seen for a block,
2256
2212
  * cast a precommit.
2257
2213
  */
2258
2214
  this.#handlePrevote = async (payload) => {
2259
2215
  try {
2260
- const message = new PrevoteMessage(payload)
2261
- const msg = message.decoded
2262
- const { blockHash, index, round, from } = msg
2263
- const validators = await this.#getConsensusValidators(Number(index))
2264
- if (!validators.includes(from)) return
2265
- const localBlock = await this.lastBlock
2266
- const localIndex = localBlock?.index !== void 0 ? localBlock.index : -1n
2267
- if (index <= localIndex) return
2268
- const voteKey = `${index}:${round}:${blockHash}`
2269
- if (!this.#prevotes.has(voteKey)) this.#prevotes.set(voteKey, /* @__PURE__ */ new Set())
2270
- this.#prevotes.get(voteKey).add(from)
2271
- const threshold = Math.ceil((2 * validators.length) / 3)
2272
- const voteCount = this.#prevotes.get(voteKey).size
2273
- debug(`[consensus] Prevotes ${voteKey}: ${voteCount}/${validators.length} (need ${threshold})`)
2274
- if (
2275
- voteCount >= threshold &&
2276
- validators.includes(peernet.selectedAccount) &&
2277
- !this.#isJailed(peernet.selectedAccount)
2278
- ) {
2279
- await this.#castVote('precommit', blockHash, Number(index), Number(round))
2216
+ const message = new PrevoteMessage(payload);
2217
+ const msg = message.decoded;
2218
+ const { blockHash, index, round, from } = msg;
2219
+ const validators = await this.#getConsensusValidators(Number(index));
2220
+ if (!validators.includes(from)) return;
2221
+ const localBlock = await this.lastBlock;
2222
+ const localIndex = localBlock?.index !== void 0 ? localBlock.index : -1n;
2223
+ if (index <= localIndex) return;
2224
+ const voteKey = `${index}:${round}:${blockHash}`;
2225
+ if (!this.#prevotes.has(voteKey)) this.#prevotes.set(voteKey, /* @__PURE__ */ new Set());
2226
+ this.#prevotes.get(voteKey).add(from);
2227
+ const threshold = Math.ceil(2 * validators.length / 3);
2228
+ const voteCount = this.#prevotes.get(voteKey).size;
2229
+ debug(`[consensus] Prevotes ${voteKey}: ${voteCount}/${validators.length} (need ${threshold})`);
2230
+ if (voteCount >= threshold && validators.includes(peernet.selectedAccount) && !this.#isJailed(peernet.selectedAccount)) {
2231
+ await this.#castVote("precommit", blockHash, Number(index), Number(round));
2280
2232
  }
2281
2233
  } catch (e) {
2282
- debug('[consensus] Error handling prevote:', e?.message)
2234
+ debug("[consensus] Error handling prevote:", e?.message);
2283
2235
  }
2284
- }
2236
+ };
2285
2237
  /**
2286
2238
  * Phase 3 — collect precommits. Once 2f+1 precommits are seen for a block,
2287
2239
  * commit it: non-proposers call #addBlock, then broadcast on add-block for
@@ -2289,252 +2241,250 @@ class Chain extends VersionControl {
2289
2241
  */
2290
2242
  this.#handlePrecommit = async (payload) => {
2291
2243
  try {
2292
- const message = new PrecommitMessage(payload)
2293
- const msg = message.decoded
2294
- const { blockHash, index, round, from } = msg
2295
- const validators = await this.#getConsensusValidators(Number(index))
2296
- if (!validators.includes(from)) return
2297
- if (index <= BigInt(this.#committedHeight)) return
2298
- const voteKey = `${index}:${round}:${blockHash}`
2299
- if (!this.#precommits.has(voteKey)) this.#precommits.set(voteKey, /* @__PURE__ */ new Set())
2300
- this.#precommits.get(voteKey).add(from)
2301
- const threshold = Math.ceil((2 * validators.length) / 3)
2302
- const voteCount = this.#precommits.get(voteKey).size
2303
- debug(`[consensus] Precommits ${voteKey}: ${voteCount}/${validators.length} (need ${threshold})`)
2244
+ const message = new PrecommitMessage(payload);
2245
+ const msg = message.decoded;
2246
+ const { blockHash, index, round, from } = msg;
2247
+ const validators = await this.#getConsensusValidators(Number(index));
2248
+ if (!validators.includes(from)) return;
2249
+ if (index <= BigInt(this.#committedHeight)) return;
2250
+ const voteKey = `${index}:${round}:${blockHash}`;
2251
+ if (!this.#precommits.has(voteKey)) this.#precommits.set(voteKey, /* @__PURE__ */ new Set());
2252
+ this.#precommits.get(voteKey).add(from);
2253
+ const threshold = Math.ceil(2 * validators.length / 3);
2254
+ const voteCount = this.#precommits.get(voteKey).size;
2255
+ debug(`[consensus] Precommits ${voteKey}: ${voteCount}/${validators.length} (need ${threshold})`);
2304
2256
  if (voteCount >= threshold && index > BigInt(this.#committedHeight)) {
2305
- this.#committedHeight = Number(index)
2306
- this.#consensusRound = 0
2257
+ this.#committedHeight = Number(index);
2258
+ this.#consensusRound = 0;
2307
2259
  for (const key of [...this.#prevotes.keys()]) {
2308
- if (BigInt(key.split(':')[0]) <= index) this.#prevotes.delete(key)
2260
+ if (BigInt(key.split(":")[0]) <= index) this.#prevotes.delete(key);
2309
2261
  }
2310
2262
  for (const key of [...this.#precommits.keys()]) {
2311
- if (BigInt(key.split(':')[0]) <= index) this.#precommits.delete(key)
2263
+ if (BigInt(key.split(":")[0]) <= index) this.#precommits.delete(key);
2312
2264
  }
2313
2265
  for (const key of [...this.#castedVotes]) {
2314
- if (BigInt(key.split(':')[1]) <= index) this.#castedVotes.delete(key)
2266
+ if (BigInt(key.split(":")[1]) <= index) this.#castedVotes.delete(key);
2315
2267
  }
2316
- const currentBlock = await this.lastBlock
2317
- const currentIndex = currentBlock?.index !== void 0 ? currentBlock.index : -1n
2268
+ const currentBlock = await this.lastBlock;
2269
+ const currentIndex = currentBlock?.index !== void 0 ? currentBlock.index : -1n;
2318
2270
  if (index > currentIndex) {
2319
- debug(`[consensus] \u2705 Committing block ${blockHash} at height ${index}`)
2271
+ debug(`[consensus] \u2705 Committing block ${blockHash} at height ${index}`);
2320
2272
  try {
2321
- const blockData = await globalThis.peernet.get(blockHash, 'block')
2322
- await this.#addBlock(blockData)
2273
+ const blockData = await globalThis.peernet.get(blockHash, "block");
2274
+ await this.#addBlock(blockData);
2323
2275
  } catch (e) {
2324
- debug(`[consensus] Failed to commit block ${blockHash}:`, e?.message)
2276
+ debug(`[consensus] Failed to commit block ${blockHash}:`, e?.message);
2325
2277
  }
2326
2278
  } else {
2327
- debug(`[consensus] \u2705 Block ${blockHash} at height ${index} already committed (proposer path)`)
2279
+ debug(`[consensus] \u2705 Block ${blockHash} at height ${index} already committed (proposer path)`);
2328
2280
  }
2329
2281
  try {
2330
- const blockData = await globalThis.peernet.get(blockHash, 'block')
2331
- globalThis.peernet.publish('add-block', blockData)
2332
- globalThis.pubsub.publish('add-block', blockData)
2282
+ const blockData = await globalThis.peernet.get(blockHash, "block");
2283
+ globalThis.peernet.publish("add-block", blockData);
2284
+ globalThis.pubsub.publish("add-block", blockData);
2333
2285
  } catch (e) {
2334
- debug('[consensus] Failed to broadcast committed block:', e?.message)
2286
+ debug("[consensus] Failed to broadcast committed block:", e?.message);
2335
2287
  }
2336
2288
  }
2337
2289
  } catch (e) {
2338
- debug('[consensus] Error handling precommit:', e?.message)
2290
+ debug("[consensus] Error handling precommit:", e?.message);
2339
2291
  }
2340
- }
2292
+ };
2341
2293
  // ─────────────────────────────────────────────────────────────────────────
2342
2294
  this.#addTransaction = async (message) => {
2343
- const transaction = new TransactionMessage(message)
2344
- const hash = await transaction.hash()
2345
- this.addPendingNonce(transaction.decoded.from, transaction.decoded.nonce)
2346
- debug(`added ${hash}`)
2347
- }
2348
- this.#init()
2349
- }
2350
- #state
2351
- #slotTime
2352
- #blockTime
2353
- #epochLength
2354
- #validators
2355
- #runningEpoch
2356
- #currentEpochStartHeight
2357
- #blocks
2358
- #participants
2359
- #participating
2360
- #jail
2361
- #jailReleaseTimers
2362
- #peerConnectionRetries
2363
- #maxPeerRetries
2364
- #peerRetryDelay
2365
- #peerReputations
2366
- #minPeerScore
2367
- #maxPeerFailures
2368
- #consensusRound
2369
- #roundTimer
2370
- #prevotes
2371
- #precommits
2372
- #committedHeight
2373
- #castedVotes
2295
+ const transaction = new TransactionMessage(message);
2296
+ const hash = await transaction.hash();
2297
+ this.addPendingNonce(transaction.decoded.from, transaction.decoded.nonce);
2298
+ debug(`added ${hash}`);
2299
+ };
2300
+ this.#init();
2301
+ }
2302
+ #state;
2303
+ #slotTime;
2304
+ #blockTime;
2305
+ #epochLength;
2306
+ #validators;
2307
+ #runningEpoch;
2308
+ #currentEpochStartHeight;
2309
+ #blocks;
2310
+ #participants;
2311
+ #participating;
2312
+ #jail;
2313
+ #jailReleaseTimers;
2314
+ #peerConnectionRetries;
2315
+ #maxPeerRetries;
2316
+ #peerRetryDelay;
2317
+ #peerReputations;
2318
+ #minPeerScore;
2319
+ #maxPeerFailures;
2320
+ #consensusRound;
2321
+ #roundTimer;
2322
+ #prevotes;
2323
+ #precommits;
2324
+ #committedHeight;
2325
+ #castedVotes;
2374
2326
  // ────────────────────────────────────────────────────────────────────────────
2375
- #connectionMonitor
2327
+ #connectionMonitor;
2376
2328
  get nativeToken() {
2377
- return addresses.nativeToken
2329
+ return addresses.nativeToken;
2378
2330
  }
2379
2331
  get validators() {
2380
- return [...this.#validators]
2332
+ return [...this.#validators];
2381
2333
  }
2382
2334
  async hasTransactionToHandle() {
2383
- const size = await globalThis.transactionPoolStore.size()
2384
- if (size > 0) return true
2385
- return false
2335
+ const size = await globalThis.transactionPoolStore.size();
2336
+ if (size > 0) return true;
2337
+ return false;
2386
2338
  }
2387
2339
  #sleep(ms) {
2388
- return new Promise((resolve) => setTimeout(resolve, ms))
2340
+ return new Promise((resolve) => setTimeout(resolve, ms));
2389
2341
  }
2390
2342
  async #recordPeerFailure(peerId, reason) {
2391
2343
  if (!this.#peerReputations.has(peerId)) {
2392
- this.#peerReputations.set(peerId, { score: 0, failures: [] })
2344
+ this.#peerReputations.set(peerId, { score: 0, failures: [] });
2393
2345
  }
2394
- const rep = this.#peerReputations.get(peerId)
2395
- rep.score -= 1
2396
- rep.failures.push(`${Date.now()}: ${reason}`)
2346
+ const rep = this.#peerReputations.get(peerId);
2347
+ rep.score -= 1;
2348
+ rep.failures.push(`${Date.now()}: ${reason}`);
2397
2349
  if (rep.failures.length > this.#maxPeerFailures) {
2398
- rep.failures.shift()
2350
+ rep.failures.shift();
2399
2351
  }
2400
2352
  if (rep.score < this.#minPeerScore) {
2401
- console.warn(`[peer-ban] Peer ${peerId} banned after ${rep.failures.length} failures`)
2353
+ console.warn(`[peer-ban] Peer ${peerId} banned after ${rep.failures.length} failures`);
2402
2354
  try {
2403
- await globalThis.peernet.disconnect(peerId)
2355
+ await globalThis.peernet.disconnect(peerId);
2404
2356
  } catch (e) {
2405
- debug(`Failed to disconnect peer ${peerId}`)
2357
+ debug(`Failed to disconnect peer ${peerId}`);
2406
2358
  }
2407
2359
  }
2408
2360
  }
2409
2361
  #isJailed(address) {
2410
- return typeof address === 'string' && this.#jail.has(address)
2362
+ return typeof address === "string" && this.#jail.has(address);
2411
2363
  }
2412
2364
  async #getConsensusValidators(nextBlockIndex) {
2413
- const localBlock = await this.lastBlock
2414
- const localIndex = localBlock?.index !== void 0 ? Number(localBlock.index) : -1
2415
- if (
2416
- Array.isArray(localBlock?.validators) &&
2417
- localBlock.validators.length > 0 &&
2418
- (nextBlockIndex === void 0 || nextBlockIndex === localIndex + 1)
2419
- ) {
2365
+ const localBlock = await this.lastBlock;
2366
+ const localIndex = localBlock?.index !== void 0 ? Number(localBlock.index) : -1;
2367
+ if (Array.isArray(localBlock?.validators) && localBlock.validators.length > 0 && (nextBlockIndex === void 0 || nextBlockIndex === localIndex + 1)) {
2420
2368
  return [
2421
- ...new Set(localBlock.validators.map((validator) => validator.address).filter((address) => Boolean(address)))
2422
- ].sort()
2369
+ ...new Set(
2370
+ localBlock.validators.map((validator) => validator.address).filter((address) => Boolean(address))
2371
+ )
2372
+ ].sort();
2423
2373
  }
2424
- const validators = await this.staticCall(addresses.validators, 'validators')
2425
- return [...new Set(validators)].sort()
2374
+ const validators = await this.staticCall(addresses.validators, "validators");
2375
+ return [...new Set(validators)].sort();
2426
2376
  }
2427
2377
  #validateBlockValidators(blockMessage) {
2428
- const validators = blockMessage.decoded.validators || []
2378
+ const validators = blockMessage.decoded.validators || [];
2429
2379
  if (!Array.isArray(validators) || validators.length === 0) {
2430
- throw new Error(`Block ${blockMessage.decoded.index} does not include validators`)
2380
+ throw new Error(`Block ${blockMessage.decoded.index} does not include validators`);
2431
2381
  }
2432
- if (!blockMessage.decoded.protocolVersion || typeof blockMessage.decoded.protocolVersion !== 'string') {
2433
- throw new Error(`Block ${blockMessage.decoded.index} does not have a valid protocolVersion field`)
2382
+ if (!blockMessage.decoded.protocolVersion || typeof blockMessage.decoded.protocolVersion !== "string") {
2383
+ throw new Error(`Block ${blockMessage.decoded.index} does not have a valid protocolVersion field`);
2434
2384
  }
2435
2385
  if (!this.isVersionCompatible(blockMessage.decoded.protocolVersion)) {
2436
2386
  throw new Error(
2437
2387
  `Block ${blockMessage.decoded.index} uses incompatible protocol version: ${blockMessage.decoded.protocolVersion} (local: ${this.version}). Major.minor version must match.`
2438
- )
2388
+ );
2439
2389
  }
2440
- if (!blockMessage.decoded.producer || typeof blockMessage.decoded.producer !== 'string') {
2441
- throw new Error(`Block ${blockMessage.decoded.index} does not have a valid producer field`)
2390
+ if (!blockMessage.decoded.producer || typeof blockMessage.decoded.producer !== "string") {
2391
+ throw new Error(`Block ${blockMessage.decoded.index} does not have a valid producer field`);
2442
2392
  }
2443
- if (!blockMessage.decoded.producerProof || typeof blockMessage.decoded.producerProof !== 'string') {
2444
- throw new Error(`Block ${blockMessage.decoded.index} does not have a valid producerProof field`)
2393
+ if (!blockMessage.decoded.producerProof || typeof blockMessage.decoded.producerProof !== "string") {
2394
+ throw new Error(`Block ${blockMessage.decoded.index} does not have a valid producerProof field`);
2445
2395
  }
2446
- const producerIsValidator = validators.some((v) => v.address === blockMessage.decoded.producer)
2396
+ const producerIsValidator = validators.some((v) => v.address === blockMessage.decoded.producer);
2447
2397
  if (!producerIsValidator) {
2448
2398
  throw new Error(
2449
2399
  `Block ${blockMessage.decoded.index} producer ${blockMessage.decoded.producer} is not in validators list`
2450
- )
2400
+ );
2451
2401
  }
2452
- const addresses2 = validators.map((validator) => validator.address)
2453
- if (addresses2.some((address) => typeof address !== 'string' || address.length === 0)) {
2454
- throw new Error(`Block ${blockMessage.decoded.index} includes an invalid validator address`)
2402
+ const addresses2 = validators.map((validator) => validator.address);
2403
+ if (addresses2.some((address) => typeof address !== "string" || address.length === 0)) {
2404
+ throw new Error(`Block ${blockMessage.decoded.index} includes an invalid validator address`);
2455
2405
  }
2456
- const canonicalAddresses = [...addresses2].sort()
2406
+ const canonicalAddresses = [...addresses2].sort();
2457
2407
  if (canonicalAddresses.some((address, index) => address !== addresses2[index])) {
2458
- throw new Error(`Block ${blockMessage.decoded.index} validators are not canonically sorted`)
2408
+ throw new Error(`Block ${blockMessage.decoded.index} validators are not canonically sorted`);
2459
2409
  }
2460
2410
  if (new Set(addresses2).size !== addresses2.length) {
2461
- throw new Error(`Block ${blockMessage.decoded.index} validators contain duplicates`)
2411
+ throw new Error(`Block ${blockMessage.decoded.index} validators contain duplicates`);
2462
2412
  }
2463
- const validatorCount = BigInt(validators.length)
2464
- const expectedReward = blockMessage.decoded.fees / validatorCount + blockMessage.decoded.reward / validatorCount
2413
+ const validatorCount = BigInt(validators.length);
2414
+ const expectedReward = blockMessage.decoded.fees / validatorCount + blockMessage.decoded.reward / validatorCount;
2465
2415
  for (const validator of validators) {
2466
2416
  if (validator.reward !== expectedReward) {
2467
2417
  throw new Error(
2468
2418
  `Block ${blockMessage.decoded.index} has an invalid reward for validator ${validator.address}: expected ${expectedReward}, got ${validator.reward}`
2469
- )
2419
+ );
2470
2420
  }
2471
2421
  }
2472
2422
  }
2473
2423
  /** Check if the next block will cross an epoch boundary (block-based timing) */
2474
2424
  #isEpochBoundary(blockHeight) {
2475
- return (blockHeight + 1) % this.#epochLength === 0
2425
+ return (blockHeight + 1) % this.#epochLength === 0;
2476
2426
  }
2477
2427
  /** Handle epoch transition when a block crosses epoch boundary */
2478
2428
  async #handleEpochBoundary(blockHeight) {
2479
- if (!this.#isEpochBoundary(blockHeight)) return
2480
- this.#currentEpochStartHeight = blockHeight + 1
2481
- this.#consensusRound = 0
2429
+ if (!this.#isEpochBoundary(blockHeight)) return;
2430
+ this.#currentEpochStartHeight = blockHeight + 1;
2431
+ this.#consensusRound = 0;
2482
2432
  debug(
2483
2433
  `[consensus] Epoch boundary at block ${blockHeight}: new epoch starts at height ${this.#currentEpochStartHeight}`
2484
- )
2434
+ );
2485
2435
  if (this.#participating && !this.#runningEpoch) {
2486
- await this.#runEpoch()
2436
+ await this.#runEpoch();
2487
2437
  }
2488
2438
  }
2489
2439
  async #runEpoch() {
2490
- if (this.#runningEpoch) return
2491
- this.#runningEpoch = true
2492
- console.log('epoch')
2493
- const validators = await this.#getConsensusValidators()
2494
- console.log({ validators })
2440
+ if (this.#runningEpoch) return;
2441
+ this.#runningEpoch = true;
2442
+ console.log("epoch");
2443
+ const validators = await this.#getConsensusValidators();
2444
+ console.log({ validators });
2495
2445
  if (this.#isJailed(peernet.selectedAccount)) {
2496
- this.#runningEpoch = false
2497
- return
2446
+ this.#runningEpoch = false;
2447
+ return;
2498
2448
  }
2499
2449
  if (!validators.includes(peernet.selectedAccount)) {
2500
- this.#runningEpoch = false
2501
- return
2450
+ this.#runningEpoch = false;
2451
+ return;
2502
2452
  }
2503
- const localBlock = await this.lastBlock
2504
- const nextIndex = (localBlock?.index !== void 0 ? Number(localBlock.index) : -1) + 1
2505
- const proposerIdx = (nextIndex + this.#consensusRound) % validators.length
2506
- const isProposer = validators[proposerIdx] === peernet.selectedAccount
2453
+ const localBlock = await this.lastBlock;
2454
+ const nextIndex = (localBlock?.index !== void 0 ? Number(localBlock.index) : -1) + 1;
2455
+ const proposerIdx = (nextIndex + this.#consensusRound) % validators.length;
2456
+ const isProposer = validators[proposerIdx] === peernet.selectedAccount;
2507
2457
  if (!isProposer) {
2508
2458
  if (!this.#roundTimer) {
2509
2459
  this.#roundTimer = setTimeout(async () => {
2510
- this.#roundTimer = null
2511
- this.#consensusRound++
2512
- debug(`[consensus] Round timed out, advancing to round ${this.#consensusRound}`)
2513
- this.#runningEpoch = false
2514
- if (this.#participating) await this.#runEpoch()
2515
- }, this.#slotTime)
2460
+ this.#roundTimer = null;
2461
+ this.#consensusRound++;
2462
+ debug(`[consensus] Round timed out, advancing to round ${this.#consensusRound}`);
2463
+ this.#runningEpoch = false;
2464
+ if (this.#participating) await this.#runEpoch();
2465
+ }, this.#slotTime);
2516
2466
  }
2517
- this.#runningEpoch = false
2518
- return
2467
+ this.#runningEpoch = false;
2468
+ return;
2519
2469
  }
2520
2470
  if (this.#roundTimer) {
2521
- clearTimeout(this.#roundTimer)
2522
- this.#roundTimer = null
2471
+ clearTimeout(this.#roundTimer);
2472
+ this.#roundTimer = null;
2523
2473
  }
2524
- const start = Date.now()
2474
+ const start = Date.now();
2525
2475
  try {
2526
- await this.#createBlock()
2476
+ await this.#createBlock();
2527
2477
  } catch (error) {
2528
- console.error(error)
2478
+ console.error(error);
2529
2479
  }
2530
- const end = Date.now()
2531
- console.log((end - start) / 1e3 + ' s')
2532
- const elapsed = end - start
2533
- const remaining = this.#blockTime - elapsed
2534
- const hasMore = await this.hasTransactionToHandle()
2535
- if (!hasMore && remaining > 0) await this.#sleep(remaining)
2536
- this.#runningEpoch = false
2537
- if (hasMore) return this.#runEpoch()
2480
+ const end = Date.now();
2481
+ console.log((end - start) / 1e3 + " s");
2482
+ const elapsed = end - start;
2483
+ const remaining = this.#blockTime - elapsed;
2484
+ const hasMore = await this.hasTransactionToHandle();
2485
+ if (!hasMore && remaining > 0) await this.#sleep(remaining);
2486
+ this.#runningEpoch = false;
2487
+ if (hasMore) return this.#runEpoch();
2538
2488
  }
2539
2489
  async #setup() {
2540
2490
  const contracts = [
@@ -2554,706 +2504,704 @@ class Chain extends VersionControl {
2554
2504
  address: addresses.nameService,
2555
2505
  message: nameServiceMessage
2556
2506
  }
2557
- ]
2507
+ ];
2558
2508
  await Promise.all(
2559
2509
  contracts.map(async ({ address, message }) => {
2560
- message = await new ContractMessage(Uint8Array.from(message.split(',').map((string) => Number(string))))
2561
- await globalThis.contractStore.put(address, message.encoded)
2510
+ message = await new ContractMessage(Uint8Array.from(message.split(",").map((string) => Number(string))));
2511
+ await globalThis.contractStore.put(address, message.encoded);
2562
2512
  })
2563
- )
2564
- console.log('handle native contracts')
2513
+ );
2514
+ console.log("handle native contracts");
2565
2515
  }
2566
2516
  async #init() {
2567
- this.#participants = []
2568
- this.#participating = false
2569
- this.#connectionMonitor = new ConnectionMonitor()
2570
- console.log('[chain] init:start')
2571
- const initialized = await globalThis.contractStore.has(addresses.contractFactory)
2572
- console.log(`chain initialized: ${initialized}`)
2573
- if (!initialized) await this.#setup()
2574
- this.utils = { formatUnits, parseUnits }
2575
- console.log('init')
2576
- await super.init()
2577
- console.log('super init done')
2578
- this.#connectionMonitor.start(this.version)
2579
- await globalThis.peernet.addRequestHandler('bw-request-message', () => {
2580
- const bw = globalThis.peernet.client?.bw || { up: 0, down: 0 }
2581
- return new BWMessage(bw)
2582
- })
2583
- await globalThis.peernet.addRequestHandler('transactionPool', this.#transactionPoolHandler.bind(this))
2584
- await globalThis.peernet.addRequestHandler('version', this.#versionHandler.bind(this))
2585
- await globalThis.peernet.addRequestHandler('stateInfo', async () => {
2586
- const lastblock = (await this.lastBlock) || { index: 0, hash: '0x0', previousHash: '0x0' }
2587
- const values = this.machine?.states?.info || {}
2588
- return new globalThis.peernet.protos['peernet-response']({
2517
+ this.#participants = [];
2518
+ this.#participating = false;
2519
+ this.#connectionMonitor = new ConnectionMonitor();
2520
+ console.log("[chain] init:start");
2521
+ const initialized = await globalThis.contractStore.has(addresses.contractFactory);
2522
+ console.log(`chain initialized: ${initialized}`);
2523
+ if (!initialized) await this.#setup();
2524
+ this.utils = { formatUnits, parseUnits };
2525
+ console.log("init");
2526
+ await super.init();
2527
+ console.log("super init done");
2528
+ this.#connectionMonitor.start(this.version);
2529
+ await globalThis.peernet.addRequestHandler("bw-request-message", () => {
2530
+ const bw = globalThis.peernet.client?.bw || { up: 0, down: 0 };
2531
+ return new BWMessage(bw);
2532
+ });
2533
+ await globalThis.peernet.addRequestHandler("transactionPool", this.#transactionPoolHandler.bind(this));
2534
+ await globalThis.peernet.addRequestHandler("version", this.#versionHandler.bind(this));
2535
+ await globalThis.peernet.addRequestHandler("stateInfo", async () => {
2536
+ const lastblock = await this.lastBlock || { index: 0, hash: "0x0", previousHash: "0x0" };
2537
+ const values = this.machine?.states?.info || {};
2538
+ return new globalThis.peernet.protos["peernet-response"]({
2589
2539
  response: new StateMessage({ lastblock, values }).encoded
2590
- })
2591
- })
2592
- globalThis.peernet.subscribe('add-block', this.#addBlock.bind(this))
2593
- globalThis.peernet.subscribe('invalid-transaction', this.#invalidTransaction.bind(this))
2594
- globalThis.peernet.subscribe('send-transaction', this.#sendTransaction.bind(this))
2595
- globalThis.peernet.subscribe('add-transaction', this.#addTransaction.bind(this))
2596
- globalThis.peernet.subscribe('validator:timeout', this.#validatorTimeout.bind(this))
2597
- globalThis.peernet.subscribe('consensus:propose', this.#handleProposal.bind(this))
2598
- globalThis.peernet.subscribe('consensus:prevote', this.#handlePrevote.bind(this))
2599
- globalThis.peernet.subscribe('consensus:precommit', this.#handlePrecommit.bind(this))
2600
- globalThis.pubsub.subscribe('peer:connected', this.#peerConnected.bind(this))
2601
- globalThis.pubsub.publish('chain:ready', true)
2602
- console.log('[chain] init:done')
2603
- this.readyResolve(true)
2540
+ });
2541
+ });
2542
+ globalThis.peernet.subscribe("add-block", this.#addBlock.bind(this));
2543
+ globalThis.peernet.subscribe("invalid-transaction", this.#invalidTransaction.bind(this));
2544
+ globalThis.peernet.subscribe("send-transaction", this.#sendTransaction.bind(this));
2545
+ globalThis.peernet.subscribe("add-transaction", this.#addTransaction.bind(this));
2546
+ globalThis.peernet.subscribe("validator:timeout", this.#validatorTimeout.bind(this));
2547
+ globalThis.peernet.subscribe("consensus:propose", this.#handleProposal.bind(this));
2548
+ globalThis.peernet.subscribe("consensus:prevote", this.#handlePrevote.bind(this));
2549
+ globalThis.peernet.subscribe("consensus:precommit", this.#handlePrecommit.bind(this));
2550
+ globalThis.pubsub.subscribe("peer:connected", this.#peerConnected.bind(this));
2551
+ globalThis.pubsub.publish("chain:ready", true);
2552
+ console.log("[chain] init:done");
2553
+ this.readyResolve(true);
2604
2554
  }
2605
2555
  async #invalidTransaction(hash) {
2606
- hash = new TextDecoder().decode(hash)
2607
- if (!(await globalThis.transactionPoolStore.has(hash))) {
2608
- debug(`transaction ${hash} not in pool`)
2609
- return
2556
+ hash = new TextDecoder().decode(hash);
2557
+ if (!await globalThis.transactionPoolStore.has(hash)) {
2558
+ debug(`transaction ${hash} not in pool`);
2559
+ return;
2610
2560
  }
2611
- console.log(`removing invalid transaction: ${hash}`)
2612
- await globalThis.transactionPoolStore.delete(hash)
2561
+ console.log(`removing invalid transaction: ${hash}`);
2562
+ await globalThis.transactionPoolStore.delete(hash);
2613
2563
  }
2614
2564
  async #validatorTimeout(validatorInfo) {
2615
- const address = validatorInfo?.address
2616
- if (!address) return
2617
- const timeout = Math.min(Math.max(Number(validatorInfo.timeout) || 0, 0), 60 * 60 * 1e3)
2618
- const existingRelease = this.#jailReleaseTimers.get(address)
2619
- if (existingRelease) clearTimeout(existingRelease)
2620
- this.#jail.add(address)
2565
+ const address = validatorInfo?.address;
2566
+ if (!address) return;
2567
+ const timeout = Math.min(Math.max(Number(validatorInfo.timeout) || 0, 0), 60 * 60 * 1e3);
2568
+ const existingRelease = this.#jailReleaseTimers.get(address);
2569
+ if (existingRelease) clearTimeout(existingRelease);
2570
+ this.#jail.add(address);
2621
2571
  const releaseTimer = setTimeout(() => {
2622
- this.#jail.delete(address)
2623
- this.#jailReleaseTimers.delete(address)
2624
- }, timeout)
2625
- this.#jailReleaseTimers.set(address, releaseTimer)
2626
- }
2627
- #castVote
2628
- #handleProposal
2629
- #handlePrevote
2630
- #handlePrecommit
2631
- #addTransaction
2572
+ this.#jail.delete(address);
2573
+ this.#jailReleaseTimers.delete(address);
2574
+ }, timeout);
2575
+ this.#jailReleaseTimers.set(address, releaseTimer);
2576
+ }
2577
+ #castVote;
2578
+ #handleProposal;
2579
+ #handlePrevote;
2580
+ #handlePrecommit;
2581
+ #addTransaction;
2632
2582
  async #prepareRequest(request) {
2633
- let node = await new globalThis.peernet.protos['peernet-request']({ request })
2634
- return globalThis.peernet.prepareMessage(node)
2583
+ let node = await new globalThis.peernet.protos["peernet-request"]({ request });
2584
+ return globalThis.peernet.prepareMessage(node);
2635
2585
  }
2636
2586
  async #makeRequest(peer, request) {
2637
- const node = await this.#prepareRequest(request)
2587
+ const node = await this.#prepareRequest(request);
2638
2588
  try {
2639
- let response = await peer.request(node.encoded)
2640
- if (response === undefined || response === null) return response
2589
+ let response = await peer.request(node.encoded);
2590
+ console.log(`raw response for request ${request}:`, response);
2591
+ if (response === void 0 || response === null) return response;
2641
2592
  const normalizeResponse = async (payload) => {
2642
- if (payload === undefined || payload === null) return payload
2643
- if (payload && typeof payload === 'object') {
2644
- if ('decoded' in payload && payload.decoded && 'response' in payload.decoded) {
2645
- return normalizeResponse(payload.decoded.response)
2593
+ if (payload === void 0 || payload === null) return payload;
2594
+ if (payload && typeof payload === "object") {
2595
+ if ("decoded" in payload && payload?.decoded && "response" in payload.decoded) {
2596
+ return normalizeResponse(payload.decoded.response);
2646
2597
  }
2647
- if ('response' in payload) {
2648
- return normalizeResponse(payload.response)
2598
+ if ("response" in payload) {
2599
+ return normalizeResponse(payload.response);
2649
2600
  }
2650
2601
  }
2651
- if (payload instanceof Uint8Array || (typeof Buffer !== 'undefined' && Buffer.isBuffer(payload))) {
2652
- return payload instanceof Uint8Array ? payload : new Uint8Array(payload)
2602
+ if (payload instanceof Uint8Array || typeof Buffer !== "undefined" && Buffer.isBuffer(payload)) {
2603
+ const bytes = payload instanceof Uint8Array ? payload : new Uint8Array(payload);
2604
+ try {
2605
+ const wrapped = await new globalThis.peernet.protos["peernet-response"](bytes);
2606
+ if (wrapped?.decoded?.response !== void 0) {
2607
+ return wrapped.decoded.response;
2608
+ }
2609
+ } catch {
2610
+ }
2611
+ try {
2612
+ return JSON.parse(new TextDecoder().decode(bytes));
2613
+ } catch {
2614
+ return bytes;
2615
+ }
2653
2616
  }
2654
- if (typeof payload === 'string') {
2617
+ if (typeof payload === "string") {
2655
2618
  try {
2656
- return JSON.parse(payload)
2619
+ return JSON.parse(payload);
2657
2620
  } catch {
2658
- return payload
2621
+ return payload;
2659
2622
  }
2660
2623
  }
2661
- return payload
2662
- }
2663
- return await normalizeResponse(response)
2624
+ return payload;
2625
+ };
2626
+ return await normalizeResponse(response);
2664
2627
  } catch (error) {
2665
- const peerId = peer?.peerId || peer?.id || peer?.address || 'unknown'
2666
- debug(`peernet request failed: ${request} -> ${peerId}:`, error?.message ?? error)
2667
- throw error
2628
+ const peerId = peer?.peerId || peer?.id || peer?.address || "unknown";
2629
+ debug(`peernet request failed: ${request} -> ${peerId}:`, error?.message ?? error);
2630
+ throw error;
2668
2631
  }
2669
2632
  }
2670
2633
  async #decodeKnownBlocksResponse(response) {
2671
- if (!response) return null
2634
+ if (!response) return null;
2672
2635
  if (Array.isArray(response)) {
2673
- return { blocks: response }
2636
+ return { blocks: response };
2674
2637
  }
2675
2638
  if (Array.isArray(response.blocks)) {
2676
- return { blocks: response.blocks }
2639
+ return { blocks: response.blocks };
2677
2640
  }
2678
2641
  if (response.response && Array.isArray(response.response.blocks)) {
2679
- return { blocks: response.response.blocks }
2642
+ return { blocks: response.response.blocks };
2680
2643
  }
2681
- if (typeof response === 'string') {
2644
+ if (typeof response === "string") {
2682
2645
  try {
2683
- const parsed = JSON.parse(response)
2684
- if (Array.isArray(parsed)) return { blocks: parsed }
2685
- if (parsed && Array.isArray(parsed.blocks)) return { blocks: parsed.blocks }
2686
- if (parsed?.response && Array.isArray(parsed.response.blocks)) return { blocks: parsed.response.blocks }
2646
+ const parsed = JSON.parse(response);
2647
+ if (Array.isArray(parsed)) return { blocks: parsed };
2648
+ if (parsed && Array.isArray(parsed.blocks)) return { blocks: parsed.blocks };
2649
+ if (parsed?.response && Array.isArray(parsed.response.blocks)) return { blocks: parsed.response.blocks };
2687
2650
  } catch {
2688
- return null
2651
+ return null;
2689
2652
  }
2690
- return null
2653
+ return null;
2691
2654
  }
2692
- if (!(response instanceof Uint8Array)) return null
2693
- let payload = response
2655
+ if (!(response instanceof Uint8Array)) return null;
2656
+ let payload = response;
2694
2657
  for (let i = 0; i < 3; i++) {
2695
- if (!(payload instanceof Uint8Array)) break
2658
+ if (!(payload instanceof Uint8Array)) break;
2696
2659
  try {
2697
- const nestedResponse = await new globalThis.peernet.protos['peernet-response'](payload)
2698
- payload = nestedResponse?.decoded?.response
2660
+ const nestedResponse = await new globalThis.peernet.protos["peernet-response"](payload);
2661
+ payload = nestedResponse?.decoded?.response;
2699
2662
  } catch {
2700
- break
2663
+ break;
2701
2664
  }
2702
2665
  }
2703
- if (Array.isArray(payload)) return { blocks: payload }
2704
- if (payload && Array.isArray(payload.blocks)) return { blocks: payload.blocks }
2705
- if (payload?.response && Array.isArray(payload.response.blocks)) return { blocks: payload.response.blocks }
2666
+ if (Array.isArray(payload)) return { blocks: payload };
2667
+ if (payload && Array.isArray(payload.blocks)) return { blocks: payload.blocks };
2668
+ if (payload?.response && Array.isArray(payload.response.blocks)) return { blocks: payload.response.blocks };
2706
2669
  try {
2707
- const decoded = new TextDecoder().decode(response)
2708
- const parsed = JSON.parse(decoded)
2709
- if (Array.isArray(parsed)) return { blocks: parsed }
2710
- if (parsed && Array.isArray(parsed.blocks)) return { blocks: parsed.blocks }
2711
- if (parsed?.response && Array.isArray(parsed.response.blocks)) return { blocks: parsed.response.blocks }
2670
+ const decoded = new TextDecoder().decode(response);
2671
+ const parsed = JSON.parse(decoded);
2672
+ if (Array.isArray(parsed)) return { blocks: parsed };
2673
+ if (parsed && Array.isArray(parsed.blocks)) return { blocks: parsed.blocks };
2674
+ if (parsed?.response && Array.isArray(parsed.response.blocks)) return { blocks: parsed.response.blocks };
2712
2675
  } catch {
2713
- return null
2676
+ return null;
2714
2677
  }
2715
- return null
2678
+ return null;
2716
2679
  }
2717
2680
  async getPeerTransactionPool(peer) {
2718
- let transactionsInPool = await this.#makeRequest(peer, 'transactionPool')
2681
+ let transactionsInPool = await this.#makeRequest(peer, "transactionPool");
2682
+ console.log("raw response for request transactionPool:", transactionsInPool);
2719
2683
  if (transactionsInPool instanceof Uint8Array) {
2720
- debug('transactionPool response must be decoded array payload')
2721
- return []
2684
+ debug("transactionPool response must be decoded array payload");
2685
+ return [];
2722
2686
  }
2723
- if (!Array.isArray(transactionsInPool)) return []
2724
- const localTransactions = new Set(await globalThis.transactionPoolStore.keys())
2725
- const transactionsToGet = []
2687
+ if (!Array.isArray(transactionsInPool)) return [];
2688
+ const localTransactions = new Set(await globalThis.transactionPoolStore.keys());
2689
+ const transactionsToGet = [];
2726
2690
  for (const key of transactionsInPool) {
2727
2691
  if (!localTransactions.has(key)) {
2728
- let txData
2692
+ let txData;
2729
2693
  try {
2730
- txData = await globalThis.peernet.get(key, 'transaction')
2694
+ txData = await globalThis.peernet.get(key, "transaction");
2731
2695
  } catch (error) {
2732
- debug(`Failed to get transaction ${key}:`, error?.message ?? error)
2696
+ debug(`Failed to get transaction ${key}:`, error?.message ?? error);
2733
2697
  }
2734
2698
  if (txData !== void 0) {
2735
- transactionsToGet.push(transactionPoolStore.put(key, txData))
2699
+ transactionsToGet.push(transactionPoolStore.put(key, txData));
2736
2700
  }
2737
2701
  }
2738
2702
  }
2739
- return Promise.all(transactionsToGet)
2703
+ return Promise.all(transactionsToGet);
2740
2704
  }
2741
2705
  async #peerConnected(peerId) {
2742
- debug(`peer connected: ${peerId}`)
2743
- const peer = peernet.getConnection(peerId)
2706
+ debug(`peer connected: ${peerId}`);
2707
+ const peer = peernet.getConnection(peerId);
2744
2708
  if (!peer) {
2745
- debug(`peer not found: ${peerId}`)
2746
- return
2709
+ debug(`peer not found: ${peerId}`);
2710
+ return;
2747
2711
  }
2748
2712
  if (!peer.version) {
2749
2713
  try {
2750
- let versionResponse = await this.#makeRequest(peer, 'version')
2714
+ let versionResponse = await this.#makeRequest(peer, "version");
2751
2715
  if (versionResponse instanceof Uint8Array) {
2752
- versionResponse = new TextDecoder().decode(versionResponse)
2716
+ versionResponse = new TextDecoder().decode(versionResponse);
2753
2717
  }
2754
- if (typeof versionResponse === 'string') {
2755
- peer.version = versionResponse
2756
- } else if (
2757
- versionResponse &&
2758
- typeof versionResponse === 'object' &&
2759
- typeof versionResponse.version === 'string'
2760
- ) {
2761
- peer.version = versionResponse.version
2718
+ if (typeof versionResponse === "string") {
2719
+ peer.version = versionResponse;
2720
+ } else if (versionResponse && typeof versionResponse === "object" && typeof versionResponse.version === "string") {
2721
+ peer.version = versionResponse.version;
2762
2722
  }
2763
- if (!peer.version || typeof peer.version !== 'string') {
2764
- const reason = `invalid version response from peer ${peerId}`
2765
- debug(reason)
2766
- await this.#recordPeerFailure(peerId, reason)
2767
- return
2723
+ if (!peer.version || typeof peer.version !== "string") {
2724
+ const reason = `invalid version response from peer ${peerId}`;
2725
+ debug(reason);
2726
+ await this.#recordPeerFailure(peerId, reason);
2727
+ return;
2768
2728
  }
2769
2729
  } catch (error) {
2770
- debug(`failed to request version from peer ${peerId}:`, error?.message ?? error)
2771
- return
2730
+ debug(`failed to request version from peer ${peerId}:`, error?.message ?? error);
2731
+ return;
2772
2732
  }
2773
2733
  }
2774
- debug(`peer connected with version ${peer.version}`)
2734
+ debug(`peer connected with version ${peer.version}`);
2775
2735
  if (!this.isVersionCompatible(peer.version)) {
2776
- const mismatchReason = `incompatible peer version ${peer.version} (local: ${this.version})`
2777
- console.error(`[chain] ${mismatchReason}`)
2778
- await this.#recordPeerFailure(peerId, mismatchReason)
2779
- return
2736
+ const mismatchReason = `incompatible peer version ${peer.version} (local: ${this.version})`;
2737
+ console.error(`[chain] ${mismatchReason}`);
2738
+ await this.#recordPeerFailure(peerId, mismatchReason);
2739
+ return;
2780
2740
  }
2781
- let lastBlock
2741
+ let lastBlock;
2782
2742
  try {
2783
- console.log('requesting last block from peer...')
2784
- console.log(await this.lastBlock)
2785
- console.log('peer response:')
2786
- const lastBlockRaw = await this.#makeRequest(peer, 'lastBlock')
2787
- if (
2788
- lastBlockRaw === undefined ||
2789
- lastBlockRaw === null ||
2790
- (typeof lastBlockRaw !== 'object' && !(lastBlockRaw instanceof Uint8Array))
2791
- ) {
2792
- throw new Error(`invalid lastBlock payload: ${typeof lastBlockRaw}`)
2793
- }
2794
- console.log('raw last block response:', lastBlockRaw)
2795
- console.log(new LastBlockMessage(lastBlockRaw))
2796
- lastBlock = new LastBlockMessage(lastBlockRaw).decoded
2743
+ console.log("requesting last block from peer...");
2744
+ console.log(await this.lastBlock);
2745
+ const lastBlockRaw = await this.#makeRequest(peer, "lastBlock");
2746
+ console.log("raw last block response:", lastBlockRaw);
2747
+ if (lastBlockRaw === void 0 || lastBlockRaw === null || typeof lastBlockRaw !== "object" && !(lastBlockRaw instanceof Uint8Array)) {
2748
+ throw new Error(`invalid lastBlock payload: ${typeof lastBlockRaw}`);
2749
+ }
2750
+ console.log(new LastBlockMessage(lastBlockRaw));
2751
+ lastBlock = new LastBlockMessage(lastBlockRaw).decoded;
2797
2752
  } catch (error) {
2798
- const peerName = peer?.peerId || peer?.id || peer?.address || peerId || 'unknown'
2799
- debug(`lastBlock request failed: ${peerName}:`, error?.message ?? error)
2800
- await this.#recordPeerFailure(peerId, `lastBlock request failed: ${error?.message ?? error}`)
2801
- return
2753
+ const peerName = peer?.peerId || peer?.id || peer?.address || peerId || "unknown";
2754
+ debug(`lastBlock request failed: ${peerName}:`, error?.message ?? error);
2755
+ await this.#recordPeerFailure(peerId, `lastBlock request failed: ${error?.message ?? error}`);
2756
+ return;
2802
2757
  }
2803
- const localBlock = await this.lastBlock
2804
- const MAX_SYNC_AHEAD = 1e5
2758
+ const localBlock = await this.lastBlock;
2759
+ const MAX_SYNC_AHEAD = 1e5;
2805
2760
  if (lastBlock?.index > BigInt(localBlock?.index ?? 0) + BigInt(MAX_SYNC_AHEAD)) {
2806
- const peerName = peer?.peerId || peer?.id || peer?.address || peerId || 'unknown'
2807
- debug(`Peer ${peerName} claims unreasonable block height ${lastBlock.index} (local: ${localBlock?.index ?? 0})`)
2808
- await this.#recordPeerFailure(peerId, `unreasonable lastBlock index: ${lastBlock.index}`)
2809
- return
2761
+ const peerName = peer?.peerId || peer?.id || peer?.address || peerId || "unknown";
2762
+ debug(`Peer ${peerName} claims unreasonable block height ${lastBlock.index} (local: ${localBlock?.index ?? 0})`);
2763
+ await this.#recordPeerFailure(peerId, `unreasonable lastBlock index: ${lastBlock.index}`);
2764
+ return;
2810
2765
  }
2811
- if (!lastBlock || !lastBlock.hash || lastBlock.hash === '0x0') {
2812
- debug(`peer has no lastBlock: ${peerId}`)
2813
- return
2766
+ if (!lastBlock || !lastBlock.hash || lastBlock.hash === "0x0") {
2767
+ debug(`peer has no lastBlock: ${peerId}`);
2768
+ return;
2814
2769
  }
2815
- const higherThenCurrentLocal = !localBlock?.index ? true : lastBlock.index > localBlock.index
2770
+ const higherThenCurrentLocal = !localBlock?.index ? true : lastBlock.index > localBlock.index;
2816
2771
  if (lastBlock) {
2817
2772
  if (!this.lastBlock || higherThenCurrentLocal) {
2818
2773
  try {
2819
- const knownBlocksRaw = await this.#makeRequest(peer, 'knownBlocks')
2820
- const knownBlocksResponse = await this.#decodeKnownBlocksResponse(knownBlocksRaw)
2774
+ const knownBlocksRaw = await this.#makeRequest(peer, "knownBlocks");
2775
+ const knownBlocksResponse = await this.#decodeKnownBlocksResponse(knownBlocksRaw);
2821
2776
  if (!knownBlocksResponse) {
2822
2777
  debug(
2823
2778
  `knownBlocks decode failed for peer ${peerId} (non-fatal), continuing sync without prefilled wantList`
2824
- )
2779
+ );
2825
2780
  } else {
2826
- const MAX_WANTLIST_SIZE = 1e3
2827
- const remaining = MAX_WANTLIST_SIZE - this.wantList.length
2781
+ const MAX_WANTLIST_SIZE = 1e3;
2782
+ const remaining = MAX_WANTLIST_SIZE - this.wantList.length;
2828
2783
  if (remaining > 0) {
2829
2784
  for (const hash of knownBlocksResponse.blocks.slice(0, remaining)) {
2830
- this.wantList.push(hash)
2785
+ this.wantList.push(hash);
2831
2786
  }
2832
2787
  }
2833
2788
  }
2834
2789
  } catch (error) {
2835
- const peerName = peer?.peerId || peer?.id || peer?.address || peerId || 'unknown'
2790
+ const peerName = peer?.peerId || peer?.id || peer?.address || peerId || "unknown";
2836
2791
  debug(
2837
2792
  `knownBlocks request failed: ${peerName} (non-fatal), continuing sync without prefilled wantList:`,
2838
2793
  error?.message ?? error
2839
- )
2794
+ );
2840
2795
  }
2841
2796
  }
2842
2797
  }
2843
2798
  if (this.wantList.length > 0) {
2844
- const promises = await Promise.allSettled(this.wantList.map((hash) => peernet.get(hash, 'block')))
2799
+ const promises = await Promise.allSettled(this.wantList.map((hash) => peernet.get(hash, "block")));
2845
2800
  for (let i = 0; i < promises.length; i++) {
2846
- const result = promises[i]
2847
- if (result.status === 'fulfilled') this.wantList.splice(i, 1)
2801
+ const result = promises[i];
2802
+ if (result.status === "fulfilled") this.wantList.splice(i, 1);
2848
2803
  }
2849
- if (this.wantList.length === 0) await this.triggerSync()
2804
+ if (this.wantList.length === 0) await this.triggerSync();
2850
2805
  }
2851
2806
  setTimeout(async () => {
2852
2807
  try {
2853
- const peerTransactionPool = (higherThenCurrentLocal && (await this.getPeerTransactionPool(peer))) || []
2854
- if (this.#participating && peerTransactionPool.length > 0) return this.#runEpoch()
2808
+ const peerTransactionPool = higherThenCurrentLocal && await this.getPeerTransactionPool(peer) || [];
2809
+ if (this.#participating && peerTransactionPool.length > 0) return this.#runEpoch();
2855
2810
  } catch (error) {
2856
- const peerName = peer?.peerId || peer?.id || peer?.address || peerId || 'unknown'
2857
- debug(`transactionPool request failed: ${peerName}:`, error?.message ?? error)
2811
+ const peerName = peer?.peerId || peer?.id || peer?.address || peerId || "unknown";
2812
+ debug(`transactionPool request failed: ${peerName}:`, error?.message ?? error);
2858
2813
  }
2859
- }, 3e3)
2814
+ }, 3e3);
2860
2815
  try {
2861
- let stateInfo = await this.#makeRequest(peer, 'stateInfo')
2816
+ let stateInfo = await this.#makeRequest(peer, "stateInfo");
2862
2817
  if (stateInfo instanceof Uint8Array) {
2863
- const decodedStateInfo = new StateMessage(stateInfo).decoded
2864
- stateInfo = decodedStateInfo?.values ?? decodedStateInfo
2818
+ const decodedStateInfo = new StateMessage(stateInfo).decoded;
2819
+ stateInfo = decodedStateInfo?.values ?? decodedStateInfo;
2865
2820
  }
2866
2821
  debug(
2867
- `sync start with peer ${peerId}: local=${localBlock?.index ?? -1} remote=${lastBlock?.index ?? -1} hash=${
2868
- lastBlock?.hash
2869
- }`
2870
- )
2871
- await this.syncChain(lastBlock)
2822
+ `sync start with peer ${peerId}: local=${localBlock?.index ?? -1} remote=${lastBlock?.index ?? -1} hash=${lastBlock?.hash}`
2823
+ );
2824
+ await this.syncChain(lastBlock);
2872
2825
  debug(
2873
2826
  `sync finished with peer ${peerId}: state=${this.syncState} localNow=${(await this.lastBlock)?.index ?? -1}`
2874
- )
2875
- this.machine.states.info = stateInfo
2827
+ );
2828
+ this.machine.states.info = stateInfo;
2876
2829
  } catch (error) {
2877
- const peerName = peer?.peerId || peer?.id || peer?.address || peerId || 'unknown'
2878
- debug(`stateInfo/syncChain failed: ${peerName}:`, error?.message ?? error)
2879
- await this.#recordPeerFailure(peerId, `stateInfo/syncChain failed: ${error?.message ?? error}`)
2880
- return
2830
+ const peerName = peer?.peerId || peer?.id || peer?.address || peerId || "unknown";
2831
+ debug(`stateInfo/syncChain failed: ${peerName}:`, error?.message ?? error);
2832
+ await this.#recordPeerFailure(peerId, `stateInfo/syncChain failed: ${error?.message ?? error}`);
2833
+ return;
2881
2834
  }
2882
2835
  }
2883
- #epochTimeout
2836
+ #epochTimeout;
2884
2837
  async #transactionPoolHandler() {
2885
- const pool = await globalThis.transactionPoolStore.keys()
2886
- return new globalThis.peernet.protos['peernet-response']({ response: pool })
2838
+ const pool = await globalThis.transactionPoolStore.keys();
2839
+ return new globalThis.peernet.protos["peernet-response"]({ response: pool });
2887
2840
  }
2888
2841
  async #versionHandler() {
2889
- return new globalThis.peernet.protos['peernet-response']({ response: this.version })
2842
+ return new globalThis.peernet.protos["peernet-response"]({ response: this.version });
2890
2843
  }
2891
2844
  async #executeTransaction({ hash, from, to, method, params, nonce }) {
2892
2845
  try {
2893
- let result = await this.machine.execute(to, method, params)
2894
- globalThis.pubsub.publish(`transaction.completed.${hash}`, { status: 'fulfilled', hash })
2895
- return result || 'no state change'
2846
+ let result = await this.machine.execute(to, method, params);
2847
+ globalThis.pubsub.publish(`transaction.completed.${hash}`, { status: "fulfilled", hash });
2848
+ return result || "no state change";
2896
2849
  } catch (error) {
2897
- await transactionPoolStore.delete(hash)
2850
+ await transactionPoolStore.delete(hash);
2898
2851
  try {
2899
- globalThis.peernet.publish('invalid-transaction', hash)
2852
+ globalThis.peernet.publish("invalid-transaction", hash);
2900
2853
  } catch (publishError) {
2901
- debug('peernet publish failed: invalid-transaction', publishError?.message ?? publishError)
2854
+ debug("peernet publish failed: invalid-transaction", publishError?.message ?? publishError);
2902
2855
  }
2903
- globalThis.pubsub.publish(`transaction.completed.${hash}`, { status: 'fail', hash, error })
2904
- throw { error, hash, from, to, params, nonce }
2856
+ globalThis.pubsub.publish(`transaction.completed.${hash}`, { status: "fail", hash, error });
2857
+ throw { error, hash, from, to, params, nonce };
2905
2858
  }
2906
2859
  }
2907
2860
  async #addBlock(block) {
2908
- const receivedEncoded = block instanceof BlockMessage ? block.encoded : block
2909
- const blockMessage = await new BlockMessage(block)
2910
- const hash = await blockMessage.hash()
2911
- const blockIndex = Number(blockMessage.decoded.index)
2912
- const existingBlockAtHeight = this.#blocks[blockIndex]
2861
+ const receivedEncoded = block instanceof BlockMessage ? block.encoded : block;
2862
+ const blockMessage = await new BlockMessage(block);
2863
+ const hash = await blockMessage.hash();
2864
+ const blockIndex = Number(blockMessage.decoded.index);
2865
+ const existingBlockAtHeight = this.#blocks[blockIndex];
2913
2866
  if (existingBlockAtHeight) {
2914
2867
  if (existingBlockAtHeight.hash !== hash) {
2915
- console.error(` Local: ${existingBlockAtHeight.hash}`)
2916
- console.error(` Remote: ${hash}`)
2917
- throw new Error(`Block conflict detected at index ${blockIndex}`)
2868
+ console.error(` Local: ${existingBlockAtHeight.hash}`);
2869
+ console.error(` Remote: ${hash}`);
2870
+ throw new Error(`Block conflict detected at index ${blockIndex}`);
2918
2871
  }
2919
- debug(`Block already in store: ${hash}`)
2920
- return
2872
+ debug(`Block already in store: ${hash}`);
2873
+ return;
2921
2874
  }
2922
2875
  if (blockIndex > 0) {
2923
- const previousBlockInfo = this.#blocks[blockIndex - 1]
2876
+ const previousBlockInfo = this.#blocks[blockIndex - 1];
2924
2877
  if (!previousBlockInfo) {
2925
- throw new Error(`Missing parent block at index ${blockIndex - 1}`)
2878
+ throw new Error(`Missing parent block at index ${blockIndex - 1}`);
2926
2879
  }
2927
2880
  if (previousBlockInfo.hash !== blockMessage.decoded.previousHash) {
2928
2881
  throw new Error(
2929
2882
  `previousHash mismatch at index ${blockIndex}: expected ${previousBlockInfo.hash}, got ${blockMessage.decoded.previousHash}`
2930
- )
2883
+ );
2931
2884
  }
2932
- } else if (blockMessage.decoded.previousHash !== '0x0') {
2933
- throw new Error(`Genesis block (index 0) must have previousHash='0x0'`)
2885
+ } else if (blockMessage.decoded.previousHash !== "0x0") {
2886
+ throw new Error(`Genesis block (index 0) must have previousHash='0x0'`);
2934
2887
  }
2935
- const canonicalEncoded = blockMessage.encoded
2936
- const byteLengthMatch = receivedEncoded.length === canonicalEncoded.length
2888
+ const canonicalEncoded = blockMessage.encoded;
2889
+ const byteLengthMatch = receivedEncoded.length === canonicalEncoded.length;
2937
2890
  if (!byteLengthMatch) {
2938
2891
  throw new Error(
2939
2892
  `[FATAL] Block data size mismatch: received ${receivedEncoded.length} bytes but canonical encoding is ${canonicalEncoded.length} bytes for block #${blockMessage.decoded.index}`
2940
- )
2893
+ );
2941
2894
  }
2942
- let mismatch = false
2895
+ let mismatch = false;
2943
2896
  for (let i = 0; i < receivedEncoded.length; i++) {
2944
2897
  if (receivedEncoded[i] !== canonicalEncoded[i]) {
2945
- mismatch = true
2946
- break
2898
+ mismatch = true;
2899
+ break;
2947
2900
  }
2948
2901
  }
2949
2902
  if (mismatch) {
2950
- throw new Error(`[FATAL] Block data corrupted in transit for block #${blockIndex} hash ${hash}`)
2903
+ throw new Error(`[FATAL] Block data corrupted in transit for block #${blockIndex} hash ${hash}`);
2951
2904
  }
2952
- console.log(`[chain] \u2705 Block data integrity verified: ${hash}`)
2953
- this.#validateBlockValidators(blockMessage)
2905
+ console.log(`[chain] \u2705 Block data integrity verified: ${hash}`);
2906
+ this.#validateBlockValidators(blockMessage);
2954
2907
  const transactions = await Promise.all(
2955
2908
  blockMessage.decoded.transactions.map(async (hash2) => {
2956
- const data = await peernet.get(hash2, 'transaction')
2957
- ;(await transactionPoolStore.has(hash2)) && (await transactionPoolStore.delete(hash2))
2958
- return new TransactionMessage(data)
2909
+ const data = await peernet.get(hash2, "transaction");
2910
+ await transactionPoolStore.has(hash2) && await transactionPoolStore.delete(hash2);
2911
+ return new TransactionMessage(data);
2959
2912
  })
2960
- )
2961
- await globalThis.blockStore.put(hash, blockMessage.encoded)
2913
+ );
2914
+ await globalThis.blockStore.put(hash, blockMessage.encoded);
2962
2915
  this.#blocks[blockIndex] = {
2963
2916
  hash,
2964
2917
  ...blockMessage.decoded
2965
- }
2966
- debug(`added block: ${hash}`)
2967
- let promises = []
2968
- let contracts = []
2918
+ };
2919
+ debug(`added block: ${hash}`);
2920
+ let promises = [];
2921
+ let contracts = [];
2969
2922
  const allTransactions = transactions.sort((a, b) => {
2970
2923
  if (a.decoded.priority !== b.decoded.priority) {
2971
- return (b.decoded.priority ? 1 : 0) - (a.decoded.priority ? 1 : 0)
2924
+ return (b.decoded.priority ? 1 : 0) - (a.decoded.priority ? 1 : 0);
2972
2925
  }
2973
- const nonceDiff = (a.decoded?.nonce ?? 0) - (b.decoded?.nonce ?? 0)
2974
- if (nonceDiff !== 0) return nonceDiff
2975
- return 0
2976
- })
2977
- const txsByAddress = /* @__PURE__ */ new Map()
2926
+ const nonceDiff = (a.decoded?.nonce ?? 0) - (b.decoded?.nonce ?? 0);
2927
+ if (nonceDiff !== 0) return nonceDiff;
2928
+ return 0;
2929
+ });
2930
+ const txsByAddress = /* @__PURE__ */ new Map();
2978
2931
  for (const transaction of allTransactions) {
2979
- const sender = transaction.decoded.from
2932
+ const sender = transaction.decoded.from;
2980
2933
  if (!txsByAddress.has(sender)) {
2981
- txsByAddress.set(sender, [])
2934
+ txsByAddress.set(sender, []);
2982
2935
  }
2983
- txsByAddress.get(sender).push(transaction)
2936
+ txsByAddress.get(sender).push(transaction);
2984
2937
  }
2985
- const addressGroups = [...txsByAddress.values()]
2938
+ const addressGroups = [...txsByAddress.values()];
2986
2939
  await Promise.all(
2987
2940
  addressGroups.map(async (addressTxs) => {
2988
2941
  for (const transaction of addressTxs) {
2989
2942
  if (!contracts.includes(transaction.decoded.to)) {
2990
- contracts.push(transaction.decoded.to)
2943
+ contracts.push(transaction.decoded.to);
2991
2944
  }
2992
- this.removePendingNonce(transaction.decoded.from, transaction.decoded.nonce)
2993
- await this.#handleTransaction(transaction, [])
2945
+ this.removePendingNonce(transaction.decoded.from, transaction.decoded.nonce);
2946
+ await this.#handleTransaction(transaction, []);
2994
2947
  }
2995
2948
  })
2996
- )
2949
+ );
2997
2950
  try {
2998
- promises = await Promise.allSettled(promises)
2999
- const noncesByAddress = {}
2951
+ promises = await Promise.allSettled(promises);
2952
+ const noncesByAddress = {};
3000
2953
  for (let transaction of transactions) {
3001
- globalThis.pubsub.publish('transaction-processed', transaction.encoded)
2954
+ globalThis.pubsub.publish("transaction-processed", transaction.encoded);
3002
2955
  if (transaction.decoded.to === globalThis.peernet.selectedAccount)
3003
- globalThis.pubsub.publish('account-transaction-processed', transaction.encoded)
3004
- if (
3005
- !noncesByAddress[transaction.decoded.from] ||
3006
- noncesByAddress?.[transaction.decoded.from] < transaction.decoded.nonce
3007
- ) {
3008
- noncesByAddress[transaction.decoded.from] = transaction.decoded.nonce
2956
+ globalThis.pubsub.publish("account-transaction-processed", transaction.encoded);
2957
+ if (!noncesByAddress[transaction.decoded.from] || noncesByAddress?.[transaction.decoded.from] < transaction.decoded.nonce) {
2958
+ noncesByAddress[transaction.decoded.from] = transaction.decoded.nonce;
3009
2959
  }
3010
2960
  }
3011
2961
  await Promise.all(
3012
2962
  Object.entries(noncesByAddress).map(([from, nonce]) => globalThis.accountsStore.put(from, String(nonce)))
3013
- )
2963
+ );
3014
2964
  if ((await this.lastBlock).index < Number(blockMessage.decoded.index)) {
3015
- await this.machine.addLoadedBlock({ ...blockMessage.decoded, loaded: true, hash: await blockMessage.hash() })
2965
+ await this.machine.addLoadedBlock({ ...blockMessage.decoded, loaded: true, hash: await blockMessage.hash() });
3016
2966
  try {
3017
- await this.call(addresses.validators, 'recordValidatorSnapshot', [blockMessage.decoded.index])
2967
+ await this.call(addresses.validators, "recordValidatorSnapshot", [blockMessage.decoded.index]);
3018
2968
  } catch (snapshotError) {
3019
- debug(`failed to record validator snapshot: ${snapshotError?.message ?? snapshotError}`)
2969
+ debug(`failed to record validator snapshot: ${snapshotError?.message ?? snapshotError}`);
3020
2970
  }
3021
- await this.#handleEpochBoundary(Number(blockMessage.decoded.index))
3022
- await this.updateState(blockMessage)
2971
+ await this.#handleEpochBoundary(Number(blockMessage.decoded.index));
2972
+ await this.updateState(blockMessage);
3023
2973
  }
3024
- globalThis.pubsub.publish('block-processed', blockMessage.decoded)
2974
+ globalThis.pubsub.publish("block-processed", blockMessage.decoded);
3025
2975
  } catch (error) {
3026
- console.log(error.hash)
3027
- console.log('errrrr')
3028
- await transactionPoolStore.delete(error.hash)
2976
+ console.log(error.hash);
2977
+ console.log("errrrr");
2978
+ await transactionPoolStore.delete(error.hash);
3029
2979
  }
3030
2980
  }
3031
2981
  async participate(address) {
3032
- this.#participating = true
2982
+ this.#participating = true;
3033
2983
  try {
3034
- if (!(await this.staticCall(addresses.validators, 'has', [address]))) {
2984
+ if (!await this.staticCall(addresses.validators, "has", [address])) {
3035
2985
  const rawTransaction = {
3036
2986
  from: address,
3037
2987
  to: addresses.validators,
3038
- method: 'addValidator',
2988
+ method: "addValidator",
3039
2989
  params: [address],
3040
- nonce: (await this.getNonce(address)) + 1,
2990
+ nonce: await this.getNonce(address) + 1,
3041
2991
  timestamp: Date.now()
3042
- }
3043
- const transaction = await signTransaction(rawTransaction, globalThis.peernet.identity)
2992
+ };
2993
+ const transaction = await signTransaction(rawTransaction, globalThis.peernet.identity);
3044
2994
  try {
3045
- await this.sendTransaction(transaction)
2995
+ await this.sendTransaction(transaction);
3046
2996
  } catch (error) {
3047
- console.error(error)
2997
+ console.error(error);
3048
2998
  }
3049
2999
  }
3050
3000
  } catch (error) {
3051
- debug('Error in participate:', error.message)
3001
+ debug("Error in participate:", error.message);
3052
3002
  }
3053
- if ((await this.hasTransactionToHandle()) && !this.#runningEpoch && this.#participating) await this.#runEpoch()
3003
+ if (await this.hasTransactionToHandle() && !this.#runningEpoch && this.#participating) await this.#runEpoch();
3054
3004
  }
3055
3005
  async #handleTransaction(transaction, latestTransactions, block) {
3056
- const hash = await transaction.hash()
3057
- const doubleTransactions = []
3058
- if (latestTransactions.includes(hash) || (await transactionStore.has(hash))) {
3059
- doubleTransactions.push(hash)
3006
+ const hash = await transaction.hash();
3007
+ const doubleTransactions = [];
3008
+ if (latestTransactions.includes(hash) || await transactionStore.has(hash)) {
3009
+ doubleTransactions.push(hash);
3060
3010
  }
3061
3011
  if (doubleTransactions.length > 0) {
3062
- await globalThis.transactionPoolStore.delete(hash)
3063
- await globalThis.peernet.publish('invalid-transaction', hash)
3064
- return
3012
+ await globalThis.transactionPoolStore.delete(hash);
3013
+ await globalThis.peernet.publish("invalid-transaction", hash);
3014
+ return;
3065
3015
  }
3066
3016
  try {
3067
- const result = await this.#executeTransaction({ ...transaction.decoded, hash })
3017
+ const result = await this.#executeTransaction({ ...transaction.decoded, hash });
3068
3018
  if (block) {
3069
- block.transactions.push(hash)
3070
- block.fees = block.fees += await calculateFee(transaction.decoded)
3019
+ block.transactions.push(hash);
3020
+ block.fees = block.fees += await calculateFee(transaction.decoded);
3071
3021
  }
3072
3022
  await globalThis.accountsStore.put(
3073
3023
  transaction.decoded.from,
3074
3024
  new TextEncoder().encode(String(transaction.decoded.nonce))
3075
- )
3076
- await transactionStore.put(hash, await transaction.encode())
3025
+ );
3026
+ await transactionStore.put(hash, await transaction.encode());
3077
3027
  } catch (e) {
3078
- console.log('vvvvvv')
3079
- console.log({ e })
3080
- console.log(hash)
3081
- peernet.publish('invalid-transaction', hash)
3082
- await globalThis.transactionPoolStore.delete(e.hash)
3028
+ console.log("vvvvvv");
3029
+ console.log({ e });
3030
+ console.log(hash);
3031
+ peernet.publish("invalid-transaction", hash);
3032
+ await globalThis.transactionPoolStore.delete(e.hash);
3083
3033
  }
3084
3034
  }
3085
3035
  // todo filter tx that need to wait on prev nonce
3086
3036
  async #createBlock(limit = this.transactionLimit) {
3087
- console.log(await globalThis.transactionPoolStore.size())
3088
- if ((await globalThis.transactionPoolStore.size()) === 0) return
3089
- let transactions = await globalThis.transactionPoolStore.values(this.transactionLimit)
3090
- if (Object.keys(transactions)?.length === 0) return
3091
- const timestamp = Date.now()
3037
+ console.log(await globalThis.transactionPoolStore.size());
3038
+ if (await globalThis.transactionPoolStore.size() === 0) return;
3039
+ let transactions = await globalThis.transactionPoolStore.values(this.transactionLimit);
3040
+ if (Object.keys(transactions)?.length === 0) return;
3041
+ const timestamp = Date.now();
3092
3042
  let block = {
3093
3043
  transactions: [],
3094
3044
  validators: [],
3095
3045
  fees: BigInt(0),
3096
3046
  timestamp,
3097
- previousHash: '',
3047
+ previousHash: "",
3098
3048
  reward: BigInt(150),
3099
3049
  index: 0,
3100
- producer: '',
3101
- producerProof: '',
3050
+ producer: "",
3051
+ producerProof: "",
3102
3052
  protocolVersion: this.version
3103
- }
3104
- const latestTransactions = await this.machine.latestTransactions()
3105
- transactions = await this.promiseTransactions(transactions)
3053
+ };
3054
+ const latestTransactions = await this.machine.latestTransactions();
3055
+ transactions = await this.promiseTransactions(transactions);
3106
3056
  const allTransactions = transactions.sort((a, b) => {
3107
3057
  if (a.decoded.priority !== b.decoded.priority) {
3108
- return (b.decoded.priority ? 1 : 0) - (a.decoded.priority ? 1 : 0)
3058
+ return (b.decoded.priority ? 1 : 0) - (a.decoded.priority ? 1 : 0);
3109
3059
  }
3110
- const nonceDiff = (a.decoded?.nonce ?? 0) - (b.decoded?.nonce ?? 0)
3111
- if (nonceDiff !== 0) return nonceDiff
3112
- return 0
3113
- })
3114
- const txsByAddress = /* @__PURE__ */ new Map()
3060
+ const nonceDiff = (a.decoded?.nonce ?? 0) - (b.decoded?.nonce ?? 0);
3061
+ if (nonceDiff !== 0) return nonceDiff;
3062
+ return 0;
3063
+ });
3064
+ const txsByAddress = /* @__PURE__ */ new Map();
3115
3065
  for (const transaction of allTransactions) {
3116
- const sender = transaction.decoded.from
3066
+ const sender = transaction.decoded.from;
3117
3067
  if (!txsByAddress.has(sender)) {
3118
- txsByAddress.set(sender, [])
3068
+ txsByAddress.set(sender, []);
3119
3069
  }
3120
- txsByAddress.get(sender).push(transaction)
3070
+ txsByAddress.get(sender).push(transaction);
3121
3071
  }
3122
- const addressGroups = [...txsByAddress.values()]
3072
+ const addressGroups = [...txsByAddress.values()];
3123
3073
  await Promise.all(
3124
3074
  addressGroups.map(async (addressTxs) => {
3125
3075
  for (const transaction of addressTxs) {
3126
- await this.#handleTransaction(transaction, latestTransactions, block)
3076
+ await this.#handleTransaction(transaction, latestTransactions, block);
3127
3077
  }
3128
3078
  })
3129
- )
3130
- if (block.transactions.length === 0) return
3131
- const validators = await this.staticCall(addresses.validators, 'validators')
3132
- const peers = {}
3079
+ );
3080
+ if (block.transactions.length === 0) return;
3081
+ const validators = await this.staticCall(addresses.validators, "validators");
3082
+ const peers = {};
3133
3083
  for (const entry of globalThis.peernet.peers) {
3134
- peers[entry[0]] = entry[1]
3084
+ peers[entry[0]] = entry[1];
3135
3085
  }
3136
3086
  const finalizeBWAndBroadcast = async () => {
3137
3087
  const bwPromises = validators.map(async (validator) => {
3138
- const peer = peers[validator]
3088
+ const peer = peers[validator];
3139
3089
  if (peer && peer.connected && this.isVersionCompatible(peer.version)) {
3140
3090
  try {
3141
- let data = await new BWRequestMessage()
3142
- const node = await globalThis.peernet.prepareMessage(data.encoded)
3143
- const bw = await peer.request(node.encoded)
3091
+ let data = await new BWRequestMessage();
3092
+ const node = await globalThis.peernet.prepareMessage(data.encoded);
3093
+ const bw = await peer.request(node.encoded);
3144
3094
  return {
3145
3095
  address: validator,
3146
3096
  bw: bw.up + bw.down
3147
- }
3097
+ };
3148
3098
  } catch (error) {
3149
- const peerId = peer?.peerId || peer?.id || peer?.address || 'unknown'
3150
- debug(`bw request failed: ${peerId}:`, error?.message ?? error)
3151
- return null
3099
+ const peerId = peer?.peerId || peer?.id || peer?.address || "unknown";
3100
+ debug(`bw request failed: ${peerId}:`, error?.message ?? error);
3101
+ return null;
3152
3102
  }
3153
3103
  } else if (globalThis.peernet.selectedAccount === validator) {
3154
3104
  return {
3155
3105
  address: globalThis.peernet.selectedAccount,
3156
3106
  bw: globalThis.peernet.bw.up + globalThis.peernet.bw.down
3157
- }
3107
+ };
3158
3108
  }
3159
- return null
3160
- })
3161
- const bwResults = await Promise.allSettled(bwPromises)
3109
+ return null;
3110
+ });
3111
+ const bwResults = await Promise.allSettled(bwPromises);
3162
3112
  for (const result of bwResults) {
3163
- if (result.status === 'fulfilled' && result.value) {
3164
- block.validators.push(result.value)
3113
+ if (result.status === "fulfilled" && result.value) {
3114
+ block.validators.push(result.value);
3165
3115
  }
3166
3116
  }
3167
- }
3117
+ };
3168
3118
  finalizeBWAndBroadcast().catch((error) => {
3169
- debug(`background BW finalization failed:`, error?.message ?? error)
3170
- })
3119
+ debug(`background BW finalization failed:`, error?.message ?? error);
3120
+ });
3171
3121
  block.validators = block.validators.map((validator) => {
3172
- validator.reward = block.fees
3173
- validator.reward += block.reward
3174
- validator.reward /= BigInt(block.validators.length)
3175
- delete validator.bw
3176
- return validator
3177
- })
3178
- const localBlock = await this.lastBlock
3179
- block.index = localBlock.index
3180
- if (block.index === void 0) block.index = 0
3181
- else block.index += 1
3182
- block.previousHash = localBlock.hash || '0x0'
3183
- const canonicalValidators = await this.staticCall(addresses.validators, 'validators')
3184
- const sortedValidators = [...canonicalValidators].sort()
3122
+ validator.reward = block.fees;
3123
+ validator.reward += block.reward;
3124
+ validator.reward /= BigInt(block.validators.length);
3125
+ delete validator.bw;
3126
+ return validator;
3127
+ });
3128
+ const localBlock = await this.lastBlock;
3129
+ block.index = localBlock.index;
3130
+ if (block.index === void 0) block.index = 0;
3131
+ else block.index += 1;
3132
+ block.previousHash = localBlock.hash || "0x0";
3133
+ const canonicalValidators = await this.staticCall(addresses.validators, "validators");
3134
+ const sortedValidators = [...canonicalValidators].sort();
3185
3135
  block.validators = sortedValidators.map((validatorAddress) => ({
3186
3136
  address: validatorAddress,
3187
3137
  reward: block.fees / BigInt(sortedValidators.length) + block.reward / BigInt(sortedValidators.length)
3188
- }))
3138
+ }));
3189
3139
  try {
3190
3140
  await Promise.all(
3191
3141
  block.transactions.map(async (transaction) => {
3192
- await globalThis.transactionStore.put(transaction, await transactionPoolStore.get(transaction))
3193
- await globalThis.transactionPoolStore.delete(transaction)
3142
+ await globalThis.transactionStore.put(transaction, await transactionPoolStore.get(transaction));
3143
+ await globalThis.transactionPoolStore.delete(transaction);
3194
3144
  })
3195
- )
3196
- block.producer = globalThis.peernet.selectedAccount || ''
3197
- const producerSigner = globalThis.peernet?.identity
3145
+ );
3146
+ block.producer = globalThis.peernet.selectedAccount || "";
3147
+ const producerSigner = globalThis.peernet?.identity;
3198
3148
  if (block.producer && producerSigner) {
3199
- const unsignedBlockMessage = await new BlockMessage({ ...block, producerProof: '' })
3200
- const unsignedBlockHash = await unsignedBlockMessage.hash()
3149
+ const unsignedBlockMessage = await new BlockMessage({ ...block, producerProof: "" });
3150
+ const unsignedBlockHash = await unsignedBlockMessage.hash();
3201
3151
  const signedProof = await signTransaction(
3202
3152
  {
3203
3153
  from: block.producer,
3204
3154
  to: addresses.validators,
3205
- method: 'produceBlock',
3155
+ method: "produceBlock",
3206
3156
  params: [unsignedBlockHash],
3207
3157
  timestamp: block.timestamp
3208
3158
  },
3209
3159
  producerSigner
3210
- )
3211
- block.producerProof = signedProof.signature
3212
- }
3213
- let blockMessage = await new BlockMessage(block)
3214
- const hash = await blockMessage.hash()
3215
- await globalThis.peernet.put(hash, blockMessage.encoded, 'block')
3216
- await this.machine.addLoadedBlock({ ...blockMessage.decoded, loaded: true, hash: await blockMessage.hash() })
3217
- await this.updateState(blockMessage)
3218
- debug(`created block: ${hash} @${block.index}`)
3219
- console.log(
3220
- `[consensus] \u{1F4E4} Proposing block #${block.index} | hash: ${hash} | round: ${this.#consensusRound}`
3221
- )
3160
+ );
3161
+ block.producerProof = signedProof.signature;
3162
+ }
3163
+ let blockMessage = await new BlockMessage(block);
3164
+ const hash = await blockMessage.hash();
3165
+ await globalThis.peernet.put(hash, blockMessage.encoded, "block");
3166
+ await this.machine.addLoadedBlock({ ...blockMessage.decoded, loaded: true, hash: await blockMessage.hash() });
3167
+ await this.updateState(blockMessage);
3168
+ debug(`created block: ${hash} @${block.index}`);
3169
+ console.log(`[consensus] \u{1F4E4} Proposing block #${block.index} | hash: ${hash} | round: ${this.#consensusRound}`);
3222
3170
  const proposalData = {
3223
3171
  blockHash: hash,
3224
3172
  index: BigInt(block.index),
3225
3173
  round: BigInt(this.#consensusRound),
3226
3174
  from: peernet.selectedAccount
3227
- }
3228
- const proposalMessage = new ProposalMessage(proposalData)
3229
- const proposalPayload = proposalMessage.encoded
3175
+ };
3176
+ const proposalMessage = new ProposalMessage(proposalData);
3177
+ const proposalPayload = proposalMessage.encoded;
3230
3178
  try {
3231
- globalThis.peernet.publish('consensus:propose', proposalPayload)
3179
+ globalThis.peernet.publish("consensus:propose", proposalPayload);
3232
3180
  } catch (publishError) {
3233
- debug('peernet publish failed: consensus:propose', publishError?.message ?? publishError)
3181
+ debug("peernet publish failed: consensus:propose", publishError?.message ?? publishError);
3234
3182
  }
3235
- await this.#castVote('prevote', hash, block.index, this.#consensusRound)
3183
+ await this.#castVote("prevote", hash, block.index, this.#consensusRound);
3236
3184
  } catch (error) {
3237
- console.log(error)
3238
- throw new Error(`invalid block ${block}`)
3185
+ console.log(error);
3186
+ throw new Error(`invalid block ${block}`);
3239
3187
  }
3240
3188
  }
3241
3189
  async #sendTransaction(transaction) {
3242
- transaction = await new TransactionMessage(transaction.encoded || transaction)
3243
- const hash = await transaction.hash()
3190
+ transaction = await new TransactionMessage(transaction.encoded || transaction);
3191
+ const hash = await transaction.hash();
3244
3192
  try {
3245
- const has = await globalThis.transactionPoolStore.has(hash)
3246
- if (!has && !(await transactionStore.has(hash))) {
3247
- await globalThis.transactionPoolStore.put(hash, transaction.encoded)
3193
+ const has = await globalThis.transactionPoolStore.has(hash);
3194
+ if (!has && !await transactionStore.has(hash)) {
3195
+ await globalThis.transactionPoolStore.put(hash, transaction.encoded);
3248
3196
  }
3249
- if (this.#participating && !this.#runningEpoch) this.#runEpoch()
3197
+ if (this.#participating && !this.#runningEpoch) this.#runEpoch();
3250
3198
  } catch (e) {
3251
3199
  try {
3252
- globalThis.peernet.publish('invalid-transaction', hash)
3200
+ globalThis.peernet.publish("invalid-transaction", hash);
3253
3201
  } catch (publishError) {
3254
- debug('peernet publish failed: invalid-transaction', publishError?.message ?? publishError)
3202
+ debug("peernet publish failed: invalid-transaction", publishError?.message ?? publishError);
3255
3203
  }
3256
- throw new Error('invalid transaction')
3204
+ throw new Error("invalid transaction");
3257
3205
  }
3258
3206
  }
3259
3207
  /**
@@ -3262,23 +3210,23 @@ class Chain extends VersionControl {
3262
3210
  * error is thrown on error so undefined data doesn't mean there is an error...
3263
3211
  **/
3264
3212
  async sendTransaction(transaction) {
3265
- const transactionMessage = await new TransactionMessage({ ...transaction })
3266
- const event = await super.sendTransaction(transactionMessage)
3267
- this.#sendTransaction(transactionMessage.encoded)
3213
+ const transactionMessage = await new TransactionMessage({ ...transaction });
3214
+ const event = await super.sendTransaction(transactionMessage);
3215
+ this.#sendTransaction(transactionMessage.encoded);
3268
3216
  try {
3269
- globalThis.peernet.publish('send-transaction', transactionMessage.encoded)
3217
+ globalThis.peernet.publish("send-transaction", transactionMessage.encoded);
3270
3218
  } catch (publishError) {
3271
- debug('peernet publish failed: send-transaction', publishError?.message ?? publishError)
3219
+ debug("peernet publish failed: send-transaction", publishError?.message ?? publishError);
3272
3220
  }
3273
- return event
3221
+ return event;
3274
3222
  }
3275
3223
  async addContract(transaction, contractMessage) {
3276
- const hash = await contractMessage.hash()
3277
- const has = await this.staticCall(addresses.contractFactory, 'isRegistered', [hash])
3278
- if (has) throw new Error('contract exists')
3279
- const tx = await this.sendTransaction(transaction)
3280
- await tx.wait
3281
- return tx
3224
+ const hash = await contractMessage.hash();
3225
+ const has = await this.staticCall(addresses.contractFactory, "isRegistered", [hash]);
3226
+ if (has) throw new Error("contract exists");
3227
+ const tx = await this.sendTransaction(transaction);
3228
+ await tx.wait;
3229
+ return tx;
3282
3230
  }
3283
3231
  /**
3284
3232
  *
@@ -3291,7 +3239,7 @@ class Chain extends VersionControl {
3291
3239
  sender,
3292
3240
  call: this.call,
3293
3241
  staticCall: this.staticCall
3294
- }
3242
+ };
3295
3243
  }
3296
3244
  /**
3297
3245
  *
@@ -3302,7 +3250,7 @@ class Chain extends VersionControl {
3302
3250
  * @returns
3303
3251
  */
3304
3252
  internalCall(sender, contract, method, parameters) {
3305
- return this.machine.execute(contract, method, parameters)
3253
+ return this.machine.execute(contract, method, parameters);
3306
3254
  }
3307
3255
  /**
3308
3256
  *
@@ -3312,31 +3260,31 @@ class Chain extends VersionControl {
3312
3260
  * @returns
3313
3261
  */
3314
3262
  call(contract, method, parameters) {
3315
- return this.machine.execute(contract, method, parameters)
3263
+ return this.machine.execute(contract, method, parameters);
3316
3264
  }
3317
3265
  staticCall(contract, method, parameters) {
3318
- return this.machine.get(contract, method, parameters)
3266
+ return this.machine.get(contract, method, parameters);
3319
3267
  }
3320
3268
  mint(to, amount) {
3321
- return this.call(addresses.nativeToken, 'mint', [to, amount])
3269
+ return this.call(addresses.nativeToken, "mint", [to, amount]);
3322
3270
  }
3323
3271
  transfer(from, to, amount) {
3324
- return this.call(addresses.nativeToken, 'transfer', [from, to, amount])
3272
+ return this.call(addresses.nativeToken, "transfer", [from, to, amount]);
3325
3273
  }
3326
3274
  balanceOf(address) {
3327
- return this.staticCall(addresses.nativeToken, 'balanceOf', [address])
3275
+ return this.staticCall(addresses.nativeToken, "balanceOf", [address]);
3328
3276
  }
3329
3277
  get balance() {
3330
- return this.staticCall(addresses.nativeToken, 'balanceOf', [globalThis.peernet.selectedAccount])
3278
+ return this.staticCall(addresses.nativeToken, "balanceOf", [globalThis.peernet.selectedAccount]);
3331
3279
  }
3332
3280
  get balances() {
3333
- return this.staticCall(addresses.nativeToken, 'balances')
3281
+ return this.staticCall(addresses.nativeToken, "balances");
3334
3282
  }
3335
3283
  get contracts() {
3336
- return this.staticCall(addresses.contractFactory, 'contracts')
3284
+ return this.staticCall(addresses.contractFactory, "contracts");
3337
3285
  }
3338
3286
  deleteAll() {
3339
- return this.machine.deleteAll()
3287
+ return this.machine.deleteAll();
3340
3288
  }
3341
3289
  /**
3342
3290
  * lookup an address for a registered name using the builtin nameService
@@ -3348,27 +3296,27 @@ class Chain extends VersionControl {
3348
3296
  * @example chain.lookup('myCoolContractName') // qmqsfddfdgfg...
3349
3297
  */
3350
3298
  lookup(name) {
3351
- return this.call(addresses.nameService, 'lookup', [name])
3299
+ return this.call(addresses.nameService, "lookup", [name]);
3352
3300
  }
3353
3301
  #monitorPeerConnections() {
3354
3302
  setInterval(() => {
3355
- const connectedPeers = Object.values(globalThis.peernet.connections).filter((peer) => peer.connected)
3356
- debug(`Connected peers: ${connectedPeers.length}`)
3303
+ const connectedPeers = Object.values(globalThis.peernet.connections).filter((peer) => peer.connected);
3304
+ debug(`Connected peers: ${connectedPeers.length}`);
3357
3305
  if (connectedPeers.length === 0) {
3358
- debug('No peers connected, attempting to reconnect...')
3359
- this.#attemptPeerReconnection()
3306
+ debug("No peers connected, attempting to reconnect...");
3307
+ this.#attemptPeerReconnection();
3360
3308
  }
3361
- }, 1e4)
3309
+ }, 1e4);
3362
3310
  }
3363
3311
  async #attemptPeerReconnection() {
3364
3312
  try {
3365
3313
  if (globalThis.peernet && globalThis.peernet.start) {
3366
- await globalThis.peernet.start()
3314
+ await globalThis.peernet.start();
3367
3315
  }
3368
3316
  } catch (error) {
3369
- console.warn('Failed to reconnect to peers:', error.message)
3317
+ console.warn("Failed to reconnect to peers:", error.message);
3370
3318
  }
3371
3319
  }
3372
3320
  }
3373
3321
 
3374
- export { Chain as default }
3322
+ export { Chain as default };