trac-msb 0.2.7 → 0.2.9

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 (187) hide show
  1. package/.github/workflows/publish.yml +8 -16
  2. package/msb.mjs +13 -25
  3. package/package.json +8 -4
  4. package/proto/network.proto +74 -0
  5. package/rpc/{create_server.mjs → create_server.js} +4 -4
  6. package/rpc/{handlers.mjs → handlers.js} +7 -7
  7. package/rpc/routes/{index.mjs → index.js} +1 -1
  8. package/rpc/routes/{v1.mjs → v1.js} +1 -1
  9. package/rpc/rpc_server.js +10 -0
  10. package/rpc/rpc_services.js +48 -7
  11. package/rpc/utils/{helpers.mjs → helpers.js} +1 -1
  12. package/src/config/config.js +137 -0
  13. package/src/config/env.js +63 -0
  14. package/src/core/network/Network.js +133 -119
  15. package/src/core/network/identity/NetworkWalletFactory.js +5 -6
  16. package/src/core/network/protocols/LegacyProtocol.js +67 -0
  17. package/src/core/network/protocols/NetworkMessages.js +48 -0
  18. package/src/core/network/protocols/ProtocolInterface.js +31 -0
  19. package/src/core/network/protocols/ProtocolSession.js +59 -0
  20. package/src/core/network/protocols/V1Protocol.js +64 -0
  21. package/src/core/network/protocols/legacy/NetworkMessageRouter.js +84 -0
  22. package/src/core/network/protocols/legacy/handlers/GetRequestHandler.js +53 -0
  23. package/src/core/network/protocols/legacy/handlers/ResponseHandler.js +37 -0
  24. package/src/core/network/{messaging → protocols/legacy}/validators/ValidatorResponse.js +2 -2
  25. package/src/core/network/{messaging → protocols/legacy}/validators/base/BaseResponse.js +13 -6
  26. package/src/core/network/protocols/shared/handlers/RoleOperationHandler.js +88 -0
  27. package/src/core/network/protocols/shared/handlers/SubnetworkOperationHandler.js +93 -0
  28. package/src/core/network/protocols/shared/handlers/TransferOperationHandler.js +57 -0
  29. package/src/core/network/{messaging → protocols/shared}/handlers/base/BaseOperationHandler.js +21 -26
  30. package/src/core/network/{messaging → protocols/shared}/validators/PartialBootstrapDeployment.js +3 -3
  31. package/src/core/network/{messaging → protocols/shared}/validators/PartialRoleAccess.js +15 -12
  32. package/src/core/network/{messaging → protocols/shared}/validators/PartialTransaction.js +10 -11
  33. package/src/core/network/{messaging → protocols/shared}/validators/PartialTransfer.js +10 -7
  34. package/src/core/network/{messaging → protocols/shared}/validators/base/PartialOperation.js +40 -22
  35. package/src/core/network/protocols/v1/NetworkMessageRouter.js +15 -0
  36. package/src/core/network/services/ConnectionManager.js +13 -19
  37. package/src/core/network/services/MessageOrchestrator.js +10 -22
  38. package/src/core/network/services/TransactionPoolService.js +10 -10
  39. package/src/core/network/services/TransactionRateLimiterService.js +5 -3
  40. package/src/core/network/services/ValidatorObserverService.js +46 -21
  41. package/src/core/state/State.js +137 -141
  42. package/src/core/state/utils/address.js +18 -16
  43. package/src/core/state/utils/adminEntry.js +17 -16
  44. package/src/core/state/utils/deploymentEntry.js +15 -15
  45. package/src/core/state/utils/transaction.js +3 -95
  46. package/src/index.js +250 -325
  47. package/src/messages/network/v1/NetworkMessageBuilder.js +325 -0
  48. package/src/messages/network/v1/NetworkMessageDirector.js +137 -0
  49. package/src/messages/network/v1/networkMessageFactory.js +12 -0
  50. package/src/messages/state/ApplyStateMessageBuilder.js +661 -0
  51. package/src/messages/state/ApplyStateMessageDirector.js +516 -0
  52. package/src/messages/state/applyStateMessageFactory.js +12 -0
  53. package/src/utils/buffer.js +53 -1
  54. package/src/utils/check.js +21 -17
  55. package/src/utils/cli.js +0 -8
  56. package/src/utils/cliCommands.js +11 -11
  57. package/src/utils/constants.js +36 -24
  58. package/src/utils/fileUtils.js +1 -4
  59. package/src/utils/helpers.js +9 -20
  60. package/src/utils/migrationUtils.js +2 -2
  61. package/src/utils/normalizers.js +94 -11
  62. package/src/utils/protobuf/network.cjs +840 -0
  63. package/src/utils/protobuf/operationHelpers.js +10 -0
  64. package/tests/acceptance/v1/account/account.test.mjs +2 -2
  65. package/tests/acceptance/v1/balance/balance.test.mjs +1 -1
  66. package/tests/acceptance/v1/broadcast-transaction/broadcast-transaction.test.mjs +11 -2
  67. package/tests/acceptance/v1/rpc.test.mjs +10 -10
  68. package/tests/acceptance/v1/tx/tx.test.mjs +4 -2
  69. package/tests/acceptance/v1/tx-details/tx-details.test.mjs +7 -3
  70. package/tests/fixtures/check.fixtures.js +42 -42
  71. package/tests/fixtures/networkV1.fixtures.js +84 -0
  72. package/tests/fixtures/protobuf.fixtures.js +110 -26
  73. package/tests/helpers/StateNetworkFactory.js +3 -5
  74. package/tests/helpers/autobaseTestHelpers.js +1 -2
  75. package/tests/helpers/config.js +3 -0
  76. package/tests/helpers/setupApplyTests.js +113 -99
  77. package/tests/helpers/transactionPayloads.mjs +26 -12
  78. package/tests/unit/messages/messages.test.js +12 -0
  79. package/tests/unit/messages/network/NetworkMessageBuilder.test.js +276 -0
  80. package/tests/unit/messages/network/NetworkMessageDirector.test.js +203 -0
  81. package/tests/unit/messages/state/applyStateMessageBuilder.complete.test.js +521 -0
  82. package/tests/unit/messages/state/applyStateMessageBuilder.partial.test.js +233 -0
  83. package/tests/unit/network/ConnectionManager.test.js +10 -7
  84. package/tests/unit/network/NetworkWalletFactory.test.js +14 -14
  85. package/tests/unit/network/networkModule.test.js +3 -2
  86. package/tests/unit/state/apply/addAdmin/addAdminHappyPathScenario.js +10 -6
  87. package/tests/unit/state/apply/addAdmin/addAdminScenarioHelpers.js +11 -8
  88. package/tests/unit/state/apply/addAdmin/state.apply.addAdmin.test.js +11 -7
  89. package/tests/unit/state/apply/addIndexer/addIndexerScenarioHelpers.js +18 -20
  90. package/tests/unit/state/apply/addWriter/addWriterScenarioHelpers.js +57 -48
  91. package/tests/unit/state/apply/addWriter/addWriterValidatorRewardScenario.js +2 -1
  92. package/tests/unit/state/apply/adminRecovery/adminRecoveryScenarioHelpers.js +72 -57
  93. package/tests/unit/state/apply/adminRecovery/state.apply.adminRecovery.test.js +3 -7
  94. package/tests/unit/state/apply/appendWhitelist/appendWhitelistScenarioHelpers.js +12 -14
  95. package/tests/unit/state/apply/balanceInitialization/balanceInitializationScenarioHelpers.js +18 -13
  96. package/tests/unit/state/apply/balanceInitialization/nodeEntryBalanceUpdateFailureScenario.js +2 -1
  97. package/tests/unit/state/apply/banValidator/banValidatorBanAndReWhitelistScenario.js +2 -1
  98. package/tests/unit/state/apply/banValidator/banValidatorScenarioHelpers.js +27 -30
  99. package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentDuplicateRegistrationScenario.js +2 -1
  100. package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentScenarioHelpers.js +24 -21
  101. package/tests/unit/state/apply/common/access-control/adminConsistencyMismatchScenario.js +5 -4
  102. package/tests/unit/state/apply/common/access-control/adminPublicKeyDecodeFailureScenario.js +4 -3
  103. package/tests/unit/state/apply/common/balances/base/requesterBalanceScenarioBase.js +2 -1
  104. package/tests/unit/state/apply/common/commonScenarioHelper.js +16 -16
  105. package/tests/unit/state/apply/common/payload-structure/initializationDisabledScenario.js +10 -5
  106. package/tests/unit/state/apply/common/payload-structure/invalidHashValidationScenario.js +2 -2
  107. package/tests/unit/state/apply/common/requester/requesterNodeEntryBufferMissingScenario.js +2 -1
  108. package/tests/unit/state/apply/common/requester/requesterNodeEntryDecodeFailureScenario.js +2 -1
  109. package/tests/unit/state/apply/common/validatorConsistency/base/validatorConsistencyScenarioBase.js +2 -1
  110. package/tests/unit/state/apply/common/validatorEntryValidation/base/validatorEntryValidationScenarioBase.js +2 -1
  111. package/tests/unit/state/apply/disableInitialization/disableInitializationScenarioHelpers.js +16 -9
  112. package/tests/unit/state/apply/removeIndexer/removeIndexerScenarioHelpers.js +6 -5
  113. package/tests/unit/state/apply/removeWriter/removeWriterScenarioHelpers.js +23 -19
  114. package/tests/unit/state/apply/transfer/transferDoubleSpendAcrossValidatorsScenario.js +45 -36
  115. package/tests/unit/state/apply/transfer/transferScenarioHelpers.js +48 -45
  116. package/tests/unit/state/apply/txOperation/txOperationScenarioHelpers.js +32 -29
  117. package/tests/unit/state/apply/txOperation/txOperationTransferFeeGuardScenarioFactory.js +2 -1
  118. package/tests/unit/state/stateModule.test.js +0 -1
  119. package/tests/unit/state/stateTestUtils.js +7 -3
  120. package/tests/unit/state/utils/address.test.js +3 -3
  121. package/tests/unit/state/utils/adminEntry.test.js +10 -9
  122. package/tests/unit/unit.test.js +1 -1
  123. package/tests/unit/utils/buffer/buffer.test.js +62 -1
  124. package/tests/unit/utils/check/adminControlOperation.test.js +3 -3
  125. package/tests/unit/utils/check/balanceInitializationOperation.test.js +2 -2
  126. package/tests/unit/utils/check/bootstrapDeploymentOperation.test.js +2 -3
  127. package/tests/unit/utils/check/common.test.js +7 -6
  128. package/tests/unit/utils/check/coreAdminOperation.test.js +3 -3
  129. package/tests/unit/utils/check/roleAccessOperation.test.js +3 -2
  130. package/tests/unit/utils/check/transactionOperation.test.js +3 -3
  131. package/tests/unit/utils/check/transferOperation.test.js +3 -3
  132. package/tests/unit/utils/fileUtils/readAddressesFromWhitelistFile.test.js +2 -1
  133. package/tests/unit/utils/fileUtils/readBalanceMigrationFile.test.js +2 -1
  134. package/tests/unit/utils/migrationUtils/validateAddressFromIncomingFile.test.js +7 -0
  135. package/tests/unit/utils/normalizers/normalizers.test.js +469 -0
  136. package/tests/unit/utils/protobuf/operationHelpers.test.js +120 -2
  137. package/tests/unit/utils/utils.test.js +0 -1
  138. package/rpc/rpc_server.mjs +0 -10
  139. package/src/core/network/messaging/NetworkMessages.js +0 -63
  140. package/src/core/network/messaging/handlers/GetRequestHandler.js +0 -112
  141. package/src/core/network/messaging/handlers/ResponseHandler.js +0 -108
  142. package/src/core/network/messaging/handlers/RoleOperationHandler.js +0 -116
  143. package/src/core/network/messaging/handlers/SubnetworkOperationHandler.js +0 -143
  144. package/src/core/network/messaging/handlers/TransferOperationHandler.js +0 -52
  145. package/src/core/network/messaging/routes/NetworkMessageRouter.js +0 -94
  146. package/src/core/network/messaging/validators/AdminResponse.js +0 -58
  147. package/src/core/network/messaging/validators/CustomNodeResponse.js +0 -46
  148. package/src/core/state/utils/indexerEntry.js +0 -105
  149. package/src/messages/base/StateBuilder.js +0 -25
  150. package/src/messages/completeStateMessages/CompleteStateMessageBuilder.js +0 -421
  151. package/src/messages/completeStateMessages/CompleteStateMessageDirector.js +0 -252
  152. package/src/messages/completeStateMessages/CompleteStateMessageOperations.js +0 -299
  153. package/src/messages/partialStateMessages/PartialStateMessageBuilder.js +0 -272
  154. package/src/messages/partialStateMessages/PartialStateMessageDirector.js +0 -137
  155. package/src/messages/partialStateMessages/PartialStateMessageOperations.js +0 -131
  156. package/src/utils/crypto.js +0 -11
  157. package/tests/integration/apply/addAdmin/addAdminBasic.test.js +0 -68
  158. package/tests/integration/apply/addAdmin/addAdminRecovery.test.js +0 -125
  159. package/tests/integration/apply/addIndexer.test.js +0 -237
  160. package/tests/integration/apply/addWhitelist.test.js +0 -53
  161. package/tests/integration/apply/addWriter.test.js +0 -244
  162. package/tests/integration/apply/apply.test.js +0 -19
  163. package/tests/integration/apply/banValidator.test.js +0 -109
  164. package/tests/integration/apply/postTx/invalidSubValues.test.js +0 -103
  165. package/tests/integration/apply/postTx/postTx.test.js +0 -222
  166. package/tests/integration/apply/removeIndexer.test.js +0 -128
  167. package/tests/integration/apply/removeWriter.test.js +0 -167
  168. package/tests/integration/apply/transfer.test.js +0 -81
  169. package/tests/integration/integration.test.js +0 -9
  170. package/tests/unit/messageOperations/assembleAddIndexerMessage.test.js +0 -21
  171. package/tests/unit/messageOperations/assembleAddWriterMessage.test.js +0 -16
  172. package/tests/unit/messageOperations/assembleAdminMessage.test.js +0 -69
  173. package/tests/unit/messageOperations/assembleBanWriterMessage.test.js +0 -16
  174. package/tests/unit/messageOperations/assemblePostTransaction.test.js +0 -442
  175. package/tests/unit/messageOperations/assembleRemoveIndexerMessage.test.js +0 -19
  176. package/tests/unit/messageOperations/assembleRemoveWriterMessage.test.js +0 -17
  177. package/tests/unit/messageOperations/assembleWhitelistMessages.test.js +0 -58
  178. package/tests/unit/messageOperations/commonsStateMessageOperationsTest.js +0 -277
  179. package/tests/unit/messageOperations/stateMessageOperations.test.js +0 -19
  180. package/tests/unit/state/utils/indexerEntry.test.js +0 -83
  181. package/tests/unit/state/utils/transaction.test.js +0 -97
  182. package/tests/unit/utils/crypto/createHash.test.js +0 -15
  183. /package/rpc/{constants.mjs → constants.js} +0 -0
  184. /package/rpc/{cors.mjs → cors.js} +0 -0
  185. /package/rpc/utils/{confirmedParameter.mjs → confirmedParameter.js} +0 -0
  186. /package/rpc/utils/{url.mjs → url.js} +0 -0
  187. /package/src/utils/{operations.js → applyOperations.js} +0 -0
