@leofcoin/chain 1.9.17 → 1.9.18

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