@xyo-network/xl1-cli-lib 1.15.21 → 1.15.23

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.
@@ -8,13 +8,16 @@ import { Mutex } from "async-mutex";
8
8
 
9
9
  // src/orchestration/actor/model/Actor.ts
10
10
  import { Base } from "@xylabs/base";
11
+ import { delay } from "@xylabs/delay";
11
12
  import { IdLogger } from "@xylabs/logger";
12
13
  import { span, spanRootAsync } from "@xylabs/telemetry";
14
+ import { Semaphore } from "async-mutex";
13
15
  var Actor = class extends Base {
14
16
  static {
15
17
  __name(this, "Actor");
16
18
  }
17
19
  _intervals = /* @__PURE__ */ new Map();
20
+ _semaphores = /* @__PURE__ */ new Map();
18
21
  _timeouts = /* @__PURE__ */ new Map();
19
22
  _active = false;
20
23
  _displayName;
@@ -49,14 +52,33 @@ var Actor = class extends Base {
49
52
  return;
50
53
  }
51
54
  let running = false;
55
+ this._semaphores.set(timerName, new Semaphore(1));
52
56
  const timeoutId = setTimeout(() => {
53
57
  const intervalId = setInterval(() => {
54
- if (!this._active || !this._intervals.has(timerName) || running) return;
55
- running = true;
56
- callback().catch((error) => {
57
- this.logger?.error(`Error in timer '${this.name}:${timerName}': ${error}`);
58
- }).finally(() => {
59
- running = false;
58
+ const semaphore = this._semaphores.get(timerName);
59
+ if (!this._active || !this._intervals.has(timerName) || !semaphore || running) return;
60
+ if (semaphore.isLocked()) {
61
+ this.logger?.warn(`Skipping timer '${this.name}:${timerName}' execution because previous execution is still running.`);
62
+ return;
63
+ }
64
+ semaphore.acquire().then(([, release]) => {
65
+ const startTime = Date.now();
66
+ running = true;
67
+ callback().then(() => {
68
+ const duration = Date.now() - startTime;
69
+ if (duration > periodMs) {
70
+ this.logger?.warn(`Timer '${this.name}:${timerName}' execution took longer (${duration}ms) than the period (${periodMs}ms).`);
71
+ } else if (duration > 5e3) {
72
+ this.logger?.warn(`Timer '${this.name}:${timerName}' execution took longer (${duration}ms) than 5000ms.`);
73
+ }
74
+ }).catch((error) => {
75
+ this.logger?.error(`Error in timer '${this.name}:${timerName}': ${error}`);
76
+ }).finally(() => {
77
+ release();
78
+ running = false;
79
+ });
80
+ }).catch((error) => {
81
+ this.logger?.error(`Error acquiring semaphore for timer '${this.name}:${timerName}': ${error}`);
60
82
  });
61
83
  }, periodMs);
62
84
  this._intervals.set(timerName, intervalId);
@@ -86,6 +108,16 @@ var Actor = class extends Base {
86
108
  await Promise.resolve();
87
109
  this._active = false;
88
110
  this.logger?.log("Stopping all timers...");
111
+ await Promise.all([
112
+ ...this._semaphores.values()
113
+ ].map(async (semaphore) => {
114
+ while (semaphore.isLocked()) {
115
+ this.logger?.log("Waiting for running timer task to complete...");
116
+ await delay(500);
117
+ }
118
+ await semaphore.acquire();
119
+ }));
120
+ this._semaphores.clear();
89
121
  for (const [, timeoutRef] of this._timeouts.entries()) {
90
122
  clearTimeout(timeoutRef);
91
123
  }
@@ -179,9 +211,15 @@ var BalanceActor = class _BalanceActor extends Actor {
179
211
  this.chainIterator.on("headUpdate", async () => {
180
212
  await this.updateBalance();
181
213
  });
182
- this.registerTimer("BalanceTimer", async () => {
183
- await this.updateBalance();
184
- }, 1e3, 1e3);
214
+ this.registerTimer(
215
+ "BalanceTimer",
216
+ async () => {
217
+ await this.updateBalance();
218
+ },
219
+ 1e3,
220
+ 1e4
221
+ /* 1000 */
222
+ );
185
223
  }
186
224
  async updateBalance() {
187
225
  if (this._updateMutex.isLocked()) return;
@@ -219,7 +257,13 @@ var ChainHeadUpdateActor = class _ChainHeadUpdateActor extends Actor {
219
257
  this.chainFinalizedArchivist.on("inserted", async (data) => {
220
258
  await this.checkInsertedForNewHead(data);
221
259
  });
222
- this.registerTimer("ChainHeadUpdateTimer", async () => await this.pollForNewHead(), 0, 250);
260
+ this.registerTimer(
261
+ "ChainHeadUpdateTimer",
262
+ async () => await this.pollForNewHead(),
263
+ 0,
264
+ 2500
265
+ /* 250 */
266
+ );
223
267
  }
224
268
  async checkInsertedForNewHead(data) {
225
269
  const candidateBlock = sortBlocks(filterAs(data.payloads, asBlockBoundWitness)).at(-1);
@@ -291,54 +335,19 @@ var ProducerActor = class _ProducerActor extends Actor {
291
335
  }
292
336
  async start() {
293
337
  await super.start();
294
- this.registerTimer("BlockProductionTimer", async () => {
295
- await this.spanAsync("produceBlock", async () => {
296
- const head = await this.chainIterator.head();
297
- const headHash = await PayloadBuilder2.hash(head);
298
- if (this._lastProducedBlock && this._lastProducedBlock[0].previous === headHash) {
299
- this.logger?.log("Block already produced:", `0x${toHex2(this._lastProducedBlock[0].block)}`);
300
- } else {
301
- const nextBlock = await this.producer.next(head);
302
- if (nextBlock) {
303
- const displayBlockNumber = `0x${toHex2(nextBlock[0].block)}`;
304
- this.logger?.log("Produced block:", displayBlockNumber);
305
- await this.chainSubmissionsArchivistWrite.insert(flattenHydratedBlock(nextBlock));
306
- this.logger?.log("Published block:", displayBlockNumber);
307
- this._lastProducedBlock = nextBlock;
308
- }
309
- }
310
- });
311
- }, 100, 500);
338
+ this.registerTimer(
339
+ "BlockProductionTimer",
340
+ async () => {
341
+ await this.produceBlock();
342
+ },
343
+ 100,
344
+ 1500
345
+ /* 500 */
346
+ );
312
347
  if (SHOULD_REGISTER_REDECLARATION_INTENT_TIMER) {
313
348
  this.registerTimer("ProducerRedeclarationTimer", async () => {
314
- await this.spanAsync("producerRedeclarationTimer", async () => {
315
- if (this.params.config.producer.disableIntentRedeclaration) return;
316
- const head = await this.chainIterator.head();
317
- if (isUndefined(head)) return;
318
- const currentBlock = head.block;
319
- const blocksUntilExpiration = await this.calculateBlocksUntilProducerDeclarationExpiration(currentBlock);
320
- if (blocksUntilExpiration > BaseBlockProducerService.RedeclarationWindow * 0.1) {
321
- this._lastRedeclarationIntent = void 0;
322
- return;
323
- }
324
- if (this._lastRedeclarationIntent) {
325
- if (this._lastRedeclarationIntent.exp > currentBlock) return;
326
- this._lastRedeclarationIntent = void 0;
327
- }
328
- if (!await this.validateCurrentBalance()) {
329
- this.logger?.error(`Add balance to address ${this.account.address} for the producer to declare it's intent.`);
330
- return;
331
- }
332
- if (!await this.validateCurrentStake()) {
333
- this.logger?.error(`Add stake to contract address ${this.params.config.chain.id} for the producer to declare it's intent.`);
334
- return;
335
- }
336
- this.logger?.log("Creating redeclaration intent for producer:", this.account.address);
337
- const redeclarationIntent = createDeclarationIntent(this.account.address, "producer", currentBlock, currentBlock + BaseBlockProducerService.RedeclarationDuration);
338
- await this.submitRedeclarationIntent(currentBlock, redeclarationIntent);
339
- this._lastRedeclarationIntent = redeclarationIntent;
340
- });
341
- }, 1e4, TEN_MINUTES);
349
+ await this.redeclareIntent();
350
+ }, TEN_MINUTES, TEN_MINUTES);
342
351
  }
343
352
  }
344
353
  async calculateBlocksUntilProducerDeclarationExpiration(currentBlock) {
@@ -351,6 +360,63 @@ var ProducerActor = class _ProducerActor extends Actor {
351
360
  const timeToProducerExpiration = currentDeclarationEnd - currentBlock;
352
361
  return timeToProducerExpiration;
353
362
  }
363
+ async produceBlock() {
364
+ await this.spanAsync("produceBlock", async () => {
365
+ const headStart = Date.now();
366
+ const head = await this.chainIterator.head();
367
+ const headDuration = Date.now() - headStart;
368
+ if (headDuration > 500) {
369
+ this.logger?.warn(`[Slow] Fetched head in ${headDuration}ms: 0x${toHex2(head._hash)}`);
370
+ }
371
+ const headHash = head._hash;
372
+ if (this._lastProducedBlock && this._lastProducedBlock[0].previous === headHash) {
373
+ this.logger?.log("Block already produced:", `0x${toHex2(this._lastProducedBlock[0].block)}`);
374
+ } else {
375
+ const nextStart = Date.now();
376
+ const nextBlock = await this.producer.next(head);
377
+ const nextDuration = Date.now() - nextStart;
378
+ if (nextDuration > 1e3) {
379
+ this.logger?.warn(`[Slow] Generated next block in ${nextDuration}ms, block: ${nextBlock?.[0]._hash}`);
380
+ }
381
+ if (nextBlock) {
382
+ const displayBlockNumber = `0x${toHex2(nextBlock[0].block)}`;
383
+ this.logger?.log("Produced block:", displayBlockNumber);
384
+ await this.chainSubmissionsArchivistWrite.insert(flattenHydratedBlock(nextBlock));
385
+ this.logger?.log("Published block:", displayBlockNumber);
386
+ this._lastProducedBlock = nextBlock;
387
+ }
388
+ }
389
+ });
390
+ }
391
+ async redeclareIntent() {
392
+ await this.spanAsync("redeclareIntent", async () => {
393
+ if (this.params.config.producer.disableIntentRedeclaration) return;
394
+ const head = await this.chainIterator.head();
395
+ if (isUndefined(head)) return;
396
+ const currentBlock = head.block;
397
+ const blocksUntilExpiration = await this.calculateBlocksUntilProducerDeclarationExpiration(currentBlock);
398
+ if (blocksUntilExpiration > BaseBlockProducerService.RedeclarationWindow * 0.1) {
399
+ this._lastRedeclarationIntent = void 0;
400
+ return;
401
+ }
402
+ if (this._lastRedeclarationIntent) {
403
+ if (this._lastRedeclarationIntent.exp > currentBlock) return;
404
+ this._lastRedeclarationIntent = void 0;
405
+ }
406
+ if (!await this.validateCurrentBalance()) {
407
+ this.logger?.error(`Add balance to address ${this.account.address} for the producer to declare it's intent.`);
408
+ return;
409
+ }
410
+ if (!await this.validateCurrentStake()) {
411
+ this.logger?.error(`Add stake to contract address ${this.params.config.chain.id} for the producer to declare it's intent.`);
412
+ return;
413
+ }
414
+ this.logger?.log("Creating redeclaration intent for producer:", this.account.address);
415
+ const redeclarationIntent = createDeclarationIntent(this.account.address, "producer", currentBlock, currentBlock + BaseBlockProducerService.RedeclarationDuration);
416
+ await this.submitRedeclarationIntent(currentBlock, redeclarationIntent);
417
+ this._lastRedeclarationIntent = redeclarationIntent;
418
+ });
419
+ }
354
420
  async submitRedeclarationIntent(currentBlock, redeclarationIntent) {
355
421
  this.logger?.log("Submitting redeclaration intent for producer:", this.account.address);
356
422
  const tx = await buildTransaction(this.chainIterator.chainId, [
@@ -438,25 +504,31 @@ var ValidatorActor = class _ValidatorActor extends Actor {
438
504
  }
439
505
  async start() {
440
506
  await super.start();
441
- this.registerTimer("BlockProductionTimer", async () => {
442
- await this.spanAsync("produceBlock", async () => {
443
- const block = await this.chainIterator.head();
444
- if (isUndefined2(block)) return;
445
- const hash = await PayloadBuilder3.hash(block);
446
- if (isDefined2(this._lastValidatedBlock) && this._lastValidatedBlockHash === hash) {
447
- this.logger?.log("Block already validated:", `0x${toHex3(block.block)}`);
448
- } else {
449
- this.logger?.log("Validating block:", `0x${toHex3(block.block)}`);
450
- const valid = await this.validateBlock(block);
451
- if (valid) {
452
- this.logger?.log("Validated block:", `0x${toHex3(block.block)}`);
507
+ this.registerTimer(
508
+ "BlockProductionTimer",
509
+ async () => {
510
+ await this.spanAsync("produceBlock", async () => {
511
+ const block = await this.chainIterator.head();
512
+ if (isUndefined2(block)) return;
513
+ const hash = await PayloadBuilder3.hash(block);
514
+ if (isDefined2(this._lastValidatedBlock) && this._lastValidatedBlockHash === hash) {
515
+ this.logger?.log("Block already validated:", `0x${toHex3(block.block)}`);
453
516
  } else {
454
- this.logger?.log("Invalid block:", `0x${toHex3(block.block)}`);
455
- await this.slashInvalidBlock(block);
517
+ this.logger?.log("Validating block:", `0x${toHex3(block.block)}`);
518
+ const valid = await this.validateBlock(block);
519
+ if (valid) {
520
+ this.logger?.log("Validated block:", `0x${toHex3(block.block)}`);
521
+ } else {
522
+ this.logger?.log("Invalid block:", `0x${toHex3(block.block)}`);
523
+ await this.slashInvalidBlock(block);
524
+ }
456
525
  }
457
- }
458
- });
459
- }, 100, 500);
526
+ });
527
+ },
528
+ 100,
529
+ 1500
530
+ /* 500 */
531
+ );
460
532
  }
461
533
  async slashInvalidBlock(_block) {
462
534
  const slashed = await Promise.resolve(true);
@@ -534,7 +606,7 @@ import { initTelemetry, startupSpanAsync as startupSpanAsync8, StepSizes, valida
534
606
  import { PayloadBuilder as PayloadBuilder7 } from "@xyo-network/payload-builder";
535
607
  import { readPayloadMapFromStore } from "@xyo-network/xl1-protocol-sdk";
536
608
  import { CompletedStepRewardAddressValidatorFactory, DerivedReceiveAddressValidatorFactory, SelfSignerValidator, TransactionTransfersValidatorFactory } from "@xyo-network/xl1-validation";
537
- import { Semaphore } from "async-mutex";
609
+ import { Semaphore as Semaphore2 } from "async-mutex";
538
610
 
539
611
  // src/orchestration/archivists/ChainFinalized/archivist.ts
540
612
  import { initArchivistSync, startupSpanAsync } from "@xyo-network/chain-sdk";
@@ -1230,7 +1302,7 @@ var getForkFromBlock = /* @__PURE__ */ __name(async (head, chainService, chainAr
1230
1302
  }, "getForkFromBlock");
1231
1303
 
1232
1304
  // src/orchestration/services/implementation/head/submitNewChain.ts
1233
- import { delay } from "@xylabs/delay";
1305
+ import { delay as delay2 } from "@xylabs/delay";
1234
1306
  import { flattenHydratedBlock as flattenHydratedBlock2 } from "@xyo-network/xl1-protocol-sdk";
1235
1307
  var submitNewChain = /* @__PURE__ */ __name(async (chain, chainArchivist, chainSubmissionsArchivistWrite) => {
1236
1308
  for (const block of chain) {
@@ -1241,7 +1313,7 @@ var submitNewChain = /* @__PURE__ */ __name(async (chain, chainArchivist, chainS
1241
1313
  bw._hash
1242
1314
  ]);
1243
1315
  if (result.length > 0) break;
1244
- await delay(1e3);
1316
+ await delay2(1e3);
1245
1317
  }
1246
1318
  }
1247
1319
  }, "submitNewChain");
@@ -1578,7 +1650,7 @@ var initServices = /* @__PURE__ */ __name(async (context) => {
1578
1650
  startupSpanAsync8("BalanceService", () => initBalanceService({
1579
1651
  name: "BalanceService",
1580
1652
  context: {
1581
- stepSemaphores: StepSizes.map(() => new Semaphore(20)),
1653
+ stepSemaphores: StepSizes.map(() => new Semaphore2(20)),
1582
1654
  store: {
1583
1655
  chainMap
1584
1656
  },
@@ -1591,7 +1663,7 @@ var initServices = /* @__PURE__ */ __name(async (context) => {
1591
1663
  startupSpanAsync8("TransferService", () => initTransferService({
1592
1664
  name: "TransferService",
1593
1665
  context: {
1594
- stepSemaphores: StepSizes.map(() => new Semaphore(20)),
1666
+ stepSemaphores: StepSizes.map(() => new Semaphore2(20)),
1595
1667
  store: {
1596
1668
  chainMap
1597
1669
  },
@@ -1827,7 +1899,7 @@ var waitForHostPort = /* @__PURE__ */ __name((host, port) => {
1827
1899
 
1828
1900
  // src/runCLI.ts
1829
1901
  var config;
1830
- var version = isDefined17("1.15.20") ? "1.15.20" : "unknown";
1902
+ var version = isDefined17("1.15.22") ? "1.15.22" : "unknown";
1831
1903
  var getContextFromConfig = /* @__PURE__ */ __name((config3) => {
1832
1904
  const logger = initLogger(config3);
1833
1905
  const orchestrator = new Orchestrator(logger);