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
@@ -0,0 +1,276 @@
1
+ import { test } from 'brittle';
2
+ import b4a from 'b4a';
3
+ import PeerWallet from 'trac-wallet';
4
+ import { TRAC_NETWORK_MSB_MAINNET_PREFIX } from 'trac-wallet/constants.js';
5
+ import { v7 as uuidv7 } from 'uuid';
6
+ import NetworkWalletFactory from '../../../../src/core/network/identity/NetworkWalletFactory.js';
7
+ import NetworkMessageBuilder from '../../../../src/messages/network/v1/NetworkMessageBuilder.js';
8
+ import {
9
+ NetworkOperationType,
10
+ ResultCode as NetworkResultCode
11
+ } from '../../../../src/utils/constants.js';
12
+ import { decodeV1networkOperation, encodeV1networkOperation } from '../../../../src/utils/protobuf/operationHelpers.js';
13
+ import { errorMessageIncludes } from '../../../helpers/regexHelper.js';
14
+ import {
15
+ createMessage,
16
+ encodeCapabilities,
17
+ safeWriteUInt32BE,
18
+ idToBuffer,
19
+ timestampToBuffer
20
+ } from '../../../../src/utils/buffer.js';
21
+ import { addressToBuffer } from '../../../../src/core/state/utils/address.js';
22
+ import { config } from '../../../helpers/config.js';
23
+ import { testKeyPair1 } from '../../../fixtures/apply.fixtures.js';
24
+
25
+ function createWallet() {
26
+ const keyPair = {
27
+ publicKey: b4a.from(testKeyPair1.publicKey, 'hex'),
28
+ secretKey: b4a.from(testKeyPair1.secretKey, 'hex')
29
+ };
30
+ return NetworkWalletFactory.provide({
31
+ enableWallet: false,
32
+ keyPair,
33
+ networkPrefix: TRAC_NETWORK_MSB_MAINNET_PREFIX
34
+ });
35
+ }
36
+
37
+ function uniqueResultCodes() {
38
+ return [...new Set(Object.values(NetworkResultCode))].sort((a, b) => a - b);
39
+ }
40
+
41
+ test('NetworkMessageBuilder builds validator connection request and verifies signature', async t => {
42
+ const wallet = createWallet();
43
+ const builder = new NetworkMessageBuilder(wallet, config);
44
+
45
+ const id = uuidv7();
46
+ const caps = ['cap:b', 'cap:a'];
47
+
48
+ await builder
49
+ .setType(NetworkOperationType.VALIDATOR_CONNECTION_REQUEST)
50
+ .setId(id)
51
+ .setTimestamp()
52
+ .setIssuerAddress(wallet.address)
53
+ .setCapabilities(caps)
54
+ .buildPayload();
55
+
56
+ const payload = builder.getResult();
57
+ t.is(payload.type, NetworkOperationType.VALIDATOR_CONNECTION_REQUEST);
58
+ t.is(payload.id, id);
59
+ t.alike(payload.capabilities, caps);
60
+ t.ok(b4a.isBuffer(payload.validator_connection_request.nonce));
61
+ t.ok(b4a.isBuffer(payload.validator_connection_request.signature));
62
+
63
+ const message = createMessage(
64
+ payload.type,
65
+ idToBuffer(id),
66
+ timestampToBuffer(payload.timestamp),
67
+ addressToBuffer(wallet.address, config.addressPrefix),
68
+ payload.validator_connection_request.nonce,
69
+ encodeCapabilities(caps)
70
+ );
71
+ const hash = await PeerWallet.blake3(message);
72
+ t.ok(wallet.verify(payload.validator_connection_request.signature, hash, wallet.publicKey));
73
+
74
+ const roundTrip = decodeV1networkOperation(encodeV1networkOperation(payload));
75
+ t.is(roundTrip.type, NetworkOperationType.VALIDATOR_CONNECTION_REQUEST);
76
+ });
77
+
78
+ test('NetworkMessageBuilder iterates validator connection response ResultCode values', async t => {
79
+ const wallet = createWallet();
80
+ const builder = new NetworkMessageBuilder(wallet, config);
81
+ const id = uuidv7();
82
+ const otherAddress = 'trac1xm76l9qaujh7vqktk8302mw9sfrxau3l45w62hqfl4kasswt6yts0autkh';
83
+ const caps = ['cap:b', 'cap:a'];
84
+
85
+ for (const code of uniqueResultCodes()) {
86
+ await builder
87
+ .setType(NetworkOperationType.VALIDATOR_CONNECTION_RESPONSE)
88
+ .setId(id)
89
+ .setTimestamp()
90
+ .setIssuerAddress(otherAddress)
91
+ .setCapabilities(caps)
92
+ .setResultCode(code)
93
+ .buildPayload();
94
+
95
+ const payload = builder.getResult();
96
+ t.is(payload.type, NetworkOperationType.VALIDATOR_CONNECTION_RESPONSE);
97
+ t.is(payload.validator_connection_response.result, code);
98
+
99
+ const msg = createMessage(
100
+ payload.type,
101
+ idToBuffer(payload.id),
102
+ timestampToBuffer(payload.timestamp),
103
+ addressToBuffer(otherAddress, config.addressPrefix),
104
+ payload.validator_connection_response.nonce,
105
+ safeWriteUInt32BE(code, 0),
106
+ encodeCapabilities(caps)
107
+ );
108
+ const hash = await PeerWallet.blake3(msg);
109
+ t.ok(wallet.verify(payload.validator_connection_response.signature, hash, wallet.publicKey));
110
+
111
+ const decoded = decodeV1networkOperation(encodeV1networkOperation(payload));
112
+ t.is(decoded.validator_connection_response.result, code);
113
+ }
114
+ });
115
+
116
+ test('NetworkMessageBuilder iterates liveness response ResultCode values', async t => {
117
+ const wallet = createWallet();
118
+ const builder = new NetworkMessageBuilder(wallet, config);
119
+ const id = uuidv7();
120
+ const caps = ['cap:b', 'cap:a'];
121
+ const data = b4a.from('ping', 'utf8');
122
+
123
+ for (const code of uniqueResultCodes()) {
124
+ await builder
125
+ .setType(NetworkOperationType.LIVENESS_RESPONSE)
126
+ .setId(id)
127
+ .setTimestamp()
128
+ .setData(data)
129
+ .setCapabilities(caps)
130
+ .setResultCode(code)
131
+ .buildPayload();
132
+
133
+ const payload = builder.getResult();
134
+ t.is(payload.type, NetworkOperationType.LIVENESS_RESPONSE);
135
+ t.is(payload.liveness_response.result, code);
136
+
137
+ const msg = createMessage(
138
+ payload.type,
139
+ idToBuffer(payload.id),
140
+ timestampToBuffer(payload.timestamp),
141
+ payload.liveness_response.nonce,
142
+ safeWriteUInt32BE(code, 0),
143
+ encodeCapabilities(caps)
144
+ );
145
+ const hash = await PeerWallet.blake3(msg);
146
+ t.ok(wallet.verify(payload.liveness_response.signature, hash, wallet.publicKey));
147
+
148
+ const decoded = decodeV1networkOperation(encodeV1networkOperation(payload));
149
+ t.is(decoded.liveness_response.result, code);
150
+ }
151
+ });
152
+
153
+ test('NetworkMessageBuilder builds liveness request and verifies signature (data not signed)', async t => {
154
+ const wallet = createWallet();
155
+ const builder = new NetworkMessageBuilder(wallet, config);
156
+
157
+ const id = uuidv7();
158
+ const caps = ['cap:b', 'cap:a'];
159
+ const data = b4a.from('ping', 'utf8');
160
+
161
+ await builder
162
+ .setType(NetworkOperationType.LIVENESS_REQUEST)
163
+ .setId(id)
164
+ .setTimestamp()
165
+ .setData(data)
166
+ .setCapabilities(caps)
167
+ .buildPayload();
168
+
169
+ const payload = builder.getResult();
170
+ t.is(payload.type, NetworkOperationType.LIVENESS_REQUEST);
171
+ t.ok(b4a.isBuffer(payload.liveness_request.nonce));
172
+ t.ok(b4a.isBuffer(payload.liveness_request.signature));
173
+
174
+ const msg = createMessage(
175
+ payload.type,
176
+ idToBuffer(payload.id),
177
+ timestampToBuffer(payload.timestamp),
178
+ payload.liveness_request.nonce,
179
+ encodeCapabilities(caps)
180
+ );
181
+ const hash = await PeerWallet.blake3(msg);
182
+ t.ok(wallet.verify(payload.liveness_request.signature, hash, wallet.publicKey));
183
+ });
184
+
185
+ test('NetworkMessageBuilder iterates broadcast transaction response ResultCode values', async t => {
186
+ const wallet = createWallet();
187
+ const builder = new NetworkMessageBuilder(wallet, config);
188
+ const id = uuidv7();
189
+ const caps = ['cap:b', 'cap:a'];
190
+
191
+ for (const code of uniqueResultCodes()) {
192
+ await builder
193
+ .setType(NetworkOperationType.BROADCAST_TRANSACTION_RESPONSE)
194
+ .setId(id)
195
+ .setTimestamp()
196
+ .setCapabilities(caps)
197
+ .setResultCode(code)
198
+ .buildPayload();
199
+
200
+ const payload = builder.getResult();
201
+ t.is(payload.type, NetworkOperationType.BROADCAST_TRANSACTION_RESPONSE);
202
+ t.is(payload.broadcast_transaction_response.result, code);
203
+
204
+ const msg = createMessage(
205
+ payload.type,
206
+ idToBuffer(payload.id),
207
+ timestampToBuffer(payload.timestamp),
208
+ payload.broadcast_transaction_response.nonce,
209
+ safeWriteUInt32BE(code, 0),
210
+ encodeCapabilities(caps)
211
+ );
212
+ const hash = await PeerWallet.blake3(msg);
213
+ t.ok(wallet.verify(payload.broadcast_transaction_response.signature, hash, wallet.publicKey));
214
+
215
+ const decoded = decodeV1networkOperation(encodeV1networkOperation(payload));
216
+ t.is(decoded.broadcast_transaction_response.result, code);
217
+ }
218
+ });
219
+
220
+ test('NetworkMessageBuilder builds broadcast transaction request and verifies signature', async t => {
221
+ const wallet = createWallet();
222
+ const builder = new NetworkMessageBuilder(wallet, config);
223
+
224
+ const id = uuidv7();
225
+ const caps = ['cap:b', 'cap:a'];
226
+ const data = b4a.from('deadbeef', 'hex');
227
+
228
+ await builder
229
+ .setType(NetworkOperationType.BROADCAST_TRANSACTION_REQUEST)
230
+ .setId(id)
231
+ .setTimestamp()
232
+ .setData(data)
233
+ .setCapabilities(caps)
234
+ .buildPayload();
235
+
236
+ const payload = builder.getResult();
237
+ t.is(payload.type, NetworkOperationType.BROADCAST_TRANSACTION_REQUEST);
238
+ t.alike(payload.broadcast_transaction_request.data, data);
239
+
240
+ const msg = createMessage(
241
+ payload.type,
242
+ idToBuffer(payload.id),
243
+ timestampToBuffer(payload.timestamp),
244
+ data,
245
+ payload.broadcast_transaction_request.nonce,
246
+ encodeCapabilities(caps)
247
+ );
248
+ const hash = await PeerWallet.blake3(msg);
249
+ t.ok(wallet.verify(payload.broadcast_transaction_request.signature, hash, wallet.publicKey));
250
+ });
251
+
252
+ test('NetworkMessageBuilder validates required inputs', async t => {
253
+ const wallet = createWallet();
254
+ const builder = new NetworkMessageBuilder(wallet, config);
255
+ const id = uuidv7();
256
+ await t.exception(
257
+ () => builder.setType(undefined),
258
+ errorMessageIncludes('Invalid operation type')
259
+ );
260
+
261
+ await t.exception(
262
+ () => builder.setCapabilities('not-an-array'),
263
+ errorMessageIncludes('Capabilities must be a string array.')
264
+ );
265
+
266
+ await t.exception(
267
+ () =>
268
+ builder
269
+ .setType(NetworkOperationType.BROADCAST_TRANSACTION_REQUEST)
270
+ .setId(id)
271
+ .setTimestamp()
272
+ .setCapabilities([])
273
+ .buildPayload(),
274
+ errorMessageIncludes('Data must be set before building broadcast transaction request')
275
+ );
276
+ });
@@ -0,0 +1,203 @@
1
+ import { test } from 'brittle';
2
+ import b4a from 'b4a';
3
+ import PeerWallet from 'trac-wallet';
4
+ import { TRAC_NETWORK_MSB_MAINNET_PREFIX } from 'trac-wallet/constants.js';
5
+
6
+ import NetworkWalletFactory from '../../../../src/core/network/identity/NetworkWalletFactory.js';
7
+ import NetworkMessageDirector from '../../../../src/messages/network/v1/NetworkMessageDirector.js';
8
+ import NetworkMessageBuilder from '../../../../src/messages/network/v1/NetworkMessageBuilder.js';
9
+ import { NetworkOperationType, ResultCode as NetworkResultCode } from '../../../../src/utils/constants.js';
10
+ import { decodeV1networkOperation, encodeV1networkOperation } from '../../../../src/utils/protobuf/operationHelpers.js';
11
+ import {
12
+ createMessage,
13
+ encodeCapabilities,
14
+ safeWriteUInt32BE,
15
+ idToBuffer,
16
+ timestampToBuffer
17
+ } from '../../../../src/utils/buffer.js';
18
+ import { addressToBuffer } from '../../../../src/core/state/utils/address.js';
19
+ import { config } from '../../../helpers/config.js';
20
+ import { testKeyPair1 } from '../../../fixtures/apply.fixtures.js';
21
+
22
+ function createWallet() {
23
+ const keyPair = {
24
+ publicKey: b4a.from(testKeyPair1.publicKey, 'hex'),
25
+ secretKey: b4a.from(testKeyPair1.secretKey, 'hex')
26
+ };
27
+ return NetworkWalletFactory.provide({
28
+ enableWallet: false,
29
+ keyPair,
30
+ networkPrefix: TRAC_NETWORK_MSB_MAINNET_PREFIX
31
+ });
32
+ }
33
+
34
+ function uniqueResultCodes() {
35
+ return [...new Set(Object.values(NetworkResultCode))].sort((a, b) => a - b);
36
+ }
37
+
38
+ test('NetworkMessageDirector builds validator connection request and verifies signature', async t => {
39
+ const wallet = createWallet();
40
+ const director = new NetworkMessageDirector(new NetworkMessageBuilder(wallet, config));
41
+
42
+ const id = '1';
43
+ const caps = ['cap:b', 'cap:a'];
44
+
45
+ const payload = await director.buildValidatorConnectionRequest(id, wallet.address, caps);
46
+ t.is(payload.type, NetworkOperationType.VALIDATOR_CONNECTION_REQUEST);
47
+ t.is(payload.id, id);
48
+ t.alike(payload.capabilities, caps);
49
+
50
+ const msg = createMessage(
51
+ payload.type,
52
+ idToBuffer(payload.id),
53
+ timestampToBuffer(payload.timestamp),
54
+ addressToBuffer(wallet.address, config.addressPrefix),
55
+ payload.validator_connection_request.nonce,
56
+ encodeCapabilities(caps)
57
+ );
58
+ const hash = await PeerWallet.blake3(msg);
59
+ t.ok(wallet.verify(payload.validator_connection_request.signature, hash, wallet.publicKey));
60
+ });
61
+
62
+ test('NetworkMessageDirector builds liveness request and verifies signature', async t => {
63
+ const wallet = createWallet();
64
+ const director = new NetworkMessageDirector(new NetworkMessageBuilder(wallet, config));
65
+
66
+ const id = '1';
67
+ const caps = ['cap:b', 'cap:a'];
68
+ const data = b4a.from('ping', 'utf8');
69
+
70
+ const payload = await director.buildLivenessRequest(id, data, caps);
71
+ t.is(payload.type, NetworkOperationType.LIVENESS_REQUEST);
72
+ t.is(payload.id, id);
73
+ t.alike(payload.capabilities, caps);
74
+
75
+ const msg = createMessage(
76
+ payload.type,
77
+ idToBuffer(payload.id),
78
+ timestampToBuffer(payload.timestamp),
79
+ payload.liveness_request.nonce,
80
+ encodeCapabilities(caps)
81
+ );
82
+ const hash = await PeerWallet.blake3(msg);
83
+ t.ok(wallet.verify(payload.liveness_request.signature, hash, wallet.publicKey));
84
+ });
85
+
86
+ test('NetworkMessageDirector iterates liveness response ResultCode values', async t => {
87
+ const wallet = createWallet();
88
+ const director = new NetworkMessageDirector(new NetworkMessageBuilder(wallet, config));
89
+
90
+ const id = '1';
91
+ const caps = ['cap:b', 'cap:a'];
92
+ const data = b4a.from('ping', 'utf8');
93
+
94
+ for (const code of uniqueResultCodes()) {
95
+ const payload = await director.buildLivenessResponse(id, data, caps, code);
96
+ t.is(payload.type, NetworkOperationType.LIVENESS_RESPONSE);
97
+ t.is(payload.liveness_response.result, code);
98
+
99
+ const msg = createMessage(
100
+ payload.type,
101
+ idToBuffer(payload.id),
102
+ timestampToBuffer(payload.timestamp),
103
+ payload.liveness_response.nonce,
104
+ safeWriteUInt32BE(code, 0),
105
+ encodeCapabilities(caps)
106
+ );
107
+ const hash = await PeerWallet.blake3(msg);
108
+ t.ok(wallet.verify(payload.liveness_response.signature, hash, wallet.publicKey));
109
+
110
+ const decoded = decodeV1networkOperation(encodeV1networkOperation(payload));
111
+ t.is(decoded.liveness_response.result, code);
112
+ }
113
+ });
114
+
115
+ test('NetworkMessageDirector builds broadcast transaction request and verifies signature', async t => {
116
+ const wallet = createWallet();
117
+ const director = new NetworkMessageDirector(new NetworkMessageBuilder(wallet, config));
118
+
119
+ const id = '1';
120
+ const data = b4a.from('deadbeef', 'hex');
121
+ const caps = ['cap:b', 'cap:a'];
122
+
123
+ const payload = await director.buildBroadcastTransactionRequest(id, data, caps);
124
+ t.is(payload.type, NetworkOperationType.BROADCAST_TRANSACTION_REQUEST);
125
+ t.is(payload.id, id);
126
+ t.alike(payload.capabilities, caps);
127
+ t.alike(payload.broadcast_transaction_request.data, data);
128
+
129
+ const message = createMessage(
130
+ payload.type,
131
+ idToBuffer(id),
132
+ timestampToBuffer(payload.timestamp),
133
+ data,
134
+ payload.broadcast_transaction_request.nonce,
135
+ encodeCapabilities(caps)
136
+ );
137
+ const hash = await PeerWallet.blake3(message);
138
+ t.ok(wallet.verify(payload.broadcast_transaction_request.signature, hash, wallet.publicKey));
139
+
140
+ const decoded = decodeV1networkOperation(encodeV1networkOperation(payload));
141
+ t.is(decoded.type, NetworkOperationType.BROADCAST_TRANSACTION_REQUEST);
142
+ });
143
+
144
+ test('NetworkMessageDirector iterates broadcast transaction response ResultCode values', async t => {
145
+ const wallet = createWallet();
146
+ const director = new NetworkMessageDirector(new NetworkMessageBuilder(wallet, config));
147
+
148
+ const id = '1';
149
+ const caps = ['cap:b', 'cap:a'];
150
+
151
+ for (const code of uniqueResultCodes()) {
152
+ const payload = await director.buildBroadcastTransactionResponse(id, caps, code);
153
+ t.is(payload.type, NetworkOperationType.BROADCAST_TRANSACTION_RESPONSE);
154
+ t.is(payload.broadcast_transaction_response.result, code);
155
+
156
+ const msg = createMessage(
157
+ payload.type,
158
+ idToBuffer(payload.id),
159
+ timestampToBuffer(payload.timestamp),
160
+ payload.broadcast_transaction_response.nonce,
161
+ safeWriteUInt32BE(code, 0),
162
+ encodeCapabilities(caps)
163
+ );
164
+ const hash = await PeerWallet.blake3(msg);
165
+ t.ok(wallet.verify(payload.broadcast_transaction_response.signature, hash, wallet.publicKey));
166
+
167
+ const decoded = decodeV1networkOperation(encodeV1networkOperation(payload));
168
+ t.is(decoded.broadcast_transaction_response.result, code);
169
+ }
170
+ });
171
+
172
+ test('NetworkMessageDirector iterates validator connection response ResultCode values', async t => {
173
+ const wallet = createWallet();
174
+ const director = new NetworkMessageDirector(new NetworkMessageBuilder(wallet, config));
175
+
176
+ const id = '1';
177
+ const caps = ['cap:b', 'cap:a'];
178
+ const otherAddress =
179
+ 'trac1xm76l9qaujh7vqktk8302mw9sfrxau3l45w62hqfl4kasswt6yts0autkh';
180
+
181
+ for (const code of uniqueResultCodes()) {
182
+ const payload = await director.buildValidatorConnectionResponse(
183
+ id,
184
+ otherAddress,
185
+ caps,
186
+ code
187
+ );
188
+ t.is(payload.type, NetworkOperationType.VALIDATOR_CONNECTION_RESPONSE);
189
+ t.is(payload.validator_connection_response.result, code);
190
+
191
+ const msg = createMessage(
192
+ payload.type,
193
+ idToBuffer(payload.id),
194
+ timestampToBuffer(payload.timestamp),
195
+ addressToBuffer(otherAddress, config.addressPrefix),
196
+ payload.validator_connection_response.nonce,
197
+ safeWriteUInt32BE(code, 0),
198
+ encodeCapabilities(caps)
199
+ );
200
+ const hash = await PeerWallet.blake3(msg);
201
+ t.ok(wallet.verify(payload.validator_connection_response.signature, hash, wallet.publicKey));
202
+ }
203
+ });