trac-msb 0.2.13 → 0.2.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/acceptance-tests.yml +38 -0
- package/.github/workflows/lint-pr-title.yml +26 -0
- package/.github/workflows/publish.yml +33 -0
- package/.github/workflows/unit-tests.yml +34 -0
- package/package.json +7 -12
- package/proto/network.proto +74 -0
- package/rpc/rpc_services.js +4 -22
- package/scripts/generate-protobufs.js +12 -37
- package/src/config/config.js +9 -26
- package/src/config/env.js +17 -27
- package/src/core/network/Network.js +36 -73
- package/src/core/network/protocols/LegacyProtocol.js +11 -21
- package/src/core/network/protocols/NetworkMessages.js +17 -38
- package/src/core/network/protocols/ProtocolInterface.js +2 -14
- package/src/core/network/protocols/ProtocolSession.js +17 -144
- package/src/core/network/protocols/V1Protocol.js +18 -37
- package/src/core/network/protocols/legacy/NetworkMessageRouter.js +19 -25
- package/src/core/network/protocols/legacy/handlers/{LegacyGetRequestHandler.js → GetRequestHandler.js} +6 -6
- package/src/core/network/protocols/legacy/handlers/ResponseHandler.js +37 -0
- package/src/core/network/protocols/{legacy/handlers/LegacyRoleOperationHandler.js → shared/handlers/RoleOperationHandler.js} +11 -18
- package/src/core/network/protocols/{legacy/handlers/LegacySubnetworkOperationHandler.js → shared/handlers/SubnetworkOperationHandler.js} +17 -28
- package/src/core/network/protocols/{legacy/handlers/LegacyTransferOperationHandler.js → shared/handlers/TransferOperationHandler.js} +11 -17
- package/src/core/network/protocols/{legacy/handlers/BaseStateOperationHandler.js → shared/handlers/base/BaseOperationHandler.js} +12 -23
- package/src/core/network/protocols/shared/validators/{PartialBootstrapDeploymentValidator.js → PartialBootstrapDeployment.js} +4 -9
- package/src/core/network/protocols/shared/validators/{PartialRoleAccessValidator.js → PartialRoleAccess.js} +17 -51
- package/src/core/network/protocols/shared/validators/{PartialTransactionValidator.js → PartialTransaction.js} +7 -21
- package/src/core/network/protocols/shared/validators/{PartialTransferValidator.js → PartialTransfer.js} +9 -26
- package/src/core/network/protocols/shared/validators/{PartialOperationValidator.js → base/PartialOperation.js} +25 -47
- package/src/core/network/protocols/v1/NetworkMessageRouter.js +7 -91
- package/src/core/network/services/ConnectionManager.js +94 -146
- package/src/core/network/services/MessageOrchestrator.js +27 -151
- package/src/core/network/services/TransactionPoolService.js +18 -129
- package/src/core/network/services/TransactionRateLimiterService.js +34 -52
- package/src/core/network/services/ValidatorObserverService.js +26 -18
- package/src/core/state/State.js +19 -70
- package/src/index.js +8 -6
- package/src/messages/network/v1/NetworkMessageBuilder.js +79 -59
- package/src/messages/network/v1/NetworkMessageDirector.js +50 -16
- package/src/utils/Scheduler.js +8 -0
- package/src/utils/constants.js +5 -71
- package/src/utils/helpers.js +1 -10
- package/src/utils/normalizers.js +0 -38
- package/src/utils/protobuf/network.cjs +840 -0
- package/src/utils/protobuf/operationHelpers.js +3 -24
- package/tests/acceptance/v1/account/account.test.mjs +2 -8
- package/tests/acceptance/v1/tx/tx.test.mjs +1 -23
- package/tests/acceptance/v1/tx-details/tx-details.test.mjs +6 -34
- package/tests/fixtures/assembleMessage.fixtures.js +8 -7
- package/tests/fixtures/networkV1.fixtures.js +28 -2
- package/tests/helpers/autobaseTestHelpers.js +5 -2
- package/tests/helpers/createTestSignature.js +3 -2
- package/tests/helpers/transactionPayloads.mjs +2 -2
- package/tests/unit/messages/network/NetworkMessageBuilder.test.js +79 -239
- package/tests/unit/messages/network/NetworkMessageDirector.test.js +77 -223
- package/tests/unit/messages/state/applyStateMessageBuilder.complete.test.js +5 -1
- package/tests/unit/messages/state/applyStateMessageBuilder.partial.test.js +5 -1
- package/tests/unit/network/ConnectionManager.test.js +191 -0
- package/tests/unit/network/networkModule.test.js +1 -4
- package/tests/unit/unit.test.js +2 -2
- package/tests/unit/utils/fileUtils/readAddressesFromWhitelistFile.test.js +2 -2
- package/tests/unit/utils/fileUtils/readBalanceMigrationFile.test.js +2 -2
- package/tests/unit/utils/protobuf/operationHelpers.test.js +4 -2
- package/tests/unit/utils/utils.test.js +0 -1
- package/proto/network/v1/enums/message_type.proto +0 -16
- package/proto/network/v1/enums/result_code.proto +0 -84
- package/proto/network/v1/messages/broadcast_transaction_request.proto +0 -9
- package/proto/network/v1/messages/broadcast_transaction_response.proto +0 -13
- package/proto/network/v1/messages/liveness_request.proto +0 -8
- package/proto/network/v1/messages/liveness_response.proto +0 -11
- package/proto/network/v1/network_message.proto +0 -22
- package/src/core/network/protocols/connectionPolicies.js +0 -88
- package/src/core/network/protocols/legacy/handlers/LegacyResponseHandler.js +0 -23
- package/src/core/network/protocols/shared/errors/SharedValidatorRejectionError.js +0 -27
- package/src/core/network/protocols/v1/V1ProtocolError.js +0 -91
- package/src/core/network/protocols/v1/handlers/V1BaseOperationHandler.js +0 -65
- package/src/core/network/protocols/v1/handlers/V1BroadcastTransactionOperationHandler.js +0 -389
- package/src/core/network/protocols/v1/handlers/V1LivenessOperationHandler.js +0 -87
- package/src/core/network/protocols/v1/validators/V1BaseOperation.js +0 -211
- package/src/core/network/protocols/v1/validators/V1BroadcastTransactionRequest.js +0 -26
- package/src/core/network/protocols/v1/validators/V1BroadcastTransactionResponse.js +0 -276
- package/src/core/network/protocols/v1/validators/V1LivenessRequest.js +0 -15
- package/src/core/network/protocols/v1/validators/V1LivenessResponse.js +0 -17
- package/src/core/network/protocols/v1/validators/V1ValidationSchema.js +0 -210
- package/src/core/network/services/PendingRequestService.js +0 -172
- package/src/core/network/services/TransactionCommitService.js +0 -149
- package/src/core/network/services/ValidatorHealthCheckService.js +0 -127
- package/src/utils/deepEqualApplyPayload.js +0 -40
- package/src/utils/logger.js +0 -25
- package/src/utils/protobuf/networkV1.generated.cjs +0 -2460
- package/tests/unit/network/LegacyNetworkMessageRouter.test.js +0 -54
- package/tests/unit/network/ProtocolSession.test.js +0 -127
- package/tests/unit/network/services/ConnectionManager.test.js +0 -450
- package/tests/unit/network/services/MessageOrchestrator.test.js +0 -445
- package/tests/unit/network/services/PendingRequestService.test.js +0 -431
- package/tests/unit/network/services/TransactionCommitService.test.js +0 -246
- package/tests/unit/network/services/TransactionPoolService.test.js +0 -489
- package/tests/unit/network/services/TransactionRateLimiterService.test.js +0 -139
- package/tests/unit/network/services/ValidatorHealthCheckService.test.js +0 -115
- package/tests/unit/network/services/services.test.js +0 -17
- package/tests/unit/network/utils/v1TestUtils.js +0 -153
- package/tests/unit/network/v1/NetworkMessageRouterV1.test.js +0 -151
- package/tests/unit/network/v1/V1BaseOperation.test.js +0 -356
- package/tests/unit/network/v1/V1BroadcastTransactionOperationHandler.test.js +0 -129
- package/tests/unit/network/v1/V1BroadcastTransactionRequest.test.js +0 -53
- package/tests/unit/network/v1/V1BroadcastTransactionResponse.test.js +0 -512
- package/tests/unit/network/v1/V1LivenessRequest.test.js +0 -32
- package/tests/unit/network/v1/V1LivenessResponse.test.js +0 -45
- package/tests/unit/network/v1/V1ResultCode.test.js +0 -84
- package/tests/unit/network/v1/V1ValidationSchema.test.js +0 -13
- package/tests/unit/network/v1/connectionPolicies.test.js +0 -49
- package/tests/unit/network/v1/handlers/V1BaseOperationHandler.test.js +0 -284
- package/tests/unit/network/v1/handlers/V1BroadcastTransactionOperationHandler.test.js +0 -794
- package/tests/unit/network/v1/handlers/V1LivenessOperationHandler.test.js +0 -193
- package/tests/unit/network/v1/v1.handlers.test.js +0 -15
- package/tests/unit/network/v1/v1.test.js +0 -19
- package/tests/unit/network/v1/v1ValidationSchema/broadcastTransactionRequest.test.js +0 -119
- package/tests/unit/network/v1/v1ValidationSchema/broadcastTransactionResponse.test.js +0 -136
- package/tests/unit/network/v1/v1ValidationSchema/common.test.js +0 -308
- package/tests/unit/network/v1/v1ValidationSchema/livenessRequest.test.js +0 -90
- package/tests/unit/network/v1/v1ValidationSchema/livenessResponse.test.js +0 -133
- package/tests/unit/utils/deepEqualApplyPayload/deepEqualApplyPayload.test.js +0 -102
|
@@ -1,389 +0,0 @@
|
|
|
1
|
-
import {networkMessageFactory} from "../../../../../messages/network/v1/networkMessageFactory.js";
|
|
2
|
-
import {
|
|
3
|
-
NETWORK_CAPABILITIES,
|
|
4
|
-
OperationType,
|
|
5
|
-
ResultCode
|
|
6
|
-
} from "../../../../../utils/constants.js";
|
|
7
|
-
import {
|
|
8
|
-
getResultCode,
|
|
9
|
-
V1TxInvalidPayloadError,
|
|
10
|
-
V1NodeHasNoWriteAccess,
|
|
11
|
-
shouldEndConnection,
|
|
12
|
-
V1TxAcceptedProofUnavailable,
|
|
13
|
-
V1UnexpectedError,
|
|
14
|
-
V1NodeOverloadedError,
|
|
15
|
-
V1TxAlreadyPendingError,
|
|
16
|
-
V1TimeoutError,
|
|
17
|
-
V1ProtocolError
|
|
18
|
-
} from "../V1ProtocolError.js";
|
|
19
|
-
import V1BroadcastTransactionRequest from "../validators/V1BroadcastTransactionRequest.js";
|
|
20
|
-
import {
|
|
21
|
-
unsafeDecodeApplyOperation,
|
|
22
|
-
unsafeEncodeApplyOperation
|
|
23
|
-
} from "../../../../../utils/protobuf/operationHelpers.js";
|
|
24
|
-
import {isBootstrapDeployment, isRoleAccess, isTransaction, isTransfer} from '../../../../../utils/applyOperations.js';
|
|
25
|
-
import PartialRoleAccessValidator from "../../shared/validators/PartialRoleAccessValidator.js";
|
|
26
|
-
import PartialBootstrapDeploymentValidator from "../../shared/validators/PartialBootstrapDeploymentValidator.js";
|
|
27
|
-
import PartialTransactionValidator from "../../shared/validators/PartialTransactionValidator.js";
|
|
28
|
-
import PartialTransferValidator from "../../shared/validators/PartialTransferValidator.js";
|
|
29
|
-
import {applyStateMessageFactory} from "../../../../../messages/state/applyStateMessageFactory.js";
|
|
30
|
-
import V1BroadcastTransactionResponse from "../validators/V1BroadcastTransactionResponse.js";
|
|
31
|
-
import V1BaseOperationHandler from "./V1BaseOperationHandler.js";
|
|
32
|
-
import {
|
|
33
|
-
TransactionPoolMissingCommitReceiptError,
|
|
34
|
-
TransactionPoolProofUnavailableError,
|
|
35
|
-
TransactionPoolFullError, TransactionPoolInvalidIncomingDataError, TransactionPoolAlreadyQueuedError
|
|
36
|
-
} from "../../../services/TransactionPoolService.js";
|
|
37
|
-
import {
|
|
38
|
-
PendingCommitInvalidTxHashError,
|
|
39
|
-
PendingCommitAlreadyExistsError,
|
|
40
|
-
PendingCommitBufferFullError, PendingCommitTimeoutError
|
|
41
|
-
} from "../../../services/TransactionCommitService.js";
|
|
42
|
-
import b4a from "b4a";
|
|
43
|
-
|
|
44
|
-
class V1BroadcastTransactionOperationHandler extends V1BaseOperationHandler {
|
|
45
|
-
#state;
|
|
46
|
-
#wallet;
|
|
47
|
-
#txPoolService;
|
|
48
|
-
#broadcastTransactionRequestValidator;
|
|
49
|
-
#broadcastTransactionResponseValidator;
|
|
50
|
-
#partialRoleAccessValidator;
|
|
51
|
-
#partialBootstrapDeploymentValidator;
|
|
52
|
-
#partialTransactionValidator;
|
|
53
|
-
#partialTransferValidator;
|
|
54
|
-
#transactionCommitService;
|
|
55
|
-
|
|
56
|
-
constructor(state, wallet, rateLimiterService, txPoolService, pendingRequestService, transactionCommitService, config) {
|
|
57
|
-
super(rateLimiterService, pendingRequestService, config);
|
|
58
|
-
this.#state = state;
|
|
59
|
-
this.#wallet = wallet;
|
|
60
|
-
this.#txPoolService = txPoolService;
|
|
61
|
-
this.#broadcastTransactionRequestValidator = new V1BroadcastTransactionRequest(config);
|
|
62
|
-
this.#partialRoleAccessValidator = new PartialRoleAccessValidator(state, this.#wallet.address, config);
|
|
63
|
-
this.#partialBootstrapDeploymentValidator = new PartialBootstrapDeploymentValidator(state, this.#wallet.address, config);
|
|
64
|
-
this.#partialTransactionValidator = new PartialTransactionValidator(state, this.#wallet.address, config);
|
|
65
|
-
this.#partialTransferValidator = new PartialTransferValidator(state, this.#wallet.address, config);
|
|
66
|
-
this.#broadcastTransactionResponseValidator = new V1BroadcastTransactionResponse(state, config);
|
|
67
|
-
this.#transactionCommitService = transactionCommitService;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async handleRequest(message, connection) {
|
|
71
|
-
let resultCode = ResultCode.OK;
|
|
72
|
-
let endConnection = false;
|
|
73
|
-
let proof = null
|
|
74
|
-
let timestamp = 0;
|
|
75
|
-
|
|
76
|
-
try {
|
|
77
|
-
this.applyRateLimit(connection);
|
|
78
|
-
await this.#broadcastTransactionRequestValidator.validate(message, connection.remotePublicKey);
|
|
79
|
-
await this.#validationCapability();
|
|
80
|
-
this.#isTxPoolFull();
|
|
81
|
-
const decodedTransaction = this.decodeApplyOperation(message.broadcast_transaction_request.data);
|
|
82
|
-
this.#sanitizeDecodedPartialTransaction(decodedTransaction);
|
|
83
|
-
const receipt = await this.dispatchTransaction(decodedTransaction);
|
|
84
|
-
proof = receipt.proof;
|
|
85
|
-
timestamp = receipt.timestamp;
|
|
86
|
-
} catch (error) {
|
|
87
|
-
const protocolError = error instanceof V1ProtocolError
|
|
88
|
-
? error
|
|
89
|
-
: new V1UnexpectedError(error?.message ?? 'Unexpected error', true);
|
|
90
|
-
resultCode = getResultCode(protocolError);
|
|
91
|
-
if (
|
|
92
|
-
resultCode === ResultCode.TX_ACCEPTED_PROOF_UNAVAILABLE &&
|
|
93
|
-
Number.isSafeInteger(protocolError.timestamp) &&
|
|
94
|
-
protocolError.timestamp > 0
|
|
95
|
-
) {
|
|
96
|
-
timestamp = protocolError.timestamp;
|
|
97
|
-
}
|
|
98
|
-
endConnection = shouldEndConnection(protocolError);
|
|
99
|
-
this.displayError(
|
|
100
|
-
"failed to process broadcast transaction request from sender",
|
|
101
|
-
connection.remotePublicKey,
|
|
102
|
-
protocolError
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
try {
|
|
107
|
-
const response = await this.#buildBroadcastTransactionResponse(
|
|
108
|
-
message.id,
|
|
109
|
-
NETWORK_CAPABILITIES,
|
|
110
|
-
proof,
|
|
111
|
-
timestamp,
|
|
112
|
-
resultCode,
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
await this.sendResponseAndMaybeClose(
|
|
116
|
-
connection,
|
|
117
|
-
response,
|
|
118
|
-
endConnection
|
|
119
|
-
);
|
|
120
|
-
} catch (error) {
|
|
121
|
-
this.displayError(
|
|
122
|
-
"failed to build/send response to sender",
|
|
123
|
-
connection.remotePublicKey,
|
|
124
|
-
error
|
|
125
|
-
);
|
|
126
|
-
connection.end();
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
async handleResponse(message, connection) {
|
|
131
|
-
try {
|
|
132
|
-
this.applyRateLimit(connection);
|
|
133
|
-
await this.resolvePendingResponse(
|
|
134
|
-
message,
|
|
135
|
-
connection,
|
|
136
|
-
this.#broadcastTransactionResponseValidator,
|
|
137
|
-
this.#extractBroadcastResultCode,
|
|
138
|
-
);
|
|
139
|
-
} catch (error) {
|
|
140
|
-
this.handlePendingResponseError(
|
|
141
|
-
message.id,
|
|
142
|
-
connection,
|
|
143
|
-
error,
|
|
144
|
-
"failed to process broadcast transaction response from sender"
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
async #buildBroadcastTransactionResponse(id, capabilities, proof, timestamp = null, resultCode) {
|
|
150
|
-
try {
|
|
151
|
-
return await networkMessageFactory(this.#wallet, this.config).buildBroadcastTransactionResponse(
|
|
152
|
-
id,
|
|
153
|
-
capabilities,
|
|
154
|
-
resultCode,
|
|
155
|
-
proof,
|
|
156
|
-
timestamp
|
|
157
|
-
);
|
|
158
|
-
} catch (error) {
|
|
159
|
-
throw new V1UnexpectedError(`Failed to build broadcast transaction response: ${error.message}`);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
decodeApplyOperation(message) {
|
|
164
|
-
try {
|
|
165
|
-
return unsafeDecodeApplyOperation(message);
|
|
166
|
-
} catch (error) {
|
|
167
|
-
throw new V1UnexpectedError(`Failed to decode apply operation from message: ${error.message}`);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
#sanitizeDecodedPartialTransaction(decodedTransaction) {
|
|
172
|
-
// Protobuf decode sets optional completion fields as null, but partial validators expect those fields to be absent.
|
|
173
|
-
// Otherwise, the presence of null fields causes validation to fail with "Expected type X but got null" errors.
|
|
174
|
-
|
|
175
|
-
const type = decodedTransaction?.type;
|
|
176
|
-
const operationKey = this.#getOperationPayloadKey(type);
|
|
177
|
-
|
|
178
|
-
if (!operationKey || !decodedTransaction?.[operationKey] || typeof decodedTransaction[operationKey] !== 'object') {
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
for (const completionField of ['va', 'vn', 'vs']) {
|
|
183
|
-
if (decodedTransaction[operationKey][completionField] === null) {
|
|
184
|
-
delete decodedTransaction[operationKey][completionField];
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
#getOperationPayloadKey(type) {
|
|
190
|
-
if (isRoleAccess(type)) return 'rao';
|
|
191
|
-
if (isTransaction(type)) return 'txo';
|
|
192
|
-
if (isBootstrapDeployment(type)) return 'bdo';
|
|
193
|
-
if (isTransfer(type)) return 'tro';
|
|
194
|
-
return null;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
#isTxPoolFull() {
|
|
198
|
-
try {
|
|
199
|
-
this.#txPoolService.validateEnqueue();
|
|
200
|
-
} catch (error) {
|
|
201
|
-
if (error instanceof TransactionPoolFullError) {
|
|
202
|
-
throw new V1NodeOverloadedError('Transaction pool is full, ignoring incoming transaction.');
|
|
203
|
-
}
|
|
204
|
-
throw error;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
async #validationCapability() {
|
|
209
|
-
const isAllowedToValidate = await this.#state.allowedToValidate(this.#wallet.address);
|
|
210
|
-
const isAdminAllowedToValidate = await this.#state.isAdminAllowedToValidate();
|
|
211
|
-
const canValidate = isAllowedToValidate || isAdminAllowedToValidate;
|
|
212
|
-
if (!canValidate) {
|
|
213
|
-
throw new V1NodeHasNoWriteAccess('State is not writable or is an indexer without admin privileges.');
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
async dispatchTransaction(decodedTransaction) {
|
|
218
|
-
if (!decodedTransaction || !Number.isInteger(decodedTransaction.type) || decodedTransaction.type === 0) {
|
|
219
|
-
throw new V1TxInvalidPayloadError('Decoded transaction type is missing.', false);
|
|
220
|
-
}
|
|
221
|
-
if (!this.#transactionCommitService) {
|
|
222
|
-
throw new V1UnexpectedError('TransactionCommitService is not configured.');
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const type = decodedTransaction.type;
|
|
226
|
-
let completeTransactionOperation;
|
|
227
|
-
|
|
228
|
-
// TODO: Consider moving logic below to strategy design pattern.
|
|
229
|
-
if (isRoleAccess(type)) {
|
|
230
|
-
await this.#partialRoleAccessValidator.validate(decodedTransaction);
|
|
231
|
-
completeTransactionOperation = await this.#buildCompleteRoleAccessOperation(decodedTransaction);
|
|
232
|
-
} else if (isTransaction(type)) {
|
|
233
|
-
await this.#partialTransactionValidator.validate(decodedTransaction);
|
|
234
|
-
completeTransactionOperation = await this.#buildCompleteTransactionOperation(decodedTransaction);
|
|
235
|
-
} else if (isBootstrapDeployment(type)) {
|
|
236
|
-
await this.#partialBootstrapDeploymentValidator.validate(decodedTransaction);
|
|
237
|
-
completeTransactionOperation = await this.#buildCompleteBootstrapDeploymentOperation(decodedTransaction);
|
|
238
|
-
} else if (isTransfer(type)) {
|
|
239
|
-
await this.#partialTransferValidator.validate(decodedTransaction);
|
|
240
|
-
completeTransactionOperation = await this.#buildCompleteTransferOperation(decodedTransaction);
|
|
241
|
-
} else {
|
|
242
|
-
throw new V1TxInvalidPayloadError(`Unsupported transaction type: ${type}`, false);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const payloadKey = this.#getOperationPayloadKey(type);
|
|
246
|
-
const txHash = b4a.toString(decodedTransaction[payloadKey].tx, 'hex');
|
|
247
|
-
|
|
248
|
-
const encodedCompleteTransaction = unsafeEncodeApplyOperation(completeTransactionOperation);
|
|
249
|
-
let pendingCommit;
|
|
250
|
-
|
|
251
|
-
try {
|
|
252
|
-
pendingCommit = this.#transactionCommitService.registerPendingCommit(txHash);
|
|
253
|
-
pendingCommit.catch(() => {});
|
|
254
|
-
} catch (error) {
|
|
255
|
-
if (error instanceof PendingCommitInvalidTxHashError) {
|
|
256
|
-
throw new V1ProtocolError(ResultCode.TX_HASH_INVALID_FORMAT, error.message, false);
|
|
257
|
-
}
|
|
258
|
-
if (error instanceof PendingCommitAlreadyExistsError) {
|
|
259
|
-
throw new V1TxAlreadyPendingError(error.message);
|
|
260
|
-
}
|
|
261
|
-
if (error instanceof PendingCommitBufferFullError) {
|
|
262
|
-
throw new V1NodeOverloadedError(error.message);
|
|
263
|
-
}
|
|
264
|
-
throw error;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
try {
|
|
268
|
-
this.#txPoolService.addTransaction(txHash, encodedCompleteTransaction);
|
|
269
|
-
} catch (error) {
|
|
270
|
-
let err = error;
|
|
271
|
-
if (error instanceof TransactionPoolFullError) {
|
|
272
|
-
err = new V1NodeOverloadedError(error.message);
|
|
273
|
-
} else if (error instanceof TransactionPoolAlreadyQueuedError) {
|
|
274
|
-
err = new V1TxAlreadyPendingError(error.message);
|
|
275
|
-
} else if (error instanceof TransactionPoolInvalidIncomingDataError) {
|
|
276
|
-
err = new V1ProtocolError(
|
|
277
|
-
ResultCode.INTERNAL_ENQUEUE_VALIDATION_FAILED,
|
|
278
|
-
`Internal enqueue validation failed: ${error.message}`,
|
|
279
|
-
false
|
|
280
|
-
);
|
|
281
|
-
}
|
|
282
|
-
this.#transactionCommitService.rejectPendingCommit(txHash, err);
|
|
283
|
-
throw err; // will be mapped anyway on lower level.
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
let receipt;
|
|
287
|
-
try {
|
|
288
|
-
receipt = await pendingCommit;
|
|
289
|
-
} catch (error) {
|
|
290
|
-
if (error instanceof TransactionPoolProofUnavailableError) {
|
|
291
|
-
throw new V1TxAcceptedProofUnavailable(error.message, false, error.timestamp);
|
|
292
|
-
}
|
|
293
|
-
if (error instanceof TransactionPoolMissingCommitReceiptError) {
|
|
294
|
-
throw new V1ProtocolError(ResultCode.TX_COMMITTED_RECEIPT_MISSING, error.message, false);
|
|
295
|
-
}
|
|
296
|
-
if (error instanceof PendingCommitTimeoutError) {
|
|
297
|
-
throw new V1TimeoutError(error.message);
|
|
298
|
-
}
|
|
299
|
-
throw error;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
return receipt;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
//TODO: Move responsibility to new class (next 4 functions)
|
|
307
|
-
async #buildCompleteRoleAccessOperation(decodedTransaction) {
|
|
308
|
-
const factory = applyStateMessageFactory(this.#wallet, this.config);
|
|
309
|
-
|
|
310
|
-
switch (decodedTransaction.type) {
|
|
311
|
-
case OperationType.ADD_WRITER:
|
|
312
|
-
return factory.buildCompleteAddWriterMessage(
|
|
313
|
-
decodedTransaction.address,
|
|
314
|
-
decodedTransaction.rao.tx,
|
|
315
|
-
decodedTransaction.rao.txv,
|
|
316
|
-
decodedTransaction.rao.iw,
|
|
317
|
-
decodedTransaction.rao.in,
|
|
318
|
-
decodedTransaction.rao.is
|
|
319
|
-
);
|
|
320
|
-
case OperationType.REMOVE_WRITER:
|
|
321
|
-
return factory.buildCompleteRemoveWriterMessage(
|
|
322
|
-
decodedTransaction.address,
|
|
323
|
-
decodedTransaction.rao.tx,
|
|
324
|
-
decodedTransaction.rao.txv,
|
|
325
|
-
decodedTransaction.rao.iw,
|
|
326
|
-
decodedTransaction.rao.in,
|
|
327
|
-
decodedTransaction.rao.is
|
|
328
|
-
);
|
|
329
|
-
case OperationType.ADMIN_RECOVERY:
|
|
330
|
-
return factory.buildCompleteAdminRecoveryMessage(
|
|
331
|
-
decodedTransaction.address,
|
|
332
|
-
decodedTransaction.rao.tx,
|
|
333
|
-
decodedTransaction.rao.txv,
|
|
334
|
-
decodedTransaction.rao.iw,
|
|
335
|
-
decodedTransaction.rao.in,
|
|
336
|
-
decodedTransaction.rao.is
|
|
337
|
-
);
|
|
338
|
-
default:
|
|
339
|
-
throw new V1TxInvalidPayloadError(`Unsupported role access transaction type: ${decodedTransaction.type}`, false);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
async #buildCompleteTransactionOperation(decodedTransaction) {
|
|
344
|
-
return applyStateMessageFactory(this.#wallet, this.config)
|
|
345
|
-
.buildCompleteTransactionOperationMessage(
|
|
346
|
-
decodedTransaction.address,
|
|
347
|
-
decodedTransaction.txo.tx,
|
|
348
|
-
decodedTransaction.txo.txv,
|
|
349
|
-
decodedTransaction.txo.iw,
|
|
350
|
-
decodedTransaction.txo.in,
|
|
351
|
-
decodedTransaction.txo.ch,
|
|
352
|
-
decodedTransaction.txo.is,
|
|
353
|
-
decodedTransaction.txo.bs,
|
|
354
|
-
decodedTransaction.txo.mbs
|
|
355
|
-
);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
async #buildCompleteBootstrapDeploymentOperation(decodedTransaction) {
|
|
359
|
-
return applyStateMessageFactory(this.#wallet, this.config)
|
|
360
|
-
.buildCompleteBootstrapDeploymentMessage(
|
|
361
|
-
decodedTransaction.address,
|
|
362
|
-
decodedTransaction.bdo.tx,
|
|
363
|
-
decodedTransaction.bdo.txv,
|
|
364
|
-
decodedTransaction.bdo.bs,
|
|
365
|
-
decodedTransaction.bdo.ic,
|
|
366
|
-
decodedTransaction.bdo.in,
|
|
367
|
-
decodedTransaction.bdo.is
|
|
368
|
-
);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
async #buildCompleteTransferOperation(decodedTransaction) {
|
|
372
|
-
return applyStateMessageFactory(this.#wallet, this.config)
|
|
373
|
-
.buildCompleteTransferOperationMessage(
|
|
374
|
-
decodedTransaction.address,
|
|
375
|
-
decodedTransaction.tro.tx,
|
|
376
|
-
decodedTransaction.tro.txv,
|
|
377
|
-
decodedTransaction.tro.in,
|
|
378
|
-
decodedTransaction.tro.to,
|
|
379
|
-
decodedTransaction.tro.am,
|
|
380
|
-
decodedTransaction.tro.is
|
|
381
|
-
);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
#extractBroadcastResultCode(payload) {
|
|
385
|
-
return payload.broadcast_transaction_response.result;
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
export default V1BroadcastTransactionOperationHandler;
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { networkMessageFactory } from "../../../../../messages/network/v1/networkMessageFactory.js";
|
|
2
|
-
import { NETWORK_CAPABILITIES, ResultCode } from "../../../../../utils/constants.js";
|
|
3
|
-
import V1LivenessRequest from "../validators/V1LivenessRequest.js";
|
|
4
|
-
import {getResultCode, shouldEndConnection, V1UnexpectedError} from "../V1ProtocolError.js";
|
|
5
|
-
import V1LivenessResponse from "../validators/V1LivenessResponse.js";
|
|
6
|
-
import V1BaseOperationHandler from "./V1BaseOperationHandler.js";
|
|
7
|
-
|
|
8
|
-
class V1LivenessOperationHandler extends V1BaseOperationHandler {
|
|
9
|
-
#wallet;
|
|
10
|
-
#v1LivenessRequestValidator;
|
|
11
|
-
#v1LivenessResponseValidator;
|
|
12
|
-
|
|
13
|
-
constructor(wallet, rateLimiterService, pendingRequestService, config) {
|
|
14
|
-
super(rateLimiterService, pendingRequestService, config);
|
|
15
|
-
this.#wallet = wallet;
|
|
16
|
-
this.#v1LivenessRequestValidator = new V1LivenessRequest(config);
|
|
17
|
-
this.#v1LivenessResponseValidator = new V1LivenessResponse(config);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async handleRequest(message, connection) {
|
|
21
|
-
let resultCode = ResultCode.OK;
|
|
22
|
-
let endConnection = false;
|
|
23
|
-
try {
|
|
24
|
-
this.applyRateLimit(connection);
|
|
25
|
-
await this.#v1LivenessRequestValidator.validate(message, connection.remotePublicKey);
|
|
26
|
-
} catch (error) {
|
|
27
|
-
resultCode = getResultCode(error);
|
|
28
|
-
endConnection = shouldEndConnection(error);
|
|
29
|
-
this.displayError("failed to process liveness request from sender",
|
|
30
|
-
connection.remotePublicKey,
|
|
31
|
-
error
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
const response = await this.#buildLivenessResponsePayload(message.id, NETWORK_CAPABILITIES, resultCode);
|
|
37
|
-
await this.sendResponseAndMaybeClose(
|
|
38
|
-
connection,
|
|
39
|
-
response,
|
|
40
|
-
endConnection
|
|
41
|
-
);
|
|
42
|
-
} catch (error) {
|
|
43
|
-
this.displayError("failed to build/send response to sender",
|
|
44
|
-
connection.remotePublicKey,
|
|
45
|
-
error
|
|
46
|
-
);
|
|
47
|
-
connection.end();
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async handleResponse(message, connection) {
|
|
52
|
-
try {
|
|
53
|
-
this.applyRateLimit(connection);
|
|
54
|
-
await this.resolvePendingResponse(
|
|
55
|
-
message,
|
|
56
|
-
connection,
|
|
57
|
-
this.#v1LivenessResponseValidator,
|
|
58
|
-
this.#extractLivenessResultCode
|
|
59
|
-
);
|
|
60
|
-
} catch (error) {
|
|
61
|
-
this.handlePendingResponseError(
|
|
62
|
-
message.id,
|
|
63
|
-
connection,
|
|
64
|
-
error,
|
|
65
|
-
"Failed to process liveness response from sender"
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async #buildLivenessResponsePayload(id, capabilities, resultCode) {
|
|
71
|
-
try {
|
|
72
|
-
return await networkMessageFactory(this.#wallet, this.config).buildLivenessResponse(
|
|
73
|
-
id,
|
|
74
|
-
capabilities,
|
|
75
|
-
resultCode
|
|
76
|
-
);
|
|
77
|
-
} catch (error) {
|
|
78
|
-
throw new V1UnexpectedError(`Failed to build liveness response: ${error.message}`);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
#extractLivenessResultCode(payload) {
|
|
83
|
-
return payload.liveness_response.result;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export default V1LivenessOperationHandler;
|
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
import V1ValidationSchema from "./V1ValidationSchema.js";
|
|
2
|
-
import {NetworkOperationType, ResultCode} from "../../../../../utils/constants.js";
|
|
3
|
-
import PeerWallet from "trac-wallet";
|
|
4
|
-
import b4a from "b4a";
|
|
5
|
-
import {
|
|
6
|
-
createMessage,
|
|
7
|
-
encodeCapabilities,
|
|
8
|
-
idToBuffer,
|
|
9
|
-
safeWriteUInt32BE,
|
|
10
|
-
timestampToBuffer
|
|
11
|
-
} from "../../../../../utils/buffer.js";
|
|
12
|
-
import {
|
|
13
|
-
V1InvalidPayloadError,
|
|
14
|
-
V1ProtocolError,
|
|
15
|
-
V1SignatureInvalidError,
|
|
16
|
-
V1UnexpectedError,
|
|
17
|
-
} from "../V1ProtocolError.js";
|
|
18
|
-
import _ from 'lodash';
|
|
19
|
-
class V1BaseOperation {
|
|
20
|
-
#v1ValidationSchema
|
|
21
|
-
#config
|
|
22
|
-
|
|
23
|
-
constructor(config) {
|
|
24
|
-
this.#config = config;
|
|
25
|
-
this.#v1ValidationSchema = new V1ValidationSchema();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async validate(payload, connection, pendingRequestServiceEntry) {
|
|
29
|
-
throw new Error("Method 'validate()' must be implemented.");
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
isPayloadSchemaValid(payload) {
|
|
33
|
-
if (_.isNil(payload?.type)) {
|
|
34
|
-
throw new V1InvalidPayloadError('Payload or payload type is missing.');
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const selectedValidator = this.#selectCheckSchemaValidator(payload.type);
|
|
38
|
-
const isPayloadValid = selectedValidator(payload);
|
|
39
|
-
if (!isPayloadValid) {
|
|
40
|
-
throw new V1InvalidPayloadError('Payload is invalid.');
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async validateSignature(payload, remotePublicKey) {
|
|
45
|
-
let signature;
|
|
46
|
-
let message;
|
|
47
|
-
try {
|
|
48
|
-
const result = this.#buildSignatureMessage(payload);
|
|
49
|
-
signature = result.signature;
|
|
50
|
-
message = result.message;
|
|
51
|
-
} catch (error) {
|
|
52
|
-
if (error instanceof V1ProtocolError) {
|
|
53
|
-
throw error;
|
|
54
|
-
}
|
|
55
|
-
throw new V1InvalidPayloadError(`Failed to build signature message: ${error.message}`);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
let hash;
|
|
59
|
-
try {
|
|
60
|
-
hash = await PeerWallet.blake3(message);
|
|
61
|
-
} catch (error) {
|
|
62
|
-
throw new V1InvalidPayloadError('Failed to hash signature message.');
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
let verified = false;
|
|
66
|
-
try {
|
|
67
|
-
verified = PeerWallet.verify(signature, hash, remotePublicKey);
|
|
68
|
-
} catch (error) {
|
|
69
|
-
verified = false;
|
|
70
|
-
}
|
|
71
|
-
if (!verified) {
|
|
72
|
-
throw new V1SignatureInvalidError('signature verification failed.');
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
#buildSignatureMessage(payload) {
|
|
77
|
-
if (!Number.isInteger(payload.type)) {
|
|
78
|
-
throw new V1InvalidPayloadError('Operation type must be an integer.');
|
|
79
|
-
}
|
|
80
|
-
if (payload.type === 0) {
|
|
81
|
-
throw new V1InvalidPayloadError('Operation type is unspecified.');
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const idBuf = idToBuffer(payload.id);
|
|
85
|
-
const tsBuf = timestampToBuffer(payload.timestamp);
|
|
86
|
-
const capsBuf = encodeCapabilities(payload.capabilities ?? []);
|
|
87
|
-
|
|
88
|
-
switch (payload.type) {
|
|
89
|
-
case NetworkOperationType.LIVENESS_REQUEST: {
|
|
90
|
-
const nonce = payload.liveness_request.nonce;
|
|
91
|
-
const signature = payload.liveness_request.signature;
|
|
92
|
-
const message = createMessage(payload.type, idBuf, tsBuf, nonce, capsBuf);
|
|
93
|
-
return {signature, message};
|
|
94
|
-
}
|
|
95
|
-
case NetworkOperationType.LIVENESS_RESPONSE: {
|
|
96
|
-
const nonce = payload.liveness_response.nonce;
|
|
97
|
-
const signature = payload.liveness_response.signature;
|
|
98
|
-
const result = payload.liveness_response.result;
|
|
99
|
-
const message = createMessage(payload.type, idBuf, tsBuf, nonce, safeWriteUInt32BE(result, 0), capsBuf);
|
|
100
|
-
return {signature, message};
|
|
101
|
-
}
|
|
102
|
-
case NetworkOperationType.BROADCAST_TRANSACTION_REQUEST: {
|
|
103
|
-
const data = payload.broadcast_transaction_request.data;
|
|
104
|
-
const nonce = payload.broadcast_transaction_request.nonce;
|
|
105
|
-
const signature = payload.broadcast_transaction_request.signature;
|
|
106
|
-
const message = createMessage(payload.type, idBuf, tsBuf, data, nonce, capsBuf);
|
|
107
|
-
return {signature, message};
|
|
108
|
-
}
|
|
109
|
-
case NetworkOperationType.BROADCAST_TRANSACTION_RESPONSE: {
|
|
110
|
-
const nonce = payload.broadcast_transaction_response.nonce;
|
|
111
|
-
const signature = payload.broadcast_transaction_response.signature;
|
|
112
|
-
const result = payload.broadcast_transaction_response.result;
|
|
113
|
-
const proofRaw = payload.broadcast_transaction_response.proof;
|
|
114
|
-
const proof = b4a.isBuffer(proofRaw) ? proofRaw : b4a.alloc(0);
|
|
115
|
-
const hasProof = proof.length > 0;
|
|
116
|
-
const timestampRaw = payload.broadcast_transaction_response.timestamp;
|
|
117
|
-
const timestamp = Number.isSafeInteger(timestampRaw) ? timestampRaw : 0;
|
|
118
|
-
const hasTimestamp = timestamp > 0;
|
|
119
|
-
|
|
120
|
-
if (result === ResultCode.OK) {
|
|
121
|
-
if (!hasProof || !hasTimestamp) {
|
|
122
|
-
throw new V1InvalidPayloadError('Result code OK requires non-empty proof and timestamp > 0.');
|
|
123
|
-
}
|
|
124
|
-
} else if (result === ResultCode.TX_ACCEPTED_PROOF_UNAVAILABLE) {
|
|
125
|
-
if (hasProof) {
|
|
126
|
-
throw new V1InvalidPayloadError('Result code TX_ACCEPTED_PROOF_UNAVAILABLE requires empty proof.');
|
|
127
|
-
}
|
|
128
|
-
if (!hasTimestamp) {
|
|
129
|
-
throw new V1InvalidPayloadError('Result code TX_ACCEPTED_PROOF_UNAVAILABLE requires timestamp > 0.');
|
|
130
|
-
}
|
|
131
|
-
} else {
|
|
132
|
-
if (hasProof) {
|
|
133
|
-
throw new V1InvalidPayloadError('Non-OK result code requires empty proof.');
|
|
134
|
-
}
|
|
135
|
-
if (timestamp !== 0) {
|
|
136
|
-
throw new V1InvalidPayloadError('Non-OK result code requires timestamp to be 0, except TX_ACCEPTED_PROOF_UNAVAILABLE.');
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const message = createMessage(
|
|
141
|
-
payload.type,
|
|
142
|
-
idBuf,
|
|
143
|
-
tsBuf,
|
|
144
|
-
nonce,
|
|
145
|
-
proof,
|
|
146
|
-
timestampToBuffer(timestamp),
|
|
147
|
-
safeWriteUInt32BE(result, 0),
|
|
148
|
-
capsBuf
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
return {signature, message};
|
|
152
|
-
}
|
|
153
|
-
default:
|
|
154
|
-
throw new V1UnexpectedError(`Unknown operation type: ${payload.type}`);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
#selectCheckSchemaValidator(type) {
|
|
159
|
-
if (!Number.isInteger(type)) {
|
|
160
|
-
throw new V1InvalidPayloadError('Operation type must be an integer.');
|
|
161
|
-
}
|
|
162
|
-
if (type === 0) {
|
|
163
|
-
throw new V1InvalidPayloadError('Operation type is unspecified.');
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
switch (type) {
|
|
167
|
-
case NetworkOperationType.LIVENESS_REQUEST:
|
|
168
|
-
return this.#v1ValidationSchema.validateV1LivenessRequest.bind(this.#v1ValidationSchema);
|
|
169
|
-
case NetworkOperationType.LIVENESS_RESPONSE:
|
|
170
|
-
return this.#v1ValidationSchema.validateV1LivenessResponse.bind(this.#v1ValidationSchema);
|
|
171
|
-
case NetworkOperationType.BROADCAST_TRANSACTION_REQUEST:
|
|
172
|
-
return this.#v1ValidationSchema.validateV1BroadcastTransactionRequest.bind(this.#v1ValidationSchema);
|
|
173
|
-
case NetworkOperationType.BROADCAST_TRANSACTION_RESPONSE:
|
|
174
|
-
return this.#v1ValidationSchema.validateV1BroadcastTransactionResponse.bind(this.#v1ValidationSchema);
|
|
175
|
-
default:
|
|
176
|
-
throw new V1UnexpectedError(`Unknown operation type: ${type}`);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
validatePeerCorrectness(remotePublicKey, pendingRequestServiceEntry) {
|
|
181
|
-
const senderPublicKeyHex = b4a.toString(remotePublicKey, 'hex');
|
|
182
|
-
if (senderPublicKeyHex !== pendingRequestServiceEntry.requestedTo) {
|
|
183
|
-
throw new V1InvalidPayloadError(
|
|
184
|
-
`Response sender mismatch. Expected ${pendingRequestServiceEntry.requestedTo}, got ${senderPublicKeyHex}.`
|
|
185
|
-
);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
validateResponseType(payload, pendingRequestServiceEntry) {
|
|
190
|
-
let expectedResponseType;
|
|
191
|
-
switch (pendingRequestServiceEntry.requestType) {
|
|
192
|
-
case NetworkOperationType.LIVENESS_REQUEST:
|
|
193
|
-
expectedResponseType = NetworkOperationType.LIVENESS_RESPONSE;
|
|
194
|
-
break;
|
|
195
|
-
case NetworkOperationType.BROADCAST_TRANSACTION_REQUEST:
|
|
196
|
-
expectedResponseType = NetworkOperationType.BROADCAST_TRANSACTION_RESPONSE;
|
|
197
|
-
break;
|
|
198
|
-
default:
|
|
199
|
-
throw new V1UnexpectedError(`Unsupported pending request type: ${pendingRequestServiceEntry.requestType}.`);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
if (payload.type !== expectedResponseType) {
|
|
203
|
-
throw new V1InvalidPayloadError(
|
|
204
|
-
`Response type mismatch for id ${pendingRequestServiceEntry.id}. Expected ${expectedResponseType}, got ${payload.type}.`
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
export default V1BaseOperation;
|