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.
- 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 +5 -10
- 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 +5 -26
- package/src/config/env.js +11 -25
- 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 +4 -5
- 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/networkV1.fixtures.js +28 -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/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/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,26 +0,0 @@
|
|
|
1
|
-
import V1BaseOperation from "./V1BaseOperation.js";
|
|
2
|
-
import b4a from "b4a";
|
|
3
|
-
import { MAX_PARTIAL_TX_PAYLOAD_BYTE_SIZE } from '../../../../../utils/constants.js';
|
|
4
|
-
import {V1InvalidPayloadError} from "../V1ProtocolError.js";
|
|
5
|
-
|
|
6
|
-
class V1BroadcastTransactionRequest extends V1BaseOperation {
|
|
7
|
-
constructor(config) {
|
|
8
|
-
super(config);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
async validate(payload, remotePublicKey) {
|
|
12
|
-
this.isPayloadSchemaValid(payload);
|
|
13
|
-
this.isDataPropertySizeValid(payload);
|
|
14
|
-
await this.validateSignature(payload, remotePublicKey);
|
|
15
|
-
return true;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
isDataPropertySizeValid(payload) {
|
|
19
|
-
if (b4a.byteLength(payload.broadcast_transaction_request.data) > MAX_PARTIAL_TX_PAYLOAD_BYTE_SIZE) {
|
|
20
|
-
throw new V1InvalidPayloadError(`The 'data' field exceeds the maximum allowed byte size of ${MAX_PARTIAL_TX_PAYLOAD_BYTE_SIZE}. Actual size: ${b4a.byteLength(payload.broadcast_transaction_request.data)}`);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export default V1BroadcastTransactionRequest;
|
|
@@ -1,276 +0,0 @@
|
|
|
1
|
-
import Autobase from "autobase";
|
|
2
|
-
import b4a from "b4a";
|
|
3
|
-
import Hypercore from 'hypercore';
|
|
4
|
-
import V1BaseOperation from "./V1BaseOperation.js";
|
|
5
|
-
import {unsafeDecodeApplyOperation} from "../../../../../utils/protobuf/operationHelpers.js";
|
|
6
|
-
import {isDeepEqualApplyPayload} from "../../../../../utils/deepEqualApplyPayload.js";
|
|
7
|
-
import {addressToBuffer, bufferToAddress} from "../../../../state/utils/address.js";
|
|
8
|
-
import {publicKeyToAddress} from "../../../../../utils/helpers.js";
|
|
9
|
-
import Check from "../../../../../utils/check.js";
|
|
10
|
-
import {OperationType, ResultCode} from "../../../../../utils/constants.js";
|
|
11
|
-
import {V1ProtocolError} from "../V1ProtocolError.js";
|
|
12
|
-
|
|
13
|
-
const VALIDATOR_METADATA_FIELDS = new Set(["va", "vn", "vs"]);
|
|
14
|
-
|
|
15
|
-
class V1BroadcastTransactionResponse extends V1BaseOperation {
|
|
16
|
-
#config;
|
|
17
|
-
#check;
|
|
18
|
-
#state;
|
|
19
|
-
|
|
20
|
-
constructor(state, config) {
|
|
21
|
-
super(config);
|
|
22
|
-
this.#state = state;
|
|
23
|
-
this.#config = config;
|
|
24
|
-
this.#check = new Check(config);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async validate(payload, connection, pendingRequestServiceEntry) {
|
|
28
|
-
this.isPayloadSchemaValid(payload);
|
|
29
|
-
this.validateResponseType(payload, pendingRequestServiceEntry);
|
|
30
|
-
this.validatePeerCorrectness(connection.remotePublicKey, pendingRequestServiceEntry);
|
|
31
|
-
await this.validateSignature(payload, connection.remotePublicKey);
|
|
32
|
-
const resultCode = payload.broadcast_transaction_response.result;
|
|
33
|
-
// if result code is not OK, we can skip the rest of the validations.
|
|
34
|
-
this.validateIfResultCodeIsValidatorInternalError(resultCode);
|
|
35
|
-
if (resultCode === ResultCode.OK) {
|
|
36
|
-
const proofResult = await this.verifyProofOfPublication(payload);
|
|
37
|
-
const {
|
|
38
|
-
validatorDecodedTx,
|
|
39
|
-
manifest
|
|
40
|
-
} = await this.assertProofPayloadMatchesRequestPayload(proofResult, pendingRequestServiceEntry);
|
|
41
|
-
this.validateDecodedCompletePayloadSchema(validatorDecodedTx);
|
|
42
|
-
const {
|
|
43
|
-
writerKeyFromManifest,
|
|
44
|
-
validatorAddressCorrelatedWithManifest
|
|
45
|
-
} = await this.validateWritingKey(validatorDecodedTx, manifest);
|
|
46
|
-
await this.validateValidatorCorrectness(
|
|
47
|
-
validatorDecodedTx,
|
|
48
|
-
connection.remotePublicKey,
|
|
49
|
-
writerKeyFromManifest,
|
|
50
|
-
validatorAddressCorrelatedWithManifest,
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return true;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
validateDecodedCompletePayloadSchema(validatorDecodedTx) {
|
|
58
|
-
const type = validatorDecodedTx?.type;
|
|
59
|
-
if (!Number.isInteger(type)) {
|
|
60
|
-
throw new V1ProtocolError(
|
|
61
|
-
ResultCode.VALIDATOR_RESPONSE_TX_TYPE_INVALID,
|
|
62
|
-
'Decoded validator transaction type is missing or invalid.',
|
|
63
|
-
false
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (!Object.values(OperationType).includes(type)) {
|
|
68
|
-
throw new V1ProtocolError(
|
|
69
|
-
ResultCode.VALIDATOR_RESPONSE_TX_TYPE_UNKNOWN,
|
|
70
|
-
`Decoded validator transaction type ${type} is not defined in OperationType constants.`,
|
|
71
|
-
false
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
let isValid = false;
|
|
76
|
-
switch (type) {
|
|
77
|
-
case OperationType.ADD_WRITER:
|
|
78
|
-
case OperationType.REMOVE_WRITER:
|
|
79
|
-
case OperationType.ADMIN_RECOVERY:
|
|
80
|
-
isValid = this.#check.validateRoleAccessOperation(validatorDecodedTx);
|
|
81
|
-
break;
|
|
82
|
-
case OperationType.BOOTSTRAP_DEPLOYMENT:
|
|
83
|
-
isValid = this.#check.validateBootstrapDeploymentOperation(validatorDecodedTx);
|
|
84
|
-
break;
|
|
85
|
-
case OperationType.TX:
|
|
86
|
-
isValid = this.#check.validateTransactionOperation(validatorDecodedTx);
|
|
87
|
-
break;
|
|
88
|
-
case OperationType.TRANSFER:
|
|
89
|
-
isValid = this.#check.validateTransferOperation(validatorDecodedTx);
|
|
90
|
-
break;
|
|
91
|
-
default:
|
|
92
|
-
throw new V1ProtocolError(
|
|
93
|
-
ResultCode.VALIDATOR_RESPONSE_TX_TYPE_UNSUPPORTED,
|
|
94
|
-
`Unsupported decoded validator transaction type: ${type}`,
|
|
95
|
-
false
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (!isValid) {
|
|
100
|
-
throw new V1ProtocolError(
|
|
101
|
-
ResultCode.VALIDATOR_RESPONSE_SCHEMA_INVALID,
|
|
102
|
-
`Decoded validator transaction schema validation failed for type ${type}.`,
|
|
103
|
-
false
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
async verifyProofOfPublication(payload) {
|
|
109
|
-
const proof = payload.broadcast_transaction_response.proof;
|
|
110
|
-
return this.#state.verifyProofOfPublication(proof);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
async assertProofPayloadMatchesRequestPayload(proofResult, pendingRequestServiceEntry) {
|
|
114
|
-
const stateTxEncodedFromRequest = pendingRequestServiceEntry.requestTxData;
|
|
115
|
-
if (!b4a.isBuffer(stateTxEncodedFromRequest) || stateTxEncodedFromRequest.length === 0) {
|
|
116
|
-
throw new V1ProtocolError(
|
|
117
|
-
ResultCode.PENDING_REQUEST_MISSING_TX_DATA,
|
|
118
|
-
'Missing transaction data in pending request entry.',
|
|
119
|
-
false
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
const provenBlock = proofResult.proof.block.value;
|
|
123
|
-
const manifest = proofResult.proof.manifest;
|
|
124
|
-
const stateTxEncodedFromResponse = await Autobase.decodeValue(provenBlock);
|
|
125
|
-
|
|
126
|
-
const stateTxDecodedFromRequest = unsafeDecodeApplyOperation(stateTxEncodedFromRequest);
|
|
127
|
-
const stateTxDecodedFromResponse = unsafeDecodeApplyOperation(stateTxEncodedFromResponse);
|
|
128
|
-
const strippedValidatorPayload = stripValidatorMetadata(stateTxDecodedFromResponse);
|
|
129
|
-
|
|
130
|
-
if (!isDeepEqualApplyPayload(stateTxDecodedFromRequest, strippedValidatorPayload)) {
|
|
131
|
-
throw new V1ProtocolError(
|
|
132
|
-
ResultCode.PROOF_PAYLOAD_MISMATCH,
|
|
133
|
-
'Decoded transaction payload mismatch after removing validator metadata fields.',
|
|
134
|
-
false
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
return {validatorDecodedTx: stateTxDecodedFromResponse, manifest};
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
async validateWritingKey(validatorDecodedTx, manifest) {
|
|
141
|
-
const writerKeyFromManifest = Hypercore.key(manifest);
|
|
142
|
-
const writerKeyFromManifestHex = b4a.toString(writerKeyFromManifest, "hex");
|
|
143
|
-
|
|
144
|
-
const validatorAddressBuffer = await this.#state.getRegisteredWriterKey(writerKeyFromManifestHex);
|
|
145
|
-
if (!b4a.isBuffer(validatorAddressBuffer) || validatorAddressBuffer.length === 0) {
|
|
146
|
-
throw new V1ProtocolError(
|
|
147
|
-
ResultCode.VALIDATOR_WRITER_KEY_NOT_REGISTERED,
|
|
148
|
-
`Validator with writer key ${writerKeyFromManifestHex} is not registered.`,
|
|
149
|
-
false
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return {
|
|
154
|
-
writerKeyFromManifest,
|
|
155
|
-
validatorAddressCorrelatedWithManifest: validatorAddressBuffer
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
async validateValidatorCorrectness(validatorDecodedTx, connectionRemotePublicKey, writerKeyFromManifest, validatorAddressCorrelatedWithManifest) {
|
|
160
|
-
const validatorAddressFromTx = extractRequiredVaFromDecodedTx(validatorDecodedTx);
|
|
161
|
-
const validatorAddressFromConnectionPublicKey = addressToBuffer(
|
|
162
|
-
publicKeyToAddress(connectionRemotePublicKey, this.#config),
|
|
163
|
-
this.#config.addressPrefix
|
|
164
|
-
);
|
|
165
|
-
|
|
166
|
-
if (!b4a.equals(validatorAddressFromTx, validatorAddressFromConnectionPublicKey)) {
|
|
167
|
-
throw new V1ProtocolError(
|
|
168
|
-
ResultCode.VALIDATOR_ADDRESS_MISMATCH,
|
|
169
|
-
`Validator address from transaction (${bufferToAddress(validatorAddressFromTx, this.#config.addressPrefix)}) does not match address derived from connection public key (${bufferToAddress(validatorAddressFromConnectionPublicKey, this.#config.addressPrefix)}).`,
|
|
170
|
-
false
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (!b4a.equals(validatorAddressFromTx, validatorAddressCorrelatedWithManifest)) {
|
|
175
|
-
throw new V1ProtocolError(
|
|
176
|
-
ResultCode.VALIDATOR_ADDRESS_MISMATCH,
|
|
177
|
-
`Validator address from transaction (${bufferToAddress(validatorAddressFromTx, this.#config.addressPrefix)}) does not match address correlated with manifest writer key (${bufferToAddress(validatorAddressCorrelatedWithManifest, this.#config.addressPrefix)}).`,
|
|
178
|
-
false
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if (!b4a.equals(validatorAddressCorrelatedWithManifest, validatorAddressFromConnectionPublicKey)) {
|
|
183
|
-
throw new V1ProtocolError(
|
|
184
|
-
ResultCode.VALIDATOR_ADDRESS_MISMATCH,
|
|
185
|
-
`Validator address correlated with manifest writer key (${bufferToAddress(validatorAddressCorrelatedWithManifest, this.#config.addressPrefix)}) does not match address derived from connection public key (${bufferToAddress(validatorAddressFromConnectionPublicKey, this.#config.addressPrefix)}).`,
|
|
186
|
-
false
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const validatorAddressFromConnection = bufferToAddress(validatorAddressFromConnectionPublicKey, this.#config.addressPrefix);
|
|
191
|
-
const account = await this.#state.getNodeEntry(validatorAddressFromConnection);
|
|
192
|
-
|
|
193
|
-
if (!account) {
|
|
194
|
-
throw new V1ProtocolError(
|
|
195
|
-
ResultCode.VALIDATOR_NODE_ENTRY_NOT_FOUND,
|
|
196
|
-
`No node entry found in state for validator address derived from connection public key (${validatorAddressFromConnection}).`,
|
|
197
|
-
false
|
|
198
|
-
);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
if (!account.isWriter) {
|
|
202
|
-
throw new V1ProtocolError(
|
|
203
|
-
ResultCode.VALIDATOR_NODE_NOT_WRITER,
|
|
204
|
-
`Node entry found for validator address derived from connection public key (${validatorAddressFromConnection}), but it is not registered as a writer.`,
|
|
205
|
-
false
|
|
206
|
-
);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if (!b4a.isBuffer(account.wk) || !b4a.equals(account.wk, writerKeyFromManifest)) {
|
|
210
|
-
throw new V1ProtocolError(
|
|
211
|
-
ResultCode.VALIDATOR_WRITER_KEY_MISMATCH,
|
|
212
|
-
`Writer key from manifest (${b4a.toString(writerKeyFromManifest, "hex")}) does not match writer key in state for validator address derived from connection public key (${validatorAddressFromConnection}).`,
|
|
213
|
-
false
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
validateIfResultCodeIsValidatorInternalError(resultCode) {
|
|
219
|
-
if (resultCode === ResultCode.TX_COMMITTED_RECEIPT_MISSING) {
|
|
220
|
-
throw new V1ProtocolError(
|
|
221
|
-
resultCode,
|
|
222
|
-
`Validator response indicates an error with result code ${resultCode}, which is an internal error code.`,
|
|
223
|
-
true
|
|
224
|
-
)
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const stripValidatorMetadata = (value) => {
|
|
230
|
-
|
|
231
|
-
if (value === null || value === undefined) return value;
|
|
232
|
-
if (b4a.isBuffer(value)) return value;
|
|
233
|
-
if (Array.isArray(value)) return value.map(stripValidatorMetadata);
|
|
234
|
-
if (typeof value !== "object") return value;
|
|
235
|
-
|
|
236
|
-
const result = {};
|
|
237
|
-
for (const [key, nestedValue] of Object.entries(value)) {
|
|
238
|
-
if (VALIDATOR_METADATA_FIELDS.has(key)) {
|
|
239
|
-
result[key] = null;
|
|
240
|
-
continue;
|
|
241
|
-
}
|
|
242
|
-
result[key] = stripValidatorMetadata(nestedValue);
|
|
243
|
-
}
|
|
244
|
-
return result;
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
export function extractRequiredVaFromDecodedTx(validatorDecodedTx) {
|
|
248
|
-
if (!validatorDecodedTx || typeof validatorDecodedTx !== 'object') {
|
|
249
|
-
throw new V1ProtocolError(
|
|
250
|
-
ResultCode.VALIDATOR_TX_OBJECT_INVALID,
|
|
251
|
-
'Invalid decoded transaction: expected object',
|
|
252
|
-
false
|
|
253
|
-
);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const operationPayload = Object.values(validatorDecodedTx).find((value) =>
|
|
257
|
-
value &&
|
|
258
|
-
typeof value === 'object' &&
|
|
259
|
-
!Array.isArray(value) &&
|
|
260
|
-
!b4a.isBuffer(value) &&
|
|
261
|
-
Object.prototype.hasOwnProperty.call(value, 'va')
|
|
262
|
-
);
|
|
263
|
-
|
|
264
|
-
const va = operationPayload?.va;
|
|
265
|
-
|
|
266
|
-
if (!b4a.isBuffer(va)) {
|
|
267
|
-
throw new V1ProtocolError(
|
|
268
|
-
ResultCode.VALIDATOR_VA_MISSING,
|
|
269
|
-
'Missing validator address (va) in decoded transaction',
|
|
270
|
-
false
|
|
271
|
-
);
|
|
272
|
-
}
|
|
273
|
-
return va;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
export default V1BroadcastTransactionResponse;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import V1BaseOperation from "./V1BaseOperation.js";
|
|
2
|
-
|
|
3
|
-
class V1LivenessRequest extends V1BaseOperation {
|
|
4
|
-
constructor(config) {
|
|
5
|
-
super(config);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
async validate(payload, remotePublicKey) {
|
|
9
|
-
this.isPayloadSchemaValid(payload);
|
|
10
|
-
await this.validateSignature(payload, remotePublicKey);
|
|
11
|
-
return true;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export default V1LivenessRequest;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import V1BaseOperation from "./V1BaseOperation.js";
|
|
2
|
-
|
|
3
|
-
class V1LivenessResponse extends V1BaseOperation {
|
|
4
|
-
constructor(config) {
|
|
5
|
-
super(config);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
async validate(payload, connection, pendingRequestServiceEntry) {
|
|
9
|
-
this.isPayloadSchemaValid(payload);
|
|
10
|
-
this.validateResponseType(payload, pendingRequestServiceEntry);
|
|
11
|
-
this.validatePeerCorrectness(connection.remotePublicKey, pendingRequestServiceEntry);
|
|
12
|
-
await this.validateSignature(payload, connection.remotePublicKey);
|
|
13
|
-
return true;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export default V1LivenessResponse;
|
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
import Validator from 'fastest-validator';
|
|
2
|
-
import b4a from 'b4a';
|
|
3
|
-
import {
|
|
4
|
-
NetworkOperationType,
|
|
5
|
-
NONCE_BYTE_LENGTH,
|
|
6
|
-
SIGNATURE_BYTE_LENGTH,
|
|
7
|
-
MAX_PARTIAL_TX_PAYLOAD_BYTE_SIZE,
|
|
8
|
-
ResultCode
|
|
9
|
-
} from '../../../../../utils/constants.js';
|
|
10
|
-
|
|
11
|
-
const ALLOWED_RESULT_CODES = Object.values(ResultCode);
|
|
12
|
-
|
|
13
|
-
class V1ValidationSchema {
|
|
14
|
-
#validator;
|
|
15
|
-
#validateV1LivenessRequest;
|
|
16
|
-
#validateV1LivenessResponse;
|
|
17
|
-
#validateV1BroadcastTransactionRequest;
|
|
18
|
-
#validateV1BroadcastTransactionResponse;
|
|
19
|
-
|
|
20
|
-
constructor() {
|
|
21
|
-
this.#validator = new Validator({
|
|
22
|
-
useNewCustomCheckerFunction: true,
|
|
23
|
-
messages: {
|
|
24
|
-
buffer: "The '{field}' field must be a Buffer! Actual: {actual}",
|
|
25
|
-
bufferLength: "The '{field}' field must be a Buffer with length {expected}! Actual: {actual}",
|
|
26
|
-
bufferMinLength: "The '{field}' field must be a Buffer with min length {expected}! Actual: {actual}",
|
|
27
|
-
bufferMaxLength: "The '{field}' field must be a Buffer with max length {expected}! Actual: {actual}",
|
|
28
|
-
nonZeroBuffer: "The '{field}' field must not be an empty or zero-filled Buffer!",
|
|
29
|
-
emptyBuffer: "The '{field}' field must not be an empty Buffer! Actual: {actual}",
|
|
30
|
-
},
|
|
31
|
-
});
|
|
32
|
-
const isBuffer = b4a.isBuffer;
|
|
33
|
-
this.#validator.add("buffer", function ({schema, messages}, path, context) {
|
|
34
|
-
const allowZero = schema.allowZero === true;
|
|
35
|
-
const allowEmpty = schema.allowEmpty === true;
|
|
36
|
-
const exactLength = Number.isInteger(schema.length) ? schema.length : null;
|
|
37
|
-
const minLength = Number.isInteger(schema.min) ? schema.min : null;
|
|
38
|
-
const maxLength = Number.isInteger(schema.max) ? schema.max : null;
|
|
39
|
-
return {
|
|
40
|
-
source:
|
|
41
|
-
`
|
|
42
|
-
if (!${isBuffer}(value)) {
|
|
43
|
-
${this.makeError({type: "buffer", actual: "value", messages})}
|
|
44
|
-
return value;
|
|
45
|
-
}
|
|
46
|
-
const len = value.length;
|
|
47
|
-
${exactLength === null ? '' : `
|
|
48
|
-
if (len !== ${exactLength}) {
|
|
49
|
-
${this.makeError({type: "bufferLength", expected: exactLength, actual: "len", messages})}
|
|
50
|
-
}`}
|
|
51
|
-
${minLength === null ? '' : `
|
|
52
|
-
if (len < ${minLength}) {
|
|
53
|
-
${this.makeError({type: "bufferMinLength", expected: minLength, actual: "len", messages})}
|
|
54
|
-
}`}
|
|
55
|
-
${maxLength === null ? '' : `
|
|
56
|
-
if (len > ${maxLength}) {
|
|
57
|
-
${this.makeError({type: "bufferMaxLength", expected: maxLength, actual: "len", messages})}
|
|
58
|
-
}`}
|
|
59
|
-
if (len === 0 && !${allowEmpty}) {
|
|
60
|
-
${this.makeError({type: "emptyBuffer", actual: "len", messages})}
|
|
61
|
-
return value;
|
|
62
|
-
}
|
|
63
|
-
if (!${allowZero}) {
|
|
64
|
-
let isZeroFilled = true;
|
|
65
|
-
for (let i = 0; i < len; i++) {
|
|
66
|
-
if (value[i] !== 0) {
|
|
67
|
-
isZeroFilled = false;
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
if (isZeroFilled) {
|
|
72
|
-
${this.makeError({type: "nonZeroBuffer", actual: "value", messages})}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return value;
|
|
76
|
-
`
|
|
77
|
-
};
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
this.#validateV1LivenessRequest = this.#compileV1LivenessRequestSchema();
|
|
81
|
-
this.#validateV1LivenessResponse = this.#compileV1LivenessResponseSchema();
|
|
82
|
-
this.#validateV1BroadcastTransactionRequest = this.#compileV1BroadcastTransactionRequestSchema();
|
|
83
|
-
this.#validateV1BroadcastTransactionResponse = this.#compileV1BroadcastTransactionResponseSchema();
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
#compileV1LivenessRequestSchema() {
|
|
87
|
-
const schema = {
|
|
88
|
-
$$strict: true,
|
|
89
|
-
type: {type: 'number', integer: true, equal: NetworkOperationType.LIVENESS_REQUEST, required: true},
|
|
90
|
-
id: {type: 'string', min: 1, max: 64, required: true},
|
|
91
|
-
timestamp: {type: 'number', integer: true, min: 1, max: Number.MAX_SAFE_INTEGER, required: true},
|
|
92
|
-
liveness_request: {
|
|
93
|
-
strict: true,
|
|
94
|
-
type: 'object',
|
|
95
|
-
props: {
|
|
96
|
-
nonce: {type: 'buffer', length: NONCE_BYTE_LENGTH, required: true},
|
|
97
|
-
signature: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true},
|
|
98
|
-
}
|
|
99
|
-
},
|
|
100
|
-
capabilities: {type: 'array', items: 'string', required: true},
|
|
101
|
-
|
|
102
|
-
};
|
|
103
|
-
return this.#validator.compile(schema);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
validateV1LivenessRequest(operation) {
|
|
107
|
-
return this.#validateV1LivenessRequest(operation) === true;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
#compileV1LivenessResponseSchema() {
|
|
111
|
-
const schema = {
|
|
112
|
-
$$strict: true,
|
|
113
|
-
type: {type: 'number', integer: true, equal: NetworkOperationType.LIVENESS_RESPONSE, required: true},
|
|
114
|
-
id: {type: 'string', min: 1, max: 64, required: true},
|
|
115
|
-
timestamp: {type: 'number', integer: true, min: 1, max: Number.MAX_SAFE_INTEGER, required: true},
|
|
116
|
-
liveness_response: {
|
|
117
|
-
strict: true,
|
|
118
|
-
type: 'object',
|
|
119
|
-
props: {
|
|
120
|
-
nonce: {type: 'buffer', length: NONCE_BYTE_LENGTH, required: true},
|
|
121
|
-
signature: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true},
|
|
122
|
-
result: {type: 'enum', values: ALLOWED_RESULT_CODES, required: true},
|
|
123
|
-
}
|
|
124
|
-
},
|
|
125
|
-
capabilities: {type: 'array', items: 'string', required: true},
|
|
126
|
-
|
|
127
|
-
};
|
|
128
|
-
return this.#validator.compile(schema);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
validateV1LivenessResponse(operation) {
|
|
132
|
-
return this.#validateV1LivenessResponse(operation) === true;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
#compileV1BroadcastTransactionRequestSchema() {
|
|
136
|
-
const schema = {
|
|
137
|
-
$$strict: true,
|
|
138
|
-
type: {
|
|
139
|
-
type: 'number',
|
|
140
|
-
integer: true,
|
|
141
|
-
equal: NetworkOperationType.BROADCAST_TRANSACTION_REQUEST,
|
|
142
|
-
required: true
|
|
143
|
-
},
|
|
144
|
-
id: {type: 'string', min: 1, max: 64, required: true},
|
|
145
|
-
timestamp: {type: 'number', integer: true, min: 1, max: Number.MAX_SAFE_INTEGER, required: true},
|
|
146
|
-
broadcast_transaction_request: {
|
|
147
|
-
strict: true,
|
|
148
|
-
type: 'object',
|
|
149
|
-
props: {
|
|
150
|
-
data: {
|
|
151
|
-
type: 'buffer',
|
|
152
|
-
min: 1,
|
|
153
|
-
max: MAX_PARTIAL_TX_PAYLOAD_BYTE_SIZE,
|
|
154
|
-
allowZero: true,
|
|
155
|
-
required: true
|
|
156
|
-
},
|
|
157
|
-
nonce: {type: 'buffer', length: NONCE_BYTE_LENGTH, required: true},
|
|
158
|
-
signature: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true},
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
capabilities: {type: 'array', items: 'string', required: true},
|
|
162
|
-
|
|
163
|
-
};
|
|
164
|
-
return this.#validator.compile(schema);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
validateV1BroadcastTransactionRequest(operation) {
|
|
168
|
-
return this.#validateV1BroadcastTransactionRequest(operation) === true;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
#compileV1BroadcastTransactionResponseSchema() {
|
|
172
|
-
const schema = {
|
|
173
|
-
$$strict: true,
|
|
174
|
-
type: {
|
|
175
|
-
type: 'number',
|
|
176
|
-
integer: true,
|
|
177
|
-
equal: NetworkOperationType.BROADCAST_TRANSACTION_RESPONSE,
|
|
178
|
-
required: true
|
|
179
|
-
},
|
|
180
|
-
id: {type: 'string', min: 1, max: 64, required: true},
|
|
181
|
-
timestamp: {type: 'number', integer: true, min: 1, max: Number.MAX_SAFE_INTEGER, required: true},
|
|
182
|
-
broadcast_transaction_response: {
|
|
183
|
-
strict: true,
|
|
184
|
-
type: 'object',
|
|
185
|
-
props: {
|
|
186
|
-
nonce: {type: 'buffer', length: NONCE_BYTE_LENGTH, required: true},
|
|
187
|
-
signature: {type: 'buffer', length: SIGNATURE_BYTE_LENGTH, required: true},
|
|
188
|
-
proof: {type: 'buffer', allowEmpty: true, allowZero: true, required: true},
|
|
189
|
-
timestamp: {
|
|
190
|
-
type: 'number',
|
|
191
|
-
integer: true,
|
|
192
|
-
min: 0,
|
|
193
|
-
max: Number.MAX_SAFE_INTEGER,
|
|
194
|
-
optional: true
|
|
195
|
-
},
|
|
196
|
-
result: {type: 'enum', values: ALLOWED_RESULT_CODES, required: true},
|
|
197
|
-
}
|
|
198
|
-
},
|
|
199
|
-
capabilities: {type: 'array', items: 'string', required: true},
|
|
200
|
-
|
|
201
|
-
};
|
|
202
|
-
return this.#validator.compile(schema);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
validateV1BroadcastTransactionResponse(operation) {
|
|
206
|
-
return this.#validateV1BroadcastTransactionResponse(operation) === true;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
export default V1ValidationSchema;
|