trac-msb 0.2.4 → 0.2.6

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 (239) 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 +12 -14
  10. package/package.json +8 -4
  11. package/rpc/constants.mjs +4 -1
  12. package/rpc/handlers.mjs +109 -66
  13. package/rpc/routes/v1.mjs +3 -1
  14. package/rpc/rpc_services.js +126 -0
  15. package/rpc/utils/confirmedParameter.mjs +17 -0
  16. package/rpc/utils/url.mjs +38 -0
  17. package/src/core/network/Network.js +27 -10
  18. package/src/core/network/identity/NetworkWalletFactory.js +78 -0
  19. package/src/core/network/services/ConnectionManager.js +2 -2
  20. package/src/core/network/services/ValidatorObserverService.js +7 -4
  21. package/src/core/state/State.js +28 -22
  22. package/src/index.js +197 -385
  23. package/src/utils/cliCommands.js +280 -0
  24. package/src/utils/constants.js +3 -1
  25. package/tests/acceptance/v1/account/account.test.mjs +123 -0
  26. package/tests/acceptance/v1/balance/balance.test.mjs +55 -0
  27. package/tests/acceptance/v1/broadcast-transaction/broadcast-transaction.test.mjs +111 -0
  28. package/tests/acceptance/v1/confirmed-length/confirmed-length.test.mjs +19 -0
  29. package/tests/acceptance/v1/fee/fee.test.mjs +11 -0
  30. package/tests/acceptance/v1/rpc.test.mjs +62 -291
  31. package/tests/acceptance/v1/tx/tx.test.mjs +98 -0
  32. package/tests/acceptance/v1/tx-details/tx-details.test.mjs +195 -0
  33. package/tests/acceptance/v1/tx-hashes/tx-hashes.test.mjs +72 -0
  34. package/tests/acceptance/v1/tx-payloads-bulk/tx-payloads-bulk.test.mjs +27 -0
  35. package/tests/acceptance/v1/txv/txv.test.mjs +11 -0
  36. package/tests/acceptance/v1/unconfirmed-length/unconfirmed-length.test.mjs +11 -0
  37. package/tests/helpers/StateNetworkFactory.js +157 -0
  38. package/tests/helpers/autobaseTestHelpers.js +369 -0
  39. package/tests/helpers/createTestSignature.js +12 -0
  40. package/tests/helpers/transactionPayloads.mjs +78 -0
  41. package/tests/unit/network/NetworkWalletFactory.test.js +156 -0
  42. package/tests/unit/state/apply/addAdmin/addAdminHappyPathScenario.js +38 -0
  43. package/tests/unit/state/apply/addAdmin/addAdminScenarioHelpers.js +273 -0
  44. package/tests/unit/state/apply/addAdmin/adminEntryEncodingFailureScenario.js +30 -0
  45. package/tests/unit/state/apply/addAdmin/adminEntryExistsScenario.js +78 -0
  46. package/tests/unit/state/apply/addAdmin/nodeEntryInitializationFailureScenario.js +30 -0
  47. package/tests/unit/state/apply/addAdmin/nonBootstrapNodeScenario.js +68 -0
  48. package/tests/unit/state/apply/addAdmin/state.apply.addAdmin.test.js +155 -0
  49. package/tests/unit/state/apply/addIndexer/addIndexerHappyPathScenario.js +39 -0
  50. package/tests/unit/state/apply/addIndexer/addIndexerMultipleIndexersInTheNetworkScenario.js +167 -0
  51. package/tests/unit/state/apply/addIndexer/addIndexerPretenderAlreadyIndexerScenario.js +21 -0
  52. package/tests/unit/state/apply/addIndexer/addIndexerPretenderNotWriterScenario.js +21 -0
  53. package/tests/unit/state/apply/addIndexer/addIndexerRemoveAndReAddScenario.js +186 -0
  54. package/tests/unit/state/apply/addIndexer/addIndexerScenarioHelpers.js +445 -0
  55. package/tests/unit/state/apply/addIndexer/addIndexerWriterKeyAlreadyRegisteredScenario.js +32 -0
  56. package/tests/unit/state/apply/addIndexer/state.apply.addIndexer.test.js +297 -0
  57. package/tests/unit/state/apply/addWriter/addWriterHappyPathScenario.js +41 -0
  58. package/tests/unit/state/apply/addWriter/addWriterInvalidValidatorSignatureScenario.js +32 -0
  59. package/tests/unit/state/apply/addWriter/addWriterNewWkScenario.js +149 -0
  60. package/tests/unit/state/apply/addWriter/addWriterRequesterAlreadyWriterScenario.js +21 -0
  61. package/tests/unit/state/apply/addWriter/addWriterRequesterBalanceInsufficientScenario.js +21 -0
  62. package/tests/unit/state/apply/addWriter/addWriterRequesterEntryDecodeFailureScenario.js +19 -0
  63. package/tests/unit/state/apply/addWriter/addWriterRequesterEntryMissingScenario.js +19 -0
  64. package/tests/unit/state/apply/addWriter/addWriterRequesterIndexerScenario.js +21 -0
  65. package/tests/unit/state/apply/addWriter/addWriterRequesterNotWhitelistedScenario.js +21 -0
  66. package/tests/unit/state/apply/addWriter/addWriterScenarioHelpers.js +757 -0
  67. package/tests/unit/state/apply/addWriter/addWriterStakeBalanceUpdateFailureScenario.js +50 -0
  68. package/tests/unit/state/apply/addWriter/addWriterStakeInsufficientBalanceScenario.js +29 -0
  69. package/tests/unit/state/apply/addWriter/addWriterStakeInvalidBalanceScenario.js +29 -0
  70. package/tests/unit/state/apply/addWriter/addWriterStakeInvalidEntryScenario.js +21 -0
  71. package/tests/unit/state/apply/addWriter/addWriterStakeStakedBalanceFailureScenario.js +37 -0
  72. package/tests/unit/state/apply/addWriter/addWriterStakeSubtractFailureScenario.js +42 -0
  73. package/tests/unit/state/apply/addWriter/addWriterValidatorRewardScenario.js +105 -0
  74. package/tests/unit/state/apply/addWriter/addWriterWriterKeyMismatchScenario.js +54 -0
  75. package/tests/unit/state/apply/addWriter/addWriterWriterKeyOwnershipScenario.js +54 -0
  76. package/tests/unit/state/apply/addWriter/addWriterZeroWriterKeyScenario.js +29 -0
  77. package/tests/unit/state/apply/addWriter/state.apply.addWriter.test.js +309 -0
  78. package/tests/unit/state/apply/adminRecovery/adminRecoveryHappyPathScenario.js +30 -0
  79. package/tests/unit/state/apply/adminRecovery/adminRecoveryScenarioHelpers.js +866 -0
  80. package/tests/unit/state/apply/adminRecovery/state.apply.adminRecovery.test.js +439 -0
  81. package/tests/unit/state/apply/appendWhitelist/appendWhitelistBanAndReapplyScenario.js +78 -0
  82. package/tests/unit/state/apply/appendWhitelist/appendWhitelistExistingReaderHappyPathScenario.js +98 -0
  83. package/tests/unit/state/apply/appendWhitelist/appendWhitelistFeeAfterDisableScenario.js +66 -0
  84. package/tests/unit/state/apply/appendWhitelist/appendWhitelistHappyPathScenario.js +55 -0
  85. package/tests/unit/state/apply/appendWhitelist/appendWhitelistInsufficientAdminBalanceScenario.js +103 -0
  86. package/tests/unit/state/apply/appendWhitelist/appendWhitelistNodeAlreadyWhitelistedScenario.js +60 -0
  87. package/tests/unit/state/apply/appendWhitelist/appendWhitelistScenarioHelpers.js +191 -0
  88. package/tests/unit/state/apply/appendWhitelist/state.apply.appendWhitelist.test.js +220 -0
  89. package/tests/unit/state/apply/balanceInitialization/balanceInitializationHappyPathScenario.js +82 -0
  90. package/tests/unit/state/apply/balanceInitialization/balanceInitializationScenarioHelpers.js +106 -0
  91. package/tests/unit/state/apply/balanceInitialization/invalidAmountScenario.js +45 -0
  92. package/tests/unit/state/apply/balanceInitialization/nodeEntryBalanceUpdateFailureScenario.js +81 -0
  93. package/tests/unit/state/apply/balanceInitialization/state.apply.balanceInitialization.test.js +189 -0
  94. package/tests/unit/state/apply/banValidator/banValidatorBanAndReWhitelistScenario.js +155 -0
  95. package/tests/unit/state/apply/banValidator/banValidatorHappyPathScenario.js +36 -0
  96. package/tests/unit/state/apply/banValidator/banValidatorScenarioHelpers.js +534 -0
  97. package/tests/unit/state/apply/banValidator/banValidatorSequentialBansScenario.js +74 -0
  98. package/tests/unit/state/apply/banValidator/banValidatorTargetDecodeFailureScenario.js +19 -0
  99. package/tests/unit/state/apply/banValidator/banValidatorTargetIndexerScenario.js +32 -0
  100. package/tests/unit/state/apply/banValidator/banValidatorTargetNodeEntryMissingScenario.js +19 -0
  101. package/tests/unit/state/apply/banValidator/banValidatorTargetRoleUpdateFailureScenario.js +19 -0
  102. package/tests/unit/state/apply/banValidator/banValidatorWhitelistedNonWriterScenario.js +38 -0
  103. package/tests/unit/state/apply/banValidator/banValidatorWhitelistedZeroBalanceScenario.js +91 -0
  104. package/tests/unit/state/apply/banValidator/banValidatorWithdrawFailureScenario.js +19 -0
  105. package/tests/unit/state/apply/banValidator/state.apply.banValidator.test.js +266 -0
  106. package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentDuplicateRegistrationScenario.js +142 -0
  107. package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentHappyPathScenario.js +26 -0
  108. package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentIncompleteOperationScenario.js +94 -0
  109. package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentInvalidDeploymentEntryScenario.js +37 -0
  110. package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentMultipleBootstrapScenario.js +86 -0
  111. package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentScenarioHelpers.js +344 -0
  112. package/tests/unit/state/apply/bootstrapDeployment/invalidValidatorNodeEntryScenario.js +57 -0
  113. package/tests/unit/state/apply/bootstrapDeployment/state.apply.bootstrapDeployment.test.js +429 -0
  114. package/tests/unit/state/apply/common/access-control/adminConsistencyMismatchScenario.js +119 -0
  115. package/tests/unit/state/apply/common/access-control/adminEntryDecodeFailureScenario.js +130 -0
  116. package/tests/unit/state/apply/common/access-control/adminEntryExistsScenario.js +93 -0
  117. package/tests/unit/state/apply/common/access-control/adminEntryMissingScenario.js +108 -0
  118. package/tests/unit/state/apply/common/access-control/adminOnlyGuardScenario.js +126 -0
  119. package/tests/unit/state/apply/common/access-control/adminPublicKeyDecodeFailureScenario.js +120 -0
  120. package/tests/unit/state/apply/common/access-control/roleAccessOperationValidationScenario.js +50 -0
  121. package/tests/unit/state/apply/common/adminControlOperationValidationScenario.js +56 -0
  122. package/tests/unit/state/apply/common/balances/adminEntryUpdateFailureScenario.js +52 -0
  123. package/tests/unit/state/apply/common/balances/base/requesterBalanceScenarioBase.js +197 -0
  124. package/tests/unit/state/apply/common/balances/feeDecodeFailureScenario.js +52 -0
  125. package/tests/unit/state/apply/common/balances/requesterBalanceDecodeFailureScenario.js +15 -0
  126. package/tests/unit/state/apply/common/balances/requesterBalanceFeeApplicationFailureScenario.js +11 -0
  127. package/tests/unit/state/apply/common/balances/requesterBalanceInsufficientScenario.js +15 -0
  128. package/tests/unit/state/apply/common/balances/requesterBalanceUpdateFailureScenario.js +11 -0
  129. package/tests/unit/state/apply/common/balances/validatorEntryRewardFailureScenario.js +11 -0
  130. package/tests/unit/state/apply/common/balances/validatorEntryUpdateFailureScenario.js +11 -0
  131. package/tests/unit/state/apply/common/balances/validatorNodeEntryDecodeFailureScenario.js +40 -0
  132. package/tests/unit/state/apply/common/base/OperationValidationScenarioBase.js +114 -0
  133. package/tests/unit/state/apply/common/commonScenarioHelper.js +103 -0
  134. package/tests/unit/state/apply/common/indexer/indexerNodeEntryDecodeFailureScenario.js +36 -0
  135. package/tests/unit/state/apply/common/indexer/indexerNodeEntryMissingScenario.js +36 -0
  136. package/tests/unit/state/apply/common/indexer/indexerRoleUpdateFailureScenario.js +29 -0
  137. package/tests/unit/state/apply/common/indexer/indexerSequenceStateInvalidScenario.js +66 -0
  138. package/tests/unit/state/apply/common/invalidMessageComponentValidationScenario.js +84 -0
  139. package/tests/unit/state/apply/common/nodeEntryInitializationFailureScenario.js +47 -0
  140. package/tests/unit/state/apply/common/operationAlreadyAppliedScenario.js +85 -0
  141. package/tests/unit/state/apply/common/payload-structure/addressWithInvalidPublicKeyScenario.js +52 -0
  142. package/tests/unit/state/apply/common/payload-structure/initializationDisabledScenario.js +49 -0
  143. package/tests/unit/state/apply/common/payload-structure/invalidAddressValidationScenario.js +73 -0
  144. package/tests/unit/state/apply/common/payload-structure/invalidHashValidationScenario.js +71 -0
  145. package/tests/unit/state/apply/common/payload-structure/invalidPayloadValidationScenario.js +31 -0
  146. package/tests/unit/state/apply/common/payload-structure/invalidSignatureValidationScenario.js +142 -0
  147. package/tests/unit/state/apply/common/payload-structure/partialOperationValidationScenario.js +87 -0
  148. package/tests/unit/state/apply/common/requester/requesterNodeEntryBufferMissingScenario.js +70 -0
  149. package/tests/unit/state/apply/common/requester/requesterNodeEntryDecodeFailureScenario.js +72 -0
  150. package/tests/unit/state/apply/common/requester/requesterNodeEntryMissingScenario.js +36 -0
  151. package/tests/unit/state/apply/common/requesterAddressValidationScenario.js +44 -0
  152. package/tests/unit/state/apply/common/requesterPublicKeyValidationScenario.js +25 -0
  153. package/tests/unit/state/apply/common/transactionValidityMismatchScenario.js +98 -0
  154. package/tests/unit/state/apply/common/validatorConsistency/base/validatorConsistencyScenarioBase.js +201 -0
  155. package/tests/unit/state/apply/common/validatorConsistency/validatorEntryDecodeFailureScenario.js +17 -0
  156. package/tests/unit/state/apply/common/validatorConsistency/validatorEntryMissingScenario.js +44 -0
  157. package/tests/unit/state/apply/common/validatorConsistency/validatorInactiveScenario.js +19 -0
  158. package/tests/unit/state/apply/common/validatorConsistency/validatorWriterKeyMismatchScenario.js +18 -0
  159. package/tests/unit/state/apply/common/validatorEntryValidation/base/validatorEntryValidationScenarioBase.js +314 -0
  160. package/tests/unit/state/apply/common/validatorEntryValidation/validatorEntryInvalidBalanceScenario.js +18 -0
  161. package/tests/unit/state/apply/common/writerKeyExistsValidationScenario.js +43 -0
  162. package/tests/unit/state/apply/disableInitialization/disableInitializationAlreadyDisabledScenario.js +53 -0
  163. package/tests/unit/state/apply/disableInitialization/disableInitializationHappyPathScenario.js +24 -0
  164. package/tests/unit/state/apply/disableInitialization/disableInitializationScenarioHelpers.js +197 -0
  165. package/tests/unit/state/apply/disableInitialization/state.apply.disableInitialization.test.js +161 -0
  166. package/tests/unit/state/apply/missing-tests.md +18 -0
  167. package/tests/unit/state/apply/removeIndexer/removeIndexerHappyPathScenario.js +58 -0
  168. package/tests/unit/state/apply/removeIndexer/removeIndexerReAddAndRemoveAgainScenario.js +98 -0
  169. package/tests/unit/state/apply/removeIndexer/removeIndexerRemoveMultipleIndexersScenario.js +167 -0
  170. package/tests/unit/state/apply/removeIndexer/removeIndexerScenarioHelpers.js +428 -0
  171. package/tests/unit/state/apply/removeIndexer/removeIndexerTargetNotIndexerScenario.js +22 -0
  172. package/tests/unit/state/apply/removeIndexer/removeIndexerWriterKeyMissingScenario.js +20 -0
  173. package/tests/unit/state/apply/removeIndexer/state.apply.removeIndexer.test.js +291 -0
  174. package/tests/unit/state/apply/removeWriter/removeWriterAndAddWriterAgainScenario.js +87 -0
  175. package/tests/unit/state/apply/removeWriter/removeWriterHappyPathScenario.js +38 -0
  176. package/tests/unit/state/apply/removeWriter/removeWriterInvalidValidatorSignatureScenario.js +32 -0
  177. package/tests/unit/state/apply/removeWriter/removeWriterRequesterBalanceInsufficientScenario.js +21 -0
  178. package/tests/unit/state/apply/removeWriter/removeWriterRequesterEntryDecodeFailureScenario.js +19 -0
  179. package/tests/unit/state/apply/removeWriter/removeWriterRequesterEntryMissingScenario.js +19 -0
  180. package/tests/unit/state/apply/removeWriter/removeWriterRequesterIndexerScenario.js +21 -0
  181. package/tests/unit/state/apply/removeWriter/removeWriterRequesterNotWriterScenario.js +21 -0
  182. package/tests/unit/state/apply/removeWriter/removeWriterRequesterRoleUpdateFailureScenario.js +19 -0
  183. package/tests/unit/state/apply/removeWriter/removeWriterScenarioHelpers.js +344 -0
  184. package/tests/unit/state/apply/removeWriter/removeWriterThroughWriterValidatorScenario.js +113 -0
  185. package/tests/unit/state/apply/removeWriter/removeWriterUnstakeFailureScenario.js +33 -0
  186. package/tests/unit/state/apply/removeWriter/removeWriterWriterKeyMismatchScenario.js +21 -0
  187. package/tests/unit/state/apply/removeWriter/removeWriterWriterKeyOwnershipScenario.js +26 -0
  188. package/tests/unit/state/apply/removeWriter/removeWriterWriterKeyRegistryMissingScenario.js +22 -0
  189. package/tests/unit/state/apply/removeWriter/state.apply.removeWriter.test.js +307 -0
  190. package/tests/unit/state/apply/state.apply.test.js +24 -0
  191. package/tests/unit/state/apply/transfer/state.apply.transfer.test.js +819 -0
  192. package/tests/unit/state/apply/transfer/transferContractSchemaValidationScenario.js +22 -0
  193. package/tests/unit/state/apply/transfer/transferDoubleSpendAcrossValidatorsScenario.js +137 -0
  194. package/tests/unit/state/apply/transfer/transferDoubleSpendSameBatchScenario.js +63 -0
  195. package/tests/unit/state/apply/transfer/transferDoubleSpendSingleValidatorScenario.js +67 -0
  196. package/tests/unit/state/apply/transfer/transferExistingRecipientAmountScenario.js +31 -0
  197. package/tests/unit/state/apply/transfer/transferExistingRecipientZeroAmountScenario.js +31 -0
  198. package/tests/unit/state/apply/transfer/transferHandlerGuardScenarios.js +22 -0
  199. package/tests/unit/state/apply/transfer/transferHappyPathScenario.js +8 -0
  200. package/tests/unit/state/apply/transfer/transferInvalidIncomingDataScenario.js +66 -0
  201. package/tests/unit/state/apply/transfer/transferNewRecipientAmountScenario.js +31 -0
  202. package/tests/unit/state/apply/transfer/transferNewRecipientZeroAmountScenario.js +31 -0
  203. package/tests/unit/state/apply/transfer/transferScenarioHelpers.js +1167 -0
  204. package/tests/unit/state/apply/transfer/transferSelfTransferAmountScenario.js +38 -0
  205. package/tests/unit/state/apply/transfer/transferSelfTransferZeroAmountScenario.js +38 -0
  206. package/tests/unit/state/apply/transfer/transferValidatorRecipientAmountScenario.js +38 -0
  207. package/tests/unit/state/apply/transfer/transferValidatorRecipientZeroAmountScenario.js +38 -0
  208. package/tests/unit/state/apply/txOperation/state.apply.txOperation.test.js +318 -0
  209. package/tests/unit/state/apply/txOperation/txOperationBootstrapNotRegisteredScenario.js +70 -0
  210. package/tests/unit/state/apply/txOperation/txOperationDifferentValidatorCreatorHappyPathScenario.js +23 -0
  211. package/tests/unit/state/apply/txOperation/txOperationInvalidDeploymentEntryScenario.js +48 -0
  212. package/tests/unit/state/apply/txOperation/txOperationInvalidFeeAmountScenario.js +39 -0
  213. package/tests/unit/state/apply/txOperation/txOperationInvalidSubnetCreatorAddressScenario.js +46 -0
  214. package/tests/unit/state/apply/txOperation/txOperationRequesterCreatorHappyPathScenario.js +21 -0
  215. package/tests/unit/state/apply/txOperation/txOperationScenarioHelpers.js +429 -0
  216. package/tests/unit/state/apply/txOperation/txOperationStandardHappyPathScenario.js +21 -0
  217. package/tests/unit/state/apply/txOperation/txOperationTransferFeeAddCreatorBalanceFailureScenario.js +26 -0
  218. package/tests/unit/state/apply/txOperation/txOperationTransferFeeAddValidatorBalanceFailureScenario.js +25 -0
  219. package/tests/unit/state/apply/txOperation/txOperationTransferFeeAddValidatorBonusFailureScenario.js +27 -0
  220. package/tests/unit/state/apply/txOperation/txOperationTransferFeeDecodeCreatorEntryScenario.js +18 -0
  221. package/tests/unit/state/apply/txOperation/txOperationTransferFeeDecodeRequesterEntryScenario.js +17 -0
  222. package/tests/unit/state/apply/txOperation/txOperationTransferFeeDecodeValidatorEntryScenario.js +31 -0
  223. package/tests/unit/state/apply/txOperation/txOperationTransferFeeGuardBypassScenario.js +49 -0
  224. package/tests/unit/state/apply/txOperation/txOperationTransferFeeGuardScenarioFactory.js +92 -0
  225. package/tests/unit/state/apply/txOperation/txOperationTransferFeeInsufficientRequesterBalanceScenario.js +28 -0
  226. package/tests/unit/state/apply/txOperation/txOperationTransferFeeInvalidCreatorBalanceScenario.js +29 -0
  227. package/tests/unit/state/apply/txOperation/txOperationTransferFeeInvalidRequesterBalanceScenario.js +28 -0
  228. package/tests/unit/state/apply/txOperation/txOperationTransferFeeInvalidRequesterEntryScenario.js +17 -0
  229. package/tests/unit/state/apply/txOperation/txOperationTransferFeeInvalidValidatorBalanceScenario.js +33 -0
  230. package/tests/unit/state/apply/txOperation/txOperationTransferFeeMissingCreatorEntryScenario.js +18 -0
  231. package/tests/unit/state/apply/txOperation/txOperationTransferFeeSubtractFailureScenario.js +25 -0
  232. package/tests/unit/state/apply/txOperation/txOperationTransferFeeUpdateCreatorBalanceFailureScenario.js +26 -0
  233. package/tests/unit/state/apply/txOperation/txOperationTransferFeeUpdateFailureScenario.js +25 -0
  234. package/tests/unit/state/apply/txOperation/txOperationTransferFeeUpdateValidatorBalanceFailureScenario.js +26 -0
  235. package/tests/unit/state/apply/txOperation/txOperationTransferFeeUpdateValidatorBonusFailureScenario.js +27 -0
  236. package/tests/unit/state/apply/txOperation/txOperationValidatorCreatorHappyPathScenario.js +21 -0
  237. package/tests/unit/state/stateModule.test.js +1 -0
  238. package/tests/unit/state/stateTestUtils.js +5 -1
  239. package/.env +0 -3
