@xyo-network/chain-services 1.3.17 → 1.3.19
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/neutral/index.mjs +77 -60
- package/dist/neutral/index.mjs.map +1 -1
- package/dist/types/AccountBalance/XyoChainAccountBalanceService.d.ts +1 -3
- package/dist/types/AccountBalance/XyoChainAccountBalanceService.d.ts.map +1 -1
- package/dist/types/BaseService.d.ts +1 -3
- package/dist/types/BaseService.d.ts.map +1 -1
- package/dist/types/BlockProducer/XyoBlockProducer.d.ts +2 -6
- package/dist/types/BlockProducer/XyoBlockProducer.d.ts.map +1 -1
- package/dist/types/ChainIndexService.d.ts +2 -6
- package/dist/types/ChainIndexService.d.ts.map +1 -1
- package/dist/types/ChainValidator/XyoValidator.d.ts +1 -3
- package/dist/types/ChainValidator/XyoValidator.d.ts.map +1 -1
- package/dist/types/PendingTransactions/PendingTransactions.d.ts +26 -7
- package/dist/types/PendingTransactions/PendingTransactions.d.ts.map +1 -1
- package/dist/types/StakeIntent/XyoStakeIntentService.d.ts +2 -6
- package/dist/types/StakeIntent/XyoStakeIntentService.d.ts.map +1 -1
- package/package.json +37 -35
- package/src/BaseService.ts +6 -12
- package/src/PendingTransactions/PendingTransactions.ts +94 -82
package/dist/neutral/index.mjs
CHANGED
|
@@ -19,15 +19,9 @@ var BaseService = class extends BaseEmitter {
|
|
|
19
19
|
static get singletons() {
|
|
20
20
|
return globalThis["xyoServiceSingletons"] ?? (globalThis["xyoServiceSingletons"] = {});
|
|
21
21
|
}
|
|
22
|
-
get meter() {
|
|
23
|
-
return this.params.meterProvider?.getMeter(this.name);
|
|
24
|
-
}
|
|
25
22
|
get name() {
|
|
26
23
|
return this.constructor.name;
|
|
27
24
|
}
|
|
28
|
-
get tracer() {
|
|
29
|
-
return this.params.traceProvider?.getTracer(this.name);
|
|
30
|
-
}
|
|
31
25
|
static async create(params) {
|
|
32
26
|
const result = new this(params);
|
|
33
27
|
if (result.name === "BaseService") throw new Error("Cannot create BaseService");
|
|
@@ -46,8 +40,8 @@ var BaseService = class extends BaseEmitter {
|
|
|
46
40
|
span(name, fn) {
|
|
47
41
|
return span(`${this.name}:${name}`, fn, this.tracer);
|
|
48
42
|
}
|
|
49
|
-
async spanAsync(name, fn
|
|
50
|
-
return await spanAsync(`${this.name}:${name}`, fn, this.tracer
|
|
43
|
+
async spanAsync(name, fn) {
|
|
44
|
+
return await spanAsync(`${this.name}:${name}`, fn, this.tracer);
|
|
51
45
|
}
|
|
52
46
|
};
|
|
53
47
|
var BaseAccountableService = class extends BaseService {
|
|
@@ -651,11 +645,12 @@ XyoElectionService = _ts_decorate6([
|
|
|
651
645
|
], XyoElectionService);
|
|
652
646
|
|
|
653
647
|
// src/PendingTransactions/PendingTransactions.ts
|
|
648
|
+
import { ValueType } from "@opentelemetry/api";
|
|
654
649
|
import { filterAs, filterAsync } from "@xylabs/array";
|
|
655
650
|
import { assertEx as assertEx7 } from "@xylabs/assert";
|
|
656
651
|
import { exists } from "@xylabs/exists";
|
|
652
|
+
import { forget } from "@xylabs/forget";
|
|
657
653
|
import { MemoryArchivist } from "@xyo-network/archivist-memory";
|
|
658
|
-
import { hydrateBlock } from "@xyo-network/chain-protocol";
|
|
659
654
|
import { validateTransaction } from "@xyo-network/chain-validation";
|
|
660
655
|
import { asOptionalTransactionBoundWitnessWithStorageMeta } from "@xyo-network/xl1-protocol";
|
|
661
656
|
import { flattenHydratedTransactions, tryHydrateTransaction } from "@xyo-network/xl1-protocol-sdk";
|
|
@@ -689,12 +684,25 @@ var XyoPendingTransactionsService = class _XyoPendingTransactionsService extends
|
|
|
689
684
|
*/
|
|
690
685
|
RemoveFinalizedTransactions: 1
|
|
691
686
|
};
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
687
|
+
/**
|
|
688
|
+
* A mutex to ensure that the counting the number of pending transactions is
|
|
689
|
+
* not called concurrently
|
|
690
|
+
*/
|
|
691
|
+
_countPendingTransactionsMutex = new Mutex2();
|
|
692
|
+
/**
|
|
693
|
+
* A local Archivist optimized for fast retrieval that stores only validated
|
|
694
|
+
* pending transactions
|
|
695
|
+
*/
|
|
696
|
+
_curatedPendingTransactionsArchivist;
|
|
697
|
+
/**
|
|
698
|
+
* The last count of total pending transactions
|
|
699
|
+
*/
|
|
700
|
+
_pendingTransactionsCount = 0;
|
|
701
|
+
/**
|
|
702
|
+
* A mutex to ensure that the curated pending transactions archivist is
|
|
703
|
+
* updated in a thread-safe manner
|
|
704
|
+
*/
|
|
705
|
+
_updateCuratedPendingTransactionsArchivistMutex = new Mutex2();
|
|
698
706
|
get chainArchivist() {
|
|
699
707
|
return assertEx7(this.params.chainArchivist, () => "No completed blocks with data archivist");
|
|
700
708
|
}
|
|
@@ -704,46 +712,41 @@ var XyoPendingTransactionsService = class _XyoPendingTransactionsService extends
|
|
|
704
712
|
get pendingTransactionsArchivist() {
|
|
705
713
|
return assertEx7(this.params.pendingTransactionsArchivist, () => "No pending transactions archivist");
|
|
706
714
|
}
|
|
715
|
+
get pendingTransactionsCount() {
|
|
716
|
+
forget(this.countPendingTransactions());
|
|
717
|
+
return this._pendingTransactionsCount;
|
|
718
|
+
}
|
|
707
719
|
get pendingTransactionsLocalArchivist() {
|
|
708
|
-
return assertEx7(this.
|
|
720
|
+
return assertEx7(this._curatedPendingTransactionsArchivist, () => "No pending transactions curated archivist");
|
|
709
721
|
}
|
|
710
722
|
get rejectedTransactionsArchivist() {
|
|
711
723
|
return assertEx7(this.params.rejectedTransactionsArchivist, () => "No rejected transactions archivist");
|
|
712
724
|
}
|
|
713
725
|
async createHandler() {
|
|
714
726
|
await super.createHandler();
|
|
715
|
-
this.
|
|
727
|
+
this._curatedPendingTransactionsArchivist = await MemoryArchivist.create({
|
|
716
728
|
account: "random"
|
|
717
729
|
});
|
|
718
730
|
this.pendingTransactionsArchivist.on("inserted", async ({ payloads }) => {
|
|
719
|
-
await this.
|
|
720
|
-
const unprocessedTransactions = await this.filterAlreadyFinalizedTransactions(payloads);
|
|
721
|
-
const hydratedUnprocessedTransactions = (await Promise.all(unprocessedTransactions.map((tx) => {
|
|
722
|
-
return tryHydrateTransaction(this.pendingTransactionsArchivist, tx._hash);
|
|
723
|
-
}))).filter(exists);
|
|
724
|
-
const validTransactions = await filterAsync(hydratedUnprocessedTransactions, async (tx) => {
|
|
725
|
-
const errors = await validateTransaction(tx, this.chainIdentification.id);
|
|
726
|
-
return errors.length > 0 ? false : true;
|
|
727
|
-
});
|
|
728
|
-
await this.pendingTransactionsLocalArchivist.insert(flattenHydratedTransactions(validTransactions));
|
|
729
|
-
}, _XyoPendingTransactionsService.MutexPriority.InsertNewTransactions);
|
|
731
|
+
await this.insertNewTransactions(payloads);
|
|
730
732
|
});
|
|
731
733
|
this.chainArchivist.on("inserted", async ({ payloads }) => {
|
|
732
|
-
await this.
|
|
733
|
-
const transactions = filterAs(payloads, asOptionalTransactionBoundWitnessWithStorageMeta);
|
|
734
|
-
await this.pendingTransactionsLocalArchivist.delete(transactions.map((tx) => tx._hash));
|
|
735
|
-
}, _XyoPendingTransactionsService.MutexPriority.RemoveFinalizedTransactions);
|
|
734
|
+
await this.removeFinalizedTransactions(payloads);
|
|
736
735
|
});
|
|
737
736
|
this.rejectedTransactionsArchivist.on("inserted", async ({ payloads }) => {
|
|
738
|
-
await this.
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
737
|
+
await this.removeRejectedTransactions(payloads);
|
|
738
|
+
});
|
|
739
|
+
const pendingTransactionsGauge = this.meter?.createObservableGauge("xyo_pending_transactions_count", {
|
|
740
|
+
description: "The current number of pending transactions",
|
|
741
|
+
valueType: ValueType.INT
|
|
742
|
+
});
|
|
743
|
+
pendingTransactionsGauge?.addCallback((observer) => {
|
|
744
|
+
observer.observe(this.pendingTransactionsCount);
|
|
742
745
|
});
|
|
743
746
|
}
|
|
744
|
-
async getPendingTransactions(head, limit
|
|
747
|
+
async getPendingTransactions(head, limit) {
|
|
745
748
|
return await this.spanAsync("getPendingTransactions", async () => {
|
|
746
|
-
return await this.
|
|
749
|
+
return await this._updateCuratedPendingTransactionsArchivistMutex.runExclusive(async () => {
|
|
747
750
|
const foundPendingTransactions = [];
|
|
748
751
|
let cursor;
|
|
749
752
|
while (foundPendingTransactions.length < limit) {
|
|
@@ -760,7 +763,15 @@ var XyoPendingTransactionsService = class _XyoPendingTransactionsService extends
|
|
|
760
763
|
const hydratedTransactions = await Promise.all(foundPendingTransactions.map((tx) => tryHydrateTransaction(this.pendingTransactionsLocalArchivist, tx._hash)));
|
|
761
764
|
return hydratedTransactions.filter(exists);
|
|
762
765
|
}, _XyoPendingTransactionsService.MutexPriority.ReadTransactions);
|
|
763
|
-
}
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
async countPendingTransactions() {
|
|
769
|
+
if (this._countPendingTransactionsMutex.isLocked()) return;
|
|
770
|
+
await this._countPendingTransactionsMutex.runExclusive(async () => {
|
|
771
|
+
const payloads = await this._curatedPendingTransactionsArchivist?.all() ?? [];
|
|
772
|
+
const pendingTransactions = filterAs(payloads, asOptionalTransactionBoundWitnessWithStorageMeta);
|
|
773
|
+
this._pendingTransactionsCount = pendingTransactions.length;
|
|
774
|
+
});
|
|
764
775
|
}
|
|
765
776
|
async filterAlreadyFinalizedTransactions(payloads) {
|
|
766
777
|
const incomingTransactions = filterAs(payloads, asOptionalTransactionBoundWitnessWithStorageMeta);
|
|
@@ -770,28 +781,34 @@ var XyoPendingTransactionsService = class _XyoPendingTransactionsService extends
|
|
|
770
781
|
const nonFinalizedTransactions = incomingTransactions.filter((item) => !finalizedTransactionHashes.has(item._hash));
|
|
771
782
|
return nonFinalizedTransactions;
|
|
772
783
|
}
|
|
773
|
-
async
|
|
774
|
-
return await this.spanAsync("
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
const
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
+
async insertNewTransactions(payloads) {
|
|
785
|
+
return await this.spanAsync("InsertNewTransactions", async () => {
|
|
786
|
+
return await this._updateCuratedPendingTransactionsArchivistMutex.runExclusive(async () => {
|
|
787
|
+
const unprocessedTransactions = await this.filterAlreadyFinalizedTransactions(payloads);
|
|
788
|
+
const hydratedUnprocessedTransactions = (await Promise.all(unprocessedTransactions.map((tx) => {
|
|
789
|
+
return tryHydrateTransaction(this.pendingTransactionsArchivist, tx._hash);
|
|
790
|
+
}))).filter(exists);
|
|
791
|
+
const validTransactions = await filterAsync(hydratedUnprocessedTransactions, async (tx) => {
|
|
792
|
+
const errors = await validateTransaction(tx, this.chainIdentification.id);
|
|
793
|
+
return errors.length > 0 ? false : true;
|
|
794
|
+
});
|
|
795
|
+
await this.pendingTransactionsLocalArchivist.insert(flattenHydratedTransactions(validTransactions));
|
|
796
|
+
}, _XyoPendingTransactionsService.MutexPriority.InsertNewTransactions);
|
|
797
|
+
});
|
|
784
798
|
}
|
|
785
|
-
async
|
|
786
|
-
return await this.
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
799
|
+
async removeFinalizedTransactions(payloads) {
|
|
800
|
+
return await this.removeTransactions(payloads, "RemoveFinalizedTransactions");
|
|
801
|
+
}
|
|
802
|
+
async removeRejectedTransactions(payloads) {
|
|
803
|
+
return await this.removeTransactions(payloads, "RemoveRejectedTransactions");
|
|
804
|
+
}
|
|
805
|
+
async removeTransactions(payloads, priority) {
|
|
806
|
+
return await this.spanAsync(priority, async () => {
|
|
807
|
+
return await this._updateCuratedPendingTransactionsArchivistMutex.runExclusive(async () => {
|
|
808
|
+
const transactions = filterAs(payloads, asOptionalTransactionBoundWitnessWithStorageMeta);
|
|
809
|
+
await this.pendingTransactionsLocalArchivist.delete(transactions.map((tx) => tx._hash));
|
|
810
|
+
}, _XyoPendingTransactionsService.MutexPriority[priority]);
|
|
811
|
+
});
|
|
795
812
|
}
|
|
796
813
|
};
|
|
797
814
|
XyoPendingTransactionsService = _ts_decorate7([
|