trac-msb 0.2.7 → 0.2.8

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 (146) hide show
  1. package/.github/workflows/publish.yml +8 -16
  2. package/docs/networking-dualstack-plan.md +75 -0
  3. package/docs/networking-layer-redesign.md +155 -0
  4. package/msb.mjs +11 -23
  5. package/package.json +2 -3
  6. package/rpc/{create_server.mjs → create_server.js} +2 -2
  7. package/rpc/{handlers.mjs → handlers.js} +5 -5
  8. package/rpc/routes/{index.mjs → index.js} +1 -1
  9. package/rpc/routes/{v1.mjs → v1.js} +1 -1
  10. package/rpc/{rpc_server.mjs → rpc_server.js} +1 -1
  11. package/rpc/rpc_services.js +4 -4
  12. package/src/config/config.js +137 -0
  13. package/src/config/env.js +61 -0
  14. package/src/core/network/Network.js +119 -73
  15. package/src/core/network/identity/NetworkWalletFactory.js +3 -4
  16. package/src/core/network/messaging/NetworkMessages.js +12 -11
  17. package/src/core/network/messaging/handlers/GetRequestHandler.js +5 -4
  18. package/src/core/network/messaging/handlers/ResponseHandler.js +4 -5
  19. package/src/core/network/messaging/handlers/RoleOperationHandler.js +17 -19
  20. package/src/core/network/messaging/handlers/SubnetworkOperationHandler.js +44 -38
  21. package/src/core/network/messaging/handlers/TransferOperationHandler.js +29 -25
  22. package/src/core/network/messaging/handlers/base/BaseOperationHandler.js +20 -21
  23. package/src/core/network/messaging/routes/NetworkMessageRouter.js +24 -20
  24. package/src/core/network/messaging/validators/AdminResponse.js +2 -2
  25. package/src/core/network/messaging/validators/CustomNodeResponse.js +2 -2
  26. package/src/core/network/messaging/validators/PartialBootstrapDeployment.js +3 -3
  27. package/src/core/network/messaging/validators/PartialRoleAccess.js +15 -12
  28. package/src/core/network/messaging/validators/PartialTransaction.js +9 -10
  29. package/src/core/network/messaging/validators/PartialTransfer.js +10 -7
  30. package/src/core/network/messaging/validators/ValidatorResponse.js +2 -2
  31. package/src/core/network/messaging/validators/base/BaseResponse.js +13 -5
  32. package/src/core/network/messaging/validators/base/PartialOperation.js +37 -21
  33. package/src/core/network/services/ConnectionManager.js +9 -15
  34. package/src/core/network/services/MessageOrchestrator.js +10 -22
  35. package/src/core/network/services/TransactionPoolService.js +9 -8
  36. package/src/core/network/services/ValidatorObserverService.js +46 -21
  37. package/src/core/state/State.js +136 -139
  38. package/src/core/state/utils/address.js +18 -16
  39. package/src/core/state/utils/adminEntry.js +17 -16
  40. package/src/core/state/utils/deploymentEntry.js +15 -15
  41. package/src/core/state/utils/transaction.js +3 -95
  42. package/src/index.js +153 -201
  43. package/src/messages/completeStateMessages/CompleteStateMessageBuilder.js +36 -32
  44. package/src/messages/completeStateMessages/CompleteStateMessageOperations.js +39 -42
  45. package/src/messages/partialStateMessages/PartialStateMessageBuilder.js +20 -20
  46. package/src/messages/partialStateMessages/PartialStateMessageOperations.js +29 -22
  47. package/src/utils/check.js +21 -17
  48. package/src/utils/cliCommands.js +11 -11
  49. package/src/utils/constants.js +2 -10
  50. package/src/utils/fileUtils.js +1 -4
  51. package/src/utils/helpers.js +9 -20
  52. package/src/utils/migrationUtils.js +2 -2
  53. package/src/utils/normalizers.js +10 -9
  54. package/tests/acceptance/v1/account/account.test.mjs +2 -2
  55. package/tests/acceptance/v1/balance/balance.test.mjs +1 -1
  56. package/tests/acceptance/v1/broadcast-transaction/broadcast-transaction.test.mjs +11 -2
  57. package/tests/acceptance/v1/rpc.test.mjs +9 -9
  58. package/tests/acceptance/v1/tx/tx.test.mjs +4 -2
  59. package/tests/acceptance/v1/tx-details/tx-details.test.mjs +7 -3
  60. package/tests/fixtures/check.fixtures.js +42 -42
  61. package/tests/fixtures/protobuf.fixtures.js +27 -26
  62. package/tests/helpers/StateNetworkFactory.js +3 -5
  63. package/tests/helpers/autobaseTestHelpers.js +1 -2
  64. package/tests/helpers/config.js +3 -0
  65. package/tests/helpers/setupApplyTests.js +89 -82
  66. package/tests/helpers/transactionPayloads.mjs +26 -12
  67. package/tests/integration/apply/addAdmin/addAdminBasic.test.js +10 -9
  68. package/tests/integration/apply/addAdmin/addAdminRecovery.test.js +20 -19
  69. package/tests/integration/apply/addIndexer.test.js +23 -21
  70. package/tests/integration/apply/addWhitelist.test.js +9 -9
  71. package/tests/integration/apply/addWriter.test.js +33 -32
  72. package/tests/integration/apply/banValidator.test.js +16 -9
  73. package/tests/integration/apply/postTx/invalidSubValues.test.js +4 -4
  74. package/tests/integration/apply/postTx/postTx.test.js +7 -33
  75. package/tests/integration/apply/removeIndexer.test.js +11 -7
  76. package/tests/integration/apply/removeWriter.test.js +20 -19
  77. package/tests/integration/apply/transfer.test.js +18 -16
  78. package/tests/unit/messageOperations/assembleAddIndexerMessage.test.js +2 -2
  79. package/tests/unit/messageOperations/assembleAddWriterMessage.test.js +2 -1
  80. package/tests/unit/messageOperations/assembleAdminMessage.test.js +9 -10
  81. package/tests/unit/messageOperations/assembleBanWriterMessage.test.js +3 -2
  82. package/tests/unit/messageOperations/assemblePostTransaction.test.js +25 -43
  83. package/tests/unit/messageOperations/assembleRemoveIndexerMessage.test.js +2 -2
  84. package/tests/unit/messageOperations/assembleRemoveWriterMessage.test.js +2 -2
  85. package/tests/unit/messageOperations/assembleWhitelistMessages.test.js +5 -4
  86. package/tests/unit/messageOperations/commonsStateMessageOperationsTest.js +4 -3
  87. package/tests/unit/network/ConnectionManager.test.js +4 -2
  88. package/tests/unit/network/NetworkWalletFactory.test.js +14 -14
  89. package/tests/unit/state/apply/addAdmin/addAdminHappyPathScenario.js +6 -6
  90. package/tests/unit/state/apply/addAdmin/addAdminScenarioHelpers.js +8 -8
  91. package/tests/unit/state/apply/addAdmin/state.apply.addAdmin.test.js +6 -5
  92. package/tests/unit/state/apply/addIndexer/addIndexerScenarioHelpers.js +24 -23
  93. package/tests/unit/state/apply/addWriter/addWriterScenarioHelpers.js +10 -16
  94. package/tests/unit/state/apply/addWriter/addWriterValidatorRewardScenario.js +2 -1
  95. package/tests/unit/state/apply/adminRecovery/adminRecoveryScenarioHelpers.js +45 -41
  96. package/tests/unit/state/apply/adminRecovery/state.apply.adminRecovery.test.js +3 -7
  97. package/tests/unit/state/apply/appendWhitelist/appendWhitelistScenarioHelpers.js +17 -16
  98. package/tests/unit/state/apply/balanceInitialization/balanceInitializationScenarioHelpers.js +3 -4
  99. package/tests/unit/state/apply/balanceInitialization/nodeEntryBalanceUpdateFailureScenario.js +2 -1
  100. package/tests/unit/state/apply/banValidator/banValidatorBanAndReWhitelistScenario.js +2 -1
  101. package/tests/unit/state/apply/banValidator/banValidatorScenarioHelpers.js +23 -25
  102. package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentDuplicateRegistrationScenario.js +2 -1
  103. package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentScenarioHelpers.js +19 -18
  104. package/tests/unit/state/apply/common/access-control/adminConsistencyMismatchScenario.js +5 -4
  105. package/tests/unit/state/apply/common/access-control/adminPublicKeyDecodeFailureScenario.js +4 -3
  106. package/tests/unit/state/apply/common/balances/base/requesterBalanceScenarioBase.js +2 -1
  107. package/tests/unit/state/apply/common/commonScenarioHelper.js +3 -4
  108. package/tests/unit/state/apply/common/payload-structure/initializationDisabledScenario.js +2 -2
  109. package/tests/unit/state/apply/common/payload-structure/invalidHashValidationScenario.js +2 -2
  110. package/tests/unit/state/apply/common/requester/requesterNodeEntryBufferMissingScenario.js +2 -1
  111. package/tests/unit/state/apply/common/requester/requesterNodeEntryDecodeFailureScenario.js +2 -1
  112. package/tests/unit/state/apply/common/validatorConsistency/base/validatorConsistencyScenarioBase.js +2 -1
  113. package/tests/unit/state/apply/common/validatorEntryValidation/base/validatorEntryValidationScenarioBase.js +2 -1
  114. package/tests/unit/state/apply/disableInitialization/disableInitializationScenarioHelpers.js +11 -10
  115. package/tests/unit/state/apply/removeIndexer/removeIndexerScenarioHelpers.js +6 -5
  116. package/tests/unit/state/apply/removeWriter/removeWriterScenarioHelpers.js +6 -7
  117. package/tests/unit/state/apply/transfer/transferDoubleSpendAcrossValidatorsScenario.js +35 -34
  118. package/tests/unit/state/apply/transfer/transferScenarioHelpers.js +44 -43
  119. package/tests/unit/state/apply/txOperation/txOperationScenarioHelpers.js +26 -25
  120. package/tests/unit/state/apply/txOperation/txOperationTransferFeeGuardScenarioFactory.js +2 -1
  121. package/tests/unit/state/stateModule.test.js +0 -1
  122. package/tests/unit/state/stateTestUtils.js +7 -3
  123. package/tests/unit/state/utils/address.test.js +3 -3
  124. package/tests/unit/state/utils/adminEntry.test.js +10 -9
  125. package/tests/unit/utils/check/adminControlOperation.test.js +3 -3
  126. package/tests/unit/utils/check/balanceInitializationOperation.test.js +2 -2
  127. package/tests/unit/utils/check/bootstrapDeploymentOperation.test.js +2 -3
  128. package/tests/unit/utils/check/common.test.js +7 -6
  129. package/tests/unit/utils/check/coreAdminOperation.test.js +3 -3
  130. package/tests/unit/utils/check/roleAccessOperation.test.js +3 -2
  131. package/tests/unit/utils/check/transactionOperation.test.js +3 -3
  132. package/tests/unit/utils/check/transferOperation.test.js +3 -3
  133. package/tests/unit/utils/fileUtils/readAddressesFromWhitelistFile.test.js +2 -1
  134. package/tests/unit/utils/fileUtils/readBalanceMigrationFile.test.js +2 -1
  135. package/tests/unit/utils/migrationUtils/validateAddressFromIncomingFile.test.js +7 -0
  136. package/tests/unit/utils/utils.test.js +0 -1
  137. package/src/core/state/utils/indexerEntry.js +0 -105
  138. package/src/utils/crypto.js +0 -11
  139. package/tests/unit/state/utils/indexerEntry.test.js +0 -83
  140. package/tests/unit/state/utils/transaction.test.js +0 -97
  141. package/tests/unit/utils/crypto/createHash.test.js +0 -15
  142. /package/rpc/{constants.mjs → constants.js} +0 -0
  143. /package/rpc/{cors.mjs → cors.js} +0 -0
  144. /package/rpc/utils/{confirmedParameter.mjs → confirmedParameter.js} +0 -0
  145. /package/rpc/utils/{helpers.mjs → helpers.js} +0 -0
  146. /package/rpc/utils/{url.mjs → url.js} +0 -0
