trac-msb 0.2.3 → 0.2.5

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 (235) hide show
  1. package/.dockerignore +16 -0
  2. package/.github/workflows/acceptance-tests.yml +7 -0
  3. package/.github/workflows/publish.yml +40 -0
  4. package/.github/workflows/{CI.yml → unit-tests.yml} +1 -1
  5. package/README.md +175 -50
  6. package/docker-compose.yml +16 -0
  7. package/dockerfile +41 -0
  8. package/docs/fee_distribution.md +89 -0
  9. package/msb.mjs +6 -4
  10. package/package.json +8 -4
  11. package/rpc/constants.mjs +4 -1
  12. package/rpc/handlers.mjs +95 -45
  13. package/rpc/routes/v1.mjs +3 -1
  14. package/rpc/utils/confirmedParameter.mjs +17 -0
  15. package/rpc/utils/url.mjs +38 -0
  16. package/src/core/network/Network.js +27 -10
  17. package/src/core/network/identity/NetworkWalletFactory.js +78 -0
  18. package/src/core/network/services/ConnectionManager.js +2 -2
  19. package/src/core/network/services/ValidatorObserverService.js +7 -4
  20. package/src/core/state/State.js +28 -22
  21. package/src/utils/constants.js +3 -1
  22. package/tests/acceptance/v1/account/account.test.mjs +123 -0
  23. package/tests/acceptance/v1/balance/balance.test.mjs +55 -0
  24. package/tests/acceptance/v1/broadcast-transaction/broadcast-transaction.test.mjs +114 -0
  25. package/tests/acceptance/v1/confirmed-length/confirmed-length.test.mjs +19 -0
  26. package/tests/acceptance/v1/fee/fee.test.mjs +11 -0
  27. package/tests/acceptance/v1/rpc.test.mjs +62 -291
  28. package/tests/acceptance/v1/tx/tx.test.mjs +103 -0
  29. package/tests/acceptance/v1/tx-details/tx-details.test.mjs +203 -0
  30. package/tests/acceptance/v1/tx-hashes/tx-hashes.test.mjs +72 -0
  31. package/tests/acceptance/v1/tx-payloads-bulk/tx-payloads-bulk.test.mjs +27 -0
  32. package/tests/acceptance/v1/txv/txv.test.mjs +11 -0
  33. package/tests/acceptance/v1/unconfirmed-length/unconfirmed-length.test.mjs +11 -0
  34. package/tests/helpers/StateNetworkFactory.js +157 -0
  35. package/tests/helpers/autobaseTestHelpers.js +369 -0
  36. package/tests/helpers/createTestSignature.js +12 -0
  37. package/tests/unit/network/NetworkWalletFactory.test.js +156 -0
  38. package/tests/unit/state/apply/addAdmin/addAdminHappyPathScenario.js +38 -0
  39. package/tests/unit/state/apply/addAdmin/addAdminScenarioHelpers.js +273 -0
  40. package/tests/unit/state/apply/addAdmin/adminEntryEncodingFailureScenario.js +30 -0
  41. package/tests/unit/state/apply/addAdmin/adminEntryExistsScenario.js +78 -0
  42. package/tests/unit/state/apply/addAdmin/nodeEntryInitializationFailureScenario.js +30 -0
  43. package/tests/unit/state/apply/addAdmin/nonBootstrapNodeScenario.js +68 -0
  44. package/tests/unit/state/apply/addAdmin/state.apply.addAdmin.test.js +155 -0
  45. package/tests/unit/state/apply/addIndexer/addIndexerHappyPathScenario.js +39 -0
  46. package/tests/unit/state/apply/addIndexer/addIndexerMultipleIndexersInTheNetworkScenario.js +167 -0
  47. package/tests/unit/state/apply/addIndexer/addIndexerPretenderAlreadyIndexerScenario.js +21 -0
  48. package/tests/unit/state/apply/addIndexer/addIndexerPretenderNotWriterScenario.js +21 -0
  49. package/tests/unit/state/apply/addIndexer/addIndexerRemoveAndReAddScenario.js +186 -0
  50. package/tests/unit/state/apply/addIndexer/addIndexerScenarioHelpers.js +445 -0
  51. package/tests/unit/state/apply/addIndexer/addIndexerWriterKeyAlreadyRegisteredScenario.js +32 -0
  52. package/tests/unit/state/apply/addIndexer/state.apply.addIndexer.test.js +297 -0
  53. package/tests/unit/state/apply/addWriter/addWriterHappyPathScenario.js +41 -0
  54. package/tests/unit/state/apply/addWriter/addWriterInvalidValidatorSignatureScenario.js +32 -0
  55. package/tests/unit/state/apply/addWriter/addWriterNewWkScenario.js +149 -0
  56. package/tests/unit/state/apply/addWriter/addWriterRequesterAlreadyWriterScenario.js +21 -0
  57. package/tests/unit/state/apply/addWriter/addWriterRequesterBalanceInsufficientScenario.js +21 -0
  58. package/tests/unit/state/apply/addWriter/addWriterRequesterEntryDecodeFailureScenario.js +19 -0
  59. package/tests/unit/state/apply/addWriter/addWriterRequesterEntryMissingScenario.js +19 -0
  60. package/tests/unit/state/apply/addWriter/addWriterRequesterIndexerScenario.js +21 -0
  61. package/tests/unit/state/apply/addWriter/addWriterRequesterNotWhitelistedScenario.js +21 -0
  62. package/tests/unit/state/apply/addWriter/addWriterScenarioHelpers.js +757 -0
  63. package/tests/unit/state/apply/addWriter/addWriterStakeBalanceUpdateFailureScenario.js +50 -0
  64. package/tests/unit/state/apply/addWriter/addWriterStakeInsufficientBalanceScenario.js +29 -0
  65. package/tests/unit/state/apply/addWriter/addWriterStakeInvalidBalanceScenario.js +29 -0
  66. package/tests/unit/state/apply/addWriter/addWriterStakeInvalidEntryScenario.js +21 -0
  67. package/tests/unit/state/apply/addWriter/addWriterStakeStakedBalanceFailureScenario.js +37 -0
  68. package/tests/unit/state/apply/addWriter/addWriterStakeSubtractFailureScenario.js +42 -0
  69. package/tests/unit/state/apply/addWriter/addWriterValidatorRewardScenario.js +105 -0
  70. package/tests/unit/state/apply/addWriter/addWriterWriterKeyMismatchScenario.js +54 -0
  71. package/tests/unit/state/apply/addWriter/addWriterWriterKeyOwnershipScenario.js +54 -0
  72. package/tests/unit/state/apply/addWriter/addWriterZeroWriterKeyScenario.js +29 -0
  73. package/tests/unit/state/apply/addWriter/state.apply.addWriter.test.js +309 -0
  74. package/tests/unit/state/apply/adminRecovery/adminRecoveryHappyPathScenario.js +30 -0
  75. package/tests/unit/state/apply/adminRecovery/adminRecoveryScenarioHelpers.js +866 -0
  76. package/tests/unit/state/apply/adminRecovery/state.apply.adminRecovery.test.js +439 -0
  77. package/tests/unit/state/apply/appendWhitelist/appendWhitelistBanAndReapplyScenario.js +78 -0
  78. package/tests/unit/state/apply/appendWhitelist/appendWhitelistExistingReaderHappyPathScenario.js +98 -0
  79. package/tests/unit/state/apply/appendWhitelist/appendWhitelistFeeAfterDisableScenario.js +66 -0
  80. package/tests/unit/state/apply/appendWhitelist/appendWhitelistHappyPathScenario.js +55 -0
  81. package/tests/unit/state/apply/appendWhitelist/appendWhitelistInsufficientAdminBalanceScenario.js +103 -0
  82. package/tests/unit/state/apply/appendWhitelist/appendWhitelistNodeAlreadyWhitelistedScenario.js +60 -0
  83. package/tests/unit/state/apply/appendWhitelist/appendWhitelistScenarioHelpers.js +191 -0
  84. package/tests/unit/state/apply/appendWhitelist/state.apply.appendWhitelist.test.js +220 -0
  85. package/tests/unit/state/apply/balanceInitialization/balanceInitializationHappyPathScenario.js +82 -0
  86. package/tests/unit/state/apply/balanceInitialization/balanceInitializationScenarioHelpers.js +106 -0
  87. package/tests/unit/state/apply/balanceInitialization/invalidAmountScenario.js +45 -0
  88. package/tests/unit/state/apply/balanceInitialization/nodeEntryBalanceUpdateFailureScenario.js +81 -0
  89. package/tests/unit/state/apply/balanceInitialization/state.apply.balanceInitialization.test.js +189 -0
  90. package/tests/unit/state/apply/banValidator/banValidatorBanAndReWhitelistScenario.js +155 -0
  91. package/tests/unit/state/apply/banValidator/banValidatorHappyPathScenario.js +36 -0
  92. package/tests/unit/state/apply/banValidator/banValidatorScenarioHelpers.js +534 -0
  93. package/tests/unit/state/apply/banValidator/banValidatorSequentialBansScenario.js +74 -0
  94. package/tests/unit/state/apply/banValidator/banValidatorTargetDecodeFailureScenario.js +19 -0
  95. package/tests/unit/state/apply/banValidator/banValidatorTargetIndexerScenario.js +32 -0
  96. package/tests/unit/state/apply/banValidator/banValidatorTargetNodeEntryMissingScenario.js +19 -0
  97. package/tests/unit/state/apply/banValidator/banValidatorTargetRoleUpdateFailureScenario.js +19 -0
  98. package/tests/unit/state/apply/banValidator/banValidatorWhitelistedNonWriterScenario.js +38 -0
  99. package/tests/unit/state/apply/banValidator/banValidatorWhitelistedZeroBalanceScenario.js +91 -0
  100. package/tests/unit/state/apply/banValidator/banValidatorWithdrawFailureScenario.js +19 -0
  101. package/tests/unit/state/apply/banValidator/state.apply.banValidator.test.js +266 -0
  102. package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentDuplicateRegistrationScenario.js +142 -0
  103. package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentHappyPathScenario.js +26 -0
  104. package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentIncompleteOperationScenario.js +94 -0
  105. package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentInvalidDeploymentEntryScenario.js +37 -0
  106. package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentMultipleBootstrapScenario.js +86 -0
  107. package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentScenarioHelpers.js +344 -0
  108. package/tests/unit/state/apply/bootstrapDeployment/invalidValidatorNodeEntryScenario.js +57 -0
  109. package/tests/unit/state/apply/bootstrapDeployment/state.apply.bootstrapDeployment.test.js +429 -0
  110. package/tests/unit/state/apply/common/access-control/adminConsistencyMismatchScenario.js +119 -0
  111. package/tests/unit/state/apply/common/access-control/adminEntryDecodeFailureScenario.js +130 -0
  112. package/tests/unit/state/apply/common/access-control/adminEntryExistsScenario.js +93 -0
  113. package/tests/unit/state/apply/common/access-control/adminEntryMissingScenario.js +108 -0
  114. package/tests/unit/state/apply/common/access-control/adminOnlyGuardScenario.js +126 -0
  115. package/tests/unit/state/apply/common/access-control/adminPublicKeyDecodeFailureScenario.js +120 -0
  116. package/tests/unit/state/apply/common/access-control/roleAccessOperationValidationScenario.js +50 -0
  117. package/tests/unit/state/apply/common/adminControlOperationValidationScenario.js +56 -0
  118. package/tests/unit/state/apply/common/balances/adminEntryUpdateFailureScenario.js +52 -0
  119. package/tests/unit/state/apply/common/balances/base/requesterBalanceScenarioBase.js +197 -0
  120. package/tests/unit/state/apply/common/balances/feeDecodeFailureScenario.js +52 -0
  121. package/tests/unit/state/apply/common/balances/requesterBalanceDecodeFailureScenario.js +15 -0
  122. package/tests/unit/state/apply/common/balances/requesterBalanceFeeApplicationFailureScenario.js +11 -0
  123. package/tests/unit/state/apply/common/balances/requesterBalanceInsufficientScenario.js +15 -0
  124. package/tests/unit/state/apply/common/balances/requesterBalanceUpdateFailureScenario.js +11 -0
  125. package/tests/unit/state/apply/common/balances/validatorEntryRewardFailureScenario.js +11 -0
  126. package/tests/unit/state/apply/common/balances/validatorEntryUpdateFailureScenario.js +11 -0
  127. package/tests/unit/state/apply/common/balances/validatorNodeEntryDecodeFailureScenario.js +40 -0
  128. package/tests/unit/state/apply/common/base/OperationValidationScenarioBase.js +114 -0
  129. package/tests/unit/state/apply/common/commonScenarioHelper.js +103 -0
  130. package/tests/unit/state/apply/common/indexer/indexerNodeEntryDecodeFailureScenario.js +36 -0
  131. package/tests/unit/state/apply/common/indexer/indexerNodeEntryMissingScenario.js +36 -0
  132. package/tests/unit/state/apply/common/indexer/indexerRoleUpdateFailureScenario.js +29 -0
  133. package/tests/unit/state/apply/common/indexer/indexerSequenceStateInvalidScenario.js +66 -0
  134. package/tests/unit/state/apply/common/invalidMessageComponentValidationScenario.js +84 -0
  135. package/tests/unit/state/apply/common/nodeEntryInitializationFailureScenario.js +47 -0
  136. package/tests/unit/state/apply/common/operationAlreadyAppliedScenario.js +85 -0
  137. package/tests/unit/state/apply/common/payload-structure/addressWithInvalidPublicKeyScenario.js +52 -0
  138. package/tests/unit/state/apply/common/payload-structure/initializationDisabledScenario.js +49 -0
  139. package/tests/unit/state/apply/common/payload-structure/invalidAddressValidationScenario.js +73 -0
  140. package/tests/unit/state/apply/common/payload-structure/invalidHashValidationScenario.js +71 -0
  141. package/tests/unit/state/apply/common/payload-structure/invalidPayloadValidationScenario.js +31 -0
  142. package/tests/unit/state/apply/common/payload-structure/invalidSignatureValidationScenario.js +142 -0
  143. package/tests/unit/state/apply/common/payload-structure/partialOperationValidationScenario.js +87 -0
  144. package/tests/unit/state/apply/common/requester/requesterNodeEntryBufferMissingScenario.js +70 -0
  145. package/tests/unit/state/apply/common/requester/requesterNodeEntryDecodeFailureScenario.js +72 -0
  146. package/tests/unit/state/apply/common/requester/requesterNodeEntryMissingScenario.js +36 -0
  147. package/tests/unit/state/apply/common/requesterAddressValidationScenario.js +44 -0
  148. package/tests/unit/state/apply/common/requesterPublicKeyValidationScenario.js +25 -0
  149. package/tests/unit/state/apply/common/transactionValidityMismatchScenario.js +98 -0
  150. package/tests/unit/state/apply/common/validatorConsistency/base/validatorConsistencyScenarioBase.js +201 -0
  151. package/tests/unit/state/apply/common/validatorConsistency/validatorEntryDecodeFailureScenario.js +17 -0
  152. package/tests/unit/state/apply/common/validatorConsistency/validatorEntryMissingScenario.js +44 -0
  153. package/tests/unit/state/apply/common/validatorConsistency/validatorInactiveScenario.js +19 -0
  154. package/tests/unit/state/apply/common/validatorConsistency/validatorWriterKeyMismatchScenario.js +18 -0
  155. package/tests/unit/state/apply/common/validatorEntryValidation/base/validatorEntryValidationScenarioBase.js +314 -0
  156. package/tests/unit/state/apply/common/validatorEntryValidation/validatorEntryInvalidBalanceScenario.js +18 -0
  157. package/tests/unit/state/apply/common/writerKeyExistsValidationScenario.js +43 -0
  158. package/tests/unit/state/apply/disableInitialization/disableInitializationAlreadyDisabledScenario.js +53 -0
  159. package/tests/unit/state/apply/disableInitialization/disableInitializationHappyPathScenario.js +24 -0
  160. package/tests/unit/state/apply/disableInitialization/disableInitializationScenarioHelpers.js +197 -0
  161. package/tests/unit/state/apply/disableInitialization/state.apply.disableInitialization.test.js +161 -0
  162. package/tests/unit/state/apply/missing-tests.md +18 -0
  163. package/tests/unit/state/apply/removeIndexer/removeIndexerHappyPathScenario.js +58 -0
  164. package/tests/unit/state/apply/removeIndexer/removeIndexerReAddAndRemoveAgainScenario.js +98 -0
  165. package/tests/unit/state/apply/removeIndexer/removeIndexerRemoveMultipleIndexersScenario.js +167 -0
  166. package/tests/unit/state/apply/removeIndexer/removeIndexerScenarioHelpers.js +428 -0
  167. package/tests/unit/state/apply/removeIndexer/removeIndexerTargetNotIndexerScenario.js +22 -0
  168. package/tests/unit/state/apply/removeIndexer/removeIndexerWriterKeyMissingScenario.js +20 -0
  169. package/tests/unit/state/apply/removeIndexer/state.apply.removeIndexer.test.js +291 -0
  170. package/tests/unit/state/apply/removeWriter/removeWriterAndAddWriterAgainScenario.js +87 -0
  171. package/tests/unit/state/apply/removeWriter/removeWriterHappyPathScenario.js +38 -0
  172. package/tests/unit/state/apply/removeWriter/removeWriterInvalidValidatorSignatureScenario.js +32 -0
  173. package/tests/unit/state/apply/removeWriter/removeWriterRequesterBalanceInsufficientScenario.js +21 -0
  174. package/tests/unit/state/apply/removeWriter/removeWriterRequesterEntryDecodeFailureScenario.js +19 -0
  175. package/tests/unit/state/apply/removeWriter/removeWriterRequesterEntryMissingScenario.js +19 -0
  176. package/tests/unit/state/apply/removeWriter/removeWriterRequesterIndexerScenario.js +21 -0
  177. package/tests/unit/state/apply/removeWriter/removeWriterRequesterNotWriterScenario.js +21 -0
  178. package/tests/unit/state/apply/removeWriter/removeWriterRequesterRoleUpdateFailureScenario.js +19 -0
  179. package/tests/unit/state/apply/removeWriter/removeWriterScenarioHelpers.js +344 -0
  180. package/tests/unit/state/apply/removeWriter/removeWriterThroughWriterValidatorScenario.js +113 -0
  181. package/tests/unit/state/apply/removeWriter/removeWriterUnstakeFailureScenario.js +33 -0
  182. package/tests/unit/state/apply/removeWriter/removeWriterWriterKeyMismatchScenario.js +21 -0
  183. package/tests/unit/state/apply/removeWriter/removeWriterWriterKeyOwnershipScenario.js +26 -0
  184. package/tests/unit/state/apply/removeWriter/removeWriterWriterKeyRegistryMissingScenario.js +22 -0
  185. package/tests/unit/state/apply/removeWriter/state.apply.removeWriter.test.js +307 -0
  186. package/tests/unit/state/apply/state.apply.test.js +24 -0
  187. package/tests/unit/state/apply/transfer/state.apply.transfer.test.js +819 -0
  188. package/tests/unit/state/apply/transfer/transferContractSchemaValidationScenario.js +22 -0
  189. package/tests/unit/state/apply/transfer/transferDoubleSpendAcrossValidatorsScenario.js +137 -0
  190. package/tests/unit/state/apply/transfer/transferDoubleSpendSameBatchScenario.js +63 -0
  191. package/tests/unit/state/apply/transfer/transferDoubleSpendSingleValidatorScenario.js +67 -0
  192. package/tests/unit/state/apply/transfer/transferExistingRecipientAmountScenario.js +31 -0
  193. package/tests/unit/state/apply/transfer/transferExistingRecipientZeroAmountScenario.js +31 -0
  194. package/tests/unit/state/apply/transfer/transferHandlerGuardScenarios.js +22 -0
  195. package/tests/unit/state/apply/transfer/transferHappyPathScenario.js +8 -0
  196. package/tests/unit/state/apply/transfer/transferInvalidIncomingDataScenario.js +66 -0
  197. package/tests/unit/state/apply/transfer/transferNewRecipientAmountScenario.js +31 -0
  198. package/tests/unit/state/apply/transfer/transferNewRecipientZeroAmountScenario.js +31 -0
  199. package/tests/unit/state/apply/transfer/transferScenarioHelpers.js +1167 -0
  200. package/tests/unit/state/apply/transfer/transferSelfTransferAmountScenario.js +38 -0
  201. package/tests/unit/state/apply/transfer/transferSelfTransferZeroAmountScenario.js +38 -0
  202. package/tests/unit/state/apply/transfer/transferValidatorRecipientAmountScenario.js +38 -0
  203. package/tests/unit/state/apply/transfer/transferValidatorRecipientZeroAmountScenario.js +38 -0
  204. package/tests/unit/state/apply/txOperation/state.apply.txOperation.test.js +318 -0
  205. package/tests/unit/state/apply/txOperation/txOperationBootstrapNotRegisteredScenario.js +70 -0
  206. package/tests/unit/state/apply/txOperation/txOperationDifferentValidatorCreatorHappyPathScenario.js +23 -0
  207. package/tests/unit/state/apply/txOperation/txOperationInvalidDeploymentEntryScenario.js +48 -0
  208. package/tests/unit/state/apply/txOperation/txOperationInvalidFeeAmountScenario.js +39 -0
  209. package/tests/unit/state/apply/txOperation/txOperationInvalidSubnetCreatorAddressScenario.js +46 -0
  210. package/tests/unit/state/apply/txOperation/txOperationRequesterCreatorHappyPathScenario.js +21 -0
  211. package/tests/unit/state/apply/txOperation/txOperationScenarioHelpers.js +429 -0
  212. package/tests/unit/state/apply/txOperation/txOperationStandardHappyPathScenario.js +21 -0
  213. package/tests/unit/state/apply/txOperation/txOperationTransferFeeAddCreatorBalanceFailureScenario.js +26 -0
  214. package/tests/unit/state/apply/txOperation/txOperationTransferFeeAddValidatorBalanceFailureScenario.js +25 -0
  215. package/tests/unit/state/apply/txOperation/txOperationTransferFeeAddValidatorBonusFailureScenario.js +27 -0
  216. package/tests/unit/state/apply/txOperation/txOperationTransferFeeDecodeCreatorEntryScenario.js +18 -0
  217. package/tests/unit/state/apply/txOperation/txOperationTransferFeeDecodeRequesterEntryScenario.js +17 -0
  218. package/tests/unit/state/apply/txOperation/txOperationTransferFeeDecodeValidatorEntryScenario.js +31 -0
  219. package/tests/unit/state/apply/txOperation/txOperationTransferFeeGuardBypassScenario.js +49 -0
  220. package/tests/unit/state/apply/txOperation/txOperationTransferFeeGuardScenarioFactory.js +92 -0
  221. package/tests/unit/state/apply/txOperation/txOperationTransferFeeInsufficientRequesterBalanceScenario.js +28 -0
  222. package/tests/unit/state/apply/txOperation/txOperationTransferFeeInvalidCreatorBalanceScenario.js +29 -0
  223. package/tests/unit/state/apply/txOperation/txOperationTransferFeeInvalidRequesterBalanceScenario.js +28 -0
  224. package/tests/unit/state/apply/txOperation/txOperationTransferFeeInvalidRequesterEntryScenario.js +17 -0
  225. package/tests/unit/state/apply/txOperation/txOperationTransferFeeInvalidValidatorBalanceScenario.js +33 -0
  226. package/tests/unit/state/apply/txOperation/txOperationTransferFeeMissingCreatorEntryScenario.js +18 -0
  227. package/tests/unit/state/apply/txOperation/txOperationTransferFeeSubtractFailureScenario.js +25 -0
  228. package/tests/unit/state/apply/txOperation/txOperationTransferFeeUpdateCreatorBalanceFailureScenario.js +26 -0
  229. package/tests/unit/state/apply/txOperation/txOperationTransferFeeUpdateFailureScenario.js +25 -0
  230. package/tests/unit/state/apply/txOperation/txOperationTransferFeeUpdateValidatorBalanceFailureScenario.js +26 -0
  231. package/tests/unit/state/apply/txOperation/txOperationTransferFeeUpdateValidatorBonusFailureScenario.js +27 -0
  232. package/tests/unit/state/apply/txOperation/txOperationValidatorCreatorHappyPathScenario.js +21 -0
  233. package/tests/unit/state/stateModule.test.js +1 -0
  234. package/tests/unit/state/stateTestUtils.js +5 -1
  235. package/.env +0 -0
