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.
- package/SECURITY.md +2 -2
- package/cli/commandHandler.js +317 -20
- package/cli/handlers.js +9 -1
- package/cli/interactive.js +4 -3
- package/cli/tokenSupplyAudit.js +90 -0
- package/msb.mjs +1 -0
- package/package.json +15 -6
- package/rpc/create_server.js +12 -3
- package/rpc/handlers.js +103 -0
- package/rpc/routes/v1.js +8 -0
- package/src/codecs/apply/applyOperationCodec.js +334 -0
- package/src/codecs/apply/applyOperations.generated.cjs +6380 -0
- package/src/codecs/consensus/v1/consensusV1.generated.cjs +3508 -0
- package/src/codecs/consensus/v1/consensusV1OperationCodec.js +161 -0
- package/src/codecs/consensus/v1/vdfConfigCodec.js +83 -0
- package/src/{utils/protobuf → codecs/network/v1}/networkV1.generated.cjs +664 -393
- package/src/codecs/network/v1/networkV1OperationCodec.js +25 -0
- package/src/codecs/protobufRuntime.cjs +95 -0
- package/src/codecs/state/escrowEntryCodec.js +45 -0
- package/src/codecs/state/state.generated.cjs +659 -0
- package/src/config/args.js +0 -1
- package/src/config/config.js +46 -7
- package/src/config/env.js +33 -6
- package/src/core/consensus/epochAppenderSelection/EpochAppenderSelectionError.js +55 -0
- package/src/core/consensus/epochAppenderSelection/EpochAppenderSelectionOperations.js +118 -0
- package/src/core/consensus/epochAppenderSelection/EpochAppenderSelector.js +1042 -0
- package/src/core/consensus/epochAppenderSelection/createEpochAppenderSelector.js +23 -0
- package/src/core/consensus/epochAppenderSelection/epochAppenderSelectionLedgerReader.js +274 -0
- package/src/core/consensus/epochAppenderSelection/epochAppenderSelectionState.js +488 -0
- package/src/core/consensus/epochAppenderSelection/epochAppenderSelectionStorage.js +93 -0
- package/src/core/consensus/quorum.js +11 -0
- package/src/core/consensus/services/EpochCoordinationRound.js +839 -0
- package/src/core/consensus/services/EpochCoordinatorOperations.js +211 -0
- package/src/core/consensus/services/EpochCoordinatorService.js +335 -0
- package/src/core/consensus/services/EpochRoundListeners.js +116 -0
- package/src/core/consensus/services/EpochStateMachine.js +141 -0
- package/src/core/consensus/services/VDFBare.js +291 -0
- package/src/core/consensus/services/VDFNode.js +111 -0
- package/src/core/consensus/services/VDFProgressWatchdog.js +79 -0
- package/src/core/consensus/services/VDFService.js +87 -0
- package/src/core/consensus/services/VDFServiceManager.js +147 -0
- package/src/core/consensus/services/createVDFService.js +16 -0
- package/src/core/consensus/services/vdf-guardian.js +32 -0
- package/src/core/consensus/services/vdf-worker.js +90 -0
- package/src/core/network/Network.js +327 -238
- package/src/core/network/protocols/consensus/IndexerMessages.js +72 -0
- package/src/core/network/protocols/consensus/v1/ConsensusV1ConnectionPolicy.js +57 -0
- package/src/core/network/protocols/consensus/v1/ConsensusV1MessageRouter.js +147 -0
- package/src/core/network/protocols/consensus/v1/ConsensusV1Protocol.js +72 -0
- package/src/core/network/protocols/consensus/v1/IndexerPendingRequestService.js +108 -0
- package/src/core/network/protocols/consensus/v1/V1ConsensusProtocolError.js +29 -0
- package/src/core/network/protocols/consensus/v1/handlers/V1EpochAppendOperationHandler.js +68 -0
- package/src/core/network/protocols/consensus/v1/handlers/V1EpochProofProposalOperationHandler.js +226 -0
- package/src/core/network/protocols/consensus/v1/validators/ConsensusValidationSchema.js +192 -0
- package/src/core/network/protocols/consensus/v1/validators/V1BaseConsensusOperation.js +428 -0
- package/src/core/network/protocols/consensus/v1/validators/V1EpochAppendReply.js +47 -0
- package/src/core/network/protocols/consensus/v1/validators/V1EpochAppendRequest.js +17 -0
- package/src/core/network/protocols/consensus/v1/validators/V1EpochProofProposalApproval.js +116 -0
- package/src/core/network/protocols/consensus/v1/validators/V1EpochProofProposalRequest.js +152 -0
- package/src/core/network/protocols/consensus/v1/validators/consensusValidationSchemaHelpers.js +145 -0
- package/src/core/network/protocols/shared/ConnectionOperationHandler.js +27 -0
- package/src/core/network/protocols/{NetworkMessages.js → validators/ValidatorMessages.js} +24 -14
- package/src/core/network/protocols/{ProtocolSession.js → validators/ValidatorProtocolSession.js} +22 -25
- package/src/core/network/protocols/{legacy/NetworkMessageRouter.js → validators/legacy/ValidatorLegacyMessageRouter.js} +6 -6
- package/src/core/network/protocols/{LegacyProtocol.js → validators/legacy/ValidatorLegacyProtocol.js} +9 -7
- package/src/core/network/protocols/{legacy → validators/legacy}/handlers/BaseStateOperationHandler.js +1 -1
- package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyGetRequestHandler.js +5 -5
- package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyRoleOperationHandler.js +5 -5
- package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacySubnetworkOperationHandler.js +5 -5
- package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyTransferOperationHandler.js +5 -5
- package/src/core/network/protocols/{ProtocolInterface.js → validators/shared/ValidatorProtocolInterface.js} +5 -5
- package/src/core/network/protocols/{shared → validators/shared}/validators/PartialBootstrapDeploymentValidator.js +1 -1
- package/src/core/network/protocols/validators/shared/validators/PartialHtlcValidator.js +325 -0
- package/src/core/network/protocols/{shared → validators/shared}/validators/PartialOperationValidator.js +44 -21
- package/src/core/network/protocols/{shared → validators/shared}/validators/PartialRoleAccessValidator.js +3 -3
- package/src/core/network/protocols/{shared → validators/shared}/validators/PartialTransactionValidator.js +3 -3
- package/src/core/network/protocols/{shared → validators/shared}/validators/PartialTransferValidator.js +4 -4
- package/src/core/network/protocols/{v1 → validators/v1}/V1ProtocolError.js +1 -1
- package/src/core/network/{services/PendingRequestService.js → protocols/validators/v1/ValidatorPendingRequestService.js} +19 -82
- package/src/core/network/protocols/{v1/NetworkMessageRouter.js → validators/v1/ValidatorV1MessageRouter.js} +9 -9
- package/src/core/network/protocols/{V1Protocol.js → validators/v1/ValidatorV1Protocol.js} +10 -8
- package/src/core/network/protocols/{connectionPolicies.js → validators/v1/connectionPolicies.js} +1 -1
- package/src/core/network/protocols/{v1 → validators/v1}/handlers/V1BaseOperationHandler.js +6 -23
- package/src/core/network/protocols/{v1 → validators/v1}/handlers/V1BroadcastTransactionOperationHandler.js +14 -9
- package/src/core/network/protocols/{v1 → validators/v1}/handlers/V1LivenessOperationHandler.js +5 -4
- package/src/core/network/protocols/{v1 → validators/v1}/handlers/broadcastTransaction/BroadcastTransactionErrorMapper.js +3 -3
- package/src/core/network/protocols/{v1 → validators/v1}/handlers/broadcastTransaction/BroadcastTransactionOperationStrategies.js +44 -1
- package/src/core/network/protocols/{v1 → validators/v1}/handlers/broadcastTransaction/BroadcastTransactionPayloadUtils.js +1 -1
- package/src/core/network/protocols/{v1 → validators/v1}/validators/V1BaseOperation.js +19 -15
- package/src/core/network/protocols/{v1 → validators/v1}/validators/V1BroadcastTransactionRequest.js +2 -2
- package/src/core/network/protocols/{v1 → validators/v1}/validators/V1BroadcastTransactionResponse.js +34 -18
- package/src/core/network/protocols/{v1 → validators/v1}/validators/V1ValidationSchema.js +3 -3
- package/src/core/network/services/IndexerConnectionManager.js +88 -0
- package/src/core/network/services/TransactionPoolService.js +11 -18
- package/src/core/network/services/TransactionRateLimiterService.js +1 -1
- package/src/core/network/services/ValidatorConnectionManager.js +163 -0
- package/src/core/network/services/{MessageOrchestrator.js → ValidatorMessageOrchestrator.js} +34 -42
- package/src/core/network/services/ValidatorObserverService.js +21 -36
- package/src/core/network/shared/BasePendingRequestService.js +67 -0
- package/src/core/network/shared/PeerConnectionManager.js +185 -0
- package/src/core/state/ConfirmationWatch.js +82 -0
- package/src/core/state/State.js +1794 -173
- package/src/core/state/StateEventQueue.js +69 -0
- package/src/core/state/utils/address.js +10 -6
- package/src/core/state/utils/epochProof.js +109 -0
- package/src/core/state/utils/escrowEntry.js +178 -0
- package/src/core/state/validators/StateValidationSchema.js +757 -0
- package/src/core/state/validators/stateValidationRules.js +312 -0
- package/src/index.js +255 -65
- package/src/messages/consensus/v1/ConsensusMessageBuilder.js +368 -0
- package/src/messages/consensus/v1/ConsensusMessageDirector.js +142 -0
- package/src/messages/consensus/v1/consensusMessageFactory.js +12 -0
- package/src/messages/consensus/v1/epochAppendMessage.js +58 -0
- package/src/messages/network/v1/NetworkMessageBuilder.js +15 -7
- package/src/messages/state/ApplyStateMessageBuilder.js +499 -13
- package/src/messages/state/ApplyStateMessageDirector.js +261 -2
- package/src/utils/StateMachine.js +125 -0
- package/src/utils/applyOperations.js +45 -2
- package/src/utils/buffer.js +239 -59
- package/src/utils/consensusConfig.js +76 -0
- package/src/utils/constants.js +174 -73
- package/src/utils/helpers.js +0 -25
- package/src/utils/htlcLock.js +122 -0
- package/src/utils/logger.js +10 -4
- package/src/utils/migrationUtils.js +2 -1
- package/src/utils/normalizers.js +113 -0
- package/src/utils/scheduler/SchedulableService.js +107 -0
- package/src/utils/{Scheduler.js → scheduler/Scheduler.js} +56 -17
- package/src/core/network/services/ConnectionManager.js +0 -406
- package/src/utils/check.js +0 -525
- package/src/utils/protobuf/applyOperations.cjs +0 -1373
- package/src/utils/protobuf/operationHelpers.js +0 -81
- /package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyResponseHandler.js +0 -0
- /package/src/core/network/protocols/{legacy → validators/legacy}/validators/ValidatorResponse.js +0 -0
- /package/src/core/network/protocols/{legacy → validators/legacy}/validators/base/BaseResponse.js +0 -0
- /package/src/core/network/protocols/{v1 → validators/v1}/validators/V1LivenessRequest.js +0 -0
- /package/src/core/network/protocols/{v1 → validators/v1}/validators/V1LivenessResponse.js +0 -0
package/src/config/config.js
CHANGED
|
@@ -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(
|
|
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 !==
|
|
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: '
|
|
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: '
|
|
120
|
-
channel: '
|
|
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
|
+
}
|