trac-msb 0.2.26 → 0.3.0-beta.2

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 (136) hide show
  1. package/SECURITY.md +2 -2
  2. package/cli/commandHandler.js +317 -20
  3. package/cli/handlers.js +9 -1
  4. package/cli/interactive.js +4 -3
  5. package/cli/tokenSupplyAudit.js +90 -0
  6. package/msb.mjs +1 -0
  7. package/package.json +15 -6
  8. package/rpc/create_server.js +12 -3
  9. package/rpc/handlers.js +121 -0
  10. package/rpc/routes/v1.js +12 -0
  11. package/src/codecs/apply/applyOperationCodec.js +334 -0
  12. package/src/codecs/apply/applyOperations.generated.cjs +6380 -0
  13. package/src/codecs/consensus/v1/consensusV1.generated.cjs +3508 -0
  14. package/src/codecs/consensus/v1/consensusV1OperationCodec.js +161 -0
  15. package/src/codecs/consensus/v1/vdfConfigCodec.js +83 -0
  16. package/src/{utils/protobuf → codecs/network/v1}/networkV1.generated.cjs +664 -393
  17. package/src/codecs/network/v1/networkV1OperationCodec.js +25 -0
  18. package/src/codecs/protobufRuntime.cjs +95 -0
  19. package/src/codecs/state/escrowEntryCodec.js +45 -0
  20. package/src/codecs/state/state.generated.cjs +659 -0
  21. package/src/config/args.js +0 -1
  22. package/src/config/config.js +41 -7
  23. package/src/config/env.js +33 -9
  24. package/src/core/consensus/epochAppenderSelection/EpochAppenderSelectionError.js +55 -0
  25. package/src/core/consensus/epochAppenderSelection/EpochAppenderSelectionOperations.js +118 -0
  26. package/src/core/consensus/epochAppenderSelection/EpochAppenderSelector.js +1042 -0
  27. package/src/core/consensus/epochAppenderSelection/createEpochAppenderSelector.js +23 -0
  28. package/src/core/consensus/epochAppenderSelection/epochAppenderSelectionLedgerReader.js +274 -0
  29. package/src/core/consensus/epochAppenderSelection/epochAppenderSelectionState.js +488 -0
  30. package/src/core/consensus/epochAppenderSelection/epochAppenderSelectionStorage.js +93 -0
  31. package/src/core/consensus/quorum.js +11 -0
  32. package/src/core/consensus/services/EpochCoordinationRound.js +839 -0
  33. package/src/core/consensus/services/EpochCoordinatorOperations.js +211 -0
  34. package/src/core/consensus/services/EpochCoordinatorService.js +335 -0
  35. package/src/core/consensus/services/EpochRoundListeners.js +116 -0
  36. package/src/core/consensus/services/EpochStateMachine.js +141 -0
  37. package/src/core/consensus/services/VDFBare.js +291 -0
  38. package/src/core/consensus/services/VDFNode.js +111 -0
  39. package/src/core/consensus/services/VDFProgressWatchdog.js +79 -0
  40. package/src/core/consensus/services/VDFService.js +87 -0
  41. package/src/core/consensus/services/VDFServiceManager.js +147 -0
  42. package/src/core/consensus/services/createVDFService.js +16 -0
  43. package/src/core/consensus/services/vdf-guardian.js +32 -0
  44. package/src/core/consensus/services/vdf-worker.js +90 -0
  45. package/src/core/network/Network.js +327 -238
  46. package/src/core/network/protocols/consensus/IndexerMessages.js +72 -0
  47. package/src/core/network/protocols/consensus/v1/ConsensusV1ConnectionPolicy.js +57 -0
  48. package/src/core/network/protocols/consensus/v1/ConsensusV1MessageRouter.js +147 -0
  49. package/src/core/network/protocols/consensus/v1/ConsensusV1Protocol.js +72 -0
  50. package/src/core/network/protocols/consensus/v1/IndexerPendingRequestService.js +108 -0
  51. package/src/core/network/protocols/consensus/v1/V1ConsensusProtocolError.js +29 -0
  52. package/src/core/network/protocols/consensus/v1/handlers/V1EpochAppendOperationHandler.js +68 -0
  53. package/src/core/network/protocols/consensus/v1/handlers/V1EpochProofProposalOperationHandler.js +226 -0
  54. package/src/core/network/protocols/consensus/v1/validators/ConsensusValidationSchema.js +192 -0
  55. package/src/core/network/protocols/consensus/v1/validators/V1BaseConsensusOperation.js +428 -0
  56. package/src/core/network/protocols/consensus/v1/validators/V1EpochAppendReply.js +47 -0
  57. package/src/core/network/protocols/consensus/v1/validators/V1EpochAppendRequest.js +17 -0
  58. package/src/core/network/protocols/consensus/v1/validators/V1EpochProofProposalApproval.js +116 -0
  59. package/src/core/network/protocols/consensus/v1/validators/V1EpochProofProposalRequest.js +152 -0
  60. package/src/core/network/protocols/consensus/v1/validators/consensusValidationSchemaHelpers.js +145 -0
  61. package/src/core/network/protocols/shared/ConnectionOperationHandler.js +27 -0
  62. package/src/core/network/protocols/{NetworkMessages.js → validators/ValidatorMessages.js} +24 -14
  63. package/src/core/network/protocols/{ProtocolSession.js → validators/ValidatorProtocolSession.js} +22 -25
  64. package/src/core/network/protocols/{legacy/NetworkMessageRouter.js → validators/legacy/ValidatorLegacyMessageRouter.js} +6 -6
  65. package/src/core/network/protocols/{LegacyProtocol.js → validators/legacy/ValidatorLegacyProtocol.js} +9 -7
  66. package/src/core/network/protocols/{legacy → validators/legacy}/handlers/BaseStateOperationHandler.js +1 -1
  67. package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyGetRequestHandler.js +5 -5
  68. package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyRoleOperationHandler.js +5 -5
  69. package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacySubnetworkOperationHandler.js +5 -5
  70. package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyTransferOperationHandler.js +5 -5
  71. package/src/core/network/protocols/{ProtocolInterface.js → validators/shared/ValidatorProtocolInterface.js} +5 -5
  72. package/src/core/network/protocols/{shared → validators/shared}/validators/PartialBootstrapDeploymentValidator.js +1 -1
  73. package/src/core/network/protocols/validators/shared/validators/PartialHtlcValidator.js +325 -0
  74. package/src/core/network/protocols/{shared → validators/shared}/validators/PartialOperationValidator.js +44 -21
  75. package/src/core/network/protocols/{shared → validators/shared}/validators/PartialRoleAccessValidator.js +3 -3
  76. package/src/core/network/protocols/{shared → validators/shared}/validators/PartialTransactionValidator.js +3 -3
  77. package/src/core/network/protocols/{shared → validators/shared}/validators/PartialTransferValidator.js +4 -4
  78. package/src/core/network/protocols/{v1 → validators/v1}/V1ProtocolError.js +1 -1
  79. package/src/core/network/{services/PendingRequestService.js → protocols/validators/v1/ValidatorPendingRequestService.js} +19 -82
  80. package/src/core/network/protocols/{v1/NetworkMessageRouter.js → validators/v1/ValidatorV1MessageRouter.js} +9 -9
  81. package/src/core/network/protocols/{V1Protocol.js → validators/v1/ValidatorV1Protocol.js} +10 -8
  82. package/src/core/network/protocols/{connectionPolicies.js → validators/v1/connectionPolicies.js} +1 -1
  83. package/src/core/network/protocols/{v1 → validators/v1}/handlers/V1BaseOperationHandler.js +6 -23
  84. package/src/core/network/protocols/{v1 → validators/v1}/handlers/V1BroadcastTransactionOperationHandler.js +14 -9
  85. package/src/core/network/protocols/{v1 → validators/v1}/handlers/V1LivenessOperationHandler.js +5 -4
  86. package/src/core/network/protocols/{v1 → validators/v1}/handlers/broadcastTransaction/BroadcastTransactionErrorMapper.js +3 -3
  87. package/src/core/network/protocols/{v1 → validators/v1}/handlers/broadcastTransaction/BroadcastTransactionOperationStrategies.js +44 -1
  88. package/src/core/network/protocols/{v1 → validators/v1}/handlers/broadcastTransaction/BroadcastTransactionPayloadUtils.js +1 -1
  89. package/src/core/network/protocols/{v1 → validators/v1}/validators/V1BaseOperation.js +19 -15
  90. package/src/core/network/protocols/{v1 → validators/v1}/validators/V1BroadcastTransactionRequest.js +2 -2
  91. package/src/core/network/protocols/{v1 → validators/v1}/validators/V1BroadcastTransactionResponse.js +34 -18
  92. package/src/core/network/protocols/{v1 → validators/v1}/validators/V1ValidationSchema.js +3 -3
  93. package/src/core/network/services/IndexerConnectionManager.js +88 -0
  94. package/src/core/network/services/TransactionPoolService.js +11 -18
  95. package/src/core/network/services/TransactionRateLimiterService.js +1 -1
  96. package/src/core/network/services/ValidatorConnectionManager.js +163 -0
  97. package/src/core/network/services/{MessageOrchestrator.js → ValidatorMessageOrchestrator.js} +34 -42
  98. package/src/core/network/services/ValidatorObserverService.js +21 -36
  99. package/src/core/network/shared/BasePendingRequestService.js +67 -0
  100. package/src/core/network/shared/PeerConnectionManager.js +185 -0
  101. package/src/core/state/State.js +1803 -159
  102. package/src/core/state/StateEventQueue.js +69 -0
  103. package/src/core/state/utils/address.js +10 -6
  104. package/src/core/state/utils/epochProof.js +109 -0
  105. package/src/core/state/utils/escrowEntry.js +178 -0
  106. package/src/core/state/validators/StateValidationSchema.js +757 -0
  107. package/src/core/state/validators/stateValidationRules.js +312 -0
  108. package/src/index.js +280 -67
  109. package/src/messages/consensus/v1/ConsensusMessageBuilder.js +368 -0
  110. package/src/messages/consensus/v1/ConsensusMessageDirector.js +142 -0
  111. package/src/messages/consensus/v1/consensusMessageFactory.js +12 -0
  112. package/src/messages/consensus/v1/epochAppendMessage.js +58 -0
  113. package/src/messages/network/v1/NetworkMessageBuilder.js +15 -7
  114. package/src/messages/state/ApplyStateMessageBuilder.js +499 -13
  115. package/src/messages/state/ApplyStateMessageDirector.js +261 -2
  116. package/src/utils/StateMachine.js +125 -0
  117. package/src/utils/applyOperations.js +45 -2
  118. package/src/utils/buffer.js +239 -59
  119. package/src/utils/consensusConfig.js +76 -0
  120. package/src/utils/constants.js +174 -73
  121. package/src/utils/helpers.js +0 -25
  122. package/src/utils/htlcLock.js +122 -0
  123. package/src/utils/logger.js +10 -4
  124. package/src/utils/migrationUtils.js +2 -1
  125. package/src/utils/normalizers.js +113 -0
  126. package/src/utils/scheduler/SchedulableService.js +107 -0
  127. package/src/utils/{Scheduler.js → scheduler/Scheduler.js} +56 -17
  128. package/src/core/network/services/ConnectionManager.js +0 -406
  129. package/src/utils/check.js +0 -525
  130. package/src/utils/protobuf/applyOperations.cjs +0 -1373
  131. package/src/utils/protobuf/operationHelpers.js +0 -81
  132. /package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyResponseHandler.js +0 -0
  133. /package/src/core/network/protocols/{legacy → validators/legacy}/validators/ValidatorResponse.js +0 -0
  134. /package/src/core/network/protocols/{legacy → validators/legacy}/validators/base/BaseResponse.js +0 -0
  135. /package/src/core/network/protocols/{v1 → validators/v1}/validators/V1LivenessRequest.js +0 -0
  136. /package/src/core/network/protocols/{v1 → validators/v1}/validators/V1LivenessResponse.js +0 -0
