trac-msb 0.2.26 → 0.3.0-beta.2

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 (136) 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 +121 -0
  10. package/rpc/routes/v1.js +12 -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 +41 -7
  23. package/src/config/env.js +33 -9
  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/State.js +1803 -159
  102. package/src/core/state/StateEventQueue.js +69 -0
  103. package/src/core/state/utils/address.js +10 -6
  104. package/src/core/state/utils/epochProof.js +109 -0
  105. package/src/core/state/utils/escrowEntry.js +178 -0
  106. package/src/core/state/validators/StateValidationSchema.js +757 -0
  107. package/src/core/state/validators/stateValidationRules.js +312 -0
  108. package/src/index.js +280 -67
  109. package/src/messages/consensus/v1/ConsensusMessageBuilder.js +368 -0
  110. package/src/messages/consensus/v1/ConsensusMessageDirector.js +142 -0
  111. package/src/messages/consensus/v1/consensusMessageFactory.js +12 -0
  112. package/src/messages/consensus/v1/epochAppendMessage.js +58 -0
  113. package/src/messages/network/v1/NetworkMessageBuilder.js +15 -7
  114. package/src/messages/state/ApplyStateMessageBuilder.js +499 -13
  115. package/src/messages/state/ApplyStateMessageDirector.js +261 -2
  116. package/src/utils/StateMachine.js +125 -0
  117. package/src/utils/applyOperations.js +45 -2
  118. package/src/utils/buffer.js +239 -59
  119. package/src/utils/consensusConfig.js +76 -0
  120. package/src/utils/constants.js +174 -73
  121. package/src/utils/helpers.js +0 -25
  122. package/src/utils/htlcLock.js +122 -0
  123. package/src/utils/logger.js +10 -4
  124. package/src/utils/migrationUtils.js +2 -1
  125. package/src/utils/normalizers.js +113 -0
  126. package/src/utils/scheduler/SchedulableService.js +107 -0
  127. package/src/utils/{Scheduler.js → scheduler/Scheduler.js} +56 -17
  128. package/src/core/network/services/ConnectionManager.js +0 -406
  129. package/src/utils/check.js +0 -525
  130. package/src/utils/protobuf/applyOperations.cjs +0 -1373
  131. package/src/utils/protobuf/operationHelpers.js +0 -81
  132. /package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyResponseHandler.js +0 -0
  133. /package/src/core/network/protocols/{legacy → validators/legacy}/validators/ValidatorResponse.js +0 -0
  134. /package/src/core/network/protocols/{legacy → validators/legacy}/validators/base/BaseResponse.js +0 -0
  135. /package/src/core/network/protocols/{v1 → validators/v1}/validators/V1LivenessRequest.js +0 -0
  136. /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,6 +219,26 @@ 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
@@ -228,6 +253,10 @@ export class Config {
228
253
  return this.#config.maxPendingRequestsInPendingRequestsService
229
254
  }
230
255
 
256
+ get maxPendingConnections() {
257
+ return this.#config.maxPendingConnections
258
+ }
259
+
231
260
  get debug() {
232
261
  return this.#config.debug
233
262
  }
@@ -251,6 +280,10 @@ export class Config {
251
280
  return this.#config.bootstrapTimeout
252
281
  }
253
282
 
