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
package/rpc/rpc_services.js
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { bufferToBigInt } from "../src/utils/amountSerialization.js";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
normalizeDecodedPayloadForJson,
|
|
4
|
+
normalizeTransactionOperation,
|
|
5
|
+
normalizeTransferOperation
|
|
6
|
+
} from "../src/utils/normalizers.js";
|
|
3
7
|
import { get_confirmed_tx_info, get_unconfirmed_tx_info } from "../src/utils/cli.js";
|
|
8
|
+
import { OperationType } from "../src/utils/constants.js";
|
|
9
|
+
import b4a from "b4a";
|
|
10
|
+
import PartialTransaction from "../src/core/network/protocols/shared/validators/PartialTransaction.js";
|
|
11
|
+
import PartialTransfer from "../src/core/network/protocols/shared/validators/PartialTransfer.js";
|
|
12
|
+
import { ValidationError, BroadcastError, NotFoundError } from "./utils/helpers.js";
|
|
4
13
|
|
|
5
14
|
export async function getBalance(msbInstance, address, confirmed) {
|
|
6
15
|
const state = msbInstance.state;
|
|
@@ -36,8 +45,47 @@ export async function getUnconfirmedLength(msbInstance) {
|
|
|
36
45
|
return msbInstance.state.getUnsignedLength();
|
|
37
46
|
}
|
|
38
47
|
|
|
39
|
-
export async function broadcastTransaction(msbInstance, payload) {
|
|
40
|
-
|
|
48
|
+
export async function broadcastTransaction(msbInstance, config, payload) {
|
|
49
|
+
if (!payload) {
|
|
50
|
+
throw new ValidationError("Transaction payload is required for broadcasting.");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let normalizedPayload;
|
|
54
|
+
let isValid = false;
|
|
55
|
+
let hash;
|
|
56
|
+
|
|
57
|
+
const partialTransferValidator = new PartialTransfer(msbInstance.state, null, config);
|
|
58
|
+
const partialTransactionValidator = new PartialTransaction(msbInstance.state, null, config);
|
|
59
|
+
|
|
60
|
+
if (payload.type === OperationType.TRANSFER) {
|
|
61
|
+
normalizedPayload = normalizeTransferOperation(payload, config);
|
|
62
|
+
isValid = await partialTransferValidator.validate(normalizedPayload);
|
|
63
|
+
hash = b4a.toString(normalizedPayload.tro.tx, "hex");
|
|
64
|
+
} else if (payload.type === OperationType.TX) {
|
|
65
|
+
normalizedPayload = normalizeTransactionOperation(payload, config);
|
|
66
|
+
isValid = await partialTransactionValidator.validate(normalizedPayload);
|
|
67
|
+
hash = b4a.toString(normalizedPayload.txo.tx, "hex");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!isValid) {
|
|
71
|
+
throw new ValidationError("Invalid transaction payload.");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const success = await msbInstance.broadcastPartialTransaction(payload);
|
|
75
|
+
|
|
76
|
+
if (!success) {
|
|
77
|
+
throw new BroadcastError("Failed to broadcast transaction after multiple attempts.");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const signedLength = msbInstance.state.getSignedLength();
|
|
81
|
+
const unsignedLength = msbInstance.state.getUnsignedLength();
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
message: "Transaction broadcasted successfully.",
|
|
85
|
+
signedLength,
|
|
86
|
+
unsignedLength,
|
|
87
|
+
tx: hash
|
|
88
|
+
};
|
|
41
89
|
}
|
|
42
90
|
|
|
43
91
|
export async function getTxHashes(msbInstance, start, end) {
|
|
@@ -48,7 +96,7 @@ export async function getTxHashes(msbInstance, start, end) {
|
|
|
48
96
|
export async function getTxDetails(msbInstance, hash) {
|
|
49
97
|
const rawPayload = await get_confirmed_tx_info(msbInstance.state, hash);
|
|
50
98
|
if (!rawPayload) {
|
|
51
|
-
|
|
99
|
+
throw new NotFoundError(`Transaction ${hash} not found.`);
|
|
52
100
|
}
|
|
53
101
|
|
|
54
102
|
return normalizeDecodedPayloadForJson(rawPayload.decoded, msbInstance.config);
|
|
@@ -56,11 +104,11 @@ export async function getTxDetails(msbInstance, hash) {
|
|
|
56
104
|
|
|
57
105
|
export async function fetchBulkTxPayloads(msbInstance, hashes) {
|
|
58
106
|
if (!Array.isArray(hashes) || hashes.length === 0) {
|
|
59
|
-
throw new
|
|
107
|
+
throw new ValidationError("Missing hash list.");
|
|
60
108
|
}
|
|
61
109
|
|
|
62
110
|
if (hashes.length > 1500) {
|
|
63
|
-
throw new
|
|
111
|
+
throw new ValidationError("Length of input tx hashes exceeded.");
|
|
64
112
|
}
|
|
65
113
|
|
|
66
114
|
const res = { results: [], missing: [] };
|
|
@@ -70,7 +118,7 @@ export async function fetchBulkTxPayloads(msbInstance, hashes) {
|
|
|
70
118
|
|
|
71
119
|
results.forEach((result, index) => {
|
|
72
120
|
const hash = hashes[index];
|
|
73
|
-
if (result
|
|
121
|
+
if (!result) {
|
|
74
122
|
res.missing.push(hash);
|
|
75
123
|
} else {
|
|
76
124
|
const decodedResult = normalizeDecodedPayloadForJson(result.decoded, msbInstance.config);
|
|
@@ -83,32 +131,21 @@ export async function fetchBulkTxPayloads(msbInstance, hashes) {
|
|
|
83
131
|
|
|
84
132
|
export async function getExtendedTxDetails(msbInstance, hash, confirmed) {
|
|
85
133
|
const state = msbInstance.state;
|
|
134
|
+
let rawPayload;
|
|
86
135
|
|
|
87
136
|
if (confirmed) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
const confirmedLength = await state.getTransactionConfirmedLength(hash);
|
|
93
|
-
if (confirmedLength === null) {
|
|
94
|
-
throw new Error(`No confirmed length found for tx hash: ${hash} in confirmed mode`);
|
|
95
|
-
}
|
|
96
|
-
const normalizedPayload = normalizeDecodedPayloadForJson(rawPayload.decoded, msbInstance.config);
|
|
97
|
-
const feeBuffer = state.getFee();
|
|
98
|
-
return {
|
|
99
|
-
txDetails: normalizedPayload,
|
|
100
|
-
confirmed_length: confirmedLength,
|
|
101
|
-
fee: bufferToBigInt(feeBuffer).toString(),
|
|
102
|
-
};
|
|
137
|
+
rawPayload = await get_confirmed_tx_info(state, hash);
|
|
138
|
+
} else {
|
|
139
|
+
rawPayload = await get_unconfirmed_tx_info(state, hash);
|
|
103
140
|
}
|
|
104
141
|
|
|
105
|
-
const rawPayload = await get_unconfirmed_tx_info(state, hash);
|
|
106
142
|
if (!rawPayload) {
|
|
107
|
-
throw new
|
|
143
|
+
throw new NotFoundError(`No payload found for tx hash: ${hash}`);
|
|
108
144
|
}
|
|
109
145
|
|
|
110
146
|
const normalizedPayload = normalizeDecodedPayloadForJson(rawPayload.decoded, msbInstance.config);
|
|
111
147
|
const length = await state.getTransactionConfirmedLength(hash);
|
|
148
|
+
|
|
112
149
|
if (length === null) {
|
|
113
150
|
return {
|
|
114
151
|
txDetails: normalizedPayload,
|
|
@@ -123,4 +160,4 @@ export async function getExtendedTxDetails(msbInstance, hash, confirmed) {
|
|
|
123
160
|
confirmed_length: length,
|
|
124
161
|
fee: bufferToBigInt(feeBuffer).toString(),
|
|
125
162
|
};
|
|
126
|
-
}
|
|
163
|
+
}
|
package/rpc/utils/helpers.js
CHANGED
|
@@ -1,74 +1,105 @@
|
|
|
1
1
|
import b4a from "b4a"
|
|
2
|
-
import { operationToPayload } from "../../src/utils/
|
|
2
|
+
import { operationToPayload } from "../../src/utils/applyOperations.js"
|
|
3
|
+
import { isHexString } from "../../src/utils/helpers.js";
|
|
4
|
+
|
|
5
|
+
export class ValidationError extends Error {
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = "ValidationError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class BroadcastError extends Error {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = "BroadcastError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class NotFoundError extends Error {
|
|
20
|
+
constructor(message) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = "NotFoundError";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
3
26
|
export function decodeBase64Payload(base64) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
27
|
+
let decodedPayloadString
|
|
28
|
+
try {
|
|
29
|
+
decodedPayloadString = b4a.from(base64, "base64").toString("utf-8")
|
|
30
|
+
} catch (err) {
|
|
31
|
+
throw new ValidationError("Failed to decode base64 payload.")
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
return JSON.parse(decodedPayloadString)
|
|
36
|
+
} catch (err) {
|
|
37
|
+
throw new ValidationError("Decoded payload is not valid JSON.")
|
|
38
|
+
}
|
|
16
39
|
}
|
|
17
40
|
|
|
18
41
|
export function isBase64(str) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
42
|
+
const base64Regex =
|
|
43
|
+
/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/
|
|
44
|
+
return base64Regex.test(str)
|
|
22
45
|
}
|
|
23
46
|
|
|
24
47
|
export function validatePayloadStructure(payload) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
48
|
+
if (
|
|
49
|
+
typeof payload !== "object" ||
|
|
50
|
+
payload === null ||
|
|
51
|
+
typeof payload.type !== "number" ||
|
|
52
|
+
typeof payload.address !== "string" ||
|
|
53
|
+
!["txo", "tro"].some((key) => key in payload && typeof payload[key] === "object")
|
|
54
|
+
) {
|
|
55
|
+
throw new ValidationError("Invalid payload structure.")
|
|
56
|
+
}
|
|
34
57
|
}
|
|
35
58
|
|
|
36
59
|
export function sanitizeTransferPayload(payload) {
|
|
37
|
-
|
|
60
|
+
const operationKey = operationToPayload(payload.type);
|
|
38
61
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
62
|
+
if (operationKey !== 'tro' && operationKey !== 'txo') {
|
|
63
|
+
throw new ValidationError('Payload is not a transfer/transaction operation.');
|
|
64
|
+
}
|
|
42
65
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
66
|
+
const operation = payload[operationKey];
|
|
67
|
+
if (payload.address && typeof payload.address === "string") {
|
|
68
|
+
payload.address = payload.address.trim()
|
|
69
|
+
}
|
|
47
70
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
71
|
+
if (operation && typeof operation === "object") {
|
|
72
|
+
for (const [key, value] of Object.entries(operation)) {
|
|
73
|
+
if (typeof value === "string") {
|
|
74
|
+
let sanitized = value.trim()
|
|
52
75
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
76
|
+
// normalize hex-like strings
|
|
77
|
+
if (/^[0-9A-F]+$/i.test(sanitized)) {
|
|
78
|
+
sanitized = sanitized.toLowerCase()
|
|
79
|
+
}
|
|
57
80
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
81
|
+
payload[operationKey][key] = sanitized
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
62
85
|
|
|
63
|
-
|
|
86
|
+
return payload
|
|
64
87
|
}
|
|
65
88
|
|
|
66
89
|
export function sanitizeBulkPayloadsRequestBody(body) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
90
|
+
const cleanBody = body
|
|
91
|
+
.replace(/^\uFEFF/, '')
|
|
92
|
+
.replace(/\r/g, '')
|
|
93
|
+
.replace(/\0/g, '')
|
|
94
|
+
.trim();
|
|
72
95
|
|
|
73
|
-
|
|
96
|
+
return JSON.parse(cleanBody);
|
|
74
97
|
}
|
|
98
|
+
|
|
99
|
+
export function isValidTxHash(hash) {
|
|
100
|
+
return isHexString(hash) && hash?.length === 64;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function hasSpacesInUrl(url) {
|
|
104
|
+
return url.includes('%20') || url.includes(' ');
|
|
105
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { createConfig, ENV } from './env.js';
|
|
2
|
+
|
|
3
|
+
const getArguments = () => {
|
|
4
|
+
const pearApp = typeof Pear !== 'undefined' ? (Pear.app ?? Pear.config) : undefined;
|
|
5
|
+
const runtimeArgs = typeof process !== 'undefined' ? process.argv.slice(2) : [];
|
|
6
|
+
return pearApp?.args ?? runtimeArgs;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const resolveEnvironment = (args = []) => {
|
|
10
|
+
const networkIndex = args.indexOf('--network');
|
|
11
|
+
const network = (networkIndex !== -1 && args[networkIndex + 1]) ? args[networkIndex + 1] : undefined;
|
|
12
|
+
|
|
13
|
+
if (network === ENV.MAINNET) return ENV.MAINNET;
|
|
14
|
+
if (network === ENV.DEVELOPMENT) return ENV.DEVELOPMENT;
|
|
15
|
+
if (network === ENV.TESTNET1 || network === 'testnet') return ENV.TESTNET1;
|
|
16
|
+
return ENV.MAINNET;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const isRpcEnabled = () => {
|
|
20
|
+
const args = getArguments();
|
|
21
|
+
return args.includes('--rpc');
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const resolveConfig = () => {
|
|
25
|
+
const args = getArguments();
|
|
26
|
+
const runRpc = isRpcEnabled();
|
|
27
|
+
const selectedEnv = resolveEnvironment(args);
|
|
28
|
+
const storesDirectoryIndex = args.indexOf('--stores-directory');
|
|
29
|
+
const storesDirectory = (storesDirectoryIndex !== -1 && args[storesDirectoryIndex + 1]) ? args[storesDirectoryIndex + 1] : undefined;
|
|
30
|
+
const hostIndex = args.indexOf('--host');
|
|
31
|
+
const host = (hostIndex !== -1 && args[hostIndex + 1]) ? args[hostIndex + 1] : undefined;
|
|
32
|
+
const portIndex = args.indexOf('--port');
|
|
33
|
+
const port = (portIndex !== -1 && args[portIndex + 1]) ? parseInt(args[portIndex + 1], 10) : undefined;
|
|
34
|
+
|
|
35
|
+
const rpc = {
|
|
36
|
+
storesDirectory,
|
|
37
|
+
enableWallet: false,
|
|
38
|
+
enableInteractiveMode: false,
|
|
39
|
+
host,
|
|
40
|
+
port
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const options = runRpc ? rpc : { storesDirectory };
|
|
44
|
+
|
|
45
|
+
return createConfig(selectedEnv, options);
|
|
46
|
+
};
|
package/src/config/config.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import b4a from 'b4a'
|
|
2
|
+
import { isDefined } from '../utils/type.js'
|
|
3
|
+
import _ from 'lodash'
|
|
2
4
|
|
|
3
5
|
export class Config {
|
|
4
6
|
#options
|
|
@@ -80,7 +82,7 @@ export class Config {
|
|
|
80
82
|
}
|
|
81
83
|
|
|
82
84
|
get isAdminMode() {
|
|
83
|
-
return this
|
|
85
|
+
return _.endsWith(this.storesDirectory, '/admin')
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
get keyPairPath() {
|
|
@@ -97,17 +99,73 @@ export class Config {
|
|
|
97
99
|
return this.#config.maxValidators
|
|
98
100
|
}
|
|
99
101
|
|
|
102
|
+
get maxPeers() {
|
|
103
|
+
if (this.#isOverriden('maxPeers')) return this.#options.maxPeers
|
|
104
|
+
return this.#config.maxPeers
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
get maxParallel() {
|
|
108
|
+
if (this.#isOverriden('maxParallel')) return this.#options.maxParallel
|
|
109
|
+
return this.#config.maxParallel
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
get maxServerConnections() {
|
|
113
|
+
if (this.#isOverriden('maxServerConnections')) return this.#options.maxServerConnections
|
|
114
|
+
return this.#config.maxServerConnections
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
get maxClientConnections() {
|
|
118
|
+
if (this.#isOverriden('maxClientConnections')) return this.#options.maxClientConnections
|
|
119
|
+
return this.#config.maxClientConnections
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
get maxWritersForAdminIndexerConnection() {
|
|
123
|
+
if (this.#isOverriden('maxWritersForAdminIndexerConnection')) return this.#options.maxWritersForAdminIndexerConnection
|
|
124
|
+
return this.#config.maxWritersForAdminIndexerConnection
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
get processIntervalMs() {
|
|
128
|
+
if (this.#isOverriden('processIntervalMs')) return this.#options.processIntervalMs
|
|
129
|
+
return this.#config.processIntervalMs
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
get maxPartialTxPayloadByteSize() {
|
|
133
|
+
if (this.#isOverriden('maxPartialTxPayloadByteSize')) return this.#options.maxPartialTxPayloadByteSize
|
|
134
|
+
return this.#config.maxPartialTxPayloadByteSize
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
get transactionPoolSize() {
|
|
138
|
+
if (this.#isOverriden('transactionPoolSize')) return this.#options.transactionPoolSize
|
|
139
|
+
return this.#config.transactionPoolSize
|
|
140
|
+
}
|
|
141
|
+
|
|
100
142
|
get networkId() {
|
|
101
143
|
return this.#config.networkId
|
|
102
144
|
}
|
|
103
145
|
|
|
146
|
+
get host() {
|
|
147
|
+
if (this.#isOverriden('host')) return this.#options.host
|
|
148
|
+
return this.#config.host
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
get port() {
|
|
152
|
+
if (this.#isOverriden('port')) return this.#options.port
|
|
153
|
+
return this.#config.port
|
|
154
|
+
}
|
|
155
|
+
|
|
104
156
|
get storesDirectory() {
|
|
105
|
-
|
|
106
|
-
|
|
157
|
+
const storesDirectory = this.#isOverriden('storesDirectory') ?
|
|
158
|
+
this.#options.storesDirectory : this.#config.storesDirectory
|
|
159
|
+
|
|
160
|
+
return _.trimEnd(storesDirectory, '/')
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
get storeName() {
|
|
164
|
+
return this.#config.storeName
|
|
107
165
|
}
|
|
108
166
|
|
|
109
167
|
get storesFullPath() {
|
|
110
|
-
return `${this.storesDirectory}
|
|
168
|
+
return `${this.storesDirectory}/${this.storeName}`
|
|
111
169
|
}
|
|
112
170
|
|
|
113
171
|
get messageThreshold() {
|
|
@@ -122,9 +180,24 @@ export class Config {
|
|
|
122
180
|
return this.#config.messageValidatorResponseTimeout
|
|
123
181
|
}
|
|
124
182
|
|
|
183
|
+
get rateLimitCleanupIntervalMs() {
|
|
184
|
+
if (this.#isOverriden('rateLimitCleanupIntervalMs')) return this.#options.rateLimitCleanupIntervalMs
|
|
185
|
+
return this.#config.rateLimitCleanupIntervalMs
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
get rateLimitConnectionTimeoutMs() {
|
|
189
|
+
if (this.#isOverriden('rateLimitConnectionTimeoutMs')) return this.#options.rateLimitConnectionTimeoutMs
|
|
190
|
+
return this.#config.rateLimitConnectionTimeoutMs
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
get rateLimitMaxTransactionsPerSecond() {
|
|
194
|
+
if (this.#isOverriden('rateLimitMaxTransactionsPerSecond')) return this.#options.rateLimitMaxTransactionsPerSecond
|
|
195
|
+
return this.#config.rateLimitMaxTransactionsPerSecond
|
|
196
|
+
}
|
|
197
|
+
|
|
125
198
|
// Most of these properties are boolean
|
|
126
199
|
#isOverriden(prop) {
|
|
127
|
-
return this.#options.hasOwnProperty(prop)
|
|
200
|
+
return this.#options.hasOwnProperty(prop) && isDefined(this.#options[prop])
|
|
128
201
|
}
|
|
129
202
|
|
|
130
203
|
#validate(options, config) {
|
package/src/config/env.js
CHANGED
|
@@ -1,13 +1,52 @@
|
|
|
1
|
-
import { TRAC_NETWORK_MSB_MAINNET_PREFIX } from 'trac-wallet/constants.js';
|
|
1
|
+
import { TRAC_NETWORK_MSB_MAINNET_PREFIX, TRAC_NETWORK_MSB_TESTNET1_PREFIX } from 'trac-wallet/constants.js';
|
|
2
2
|
import { Config } from './config.js';
|
|
3
|
+
import { TRAC_NETWORK_TESTNET_ID, TRAC_NETWORK_MAINNET_ID } from 'trac-crypto-api/constants.js';
|
|
3
4
|
|
|
4
5
|
export const ENV = {
|
|
5
6
|
MAINNET: 'mainnet',
|
|
6
7
|
DEVELOPMENT: 'development',
|
|
7
8
|
TESTNET1: 'testnet1'
|
|
8
9
|
}
|
|
10
|
+
// TODO: CREATE TEST ENV CONFIG SIMILAR TO MAINNET AND USE IT IN TESTS.
|
|
9
11
|
|
|
10
12
|
const configData = {
|
|
13
|
+
[ENV.TESTNET1]: {
|
|
14
|
+
addressLength: 67,
|
|
15
|
+
addressPrefix: TRAC_NETWORK_MSB_TESTNET1_PREFIX,
|
|
16
|
+
addressPrefixLength: TRAC_NETWORK_MSB_TESTNET1_PREFIX.length,
|
|
17
|
+
bech32mHrpLength: TRAC_NETWORK_MSB_TESTNET1_PREFIX.length + 1, // len(addressPrefix + separator)
|
|
18
|
+
bootstrap: 'a7c0c2cf8e4722129097f89b2a29a092f23d6268fcca3fd9570ba5b702b99b95',
|
|
19
|
+
channel: '1111trac1network1msb1testnet1111',
|
|
20
|
+
dhtBootstrap: ['116.202.214.149:10001', '157.180.12.214:10001', 'node1.hyperdht.org:49737', 'node2.hyperdht.org:49737', 'node3.hyperdht.org:49737'], // these are used to peer discovery
|
|
21
|
+
disableRateLimit: false,
|
|
22
|
+
enableErrorApplyLogs: true,
|
|
23
|
+
enableInteractiveMode: true,
|
|
24
|
+
enableRoleRequester: false,
|
|
25
|
+
enableTxApplyLogs: true,
|
|
26
|
+
enableValidatorObserver: true,
|
|
27
|
+
enableWallet: true,
|
|
28
|
+
maxValidators: 6,
|
|
29
|
+
maxRetries: 1,
|
|
30
|
+
messageThreshold: 1000,
|
|
31
|
+
messageValidatorRetryDelay: 1000, //How long to wait before retrying (ms) MESSAGE_VALIDATOR_RETRY_DELAY_MS
|
|
32
|
+
messageValidatorResponseTimeout: 3 * 3 * 1000, //Overall timeout for sending a message (ms). This is 3 * maxRetries * messageValidatorRetryDelay;
|
|
33
|
+
host: 'localhost',
|
|
34
|
+
port: 5000,
|
|
35
|
+
networkId: TRAC_NETWORK_TESTNET_ID,
|
|
36
|
+
maxPeers: 64, // Connectivity constants
|
|
37
|
+
maxParallel: 64, // Connectivity constants
|
|
38
|
+
maxServerConnections: Infinity, // Connectivity constants
|
|
39
|
+
maxClientConnections: Infinity, // Connectivity constants
|
|
40
|
+
maxWritersForAdminIndexerConnection: 10, // Connectivity constants
|
|
41
|
+
processIntervalMs: 50, // Pool constants
|
|
42
|
+
maxPartialTxPayloadByteSize: 3072, // Operation handler constants
|
|
43
|
+
transactionPoolSize: 1000, // Operation handler constants
|
|
44
|
+
rateLimitCleanupIntervalMs: 120_000, // Rate limiting constants
|
|
45
|
+
rateLimitConnectionTimeoutMs: 60_000, // Rate limiting constants
|
|
46
|
+
rateLimitMaxTransactionsPerSecond: 50, // Rate limiting constants
|
|
47
|
+
storesDirectory : 'stores/',
|
|
48
|
+
storeName: 'testnet',
|
|
49
|
+
},
|
|
11
50
|
[ENV.MAINNET]: {
|
|
12
51
|
addressLength: 63,
|
|
13
52
|
addressPrefix: TRAC_NETWORK_MSB_MAINNET_PREFIX,
|
|
@@ -28,8 +67,22 @@ const configData = {
|
|
|
28
67
|
messageThreshold: 3,
|
|
29
68
|
messageValidatorRetryDelay: 1000, //How long to wait before retrying (ms) MESSAGE_VALIDATOR_RETRY_DELAY_MS
|
|
30
69
|
messageValidatorResponseTimeout: 3 * 3 * 1000, //Overall timeout for sending a message (ms). This is 3 * maxRetries * messageValidatorRetryDelay;
|
|
31
|
-
|
|
70
|
+
host: 'localhost',
|
|
71
|
+
port: 5000,
|
|
72
|
+
networkId: TRAC_NETWORK_MAINNET_ID,
|
|
73
|
+
maxPeers: 64, // Connectivity constants
|
|
74
|
+
maxParallel: 64, // Connectivity constants
|
|
75
|
+
maxServerConnections: Infinity, // Connectivity constants
|
|
76
|
+
maxClientConnections: Infinity, // Connectivity constants
|
|
77
|
+
maxWritersForAdminIndexerConnection: 10, // Connectivity constants
|
|
78
|
+
processIntervalMs: 50, // Pool constants
|
|
79
|
+
maxPartialTxPayloadByteSize: 3072, // Operation handler constants
|
|
80
|
+
transactionPoolSize: 1000, // Operation handler constants
|
|
81
|
+
rateLimitCleanupIntervalMs: 120_000, // Rate limiting constants
|
|
82
|
+
rateLimitConnectionTimeoutMs: 60_000, // Rate limiting constants
|
|
83
|
+
rateLimitMaxTransactionsPerSecond: 50, // Rate limiting constants
|
|
32
84
|
storesDirectory: 'stores/',
|
|
85
|
+
storeName: 'mainnet',
|
|
33
86
|
},
|
|
34
87
|
[ENV.DEVELOPMENT]: {
|
|
35
88
|
addressLength: 63,
|
|
@@ -51,8 +104,22 @@ const configData = {
|
|
|
51
104
|
messageThreshold: 1000,
|
|
52
105
|
messageValidatorRetryDelay: 1000, //How long to wait before retrying (ms) MESSAGE_VALIDATOR_RETRY_DELAY_MS
|
|
53
106
|
messageValidatorResponseTimeout: 3 * 3 * 1000, //Overall timeout for sending a message (ms). This is 3 * maxRetries * messageValidatorRetryDelay;
|
|
54
|
-
|
|
107
|
+
host: 'localhost',
|
|
108
|
+
port: 5000,
|
|
109
|
+
networkId: TRAC_NETWORK_TESTNET_ID,
|
|
110
|
+
maxPeers: 64, // Connectivity constants
|
|
111
|
+
maxParallel: 64, // Connectivity constants
|
|
112
|
+
maxServerConnections: Infinity, // Connectivity constants
|
|
113
|
+
maxClientConnections: Infinity, // Connectivity constants
|
|
114
|
+
maxWritersForAdminIndexerConnection: 10, // Connectivity constants
|
|
115
|
+
processIntervalMs: 50, // Pool constants
|
|
116
|
+
maxPartialTxPayloadByteSize: 3072, // Operation handler constants
|
|
117
|
+
transactionPoolSize: 1000, // Operation handler constants
|
|
118
|
+
rateLimitCleanupIntervalMs: 120_000, // Rate limiting constants
|
|
119
|
+
rateLimitConnectionTimeoutMs: 60_000, // Rate limiting constants
|
|
120
|
+
rateLimitMaxTransactionsPerSecond: 50, // Rate limiting constants
|
|
55
121
|
storesDirectory : 'stores/',
|
|
122
|
+
storeName: 'development',
|
|
56
123
|
}
|
|
57
124
|
}
|
|
58
125
|
|