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.
- package/.dockerignore +16 -0
- package/.github/workflows/acceptance-tests.yml +7 -0
- package/.github/workflows/publish.yml +40 -0
- package/.github/workflows/{CI.yml → unit-tests.yml} +1 -1
- package/README.md +175 -50
- package/docker-compose.yml +16 -0
- package/dockerfile +41 -0
- package/docs/fee_distribution.md +89 -0
- package/msb.mjs +12 -14
- package/package.json +8 -4
- package/rpc/constants.mjs +4 -1
- package/rpc/handlers.mjs +109 -66
- package/rpc/routes/v1.mjs +3 -1
- package/rpc/rpc_services.js +126 -0
- package/rpc/utils/confirmedParameter.mjs +17 -0
- package/rpc/utils/url.mjs +38 -0
- package/src/core/network/Network.js +27 -10
- package/src/core/network/identity/NetworkWalletFactory.js +78 -0
- package/src/core/network/services/ConnectionManager.js +2 -2
- package/src/core/network/services/ValidatorObserverService.js +7 -4
- package/src/core/state/State.js +28 -22
- package/src/index.js +197 -385
- package/src/utils/cliCommands.js +280 -0
- package/src/utils/constants.js +3 -1
- package/tests/acceptance/v1/account/account.test.mjs +123 -0
- package/tests/acceptance/v1/balance/balance.test.mjs +55 -0
- package/tests/acceptance/v1/broadcast-transaction/broadcast-transaction.test.mjs +111 -0
- package/tests/acceptance/v1/confirmed-length/confirmed-length.test.mjs +19 -0
- package/tests/acceptance/v1/fee/fee.test.mjs +11 -0
- package/tests/acceptance/v1/rpc.test.mjs +62 -291
- package/tests/acceptance/v1/tx/tx.test.mjs +98 -0
- package/tests/acceptance/v1/tx-details/tx-details.test.mjs +195 -0
- package/tests/acceptance/v1/tx-hashes/tx-hashes.test.mjs +72 -0
- package/tests/acceptance/v1/tx-payloads-bulk/tx-payloads-bulk.test.mjs +27 -0
- package/tests/acceptance/v1/txv/txv.test.mjs +11 -0
- package/tests/acceptance/v1/unconfirmed-length/unconfirmed-length.test.mjs +11 -0
- package/tests/helpers/StateNetworkFactory.js +157 -0
- package/tests/helpers/autobaseTestHelpers.js +369 -0
- package/tests/helpers/createTestSignature.js +12 -0
- package/tests/helpers/transactionPayloads.mjs +78 -0
- package/tests/unit/network/NetworkWalletFactory.test.js +156 -0
- package/tests/unit/state/apply/addAdmin/addAdminHappyPathScenario.js +38 -0
- package/tests/unit/state/apply/addAdmin/addAdminScenarioHelpers.js +273 -0
- package/tests/unit/state/apply/addAdmin/adminEntryEncodingFailureScenario.js +30 -0
- package/tests/unit/state/apply/addAdmin/adminEntryExistsScenario.js +78 -0
- package/tests/unit/state/apply/addAdmin/nodeEntryInitializationFailureScenario.js +30 -0
- package/tests/unit/state/apply/addAdmin/nonBootstrapNodeScenario.js +68 -0
- package/tests/unit/state/apply/addAdmin/state.apply.addAdmin.test.js +155 -0
- package/tests/unit/state/apply/addIndexer/addIndexerHappyPathScenario.js +39 -0
- package/tests/unit/state/apply/addIndexer/addIndexerMultipleIndexersInTheNetworkScenario.js +167 -0
- package/tests/unit/state/apply/addIndexer/addIndexerPretenderAlreadyIndexerScenario.js +21 -0
- package/tests/unit/state/apply/addIndexer/addIndexerPretenderNotWriterScenario.js +21 -0
- package/tests/unit/state/apply/addIndexer/addIndexerRemoveAndReAddScenario.js +186 -0
- package/tests/unit/state/apply/addIndexer/addIndexerScenarioHelpers.js +445 -0
- package/tests/unit/state/apply/addIndexer/addIndexerWriterKeyAlreadyRegisteredScenario.js +32 -0
- package/tests/unit/state/apply/addIndexer/state.apply.addIndexer.test.js +297 -0
- package/tests/unit/state/apply/addWriter/addWriterHappyPathScenario.js +41 -0
- package/tests/unit/state/apply/addWriter/addWriterInvalidValidatorSignatureScenario.js +32 -0
- package/tests/unit/state/apply/addWriter/addWriterNewWkScenario.js +149 -0
- package/tests/unit/state/apply/addWriter/addWriterRequesterAlreadyWriterScenario.js +21 -0
- package/tests/unit/state/apply/addWriter/addWriterRequesterBalanceInsufficientScenario.js +21 -0
- package/tests/unit/state/apply/addWriter/addWriterRequesterEntryDecodeFailureScenario.js +19 -0
- package/tests/unit/state/apply/addWriter/addWriterRequesterEntryMissingScenario.js +19 -0
- package/tests/unit/state/apply/addWriter/addWriterRequesterIndexerScenario.js +21 -0
- package/tests/unit/state/apply/addWriter/addWriterRequesterNotWhitelistedScenario.js +21 -0
- package/tests/unit/state/apply/addWriter/addWriterScenarioHelpers.js +757 -0
- package/tests/unit/state/apply/addWriter/addWriterStakeBalanceUpdateFailureScenario.js +50 -0
- package/tests/unit/state/apply/addWriter/addWriterStakeInsufficientBalanceScenario.js +29 -0
- package/tests/unit/state/apply/addWriter/addWriterStakeInvalidBalanceScenario.js +29 -0
- package/tests/unit/state/apply/addWriter/addWriterStakeInvalidEntryScenario.js +21 -0
- package/tests/unit/state/apply/addWriter/addWriterStakeStakedBalanceFailureScenario.js +37 -0
- package/tests/unit/state/apply/addWriter/addWriterStakeSubtractFailureScenario.js +42 -0
- package/tests/unit/state/apply/addWriter/addWriterValidatorRewardScenario.js +105 -0
- package/tests/unit/state/apply/addWriter/addWriterWriterKeyMismatchScenario.js +54 -0
- package/tests/unit/state/apply/addWriter/addWriterWriterKeyOwnershipScenario.js +54 -0
- package/tests/unit/state/apply/addWriter/addWriterZeroWriterKeyScenario.js +29 -0
- package/tests/unit/state/apply/addWriter/state.apply.addWriter.test.js +309 -0
- package/tests/unit/state/apply/adminRecovery/adminRecoveryHappyPathScenario.js +30 -0
- package/tests/unit/state/apply/adminRecovery/adminRecoveryScenarioHelpers.js +866 -0
- package/tests/unit/state/apply/adminRecovery/state.apply.adminRecovery.test.js +439 -0
- package/tests/unit/state/apply/appendWhitelist/appendWhitelistBanAndReapplyScenario.js +78 -0
- package/tests/unit/state/apply/appendWhitelist/appendWhitelistExistingReaderHappyPathScenario.js +98 -0
- package/tests/unit/state/apply/appendWhitelist/appendWhitelistFeeAfterDisableScenario.js +66 -0
- package/tests/unit/state/apply/appendWhitelist/appendWhitelistHappyPathScenario.js +55 -0
- package/tests/unit/state/apply/appendWhitelist/appendWhitelistInsufficientAdminBalanceScenario.js +103 -0
- package/tests/unit/state/apply/appendWhitelist/appendWhitelistNodeAlreadyWhitelistedScenario.js +60 -0
- package/tests/unit/state/apply/appendWhitelist/appendWhitelistScenarioHelpers.js +191 -0
- package/tests/unit/state/apply/appendWhitelist/state.apply.appendWhitelist.test.js +220 -0
- package/tests/unit/state/apply/balanceInitialization/balanceInitializationHappyPathScenario.js +82 -0
- package/tests/unit/state/apply/balanceInitialization/balanceInitializationScenarioHelpers.js +106 -0
- package/tests/unit/state/apply/balanceInitialization/invalidAmountScenario.js +45 -0
- package/tests/unit/state/apply/balanceInitialization/nodeEntryBalanceUpdateFailureScenario.js +81 -0
- package/tests/unit/state/apply/balanceInitialization/state.apply.balanceInitialization.test.js +189 -0
- package/tests/unit/state/apply/banValidator/banValidatorBanAndReWhitelistScenario.js +155 -0
- package/tests/unit/state/apply/banValidator/banValidatorHappyPathScenario.js +36 -0
- package/tests/unit/state/apply/banValidator/banValidatorScenarioHelpers.js +534 -0
- package/tests/unit/state/apply/banValidator/banValidatorSequentialBansScenario.js +74 -0
- package/tests/unit/state/apply/banValidator/banValidatorTargetDecodeFailureScenario.js +19 -0
- package/tests/unit/state/apply/banValidator/banValidatorTargetIndexerScenario.js +32 -0
- package/tests/unit/state/apply/banValidator/banValidatorTargetNodeEntryMissingScenario.js +19 -0
- package/tests/unit/state/apply/banValidator/banValidatorTargetRoleUpdateFailureScenario.js +19 -0
- package/tests/unit/state/apply/banValidator/banValidatorWhitelistedNonWriterScenario.js +38 -0
- package/tests/unit/state/apply/banValidator/banValidatorWhitelistedZeroBalanceScenario.js +91 -0
- package/tests/unit/state/apply/banValidator/banValidatorWithdrawFailureScenario.js +19 -0
- package/tests/unit/state/apply/banValidator/state.apply.banValidator.test.js +266 -0
- package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentDuplicateRegistrationScenario.js +142 -0
- package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentHappyPathScenario.js +26 -0
- package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentIncompleteOperationScenario.js +94 -0
- package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentInvalidDeploymentEntryScenario.js +37 -0
- package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentMultipleBootstrapScenario.js +86 -0
- package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentScenarioHelpers.js +344 -0
- package/tests/unit/state/apply/bootstrapDeployment/invalidValidatorNodeEntryScenario.js +57 -0
- package/tests/unit/state/apply/bootstrapDeployment/state.apply.bootstrapDeployment.test.js +429 -0
- package/tests/unit/state/apply/common/access-control/adminConsistencyMismatchScenario.js +119 -0
- package/tests/unit/state/apply/common/access-control/adminEntryDecodeFailureScenario.js +130 -0
- package/tests/unit/state/apply/common/access-control/adminEntryExistsScenario.js +93 -0
- package/tests/unit/state/apply/common/access-control/adminEntryMissingScenario.js +108 -0
- package/tests/unit/state/apply/common/access-control/adminOnlyGuardScenario.js +126 -0
- package/tests/unit/state/apply/common/access-control/adminPublicKeyDecodeFailureScenario.js +120 -0
- package/tests/unit/state/apply/common/access-control/roleAccessOperationValidationScenario.js +50 -0
- package/tests/unit/state/apply/common/adminControlOperationValidationScenario.js +56 -0
- package/tests/unit/state/apply/common/balances/adminEntryUpdateFailureScenario.js +52 -0
- package/tests/unit/state/apply/common/balances/base/requesterBalanceScenarioBase.js +197 -0
- package/tests/unit/state/apply/common/balances/feeDecodeFailureScenario.js +52 -0
- package/tests/unit/state/apply/common/balances/requesterBalanceDecodeFailureScenario.js +15 -0
- package/tests/unit/state/apply/common/balances/requesterBalanceFeeApplicationFailureScenario.js +11 -0
- package/tests/unit/state/apply/common/balances/requesterBalanceInsufficientScenario.js +15 -0
- package/tests/unit/state/apply/common/balances/requesterBalanceUpdateFailureScenario.js +11 -0
- package/tests/unit/state/apply/common/balances/validatorEntryRewardFailureScenario.js +11 -0
- package/tests/unit/state/apply/common/balances/validatorEntryUpdateFailureScenario.js +11 -0
- package/tests/unit/state/apply/common/balances/validatorNodeEntryDecodeFailureScenario.js +40 -0
- package/tests/unit/state/apply/common/base/OperationValidationScenarioBase.js +114 -0
- package/tests/unit/state/apply/common/commonScenarioHelper.js +103 -0
- package/tests/unit/state/apply/common/indexer/indexerNodeEntryDecodeFailureScenario.js +36 -0
- package/tests/unit/state/apply/common/indexer/indexerNodeEntryMissingScenario.js +36 -0
- package/tests/unit/state/apply/common/indexer/indexerRoleUpdateFailureScenario.js +29 -0
- package/tests/unit/state/apply/common/indexer/indexerSequenceStateInvalidScenario.js +66 -0
- package/tests/unit/state/apply/common/invalidMessageComponentValidationScenario.js +84 -0
- package/tests/unit/state/apply/common/nodeEntryInitializationFailureScenario.js +47 -0
- package/tests/unit/state/apply/common/operationAlreadyAppliedScenario.js +85 -0
- package/tests/unit/state/apply/common/payload-structure/addressWithInvalidPublicKeyScenario.js +52 -0
- package/tests/unit/state/apply/common/payload-structure/initializationDisabledScenario.js +49 -0
- package/tests/unit/state/apply/common/payload-structure/invalidAddressValidationScenario.js +73 -0
- package/tests/unit/state/apply/common/payload-structure/invalidHashValidationScenario.js +71 -0
- package/tests/unit/state/apply/common/payload-structure/invalidPayloadValidationScenario.js +31 -0
- package/tests/unit/state/apply/common/payload-structure/invalidSignatureValidationScenario.js +142 -0
- package/tests/unit/state/apply/common/payload-structure/partialOperationValidationScenario.js +87 -0
- package/tests/unit/state/apply/common/requester/requesterNodeEntryBufferMissingScenario.js +70 -0
- package/tests/unit/state/apply/common/requester/requesterNodeEntryDecodeFailureScenario.js +72 -0
- package/tests/unit/state/apply/common/requester/requesterNodeEntryMissingScenario.js +36 -0
- package/tests/unit/state/apply/common/requesterAddressValidationScenario.js +44 -0
- package/tests/unit/state/apply/common/requesterPublicKeyValidationScenario.js +25 -0
- package/tests/unit/state/apply/common/transactionValidityMismatchScenario.js +98 -0
- package/tests/unit/state/apply/common/validatorConsistency/base/validatorConsistencyScenarioBase.js +201 -0
- package/tests/unit/state/apply/common/validatorConsistency/validatorEntryDecodeFailureScenario.js +17 -0
- package/tests/unit/state/apply/common/validatorConsistency/validatorEntryMissingScenario.js +44 -0
- package/tests/unit/state/apply/common/validatorConsistency/validatorInactiveScenario.js +19 -0
- package/tests/unit/state/apply/common/validatorConsistency/validatorWriterKeyMismatchScenario.js +18 -0
- package/tests/unit/state/apply/common/validatorEntryValidation/base/validatorEntryValidationScenarioBase.js +314 -0
- package/tests/unit/state/apply/common/validatorEntryValidation/validatorEntryInvalidBalanceScenario.js +18 -0
- package/tests/unit/state/apply/common/writerKeyExistsValidationScenario.js +43 -0
- package/tests/unit/state/apply/disableInitialization/disableInitializationAlreadyDisabledScenario.js +53 -0
- package/tests/unit/state/apply/disableInitialization/disableInitializationHappyPathScenario.js +24 -0
- package/tests/unit/state/apply/disableInitialization/disableInitializationScenarioHelpers.js +197 -0
- package/tests/unit/state/apply/disableInitialization/state.apply.disableInitialization.test.js +161 -0
- package/tests/unit/state/apply/missing-tests.md +18 -0
- package/tests/unit/state/apply/removeIndexer/removeIndexerHappyPathScenario.js +58 -0
- package/tests/unit/state/apply/removeIndexer/removeIndexerReAddAndRemoveAgainScenario.js +98 -0
- package/tests/unit/state/apply/removeIndexer/removeIndexerRemoveMultipleIndexersScenario.js +167 -0
- package/tests/unit/state/apply/removeIndexer/removeIndexerScenarioHelpers.js +428 -0
- package/tests/unit/state/apply/removeIndexer/removeIndexerTargetNotIndexerScenario.js +22 -0
- package/tests/unit/state/apply/removeIndexer/removeIndexerWriterKeyMissingScenario.js +20 -0
- package/tests/unit/state/apply/removeIndexer/state.apply.removeIndexer.test.js +291 -0
- package/tests/unit/state/apply/removeWriter/removeWriterAndAddWriterAgainScenario.js +87 -0
- package/tests/unit/state/apply/removeWriter/removeWriterHappyPathScenario.js +38 -0
- package/tests/unit/state/apply/removeWriter/removeWriterInvalidValidatorSignatureScenario.js +32 -0
- package/tests/unit/state/apply/removeWriter/removeWriterRequesterBalanceInsufficientScenario.js +21 -0
- package/tests/unit/state/apply/removeWriter/removeWriterRequesterEntryDecodeFailureScenario.js +19 -0
- package/tests/unit/state/apply/removeWriter/removeWriterRequesterEntryMissingScenario.js +19 -0
- package/tests/unit/state/apply/removeWriter/removeWriterRequesterIndexerScenario.js +21 -0
- package/tests/unit/state/apply/removeWriter/removeWriterRequesterNotWriterScenario.js +21 -0
- package/tests/unit/state/apply/removeWriter/removeWriterRequesterRoleUpdateFailureScenario.js +19 -0
- package/tests/unit/state/apply/removeWriter/removeWriterScenarioHelpers.js +344 -0
- package/tests/unit/state/apply/removeWriter/removeWriterThroughWriterValidatorScenario.js +113 -0
- package/tests/unit/state/apply/removeWriter/removeWriterUnstakeFailureScenario.js +33 -0
- package/tests/unit/state/apply/removeWriter/removeWriterWriterKeyMismatchScenario.js +21 -0
- package/tests/unit/state/apply/removeWriter/removeWriterWriterKeyOwnershipScenario.js +26 -0
- package/tests/unit/state/apply/removeWriter/removeWriterWriterKeyRegistryMissingScenario.js +22 -0
- package/tests/unit/state/apply/removeWriter/state.apply.removeWriter.test.js +307 -0
- package/tests/unit/state/apply/state.apply.test.js +24 -0
- package/tests/unit/state/apply/transfer/state.apply.transfer.test.js +819 -0
- package/tests/unit/state/apply/transfer/transferContractSchemaValidationScenario.js +22 -0
- package/tests/unit/state/apply/transfer/transferDoubleSpendAcrossValidatorsScenario.js +137 -0
- package/tests/unit/state/apply/transfer/transferDoubleSpendSameBatchScenario.js +63 -0
- package/tests/unit/state/apply/transfer/transferDoubleSpendSingleValidatorScenario.js +67 -0
- package/tests/unit/state/apply/transfer/transferExistingRecipientAmountScenario.js +31 -0
- package/tests/unit/state/apply/transfer/transferExistingRecipientZeroAmountScenario.js +31 -0
- package/tests/unit/state/apply/transfer/transferHandlerGuardScenarios.js +22 -0
- package/tests/unit/state/apply/transfer/transferHappyPathScenario.js +8 -0
- package/tests/unit/state/apply/transfer/transferInvalidIncomingDataScenario.js +66 -0
- package/tests/unit/state/apply/transfer/transferNewRecipientAmountScenario.js +31 -0
- package/tests/unit/state/apply/transfer/transferNewRecipientZeroAmountScenario.js +31 -0
- package/tests/unit/state/apply/transfer/transferScenarioHelpers.js +1167 -0
- package/tests/unit/state/apply/transfer/transferSelfTransferAmountScenario.js +38 -0
- package/tests/unit/state/apply/transfer/transferSelfTransferZeroAmountScenario.js +38 -0
- package/tests/unit/state/apply/transfer/transferValidatorRecipientAmountScenario.js +38 -0
- package/tests/unit/state/apply/transfer/transferValidatorRecipientZeroAmountScenario.js +38 -0
- package/tests/unit/state/apply/txOperation/state.apply.txOperation.test.js +318 -0
- package/tests/unit/state/apply/txOperation/txOperationBootstrapNotRegisteredScenario.js +70 -0
- package/tests/unit/state/apply/txOperation/txOperationDifferentValidatorCreatorHappyPathScenario.js +23 -0
- package/tests/unit/state/apply/txOperation/txOperationInvalidDeploymentEntryScenario.js +48 -0
- package/tests/unit/state/apply/txOperation/txOperationInvalidFeeAmountScenario.js +39 -0
- package/tests/unit/state/apply/txOperation/txOperationInvalidSubnetCreatorAddressScenario.js +46 -0
- package/tests/unit/state/apply/txOperation/txOperationRequesterCreatorHappyPathScenario.js +21 -0
- package/tests/unit/state/apply/txOperation/txOperationScenarioHelpers.js +429 -0
- package/tests/unit/state/apply/txOperation/txOperationStandardHappyPathScenario.js +21 -0
- package/tests/unit/state/apply/txOperation/txOperationTransferFeeAddCreatorBalanceFailureScenario.js +26 -0
- package/tests/unit/state/apply/txOperation/txOperationTransferFeeAddValidatorBalanceFailureScenario.js +25 -0
- package/tests/unit/state/apply/txOperation/txOperationTransferFeeAddValidatorBonusFailureScenario.js +27 -0
- package/tests/unit/state/apply/txOperation/txOperationTransferFeeDecodeCreatorEntryScenario.js +18 -0
- package/tests/unit/state/apply/txOperation/txOperationTransferFeeDecodeRequesterEntryScenario.js +17 -0
- package/tests/unit/state/apply/txOperation/txOperationTransferFeeDecodeValidatorEntryScenario.js +31 -0
- package/tests/unit/state/apply/txOperation/txOperationTransferFeeGuardBypassScenario.js +49 -0
- package/tests/unit/state/apply/txOperation/txOperationTransferFeeGuardScenarioFactory.js +92 -0
- package/tests/unit/state/apply/txOperation/txOperationTransferFeeInsufficientRequesterBalanceScenario.js +28 -0
- package/tests/unit/state/apply/txOperation/txOperationTransferFeeInvalidCreatorBalanceScenario.js +29 -0
- package/tests/unit/state/apply/txOperation/txOperationTransferFeeInvalidRequesterBalanceScenario.js +28 -0
- package/tests/unit/state/apply/txOperation/txOperationTransferFeeInvalidRequesterEntryScenario.js +17 -0
- package/tests/unit/state/apply/txOperation/txOperationTransferFeeInvalidValidatorBalanceScenario.js +33 -0
- package/tests/unit/state/apply/txOperation/txOperationTransferFeeMissingCreatorEntryScenario.js +18 -0
- package/tests/unit/state/apply/txOperation/txOperationTransferFeeSubtractFailureScenario.js +25 -0
- package/tests/unit/state/apply/txOperation/txOperationTransferFeeUpdateCreatorBalanceFailureScenario.js +26 -0
- package/tests/unit/state/apply/txOperation/txOperationTransferFeeUpdateFailureScenario.js +25 -0
- package/tests/unit/state/apply/txOperation/txOperationTransferFeeUpdateValidatorBalanceFailureScenario.js +26 -0
- package/tests/unit/state/apply/txOperation/txOperationTransferFeeUpdateValidatorBonusFailureScenario.js +27 -0
- package/tests/unit/state/apply/txOperation/txOperationValidatorCreatorHappyPathScenario.js +21 -0
- package/tests/unit/state/stateModule.test.js +1 -0
- package/tests/unit/state/stateTestUtils.js +5 -1
- package/.env +0 -3
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { eventFlush } from '../../../../../helpers/autobaseTestHelpers.js';
|
|
2
|
+
import OperationValidationScenarioBase from '../base/OperationValidationScenarioBase.js';
|
|
3
|
+
|
|
4
|
+
export default class AdminEntryExistsScenario extends OperationValidationScenarioBase {
|
|
5
|
+
constructor({
|
|
6
|
+
title,
|
|
7
|
+
setupScenario,
|
|
8
|
+
buildValidPayload,
|
|
9
|
+
assertStateUnchanged,
|
|
10
|
+
buildDuplicatePayload,
|
|
11
|
+
selectInitialNode = defaultSelectNode,
|
|
12
|
+
selectDuplicateNode,
|
|
13
|
+
beforeDuplicateApply,
|
|
14
|
+
applyInitialPayload = true,
|
|
15
|
+
expectedLogs
|
|
16
|
+
}) {
|
|
17
|
+
const mutatePayload =
|
|
18
|
+
buildDuplicatePayload
|
|
19
|
+
? ((t, validPayload, context) => buildDuplicatePayload(context, t, validPayload))
|
|
20
|
+
: ((_, validPayload) => validPayload);
|
|
21
|
+
|
|
22
|
+
const applyInvalidPayload = createApplyInvalidPayload({
|
|
23
|
+
selectInitialNode,
|
|
24
|
+
selectDuplicateNode: selectDuplicateNode ?? selectInitialNode,
|
|
25
|
+
beforeDuplicateApply,
|
|
26
|
+
applyInitialPayload
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
super({
|
|
30
|
+
title,
|
|
31
|
+
setupScenario,
|
|
32
|
+
buildValidPayload,
|
|
33
|
+
mutatePayload,
|
|
34
|
+
applyInvalidPayload,
|
|
35
|
+
assertStateUnchanged,
|
|
36
|
+
expectedLogs
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function createApplyInvalidPayload({
|
|
42
|
+
selectInitialNode,
|
|
43
|
+
selectDuplicateNode,
|
|
44
|
+
beforeDuplicateApply,
|
|
45
|
+
applyInitialPayload
|
|
46
|
+
}) {
|
|
47
|
+
return async (context, invalidPayload, t, validPayload) => {
|
|
48
|
+
const initialNode = selectInitialNode?.(context);
|
|
49
|
+
const duplicateNode = selectDuplicateNode?.(context);
|
|
50
|
+
|
|
51
|
+
if (applyInitialPayload && !initialNode?.base) {
|
|
52
|
+
throw new Error('Admin entry exists scenario requires an initial node with a writable base.');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!duplicateNode?.base) {
|
|
56
|
+
throw new Error('Admin entry exists scenario requires a duplicate node with a writable base.');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (applyInitialPayload) {
|
|
60
|
+
await applyPayload(initialNode, validPayload);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let cleanup;
|
|
64
|
+
if (beforeDuplicateApply) {
|
|
65
|
+
cleanup = await beforeDuplicateApply({
|
|
66
|
+
context,
|
|
67
|
+
t,
|
|
68
|
+
initialPayload: validPayload,
|
|
69
|
+
duplicatePayload: invalidPayload,
|
|
70
|
+
initialNode,
|
|
71
|
+
duplicateNode
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
await applyPayload(duplicateNode, invalidPayload);
|
|
77
|
+
} finally {
|
|
78
|
+
if (typeof cleanup === 'function') {
|
|
79
|
+
await cleanup();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function applyPayload(node, payload) {
|
|
86
|
+
await node.base.append(payload);
|
|
87
|
+
await node.base.update();
|
|
88
|
+
await eventFlush();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function defaultSelectNode(context) {
|
|
92
|
+
return context.adminBootstrap ?? context.bootstrap ?? context.peers?.[0] ?? null;
|
|
93
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import b4a from 'b4a';
|
|
2
|
+
import { eventFlush } from '../../../../../helpers/autobaseTestHelpers.js';
|
|
3
|
+
import OperationValidationScenarioBase from '../base/OperationValidationScenarioBase.js';
|
|
4
|
+
import { EntryType } from '../../../../../../src/utils/constants.js';
|
|
5
|
+
|
|
6
|
+
const ADMIN_KEY_BUFFER = b4a.from(EntryType.ADMIN);
|
|
7
|
+
|
|
8
|
+
export default class AdminEntryMissingScenario extends OperationValidationScenarioBase {
|
|
9
|
+
constructor({
|
|
10
|
+
title,
|
|
11
|
+
setupScenario,
|
|
12
|
+
buildValidPayload,
|
|
13
|
+
assertStateUnchanged,
|
|
14
|
+
selectNode = defaultSelectNode,
|
|
15
|
+
expectedLogs
|
|
16
|
+
}) {
|
|
17
|
+
super({
|
|
18
|
+
title,
|
|
19
|
+
setupScenario,
|
|
20
|
+
buildValidPayload,
|
|
21
|
+
mutatePayload: passThroughPayload,
|
|
22
|
+
applyInvalidPayload: createApplyInvalidPayload(selectNode),
|
|
23
|
+
assertStateUnchanged,
|
|
24
|
+
expectedLogs
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function passThroughPayload(_t, payload) {
|
|
30
|
+
return payload;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function defaultSelectNode(context) {
|
|
34
|
+
return context.adminBootstrap ?? context.bootstrap ?? context.peers?.[0] ?? null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function createApplyInvalidPayload(selectNode) {
|
|
38
|
+
return async (context, payload) => {
|
|
39
|
+
const node = selectNode(context);
|
|
40
|
+
if (!node?.base) {
|
|
41
|
+
throw new Error('Admin entry missing scenario requires a writable node.');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const cleanup = patchAdminEntryAbsent(node.base);
|
|
45
|
+
try {
|
|
46
|
+
await applyPayload(node, payload);
|
|
47
|
+
} finally {
|
|
48
|
+
await cleanup?.();
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function patchAdminEntryAbsent(base) {
|
|
54
|
+
const originalApply = base._handlers.apply;
|
|
55
|
+
let shouldPatchNextApply = true;
|
|
56
|
+
|
|
57
|
+
base._handlers.apply = async (nodes, view, baseCtx) => {
|
|
58
|
+
if (!shouldPatchNextApply) {
|
|
59
|
+
return originalApply(nodes, view, baseCtx);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
shouldPatchNextApply = false;
|
|
63
|
+
const previousBatch = view.batch;
|
|
64
|
+
const boundBatch = previousBatch.bind(view);
|
|
65
|
+
|
|
66
|
+
view.batch = function patchedBatch(...args) {
|
|
67
|
+
const batch = boundBatch(...args);
|
|
68
|
+
const originalGet = batch.get?.bind(batch);
|
|
69
|
+
if (typeof originalGet === 'function') {
|
|
70
|
+
let suppressed = false;
|
|
71
|
+
batch.get = async key => {
|
|
72
|
+
if (!isAdminEntryKey(key) || suppressed) {
|
|
73
|
+
return originalGet(key);
|
|
74
|
+
}
|
|
75
|
+
suppressed = true;
|
|
76
|
+
return null;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
return batch;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
return await originalApply(nodes, view, baseCtx);
|
|
84
|
+
} finally {
|
|
85
|
+
view.batch = previousBatch;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
return () => {
|
|
90
|
+
base._handlers.apply = originalApply;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function isAdminEntryKey(key) {
|
|
95
|
+
if (typeof key === 'string') {
|
|
96
|
+
return key === EntryType.ADMIN;
|
|
97
|
+
}
|
|
98
|
+
if (b4a.isBuffer(key)) {
|
|
99
|
+
return b4a.equals(key, ADMIN_KEY_BUFFER);
|
|
100
|
+
}
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function applyPayload(node, payload) {
|
|
105
|
+
await node.base.append(payload);
|
|
106
|
+
await node.base.update();
|
|
107
|
+
await eventFlush();
|
|
108
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { eventFlush } from '../../../../../helpers/autobaseTestHelpers.js';
|
|
2
|
+
import OperationValidationScenarioBase from '../base/OperationValidationScenarioBase.js';
|
|
3
|
+
|
|
4
|
+
export default class AdminOnlyGuardScenario extends OperationValidationScenarioBase {
|
|
5
|
+
constructor({
|
|
6
|
+
title,
|
|
7
|
+
setupScenario,
|
|
8
|
+
buildValidPayload,
|
|
9
|
+
assertStateUnchanged,
|
|
10
|
+
selectNode = defaultSelectNode,
|
|
11
|
+
selectReader = defaultSelectReader,
|
|
12
|
+
beforeApply,
|
|
13
|
+
expectedLogs
|
|
14
|
+
}) {
|
|
15
|
+
super({
|
|
16
|
+
title,
|
|
17
|
+
setupScenario,
|
|
18
|
+
buildValidPayload,
|
|
19
|
+
mutatePayload: passThroughPayload,
|
|
20
|
+
applyInvalidPayload: createApplyInvalidPayload({
|
|
21
|
+
selectNode,
|
|
22
|
+
selectReader,
|
|
23
|
+
beforeApply
|
|
24
|
+
}),
|
|
25
|
+
assertStateUnchanged,
|
|
26
|
+
expectedLogs
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function passThroughPayload(_t, payload) {
|
|
32
|
+
return payload;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function defaultSelectNode(context) {
|
|
36
|
+
return context.adminBootstrap ?? context.bootstrap ?? context.peers?.[0] ?? null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function defaultSelectReader(context) {
|
|
40
|
+
const readers = context.peers?.slice(1) ?? [];
|
|
41
|
+
return readers[0] ?? null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function createApplyInvalidPayload({ selectNode, selectReader, beforeApply }) {
|
|
45
|
+
return async (context, payload, t, validPayload) => {
|
|
46
|
+
const node = selectNode(context);
|
|
47
|
+
const fakeNode = selectReader(context);
|
|
48
|
+
|
|
49
|
+
if (!node?.base) {
|
|
50
|
+
throw new Error('Admin-only guard scenario requires a writable node.');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!fakeNode?.base) {
|
|
54
|
+
throw new Error('Admin-only guard scenario requires a fake reader node.');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const cleanupFns = [];
|
|
58
|
+
|
|
59
|
+
if (beforeApply) {
|
|
60
|
+
const cleanup = await beforeApply({
|
|
61
|
+
context,
|
|
62
|
+
t,
|
|
63
|
+
payload,
|
|
64
|
+
validPayload,
|
|
65
|
+
node,
|
|
66
|
+
impersonator: fakeNode
|
|
67
|
+
});
|
|
68
|
+
if (typeof cleanup === 'function') {
|
|
69
|
+
cleanupFns.push(cleanup);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
cleanupFns.push(patchRequesterKey(node.base, fakeNode.base.local.key));
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
await applyPayload(node, payload);
|
|
77
|
+
} finally {
|
|
78
|
+
while (cleanupFns.length) {
|
|
79
|
+
const cleanup = cleanupFns.pop();
|
|
80
|
+
await cleanup?.();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function patchRequesterKey(base, impersonatorKey) {
|
|
87
|
+
const originalApply = base._handlers.apply;
|
|
88
|
+
let shouldPatchNextApply = true;
|
|
89
|
+
|
|
90
|
+
base._handlers.apply = async (nodes, view, baseCtx) => {
|
|
91
|
+
if (!shouldPatchNextApply) {
|
|
92
|
+
return originalApply(nodes, view, baseCtx);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
shouldPatchNextApply = false;
|
|
96
|
+
const patchedNodes = nodes.map(node => {
|
|
97
|
+
if (!node?.from) return node;
|
|
98
|
+
return {
|
|
99
|
+
...node,
|
|
100
|
+
from: new Proxy(node.from, {
|
|
101
|
+
// We only need to spoof node.from.key. Using a Proxy lets us override that single
|
|
102
|
+
// property while delegating every other access back to the original object via Reflect.
|
|
103
|
+
// This keeps the Hypercore/Autobase node shape intact without manual cloning.
|
|
104
|
+
get(target, prop, receiver) {
|
|
105
|
+
if (prop === 'key') {
|
|
106
|
+
return impersonatorKey;
|
|
107
|
+
}
|
|
108
|
+
return Reflect.get(target, prop, receiver);
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return originalApply(patchedNodes, view, baseCtx);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
return () => {
|
|
118
|
+
base._handlers.apply = originalApply;
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function applyPayload(node, payload) {
|
|
123
|
+
await node.base.append(payload);
|
|
124
|
+
await node.base.update();
|
|
125
|
+
await eventFlush();
|
|
126
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import b4a from 'b4a';
|
|
2
|
+
import OperationValidationScenarioBase from '../base/OperationValidationScenarioBase.js';
|
|
3
|
+
import { eventFlush } from '../../../../../helpers/autobaseTestHelpers.js';
|
|
4
|
+
import { EntryType, TRAC_ADDRESS_SIZE } from '../../../../../../src/utils/constants.js';
|
|
5
|
+
|
|
6
|
+
const ADMIN_KEY_BUFFER = b4a.from(EntryType.ADMIN);
|
|
7
|
+
|
|
8
|
+
export default class AdminPublicKeyDecodeFailureScenario extends OperationValidationScenarioBase {
|
|
9
|
+
constructor({
|
|
10
|
+
title,
|
|
11
|
+
setupScenario,
|
|
12
|
+
buildValidPayload,
|
|
13
|
+
assertStateUnchanged,
|
|
14
|
+
expectedLogs
|
|
15
|
+
}) {
|
|
16
|
+
super({
|
|
17
|
+
title,
|
|
18
|
+
setupScenario,
|
|
19
|
+
buildValidPayload,
|
|
20
|
+
mutatePayload: passThroughPayload,
|
|
21
|
+
applyInvalidPayload: applyWithCorruptedAdminEntry,
|
|
22
|
+
assertStateUnchanged,
|
|
23
|
+
expectedLogs
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function passThroughPayload(_t, payload) {
|
|
29
|
+
return payload;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function applyWithCorruptedAdminEntry(context, payload) {
|
|
33
|
+
const adminNode = context.adminBootstrap;
|
|
34
|
+
if (!adminNode?.base) {
|
|
35
|
+
throw new Error('Admin public key decode scenario requires an admin bootstrap node.');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const cleanup = patchAdminEntryAddress(adminNode.base);
|
|
39
|
+
try {
|
|
40
|
+
await adminNode.base.append(payload);
|
|
41
|
+
await adminNode.base.update();
|
|
42
|
+
await eventFlush();
|
|
43
|
+
} finally {
|
|
44
|
+
await cleanup?.();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function patchAdminEntryAddress(base) {
|
|
49
|
+
const originalApply = base._handlers.apply;
|
|
50
|
+
let shouldPatchNextApply = true;
|
|
51
|
+
|
|
52
|
+
base._handlers.apply = async (nodes, view, baseCtx) => {
|
|
53
|
+
if (!shouldPatchNextApply) {
|
|
54
|
+
return originalApply(nodes, view, baseCtx);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
shouldPatchNextApply = false;
|
|
58
|
+
const previousBatch = view.batch;
|
|
59
|
+
const boundBatch = previousBatch.bind(view);
|
|
60
|
+
|
|
61
|
+
view.batch = function patchedBatch(...args) {
|
|
62
|
+
const batch = boundBatch(...args);
|
|
63
|
+
const originalGet = batch.get?.bind(batch);
|
|
64
|
+
if (typeof originalGet === 'function') {
|
|
65
|
+
let mutatedOnce = false;
|
|
66
|
+
batch.get = async key => {
|
|
67
|
+
if (!isAdminEntryKey(key) || mutatedOnce) {
|
|
68
|
+
return originalGet(key);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const adminEntry = await originalGet(key);
|
|
72
|
+
if (!adminEntry?.value) {
|
|
73
|
+
return adminEntry;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
mutatedOnce = true;
|
|
77
|
+
return {
|
|
78
|
+
...adminEntry,
|
|
79
|
+
value: mutateAdminAddress(adminEntry.value)
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return batch;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
return await originalApply(nodes, view, baseCtx);
|
|
89
|
+
} finally {
|
|
90
|
+
view.batch = previousBatch;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
return () => {
|
|
95
|
+
base._handlers.apply = originalApply;
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function mutateAdminAddress(value) {
|
|
100
|
+
if (!b4a.isBuffer(value) || value.length < TRAC_ADDRESS_SIZE) {
|
|
101
|
+
return value;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const mutated = b4a.from(value);
|
|
105
|
+
const lastIndex = TRAC_ADDRESS_SIZE - 1;
|
|
106
|
+
const asciiP = 'p'.charCodeAt(0);
|
|
107
|
+
const asciiQ = 'q'.charCodeAt(0);
|
|
108
|
+
mutated[lastIndex] = mutated[lastIndex] === asciiP ? asciiQ : asciiP;
|
|
109
|
+
return mutated;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function isAdminEntryKey(key) {
|
|
113
|
+
if (typeof key === 'string') {
|
|
114
|
+
return key === EntryType.ADMIN;
|
|
115
|
+
}
|
|
116
|
+
if (b4a.isBuffer(key)) {
|
|
117
|
+
return b4a.equals(key, ADMIN_KEY_BUFFER);
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { eventFlush } from '../../../../../helpers/autobaseTestHelpers.js';
|
|
2
|
+
import {
|
|
3
|
+
safeDecodeApplyOperation,
|
|
4
|
+
safeEncodeApplyOperation
|
|
5
|
+
} from '../../../../../../src/utils/protobuf/operationHelpers.js';
|
|
6
|
+
import OperationValidationScenarioBase from '../base/OperationValidationScenarioBase.js';
|
|
7
|
+
|
|
8
|
+
export default class RoleAccessOperationValidationScenario extends OperationValidationScenarioBase {
|
|
9
|
+
constructor({
|
|
10
|
+
title,
|
|
11
|
+
setupScenario,
|
|
12
|
+
buildValidPayload,
|
|
13
|
+
assertStateUnchanged,
|
|
14
|
+
mutatePayload = defaultMutateRoleAccessOperation,
|
|
15
|
+
applyInvalidPayload = defaultApplyInvalidPayload,
|
|
16
|
+
expectedLogs
|
|
17
|
+
}) {
|
|
18
|
+
super({
|
|
19
|
+
title,
|
|
20
|
+
setupScenario,
|
|
21
|
+
buildValidPayload,
|
|
22
|
+
mutatePayload,
|
|
23
|
+
applyInvalidPayload,
|
|
24
|
+
assertStateUnchanged,
|
|
25
|
+
expectedLogs
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function defaultMutateRoleAccessOperation(t, validPayload) {
|
|
31
|
+
const decodedPayload = safeDecodeApplyOperation(validPayload);
|
|
32
|
+
t.ok(decodedPayload, 'role access payload decodes');
|
|
33
|
+
const roleAccess = decodedPayload?.rao;
|
|
34
|
+
t.ok(roleAccess, 'role access payload contains RAO component');
|
|
35
|
+
if (!roleAccess) return validPayload;
|
|
36
|
+
|
|
37
|
+
const originalWritingKey = roleAccess.iw;
|
|
38
|
+
t.ok(originalWritingKey, 'role access payload includes writing key');
|
|
39
|
+
if (!originalWritingKey) return validPayload;
|
|
40
|
+
|
|
41
|
+
roleAccess.iw = originalWritingKey.subarray(0, 8);
|
|
42
|
+
return safeEncodeApplyOperation(decodedPayload);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function defaultApplyInvalidPayload(context, invalidPayload) {
|
|
46
|
+
const node = context.bootstrap ?? context.adminBootstrap;
|
|
47
|
+
await node.base.append(invalidPayload);
|
|
48
|
+
await node.base.update();
|
|
49
|
+
await eventFlush();
|
|
50
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { eventFlush } from '../../../../helpers/autobaseTestHelpers.js';
|
|
2
|
+
import {
|
|
3
|
+
safeDecodeApplyOperation,
|
|
4
|
+
safeEncodeApplyOperation
|
|
5
|
+
} from '../../../../../src/utils/protobuf/operationHelpers.js';
|
|
6
|
+
import OperationValidationScenarioBase from './base/OperationValidationScenarioBase.js';
|
|
7
|
+
|
|
8
|
+
export default class AdminControlOperationValidationScenario extends OperationValidationScenarioBase {
|
|
9
|
+
constructor({
|
|
10
|
+
title,
|
|
11
|
+
setupScenario,
|
|
12
|
+
buildValidPayload,
|
|
13
|
+
assertStateUnchanged,
|
|
14
|
+
mutatePayload = defaultMutateAdminControlOperation,
|
|
15
|
+
applyInvalidPayload = defaultApplyInvalidPayload,
|
|
16
|
+
expectedLogs
|
|
17
|
+
}) {
|
|
18
|
+
super({
|
|
19
|
+
title,
|
|
20
|
+
setupScenario,
|
|
21
|
+
buildValidPayload,
|
|
22
|
+
mutatePayload,
|
|
23
|
+
applyInvalidPayload,
|
|
24
|
+
assertStateUnchanged,
|
|
25
|
+
expectedLogs
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function defaultMutateAdminControlOperation(t, validPayload) {
|
|
31
|
+
const decodedPayload = safeDecodeApplyOperation(validPayload);
|
|
32
|
+
t.ok(decodedPayload, 'admin control payload decodes');
|
|
33
|
+
const adminControl = decodedPayload?.aco;
|
|
34
|
+
t.ok(adminControl, 'admin control payload includes ACO component');
|
|
35
|
+
if (!adminControl) return validPayload;
|
|
36
|
+
|
|
37
|
+
const originalTx = adminControl.tx;
|
|
38
|
+
t.ok(originalTx, 'admin control payload includes transaction hash');
|
|
39
|
+
if (!originalTx) return validPayload;
|
|
40
|
+
|
|
41
|
+
adminControl.tx = originalTx.subarray(0, Math.max(1, originalTx.length - 1));
|
|
42
|
+
return safeEncodeApplyOperation(decodedPayload);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function defaultApplyInvalidPayload(context, invalidPayload) {
|
|
46
|
+
const operatorNode = context.adminBootstrap ?? context.bootstrap;
|
|
47
|
+
if (!operatorNode?.base) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
'Admin control validation scenarios require an admin bootstrap or bootstrap node with a base.'
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
await operatorNode.base.append(invalidPayload);
|
|
54
|
+
await operatorNode.base.update();
|
|
55
|
+
await eventFlush();
|
|
56
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import OperationValidationScenarioBase from '../base/OperationValidationScenarioBase.js';
|
|
2
|
+
import { BALANCE_ZERO } from '../../../../../../src/core/state/utils/balance.js';
|
|
3
|
+
import { eventFlush } from '../../../../../helpers/autobaseTestHelpers.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Forces a single failure when updating the admin entry balance (Balance#update returns null).
|
|
7
|
+
* Useful for handlers that subtract a fee from the admin and then persist the updated entry.
|
|
8
|
+
*/
|
|
9
|
+
export default function createAdminEntryUpdateFailureScenario({
|
|
10
|
+
title,
|
|
11
|
+
setupScenario,
|
|
12
|
+
buildValidPayload,
|
|
13
|
+
assertStateUnchanged,
|
|
14
|
+
selectNode,
|
|
15
|
+
beforeApply,
|
|
16
|
+
expectedLogs = ['Failed to update admin entry.']
|
|
17
|
+
}) {
|
|
18
|
+
return new OperationValidationScenarioBase({
|
|
19
|
+
title,
|
|
20
|
+
setupScenario,
|
|
21
|
+
buildValidPayload,
|
|
22
|
+
mutatePayload: (_t, payload) => payload,
|
|
23
|
+
applyInvalidPayload: async (context, invalidPayload) => {
|
|
24
|
+
const node = selectNode ? selectNode(context) : context.adminBootstrap;
|
|
25
|
+
if (beforeApply) {
|
|
26
|
+
await beforeApply(context);
|
|
27
|
+
}
|
|
28
|
+
const balancePrototype = Object.getPrototypeOf(BALANCE_ZERO);
|
|
29
|
+
const originalUpdate = balancePrototype.update;
|
|
30
|
+
let shouldFailNextUpdate = true;
|
|
31
|
+
|
|
32
|
+
balancePrototype.update = function patchedUpdate(...args) {
|
|
33
|
+
if (shouldFailNextUpdate) {
|
|
34
|
+
shouldFailNextUpdate = false;
|
|
35
|
+
console.error(expectedLogs[0]);
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
return originalUpdate.call(this, ...args);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
await node.base.append(invalidPayload);
|
|
43
|
+
await node.base.update();
|
|
44
|
+
await eventFlush();
|
|
45
|
+
} finally {
|
|
46
|
+
balancePrototype.update = originalUpdate;
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
assertStateUnchanged,
|
|
50
|
+
expectedLogs
|
|
51
|
+
});
|
|
52
|
+
}
|