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.
Files changed (114) hide show
  1. package/package.json +9 -4
  2. package/proto/network/v1/enums/message_type.proto +16 -0
  3. package/proto/network/v1/enums/result_code.proto +84 -0
  4. package/proto/network/v1/messages/broadcast_transaction_request.proto +9 -0
  5. package/proto/network/v1/messages/broadcast_transaction_response.proto +13 -0
  6. package/proto/network/v1/messages/liveness_request.proto +8 -0
  7. package/proto/network/v1/messages/liveness_response.proto +11 -0
  8. package/proto/network/v1/network_message.proto +22 -0
  9. package/rpc/rpc_services.js +22 -4
  10. package/scripts/generate-protobufs.js +37 -12
  11. package/src/config/config.js +26 -5
  12. package/src/config/env.js +25 -11
  13. package/src/core/network/Network.js +73 -36
  14. package/src/core/network/protocols/LegacyProtocol.js +21 -11
  15. package/src/core/network/protocols/NetworkMessages.js +38 -17
  16. package/src/core/network/protocols/ProtocolInterface.js +14 -2
  17. package/src/core/network/protocols/ProtocolSession.js +144 -17
  18. package/src/core/network/protocols/V1Protocol.js +37 -18
  19. package/src/core/network/protocols/connectionPolicies.js +88 -0
  20. package/src/core/network/protocols/legacy/NetworkMessageRouter.js +25 -19
  21. package/src/core/network/protocols/{shared/handlers/base/BaseOperationHandler.js → legacy/handlers/BaseStateOperationHandler.js} +23 -12
  22. package/src/core/network/protocols/legacy/handlers/{GetRequestHandler.js → LegacyGetRequestHandler.js} +6 -6
  23. package/src/core/network/protocols/legacy/handlers/LegacyResponseHandler.js +23 -0
  24. package/src/core/network/protocols/{shared/handlers/RoleOperationHandler.js → legacy/handlers/LegacyRoleOperationHandler.js} +18 -11
  25. package/src/core/network/protocols/{shared/handlers/SubnetworkOperationHandler.js → legacy/handlers/LegacySubnetworkOperationHandler.js} +28 -17
  26. package/src/core/network/protocols/{shared/handlers/TransferOperationHandler.js → legacy/handlers/LegacyTransferOperationHandler.js} +17 -11
  27. package/src/core/network/protocols/shared/errors/SharedValidatorRejectionError.js +27 -0
  28. package/src/core/network/protocols/shared/validators/{PartialBootstrapDeployment.js → PartialBootstrapDeploymentValidator.js} +9 -4
  29. package/src/core/network/protocols/shared/validators/{base/PartialOperation.js → PartialOperationValidator.js} +47 -25
  30. package/src/core/network/protocols/shared/validators/{PartialRoleAccess.js → PartialRoleAccessValidator.js} +51 -17
  31. package/src/core/network/protocols/shared/validators/{PartialTransaction.js → PartialTransactionValidator.js} +21 -7
  32. package/src/core/network/protocols/shared/validators/{PartialTransfer.js → PartialTransferValidator.js} +26 -9
  33. package/src/core/network/protocols/v1/NetworkMessageRouter.js +91 -7
  34. package/src/core/network/protocols/v1/V1ProtocolError.js +91 -0
  35. package/src/core/network/protocols/v1/handlers/V1BaseOperationHandler.js +65 -0
  36. package/src/core/network/protocols/v1/handlers/V1BroadcastTransactionOperationHandler.js +389 -0
  37. package/src/core/network/protocols/v1/handlers/V1LivenessOperationHandler.js +87 -0
  38. package/src/core/network/protocols/v1/validators/V1BaseOperation.js +211 -0
  39. package/src/core/network/protocols/v1/validators/V1BroadcastTransactionRequest.js +26 -0
  40. package/src/core/network/protocols/v1/validators/V1BroadcastTransactionResponse.js +276 -0
  41. package/src/core/network/protocols/v1/validators/V1LivenessRequest.js +15 -0
  42. package/src/core/network/protocols/v1/validators/V1LivenessResponse.js +17 -0
  43. package/src/core/network/protocols/v1/validators/V1ValidationSchema.js +210 -0
  44. package/src/core/network/services/ConnectionManager.js +146 -94
  45. package/src/core/network/services/MessageOrchestrator.js +151 -27
  46. package/src/core/network/services/PendingRequestService.js +172 -0
  47. package/src/core/network/services/TransactionCommitService.js +149 -0
  48. package/src/core/network/services/TransactionPoolService.js +129 -18
  49. package/src/core/network/services/TransactionRateLimiterService.js +52 -34
  50. package/src/core/network/services/ValidatorHealthCheckService.js +127 -0
  51. package/src/core/network/services/ValidatorObserverService.js +18 -26
  52. package/src/core/state/State.js +70 -19
  53. package/src/index.js +5 -4
  54. package/src/messages/network/v1/NetworkMessageBuilder.js +59 -79
  55. package/src/messages/network/v1/NetworkMessageDirector.js +16 -50
  56. package/src/utils/Scheduler.js +0 -8
  57. package/src/utils/constants.js +71 -5
  58. package/src/utils/deepEqualApplyPayload.js +40 -0
  59. package/src/utils/helpers.js +10 -1
  60. package/src/utils/logger.js +25 -0
  61. package/src/utils/normalizers.js +38 -0
  62. package/src/utils/protobuf/networkV1.generated.cjs +2460 -0
  63. package/src/utils/protobuf/operationHelpers.js +24 -3
  64. package/tests/acceptance/v1/account/account.test.mjs +8 -2
  65. package/tests/acceptance/v1/tx/tx.test.mjs +23 -1
  66. package/tests/acceptance/v1/tx-details/tx-details.test.mjs +34 -6
  67. package/tests/fixtures/networkV1.fixtures.js +2 -28
  68. package/tests/helpers/transactionPayloads.mjs +2 -2
  69. package/tests/unit/messages/network/NetworkMessageBuilder.test.js +239 -79
  70. package/tests/unit/messages/network/NetworkMessageDirector.test.js +223 -77
  71. package/tests/unit/network/LegacyNetworkMessageRouter.test.js +54 -0
  72. package/tests/unit/network/ProtocolSession.test.js +127 -0
  73. package/tests/unit/network/networkModule.test.js +4 -1
  74. package/tests/unit/network/services/ConnectionManager.test.js +450 -0
  75. package/tests/unit/network/services/MessageOrchestrator.test.js +445 -0
  76. package/tests/unit/network/services/PendingRequestService.test.js +431 -0
  77. package/tests/unit/network/services/TransactionCommitService.test.js +246 -0
  78. package/tests/unit/network/services/TransactionPoolService.test.js +489 -0
  79. package/tests/unit/network/services/TransactionRateLimiterService.test.js +139 -0
  80. package/tests/unit/network/services/ValidatorHealthCheckService.test.js +115 -0
  81. package/tests/unit/network/services/services.test.js +17 -0
  82. package/tests/unit/network/utils/v1TestUtils.js +153 -0
  83. package/tests/unit/network/v1/NetworkMessageRouterV1.test.js +151 -0
  84. package/tests/unit/network/v1/V1BaseOperation.test.js +356 -0
  85. package/tests/unit/network/v1/V1BroadcastTransactionOperationHandler.test.js +129 -0
  86. package/tests/unit/network/v1/V1BroadcastTransactionRequest.test.js +53 -0
  87. package/tests/unit/network/v1/V1BroadcastTransactionResponse.test.js +512 -0
  88. package/tests/unit/network/v1/V1LivenessRequest.test.js +32 -0
  89. package/tests/unit/network/v1/V1LivenessResponse.test.js +45 -0
  90. package/tests/unit/network/v1/V1ResultCode.test.js +84 -0
  91. package/tests/unit/network/v1/V1ValidationSchema.test.js +13 -0
  92. package/tests/unit/network/v1/connectionPolicies.test.js +49 -0
  93. package/tests/unit/network/v1/handlers/V1BaseOperationHandler.test.js +284 -0
  94. package/tests/unit/network/v1/handlers/V1BroadcastTransactionOperationHandler.test.js +794 -0
  95. package/tests/unit/network/v1/handlers/V1LivenessOperationHandler.test.js +193 -0
  96. package/tests/unit/network/v1/v1.handlers.test.js +15 -0
  97. package/tests/unit/network/v1/v1.test.js +19 -0
  98. package/tests/unit/network/v1/v1ValidationSchema/broadcastTransactionRequest.test.js +119 -0
  99. package/tests/unit/network/v1/v1ValidationSchema/broadcastTransactionResponse.test.js +136 -0
  100. package/tests/unit/network/v1/v1ValidationSchema/common.test.js +308 -0
  101. package/tests/unit/network/v1/v1ValidationSchema/livenessRequest.test.js +90 -0
  102. package/tests/unit/network/v1/v1ValidationSchema/livenessResponse.test.js +133 -0
  103. package/tests/unit/unit.test.js +2 -2
  104. package/tests/unit/utils/deepEqualApplyPayload/deepEqualApplyPayload.test.js +102 -0
  105. package/tests/unit/utils/protobuf/operationHelpers.test.js +2 -4
  106. package/tests/unit/utils/utils.test.js +1 -0
  107. package/.github/workflows/acceptance-tests.yml +0 -38
  108. package/.github/workflows/lint-pr-title.yml +0 -26
  109. package/.github/workflows/publish.yml +0 -33
  110. package/.github/workflows/unit-tests.yml +0 -34
  111. package/proto/network.proto +0 -74
  112. package/src/core/network/protocols/legacy/handlers/ResponseHandler.js +0 -37
  113. package/src/utils/protobuf/network.cjs +0 -840
  114. 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
