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
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import b4a from 'b4a';
|
|
2
|
-
import
|
|
3
|
-
import CompleteStateMessageOperations from '../../../../../src/messages/completeStateMessages/CompleteStateMessageOperations.js';
|
|
2
|
+
import { applyStateMessageFactory } from '../../../../../src/messages/state/applyStateMessageFactory.js';
|
|
4
3
|
import {
|
|
5
4
|
deriveIndexerSequenceState,
|
|
6
5
|
eventFlush
|
|
@@ -139,20 +138,22 @@ export async function buildTxOperationPayload(
|
|
|
139
138
|
writerKeyBuffer = broadcasterPeer.base.local.key
|
|
140
139
|
} = {}
|
|
141
140
|
) {
|
|
142
|
-
|
|
141
|
+
const resolvedTxValidity = txValidity ?? (await deriveIndexerSequenceState(validatorPeer.base));
|
|
143
142
|
|
|
144
|
-
const partial = await
|
|
145
|
-
.
|
|
143
|
+
const partial = await applyStateMessageFactory(broadcasterPeer.wallet, config)
|
|
144
|
+
.buildPartialTransactionOperationMessage(
|
|
145
|
+
broadcasterPeer.wallet.address,
|
|
146
146
|
writerKeyBuffer.toString('hex'),
|
|
147
147
|
resolvedTxValidity.toString('hex'),
|
|
148
148
|
contentHash.toString('hex'),
|
|
149
149
|
externalBootstrap.toString('hex'),
|
|
150
|
-
msbBootstrap.toString('hex')
|
|
150
|
+
msbBootstrap.toString('hex'),
|
|
151
|
+
'json'
|
|
151
152
|
);
|
|
152
153
|
|
|
153
|
-
|
|
154
|
-
.
|
|
155
|
-
|
|
154
|
+
const payload = await applyStateMessageFactory(validatorPeer.wallet, config)
|
|
155
|
+
.buildCompleteTransactionOperationMessage(
|
|
156
|
+
partial.address,
|
|
156
157
|
b4a.from(partial.txo.tx, 'hex'),
|
|
157
158
|
b4a.from(partial.txo.txv, 'hex'),
|
|
158
159
|
b4a.from(partial.txo.iw, 'hex'),
|
|
@@ -162,6 +163,7 @@ export async function buildTxOperationPayload(
|
|
|
162
163
|
b4a.from(partial.txo.bs, 'hex'),
|
|
163
164
|
b4a.from(partial.txo.mbs, 'hex')
|
|
164
165
|
);
|
|
166
|
+
return safeEncodeApplyOperation(payload);
|
|
165
167
|
}
|
|
166
168
|
|
|
167
169
|
export async function buildTxOperationPayloadWithTxValidity(context, txValidity, options = {}) {
|
package/tests/unit/unit.test.js
CHANGED
|
@@ -7,7 +7,7 @@ async function runTests() {
|
|
|
7
7
|
await import('./network/networkModule.test.js')
|
|
8
8
|
await import('./state/stateModule.test.js');
|
|
9
9
|
await import('./utils/utils.test.js');
|
|
10
|
-
|
|
10
|
+
await import('./messages/messages.test.js');
|
|
11
11
|
test.resume();
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import test from 'brittle';
|
|
2
2
|
import b4a from 'b4a';
|
|
3
|
-
import {createMessage, isBufferValid, safeWriteUInt32BE, deepCopyBuffer} from '../../../../src/utils/buffer.js';
|
|
3
|
+
import { createMessage, isBufferValid, safeWriteUInt32BE, deepCopyBuffer, encodeCapabilities, timestampToBuffer, idToBuffer } from '../../../../src/utils/buffer.js';
|
|
4
|
+
import { errorMessageIncludes } from "../../../helpers/regexHelper.js";
|
|
4
5
|
|
|
5
6
|
const invalidDataTypes = [
|
|
6
7
|
null,
|
|
@@ -188,3 +189,63 @@ test('deepCopyBuffer - modifying copy does not affect original (is not a referen
|
|
|
188
189
|
t.is(buf[0], 9, 'original unchanged');
|
|
189
190
|
t.is(copy[0], 1, 'copy modified independently');
|
|
190
191
|
});
|
|
192
|
+
|
|
193
|
+
test('encodeCapabilities - deterministic ordering and encoding', t => {
|
|
194
|
+
const caps = ['cap-b', 'cap-a'];
|
|
195
|
+
const result = encodeCapabilities(caps);
|
|
196
|
+
|
|
197
|
+
const capA = b4a.from('cap-a', 'utf8');
|
|
198
|
+
const capB = b4a.from('cap-b', 'utf8');
|
|
199
|
+
|
|
200
|
+
const expected = b4a.concat([
|
|
201
|
+
b4a.from([0x00, capA.length]),
|
|
202
|
+
capA,
|
|
203
|
+
b4a.from([0x00, capB.length]),
|
|
204
|
+
capB
|
|
205
|
+
]);
|
|
206
|
+
|
|
207
|
+
t.is(result.length, expected.length, 'length matches');
|
|
208
|
+
t.ok(b4a.equals(result, expected), 'ordering is sorted and encoding matches');
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test('encodeCapabilities - empty array yields empty buffer', t => {
|
|
212
|
+
const result = encodeCapabilities([]);
|
|
213
|
+
t.ok(b4a.isBuffer(result), 'returns a buffer');
|
|
214
|
+
t.is(result.length, 0, 'empty buffer for no caps');
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
test('encodeCapabilities - throws on invalid input', t => {
|
|
218
|
+
t.exception(
|
|
219
|
+
() => encodeCapabilities('not-array'),
|
|
220
|
+
errorMessageIncludes('Capabilities must be an array')
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
t.exception(
|
|
224
|
+
() => encodeCapabilities([1, 2]),
|
|
225
|
+
errorMessageIncludes('must contain only strings')
|
|
226
|
+
);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
test('timestampToBuffer - encodes uint64 BE', t => {
|
|
230
|
+
const ts = 2n ** 53n; // beyond uint32
|
|
231
|
+
|
|
232
|
+
const tsBuf = timestampToBuffer(ts);
|
|
233
|
+
|
|
234
|
+
t.is(tsBuf.length, 8);
|
|
235
|
+
t.is(tsBuf.readBigUInt64BE(0), ts);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
test('idToBuffer - encodes utf8 string', t => {
|
|
239
|
+
const id = 'test-id';
|
|
240
|
+
const idBuf = idToBuffer(id);
|
|
241
|
+
t.ok(b4a.isBuffer(idBuf));
|
|
242
|
+
t.ok(b4a.equals(idBuf, b4a.from(id, 'utf8')));
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
test('timestampToBuffer and idToBuffer - reject invalid input', t => {
|
|
246
|
+
t.exception(() => timestampToBuffer(-1), errorMessageIncludes('timestamp'));
|
|
247
|
+
t.exception(() => timestampToBuffer(1.5), errorMessageIncludes('timestamp'));
|
|
248
|
+
t.exception(() => timestampToBuffer('1'), errorMessageIncludes('timestamp'));
|
|
249
|
+
t.exception.all(() => idToBuffer(1));
|
|
250
|
+
t.exception.all(() => idToBuffer(null));
|
|
251
|
+
});
|
|
@@ -4,6 +4,7 @@ import { errorMessageIncludes } from "../../../helpers/regexHelper.js";
|
|
|
4
4
|
import fs from 'fs';
|
|
5
5
|
import PeerWallet from 'trac-wallet';
|
|
6
6
|
import { config } from '../../../helpers/config.js';
|
|
7
|
+
import { asAddress } from '../../../helpers/address.js';
|
|
7
8
|
|
|
8
9
|
const DUMMY_PATH_OK = './dummy_whitelist_ok.csv';
|
|
9
10
|
const DUMMY_PATH_DUP = './dummy_whitelist_dup.csv';
|
|
@@ -12,8 +13,8 @@ const DUMMY_PATH_BLANK = './dummy_whitelist_blank.csv';
|
|
|
12
13
|
const DUMMY_PATH_BOM = './dummy_whitelist_bom.csv';
|
|
13
14
|
const DUMMY_PATH_LARGE = './dummy_whitelist_large.csv';
|
|
14
15
|
|
|
15
|
-
const ADDR1 = '
|
|
16
|
-
const ADDR2 = '
|
|
16
|
+
const ADDR1 = asAddress('6a38e14198866f0fdf4d4495b07e066cfd0a2e8cbe774d11af37d15f741ac984');
|
|
17
|
+
const ADDR2 = asAddress('544514242356432739de9af71deb8d526fb03d6c5c15e0a934d9a20b6710e2fe');
|
|
17
18
|
|
|
18
19
|
hook('Initialize dummy whitelist files', async t => {
|
|
19
20
|
// Happy path
|
|
@@ -91,4 +92,4 @@ hook('Cleanup dummy whitelist files', async t => {
|
|
|
91
92
|
[DUMMY_PATH_OK, DUMMY_PATH_DUP, DUMMY_PATH_EMPTY, DUMMY_PATH_BLANK, DUMMY_PATH_BOM, DUMMY_PATH_LARGE].forEach(path => {
|
|
92
93
|
if (fs.existsSync(path)) fs.unlinkSync(path);
|
|
93
94
|
});
|
|
94
|
-
});
|
|
95
|
+
});
|
|
@@ -4,6 +4,7 @@ import { errorMessageIncludes } from "../../../helpers/regexHelper.js";
|
|
|
4
4
|
import fs from 'fs';
|
|
5
5
|
import PeerWallet from 'trac-wallet';
|
|
6
6
|
import { config } from '../../../helpers/config.js';
|
|
7
|
+
import { asAddress } from '../../../helpers/address.js';
|
|
7
8
|
|
|
8
9
|
const DUMMY_PATH_OK = './dummy_balance_ok.csv';
|
|
9
10
|
const DUMMY_PATH_DUP = './dummy_balance_dup.csv';
|
|
@@ -19,8 +20,8 @@ const DUMMY_PATH_ZERO = './dummy_balance_zero.csv';
|
|
|
19
20
|
const DUMMY_PATH_BOM = './dummy_balance_bom.csv';
|
|
20
21
|
const DUMMY_PATH_LARGE = './dummy_balance_large.csv';
|
|
21
22
|
|
|
22
|
-
const ADDR1 = '
|
|
23
|
-
const ADDR2 = '
|
|
23
|
+
const ADDR1 = asAddress('6a38e14198866f0fdf4d4495b07e066cfd0a2e8cbe774d11af37d15f741ac984');
|
|
24
|
+
const ADDR2 = asAddress('544514242356432739de9af71deb8d526fb03d6c5c15e0a934d9a20b6710e2fe');
|
|
24
25
|
|
|
25
26
|
hook('Initialize dummy balance files', async t => {
|
|
26
27
|
// Happy path
|
|
@@ -4,9 +4,10 @@ import { errorMessageIncludes } from "../../../helpers/regexHelper.js";
|
|
|
4
4
|
import { ZERO_LICENSE } from '../../../../src/core/state/utils/nodeEntry.js';
|
|
5
5
|
import b4a from 'b4a';
|
|
6
6
|
import { config } from '../../../helpers/config.js';
|
|
7
|
+
import { asAddress } from '../../../helpers/address.js';
|
|
7
8
|
|
|
8
|
-
const VALID_ADDRESS = '
|
|
9
|
-
const ADMIN_ADDRESS = '
|
|
9
|
+
const VALID_ADDRESS = asAddress('6a38e14198866f0fdf4d4495b07e066cfd0a2e8cbe774d11af37d15f741ac984');
|
|
10
|
+
const ADMIN_ADDRESS = asAddress('233aa0b7971509059e4816c782b32fec29b3797876bf92c072d1b0e058c5bf70');
|
|
10
11
|
const INVALID_ADDRESS = 'notanaddress';
|
|
11
12
|
const LICENSE_NUMBER_ONE = b4a.alloc(4, 1);
|
|
12
13
|
|
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
import { test } from 'brittle';
|
|
2
|
+
import b4a from 'b4a';
|
|
3
|
+
|
|
4
|
+
import { config } from '../../../helpers/config.js';
|
|
5
|
+
import { randomAddress } from '../../state/stateTestUtils.js';
|
|
6
|
+
import { errorMessageIncludes } from '../../../helpers/regexHelper.js';
|
|
7
|
+
import { OperationType } from '../../../../src/utils/constants.js';
|
|
8
|
+
import {
|
|
9
|
+
normalizeBootstrapDeploymentOperation,
|
|
10
|
+
normalizeDecodedPayloadForJson,
|
|
11
|
+
normalizeRoleAccessOperation,
|
|
12
|
+
normalizeTransactionOperation,
|
|
13
|
+
normalizeTransferOperation
|
|
14
|
+
} from '../../../../src/utils/normalizers.js';
|
|
15
|
+
import { addressToBuffer } from '../../../../src/core/state/utils/address.js';
|
|
16
|
+
import { bigIntTo16ByteBuffer } from '../../../../src/utils/amountSerialization.js';
|
|
17
|
+
|
|
18
|
+
const hex = (value, bytes) => value.repeat(bytes);
|
|
19
|
+
const toBuffer = value => b4a.from(value, 'hex');
|
|
20
|
+
|
|
21
|
+
test('normalizeTransferOperation normalizes hex strings and addresses', t => {
|
|
22
|
+
const sender = randomAddress(config.addressPrefix);
|
|
23
|
+
const recipient = randomAddress(config.addressPrefix);
|
|
24
|
+
const tx = hex('11', 32);
|
|
25
|
+
const txv = hex('22', 32);
|
|
26
|
+
const nonce = hex('33', 32);
|
|
27
|
+
const amount = hex('44', 16);
|
|
28
|
+
const signature = hex('55', 64);
|
|
29
|
+
|
|
30
|
+
const payload = {
|
|
31
|
+
type: OperationType.TRANSFER,
|
|
32
|
+
address: sender,
|
|
33
|
+
tro: {
|
|
34
|
+
tx,
|
|
35
|
+
txv,
|
|
36
|
+
in: nonce,
|
|
37
|
+
to: recipient,
|
|
38
|
+
am: amount,
|
|
39
|
+
is: signature
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const normalized = normalizeTransferOperation(payload, config);
|
|
44
|
+
|
|
45
|
+
t.is(normalized.type, OperationType.TRANSFER);
|
|
46
|
+
t.ok(b4a.equals(normalized.address, addressToBuffer(sender, config.addressPrefix)));
|
|
47
|
+
t.ok(b4a.equals(normalized.tro.tx, toBuffer(tx)));
|
|
48
|
+
t.ok(b4a.equals(normalized.tro.txv, toBuffer(txv)));
|
|
49
|
+
t.ok(b4a.equals(normalized.tro.in, toBuffer(nonce)));
|
|
50
|
+
t.ok(b4a.equals(normalized.tro.to, addressToBuffer(recipient, config.addressPrefix)));
|
|
51
|
+
t.ok(b4a.equals(normalized.tro.am, toBuffer(amount)));
|
|
52
|
+
t.ok(b4a.equals(normalized.tro.is, toBuffer(signature)));
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('normalizeTransferOperation accepts buffer inputs', t => {
|
|
56
|
+
const sender = randomAddress(config.addressPrefix);
|
|
57
|
+
const recipient = randomAddress(config.addressPrefix);
|
|
58
|
+
const tx = toBuffer(hex('aa', 32));
|
|
59
|
+
const txv = toBuffer(hex('bb', 32));
|
|
60
|
+
const nonce = toBuffer(hex('cc', 32));
|
|
61
|
+
const amount = toBuffer(hex('dd', 16));
|
|
62
|
+
const signature = toBuffer(hex('ee', 64));
|
|
63
|
+
|
|
64
|
+
const payload = {
|
|
65
|
+
type: OperationType.TRANSFER,
|
|
66
|
+
address: sender,
|
|
67
|
+
tro: {
|
|
68
|
+
tx,
|
|
69
|
+
txv,
|
|
70
|
+
in: nonce,
|
|
71
|
+
to: recipient,
|
|
72
|
+
am: amount,
|
|
73
|
+
is: signature
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const normalized = normalizeTransferOperation(payload, config);
|
|
78
|
+
t.ok(b4a.equals(normalized.tro.tx, tx));
|
|
79
|
+
t.ok(b4a.equals(normalized.tro.txv, txv));
|
|
80
|
+
t.ok(b4a.equals(normalized.tro.in, nonce));
|
|
81
|
+
t.ok(b4a.equals(normalized.tro.am, amount));
|
|
82
|
+
t.ok(b4a.equals(normalized.tro.is, signature));
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test('normalizeTransferOperation throws on missing payload fields', t => {
|
|
86
|
+
t.exception(
|
|
87
|
+
() => normalizeTransferOperation({ type: OperationType.TRANSFER }, config),
|
|
88
|
+
errorMessageIncludes('Invalid payload for transfer operation normalization.')
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
t.exception(
|
|
92
|
+
() => normalizeTransferOperation({ type: OperationType.TX, address: 'x', tro: {} }, config),
|
|
93
|
+
errorMessageIncludes('Missing required fields in transfer operation payload.')
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const sender = randomAddress(config.addressPrefix);
|
|
97
|
+
const payload = {
|
|
98
|
+
type: OperationType.TRANSFER,
|
|
99
|
+
address: sender,
|
|
100
|
+
tro: {
|
|
101
|
+
tx: hex('11', 32),
|
|
102
|
+
txv: hex('22', 32),
|
|
103
|
+
in: hex('33', 32),
|
|
104
|
+
to: randomAddress(config.addressPrefix),
|
|
105
|
+
am: hex('44', 16)
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
t.exception(
|
|
109
|
+
() => normalizeTransferOperation(payload, config),
|
|
110
|
+
errorMessageIncludes('Missing required fields in transfer operation payload.')
|
|
111
|
+
);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test('normalizeTransferOperation throws on invalid hex string', t => {
|
|
115
|
+
const sender = randomAddress(config.addressPrefix);
|
|
116
|
+
const payload = {
|
|
117
|
+
type: OperationType.TRANSFER,
|
|
118
|
+
address: sender,
|
|
119
|
+
tro: {
|
|
120
|
+
tx: 'zz',
|
|
121
|
+
txv: hex('22', 32),
|
|
122
|
+
in: hex('33', 32),
|
|
123
|
+
to: randomAddress(config.addressPrefix),
|
|
124
|
+
am: hex('44', 16),
|
|
125
|
+
is: hex('55', 64)
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
t.exception(
|
|
129
|
+
() => normalizeTransferOperation(payload, config),
|
|
130
|
+
errorMessageIncludes('Invalid hex string')
|
|
131
|
+
);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('normalizeTransactionOperation normalizes hex strings and addresses', t => {
|
|
135
|
+
const sender = randomAddress(config.addressPrefix);
|
|
136
|
+
const tx = hex('11', 32);
|
|
137
|
+
const txv = hex('22', 32);
|
|
138
|
+
const writerKey = hex('33', 32);
|
|
139
|
+
const contentHash = hex('44', 32);
|
|
140
|
+
const bootstrap = hex('55', 32);
|
|
141
|
+
const msbBootstrap = hex('66', 32);
|
|
142
|
+
const nonce = hex('77', 32);
|
|
143
|
+
const signature = hex('88', 64);
|
|
144
|
+
|
|
145
|
+
const payload = {
|
|
146
|
+
type: OperationType.TX,
|
|
147
|
+
address: sender,
|
|
148
|
+
txo: {
|
|
149
|
+
tx,
|
|
150
|
+
txv,
|
|
151
|
+
iw: writerKey,
|
|
152
|
+
ch: contentHash,
|
|
153
|
+
bs: bootstrap,
|
|
154
|
+
mbs: msbBootstrap,
|
|
155
|
+
in: nonce,
|
|
156
|
+
is: signature
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const normalized = normalizeTransactionOperation(payload, config);
|
|
161
|
+
t.is(normalized.type, OperationType.TX);
|
|
162
|
+
t.ok(b4a.equals(normalized.address, addressToBuffer(sender, config.addressPrefix)));
|
|
163
|
+
t.ok(b4a.equals(normalized.txo.tx, toBuffer(tx)));
|
|
164
|
+
t.ok(b4a.equals(normalized.txo.txv, toBuffer(txv)));
|
|
165
|
+
t.ok(b4a.equals(normalized.txo.iw, toBuffer(writerKey)));
|
|
166
|
+
t.ok(b4a.equals(normalized.txo.ch, toBuffer(contentHash)));
|
|
167
|
+
t.ok(b4a.equals(normalized.txo.bs, toBuffer(bootstrap)));
|
|
168
|
+
t.ok(b4a.equals(normalized.txo.mbs, toBuffer(msbBootstrap)));
|
|
169
|
+
t.ok(b4a.equals(normalized.txo.in, toBuffer(nonce)));
|
|
170
|
+
t.ok(b4a.equals(normalized.txo.is, toBuffer(signature)));
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test('normalizeTransactionOperation accepts buffer inputs', t => {
|
|
174
|
+
const sender = randomAddress(config.addressPrefix);
|
|
175
|
+
const tx = toBuffer(hex('aa', 32));
|
|
176
|
+
const txv = toBuffer(hex('bb', 32));
|
|
177
|
+
const writerKey = toBuffer(hex('cc', 32));
|
|
178
|
+
const contentHash = toBuffer(hex('dd', 32));
|
|
179
|
+
const bootstrap = toBuffer(hex('ee', 32));
|
|
180
|
+
const msbBootstrap = toBuffer(hex('ff', 32));
|
|
181
|
+
const nonce = toBuffer(hex('12', 32));
|
|
182
|
+
const signature = toBuffer(hex('34', 64));
|
|
183
|
+
|
|
184
|
+
const payload = {
|
|
185
|
+
type: OperationType.TX,
|
|
186
|
+
address: sender,
|
|
187
|
+
txo: {
|
|
188
|
+
tx,
|
|
189
|
+
txv,
|
|
190
|
+
iw: writerKey,
|
|
191
|
+
ch: contentHash,
|
|
192
|
+
bs: bootstrap,
|
|
193
|
+
mbs: msbBootstrap,
|
|
194
|
+
in: nonce,
|
|
195
|
+
is: signature
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const normalized = normalizeTransactionOperation(payload, config);
|
|
200
|
+
t.ok(b4a.equals(normalized.txo.tx, tx));
|
|
201
|
+
t.ok(b4a.equals(normalized.txo.txv, txv));
|
|
202
|
+
t.ok(b4a.equals(normalized.txo.iw, writerKey));
|
|
203
|
+
t.ok(b4a.equals(normalized.txo.ch, contentHash));
|
|
204
|
+
t.ok(b4a.equals(normalized.txo.bs, bootstrap));
|
|
205
|
+
t.ok(b4a.equals(normalized.txo.mbs, msbBootstrap));
|
|
206
|
+
t.ok(b4a.equals(normalized.txo.in, nonce));
|
|
207
|
+
t.ok(b4a.equals(normalized.txo.is, signature));
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
test('normalizeTransactionOperation throws on missing payload fields', t => {
|
|
211
|
+
t.exception(
|
|
212
|
+
() => normalizeTransactionOperation({ type: OperationType.TX }, config),
|
|
213
|
+
errorMessageIncludes('Invalid payload for transaction operation normalization.')
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
t.exception(
|
|
217
|
+
() => normalizeTransactionOperation({ type: OperationType.TRANSFER, address: 'x', txo: {} }, config),
|
|
218
|
+
errorMessageIncludes('Missing required fields in transaction operation payload.')
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
const sender = randomAddress(config.addressPrefix);
|
|
222
|
+
const payload = {
|
|
223
|
+
type: OperationType.TX,
|
|
224
|
+
address: sender,
|
|
225
|
+
txo: {
|
|
226
|
+
tx: hex('11', 32),
|
|
227
|
+
txv: hex('22', 32),
|
|
228
|
+
iw: hex('33', 32),
|
|
229
|
+
ch: hex('44', 32),
|
|
230
|
+
bs: hex('55', 32),
|
|
231
|
+
mbs: hex('66', 32),
|
|
232
|
+
in: hex('77', 32)
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
t.exception(
|
|
236
|
+
() => normalizeTransactionOperation(payload, config),
|
|
237
|
+
errorMessageIncludes('Missing required fields in transaction operation payload.')
|
|
238
|
+
);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test('normalizeTransactionOperation throws on invalid hex string', t => {
|
|
242
|
+
const sender = randomAddress(config.addressPrefix);
|
|
243
|
+
const payload = {
|
|
244
|
+
type: OperationType.TX,
|
|
245
|
+
address: sender,
|
|
246
|
+
txo: {
|
|
247
|
+
tx: 'zz',
|
|
248
|
+
txv: hex('22', 32),
|
|
249
|
+
iw: hex('33', 32),
|
|
250
|
+
ch: hex('44', 32),
|
|
251
|
+
bs: hex('55', 32),
|
|
252
|
+
mbs: hex('66', 32),
|
|
253
|
+
in: hex('77', 32),
|
|
254
|
+
is: hex('88', 64)
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
t.exception(
|
|
258
|
+
() => normalizeTransactionOperation(payload, config),
|
|
259
|
+
errorMessageIncludes('Invalid hex string')
|
|
260
|
+
);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
test('normalizeRoleAccessOperation normalizes hex strings and addresses', t => {
|
|
264
|
+
const sender = randomAddress(config.addressPrefix);
|
|
265
|
+
const payload = {
|
|
266
|
+
type: OperationType.ADD_WRITER,
|
|
267
|
+
address: sender,
|
|
268
|
+
rao: {
|
|
269
|
+
tx: hex('11', 32),
|
|
270
|
+
txv: hex('22', 32),
|
|
271
|
+
iw: hex('33', 32),
|
|
272
|
+
in: hex('44', 32),
|
|
273
|
+
is: hex('55', 64)
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
const normalized = normalizeRoleAccessOperation(payload, config);
|
|
278
|
+
t.is(normalized.type, OperationType.ADD_WRITER);
|
|
279
|
+
t.ok(b4a.equals(normalized.address, addressToBuffer(sender, config.addressPrefix)));
|
|
280
|
+
t.ok(b4a.equals(normalized.rao.tx, toBuffer(hex('11', 32))));
|
|
281
|
+
t.ok(b4a.equals(normalized.rao.txv, toBuffer(hex('22', 32))));
|
|
282
|
+
t.ok(b4a.equals(normalized.rao.iw, toBuffer(hex('33', 32))));
|
|
283
|
+
t.ok(b4a.equals(normalized.rao.in, toBuffer(hex('44', 32))));
|
|
284
|
+
t.ok(b4a.equals(normalized.rao.is, toBuffer(hex('55', 64))));
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
test('normalizeRoleAccessOperation accepts buffer inputs', t => {
|
|
288
|
+
const sender = randomAddress(config.addressPrefix);
|
|
289
|
+
const tx = toBuffer(hex('aa', 32));
|
|
290
|
+
const txv = toBuffer(hex('bb', 32));
|
|
291
|
+
const writerKey = toBuffer(hex('cc', 32));
|
|
292
|
+
const nonce = toBuffer(hex('dd', 32));
|
|
293
|
+
const signature = toBuffer(hex('ee', 64));
|
|
294
|
+
|
|
295
|
+
const payload = {
|
|
296
|
+
type: OperationType.REMOVE_WRITER,
|
|
297
|
+
address: sender,
|
|
298
|
+
rao: {
|
|
299
|
+
tx,
|
|
300
|
+
txv,
|
|
301
|
+
iw: writerKey,
|
|
302
|
+
in: nonce,
|
|
303
|
+
is: signature
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
const normalized = normalizeRoleAccessOperation(payload, config);
|
|
308
|
+
t.ok(b4a.equals(normalized.rao.tx, tx));
|
|
309
|
+
t.ok(b4a.equals(normalized.rao.txv, txv));
|
|
310
|
+
t.ok(b4a.equals(normalized.rao.iw, writerKey));
|
|
311
|
+
t.ok(b4a.equals(normalized.rao.in, nonce));
|
|
312
|
+
t.ok(b4a.equals(normalized.rao.is, signature));
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
test('normalizeRoleAccessOperation throws on missing payload fields', t => {
|
|
316
|
+
t.exception(
|
|
317
|
+
() => normalizeRoleAccessOperation({ type: OperationType.ADD_WRITER }, config),
|
|
318
|
+
errorMessageIncludes('Invalid payload for role access normalization.')
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
t.exception(
|
|
322
|
+
() => normalizeRoleAccessOperation({ type: OperationType.ADD_WRITER, address: 'x', rao: {} }, config),
|
|
323
|
+
errorMessageIncludes('Missing required fields in role access payload.')
|
|
324
|
+
);
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
test('normalizeRoleAccessOperation throws on invalid hex string', t => {
|
|
328
|
+
const sender = randomAddress(config.addressPrefix);
|
|
329
|
+
const payload = {
|
|
330
|
+
type: OperationType.ADD_WRITER,
|
|
331
|
+
address: sender,
|
|
332
|
+
rao: {
|
|
333
|
+
tx: 'zz',
|
|
334
|
+
txv: hex('22', 32),
|
|
335
|
+
iw: hex('33', 32),
|
|
336
|
+
in: hex('44', 32),
|
|
337
|
+
is: hex('55', 64)
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
t.exception(
|
|
341
|
+
() => normalizeRoleAccessOperation(payload, config),
|
|
342
|
+
errorMessageIncludes('Invalid hex string')
|
|
343
|
+
);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
test('normalizeBootstrapDeploymentOperation normalizes hex strings and addresses', t => {
|
|
347
|
+
const sender = randomAddress(config.addressPrefix);
|
|
348
|
+
const payload = {
|
|
349
|
+
type: OperationType.BOOTSTRAP_DEPLOYMENT,
|
|
350
|
+
address: sender,
|
|
351
|
+
bdo: {
|
|
352
|
+
tx: hex('11', 32),
|
|
353
|
+
txv: hex('22', 32),
|
|
354
|
+
bs: hex('33', 32),
|
|
355
|
+
ic: hex('44', 32),
|
|
356
|
+
in: hex('55', 32),
|
|
357
|
+
is: hex('66', 64)
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
const normalized = normalizeBootstrapDeploymentOperation(payload, config);
|
|
362
|
+
t.is(normalized.type, OperationType.BOOTSTRAP_DEPLOYMENT);
|
|
363
|
+
t.ok(b4a.equals(normalized.address, addressToBuffer(sender, config.addressPrefix)));
|
|
364
|
+
t.ok(b4a.equals(normalized.bdo.tx, toBuffer(hex('11', 32))));
|
|
365
|
+
t.ok(b4a.equals(normalized.bdo.txv, toBuffer(hex('22', 32))));
|
|
366
|
+
t.ok(b4a.equals(normalized.bdo.bs, toBuffer(hex('33', 32))));
|
|
367
|
+
t.ok(b4a.equals(normalized.bdo.ic, toBuffer(hex('44', 32))));
|
|
368
|
+
t.ok(b4a.equals(normalized.bdo.in, toBuffer(hex('55', 32))));
|
|
369
|
+
t.ok(b4a.equals(normalized.bdo.is, toBuffer(hex('66', 64))));
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
test('normalizeBootstrapDeploymentOperation accepts buffer inputs', t => {
|
|
373
|
+
const sender = randomAddress(config.addressPrefix);
|
|
374
|
+
const tx = toBuffer(hex('aa', 32));
|
|
375
|
+
const txv = toBuffer(hex('bb', 32));
|
|
376
|
+
const bootstrap = toBuffer(hex('cc', 32));
|
|
377
|
+
const channel = toBuffer(hex('dd', 32));
|
|
378
|
+
const nonce = toBuffer(hex('ee', 32));
|
|
379
|
+
const signature = toBuffer(hex('ff', 64));
|
|
380
|
+
|
|
381
|
+
const payload = {
|
|
382
|
+
type: OperationType.BOOTSTRAP_DEPLOYMENT,
|
|
383
|
+
address: sender,
|
|
384
|
+
bdo: {
|
|
385
|
+
tx,
|
|
386
|
+
txv,
|
|
387
|
+
bs: bootstrap,
|
|
388
|
+
ic: channel,
|
|
389
|
+
in: nonce,
|
|
390
|
+
is: signature
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
const normalized = normalizeBootstrapDeploymentOperation(payload, config);
|
|
395
|
+
t.ok(b4a.equals(normalized.bdo.tx, tx));
|
|
396
|
+
t.ok(b4a.equals(normalized.bdo.txv, txv));
|
|
397
|
+
t.ok(b4a.equals(normalized.bdo.bs, bootstrap));
|
|
398
|
+
t.ok(b4a.equals(normalized.bdo.ic, channel));
|
|
399
|
+
t.ok(b4a.equals(normalized.bdo.in, nonce));
|
|
400
|
+
t.ok(b4a.equals(normalized.bdo.is, signature));
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
test('normalizeBootstrapDeploymentOperation throws on missing payload fields', t => {
|
|
404
|
+
t.exception(
|
|
405
|
+
() => normalizeBootstrapDeploymentOperation({ type: OperationType.BOOTSTRAP_DEPLOYMENT }, config),
|
|
406
|
+
errorMessageIncludes('Invalid payload for bootstrap deployment normalization.')
|
|
407
|
+
);
|
|
408
|
+
|
|
409
|
+
t.exception(
|
|
410
|
+
() => normalizeBootstrapDeploymentOperation({ type: OperationType.TX, address: 'x', bdo: {} }, config),
|
|
411
|
+
errorMessageIncludes('Missing required fields in bootstrap deployment payload.')
|
|
412
|
+
);
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
test('normalizeBootstrapDeploymentOperation throws on invalid hex string', t => {
|
|
416
|
+
const sender = randomAddress(config.addressPrefix);
|
|
417
|
+
const payload = {
|
|
418
|
+
type: OperationType.BOOTSTRAP_DEPLOYMENT,
|
|
419
|
+
address: sender,
|
|
420
|
+
bdo: {
|
|
421
|
+
tx: 'zz',
|
|
422
|
+
txv: hex('22', 32),
|
|
423
|
+
bs: hex('33', 32),
|
|
424
|
+
ic: hex('44', 32),
|
|
425
|
+
in: hex('55', 32),
|
|
426
|
+
is: hex('66', 64)
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
t.exception(
|
|
430
|
+
() => normalizeBootstrapDeploymentOperation(payload, config),
|
|
431
|
+
errorMessageIncludes('Invalid hex string')
|
|
432
|
+
);
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
test('normalizeDecodedPayloadForJson converts buffers to strings', t => {
|
|
436
|
+
const address = randomAddress(config.addressPrefix);
|
|
437
|
+
const addressBuf = addressToBuffer(address, config.addressPrefix);
|
|
438
|
+
const amountBuf = bigIntTo16ByteBuffer(1234n);
|
|
439
|
+
const otherBuf = b4a.from('abcd', 'hex');
|
|
440
|
+
|
|
441
|
+
const payload = {
|
|
442
|
+
address: addressBuf,
|
|
443
|
+
am: amountBuf,
|
|
444
|
+
nested: {
|
|
445
|
+
to: addressBuf,
|
|
446
|
+
amount: amountBuf,
|
|
447
|
+
other: otherBuf
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
const normalized = normalizeDecodedPayloadForJson(payload, config);
|
|
452
|
+
t.is(normalized.address, address);
|
|
453
|
+
t.is(normalized.am, '1234');
|
|
454
|
+
t.is(normalized.nested.to, address);
|
|
455
|
+
t.is(normalized.nested.amount, '1234');
|
|
456
|
+
t.is(normalized.nested.other, 'abcd');
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
test('normalizeDecodedPayloadForJson falls back to hex for invalid address buffers', t => {
|
|
460
|
+
const bad = b4a.from('deadbeef', 'hex');
|
|
461
|
+
const payload = { address: bad };
|
|
462
|
+
const normalized = normalizeDecodedPayloadForJson(payload, config);
|
|
463
|
+
t.is(normalized.address, b4a.toString(bad, 'hex'));
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
test('normalizeDecodedPayloadForJson returns input for non-objects', t => {
|
|
467
|
+
t.is(normalizeDecodedPayloadForJson(null, config), null);
|
|
468
|
+
t.is(normalizeDecodedPayloadForJson('value', config), 'value');
|
|
469
|
+
});
|