@@ -1,33 +1,27 @@
1
- import {NetworkOperationType, ResultCode} from '../../../utils/constants.js';
2
- import {isHexString, publicKeyToAddress} from '../../../utils/helpers.js';
3
- import {V1ProtocolError} from "../protocols/v1/V1ProtocolError.js";
1
+ import {NetworkOperationType, PEER_PUBLIC_KEY_HEX_LENGTH, ResultCode} from '../../../../../utils/constants.js';
2
+ import {isHexString, publicKeyToAddress} from '../../../../../utils/helpers.js';
3
+ import {V1ProtocolError} from "./V1ProtocolError.js";
4
4
  import b4a from 'b4a';
5
+ import BasePendingRequestService from '../../../shared/BasePendingRequestService.js';
5
6
 
6
- const PEER_PUBLIC_KEY_HEX_LENGTH = 64;
7
-
8
- export class PendingRequestServiceTimeoutError extends Error {
7
+ export class ValidatorPendingRequestServiceTimeoutError extends Error {
9
8
  constructor(requestId, peerAddress, timeoutMs) {
10
9
  super(`Pending request ${requestId} to peer ${peerAddress} timed out after ${timeoutMs} ms.`);
11
10
  this.name = this.constructor.name;
12
11
  }
13
12
  }
14
13
 
15
- export default class PendingRequestService {
16
- #pendingRequests;
14
+ export default class ValidatorPendingRequestService extends BasePendingRequestService {
17
15
  #requestMessageTypes = [NetworkOperationType.LIVENESS_REQUEST, NetworkOperationType.BROADCAST_TRANSACTION_REQUEST];
18
16
  #config;
19
17
 
20
18
  constructor(config) {
21
- this.#pendingRequests = new Map(); // Map<id, pendingRequestEntry>
19
+ super();
22
20
  this.#config = config;
23
21
  }
24
22
 
25
- has(id) {
26
- return this.#pendingRequests.has(id);
27
- }
28
-
29
23
  isProbePending(peerPubKeyHex) {
30
- for (const [, entry] of this.#pendingRequests) {
24
+ for (const [, entry] of this._pendingRequests) {
31
25
  if (entry.requestedTo === peerPubKeyHex && entry.requestType === NetworkOperationType.LIVENESS_REQUEST) {
32
26
  return true;
33
27
  }
@@ -40,15 +34,11 @@ export default class PendingRequestService {
40
34
  throw new Error('Invalid peer public key. Expected 32-byte hex string.');
41
35
  }
42
36
 
43
- if (!message || typeof message !== 'object') {
44
- throw new Error('Pending request message must be an object.');
45
- }
46
-
47
- if (typeof message.id !== 'string' || message.id.length === 0) {
37
+ if (typeof message?.id !== 'string' || message?.id.length === 0) {
48
38
  throw new Error('Pending request ID must be a non-empty string.');
49
39
  }
50
40
 
51
- if (!this.#requestMessageTypes.includes(message.type)) {
41
+ if (!this.#requestMessageTypes.includes(message?.type)) {
52
42
  throw new Error('Unsupported pending request type.');
53
43
  }
54
44
  }
@@ -60,11 +50,11 @@ export default class PendingRequestService {
60
50
  this.#validateRegisterInput(peerPubKeyHex, message);
61
51
  const id = message.id;
62
52
  const peerAddress = publicKeyToAddress(peerPubKeyHex, this.#config);
63
- if (this.#pendingRequests.size >= this.#config.maxPendingRequestsInPendingRequestsService) {
53
+ if (this._pendingRequests.size >= this.#config.maxPendingRequestsInPendingRequestsService) {
64
54
  throw new Error('Maximum number of pending requests reached.');
65
55
  }
66
56
 
67
- if (this.#pendingRequests.has(id)) {
57
+ if (this._pendingRequests.has(id)) {
68
58
  throw new Error(`Pending request with ID ${id} from peer ${peerPubKeyHex} already exists.`);
69
59
  }
70
60
 
@@ -86,7 +76,7 @@ export default class PendingRequestService {
86
76
  entry.timeoutId = setTimeout(() => {
87
77
  this.rejectPendingRequest(
88
78
  id,
89
- new PendingRequestServiceTimeoutError(
79
+ new ValidatorPendingRequestServiceTimeoutError(
90
80
  id,
91
81
  peerAddress,
92
82
  this.#config.pendingRequestTimeout
@@ -95,7 +85,7 @@ export default class PendingRequestService {
95
85
 
96
86
  }, this.#config.pendingRequestTimeout);
97
87
 
98
- this.#pendingRequests.set(id, entry);
88
+ this._pendingRequests.set(id, entry);
99
89
  return promise;
100
90
  }
101
91
 
@@ -105,21 +95,6 @@ export default class PendingRequestService {
105
95
  return b4a.isBuffer(txData) ? txData : null;
106
96
  }
107
97
 
108
- getAndDeletePendingRequest(id) {
109
- const entry = this.#pendingRequests.get(id);
110
- if (!entry) return null;
111
-
112
- clearTimeout(entry.timeoutId);
113
- this.#pendingRequests.delete(id);
114
- return entry;
115
- }
116
-
117
- getPendingRequest(id) {
118
- const entry = this.#pendingRequests.get(id);
119
- if (!entry) return null;
120
- return entry;
121
- }
122
-
123
98
  // for now, we are resolving only resultCode, but we can extend it in the future if needed...
124
99
  resolvePendingRequest(id, resultCode = ResultCode.OK) {
125
100
  const entry = this.getAndDeletePendingRequest(id);
@@ -128,48 +103,10 @@ export default class PendingRequestService {
128
103
  return true;
129
104
  }
130
105
 
131
- rejectPendingRequest(id, error) {
132
- const entry = this.getAndDeletePendingRequest(id);
133
- if (!entry) return false;
134
- entry.reject(error instanceof Error ? error : new Error(error?.message ?? 'Unexpected error'));
135
- return true;
136
- }
137
-
138
- rejectPendingRequestsForPeer(peerPubKeyHex, error) {
139
- const idsToReject = [];
140
- for (const [id, entry] of this.#pendingRequests) {
141
- if (entry.requestedTo === peerPubKeyHex) idsToReject.push(id);
142
- }
143
-
144
- for (const id of idsToReject) {
145
- this.rejectPendingRequest(id, error);
146
- }
147
-
148
- return idsToReject.length;
149
- }
150
-
151
- stopPendingRequestTimeout(id) {
152
- const entry = this.#pendingRequests.get(id);
153
- if (!entry) return false;
154
-
155
- clearTimeout(entry.timeoutId);
156
- entry.timeoutId = null;
157
- return true;
158
- }
159
-
160
- close() {
161
- for (const [id, entry] of this.#pendingRequests) {
162
- clearTimeout(entry.timeoutId);
163
- try {
164
- entry.reject(
165
- new V1ProtocolError(
166
- ResultCode.UNEXPECTED_ERROR,
167
- `Pending request ${id} cancelled (shutdown).`)
168
- );
169
- } catch (error) {
170
- console.error(`PendingRequestService.close: failed to reject pending request ${id}:`, error);
171
- }
172
- }
173
- this.#pendingRequests.clear();
106
+ _createShutdownError(id) {
107
+ return new V1ProtocolError(
108
+ ResultCode.UNEXPECTED_ERROR,
109
+ `Pending request ${id} cancelled (shutdown).`
110
+ );
174
111
  }
175
112
  }
@@ -1,11 +1,11 @@
1
- import { decodeV1networkOperation } from '../../../../utils/protobuf/operationHelpers.js'
1
+ import { decodeV1networkOperation } from '../../../../../codecs/network/v1/networkV1OperationCodec.js'
2
2
  import b4a from 'b4a'
3
- import { NetworkOperationType, V1_PROTOCOL_PAYLOAD_MAX_SIZE } from '../../../../utils/constants.js'
4
- import { publicKeyToAddress } from '../../../../utils/helpers.js'
3
+ import { NetworkOperationType, V1_PROTOCOL_PAYLOAD_MAX_SIZE } from '../../../../../utils/constants.js'
4
+ import { publicKeyToAddress } from '../../../../../utils/helpers.js'
5
5
  import V1LivenessOperationHandler from './handlers/V1LivenessOperationHandler.js'
6
6
  import V1BroadcastTransactionOperationHandler from './handlers/V1BroadcastTransactionOperationHandler.js'
7
7
 
8
- class NetworkMessageRouterV1 {
8
+ class ValidatorV1MessageRouter {
9
9
  #config
10
10
  #livenessRequestHandler
11
11
  #broadcastTransactionHandler
@@ -59,19 +59,19 @@ class NetworkMessageRouterV1 {
59
59
  }
60
60
 
61
61
  // We received a v1 message, so we set the connection protocol accordingly
62
- connection.protocolSession.setV1AsPreferredProtocol()
62
+ connection.protocolSessions.validator.setV1AsPreferredProtocol()
63
63
 
64
64
  try {
65
65
  switch (decodedMessage.type) {
66
66
  case NetworkOperationType.LIVENESS_REQUEST:
67
- await this.#livenessRequestHandler.handleRequest(decodedMessage, connection);
67
+ await this.#livenessRequestHandler.handleRequest(decodedMessage, connection, connection.protocolSessions.validator);
68
68
  break;
69
69
  case NetworkOperationType.LIVENESS_RESPONSE:
70
70
  await this.#livenessRequestHandler.handleResponse(decodedMessage, connection);
71
71
  break;
72
72
 
73
73
  case NetworkOperationType.BROADCAST_TRANSACTION_REQUEST:
74
- await this.#broadcastTransactionHandler.handleRequest(decodedMessage, connection);
74
+ await this.#broadcastTransactionHandler.handleRequest(decodedMessage, connection, connection.protocolSessions.validator);
75
75
  break;
76
76
 
77
77
  case NetworkOperationType.BROADCAST_TRANSACTION_RESPONSE:
@@ -91,9 +91,9 @@ class NetworkMessageRouterV1 {
91
91
 
92
92
  #disconnect(connection, reason) {
93
93
  const sender = publicKeyToAddress(connection.remotePublicKey, this.#config)
94
- console.error(`NetworkMessageRouterV1: ${reason}, sender: ${sender}`)
94
+ console.error(`ValidatorV1MessageRouter: ${reason}, sender: ${sender}`)
95
95
  connection.end();
96
96
  }
97
97
  }
98
98
 
99
- export default NetworkMessageRouterV1
99
+ export default ValidatorV1MessageRouter
@@ -1,9 +1,9 @@
1
1
  import Protomux from 'protomux';
2
- import ProtocolInterface from './ProtocolInterface.js';
2
+ import ValidatorProtocolInterface from '../shared/ValidatorProtocolInterface.js';
3
3
  import c from 'compact-encoding';
4
- import {encodeV1networkOperation, decodeV1networkOperation} from '../../../utils/protobuf/operationHelpers.js';
4
+ import { encodeV1networkOperation, decodeV1networkOperation } from '../../../../../codecs/network/v1/networkV1OperationCodec.js';
5
5
 
6
- class V1Protocol extends ProtocolInterface {
6
+ class ValidatorV1Protocol extends ValidatorProtocolInterface {
7
7
  #channel;
8
8
  #session;
9
9
  #router;
@@ -38,13 +38,15 @@ class V1Protocol extends ProtocolInterface {
38
38
  }
39
39
  });
40
40
 
41
+ if (!this.#channel) return; // connection already destroyed before protocol setup completed
42
+
41
43
  this.#channel.open();
42
44
 
43
45
  this.#session = this.#channel.addMessage({
44
46
  encoding: c.raw,
45
47
  onmessage: (incomingMessage) => {
46
48
  this.#router.route(incomingMessage, connection).catch((err) => {
47
- console.error(`V1Protocol: unhandled router error: ${err.message}`);
49
+ console.error(`ValidatorV1Protocol: unhandled router error: ${err.message}`);
48
50
  try {
49
51
  connection.end();
50
52
  } catch {
@@ -55,7 +57,7 @@ class V1Protocol extends ProtocolInterface {
55
57
  }
56
58
 
57
59
  // 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
60
+ // NOTE: This method might be moved to v1/ValidatorLegacyMessageRouter.js as it is only used there
59
61
  decode(message) {
60
62
  return decodeV1networkOperation(message);
61
63
  }
@@ -72,12 +74,12 @@ class V1Protocol extends ProtocolInterface {
72
74
  }
73
75
 
74
76
  sendAndForget(message) {
75
- this.#session.send(encodeV1networkOperation(message));
77
+ this.#session?.send(encodeV1networkOperation(message));
76
78
  }
77
79
 
78
80
  close() {
79
- this.#channel.close();
81
+ this.#channel?.close();
80
82
  }
81
83
  }
82
84
 
83
- export default V1Protocol;
85
+ export default ValidatorV1Protocol;
@@ -1,4 +1,4 @@
1
- import { ResultCode } from '../../../utils/constants.js';
1
+ import { ResultCode } from '../../../../../utils/constants.js';
2
2
 
3
3
  // TODO: Consider how to behave with ResultCode.UNSPECIFIED
4
4
 
@@ -1,30 +1,26 @@
1
- import {ResultCode} from "../../../../../utils/constants.js";
2
- import {publicKeyToAddress} from "../../../../../utils/helpers.js";
1
+ import {ResultCode} from "../../../../../../utils/constants.js";
3
2
  import {V1ProtocolError} from "../V1ProtocolError.js";
3
+ import ConnectionOperationHandler from "../../../shared/ConnectionOperationHandler.js";
4
4
 
5
- class V1BaseOperationHandler {
5
+ class V1BaseOperationHandler extends ConnectionOperationHandler{
6
6
  #rateLimiterService;
7
7
  #pendingRequestService;
8
- #config;
9
-
10
8
  constructor(rateLimiterService, pendingRequestService, config) {
9
+ super(config);
11
10
  this.#rateLimiterService = rateLimiterService;
12
11
  this.#pendingRequestService = pendingRequestService;
13
- this.#config = config;
14
12
  }
15
13
 
16
- get config() {
17
- return this.#config;
18
- }
19
14
 
20
15
  applyRateLimit(connection) {
21
- if (!this.#config.disableRateLimit) {
16
+ if (!this.config.disableRateLimit) {
22
17
  this.#rateLimiterService.v1HandleRateLimit(connection);
23
18
  }
24
19
  }
25
20
 
26
21
  async resolvePendingResponse(message, connection, validator, extractResultCode) {
27
22
  const pendingRequestServiceEntry = this.#pendingRequestService.getPendingRequest(message.id);
23
+ //TODO: Investigate if this return false shouldn't be a throw.
28
24
  if (!pendingRequestServiceEntry) return false;
29
25
 
30
26
  this.#pendingRequestService.stopPendingRequestTimeout(message.id);
@@ -42,19 +38,6 @@ class V1BaseOperationHandler {
42
38
  this.displayError(step, connection.remotePublicKey, protocolError);
43
39
  }
44
40
 
45
- async sendResponseAndMaybeClose(connection, response, endConnection) {
46
- connection.protocolSession.sendAndForget(response);
47
- if (!endConnection) return;
48
-
49
- await connection.flush();
50
- connection.end();
51
- }
52
-
53
- displayError(step = "undefined step", senderPublicKey, error) {
54
- const errorMessage = error?.message ?? 'Unexpected error';
55
- console.error(`${this.constructor.name}: ${step} ${publicKeyToAddress(senderPublicKey, this.#config)}: ${errorMessage}`);
56
- }
57
-
58
41
  #toProtocolError(error) {
59
42
  if (error instanceof V1ProtocolError) {
60
43
  return error;
@@ -1,8 +1,8 @@
1
- import {networkMessageFactory} from "../../../../../messages/network/v1/networkMessageFactory.js";
1
+ import {networkMessageFactory} from "../../../../../../messages/network/v1/networkMessageFactory.js";
2
2
  import {
3
3
  NETWORK_CAPABILITIES,
4
4
  ResultCode
5
- } from "../../../../../utils/constants.js";
5
+ } from "../../../../../../utils/constants.js";
6
6
  import {
7
7
  getResultCode,
8
8
  V1ProtocolError
@@ -11,12 +11,13 @@ import V1BroadcastTransactionRequest from "../validators/V1BroadcastTransactionR
11
11
  import {
12
12
  unsafeDecodeApplyOperation,
13
13
  unsafeEncodeApplyOperation
14
- } from "../../../../../utils/protobuf/operationHelpers.js";
14
+ } from "../../../../../../codecs/apply/applyOperationCodec.js";
15
15
  import PartialRoleAccessValidator from "../../shared/validators/PartialRoleAccessValidator.js";
16
16
  import PartialBootstrapDeploymentValidator from "../../shared/validators/PartialBootstrapDeploymentValidator.js";
17
17
  import PartialTransactionValidator from "../../shared/validators/PartialTransactionValidator.js";
18
18
  import PartialTransferValidator from "../../shared/validators/PartialTransferValidator.js";
19
- import {applyStateMessageFactory} from "../../../../../messages/state/applyStateMessageFactory.js";
19
+ import PartialHtlcValidator from '../../shared/validators/PartialHtlcValidator.js';
20
+ import {applyStateMessageFactory} from "../../../../../../messages/state/applyStateMessageFactory.js";
20
21
  import V1BroadcastTransactionResponse from "../validators/V1BroadcastTransactionResponse.js";
21
22
  import V1BaseOperationHandler from "./V1BaseOperationHandler.js";
22
23
  import {
@@ -33,7 +34,7 @@ import {
33
34
  mapTransactionEnqueueError,
34
35
  mapTxPoolAvailabilityError
35
36
  } from "./broadcastTransaction/BroadcastTransactionErrorMapper.js";
36
- import {shouldEndConnection} from "../../connectionPolicies.js";
37
+ import {shouldEndConnection} from "../connectionPolicies.js";
37
38
 
38
39
  class V1BroadcastTransactionOperationHandler extends V1BaseOperationHandler {
39
40
  #state;
@@ -47,6 +48,7 @@ class V1BroadcastTransactionOperationHandler extends V1BaseOperationHandler {
47
48
  #partialTransferValidator;
48
49
  #transactionCommitService;
49
50
  #operationStrategies;
51
+ #partialHtlcValidator;
50
52
 
51
53
  constructor(state, wallet, rateLimiterService, txPoolService, pendingRequestService, transactionCommitService, config) {
52
54
  super(rateLimiterService, pendingRequestService, config);
@@ -58,6 +60,7 @@ class V1BroadcastTransactionOperationHandler extends V1BaseOperationHandler {
58
60
  this.#partialBootstrapDeploymentValidator = new PartialBootstrapDeploymentValidator(state, this.#wallet.address, config);
59
61
  this.#partialTransactionValidator = new PartialTransactionValidator(state, this.#wallet.address, config);
60
62
  this.#partialTransferValidator = new PartialTransferValidator(state, this.#wallet.address, config);
63
+ this.#partialHtlcValidator = new PartialHtlcValidator(state, this.#wallet.address, config);
61
64
  this.#broadcastTransactionResponseValidator = new V1BroadcastTransactionResponse(state, config);
62
65
  this.#transactionCommitService = transactionCommitService;
63
66
  this.#operationStrategies = createBroadcastTransactionOperationStrategies({
@@ -65,13 +68,14 @@ class V1BroadcastTransactionOperationHandler extends V1BaseOperationHandler {
65
68
  partialBootstrapDeploymentValidator: this.#partialBootstrapDeploymentValidator,
66
69
  partialTransactionValidator: this.#partialTransactionValidator,
67
70
  partialTransferValidator: this.#partialTransferValidator,
71
+ partialHtlcValidator: this.#partialHtlcValidator,
68
72
  createApplyStateMessageFactory: () => applyStateMessageFactory(this.#wallet, this.config)
69
73
  });
70
74
  }
71
75
 
72
- async handleRequest(message, connection) {
76
+ async handleRequest(message, connection, protocolSession) {
73
77
  const outcome = await this.#processBroadcastTransactionRequest(message, connection);
74
- await this.#sendBroadcastTransactionResponse(message.id, connection, outcome);
78
+ await this.#sendBroadcastTransactionResponse(message.id, connection, protocolSession, outcome);
75
79
  }
76
80
 
77
81
  async handleResponse(message, connection) {
@@ -111,7 +115,7 @@ class V1BroadcastTransactionOperationHandler extends V1BaseOperationHandler {
111
115
  try {
112
116
  return unsafeDecodeApplyOperation(message);
113
117
  } catch (error) {
114
- throw new V1ProtocolError(ResultCode.UNEXPECTED_ERROR, `Failed to decode apply operation from message: ${error.message}`);
118
+ throw new V1ProtocolError(ResultCode.TX_INVALID_PAYLOAD, `Failed to decode apply operation from message: ${error.message}`);
115
119
  }
116
120
  }
117
121
 
@@ -170,7 +174,7 @@ class V1BroadcastTransactionOperationHandler extends V1BaseOperationHandler {
170
174
  };
171
175
  }
172
176
 
173
- async #sendBroadcastTransactionResponse(messageId, connection, {proof, timestamp, resultCode, endConnection}) {
177
+ async #sendBroadcastTransactionResponse(messageId, connection, protocolSession, {proof, timestamp, resultCode, endConnection}) {
174
178
  try {
175
179
  const response = await this.#buildBroadcastTransactionResponse(
176
180
  messageId,
@@ -181,6 +185,7 @@ class V1BroadcastTransactionOperationHandler extends V1BaseOperationHandler {
181
185
  );
182
186
 
183
187
  await this.sendResponseAndMaybeClose(
188
+ protocolSession,
184
189
  connection,
185
190
  response,
186
191
  endConnection
@@ -1,10 +1,10 @@
1
- import {networkMessageFactory} from "../../../../../messages/network/v1/networkMessageFactory.js";
2
- import {NETWORK_CAPABILITIES, ResultCode} from "../../../../../utils/constants.js";
1
+ import {networkMessageFactory} from "../../../../../../messages/network/v1/networkMessageFactory.js";
2
+ import {NETWORK_CAPABILITIES, ResultCode} from "../../../../../../utils/constants.js";
3
3
  import V1LivenessRequest from "../validators/V1LivenessRequest.js";
4
4
  import {getResultCode, V1ProtocolError} from "../V1ProtocolError.js";
5
5
  import V1LivenessResponse from "../validators/V1LivenessResponse.js";
6
6
  import V1BaseOperationHandler from "./V1BaseOperationHandler.js";
7
- import {shouldEndConnection} from "../../connectionPolicies.js"
7
+ import {shouldEndConnection} from "../connectionPolicies.js"
8
8
 
9
9
  class V1LivenessOperationHandler extends V1BaseOperationHandler {
10
10
  #wallet;
@@ -18,7 +18,7 @@ class V1LivenessOperationHandler extends V1BaseOperationHandler {
18
18
  this.#v1LivenessResponseValidator = new V1LivenessResponse(config);
19
19
  }
20
20
 
21
- async handleRequest(message, connection) {
21
+ async handleRequest(message, connection, protocolSession) {
22
22
  let resultCode = ResultCode.OK;
23
23
  let endConnection = false;
24
24
  try {
@@ -36,6 +36,7 @@ class V1LivenessOperationHandler extends V1BaseOperationHandler {
36
36
  try {
37
37
  const response = await this.#buildLivenessResponsePayload(message.id, NETWORK_CAPABILITIES, resultCode);
38
38
  await this.sendResponseAndMaybeClose(
39
+ protocolSession,
39
40
  connection,
40
41
  response,
41
42
  endConnection
@@ -1,4 +1,4 @@
1
- import {ResultCode} from "../../../../../../utils/constants.js";
1
+ import {ResultCode} from "../../../../../../../utils/constants.js";
2
2
  import {V1ProtocolError} from "../../V1ProtocolError.js";
3
3
  import {
4
4
  TransactionPoolAlreadyQueuedError,
@@ -6,13 +6,13 @@ import {
6
6
  TransactionPoolInvalidIncomingDataError,
7
7
  TransactionPoolMissingCommitReceiptError,
8
8
  TransactionPoolProofUnavailableError
9
- } from "../../../../services/TransactionPoolService.js";
9
+ } from "../../../../../services/TransactionPoolService.js";
10
10
  import {
11
11
  PendingCommitAlreadyExistsError,
12
12
  PendingCommitBufferFullError,
13
13
  PendingCommitInvalidTxHashError,
14
14
  PendingCommitTimeoutError
15
- } from "../../../../services/TransactionCommitService.js";
15
+ } from "../../../../../services/TransactionCommitService.js";
16
16
 
17
17
  export function mapTxPoolAvailabilityError(error) {
18
18
  if (error instanceof TransactionPoolFullError) {
@@ -1,4 +1,4 @@
1
- import {OperationType, ResultCode} from "../../../../../../utils/constants.js";
1
+ import {OperationType, ResultCode} from "../../../../../../../utils/constants.js";
2
2
  import {V1ProtocolError} from "../../V1ProtocolError.js";
3
3
 
4
4
  function createOperationStrategy(payloadKey, validator, buildCompleteOperation) {
@@ -16,6 +16,7 @@ export function createBroadcastTransactionOperationStrategies({
16
16
  partialBootstrapDeploymentValidator,
17
17
  partialTransactionValidator,
18
18
  partialTransferValidator,
19
+ partialHtlcValidator,
19
20
  createApplyStateMessageFactory
20
21
  }) {
21
22
  return new Map([
@@ -113,6 +114,48 @@ export function createBroadcastTransactionOperationStrategies({
113
114
  decodedTransaction.tro.is
114
115
  )
115
116
  )
117
+ ],
118
+ [
119
+ OperationType.HTLC_LOCK,
120
+ createOperationStrategy(
121
+ 'hlo',
122
+ partialHtlcValidator,
123
+ decodedOperation => createApplyStateMessageFactory().buildCompleteHtlcLockOperationMessage(
124
+ decodedOperation.address,
125
+ decodedOperation.hlo
126
+ )
127
+ )
128
+ ],
129
+ [
130
+ OperationType.HTLC_CLAIM,
131
+ createOperationStrategy(
132
+ 'hco',
133
+ partialHtlcValidator,
134
+ decodedOperation => createApplyStateMessageFactory().buildCompleteHtlcClaimOperationMessage(
135
+ decodedOperation.address,
136
+ decodedOperation.hco.tx,
137
+ decodedOperation.hco.txv,
138
+ decodedOperation.hco.li,
139
+ decodedOperation.hco.pi,
140
+ decodedOperation.hco.in,
141
+ decodedOperation.hco.is
142
+ )
143
+ )
144
+ ],
145
+ [
146
+ OperationType.HTLC_REFUND,
147
+ createOperationStrategy(
148
+ 'hro',
149
+ partialHtlcValidator,
150
+ decodedOperation => createApplyStateMessageFactory().buildCompleteHtlcRefundOperationMessage(
151
+ decodedOperation.address,
152
+ decodedOperation.hro.tx,
153
+ decodedOperation.hro.txv,
154
+ decodedOperation.hro.li,
155
+ decodedOperation.hro.in,
156
+ decodedOperation.hro.is
157
+ )
158
+ )
116
159
  ]
117
160
  ]);
118
161
  }
@@ -1,6 +1,6 @@
1
1
  import b4a from "b4a";
2
2
 
3
- import { operationToPayload } from "../../../../../../utils/applyOperations.js";
3
+ import { operationToPayload } from "../../../../../../../utils/applyOperations.js";
4
4
 
5
5
  const COMPLETION_FIELDS = ['va', 'vn', 'vs'];
6
6
 
@@ -1,14 +1,14 @@
1
1
  import V1ValidationSchema from "./V1ValidationSchema.js";
2
- import {NetworkOperationType, ResultCode} from "../../../../../utils/constants.js";
2
+ import {NetworkOperationType, ResultCode} from "../../../../../../utils/constants.js";
3
3
  import tracCryptoApi from "trac-crypto-api";
4
4
  import b4a from "b4a";
5
5
  import {
6
6
  createMessage,
7
7
  encodeCapabilities,
8
8
  idToBuffer,
9
- safeWriteUInt32BE,
10
- timestampToBuffer
11
- } from "../../../../../utils/buffer.js";
9
+ timestampToBuffer,
10
+ uint32ToBuffer
11
+ } from "../../../../../../utils/buffer.js";
12
12
  import {
13
13
  V1ProtocolError,
14
14
  } from "../V1ProtocolError.js";
@@ -33,7 +33,7 @@ class V1BaseOperation {
33
33
  const selectedValidator = this.#selectCheckSchemaValidator(payload.type);
34
34
  const isPayloadValid = selectedValidator(payload);
35
35
  if (!isPayloadValid) {
36
- throw new V1ProtocolError(ResultCode.INVALID_PAYLOAD, 'Payload is invalid.');
36
+ throw new V1ProtocolError(ResultCode.SCHEMA_VALIDATION_FAILED, 'Payload is invalid.');
37
37
  }
38
38
  }
39
39
 
@@ -48,14 +48,18 @@ class V1BaseOperation {
48
48
  if (error instanceof V1ProtocolError) {
49
49
  throw error;
50
50
  }
51
- throw new V1ProtocolError(ResultCode.INVALID_PAYLOAD, `Failed to build signature message: ${error.message}`);
51
+ throw new V1ProtocolError(ResultCode.UNEXPECTED_ERROR, `Failed to build signature message: ${error.message}`);
52
+ }
53
+
54
+ if (!remotePublicKey) {
55
+ throw new V1ProtocolError(ResultCode.UNEXPECTED_ERROR, 'Remote public key is missing.');
52
56
  }
53
57
 
54
58
  let hash;
55
59
  try {
56
60
  hash = await tracCryptoApi.hash.blake3(message);
57
61
  } catch {
58
- throw new V1ProtocolError(ResultCode.INVALID_PAYLOAD, 'Failed to hash signature message.');
62
+ throw new V1ProtocolError(ResultCode.UNEXPECTED_ERROR, 'Failed to hash signature message.');
59
63
  }
60
64
 
61
65
  let verified = false;
@@ -71,10 +75,10 @@ class V1BaseOperation {
71
75
 
72
76
  #buildSignatureMessage(payload) {
73
77
  if (!Number.isInteger(payload.type)) {
74
- throw new V1ProtocolError(ResultCode.INVALID_PAYLOAD, 'Operation type must be an integer.');
78
+ throw new V1ProtocolError(ResultCode.OPERATION_TYPE_UNKNOWN, 'Operation type must be an integer.');
75
79
  }
76
80
  if (payload.type === 0) {
77
- throw new V1ProtocolError(ResultCode.INVALID_PAYLOAD, 'Operation type is unspecified.');
81
+ throw new V1ProtocolError(ResultCode.OPERATION_TYPE_UNKNOWN, 'Operation type is unspecified.');
78
82
  }
79
83
 
80
84
  const idBuf = idToBuffer(payload.id);
@@ -92,7 +96,7 @@ class V1BaseOperation {
92
96
  const nonce = payload.liveness_response.nonce;
93
97
  const signature = payload.liveness_response.signature;
94
98
  const result = payload.liveness_response.result;
95
- const message = createMessage(payload.type, idBuf, tsBuf, nonce, safeWriteUInt32BE(result, 0), capsBuf);
99
+ const message = createMessage(payload.type, idBuf, tsBuf, nonce, uint32ToBuffer(result), capsBuf);
96
100
  return {signature, message};
97
101
  }
98
102
  case NetworkOperationType.BROADCAST_TRANSACTION_REQUEST: {
@@ -140,23 +144,23 @@ class V1BaseOperation {
140
144
  nonce,
141
145
  proof,
142
146
  timestampToBuffer(timestamp),
143
- safeWriteUInt32BE(result, 0),
147
+ uint32ToBuffer(result),
144
148
  capsBuf
145
149
  );
146
150
 
147
151
  return {signature, message};
148
152
  }
149
153
  default:
150
- throw new V1ProtocolError(ResultCode.UNEXPECTED_ERROR, `Unknown operation type: ${payload.type}`);
154
+ throw new V1ProtocolError(ResultCode.OPERATION_TYPE_UNKNOWN, `Unknown operation type: ${payload.type}`);
151
155
  }
152
156
  }
153
157
 
154
158
  #selectCheckSchemaValidator(type) {
155
159
  if (!Number.isInteger(type)) {
156
- throw new V1ProtocolError(ResultCode.INVALID_PAYLOAD, 'Operation type must be an integer.');
160
+ throw new V1ProtocolError(ResultCode.OPERATION_TYPE_UNKNOWN, 'Operation type must be an integer.');
157
161
  }
158
162
  if (type === 0) {
159
- throw new V1ProtocolError(ResultCode.INVALID_PAYLOAD, 'Operation type is unspecified.');
163
+ throw new V1ProtocolError(ResultCode.OPERATION_TYPE_UNKNOWN, 'Operation type is unspecified.');
160
164
  }
161
165
 
162
166
  switch (type) {
@@ -169,7 +173,7 @@ class V1BaseOperation {
169
173
  case NetworkOperationType.BROADCAST_TRANSACTION_RESPONSE:
170
174
  return this.#v1ValidationSchema.validateV1BroadcastTransactionResponse.bind(this.#v1ValidationSchema);
171
175
  default:
172
- throw new V1ProtocolError(ResultCode.UNEXPECTED_ERROR, `Unknown operation type: ${type}`);
176
+ throw new V1ProtocolError(ResultCode.OPERATION_TYPE_UNKNOWN, `Unknown operation type: ${type}`);
173
177
  }
174
178
  }
175
179