trac-msb 0.2.9 → 0.2.11
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/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 +4 -21
- package/package.json +16 -12
- package/proto/network/v1/enums/message_type.proto +16 -0
- package/proto/network/v1/enums/result_code.proto +84 -0
- package/proto/network/v1/messages/broadcast_transaction_request.proto +9 -0
- package/proto/network/v1/messages/broadcast_transaction_response.proto +13 -0
- package/proto/network/v1/messages/liveness_request.proto +8 -0
- package/proto/network/v1/messages/liveness_response.proto +11 -0
- package/proto/network/v1/network_message.proto +22 -0
- package/rpc/handlers.js +163 -90
- package/rpc/routes/v1.js +3 -1
- package/rpc/rpc_server.js +3 -3
- package/rpc/rpc_services.js +45 -31
- package/rpc/utils/helpers.js +82 -51
- package/scripts/generate-protobufs.js +37 -12
- package/src/config/args.js +46 -0
- package/src/config/config.js +99 -5
- package/src/config/env.js +86 -7
- package/src/core/network/Network.js +79 -46
- package/src/core/network/protocols/LegacyProtocol.js +21 -11
- package/src/core/network/protocols/NetworkMessages.js +38 -17
- package/src/core/network/protocols/ProtocolInterface.js +14 -2
- package/src/core/network/protocols/ProtocolSession.js +144 -17
- package/src/core/network/protocols/V1Protocol.js +37 -18
- package/src/core/network/protocols/connectionPolicies.js +88 -0
- package/src/core/network/protocols/legacy/NetworkMessageRouter.js +26 -20
- package/src/core/network/protocols/{shared/handlers/base/BaseOperationHandler.js → legacy/handlers/BaseStateOperationHandler.js} +25 -15
- package/src/core/network/protocols/legacy/handlers/{GetRequestHandler.js → LegacyGetRequestHandler.js} +6 -6
- package/src/core/network/protocols/legacy/handlers/LegacyResponseHandler.js +23 -0
- package/src/core/network/protocols/{shared/handlers/RoleOperationHandler.js → legacy/handlers/LegacyRoleOperationHandler.js} +20 -13
- package/src/core/network/protocols/{shared/handlers/SubnetworkOperationHandler.js → legacy/handlers/LegacySubnetworkOperationHandler.js} +29 -18
- package/src/core/network/protocols/{shared/handlers/TransferOperationHandler.js → legacy/handlers/LegacyTransferOperationHandler.js} +18 -12
- package/src/core/network/protocols/legacy/validators/base/BaseResponse.js +1 -1
- package/src/core/network/protocols/shared/errors/SharedValidatorRejectionError.js +27 -0
- package/src/core/network/protocols/shared/validators/{PartialBootstrapDeployment.js → PartialBootstrapDeploymentValidator.js} +9 -4
- package/src/core/network/protocols/shared/validators/{base/PartialOperation.js → PartialOperationValidator.js} +47 -25
- package/src/core/network/protocols/shared/validators/{PartialRoleAccess.js → PartialRoleAccessValidator.js} +51 -17
- package/src/core/network/protocols/shared/validators/{PartialTransaction.js → PartialTransactionValidator.js} +21 -7
- package/src/core/network/protocols/shared/validators/{PartialTransfer.js → PartialTransferValidator.js} +26 -9
- package/src/core/network/protocols/v1/NetworkMessageRouter.js +91 -7
- package/src/core/network/protocols/v1/V1ProtocolError.js +91 -0
- package/src/core/network/protocols/v1/handlers/V1BaseOperationHandler.js +65 -0
- package/src/core/network/protocols/v1/handlers/V1BroadcastTransactionOperationHandler.js +389 -0
- package/src/core/network/protocols/v1/handlers/V1LivenessOperationHandler.js +87 -0
- package/src/core/network/protocols/v1/validators/V1BaseOperation.js +211 -0
- package/src/core/network/protocols/v1/validators/V1BroadcastTransactionRequest.js +26 -0
- package/src/core/network/protocols/v1/validators/V1BroadcastTransactionResponse.js +276 -0
- package/src/core/network/protocols/v1/validators/V1LivenessRequest.js +15 -0
- package/src/core/network/protocols/v1/validators/V1LivenessResponse.js +17 -0
- package/src/core/network/protocols/v1/validators/V1ValidationSchema.js +210 -0
- package/src/core/network/services/ConnectionManager.js +147 -95
- package/src/core/network/services/MessageOrchestrator.js +152 -28
- package/src/core/network/services/PendingRequestService.js +172 -0
- package/src/core/network/services/TransactionCommitService.js +149 -0
- package/src/core/network/services/TransactionPoolService.js +133 -22
- package/src/core/network/services/TransactionRateLimiterService.js +57 -42
- package/src/core/network/services/ValidatorHealthCheckService.js +127 -0
- package/src/core/network/services/ValidatorObserverService.js +23 -32
- package/src/core/state/State.js +72 -22
- package/src/index.js +8 -5
- package/src/messages/network/v1/NetworkMessageBuilder.js +61 -81
- package/src/messages/network/v1/NetworkMessageDirector.js +16 -50
- package/src/messages/state/ApplyStateMessageBuilder.js +1 -1
- package/src/utils/Scheduler.js +0 -8
- package/src/utils/check.js +1 -1
- package/src/utils/constants.js +68 -19
- package/src/utils/deepEqualApplyPayload.js +40 -0
- package/src/utils/fileUtils.js +13 -0
- package/src/utils/helpers.js +10 -1
- package/src/utils/logger.js +25 -0
- package/src/utils/normalizers.js +38 -0
- package/src/utils/protobuf/networkV1.generated.cjs +2460 -0
- package/src/utils/protobuf/operationHelpers.js +24 -3
- package/src/utils/type.js +26 -0
- package/tests/acceptance/v1/account/account.test.mjs +8 -2
- 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 +3 -2
- package/tests/acceptance/v1/tx/tx.test.mjs +50 -17
- package/tests/acceptance/v1/tx-details/tx-details.test.mjs +60 -18
- package/tests/fixtures/check.fixtures.js +33 -32
- package/tests/fixtures/networkV1.fixtures.js +2 -27
- package/tests/fixtures/protobuf.fixtures.js +33 -32
- 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 +6 -10
- package/tests/helpers/transactionPayloads.mjs +2 -2
- package/tests/unit/messages/network/NetworkMessageBuilder.test.js +241 -81
- package/tests/unit/messages/network/NetworkMessageDirector.test.js +225 -81
- package/tests/unit/network/LegacyNetworkMessageRouter.test.js +54 -0
- package/tests/unit/network/ProtocolSession.test.js +127 -0
- package/tests/unit/network/networkModule.test.js +4 -1
- package/tests/unit/network/services/ConnectionManager.test.js +450 -0
- package/tests/unit/network/services/MessageOrchestrator.test.js +445 -0
- package/tests/unit/network/services/PendingRequestService.test.js +431 -0
- package/tests/unit/network/services/TransactionCommitService.test.js +246 -0
- package/tests/unit/network/services/TransactionPoolService.test.js +489 -0
- package/tests/unit/network/services/TransactionRateLimiterService.test.js +139 -0
- package/tests/unit/network/services/ValidatorHealthCheckService.test.js +115 -0
- package/tests/unit/network/services/services.test.js +17 -0
- package/tests/unit/network/utils/v1TestUtils.js +153 -0
- package/tests/unit/network/v1/NetworkMessageRouterV1.test.js +151 -0
- package/tests/unit/network/v1/V1BaseOperation.test.js +356 -0
- package/tests/unit/network/v1/V1BroadcastTransactionOperationHandler.test.js +129 -0
- package/tests/unit/network/v1/V1BroadcastTransactionRequest.test.js +53 -0
- package/tests/unit/network/v1/V1BroadcastTransactionResponse.test.js +512 -0
- package/tests/unit/network/v1/V1LivenessRequest.test.js +32 -0
- package/tests/unit/network/v1/V1LivenessResponse.test.js +45 -0
- package/tests/unit/network/v1/V1ResultCode.test.js +84 -0
- package/tests/unit/network/v1/V1ValidationSchema.test.js +13 -0
- package/tests/unit/network/v1/connectionPolicies.test.js +49 -0
- package/tests/unit/network/v1/handlers/V1BaseOperationHandler.test.js +284 -0
- package/tests/unit/network/v1/handlers/V1BroadcastTransactionOperationHandler.test.js +794 -0
- package/tests/unit/network/v1/handlers/V1LivenessOperationHandler.test.js +193 -0
- package/tests/unit/network/v1/v1.handlers.test.js +15 -0
- package/tests/unit/network/v1/v1.test.js +19 -0
- package/tests/unit/network/v1/v1ValidationSchema/broadcastTransactionRequest.test.js +119 -0
- package/tests/unit/network/v1/v1ValidationSchema/broadcastTransactionResponse.test.js +136 -0
- package/tests/unit/network/v1/v1ValidationSchema/common.test.js +308 -0
- package/tests/unit/network/v1/v1ValidationSchema/livenessRequest.test.js +90 -0
- package/tests/unit/network/v1/v1ValidationSchema/livenessResponse.test.js +133 -0
- package/tests/unit/unit.test.js +2 -2
- package/tests/unit/utils/deepEqualApplyPayload/deepEqualApplyPayload.test.js +102 -0
- 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/protobuf/operationHelpers.test.js +2 -4
- package/tests/unit/utils/type/type.test.js +25 -0
- package/tests/unit/utils/utils.test.js +2 -0
- package/.github/workflows/acceptance-tests.yml +0 -42
- package/.github/workflows/publish.yml +0 -33
- package/.github/workflows/unit-tests.yml +0 -40
- package/proto/network.proto +0 -74
- package/src/core/network/protocols/legacy/handlers/ResponseHandler.js +0 -37
- package/src/utils/protobuf/network.cjs +0 -840
- package/tests/unit/network/ConnectionManager.test.js +0 -191
package/rpc/routes/v1.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
handleHealth,
|
|
2
3
|
handleBalance,
|
|
3
4
|
handleTxv,
|
|
4
5
|
handleFee,
|
|
@@ -9,10 +10,11 @@ import {
|
|
|
9
10
|
handleTransactionDetails,
|
|
10
11
|
handleFetchBulkTxPayloads,
|
|
11
12
|
handleTransactionExtendedDetails,
|
|
12
|
-
handleAccountDetails
|
|
13
|
+
handleAccountDetails,
|
|
13
14
|
} from '../handlers.js';
|
|
14
15
|
|
|
15
16
|
export const v1Routes = [
|
|
17
|
+
{ method: 'GET', path: '/health', handler: handleHealth },
|
|
16
18
|
{ method: 'GET', path: '/balance', handler: handleBalance },
|
|
17
19
|
{ method: 'GET', path: '/txv', handler: handleTxv },
|
|
18
20
|
{ method: 'GET', path: '/fee', handler: handleFee },
|
package/rpc/rpc_server.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { createServer } from "./create_server.js";
|
|
2
2
|
|
|
3
3
|
// Called by msb.mjs file
|
|
4
|
-
export function startRpcServer(msbInstance, config
|
|
4
|
+
export function startRpcServer(msbInstance, config) {
|
|
5
5
|
const server = createServer(msbInstance, config)
|
|
6
6
|
|
|
7
|
-
return server.listen(port, host, () => {
|
|
8
|
-
console.log(`Running RPC with http at http://${host}:${port}`);
|
|
7
|
+
return server.listen(config.port, config.host, () => {
|
|
8
|
+
console.log(`Running RPC with http at http://${config.host}:${config.port}`);
|
|
9
9
|
});
|
|
10
10
|
}
|
package/rpc/rpc_services.js
CHANGED
|
@@ -5,10 +5,24 @@ import {
|
|
|
5
5
|
normalizeTransferOperation
|
|
6
6
|
} from "../src/utils/normalizers.js";
|
|
7
7
|
import { get_confirmed_tx_info, get_unconfirmed_tx_info } from "../src/utils/cli.js";
|
|
8
|
-
import {OperationType} from "../src/utils/constants.js";
|
|
8
|
+
import { OperationType } from "../src/utils/constants.js";
|
|
9
|
+
import { sleep } from "../src/utils/helpers.js";
|
|
9
10
|
import b4a from "b4a";
|
|
10
|
-
import
|
|
11
|
-
import
|
|
11
|
+
import { ValidationError, BroadcastError, NotFoundError } from "./utils/helpers.js";
|
|
12
|
+
import PartialTransactionValidator from "../src/core/network/protocols/shared/validators/PartialTransactionValidator.js";
|
|
13
|
+
import PartialTransferValidator from "../src/core/network/protocols/shared/validators/PartialTransferValidator.js";
|
|
14
|
+
|
|
15
|
+
// This was added because V1 is not waiting for signed/unsigned state. So to include reverse compatibility
|
|
16
|
+
// we need to slow down v1 to legacy case.
|
|
17
|
+
const waitForUnconfirmedTx = async (state, txHash, config) => {
|
|
18
|
+
const startedAt = Date.now();
|
|
19
|
+
while ((Date.now() - startedAt) < config.messageValidatorResponseTimeout) {
|
|
20
|
+
const payload = await state.get(txHash);
|
|
21
|
+
if (payload) return true;
|
|
22
|
+
await sleep(100);
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
25
|
+
};
|
|
12
26
|
|
|
13
27
|
export async function getBalance(msbInstance, address, confirmed) {
|
|
14
28
|
const state = msbInstance.state;
|
|
@@ -46,14 +60,15 @@ export async function getUnconfirmedLength(msbInstance) {
|
|
|
46
60
|
|
|
47
61
|
export async function broadcastTransaction(msbInstance, config, payload) {
|
|
48
62
|
if (!payload) {
|
|
49
|
-
throw new
|
|
63
|
+
throw new ValidationError("Transaction payload is required for broadcasting.");
|
|
50
64
|
}
|
|
65
|
+
|
|
51
66
|
let normalizedPayload;
|
|
52
67
|
let isValid = false;
|
|
53
68
|
let hash;
|
|
54
69
|
|
|
55
|
-
const partialTransferValidator = new
|
|
56
|
-
const partialTransactionValidator = new
|
|
70
|
+
const partialTransferValidator = new PartialTransferValidator(msbInstance.state, null , config);
|
|
71
|
+
const partialTransactionValidator = new PartialTransactionValidator(msbInstance.state, null , config);
|
|
57
72
|
|
|
58
73
|
if (payload.type === OperationType.TRANSFER) {
|
|
59
74
|
normalizedPayload = normalizeTransferOperation(payload, config);
|
|
@@ -66,19 +81,29 @@ export async function broadcastTransaction(msbInstance, config, payload) {
|
|
|
66
81
|
}
|
|
67
82
|
|
|
68
83
|
if (!isValid) {
|
|
69
|
-
throw new
|
|
84
|
+
throw new ValidationError("Invalid transaction payload.");
|
|
70
85
|
}
|
|
71
86
|
|
|
72
87
|
const success = await msbInstance.broadcastPartialTransaction(payload);
|
|
73
88
|
|
|
74
89
|
if (!success) {
|
|
75
|
-
throw new
|
|
90
|
+
throw new BroadcastError("Failed to broadcast transaction after multiple attempts.");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const isConfirmed = await waitForUnconfirmedTx(msbInstance.state, hash, config);
|
|
94
|
+
if (!isConfirmed) {
|
|
95
|
+
throw new BroadcastError("Failed to broadcast transaction after multiple attempts.");
|
|
76
96
|
}
|
|
77
97
|
|
|
78
98
|
const signedLength = msbInstance.state.getSignedLength();
|
|
79
99
|
const unsignedLength = msbInstance.state.getUnsignedLength();
|
|
80
100
|
|
|
81
|
-
return {
|
|
101
|
+
return {
|
|
102
|
+
message: "Transaction broadcasted successfully.",
|
|
103
|
+
signedLength,
|
|
104
|
+
unsignedLength,
|
|
105
|
+
tx: hash
|
|
106
|
+
};
|
|
82
107
|
}
|
|
83
108
|
|
|
84
109
|
export async function getTxHashes(msbInstance, start, end) {
|
|
@@ -89,7 +114,7 @@ export async function getTxHashes(msbInstance, start, end) {
|
|
|
89
114
|
export async function getTxDetails(msbInstance, hash) {
|
|
90
115
|
const rawPayload = await get_confirmed_tx_info(msbInstance.state, hash);
|
|
91
116
|
if (!rawPayload) {
|
|
92
|
-
|
|
117
|
+
throw new NotFoundError(`Transaction ${hash} not found.`);
|
|
93
118
|
}
|
|
94
119
|
|
|
95
120
|
return normalizeDecodedPayloadForJson(rawPayload.decoded, msbInstance.config);
|
|
@@ -97,11 +122,11 @@ export async function getTxDetails(msbInstance, hash) {
|
|
|
97
122
|
|
|
98
123
|
export async function fetchBulkTxPayloads(msbInstance, hashes) {
|
|
99
124
|
if (!Array.isArray(hashes) || hashes.length === 0) {
|
|
100
|
-
throw new
|
|
125
|
+
throw new ValidationError("Missing hash list.");
|
|
101
126
|
}
|
|
102
127
|
|
|
103
128
|
if (hashes.length > 1500) {
|
|
104
|
-
throw new
|
|
129
|
+
throw new ValidationError("Length of input tx hashes exceeded.");
|
|
105
130
|
}
|
|
106
131
|
|
|
107
132
|
const res = { results: [], missing: [] };
|
|
@@ -111,7 +136,7 @@ export async function fetchBulkTxPayloads(msbInstance, hashes) {
|
|
|
111
136
|
|
|
112
137
|
results.forEach((result, index) => {
|
|
113
138
|
const hash = hashes[index];
|
|
114
|
-
if (result
|
|
139
|
+
if (!result) {
|
|
115
140
|
res.missing.push(hash);
|
|
116
141
|
} else {
|
|
117
142
|
const decodedResult = normalizeDecodedPayloadForJson(result.decoded, msbInstance.config);
|
|
@@ -124,32 +149,21 @@ export async function fetchBulkTxPayloads(msbInstance, hashes) {
|
|
|
124
149
|
|
|
125
150
|
export async function getExtendedTxDetails(msbInstance, hash, confirmed) {
|
|
126
151
|
const state = msbInstance.state;
|
|
152
|
+
let rawPayload;
|
|
127
153
|
|
|
128
154
|
if (confirmed) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
const confirmedLength = await state.getTransactionConfirmedLength(hash);
|
|
134
|
-
if (confirmedLength === null) {
|
|
135
|
-
throw new Error(`No confirmed length found for tx hash: ${hash} in confirmed mode`);
|
|
136
|
-
}
|
|
137
|
-
const normalizedPayload = normalizeDecodedPayloadForJson(rawPayload.decoded, msbInstance.config);
|
|
138
|
-
const feeBuffer = state.getFee();
|
|
139
|
-
return {
|
|
140
|
-
txDetails: normalizedPayload,
|
|
141
|
-
confirmed_length: confirmedLength,
|
|
142
|
-
fee: bufferToBigInt(feeBuffer).toString(),
|
|
143
|
-
};
|
|
155
|
+
rawPayload = await get_confirmed_tx_info(state, hash);
|
|
156
|
+
} else {
|
|
157
|
+
rawPayload = await get_unconfirmed_tx_info(state, hash);
|
|
144
158
|
}
|
|
145
159
|
|
|
146
|
-
const rawPayload = await get_unconfirmed_tx_info(state, hash);
|
|
147
160
|
if (!rawPayload) {
|
|
148
|
-
throw new
|
|
161
|
+
throw new NotFoundError(`No payload found for tx hash: ${hash}`);
|
|
149
162
|
}
|
|
150
163
|
|
|
151
164
|
const normalizedPayload = normalizeDecodedPayloadForJson(rawPayload.decoded, msbInstance.config);
|
|
152
165
|
const length = await state.getTransactionConfirmedLength(hash);
|
|
166
|
+
|
|
153
167
|
if (length === null) {
|
|
154
168
|
return {
|
|
155
169
|
txDetails: normalizedPayload,
|
|
@@ -164,4 +178,4 @@ export async function getExtendedTxDetails(msbInstance, hash, confirmed) {
|
|
|
164
178
|
confirmed_length: length,
|
|
165
179
|
fee: bufferToBigInt(feeBuffer).toString(),
|
|
166
180
|
};
|
|
167
|
-
}
|
|
181
|
+
}
|
package/rpc/utils/helpers.js
CHANGED
|
@@ -1,74 +1,105 @@
|
|
|
1
1
|
import b4a from "b4a"
|
|
2
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
|
+
}
|
|
@@ -2,10 +2,10 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
|
-
import {
|
|
5
|
+
import { execFileSync } from 'child_process';
|
|
6
6
|
|
|
7
7
|
function generateCJSFromProto(inputPath, outputPath) {
|
|
8
|
-
|
|
8
|
+
execFileSync('protocol-buffers', [inputPath, '-o', outputPath]);
|
|
9
9
|
console.log(`${outputPath} has been generated.`);
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -17,26 +17,51 @@ function transformToUseB4a(outputPath) {
|
|
|
17
17
|
console.log(`${outputPath} has been modified to use b4a.`);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
function generatePbjsModule(pbjsPath, protoRootPath, entryPath, outputPath) {
|
|
21
|
+
execFileSync(pbjsPath, [
|
|
22
|
+
'-t', 'static-module',
|
|
23
|
+
'-w', 'commonjs',
|
|
24
|
+
'--keep-case',
|
|
25
|
+
'-p', protoRootPath,
|
|
26
|
+
'-o', outputPath,
|
|
27
|
+
entryPath
|
|
28
|
+
]);
|
|
29
|
+
console.log(`${outputPath} has been generated.`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function transformPbjsForBare(outputPath) {
|
|
33
|
+
let content = fs.readFileSync(outputPath, 'utf-8');
|
|
34
|
+
const shim = `if (typeof globalThis !== 'undefined' && typeof globalThis.self === 'undefined') {\n globalThis.self = globalThis;\n}\n`;
|
|
35
|
+
const strictDirective = '"use strict";';
|
|
36
|
+
|
|
37
|
+
if (content.includes(strictDirective)) {
|
|
38
|
+
content = content.replace(strictDirective, `${strictDirective}\n${shim}`);
|
|
39
|
+
} else {
|
|
40
|
+
content = `${strictDirective}\n${shim}${content}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
fs.writeFileSync(outputPath, content, 'utf-8');
|
|
44
|
+
console.log(`${outputPath} has been modified for bare-compatible protobufjs runtime.`);
|
|
45
|
+
}
|
|
20
46
|
|
|
21
47
|
function main() {
|
|
22
48
|
const directoryName = path.dirname(fileURLToPath(import.meta.url));
|
|
23
49
|
|
|
24
50
|
const inputDir = path.join(directoryName, '../proto');
|
|
25
51
|
const outputDir = path.join(directoryName, '../src/utils/protobuf');
|
|
52
|
+
const pbjsPath = path.join(directoryName, '../node_modules/.bin/pbjs');
|
|
53
|
+
const applyInputPath = path.join(inputDir, 'applyOperations.proto');
|
|
54
|
+
const applyOutputPath = path.join(outputDir, 'applyOperations.cjs');
|
|
55
|
+
const networkEntryPath = path.join(inputDir, 'network/v1/network_message.proto');
|
|
56
|
+
const generatedNetworkOutputPath = path.join(outputDir, 'networkV1.generated.cjs');
|
|
26
57
|
|
|
27
58
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
28
59
|
|
|
29
|
-
|
|
60
|
+
generateCJSFromProto(applyInputPath, applyOutputPath);
|
|
61
|
+
transformToUseB4a(applyOutputPath);
|
|
30
62
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const inputPath = path.join(inputDir, file);
|
|
34
|
-
const outputPath = path.join(outputDir, `${name}.cjs`);
|
|
35
|
-
|
|
36
|
-
generateCJSFromProto(inputPath, outputPath);
|
|
37
|
-
transformToUseB4a(outputPath);
|
|
38
|
-
}
|
|
63
|
+
generatePbjsModule(pbjsPath, inputDir, networkEntryPath, generatedNetworkOutputPath);
|
|
64
|
+
transformPbjsForBare(generatedNetworkOutputPath);
|
|
39
65
|
}
|
|
40
66
|
|
|
41
67
|
main();
|
|
42
|
-
|
|
@@ -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,68 @@ 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 transactionPoolSize() {
|
|
133
|
+
if (this.#isOverriden('transactionPoolSize')) return this.#options.transactionPoolSize
|
|
134
|
+
return this.#config.transactionPoolSize
|
|
135
|
+
}
|
|
136
|
+
|
|
100
137
|
get networkId() {
|
|
101
138
|
return this.#config.networkId
|
|
102
139
|
}
|
|
103
140
|
|
|
141
|
+
get host() {
|
|
142
|
+
if (this.#isOverriden('host')) return this.#options.host
|
|
143
|
+
return this.#config.host
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
get port() {
|
|
147
|
+
if (this.#isOverriden('port')) return this.#options.port
|
|
148
|
+
return this.#config.port
|
|
149
|
+
}
|
|
150
|
+
|
|
104
151
|
get storesDirectory() {
|
|
105
|
-
|
|
106
|
-
|
|
152
|
+
const storesDirectory = this.#isOverriden('storesDirectory') ?
|
|
153
|
+
this.#options.storesDirectory : this.#config.storesDirectory
|
|
154
|
+
|
|
155
|
+
return _.trimEnd(storesDirectory, '/')
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
get storeName() {
|
|
159
|
+
return this.#config.storeName
|
|
107
160
|
}
|
|
108
161
|
|
|
109
162
|
get storesFullPath() {
|
|
110
|
-
return `${this.storesDirectory}
|
|
163
|
+
return `${this.storesDirectory}/${this.storeName}`
|
|
111
164
|
}
|
|
112
165
|
|
|
113
166
|
get messageThreshold() {
|
|
@@ -122,9 +175,49 @@ export class Config {
|
|
|
122
175
|
return this.#config.messageValidatorResponseTimeout
|
|
123
176
|
}
|
|
124
177
|
|
|
178
|
+
get rateLimitCleanupIntervalMs() {
|
|
179
|
+
if (this.#isOverriden('rateLimitCleanupIntervalMs')) return this.#options.rateLimitCleanupIntervalMs
|
|
180
|
+
return this.#config.rateLimitCleanupIntervalMs
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
get rateLimitConnectionTimeoutMs() {
|
|
184
|
+
if (this.#isOverriden('rateLimitConnectionTimeoutMs')) return this.#options.rateLimitConnectionTimeoutMs
|
|
185
|
+
return this.#config.rateLimitConnectionTimeoutMs
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
get rateLimitMaxTransactionsPerSecond() {
|
|
189
|
+
if (this.#isOverriden('rateLimitMaxTransactionsPerSecond')) return this.#options.rateLimitMaxTransactionsPerSecond
|
|
190
|
+
return this.#config.rateLimitMaxTransactionsPerSecond
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
get pendingRequestTimeout() {
|
|
194
|
+
return this.#config.pendingRequestTimeout
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
get txCommitTimeout() {
|
|
198
|
+
return this.#config.txCommitTimeout
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
get txPoolSize() {
|
|
202
|
+
return this.#config.txPoolSize
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
get validatorHealthCheckInterval() {
|
|
206
|
+
if (this.#isOverriden('validatorHealthCheckInterval')) return this.#options.validatorHealthCheckInterval
|
|
207
|
+
return this.#config.validatorHealthCheckInterval
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
get maxPendingRequestsInPendingRequestsService() {
|
|
211
|
+
return this.#config.maxPendingRequestsInPendingRequestsService
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
get debug() {
|
|
215
|
+
return this.#config.debug
|
|
216
|
+
}
|
|
217
|
+
|
|
125
218
|
// Most of these properties are boolean
|
|
126
219
|
#isOverriden(prop) {
|
|
127
|
-
return this.#options.hasOwnProperty(prop)
|
|
220
|
+
return this.#options.hasOwnProperty(prop) && isDefined(this.#options[prop])
|
|
128
221
|
}
|
|
129
222
|
|
|
130
223
|
#validate(options, config) {
|
|
@@ -134,4 +227,5 @@ export class Config {
|
|
|
134
227
|
);
|
|
135
228
|
}
|
|
136
229
|
}
|
|
230
|
+
|
|
137
231
|
}
|