trac-msb 0.2.8 → 0.2.10

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 (151) hide show
  1. package/.github/workflows/acceptance-tests.yml +7 -11
  2. package/.github/workflows/lint-pr-title.yml +26 -0
  3. package/.github/workflows/unit-tests.yml +2 -8
  4. package/CODE_OF_CONDUCT.md +128 -0
  5. package/README.md +33 -18
  6. package/docker-compose.yml +1 -0
  7. package/docs/trac_network_http_api.openapi.yaml +889 -0
  8. package/msb.mjs +5 -22
  9. package/package.json +14 -10
  10. package/proto/network.proto +74 -0
  11. package/rpc/create_server.js +2 -2
  12. package/rpc/handlers.js +165 -92
  13. package/rpc/routes/v1.js +3 -1
  14. package/rpc/rpc_server.js +4 -4
  15. package/rpc/rpc_services.js +62 -25
  16. package/rpc/utils/helpers.js +83 -52
  17. package/src/config/args.js +46 -0
  18. package/src/config/config.js +78 -5
  19. package/src/config/env.js +70 -3
  20. package/src/core/network/Network.js +34 -70
  21. package/src/core/network/identity/NetworkWalletFactory.js +2 -2
  22. package/src/core/network/protocols/LegacyProtocol.js +67 -0
  23. package/src/core/network/protocols/NetworkMessages.js +48 -0
  24. package/src/core/network/protocols/ProtocolInterface.js +31 -0
  25. package/src/core/network/protocols/ProtocolSession.js +59 -0
  26. package/src/core/network/protocols/V1Protocol.js +64 -0
  27. package/src/core/network/protocols/legacy/NetworkMessageRouter.js +84 -0
  28. package/src/core/network/protocols/legacy/handlers/GetRequestHandler.js +53 -0
  29. package/src/core/network/protocols/legacy/handlers/ResponseHandler.js +37 -0
  30. package/src/core/network/{messaging → protocols/legacy}/validators/base/BaseResponse.js +2 -3
  31. package/src/core/network/protocols/shared/handlers/RoleOperationHandler.js +88 -0
  32. package/src/core/network/protocols/shared/handlers/SubnetworkOperationHandler.js +93 -0
  33. package/src/core/network/{messaging → protocols/shared}/handlers/TransferOperationHandler.js +17 -16
  34. package/src/core/network/{messaging → protocols/shared}/handlers/base/BaseOperationHandler.js +10 -15
  35. package/src/core/network/{messaging → protocols/shared}/validators/PartialBootstrapDeployment.js +2 -2
  36. package/src/core/network/{messaging → protocols/shared}/validators/PartialRoleAccess.js +5 -5
  37. package/src/core/network/{messaging → protocols/shared}/validators/PartialTransaction.js +4 -4
  38. package/src/core/network/{messaging → protocols/shared}/validators/PartialTransfer.js +4 -4
  39. package/src/core/network/{messaging → protocols/shared}/validators/base/PartialOperation.js +14 -12
  40. package/src/core/network/protocols/v1/NetworkMessageRouter.js +15 -0
  41. package/src/core/network/services/ConnectionManager.js +5 -5
  42. package/src/core/network/services/MessageOrchestrator.js +2 -2
  43. package/src/core/network/services/TransactionPoolService.js +5 -6
  44. package/src/core/network/services/TransactionRateLimiterService.js +12 -13
  45. package/src/core/network/services/ValidatorObserverService.js +5 -6
  46. package/src/core/state/State.js +3 -5
  47. package/src/index.js +156 -181
  48. package/src/messages/network/v1/NetworkMessageBuilder.js +325 -0
  49. package/src/messages/network/v1/NetworkMessageDirector.js +137 -0
  50. package/src/messages/network/v1/networkMessageFactory.js +12 -0
  51. package/src/messages/state/ApplyStateMessageBuilder.js +661 -0
  52. package/src/messages/state/ApplyStateMessageDirector.js +516 -0
  53. package/src/messages/state/applyStateMessageFactory.js +12 -0
  54. package/src/utils/buffer.js +53 -1
  55. package/src/utils/check.js +1 -1
  56. package/src/utils/cli.js +0 -8
  57. package/src/utils/constants.js +33 -30
  58. package/src/utils/fileUtils.js +13 -0
  59. package/src/utils/normalizers.js +84 -2
  60. package/src/utils/protobuf/network.cjs +840 -0
  61. package/src/utils/protobuf/operationHelpers.js +10 -0
  62. package/src/utils/type.js +26 -0
  63. package/tests/acceptance/v1/balance/balance.test.mjs +1 -2
  64. package/tests/acceptance/v1/broadcast-transaction/broadcast-transaction.test.mjs +26 -30
  65. package/tests/acceptance/v1/health/health.test.mjs +33 -0
  66. package/tests/acceptance/v1/rpc.test.mjs +4 -3
  67. package/tests/acceptance/v1/tx/tx.test.mjs +27 -16
  68. package/tests/acceptance/v1/tx-details/tx-details.test.mjs +26 -12
  69. package/tests/fixtures/check.fixtures.js +33 -32
  70. package/tests/fixtures/networkV1.fixtures.js +85 -0
  71. package/tests/fixtures/protobuf.fixtures.js +109 -25
  72. package/tests/helpers/StateNetworkFactory.js +2 -2
  73. package/tests/helpers/address.js +6 -0
  74. package/tests/helpers/autobaseTestHelpers.js +2 -1
  75. package/tests/helpers/config.js +2 -1
  76. package/tests/helpers/setupApplyTests.js +59 -56
  77. package/tests/unit/messages/messages.test.js +12 -0
  78. package/tests/unit/messages/network/NetworkMessageBuilder.test.js +276 -0
  79. package/tests/unit/messages/network/NetworkMessageDirector.test.js +201 -0
  80. package/tests/unit/messages/state/applyStateMessageBuilder.complete.test.js +521 -0
  81. package/tests/unit/messages/state/applyStateMessageBuilder.partial.test.js +233 -0
  82. package/tests/unit/network/ConnectionManager.test.js +6 -5
  83. package/tests/unit/network/networkModule.test.js +3 -2
  84. package/tests/unit/state/apply/addAdmin/addAdminHappyPathScenario.js +10 -6
  85. package/tests/unit/state/apply/addAdmin/addAdminScenarioHelpers.js +9 -6
  86. package/tests/unit/state/apply/addAdmin/state.apply.addAdmin.test.js +10 -7
  87. package/tests/unit/state/apply/addIndexer/addIndexerScenarioHelpers.js +18 -21
  88. package/tests/unit/state/apply/addWriter/addWriterScenarioHelpers.js +53 -38
  89. package/tests/unit/state/apply/adminRecovery/adminRecoveryScenarioHelpers.js +46 -35
  90. package/tests/unit/state/apply/appendWhitelist/appendWhitelistScenarioHelpers.js +13 -16
  91. package/tests/unit/state/apply/balanceInitialization/balanceInitializationScenarioHelpers.js +17 -11
  92. package/tests/unit/state/apply/banValidator/banValidatorScenarioHelpers.js +11 -12
  93. package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentScenarioHelpers.js +9 -7
  94. package/tests/unit/state/apply/common/commonScenarioHelper.js +15 -14
  95. package/tests/unit/state/apply/common/payload-structure/initializationDisabledScenario.js +9 -4
  96. package/tests/unit/state/apply/disableInitialization/disableInitializationScenarioHelpers.js +17 -11
  97. package/tests/unit/state/apply/removeWriter/removeWriterScenarioHelpers.js +19 -14
  98. package/tests/unit/state/apply/transfer/transferDoubleSpendAcrossValidatorsScenario.js +37 -29
  99. package/tests/unit/state/apply/transfer/transferScenarioHelpers.js +9 -7
  100. package/tests/unit/state/apply/txOperation/txOperationScenarioHelpers.js +11 -9
  101. package/tests/unit/unit.test.js +1 -1
  102. package/tests/unit/utils/buffer/buffer.test.js +62 -1
  103. package/tests/unit/utils/fileUtils/readAddressesFromWhitelistFile.test.js +4 -3
  104. package/tests/unit/utils/fileUtils/readBalanceMigrationFile.test.js +3 -2
  105. package/tests/unit/utils/migrationUtils/validateAddressFromIncomingFile.test.js +3 -2
  106. package/tests/unit/utils/normalizers/normalizers.test.js +469 -0
  107. package/tests/unit/utils/protobuf/operationHelpers.test.js +120 -2
  108. package/tests/unit/utils/type/type.test.js +25 -0
  109. package/tests/unit/utils/utils.test.js +1 -0
  110. package/docs/networking-dualstack-plan.md +0 -75
  111. package/docs/networking-layer-redesign.md +0 -155
  112. package/src/core/network/messaging/NetworkMessages.js +0 -64
  113. package/src/core/network/messaging/handlers/GetRequestHandler.js +0 -113
  114. package/src/core/network/messaging/handlers/ResponseHandler.js +0 -107
  115. package/src/core/network/messaging/handlers/RoleOperationHandler.js +0 -114
  116. package/src/core/network/messaging/handlers/SubnetworkOperationHandler.js +0 -149
  117. package/src/core/network/messaging/routes/NetworkMessageRouter.js +0 -98
  118. package/src/core/network/messaging/validators/AdminResponse.js +0 -58
  119. package/src/core/network/messaging/validators/CustomNodeResponse.js +0 -46
  120. package/src/messages/base/StateBuilder.js +0 -25
  121. package/src/messages/completeStateMessages/CompleteStateMessageBuilder.js +0 -425
  122. package/src/messages/completeStateMessages/CompleteStateMessageDirector.js +0 -252
  123. package/src/messages/completeStateMessages/CompleteStateMessageOperations.js +0 -296
  124. package/src/messages/partialStateMessages/PartialStateMessageBuilder.js +0 -272
  125. package/src/messages/partialStateMessages/PartialStateMessageDirector.js +0 -137
  126. package/src/messages/partialStateMessages/PartialStateMessageOperations.js +0 -138
  127. package/tests/integration/apply/addAdmin/addAdminBasic.test.js +0 -69
  128. package/tests/integration/apply/addAdmin/addAdminRecovery.test.js +0 -126
  129. package/tests/integration/apply/addIndexer.test.js +0 -239
  130. package/tests/integration/apply/addWhitelist.test.js +0 -53
  131. package/tests/integration/apply/addWriter.test.js +0 -245
  132. package/tests/integration/apply/apply.test.js +0 -19
  133. package/tests/integration/apply/banValidator.test.js +0 -116
  134. package/tests/integration/apply/postTx/invalidSubValues.test.js +0 -103
  135. package/tests/integration/apply/postTx/postTx.test.js +0 -196
  136. package/tests/integration/apply/removeIndexer.test.js +0 -132
  137. package/tests/integration/apply/removeWriter.test.js +0 -168
  138. package/tests/integration/apply/transfer.test.js +0 -83
  139. package/tests/integration/integration.test.js +0 -9
  140. package/tests/unit/messageOperations/assembleAddIndexerMessage.test.js +0 -21
  141. package/tests/unit/messageOperations/assembleAddWriterMessage.test.js +0 -17
  142. package/tests/unit/messageOperations/assembleAdminMessage.test.js +0 -68
  143. package/tests/unit/messageOperations/assembleBanWriterMessage.test.js +0 -17
  144. package/tests/unit/messageOperations/assemblePostTransaction.test.js +0 -424
  145. package/tests/unit/messageOperations/assembleRemoveIndexerMessage.test.js +0 -19
  146. package/tests/unit/messageOperations/assembleRemoveWriterMessage.test.js +0 -17
  147. package/tests/unit/messageOperations/assembleWhitelistMessages.test.js +0 -59
  148. package/tests/unit/messageOperations/commonsStateMessageOperationsTest.js +0 -278
  149. package/tests/unit/messageOperations/stateMessageOperations.test.js +0 -19
  150. /package/src/core/network/{messaging → protocols/legacy}/validators/ValidatorResponse.js +0 -0
  151. /package/src/utils/{operations.js → applyOperations.js} +0 -0
