@xyo-network/chain-services 1.5.10 → 1.5.12
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 +89 -56
- package/dist/neutral/index.mjs.map +1 -1
- package/dist/types/BlockProducer/XyoBlockProducer.d.ts +2 -2
- package/dist/types/BlockProducer/XyoBlockProducer.d.ts.map +1 -1
- package/dist/types/ChainValidator/XyoValidator.d.ts +2 -2
- package/dist/types/ChainValidator/XyoValidator.d.ts.map +1 -1
- package/dist/types/PendingTransactions/PendingTransactions.d.ts +9 -8
- package/dist/types/PendingTransactions/PendingTransactions.d.ts.map +1 -1
- package/package.json +22 -22
- package/src/BlockProducer/XyoBlockProducer.ts +4 -4
- package/src/ChainValidator/XyoValidator.ts +3 -3
- package/src/PendingTransactions/PendingTransactions.ts +94 -53
|
@@ -9,7 +9,7 @@ export interface XyoValidatorParams extends BaseServiceParams {
|
|
|
9
9
|
chainArchivist: ReadArchivist;
|
|
10
10
|
chainInformation: ChainInformation;
|
|
11
11
|
electionService: ElectionService;
|
|
12
|
-
|
|
12
|
+
pendingBundledTransactionsArchivist: ArchivistInstance;
|
|
13
13
|
rewardService: BlockRewardService;
|
|
14
14
|
stakeIntentService: StakeIntentService;
|
|
15
15
|
validateHydratedBlockState: HydratedBlockStateValidationFunction;
|
|
@@ -20,7 +20,7 @@ export declare class XyoValidator<TParams extends XyoValidatorParams = XyoValida
|
|
|
20
20
|
protected get chainArchivist(): TParams["chainArchivist"];
|
|
21
21
|
protected get chainInfo(): TParams["chainInformation"];
|
|
22
22
|
protected get electionService(): TParams["electionService"];
|
|
23
|
-
protected get
|
|
23
|
+
protected get pendingBundledTransactionsArchivist(): TParams["pendingBundledTransactionsArchivist"];
|
|
24
24
|
protected get rewardService(): TParams["rewardService"];
|
|
25
25
|
validatePendingBlock(_block: BlockBoundWitness): Promisable<Error[]>;
|
|
26
26
|
validatePendingTransaction(hydratedTransaction: HydratedTransaction): Promise<boolean>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"XyoValidator.d.ts","sourceRoot":"","sources":["../../../src/ChainValidator/XyoValidator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAC5D,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AAE/E,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,oCAAoC,EACpC,mBAAmB,EAEnB,kBAAkB,EACnB,MAAM,2BAA2B,CAAA;AAElC,OAAO,EAAE,WAAW,EAAoB,MAAM,mBAAmB,CAAA;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAM5C,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,OAAO,EAAE,eAAe,CAAA;IACxB,cAAc,EAAE,aAAa,CAAA;IAC7B,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,eAAe,EAAE,eAAe,CAAA;IAChC,
|
|
1
|
+
{"version":3,"file":"XyoValidator.d.ts","sourceRoot":"","sources":["../../../src/ChainValidator/XyoValidator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAC5D,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AAE/E,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,oCAAoC,EACpC,mBAAmB,EAEnB,kBAAkB,EACnB,MAAM,2BAA2B,CAAA;AAElC,OAAO,EAAE,WAAW,EAAoB,MAAM,mBAAmB,CAAA;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAM5C,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,OAAO,EAAE,eAAe,CAAA;IACxB,cAAc,EAAE,aAAa,CAAA;IAC7B,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,eAAe,EAAE,eAAe,CAAA;IAChC,mCAAmC,EAAE,iBAAiB,CAAA;IACtD,aAAa,EAAE,kBAAkB,CAAA;IACjC,kBAAkB,EAAE,kBAAkB,CAAA;IACtC,0BAA0B,EAAE,oCAAoC,CAAA;CACjE;AAED,qBACa,YAAY,CAAC,OAAO,SAAS,kBAAkB,GAAG,kBAAkB,CAAE,SAAQ,WAAW,CAAC,OAAO,CAAE,YAAW,SAAS;IAClI,IAAI,OAAO,sBAEV;IAED,SAAS,KAAK,OAAO,uBAEpB;IAED,SAAS,KAAK,cAAc,8BAE3B;IAED,SAAS,KAAK,SAAS,gCAEtB;IAED,SAAS,KAAK,eAAe,+BAE5B;IAED,SAAS,KAAK,mCAAmC,mDAEhD;IAED,SAAS,KAAK,aAAa,6BAE1B;IAED,oBAAoB,CAAC,MAAM,EAAE,iBAAiB,GAAG,UAAU,CAAC,KAAK,EAAE,CAAC;IAK9D,0BAA0B,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC;CAQ7F"}
|
|
@@ -5,8 +5,8 @@ import { BaseService } from '../BaseService.ts';
|
|
|
5
5
|
export interface XyoPendingTransactionsServiceParams extends BaseServiceParams {
|
|
6
6
|
chainArchivist?: ArchivistInstance;
|
|
7
7
|
chainIdentification?: ChainIdentification;
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
pendingBundledTransactionsArchivist?: ArchivistInstance;
|
|
9
|
+
rejectedBundledTransactionsArchivist?: ArchivistInstance;
|
|
10
10
|
}
|
|
11
11
|
export declare class XyoPendingTransactionsService extends BaseService<XyoPendingTransactionsServiceParams> implements PendingTransactionsService {
|
|
12
12
|
private static readonly MutexPriority;
|
|
@@ -19,11 +19,12 @@ export declare class XyoPendingTransactionsService extends BaseService<XyoPendin
|
|
|
19
19
|
* A local Archivist optimized for fast retrieval that stores only validated
|
|
20
20
|
* pending transactions
|
|
21
21
|
*/
|
|
22
|
-
private
|
|
22
|
+
private _curatedPendingBundledTransactionsArchivist;
|
|
23
23
|
/**
|
|
24
24
|
* The last count of total pending transactions
|
|
25
25
|
*/
|
|
26
26
|
private _pendingTransactionsCount;
|
|
27
|
+
private _removablePendingTransactionHashes;
|
|
27
28
|
/**
|
|
28
29
|
* A mutex to ensure that the curated pending transactions archivist is
|
|
29
30
|
* updated in a thread-safe manner
|
|
@@ -31,17 +32,17 @@ export declare class XyoPendingTransactionsService extends BaseService<XyoPendin
|
|
|
31
32
|
private _updateCuratedPendingTransactionsArchivistMutex;
|
|
32
33
|
private get chainArchivist();
|
|
33
34
|
private get chainIdentification();
|
|
34
|
-
private get
|
|
35
|
+
private get pendingBundledTransactionsArchivist();
|
|
36
|
+
private get pendingBundledTransactionsLocalArchivist();
|
|
35
37
|
private get pendingTransactionsCount();
|
|
36
|
-
private get
|
|
37
|
-
private get rejectedTransactionsArchivist();
|
|
38
|
+
private get rejectedBundledTransactionsArchivist();
|
|
38
39
|
createHandler(): Promise<void>;
|
|
39
40
|
getPendingTransactions(head: Hash, limit: number): Promise<HydratedTransactionWithStorageMeta[]>;
|
|
40
41
|
private countPendingTransactions;
|
|
41
42
|
private filterAlreadyFinalizedTransactions;
|
|
42
43
|
private insertNewTransactions;
|
|
44
|
+
private removeBundledTransactions;
|
|
43
45
|
private removeFinalizedTransactions;
|
|
44
|
-
private
|
|
45
|
-
private removeTransactions;
|
|
46
|
+
private removeRejectedBundledTransactions;
|
|
46
47
|
}
|
|
47
48
|
//# sourceMappingURL=PendingTransactions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PendingTransactions.d.ts","sourceRoot":"","sources":["../../../src/PendingTransactions/PendingTransactions.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAElC,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;
|
|
1
|
+
{"version":3,"file":"PendingTransactions.d.ts","sourceRoot":"","sources":["../../../src/PendingTransactions/PendingTransactions.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAElC,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAOhE,OAAO,EAC6C,iBAAiB,EACnE,mBAAmB,EAAE,kCAAkC,EAEvD,0BAA0B,EAC3B,MAAM,2BAA2B,CAAA;AAIlC,OAAO,EAAE,WAAW,EAAoB,MAAM,mBAAmB,CAAA;AAEjE,MAAM,WAAW,mCAAoC,SAAQ,iBAAiB;IAC5E,cAAc,CAAC,EAAE,iBAAiB,CAAA;IAClC,mBAAmB,CAAC,EAAE,mBAAmB,CAAA;IACzC,mCAAmC,CAAC,EAAE,iBAAiB,CAAA;IACvD,oCAAoC,CAAC,EAAE,iBAAiB,CAAA;CACzD;AAYD,qBACa,6BAA8B,SAAQ,WAAW,CAAC,mCAAmC,CAAE,YAAW,0BAA0B;IACvI,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAiB3B;IAEV;;;OAGG;IACH,OAAO,CAAC,8BAA8B,CAAc;IAEpD;;;OAGG;IACH,OAAO,CAAC,2CAA2C,CAA6B;IAEhF;;OAEG;IACH,OAAO,CAAC,yBAAyB,CAAY;IAE7C,OAAO,CAAC,kCAAkC,CAAuB;IAEjE;;;OAGG;IACH,OAAO,CAAC,+CAA+C,CAAc;IAErE,OAAO,KAAK,cAAc,GAEzB;IAED,OAAO,KAAK,mBAAmB,GAE9B;IAED,OAAO,KAAK,mCAAmC,GAE9C;IAED,OAAO,KAAK,wCAAwC,GAEnD;IAED,OAAO,KAAK,wBAAwB,GAGnC;IAED,OAAO,KAAK,oCAAoC,GAE/C;IAEc,aAAa;IA4BtB,sBAAsB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kCAAkC,EAAE,CAAC;YAgCxF,wBAAwB;YAQxB,kCAAkC;YAUlC,qBAAqB;YA8BrB,yBAAyB;IAgBvC,OAAO,CAAC,2BAA2B;IAOnC,OAAO,CAAC,iCAAiC;CAM1C"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "http://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@xyo-network/chain-services",
|
|
4
|
-
"version": "1.5.
|
|
4
|
+
"version": "1.5.12",
|
|
5
5
|
"description": "XYO Layer One SDK Services",
|
|
6
6
|
"homepage": "https://xylabs.com",
|
|
7
7
|
"bugs": {
|
|
@@ -46,24 +46,24 @@
|
|
|
46
46
|
"@xylabs/promise": "^4.11.10",
|
|
47
47
|
"@xylabs/telemetry": "^4.11.10",
|
|
48
48
|
"@xylabs/typeof": "^4.11.10",
|
|
49
|
-
"@xyo-network/account-model": "^3.18.
|
|
50
|
-
"@xyo-network/archivist-memory": "^3.18.
|
|
51
|
-
"@xyo-network/archivist-model": "^3.18.
|
|
52
|
-
"@xyo-network/boundwitness-model": "^3.18.
|
|
53
|
-
"@xyo-network/boundwitness-validator": "^3.18.
|
|
54
|
-
"@xyo-network/boundwitness-wrapper": "^3.18.
|
|
55
|
-
"@xyo-network/chain-analyze": "^1.5.
|
|
56
|
-
"@xyo-network/chain-ethereum": "^1.5.
|
|
57
|
-
"@xyo-network/chain-modules": "^1.5.
|
|
58
|
-
"@xyo-network/chain-protocol": "^1.5.
|
|
59
|
-
"@xyo-network/chain-utils": "^1.5.
|
|
60
|
-
"@xyo-network/chain-validation": "^1.5.
|
|
61
|
-
"@xyo-network/chain-wrappers": "^1.5.
|
|
62
|
-
"@xyo-network/payload-builder": "^3.18.
|
|
63
|
-
"@xyo-network/payload-model": "^3.18.
|
|
49
|
+
"@xyo-network/account-model": "^3.18.2",
|
|
50
|
+
"@xyo-network/archivist-memory": "^3.18.2",
|
|
51
|
+
"@xyo-network/archivist-model": "^3.18.2",
|
|
52
|
+
"@xyo-network/boundwitness-model": "^3.18.2",
|
|
53
|
+
"@xyo-network/boundwitness-validator": "^3.18.2",
|
|
54
|
+
"@xyo-network/boundwitness-wrapper": "^3.18.2",
|
|
55
|
+
"@xyo-network/chain-analyze": "^1.5.12",
|
|
56
|
+
"@xyo-network/chain-ethereum": "^1.5.12",
|
|
57
|
+
"@xyo-network/chain-modules": "^1.5.12",
|
|
58
|
+
"@xyo-network/chain-protocol": "^1.5.12",
|
|
59
|
+
"@xyo-network/chain-utils": "^1.5.12",
|
|
60
|
+
"@xyo-network/chain-validation": "^1.5.12",
|
|
61
|
+
"@xyo-network/chain-wrappers": "^1.5.12",
|
|
62
|
+
"@xyo-network/payload-builder": "^3.18.2",
|
|
63
|
+
"@xyo-network/payload-model": "^3.18.2",
|
|
64
64
|
"@xyo-network/typechain": "^3.5.4",
|
|
65
65
|
"@xyo-network/xl1-protocol": "^1.4.16",
|
|
66
|
-
"@xyo-network/xl1-protocol-sdk": "^1.5.
|
|
66
|
+
"@xyo-network/xl1-protocol-sdk": "^1.5.12",
|
|
67
67
|
"async-mutex": "^0.5.0",
|
|
68
68
|
"ethers": "6.14.3",
|
|
69
69
|
"lru-cache": "^11.1.0",
|
|
@@ -75,13 +75,13 @@
|
|
|
75
75
|
"@xylabs/ts-scripts-yarn3": "^6.5.7",
|
|
76
76
|
"@xylabs/tsconfig": "^6.5.7",
|
|
77
77
|
"@xylabs/vitest-extended": "^4.11.10",
|
|
78
|
-
"@xyo-network/account": "^3.18.
|
|
79
|
-
"@xyo-network/account-model": "^3.18.
|
|
80
|
-
"@xyo-network/chain-validation": "^1.5.
|
|
81
|
-
"@xyo-network/wallet": "^3.18.
|
|
78
|
+
"@xyo-network/account": "^3.18.2",
|
|
79
|
+
"@xyo-network/account-model": "^3.18.2",
|
|
80
|
+
"@xyo-network/chain-validation": "^1.5.12",
|
|
81
|
+
"@xyo-network/wallet": "^3.18.2",
|
|
82
82
|
"knip": "^5.59.1",
|
|
83
83
|
"typescript": "^5.8.3",
|
|
84
|
-
"vitest": "^3.2.
|
|
84
|
+
"vitest": "^3.2.1",
|
|
85
85
|
"vitest-mock-extended": "^3.1.0"
|
|
86
86
|
},
|
|
87
87
|
"engines": {
|
|
@@ -40,7 +40,7 @@ export const XYO_PRODUCER_RESTAKE_WINDOW = 500n
|
|
|
40
40
|
export interface XyoBlockProducerParams extends XyoValidatorParams {
|
|
41
41
|
balanceService: AccountBalanceService
|
|
42
42
|
pendingTransactionsService: PendingTransactionsService
|
|
43
|
-
|
|
43
|
+
rejectedBundledTransactionsArchivist: ArchivistInstance
|
|
44
44
|
rewardAddress: Address
|
|
45
45
|
}
|
|
46
46
|
|
|
@@ -80,8 +80,8 @@ export class XyoBlockProducer extends BaseService<XyoBlockProducerParams> implem
|
|
|
80
80
|
return assertEx(this.params.pendingTransactionsService, () => 'Missing pendingTransactionsService')
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
protected get
|
|
84
|
-
return assertEx(this.params.
|
|
83
|
+
protected get rejectedBundledTransactionsArchivist() {
|
|
84
|
+
return assertEx(this.params.rejectedBundledTransactionsArchivist, () => 'No rejected bundled transactions archivist')
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
protected get rewardAddress(): Address {
|
|
@@ -206,7 +206,7 @@ export class XyoBlockProducer extends BaseService<XyoBlockProducerParams> implem
|
|
|
206
206
|
if (errors.length > 0) {
|
|
207
207
|
this.logger?.warn(`Validation of produced block failed: ${errors.at(0)?.message}`)
|
|
208
208
|
const rejectedTransactions = block[1]
|
|
209
|
-
await this.
|
|
209
|
+
await this.rejectedBundledTransactionsArchivist.insert(rejectedTransactions)
|
|
210
210
|
} else {
|
|
211
211
|
return block
|
|
212
212
|
}
|
|
@@ -27,7 +27,7 @@ export interface XyoValidatorParams extends BaseServiceParams {
|
|
|
27
27
|
chainArchivist: ReadArchivist
|
|
28
28
|
chainInformation: ChainInformation
|
|
29
29
|
electionService: ElectionService
|
|
30
|
-
|
|
30
|
+
pendingBundledTransactionsArchivist: ArchivistInstance
|
|
31
31
|
rewardService: BlockRewardService
|
|
32
32
|
stakeIntentService: StakeIntentService
|
|
33
33
|
validateHydratedBlockState: HydratedBlockStateValidationFunction
|
|
@@ -55,8 +55,8 @@ export class XyoValidator<TParams extends XyoValidatorParams = XyoValidatorParam
|
|
|
55
55
|
return assertEx(this.params.electionService, () => 'electionService is required')
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
protected get
|
|
59
|
-
return assertEx(this.params.
|
|
58
|
+
protected get pendingBundledTransactionsArchivist() {
|
|
59
|
+
return assertEx(this.params.pendingBundledTransactionsArchivist, () => 'pendingBundledTransactions is required')
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
protected get rewardService() {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ValueType } from '@opentelemetry/api'
|
|
2
|
-
import {
|
|
2
|
+
import { filterAsync } from '@xylabs/array'
|
|
3
3
|
import { assertEx } from '@xylabs/assert'
|
|
4
4
|
import { exists } from '@xylabs/exists'
|
|
5
5
|
import { forget } from '@xylabs/forget'
|
|
@@ -7,14 +7,18 @@ import { Hash } from '@xylabs/hex'
|
|
|
7
7
|
import { MemoryArchivist } from '@xyo-network/archivist-memory'
|
|
8
8
|
import { ArchivistInstance } from '@xyo-network/archivist-model'
|
|
9
9
|
import { validateTransaction } from '@xyo-network/chain-validation'
|
|
10
|
+
import { PayloadBuilder } from '@xyo-network/payload-builder'
|
|
10
11
|
import {
|
|
11
|
-
Payload,
|
|
12
|
+
Payload,
|
|
13
|
+
PayloadBundle, Sequence, WithStorageMeta,
|
|
12
14
|
} from '@xyo-network/payload-model'
|
|
13
15
|
import {
|
|
14
|
-
asOptionalTransactionBoundWitnessWithStorageMeta, BaseServiceParams,
|
|
15
|
-
|
|
16
|
+
asOptionalTransactionBoundWitnessWithStorageMeta, BaseServiceParams,
|
|
17
|
+
ChainIdentification, HydratedTransactionWithStorageMeta,
|
|
18
|
+
isTransactionBoundWitnessWithStorageMeta,
|
|
19
|
+
PendingTransactionsService,
|
|
16
20
|
} from '@xyo-network/xl1-protocol'
|
|
17
|
-
import {
|
|
21
|
+
import { flattenHydratedTransaction } from '@xyo-network/xl1-protocol-sdk'
|
|
18
22
|
import { Mutex } from 'async-mutex'
|
|
19
23
|
|
|
20
24
|
import { BaseService, creatableService } from '../BaseService.ts'
|
|
@@ -22,8 +26,18 @@ import { BaseService, creatableService } from '../BaseService.ts'
|
|
|
22
26
|
export interface XyoPendingTransactionsServiceParams extends BaseServiceParams {
|
|
23
27
|
chainArchivist?: ArchivistInstance
|
|
24
28
|
chainIdentification?: ChainIdentification
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
pendingBundledTransactionsArchivist?: ArchivistInstance
|
|
30
|
+
rejectedBundledTransactionsArchivist?: ArchivistInstance
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function bundledPayloadsToHydratedTransaction(
|
|
34
|
+
payload: WithStorageMeta<PayloadBundle>,
|
|
35
|
+
): Promise<HydratedTransactionWithStorageMeta | undefined> {
|
|
36
|
+
const withStorageMeta = await PayloadBuilder.addStorageMeta(payload.payloads)
|
|
37
|
+
const tx = asOptionalTransactionBoundWitnessWithStorageMeta(withStorageMeta.find(p => p._hash === payload.root))
|
|
38
|
+
if (tx) {
|
|
39
|
+
return [tx, withStorageMeta.map(p => p._hash === payload.root ? undefined : p).filter(exists)]
|
|
40
|
+
}
|
|
27
41
|
}
|
|
28
42
|
|
|
29
43
|
@creatableService()
|
|
@@ -57,13 +71,15 @@ export class XyoPendingTransactionsService extends BaseService<XyoPendingTransac
|
|
|
57
71
|
* A local Archivist optimized for fast retrieval that stores only validated
|
|
58
72
|
* pending transactions
|
|
59
73
|
*/
|
|
60
|
-
private
|
|
74
|
+
private _curatedPendingBundledTransactionsArchivist: MemoryArchivist | undefined
|
|
61
75
|
|
|
62
76
|
/**
|
|
63
77
|
* The last count of total pending transactions
|
|
64
78
|
*/
|
|
65
79
|
private _pendingTransactionsCount: number = 0
|
|
66
80
|
|
|
81
|
+
private _removablePendingTransactionHashes: Set<Hash> = new Set()
|
|
82
|
+
|
|
67
83
|
/**
|
|
68
84
|
* A mutex to ensure that the curated pending transactions archivist is
|
|
69
85
|
* updated in a thread-safe manner
|
|
@@ -78,8 +94,12 @@ export class XyoPendingTransactionsService extends BaseService<XyoPendingTransac
|
|
|
78
94
|
return assertEx(this.params.chainIdentification, () => 'No chain id')
|
|
79
95
|
}
|
|
80
96
|
|
|
81
|
-
private get
|
|
82
|
-
return assertEx(this.params.
|
|
97
|
+
private get pendingBundledTransactionsArchivist() {
|
|
98
|
+
return assertEx(this.params.pendingBundledTransactionsArchivist, () => 'No pending bundled transactions archivist')
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private get pendingBundledTransactionsLocalArchivist() {
|
|
102
|
+
return assertEx(this._curatedPendingBundledTransactionsArchivist, () => 'No pending bundled transactions curated archivist')
|
|
83
103
|
}
|
|
84
104
|
|
|
85
105
|
private get pendingTransactionsCount() {
|
|
@@ -87,31 +107,27 @@ export class XyoPendingTransactionsService extends BaseService<XyoPendingTransac
|
|
|
87
107
|
return this._pendingTransactionsCount
|
|
88
108
|
}
|
|
89
109
|
|
|
90
|
-
private get
|
|
91
|
-
return assertEx(this.
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
private get rejectedTransactionsArchivist() {
|
|
95
|
-
return assertEx(this.params.rejectedTransactionsArchivist, () => 'No rejected transactions archivist')
|
|
110
|
+
private get rejectedBundledTransactionsArchivist() {
|
|
111
|
+
return assertEx(this.params.rejectedBundledTransactionsArchivist, () => 'No rejected bundled transactions archivist')
|
|
96
112
|
}
|
|
97
113
|
|
|
98
114
|
override async createHandler() {
|
|
99
115
|
await super.createHandler()
|
|
100
|
-
this.
|
|
116
|
+
this._curatedPendingBundledTransactionsArchivist = await MemoryArchivist.create({ account: 'random' })
|
|
101
117
|
|
|
102
118
|
// On new pending transactions, insert them into the curated archivist
|
|
103
|
-
this.
|
|
104
|
-
await this.insertNewTransactions(payloads)
|
|
119
|
+
this.pendingBundledTransactionsArchivist.on('inserted', async ({ payloads }) => {
|
|
120
|
+
await this.insertNewTransactions(payloads as WithStorageMeta<PayloadBundle>[])
|
|
105
121
|
})
|
|
106
122
|
|
|
107
123
|
// On new finalized blocks, remove the transactions from the curated archivist
|
|
108
|
-
this.chainArchivist.on('inserted',
|
|
109
|
-
|
|
124
|
+
this.chainArchivist.on('inserted', ({ payloads }) => {
|
|
125
|
+
this.removeFinalizedTransactions(payloads)
|
|
110
126
|
})
|
|
111
127
|
|
|
112
128
|
// On new rejected blocks, remove the transactions from the curated archivist
|
|
113
|
-
this.
|
|
114
|
-
|
|
129
|
+
this.rejectedBundledTransactionsArchivist.on('inserted', ({ payloads }) => {
|
|
130
|
+
this.removeRejectedBundledTransactions(payloads)
|
|
115
131
|
})
|
|
116
132
|
|
|
117
133
|
const pendingTransactionsGauge = this.meter?.createObservableGauge(
|
|
@@ -126,21 +142,31 @@ export class XyoPendingTransactionsService extends BaseService<XyoPendingTransac
|
|
|
126
142
|
async getPendingTransactions(head: Hash, limit: number): Promise<HydratedTransactionWithStorageMeta[]> {
|
|
127
143
|
return await this.spanAsync('getPendingTransactions', async () => {
|
|
128
144
|
return await this._updateCuratedPendingTransactionsArchivistMutex.runExclusive(async () => {
|
|
129
|
-
const foundPendingTransactions:
|
|
145
|
+
const foundPendingTransactions: HydratedTransactionWithStorageMeta[] = []
|
|
146
|
+
const foundPendingTransactionsToDeleteHashes: Hash[] = []
|
|
130
147
|
let cursor: Sequence | undefined
|
|
131
148
|
while (foundPendingTransactions.length < limit) {
|
|
132
|
-
const payloads = await this.
|
|
149
|
+
const payloads = await this.pendingBundledTransactionsLocalArchivist.next({
|
|
133
150
|
limit: 100, order: 'asc', cursor,
|
|
134
|
-
})
|
|
151
|
+
}) as WithStorageMeta<PayloadBundle>[]
|
|
135
152
|
if (payloads.length === 0) break
|
|
136
153
|
cursor = payloads.at(-1)?._sequence
|
|
137
|
-
const
|
|
154
|
+
const deletedTransactionBundles = payloads.filter(tx => this._removablePendingTransactionHashes.has(tx.root))
|
|
155
|
+
foundPendingTransactionsToDeleteHashes.push(...deletedTransactionBundles.map(tx => tx._hash).filter(exists))
|
|
156
|
+
const undeletedTransactionBundles = payloads.filter(tx => !this._removablePendingTransactionHashes.has(tx.root))
|
|
157
|
+
// add the items that are not to be deleted
|
|
158
|
+
const transactions = (await Promise.all(
|
|
159
|
+
undeletedTransactionBundles.map(p => bundledPayloadsToHydratedTransaction(p)),
|
|
160
|
+
)).filter(exists)
|
|
138
161
|
foundPendingTransactions.push(...transactions)
|
|
139
162
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
163
|
+
// remove the hashes from delete queue
|
|
164
|
+
for (const hash of foundPendingTransactionsToDeleteHashes) {
|
|
165
|
+
this._removablePendingTransactionHashes.delete(hash)
|
|
166
|
+
}
|
|
167
|
+
// actually delete the bundles
|
|
168
|
+
await this.pendingBundledTransactionsLocalArchivist.delete(foundPendingTransactionsToDeleteHashes)
|
|
169
|
+
return foundPendingTransactions
|
|
144
170
|
}, XyoPendingTransactionsService.MutexPriority.ReadTransactions)
|
|
145
171
|
})
|
|
146
172
|
}
|
|
@@ -148,30 +174,30 @@ export class XyoPendingTransactionsService extends BaseService<XyoPendingTransac
|
|
|
148
174
|
private async countPendingTransactions() {
|
|
149
175
|
if (this._countPendingTransactionsMutex.isLocked()) return
|
|
150
176
|
await this._countPendingTransactionsMutex.runExclusive(async () => {
|
|
151
|
-
const payloads = (await this.
|
|
152
|
-
|
|
153
|
-
this._pendingTransactionsCount = pendingTransactions.length
|
|
177
|
+
const payloads = (await this._curatedPendingBundledTransactionsArchivist?.all()) ?? []
|
|
178
|
+
this._pendingTransactionsCount = payloads.length
|
|
154
179
|
})
|
|
155
180
|
}
|
|
156
181
|
|
|
157
|
-
private async filterAlreadyFinalizedTransactions(
|
|
158
|
-
|
|
159
|
-
|
|
182
|
+
private async filterAlreadyFinalizedTransactions(
|
|
183
|
+
incomingTransactions: WithStorageMeta<PayloadBundle>[],
|
|
184
|
+
): Promise<WithStorageMeta<PayloadBundle>[]> {
|
|
185
|
+
const incomingTransactionHashes = incomingTransactions.map(payload => payload.root)
|
|
160
186
|
const finalizedTransactions = await this.chainArchivist.get(incomingTransactionHashes)
|
|
161
187
|
const finalizedTransactionHashes = new Set(finalizedTransactions.map(item => item._hash))
|
|
162
188
|
const nonFinalizedTransactions = incomingTransactions.filter(item => !finalizedTransactionHashes.has(item._hash))
|
|
163
189
|
return nonFinalizedTransactions
|
|
164
190
|
}
|
|
165
191
|
|
|
166
|
-
private async insertNewTransactions(payloads: WithStorageMeta<
|
|
192
|
+
private async insertNewTransactions(payloads: WithStorageMeta<PayloadBundle>[]) {
|
|
167
193
|
this.logger?.log('insertNewTransactions', payloads)
|
|
168
194
|
return await this.spanAsync('InsertNewTransactions', async () => {
|
|
169
195
|
return await this._updateCuratedPendingTransactionsArchivistMutex.runExclusive(async () => {
|
|
170
196
|
// Check incoming transactions against finalized transactions
|
|
171
197
|
const unprocessedTransactions = await this.filterAlreadyFinalizedTransactions(payloads)
|
|
172
198
|
// Hydrate all unprocessed transactions
|
|
173
|
-
const hydratedUnprocessedTransactions = (await Promise.all(unprocessedTransactions.map((tx) => {
|
|
174
|
-
return
|
|
199
|
+
const hydratedUnprocessedTransactions = (await Promise.all(unprocessedTransactions.map(async (tx) => {
|
|
200
|
+
return await bundledPayloadsToHydratedTransaction(tx)
|
|
175
201
|
}))).filter(exists)
|
|
176
202
|
// Filter to only valid transactions
|
|
177
203
|
const validTransactions = await filterAsync(hydratedUnprocessedTransactions, async (tx) => {
|
|
@@ -182,29 +208,44 @@ export class XyoPendingTransactionsService extends BaseService<XyoPendingTransac
|
|
|
182
208
|
return errors.length > 0 ? false : true
|
|
183
209
|
})
|
|
184
210
|
if (validTransactions.length > 0) {
|
|
185
|
-
await this.
|
|
211
|
+
await this.pendingBundledTransactionsLocalArchivist.insert(validTransactions.map((tx) => {
|
|
212
|
+
return {
|
|
213
|
+
root: tx[0]._hash,
|
|
214
|
+
payloads: flattenHydratedTransaction(tx),
|
|
215
|
+
} as PayloadBundle
|
|
216
|
+
}))
|
|
186
217
|
}
|
|
187
218
|
}, XyoPendingTransactionsService.MutexPriority.InsertNewTransactions)
|
|
188
219
|
})
|
|
189
220
|
}
|
|
190
221
|
|
|
191
|
-
private async
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
private async removeRejectedTransactions(payloads: WithStorageMeta<Payload>[]) {
|
|
196
|
-
return await this.removeTransactions(payloads, 'RemoveRejectedTransactions')
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
private async removeTransactions(
|
|
200
|
-
payloads: WithStorageMeta<Payload>[],
|
|
222
|
+
private async removeBundledTransactions(
|
|
223
|
+
bundledPayloads: WithStorageMeta<PayloadBundle>[],
|
|
201
224
|
priority: keyof typeof XyoPendingTransactionsService.MutexPriority,
|
|
202
225
|
) {
|
|
203
226
|
return await this.spanAsync(priority, async () => {
|
|
204
227
|
return await this._updateCuratedPendingTransactionsArchivistMutex.runExclusive(async () => {
|
|
205
|
-
const
|
|
206
|
-
|
|
228
|
+
const bundledTransactions = (await Promise.all(bundledPayloads.map(async (payload) => {
|
|
229
|
+
const withStorageMeta = await PayloadBuilder.addStorageMeta(payload.payloads)
|
|
230
|
+
const tx = asOptionalTransactionBoundWitnessWithStorageMeta(withStorageMeta.find(p => p._hash === payload.root))
|
|
231
|
+
return tx !== undefined && payload._hash !== undefined ? tx : undefined
|
|
232
|
+
}))).filter(exists)
|
|
233
|
+
await this.pendingBundledTransactionsLocalArchivist.delete(bundledTransactions.map(btx => btx._hash))
|
|
207
234
|
}, XyoPendingTransactionsService.MutexPriority[priority])
|
|
208
235
|
})
|
|
209
236
|
}
|
|
237
|
+
|
|
238
|
+
private removeFinalizedTransactions(payloads: WithStorageMeta<Payload>[]) {
|
|
239
|
+
const finalizedTransactionHashes = payloads.filter(isTransactionBoundWitnessWithStorageMeta).map(p => p._hash)
|
|
240
|
+
for (const hash of finalizedTransactionHashes) {
|
|
241
|
+
this._removablePendingTransactionHashes.add(hash)
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
private removeRejectedBundledTransactions(payloads: WithStorageMeta<Payload>[]) {
|
|
246
|
+
const rejectedTransactionHashes = payloads.filter(isTransactionBoundWitnessWithStorageMeta).map(p => p._hash)
|
|
247
|
+
for (const hash of rejectedTransactionHashes) {
|
|
248
|
+
this._removablePendingTransactionHashes.add(hash)
|
|
249
|
+
}
|
|
250
|
+
}
|
|
210
251
|
}
|