@@ -1,13 +1,11 @@
1
1
  import b4a from 'b4a';
2
2
  import PeerWallet from 'trac-wallet';
3
-
4
3
  import Check from '../../../../../utils/check.js';
5
- import { bufferToAddress } from "../../../../state/utils/address.js";
6
- import { createMessage } from "../../../../../utils/buffer.js";
7
- import { OperationType, NETWORK_ID } from "../../../../../utils/constants.js";
8
- import { blake3Hash } from "../../../../../utils/crypto.js";
9
- import { bufferToBigInt } from "../../../../../utils/amountSerialization.js";
10
- import { FEE } from "../../../../state/utils/transaction.js";
4
+ import {bufferToAddress} from "../../../../state/utils/address.js";
5
+ import {createMessage} from "../../../../../utils/buffer.js";
6
+ import {OperationType} from "../../../../../utils/constants.js";
7
+ import {bufferToBigInt} from "../../../../../utils/amountSerialization.js";
8
+ import {FEE} from "../../../../state/utils/transaction.js";
11
9
  import * as operationsUtils from '../../../../../utils/operations.js';
12
10
 
13
11
  const MAX_AMOUNT = BigInt('0xffffffffffffffffffffffffffffffff');
@@ -17,12 +15,16 @@ const PUBLIC_KEY_LENGTH = 32;
17
15
  class PartialOperation {
18
16
  #state;
19
17
  #check;
18
+ #config
19
+ #wallet
20
20
 
21
- constructor(state) {
21
+ constructor(state, wallet, config) {
22
22
  this.#state = state;
23
- this.#check = new Check();
23
+ this.#config = config;
24
+ this.#check = new Check(this.#config);
24
25
  this.max_amount = MAX_AMOUNT;
25
26
  this.fee = FEE_BIGINT;
27
+ this.#wallet = wallet;
26
28
  }
27
29
 
28
30
  get state() {
@@ -33,7 +35,9 @@ class PartialOperation {
33
35
  return this.#check;
34
36
  }
35
37
 
36
- async validate(payload) { throw new Error("Method 'validate()' must be implemented."); }
38
+ async validate(payload) {
39
+ throw new Error("Method 'validate()' must be implemented.");
40
+ }
37
41
 
38
42
  isPayloadSchemaValid(payload) {
39
43
  if (!payload || !payload.type) {
@@ -65,7 +69,7 @@ class PartialOperation {
65
69
  }
66
70
 
67
71
  validateRequesterAddress(payload) {
68
- const incomingAddress = bufferToAddress(payload.address);
72
+ const incomingAddress = bufferToAddress(payload.address, this.#config.addressPrefix);
69
73
  if (!incomingAddress) {
70
74
  throw new Error('Invalid requesting address in payload.');
71
75
  }
@@ -87,7 +91,7 @@ class PartialOperation {
87
91
  case OperationType.REMOVE_WRITER:
88
92
  case OperationType.ADMIN_RECOVERY:
89
93
  return [
90
- NETWORK_ID,
94
+ this.#config.networkId,
91
95
  operation.txv,
92
96
  operation.iw,
93
97
  operation.in,
@@ -95,7 +99,7 @@ class PartialOperation {
95
99
  ];
96
100
  case OperationType.BOOTSTRAP_DEPLOYMENT:
97
101
  return [
98
- NETWORK_ID,
102
+ this.#config.networkId,
99
103
  operation.txv,
100
104
  operation.bs,
101
105
  operation.ic,
@@ -104,7 +108,7 @@ class PartialOperation {
104
108
  ];
105
109
  case OperationType.TX:
106
110
  return [
107
- NETWORK_ID,
111
+ this.#config.networkId,
108
112
  operation.txv,
109
113
  operation.iw,
110
114
  operation.ch,
@@ -115,7 +119,7 @@ class PartialOperation {
115
119
  ];
116
120
  case OperationType.TRANSFER:
117
121
  return [
118
- NETWORK_ID,
122
+ this.#config.networkId,
119
123
  operation.txv,
120
124
  operation.to,
121
125
  operation.am,
@@ -131,12 +135,12 @@ class PartialOperation {
131
135
  const operationKey = operationsUtils.operationToPayload(payload.type);
132
136
  const operation = payload[operationKey];
133
137
 
134
- const incomingPublicKey = PeerWallet.decodeBech32mSafe(bufferToAddress(payload.address));
138
+ const incomingPublicKey = PeerWallet.decodeBech32mSafe(bufferToAddress(payload.address, this.#config.addressPrefix));
135
139
  const incomingSignature = operation.is;
136
140
  const messageComponents = this.#getMessageComponents(payload);
137
141
 
138
142
  const message = createMessage(...messageComponents);
139
- const messageHash = await blake3Hash(message);
143
+ const messageHash = await PeerWallet.blake3(message);
140
144
  const payloadHash = operation.tx;
141
145
  if (!b4a.equals(payloadHash, messageHash)) {
142
146
  throw new Error('Regenerated transaction does not match incoming transaction in payload.');
@@ -172,16 +176,16 @@ class PartialOperation {
172
176
  isOperationNotCompleted(payload) {
173
177
  const operationKey = operationsUtils.operationToPayload(payload.type);
174
178
  const operation = payload[operationKey];
175
- const { va, vn, vs } = operation;
179
+ const {va, vn, vs} = operation;
176
180
 
177
- const condition = !!(va === undefined && vn === undefined && vs === undefined);
181
+ const condition = va === undefined && vn === undefined && vs === undefined
178
182
  if (!condition) {
179
183
  throw new Error('Transfer operation must not be completed already (va, vn, vs must be undefined).');
180
184
  }
181
185
  }
182
186
 
183
187
  async validateRequesterBalance(payload, signed = false) {
184
- const requesterAddress = bufferToAddress(payload.address);
188
+ const requesterAddress = bufferToAddress(payload.address, this.#config.addressPrefix);
185
189
  let requesterEntry;
186
190
  if (signed) {
187
191
  requesterEntry = await this.state.getNodeEntry(requesterAddress);
@@ -204,11 +208,23 @@ class PartialOperation {
204
208
  const operationKey = operationsUtils.operationToPayload(payload.type);
205
209
  const operation = payload[operationKey];
206
210
  const bs = operation.bs;
207
- if (b4a.equals(this.state.bootstrap, bs)) {
211
+ if (b4a.equals(this.#config.bootstrap, bs)) {
208
212
  throw new Error(`External bootstrap is the same as MSB bootstrap: ${bs.toString('hex')}`);
209
213
  }
210
214
  }
211
215
 
216
+ /*
217
+ * Guard against self-validation (RPC/orchestrator loop): a validator may receive its own submitted tx for validation.
218
+ * Even if unlikely, this must be rejected to avoid incorrect failures/punishments.
219
+ * Flow: Validator -> submits tx with tap-wallet -> RPC-> Validator -validates tx-> REJECT (self-validation)
220
+ */
221
+ validateNoSelfValidation(payload) {
222
+ const requesterAddress = bufferToAddress(payload.address, this.#config.addressPrefix);
223
+ if (this.#wallet.address === requesterAddress) {
224
+ throw new Error('Requester address cannot be the same as the validator wallet address.');
225
+ }
226
+ }
227
+
212
228
  }
213
229
 
214
230
  export default PartialOperation;
@@ -1,7 +1,6 @@
1
- import { MAX_VALIDATORS_IN_CONNECTION_POOL } from "../../../utils/constants.js"
2
1
  import b4a from 'b4a'
3
2
  import PeerWallet from "trac-wallet"
4
- import { TRAC_NETWORK_MSB_MAINNET_PREFIX } from 'trac-wallet/constants.js';
3
+
5
4
 
6
5
  // -- Debug Mode --
7
6
  // TODO: Implement a better debug system in the future. This is just temporary.
@@ -15,14 +14,18 @@ const debugLog = (...args) => {
15
14
  class ConnectionManager {
16
15
  #validators
17
16
  #maxValidators
17
+ #config
18
18
 
19
19
  // Note: #validators is using publicKey (Buffer) as key
20
20
  // As Buffers are objects, we will rely on internal conversions done by JS to compare them.
21
21
  // It would be better to handle these conversions manually by using hex strings as keys to avoid issues
22
-
23
- constructor({ maxValidators }) {
22
+ /**
23
+ * @param {object} config
24
+ **/
25
+ constructor(config) {
24
26
  this.#validators = new Map();
25
- this.#maxValidators = maxValidators || MAX_VALIDATORS_IN_CONNECTION_POOL
27
+ this.#config = config
28
+ this.#maxValidators = config.maxValidators
26
29
  }
27
30
 
28
31
  /**
@@ -288,19 +291,10 @@ class ConnectionManager {
288
291
  }
289
292
  }
290
293
 
291
- #evictRandomValidator() {
292
- const connected = this.connectedValidators();
293
- if (connected.length === 0) return;
294
-
295
- const idx = Math.floor(Math.random() * connected.length);
296
- const toRemove = connected[idx];
297
- this.remove(toRemove);
298
- }
299
-
300
294
  #toAddress(publicKey) {
301
295
  const keyHex = b4a.isBuffer(publicKey) ? publicKey : b4a.from(publicKey, 'hex');
302
296
  return PeerWallet.encodeBech32m(
303
- TRAC_NETWORK_MSB_MAINNET_PREFIX, // TODO: This won't work for other networks. Make it dynamic after configuration is available.
297
+ this.#config.addressPrefix,
304
298
  keyHex
305
299
  );
306
300
  }
@@ -1,34 +1,21 @@
1
1
  import { sleep } from '../../../utils/helpers.js';
2
- import {
3
- MAX_MESSAGE_SEND_ATTEMPTS,
4
- MAX_SUCCESSIVE_MESSAGES_PER_VALIDATOR,
5
- MESSAGE_VALIDATOR_RESPONSE_TIMEOUT_MS,
6
- MESSAGE_VALIDATOR_RETRY_DELAY_MS
7
- } from '../../../utils/constants.js';
8
-
2
+ import { operationToPayload } from '../../../utils/operations.js';
9
3
  /**
10
4
  * MessageOrchestrator coordinates message submission, retry, and validator management.
11
5
  * It works with ConnectionManager and ledger state to ensure reliable message delivery.
12
6
  */
13
7
  class MessageOrchestrator {
8
+ #config;
14
9
  /**
15
10
  * Attempts to send a message to validators with retries and state checks.
16
11
  * @param {ConnectionManager} connectionManager - The connection manager instance
17
12
  * @param {object} state - The state to look for the message outcome
18
- * @param {object} options - { messageThreshold: number, maxRetries: number, retryDelay: number (milliseconds), timeout: number (milliseconds) }
19
- * messageThreshold: How many successful sends before removing a validator from the pool
20
- * maxRetries: How many times to retry sending a message to a single validator
21
- * retryDelay: How long to wait between retries (ms)
22
- * timeout: Overall timeout for sending a message (ms)
13
+ * @param {object} config - Configuration options:
23
14
  */
24
- constructor(connectionManager, state, options = {}) {
15
+ constructor(connectionManager, state, config) {
25
16
  this.connectionManager = connectionManager;
26
17
  this.state = state;
27
- // TODO: Adjust these default values or fetch them from config
28
- this.messageThreshold = options.messageThreshold || MAX_SUCCESSIVE_MESSAGES_PER_VALIDATOR;
29
- this.maxRetries = options.maxRetries || MAX_MESSAGE_SEND_ATTEMPTS; // Amount of retries for a single validator
30
- this.retryDelay = options.retryDelay || MESSAGE_VALIDATOR_RETRY_DELAY_MS; // How long to wait before retrying (ms)
31
- this.timeout = options.timeout || MESSAGE_VALIDATOR_RESPONSE_TIMEOUT_MS; // Overall timeout for sending a message (ms)
18
+ this.#config = config;
32
19
  }
33
20
 
34
21
  /**
@@ -38,7 +25,7 @@ class MessageOrchestrator {
38
25
  */
39
26
  async send(message) {
40
27
  const startTime = Date.now();
41
- while (Date.now() - startTime < this.timeout) {
28
+ while (Date.now() - startTime < this.#config.messageValidatorResponseTimeout) {
42
29
  const validator = this.connectionManager.pickRandomConnectedValidator();
43
30
  if (!validator) return false;
44
31
 
@@ -52,10 +39,11 @@ class MessageOrchestrator {
52
39
 
53
40
  async #attemptSendMessage(validator, message) {
54
41
  let attempts = 0;
55
- while (attempts < this.maxRetries) {
42
+ const deductedTxType = operationToPayload(message.type);
43
+ while (attempts <= this.#config.maxRetries) {
56
44
  this.connectionManager.sendSingleMessage(message, validator);
57
45
 
58
- const appeared = await this.waitForUnsignedState(message.tro.tx, this.retryDelay);
46
+ const appeared = await this.waitForUnsignedState(message[deductedTxType].tx, this.#config.messageValidatorRetryDelay);
59
47
  if (appeared) {
60
48
  this.incrementSentCount(validator);
61
49
  if (this.shouldRemove(validator)) {
@@ -88,7 +76,7 @@ class MessageOrchestrator {
88
76
  }
89
77
 
90
78
  shouldRemove(validatorPubKey) {
91
- return this.connectionManager.getSentCount(validatorPubKey) >= this.messageThreshold;
79
+ return this.connectionManager.getSentCount(validatorPubKey) >= this.#config.messageThreshold;
92
80
  }
93
81
  }
94
82
 
@@ -5,14 +5,19 @@ import Scheduler from '../../../utils/Scheduler.js';
5
5
  class TransactionPoolService {
6
6
  #state;
7
7
  #address;
8
- #options;
8
+ #config;
9
9
  #tx_pool = [];
10
10
  #scheduler = null;
11
11
 
12
- constructor(state, address, options = {}) {
12
+ /**
13
+ * @param {State} state
14
+ * @param {string} address
15
+ * @param {object} config
16
+ **/
17
+ constructor(state, address, config) {
13
18
  this.#state = state;
14
19
  this.#address = address;
15
- this.#options = options;
20
+ this.#config = config;
16
21
  }
17
22
 
18
23
  get tx_pool() {
@@ -27,12 +32,8 @@ class TransactionPoolService {
27
32
  return this.#address;
28
33
  }
29
34
 
30
- get options() {
31
- return this.#options;
32
- }
33
-
34
35
  async start() {
35
- if (!this.options.enable_wallet) {
36
+ if (!this.#config.enableWallet) {
36
37
  console.info('TransactionPoolService can not start. Wallet is not enabled');
37
38
  return;
38
39
  }
@@ -1,12 +1,14 @@
1
1
  import PeerWallet from "trac-wallet";
2
2
  import b4a from "b4a";
3
- import { MAX_WRITERS_FOR_ADMIN_INDEXER_CONNECTION, TRAC_ADDRESS_SIZE } from '../../../utils/constants.js';
3
+ import { MAX_WRITERS_FOR_ADMIN_INDEXER_CONNECTION } from '../../../utils/constants.js';
4
4
  import { bufferToAddress } from '../../state/utils/address.js';
5
5
  import { sleep } from '../../../utils/helpers.js';
6
6
  import Scheduler from "../../../utils/Scheduler.js";
7
+ import Network from "../Network.js";
7
8
 
8
- const POLL_INTERVAL = 3500 // This was increase since the iterations dont wait for the execution its about 10 * DELAY_INTERVAL
9
- const DELAY_INTERVAL = 250
9
+ const DELAY_INTERVAL = 50
10
+ const VALIDATOR_CANDIDATES_PER_CYCLE = 10
11
+ const POLL_INTERVAL = (VALIDATOR_CANDIDATES_PER_CYCLE + 1) * DELAY_INTERVAL // This is to avoid more than one instance of the worker running at the same time
10
12
 
11
13
  // -- Debug Mode --
12
14
  // TODO: Implement a better debug system in the future. This is just temporary.
@@ -18,19 +20,31 @@ const debugLog = (...args) => {
18
20
  };
19
21
 
20
22
  class ValidatorObserverService {
21
- #enable_validator_observer;
23
+ #config;
22
24
  #state;
23
25
  #network;
24
26
  #scheduler;
25
27
  #address;
26
28
  #isInterrupted
27
29
 
28
- constructor(network, state, address, options = {}) {
29
- this.#enable_validator_observer = options.enable_validator_observer !== false;
30
+ /**
31
+ * @param {Network} network
32
+ * @param {State} state
33
+ * @param {string} address
34
+ * @param {object} config
35
+ **/
36
+ constructor(network, state, address, config) {
37
+ this.#config = config
30
38
  this.#network = network;
31
39
  this.#state = state;
32
40
  this.#address = address;
33
41
  this.#isInterrupted = false;
42
+ if (DEBUG) {
43
+ this.initTimestamp = Date.now();
44
+ this.reachedMax = false;
45
+ this.end = 0;
46
+ this.begin = 0;
47
+ }
34
48
  }
35
49
 
36
50
  get state() {
@@ -65,17 +79,29 @@ class ValidatorObserverService {
65
79
 
66
80
  async #worker(next) {
67
81
  if (!this.#network.validatorConnectionManager.maxConnectionsReached()) {
82
+ if (DEBUG) this.begin = Date.now();
68
83
  const length = await this.#lengthEntry()
69
84
 
70
85
  const promises = [];
71
- for (let i = 0; i < 10; i++) {
86
+ for (let i = 0; i < VALIDATOR_CANDIDATES_PER_CYCLE; i++) {
72
87
  promises.push(this.#findValidator(this.#address, length + 1));
73
88
  await sleep(DELAY_INTERVAL); // Low key dangerous as the network progresses
74
89
  }
75
90
  await Promise.all(promises);
76
91
 
77
- next(POLL_INTERVAL)
92
+ if (DEBUG) this.end = Date.now();
93
+ debugLog('Worker cycle completed in (ms):', this.end - this.begin, '| Validator Connections:', this.#network.validatorConnectionManager.connectionCount(), " | Pending: ", this.#network.pendingConnectionsCount());
94
+ }
95
+ else if (DEBUG) {
96
+ if (!this.reachedMax) {
97
+ this.reachedMax = true;
98
+ debugLog('Max validator connections reached. Skipping this cycle.');
99
+ const now = Date.now();
100
+ const elapsed = now - this.initTimestamp;
101
+ debugLog('>>> Time elapsed since start (ms):', elapsed);
102
+ }
78
103
  }
104
+ next(POLL_INTERVAL);
79
105
  }
80
106
 
81
107
  async #findValidator(address, validatorListLength) {
@@ -98,30 +124,33 @@ class ValidatorObserverService {
98
124
  else {
99
125
  debugLog(`Found valid validator to connect after ${attempts} attempts.`);
100
126
  }
101
-
127
+
102
128
  if (!isValidatorValid) return;
103
-
104
- const validatorAddress = bufferToAddress(validatorAddressBuffer);
129
+
130
+ const validatorAddress = bufferToAddress(validatorAddressBuffer, this.#config.addressPrefix);
105
131
  const validatorPubKeyBuffer = PeerWallet.decodeBech32m(validatorAddress);
106
132
  const validatorPubKeyHex = validatorPubKeyBuffer.toString('hex');
107
133
  const adminEntry = await this.state.getAdminEntry();
108
134
 
109
-
110
135
  if (validatorAddress !== adminEntry?.address || validatorListLength < MAX_WRITERS_FOR_ADMIN_INDEXER_CONNECTION) {
111
- await this.#network.tryConnect(validatorPubKeyHex, 'validator');
136
+ this.#network.tryConnect(validatorPubKeyHex, 'validator');
112
137
  }
113
138
  };
114
139
 
115
140
  async #isValidatorValid(forbiddenAddress, validatorAddressBuffer, validatorListLength) {
116
- if (validatorAddressBuffer === null || b4a.byteLength(validatorAddressBuffer) !== TRAC_ADDRESS_SIZE) return false;
117
-
118
- const validatorAddress = bufferToAddress(validatorAddressBuffer);
141
+ if (validatorAddressBuffer === null || b4a.byteLength(validatorAddressBuffer) !== this.#config.addressLength) return false;
142
+
143
+ const validatorAddress = bufferToAddress(validatorAddressBuffer, this.#config.addressPrefix);
119
144
  if (validatorAddress === forbiddenAddress) return false;
120
145
 
121
146
  const validatorPubKeyBuffer = PeerWallet.decodeBech32m(validatorAddress);
122
147
  const validatorEntry = await this.state.getNodeEntry(validatorAddress);
123
148
  const adminEntry = await this.state.getAdminEntry();
124
149
 
150
+ if (this.#network.isConnectionPending(validatorPubKeyBuffer.toString('hex'))) {
151
+ return false;
152
+ }
153
+
125
154
  if (validatorAddress === adminEntry?.address && validatorListLength >= MAX_WRITERS_FOR_ADMIN_INDEXER_CONNECTION) {
126
155
  if (this.#network.validatorConnectionManager.exists(validatorPubKeyBuffer)) {
127
156
  this.#network.validatorConnectionManager.remove(validatorPubKeyBuffer)
@@ -146,11 +175,7 @@ class ValidatorObserverService {
146
175
  }
147
176
 
148
177
  #shouldRun() {
149
- if (!this.#enable_validator_observer || this.#isInterrupted) {
150
- return false;
151
- }
152
-
153
- return true;
178
+ return this.#config.enableValidatorObserver && !this.#isInterrupted
154
179
  }
155
180
 
156
181
  async #lengthEntry() {