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,87 @@
1
+ import b4a from 'b4a';
2
+ import OperationValidationScenarioBase from '../base/OperationValidationScenarioBase.js';
3
+ import {
4
+ safeDecodeApplyOperation,
5
+ safeEncodeApplyOperation
6
+ } from '../../../../../../src/utils/protobuf/operationHelpers.js';
7
+ import { eventFlush } from '../../../../../helpers/autobaseTestHelpers.js';
8
+
9
+ export const PartialOperationMutationStrategy = {
10
+ MISSING_COMPONENT: 'missing-component',
11
+ NONCE_MATCH: 'nonce-match',
12
+ ADDRESS_MATCH: 'address-match',
13
+ SIGNATURE_MATCH: 'signature-match'
14
+ };
15
+
16
+ export default class PartialOperationValidationScenario extends OperationValidationScenarioBase {
17
+ constructor({
18
+ title,
19
+ setupScenario,
20
+ buildValidPayload,
21
+ assertStateUnchanged,
22
+ strategy,
23
+ parentKey = 'rao',
24
+ applyInvalidPayload = defaultApplyInvalidPayload,
25
+ expectedLogs
26
+ }) {
27
+ const mutatePayload = createMutationStrategy(strategy, parentKey);
28
+ super({
29
+ title,
30
+ setupScenario,
31
+ buildValidPayload,
32
+ mutatePayload,
33
+ applyInvalidPayload,
34
+ assertStateUnchanged,
35
+ expectedLogs
36
+ });
37
+ }
38
+ }
39
+
40
+ function createMutationStrategy(strategy, parentKey) {
41
+ switch (strategy) {
42
+ case PartialOperationMutationStrategy.MISSING_COMPONENT:
43
+ return (t, payload) => removeComponent(t, payload, parentKey, 'vs');
44
+ case PartialOperationMutationStrategy.NONCE_MATCH:
45
+ return (t, payload) => duplicateField(t, payload, parentKey, 'vn', 'in');
46
+ case PartialOperationMutationStrategy.ADDRESS_MATCH:
47
+ return (t, payload) => alignAddress(t, payload, parentKey);
48
+ case PartialOperationMutationStrategy.SIGNATURE_MATCH:
49
+ return (t, payload) => duplicateField(t, payload, parentKey, 'vs', 'is');
50
+ default:
51
+ throw new Error(`Unsupported partial operation strategy: ${strategy}`);
52
+ }
53
+ }
54
+
55
+ function removeComponent(t, validPayload, parentKey, component) {
56
+ const decoded = safeDecodeApplyOperation(validPayload);
57
+ t.ok(decoded, 'fixtures decode');
58
+ const parent = decoded[parentKey];
59
+ if (!parent) return validPayload;
60
+ delete parent[component];
61
+ return safeEncodeApplyOperation(decoded);
62
+ }
63
+
64
+ function duplicateField(t, validPayload, parentKey, targetKey, sourceKey) {
65
+ const decoded = safeDecodeApplyOperation(validPayload);
66
+ t.ok(decoded, 'fixtures decode');
67
+ const parent = decoded[parentKey];
68
+ if (!parent || !parent[sourceKey]) return validPayload;
69
+ parent[targetKey] = b4a.from(parent[sourceKey]);
70
+ return safeEncodeApplyOperation(decoded);
71
+ }
72
+
73
+ function alignAddress(t, validPayload, parentKey) {
74
+ const decoded = safeDecodeApplyOperation(validPayload);
75
+ t.ok(decoded, 'fixtures decode');
76
+ const parent = decoded[parentKey];
77
+ if (!parent || !decoded.address) return validPayload;
78
+ parent.va = b4a.from(decoded.address);
79
+ return safeEncodeApplyOperation(decoded);
80
+ }
81
+
82
+ async function defaultApplyInvalidPayload(context, invalidPayload) {
83
+ const { bootstrap } = context;
84
+ await bootstrap.base.append(invalidPayload);
85
+ await bootstrap.base.update();
86
+ await eventFlush();
87
+ }
@@ -0,0 +1,70 @@
1
+ import b4a from 'b4a';
2
+ import OperationValidationScenarioBase from '../base/OperationValidationScenarioBase.js';
3
+ import addressUtils from '../../../../../../src/core/state/utils/address.js';
4
+ import { eventFlush } from '../../../../../helpers/autobaseTestHelpers.js';
5
+
6
+ export default class RequesterNodeEntryBufferMissingScenario extends OperationValidationScenarioBase {
7
+ constructor({
8
+ title = 'State.apply operation rejects payloads when requester node entry buffer is missing',
9
+ setupScenario,
10
+ buildValidPayload,
11
+ assertStateUnchanged,
12
+ expectedLogs = ['Invalid requester node entry buffer.'],
13
+ selectNode = context => context.bootstrap ?? context.adminBootstrap ?? context.peers?.[0],
14
+ selectPeer = context => context.bootstrapDeployment?.deployerPeer ?? context.peers?.[1]
15
+ }) {
16
+ super({
17
+ title,
18
+ setupScenario,
19
+ buildValidPayload,
20
+ mutatePayload: (_t, payload) => payload,
21
+ applyInvalidPayload: async (context, payload) => {
22
+ const node = selectNode(context);
23
+ const peer = selectPeer(context);
24
+ if (!node?.base || !peer?.wallet?.address) {
25
+ throw new Error('Requester node entry buffer scenario requires node and peer.');
26
+ }
27
+
28
+ const targetAddressString = peer.wallet.address;
29
+ const targetAddressBuffer = addressUtils.addressToBuffer(targetAddressString);
30
+
31
+ const originalApply = node.base._handlers.apply;
32
+ node.base._handlers.apply = async function patchedApply(nodes, view, baseCtx) {
33
+ const originalBatch = view.batch;
34
+ view.batch = function patchedBatch(...args) {
35
+ const batch = originalBatch.apply(this, args);
36
+ if (!batch?.get) return batch;
37
+ const originalGet = batch.get.bind(batch);
38
+ batch.get = async key => {
39
+ if (isTargetKey(key, targetAddressString, targetAddressBuffer)) return null;
40
+ return originalGet(key);
41
+ };
42
+ return batch;
43
+ };
44
+
45
+ try {
46
+ return await originalApply.call(this, nodes, view, baseCtx);
47
+ } finally {
48
+ view.batch = originalBatch;
49
+ }
50
+ };
51
+
52
+ try {
53
+ await node.base.append(payload);
54
+ await node.base.update();
55
+ await eventFlush();
56
+ } finally {
57
+ node.base._handlers.apply = originalApply;
58
+ }
59
+ },
60
+ assertStateUnchanged,
61
+ expectedLogs
62
+ });
63
+ }
64
+ }
65
+
66
+ function isTargetKey(key, targetAddressString, targetAddressBuffer) {
67
+ if (typeof key === 'string') return key === targetAddressString;
68
+ if (b4a.isBuffer(key) && targetAddressBuffer) return b4a.equals(key, targetAddressBuffer);
69
+ return false;
70
+ }
@@ -0,0 +1,72 @@
1
+ import b4a from 'b4a';
2
+ import OperationValidationScenarioBase from '../base/OperationValidationScenarioBase.js';
3
+ import addressUtils from '../../../../../../src/core/state/utils/address.js';
4
+ import { eventFlush } from '../../../../../helpers/autobaseTestHelpers.js';
5
+
6
+ export default class RequesterNodeEntryDecodeFailureScenario extends OperationValidationScenarioBase {
7
+ constructor({
8
+ title = 'State.apply operation rejects payloads when requester node entry cannot be decoded',
9
+ setupScenario,
10
+ buildValidPayload,
11
+ assertStateUnchanged,
12
+ expectedLogs = ['Invalid requester node entry.'],
13
+ selectNode = context => context.bootstrap ?? context.adminBootstrap ?? context.peers?.[0],
14
+ selectPeer = context => context.bootstrapDeployment?.deployerPeer ?? context.peers?.[1]
15
+ }) {
16
+ super({
17
+ title,
18
+ setupScenario,
19
+ buildValidPayload,
20
+ mutatePayload: (_t, payload) => payload,
21
+ applyInvalidPayload: async (context, payload) => {
22
+ const node = selectNode(context);
23
+ const peer = selectPeer(context);
24
+ if (!node?.base || !peer?.wallet?.address) {
25
+ throw new Error('Requester node entry decode scenario requires node and peer.');
26
+ }
27
+
28
+ const targetAddressString = peer.wallet.address;
29
+ const targetAddressBuffer = addressUtils.addressToBuffer(targetAddressString);
30
+
31
+ const originalApply = node.base._handlers.apply;
32
+ node.base._handlers.apply = async function patchedApply(nodes, view, baseCtx) {
33
+ const originalBatch = view.batch;
34
+ view.batch = function patchedBatch(...args) {
35
+ const batch = originalBatch.apply(this, args);
36
+ if (!batch?.get) return batch;
37
+ const originalGet = batch.get.bind(batch);
38
+ batch.get = async key => {
39
+ if (isTargetKey(key, targetAddressString, targetAddressBuffer)) {
40
+ return { key, value: b4a.alloc(0) };
41
+ }
42
+ return originalGet(key);
43
+ };
44
+ return batch;
45
+ };
46
+
47
+ try {
48
+ return await originalApply.call(this, nodes, view, baseCtx);
49
+ } finally {
50
+ view.batch = originalBatch;
51
+ }
52
+ };
53
+
54
+ try {
55
+ await node.base.append(payload);
56
+ await node.base.update();
57
+ await eventFlush();
58
+ } finally {
59
+ node.base._handlers.apply = originalApply;
60
+ }
61
+ },
62
+ assertStateUnchanged,
63
+ expectedLogs
64
+ });
65
+ }
66
+ }
67
+
68
+ function isTargetKey(key, targetAddressString, targetAddressBuffer) {
69
+ if (typeof key === 'string') return key === targetAddressString;
70
+ if (b4a.isBuffer(key) && targetAddressBuffer) return b4a.equals(key, targetAddressBuffer);
71
+ return false;
72
+ }
@@ -0,0 +1,36 @@
1
+ import OperationValidationScenarioBase from '../base/OperationValidationScenarioBase.js';
2
+ import { applyWithRequesterEntryRemoval } from '../../addWriter/addWriterScenarioHelpers.js';
3
+
4
+ const passThroughPayload = (_t, payload) => payload;
5
+
6
+ export default class RequesterNodeEntryMissingScenario extends OperationValidationScenarioBase {
7
+ constructor({
8
+ title,
9
+ setupScenario,
10
+ buildValidPayload,
11
+ assertStateUnchanged,
12
+ expectedLogs,
13
+ selectPeer,
14
+ mutatePayload = passThroughPayload
15
+ }) {
16
+ if (typeof selectPeer !== 'function') {
17
+ throw new Error('Requester node entry scenario requires a selectPeer function.');
18
+ }
19
+
20
+ super({
21
+ title,
22
+ setupScenario,
23
+ buildValidPayload,
24
+ mutatePayload,
25
+ applyInvalidPayload: async (context, invalidPayload) => {
26
+ const peer = selectPeer(context);
27
+ if (!peer) {
28
+ throw new Error('Requester node entry scenario requires a peer instance.');
29
+ }
30
+ await applyWithRequesterEntryRemoval(context, invalidPayload, { peer });
31
+ },
32
+ assertStateUnchanged,
33
+ expectedLogs
34
+ });
35
+ }
36
+ }
@@ -0,0 +1,44 @@
1
+ import b4a from 'b4a';
2
+ import { eventFlush } from '../../../../helpers/autobaseTestHelpers.js';
3
+ import { safeDecodeApplyOperation, safeEncodeApplyOperation } from '../../../../../src/utils/protobuf/operationHelpers.js';
4
+ import OperationValidationScenarioBase from './base/OperationValidationScenarioBase.js';
5
+
6
+ export default class RequesterAddressValidationScenario extends OperationValidationScenarioBase {
7
+ constructor({
8
+ title,
9
+ setupScenario,
10
+ buildValidPayload,
11
+ assertStateUnchanged,
12
+ mutatePayload = defaultMutateRequesterPayload,
13
+ applyInvalidPayload = defaultApplyInvalidRequesterPayload,
14
+ expectedLogs
15
+ }) {
16
+ super({
17
+ title,
18
+ setupScenario,
19
+ buildValidPayload,
20
+ mutatePayload,
21
+ applyInvalidPayload,
22
+ assertStateUnchanged,
23
+ expectedLogs
24
+ });
25
+ }
26
+ }
27
+
28
+ function defaultMutateRequesterPayload(t, validPayload) {
29
+ const decodedPayload = safeDecodeApplyOperation(validPayload);
30
+ t.ok(decodedPayload, 'fixtures decode');
31
+
32
+ const invalidAddressBuffer = b4a.from(decodedPayload.address);
33
+ invalidAddressBuffer[0] = invalidAddressBuffer[0] === 120 ? 121 : 120;
34
+ decodedPayload.address = invalidAddressBuffer;
35
+
36
+ return safeEncodeApplyOperation(decodedPayload);
37
+ }
38
+
39
+ async function defaultApplyInvalidRequesterPayload(context, invalidPayload) {
40
+ const { bootstrap } = context;
41
+ await bootstrap.base.append(invalidPayload);
42
+ await bootstrap.base.update();
43
+ await eventFlush();
44
+ }
@@ -0,0 +1,25 @@
1
+ import b4a from 'b4a';
2
+ import RequesterAddressValidationScenario from './requesterAddressValidationScenario.js';
3
+ import { safeDecodeApplyOperation, safeEncodeApplyOperation } from '../../../../../src/utils/protobuf/operationHelpers.js';
4
+
5
+ function mutateRequesterPublicKey(t, validPayload) {
6
+ const decodedPayload = safeDecodeApplyOperation(validPayload);
7
+ t.ok(decodedPayload, 'fixtures decode');
8
+
9
+ const mutatedAddress = b4a.from(decodedPayload.address);
10
+ const lastIndex = mutatedAddress.length - 1;
11
+ const currentChar = mutatedAddress[lastIndex];
12
+ const asciiP = 'p'.charCodeAt(0);
13
+ const asciiQ = 'q'.charCodeAt(0);
14
+ mutatedAddress[lastIndex] = currentChar === asciiP ? asciiQ : asciiP;
15
+
16
+ decodedPayload.address = mutatedAddress;
17
+ return safeEncodeApplyOperation(decodedPayload);
18
+ }
19
+
20
+ export default function createRequesterPublicKeyValidationScenario(config) {
21
+ return new RequesterAddressValidationScenario({
22
+ ...config,
23
+ mutatePayload: mutateRequesterPublicKey
24
+ });
25
+ }
@@ -0,0 +1,98 @@
1
+ import b4a from 'b4a';
2
+ import { eventFlush } from '../../../../helpers/autobaseTestHelpers.js';
3
+ import { safeDecodeApplyOperation } from '../../../../../src/utils/protobuf/operationHelpers.js';
4
+ import OperationValidationScenarioBase from './base/OperationValidationScenarioBase.js';
5
+
6
+ export default class TransactionValidityMismatchScenario extends OperationValidationScenarioBase {
7
+ constructor({
8
+ title,
9
+ setupScenario,
10
+ buildValidPayload,
11
+ assertStateUnchanged,
12
+ txValidityPath = ['cao', 'txv'],
13
+ applyInvalidPayload = defaultApplyInvalidPayload,
14
+ rebuildPayloadWithTxValidity,
15
+ expectedLogs
16
+ }) {
17
+ if (typeof rebuildPayloadWithTxValidity !== 'function') {
18
+ throw new Error(
19
+ 'Transaction validity mismatch scenario requires a rebuildPayloadWithTxValidity function.'
20
+ );
21
+ }
22
+
23
+ super({
24
+ title,
25
+ setupScenario,
26
+ buildValidPayload,
27
+ mutatePayload: (t, payload, context) =>
28
+ mutateTxValidityPayload({
29
+ t,
30
+ validPayload: payload,
31
+ context,
32
+ txValidityPath,
33
+ rebuildPayloadWithTxValidity
34
+ }),
35
+ applyInvalidPayload,
36
+ assertStateUnchanged,
37
+ expectedLogs
38
+ });
39
+ }
40
+ }
41
+
42
+ async function mutateTxValidityPayload({
43
+ t,
44
+ validPayload,
45
+ context,
46
+ txValidityPath,
47
+ rebuildPayloadWithTxValidity
48
+ }) {
49
+ const path = Array.isArray(txValidityPath) ? txValidityPath : [txValidityPath];
50
+ if (!path.length) {
51
+ throw new Error('Transaction validity mutation requires a non-empty path.');
52
+ }
53
+
54
+ const decodedPayload = safeDecodeApplyOperation(validPayload);
55
+ t.ok(decodedPayload, 'fixtures decode');
56
+
57
+ const txValidityBuffer = locateTxValidityBuffer(decodedPayload, path);
58
+ if (!txValidityBuffer) {
59
+ return validPayload;
60
+ }
61
+
62
+ const mutatedValidity = flipTxValidity(txValidityBuffer);
63
+ return rebuildPayloadWithTxValidity({
64
+ context,
65
+ t,
66
+ validPayload,
67
+ mutatedTxValidity: mutatedValidity
68
+ });
69
+ }
70
+
71
+ function locateTxValidityBuffer(payload, path) {
72
+ let current = payload;
73
+ for (let i = 0; i < path.length - 1; i++) {
74
+ if (!current) return null;
75
+ current = current[path[i]];
76
+ }
77
+
78
+ const field = path[path.length - 1];
79
+ const value = current?.[field];
80
+ if (!b4a.isBuffer(value) || value.length === 0) {
81
+ return null;
82
+ }
83
+ return value;
84
+ }
85
+
86
+ function flipTxValidity(txValidityBuffer) {
87
+ const mutatedValidity = b4a.from(txValidityBuffer);
88
+ const lastIndex = mutatedValidity.length - 1;
89
+ mutatedValidity[lastIndex] ^= 0xff;
90
+ return mutatedValidity;
91
+ }
92
+
93
+ async function defaultApplyInvalidPayload(context, invalidPayload) {
94
+ const { bootstrap } = context;
95
+ await bootstrap.base.append(invalidPayload);
96
+ await bootstrap.base.update();
97
+ await eventFlush();
98
+ }
@@ -0,0 +1,201 @@
1
+ import b4a from 'b4a';
2
+ import OperationValidationScenarioBase from '../../base/OperationValidationScenarioBase.js';
3
+ import { safeDecodeApplyOperation } from '../../../../../../../src/utils/protobuf/operationHelpers.js';
4
+ import addressUtils from '../../../../../../../src/core/state/utils/address.js';
5
+ import { eventFlush } from '../../../../../../helpers/autobaseTestHelpers.js';
6
+
7
+ export const ValidatorEntryMutation = {
8
+ DELETE: Symbol('validator-entry-delete')
9
+ };
10
+
11
+ const DEFAULT_VALIDATOR_ADDRESS_PATH = ['rao', 'va'];
12
+
13
+ export default class ValidatorConsistencyScenarioBase extends OperationValidationScenarioBase {
14
+ constructor({
15
+ title,
16
+ setupScenario,
17
+ buildValidPayload,
18
+ assertStateUnchanged,
19
+ mutateEntry,
20
+ selectNode = defaultSelectNode,
21
+ validatorAddressPath = DEFAULT_VALIDATOR_ADDRESS_PATH,
22
+ expectedLogs,
23
+ applyInvalidPayload
24
+ }) {
25
+ if (typeof mutateEntry !== 'function') {
26
+ throw new Error('Validator consistency scenario requires a mutateEntry function.');
27
+ }
28
+
29
+ super({
30
+ title,
31
+ setupScenario,
32
+ buildValidPayload,
33
+ mutatePayload: passThroughPayload,
34
+ applyInvalidPayload:
35
+ typeof applyInvalidPayload === 'function'
36
+ ? applyInvalidPayload
37
+ : createApplyInvalidPayload({
38
+ selectNode,
39
+ validatorAddressPath,
40
+ mutateEntry
41
+ }),
42
+ assertStateUnchanged,
43
+ expectedLogs
44
+ });
45
+ }
46
+ }
47
+
48
+ function passThroughPayload(_t, payload) {
49
+ return payload;
50
+ }
51
+
52
+ function defaultSelectNode(context) {
53
+ return context.adminBootstrap ?? context.bootstrap ?? context.peers?.[0] ?? null;
54
+ }
55
+
56
+ function createApplyInvalidPayload({ selectNode, validatorAddressPath, mutateEntry }) {
57
+ return async (context, payload, t, validPayload) => {
58
+ const node = selectNode(context);
59
+ if (!node?.base) {
60
+ throw new Error('Validator consistency scenario requires a writable node.');
61
+ }
62
+
63
+ const validatorAddress = extractValidatorAddress(validPayload ?? payload, validatorAddressPath);
64
+ if (!validatorAddress) {
65
+ throw new Error('Validator address could not be derived from payload.');
66
+ }
67
+
68
+ const cleanup = patchValidatorEntry({
69
+ base: node.base,
70
+ mutateEntry,
71
+ context,
72
+ t,
73
+ validatorAddressString: validatorAddress.string,
74
+ validatorAddressBuffer: validatorAddress.buffer
75
+ });
76
+
77
+ try {
78
+ await node.base.append(payload);
79
+ await node.base.update();
80
+ await eventFlush();
81
+ } finally {
82
+ await cleanup();
83
+ }
84
+ };
85
+ }
86
+
87
+ function patchValidatorEntry({
88
+ base,
89
+ mutateEntry,
90
+ context,
91
+ t,
92
+ validatorAddressString,
93
+ validatorAddressBuffer
94
+ }) {
95
+ const originalApply = base._handlers.apply;
96
+ let shouldInterceptNextApply = true;
97
+
98
+ base._handlers.apply = async function patchedApply(nodes, view, baseCtx) {
99
+ if (!shouldInterceptNextApply) {
100
+ return originalApply.call(this, nodes, view, baseCtx);
101
+ }
102
+
103
+ shouldInterceptNextApply = false;
104
+ const originalBatch = view.batch;
105
+ view.batch = function patchedBatch(...args) {
106
+ const batch = originalBatch.apply(this, args);
107
+ if (!batch || typeof batch.get !== 'function') {
108
+ return batch;
109
+ }
110
+
111
+ const originalGet = batch.get.bind(batch);
112
+ let hasMutatedEntry = false;
113
+
114
+ batch.get = async key => {
115
+ if (
116
+ !hasMutatedEntry &&
117
+ isValidatorKeyMatch(key, validatorAddressString, validatorAddressBuffer)
118
+ ) {
119
+ hasMutatedEntry = true;
120
+ const entry = await originalGet(key);
121
+
122
+ const mutation = await mutateEntry(entry, {
123
+ context,
124
+ t,
125
+ validatorAddress: validatorAddressString
126
+ });
127
+
128
+ return applyEntryMutation(entry, mutation);
129
+ }
130
+
131
+ return originalGet(key);
132
+ };
133
+
134
+ return batch;
135
+ };
136
+
137
+ try {
138
+ return await originalApply.call(this, nodes, view, baseCtx);
139
+ } finally {
140
+ view.batch = originalBatch;
141
+ }
142
+ };
143
+
144
+ return async () => {
145
+ base._handlers.apply = originalApply;
146
+ };
147
+ }
148
+
149
+ function applyEntryMutation(entry, mutation) {
150
+ if (typeof mutation === 'undefined') {
151
+ return entry;
152
+ }
153
+
154
+ if (mutation === ValidatorEntryMutation.DELETE) {
155
+ return null;
156
+ }
157
+
158
+ if (entry && (b4a.isBuffer(mutation) || mutation instanceof Uint8Array)) {
159
+ return {
160
+ ...entry,
161
+ value: b4a.from(mutation)
162
+ };
163
+ }
164
+
165
+ if (mutation && typeof mutation === 'object') {
166
+ return mutation;
167
+ }
168
+
169
+ throw new Error('Invalid validator entry mutation result.');
170
+ }
171
+
172
+ function extractValidatorAddress(payloadBuffer, path) {
173
+ const decoded = safeDecodeApplyOperation(payloadBuffer);
174
+ if (!decoded) return null;
175
+
176
+ const value = Array.isArray(path) && path.length > 0 ? traversePath(decoded, path) : null;
177
+ if (!value || !b4a.isBuffer(value) || value.length === 0) {
178
+ return null;
179
+ }
180
+
181
+ const addressString = addressUtils.bufferToAddress(value);
182
+ if (!addressString) {
183
+ return null;
184
+ }
185
+
186
+ return { buffer: value, string: addressString };
187
+ }
188
+
189
+ function traversePath(payload, path) {
190
+ return path.reduce((current, segment) => (current ? current[segment] : null), payload);
191
+ }
192
+
193
+ function isValidatorKeyMatch(key, targetString, targetBuffer) {
194
+ if (typeof key === 'string') {
195
+ return key === targetString;
196
+ }
197
+ if (b4a.isBuffer(key) && targetBuffer) {
198
+ return b4a.equals(key, targetBuffer);
199
+ }
200
+ return false;
201
+ }
@@ -0,0 +1,17 @@
1
+ import b4a from 'b4a';
2
+ import ValidatorEntryValidationScenarioBase from '../validatorEntryValidation/base/validatorEntryValidationScenarioBase.js';
3
+
4
+ export default class ValidatorEntryDecodeFailureScenario extends ValidatorEntryValidationScenarioBase {
5
+ constructor(options) {
6
+ super({
7
+ ...options,
8
+ mutateEntry: entry => {
9
+ if (!entry?.value) {
10
+ throw new Error('Validator entry decode scenario requires an existing entry.');
11
+ }
12
+ return { ...entry, value: b4a.alloc(1) };
13
+ },
14
+ expectedLogs: options?.expectedLogs ?? ['Failed to decode validator entry.']
15
+ });
16
+ }
17
+ }
@@ -0,0 +1,44 @@
1
+ import OperationValidationScenarioBase from '../base/OperationValidationScenarioBase.js';
2
+ import { eventFlush } from '../../../../../helpers/autobaseTestHelpers.js';
3
+
4
+ export default class ValidatorEntryMissingScenario extends OperationValidationScenarioBase {
5
+ constructor({
6
+ title,
7
+ setupScenario,
8
+ buildValidPayload,
9
+ assertStateUnchanged,
10
+ selectNode = defaultSelectNode,
11
+ expectedLogs
12
+ }) {
13
+ super({
14
+ title,
15
+ setupScenario,
16
+ buildValidPayload,
17
+ mutatePayload: passThroughPayload,
18
+ applyInvalidPayload: createApplyInvalidPayload(selectNode),
19
+ assertStateUnchanged,
20
+ expectedLogs
21
+ });
22
+ }
23
+ }
24
+
25
+ function passThroughPayload(_t, payload) {
26
+ return payload;
27
+ }
28
+
29
+ function defaultSelectNode(context) {
30
+ return context.adminBootstrap ?? context.bootstrap ?? context.peers?.[0] ?? null;
31
+ }
32
+
33
+ function createApplyInvalidPayload(selectNode) {
34
+ return async (context, payload) => {
35
+ const node = selectNode(context);
36
+ if (!node.base) {
37
+ throw new Error('Validator entry missing scenario requires a writable node.');
38
+ }
39
+
40
+ await node.base.append(payload);
41
+ await node.base.update();
42
+ await eventFlush();
43
+ };
44
+ }