trac-msb 0.2.24 → 0.3.0-beta.1

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.
Files changed (137) hide show
  1. package/SECURITY.md +2 -2
  2. package/cli/commandHandler.js +317 -20
  3. package/cli/handlers.js +9 -1
  4. package/cli/interactive.js +4 -3
  5. package/cli/tokenSupplyAudit.js +90 -0
  6. package/msb.mjs +1 -0
  7. package/package.json +15 -6
  8. package/rpc/create_server.js +12 -3
  9. package/rpc/handlers.js +103 -0
  10. package/rpc/routes/v1.js +8 -0
  11. package/src/codecs/apply/applyOperationCodec.js +334 -0
  12. package/src/codecs/apply/applyOperations.generated.cjs +6380 -0
  13. package/src/codecs/consensus/v1/consensusV1.generated.cjs +3508 -0
  14. package/src/codecs/consensus/v1/consensusV1OperationCodec.js +161 -0
  15. package/src/codecs/consensus/v1/vdfConfigCodec.js +83 -0
  16. package/src/{utils/protobuf → codecs/network/v1}/networkV1.generated.cjs +664 -393
  17. package/src/codecs/network/v1/networkV1OperationCodec.js +25 -0
  18. package/src/codecs/protobufRuntime.cjs +95 -0
  19. package/src/codecs/state/escrowEntryCodec.js +45 -0
  20. package/src/codecs/state/state.generated.cjs +659 -0
  21. package/src/config/args.js +0 -1
  22. package/src/config/config.js +46 -7
  23. package/src/config/env.js +33 -6
  24. package/src/core/consensus/epochAppenderSelection/EpochAppenderSelectionError.js +55 -0
  25. package/src/core/consensus/epochAppenderSelection/EpochAppenderSelectionOperations.js +118 -0
  26. package/src/core/consensus/epochAppenderSelection/EpochAppenderSelector.js +1042 -0
  27. package/src/core/consensus/epochAppenderSelection/createEpochAppenderSelector.js +23 -0
  28. package/src/core/consensus/epochAppenderSelection/epochAppenderSelectionLedgerReader.js +274 -0
  29. package/src/core/consensus/epochAppenderSelection/epochAppenderSelectionState.js +488 -0
  30. package/src/core/consensus/epochAppenderSelection/epochAppenderSelectionStorage.js +93 -0
  31. package/src/core/consensus/quorum.js +11 -0
  32. package/src/core/consensus/services/EpochCoordinationRound.js +839 -0
  33. package/src/core/consensus/services/EpochCoordinatorOperations.js +211 -0
  34. package/src/core/consensus/services/EpochCoordinatorService.js +335 -0
  35. package/src/core/consensus/services/EpochRoundListeners.js +116 -0
  36. package/src/core/consensus/services/EpochStateMachine.js +141 -0
  37. package/src/core/consensus/services/VDFBare.js +291 -0
  38. package/src/core/consensus/services/VDFNode.js +111 -0
  39. package/src/core/consensus/services/VDFProgressWatchdog.js +79 -0
  40. package/src/core/consensus/services/VDFService.js +87 -0
  41. package/src/core/consensus/services/VDFServiceManager.js +147 -0
  42. package/src/core/consensus/services/createVDFService.js +16 -0
  43. package/src/core/consensus/services/vdf-guardian.js +32 -0
  44. package/src/core/consensus/services/vdf-worker.js +90 -0
  45. package/src/core/network/Network.js +327 -238
  46. package/src/core/network/protocols/consensus/IndexerMessages.js +72 -0
  47. package/src/core/network/protocols/consensus/v1/ConsensusV1ConnectionPolicy.js +57 -0
  48. package/src/core/network/protocols/consensus/v1/ConsensusV1MessageRouter.js +147 -0
  49. package/src/core/network/protocols/consensus/v1/ConsensusV1Protocol.js +72 -0
  50. package/src/core/network/protocols/consensus/v1/IndexerPendingRequestService.js +108 -0
  51. package/src/core/network/protocols/consensus/v1/V1ConsensusProtocolError.js +29 -0
  52. package/src/core/network/protocols/consensus/v1/handlers/V1EpochAppendOperationHandler.js +68 -0
  53. package/src/core/network/protocols/consensus/v1/handlers/V1EpochProofProposalOperationHandler.js +226 -0
  54. package/src/core/network/protocols/consensus/v1/validators/ConsensusValidationSchema.js +192 -0
  55. package/src/core/network/protocols/consensus/v1/validators/V1BaseConsensusOperation.js +428 -0
  56. package/src/core/network/protocols/consensus/v1/validators/V1EpochAppendReply.js +47 -0
  57. package/src/core/network/protocols/consensus/v1/validators/V1EpochAppendRequest.js +17 -0
  58. package/src/core/network/protocols/consensus/v1/validators/V1EpochProofProposalApproval.js +116 -0
  59. package/src/core/network/protocols/consensus/v1/validators/V1EpochProofProposalRequest.js +152 -0
  60. package/src/core/network/protocols/consensus/v1/validators/consensusValidationSchemaHelpers.js +145 -0
  61. package/src/core/network/protocols/shared/ConnectionOperationHandler.js +27 -0
  62. package/src/core/network/protocols/{NetworkMessages.js → validators/ValidatorMessages.js} +24 -14
  63. package/src/core/network/protocols/{ProtocolSession.js → validators/ValidatorProtocolSession.js} +22 -25
  64. package/src/core/network/protocols/{legacy/NetworkMessageRouter.js → validators/legacy/ValidatorLegacyMessageRouter.js} +6 -6
  65. package/src/core/network/protocols/{LegacyProtocol.js → validators/legacy/ValidatorLegacyProtocol.js} +9 -7
  66. package/src/core/network/protocols/{legacy → validators/legacy}/handlers/BaseStateOperationHandler.js +1 -1
  67. package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyGetRequestHandler.js +5 -5
  68. package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyRoleOperationHandler.js +5 -5
  69. package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacySubnetworkOperationHandler.js +5 -5
  70. package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyTransferOperationHandler.js +5 -5
  71. package/src/core/network/protocols/{ProtocolInterface.js → validators/shared/ValidatorProtocolInterface.js} +5 -5
  72. package/src/core/network/protocols/{shared → validators/shared}/validators/PartialBootstrapDeploymentValidator.js +1 -1
  73. package/src/core/network/protocols/validators/shared/validators/PartialHtlcValidator.js +325 -0
  74. package/src/core/network/protocols/{shared → validators/shared}/validators/PartialOperationValidator.js +44 -21
  75. package/src/core/network/protocols/{shared → validators/shared}/validators/PartialRoleAccessValidator.js +3 -3
  76. package/src/core/network/protocols/{shared → validators/shared}/validators/PartialTransactionValidator.js +3 -3
  77. package/src/core/network/protocols/{shared → validators/shared}/validators/PartialTransferValidator.js +4 -4
  78. package/src/core/network/protocols/{v1 → validators/v1}/V1ProtocolError.js +1 -1
  79. package/src/core/network/{services/PendingRequestService.js → protocols/validators/v1/ValidatorPendingRequestService.js} +19 -82
  80. package/src/core/network/protocols/{v1/NetworkMessageRouter.js → validators/v1/ValidatorV1MessageRouter.js} +9 -9
  81. package/src/core/network/protocols/{V1Protocol.js → validators/v1/ValidatorV1Protocol.js} +10 -8
  82. package/src/core/network/protocols/{connectionPolicies.js → validators/v1/connectionPolicies.js} +1 -1
  83. package/src/core/network/protocols/{v1 → validators/v1}/handlers/V1BaseOperationHandler.js +6 -23
  84. package/src/core/network/protocols/{v1 → validators/v1}/handlers/V1BroadcastTransactionOperationHandler.js +14 -9
  85. package/src/core/network/protocols/{v1 → validators/v1}/handlers/V1LivenessOperationHandler.js +5 -4
  86. package/src/core/network/protocols/{v1 → validators/v1}/handlers/broadcastTransaction/BroadcastTransactionErrorMapper.js +3 -3
  87. package/src/core/network/protocols/{v1 → validators/v1}/handlers/broadcastTransaction/BroadcastTransactionOperationStrategies.js +44 -1
  88. package/src/core/network/protocols/{v1 → validators/v1}/handlers/broadcastTransaction/BroadcastTransactionPayloadUtils.js +1 -1
  89. package/src/core/network/protocols/{v1 → validators/v1}/validators/V1BaseOperation.js +19 -15
  90. package/src/core/network/protocols/{v1 → validators/v1}/validators/V1BroadcastTransactionRequest.js +2 -2
  91. package/src/core/network/protocols/{v1 → validators/v1}/validators/V1BroadcastTransactionResponse.js +34 -18
  92. package/src/core/network/protocols/{v1 → validators/v1}/validators/V1ValidationSchema.js +3 -3
  93. package/src/core/network/services/IndexerConnectionManager.js +88 -0
  94. package/src/core/network/services/TransactionPoolService.js +11 -18
  95. package/src/core/network/services/TransactionRateLimiterService.js +1 -1
  96. package/src/core/network/services/ValidatorConnectionManager.js +163 -0
  97. package/src/core/network/services/{MessageOrchestrator.js → ValidatorMessageOrchestrator.js} +34 -42
  98. package/src/core/network/services/ValidatorObserverService.js +21 -36
  99. package/src/core/network/shared/BasePendingRequestService.js +67 -0
  100. package/src/core/network/shared/PeerConnectionManager.js +185 -0
  101. package/src/core/state/ConfirmationWatch.js +82 -0
  102. package/src/core/state/State.js +1794 -173
  103. package/src/core/state/StateEventQueue.js +69 -0
  104. package/src/core/state/utils/address.js +10 -6
  105. package/src/core/state/utils/epochProof.js +109 -0
  106. package/src/core/state/utils/escrowEntry.js +178 -0
  107. package/src/core/state/validators/StateValidationSchema.js +757 -0
  108. package/src/core/state/validators/stateValidationRules.js +312 -0
  109. package/src/index.js +255 -65
  110. package/src/messages/consensus/v1/ConsensusMessageBuilder.js +368 -0
  111. package/src/messages/consensus/v1/ConsensusMessageDirector.js +142 -0
  112. package/src/messages/consensus/v1/consensusMessageFactory.js +12 -0
  113. package/src/messages/consensus/v1/epochAppendMessage.js +58 -0
  114. package/src/messages/network/v1/NetworkMessageBuilder.js +15 -7
  115. package/src/messages/state/ApplyStateMessageBuilder.js +499 -13
  116. package/src/messages/state/ApplyStateMessageDirector.js +261 -2
  117. package/src/utils/StateMachine.js +125 -0
  118. package/src/utils/applyOperations.js +45 -2
  119. package/src/utils/buffer.js +239 -59
  120. package/src/utils/consensusConfig.js +76 -0
  121. package/src/utils/constants.js +174 -73
  122. package/src/utils/helpers.js +0 -25
  123. package/src/utils/htlcLock.js +122 -0
  124. package/src/utils/logger.js +10 -4
  125. package/src/utils/migrationUtils.js +2 -1
  126. package/src/utils/normalizers.js +113 -0
  127. package/src/utils/scheduler/SchedulableService.js +107 -0
  128. package/src/utils/{Scheduler.js → scheduler/Scheduler.js} +56 -17
  129. package/src/core/network/services/ConnectionManager.js +0 -406
  130. package/src/utils/check.js +0 -525
  131. package/src/utils/protobuf/applyOperations.cjs +0 -1373
  132. package/src/utils/protobuf/operationHelpers.js +0 -81
  133. /package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyResponseHandler.js +0 -0
  134. /package/src/core/network/protocols/{legacy → validators/legacy}/validators/ValidatorResponse.js +0 -0
  135. /package/src/core/network/protocols/{legacy → validators/legacy}/validators/base/BaseResponse.js +0 -0
  136. /package/src/core/network/protocols/{v1 → validators/v1}/validators/V1LivenessRequest.js +0 -0
  137. /package/src/core/network/protocols/{v1 → validators/v1}/validators/V1LivenessResponse.js +0 -0
