trac-msb 0.2.11 → 0.2.12

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/.github/workflows/acceptance-tests.yml +38 -0
  2. package/.github/workflows/lint-pr-title.yml +26 -0
  3. package/.github/workflows/publish.yml +33 -0
  4. package/.github/workflows/unit-tests.yml +34 -0
  5. package/package.json +5 -10
  6. package/proto/network.proto +74 -0
  7. package/rpc/rpc_services.js +4 -22
  8. package/scripts/generate-protobufs.js +12 -37
  9. package/src/config/config.js +5 -26
  10. package/src/config/env.js +11 -25
  11. package/src/core/network/Network.js +36 -73
  12. package/src/core/network/protocols/LegacyProtocol.js +11 -21
  13. package/src/core/network/protocols/NetworkMessages.js +17 -38
  14. package/src/core/network/protocols/ProtocolInterface.js +2 -14
  15. package/src/core/network/protocols/ProtocolSession.js +17 -144
  16. package/src/core/network/protocols/V1Protocol.js +18 -37
  17. package/src/core/network/protocols/legacy/NetworkMessageRouter.js +19 -25
  18. package/src/core/network/protocols/legacy/handlers/{LegacyGetRequestHandler.js → GetRequestHandler.js} +6 -6
  19. package/src/core/network/protocols/legacy/handlers/ResponseHandler.js +37 -0
  20. package/src/core/network/protocols/{legacy/handlers/LegacyRoleOperationHandler.js → shared/handlers/RoleOperationHandler.js} +11 -18
  21. package/src/core/network/protocols/{legacy/handlers/LegacySubnetworkOperationHandler.js → shared/handlers/SubnetworkOperationHandler.js} +17 -28
  22. package/src/core/network/protocols/{legacy/handlers/LegacyTransferOperationHandler.js → shared/handlers/TransferOperationHandler.js} +11 -17
  23. package/src/core/network/protocols/{legacy/handlers/BaseStateOperationHandler.js → shared/handlers/base/BaseOperationHandler.js} +12 -23
  24. package/src/core/network/protocols/shared/validators/{PartialBootstrapDeploymentValidator.js → PartialBootstrapDeployment.js} +4 -9
  25. package/src/core/network/protocols/shared/validators/{PartialRoleAccessValidator.js → PartialRoleAccess.js} +17 -51
  26. package/src/core/network/protocols/shared/validators/{PartialTransactionValidator.js → PartialTransaction.js} +7 -21
  27. package/src/core/network/protocols/shared/validators/{PartialTransferValidator.js → PartialTransfer.js} +9 -26
  28. package/src/core/network/protocols/shared/validators/{PartialOperationValidator.js → base/PartialOperation.js} +25 -47
  29. package/src/core/network/protocols/v1/NetworkMessageRouter.js +7 -91
  30. package/src/core/network/services/ConnectionManager.js +94 -146
  31. package/src/core/network/services/MessageOrchestrator.js +27 -151
  32. package/src/core/network/services/TransactionPoolService.js +18 -129
  33. package/src/core/network/services/TransactionRateLimiterService.js +34 -52
  34. package/src/core/network/services/ValidatorObserverService.js +26 -18
  35. package/src/core/state/State.js +19 -70
  36. package/src/index.js +4 -5
  37. package/src/messages/network/v1/NetworkMessageBuilder.js +79 -59
  38. package/src/messages/network/v1/NetworkMessageDirector.js +50 -16
  39. package/src/utils/Scheduler.js +8 -0
  40. package/src/utils/constants.js +5 -71
  41. package/src/utils/helpers.js +1 -10
  42. package/src/utils/normalizers.js +0 -38
  43. package/src/utils/protobuf/network.cjs +840 -0
  44. package/src/utils/protobuf/operationHelpers.js +3 -24
  45. package/tests/acceptance/v1/account/account.test.mjs +2 -8
  46. package/tests/acceptance/v1/tx/tx.test.mjs +1 -23
  47. package/tests/acceptance/v1/tx-details/tx-details.test.mjs +6 -34
  48. package/tests/fixtures/networkV1.fixtures.js +28 -2
  49. package/tests/helpers/transactionPayloads.mjs +2 -2
  50. package/tests/unit/messages/network/NetworkMessageBuilder.test.js +79 -239
  51. package/tests/unit/messages/network/NetworkMessageDirector.test.js +77 -223
  52. package/tests/unit/network/ConnectionManager.test.js +191 -0
  53. package/tests/unit/network/networkModule.test.js +1 -4
  54. package/tests/unit/unit.test.js +2 -2
  55. package/tests/unit/utils/protobuf/operationHelpers.test.js +4 -2
  56. package/tests/unit/utils/utils.test.js +0 -1
  57. package/proto/network/v1/enums/message_type.proto +0 -16
  58. package/proto/network/v1/enums/result_code.proto +0 -84
  59. package/proto/network/v1/messages/broadcast_transaction_request.proto +0 -9
  60. package/proto/network/v1/messages/broadcast_transaction_response.proto +0 -13
  61. package/proto/network/v1/messages/liveness_request.proto +0 -8
  62. package/proto/network/v1/messages/liveness_response.proto +0 -11
  63. package/proto/network/v1/network_message.proto +0 -22
  64. package/src/core/network/protocols/connectionPolicies.js +0 -88
  65. package/src/core/network/protocols/legacy/handlers/LegacyResponseHandler.js +0 -23
  66. package/src/core/network/protocols/shared/errors/SharedValidatorRejectionError.js +0 -27
  67. package/src/core/network/protocols/v1/V1ProtocolError.js +0 -91
  68. package/src/core/network/protocols/v1/handlers/V1BaseOperationHandler.js +0 -65
  69. package/src/core/network/protocols/v1/handlers/V1BroadcastTransactionOperationHandler.js +0 -389
  70. package/src/core/network/protocols/v1/handlers/V1LivenessOperationHandler.js +0 -87
  71. package/src/core/network/protocols/v1/validators/V1BaseOperation.js +0 -211
  72. package/src/core/network/protocols/v1/validators/V1BroadcastTransactionRequest.js +0 -26
  73. package/src/core/network/protocols/v1/validators/V1BroadcastTransactionResponse.js +0 -276
  74. package/src/core/network/protocols/v1/validators/V1LivenessRequest.js +0 -15
  75. package/src/core/network/protocols/v1/validators/V1LivenessResponse.js +0 -17
  76. package/src/core/network/protocols/v1/validators/V1ValidationSchema.js +0 -210
  77. package/src/core/network/services/PendingRequestService.js +0 -172
  78. package/src/core/network/services/TransactionCommitService.js +0 -149
  79. package/src/core/network/services/ValidatorHealthCheckService.js +0 -127
  80. package/src/utils/deepEqualApplyPayload.js +0 -40
  81. package/src/utils/logger.js +0 -25
  82. package/src/utils/protobuf/networkV1.generated.cjs +0 -2460
  83. package/tests/unit/network/LegacyNetworkMessageRouter.test.js +0 -54
  84. package/tests/unit/network/ProtocolSession.test.js +0 -127
  85. package/tests/unit/network/services/ConnectionManager.test.js +0 -450
  86. package/tests/unit/network/services/MessageOrchestrator.test.js +0 -445
  87. package/tests/unit/network/services/PendingRequestService.test.js +0 -431
  88. package/tests/unit/network/services/TransactionCommitService.test.js +0 -246
  89. package/tests/unit/network/services/TransactionPoolService.test.js +0 -489
  90. package/tests/unit/network/services/TransactionRateLimiterService.test.js +0 -139
  91. package/tests/unit/network/services/ValidatorHealthCheckService.test.js +0 -115
  92. package/tests/unit/network/services/services.test.js +0 -17
  93. package/tests/unit/network/utils/v1TestUtils.js +0 -153
  94. package/tests/unit/network/v1/NetworkMessageRouterV1.test.js +0 -151
  95. package/tests/unit/network/v1/V1BaseOperation.test.js +0 -356
  96. package/tests/unit/network/v1/V1BroadcastTransactionOperationHandler.test.js +0 -129
  97. package/tests/unit/network/v1/V1BroadcastTransactionRequest.test.js +0 -53
  98. package/tests/unit/network/v1/V1BroadcastTransactionResponse.test.js +0 -512
  99. package/tests/unit/network/v1/V1LivenessRequest.test.js +0 -32
  100. package/tests/unit/network/v1/V1LivenessResponse.test.js +0 -45
  101. package/tests/unit/network/v1/V1ResultCode.test.js +0 -84
  102. package/tests/unit/network/v1/V1ValidationSchema.test.js +0 -13
  103. package/tests/unit/network/v1/connectionPolicies.test.js +0 -49
  104. package/tests/unit/network/v1/handlers/V1BaseOperationHandler.test.js +0 -284
  105. package/tests/unit/network/v1/handlers/V1BroadcastTransactionOperationHandler.test.js +0 -794
  106. package/tests/unit/network/v1/handlers/V1LivenessOperationHandler.test.js +0 -193
  107. package/tests/unit/network/v1/v1.handlers.test.js +0 -15
  108. package/tests/unit/network/v1/v1.test.js +0 -19
  109. package/tests/unit/network/v1/v1ValidationSchema/broadcastTransactionRequest.test.js +0 -119
  110. package/tests/unit/network/v1/v1ValidationSchema/broadcastTransactionResponse.test.js +0 -136
  111. package/tests/unit/network/v1/v1ValidationSchema/common.test.js +0 -308
  112. package/tests/unit/network/v1/v1ValidationSchema/livenessRequest.test.js +0 -90
  113. package/tests/unit/network/v1/v1ValidationSchema/livenessResponse.test.js +0 -133
  114. package/tests/unit/utils/deepEqualApplyPayload/deepEqualApplyPayload.test.js +0 -102
