trac-msb 0.2.8 → 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 (123) hide show
  1. package/msb.mjs +3 -3
  2. package/package.json +8 -3
  3. package/proto/network.proto +74 -0
  4. package/rpc/create_server.js +2 -2
  5. package/rpc/handlers.js +2 -2
  6. package/rpc/rpc_server.js +2 -2
  7. package/rpc/rpc_services.js +44 -3
  8. package/rpc/utils/helpers.js +1 -1
  9. package/src/config/env.js +2 -0
  10. package/src/core/network/Network.js +29 -61
  11. package/src/core/network/identity/NetworkWalletFactory.js +2 -2
  12. package/src/core/network/protocols/LegacyProtocol.js +67 -0
  13. package/src/core/network/protocols/NetworkMessages.js +48 -0
  14. package/src/core/network/protocols/ProtocolInterface.js +31 -0
  15. package/src/core/network/protocols/ProtocolSession.js +59 -0
  16. package/src/core/network/protocols/V1Protocol.js +64 -0
  17. package/src/core/network/protocols/legacy/NetworkMessageRouter.js +84 -0
  18. package/src/core/network/protocols/legacy/handlers/GetRequestHandler.js +53 -0
  19. package/src/core/network/protocols/legacy/handlers/ResponseHandler.js +37 -0
  20. package/src/core/network/{messaging → protocols/legacy}/validators/base/BaseResponse.js +1 -2
  21. package/src/core/network/protocols/shared/handlers/RoleOperationHandler.js +88 -0
  22. package/src/core/network/protocols/shared/handlers/SubnetworkOperationHandler.js +93 -0
  23. package/src/core/network/{messaging → protocols/shared}/handlers/TransferOperationHandler.js +16 -15
  24. package/src/core/network/{messaging → protocols/shared}/handlers/base/BaseOperationHandler.js +7 -11
  25. package/src/core/network/{messaging → protocols/shared}/validators/PartialBootstrapDeployment.js +2 -2
  26. package/src/core/network/{messaging → protocols/shared}/validators/PartialRoleAccess.js +5 -5
  27. package/src/core/network/{messaging → protocols/shared}/validators/PartialTransaction.js +4 -4
  28. package/src/core/network/{messaging → protocols/shared}/validators/PartialTransfer.js +4 -4
  29. package/src/core/network/{messaging → protocols/shared}/validators/base/PartialOperation.js +14 -12
  30. package/src/core/network/protocols/v1/NetworkMessageRouter.js +15 -0
  31. package/src/core/network/services/ConnectionManager.js +4 -4
  32. package/src/core/network/services/MessageOrchestrator.js +1 -1
  33. package/src/core/network/services/TransactionPoolService.js +1 -2
  34. package/src/core/network/services/TransactionRateLimiterService.js +5 -3
  35. package/src/core/state/State.js +1 -2
  36. package/src/index.js +153 -180
  37. package/src/messages/network/v1/NetworkMessageBuilder.js +325 -0
  38. package/src/messages/network/v1/NetworkMessageDirector.js +137 -0
  39. package/src/messages/network/v1/networkMessageFactory.js +12 -0
  40. package/src/messages/state/ApplyStateMessageBuilder.js +661 -0
  41. package/src/messages/state/ApplyStateMessageDirector.js +516 -0
  42. package/src/messages/state/applyStateMessageFactory.js +12 -0
  43. package/src/utils/buffer.js +53 -1
  44. package/src/utils/cli.js +0 -8
  45. package/src/utils/constants.js +34 -14
  46. package/src/utils/normalizers.js +84 -2
  47. package/src/utils/protobuf/network.cjs +840 -0
  48. package/src/utils/protobuf/operationHelpers.js +10 -0
  49. package/tests/acceptance/v1/rpc.test.mjs +1 -1
  50. package/tests/fixtures/networkV1.fixtures.js +84 -0
  51. package/tests/fixtures/protobuf.fixtures.js +83 -0
  52. package/tests/helpers/config.js +1 -1
  53. package/tests/helpers/setupApplyTests.js +53 -46
  54. package/tests/unit/messages/messages.test.js +12 -0
  55. package/tests/unit/messages/network/NetworkMessageBuilder.test.js +276 -0
  56. package/tests/unit/messages/network/NetworkMessageDirector.test.js +203 -0
  57. package/tests/unit/messages/state/applyStateMessageBuilder.complete.test.js +521 -0
  58. package/tests/unit/messages/state/applyStateMessageBuilder.partial.test.js +233 -0
  59. package/tests/unit/network/ConnectionManager.test.js +6 -5
  60. package/tests/unit/network/networkModule.test.js +3 -2
  61. package/tests/unit/state/apply/addAdmin/addAdminHappyPathScenario.js +10 -6
  62. package/tests/unit/state/apply/addAdmin/addAdminScenarioHelpers.js +9 -6
  63. package/tests/unit/state/apply/addAdmin/state.apply.addAdmin.test.js +10 -7
  64. package/tests/unit/state/apply/addIndexer/addIndexerScenarioHelpers.js +18 -21
  65. package/tests/unit/state/apply/addWriter/addWriterScenarioHelpers.js +53 -38
  66. package/tests/unit/state/apply/adminRecovery/adminRecoveryScenarioHelpers.js +46 -35
  67. package/tests/unit/state/apply/appendWhitelist/appendWhitelistScenarioHelpers.js +13 -16
  68. package/tests/unit/state/apply/balanceInitialization/balanceInitializationScenarioHelpers.js +17 -11
  69. package/tests/unit/state/apply/banValidator/banValidatorScenarioHelpers.js +11 -12
  70. package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentScenarioHelpers.js +9 -7
  71. package/tests/unit/state/apply/common/commonScenarioHelper.js +15 -14
  72. package/tests/unit/state/apply/common/payload-structure/initializationDisabledScenario.js +9 -4
  73. package/tests/unit/state/apply/disableInitialization/disableInitializationScenarioHelpers.js +17 -11
  74. package/tests/unit/state/apply/removeWriter/removeWriterScenarioHelpers.js +19 -14
  75. package/tests/unit/state/apply/transfer/transferDoubleSpendAcrossValidatorsScenario.js +37 -29
  76. package/tests/unit/state/apply/transfer/transferScenarioHelpers.js +9 -7
  77. package/tests/unit/state/apply/txOperation/txOperationScenarioHelpers.js +11 -9
  78. package/tests/unit/unit.test.js +1 -1
  79. package/tests/unit/utils/buffer/buffer.test.js +62 -1
  80. package/tests/unit/utils/normalizers/normalizers.test.js +469 -0
  81. package/tests/unit/utils/protobuf/operationHelpers.test.js +120 -2
  82. package/docs/networking-dualstack-plan.md +0 -75
  83. package/docs/networking-layer-redesign.md +0 -155
  84. package/src/core/network/messaging/NetworkMessages.js +0 -64
  85. package/src/core/network/messaging/handlers/GetRequestHandler.js +0 -113
  86. package/src/core/network/messaging/handlers/ResponseHandler.js +0 -107
  87. package/src/core/network/messaging/handlers/RoleOperationHandler.js +0 -114
  88. package/src/core/network/messaging/handlers/SubnetworkOperationHandler.js +0 -149
  89. package/src/core/network/messaging/routes/NetworkMessageRouter.js +0 -98
  90. package/src/core/network/messaging/validators/AdminResponse.js +0 -58
  91. package/src/core/network/messaging/validators/CustomNodeResponse.js +0 -46
  92. package/src/messages/base/StateBuilder.js +0 -25
  93. package/src/messages/completeStateMessages/CompleteStateMessageBuilder.js +0 -425
  94. package/src/messages/completeStateMessages/CompleteStateMessageDirector.js +0 -252
  95. package/src/messages/completeStateMessages/CompleteStateMessageOperations.js +0 -296
  96. package/src/messages/partialStateMessages/PartialStateMessageBuilder.js +0 -272
  97. package/src/messages/partialStateMessages/PartialStateMessageDirector.js +0 -137
  98. package/src/messages/partialStateMessages/PartialStateMessageOperations.js +0 -138
  99. package/tests/integration/apply/addAdmin/addAdminBasic.test.js +0 -69
  100. package/tests/integration/apply/addAdmin/addAdminRecovery.test.js +0 -126
  101. package/tests/integration/apply/addIndexer.test.js +0 -239
  102. package/tests/integration/apply/addWhitelist.test.js +0 -53
  103. package/tests/integration/apply/addWriter.test.js +0 -245
  104. package/tests/integration/apply/apply.test.js +0 -19
  105. package/tests/integration/apply/banValidator.test.js +0 -116
  106. package/tests/integration/apply/postTx/invalidSubValues.test.js +0 -103
  107. package/tests/integration/apply/postTx/postTx.test.js +0 -196
  108. package/tests/integration/apply/removeIndexer.test.js +0 -132
  109. package/tests/integration/apply/removeWriter.test.js +0 -168
  110. package/tests/integration/apply/transfer.test.js +0 -83
  111. package/tests/integration/integration.test.js +0 -9
  112. package/tests/unit/messageOperations/assembleAddIndexerMessage.test.js +0 -21
  113. package/tests/unit/messageOperations/assembleAddWriterMessage.test.js +0 -17
  114. package/tests/unit/messageOperations/assembleAdminMessage.test.js +0 -68
  115. package/tests/unit/messageOperations/assembleBanWriterMessage.test.js +0 -17
  116. package/tests/unit/messageOperations/assemblePostTransaction.test.js +0 -424
  117. package/tests/unit/messageOperations/assembleRemoveIndexerMessage.test.js +0 -19
  118. package/tests/unit/messageOperations/assembleRemoveWriterMessage.test.js +0 -17
  119. package/tests/unit/messageOperations/assembleWhitelistMessages.test.js +0 -59
  120. package/tests/unit/messageOperations/commonsStateMessageOperationsTest.js +0 -278
  121. package/tests/unit/messageOperations/stateMessageOperations.test.js +0 -19
  122. /package/src/core/network/{messaging → protocols/legacy}/validators/ValidatorResponse.js +0 -0
  123. /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
+ });