@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.
- package/dist/node/index.mjs +151 -79
- package/dist/node/index.mjs.map +1 -1
- package/dist/node/orchestration/actor/implementation/ProducerActor.d.ts +2 -0
- package/dist/node/orchestration/actor/implementation/ProducerActor.d.ts.map +1 -1
- package/dist/node/orchestration/actor/model/Actor.d.ts +2 -0
- package/dist/node/orchestration/actor/model/Actor.d.ts.map +1 -1
- package/dist/node/xl1.mjs +128 -62
- package/dist/node/xl1.mjs.map +1 -1
- package/package.json +28 -28
- package/src/orchestration/actor/implementation/BalanceActor.ts +1 -1
- package/src/orchestration/actor/implementation/ChainHeadUpdateActor.ts +1 -1
- package/src/orchestration/actor/implementation/ProducerActor.ts +106 -88
- package/src/orchestration/actor/implementation/ValidatorActor.ts +1 -1
- package/src/orchestration/actor/model/Actor.ts +54 -9
package/dist/node/index.mjs
CHANGED
|
@@ -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
|
-
|
|
55
|
-
running
|
|
56
|
-
|
|
57
|
-
this.logger?.
|
|
58
|
-
|
|
59
|
-
|
|
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(
|
|
183
|
-
|
|
184
|
-
|
|
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(
|
|
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(
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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.
|
|
315
|
-
|
|
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(
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
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("
|
|
455
|
-
await this.
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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);
|