@@ -1,11 +1,10 @@
1
1
  import b4a from 'b4a';
2
- import {OperationType, ResultCode} from "../../../../../utils/constants.js";
2
+ import {OperationType} from "../../../../../utils/constants.js";
3
3
  import {bufferToAddress} from "../../../../state/utils/address.js";
4
- import PartialOperationValidator from './PartialOperationValidator.js';
4
+ import PartialOperation from './base/PartialOperation.js';
5
5
  import {bufferToBigInt} from "../../../../../utils/amountSerialization.js";
6
- import SharedValidatorRejectionError from '../errors/SharedValidatorRejectionError.js';
7
6
 
8
- class PartialRoleAccessValidator extends PartialOperationValidator {
7
+ class PartialRoleAccess extends PartialOperation {
9
8
  #config;
10
9
 
11
10
  constructor(state, selfAddress, config) {
@@ -43,26 +42,17 @@ class PartialRoleAccessValidator extends PartialOperationValidator {
43
42
  const nodeAddress = bufferToAddress(payload.address, this.#config.addressPrefix);
44
43
  const nodeEntry = await this.state.getNodeEntry(nodeAddress);
45
44
  if (!nodeEntry) {
46
- throw new SharedValidatorRejectionError(
47
- ResultCode.ROLE_NODE_ENTRY_NOT_FOUND,
48
- `Node with address ${nodeAddress} entry does not exist.`
49
- );
45
+ throw new Error(`Node with address ${nodeAddress} entry does not exist.`);
50
46
  }
51
47
 
52
48
  const isNodeAlreadyWriter = nodeEntry.isWriter;
53
49
  if (isNodeAlreadyWriter) {
54
- throw new SharedValidatorRejectionError(
55
- ResultCode.ROLE_NODE_ALREADY_WRITER,
56
- `Node with address ${nodeAddress} is already a writer.`
57
- );
50
+ throw new Error(`Node with address ${nodeAddress} is already a writer.`);
58
51
  }
59
52
 
60
53
  const isNodeWhitelisted = nodeEntry.isWhitelisted;
61
54
  if (!isNodeWhitelisted) {
62
- throw new SharedValidatorRejectionError(
63
- ResultCode.ROLE_NODE_NOT_WHITELISTED,
64
- `Node with address ${nodeAddress} is not whitelisted.`
65
- );
55
+ throw new Error(`Node with address ${nodeAddress} is not whitelisted.`);
66
56
  }
67
57
  return;
68
58
 
@@ -70,33 +60,24 @@ class PartialRoleAccessValidator extends PartialOperationValidator {
70
60
  const nodeAddress = bufferToAddress(payload.address, this.#config.addressPrefix);
71
61
  const nodeEntry = await this.state.getNodeEntry(nodeAddress);
72
62
  if (!nodeEntry) {
73
- throw new SharedValidatorRejectionError(
74
- ResultCode.ROLE_NODE_ENTRY_NOT_FOUND,
75
- `Node with address ${nodeAddress} entry does not exist.`
76
- );
63
+ throw new Error(`Node with address ${nodeAddress} entry does not exist.`);
77
64
  }
78
65
 
79
66
  const isAlreadyWriter = nodeEntry.isWriter;
80
67
  if (!isAlreadyWriter) {
81
- throw new SharedValidatorRejectionError(
82
- ResultCode.ROLE_NODE_NOT_WRITER,
83
- `Node with address ${nodeAddress} is not a writer.`
84
- );
68
+ throw new Error(`Node with address ${nodeAddress} is not a writer.`);
85
69
  }
86
70
 
87
71
  const isAlreadyIndexer = nodeEntry.isIndexer;
88
72
  if (isAlreadyIndexer) {
89
- throw new SharedValidatorRejectionError(
90
- ResultCode.ROLE_NODE_IS_INDEXER,
91
- `Node with address ${nodeAddress} is an indexer.`
92
- );
73
+ throw new Error(`Node with address ${nodeAddress} is an indexer.`);
93
74
  }
94
75
  return;
95
76
 
96
77
  } else if (type === OperationType.ADMIN_RECOVERY) {
97
78
  const adminEntry = await this.state.getAdminEntry();
98
79
  if (!adminEntry) {
99
- throw new SharedValidatorRejectionError(ResultCode.ROLE_ADMIN_ENTRY_MISSING, 'Admin entry does not exist.');
80
+ throw new Error('Admin entry does not exist.');
100
81
  }
101
82
 
102
83
  const adminAddressBuffer = payload.address;
@@ -106,29 +87,20 @@ class PartialRoleAccessValidator extends PartialOperationValidator {
106
87
  !b4a.equals(payload.rao.iw, adminEntry.wk)
107
88
  );
108
89
  if (!isRecoveryCase) {
109
- throw new SharedValidatorRejectionError(
110
- ResultCode.ROLE_INVALID_RECOVERY_CASE,
111
- `Node with address ${adminAddress} is not a valid recovery case.`
112
- );
90
+ throw new Error(`Node with address ${adminAddress} is not a valid recovery case.`);
113
91
  }
114
92
 
115
93
  return;
116
94
  }
117
95
 
118
- throw new SharedValidatorRejectionError(
119
- ResultCode.ROLE_UNKNOWN_OPERATION,
120
- `Unknown role access operation type: ${type}`
121
- );
96
+ throw new Error(`Unknown role access operation type: ${type}`);
122
97
  }
123
98
 
124
99
  async validateWriterKey(payload) {
125
100
  const requesterAddress = bufferToAddress(payload.address, this.#config.addressPrefix);
126
101
  const nodeEntry = await this.state.getNodeEntry(requesterAddress);
127
102
  if (!nodeEntry) {
128
- throw new SharedValidatorRejectionError(
129
- ResultCode.REQUESTER_NOT_FOUND,
130
- `Node entry not found for address ${requesterAddress}`
131
- );
103
+ throw new Error(`Node entry not found for address ${requesterAddress}`);
132
104
  }
133
105
 
134
106
  const writerKey = payload.rao.iw.toString('hex');
@@ -139,10 +111,7 @@ class PartialRoleAccessValidator extends PartialOperationValidator {
139
111
  const isOwner = b4a.equals(addressFromRegisteredWritingKey, payload.address);
140
112
 
141
113
  if (!isCurrentWk || !isOwner) {
142
- throw new SharedValidatorRejectionError(
143
- ResultCode.ROLE_INVALID_WRITER_KEY,
144
- 'Invalid writer key: either not owned by requester or different from assigned key'
145
- );
114
+ throw new Error('Invalid writer key: either not owned by requester or different from assigned key');
146
115
  }
147
116
  }
148
117
  }
@@ -157,18 +126,15 @@ class PartialRoleAccessValidator extends PartialOperationValidator {
157
126
  }
158
127
 
159
128
  if (!requesterEntry) {
160
- throw new SharedValidatorRejectionError(ResultCode.REQUESTER_NOT_FOUND, 'Requester address not found in state');
129
+ throw new Error('Requester address not found in state');
161
130
  }
162
131
  const requesterBalance = bufferToBigInt(requesterEntry.balance);
163
132
 
164
133
  const requiredBalance = this.fee * 11n;
165
134
  if (requesterBalance < requiredBalance) {
166
- throw new SharedValidatorRejectionError(
167
- ResultCode.ROLE_INSUFFICIENT_FEE_BALANCE,
168
- 'Insufficient requester balance to cover role access operation FEE.'
169
- );
135
+ throw new Error('Insufficient requester balance to cover role access operation FEE.');
170
136
  }
171
137
  }
172
138
  }
173
139
 
174
- export default PartialRoleAccessValidator;
140
+ export default PartialRoleAccess;
@@ -1,11 +1,9 @@
1
1
  import b4a from 'b4a';
2
2
  import {safeDecodeApplyOperation} from "../../../../../utils/protobuf/operationHelpers.js";
3
3
  import deploymentEntryUtils from "../../../../state/utils/deploymentEntry.js";
4
- import PartialOperationValidator from './PartialOperationValidator.js';
5
- import {ResultCode} from "../../../../../utils/constants.js";
6
- import SharedValidatorRejectionError from '../errors/SharedValidatorRejectionError.js';
4
+ import PartialOperation from './base/PartialOperation.js';
7
5
 
8
- class PartialTransactionValidator extends PartialOperationValidator {
6
+ class PartialTransaction extends PartialOperation {
9
7
  #config
10
8
 
11
9
  constructor(state, selfAddress, config) {
@@ -34,20 +32,14 @@ class PartialTransactionValidator extends PartialOperationValidator {
34
32
 
35
33
  validateMsbBootstrap(payload) {
36
34
  if (!b4a.equals(this.#config.bootstrap, payload.txo.mbs)) {
37
- throw new SharedValidatorRejectionError(
38
- ResultCode.MSB_BOOTSTRAP_MISMATCH,
39
- `Declared MSB bootstrap is different than network bootstrap in transaction operation: ${payload.txo.mbs.toString('hex')}`
40
- );
35
+ throw new Error(`Declared MSB bootstrap is different than network bootstrap in transaction operation: ${payload.txo.mbs.toString('hex')}`);
41
36
  }
42
37
  }
43
38
 
44
39
  async validateIfExternalBootstrapHasBeenDeployed(payload) {
45
40
  const externalBootstrapResult = await this.state.getRegisteredBootstrapEntry(payload.txo.bs.toString('hex'));
46
41
  if (externalBootstrapResult === null) {
47
- throw new SharedValidatorRejectionError(
48
- ResultCode.EXTERNAL_BOOTSTRAP_NOT_DEPLOYED,
49
- `External bootstrap with hash ${payload.txo.bs.toString('hex')} is not registered as deployment entry.`
50
- );
42
+ throw new Error(`External bootstrap with hash ${payload.txo.bs.toString('hex')} is not registered as deployment entry.`);
51
43
  }
52
44
 
53
45
  const decodedPayload = deploymentEntryUtils.decode(externalBootstrapResult, this.#config.addressLength);
@@ -55,23 +47,17 @@ class PartialTransactionValidator extends PartialOperationValidator {
55
47
  const getBootstrapTransactionTxPayload = await this.state.get(txHash.toString('hex'));
56
48
 
57
49
  if (getBootstrapTransactionTxPayload === null) {
58
- throw new SharedValidatorRejectionError(
59
- ResultCode.EXTERNAL_BOOTSTRAP_TX_MISSING,
60
- `External bootstrap is not registered as usual tx ${externalBootstrapResult.toString('hex')}: ${payload}`
61
- );
50
+ throw new Error(`External bootstrap is not registered as usual tx ${externalBootstrapResult.toString('hex')}: ${payload}`);
62
51
  }
63
52
 
64
53
  const decodedBootstrapDeployment = safeDecodeApplyOperation(getBootstrapTransactionTxPayload)
65
54
 
66
55
  // edge case
67
56
  if (!b4a.equals(decodedBootstrapDeployment.bdo.bs, payload.txo.bs)) {
68
- throw new SharedValidatorRejectionError(
69
- ResultCode.EXTERNAL_BOOTSTRAP_MISMATCH,
70
- `External bootstrap does not match the one in the transaction payload: ${decodedBootstrapDeployment.bdo.bs.toString('hex')} !== ${payload.txo.bs.toString('hex')}`
71
- );
57
+ throw new Error(`External bootstrap does not match the one in the transaction payload: ${decodedBootstrapDeployment.bdo.bs.toString('hex')} !== ${payload.txo.bs.toString('hex')}`);
72
58
  }
73
59
  }
74
60
 
75
61
  }
76
62
 
77
- export default PartialTransactionValidator;
63
+ export default PartialTransaction;
@@ -2,11 +2,9 @@ import PeerWallet from 'trac-wallet';
2
2
 
3
3
  import {bufferToAddress} from "../../../../state/utils/address.js";
4
4
  import {bufferToBigInt} from "../../../../../utils/amountSerialization.js";
5
- import {ResultCode} from "../../../../../utils/constants.js";
6
- import PartialOperationValidator from './PartialOperationValidator.js';
7
- import SharedValidatorRejectionError from '../errors/SharedValidatorRejectionError.js';
5
+ import PartialOperation from './base/PartialOperation.js';
8
6
 
9
- class PartialTransferValidator extends PartialOperationValidator {
7
+ class PartialTransfer extends PartialOperation {
10
8
  #config
11
9
 
12
10
  constructor(state, selfAddress, config) {
@@ -33,18 +31,12 @@ class PartialTransferValidator extends PartialOperationValidator {
33
31
  #validateRecipientAddress(payload) {
34
32
  const incomingAddress = bufferToAddress(payload.tro.to, this.#config.addressPrefix);
35
33
  if (!incomingAddress) {
36
- throw new SharedValidatorRejectionError(
37
- ResultCode.TRANSFER_RECIPIENT_ADDRESS_INVALID,
38
- 'Invalid recipient address in transfer payload.'
39
- );
34
+ throw new Error('Invalid recipient address in transfer payload.');
40
35
  }
41
36
 
42
37
  const incomingPublicKey = PeerWallet.decodeBech32mSafe(incomingAddress);
43
38
  if (incomingPublicKey === null) {
44
- throw new SharedValidatorRejectionError(
45
- ResultCode.TRANSFER_RECIPIENT_PUBLIC_KEY_INVALID,
46
- 'Invalid recipient public key in transfer payload.'
47
- );
39
+ throw new Error('Invalid recipient public key in transfer payload.');
48
40
  }
49
41
 
50
42
  }
@@ -55,10 +47,7 @@ class PartialTransferValidator extends PartialOperationValidator {
55
47
 
56
48
  const transferAmount = bufferToBigInt(payload.tro.am);
57
49
  if (transferAmount > this.max_amount) {
58
- throw new SharedValidatorRejectionError(
59
- ResultCode.TRANSFER_AMOUNT_TOO_LARGE,
60
- 'Transfer amount exceeds maximum allowed value'
61
- );
50
+ throw new Error('Transfer amount exceeds maximum allowed value');
62
51
  }
63
52
 
64
53
  const isSelfTransfer = senderAddress === recipientAddress;
@@ -66,15 +55,12 @@ class PartialTransferValidator extends PartialOperationValidator {
66
55
 
67
56
  const senderEntry = await this.state.getNodeEntryUnsigned(senderAddress);
68
57
  if (!senderEntry) {
69
- throw new SharedValidatorRejectionError(ResultCode.TRANSFER_SENDER_NOT_FOUND, 'Sender account not found');
58
+ throw new Error('Sender account not found');
70
59
  }
71
60
 
72
61
  const senderBalance = bufferToBigInt(senderEntry.balance);
73
62
  if (!(senderBalance >= totalDeductedAmount)) {
74
- throw new SharedValidatorRejectionError(
75
- ResultCode.TRANSFER_INSUFFICIENT_BALANCE,
76
- 'Insufficient balance for transfer' + (isSelfTransfer ? ' fee' : ' + fee')
77
- );
63
+ throw new Error('Insufficient balance for transfer' + (isSelfTransfer ? ' fee' : ' + fee'));
78
64
  }
79
65
 
80
66
  if (!isSelfTransfer) {
@@ -83,14 +69,11 @@ class PartialTransferValidator extends PartialOperationValidator {
83
69
  const recipientBalance = bufferToBigInt(recipientEntry.balance);
84
70
  const newRecipientBalance = recipientBalance + transferAmount;
85
71
  if (newRecipientBalance > this.max_amount) {
86
- throw new SharedValidatorRejectionError(
87
- ResultCode.TRANSFER_RECIPIENT_BALANCE_OVERFLOW,
88
- 'Transfer would cause recipient balance to exceed maximum allowed value'
89
- );
72
+ throw new Error('Transfer would cause recipient balance to exceed maximum allowed value');
90
73
  }
91
74
  }
92
75
  }
93
76
  }
94
77
  }
95
78
 
96
- export default PartialTransferValidator;
79
+ export default PartialTransfer;
@@ -1,19 +1,18 @@
1
1
  import b4a from 'b4a';
2
2
  import PeerWallet from 'trac-wallet';
3
- import Check from '../../../../../utils/check.js';
4
- import {bufferToAddress} from "../../../../state/utils/address.js";
5
- import {createMessage} from "../../../../../utils/buffer.js";
6
- import {OperationType, ResultCode} from "../../../../../utils/constants.js";
7
- import {bufferToBigInt} from "../../../../../utils/amountSerialization.js";
8
- import {FEE} from "../../../../state/utils/transaction.js";
9
- import * as operationsUtils from '../../../../../utils/applyOperations.js';
10
- import SharedValidatorRejectionError from '../errors/SharedValidatorRejectionError.js';
3
+ import Check from '../../../../../../utils/check.js';
4
+ import {bufferToAddress} from "../../../../../state/utils/address.js";
5
+ import {createMessage} from "../../../../../../utils/buffer.js";
6
+ import {OperationType} from "../../../../../../utils/constants.js";
7
+ import {bufferToBigInt} from "../../../../../../utils/amountSerialization.js";
8
+ import {FEE} from "../../../../../state/utils/transaction.js";
9
+ import * as operationsUtils from '../../../../../../utils/applyOperations.js';
11
10
 
12
11
  const MAX_AMOUNT = BigInt('0xffffffffffffffffffffffffffffffff');
13
12
  const FEE_BIGINT = bufferToBigInt(FEE);
14
13
  const PUBLIC_KEY_LENGTH = 32;
15
14
 
16
- class PartialOperationValidator {
15
+ class PartialOperation {
17
16
  #state;
18
17
  #check;
19
18
  #config
@@ -37,18 +36,18 @@ class PartialOperationValidator {
37
36
  }
38
37
 
39
38
  async validate(payload) {
40
- throw new SharedValidatorRejectionError(ResultCode.UNEXPECTED_ERROR, "Method 'validate()' must be implemented.");
39
+ throw new Error("Method 'validate()' must be implemented.");
41
40
  }
42
41
 
43
42
  isPayloadSchemaValid(payload) {
44
43
  if (!payload || !payload.type) {
45
- throw new SharedValidatorRejectionError(ResultCode.TX_INVALID_PAYLOAD, 'Payload or payload type is missing.');
44
+ throw new Error('Payload or payload type is missing.');
46
45
  }
47
46
 
48
47
  const selectedValidator = this.#selectCheckSchemaValidator(payload.type);
49
48
  const isPayloadValid = selectedValidator(payload);
50
49
  if (!isPayloadValid) {
51
- throw new SharedValidatorRejectionError(ResultCode.SCHEMA_VALIDATION_FAILED, 'Payload is invalid.');
50
+ throw new Error(`Payload is invalid.`);
52
51
  }
53
52
  }
54
53
 
@@ -65,24 +64,21 @@ class PartialOperationValidator {
65
64
  case OperationType.TRANSFER:
66
65
  return this.check.validateTransferOperation.bind(this.check);
67
66
  default:
68
- throw new SharedValidatorRejectionError(
69
- ResultCode.OPERATION_TYPE_UNKNOWN,
70
- `Unknown operation type: ${type}`
71
- );
67
+ throw new Error(`Unknown operation type: ${type}`);
72
68
  }
73
69
  }
74
70
 
75
71
  validateRequesterAddress(payload) {
76
72
  const incomingAddress = bufferToAddress(payload.address, this.#config.addressPrefix);
77
73
  if (!incomingAddress) {
78
- throw new SharedValidatorRejectionError(ResultCode.REQUESTER_ADDRESS_INVALID, 'Invalid requesting address in payload.');
74
+ throw new Error('Invalid requesting address in payload.');
79
75
  }
80
76
 
81
77
  const incomingPublicKey = PeerWallet.decodeBech32mSafe(incomingAddress);
82
78
 
83
79
  // TODO: We can add check if public key belongs to the Ed25519 curve. Validate signature already checks that but it would be amazing to catch it earlier.
84
80
  if (!incomingPublicKey || incomingPublicKey.length !== PUBLIC_KEY_LENGTH) {
85
- throw new SharedValidatorRejectionError(ResultCode.REQUESTER_PUBLIC_KEY_INVALID, 'Invalid requesting public key in payload.');
81
+ throw new Error('Invalid requesting public key in payload.');
86
82
  }
87
83
  }
88
84
 
@@ -131,10 +127,7 @@ class PartialOperationValidator {
131
127
  OperationType.TRANSFER
132
128
  ];
133
129
  default:
134
- throw new SharedValidatorRejectionError(
135
- ResultCode.OPERATION_TYPE_UNKNOWN,
136
- `Unknown operation type: ${payload.type}`
137
- );
130
+ throw new Error(`Unknown operation type: ${payload.type}`);
138
131
  }
139
132
  }
140
133
 
@@ -150,14 +143,11 @@ class PartialOperationValidator {
150
143
  const messageHash = await PeerWallet.blake3(message);
151
144
  const payloadHash = operation.tx;
152
145
  if (!b4a.equals(payloadHash, messageHash)) {
153
- throw new SharedValidatorRejectionError(
154
- ResultCode.TX_HASH_MISMATCH,
155
- 'Regenerated transaction does not match incoming transaction in payload.'
156
- );
146
+ throw new Error('Regenerated transaction does not match incoming transaction in payload.');
157
147
  }
158
148
 
159
149
  if (!PeerWallet.verify(incomingSignature, messageHash, incomingPublicKey)) {
160
- throw new SharedValidatorRejectionError(ResultCode.TX_SIGNATURE_INVALID, 'Invalid signature in payload.');
150
+ throw new Error('Invalid signature in payload.');
161
151
  }
162
152
  }
163
153
 
@@ -168,7 +158,7 @@ class PartialOperationValidator {
168
158
  const incomingTxv = operation.txv
169
159
 
170
160
  if (!b4a.equals(currentTxv, incomingTxv)) {
171
- throw new SharedValidatorRejectionError(ResultCode.TX_EXPIRED, 'Transaction has expired.');
161
+ throw new Error(`Transaction has expired.`);
172
162
  }
173
163
  }
174
164
 
@@ -179,10 +169,7 @@ class PartialOperationValidator {
179
169
  const txHex = tx.toString('hex');
180
170
 
181
171
  if (await this.state.get(txHex) !== null) {
182
- throw new SharedValidatorRejectionError(
183
- ResultCode.TX_ALREADY_EXISTS,
184
- `Transaction with hash ${txHex} already exists in the state.`
185
- );
172
+ throw new Error(`Transaction with hash ${txHex} already exists in the state.`);
186
173
  }
187
174
  }
188
175
 
@@ -193,10 +180,7 @@ class PartialOperationValidator {
193
180
 
194
181
  const condition = va === undefined && vn === undefined && vs === undefined
195
182
  if (!condition) {
196
- throw new SharedValidatorRejectionError(
197
- ResultCode.OPERATION_ALREADY_COMPLETED,
198
- 'Transfer operation must not be completed already (va, vn, vs must be undefined).'
199
- );
183
+ throw new Error('Transfer operation must not be completed already (va, vn, vs must be undefined).');
200
184
  }
201
185
  }
202
186
 
@@ -210,12 +194,12 @@ class PartialOperationValidator {
210
194
  }
211
195
 
212
196
  if (!requesterEntry) {
213
- throw new SharedValidatorRejectionError(ResultCode.REQUESTER_NOT_FOUND, 'Requester address not found in state');
197
+ throw new Error('Requester address not found in state');
214
198
  }
215
199
 
216
200
  const requesterBalance = bufferToBigInt(requesterEntry.balance);
217
201
  if (requesterBalance < FEE_BIGINT) {
218
- throw new SharedValidatorRejectionError(ResultCode.INSUFFICIENT_FEE_BALANCE, 'Insufficient balance to cover transaction fee.');
202
+ throw new Error('Insufficient balance to cover transaction fee.');
219
203
  }
220
204
  }
221
205
 
@@ -225,10 +209,7 @@ class PartialOperationValidator {
225
209
  const operation = payload[operationKey];
226
210
  const bs = operation.bs;
227
211
  if (b4a.equals(this.#config.bootstrap, bs)) {
228
- throw new SharedValidatorRejectionError(
229
- ResultCode.EXTERNAL_BOOTSTRAP_EQUALS_MSB_BOOTSTRAP,
230
- `External bootstrap is the same as MSB bootstrap: ${bs.toString('hex')}`
231
- );
212
+ throw new Error(`External bootstrap is the same as MSB bootstrap: ${bs.toString('hex')}`);
232
213
  }
233
214
  }
234
215
 
@@ -242,13 +223,10 @@ class PartialOperationValidator {
242
223
 
243
224
  const requesterAddress = bufferToAddress(payload.address, this.#config.addressPrefix);
244
225
  if (this.#selfAddress === requesterAddress) {
245
- throw new SharedValidatorRejectionError(
246
- ResultCode.SELF_VALIDATION_FORBIDDEN,
247
- 'Requester address cannot be the same as the validator wallet address.'
248
- );
226
+ throw new Error('Requester address cannot be the same as the validator wallet address.');
249
227
  }
250
228
  }
251
229
 
252
230
  }
253
231
 
254
- export default PartialOperationValidator;
232
+ export default PartialOperation;
@@ -1,99 +1,15 @@
1
- import { decodeV1networkOperation } from '../../../../utils/protobuf/operationHelpers.js'
2
- import b4a from 'b4a'
3
- import { NetworkOperationType, V1_PROTOCOL_PAYLOAD_MAX_SIZE } from '../../../../utils/constants.js'
4
- import { publicKeyToAddress } from '../../../../utils/helpers.js'
5
- import V1LivenessOperationHandler from './handlers/V1LivenessOperationHandler.js'
6
- import V1BroadcastTransactionOperationHandler from './handlers/V1BroadcastTransactionOperationHandler.js'
1
+ import { MessageHeader } from '../../../../utils/protobuf/network.cjs';
7
2
 
8
3
  class NetworkMessageRouterV1 {
9
- #config
10
- #livenessRequestHandler
11
- #broadcastTransactionHandler
4
+ #config;
12
5
 
13
- constructor(
14
- state,
15
- wallet,
16
- rateLimiterService,
17
- txPoolService,
18
- pendingRequestsService,
19
- transactionCommitService,
20
- config
21
- ) {
22
- this.#config = config
23
- this.#livenessRequestHandler = new V1LivenessOperationHandler(
24
- wallet,
25
- rateLimiterService,
26
- pendingRequestsService,
27
- config
28
- );
29
- this.#broadcastTransactionHandler = new V1BroadcastTransactionOperationHandler(
30
- state,
31
- wallet,
32
- rateLimiterService,
33
- txPoolService,
34
- pendingRequestsService,
35
- transactionCommitService,
36
- config
37
- );
6
+ constructor(config) {
7
+ this.#config = config;
38
8
  }
39
9
 
40
- async route(incomingMessage, connection) {
41
- if (!this.#preValidate(incomingMessage)) {
42
- this.#disconnect(connection, 'Pre-validation failed for incoming V1 message')
43
- return;
44
- }
45
- let decodedMessage;
46
-
47
- try {
48
- decodedMessage = decodeV1networkOperation(incomingMessage)
49
- } catch (error) {
50
- this.#disconnect(connection, `Failed to decode incoming V1 message: ${error.message}`)
51
- return;
52
- }
53
-
54
- // TODO: Decide if we really need to check decodedMessage.type here, since this is done
55
- // again in the next switch statement
56
- if (!decodedMessage || !Number.isInteger(decodedMessage.type) || decodedMessage.type <= 0) {
57
- this.#disconnect(connection, `Invalid V1 message type: ${decodedMessage?.type}`)
58
- return;
59
- }
60
-
61
- // We received a v1 message, so we set the connection protocol accordingly
62
- connection.protocolSession.setV1AsPreferredProtocol()
63
-
64
- try {
65
- switch (decodedMessage.type) {
66
- case NetworkOperationType.LIVENESS_REQUEST:
67
- await this.#livenessRequestHandler.handleRequest(decodedMessage, connection);
68
- break;
69
- case NetworkOperationType.LIVENESS_RESPONSE:
70
- await this.#livenessRequestHandler.handleResponse(decodedMessage, connection);
71
- break;
72
-
73
- case NetworkOperationType.BROADCAST_TRANSACTION_REQUEST:
74
- await this.#broadcastTransactionHandler.handleRequest(decodedMessage, connection);
75
- break;
76
-
77
- case NetworkOperationType.BROADCAST_TRANSACTION_RESPONSE:
78
- await this.#broadcastTransactionHandler.handleResponse(decodedMessage, connection);
79
- break;
80
- default:
81
- this.#disconnect(connection, `Unsupported V1 message type: ${decodedMessage.type}`)
82
- }
83
- } catch (error) {
84
- this.#disconnect(connection, `Unhandled error while routing V1 message: ${error.message}`)
85
- }
86
- }
87
-
88
- #preValidate(incomingMessage) {
89
- return !(!incomingMessage || !b4a.isBuffer(incomingMessage) || incomingMessage.length === 0 || incomingMessage.length > V1_PROTOCOL_PAYLOAD_MAX_SIZE);
90
- }
91
-
92
- #disconnect(connection, reason) {
93
- const sender = publicKeyToAddress(connection.remotePublicKey, this.#config)
94
- console.error(`NetworkMessageRouterV1: ${reason}, sender: ${sender}`)
95
- connection.end();
10
+ async route(incomingMessage) {
11
+ MessageHeader.decode(incomingMessage);
96
12
  }
97
13
  }
98
14
 
99
- export default NetworkMessageRouterV1
15
+ export default NetworkMessageRouterV1;