trac-msb 0.2.12 → 0.2.13
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/package.json +9 -4
- 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/rpc_services.js +22 -4
- package/scripts/generate-protobufs.js +37 -12
- package/src/config/config.js +26 -5
- package/src/config/env.js +25 -11
- package/src/core/network/Network.js +73 -36
- 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 +25 -19
- package/src/core/network/protocols/{shared/handlers/base/BaseOperationHandler.js → legacy/handlers/BaseStateOperationHandler.js} +23 -12
- 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} +18 -11
- package/src/core/network/protocols/{shared/handlers/SubnetworkOperationHandler.js → legacy/handlers/LegacySubnetworkOperationHandler.js} +28 -17
- package/src/core/network/protocols/{shared/handlers/TransferOperationHandler.js → legacy/handlers/LegacyTransferOperationHandler.js} +17 -11
- 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 +146 -94
- package/src/core/network/services/MessageOrchestrator.js +151 -27
- 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 +129 -18
- package/src/core/network/services/TransactionRateLimiterService.js +52 -34
- package/src/core/network/services/ValidatorHealthCheckService.js +127 -0
- package/src/core/network/services/ValidatorObserverService.js +18 -26
- package/src/core/state/State.js +70 -19
- package/src/index.js +5 -4
- package/src/messages/network/v1/NetworkMessageBuilder.js +59 -79
- package/src/messages/network/v1/NetworkMessageDirector.js +16 -50
- package/src/utils/Scheduler.js +0 -8
- package/src/utils/constants.js +71 -5
- package/src/utils/deepEqualApplyPayload.js +40 -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/tests/acceptance/v1/account/account.test.mjs +8 -2
- package/tests/acceptance/v1/tx/tx.test.mjs +23 -1
- package/tests/acceptance/v1/tx-details/tx-details.test.mjs +34 -6
- package/tests/fixtures/networkV1.fixtures.js +2 -28
- package/tests/helpers/transactionPayloads.mjs +2 -2
- package/tests/unit/messages/network/NetworkMessageBuilder.test.js +239 -79
- package/tests/unit/messages/network/NetworkMessageDirector.test.js +223 -77
- 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/protobuf/operationHelpers.test.js +2 -4
- package/tests/unit/utils/utils.test.js +1 -0
- package/.github/workflows/acceptance-tests.yml +0 -38
- package/.github/workflows/lint-pr-title.yml +0 -26
- package/.github/workflows/publish.yml +0 -33
- package/.github/workflows/unit-tests.yml +0 -34
- 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
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import Protomux from 'protomux';
|
|
2
2
|
import ProtocolInterface from './ProtocolInterface.js';
|
|
3
|
-
import b4a from 'b4a';
|
|
4
3
|
import c from 'compact-encoding';
|
|
4
|
+
import {encodeV1networkOperation, decodeV1networkOperation} from '../../../utils/protobuf/operationHelpers.js';
|
|
5
5
|
|
|
6
6
|
class V1Protocol extends ProtocolInterface {
|
|
7
7
|
#channel;
|
|
8
8
|
#session;
|
|
9
|
-
#config;
|
|
10
9
|
#router;
|
|
10
|
+
#publicKeyHex;
|
|
11
|
+
#pendingRequestService;
|
|
11
12
|
|
|
12
|
-
constructor(router, connection, config) {
|
|
13
|
-
super(router, connection, config);
|
|
14
|
-
this.#config = config;
|
|
13
|
+
constructor(router, connection, pendingRequestService, config) {
|
|
14
|
+
super(router, connection, pendingRequestService, config);
|
|
15
15
|
this.#router = router;
|
|
16
|
+
this.#publicKeyHex = connection.remotePublicKey.toString('hex');
|
|
17
|
+
this.#pendingRequestService = pendingRequestService;
|
|
16
18
|
this.init(connection);
|
|
17
19
|
}
|
|
18
20
|
|
|
@@ -30,30 +32,47 @@ class V1Protocol extends ProtocolInterface {
|
|
|
30
32
|
|
|
31
33
|
this.#channel = mux.createChannel({
|
|
32
34
|
protocol: 'network/v1',
|
|
33
|
-
onopen() {
|
|
34
|
-
|
|
35
|
+
onopen() {
|
|
36
|
+
},
|
|
37
|
+
onclose() {
|
|
38
|
+
}
|
|
35
39
|
});
|
|
36
40
|
|
|
37
41
|
this.#channel.open();
|
|
38
42
|
|
|
39
43
|
this.#session = this.#channel.addMessage({
|
|
40
44
|
encoding: c.raw,
|
|
41
|
-
onmessage:
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
onmessage: (incomingMessage) => {
|
|
46
|
+
this.#router.route(incomingMessage, connection).catch((err) => {
|
|
47
|
+
console.error(`V1Protocol: unhandled router error: ${err.message}`);
|
|
48
|
+
try {
|
|
49
|
+
connection.end();
|
|
50
|
+
} catch {
|
|
47
51
|
}
|
|
48
|
-
}
|
|
49
|
-
console.error(`NetworkMessages: Failed to handle incoming v1 message: ${error.message}`);
|
|
50
|
-
}
|
|
52
|
+
});
|
|
51
53
|
}
|
|
52
54
|
});
|
|
53
55
|
}
|
|
54
56
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
// TODO: Consider making this method private/internal-only, just like 'encode'
|
|
58
|
+
// NOTE: This method might be moved to v1/NetworkMessageRouter.js as it is only used there
|
|
59
|
+
decode(message) {
|
|
60
|
+
return decodeV1networkOperation(message);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async send(message) {
|
|
64
|
+
const encodedMessage = encodeV1networkOperation(message);
|
|
65
|
+
const msgReplyPromise = this.#pendingRequestService.registerPendingRequest(this.#publicKeyHex, message);
|
|
66
|
+
try {
|
|
67
|
+
this.#session.send(encodedMessage);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
this.#pendingRequestService.rejectPendingRequest(message.id, error);
|
|
70
|
+
}
|
|
71
|
+
return msgReplyPromise;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
sendAndForget(message) {
|
|
75
|
+
this.#session.send(encodeV1networkOperation(message));
|
|
57
76
|
}
|
|
58
77
|
|
|
59
78
|
close() {
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { ResultCode } from '../../../utils/constants.js';
|
|
2
|
+
|
|
3
|
+
// TODO: Consider how to behave with ResultCode.UNSPECIFIED
|
|
4
|
+
|
|
5
|
+
export const SENDER_ACTION = Object.freeze({
|
|
6
|
+
UNDEFINED: 'UNDEFINED',
|
|
7
|
+
SUCCESS: 'SUCCESS',
|
|
8
|
+
ROTATE: 'ROTATE',
|
|
9
|
+
NO_ROTATE: 'NO_ROTATE',
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const SUCCESS_CODES = new Set([
|
|
13
|
+
ResultCode.OK,
|
|
14
|
+
]);
|
|
15
|
+
|
|
16
|
+
const ROTATE_CODES = new Set([
|
|
17
|
+
ResultCode.UNSPECIFIED,
|
|
18
|
+
ResultCode.INVALID_PAYLOAD,
|
|
19
|
+
ResultCode.RATE_LIMITED,
|
|
20
|
+
ResultCode.SIGNATURE_INVALID,
|
|
21
|
+
ResultCode.UNEXPECTED_ERROR,
|
|
22
|
+
ResultCode.TIMEOUT,
|
|
23
|
+
ResultCode.NODE_HAS_NO_WRITE_ACCESS,
|
|
24
|
+
ResultCode.TX_ACCEPTED_PROOF_UNAVAILABLE,
|
|
25
|
+
ResultCode.NODE_OVERLOADED,
|
|
26
|
+
ResultCode.OPERATION_TYPE_UNKNOWN,
|
|
27
|
+
ResultCode.SCHEMA_VALIDATION_FAILED,
|
|
28
|
+
ResultCode.REQUESTER_ADDRESS_INVALID,
|
|
29
|
+
ResultCode.REQUESTER_PUBLIC_KEY_INVALID,
|
|
30
|
+
ResultCode.TX_HASH_MISMATCH,
|
|
31
|
+
ResultCode.TX_SIGNATURE_INVALID,
|
|
32
|
+
ResultCode.TX_EXPIRED,
|
|
33
|
+
ResultCode.TX_ALREADY_EXISTS,
|
|
34
|
+
ResultCode.OPERATION_ALREADY_COMPLETED,
|
|
35
|
+
ResultCode.REQUESTER_NOT_FOUND,
|
|
36
|
+
ResultCode.INSUFFICIENT_FEE_BALANCE,
|
|
37
|
+
ResultCode.EXTERNAL_BOOTSTRAP_EQUALS_MSB_BOOTSTRAP,
|
|
38
|
+
ResultCode.SELF_VALIDATION_FORBIDDEN,
|
|
39
|
+
ResultCode.ROLE_NODE_ENTRY_NOT_FOUND,
|
|
40
|
+
ResultCode.ROLE_NODE_ALREADY_WRITER,
|
|
41
|
+
ResultCode.ROLE_NODE_NOT_WHITELISTED,
|
|
42
|
+
ResultCode.ROLE_NODE_NOT_WRITER,
|
|
43
|
+
ResultCode.ROLE_NODE_IS_INDEXER,
|
|
44
|
+
ResultCode.ROLE_ADMIN_ENTRY_MISSING,
|
|
45
|
+
ResultCode.ROLE_INVALID_RECOVERY_CASE,
|
|
46
|
+
ResultCode.ROLE_UNKNOWN_OPERATION,
|
|
47
|
+
ResultCode.ROLE_INVALID_WRITER_KEY,
|
|
48
|
+
ResultCode.ROLE_INSUFFICIENT_FEE_BALANCE,
|
|
49
|
+
ResultCode.MSB_BOOTSTRAP_MISMATCH,
|
|
50
|
+
ResultCode.EXTERNAL_BOOTSTRAP_NOT_DEPLOYED,
|
|
51
|
+
ResultCode.EXTERNAL_BOOTSTRAP_TX_MISSING,
|
|
52
|
+
ResultCode.EXTERNAL_BOOTSTRAP_MISMATCH,
|
|
53
|
+
ResultCode.BOOTSTRAP_ALREADY_EXISTS,
|
|
54
|
+
ResultCode.TRANSFER_RECIPIENT_ADDRESS_INVALID,
|
|
55
|
+
ResultCode.TRANSFER_RECIPIENT_PUBLIC_KEY_INVALID,
|
|
56
|
+
ResultCode.TRANSFER_AMOUNT_TOO_LARGE,
|
|
57
|
+
ResultCode.TRANSFER_SENDER_NOT_FOUND,
|
|
58
|
+
ResultCode.TRANSFER_INSUFFICIENT_BALANCE,
|
|
59
|
+
ResultCode.TRANSFER_RECIPIENT_BALANCE_OVERFLOW,
|
|
60
|
+
ResultCode.TX_HASH_INVALID_FORMAT,
|
|
61
|
+
ResultCode.INTERNAL_ENQUEUE_VALIDATION_FAILED,
|
|
62
|
+
ResultCode.TX_COMMITTED_RECEIPT_MISSING,
|
|
63
|
+
ResultCode.VALIDATOR_RESPONSE_TX_TYPE_INVALID,
|
|
64
|
+
ResultCode.VALIDATOR_RESPONSE_TX_TYPE_UNKNOWN,
|
|
65
|
+
ResultCode.VALIDATOR_RESPONSE_TX_TYPE_UNSUPPORTED,
|
|
66
|
+
ResultCode.VALIDATOR_RESPONSE_SCHEMA_INVALID,
|
|
67
|
+
ResultCode.PENDING_REQUEST_MISSING_TX_DATA,
|
|
68
|
+
ResultCode.PROOF_PAYLOAD_MISMATCH,
|
|
69
|
+
ResultCode.VALIDATOR_WRITER_KEY_NOT_REGISTERED,
|
|
70
|
+
ResultCode.VALIDATOR_ADDRESS_MISMATCH,
|
|
71
|
+
ResultCode.VALIDATOR_NODE_ENTRY_NOT_FOUND,
|
|
72
|
+
ResultCode.VALIDATOR_NODE_NOT_WRITER,
|
|
73
|
+
ResultCode.VALIDATOR_WRITER_KEY_MISMATCH,
|
|
74
|
+
ResultCode.VALIDATOR_TX_OBJECT_INVALID,
|
|
75
|
+
ResultCode.VALIDATOR_VA_MISSING,
|
|
76
|
+
ResultCode.TX_INVALID_PAYLOAD
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
const NO_ROTATE_CODES = new Set([
|
|
80
|
+
ResultCode.TX_ALREADY_PENDING,
|
|
81
|
+
]);
|
|
82
|
+
|
|
83
|
+
export function resultToValidatorAction(resultCode) {
|
|
84
|
+
if (SUCCESS_CODES.has(resultCode)) return SENDER_ACTION.SUCCESS;
|
|
85
|
+
if (ROTATE_CODES.has(resultCode)) return SENDER_ACTION.ROTATE;
|
|
86
|
+
if (NO_ROTATE_CODES.has(resultCode)) return SENDER_ACTION.NO_ROTATE;
|
|
87
|
+
return SENDER_ACTION.UNDEFINED;
|
|
88
|
+
}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import b4a from "b4a";
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
2
|
+
import _ from 'lodash';
|
|
3
|
+
import LegacyGetRequestHandler from "./handlers/LegacyGetRequestHandler.js";
|
|
4
|
+
import LegacyResponseHandler from "./handlers/LegacyResponseHandler.js";
|
|
5
|
+
import LegacyRoleOperationHandler from "./handlers/LegacyRoleOperationHandler.js";
|
|
6
|
+
import LegacySubnetworkOperationHandler from "./handlers/LegacySubnetworkOperationHandler.js";
|
|
7
|
+
import LegacyTransferOperationHandler from "./handlers/LegacyTransferOperationHandler.js";
|
|
7
8
|
import { NETWORK_MESSAGE_TYPES } from '../../../../utils/constants.js';
|
|
8
9
|
import * as operation from '../../../../utils/applyOperations.js';
|
|
9
|
-
import State from "../../../state/State.js";
|
|
10
|
-
import PeerWallet from "trac-wallet";
|
|
11
10
|
|
|
12
11
|
class NetworkMessageRouter {
|
|
13
12
|
#handlers;
|
|
@@ -18,29 +17,32 @@ class NetworkMessageRouter {
|
|
|
18
17
|
* @param {PeerWallet} wallet
|
|
19
18
|
* @param {TransactionRateLimiterService} rateLimiterService
|
|
20
19
|
* @param {TransactionPoolService} txPoolService
|
|
21
|
-
* @param {ConnectionManager} connectionManager
|
|
22
20
|
* @param {Config} config
|
|
23
21
|
**/
|
|
24
|
-
constructor(state, wallet, rateLimiterService, txPoolService,
|
|
22
|
+
constructor(state, wallet, rateLimiterService, txPoolService, config) {
|
|
25
23
|
this.#config = config;
|
|
26
24
|
|
|
27
25
|
this.#handlers = {
|
|
28
|
-
get: new
|
|
29
|
-
response: new
|
|
30
|
-
roleTransaction: new
|
|
31
|
-
subNetworkTransaction: new
|
|
32
|
-
tracNetworkTransaction: new
|
|
26
|
+
get: new LegacyGetRequestHandler(wallet, state),
|
|
27
|
+
response: new LegacyResponseHandler(state, wallet, this.#config),
|
|
28
|
+
roleTransaction: new LegacyRoleOperationHandler(state, wallet, rateLimiterService, txPoolService, this.#config),
|
|
29
|
+
subNetworkTransaction: new LegacySubnetworkOperationHandler(state, wallet, rateLimiterService, txPoolService, this.#config),
|
|
30
|
+
tracNetworkTransaction: new LegacyTransferOperationHandler(state, wallet, rateLimiterService, txPoolService, this.#config),
|
|
31
|
+
|
|
33
32
|
}
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
async route(incomingMessage, connection) {
|
|
36
|
+
this.#preValidate(incomingMessage);
|
|
38
37
|
const channelString = b4a.toString(this.#config.channel, 'utf8');
|
|
38
|
+
|
|
39
|
+
// We received a legacy message, so we set the connection protocol accordingly
|
|
40
|
+
connection.protocolSession.setLegacyAsPreferredProtocol();
|
|
39
41
|
if (this.#isGetRequest(incomingMessage)) {
|
|
40
|
-
await this.#handlers.get.handle(incomingMessage,
|
|
42
|
+
await this.#handlers.get.handle(incomingMessage, connection, channelString);
|
|
41
43
|
}
|
|
42
44
|
else if (this.#isResponse(incomingMessage)) {
|
|
43
|
-
await this.#handlers.response.handle(incomingMessage,
|
|
45
|
+
await this.#handlers.response.handle(incomingMessage, channelString);
|
|
44
46
|
}
|
|
45
47
|
else if (this.#isRoleAccessOperation(incomingMessage)) {
|
|
46
48
|
await this.#handlers.roleTransaction.handle(incomingMessage, connection);
|
|
@@ -54,14 +56,18 @@ class NetworkMessageRouter {
|
|
|
54
56
|
else {
|
|
55
57
|
throw new Error(`Failed to route message. Pubkey of requester is ${connection.remotePublicKey ? b4a.toString(connection.remotePublicKey, 'hex') : 'unknown'}`);
|
|
56
58
|
}
|
|
59
|
+
}
|
|
57
60
|
|
|
61
|
+
#preValidate(message) {
|
|
62
|
+
if (!_.isPlainObject(message) && typeof message !== 'string') {
|
|
63
|
+
throw new Error('Invalid message format: expected object or string.');
|
|
64
|
+
}
|
|
58
65
|
}
|
|
59
66
|
|
|
60
67
|
#isGetRequest(message) {
|
|
61
68
|
return Object.values(NETWORK_MESSAGE_TYPES.GET).includes(message);
|
|
62
69
|
}
|
|
63
70
|
|
|
64
|
-
|
|
65
71
|
#isResponse(message) {
|
|
66
72
|
return Object.values(NETWORK_MESSAGE_TYPES.RESPONSE).includes(message.op);
|
|
67
73
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import b4a from 'b4a';
|
|
2
|
+
import {publicKeyToAddress} from "../../../../../utils/helpers.js";
|
|
2
3
|
|
|
3
|
-
class
|
|
4
|
+
class BaseStateOperationHandler {
|
|
4
5
|
#state;
|
|
5
6
|
#wallet;
|
|
6
7
|
#rateLimiter;
|
|
@@ -15,8 +16,8 @@ class BaseOperationHandler {
|
|
|
15
16
|
* @param {Config} config
|
|
16
17
|
**/
|
|
17
18
|
constructor(state, wallet, rateLimiter, txPoolService, config) {
|
|
18
|
-
if (new.target ===
|
|
19
|
-
throw new Error('
|
|
19
|
+
if (new.target === BaseStateOperationHandler) {
|
|
20
|
+
throw new Error('BaseStateOperationHandler is abstract and cannot be instantiated directly');
|
|
20
21
|
}
|
|
21
22
|
this.#state = state;
|
|
22
23
|
this.#wallet = wallet;
|
|
@@ -37,18 +38,18 @@ class BaseOperationHandler {
|
|
|
37
38
|
throw new Error('OperationHandler: State is not writable or is an indexer without admin privileges.');
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (b4a.byteLength(JSON.stringify(payload)) > this.#config.maxPartialTxPayloadByteSize) {
|
|
45
|
-
throw new Error(`OperationHandler: Payload size exceeds maximum limit of ${this.#config.maxPartialTxPayloadByteSize} bytes by ${b4a.byteLength(JSON.stringify(payload)) - this.#config.maxPartialTxPayloadByteSize} bytes.`);
|
|
41
|
+
this.#txPoolService.validateEnqueue();
|
|
42
|
+
if (b4a.byteLength(JSON.stringify(payload)) > this.#config.transactionPoolSize) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
`OperationHandler: Payload size exceeds maximum limit of ${this.#config.transactionPoolSize} bytes by ${b4a.byteLength(JSON.stringify(payload)) - this.#config.transactionPoolSize} bytes.`);
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
if (!this.#config.disableRateLimit) {
|
|
49
|
-
const shouldDisconnect = this.#rateLimiter.
|
|
48
|
+
const shouldDisconnect = this.#rateLimiter.legacyHandleRateLimit(connection);
|
|
50
49
|
if (shouldDisconnect) {
|
|
51
|
-
throw new Error(
|
|
50
|
+
throw new Error(
|
|
51
|
+
`OperationHandler: Rate limit exceeded for ${publicKeyToAddress(connection.remotePublicKey, this.#config)}. Disconnecting...`
|
|
52
|
+
);
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
55
|
}
|
|
@@ -58,9 +59,19 @@ class BaseOperationHandler {
|
|
|
58
59
|
await this.handleOperation(payload, connection);
|
|
59
60
|
}
|
|
60
61
|
|
|
62
|
+
enqueueTransaction(txHash, encodedOperation) {
|
|
63
|
+
try {
|
|
64
|
+
this.#txPoolService.addTransaction(txHash, encodedOperation);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
throw new Error(
|
|
67
|
+
`${this.constructor.name}: Failed to add transaction ${txHash} to transaction pool: ${error?.message ?? String(error)}`
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
61
72
|
async handleOperation(payload, connection) {
|
|
62
73
|
throw new Error('handleOperation must be implemented by child class');
|
|
63
74
|
}
|
|
64
75
|
|
|
65
76
|
}
|
|
66
|
-
export default
|
|
77
|
+
export default BaseStateOperationHandler;
|
|
@@ -2,7 +2,7 @@ import { NETWORK_MESSAGE_TYPES } from '../../../../../utils/constants.js';
|
|
|
2
2
|
import PeerWallet from 'trac-wallet';
|
|
3
3
|
import b4a from 'b4a';
|
|
4
4
|
|
|
5
|
-
class
|
|
5
|
+
class LegacyGetRequestHandler {
|
|
6
6
|
#wallet;
|
|
7
7
|
#state;
|
|
8
8
|
|
|
@@ -15,17 +15,17 @@ class GetRequestHandler {
|
|
|
15
15
|
return this.#state;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
async handle(message,
|
|
18
|
+
async handle(message, connection, channelString) {
|
|
19
19
|
switch (message) {
|
|
20
20
|
case NETWORK_MESSAGE_TYPES.GET.VALIDATOR:
|
|
21
|
-
await this.handleGetValidatorResponse(
|
|
21
|
+
await this.handleGetValidatorResponse(connection, channelString);
|
|
22
22
|
break;
|
|
23
23
|
default:
|
|
24
24
|
throw new Error(`Unhandled GET type: ${message}`);
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
async handleGetValidatorResponse(
|
|
28
|
+
async handleGetValidatorResponse(connection, channelString) {
|
|
29
29
|
const nonce = PeerWallet.generateNonce().toString('hex');
|
|
30
30
|
const payload = {
|
|
31
31
|
op: 'validatorResponse',
|
|
@@ -46,8 +46,8 @@ class GetRequestHandler {
|
|
|
46
46
|
...payload,
|
|
47
47
|
sig: sig.toString('hex'),
|
|
48
48
|
};
|
|
49
|
-
|
|
49
|
+
connection.protocolSession.sendAndForget(responseMessage)
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
export default
|
|
53
|
+
export default LegacyGetRequestHandler;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import ValidatorResponse from '../validators/ValidatorResponse.js';
|
|
2
|
+
|
|
3
|
+
class LegacyResponseHandler {
|
|
4
|
+
#responseValidator;
|
|
5
|
+
|
|
6
|
+
constructor(state, wallet, config) {
|
|
7
|
+
this.#responseValidator = new ValidatorResponse(state, wallet, config);
|
|
8
|
+
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async handle(message, channelString) {
|
|
12
|
+
await this.#handleValidatorResponse(message, channelString);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async #handleValidatorResponse(message, channelString) {
|
|
16
|
+
const isValid = await this.#responseValidator.validate(message, channelString);
|
|
17
|
+
if (!isValid) {
|
|
18
|
+
throw new Error("Validator response verification failed");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default LegacyResponseHandler;
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import {OperationType} from '../../../../../utils/constants.js';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
2
|
+
import PartialRoleAccessValidator from "../../shared/validators/PartialRoleAccessValidator.js";
|
|
3
|
+
import BaseStateOperationHandler from './BaseStateOperationHandler.js';
|
|
4
4
|
import {applyStateMessageFactory} from "../../../../../messages/state/applyStateMessageFactory.js";
|
|
5
5
|
import {safeEncodeApplyOperation} from "../../../../../utils/protobuf/operationHelpers.js";
|
|
6
6
|
import {normalizeRoleAccessOperation} from "../../../../../utils/normalizers.js";
|
|
7
|
+
import { publicKeyToAddress } from "../../../../../utils/helpers.js"
|
|
8
|
+
import b4a from "b4a";
|
|
7
9
|
|
|
8
|
-
class
|
|
10
|
+
class LegacyRoleOperationHandler extends BaseStateOperationHandler {
|
|
9
11
|
#partialRoleAccessValidator;
|
|
10
12
|
#wallet;
|
|
11
13
|
#config;
|
|
12
|
-
#txPoolService;
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* @param {State} state
|
|
@@ -22,8 +23,7 @@ class RoleOperationHandler extends BaseOperationHandler {
|
|
|
22
23
|
super(state, wallet, rateLimiter, txPoolService, config);
|
|
23
24
|
this.#wallet = wallet;
|
|
24
25
|
this.#config = config;
|
|
25
|
-
this.#partialRoleAccessValidator = new
|
|
26
|
-
this.#txPoolService = txPoolService;
|
|
26
|
+
this.#partialRoleAccessValidator = new PartialRoleAccessValidator(state, this.#wallet.address ,this.#config)
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
get partialRoleAccessValidator() {
|
|
@@ -35,7 +35,8 @@ class RoleOperationHandler extends BaseOperationHandler {
|
|
|
35
35
|
const isValid = await this.partialRoleAccessValidator.validate(normalizedPartialRoleAccessPayload)
|
|
36
36
|
let completePayload = null
|
|
37
37
|
if (!isValid) {
|
|
38
|
-
throw new Error(
|
|
38
|
+
throw new Error(
|
|
39
|
+
`OperationHandler: partial role access payload validation failed. Requested by ${publicKeyToAddress(connection.remotePublicKey, this.#config)}`);
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
switch (normalizedPartialRoleAccessPayload.type) {
|
|
@@ -74,15 +75,21 @@ class RoleOperationHandler extends BaseOperationHandler {
|
|
|
74
75
|
)
|
|
75
76
|
break;
|
|
76
77
|
default:
|
|
77
|
-
throw new Error(
|
|
78
|
+
throw new Error(
|
|
79
|
+
`OperationHandler: Assembling complete role access operation failed due to unsupported operation type. Requested by ${publicKeyToAddress(connection.remotePublicKey, this.#config)}`
|
|
80
|
+
);
|
|
78
81
|
}
|
|
79
82
|
|
|
80
83
|
if (!completePayload) {
|
|
81
|
-
throw new Error(
|
|
84
|
+
throw new Error(
|
|
85
|
+
`OperationHandler: Assembling complete role access operation failed. Requested by ${publicKeyToAddress(connection.remotePublicKey, this.#config)}`
|
|
86
|
+
);
|
|
82
87
|
}
|
|
83
88
|
|
|
84
|
-
|
|
89
|
+
const encodedOperation = safeEncodeApplyOperation(completePayload);
|
|
90
|
+
const txHash = b4a.toString(completePayload.rao.tx, 'hex');
|
|
91
|
+
this.enqueueTransaction(txHash, encodedOperation);
|
|
85
92
|
}
|
|
86
93
|
}
|
|
87
94
|
|
|
88
|
-
export default
|
|
95
|
+
export default LegacyRoleOperationHandler;
|
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
import
|
|
1
|
+
import BaseStateOperationHandler from './BaseStateOperationHandler.js';
|
|
2
2
|
import {
|
|
3
3
|
OperationType
|
|
4
4
|
} from '../../../../../utils/constants.js';
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import PartialBootstrapDeploymentValidator from "../../shared/validators/PartialBootstrapDeploymentValidator.js";
|
|
6
|
+
import PartialTransactionValidator from "../../shared/validators/PartialTransactionValidator.js";
|
|
7
7
|
import {applyStateMessageFactory} from "../../../../../messages/state/applyStateMessageFactory.js";
|
|
8
8
|
import {safeEncodeApplyOperation} from "../../../../../utils/protobuf/operationHelpers.js";
|
|
9
9
|
import {
|
|
10
10
|
normalizeBootstrapDeploymentOperation,
|
|
11
11
|
normalizeTransactionOperation
|
|
12
12
|
} from "../../../../../utils/normalizers.js";
|
|
13
|
+
import b4a from "b4a";
|
|
14
|
+
import {publicKeyToAddress} from "../../../../../utils/helpers.js";
|
|
13
15
|
|
|
14
16
|
|
|
15
|
-
class
|
|
17
|
+
class LegacySubnetworkOperationHandler extends BaseStateOperationHandler {
|
|
16
18
|
#partialBootstrapDeploymentValidator;
|
|
17
19
|
#partialTransactionValidator;
|
|
18
20
|
#config;
|
|
19
21
|
#wallet;
|
|
20
|
-
#txPoolService;
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* @param {State} state
|
|
@@ -26,22 +27,23 @@ class SubnetworkOperationHandler extends BaseOperationHandler {
|
|
|
26
27
|
* @param {TransactionPoolService} txPoolService
|
|
27
28
|
* @param {Config} config
|
|
28
29
|
**/
|
|
29
|
-
constructor(
|
|
30
|
+
constructor(state, wallet, rateLimiter, txPoolService, config) {
|
|
30
31
|
super(state, wallet, rateLimiter, txPoolService, config);
|
|
31
32
|
this.#config = config;
|
|
32
33
|
this.#wallet = wallet
|
|
33
|
-
this.#partialBootstrapDeploymentValidator = new
|
|
34
|
-
this.#partialTransactionValidator = new
|
|
35
|
-
this.#txPoolService = txPoolService;
|
|
34
|
+
this.#partialBootstrapDeploymentValidator = new PartialBootstrapDeploymentValidator(state, this.#wallet.address, config);
|
|
35
|
+
this.#partialTransactionValidator = new PartialTransactionValidator(state, this.#wallet.address, config);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
async handleOperation(payload, connection)
|
|
38
|
+
async handleOperation(payload, connection) {
|
|
39
39
|
if (payload.type === OperationType.TX) {
|
|
40
40
|
await this.#partialTransactionSubHandler(payload, connection);
|
|
41
41
|
} else if (payload.type === OperationType.BOOTSTRAP_DEPLOYMENT) {
|
|
42
42
|
await this.#partialBootstrapDeploymentSubHandler(payload, connection);
|
|
43
43
|
} else {
|
|
44
|
-
throw new Error(
|
|
44
|
+
throw new Error(
|
|
45
|
+
`Unsupported operation type for LegacySubnetworkOperationHandler. Requested by ${publicKeyToAddress(connection.remotePublicKey, this.#config)} `
|
|
46
|
+
);
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
49
|
|
|
@@ -49,10 +51,12 @@ class SubnetworkOperationHandler extends BaseOperationHandler {
|
|
|
49
51
|
const normalizedPayload = normalizeTransactionOperation(payload, this.#config);
|
|
50
52
|
const isValid = await this.#partialTransactionValidator.validate(normalizedPayload);
|
|
51
53
|
if (!isValid) {
|
|
52
|
-
throw new Error(
|
|
54
|
+
throw new Error(`
|
|
55
|
+
SubnetworkHandler: Transaction validation failed. Requested by ${publicKeyToAddress(connection.remotePublicKey, this.#config)}`
|
|
56
|
+
);
|
|
53
57
|
}
|
|
54
58
|
|
|
55
|
-
const completeTransactionOperation = await applyStateMessageFactory(this.#wallet,this.#config)
|
|
59
|
+
const completeTransactionOperation = await applyStateMessageFactory(this.#wallet, this.#config)
|
|
56
60
|
.buildCompleteTransactionOperationMessage(
|
|
57
61
|
normalizedPayload.address,
|
|
58
62
|
normalizedPayload.txo.tx,
|
|
@@ -64,14 +68,19 @@ class SubnetworkOperationHandler extends BaseOperationHandler {
|
|
|
64
68
|
normalizedPayload.txo.bs,
|
|
65
69
|
normalizedPayload.txo.mbs
|
|
66
70
|
)
|
|
67
|
-
|
|
71
|
+
const encodedOperation = safeEncodeApplyOperation(completeTransactionOperation);
|
|
72
|
+
const txHash = b4a.toString(normalizedPayload.txo.tx, 'hex');
|
|
73
|
+
this.enqueueTransaction(txHash, encodedOperation);
|
|
74
|
+
|
|
68
75
|
}
|
|
69
76
|
|
|
70
77
|
async #partialBootstrapDeploymentSubHandler(payload, connection) {
|
|
71
78
|
const normalizedPayload = normalizeBootstrapDeploymentOperation(payload, this.#config);
|
|
72
79
|
const isValid = await this.#partialBootstrapDeploymentValidator.validate(normalizedPayload);
|
|
73
80
|
if (!isValid) {
|
|
74
|
-
throw new Error(
|
|
81
|
+
throw new Error(
|
|
82
|
+
`SubnetworkHandler: Bootstrap deployment validation failed. Requested by ${publicKeyToAddress(connection.remotePublicKey, this.#config)}`
|
|
83
|
+
);
|
|
75
84
|
}
|
|
76
85
|
|
|
77
86
|
|
|
@@ -85,9 +94,11 @@ class SubnetworkOperationHandler extends BaseOperationHandler {
|
|
|
85
94
|
normalizedPayload.bdo.in,
|
|
86
95
|
normalizedPayload.bdo.is
|
|
87
96
|
)
|
|
88
|
-
|
|
97
|
+
const encodedOperation = safeEncodeApplyOperation(completeBootstrapDeploymentOperation);
|
|
98
|
+
const txHash = b4a.toString(normalizedPayload.bdo.tx, 'hex');
|
|
99
|
+
this.enqueueTransaction(txHash, encodedOperation);
|
|
89
100
|
|
|
90
101
|
}
|
|
91
102
|
}
|
|
92
103
|
|
|
93
|
-
export default
|
|
104
|
+
export default LegacySubnetworkOperationHandler;
|
|
@@ -1,33 +1,36 @@
|
|
|
1
|
-
import
|
|
1
|
+
import BaseStateOperationHandler from './BaseStateOperationHandler.js';
|
|
2
2
|
import {OperationType} from '../../../../../utils/constants.js';
|
|
3
|
-
import
|
|
3
|
+
import PartialTransferValidator from "../../shared/validators/PartialTransferValidator.js";
|
|
4
4
|
import {normalizeTransferOperation} from "../../../../../utils/normalizers.js"
|
|
5
5
|
import {applyStateMessageFactory} from "../../../../../messages/state/applyStateMessageFactory.js";
|
|
6
6
|
import {safeEncodeApplyOperation} from "../../../../../utils/protobuf/operationHelpers.js";
|
|
7
|
+
import b4a from "b4a";
|
|
8
|
+
import {publicKeyToAddress} from "../../../../../utils/helpers.js";
|
|
7
9
|
|
|
8
|
-
class
|
|
10
|
+
class LegacyTransferOperationHandler extends BaseStateOperationHandler {
|
|
9
11
|
#partialTransferValidator;
|
|
10
12
|
#config;
|
|
11
13
|
#wallet;
|
|
12
|
-
#txPoolService;
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* @param {State} state
|
|
16
17
|
* @param {PeerWallet} wallet
|
|
17
18
|
* @param {TransactionRateLimiterService} rateLimiter
|
|
19
|
+
* @param {TransactionPoolService} txPoolService
|
|
18
20
|
* @param {Config} config
|
|
19
21
|
**/
|
|
20
22
|
constructor(state, wallet, rateLimiter, txPoolService, config) {
|
|
21
23
|
super(state, wallet, rateLimiter, txPoolService, config);
|
|
22
24
|
this.#config = config;
|
|
23
25
|
this.#wallet = wallet;
|
|
24
|
-
this.#partialTransferValidator = new
|
|
25
|
-
this.#txPoolService = txPoolService;
|
|
26
|
+
this.#partialTransferValidator = new PartialTransferValidator(state, this.#wallet.address, this.#config);
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
async handleOperation(payload, connection) {
|
|
29
30
|
if (payload.type !== OperationType.TRANSFER) {
|
|
30
|
-
throw new Error(
|
|
31
|
+
throw new Error(
|
|
32
|
+
`Unsupported operation type for LegacyTransferOperationHandler. Requested by ${publicKeyToAddress(connection.remotePublicKey, this.#config)}`
|
|
33
|
+
);
|
|
31
34
|
}
|
|
32
35
|
await this.#handleTransfer(payload, connection);
|
|
33
36
|
}
|
|
@@ -36,7 +39,9 @@ class TransferOperationHandler extends BaseOperationHandler {
|
|
|
36
39
|
const normalizedPayload = normalizeTransferOperation(payload, this.#config);
|
|
37
40
|
const isValid = await this.#partialTransferValidator.validate(normalizedPayload);
|
|
38
41
|
if (!isValid) {
|
|
39
|
-
throw new Error(
|
|
42
|
+
throw new Error(
|
|
43
|
+
`TransferHandler: Transfer validation failed. Requested by ${publicKeyToAddress(connection.remotePublicKey, this.#config)}`
|
|
44
|
+
);
|
|
40
45
|
}
|
|
41
46
|
|
|
42
47
|
const completeTransferOperation = await applyStateMessageFactory(this.#wallet, this.#config)
|
|
@@ -49,9 +54,10 @@ class TransferOperationHandler extends BaseOperationHandler {
|
|
|
49
54
|
normalizedPayload.tro.am,
|
|
50
55
|
normalizedPayload.tro.is
|
|
51
56
|
)
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
const encodedOperation = safeEncodeApplyOperation(completeTransferOperation);
|
|
58
|
+
const txHash = b4a.toString(normalizedPayload.tro.tx, 'hex');
|
|
59
|
+
this.enqueueTransaction(txHash, encodedOperation);
|
|
54
60
|
}
|
|
55
61
|
}
|
|
56
62
|
|
|
57
|
-
export default
|
|
63
|
+
export default LegacyTransferOperationHandler;
|