package/rpc/handlers.mjs CHANGED
@@ -1,26 +1,26 @@
1
1
  import { decodeBase64Payload, isBase64, sanitizeBulkPayloadsRequestBody, sanitizeTransferPayload, validatePayloadStructure } from "./utils/helpers.mjs"
2
- import { MAX_SIGNED_LENGTH } from "./constants.mjs";
3
- import { isHexString } from "../src/utils/helpers";
2
+ import { MAX_SIGNED_LENGTH, ZERO_WK } from "./constants.mjs";
3
+ import { buildRequestUrl } from "./utils/url.mjs";
4
+ import { isHexString } from "../src/utils/helpers.js";
5
+ import { bufferToBigInt, licenseBufferToBigInt } from "../src/utils/amountSerialization.js";
6
+ import { isAddressValid } from "../src/core/state/utils/address.js";
7
+ import { getConfirmedParameter } from "./utils/confirmedParameter.mjs";
4
8
 
5
9
  export async function handleBalance({ req, respond, msbInstance }) {
6
- const [path, queryString] = req.url.split("?");
7
- const parts = path.split("/").filter(Boolean);
10
+ const url = buildRequestUrl(req);
11
+ const parts = url.pathname.split("/").filter(Boolean);
8
12
  const address = parts[2];
9
13
 
10
- let confirmed = true; // default
11
- if (queryString) {
12
- const params = new URLSearchParams(queryString);
13
- if (params.has("confirmed")) {
14
- confirmed = params.get("confirmed") === "true";
15
- }
16
- }
14
+ const confirmedParam = getConfirmedParameter(url);
15
+ const confirmed = confirmedParam === null ? false : confirmedParam; // invalid -> fallback to unconfirmed
17
16
 
17
+ // TODO: VALIDATION?
18
18
  if (!address) {
19
19
  respond(400, { error: 'Wallet address is required' });
20
20
  return;
21
21
  }
22
-
23
- const commandString =`/get_balance ${address} ${confirmed}`;
22
+
23
+ const commandString = `/get_balance ${address} ${confirmed}`;
24
24
  const nodeInfo = await msbInstance.handleCommand(commandString);
25
25
  const balance = nodeInfo?.balance || 0;
26
26
  respond(200, { address, balance });
@@ -71,14 +71,14 @@ export async function handleBroadcastTransaction({ msbInstance, respond, req })
71
71
  let code = error instanceof SyntaxError ? 400 : 500;
72
72
  let errorMsg = code === 400 ? 'Invalid JSON payload.' : 'An error occurred processing the transaction.'
73
73
 
74
- if(error.message.includes("Failed to broadcast transaction after multiple attempts.")){
74
+ if (error.message.includes("Failed to broadcast transaction after multiple attempts.")) {
75
75
  code = 429;
76
76
  errorMsg = "Failed to broadcast transaction after multiple attempts."
77
77
  }
78
-
78
+
79
79
  console.error('Error in handleBroadcastTransaction:', error);
80
80
  // Use 400 for client errors (like bad JSON), 500 for server/command errors
81
- respond(code, { error: errorMsg});
81
+ respond(code, { error: errorMsg });
82
82
  }
83
83
  });