283
+ get connectTimeoutMs() {
284
+ return this.#config.connectTimeoutMs
285
+ }
286
+
254
287
  get writersShortCacheTTL() {
255
288
  if (this.#isOverriden('writersShortCacheTTL')) return this.#options.writersShortCacheTTL
256
289
  return this.#config.writersShortCacheTTL
@@ -279,7 +312,7 @@ export class Config {
279
312
  }
280
313
 
281
314
  #normalizeChannel(channel) {
282
- return b4a.alloc(32).fill(channel)
315
+ return b4a.alloc(CHANNEL_BYTE_LENGTH).fill(channel)
283
316
  }
284
317
 
285
318
  #validateStringOverride(field, value) {
@@ -296,7 +329,7 @@ export class Config {
296
329
 
297
330
  #validateBootstrapOverride(bootstrap) {
298
331
  if (b4a.isBuffer(bootstrap)) {
299
- if (bootstrap.length !== 32) {
332
+ if (bootstrap.length !== BOOTSTRAP_BYTE_LENGTH) {
300
333
  throw new Error('MainSettlementBus Config: bootstrap must be a 32-byte hex string or Buffer.');
301
334
  }
302
335
  return;
@@ -370,4 +403,5 @@ export class Config {
370
403
  this.#validateDhtBootstrapOverride(options.dhtBootstrap);
371
404
  }
372
405
  }
406
+
373
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,11 +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
60
- confirmationStallTimeout: 120_000, // Force a fast-forward when the confirmed length has not moved for this long while unconfirmed entries wait (ms, 0 = off)
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
61
69
  storesDirectory: 'stores/',
62
70
  storeName: 'testnet',
63
71
  },
@@ -71,17 +79,19 @@ const configData = {
71
79
  channel: '0000trac0network0msb0mainnet0000',
72
80
  dhtBootstrap: ['116.202.214.149:10001','157.180.12.214:10001','node1.hyperdht.org:49737','node2.hyperdht.org:49737','node3.hyperdht.org:49737'],
73
81
  derivationPath: address.MAINNET_DERIVATION_PATH,
74
- enableValidatorObserver: true,
75
82
  pollInterval: 500, // Validator observer poll interval
76
83
  adminCacheTTL: 3_600_000, // Admin cache TTL ms
77
84
  validatorConnectionAttemptDelay: 5, // Delay between validator connection attempts (ms)
85
+ connectTimeoutMs: 5_000,
78
86
  bootstrapTimeout: 120_000, // time used (ms) to connect to new validators at bootstrap
79
87
  writersShortCacheTTL: 2_000, // short TTL during bootstrap
80
88
  writersLongCacheTTL: 120_000, // long TTL after bootstrap
81
89
  maxValidators: 50,
90
+ maxPendingConnections: 50,
82
91
  maxWritersForAdminIndexerConnection: 10, // Connectivity constants
83
92
  disableRateLimit: false,
84
93
  enableErrorApplyLogs: false,
94
+ enableLogTimestamp: false,
85
95
  enableInteractiveMode: true,
86
96
  enableRoleRequester: false,
87
97
  enableTxApplyLogs: false,
@@ -104,11 +114,17 @@ const configData = {
104
114
  rateLimitMaxTransactionsPerSecond: 50, // Rate limiting constants
105
115
  maxPendingRequestsInPendingRequestsService: 50_000, // Maximum number of pending requests in PendingRequestService (This value should not exceed 256MB)
106
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
107
118
  txCommitTimeout: 5_000, // Wait for local append and publication proof (ms); shorter than the response deadline
108
119
  txPoolSize: 1000, // size of transaction pool
109
120
  validatorHealthCheckInterval: 5 * 60 * 1000, // How often to check validator health (ms)
110
121
  validatorHealthCheckFailureThreshold: 3, // Consecutive failed health checks before a validator is removed
111
- confirmationStallTimeout: 120_000, // Force a fast-forward when the confirmed length has not moved for this long while unconfirmed entries wait (ms, 0 = off)
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
112
128
  storesDirectory: 'stores/',
113
129
  storeName: 'mainnet',
114
130
  },
@@ -118,21 +134,23 @@ const configData = {
118
134
  addressPrefix: TRAC_NETWORK_MSB_MAINNET_PREFIX,
119
135
  addressPrefixLength: TRAC_NETWORK_MSB_MAINNET_PREFIX.length,
120
136
  bech32mHrpLength: TRAC_NETWORK_MSB_MAINNET_PREFIX.length + 1, // len(addressPrefix + separator)
121
- bootstrap: '12f7f1668eac2e691e17cbc6a53e509c5cee78cdcac562313091c64e5fd077d6',
122
- channel: '12312313123123',
137
+ bootstrap: 'e81a23d67224e794a7df923843591880c24a4fd4de1795a80108035a7fcdfcbd',
138
+ channel: '123123131231233',
123
139
  dhtBootstrap: ['116.202.214.149:10001','157.180.12.214:10001','node1.hyperdht.org:49737','node2.hyperdht.org:49737','node3.hyperdht.org:49737'],
124
140
  derivationPath: address.MAINNET_DERIVATION_PATH,
125
- enableValidatorObserver: true,
126
141
  pollInterval: 500, // Validator observer poll interval
127
142
  adminCacheTTL: 60_000, // Admin cache TTL ms
128
143
  validatorConnectionAttemptDelay: 5, // Delay between validator connection attempts (ms)
144
+ connectTimeoutMs: 5_000,
129
145
  bootstrapTimeout: 30_000, // time used (ms) to connect to new validators at bootstrap
130
146
  writersShortCacheTTL: 1_000, // short TTL during bootstrap
131
147
  writersLongCacheTTL: 2_000, // long TTL after bootstrap
132
148
  maxValidators: 10,
149
+ maxPendingConnections: 50,
133
150
  maxWritersForAdminIndexerConnection: 10, // Connectivity constants
134
151
  disableRateLimit: false,
135
152
  enableErrorApplyLogs: true,
153
+ enableLogTimestamp: true,
136
154
  enableInteractiveMode: true,
137
155
  enableRoleRequester: false,
138
156
  enableTxApplyLogs: true,
@@ -155,11 +173,17 @@ const configData = {
155
173
  rateLimitMaxTransactionsPerSecond: 50, // Rate limiting constants
156
174
  maxPendingRequestsInPendingRequestsService: 50_000, // Maximum number of pending requests in PendingRequestService (This value should not exceed 256MB)
157
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
158
177
  txCommitTimeout: 5_000, // Wait for local append and publication proof (ms); shorter than the response deadline
159
178
  txPoolSize: 1000, // size of transaction pool
160
179
  validatorHealthCheckInterval: 1_000, // How often to check validator health (ms)
161
180
  validatorHealthCheckFailureThreshold: 3, // Consecutive failed health checks before a validator is removed
162
- confirmationStallTimeout: 120_000, // Force a fast-forward when the confirmed length has not moved for this long while unconfirmed entries wait (ms, 0 = off)
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
163
187
  storesDirectory: 'stores/',
164
188
  storeName: 'development',
165
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
+ }