@xyo-network/chain-services 1.5.11 → 1.5.13

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.
@@ -9,7 +9,7 @@ export interface XyoValidatorParams extends BaseServiceParams {
9
9
  chainArchivist: ReadArchivist;
10
10
  chainInformation: ChainInformation;
11
11
  electionService: ElectionService;
12
- pendingTransactionsArchivist: ArchivistInstance;
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 pendingTransactionsArchivist(): TParams["pendingTransactionsArchivist"];
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,4BAA4B,EAAE,iBAAiB,CAAA;IAC/C,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,4BAA4B,4CAEzC;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"}
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
- pendingTransactionsArchivist?: ArchivistInstance;
9
- rejectedTransactionsArchivist?: ArchivistInstance;
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 _curatedPendingTransactionsArchivist;
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 pendingTransactionsArchivist();
35
+ private get pendingBundledTransactionsArchivist();
36
+ private get pendingBundledTransactionsLocalArchivist();
35
37
  private get pendingTransactionsCount();
36
- private get pendingTransactionsLocalArchivist();
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 removeRejectedTransactions;
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;AAKhE,OAAO,EAC6C,iBAAiB,EAAE,mBAAmB,EAAE,kCAAkC,EAC5H,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,4BAA4B,CAAC,EAAE,iBAAiB,CAAA;IAChD,6BAA6B,CAAC,EAAE,iBAAiB,CAAA;CAClD;AAED,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,oCAAoC,CAA6B;IAEzE;;OAEG;IACH,OAAO,CAAC,yBAAyB,CAAY;IAE7C;;;OAGG;IACH,OAAO,CAAC,+CAA+C,CAAc;IAErE,OAAO,KAAK,cAAc,GAEzB;IAED,OAAO,KAAK,mBAAmB,GAE9B;IAED,OAAO,KAAK,4BAA4B,GAEvC;IAED,OAAO,KAAK,wBAAwB,GAGnC;IAED,OAAO,KAAK,iCAAiC,GAE5C;IAED,OAAO,KAAK,6BAA6B,GAExC;IAEc,aAAa;IA4BtB,sBAAsB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kCAAkC,EAAE,CAAC;YAsBxF,wBAAwB;YASxB,kCAAkC;YASlC,qBAAqB;YAyBrB,2BAA2B;YAI3B,0BAA0B;YAI1B,kBAAkB;CAWjC"}
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;AAQhE,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;AAcD,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;IA+BtB,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.11",
4
+ "version": "1.5.13",
5
5
  "description": "XYO Layer One SDK Services",
6
6
  "homepage": "https://xylabs.com",
7
7
  "bugs": {
@@ -35,35 +35,35 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@opentelemetry/api": "^1.9.0",
38
- "@xylabs/array": "^4.11.10",
39
- "@xylabs/assert": "^4.11.10",
40
- "@xylabs/base": "^4.11.10",
41
- "@xylabs/decimal-precision": "^4.11.10",
42
- "@xylabs/events": "^4.11.10",
43
- "@xylabs/exists": "^4.11.10",
44
- "@xylabs/forget": "^4.11.10",
45
- "@xylabs/hex": "^4.11.10",
46
- "@xylabs/promise": "^4.11.10",
47
- "@xylabs/telemetry": "^4.11.10",
48
- "@xylabs/typeof": "^4.11.10",
49
- "@xyo-network/account-model": "^3.18.0",
50
- "@xyo-network/archivist-memory": "^3.18.0",
51
- "@xyo-network/archivist-model": "^3.18.0",
52
- "@xyo-network/boundwitness-model": "^3.18.0",
53
- "@xyo-network/boundwitness-validator": "^3.18.0",
54
- "@xyo-network/boundwitness-wrapper": "^3.18.0",
55
- "@xyo-network/chain-analyze": "^1.5.11",
56
- "@xyo-network/chain-ethereum": "^1.5.11",
57
- "@xyo-network/chain-modules": "^1.5.11",
58
- "@xyo-network/chain-protocol": "^1.5.11",
59
- "@xyo-network/chain-utils": "^1.5.11",
60
- "@xyo-network/chain-validation": "^1.5.11",
61
- "@xyo-network/chain-wrappers": "^1.5.11",
62
- "@xyo-network/payload-builder": "^3.18.0",
63
- "@xyo-network/payload-model": "^3.18.0",
38
+ "@xylabs/array": "^4.11.11",
39
+ "@xylabs/assert": "^4.11.11",
40
+ "@xylabs/base": "^4.11.11",
41
+ "@xylabs/decimal-precision": "^4.11.11",
42
+ "@xylabs/events": "^4.11.11",
43
+ "@xylabs/exists": "^4.11.11",
44
+ "@xylabs/forget": "^4.11.11",
45
+ "@xylabs/hex": "^4.11.11",
46
+ "@xylabs/promise": "^4.11.11",
47
+ "@xylabs/telemetry": "^4.11.11",
48
+ "@xylabs/typeof": "^4.11.11",
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.13",
56
+ "@xyo-network/chain-ethereum": "^1.5.13",
57
+ "@xyo-network/chain-modules": "^1.5.13",
58
+ "@xyo-network/chain-protocol": "^1.5.13",
59
+ "@xyo-network/chain-utils": "^1.5.13",
60
+ "@xyo-network/chain-validation": "^1.5.13",
61
+ "@xyo-network/chain-wrappers": "^1.5.13",
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.11",
66
+ "@xyo-network/xl1-protocol-sdk": "^1.5.13",
67
67
  "async-mutex": "^0.5.0",
68
68
  "ethers": "6.14.3",
69
69
  "lru-cache": "^11.1.0",
@@ -71,17 +71,17 @@
71
71
  },
72
72
  "devDependencies": {
73
73
  "@types/node": "^22.15.29",
74
- "@xylabs/delay": "^4.11.10",
75
- "@xylabs/ts-scripts-yarn3": "^6.5.7",
76
- "@xylabs/tsconfig": "^6.5.7",
77
- "@xylabs/vitest-extended": "^4.11.10",
78
- "@xyo-network/account": "^3.18.0",
79
- "@xyo-network/account-model": "^3.18.0",
80
- "@xyo-network/chain-validation": "^1.5.11",
81
- "@xyo-network/wallet": "^3.18.0",
82
- "knip": "^5.59.1",
74
+ "@xylabs/delay": "^4.11.11",
75
+ "@xylabs/ts-scripts-yarn3": "^6.5.8",
76
+ "@xylabs/tsconfig": "^6.5.8",
77
+ "@xylabs/vitest-extended": "^4.11.11",
78
+ "@xyo-network/account": "^3.18.2",
79
+ "@xyo-network/account-model": "^3.18.2",
80
+ "@xyo-network/chain-validation": "^1.5.13",
81
+ "@xyo-network/wallet": "^3.18.2",
82
+ "knip": "^5.60.0",
83
83
  "typescript": "^5.8.3",
84
- "vitest": "^3.2.0",
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
- rejectedTransactionsArchivist: ArchivistInstance
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 rejectedTransactionsArchivist() {
84
- return assertEx(this.params.rejectedTransactionsArchivist, () => 'No rejected transactions archivist')
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.rejectedTransactionsArchivist.insert(rejectedTransactions)
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
- pendingTransactionsArchivist: ArchivistInstance
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 pendingTransactionsArchivist() {
59
- return assertEx(this.params.pendingTransactionsArchivist, () => 'pendingTransactions is required')
58
+ protected get pendingBundledTransactionsArchivist() {
59
+ return assertEx(this.params.pendingBundledTransactionsArchivist, () => 'pendingBundledTransactions is required')
60
60
  }
61
61
 
62
62
  protected get rewardService() {
@@ -1,20 +1,25 @@
1
1
  import { ValueType } from '@opentelemetry/api'
2
- import { filterAs, filterAsync } from '@xylabs/array'
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'
6
6
  import { Hash } from '@xylabs/hex'
7
7
  import { MemoryArchivist } from '@xyo-network/archivist-memory'
8
8
  import { ArchivistInstance } from '@xyo-network/archivist-model'
9
+ import { globalAttributes } from '@xyo-network/chain-telemetry'
9
10
  import { validateTransaction } from '@xyo-network/chain-validation'
11
+ import { PayloadBuilder } from '@xyo-network/payload-builder'
10
12
  import {
11
- Payload, Sequence, WithStorageMeta,
13
+ Payload,
14
+ PayloadBundle, Sequence, WithStorageMeta,
12
15
  } from '@xyo-network/payload-model'
13
16
  import {
14
- asOptionalTransactionBoundWitnessWithStorageMeta, BaseServiceParams, ChainIdentification, HydratedTransactionWithStorageMeta,
15
- PendingTransactionsService, TransactionBoundWitness,
17
+ asOptionalTransactionBoundWitnessWithStorageMeta, BaseServiceParams,
18
+ ChainIdentification, HydratedTransactionWithStorageMeta,
19
+ isTransactionBoundWitnessWithStorageMeta,
20
+ PendingTransactionsService,
16
21
  } from '@xyo-network/xl1-protocol'
17
- import { flattenHydratedTransactions, tryHydrateTransaction } from '@xyo-network/xl1-protocol-sdk'
22
+ import { flattenHydratedTransaction } from '@xyo-network/xl1-protocol-sdk'
18
23
  import { Mutex } from 'async-mutex'
19
24
 
20
25
  import { BaseService, creatableService } from '../BaseService.ts'
@@ -22,10 +27,22 @@ import { BaseService, creatableService } from '../BaseService.ts'
22
27
  export interface XyoPendingTransactionsServiceParams extends BaseServiceParams {
23
28
  chainArchivist?: ArchivistInstance
24
29
  chainIdentification?: ChainIdentification
25
- pendingTransactionsArchivist?: ArchivistInstance
26
- rejectedTransactionsArchivist?: ArchivistInstance
30
+ pendingBundledTransactionsArchivist?: ArchivistInstance
31
+ rejectedBundledTransactionsArchivist?: ArchivistInstance
27
32
  }
28
33
 
34
+ async function bundledPayloadsToHydratedTransaction(
35
+ payload: WithStorageMeta<PayloadBundle>,
36
+ ): Promise<HydratedTransactionWithStorageMeta | undefined> {
37
+ const withStorageMeta = await PayloadBuilder.addStorageMeta(payload.payloads)
38
+ const tx = asOptionalTransactionBoundWitnessWithStorageMeta(withStorageMeta.find(p => p._hash === payload.root))
39
+ if (tx) {
40
+ return [tx, withStorageMeta.map(p => p._hash === payload.root ? undefined : p).filter(exists)]
41
+ }
42
+ }
43
+
44
+ globalAttributes.setAttribute('XyoPendingTransactionsService:status', 'unknown')
45
+
29
46
  @creatableService()
30
47
  export class XyoPendingTransactionsService extends BaseService<XyoPendingTransactionsServiceParams> implements PendingTransactionsService {
31
48
  private static readonly MutexPriority = {
@@ -57,13 +74,15 @@ export class XyoPendingTransactionsService extends BaseService<XyoPendingTransac
57
74
  * A local Archivist optimized for fast retrieval that stores only validated
58
75
  * pending transactions
59
76
  */
60
- private _curatedPendingTransactionsArchivist: MemoryArchivist | undefined
77
+ private _curatedPendingBundledTransactionsArchivist: MemoryArchivist | undefined
61
78
 
62
79
  /**
63
80
  * The last count of total pending transactions
64
81
  */
65
82
  private _pendingTransactionsCount: number = 0
66
83
 
84
+ private _removablePendingTransactionHashes: Set<Hash> = new Set()
85
+
67
86
  /**
68
87
  * A mutex to ensure that the curated pending transactions archivist is
69
88
  * updated in a thread-safe manner
@@ -78,8 +97,12 @@ export class XyoPendingTransactionsService extends BaseService<XyoPendingTransac
78
97
  return assertEx(this.params.chainIdentification, () => 'No chain id')
79
98
  }
80
99
 
81
- private get pendingTransactionsArchivist() {
82
- return assertEx(this.params.pendingTransactionsArchivist, () => 'No pending transactions archivist')
100
+ private get pendingBundledTransactionsArchivist() {
101
+ return assertEx(this.params.pendingBundledTransactionsArchivist, () => 'No pending bundled transactions archivist')
102
+ }
103
+
104
+ private get pendingBundledTransactionsLocalArchivist() {
105
+ return assertEx(this._curatedPendingBundledTransactionsArchivist, () => 'No pending bundled transactions curated archivist')
83
106
  }
84
107
 
85
108
  private get pendingTransactionsCount() {
@@ -87,60 +110,69 @@ export class XyoPendingTransactionsService extends BaseService<XyoPendingTransac
87
110
  return this._pendingTransactionsCount
88
111
  }
89
112
 
90
- private get pendingTransactionsLocalArchivist() {
91
- return assertEx(this._curatedPendingTransactionsArchivist, () => 'No pending transactions curated archivist')
92
- }
93
-
94
- private get rejectedTransactionsArchivist() {
95
- return assertEx(this.params.rejectedTransactionsArchivist, () => 'No rejected transactions archivist')
113
+ private get rejectedBundledTransactionsArchivist() {
114
+ return assertEx(this.params.rejectedBundledTransactionsArchivist, () => 'No rejected bundled transactions archivist')
96
115
  }
97
116
 
98
117
  override async createHandler() {
99
118
  await super.createHandler()
100
- this._curatedPendingTransactionsArchivist = await MemoryArchivist.create({ account: 'random' })
119
+ this._curatedPendingBundledTransactionsArchivist = await MemoryArchivist.create({ account: 'random' })
101
120
 
102
121
  // On new pending transactions, insert them into the curated archivist
103
- this.pendingTransactionsArchivist.on('inserted', async ({ payloads }) => {
104
- await this.insertNewTransactions(payloads)
122
+ this.pendingBundledTransactionsArchivist.on('inserted', async ({ payloads }) => {
123
+ await this.insertNewTransactions(payloads as WithStorageMeta<PayloadBundle>[])
105
124
  })
106
125
 
107
126
  // On new finalized blocks, remove the transactions from the curated archivist
108
- this.chainArchivist.on('inserted', async ({ payloads }) => {
109
- await this.removeFinalizedTransactions(payloads)
127
+ this.chainArchivist.on('inserted', ({ payloads }) => {
128
+ this.removeFinalizedTransactions(payloads)
110
129
  })
111
130
 
112
131
  // On new rejected blocks, remove the transactions from the curated archivist
113
- this.rejectedTransactionsArchivist.on('inserted', async ({ payloads }) => {
114
- await this.removeRejectedTransactions(payloads)
132
+ this.rejectedBundledTransactionsArchivist.on('inserted', ({ payloads }) => {
133
+ this.removeRejectedBundledTransactions(payloads)
115
134
  })
116
135
 
117
- const pendingTransactionsGauge = this.meter?.createObservableGauge(
118
- 'xyo_pending_transactions_count',
119
- { description: 'The current number of pending transactions', valueType: ValueType.INT },
136
+ const pendingTransactionsCounter = this.meter?.createObservableUpDownCounter(
137
+ 'xyo_pending_transactions_counter',
138
+ {
139
+ description: 'The current number of pending transactions', valueType: ValueType.INT, unit: '1',
140
+ },
120
141
  )
121
- pendingTransactionsGauge?.addCallback((observer) => {
142
+ pendingTransactionsCounter?.addCallback((observer) => {
122
143
  observer.observe(this.pendingTransactionsCount)
123
144
  })
145
+ globalAttributes.setAttribute('XyoPendingTransactionsService:status', 'created')
124
146
  }
125
147
 
126
148
  async getPendingTransactions(head: Hash, limit: number): Promise<HydratedTransactionWithStorageMeta[]> {
127
149
  return await this.spanAsync('getPendingTransactions', async () => {
128
150
  return await this._updateCuratedPendingTransactionsArchivistMutex.runExclusive(async () => {
129
- const foundPendingTransactions: WithStorageMeta<TransactionBoundWitness>[] = []
151
+ const foundPendingTransactions: HydratedTransactionWithStorageMeta[] = []
152
+ const foundPendingTransactionsToDeleteHashes: Hash[] = []
130
153
  let cursor: Sequence | undefined
131
154
  while (foundPendingTransactions.length < limit) {
132
- const payloads = await this.pendingTransactionsLocalArchivist.next({
155
+ const payloads = await this.pendingBundledTransactionsLocalArchivist.next({
133
156
  limit: 100, order: 'asc', cursor,
134
- })
157
+ }) as WithStorageMeta<PayloadBundle>[]
135
158
  if (payloads.length === 0) break
136
159
  cursor = payloads.at(-1)?._sequence
137
- const transactions = payloads.map(payload => asOptionalTransactionBoundWitnessWithStorageMeta(payload)).filter(exists)
160
+ const deletedTransactionBundles = payloads.filter(tx => this._removablePendingTransactionHashes.has(tx.root))
161
+ foundPendingTransactionsToDeleteHashes.push(...deletedTransactionBundles.map(tx => tx._hash).filter(exists))
162
+ const undeletedTransactionBundles = payloads.filter(tx => !this._removablePendingTransactionHashes.has(tx.root))
163
+ // add the items that are not to be deleted
164
+ const transactions = (await Promise.all(
165
+ undeletedTransactionBundles.map(p => bundledPayloadsToHydratedTransaction(p)),
166
+ )).filter(exists)
138
167
  foundPendingTransactions.push(...transactions)
139
168
  }
140
- const hydratedTransactions = await Promise.all(
141
- foundPendingTransactions.map(tx => tryHydrateTransaction(this.pendingTransactionsLocalArchivist, tx._hash)),
142
- )
143
- return hydratedTransactions.filter(exists)
169
+ // remove the hashes from delete queue
170
+ for (const hash of foundPendingTransactionsToDeleteHashes) {
171
+ this._removablePendingTransactionHashes.delete(hash)
172
+ }
173
+ // actually delete the bundles
174
+ await this.pendingBundledTransactionsLocalArchivist.delete(foundPendingTransactionsToDeleteHashes)
175
+ return foundPendingTransactions
144
176
  }, XyoPendingTransactionsService.MutexPriority.ReadTransactions)
145
177
  })
146
178
  }
@@ -148,30 +180,30 @@ export class XyoPendingTransactionsService extends BaseService<XyoPendingTransac
148
180
  private async countPendingTransactions() {
149
181
  if (this._countPendingTransactionsMutex.isLocked()) return
150
182
  await this._countPendingTransactionsMutex.runExclusive(async () => {
151
- const payloads = (await this._curatedPendingTransactionsArchivist?.all()) ?? []
152
- const pendingTransactions = filterAs(payloads, asOptionalTransactionBoundWitnessWithStorageMeta)
153
- this._pendingTransactionsCount = pendingTransactions.length
183
+ const payloads = (await this._curatedPendingBundledTransactionsArchivist?.all()) ?? []
184
+ this._pendingTransactionsCount = payloads.length
154
185
  })
155
186
  }
156
187
 
157
- private async filterAlreadyFinalizedTransactions(payloads: WithStorageMeta<Payload>[]): Promise<WithStorageMeta<TransactionBoundWitness>[]> {
158
- const incomingTransactions = filterAs(payloads, asOptionalTransactionBoundWitnessWithStorageMeta)
159
- const incomingTransactionHashes = incomingTransactions.map(payload => payload._hash)
188
+ private async filterAlreadyFinalizedTransactions(
189
+ incomingTransactions: WithStorageMeta<PayloadBundle>[],
190
+ ): Promise<WithStorageMeta<PayloadBundle>[]> {
191
+ const incomingTransactionHashes = incomingTransactions.map(payload => payload.root)
160
192
  const finalizedTransactions = await this.chainArchivist.get(incomingTransactionHashes)
161
193
  const finalizedTransactionHashes = new Set(finalizedTransactions.map(item => item._hash))
162
194
  const nonFinalizedTransactions = incomingTransactions.filter(item => !finalizedTransactionHashes.has(item._hash))
163
195
  return nonFinalizedTransactions
164
196
  }
165
197
 
166
- private async insertNewTransactions(payloads: WithStorageMeta<Payload>[]) {
198
+ private async insertNewTransactions(payloads: WithStorageMeta<PayloadBundle>[]) {
167
199
  this.logger?.log('insertNewTransactions', payloads)
168
200
  return await this.spanAsync('InsertNewTransactions', async () => {
169
201
  return await this._updateCuratedPendingTransactionsArchivistMutex.runExclusive(async () => {
170
202
  // Check incoming transactions against finalized transactions
171
203
  const unprocessedTransactions = await this.filterAlreadyFinalizedTransactions(payloads)
172
204
  // Hydrate all unprocessed transactions
173
- const hydratedUnprocessedTransactions = (await Promise.all(unprocessedTransactions.map((tx) => {
174
- return tryHydrateTransaction(this.pendingTransactionsArchivist, tx._hash)
205
+ const hydratedUnprocessedTransactions = (await Promise.all(unprocessedTransactions.map(async (tx) => {
206
+ return await bundledPayloadsToHydratedTransaction(tx)
175
207
  }))).filter(exists)
176
208
  // Filter to only valid transactions
177
209
  const validTransactions = await filterAsync(hydratedUnprocessedTransactions, async (tx) => {
@@ -182,29 +214,44 @@ export class XyoPendingTransactionsService extends BaseService<XyoPendingTransac
182
214
  return errors.length > 0 ? false : true
183
215
  })
184
216
  if (validTransactions.length > 0) {
185
- await this.pendingTransactionsLocalArchivist.insert(flattenHydratedTransactions(validTransactions))
217
+ await this.pendingBundledTransactionsLocalArchivist.insert(validTransactions.map((tx) => {
218
+ return {
219
+ root: tx[0]._hash,
220
+ payloads: flattenHydratedTransaction(tx),
221
+ } as PayloadBundle
222
+ }))
186
223
  }
187
224
  }, XyoPendingTransactionsService.MutexPriority.InsertNewTransactions)
188
225
  })
189
226
  }
190
227
 
191
- private async removeFinalizedTransactions(payloads: WithStorageMeta<Payload>[]) {
192
- return await this.removeTransactions(payloads, 'RemoveFinalizedTransactions')
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>[],
228
+ private async removeBundledTransactions(
229
+ bundledPayloads: WithStorageMeta<PayloadBundle>[],
201
230
  priority: keyof typeof XyoPendingTransactionsService.MutexPriority,
202
231
  ) {
203
232
  return await this.spanAsync(priority, async () => {
204
233
  return await this._updateCuratedPendingTransactionsArchivistMutex.runExclusive(async () => {
205
- const transactions = filterAs(payloads, asOptionalTransactionBoundWitnessWithStorageMeta)
206
- await this.pendingTransactionsLocalArchivist.delete(transactions.map(tx => tx._hash))
234
+ const bundledTransactions = (await Promise.all(bundledPayloads.map(async (payload) => {
235
+ const withStorageMeta = await PayloadBuilder.addStorageMeta(payload.payloads)
236
+ const tx = asOptionalTransactionBoundWitnessWithStorageMeta(withStorageMeta.find(p => p._hash === payload.root))
237
+ return tx !== undefined && payload._hash !== undefined ? tx : undefined
238
+ }))).filter(exists)
239
+ await this.pendingBundledTransactionsLocalArchivist.delete(bundledTransactions.map(btx => btx._hash))
207
240
  }, XyoPendingTransactionsService.MutexPriority[priority])
208
241
  })
209
242
  }
243
+
244
+ private removeFinalizedTransactions(payloads: WithStorageMeta<Payload>[]) {
245
+ const finalizedTransactionHashes = payloads.filter(isTransactionBoundWitnessWithStorageMeta).map(p => p._hash)
246
+ for (const hash of finalizedTransactionHashes) {
247
+ this._removablePendingTransactionHashes.add(hash)
248
+ }
249
+ }
250
+
251
+ private removeRejectedBundledTransactions(payloads: WithStorageMeta<Payload>[]) {
252
+ const rejectedTransactionHashes = payloads.filter(isTransactionBoundWitnessWithStorageMeta).map(p => p._hash)
253
+ for (const hash of rejectedTransactionHashes) {
254
+ this._removablePendingTransactionHashes.add(hash)
255
+ }
256
+ }
210
257
  }