84
84
 
@@ -89,8 +89,10 @@ export async function handleBroadcastTransaction({ msbInstance, respond, req })
89
89
  }
90
90
 
91
91
  export async function handleTxHashes({ msbInstance, respond, req }) {
92
- const startSignedLengthStr = req.url.split('/')[3];
93
- const endSignedLengthStr = req.url.split('/')[4];
92
+ const url = buildRequestUrl(req);
93
+ const pathParts = url.pathname.split('/').filter(Boolean);
94
+ const startSignedLengthStr = pathParts[2];
95
+ const endSignedLengthStr = pathParts[3];
94
96
 
95
97
  const startSignedLength = parseInt(startSignedLengthStr);
96
98
  const endSignedLength = parseInt(endSignedLengthStr);
@@ -120,7 +122,7 @@ export async function handleTxHashes({ msbInstance, respond, req }) {
120
122
 
121
123
  // 5. Adjust the end index to not exceed the confirmed length.
122
124
  const adjustedEndLength = Math.min(endSignedLength, currentConfirmedLength)
123
-
125
+
124
126
  // 6. Fetch txs hashes for the adjusted range, assuming the command takes start and end index.
125
127
  const commandString = `/get_txs_hashes ${startSignedLength} ${adjustedEndLength}`;
126
128
  const { hashes } = await msbInstance.handleCommand(commandString);
@@ -128,16 +130,21 @@ export async function handleTxHashes({ msbInstance, respond, req }) {
128
130
  }
129
131
 
130
132
  export async function handleUnconfirmedLength({ msbInstance, respond }) {
133
+ // TODO: VALIDATION?
131
134
  const commandString = '/unconfirmed_length';
132
135
  const unconfirmed_length = await msbInstance.handleCommand(commandString);
133
136
  respond(200, { unconfirmed_length });
134
137
  }
135
138
 
136
139
  export async function handleTransactionDetails({ msbInstance, respond, req }) {
137
- const hash = req.url.split('/')[3];
140
+ // TODO: VALIDATION?
141
+ const url = buildRequestUrl(req);
142
+ const pathParts = url.pathname.split('/').filter(Boolean);
143
+ const hash = pathParts[2];
144
+
138
145
  const commandString = `/get_tx_details ${hash}`;
139
146
  const txDetails = await msbInstance.handleCommand(commandString);
140
- respond(txDetails === null ? 404 : 200 , { txDetails });
147
+ respond(txDetails === null ? 404 : 200, { txDetails });
141
148
  }
142
149
 
143
150
  export async function handleFetchBulkTxPayloads({ msbInstance, respond, req }) {
@@ -150,9 +157,9 @@ export async function handleFetchBulkTxPayloads({ msbInstance, respond, req }) {
150
157
  if (headersSent) return; // Stop processing if response has started/errored
151
158
 
152
159
  bytesRead += chunk.length;
153
- if (bytesRead > limitBytes) {
160
+ if (bytesRead > limitBytes) {
154
161
  respond(413, { error: 'Request body too large.' });
155
- headersSent = true;
162
+ headersSent = true;
156
163
  req.destroy(); // Stop receiving data (GOOD PRACTICE)
157
164
  return;
158
165
  }
@@ -164,16 +171,16 @@ export async function handleFetchBulkTxPayloads({ msbInstance, respond, req }) {
164
171
 
165
172
 
166
173
  try {
167
- if (body === null || body === ''){
174
+ if (body === null || body === '') {
168
175
  return respond(400, { error: 'Missing payload.' });
169
176
  }
170
177
 
171
178
  const sanitizedPayload = sanitizeBulkPayloadsRequestBody(body);
172
179
 
173
- if (sanitizedPayload === null){
180
+ if (sanitizedPayload === null) {
174
181
  return respond(400, { error: 'Invalid payload.' });
175
182
  }
176
-
183
+
177
184
  const { hashes } = sanitizedPayload;
178
185
 
179
186
  if (!Array.isArray(hashes) || hashes.length === 0) {
@@ -186,11 +193,11 @@ export async function handleFetchBulkTxPayloads({ msbInstance, respond, req }) {
186
193
 
187
194
  const uniqueHashes = [...new Set(hashes)];
188
195
 
189
- const commandResult = await msbInstance.handleCommand( `/get_tx_payloads_bulk`, null, uniqueHashes)
196
+ const commandResult = await msbInstance.handleCommand(`/get_tx_payloads_bulk`, null, uniqueHashes)
190
197
 
191
198
  const responseString = JSON.stringify(commandResult);
192
199
  if (Buffer.byteLength(responseString, 'utf8') > 2_000_000) {
193
- return respond(413, { error: 'Response too large. Reduce number of hashes.'});
200
+ return respond(413, { error: 'Response too large. Reduce number of hashes.' });
194
201
  }
195
202
 
196
203
  return respond(200, commandResult);
@@ -209,29 +216,23 @@ export async function handleFetchBulkTxPayloads({ msbInstance, respond, req }) {
209
216
  }
210
217
 
211
218
  export async function handleTransactionExtendedDetails({ msbInstance, respond, req }) {
212
- const [path, queryString] = req.url.split("?");
213
- const pathParts = path.split('/');
214
- const hash = pathParts[4];
215
-
219
+ const url = buildRequestUrl(req);
220
+ const pathParts = url.pathname.split('/').filter(Boolean);
221
+ const hash = pathParts[3];
222
+
216
223
  if (!hash) {
217
224
  return respond(400, { error: "Transaction hash is required" });
218
225
  }
219
-
226
+
220
227
  if (isHexString(hash) === false || hash.length !== 64) {
221
228
  return respond(400, { error: "Invalid transaction hash format" });
222
229
  }
223
- let confirmed = true; // default
224
- if (queryString) {
225
- const params = new URLSearchParams(queryString);
226
- if (params.has("confirmed")) {
227
- const confirmedParam = params.get("confirmed");
228
- if (confirmedParam !== "true" && confirmedParam !== "false") {
229
- return respond(400, { error: 'Parameter "confirmed" must be exactly "true" or "false"' });
230
- }
231
- confirmed = confirmedParam === "true";
232
- }
230
+
231
+ const confirmed = getConfirmedParameter(url);
232
+ if (confirmed === null) {
233
+ return respond(400, { error: 'Parameter "confirmed" must be exactly "true" or "false"' });
233
234
  }
234
-
235
+
235
236
  try {
236
237
  let txDetails;
237
238
  const commandString = `/get_extended_tx_details ${hash} ${confirmed}`;
@@ -249,4 +250,53 @@ export async function handleTransactionExtendedDetails({ msbInstance, respond, r
249
250
  respond(500, { error: 'An error occurred processing the request.' });
250
251
  }
251
252
  }
252
- }
253
+ }
254
+
255
+ export async function handleAccountDetails({ msbInstance, respond, req }) {
256
+ const url = buildRequestUrl(req);
257
+ const address = url.pathname.split('/').filter(Boolean)[2];
258
+
259
+ if (!address) {
260
+ return respond(400, { error: "Account address is required" });
261
+ }
262
+
263
+ const confirmed = getConfirmedParameter(url);
264
+ if (confirmed === null) {
265
+ return respond(400, { error: 'Parameter "confirmed" must be exactly "true" or "false"' });
266
+ }
267
+
268
+ if (!isAddressValid(address)) {
269
+ return respond(400, { error: "Invalid account address format" });
270
+ }
271
+
272
+ const defaultAccountState = {
273
+ address,
274
+ writingKey: ZERO_WK.toString('hex'),
275
+ isWhitelisted: false,
276
+ isValidator: false,
277
+ isIndexer: false,
278
+ license: null,
279
+ balance: '0',
280
+ stakedBalance: '0',
281
+ };
282
+
283
+ const nodeEntry = confirmed
284
+ ? await msbInstance.state.getNodeEntry(address)
285
+ : await msbInstance.state.getNodeEntryUnsigned(address);
286
+ if (!nodeEntry) {
287
+ return respond(200, defaultAccountState);
288
+ }
289
+
290
+ const licenseValue = licenseBufferToBigInt(nodeEntry.license);
291
+
292
+ return respond(200, {
293
+ ...defaultAccountState,
294
+ writingKey: nodeEntry.wk.toString('hex'),
295
+ isWhitelisted: nodeEntry.isWhitelisted,
296
+ isValidator: nodeEntry.isWriter,
297
+ isIndexer: nodeEntry.isIndexer,
298
+ license: licenseValue === 0n ? null : licenseValue.toString(),
299
+ balance: bufferToBigInt(nodeEntry.balance).toString(),
300
+ stakedBalance: bufferToBigInt(nodeEntry.stakedBalance).toString(),
301
+ });
302
+ }
package/rpc/routes/v1.mjs CHANGED
@@ -8,7 +8,8 @@ import {
8
8
  handleUnconfirmedLength,
9
9
  handleTransactionDetails,
10
10
  handleFetchBulkTxPayloads,
11
- handleTransactionExtendedDetails
11
+ handleTransactionExtendedDetails,
12
+ handleAccountDetails
12
13
  } from '../handlers.mjs';
13
14
 
14
15
  export const v1Routes = [
@@ -22,4 +23,5 @@ export const v1Routes = [
22
23
  { method: 'GET', path: '/tx', handler: handleTransactionDetails },
23
24
  { method: 'POST', path: '/tx-payloads-bulk', handler: handleFetchBulkTxPayloads },
24
25
  { method: 'GET', path: '/tx/details', handler: handleTransactionExtendedDetails },
26
+ { method: 'GET', path: '/account', handler: handleAccountDetails },
25
27
  ];
@@ -0,0 +1,17 @@
1
+ export function getConfirmedParameter(url, { defaultValue = true } = {}) {
2
+ const confirmedParam = url.searchParams.get("confirmed");
3
+
4
+ if (confirmedParam === null) {
5
+ return defaultValue;
6
+ }
7
+
8
+ if (confirmedParam === "true") {
9
+ return true;
10
+ }
11
+
12
+ if (confirmedParam === "false") {
13
+ return false;
14
+ }
15
+
16
+ return null;
17
+ }
@@ -0,0 +1,38 @@
1
+ const HOST_HEADER_PATTERN = /^[\[\]A-Za-z0-9:.-]+(:\d{1,5})?$/;
2
+
3
+ const isValidHostHeader = (hostHeader) => {
4
+ if (!hostHeader) return false;
5
+ if (hostHeader.length > 255) return false;
6
+ const trimmed = hostHeader.trim();
7
+
8
+ if (/[\/\\\s]/.test(trimmed)) return false;
9
+
10
+ return HOST_HEADER_PATTERN.test(trimmed);
11
+ };
12
+
13
+ const socketAddressToHost = (address, port) => {
14
+ if (!address) return null;
15
+ const needsBrackets = address.includes(':') && !address.startsWith('[');
16
+ const host = needsBrackets ? `[${address}]` : address;
17
+ return port ? `${host}:${port}` : host;
18
+ };
19
+
20
+ const detectProtocol = (req) => {
21
+ const forwardedProto = req?.headers?.['x-forwarded-proto'];
22
+ if (forwardedProto === 'https') return 'https';
23
+ if (forwardedProto === 'http') return 'http';
24
+
25
+ if (req?.socket?.encrypted) return 'https';
26
+
27
+ return 'http';
28
+ };
29
+
30
+ export const buildRequestUrl = (req) => {
31
+ const safeHost = isValidHostHeader(req?.headers?.host)
32
+ ? req.headers.host.trim()
33
+ : socketAddressToHost(req?.socket?.localAddress, req?.socket?.localPort);
34
+
35
+ const protocol = detectProtocol(req);
36
+ const base = safeHost ? `${protocol}://${safeHost}` : `${protocol}://localhost`;
37
+ return new URL(req?.url || '/', base);
38
+ };
@@ -17,7 +17,7 @@ import {
17
17
  DHT_BOOTSTRAPS
18
18
  } from '../../utils/constants.js';
19
19
  import ConnectionManager from './services/ConnectionManager.js';
20
-
20
+ import NetworkWalletFactory from './identity/NetworkWalletFactory.js';
21
21
  const wakeup = new w();
22
22
 
23
23
  class Network extends ReadyResource {
@@ -29,15 +29,18 @@ class Network extends ReadyResource {
29
29
  #transactionPoolService;
30
30
  #validatorObserverService;
31
31
  #validatorConnectionManager;
32
+ #options;
33
+ #identityProvider = null;
32
34
 
33
35
  constructor(state, channel, address = null, options = {}) {
34
36
  super();
37
+ this.#options = options;
35
38
  this.#enable_wallet = options.enable_wallet !== false;
36
39
  this.#channel = channel;
37
40
  this.#transactionPoolService = new TransactionPoolService(state, address, options);
38
- this.#validatorObserverService = new ValidatorObserverService(this, state, address, options)
41
+ this.#validatorObserverService = new ValidatorObserverService(this, state, address, options);
39
42
  this.#networkMessages = new NetworkMessages(this, options);
40
- this.#validatorConnectionManager = new ConnectionManager({ maxValidators: options.max_validators })
43
+ this.#validatorConnectionManager = new ConnectionManager({ maxValidators: options.max_validators });
41
44
  this.admin_stream = null;
42
45
  this.admin = null;
43
46
  this.validator = null;
@@ -90,6 +93,7 @@ class Network extends ReadyResource {
90
93
  ) {
91
94
  if (!this.#swarm) {
92
95
  const keyPair = await this.initializeNetworkingKeyPair(store, wallet);
96
+ const wrappedWallet = this.#getNetworkWalletWrapper(wallet, keyPair);
93
97
  this.#swarm = new Hyperswarm({
94
98
  keyPair,
95
99
  bootstrap: this.#dht_bootstrap,
@@ -100,7 +104,7 @@ class Network extends ReadyResource {
100
104
  });
101
105
 
102
106
  console.log(`Channel: ${b4a.toString(this.#channel)}`);
103
- this.#networkMessages.initializeMessageRouter(state, wallet);
107
+ this.#networkMessages.initializeMessageRouter(state, wrappedWallet);
104
108
 
105
109
  this.#swarm.on('connection', async (connection) => {
106
110
  const { message_channel, message } = await this.#networkMessages.setupProtomuxMessages(connection);
@@ -120,7 +124,7 @@ class Network extends ReadyResource {
120
124
  this.custom_stream = null;
121
125
  this.custom_node = null;
122
126
  }
123
- try{ message_channel.close() }catch(e){}
127
+ try { message_channel.close() } catch (e) { }
124
128
 
125
129
  });
126
130
 
@@ -129,7 +133,7 @@ class Network extends ReadyResource {
129
133
  error && error.message && (
130
134
  error.message.includes('connection reset by peer') ||
131
135
  error.message.includes('Duplicate connection') ||
132
- error.message.includes('connection timed out') )
136
+ error.message.includes('connection timed out'))
133
137
  ) {
134
138
  // TODO: decide if we want to handle this error in a specific way. It generates a lot of logs.
135
139
  return;
@@ -168,11 +172,11 @@ class Network extends ReadyResource {
168
172
  cnt += 1;
169
173
  }
170
174
  }
171
-
175
+
172
176
  if (this.#swarm.peers.has(publicKey)) {
173
177
  let stream;
174
178
  const peerInfo = this.#swarm.peers.get(publicKey)
175
- stream = this.#swarm._allConnections.get(peerInfo.publicKey)
179
+ stream = this.#swarm._allConnections.get(peerInfo.publicKey)
176
180
  if (stream !== undefined && stream.messenger !== undefined) {
177
181
  if (type === 'validator') {
178
182
  this.#validatorConnectionManager.addValidator(b4a.from(publicKey, 'hex'), stream)
@@ -183,8 +187,8 @@ class Network extends ReadyResource {
183
187
  }
184
188
 
185
189
  async isConnected(publicKey) {
186
- return this.#swarm.peers.has(publicKey) &&
187
- this.#swarm.peers.get(publicKey).connectedTime != -1
190
+ return this.#swarm.peers.has(publicKey) &&
191
+ this.#swarm.peers.get(publicKey).connectedTime != -1
188
192
  }
189
193
 
190
194
  async #sendRequestByType(stream, type) {
@@ -239,6 +243,19 @@ class Network extends ReadyResource {
239
243
  console.log(e)
240
244
  }
241
245
  }
246
+
247
+ #getNetworkWalletWrapper(wallet, keyPair) {
248
+ if (!this.#identityProvider) {
249
+ this.#identityProvider = NetworkWalletFactory.provide({
250
+ enableWallet: this.#enable_wallet,
251
+ wallet,
252
+ keyPair,
253
+ networkPrefix: this.#options?.networkPrefix
254
+ });
255
+ }
256
+ return this.#identityProvider;
257
+ }
258
+
242
259
  }
243
260
 
244
261
  export default Network;
@@ -0,0 +1,78 @@
1
+ import PeerWallet from 'trac-wallet';
2
+ import { TRAC_NETWORK_MSB_MAINNET_PREFIX } from 'trac-wallet/constants.js';
3
+ import b4a from 'b4a';
4
+
5
+ export class NetworkWalletFactory {
6
+ static provide(options = {}) {
7
+ const {
8
+ enableWallet = true,
9
+ wallet,
10
+ keyPair,
11
+ networkPrefix = TRAC_NETWORK_MSB_MAINNET_PREFIX
12
+ } = options;
13
+
14
+ if (enableWallet) {
15
+ if (!wallet) {
16
+ throw new Error('NetworkingWalletFactory: wallet instance is required when wallet is enabled');
17
+ }
18
+ return wallet;
19
+ }
20
+
21
+ if (!keyPair) {
22
+ throw new Error('NetworkingWalletFactory: keyPair must be provided when wallet is disabled');
23
+ }
24
+
25
+ return new EphemeralWallet(keyPair, networkPrefix);
26
+ }
27
+ }
28
+
29
+ // TODO: Once Wallet class in trac-wallet exposes a constructor/factory that accepts an existing keyPair
30
+ // (e.g. Wallet.fromKeyPair({ publicKey, secretKey }, networkPrefix)), replace EphemeralWallet
31
+ // with a thin wrapper around that functionality instead of duplicating signing/verification logic.
32
+ class EphemeralWallet {
33
+ #publicKey;
34
+ #secretKey;
35
+ #address;
36
+
37
+ constructor(keyPair, networkPrefix = TRAC_NETWORK_MSB_MAINNET_PREFIX) {
38
+
39
+ if (!keyPair?.publicKey || !keyPair?.secretKey) {
40
+ throw new Error('NetworkIdentityProvider: keyPair with publicKey and secretKey is required');
41
+ }
42
+ this.#assertBuffer(keyPair.publicKey);
43
+ this.#assertBuffer(keyPair.secretKey);
44
+
45
+ const address = PeerWallet.encodeBech32m(networkPrefix, keyPair.publicKey);
46
+ if (!address) {
47
+ throw new Error('NetworkIdentityProvider: failed to derive address from networking key pair');
48
+ }
49
+
50
+ this.#publicKey = keyPair.publicKey;
51
+ this.#secretKey = keyPair.secretKey;
52
+ this.#address = address;
53
+ }
54
+
55
+ get publicKey() {
56
+ return this.#publicKey;
57
+ }
58
+
59
+ get address() {
60
+ return this.#address;
61
+ }
62
+
63
+ sign(message) {
64
+ return PeerWallet.sign(message, this.#secretKey);
65
+ }
66
+
67
+ verify(signature, message, publicKey = this.#publicKey) {
68
+ return PeerWallet.verify(signature, message, publicKey);
69
+ }
70
+
71
+ #assertBuffer(value) {
72
+ if (!b4a.isBuffer(value)) {
73
+ throw new Error(`NetworkIdentityProvider: value must be a Buffer`);
74
+ }
75
+ }
76
+ }
77
+
78
+ export default NetworkWalletFactory;
@@ -1,4 +1,4 @@
1
- import { MAX_VALIDATORS } from "../../../utils/constants.js"
1
+ import { MAX_VALIDATORS, MAX_REQUEST_COUNT } from "../../../utils/constants.js"
2
2
  import b4a from 'b4a'
3
3
  import PeerWallet from "trac-wallet"
4
4
  import { TRAC_NETWORK_MSB_MAINNET_PREFIX } from 'trac-wallet/constants.js';
@@ -19,7 +19,7 @@ class ConnectionManager {
19
19
  }
20
20
 
21
21
  send(message, retries = 3) {
22
- if (this.#requestCount >= 10) {
22
+ if (this.#requestCount >= MAX_REQUEST_COUNT) {
23
23
  this.#requestCount = 0
24
24
  this.#updateNext()
25
25
  }
@@ -10,7 +10,6 @@ const DELAY_INTERVAL = 250
10
10
 
11
11
  class ValidatorObserverService {
12
12
  #enable_validator_observer;
13
- #enable_wallet;
14
13
  #state;
15
14
  #network;
16
15
  #scheduler;
@@ -18,7 +17,7 @@ class ValidatorObserverService {
18
17
  #isInterrupted
19
18
 
20
19
  constructor(network, state, address, options = {}) {
21
- this.#enable_wallet = options.enable_wallet !== false;
20
+ this.#enable_validator_observer = options.enable_validator_observer !== false;
22
21
  this.#network = network;
23
22
  this.#state = state;
24
23
  this.#address = address;
@@ -34,7 +33,7 @@ class ValidatorObserverService {
34
33
  // OS CALLS, ACCUMULATORS, MAYBE THIS IS POSSIBLE TO CHECK I/O QUEUE IF IT COINTAIN IT. FOR NOW WE ARE USING SLEEP.
35
34
  async start() {
36
35
  if (!this.#shouldRun()) {
37
- console.info('ValidatorObserverService can not start. Wallet is not enabled');
36
+ console.info('ValidatorObserverService can not start. Disabled by configuration.');
38
37
  return;
39
38
  }
40
39
  if (this.#scheduler && this.#scheduler.isRunning) {
@@ -111,7 +110,11 @@ class ValidatorObserverService {
111
110
  };
112
111
 
113
112
  #shouldRun() {
114
- return this.#enable_wallet && !this.#isInterrupted
113
+ if (!this.#enable_validator_observer || this.#isInterrupted) {
114
+ return false;
115
+ }
116
+
117
+ return true;
115
118
  }
116
119
 
117
120
  async #lengthEntry() {