@@ -1,138 +0,0 @@
1
- import PartialStateMessageBuilder from './PartialStateMessageBuilder.js';
2
- import PartialStateMessageDirector from './PartialStateMessageDirector.js';
3
-
4
- class PartialStateMessageOperations {
5
- #wallet;
6
- #config
7
-
8
- /**
9
- * @param {PeerWallet} wallet - Wallet of the requester/invoker node that broadcasts the operation
10
- * @param {object} config - A configuration object
11
- */
12
- constructor(wallet, config) {
13
- this.#wallet = wallet;
14
- this.#config = config;
15
- }
16
-
17
- /**
18
- * Assembles a PARTIAL bootstrap deployment operation, which can be sent to a validator.
19
- * The validator can sign this operation to make it COMPLETE and broadcast it to the network.
20
- * Bootstrap deployment is required to register a subnetwork. The network will reject
21
- * TransactionOperation messages for external bootstraps that are not registered.
22
- * Do NOT attempt to register the MSB bootstrap key.
23
- * @param {String} externalBootstrap - Bootstrap key from the subnetwork to be registered.
24
- * MUST be different from the MSB bootstrap key.
25
- * BEFORE deploying ensure if the subnetwork bootstrap is not already deployed.
26
- * @param {String} txValidity - Transaction validity hash representing the current indexer combination.
27
- * The operation remains valid as long as indexer keys maintain their order.
28
- * Acts as protection against deferred execution attacks.
29
- * @returns {Promise<Object>} The assembled bootstrap deployment operation message
30
- * @throws {Error} If assembly of the bootstrap deployment operation message fails
31
- */
32
- async assembleBootstrapDeploymentMessage(externalBootstrap, channel, txValidity) {
33
- try {
34
- const builder = new PartialStateMessageBuilder(this.#wallet, this.#config);
35
- const director = new PartialStateMessageDirector();
36
- director.builder = builder;
37
- return await director.buildPartialBootstrapDeploymentMessage(
38
- this.#wallet.address,
39
- externalBootstrap,
40
- channel,
41
- txValidity
42
- );
43
- } catch (error) {
44
- throw new Error(`Failed to assemble partial bootstrap deployment message: ${error.message}`);
45
- }
46
- }
47
-
48
- async assembleAddWriterMessage(writingKey, txValidity) {
49
- try {
50
- const builder = new PartialStateMessageBuilder(this.#wallet, this.#config);
51
- const director = new PartialStateMessageDirector();
52
- director.builder = builder;
53
- return await director.buildAddWriterMessage(this.#wallet.address, writingKey, txValidity);
54
- } catch (error) {
55
- throw new Error(`Failed to assemble add writer message: ${error.message}`);
56
- }
57
- }
58
-
59
- async assembleRemoveWriterMessage(writerKey, txValidity) {
60
- try {
61
- const builder = new PartialStateMessageBuilder(this.#wallet, this.#config);
62
- const director = new PartialStateMessageDirector();
63
- director.builder = builder;
64
- return await director.buildRemoveWriterMessage(this.#wallet.address, writerKey, txValidity);
65
- } catch (error) {
66
- throw new Error(`Failed to assemble remove writer message: ${error.message}`);
67
- }
68
- }
69
-
70
- async assembleAdminRecoveryMessage(writingKey, txValidity) {
71
- try {
72
- const builder = new PartialStateMessageBuilder(this.#wallet, this.#config);
73
- const director = new PartialStateMessageDirector();
74
- director.builder = builder;
75
- return await director.buildAdminRecoveryMessage(this.#wallet.address, writingKey, txValidity);
76
- } catch (error) {
77
- throw new Error(`Failed to assemble admin recovery message: ${error.message}`);
78
- }
79
- }
80
-
81
-
82
- /**
83
- * Assembles a PARTIAL transaction operation, which can be sent to a validator, who can then
84
- * sign the transaction to make it COMPLETE.
85
- * @param {String} incomingWritingKey - Writing key from the subnetwork, used for authentication of the requesting node
86
- * @param {String} txValidity - Transaction validity hash representing current indexer combination.
87
- * Transaction remains valid as long as indexer keys maintain their order.
88
- * Acts as protection against deferred execution attacks.
89
- * @param {String} contentHash - Hash of the contract content from the subnetwork,
90
- * ensures data integrity between networks
91
- * @param {String} externalBootstrap - Bootstrap key from the subnetwork,
92
- * used for cross-network communication verification.
93
- * MUST BE DIFFERENT from the MSB bootstrap key.
94
- * transaction will be rejected if external bootstrap won't be
95
- * deployed in the MSB (bootstrapDeploymentOperation).
96
- * @param {String} msbBootstrap - Main Settlement Bus bootstrap key,
97
- * used for internal network verification
98
- * @returns {Promise<Object>} The assembled transaction operation message
99
- * @throws {Error} If assembly of the transaction operation message fails
100
- */
101
- async assembleTransactionOperationMessage(incomingWritingKey, txValidity, contentHash, externalBootstrap, msbBootstrap) {
102
- try {
103
- const builder = new PartialStateMessageBuilder(this.#wallet, this.#config);
104
- const director = new PartialStateMessageDirector();
105
- director.builder = builder;
106
- return await director.buildTransactionOperationMessage(
107
- this.#wallet.address,
108
- incomingWritingKey,
109
- txValidity,
110
- contentHash,
111
- externalBootstrap,
112
- msbBootstrap
113
- );
114
- } catch (error) {
115
- throw new Error(`Failed to assemble transaction operation message: ${error.message}`);
116
- }
117
- }
118
-
119
- async assembleTransferOperationMessage(recipientAddress, amount, txValidity) {
120
- try {
121
- const builder = new PartialStateMessageBuilder(this.#wallet, this.#config);
122
- const director = new PartialStateMessageDirector();
123
- director.builder = builder;
124
- return await director.buildTransferOperationMessage(
125
- this.#wallet.address,
126
- recipientAddress,
127
- amount,
128
- txValidity
129
- );
130
- } catch (error) {
131
- throw new Error(`Failed to assemble transfer operation message: ${error.message}`);
132
- }
133
-
134
- }
135
-
136
- }
137
-
138
- export default PartialStateMessageOperations;
@@ -1,69 +0,0 @@
1
- import {test, hook} from '../../../helpers/wrapper.js';
2
- import {
3
- initMsbAdmin, initTemporaryDirectory, removeTemporaryDirectory, setupMsbPeer, setupMsbWriter, setupMsbIndexer,
4
- tryToSyncWriters
5
- } from '../../../helpers/setupApplyTests.js';
6
- import {randomBytes} from '../../../helpers/setupApplyTests.js';
7
- import CompleteStateMessageOperations from '../../../../src/messages/completeStateMessages/CompleteStateMessageOperations.js';
8
- import { config } from '../../../helpers/config.js';
9
- import {testKeyPair1} from '../../../fixtures/apply.fixtures.js';
10
- import b4a from 'b4a';
11
- import { ADMIN_INITIAL_BALANCE } from '../../../../src/utils/constants.js';
12
-
13
- //TODO: ADD TEST WHEN NON-ADMIN NODE FORGES ADD ADMIN OPERATION AND BROADCASTS IT TO THE STATE - SHOULD BE REJECTED
14
-
15
- let admin;
16
- let tmpDirectory;
17
- let randomChannel;
18
-
19
- const sendAddAdmin = async (invoker) => {
20
- const validity = b4a.from(await admin.msb.state.getIndexerSequenceState(), 'hex')
21
- const addAdminMessage = await new CompleteStateMessageOperations(admin.wallet, config)
22
- .assembleAddAdminMessage(
23
- admin.msb.state.writingKey,
24
- validity
25
- );
26
-
27
- // add admin to base
28
- await invoker.msb.state.append(addAdminMessage); // Send `add admin` request to apply function
29
- }
30
-
31
- hook('Initialize admin for addAdmin tests', async () => {
32
- randomChannel = randomBytes(32).toString('hex');
33
- const baseOptions = {
34
- enableTxApplyLogs: false,
35
- enableInteractiveMode: false,
36
- enableRoleRequester: false,
37
- channel: randomChannel,
38
- enableValidatorObserver: false,
39
- }
40
- tmpDirectory = await initTemporaryDirectory();
41
- admin = await initMsbAdmin(testKeyPair1, tmpDirectory, baseOptions);
42
- await admin.msb.ready();
43
- });
44
-
45
- test('Apply function addAdmin for the first time - happy path', async (k) => {
46
- const writersLength = await admin.msb.state.getWriterLength();
47
- const adminEntryBefore = await admin.msb.state.getAdminEntry();
48
- k.is(adminEntryBefore, null, 'Admin entry should be null before adding a new admin');
49
-
50
- await sendAddAdmin(admin)
51
- await tryToSyncWriters(admin);
52
- const adminEntryAfter = await admin.msb.state.getAdminEntry(); // check if the admin entry was added successfully in the base
53
- const nodeAdminEntry = await admin.msb.state.getNodeEntry(adminEntryAfter.address)
54
- const newWritersLength = await admin.msb.state.getWriterLength();
55
- // check the result
56
- k.ok(adminEntryAfter, 'Result should not be null');
57
- k.ok(adminEntryAfter.address === admin.wallet.address, 'Admin address in base should match admin wallet address');
58
- k.ok(b4a.equals(adminEntryAfter.wk, admin.msb.state.writingKey), 'Admin writing key in base should match admin MSB writing key');
59
- k.ok(b4a.equals(adminEntryAfter.wk, admin.options.bootstrap), 'Admin writing key in base should match bootstrap key');
60
- k.is(nodeAdminEntry.isWriter, true, 'Admin should be writer');
61
- k.is(nodeAdminEntry.isIndexer, true, 'Admin should be indexer');
62
- k.ok(b4a.equals(nodeAdminEntry.balance, ADMIN_INITIAL_BALANCE), 'Admin should have an initial balance');
63
- k.is(newWritersLength, writersLength + 1, 'Admin should increase writers length');
64
- });
65
-
66
- hook('Clean up addAdmin recovery setup', async () => {
67
- if (admin && admin.msb) await admin.msb.close();
68
- if (tmpDirectory) await removeTemporaryDirectory(tmpDirectory);
69
- });
@@ -1,126 +0,0 @@
1
- import {test, hook} from '../../../helpers/wrapper.js';
2
- import {
3
- initTemporaryDirectory, removeTemporaryDirectory, setupMsbPeer, setupMsbWriter, setupMsbIndexer,
4
- tryToSyncWriters, waitForAdminEntry, setupMsbAdmin
5
- } from '../../../helpers/setupApplyTests.js';
6
-
7
- import {randomBytes} from '../../../helpers/setupApplyTests.js';
8
- import CompleteStateMessageOperations from '../../../../src/messages/completeStateMessages/CompleteStateMessageOperations.js';
9
- import PartialStateMessageOperations from '../../../../src/messages/partialStateMessages/PartialStateMessageOperations.js'
10
- import {testKeyPair1, testKeyPair2, testKeyPair3, testKeyPair4} from '../../../fixtures/apply.fixtures.js';
11
- import b4a from 'b4a';
12
- import { decode as decodeAdmin } from '../../../../src/core/state/utils/adminEntry.js';
13
- import { EntryType } from '../../../../src/utils/constants.js';
14
- import { config } from '../../../helpers/config.js';
15
- //TODO: ADD TEST WHEN NON-ADMIN NODE FORGES ADD ADMIN OPERATION AND BROADCASTS IT TO THE STATE - SHOULD BE REJECTED
16
-
17
- let admin, newAdmin;
18
- let indexer1, indexer2, writer;
19
- let tmpDirectory;
20
- let randomChannel;
21
-
22
- hook('Initialize admin for addAdmin tests', async () => {
23
- randomChannel = randomBytes(32).toString('hex');
24
- const baseOptions = {
25
- enableTxApplyLogs: false,
26
- enableInteractiveMode: false,
27
- enableRoleRequester: false,
28
- channel: randomChannel,
29
- enableValidatorObserver: false,
30
- }
31
- tmpDirectory = await initTemporaryDirectory()
32
- admin = await setupMsbAdmin(testKeyPair1, tmpDirectory, baseOptions);
33
-
34
- // Setup nodes
35
- writer = await setupMsbWriter(admin, 'writer', testKeyPair2, tmpDirectory, admin.options);
36
- indexer1 = await setupMsbWriter(admin, 'indexer1', testKeyPair3, tmpDirectory, admin.options);
37
- indexer2 = await setupMsbWriter(admin, 'indexer2', testKeyPair4, tmpDirectory, admin.options);
38
-
39
- // Setup indexers after network is stable
40
- indexer1 = await setupMsbIndexer(indexer1, admin);
41
- indexer2 = await setupMsbIndexer(indexer2, admin);
42
- });
43
-
44
- test('Apply function addAdmin for recovery - happy path', async (k) => {
45
- const formerBootstrap = admin.options.bootstrap
46
- await tryToSyncWriters(admin, writer, indexer1, indexer2);
47
-
48
- const adminEntryBefore = await admin.msb.state.getAdminEntry();
49
- const admI1 = await indexer1.msb.state.getAdminEntry();
50
- const admI2 = await indexer2.msb.state.getAdminEntry();
51
- const admW = await writer.msb.state.getAdminEntry();
52
-
53
- await waitForAdminEntry(admin, {
54
- address: admin.wallet.address,
55
- wk: admin.msb.state.writingKey
56
- })
57
-
58
- await waitForAdminEntry(indexer1, {
59
- address: admin.wallet.address,
60
- wk: admin.msb.state.writingKey
61
- })
62
-
63
- await waitForAdminEntry(indexer2, {
64
- address: admin.wallet.address,
65
- wk: admin.msb.state.writingKey
66
- })
67
-
68
- await waitForAdminEntry(writer, {
69
- address: admin.wallet.address,
70
- wk: admin.msb.state.writingKey
71
- })
72
-
73
- // waitForIndexersConnection
74
-
75
- k.ok(adminEntryBefore !== null, 'Admin entry should not be null before recovery');
76
- k.ok(b4a.equals(adminEntryBefore.wk, admin.options.bootstrap), 'Admin writing key in base should match bootstrap key');
77
- k.ok(b4a.equals(adminEntryBefore.wk, admI1.wk), 'Admin entry writer key the same as indexer');
78
- k.ok(b4a.equals(admI1.wk, admI2.wk), 'Admin entry should be the same for both indexers');
79
- k.ok(b4a.equals(admI1.wk, admW.wk), 'Admin entry should be the same for writer');
80
- k.ok(adminEntryBefore.address === admI1.address, 'Admin entry address the same as indexer');
81
- k.ok(admI1.address === admI2.address, 'Admin address should be the same for both indexers');
82
- k.ok(admI1.address === admW.address, 'Admin address should be the same for writer');
83
- const adminAddressBeforeRecovery = admin.wallet.address
84
-
85
- // Simulate recovery by creating a new admin instance
86
- newAdmin = await setupMsbPeer('newAdmin', testKeyPair1, tmpDirectory, admin.options);
87
- await admin.msb.close(); // close the admin instance to simulate recovery
88
- await newAdmin.msb.ready();
89
- await newAdmin.msb.state.append(null);
90
- const validity = b4a.toString(await newAdmin.msb.state.getIndexerSequenceState(), 'hex')
91
- const addAdminMessage = await new PartialStateMessageOperations(newAdmin.wallet, config)
92
- .assembleAdminRecoveryMessage(
93
- b4a.toString(newAdmin.msb.state.writingKey, 'hex'),
94
- validity
95
- );
96
-
97
- const rawTx = await new CompleteStateMessageOperations(writer.wallet, config)
98
- .assembleAdminRecoveryMessage(
99
- addAdminMessage.address,
100
- b4a.from(addAdminMessage.rao.tx, 'hex'),
101
- b4a.from(addAdminMessage.rao.txv, 'hex'),
102
- b4a.from(addAdminMessage.rao.iw, 'hex'),
103
- b4a.from(addAdminMessage.rao.in, 'hex'),
104
- b4a.from(addAdminMessage.rao.is, 'hex')
105
- )
106
- await writer.msb.state.append(rawTx)
107
- await tryToSyncWriters(writer, indexer1, indexer2, newAdmin);
108
- const adminEntryAfter = decodeAdmin(await writer.msb.state.get(EntryType.ADMIN), config.addressPrefix); // check if the admin entry was added successfully in the base
109
- k.ok(adminEntryAfter, 'Result should not be null');
110
- k.ok(adminEntryAfter.address === newAdmin.wallet.address, 'New Admin address in base should match new admin wallet address');
111
- k.ok(adminAddressBeforeRecovery === newAdmin.wallet.address, 'New Admin wallet address should be the same as old admin wallet address');
112
- k.ok(b4a.equals(adminEntryAfter.wk, newAdmin.msb.state.writingKey), 'New Admin writing key in base should match new admin MSB writing key');
113
- k.ok(!b4a.equals(adminEntryBefore.wk, adminEntryAfter.wk), 'New Admin writing key in base should have changed');
114
- k.ok(!b4a.equals(adminEntryAfter.wk, formerBootstrap), 'New Admin should not be bootstrap anymore');
115
- //k.ok(newAdmin.msb.state.isWritable(), 'New Admin should be a writer');
116
- // k.ok(newAdmin.msb.state.isIndexer(), 'New Admin should be an indexer'); // wait until holepunch team will fix bug with rotation.
117
- });
118
-
119
- hook('Clean up addAdmin recovery setup', async () => {
120
- if (admin && admin.msb) await admin.msb.close();
121
- if (newAdmin && newAdmin.msb) await newAdmin.msb.close();
122
- if (indexer1 && indexer1.msb) await indexer1.msb.close();
123
- if (indexer2 && indexer2.msb) await indexer2.msb.close();
124
- if (writer && writer.msb) await writer.msb.close();
125
- if (tmpDirectory) await removeTemporaryDirectory(tmpDirectory);
126
- });
@@ -1,239 +0,0 @@
1
- import {test, hook, solo} from 'brittle';
2
- import CompleteStateMessageOperations from '../../../src/messages/completeStateMessages/CompleteStateMessageOperations.js';
3
- import {
4
- initTemporaryDirectory,
5
- removeTemporaryDirectory,
6
- setupMsbAdmin,
7
- setupMsbWriter,
8
- randomBytes,
9
- setupMsbPeer,
10
- setupWhitelist, waitForNodeState, tryToSyncWriters, waitIndexer
11
- } from '../../helpers/setupApplyTests.js';
12
- import {
13
- testKeyPair1,
14
- testKeyPair2,
15
- testKeyPair3,
16
- testKeyPair4,
17
- testKeyPair5,
18
- testKeyPair6,
19
- testKeyPair7
20
- } from '../../fixtures/apply.fixtures.js';
21
- import b4a from 'b4a';
22
- import { config } from '../../helpers/config.js';
23
-
24
- let tmpDirectory, admin, indexer1, indexer2, reader1, reader2, indexer3, writer;
25
-
26
- hook('Initialize nodes for addIndexer tests', async t => {
27
- const randomChannel = randomBytes(32).toString('hex');
28
- const baseOptions = {
29
- enableTxApplyLogs: false,
30
- enableInteractiveMode: false,
31
- enableRoleRequester: false,
32
- enableValidatorObserver: false,
33
- channel: randomChannel,
34
- }
35
-
36
- tmpDirectory = await initTemporaryDirectory()
37
- admin = await setupMsbAdmin(testKeyPair1, tmpDirectory, baseOptions);
38
-
39
- indexer1 = await setupMsbWriter(admin, 'indexer1', testKeyPair2, tmpDirectory, admin.options);
40
- indexer2 = await setupMsbWriter(admin, 'indexer2', testKeyPair3, tmpDirectory, admin.options);
41
- indexer3 = await setupMsbWriter(admin, 'indexer3', testKeyPair4, tmpDirectory, admin.options);
42
-
43
- reader1 = await setupMsbPeer('reader1', testKeyPair5, tmpDirectory, admin.options);
44
- reader2 = await setupMsbPeer('reader2', testKeyPair6, tmpDirectory, admin.options);
45
- await setupWhitelist(admin, [reader2.wallet.address]);
46
-
47
- writer = await setupMsbWriter(admin, 'writer', testKeyPair7, tmpDirectory, admin.options);
48
- });
49
-
50
- test('handleApplyAddIndexerOperation (apply) - Append addIndexer payload into the base - happy path', async t => {
51
- // indexer1 is already a writer -> this writer will become an indexer
52
- // indexer2 is already a writer.
53
- // reader1 is just a reading node.
54
- // reader2 is just a reading node.
55
- // indexer3 is just a writer.
56
- const oldIndexersEntry = await admin.msb.state.getIndexersEntry();
57
- const validity = await admin.msb.state.getIndexerSequenceState()
58
- const assembledAddIndexerMessage = await new CompleteStateMessageOperations(admin.wallet, config)
59
- .assembleAddIndexerMessage(indexer1.wallet.address, validity);
60
- await waitIndexer(indexer1, async () => await admin.msb.state.append(assembledAddIndexerMessage))
61
-
62
- await waitForNodeState(admin, indexer1.wallet.address, {
63
- wk: indexer1.msb.state.writingKey,
64
- isWhitelisted: true,
65
- isWriter: true,
66
- isIndexer: true,
67
- })
68
-
69
- const nodeInfo = await admin.msb.state.getNodeEntry(indexer1.wallet.address);
70
- const indexersEntry = await admin.msb.state.getIndexersEntry();
71
-
72
- t.is(indexersEntry.length, oldIndexersEntry.length + 1, 'Indexers entry count should be 2');
73
- t.is(!!indexersEntry.find(({ key }) => b4a.equals(key, indexer1.msb.state.writingKey)), true, 'Indexer address should not be included in the indexers entry');
74
- t.is(nodeInfo.isIndexer, true, 'Node info should indicate that the node is an indexer');
75
- });
76
-
77
- test('handleApplyAddIndexerOperation (apply) - Append addIndexer payload into the base - idempotence', async t => {
78
- // indexer1 is already an indexer.
79
- // indexer2 is already a writer -> this writer will become an indexer
80
- // writer is already a writer.
81
- // reader1 is just a reading node.
82
- // reader2 is just a reading node.
83
- // indexer3 is just a writer.
84
- const indexersEntryBefore = await admin.msb.state.getIndexersEntry();
85
- const assembledAddIndexerMessage = await new CompleteStateMessageOperations(admin.wallet, config)
86
- .assembleAddIndexerMessage(
87
- indexer2.wallet.address,
88
- await admin.msb.state.getIndexerSequenceState()
89
- );
90
- await waitIndexer(indexer2, async () => await admin.msb.state.append(assembledAddIndexerMessage))
91
-
92
- await waitForNodeState(admin, indexer2.wallet.address, {
93
- wk: indexer2.msb.state.writingKey,
94
- isWhitelisted: true,
95
- isWriter: true,
96
- isIndexer: true,
97
- })
98
-
99
- await tryToSyncWriters(admin, indexer1, indexer2);
100
-
101
- const adminSignedLengthBefore = admin.msb.state.getSignedLength();
102
- const reqAddIndexerMessageAgain = await new CompleteStateMessageOperations(admin.wallet, config).assembleAddIndexerMessage(
103
- indexer2.wallet.address,
104
- await admin.msb.state.getIndexerSequenceState()
105
- );
106
-
107
- await admin.msb.state.append(reqAddIndexerMessageAgain);
108
-
109
- await waitForNodeState(admin, indexer2.wallet.address, {
110
- wk: indexer2.msb.state.writingKey,
111
- isWhitelisted: true,
112
- isWriter: true,
113
- isIndexer: true,
114
- })
115
-
116
- await waitForNodeState(indexer2, indexer2.wallet.address, {
117
- wk: indexer2.msb.state.writingKey,
118
- isWhitelisted: true,
119
- isWriter: true,
120
- isIndexer: true,
121
- })
122
-
123
- const adminSignedLengthAfter = admin.msb.state.getSignedLength();
124
- const indexersEntry = await admin.msb.state.getIndexersEntry();
125
-
126
- t.is(indexersEntry.length, indexersEntryBefore.length + 1, `Indexers entry count should be ${indexersEntry.length}`);
127
- t.is(adminSignedLengthBefore, adminSignedLengthAfter, 'Admin signed length should not change');
128
- });
129
-
130
- test('handleApplyAddIndexerOperation (apply) - Append addIndexer payload into the base - candidate is not a writer', async t => {
131
- // indexer1 is already an indexer.
132
- // indexer2 is already an indexer.
133
- // reader1 is just a reading node -> will not become an indexer it will still a reader.
134
- // reader2 is just a reading node.
135
- // indexer3 is just a writer.
136
- const indexersEntryBefore = await indexer1.msb.state.getIndexersEntry();
137
- const validity = await admin.msb.state.getIndexerSequenceState()
138
- const reqAddReader = await new CompleteStateMessageOperations(admin.wallet, config)
139
- .assembleAddIndexerMessage(reader1.wallet.address, validity);
140
-
141
- const adminSignedLengthBefore = admin.msb.state.getSignedLength()
142
- const indexer1SignedLengthBefore = indexer1.msb.state.getSignedLength();
143
- const indexer2SignedLengthBefore = indexer2.msb.state.getSignedLength();
144
-
145
- await admin.msb.state.append(reqAddReader);
146
- await tryToSyncWriters(admin, indexer1, indexer2);
147
- const adminSignedLengthAfter = admin.msb.state.getSignedLength();
148
- const indexer1SignedLengthAfter = indexer1.msb.state.getSignedLength();
149
- const indexer2SignedLengthAfter = indexer2.msb.state.getSignedLength();
150
-
151
- const indexersEntry = await admin.msb.state.getIndexersEntry();
152
- const nodeInfo = await admin.msb.state.getNodeEntry(reader1.wallet.address);
153
-
154
- t.is(indexersEntry.length, indexersEntryBefore.length, `Indexers entry count should be ${indexersEntry.length}`);
155
- t.is(!!indexersEntry.find(({ key }) => b4a.equals(key, reader1.msb.state.writingKey)), false, 'Reader address should not be included in the indexers entry');
156
- t.is(nodeInfo, null, 'Node info should be null for reader');
157
- t.is(adminSignedLengthBefore, adminSignedLengthAfter, 'Admin signed length should not change');
158
- t.is(indexer1SignedLengthBefore, indexer1SignedLengthAfter, 'Indexer1 signed length should not change');
159
- t.is(indexer2SignedLengthBefore, indexer2SignedLengthAfter, 'Indexer2 signed length should not change');
160
- });
161
-
162
- test('handleApplyAddIndexerOperation (apply) - Append addIndexer payload into the base - candidate is not a writer, but whitelisted', async t => {
163
- // indexer1 is already an indexer.
164
- // indexer2 is already an indexer.
165
- // reader1 is just a reading node.
166
- // reader2 is just a reading node -> will be whitelisted -> wil try to become an indexer but will not be able to.
167
- // indexer3 is just a writer.
168
-
169
- const indexersEntryBeforeWhitelist = await admin.msb.state.getIndexersEntry();
170
- const adminSignedLengthBefore = admin.msb.state.getSignedLength();
171
- const validity = await admin.msb.state.getIndexerSequenceState()
172
- const reqAddIndexer2 = await new CompleteStateMessageOperations(admin.wallet, config)
173
- .assembleAddIndexerMessage(
174
- reader2.wallet.address,
175
- validity);
176
-
177
- await admin.msb.state.append(reqAddIndexer2);
178
- await tryToSyncWriters(admin, indexer1, indexer2);
179
-
180
-
181
- const adminSignedLengthAfter = admin.msb.state.getSignedLength();
182
-
183
- const indexersEntryAfterWhitelist = await admin.msb.state.getIndexersEntry();
184
- const nodeEntry = await admin.msb.state.getNodeEntry(reader2.wallet.address);
185
-
186
- t.is(indexersEntryAfterWhitelist.length, indexersEntryBeforeWhitelist.length, `Indexers entry count should be ${indexersEntryAfterWhitelist.length}`);
187
- t.is(!!indexersEntryAfterWhitelist.find(({ key }) => b4a.equals(key, reader2.msb.state.writingKey)), false, 'Reader address should not be included in the indexers entry');
188
- t.is(nodeEntry.isIndexer, false, 'Node info should not indicate that the node is an indexer');
189
- t.is(adminSignedLengthBefore, adminSignedLengthAfter, 'Admin signed length should not change');
190
- });
191
-
192
- test('handleApplyAddIndexerOperation (apply) - Append addIndexer payload into the base by non admin node (writer)', async t => {
193
- // indexer1 is already an indexer.
194
- // indexer2 is already an indexer.
195
- // reader1 is just a reading node.
196
- // reader2 is just a reading node.
197
- // indexer3 is just a writer -> writer will try to add indexer3 as an indexer, however it won't be able to because it is not an admin.
198
- // writer is just a writer.
199
- const indexersEntryBefore = await writer.msb.state.getIndexersEntry();
200
- const adminSignedLengthBefore = admin.msb.state.getSignedLength();
201
-
202
- const validity = await admin.msb.state.getIndexerSequenceState()
203
- const assembledAddIndexerMessage = await new CompleteStateMessageOperations(admin.wallet, config)
204
- .assembleAddIndexerMessage(
205
- indexer3.wallet.address,
206
- validity);
207
-
208
- await writer.msb.state.append(assembledAddIndexerMessage);
209
- await tryToSyncWriters(admin, writer, indexer1, indexer2);
210
-
211
- await waitForNodeState(writer, indexer3.wallet.address, {
212
- wk: indexer3.msb.state.writingKey,
213
- isWhitelisted: true,
214
- isWriter: true,
215
- isIndexer: false,
216
- })
217
-
218
- const adminSignedLengthAfter = admin.msb.state.getSignedLength();
219
- const indexersEntry = await writer.msb.state.getIndexersEntry();
220
- const nodeEntry = await writer.msb.state.getNodeEntry(indexer3.wallet.address);
221
-
222
- t.is(indexersEntry.length, indexersEntryBefore.length, `Indexers entry count should be ${indexersEntry.length}`);
223
- t.is(!!indexersEntry.find(({ key }) => b4a.equals(key, indexer3.msb.state.writingKey)), false, 'Indexer address should not be included in the indexers entry');
224
- t.is(nodeEntry.isIndexer, false, 'Node info should indicate that the node is not an indexer');
225
- t.is(adminSignedLengthBefore, adminSignedLengthAfter, 'Admin signed length should not change');
226
- });
227
-
228
-
229
- hook('Clean up addIndexer setup', async t => {
230
- const toClose = []
231
- if (admin?.msb) toClose.push(admin.msb.close());
232
- if (indexer1?.msb) toClose.push(indexer1.msb.close());
233
- if (indexer2?.msb) toClose.push(indexer2.msb.close());
234
- if (reader2?.msb) toClose.push(reader2.msb.close());
235
- if (reader1?.msb) toClose.push(reader1.msb.close());
236
- if (indexer3?.msb) toClose.push(indexer3.msb.close());
237
- await Promise.all(toClose)
238
- if (tmpDirectory) await removeTemporaryDirectory(tmpDirectory);
239
- });
@@ -1,53 +0,0 @@
1
- import { test, hook } from '../../helpers/wrapper.js';
2
- import b4a from 'b4a';
3
- import { setupMsbAdmin, initTemporaryDirectory, removeTemporaryDirectory, randomBytes } from '../../helpers/setupApplyTests.js';
4
- import { testKeyPair1, testKeyPair2 } from '../../fixtures/apply.fixtures.js';
5
- import fileUtils from '../../../src/utils/fileUtils.js';
6
- import CompleteStateMessageOperations from '../../../src/messages/completeStateMessages/CompleteStateMessageOperations.js';
7
- import { address as addressApi } from 'trac-crypto-api';
8
- import { config } from '../../helpers/config.js';
9
-
10
- let admin, whitelistKeys, tmpDirectory, originalReadAddressesFromWhitelistFile;
11
- const address = addressApi.encode(config.addressPrefix, b4a.from(testKeyPair2.publicKey, 'hex'))
12
- hook('Initialize admin node for addWhitelist tests', async () => {
13
- const randomChannel = randomBytes(32).toString('hex');
14
- const baseOptions = {
15
- enable_txchannels: false,
16
- enableTxApplyLogs: false,
17
- enableInteractiveMode: false,
18
- enableRoleRequester: false,
19
- channel: randomChannel,
20
- }
21
- tmpDirectory = await initTemporaryDirectory();
22
-
23
- // Configure admin
24
- admin = await setupMsbAdmin(testKeyPair1, tmpDirectory, baseOptions);
25
- await admin.msb.ready();
26
-
27
- // Configure whitelist
28
- whitelistKeys = [address];
29
- originalReadAddressesFromWhitelistFile = fileUtils.readAddressesFromWhitelistFile;
30
- fileUtils.readAddressesFromWhitelistFile = async () => whitelistKeys;
31
- });
32
-
33
- test('Apply function addWhitelist - happy path', async (t) => {
34
- const validity = await admin.msb.state.getIndexerSequenceState();
35
- const payload = await new CompleteStateMessageOperations(admin.wallet, config)
36
- .assembleAppendWhitelistMessages(validity, address);
37
-
38
- await admin.msb.state.append(payload);
39
- const isWhitelisted = await admin.msb.state.isAddressWhitelisted(address);
40
- t.is(isWhitelisted, true, 'Whitelist entry should be created and true');
41
- });
42
-
43
- //TODO: ADD TEST TO APPEND ADDRESS WHICH IS ALREADY WHITELISTED - SIGNED LENGTH SHOULD NOT CHANGE
44
-
45
- hook('Cleanup after addWhitelist tests', async () => {
46
- if (admin && admin.msb) {
47
- await admin.msb.close();
48
- }
49
- if (tmpDirectory) {
50
- await removeTemporaryDirectory(tmpDirectory);
51
- }
52
- fileUtils.readAddressesFromWhitelistFile = originalReadAddressesFromWhitelistFile;
53
- });