@@ -1,6 +1,7 @@
1
1
  import b4a from 'b4a'
2
2
  import { isDefined } from '../utils/type.js'
3
3
  import _ from 'lodash'
4
+ import { BOOTSTRAP_BYTE_LENGTH, CHANNEL_BYTE_LENGTH } from '../utils/constants.js'
4
5
 
5
6
  export class Config {
6
7
  #options
@@ -59,6 +60,11 @@ export class Config {
59
60
  return !!this.#config.enableErrorApplyLogs
60
61
  }
61
62
 
63
+ get enableLogTimestamp() {
64
+ if (this.#isOverriden('enableLogTimestamp')) return !!this.#options.enableLogTimestamp
65
+ return !!this.#config.enableLogTimestamp
66
+ }
67
+
62
68
  get enableInteractiveMode() {
63
69
  if (this.#isOverriden('enableInteractiveMode')) return this.#options.enableInteractiveMode !== false
64
70
  return !!this.#config.enableInteractiveMode
@@ -69,11 +75,6 @@ export class Config {
69
75
  return !!this.#config.enableRoleRequester
70
76
  }
71
77
 
72
- get enableValidatorObserver() {
73
- if (this.#isOverriden('enableValidatorObserver')) return !!this.#options.enableValidatorObserver
74
- return !!this.#config.enableValidatorObserver
75
- }
76
-
77
78
  get enableTxApplyLogs() {
78
79
  if (this.#isOverriden('enableTxApplyLogs')) return !!this.#options.enableTxApplyLogs
79
80
  return !!this.#config.enableTxApplyLogs
@@ -201,6 +202,10 @@ export class Config {
201
202
  return this.#config.pendingRequestTimeout
202
203
  }
203
204
 
205
+ get indexerPendingRequestTimeout() {
206
+ return this.#config.indexerPendingRequestTimeout
207
+ }
208
+
204
209
  get txCommitTimeout() {
205
210
  return this.#config.txCommitTimeout
206
211
  }
@@ -214,15 +219,44 @@ export class Config {
214
219
  return this.#config.validatorHealthCheckInterval
215
220
  }
216
221
 
222
+ get epochInterval() {
223
+ return this.#config.epochInterval
224
+ }
225
+
226
+ get epochBackoffDelay() {
227
+ return this.#config.epochBackoffDelay
228
+ }
229
+
230
+ get epochSignatureTimeout() {
231
+ return this.#config.epochSignatureTimeout
232
+ }
233
+
234
+ get epochRemoteProposalTimeout() {
235
+ return this.#config.epochRemoteProposalTimeout
236
+ }
237
+
238
+ get epochAppendTimeout() {
239
+ return this.#config.epochAppendTimeout
240
+ }
241
+
217
242
  get validatorHealthCheckFailureThreshold() {
218
243
  if (this.#isOverriden('validatorHealthCheckFailureThreshold')) return this.#options.validatorHealthCheckFailureThreshold
219
244
  return this.#config.validatorHealthCheckFailureThreshold
220
245
  }
221
246
 
247
+ get confirmationStallTimeout() {
248
+ if (this.#isOverriden('confirmationStallTimeout')) return this.#options.confirmationStallTimeout
249
+ return this.#config.confirmationStallTimeout
250
+ }
251
+
222
252
  get maxPendingRequestsInPendingRequestsService() {
223
253
  return this.#config.maxPendingRequestsInPendingRequestsService
224
254
  }
225
255
 
256
+ get maxPendingConnections() {
257
+ return this.#config.maxPendingConnections
258
+ }
259
+
226
260
  get debug() {
227
261
  return this.#config.debug
228
262
  }
@@ -246,6 +280,10 @@ export class Config {
246
280
  return this.#config.bootstrapTimeout
247
281
  }
248
282
 
283
+ get connectTimeoutMs() {
284
+ return this.#config.connectTimeoutMs
285
+ }
286
+
249
287
  get writersShortCacheTTL() {
250
288
  if (this.#isOverriden('writersShortCacheTTL')) return this.#options.writersShortCacheTTL
251
289
  return this.#config.writersShortCacheTTL
@@ -274,7 +312,7 @@ export class Config {
274
312
  }
275
313
 
276
314
  #normalizeChannel(channel) {
277
- return b4a.alloc(32).fill(channel)
315
+ return b4a.alloc(CHANNEL_BYTE_LENGTH).fill(channel)
278
316
  }
279
317
 
280
318
  #validateStringOverride(field, value) {
@@ -291,7 +329,7 @@ export class Config {
291
329
 
292
330
  #validateBootstrapOverride(bootstrap) {
293
331
  if (b4a.isBuffer(bootstrap)) {
294
- if (bootstrap.length !== 32) {
332
+ if (bootstrap.length !== BOOTSTRAP_BYTE_LENGTH) {
295
333
  throw new Error('MainSettlementBus Config: bootstrap must be a 32-byte hex string or Buffer.');
296
334
  }
297
335
  return;
@@ -365,4 +403,5 @@ export class Config {
365
403
  this.#validateDhtBootstrapOverride(options.dhtBootstrap);
366
404
  }
367
405
  }
406
+
368
407
  }
package/src/config/env.js CHANGED
@@ -17,20 +17,22 @@ const configData = {
17
17
  addressPrefixLength: TRAC_NETWORK_MSB_TESTNET1_PREFIX.length,
18
18
  bech32mHrpLength: TRAC_NETWORK_MSB_TESTNET1_PREFIX.length + 1, // len(addressPrefix + separator)
19
19
  bootstrap: 'c184f4ad8e9cf5e911f9415b60e7dcfb30aed73ebd8a402ef68e1b154624f5ef',
20
- channel: '1111trac1network1msb1testnet1111',
20
+ channel: '2222trac2network2msb2testnet2222',
21
21
  dhtBootstrap: ['116.202.214.149:10001','157.180.12.214:10001','node1.hyperdht.org:49737','node2.hyperdht.org:49737','node3.hyperdht.org:49737'], // these are used to peer discovery
22
22
  derivationPath: address.TESNET_DERIVATION_PATH,
23
- enableValidatorObserver: true,
24
23
  pollInterval: 500, // Validator observer poll interval
25
24
  adminCacheTTL: 10_000, // Admin cache TTL ms
26
25
  validatorConnectionAttemptDelay: 5, // Delay between validator connection attempts (ms)
26
+ connectTimeoutMs: 5_000,
27
27
  bootstrapTimeout: 60_000, // time used (ms) to connect to new validators at bootstrap
28
28
  writersShortCacheTTL: 10_000, // short TTL during bootstrap
29
29
  writersLongCacheTTL: 120_000, // long TTL after bootstrap
30
30
  maxValidators: 50,
31
+ maxPendingConnections: 50,
31
32
  maxWritersForAdminIndexerConnection: 10, // Connectivity constants
32
33
  disableRateLimit: false,
33
34
  enableErrorApplyLogs: true,
35
+ enableLogTimestamp: false,
34
36
  enableInteractiveMode: true,
35
37
  enableRoleRequester: false,
36
38
  enableTxApplyLogs: true,
@@ -53,10 +55,17 @@ const configData = {
53
55
  rateLimitMaxTransactionsPerSecond: 50, // Rate limiting constants
54
56
  maxPendingRequestsInPendingRequestsService: 50_000, // Maximum number of pending requests in PendingRequestService (This value should not exceed 256MB)
55
57
  pendingRequestTimeout: 10_000, // Deadline for a pending V1 response (ms), including health checks
58
+ indexerPendingRequestTimeout: 20000, // constant after which time the transaction will be considered invalid
56
59
  txCommitTimeout: 5_000, // Wait for local append and publication proof (ms); shorter than the response deadline
57
60
  txPoolSize: 1000, // size of transaction pool
58
61
  validatorHealthCheckInterval: 5 * 60 * 1000, // How often to check validator health (ms)
59
62
  validatorHealthCheckFailureThreshold: 3, // Consecutive failed health checks before a validator is removed
63
+ confirmationStallTimeout: 120_000, // Force a fast-forward when confirmations stall with unconfirmed entries (ms, 0 = off)
64
+ epochInterval: 3 * 60 * 1000, // How often to trigger epoch proof proposal (ms)
65
+ epochBackoffDelay: 30_000, // Delay before retrying epoch coordination after a failed attempt (ms)
66
+ epochSignatureTimeout: 20_000, // Max time delay an indexer have to sign a proposal
67
+ epochAppendTimeout: 2_000, // Max time a proposer has to append the new epoch in the log
68
+ epochRemoteProposalTimeout: 20_000, // Max time to wait for a competing proposal to land before broadcasting our own
60
69
  storesDirectory: 'stores/',
61
70
  storeName: 'testnet',
62
71
  },
@@ -70,17 +79,19 @@ const configData = {
70
79
  channel: '0000trac0network0msb0mainnet0000',
71
80
  dhtBootstrap: ['116.202.214.149:10001','157.180.12.214:10001','node1.hyperdht.org:49737','node2.hyperdht.org:49737','node3.hyperdht.org:49737'],
72
81
  derivationPath: address.MAINNET_DERIVATION_PATH,
73
- enableValidatorObserver: true,
74
82
  pollInterval: 500, // Validator observer poll interval
75
83
  adminCacheTTL: 3_600_000, // Admin cache TTL ms
76
84
  validatorConnectionAttemptDelay: 5, // Delay between validator connection attempts (ms)
85
+ connectTimeoutMs: 5_000,
77
86
  bootstrapTimeout: 120_000, // time used (ms) to connect to new validators at bootstrap
78
87
  writersShortCacheTTL: 2_000, // short TTL during bootstrap
79
88
  writersLongCacheTTL: 120_000, // long TTL after bootstrap
80
89
  maxValidators: 50,
90
+ maxPendingConnections: 50,
81
91
  maxWritersForAdminIndexerConnection: 10, // Connectivity constants
82
92
  disableRateLimit: false,
83
93
  enableErrorApplyLogs: false,
94
+ enableLogTimestamp: false,
84
95
  enableInteractiveMode: true,
85
96
  enableRoleRequester: false,
86
97
  enableTxApplyLogs: false,
@@ -103,10 +114,17 @@ const configData = {
103
114
  rateLimitMaxTransactionsPerSecond: 50, // Rate limiting constants
104
115
  maxPendingRequestsInPendingRequestsService: 50_000, // Maximum number of pending requests in PendingRequestService (This value should not exceed 256MB)
105
116
  pendingRequestTimeout: 10_000, // Deadline for a pending V1 response (ms), including health checks
117
+ indexerPendingRequestTimeout: 20000, // constant after which time the transaction will be considered invalid
106
118
  txCommitTimeout: 5_000, // Wait for local append and publication proof (ms); shorter than the response deadline
107
119
  txPoolSize: 1000, // size of transaction pool
108
120
  validatorHealthCheckInterval: 5 * 60 * 1000, // How often to check validator health (ms)
109
121
  validatorHealthCheckFailureThreshold: 3, // Consecutive failed health checks before a validator is removed
122
+ confirmationStallTimeout: 120_000, // Force a fast-forward when confirmations stall with unconfirmed entries (ms, 0 = off)
123
+ epochInterval: 3 * 60 * 1000, // How often to trigger epoch proof proposal (ms)
124
+ epochBackoffDelay: 30_000, // Delay before retrying epoch coordination after a failed attempt (ms)
125
+ epochSignatureTimeout: 20_000, // Max time delay an indexer have to sign a proposal
126
+ epochAppendTimeout: 2_000, // Max time a proposer has to append the new epoch in the log
127
+ epochRemoteProposalTimeout: 20_000, // Max time to wait for a competing proposal to land before broadcasting our own
110
128
  storesDirectory: 'stores/',
111
129
  storeName: 'mainnet',
112
130
  },
@@ -116,21 +134,23 @@ const configData = {
116
134
  addressPrefix: TRAC_NETWORK_MSB_MAINNET_PREFIX,
117
135
  addressPrefixLength: TRAC_NETWORK_MSB_MAINNET_PREFIX.length,
118
136
  bech32mHrpLength: TRAC_NETWORK_MSB_MAINNET_PREFIX.length + 1, // len(addressPrefix + separator)
119
- bootstrap: '12f7f1668eac2e691e17cbc6a53e509c5cee78cdcac562313091c64e5fd077d6',
120
- channel: '12312313123123',
137
+ bootstrap: 'e81a23d67224e794a7df923843591880c24a4fd4de1795a80108035a7fcdfcbd',
138
+ channel: '123123131231233',
121
139
  dhtBootstrap: ['116.202.214.149:10001','157.180.12.214:10001','node1.hyperdht.org:49737','node2.hyperdht.org:49737','node3.hyperdht.org:49737'],
122
140
  derivationPath: address.MAINNET_DERIVATION_PATH,
123
- enableValidatorObserver: true,
124
141
  pollInterval: 500, // Validator observer poll interval
125
142
  adminCacheTTL: 60_000, // Admin cache TTL ms
126
143
  validatorConnectionAttemptDelay: 5, // Delay between validator connection attempts (ms)
144
+ connectTimeoutMs: 5_000,
127
145
  bootstrapTimeout: 30_000, // time used (ms) to connect to new validators at bootstrap
128
146
  writersShortCacheTTL: 1_000, // short TTL during bootstrap
129
147
  writersLongCacheTTL: 2_000, // long TTL after bootstrap
130
148
  maxValidators: 10,
149
+ maxPendingConnections: 50,
131
150
  maxWritersForAdminIndexerConnection: 10, // Connectivity constants
132
151
  disableRateLimit: false,
133
152
  enableErrorApplyLogs: true,
153
+ enableLogTimestamp: true,
134
154
  enableInteractiveMode: true,
135
155
  enableRoleRequester: false,
136
156
  enableTxApplyLogs: true,
@@ -153,10 +173,17 @@ const configData = {
153
173
  rateLimitMaxTransactionsPerSecond: 50, // Rate limiting constants
154
174
  maxPendingRequestsInPendingRequestsService: 50_000, // Maximum number of pending requests in PendingRequestService (This value should not exceed 256MB)
155
175
  pendingRequestTimeout: 10_000, // Deadline for a pending V1 response (ms), including health checks
176
+ indexerPendingRequestTimeout: 20000, // constant after which time the transaction will be considered invalid
156
177
  txCommitTimeout: 5_000, // Wait for local append and publication proof (ms); shorter than the response deadline
157
178
  txPoolSize: 1000, // size of transaction pool
158
179
  validatorHealthCheckInterval: 1_000, // How often to check validator health (ms)
159
180
  validatorHealthCheckFailureThreshold: 3, // Consecutive failed health checks before a validator is removed
181
+ confirmationStallTimeout: 120_000, // Force a fast-forward when confirmations stall with unconfirmed entries (ms, 0 = off)
182
+ epochInterval: 30 * 1000, // How often to trigger epoch proof proposal (ms)
183
+ epochBackoffDelay: 30_000, // Delay before retrying epoch coordination after a failed attempt (ms)
184
+ epochSignatureTimeout: 40_000, // Max time delay an indexer have to sign a proposal
185
+ epochAppendTimeout: 10_000, // Max time a proposer has to append the new epoch in the log
186
+ epochRemoteProposalTimeout: 40_000, // Max time to wait for a competing proposal to land before broadcasting our own
160
187
  storesDirectory: 'stores/',
161
188
  storeName: 'development',
162
189
  }
@@ -0,0 +1,55 @@
1
+ /** Error codes used when handling election failures and building protocol replies. */
2
+ export const EpochAppenderSelectionErrorCode = Object.freeze({
3
+ SELECTION_STATE_INVALID: 'SELECTION_STATE_INVALID',
4
+ RESERVATION_INVALID: 'RESERVATION_INVALID',
5
+ PUBLICATION_MARKER_INVALID: 'PUBLICATION_MARKER_INVALID',
6
+ PERSISTENCE_FAILED: 'PERSISTENCE_FAILED',
7
+ SELECTOR_CLOSED: 'SELECTOR_CLOSED',
8
+ SELECTOR_UNAVAILABLE: 'SELECTOR_UNAVAILABLE',
9
+ REQUEST_STALE: 'REQUEST_STALE',
10
+ REQUEST_CANCELLED: 'REQUEST_CANCELLED',
11
+ ELECTION_SUPERSEDED: 'ELECTION_SUPERSEDED',
12
+ ELECTION_BUSY: 'ELECTION_BUSY',
13
+ ALREADY_WAITING: 'ALREADY_WAITING',
14
+ PUBLICATION_UNRESOLVED: 'PUBLICATION_UNRESOLVED',
15
+ REPLIES_INCOMPLETE: 'REPLIES_INCOMPLETE',
16
+ REPLY_TIMEOUT: 'REPLY_TIMEOUT',
17
+ CONTEXT_CHANGED: 'CONTEXT_CHANGED',
18
+ NOT_IN_COHORT: 'NOT_IN_COHORT',
19
+ UNEXPECTED_PEER: 'UNEXPECTED_PEER',
20
+ LOGICAL_COUNTER_INVALID: 'LOGICAL_COUNTER_INVALID',
21
+ LOGICAL_CLOCK_EXHAUSTED: 'LOGICAL_CLOCK_EXHAUSTED',
22
+ SIGNED_CHECKPOINT_UNAVAILABLE: 'SIGNED_CHECKPOINT_UNAVAILABLE',
23
+ SIGNED_VIEW_INVALID: 'SIGNED_VIEW_INVALID',
24
+ EPOCH_NOT_INITIALIZED: 'EPOCH_NOT_INITIALIZED',
25
+ PARENT_MISSING: 'PARENT_MISSING',
26
+ MEMBER_IDENTITY_MISSING: 'MEMBER_IDENTITY_MISSING',
27
+ MEMBERSHIP_INVALID: 'MEMBERSHIP_INVALID',
28
+ CONFIG_MISSING: 'CONFIG_MISSING',
29
+ });
30
+
31
+ /**
32
+ * Describes an appender selection error. Callers use the code to decide what to do next. The message
33
+ * and details help explain the failure in logs. Protocol handlers convert these errors to protocol
34
+ * result codes.
35
+ */
36
+ export class EpochAppenderSelectionError extends Error {
37
+ /**
38
+ * @param {string} code One of EpochAppenderSelectionErrorCode.
39
+ * @param {string} message Message shown in logs. Callers use the code to handle the error.
40
+ * @param {object} [options] Extra details and the original error.
41
+ * @param {object} [options.details] Request ID and other details about the failure.
42
+ * @param {Error} [options.cause] Original error that caused this failure.
43
+ */
44
+ constructor(code, message, { details, cause } = {}) {
45
+ super(message);
46
+ this.name = this.constructor.name;
47
+ this.code = code;
48
+ if (details !== undefined) {
49
+ this.details = details;
50
+ }
51
+ if (cause !== undefined) {
52
+ this.cause = cause;
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,118 @@
1
+ import { generateUUID } from '../../../utils/helpers.js';
2
+ import { consensusMessageFactory } from '../../../messages/consensus/v1/consensusMessageFactory.js';
3
+ import { EpochAppenderSelectionError, EpochAppenderSelectionErrorCode } from './EpochAppenderSelectionError.js';
4
+ import { loadSelectionState, saveSelectionState } from './epochAppenderSelectionStorage.js';
5
+
6
+ /**
7
+ * Provides local storage, signed ledger reads and network requests for the selector. The selector uses
8
+ * these methods to collect votes. The round handles the epoch append.
9
+ */
10
+ export class EpochAppenderSelectionOperations {
11
+ #state;
12
+ #wallet;
13
+ #config;
14
+ #getIndexerConnectionManager;
15
+ #logger;
16
+ #pendingRequestService;
17
+
18
+ /**
19
+ * Sets up the services used by the selector. The connection manager is read through a callback
20
+ * because Network creates it after the selector.
21
+ *
22
+ * @param {import('../../state/State.js').default} state Access to signed ledger data and local storage.
23
+ * @param {object} wallet Wallet used to sign REQUEST messages.
24
+ * @param {object} config Network and message encoding config.
25
+ * @param {function(): import('../../network/services/IndexerConnectionManager.js').default} getIndexerConnectionManager Returns the connection manager once it is ready.
26
+ * @param {object} [logger] Logger for operation errors.
27
+ * @param {object} [pendingRequestService] Tracks pending requests and cancels them when needed.
28
+ */
29
+ constructor(state, wallet, config, getIndexerConnectionManager, logger, pendingRequestService) {
30
+ this.#state = state;
31
+ this.#wallet = wallet;
32
+ this.#config = config;
33
+ this.#getIndexerConnectionManager = getIndexerConnectionManager;
34
+ this.#logger = logger;
35
+ this.#pendingRequestService = pendingRequestService;
36
+ }
37
+
38
+ /**
39
+ * Loads the election state saved on this node.
40
+ *
41
+ * @returns {Promise<import('./epochAppenderSelectionState.js').EpochAppenderSelectionState|null>}
42
+ */
43
+ load() {
44
+ return loadSelectionState(this.#state.base);
45
+ }
46
+
47
+ /**
48
+ * Saves a copy of the election state on this node.
49
+ *
50
+ * @param {import('./epochAppenderSelectionState.js').EpochAppenderSelectionState} selectionState Election state to save locally.
51
+ * @returns {Promise<void>}
52
+ */
53
+ save(selectionState) {
54
+ return saveSelectionState(this.#state.base, selectionState);
55
+ }
56
+
57
+ /**
58
+ * Reads the epoch, consensus config and indexers from the same signed checkpoint.
59
+ *
60
+ * @returns {Promise<import('./epochAppenderSelectionState.js').EpochAppenderSelectionContext>}
61
+ */
62
+ readContext() {
63
+ return this.#state.getEpochAppenderSelectionContext();
64
+ }
65
+
66
+ /**
67
+ * Checks whether the signed ledger has processed this append.
68
+ *
69
+ * @param {import('./epochAppenderSelectionState.js').EpochAppendPublication} publication Saved writer position and payload hash for this append.
70
+ * @returns {Promise<import('./epochAppenderSelectionState.js').EpochAppendOutcomeResult>}
71
+ */
72
+ readOutcome(publication) {
73
+ return this.#state.getEpochAppendOutcome(publication);
74
+ }
75
+
76
+ /**
77
+ * Connects to the current indexers through the existing session manager.
78
+ *
79
+ * @returns {Promise<void>}
80
+ */
81
+ connect() {
82
+ return this.#getIndexerConnectionManager().connect();
83
+ }
84
+
85
+ /**
86
+ * Signs and sends a REQUEST for an appender vote. Registers a callback so the election can cancel
87
+ * the pending request. If cancellation happens during signing, nothing is sent.
88
+ *
89
+ * @param {string} peerPublicKey Target wallet key, encoded as hex.
90
+ * @param {import('./epochAppenderSelectionState.js').EpochAppendRequest} selectionRequest Request containing the candidate, election term and payload hash.
91
+ * @param {import('./epochAppenderSelectionState.js').EpochSelectionRequestLifecycle} requestLifecycle Callbacks that check whether the request is active and register cancellation.
92
+ * @returns {Promise<import('./epochAppenderSelectionState.js').EpochAppendReply|null>} Validated reply, or null after cancellation.
93
+ */
94
+ async sendRequest(peerPublicKey, selectionRequest, requestLifecycle) {
95
+ const requestMessage = await consensusMessageFactory(this.#wallet, this.#config).buildRequest(generateUUID(), selectionRequest);
96
+ if (!requestLifecycle.isActive()) {
97
+ return null;
98
+ }
99
+ requestLifecycle.onPending(() => {
100
+ const error = new EpochAppenderSelectionError(
101
+ EpochAppenderSelectionErrorCode.REQUEST_CANCELLED,
102
+ 'Epoch append request no longer waiting',
103
+ { details: { requestId: selectionRequest.requestId, sessionId: requestMessage.session_id } }
104
+ );
105
+ this.#pendingRequestService?.rejectPendingRequest(requestMessage.session_id, error);
106
+ });
107
+ return this.#getIndexerConnectionManager().send(peerPublicKey, requestMessage);
108
+ }
109
+
110
+ /**
111
+ * Logs an error from a background operation. This does not change the election state.
112
+ *
113
+ * @param {Error} error Error from storage, signed context reads or a peer request.
114
+ */
115
+ onError(error) {
116
+ this.#logger?.debug?.(`[EpochAppenderSelector] ${error.message}`);
117
+ }
118
+ }