- onclose() { }
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: async (incomingMessage) => {
42
- try {
43
- if (b4a.isBuffer(incomingMessage)) {
44
- await this.#router.route(incomingMessage, connection, this.#session);
45
- } else {
46
- throw new Error('NetworkMessages: v1 message must be a buffer');
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
- } catch (error) {
49
- console.error(`NetworkMessages: Failed to handle incoming v1 message: ${error.message}`);
50
- }
52
+ });
51
53
  }
52
54
  });
53
55
  }
54
56
 
55
- send(message) {
56
- this.#session.send(message);
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 GetRequestHandler from "./handlers/GetRequestHandler.js";
3
- import ResponseHandler from "./handlers/ResponseHandler.js";
4
- import RoleOperationHandler from "../shared/handlers/RoleOperationHandler.js";
5
- import SubnetworkOperationHandler from "../shared/handlers/SubnetworkOperationHandler.js";
6
- import TransferOperationHandler from "../shared/handlers/TransferOperationHandler.js";
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, connectionManager, config) {
22
+ constructor(state, wallet, rateLimiterService, txPoolService, config) {
25
23
  this.#config = config;
26
24
 
27
25
  this.#handlers = {
28
- get: new GetRequestHandler(wallet, state),
29
- response: new ResponseHandler(state, wallet, connectionManager, this.#config),
30
- roleTransaction: new RoleOperationHandler(state, wallet, rateLimiterService, txPoolService, this.#config),
31
- subNetworkTransaction: new SubnetworkOperationHandler(state, wallet, rateLimiterService, txPoolService, this.#config),
32
- tracNetworkTransaction: new TransferOperationHandler(state, wallet, rateLimiterService, txPoolService, this.#config),
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
- // NOTE: messageProtomux can be deleted, ad this is a session, and we can extract this from connection
37
- async route(incomingMessage, connection, messageProtomux) {
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, messageProtomux, connection, channelString);
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, connection, channelString);
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 BaseOperationHandler {
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 === BaseOperationHandler) {
19
- throw new Error('BaseOperationHandler is abstract and cannot be instantiated directly');
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
- if (this.#txPoolService.tx_pool.length >= this.#config.transactionPoolSize) {
41
- throw new Error("OperationHandler: Transaction pool is full, ignoring incoming transaction.");
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.handleRateLimit(connection);
48
+ const shouldDisconnect = this.#rateLimiter.legacyHandleRateLimit(connection);
50
49
  if (shouldDisconnect) {
51
- throw new Error(`OperationHandler: Rate limit exceeded for peer ${b4a.toString(connection.remotePublicKey, 'hex')}. Disconnecting...`);
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 BaseOperationHandler;
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 GetRequestHandler {
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, messageProtomux, connection, channelString) {
18
+ async handle(message, connection, channelString) {
19
19
  switch (message) {
20
20
  case NETWORK_MESSAGE_TYPES.GET.VALIDATOR:
21
- await this.handleGetValidatorResponse(messageProtomux, connection, channelString);
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(messageProtomux, connection, channelString) {
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
- messageProtomux.send(responseMessage);
49
+ connection.protocolSession.sendAndForget(responseMessage)
50
50
  }
51
51
  }
52
52
 
53
- export default GetRequestHandler;
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 PartialRoleAccess from "../validators/PartialRoleAccess.js";
3
- import BaseOperationHandler from './base/BaseOperationHandler.js';
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 RoleOperationHandler extends BaseOperationHandler {
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 PartialRoleAccess(state, this.#wallet.address ,this.#config)
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("OperationHandler: partial role access payload validation failed.");
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("OperationHandler: Assembling complete role access operation failed due to unsupported operation type.");
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("OperationHandler: Assembling complete role access operation failed.");
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
- this.#txPoolService.addTransaction(safeEncodeApplyOperation(completePayload))
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 RoleOperationHandler;
95
+ export default LegacyRoleOperationHandler;
@@ -1,23 +1,24 @@
1
- import BaseOperationHandler from './base/BaseOperationHandler.js';
1
+ import BaseStateOperationHandler from './BaseStateOperationHandler.js';
2
2
  import {
3
3
  OperationType
4
4
  } from '../../../../../utils/constants.js';
5
- import PartialBootstrapDeployment from "../validators/PartialBootstrapDeployment.js";
6
- import PartialTransaction from "../validators/PartialTransaction.js";
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 SubnetworkOperationHandler extends BaseOperationHandler {
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( state, wallet, rateLimiter, txPoolService, config) {
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 PartialBootstrapDeployment(state, this.#wallet.address, config);
34
- this.#partialTransactionValidator = new PartialTransaction(state, this.#wallet.address, config);
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('Unsupported operation type for SubnetworkOperationHandler');
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("SubnetworkHandler: Transaction validation failed.");
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
- this.#txPoolService.addTransaction(safeEncodeApplyOperation(completeTransactionOperation));
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("SubnetworkHandler: Bootstrap deployment validation failed.");
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
- this.#txPoolService.addTransaction(safeEncodeApplyOperation(completeBootstrapDeploymentOperation));
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 SubnetworkOperationHandler;
104
+ export default LegacySubnetworkOperationHandler;
@@ -1,33 +1,36 @@
1
- import BaseOperationHandler from './base/BaseOperationHandler.js';
1
+ import BaseStateOperationHandler from './BaseStateOperationHandler.js';
2
2
  import {OperationType} from '../../../../../utils/constants.js';
3
- import PartialTransfer from "../validators/PartialTransfer.js";
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 TransferOperationHandler extends BaseOperationHandler {
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 PartialTransfer(state, this.#wallet.address, this.#config);
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('Unsupported operation type for TransferOperationHandler');
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("TransferHandler: Transfer validation failed.");
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
- this.#txPoolService.addTransaction(safeEncodeApplyOperation(completeTransferOperation));
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 TransferOperationHandler;
63
+ export default LegacyTransferOperationHandler;