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.
- package/.github/workflows/acceptance-tests.yml +7 -11
- package/.github/workflows/lint-pr-title.yml +26 -0
- package/.github/workflows/unit-tests.yml +2 -8
- package/CODE_OF_CONDUCT.md +128 -0
- package/README.md +33 -18
- package/docker-compose.yml +1 -0
- package/docs/trac_network_http_api.openapi.yaml +889 -0
- package/msb.mjs +5 -22
- package/package.json +14 -10
- package/proto/network.proto +74 -0
- package/rpc/create_server.js +2 -2
- package/rpc/handlers.js +165 -92
- package/rpc/routes/v1.js +3 -1
- package/rpc/rpc_server.js +4 -4
- package/rpc/rpc_services.js +62 -25
- package/rpc/utils/helpers.js +83 -52
- package/src/config/args.js +46 -0
- package/src/config/config.js +78 -5
- package/src/config/env.js +70 -3
- package/src/core/network/Network.js +34 -70
- package/src/core/network/identity/NetworkWalletFactory.js +2 -2
- package/src/core/network/protocols/LegacyProtocol.js +67 -0
- package/src/core/network/protocols/NetworkMessages.js +48 -0
- package/src/core/network/protocols/ProtocolInterface.js +31 -0
- package/src/core/network/protocols/ProtocolSession.js +59 -0
- package/src/core/network/protocols/V1Protocol.js +64 -0
- package/src/core/network/protocols/legacy/NetworkMessageRouter.js +84 -0
- package/src/core/network/protocols/legacy/handlers/GetRequestHandler.js +53 -0
- package/src/core/network/protocols/legacy/handlers/ResponseHandler.js +37 -0
- package/src/core/network/{messaging → protocols/legacy}/validators/base/BaseResponse.js +2 -3
- package/src/core/network/protocols/shared/handlers/RoleOperationHandler.js +88 -0
- package/src/core/network/protocols/shared/handlers/SubnetworkOperationHandler.js +93 -0
- package/src/core/network/{messaging → protocols/shared}/handlers/TransferOperationHandler.js +17 -16
- package/src/core/network/{messaging → protocols/shared}/handlers/base/BaseOperationHandler.js +10 -15
- package/src/core/network/{messaging → protocols/shared}/validators/PartialBootstrapDeployment.js +2 -2
- package/src/core/network/{messaging → protocols/shared}/validators/PartialRoleAccess.js +5 -5
- package/src/core/network/{messaging → protocols/shared}/validators/PartialTransaction.js +4 -4
- package/src/core/network/{messaging → protocols/shared}/validators/PartialTransfer.js +4 -4
- package/src/core/network/{messaging → protocols/shared}/validators/base/PartialOperation.js +14 -12
- package/src/core/network/protocols/v1/NetworkMessageRouter.js +15 -0
- package/src/core/network/services/ConnectionManager.js +5 -5
- package/src/core/network/services/MessageOrchestrator.js +2 -2
- package/src/core/network/services/TransactionPoolService.js +5 -6
- package/src/core/network/services/TransactionRateLimiterService.js +12 -13
- package/src/core/network/services/ValidatorObserverService.js +5 -6
- package/src/core/state/State.js +3 -5
- package/src/index.js +156 -181
- package/src/messages/network/v1/NetworkMessageBuilder.js +325 -0
- package/src/messages/network/v1/NetworkMessageDirector.js +137 -0
- package/src/messages/network/v1/networkMessageFactory.js +12 -0
- package/src/messages/state/ApplyStateMessageBuilder.js +661 -0
- package/src/messages/state/ApplyStateMessageDirector.js +516 -0
- package/src/messages/state/applyStateMessageFactory.js +12 -0
- package/src/utils/buffer.js +53 -1
- package/src/utils/check.js +1 -1
- package/src/utils/cli.js +0 -8
- package/src/utils/constants.js +33 -30
- package/src/utils/fileUtils.js +13 -0
- package/src/utils/normalizers.js +84 -2
- package/src/utils/protobuf/network.cjs +840 -0
- package/src/utils/protobuf/operationHelpers.js +10 -0
- package/src/utils/type.js +26 -0
- package/tests/acceptance/v1/balance/balance.test.mjs +1 -2
- package/tests/acceptance/v1/broadcast-transaction/broadcast-transaction.test.mjs +26 -30
- package/tests/acceptance/v1/health/health.test.mjs +33 -0
- package/tests/acceptance/v1/rpc.test.mjs +4 -3
- package/tests/acceptance/v1/tx/tx.test.mjs +27 -16
- package/tests/acceptance/v1/tx-details/tx-details.test.mjs +26 -12
- package/tests/fixtures/check.fixtures.js +33 -32
- package/tests/fixtures/networkV1.fixtures.js +85 -0
- package/tests/fixtures/protobuf.fixtures.js +109 -25
- package/tests/helpers/StateNetworkFactory.js +2 -2
- package/tests/helpers/address.js +6 -0
- package/tests/helpers/autobaseTestHelpers.js +2 -1
- package/tests/helpers/config.js +2 -1
- package/tests/helpers/setupApplyTests.js +59 -56
- package/tests/unit/messages/messages.test.js +12 -0
- package/tests/unit/messages/network/NetworkMessageBuilder.test.js +276 -0
- package/tests/unit/messages/network/NetworkMessageDirector.test.js +201 -0
- package/tests/unit/messages/state/applyStateMessageBuilder.complete.test.js +521 -0
- package/tests/unit/messages/state/applyStateMessageBuilder.partial.test.js +233 -0
- package/tests/unit/network/ConnectionManager.test.js +6 -5
- package/tests/unit/network/networkModule.test.js +3 -2
- package/tests/unit/state/apply/addAdmin/addAdminHappyPathScenario.js +10 -6
- package/tests/unit/state/apply/addAdmin/addAdminScenarioHelpers.js +9 -6
- package/tests/unit/state/apply/addAdmin/state.apply.addAdmin.test.js +10 -7
- package/tests/unit/state/apply/addIndexer/addIndexerScenarioHelpers.js +18 -21
- package/tests/unit/state/apply/addWriter/addWriterScenarioHelpers.js +53 -38
- package/tests/unit/state/apply/adminRecovery/adminRecoveryScenarioHelpers.js +46 -35
- package/tests/unit/state/apply/appendWhitelist/appendWhitelistScenarioHelpers.js +13 -16
- package/tests/unit/state/apply/balanceInitialization/balanceInitializationScenarioHelpers.js +17 -11
- package/tests/unit/state/apply/banValidator/banValidatorScenarioHelpers.js +11 -12
- package/tests/unit/state/apply/bootstrapDeployment/bootstrapDeploymentScenarioHelpers.js +9 -7
- package/tests/unit/state/apply/common/commonScenarioHelper.js +15 -14
- package/tests/unit/state/apply/common/payload-structure/initializationDisabledScenario.js +9 -4
- package/tests/unit/state/apply/disableInitialization/disableInitializationScenarioHelpers.js +17 -11
- package/tests/unit/state/apply/removeWriter/removeWriterScenarioHelpers.js +19 -14
- package/tests/unit/state/apply/transfer/transferDoubleSpendAcrossValidatorsScenario.js +37 -29
- package/tests/unit/state/apply/transfer/transferScenarioHelpers.js +9 -7
- package/tests/unit/state/apply/txOperation/txOperationScenarioHelpers.js +11 -9
- package/tests/unit/unit.test.js +1 -1
- package/tests/unit/utils/buffer/buffer.test.js +62 -1
- package/tests/unit/utils/fileUtils/readAddressesFromWhitelistFile.test.js +4 -3
- package/tests/unit/utils/fileUtils/readBalanceMigrationFile.test.js +3 -2
- package/tests/unit/utils/migrationUtils/validateAddressFromIncomingFile.test.js +3 -2
- package/tests/unit/utils/normalizers/normalizers.test.js +469 -0
- package/tests/unit/utils/protobuf/operationHelpers.test.js +120 -2
- package/tests/unit/utils/type/type.test.js +25 -0
- package/tests/unit/utils/utils.test.js +1 -0
- package/docs/networking-dualstack-plan.md +0 -75
- package/docs/networking-layer-redesign.md +0 -155
- package/src/core/network/messaging/NetworkMessages.js +0 -64
- package/src/core/network/messaging/handlers/GetRequestHandler.js +0 -113
- package/src/core/network/messaging/handlers/ResponseHandler.js +0 -107
- package/src/core/network/messaging/handlers/RoleOperationHandler.js +0 -114
- package/src/core/network/messaging/handlers/SubnetworkOperationHandler.js +0 -149
- package/src/core/network/messaging/routes/NetworkMessageRouter.js +0 -98
- package/src/core/network/messaging/validators/AdminResponse.js +0 -58
- package/src/core/network/messaging/validators/CustomNodeResponse.js +0 -46
- package/src/messages/base/StateBuilder.js +0 -25
- package/src/messages/completeStateMessages/CompleteStateMessageBuilder.js +0 -425
- package/src/messages/completeStateMessages/CompleteStateMessageDirector.js +0 -252
- package/src/messages/completeStateMessages/CompleteStateMessageOperations.js +0 -296
- package/src/messages/partialStateMessages/PartialStateMessageBuilder.js +0 -272
- package/src/messages/partialStateMessages/PartialStateMessageDirector.js +0 -137
- package/src/messages/partialStateMessages/PartialStateMessageOperations.js +0 -138
- package/tests/integration/apply/addAdmin/addAdminBasic.test.js +0 -69
- package/tests/integration/apply/addAdmin/addAdminRecovery.test.js +0 -126
- package/tests/integration/apply/addIndexer.test.js +0 -239
- package/tests/integration/apply/addWhitelist.test.js +0 -53
- package/tests/integration/apply/addWriter.test.js +0 -245
- package/tests/integration/apply/apply.test.js +0 -19
- package/tests/integration/apply/banValidator.test.js +0 -116
- package/tests/integration/apply/postTx/invalidSubValues.test.js +0 -103
- package/tests/integration/apply/postTx/postTx.test.js +0 -196
- package/tests/integration/apply/removeIndexer.test.js +0 -132
- package/tests/integration/apply/removeWriter.test.js +0 -168
- package/tests/integration/apply/transfer.test.js +0 -83
- package/tests/integration/integration.test.js +0 -9
- package/tests/unit/messageOperations/assembleAddIndexerMessage.test.js +0 -21
- package/tests/unit/messageOperations/assembleAddWriterMessage.test.js +0 -17
- package/tests/unit/messageOperations/assembleAdminMessage.test.js +0 -68
- package/tests/unit/messageOperations/assembleBanWriterMessage.test.js +0 -17
- package/tests/unit/messageOperations/assemblePostTransaction.test.js +0 -424
- package/tests/unit/messageOperations/assembleRemoveIndexerMessage.test.js +0 -19
- package/tests/unit/messageOperations/assembleRemoveWriterMessage.test.js +0 -17
- package/tests/unit/messageOperations/assembleWhitelistMessages.test.js +0 -59
- package/tests/unit/messageOperations/commonsStateMessageOperationsTest.js +0 -278
- package/tests/unit/messageOperations/stateMessageOperations.test.js +0 -19
- /package/src/core/network/{messaging → protocols/legacy}/validators/ValidatorResponse.js +0 -0
- /package/src/utils/{operations.js → applyOperations.js} +0 -0
|
@@ -3,16 +3,13 @@ import {generateMnemonic, mnemonicToSeed} from 'bip39-mnemonic';
|
|
|
3
3
|
import b4a from 'b4a'
|
|
4
4
|
import PeerWallet from "trac-wallet"
|
|
5
5
|
import path from 'path';
|
|
6
|
-
import CompleteStateMessageOperations from '../../src/messages/completeStateMessages/CompleteStateMessageOperations.js'
|
|
7
|
-
import PartialStateMessageOperations from '../../src/messages/partialStateMessages/PartialStateMessageOperations.js';
|
|
8
6
|
import {MainSettlementBus} from '../../src/index.js'
|
|
9
7
|
import { createConfig, ENV } from '../../src/config/env.js'
|
|
10
8
|
import fileUtils from '../../src/utils/fileUtils.js'
|
|
11
9
|
import {EntryType} from '../../src/utils/constants.js';
|
|
12
10
|
import {sleep} from '../../src/utils/helpers.js'
|
|
13
11
|
import {formatIndexersEntry} from '../../src/utils/helpers.js';
|
|
14
|
-
import
|
|
15
|
-
import CompleteStateMessageDirector from '../../src/messages/completeStateMessages/CompleteStateMessageDirector.js'
|
|
12
|
+
import { applyStateMessageFactory } from "../../src/messages/state/applyStateMessageFactory.js";
|
|
16
13
|
import { safeEncodeApplyOperation } from "../../src/utils/protobuf/operationHelpers.js"
|
|
17
14
|
import { $TNK } from '../../src/core/state/utils/balance.js';
|
|
18
15
|
import { EventType } from '../../src/utils/constants.js';
|
|
@@ -69,14 +66,13 @@ export const tick = () => new Promise(resolve => setImmediate(resolve));
|
|
|
69
66
|
|
|
70
67
|
export async function fundPeer(admin, toFund, amount) {
|
|
71
68
|
const txValidity = await admin.msb.state.getIndexerSequenceState()
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
);
|
|
69
|
+
const payload = await applyStateMessageFactory(admin.wallet, admin.config)
|
|
70
|
+
.buildCompleteBalanceInitializationMessage(
|
|
71
|
+
admin.wallet.address,
|
|
72
|
+
toFund.wallet.address,
|
|
73
|
+
amount,
|
|
74
|
+
txValidity
|
|
75
|
+
);
|
|
80
76
|
|
|
81
77
|
await admin.msb.state.append(safeEncodeApplyOperation(payload));
|
|
82
78
|
await tick()
|
|
@@ -86,11 +82,10 @@ export async function fundPeer(admin, toFund, amount) {
|
|
|
86
82
|
}
|
|
87
83
|
|
|
88
84
|
export async function initMsbPeer(peerName, peerKeyPair, temporaryDirectory, options = {}) {
|
|
89
|
-
const
|
|
90
|
-
peer
|
|
91
|
-
peer.options
|
|
92
|
-
peer.
|
|
93
|
-
peer.config = createConfig(ENV.DEVELOPMENT, peer.options)
|
|
85
|
+
const config = createConfig(ENV.DEVELOPMENT, { ...options, storesDirectory: `${temporaryDirectory}/${peerName}` })
|
|
86
|
+
const peer = await initDirectoryStructure(peerName, peerKeyPair, config.storesFullPath);
|
|
87
|
+
peer.options = { ...options, storesDirectory: config.storesDirectory }
|
|
88
|
+
peer.config = config
|
|
94
89
|
const msb = new MainSettlementBus(peer.config);
|
|
95
90
|
|
|
96
91
|
peer.msb = msb;
|
|
@@ -124,10 +119,10 @@ export async function initMsbAdmin(keyPair, temporaryDirectory, options = {}) {
|
|
|
124
119
|
export async function setupMsbAdmin(keyPair, temporaryDirectory, options = {}) {
|
|
125
120
|
const admin = await initMsbAdmin(keyPair, temporaryDirectory, options);
|
|
126
121
|
const txValidity = await admin.msb.state.getIndexerSequenceState();
|
|
127
|
-
const
|
|
128
|
-
.
|
|
122
|
+
const payload = await applyStateMessageFactory(admin.wallet, admin.config)
|
|
123
|
+
.buildCompleteAddAdminMessage(admin.wallet.address, admin.msb.state.writingKey, txValidity);
|
|
129
124
|
|
|
130
|
-
await admin.msb.state.append(
|
|
125
|
+
await admin.msb.state.append(safeEncodeApplyOperation(payload));
|
|
131
126
|
await tick();
|
|
132
127
|
return admin;
|
|
133
128
|
}
|
|
@@ -137,22 +132,25 @@ export async function setupNodeAsWriter(admin, writerCandidate) {
|
|
|
137
132
|
await setupWhitelist(admin, [writerCandidate.wallet.address]); // ensure if is whitelisted
|
|
138
133
|
|
|
139
134
|
const validity = await admin.msb.getIndexerSequenceState()
|
|
140
|
-
const req = await
|
|
141
|
-
.
|
|
135
|
+
const req = await applyStateMessageFactory(writerCandidate.wallet, admin.config)
|
|
136
|
+
.buildPartialAddWriterMessage(
|
|
137
|
+
writerCandidate.wallet.address,
|
|
142
138
|
b4a.toString(writerCandidate.msb.state.writingKey, 'hex'),
|
|
143
|
-
b4a.toString(validity, 'hex')
|
|
139
|
+
b4a.toString(validity, 'hex'),
|
|
140
|
+
'json'
|
|
141
|
+
);
|
|
144
142
|
|
|
145
143
|
await waitWritable(admin, writerCandidate, async () => {
|
|
146
|
-
const
|
|
147
|
-
.
|
|
144
|
+
const payload = await applyStateMessageFactory(admin.wallet, admin.config)
|
|
145
|
+
.buildCompleteAddWriterMessage(
|
|
148
146
|
admin.wallet.address,
|
|
149
147
|
b4a.from(req.rao.tx, 'hex'),
|
|
150
148
|
b4a.from(req.rao.txv, 'hex'),
|
|
151
149
|
b4a.from(req.rao.iw, 'hex'),
|
|
152
150
|
b4a.from(req.rao.in, 'hex'),
|
|
153
151
|
b4a.from(req.rao.is, 'hex')
|
|
154
|
-
)
|
|
155
|
-
await admin.msb.state.append(
|
|
152
|
+
);
|
|
153
|
+
await admin.msb.state.append(safeEncodeApplyOperation(payload))
|
|
156
154
|
})
|
|
157
155
|
|
|
158
156
|
return writerCandidate;
|
|
@@ -172,22 +170,25 @@ export async function promoteToWriter(admin, writerCandidate) {
|
|
|
172
170
|
isIndexer: false,
|
|
173
171
|
})
|
|
174
172
|
const validity = await admin.msb.state.getIndexerSequenceState()
|
|
175
|
-
const req = await
|
|
176
|
-
.
|
|
173
|
+
const req = await applyStateMessageFactory(writerCandidate.wallet, writerCandidate.config)
|
|
174
|
+
.buildPartialAddWriterMessage(
|
|
175
|
+
writerCandidate.wallet.address,
|
|
177
176
|
b4a.toString(writerCandidate.msb.state.writingKey, 'hex'),
|
|
178
|
-
b4a.toString(validity, 'hex')
|
|
177
|
+
b4a.toString(validity, 'hex'),
|
|
178
|
+
'json'
|
|
179
|
+
);
|
|
179
180
|
|
|
180
181
|
await waitWritable(writerCandidate, writerCandidate, async () => {
|
|
181
|
-
const
|
|
182
|
-
.
|
|
182
|
+
const payload = await applyStateMessageFactory(admin.wallet, admin.config)
|
|
183
|
+
.buildCompleteAddWriterMessage(
|
|
183
184
|
req.address,
|
|
184
185
|
b4a.from(req.rao.tx, 'hex'),
|
|
185
186
|
b4a.from(req.rao.txv, 'hex'),
|
|
186
187
|
b4a.from(req.rao.iw, 'hex'),
|
|
187
188
|
b4a.from(req.rao.in, 'hex'),
|
|
188
189
|
b4a.from(req.rao.is, 'hex')
|
|
189
|
-
)
|
|
190
|
-
await admin.msb.state.append(
|
|
190
|
+
);
|
|
191
|
+
await admin.msb.state.append(safeEncodeApplyOperation(payload))
|
|
191
192
|
})
|
|
192
193
|
|
|
193
194
|
return writerCandidate;
|
|
@@ -206,10 +207,10 @@ export async function setupMsbWriter(admin, peerName, peerKeyPair, temporaryDire
|
|
|
206
207
|
export async function setupMsbIndexer(indexerCandidate, admin) {
|
|
207
208
|
try {
|
|
208
209
|
const validity = await admin.msb.state.getIndexerSequenceState()
|
|
209
|
-
const
|
|
210
|
-
.
|
|
210
|
+
const payload = await applyStateMessageFactory(admin.wallet, admin.config)
|
|
211
|
+
.buildCompleteAddIndexerMessage(admin.wallet.address, indexerCandidate.wallet.address, validity);
|
|
211
212
|
|
|
212
|
-
await admin.msb.state.append(
|
|
213
|
+
await admin.msb.state.append(safeEncodeApplyOperation(payload));
|
|
213
214
|
await tick(); // wait for the request to be processed
|
|
214
215
|
|
|
215
216
|
const isIndexer = async () => {
|
|
@@ -260,10 +261,10 @@ export async function setupWhitelist(admin, whitelistAddresses) {
|
|
|
260
261
|
fileUtils.readAddressesFromWhitelistFile = async () => whitelistAddresses;
|
|
261
262
|
const validity = await admin.msb.state.getIndexerSequenceState()
|
|
262
263
|
for (const address of whitelistAddresses) {
|
|
263
|
-
const
|
|
264
|
-
.
|
|
264
|
+
const payload = await applyStateMessageFactory(admin.wallet, admin.config)
|
|
265
|
+
.buildCompleteAppendWhitelistMessage(admin.wallet.address, address, validity);
|
|
265
266
|
|
|
266
|
-
await admin.msb.state.append(
|
|
267
|
+
await admin.msb.state.append(safeEncodeApplyOperation(payload));
|
|
267
268
|
await sleep(100)
|
|
268
269
|
}
|
|
269
270
|
|
|
@@ -288,9 +289,7 @@ export async function removeTemporaryDirectory(temporaryDirectory) {
|
|
|
288
289
|
export async function initDirectoryStructure(peerName, keyPair, temporaryDirectory) {
|
|
289
290
|
try {
|
|
290
291
|
await ensureEnvReady();
|
|
291
|
-
const
|
|
292
|
-
const storeName = peerName + '/';
|
|
293
|
-
const corestoreDbDirectory = path.join(storesDirectory, storeName, 'db');
|
|
292
|
+
const corestoreDbDirectory = path.join(temporaryDirectory, 'db');
|
|
294
293
|
await fsp.mkdir(corestoreDbDirectory, {recursive: true});
|
|
295
294
|
|
|
296
295
|
const keypath = path.join(corestoreDbDirectory, 'keypair.json');
|
|
@@ -301,8 +300,7 @@ export async function initDirectoryStructure(peerName, keyPair, temporaryDirecto
|
|
|
301
300
|
await wallet.ready
|
|
302
301
|
await wallet.exportToFile(keypath)
|
|
303
302
|
return {
|
|
304
|
-
storesDirectory,
|
|
305
|
-
storeName,
|
|
303
|
+
storesDirectory: temporaryDirectory,
|
|
306
304
|
corestoreDbDirectory,
|
|
307
305
|
keypath,
|
|
308
306
|
}
|
|
@@ -314,15 +312,17 @@ export async function initDirectoryStructure(peerName, keyPair, temporaryDirecto
|
|
|
314
312
|
export const deployExternalBootstrap = async (writer, externalNode) => {
|
|
315
313
|
const externalBootstrap = randomBytes(32).toString('hex');
|
|
316
314
|
const txValidity = await writer.msb.state.getIndexerSequenceState();
|
|
317
|
-
const payload = await
|
|
318
|
-
.
|
|
315
|
+
const payload = await applyStateMessageFactory(externalNode.msb.wallet, admin.config)
|
|
316
|
+
.buildPartialBootstrapDeploymentMessage(
|
|
317
|
+
externalNode.msb.wallet.address,
|
|
319
318
|
externalBootstrap,
|
|
320
319
|
randomBytes(32).toString('hex'),
|
|
321
|
-
txValidity.toString('hex')
|
|
320
|
+
txValidity.toString('hex'),
|
|
321
|
+
'json'
|
|
322
322
|
);
|
|
323
323
|
|
|
324
|
-
const
|
|
325
|
-
.
|
|
324
|
+
const rawPayload = await applyStateMessageFactory(writer.msb.wallet, admin.config)
|
|
325
|
+
.buildCompleteBootstrapDeploymentMessage(
|
|
326
326
|
payload.address,
|
|
327
327
|
b4a.from(payload.bdo.tx, 'hex'),
|
|
328
328
|
b4a.from(payload.bdo.txv, 'hex'),
|
|
@@ -331,7 +331,7 @@ export const deployExternalBootstrap = async (writer, externalNode) => {
|
|
|
331
331
|
b4a.from(payload.bdo.in, 'hex'),
|
|
332
332
|
b4a.from(payload.bdo.is, 'hex'),
|
|
333
333
|
)
|
|
334
|
-
await writer.msb.state.base.append(
|
|
334
|
+
await writer.msb.state.base.append(safeEncodeApplyOperation(rawPayload))
|
|
335
335
|
await tick()
|
|
336
336
|
await waitForHash(writer, payload.bdo.tx)
|
|
337
337
|
return externalBootstrap
|
|
@@ -353,17 +353,19 @@ export const generatePostTx = async (writer, externalNode, externalContractBoots
|
|
|
353
353
|
|
|
354
354
|
const contentHash = await PeerWallet.blake3(JSON.stringify(testObj));
|
|
355
355
|
const validity = await writer.msb.state.getIndexerSequenceState()
|
|
356
|
-
const tx = await
|
|
357
|
-
.
|
|
356
|
+
const tx = await applyStateMessageFactory(externalNode.wallet, admin.config)
|
|
357
|
+
.buildPartialTransactionOperationMessage(
|
|
358
|
+
externalNode.wallet.address,
|
|
358
359
|
peerWriterKey,
|
|
359
360
|
b4a.toString(validity, 'hex'),
|
|
360
361
|
b4a.toString(contentHash, 'hex'),
|
|
361
362
|
externalContractBootstrap,
|
|
362
|
-
b4a.toString(writer.msb.bootstrap, 'hex')
|
|
363
|
+
b4a.toString(writer.msb.bootstrap, 'hex'),
|
|
364
|
+
'json'
|
|
363
365
|
)
|
|
364
366
|
|
|
365
|
-
const
|
|
366
|
-
.
|
|
367
|
+
const postTxPayload = await applyStateMessageFactory(writer.wallet, admin.config)
|
|
368
|
+
.buildCompleteTransactionOperationMessage(
|
|
367
369
|
tx.address,
|
|
368
370
|
b4a.from(tx.txo.tx, 'hex'),
|
|
369
371
|
b4a.from(tx.txo.txv, 'hex'),
|
|
@@ -375,6 +377,7 @@ export const generatePostTx = async (writer, externalNode, externalContractBoots
|
|
|
375
377
|
b4a.from(tx.txo.mbs, 'hex')
|
|
376
378
|
);
|
|
377
379
|
|
|
380
|
+
const postTx = safeEncodeApplyOperation(postTxPayload);
|
|
378
381
|
return { postTx, txHash: tx.txo.tx };
|
|
379
382
|
}
|
|
380
383
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { default as test } from 'brittle';
|
|
2
|
+
|
|
3
|
+
async function runMsgUtilsTests() {
|
|
4
|
+
test.pause();
|
|
5
|
+
await import('./network/NetworkMessageBuilder.test.js');
|
|
6
|
+
await import('./network/NetworkMessageDirector.test.js');
|
|
7
|
+
await import('./state/applyStateMessageBuilder.complete.test.js');
|
|
8
|
+
await import('./state/applyStateMessageBuilder.partial.test.js');
|
|
9
|
+
test.resume();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
await runMsgUtilsTests();
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { test } from 'brittle';
|
|
2
|
+
import b4a from 'b4a';
|
|
3
|
+
import PeerWallet from 'trac-wallet';
|
|
4
|
+
import { v7 as uuidv7 } from 'uuid';
|
|
5
|
+
import NetworkWalletFactory from '../../../../src/core/network/identity/NetworkWalletFactory.js';
|
|
6
|
+
import NetworkMessageBuilder from '../../../../src/messages/network/v1/NetworkMessageBuilder.js';
|
|
7
|
+
import {
|
|
8
|
+
NetworkOperationType,
|
|
9
|
+
ResultCode as NetworkResultCode
|
|
10
|
+
} from '../../../../src/utils/constants.js';
|
|
11
|
+
import { decodeV1networkOperation, encodeV1networkOperation } from '../../../../src/utils/protobuf/operationHelpers.js';
|
|
12
|
+
import { errorMessageIncludes } from '../../../helpers/regexHelper.js';
|
|
13
|
+
import {
|
|
14
|
+
createMessage,
|
|
15
|
+
encodeCapabilities,
|
|
16
|
+
safeWriteUInt32BE,
|
|
17
|
+
idToBuffer,
|
|
18
|
+
timestampToBuffer
|
|
19
|
+
} from '../../../../src/utils/buffer.js';
|
|
20
|
+
import { addressToBuffer } from '../../../../src/core/state/utils/address.js';
|
|
21
|
+
import { config } from '../../../helpers/config.js';
|
|
22
|
+
import { asAddress } from '../../../helpers/address.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: config.addressPrefix
|
|
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 = asAddress('36fdaf941de4afe602cbb1e2f56dc582466ef23fad1da55c09fd6dd841cbd117');
|
|
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
|
+
});
|