@@ -1,19 +0,0 @@
1
- import {default as test} from 'brittle';
2
-
3
- async function runCheckTests() {
4
- test.pause();
5
- await import('./addAdmin/addAdminBasic.test.js');
6
- await import('./addAdmin/addAdminRecovery.test.js');
7
- await import('./addWhitelist.test.js');
8
- await import('./addWriter.test.js');
9
- await import('./removeWriter.test.js');
10
- await import('./addIndexer.test.js');
11
- await import('./removeIndexer.test.js');
12
- await import('./postTx/postTx.test.js');
13
- await import('./transfer.test.js');
14
- await import('./postTx/invalidSubValues.test.js');
15
- await import('./banValidator.test.js')
16
- test.resume();
17
- }
18
-
19
- await runCheckTests();
@@ -1,109 +0,0 @@
1
- import { test, hook } from '../../helpers/wrapper.js';
2
-
3
- import {
4
- initTemporaryDirectory,
5
- removeTemporaryDirectory,
6
- setupMsbWriter,
7
- setupMsbIndexer,
8
- setupMsbAdmin,
9
- tryToSyncWriters
10
- } from '../../helpers/setupApplyTests.js';
11
- import { randomBytes } from '../../helpers/setupApplyTests.js';
12
- import CompleteStateMessageOperations from '../../../src/messages/completeStateMessages/CompleteStateMessageOperations.js';
13
- import { testKeyPair1, testKeyPair2, testKeyPair3, testKeyPair4 } from '../../fixtures/apply.fixtures.js';
14
- import { sleep } from '../../../src/utils/helpers.js';
15
- import b4a from 'b4a'
16
-
17
- let admin;
18
- let indexer, writer1, writer2;
19
- let tmpDirectory;
20
-
21
- hook('Initialize nodes for banValidator tests', async () => {
22
- const randomChannel = randomBytes(32).toString('hex');
23
- const baseOptions = {
24
- enable_tx_apply_logs: false,
25
- enable_interactive_mode: false,
26
- enable_role_requester: false,
27
- channel: randomChannel,
28
- enable_validator_observer: false,
29
- }
30
- tmpDirectory = await initTemporaryDirectory();
31
- admin = await setupMsbAdmin(testKeyPair1, tmpDirectory, baseOptions);
32
-
33
- indexer = await setupMsbWriter(admin, 'indexer', testKeyPair2, tmpDirectory, admin.options);
34
- indexer = await setupMsbIndexer(indexer, admin);
35
-
36
- writer1 = await setupMsbWriter(admin, 'writer1', testKeyPair3, tmpDirectory, admin.options);
37
- writer2 = await setupMsbWriter(admin, 'writer2', testKeyPair4, tmpDirectory, admin.options);
38
- });
39
-
40
- test('handleApplyBanValidatorOperation (apply) - Append banValidator payload - ban indexer', async t => {
41
- const validity = await admin.msb.state.getIndexerSequenceState()
42
- const assembledBanWriter = await CompleteStateMessageOperations.assembleBanWriterMessage(admin.wallet, indexer.wallet.address, validity);
43
- await admin.msb.state.append(assembledBanWriter);
44
- await tryToSyncWriters(admin, indexer, writer1, writer2);
45
-
46
- const indexersEntry = await indexer.msb.state.getIndexersEntry();
47
- const nodeInfo = await indexer.msb.state.getNodeEntry(indexer.wallet.address);
48
-
49
- t.is(indexersEntry.length, 2, 'Indexers entry count should be 2');
50
- t.is(!!indexersEntry.find(({ key }) => b4a.equals(key, indexer.msb.state.writingKey)), true, 'Indexer address should be still included in the indexers entry');
51
- t.is(nodeInfo.isIndexer, true, 'Node info should indicate that the node is still an indexer');
52
- });
53
-
54
- test('handleApplyBanValidatorOperation (apply) - Append banValidator payload into the base by non-admin node', async t => {
55
- const validity = await admin.msb.state.getIndexerSequenceState()
56
- const assembledBanWriter = await CompleteStateMessageOperations.assembleBanWriterMessage(writer1.wallet, writer2.wallet.address, validity);
57
- await writer1.msb.state.append(assembledBanWriter);
58
- await sleep(5000); // wait for both peers to sync state
59
- await tryToSyncWriters(admin);
60
-
61
- const nodeInfo = await writer2.msb.state.getNodeEntry(writer2.wallet.address);
62
-
63
- t.is(nodeInfo.isWriter, true, 'Node info should indicate that the node is still a writer');
64
- t.is(nodeInfo.isWhitelisted, true, 'Node info should indicate that the node is still whitelisted');
65
- });
66
-
67
-
68
- test('handleApplyBanValidatorOperation (apply) - Append banValidator payload into the base - happy path', async t => {
69
- const validity = await admin.msb.state.getIndexerSequenceState()
70
- const assembledBanWriter = await CompleteStateMessageOperations.assembleBanWriterMessage(admin.wallet, writer1.wallet.address, validity);
71
- await admin.msb.state.append(assembledBanWriter);
72
- await sleep(5000); // wait for both peers to sync state
73
-
74
- const nodeInfo = await writer1.msb.state.getNodeEntry(writer1.wallet.address);
75
-
76
- t.is(nodeInfo.isWriter, false, 'Node info should indicate that the node is not a writer anymore');
77
- t.is(nodeInfo.isWhitelisted, false, 'Node info should indicate that the node is not whitelisted anymore');
78
- t.is(writer1.msb.state.isWritable(), false, 'Writer1 should not be a writer anymore');
79
- });
80
-
81
- test('handleApplyBanValidatorOperation (apply) - Append banValidator payload into the base - idempotence', async t => {
82
- const validity = await admin.msb.state.getIndexerSequenceState()
83
- const assembledBanWriter = await CompleteStateMessageOperations.assembleBanWriterMessage(admin.wallet, writer2.wallet.address, validity);
84
- await admin.msb.state.append(assembledBanWriter);
85
- await sleep(5000); // wait for both peers to sync state
86
-
87
- const nodeInfo = await writer2.msb.state.getNodeEntry(writer2.wallet.address);
88
-
89
- const validity2 = await admin.msb.state.getIndexerSequenceState()
90
- const assembledBanWriter2 = await CompleteStateMessageOperations.assembleBanWriterMessage(admin.wallet, writer2.wallet.address, validity2);
91
- await admin.msb.state.append(assembledBanWriter2);
92
- await sleep(5000); // wait for both peers to sync state
93
-
94
- t.is(nodeInfo.isIndexer, false, 'Node info should indicate that the node is not a writer anymore');
95
- t.is(nodeInfo.isWriter, false, 'Node info should indicate that the node is not a writer anymore');
96
- t.is(nodeInfo.isWhitelisted, false, 'Node info should indicate that the node is not whitelisted anymore');
97
- t.is(writer1.msb.state.isWritable(), false, 'Writer2 should not be a writer anymore');
98
- t.is(writer1.msb.state.isIndexer(), false, 'Writer2 should not be a writer anymore');
99
- });
100
-
101
- hook('Clean up banValidator setup', async t => {
102
- const toClose = [];
103
- if (admin?.msb) toClose.push(admin.msb.close());
104
- if (indexer?.msb) toClose.push(indexer.msb.close());
105
- if (writer1?.msb) toClose.push(writer1.msb.close());
106
- if (writer2?.msb) toClose.push(writer2.msb.close());
107
- await Promise.all(toClose);
108
- if (tmpDirectory) await removeTemporaryDirectory(tmpDirectory);
109
- });
@@ -1,103 +0,0 @@
1
- import {hook, test} from '../../../helpers/wrapper.js';
2
- import {
3
- generatePostTx,
4
- initTemporaryDirectory,
5
- randomBytes,
6
- removeTemporaryDirectory,
7
- setupMsbAdmin,
8
- setupMsbPeer,
9
- setupMsbWriter,
10
- fundPeer,
11
- deployExternalBootstrap,
12
- tryToSyncWriters,
13
- waitDemotion,
14
- promoteToWriter
15
- } from '../../../helpers/setupApplyTests.js';
16
- import {safeDecodeApplyOperation, safeEncodeApplyOperation} from '../../../../src/utils/protobuf/operationHelpers.js'
17
- import {testKeyPair1, testKeyPair2, testKeyPair4, testKeyPair5} from '../../../fixtures/apply.fixtures.js';
18
- import { $TNK } from '../../../../src/core/state/utils/balance.js';
19
- import { decode as decodeNodeEntry } from '../../../../src/core/state/utils/nodeEntry.js';
20
-
21
- let tmpDirectory, admin, writer, externalNode, externalBootstrap, maliciousPeer;
22
- // is and vs is already covered
23
- const testCases = [
24
- { name: 'modified tx', mod: (txPayload, maliciousValue) => { return { ...txPayload.txo, tx: maliciousValue }; } },
25
- { name: 'modified incoming writingKey', mod: (txPayload, maliciousValue) => { return { ...txPayload.txo, iw: maliciousValue }; } },
26
- { name: 'modified incoming nonce', mod: (txPayload, maliciousValue) => { return { ...txPayload.txo, in: maliciousValue }; } },
27
- { name: 'modified content hash', mod: (txPayload, maliciousValue) => { return { ...txPayload.txo, ch: maliciousValue }; } },
28
- { name: 'modified external bootstrap', mod: (txPayload, maliciousValue) => { return { ...txPayload.txo, bs: maliciousValue }; } },
29
- { name: 'modified MSB bootstrap', mod: (txPayload, maliciousValue) => { return { ...txPayload.txo, mbs: maliciousValue }; } },
30
- { name: 'modified validator nonce', mod: (txPayload, maliciousValue) => { return { ...txPayload.txo, vn: maliciousValue }; } },
31
- ];
32
-
33
- const close = async node => {
34
- await node.msb.close()
35
- }
36
-
37
- hook('Initialize nodes', async t => {
38
- const randomChannel = randomBytes(32).toString('hex');
39
-
40
- const baseOptions = {
41
- enable_tx_apply_logs: false,
42
- enable_interactive_mode: false,
43
- enable_role_requester: false,
44
- enable_validator_observer: false,
45
- channel: randomChannel,
46
- }
47
-
48
- tmpDirectory = await initTemporaryDirectory();
49
- admin = await setupMsbAdmin(testKeyPair1, tmpDirectory, baseOptions);
50
- writer = await setupMsbWriter(admin, 'writer1', testKeyPair2, tmpDirectory, admin.options);
51
- externalNode = await setupMsbPeer('reader1', testKeyPair4, tmpDirectory, admin.options);
52
- await fundPeer(admin, externalNode, $TNK(1n)) // we fund it since it will deploy stuff
53
- externalBootstrap = await deployExternalBootstrap(writer, externalNode)
54
- await tryToSyncWriters(writer, admin)
55
- maliciousPeer = await setupMsbPeer('maliciousWriter', testKeyPair5, tmpDirectory, admin.options);
56
- await fundPeer(admin, maliciousPeer, $TNK(10n))
57
- });
58
-
59
- test('handleApplyTxOperation (apply) - invalid txo sub-values', async t => {
60
- const {postTx, txHash} = await generatePostTx(writer, externalNode, externalBootstrap)
61
- const decodedPostTx = safeDecodeApplyOperation(postTx);
62
-
63
- for (let i = 0; i < testCases.length; i++) {
64
- const testCase = testCases[i]
65
-
66
- const maliciousWriter = await promoteToWriter(admin, maliciousPeer)
67
- // all of these values are buffers 32 bytes long
68
- const maliciousValue = randomBytes(32);
69
-
70
- const modifiedTxo = testCase.mod(decodedPostTx, maliciousValue);
71
- const modifiedPostTx = {
72
- ...decodedPostTx,
73
- txo: modifiedTxo
74
- };
75
- const encodedMaliciousPostTx = safeEncodeApplyOperation(modifiedPostTx);
76
-
77
- await waitDemotion(maliciousWriter, async () => {
78
- await maliciousWriter.msb.state.append(encodedMaliciousPostTx);
79
- })
80
-
81
- if (testCase.name === 'modified tx') {
82
- const result = await admin.msb.state.get(maliciousValue.toString('hex'));
83
- t.absent(result, `post tx with ${testCase.name} should not be added to the base`);
84
- } else {
85
- const result = await admin.msb.state.get(txHash);
86
- t.absent(result, `post tx with ${testCase.name} should not be added to the base`);
87
- }
88
-
89
- // should be penalized
90
- const node = decodeNodeEntry(await maliciousWriter.msb.state.get(maliciousWriter.wallet.address))
91
- t.ok(node, 'Result should not be null');
92
- t.is(node.isWriter, false, 'Result should indicate that the peer is not a writer');
93
- }
94
- });
95
-
96
- hook('Clean up postTx setup', async t => {
97
- // close msbBoostrap and remove temp directory
98
- if (writer?.msb) await close(writer)
99
- if (externalNode?.msb) await close(externalNode)
100
- if (admin?.msb) await close(admin)
101
- if (maliciousPeer?.msb) await close(maliciousPeer)
102
- if (tmpDirectory) await removeTemporaryDirectory(tmpDirectory);
103
- });
@@ -1,222 +0,0 @@
1
- import {hook, test} from '../../../helpers/wrapper.js';
2
- import b4a from "b4a";
3
- import {
4
- generatePostTx,
5
- initTemporaryDirectory,
6
- randomBytes,
7
- removeTemporaryDirectory,
8
- setupMsbAdmin,
9
- setupMsbPeer,
10
- setupMsbWriter,
11
- tick,
12
- fundPeer,
13
- deployExternalBootstrap,
14
- tryToSyncWriters,
15
- waitForHash,
16
- waitDemotion,
17
- promoteToWriter
18
- } from '../../../helpers/setupApplyTests.js';
19
- import {safeDecodeApplyOperation, safeEncodeApplyOperation} from '../../../../src/utils/protobuf/operationHelpers.js'
20
- import {testKeyPair1, testKeyPair2, testKeyPair3, testKeyPair4, testKeyPair5} from '../../../fixtures/apply.fixtures.js';
21
- import {OperationType} from "../../../../src/utils/constants.js";
22
- import {addressToBuffer} from "../../../../src/core/state/utils/address.js";
23
- import { $TNK } from '../../../../src/core/state/utils/balance.js';
24
-
25
- let tmpDirectory, admin, writer, externalNode, externalBootstrap, maliciousPeer;
26
-
27
- const close = async node => {
28
- await node.msb.close()
29
- }
30
-
31
- hook('Initialize nodes', async t => {
32
- const randomChannel = randomBytes(32).toString('hex');
33
-
34
- const baseOptions = {
35
- enable_tx_apply_logs: false,
36
- enable_interactive_mode: false,
37
- enable_role_requester: false,
38
- enable_validator_observer: false,
39
- channel: randomChannel,
40
- }
41
-
42
- tmpDirectory = await initTemporaryDirectory();
43
- admin = await setupMsbAdmin(testKeyPair1, tmpDirectory, baseOptions);
44
- writer = await setupMsbWriter(admin, 'writer1', testKeyPair2, tmpDirectory, admin.options);
45
- externalNode = await setupMsbPeer('reader1', testKeyPair4, tmpDirectory, admin.options);
46
- await fundPeer(admin, externalNode, $TNK(1n)) // we fund it since it will deploy stuff
47
- externalBootstrap = await deployExternalBootstrap(writer, externalNode)
48
- await tryToSyncWriters(writer, admin)
49
- maliciousPeer = await setupMsbPeer('maliciousWriter', testKeyPair5, tmpDirectory, admin.options);
50
- await fundPeer(admin, maliciousPeer, $TNK(10n))
51
- });
52
-
53
- test('handleApplyTxOperation (apply) - Append POST_TX into the base - Happy path', async t => {
54
- const {postTx, txHash} = await generatePostTx(writer, externalNode, externalBootstrap)
55
- await writer.msb.state.append(postTx)
56
- await waitForHash(writer, txHash)
57
- await tick();
58
-
59
- const result = await writer.msb.state.get(txHash);
60
- t.ok(result, 'post tx added to the base');
61
- })
62
-
63
- // Negative cases
64
-
65
- // TODO: This test has been disabled because we got rid of JSON schema validation in favor of protobuf validation. To enable this test again, we need to write a fake protobuf schema for postTx (maybe also for other operations) and forge an invalid payload.
66
-
67
- // test('nested object in postTx', async t => {
68
- // //is already tested in /test/check/postTx.test.js
69
- // let { postTx, preTxHash: txHash } = await generatePostTx(admin.msb, admin.wallet, legitWallet)
70
- // postTx = {
71
- // ...postTx,
72
- // foo: 'bar',
73
- // }
74
- // await admin.msb.state.append(postTx);
75
- // await tick();
76
-
77
- // t.absent(await admin.msb.state.get(txHash), 'post tx with nested object should not be added to the base');
78
- // postTx = {
79
- // ...postTx,
80
- // value: {
81
- // ...postTx.value,
82
- // foo: 'bar',
83
- // }
84
- // }
85
- // await admin.msb.state.append(postTx);
86
- // await tick();
87
- // t.absent(await admin.msb.state.get(txHash), 'post tx with nested object in value property should not be added to the base');
88
-
89
- // })
90
-
91
- test('handleApplyTxOperation (apply) - different operation type', async t => {
92
- const maliciousWriter = await promoteToWriter(admin, maliciousPeer)
93
- const {postTx, txHash} = await generatePostTx(writer, externalNode, externalBootstrap)
94
- const replaceByte = (input, index, replacement) => {
95
- const bufferHex = b4a.from(input, 'hex');
96
- bufferHex[index] = replacement;
97
- return b4a.from(bufferHex, 'hex');
98
- }
99
-
100
- const replacedPostTx = replaceByte(b4a.toString(postTx, 'hex'), 1, OperationType.ADD_ADMIN);
101
-
102
- await waitDemotion(maliciousWriter, async () => {
103
- await maliciousWriter.msb.state.append(replacedPostTx);
104
- })
105
- await tick();
106
-
107
- t.absent(await writer.msb.state.get(txHash), 'post tx with incorrect operation type should not be added to the base');
108
- })
109
-
110
- // test('handleApplyTxOperation (apply) - replay attack', async t => {
111
- // const {postTx, txHash} = await generatePostTx(writer, externalNode, externalBootstrap)
112
- // const rawTx = await CompleteStateMessageOperations.assembleCompleteTransactionOperationMessage(
113
- // writer.msb.wallet,
114
- // postTx.address,
115
- // b4a.from(postTx.txo.tx, 'hex'),
116
- // b4a.from(postTx.txo.txv, 'hex'),
117
- // b4a.from(postTx.txo.iw, 'hex'),
118
- // b4a.from(postTx.txo.in, 'hex'),
119
- // b4a.from(postTx.txo.ch, 'hex'),
120
- // b4a.from(postTx.txo.is, 'hex'),
121
- // b4a.from(postTx.txo.bs, 'hex'),
122
- // b4a.from(postTx.txo.mbs, 'hex')
123
- // );
124
- // await writer.msb.state.append(rawTx);
125
- // await tick();
126
- // await sleep(500)
127
- // const firstRes = await writer.msb.state.base.view.get(txHash);
128
-
129
- // await writer.msb.state.append(rawTx);
130
- // await sleep(500)
131
- // await tick();
132
- // const secondRes = await writer.msb.state.base.view.get(txHash);
133
-
134
- // t.is(firstRes.seq, secondRes.seq, 'post tx should not be added to the base twice');
135
- // })
136
-
137
- test('handleApplyTxOperation (apply) - invalid postTx signature (adversary signature - writer signature)', async t => {
138
- const maliciousWriter = await promoteToWriter(admin, maliciousPeer)
139
- const {postTx, txHash} = await generatePostTx(writer, externalNode, externalBootstrap)
140
- let decodedPostTx = safeDecodeApplyOperation(postTx);
141
-
142
- decodedPostTx.txo.vs = maliciousWriter.wallet.sign(
143
- b4a.concat([decodedPostTx.txo.tx, decodedPostTx.txo.vn])
144
- );
145
- const encodedMaliciousPostTx = safeEncodeApplyOperation(decodedPostTx);
146
- await waitDemotion(maliciousWriter, async () => {
147
- await maliciousWriter.msb.state.append(encodedMaliciousPostTx);
148
- })
149
-
150
- const result = await admin.msb.state.get(txHash);
151
- t.absent(result, 'adversary\'s fake signature should not be added to the base');
152
- });
153
-
154
-
155
- test('handleApplyTxOperation (apply) - invalid postTx signature (adversary signature - peer signature)', async t => {
156
- const maliciousWriter = await promoteToWriter(admin, maliciousPeer)
157
- const {postTx, txHash} = await generatePostTx(writer, externalNode, externalBootstrap)
158
-
159
- let decodedPostTx = safeDecodeApplyOperation(postTx);
160
-
161
- decodedPostTx.txo.is = maliciousWriter.wallet.sign(
162
- decodedPostTx.txo.tx
163
- );
164
- const encodedMaliciousPostTx = safeEncodeApplyOperation(decodedPostTx);
165
- await waitDemotion(maliciousWriter, async () => {
166
- await maliciousWriter.msb.state.append(encodedMaliciousPostTx);
167
- })
168
-
169
- const result = await writer.msb.state.get(txHash);
170
- t.absent(result, 'adversary prepared fake postTx signature (third key pair) should not be added to the base');
171
- });
172
-
173
- test('handleApplyTxOperation (apply) - oversized transaction', async t => {
174
- const maliciousWriter = await promoteToWriter(admin, maliciousPeer)
175
- const {postTx, txHash} = await generatePostTx(writer, externalNode, externalBootstrap)
176
- let decodedPostTx = safeDecodeApplyOperation(postTx);
177
-
178
- decodedPostTx.txo.vn = randomBytes(5000);
179
- const encodedMaliciousPostTx = safeEncodeApplyOperation(decodedPostTx);
180
-
181
- await waitDemotion(maliciousWriter, async () => {
182
- await maliciousWriter.msb.state.append(encodedMaliciousPostTx);
183
- })
184
- const result = await admin.msb.state.get(txHash);
185
- t.absent(result, 'oversized post tx should not be added to the base');
186
- });
187
-
188
- test('handleApplyTxOperation (apply) - invalid postTx address (malicious node replaces address)', async t => {
189
- const maliciousWriter = await promoteToWriter(admin, maliciousPeer)
190
- const {postTx, txHash} = await generatePostTx(writer, externalNode, externalBootstrap)
191
- let decodedPostTx = safeDecodeApplyOperation(postTx);
192
- decodedPostTx.address = addressToBuffer(maliciousWriter.wallet.address);
193
- const encodedMaliciousPostTx = safeEncodeApplyOperation(decodedPostTx);
194
- await maliciousWriter.msb.state.append(encodedMaliciousPostTx);
195
- await waitDemotion(maliciousWriter, async () => {
196
- await maliciousWriter.msb.state.append(encodedMaliciousPostTx);
197
- })
198
- const result = await admin.msb.state.get(txHash);
199
- t.absent(result, 'post tx with malicious address should not be added to the base');
200
- });
201
-
202
- test('handleApplyTxOperation (apply) - invalid postTx txo.ia (malicious node replaces ia)', async t => {
203
- const maliciousWriter = await promoteToWriter(admin, maliciousPeer)
204
- const {postTx, txHash} = await generatePostTx(writer, externalNode, externalBootstrap)
205
- let decodedPostTx = safeDecodeApplyOperation(postTx);
206
- decodedPostTx.txo.ia = addressToBuffer(maliciousWriter.wallet.address);
207
- const encodedMaliciousPostTx = safeEncodeApplyOperation(decodedPostTx);
208
- await waitDemotion(maliciousWriter, async () => {
209
- await maliciousWriter.msb.state.append(encodedMaliciousPostTx);
210
- })
211
- const result = await admin.msb.state.get(txHash);
212
- t.absent(result, 'post tx with malicious txo.ia should not be added to the base');
213
- });
214
-
215
- hook('Clean up postTx setup', async t => {
216
- // close msbBoostrap and remove temp directory
217
- if (writer?.msb) await close(writer)
218
- if (externalNode?.msb) await close(externalNode)
219
- if (admin?.msb) await close(admin)
220
- if (maliciousPeer?.msb) await close(maliciousPeer)
221
- if (tmpDirectory) await removeTemporaryDirectory(tmpDirectory);
222
- });
@@ -1,128 +0,0 @@
1
- import {test, hook} from '../../helpers/wrapper.js';
2
-
3
- import CompleteStateMessageOperations from '../../../src/messages/completeStateMessages/CompleteStateMessageOperations.js';
4
- import {
5
- initTemporaryDirectory,
6
- removeTemporaryDirectory,
7
- setupMsbAdmin,
8
- setupMsbWriter,
9
- randomBytes,
10
- setupMsbIndexer, waitForNodeState, tryToSyncWriters
11
- } from '../../helpers/setupApplyTests.js';
12
- import {testKeyPair1, testKeyPair2, testKeyPair3, testKeyPair4} from '../../fixtures/apply.fixtures.js';
13
- import b4a from 'b4a'
14
-
15
- let tmpDirectory, admin, indexer1, indexer2, writer;
16
-
17
- hook('Initialize nodes for addIndexer tests', async t => {
18
- const randomChannel = randomBytes(32).toString('hex');
19
- const baseOptions = {
20
- enable_tx_apply_logs: false,
21
- enable_interactive_mode: false,
22
- enable_role_requester: false,
23
- enable_validator_observer: false,
24
- channel: randomChannel,
25
- }
26
- tmpDirectory = await initTemporaryDirectory();
27
-
28
- admin = await setupMsbAdmin(testKeyPair1, tmpDirectory, baseOptions);
29
- indexer1 = await setupMsbWriter(admin, 'indexer1', testKeyPair2, tmpDirectory, admin.options);
30
- indexer1 = await setupMsbIndexer(indexer1, admin);
31
-
32
- indexer2 = await setupMsbWriter(admin, 'indexer2', testKeyPair3, tmpDirectory, admin.options);
33
- indexer2 = await setupMsbIndexer(indexer2, admin);
34
-
35
- writer = await setupMsbWriter(admin, 'writer', testKeyPair4, tmpDirectory, admin.options);
36
- });
37
-
38
- test('handleApplyRemoveIndexerOperation (apply) - Append removeIndexer payload into the base - happy path', async t => {
39
- // indexer1 is already an indexer -> this indexer will lose its indexer status and will become a writer.
40
- // indexer2 is already an indexer
41
- // writer is already a writer
42
- const indexersEntryBefore = await writer.msb.state.getIndexersEntry();
43
- const validity = await admin.msb.state.getIndexerSequenceState()
44
- const assembledRemoveIndexerMessage = await CompleteStateMessageOperations.assembleRemoveIndexerMessage(admin.wallet, indexer1.wallet.address, validity);
45
- await admin.msb.state.append(assembledRemoveIndexerMessage);
46
- await tryToSyncWriters(admin, indexer1, indexer2);
47
- await waitForNodeState(indexer1, indexer1.wallet.address, {
48
- wk: indexer1.msb.state.writingKey,
49
- isWhitelisted: true,
50
- isWriter: true,
51
- isIndexer: false,
52
- })
53
-
54
- const indexersEntry = await indexer1.msb.state.getIndexersEntry();
55
- const nodeEntryIndexer1 = await indexer1.msb.state.getNodeEntry(indexer1.wallet.address);
56
-
57
- t.is(indexersEntry.length, indexersEntryBefore.length - 1, `Indexers entry count should be still ${indexersEntryBefore.length - 1}`);
58
- t.is(!!indexersEntry.find(({ key }) => b4a.equals(key, indexer1.msb.state.writingKey)), false, 'Indexer address should not be included in the indexers entry');
59
- t.is(nodeEntryIndexer1.isWriter, true, 'Node info should indicate that the node is a writer');
60
- t.is(nodeEntryIndexer1.isIndexer, false, 'Node info should indicate that the node is not an indexer');
61
- });
62
-
63
-
64
- test('handleApplyRemoveIndexerOperation (apply) - Append removeIndexer payload into the base - idempotence', async t => {
65
- // indexer1 is already a writer (after the previous test) -> let's test idempotence on this node.
66
- // indexer2 is already an indexer
67
- // writer is already a writer
68
- const adminSignedLengthBefore = admin.msb.state.getSignedLength();
69
- const indexer2SignedLengthBefore = indexer2.msb.state.getSignedLength();
70
- const writerSignedLengthBefore = writer.msb.state.getSignedLength();
71
-
72
- const indexersEntryBefore = await indexer1.msb.state.getIndexersEntry();
73
- const validity = await admin.msb.state.getIndexerSequenceState()
74
- const assembledRemoveIndexerMessage = await CompleteStateMessageOperations.assembleRemoveIndexerMessage(admin.wallet, indexer1.wallet.address, validity);
75
- await admin.msb.state.append(assembledRemoveIndexerMessage);
76
- await tryToSyncWriters(admin, indexer2, writer);
77
-
78
- const adminSignedLengthAfter = admin.msb.state.getSignedLength();
79
- const indexer2SignedLengthAfter = indexer2.msb.state.getSignedLength();
80
- const writerSignedLengthAfter = writer.msb.state.getSignedLength();
81
-
82
- const indexersEntry = await indexer1.msb.state.getIndexersEntry();
83
- const nodeInfo = await indexer1.msb.state.getNodeEntry(indexer1.wallet.address);
84
-
85
- t.is(indexersEntry.length, indexersEntryBefore.length, `Indexers entry count should remain ${indexersEntryBefore.length}`);
86
- t.is(!!indexersEntry.find(({ key }) => b4a.equals(key, indexer1.msb.state.writingKey)), false, 'Indexer address should not be included in the indexers entry');
87
- t.is(nodeInfo.isWriter, true, 'Node info should indicate that the node is a writer');
88
- t.is(nodeInfo.isIndexer, false, 'Node info should indicate that the node is not an indexer');
89
- t.is(adminSignedLengthBefore, adminSignedLengthAfter, 'Admin signed length should not change');
90
- t.is(indexer2SignedLengthBefore, indexer2SignedLengthAfter, 'Indexer2 signed length should not change');
91
- t.is(writerSignedLengthBefore, writerSignedLengthAfter, 'Writer signed length should not change');
92
- });
93
-
94
- test('handleApplyAddIndexerOperation (apply) - Append removeIndexer payload into the base by non-admin node', async t => {
95
- // indexer1 is already a writer.
96
- // indexer2 is already an indexer -> should still be an indexer after the operation.
97
- // writer is already a writer -> will try to remove indexer2 as a non-admin node, however it should not be allowed.
98
- const indexersEntryBefore = await indexer2.msb.state.getIndexersEntry();
99
- const writerSignedLengthBefore = admin.msb.state.getSignedLength();
100
- const indexer2SignedLengthBefore = indexer2.msb.state.getSignedLength();
101
-
102
- const validity = await admin.msb.state.getIndexerSequenceState()
103
- const assembledRemoveIndexerMessage = await CompleteStateMessageOperations.assembleRemoveIndexerMessage(admin.wallet, indexer2.wallet.address, validity);
104
- await writer.msb.state.append(assembledRemoveIndexerMessage);
105
- await tryToSyncWriters(admin, indexer2, writer);
106
-
107
- const writerSignedLengthAfter = writer.msb.state.getSignedLength();
108
- const indexer2SignedLengthAfter = indexer2.msb.state.getSignedLength();
109
-
110
- const indexersEntry = await indexer2.msb.state.getIndexersEntry();
111
- const nodeInfo = await indexer2.msb.state.getNodeEntry(indexer2.wallet.address);
112
-
113
- t.is(indexersEntry.length, indexersEntryBefore.length, `Indexers entry count should be still ${indexersEntryBefore.length}`);
114
- t.is(!!indexersEntry.find(({ key }) => b4a.equals(key, indexer2.msb.state.writingKey)), true, 'Indexer address should not be included in the indexers entry');
115
- t.is(nodeInfo.isIndexer, true, 'Node info should indicate that the node is an indexer');
116
- t.is(writerSignedLengthBefore, writerSignedLengthAfter, 'Writer signed length should not change');
117
- t.is(indexer2SignedLengthBefore, indexer2SignedLengthAfter, 'Indexer2 signed length should not change');
118
- });
119
-
120
- hook('Clean up removeIndexer setup', async t => {
121
- const toClose = []
122
- if (admin?.msb) toClose.push(admin.msb.close());
123
- if (indexer1?.msb) toClose.push(indexer1.msb.close());
124
- if (indexer2?.msb) toClose.push(indexer2.msb.close());
125
- if (writer?.msb) toClose.push(writer.msb.close());
126
- await Promise.all(toClose)
127
- if (tmpDirectory) await removeTemporaryDirectory(tmpDirectory);
128
- });