@@ -0,0 +1,72 @@
1
+ import request from "supertest"
2
+
3
+ export const registerTxHashesTests = (context) => {
4
+ describe("GET /v1/tx-hashes", () => {
5
+ it("< 1000", async () => {
6
+ const res = await request(context.server).get("/v1/tx-hashes/1/1001")
7
+ expect(res.statusCode).toBe(200)
8
+ expect(res.body).toEqual({
9
+ hashes: expect.arrayContaining([
10
+ expect.objectContaining({
11
+ hash: expect.any(String),
12
+ confirmed_length: expect.any(Number),
13
+ })
14
+ ])
15
+ })
16
+ })
17
+
18
+ it("> 1000", async () => {
19
+ const res = await request(context.server).get("/v1/tx-hashes/1/1002")
20
+ expect(res.statusCode).toBe(400)
21
+ })
22
+
23
+ it("returns 400 for non-integer params", async () => {
24
+ const res = await request(context.server).get("/v1/tx-hashes/foo/bar")
25
+ expect(res.statusCode).toBe(400)
26
+ expect(res.body).toEqual({ error: "Params must be integer" })
27
+ })
28
+
29
+ it("returns 400 for negative params", async () => {
30
+ const res = await request(context.server).get("/v1/tx-hashes/-1/10")
31
+ expect(res.statusCode).toBe(400)
32
+ expect(res.body).toEqual({ error: "Params must be non-negative" })
33
+ })
34
+
35
+ it("returns 400 when end < start", async () => {
36
+ const res = await request(context.server).get("/v1/tx-hashes/10/5")
37
+ expect(res.statusCode).toBe(400)
38
+ expect(res.body).toEqual({ error: "endSignedLength must be greater than or equal to startSignedLength." })
39
+ })
40
+
41
+ it("accepts boundary at exactly MAX_SIGNED_LENGTH", async () => {
42
+ const res = await request(context.server).get("/v1/tx-hashes/1/1001")
43
+ expect(res.statusCode).toBe(200)
44
+ })
45
+
46
+ it("trims range to current confirmed length", async () => {
47
+ const confirmed = await request(context.server).get("/v1/confirmed-length")
48
+ expect(confirmed.statusCode).toBe(200)
49
+ const beyond = confirmed.body.confirmed_length + 50
50
+ const res = await request(context.server).get(`/v1/tx-hashes/0/${beyond}`)
51
+ expect(res.statusCode).toBe(200)
52
+ const hashes = res.body.hashes || []
53
+ // last item confirmed_length should not exceed current confirmed length
54
+ const maxReturned = hashes.reduce((max, { confirmed_length }) => Math.max(max, confirmed_length || 0), 0)
55
+ expect(maxReturned).toBeLessThanOrEqual(confirmed.body.confirmed_length)
56
+ })
57
+
58
+ it("returns empty hashes when no data in range", async () => {
59
+ const res = await request(context.server).get("/v1/tx-hashes/0/0")
60
+ expect(res.statusCode).toBe(200)
61
+ expect(res.body).toHaveProperty("hashes")
62
+ expect(Array.isArray(res.body.hashes)).toBe(true)
63
+ })
64
+
65
+ it("returns empty hashes when start equals end", async () => {
66
+ const res = await request(context.server).get("/v1/tx-hashes/5/5")
67
+ expect(res.statusCode).toBe(200)
68
+ expect(res.body).toHaveProperty("hashes")
69
+ expect(res.body.hashes).toEqual([])
70
+ })
71
+ })
72
+ }
@@ -0,0 +1,27 @@
1
+ import request from "supertest"
2
+
3
+ export const registerTxPayloadsBulkTests = (context) => {
4
+ describe("POST /v1/tx-payloads-bulk", () => {
5
+ it("returns payloads for requested hashes", async () => {
6
+ const result = await context.rpcMsb.state.confirmedTransactionsBetween(0, 40) // Arbitrary range that should contain valid entries
7
+ const hashes = result.map(({ hash }) => hash)
8
+
9
+ const payload = { hashes }
10
+
11
+ const res = await request(context.server)
12
+ .post("/v1/tx-payloads-bulk")
13
+ .set("Accept", "application/json")
14
+ .send(JSON.stringify(payload))
15
+
16
+ expect(res.statusCode).toBe(200)
17
+ expect(res.body).toMatchObject({
18
+ results: expect.arrayOf(
19
+ expect.objectContaining({
20
+ hash: expect.any(String),
21
+ })
22
+ ),
23
+ missing: []
24
+ })
25
+ })
26
+ })
27
+ }
@@ -0,0 +1,11 @@
1
+ import request from "supertest"
2
+
3
+ export const registerTxvTests = (context) => {
4
+ describe("GET /v1/txv", () => {
5
+ it("returns txv hash", async () => {
6
+ const res = await request(context.server).get("/v1/txv")
7
+ expect(res.statusCode).toBe(200)
8
+ expect(res.body).toEqual({ txv: expect.stringMatching(/^[a-z0-9]{64}$/) })
9
+ })
10
+ })
11
+ }
@@ -0,0 +1,11 @@
1
+ import request from "supertest"
2
+
3
+ export const registerUnconfirmedLengthTests = (context) => {
4
+ describe("GET /v1/unconfirmed-length", () => {
5
+ it("returns unconfirmed length", async () => {
6
+ const res = await request(context.server).get("/v1/unconfirmed-length")
7
+ expect(res.statusCode).toBe(200)
8
+ expect(res.body).toEqual({ unconfirmed_length: expect.any(Number) })
9
+ })
10
+ })
11
+ }
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Lightweight factory for spinning up Autobase+State test networks.
3
+ *
4
+ * Each node gets:
5
+ * - a Corestore/Autobase pair created via test/testHelpers/autobaseTestHelpers
6
+ * - a PeerWallet (bootstrap uses the deterministic test mnemonic)
7
+ * - a State instance wired to the same bootstrap key so we can plug its apply handler directly
8
+ *
9
+ * Tests can grab `network.adminBootstrap` (the first node) plus the rest from `network.peers`,
10
+ * call `await network.sync()` to replicate, and `await network.teardown()` in their cleanup hook.
11
+ */
12
+
13
+ import State from '../../src/core/state/State.js';
14
+ import {
15
+ create,
16
+ createStores,
17
+ replicateAndSync,
18
+ defaultOpenHyperbeeView,
19
+ createWallet,
20
+ seedIndexerList
21
+ } from './autobaseTestHelpers.js';
22
+ import {
23
+ AUTOBASE_VALUE_ENCODING,
24
+ ACK_INTERVAL
25
+ } from '../../src/utils/constants.js';
26
+ import { testKeyPair1 } from '../fixtures/apply.fixtures.js';
27
+
28
+ export class StateNetworkFactory {
29
+
30
+ static async create(options = {}) {
31
+ const factory = new StateNetworkFactory(options);
32
+ await factory.#initialize();
33
+ return factory;
34
+ }
35
+
36
+ #adminPeer = null;
37
+ #peers = [];
38
+ #bases = [];
39
+ #harness = createHarness();
40
+ #options;
41
+
42
+ constructor({
43
+ nodes = 2,
44
+ valueEncoding = AUTOBASE_VALUE_ENCODING,
45
+ stateOptions = {},
46
+ autobaseOptions = {},
47
+ open = defaultOpenHyperbeeView,
48
+ seedIndexers = true
49
+ } = {}) {
50
+ if (nodes < 1) throw new Error('StateNetworkFactory requires at least one node');
51
+ this.#options = {
52
+ nodes,
53
+ valueEncoding,
54
+ stateOptions,
55
+ autobaseOptions,
56
+ open,
57
+ seedIndexers
58
+ };
59
+ }
60
+
61
+ get adminBootstrap() {
62
+ return this.#adminPeer;
63
+ }
64
+
65
+ get peers() {
66
+ return this.#peers;
67
+ }
68
+
69
+ // Backwards compatibility
70
+ get bootstrap() {
71
+ return this.#adminPeer;
72
+ }
73
+
74
+ get nodes() {
75
+ return this.#peers;
76
+ }
77
+
78
+ async sync() {
79
+ await replicateAndSync(this.#bases);
80
+ }
81
+
82
+ async teardown() {
83
+ await this.#harness.cleanup();
84
+ }
85
+
86
+ async #initialize() {
87
+ const { nodes, valueEncoding, stateOptions, autobaseOptions, open, seedIndexers } = this.#options;
88
+
89
+ const stateStores = await createStores(nodes, this.#harness);
90
+ const { bases } = await create(nodes, this.#harness, {
91
+ apply: async () => {},
92
+ open,
93
+ valueEncoding,
94
+ ackInterval: ACK_INTERVAL,
95
+ bigBatches: false,
96
+ optimistic: false,
97
+ ...autobaseOptions
98
+ });
99
+ this.#bases = bases;
100
+
101
+ await Promise.all(bases.map(base => base.ready()));
102
+
103
+ const bootstrapKey = bases[0].local.key;
104
+ const descriptors = [];
105
+
106
+ for (let i = 0; i < nodes; i++) {
107
+ const mnemonic = i === 0 ? testKeyPair1.mnemonic : null;
108
+ const wallet = await createWallet(mnemonic);
109
+ const state = new State(stateStores[i].session(), bootstrapKey, wallet, {
110
+ enable_tx_apply_logs: false,
111
+ enable_error_apply_logs: true,
112
+ ...stateOptions
113
+ });
114
+
115
+ bases[i]._handlers.apply = state.applyHandler;
116
+ descriptors.push({
117
+ index: i,
118
+ name: bases[i].name,
119
+ base: bases[i],
120
+ state,
121
+ wallet
122
+ });
123
+ }
124
+
125
+ if (seedIndexers) {
126
+ for (const descriptor of descriptors) {
127
+ seedIndexerList(descriptor.base, [bootstrapKey]);
128
+ }
129
+ }
130
+
131
+ this.#adminPeer = descriptors[0];
132
+ this.#peers = descriptors;
133
+ }
134
+ }
135
+
136
+ export async function setupStateNetwork(options = {}) {
137
+ return StateNetworkFactory.create(options);
138
+ }
139
+
140
+ function createHarness() {
141
+ const teardowns = [];
142
+ return {
143
+ teardown(fn, { order = 0 } = {}) {
144
+ teardowns.push({ fn, order });
145
+ },
146
+ async cleanup() {
147
+ const sorted = teardowns.sort((a, b) => b.order - a.order);
148
+ for (const { fn } of sorted) {
149
+ try {
150
+ await fn();
151
+ } catch (err) {
152
+ console.error('teardown failed', err);
153
+ }
154
+ }
155
+ }
156
+ };
157
+ }
@@ -0,0 +1,369 @@
1
+ // The code below originates from the holepunch/autobase repository (https://github.com/holepunchto/autobase)
2
+ // License: Apache 2.0
3
+ // The holepunch team has granted permission to reuse this code in the Trac Systems project.
4
+ // Huge thanks to the holepunch team for their work and support!
5
+ import path from 'path';
6
+ import Corestore from 'corestore';
7
+ import Autobase from 'autobase';
8
+ import Hyperbee from 'hyperbee';
9
+ import b4a from 'b4a';
10
+ import PeerWallet from 'trac-wallet';
11
+ import { blake3Hash } from '../../src/utils/crypto.js';
12
+ import {
13
+ ACK_INTERVAL,
14
+ AUTOBASE_VALUE_ENCODING,
15
+ HYPERBEE_KEY_ENCODING,
16
+ HYPERBEE_VALUE_ENCODING,
17
+ TRAC_NAMESPACE
18
+ } from '../../src/utils/constants.js';
19
+
20
+ const argv = typeof globalThis.Bare !== 'undefined' ? globalThis.Bare.argv : process.argv;
21
+
22
+ export const encryptionKey = argv?.includes('--encrypt-all')
23
+ ? b4a.alloc(32).fill('autobase-encryption-test')
24
+ : undefined;
25
+
26
+ export async function createStores(n, t, opts = {}) {
27
+ const storage = opts.storage || (() => tmpDir(t));
28
+ const offset = opts.offset || 0;
29
+
30
+ const stores = [];
31
+ for (let i = offset; i < n + offset; i++) {
32
+ const primaryKey = Buffer.alloc(32, i);
33
+ const globalCache = opts.globalCache || null;
34
+ const dir = await storage();
35
+ stores.push(new Corestore(dir, { primaryKey, encryptionKey, globalCache }));
36
+ }
37
+
38
+ t.teardown(async () => {
39
+ for (const store of stores) {
40
+ try {
41
+ await store.close();
42
+ } catch (err) {
43
+ console.error('corestore close failed', err);
44
+ }
45
+ }
46
+ }, { order: 2 });
47
+ return stores;
48
+ }
49
+
50
+ export async function create(n, t, opts = {}) {
51
+ const stores = await createStores(n, t, opts);
52
+ const bases = [createBase(stores[0], null, t, opts)];
53
+ await bases[0].ready();
54
+ bases[0].name = 'a';
55
+
56
+ if (n === 1) return { stores, bases };
57
+
58
+ for (let i = 1; i < n; i++) {
59
+ const base = createBase(stores[i], bases[0].local.key, t, opts);
60
+ await base.ready();
61
+ base.name = String.fromCharCode('a'.charCodeAt(0) + i);
62
+ bases.push(base);
63
+ }
64
+
65
+ return { stores, bases };
66
+ }
67
+
68
+ export function createBase(store, key, t, opts = {}) {
69
+ const {
70
+ open = defaultOpenHyperbeeView,
71
+ valueEncoding = AUTOBASE_VALUE_ENCODING,
72
+ ackInterval = ACK_INTERVAL,
73
+ bigBatches = false,
74
+ optimistic = false,
75
+ ...rest
76
+ } = opts;
77
+
78
+ const base = new Autobase(store.session(), key, {
79
+ open,
80
+ close: undefined,
81
+ valueEncoding,
82
+ ackInterval,
83
+ bigBatches,
84
+ optimistic,
85
+ ackThreshold: 0,
86
+ encryptionKey,
87
+ fastForward: false,
88
+ ...rest
89
+ });
90
+
91
+ base.on('error', err => {
92
+ if (err?.code === 'SESSION_CLOSED') return;
93
+ console.error('autobase error', err);
94
+ });
95
+
96
+ if (opts.maxSupportedVersion !== undefined) {
97
+ base.maxSupportedVersion = opts.maxSupportedVersion;
98
+ }
99
+
100
+ t.teardown(async () => {
101
+ try {
102
+ await base.advance();
103
+ } catch (err) {
104
+ if (err?.code !== 'SESSION_CLOSED') {
105
+ console.error('base advance failed', err);
106
+ }
107
+ }
108
+ try {
109
+ await base.close();
110
+ } catch (err) {
111
+ console.error('base close failed', err);
112
+ }
113
+ }, { order: 1 });
114
+ return base;
115
+ }
116
+
117
+ export function defaultOpenHyperbeeView(store) {
118
+ return new Hyperbee(store.get(TRAC_NAMESPACE), {
119
+ extension: false,
120
+ keyEncoding: HYPERBEE_KEY_ENCODING,
121
+ valueEncoding: HYPERBEE_VALUE_ENCODING
122
+ });
123
+ }
124
+
125
+ export async function createWallet(mnemonic = null) {
126
+ const wallet = new PeerWallet();
127
+ await wallet.generateKeyPair(mnemonic ?? undefined);
128
+ return wallet;
129
+ }
130
+
131
+ export function seedIndexerList(base, keys) {
132
+ base.system.indexers = keys.map(key => ({ key, length: 0 }));
133
+ if (base.system._indexerMap instanceof Map) {
134
+ for (const key of keys) {
135
+ base.system._indexerMap.set(b4a.toString(key, 'hex'), { key, length: 0 });
136
+ }
137
+ }
138
+ }
139
+
140
+ export const seedBootstrapIndexer = (network) => {
141
+ const bootstrapPeer = network.adminBootstrap ?? network.bootstrap;
142
+ const key = bootstrapPeer.base.local.key;
143
+ for (const { base } of network.nodes) {
144
+ seedIndexerList(base, [key]);
145
+ }
146
+ };
147
+
148
+ export async function replicateAndSync(bases, opts) {
149
+ const done = replicate(bases);
150
+ await sync(bases, opts);
151
+ await done();
152
+ }
153
+
154
+ export async function sync(bases, { checkHash = true } = {}) {
155
+ for (const base of bases) {
156
+ await base.update();
157
+ }
158
+
159
+ if (bases.length === 1) return;
160
+
161
+ return new Promise((resolve, reject) => {
162
+ let done = false;
163
+ let checks = 0;
164
+
165
+ for (const base of bases) {
166
+ base.on('update', check);
167
+ base.on('error', shutdown);
168
+ }
169
+
170
+ check();
171
+
172
+ async function check() {
173
+ checks++;
174
+ for (const base of bases) {
175
+ if (base.interrupted) return shutdown(new Error('base was interrupted, reason at base.interrupted'));
176
+ }
177
+ if (!(await areSame(checkHash))) return maybeShutdown();
178
+ for (const base of bases) {
179
+ await base.update();
180
+ }
181
+ if (!(await areSame(checkHash))) return maybeShutdown();
182
+ shutdown();
183
+ }
184
+
185
+ function maybeShutdown() {
186
+ if (done) return shutdown();
187
+ checks--;
188
+ }
189
+
190
+ async function areSame(checkHash) {
191
+ return sameHeadsAcross(bases) && await sameHash(bases, checkHash);
192
+ }
193
+
194
+ function shutdown(err) {
195
+ checks--;
196
+ done = true;
197
+ if (checks !== 0 && !err) return;
198
+
199
+ for (const base of bases) {
200
+ base.off('update', check);
201
+ base.off('error', shutdown);
202
+ }
203
+
204
+ if (err) reject(err);
205
+ else resolve();
206
+ }
207
+ });
208
+ }
209
+
210
+ function replicate(bases) {
211
+ const streams = [];
212
+ const missing = bases.slice();
213
+
214
+ while (missing.length) {
215
+ const a = missing.pop();
216
+ for (const b of missing) {
217
+ const s1 = a.replicate(true);
218
+ const s2 = b.replicate(false);
219
+
220
+ s1.on('error', err => {
221
+ if (err.code) console.log('autobase replicate error:', err.stack);
222
+ });
223
+ s2.on('error', err => {
224
+ if (err.code) console.log('autobase replicate error:', err.stack);
225
+ });
226
+
227
+ s1.pipe(s2).pipe(s1);
228
+ streams.push(s1, s2);
229
+ }
230
+ }
231
+
232
+ return close;
233
+
234
+ function close() {
235
+ return Promise.all(streams.map(s => {
236
+ s.destroy();
237
+ return new Promise(resolve => s.on('close', resolve));
238
+ }));
239
+ }
240
+ }
241
+
242
+ function sameHeadsAcross(bases) {
243
+ const first = bases[0];
244
+ for (let i = 1; i < bases.length; i++) {
245
+ if (!sameHeads(first, bases[i])) return false;
246
+ }
247
+ return true;
248
+ }
249
+
250
+ async function sameHash(bases, check) {
251
+ if (!check) return true;
252
+ const first = bases[0];
253
+ const h1 = await first.hash();
254
+ for (let i = 1; i < bases.length; i++) {
255
+ if (bases[i].signedLength !== first.signedLength) return false;
256
+ const h2 = await bases[i].hash();
257
+ if (!b4a.equals(h1, h2)) return false;
258
+ }
259
+ return true;
260
+ }
261
+
262
+ function sameHeads(a, b) {
263
+ if (a.updating || b.updating) return false;
264
+
265
+ const h1 = a.heads();
266
+ const h2 = b.heads();
267
+
268
+ if (h1.length !== h2.length) return false;
269
+
270
+ for (let i = 0; i < h1.length; i++) {
271
+ const h1i = h1[i];
272
+ const h2i = h2[i];
273
+
274
+ if (!b4a.equals(h1i.key, h2i.key)) return false;
275
+ if (h1i.length !== h2i.length) return false;
276
+ }
277
+
278
+ return true;
279
+ }
280
+
281
+ export function eventFlush() {
282
+ return new Promise(resolve => setImmediate(resolve));
283
+ }
284
+
285
+ export function deriveIndexerSequenceState(base) {
286
+ const indexers = base.system?.indexers || [];
287
+ const buffers = indexers
288
+ .map(entry => entry?.key)
289
+ .filter(key => key && key.length > 0);
290
+ const concatenated = buffers.length > 0 ? b4a.concat(buffers) : b4a.alloc(0);
291
+ return blake3Hash(concatenated);
292
+ }
293
+
294
+ let osModule;
295
+ let fsPromises;
296
+
297
+ async function ensureEnvReady() {
298
+ if (osModule && fsPromises) return;
299
+
300
+ if (typeof globalThis.Bare !== 'undefined') {
301
+ const bareOs = await import('bare-os');
302
+ osModule = bareOs.default || bareOs;
303
+
304
+ const bareFs = await import('bare-fs');
305
+ const resolved = bareFs.default || bareFs;
306
+ fsPromises = resolved.promises;
307
+ } else {
308
+ const nodeOs = await import('os');
309
+ osModule = nodeOs.default || nodeOs;
310
+
311
+ const nodeFs = await import('fs/promises');
312
+ fsPromises = nodeFs.default || nodeFs;
313
+ }
314
+ }
315
+
316
+ async function tmpDir(t) {
317
+ await ensureEnvReady();
318
+ const prefix = path.join(osModule.tmpdir(), 'msb-autobase-');
319
+ const dir = await createTempDir(prefix);
320
+ t.teardown(() => cleanupTempDir(dir), { order: 3 });
321
+ return dir;
322
+ }
323
+
324
+ async function createTempDir(prefix) {
325
+ if (typeof fsPromises.mkdtemp === 'function') {
326
+ return fsPromises.mkdtemp(prefix);
327
+ }
328
+ const uniqueDir = `${prefix}${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
329
+ await fsPromises.mkdir(uniqueDir, { recursive: true });
330
+ return uniqueDir;
331
+ }
332
+
333
+ async function cleanupTempDir(dir) {
334
+ if (!fsPromises) return;
335
+
336
+ try {
337
+ if (typeof fsPromises.rm === 'function') {
338
+ await fsPromises.rm(dir, { recursive: true, force: true });
339
+ } else if (typeof fsPromises.rmdir === 'function') {
340
+ await removeRecursively(dir);
341
+ }
342
+ } catch (err) {
343
+ if (err?.code === 'ENOENT') return;
344
+ // Windows sometimes keeps LOCK files open briefly. Ignore busy/permission errors during teardown.
345
+ if (err?.code === 'EBUSY' || err?.code === 'EPERM') return;
346
+ throw err;
347
+ }
348
+ }
349
+
350
+ async function removeRecursively(target) {
351
+ let stats;
352
+ try {
353
+ stats = await fsPromises.lstat(target);
354
+ } catch (err) {
355
+ if (err?.code === 'ENOENT') return;
356
+ throw err;
357
+ }
358
+
359
+ if (!stats.isDirectory()) {
360
+ await fsPromises.unlink(target);
361
+ return;
362
+ }
363
+
364
+ const entries = await fsPromises.readdir(target);
365
+ for (const entry of entries) {
366
+ await removeRecursively(path.join(target, entry));
367
+ }
368
+ await fsPromises.rmdir(target);
369
+ }
@@ -0,0 +1,12 @@
1
+ import PeerWallet from 'trac-wallet';
2
+
3
+ export async function createSignature(payloadBuffer) {
4
+ const wallet = new PeerWallet();
5
+ await wallet.generateKeyPair();
6
+ const signature = wallet.sign(payloadBuffer);
7
+ return { signature, wallet };
8
+ }
9
+
10
+ export default {
11
+ createSignature
12
+ };