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.
- package/SECURITY.md +2 -2
- package/cli/commandHandler.js +317 -20
- package/cli/handlers.js +9 -1
- package/cli/interactive.js +4 -3
- package/cli/tokenSupplyAudit.js +90 -0
- package/msb.mjs +1 -0
- package/package.json +15 -6
- package/rpc/create_server.js +12 -3
- package/rpc/handlers.js +121 -0
- package/rpc/routes/v1.js +12 -0
- package/src/codecs/apply/applyOperationCodec.js +334 -0
- package/src/codecs/apply/applyOperations.generated.cjs +6380 -0
- package/src/codecs/consensus/v1/consensusV1.generated.cjs +3508 -0
- package/src/codecs/consensus/v1/consensusV1OperationCodec.js +161 -0
- package/src/codecs/consensus/v1/vdfConfigCodec.js +83 -0
- package/src/{utils/protobuf → codecs/network/v1}/networkV1.generated.cjs +664 -393
- package/src/codecs/network/v1/networkV1OperationCodec.js +25 -0
- package/src/codecs/protobufRuntime.cjs +95 -0
- package/src/codecs/state/escrowEntryCodec.js +45 -0
- package/src/codecs/state/state.generated.cjs +659 -0
- package/src/config/args.js +0 -1
- package/src/config/config.js +41 -7
- package/src/config/env.js +33 -9
- package/src/core/consensus/epochAppenderSelection/EpochAppenderSelectionError.js +55 -0
- package/src/core/consensus/epochAppenderSelection/EpochAppenderSelectionOperations.js +118 -0
- package/src/core/consensus/epochAppenderSelection/EpochAppenderSelector.js +1042 -0
- package/src/core/consensus/epochAppenderSelection/createEpochAppenderSelector.js +23 -0
- package/src/core/consensus/epochAppenderSelection/epochAppenderSelectionLedgerReader.js +274 -0
- package/src/core/consensus/epochAppenderSelection/epochAppenderSelectionState.js +488 -0
- package/src/core/consensus/epochAppenderSelection/epochAppenderSelectionStorage.js +93 -0
- package/src/core/consensus/quorum.js +11 -0
- package/src/core/consensus/services/EpochCoordinationRound.js +839 -0
- package/src/core/consensus/services/EpochCoordinatorOperations.js +211 -0
- package/src/core/consensus/services/EpochCoordinatorService.js +335 -0
- package/src/core/consensus/services/EpochRoundListeners.js +116 -0
- package/src/core/consensus/services/EpochStateMachine.js +141 -0
- package/src/core/consensus/services/VDFBare.js +291 -0
- package/src/core/consensus/services/VDFNode.js +111 -0
- package/src/core/consensus/services/VDFProgressWatchdog.js +79 -0
- package/src/core/consensus/services/VDFService.js +87 -0
- package/src/core/consensus/services/VDFServiceManager.js +147 -0
- package/src/core/consensus/services/createVDFService.js +16 -0
- package/src/core/consensus/services/vdf-guardian.js +32 -0
- package/src/core/consensus/services/vdf-worker.js +90 -0
- package/src/core/network/Network.js +327 -238
- package/src/core/network/protocols/consensus/IndexerMessages.js +72 -0
- package/src/core/network/protocols/consensus/v1/ConsensusV1ConnectionPolicy.js +57 -0
- package/src/core/network/protocols/consensus/v1/ConsensusV1MessageRouter.js +147 -0
- package/src/core/network/protocols/consensus/v1/ConsensusV1Protocol.js +72 -0
- package/src/core/network/protocols/consensus/v1/IndexerPendingRequestService.js +108 -0
- package/src/core/network/protocols/consensus/v1/V1ConsensusProtocolError.js +29 -0
- package/src/core/network/protocols/consensus/v1/handlers/V1EpochAppendOperationHandler.js +68 -0
- package/src/core/network/protocols/consensus/v1/handlers/V1EpochProofProposalOperationHandler.js +226 -0
- package/src/core/network/protocols/consensus/v1/validators/ConsensusValidationSchema.js +192 -0
- package/src/core/network/protocols/consensus/v1/validators/V1BaseConsensusOperation.js +428 -0
- package/src/core/network/protocols/consensus/v1/validators/V1EpochAppendReply.js +47 -0
- package/src/core/network/protocols/consensus/v1/validators/V1EpochAppendRequest.js +17 -0
- package/src/core/network/protocols/consensus/v1/validators/V1EpochProofProposalApproval.js +116 -0
- package/src/core/network/protocols/consensus/v1/validators/V1EpochProofProposalRequest.js +152 -0
- package/src/core/network/protocols/consensus/v1/validators/consensusValidationSchemaHelpers.js +145 -0
- package/src/core/network/protocols/shared/ConnectionOperationHandler.js +27 -0
- package/src/core/network/protocols/{NetworkMessages.js → validators/ValidatorMessages.js} +24 -14
- package/src/core/network/protocols/{ProtocolSession.js → validators/ValidatorProtocolSession.js} +22 -25
- package/src/core/network/protocols/{legacy/NetworkMessageRouter.js → validators/legacy/ValidatorLegacyMessageRouter.js} +6 -6
- package/src/core/network/protocols/{LegacyProtocol.js → validators/legacy/ValidatorLegacyProtocol.js} +9 -7
- package/src/core/network/protocols/{legacy → validators/legacy}/handlers/BaseStateOperationHandler.js +1 -1
- package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyGetRequestHandler.js +5 -5
- package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyRoleOperationHandler.js +5 -5
- package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacySubnetworkOperationHandler.js +5 -5
- package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyTransferOperationHandler.js +5 -5
- package/src/core/network/protocols/{ProtocolInterface.js → validators/shared/ValidatorProtocolInterface.js} +5 -5
- package/src/core/network/protocols/{shared → validators/shared}/validators/PartialBootstrapDeploymentValidator.js +1 -1
- package/src/core/network/protocols/validators/shared/validators/PartialHtlcValidator.js +325 -0
- package/src/core/network/protocols/{shared → validators/shared}/validators/PartialOperationValidator.js +44 -21
- package/src/core/network/protocols/{shared → validators/shared}/validators/PartialRoleAccessValidator.js +3 -3
- package/src/core/network/protocols/{shared → validators/shared}/validators/PartialTransactionValidator.js +3 -3
- package/src/core/network/protocols/{shared → validators/shared}/validators/PartialTransferValidator.js +4 -4
- package/src/core/network/protocols/{v1 → validators/v1}/V1ProtocolError.js +1 -1
- package/src/core/network/{services/PendingRequestService.js → protocols/validators/v1/ValidatorPendingRequestService.js} +19 -82
- package/src/core/network/protocols/{v1/NetworkMessageRouter.js → validators/v1/ValidatorV1MessageRouter.js} +9 -9
- package/src/core/network/protocols/{V1Protocol.js → validators/v1/ValidatorV1Protocol.js} +10 -8
- package/src/core/network/protocols/{connectionPolicies.js → validators/v1/connectionPolicies.js} +1 -1
- package/src/core/network/protocols/{v1 → validators/v1}/handlers/V1BaseOperationHandler.js +6 -23
- package/src/core/network/protocols/{v1 → validators/v1}/handlers/V1BroadcastTransactionOperationHandler.js +14 -9
- package/src/core/network/protocols/{v1 → validators/v1}/handlers/V1LivenessOperationHandler.js +5 -4
- package/src/core/network/protocols/{v1 → validators/v1}/handlers/broadcastTransaction/BroadcastTransactionErrorMapper.js +3 -3
- package/src/core/network/protocols/{v1 → validators/v1}/handlers/broadcastTransaction/BroadcastTransactionOperationStrategies.js +44 -1
- package/src/core/network/protocols/{v1 → validators/v1}/handlers/broadcastTransaction/BroadcastTransactionPayloadUtils.js +1 -1
- package/src/core/network/protocols/{v1 → validators/v1}/validators/V1BaseOperation.js +19 -15
- package/src/core/network/protocols/{v1 → validators/v1}/validators/V1BroadcastTransactionRequest.js +2 -2
- package/src/core/network/protocols/{v1 → validators/v1}/validators/V1BroadcastTransactionResponse.js +34 -18
- package/src/core/network/protocols/{v1 → validators/v1}/validators/V1ValidationSchema.js +3 -3
- package/src/core/network/services/IndexerConnectionManager.js +88 -0
- package/src/core/network/services/TransactionPoolService.js +11 -18
- package/src/core/network/services/TransactionRateLimiterService.js +1 -1
- package/src/core/network/services/ValidatorConnectionManager.js +163 -0
- package/src/core/network/services/{MessageOrchestrator.js → ValidatorMessageOrchestrator.js} +34 -42
- package/src/core/network/services/ValidatorObserverService.js +21 -36
- package/src/core/network/shared/BasePendingRequestService.js +67 -0
- package/src/core/network/shared/PeerConnectionManager.js +185 -0
- package/src/core/state/State.js +1803 -159
- package/src/core/state/StateEventQueue.js +69 -0
- package/src/core/state/utils/address.js +10 -6
- package/src/core/state/utils/epochProof.js +109 -0
- package/src/core/state/utils/escrowEntry.js +178 -0
- package/src/core/state/validators/StateValidationSchema.js +757 -0
- package/src/core/state/validators/stateValidationRules.js +312 -0
- package/src/index.js +280 -67
- package/src/messages/consensus/v1/ConsensusMessageBuilder.js +368 -0
- package/src/messages/consensus/v1/ConsensusMessageDirector.js +142 -0
- package/src/messages/consensus/v1/consensusMessageFactory.js +12 -0
- package/src/messages/consensus/v1/epochAppendMessage.js +58 -0
- package/src/messages/network/v1/NetworkMessageBuilder.js +15 -7
- package/src/messages/state/ApplyStateMessageBuilder.js +499 -13
- package/src/messages/state/ApplyStateMessageDirector.js +261 -2
- package/src/utils/StateMachine.js +125 -0
- package/src/utils/applyOperations.js +45 -2
- package/src/utils/buffer.js +239 -59
- package/src/utils/consensusConfig.js +76 -0
- package/src/utils/constants.js +174 -73
- package/src/utils/helpers.js +0 -25
- package/src/utils/htlcLock.js +122 -0
- package/src/utils/logger.js +10 -4
- package/src/utils/migrationUtils.js +2 -1
- package/src/utils/normalizers.js +113 -0
- package/src/utils/scheduler/SchedulableService.js +107 -0
- package/src/utils/{Scheduler.js → scheduler/Scheduler.js} +56 -17
- package/src/core/network/services/ConnectionManager.js +0 -406
- package/src/utils/check.js +0 -525
- package/src/utils/protobuf/applyOperations.cjs +0 -1373
- package/src/utils/protobuf/operationHelpers.js +0 -81
- /package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyResponseHandler.js +0 -0
- /package/src/core/network/protocols/{legacy → validators/legacy}/validators/ValidatorResponse.js +0 -0
- /package/src/core/network/protocols/{legacy → validators/legacy}/validators/base/BaseResponse.js +0 -0
- /package/src/core/network/protocols/{v1 → validators/v1}/validators/V1LivenessRequest.js +0 -0
- /package/src/core/network/protocols/{v1 → validators/v1}/validators/V1LivenessResponse.js +0 -0
package/src/core/network/protocols/{v1 → validators/v1}/validators/V1BroadcastTransactionRequest.js
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import V1BaseOperation from "./V1BaseOperation.js";
|
|
2
2
|
import b4a from "b4a";
|
|
3
|
-
import {MAX_PARTIAL_TX_PAYLOAD_BYTE_SIZE, ResultCode} from '
|
|
3
|
+
import {MAX_PARTIAL_TX_PAYLOAD_BYTE_SIZE, ResultCode} from '../../../../../../utils/constants.js';
|
|
4
4
|
import {V1ProtocolError} from "../V1ProtocolError.js";
|
|
5
5
|
|
|
6
6
|
class V1BroadcastTransactionRequest extends V1BaseOperation {
|
|
@@ -18,7 +18,7 @@ class V1BroadcastTransactionRequest extends V1BaseOperation {
|
|
|
18
18
|
isDataPropertySizeValid(payload) {
|
|
19
19
|
if (b4a.byteLength(payload.broadcast_transaction_request.data) > MAX_PARTIAL_TX_PAYLOAD_BYTE_SIZE) {
|
|
20
20
|
throw new V1ProtocolError(
|
|
21
|
-
ResultCode.
|
|
21
|
+
ResultCode.SCHEMA_VALIDATION_FAILED,
|
|
22
22
|
`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)}`);
|
|
23
23
|
}
|
|
24
24
|
}
|
package/src/core/network/protocols/{v1 → validators/v1}/validators/V1BroadcastTransactionResponse.js
RENAMED
|
@@ -2,44 +2,44 @@ import Autobase from "autobase";
|
|
|
2
2
|
import b4a from "b4a";
|
|
3
3
|
import Hypercore from 'hypercore';
|
|
4
4
|
import V1BaseOperation from "./V1BaseOperation.js";
|
|
5
|
-
import {unsafeDecodeApplyOperation} from "
|
|
6
|
-
import {isDeepEqualApplyPayload} from "
|
|
7
|
-
import {addressToBuffer, bufferToAddress} from "
|
|
8
|
-
import {publicKeyToAddress} from "
|
|
9
|
-
import
|
|
10
|
-
import {OperationType, ResultCode} from "
|
|
5
|
+
import {unsafeDecodeApplyOperation} from "../../../../../../codecs/apply/applyOperationCodec.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 StateValidationSchema from "../../../../../state/validators/StateValidationSchema.js";
|
|
10
|
+
import {OperationType, ResultCode} from "../../../../../../utils/constants.js";
|
|
11
11
|
import {V1ProtocolError} from "../V1ProtocolError.js";
|
|
12
12
|
|
|
13
13
|
const VALIDATOR_METADATA_FIELDS = new Set(["va", "vn", "vs"]);
|
|
14
14
|
|
|
15
|
-
const stripValidatorMetadata = (value) => {
|
|
15
|
+
const stripValidatorMetadata = (value, omitFields = false) => {
|
|
16
16
|
|
|
17
17
|
if (value === null || value === undefined) return value;
|
|
18
18
|
if (b4a.isBuffer(value)) return value;
|
|
19
|
-
if (Array.isArray(value)) return value.map(stripValidatorMetadata);
|
|
19
|
+
if (Array.isArray(value)) return value.map(item => stripValidatorMetadata(item, omitFields));
|
|
20
20
|
if (typeof value !== "object") return value;
|
|
21
21
|
|
|
22
22
|
const result = {};
|
|
23
23
|
for (const [key, nestedValue] of Object.entries(value)) {
|
|
24
24
|
if (VALIDATOR_METADATA_FIELDS.has(key)) {
|
|
25
|
-
result[key] = null;
|
|
25
|
+
if (!omitFields) result[key] = null;
|
|
26
26
|
continue;
|
|
27
27
|
}
|
|
28
|
-
result[key] = stripValidatorMetadata(nestedValue);
|
|
28
|
+
result[key] = stripValidatorMetadata(nestedValue, omitFields);
|
|
29
29
|
}
|
|
30
30
|
return result;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
class V1BroadcastTransactionResponse extends V1BaseOperation {
|
|
34
34
|
#config;
|
|
35
|
-
#
|
|
35
|
+
#stateValidationSchema;
|
|
36
36
|
#state;
|
|
37
37
|
|
|
38
38
|
constructor(state, config) {
|
|
39
39
|
super(config);
|
|
40
40
|
this.#state = state;
|
|
41
41
|
this.#config = config;
|
|
42
|
-
this.#
|
|
42
|
+
this.#stateValidationSchema = new StateValidationSchema(config);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
async validate(payload, connection, pendingRequestServiceEntry) {
|
|
@@ -90,19 +90,31 @@ class V1BroadcastTransactionResponse extends V1BaseOperation {
|
|
|
90
90
|
|
|
91
91
|
let isValid = false;
|
|
92
92
|
switch (type) {
|
|
93
|
+
case OperationType.HTLC_LOCK:
|
|
94
|
+
isValid = this.#stateValidationSchema.validateHtlcLockOperation(validatorDecodedTx) &&
|
|
95
|
+
[...VALIDATOR_METADATA_FIELDS].every(field => b4a.isBuffer(validatorDecodedTx.hlo[field]));
|
|
96
|
+
break;
|
|
97
|
+
case OperationType.HTLC_CLAIM:
|
|
98
|
+
isValid = this.#stateValidationSchema.validateHtlcClaimOperation(validatorDecodedTx) &&
|
|
99
|
+
[...VALIDATOR_METADATA_FIELDS].every(field => b4a.isBuffer(validatorDecodedTx.hco?.[field]));
|
|
100
|
+
break;
|
|
101
|
+
case OperationType.HTLC_REFUND:
|
|
102
|
+
isValid = this.#stateValidationSchema.validateHtlcRefundOperation(validatorDecodedTx) &&
|
|
103
|
+
[...VALIDATOR_METADATA_FIELDS].every(field => b4a.isBuffer(validatorDecodedTx.hro?.[field]));
|
|
104
|
+
break;
|
|
93
105
|
case OperationType.ADD_WRITER:
|
|
94
106
|
case OperationType.REMOVE_WRITER:
|
|
95
107
|
case OperationType.ADMIN_RECOVERY:
|
|
96
|
-
isValid = this.#
|
|
108
|
+
isValid = this.#stateValidationSchema.validateRoleAccessOperation(validatorDecodedTx);
|
|
97
109
|
break;
|
|
98
110
|
case OperationType.BOOTSTRAP_DEPLOYMENT:
|
|
99
|
-
isValid = this.#
|
|
111
|
+
isValid = this.#stateValidationSchema.validateBootstrapDeploymentOperation(validatorDecodedTx);
|
|
100
112
|
break;
|
|
101
113
|
case OperationType.TX:
|
|
102
|
-
isValid = this.#
|
|
114
|
+
isValid = this.#stateValidationSchema.validateTransactionOperation(validatorDecodedTx);
|
|
103
115
|
break;
|
|
104
116
|
case OperationType.TRANSFER:
|
|
105
|
-
isValid = this.#
|
|
117
|
+
isValid = this.#stateValidationSchema.validateTransferOperation(validatorDecodedTx);
|
|
106
118
|
break;
|
|
107
119
|
default:
|
|
108
120
|
throw new V1ProtocolError(
|
|
@@ -138,7 +150,11 @@ class V1BroadcastTransactionResponse extends V1BaseOperation {
|
|
|
138
150
|
|
|
139
151
|
const stateTxDecodedFromRequest = unsafeDecodeApplyOperation(stateTxEncodedFromRequest);
|
|
140
152
|
const stateTxDecodedFromResponse = unsafeDecodeApplyOperation(stateTxEncodedFromResponse);
|
|
141
|
-
const strippedValidatorPayload = stripValidatorMetadata(
|
|
153
|
+
const strippedValidatorPayload = stripValidatorMetadata(
|
|
154
|
+
stateTxDecodedFromResponse,
|
|
155
|
+
stateTxDecodedFromRequest.type === OperationType.HTLC_CLAIM ||
|
|
156
|
+
stateTxDecodedFromRequest.type === OperationType.HTLC_REFUND
|
|
157
|
+
);
|
|
142
158
|
|
|
143
159
|
if (!isDeepEqualApplyPayload(stateTxDecodedFromRequest, strippedValidatorPayload)) {
|
|
144
160
|
throw new V1ProtocolError(
|
|
@@ -168,12 +184,12 @@ class V1BroadcastTransactionResponse extends V1BaseOperation {
|
|
|
168
184
|
}
|
|
169
185
|
|
|
170
186
|
async validateValidatorCorrectness(validatorDecodedTx, connectionRemotePublicKey, writerKeyFromManifest, validatorAddressCorrelatedWithManifest) {
|
|
171
|
-
const validatorAddressFromTx = extractRequiredVaFromDecodedTx(validatorDecodedTx);
|
|
172
187
|
const validatorAddressFromConnectionPublicKey = addressToBuffer(
|
|
173
188
|
publicKeyToAddress(connectionRemotePublicKey, this.#config),
|
|
174
189
|
this.#config.addressPrefix
|
|
175
190
|
);
|
|
176
191
|
|
|
192
|
+
const validatorAddressFromTx = extractRequiredVaFromDecodedTx(validatorDecodedTx);
|
|
177
193
|
if (!b4a.equals(validatorAddressFromTx, validatorAddressFromConnectionPublicKey)) {
|
|
178
194
|
throw new V1ProtocolError(
|
|
179
195
|
ResultCode.VALIDATOR_ADDRESS_MISMATCH,
|
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
NONCE_BYTE_LENGTH,
|
|
6
6
|
SIGNATURE_BYTE_LENGTH,
|
|
7
7
|
MAX_PARTIAL_TX_PAYLOAD_BYTE_SIZE,
|
|
8
|
-
|
|
9
|
-
} from '
|
|
8
|
+
NetworkResultCode
|
|
9
|
+
} from '../../../../../../utils/constants.js';
|
|
10
10
|
|
|
11
|
-
const ALLOWED_RESULT_CODES = Object.values(
|
|
11
|
+
const ALLOWED_RESULT_CODES = Object.values(NetworkResultCode);
|
|
12
12
|
|
|
13
13
|
class V1ValidationSchema {
|
|
14
14
|
#validator;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import tracCryptoApi from 'trac-crypto-api'
|
|
2
|
+
import { PeerConnectionManager } from '../shared/PeerConnectionManager.js'
|
|
3
|
+
import b4a from "b4a"
|
|
4
|
+
import { bufferToAddress } from '../../state/utils/address.js'
|
|
5
|
+
|
|
6
|
+
class IndexerConnectionManager extends PeerConnectionManager {
|
|
7
|
+
#messages
|
|
8
|
+
#state
|
|
9
|
+
#network
|
|
10
|
+
#wallet
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
constructor(maxIndexers, config, logger, messages, state, network, wallet) {
|
|
14
|
+
super(maxIndexers, config, logger);
|
|
15
|
+
this.#messages = messages;
|
|
16
|
+
this.#state = state;
|
|
17
|
+
this.#network = network;
|
|
18
|
+
this.#wallet = wallet;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async add(publicKey, connection) {
|
|
22
|
+
await this.#messages.attachChannel(connection);
|
|
23
|
+
if (connection.destroyed) return;
|
|
24
|
+
if (!connection.protocolSessions?.indexer || connection.protocolSessions.indexer.closed) return;
|
|
25
|
+
this._add(publicKey, connection)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async connect() {
|
|
29
|
+
const entries = await this.#state.getIndexersEntry();
|
|
30
|
+
// Promotion events can precede Autobase's membership update. Refresh the
|
|
31
|
+
// capacity from the same snapshot used for discovery on every retry.
|
|
32
|
+
this.setMax(Math.max(0, entries.length - 1));
|
|
33
|
+
|
|
34
|
+
for (const entry of entries) {
|
|
35
|
+
const writerKeyHex = b4a.toString(entry.key, 'hex');
|
|
36
|
+
const addressBuffer = await this.#state.getRegisteredWriterKey(writerKeyHex);
|
|
37
|
+
if (!addressBuffer) continue;
|
|
38
|
+
|
|
39
|
+
const addr = bufferToAddress(addressBuffer, this._config.addressPrefix);
|
|
40
|
+
if (!addr || addr === this.#wallet.address) continue;
|
|
41
|
+
|
|
42
|
+
const publicKey = tracCryptoApi.address.decode(addr);
|
|
43
|
+
const publicKeyHex = b4a.toString(publicKey, 'hex');
|
|
44
|
+
|
|
45
|
+
const isConnected = this.connected(publicKey);
|
|
46
|
+
const isPending = this.#network.isConnectionPending(publicKeyHex);
|
|
47
|
+
if (isConnected || isPending) continue;
|
|
48
|
+
|
|
49
|
+
await this.#network.tryConnect(publicKeyHex, "indexer");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
remove(publicKey, connection = null) {
|
|
54
|
+
const key = this._toHexString(publicKey);
|
|
55
|
+
const entry = this._connections.get(key);
|
|
56
|
+
if (!entry) return;
|
|
57
|
+
if (connection && entry.connection !== connection) return;
|
|
58
|
+
|
|
59
|
+
const targetConnection = connection ?? entry.connection;
|
|
60
|
+
this._connections.delete(key);
|
|
61
|
+
targetConnection.protocolSessions.indexer?.close();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async send(publicKey, message) {
|
|
65
|
+
const connection = this.getConnection(publicKey);
|
|
66
|
+
if (!connection) {
|
|
67
|
+
throw new Error(`PeerConnectionManager: no session for ${this._toHexString(publicKey)}`);
|
|
68
|
+
}
|
|
69
|
+
if (!connection.connected) {
|
|
70
|
+
this.remove(publicKey, connection);
|
|
71
|
+
throw new Error(`PeerConnectionManager: stale connection for ${this._toHexString(publicKey)}`);
|
|
72
|
+
}
|
|
73
|
+
return connection.protocolSessions.indexer.send(message);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
sendAndForget(publicKey, message) {
|
|
77
|
+
const connection = this.getConnection(publicKey);
|
|
78
|
+
if (!connection) return;
|
|
79
|
+
connection.protocolSessions.indexer.sendAndForget(message);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
prettyPrint() {
|
|
83
|
+
console.log(`Connection count: ${this._connections.size}`);
|
|
84
|
+
console.log(`Indexer map keys:\n${Array.from(this._connections.keys()).join('\n')}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export default IndexerConnectionManager;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// PoolService.js
|
|
2
2
|
import { BATCH_SIZE } from '../../../utils/constants.js';
|
|
3
|
-
import
|
|
3
|
+
import SchedulableService from '../../../utils/scheduler/SchedulableService.js';
|
|
4
4
|
import Denque from "denque";
|
|
5
5
|
import b4a from "b4a";
|
|
6
6
|
|
|
@@ -43,13 +43,12 @@ export class TransactionPoolAlreadyQueuedError extends Error {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
class TransactionPoolService {
|
|
46
|
+
class TransactionPoolService extends SchedulableService {
|
|
47
47
|
#state;
|
|
48
48
|
#address;
|
|
49
49
|
#config;
|
|
50
50
|
#txPool = new Denque();
|
|
51
51
|
#transactionCommitService
|
|
52
|
-
#scheduler = null;
|
|
53
52
|
#queuedTxHashes
|
|
54
53
|
|
|
55
54
|
/**
|
|
@@ -59,6 +58,7 @@ class TransactionPoolService {
|
|
|
59
58
|
* @param {Config} config
|
|
60
59
|
**/
|
|
61
60
|
constructor(state, address, transactionCommitService, config) {
|
|
61
|
+
super();
|
|
62
62
|
this.#state = state;
|
|
63
63
|
this.#address = address;
|
|
64
64
|
this.#transactionCommitService = transactionCommitService;
|
|
@@ -79,16 +79,15 @@ class TransactionPoolService {
|
|
|
79
79
|
console.info('TransactionPoolService can not start. Wallet is not enabled');
|
|
80
80
|
return;
|
|
81
81
|
}
|
|
82
|
-
if (this.#scheduler && this.#scheduler.isRunning) {
|
|
83
|
-
console.info('TransactionPoolService is already started');
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
82
|
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
return super.start();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
getScheduleInterval() {
|
|
87
|
+
return this.#config.processIntervalMs;
|
|
89
88
|
}
|
|
90
89
|
|
|
91
|
-
async
|
|
90
|
+
async worker(next) {
|
|
92
91
|
try {
|
|
93
92
|
await this.#processTransactions();
|
|
94
93
|
if (this.#txPool.size() > 0) {
|
|
@@ -101,10 +100,6 @@ class TransactionPoolService {
|
|
|
101
100
|
}
|
|
102
101
|
}
|
|
103
102
|
|
|
104
|
-
#createScheduler() {
|
|
105
|
-
return new Scheduler((next) => this.#worker(next), this.#config.processIntervalMs);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
103
|
async #processTransactions() {
|
|
109
104
|
const canValidate = await this.#checkValidationPermissions();
|
|
110
105
|
if (!canValidate || this.#txPool.size() === 0) return;
|
|
@@ -187,10 +182,8 @@ class TransactionPoolService {
|
|
|
187
182
|
this.txPool.push(txData);
|
|
188
183
|
}
|
|
189
184
|
|
|
190
|
-
async
|
|
191
|
-
|
|
192
|
-
await this.#scheduler.stop(waitForCurrent);
|
|
193
|
-
this.#scheduler = null;
|
|
185
|
+
async stop(waitForCurrent = true) {
|
|
186
|
+
await super.stop(waitForCurrent);
|
|
194
187
|
this.#queuedTxHashes.clear();
|
|
195
188
|
this.#txPool.clear();
|
|
196
189
|
console.info('TransactionPoolService: closing gracefully...');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import b4a from 'b4a';
|
|
2
|
-
import {V1ProtocolError} from "../protocols/v1/V1ProtocolError.js";
|
|
2
|
+
import {V1ProtocolError} from "../protocols/validators/v1/V1ProtocolError.js";
|
|
3
3
|
import {ResultCode} from "../../../utils/constants.js";
|
|
4
4
|
import {publicKeyToAddress} from "../../../utils/helpers.js";
|
|
5
5
|
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import {EventType, ResultCode} from '../../../utils/constants.js';
|
|
2
|
+
import {publicKeyToAddress} from "../../../utils/helpers.js";
|
|
3
|
+
import { PeerConnectionManager, PeerConnectionManagerError } from '../shared/PeerConnectionManager.js'
|
|
4
|
+
import ValidatorHealthCheckService from './ValidatorHealthCheckService.js'
|
|
5
|
+
|
|
6
|
+
const DEFAULT_HEALTH_CHECK_FAILURE_THRESHOLD = 3;
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {import('hyperswarm').Connection} Connection
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
class ValidatorConnectionManager extends PeerConnectionManager {
|
|
12
|
+
#healthCheckService
|
|
13
|
+
#messages
|
|
14
|
+
#healthCheckFailures = new Map();
|
|
15
|
+
#healthCheckFailureThreshold;
|
|
16
|
+
// Note: _connections is using publicKey (Buffer) as key
|
|
17
|
+
// As Buffers are objects, we will rely on internal conversions done by JS to compare them.
|
|
18
|
+
// It would be better to handle these conversions manually by using hex strings as keys to avoid issues
|
|
19
|
+
/**
|
|
20
|
+
* @param {Config} config
|
|
21
|
+
**/
|
|
22
|
+
constructor(maxValidators, config, logger, messages) {
|
|
23
|
+
super(maxValidators, config, logger, messages);
|
|
24
|
+
this.#messages = messages
|
|
25
|
+
this.#healthCheckService = new ValidatorHealthCheckService(config);
|
|
26
|
+
const threshold = Number(config.validatorHealthCheckFailureThreshold);
|
|
27
|
+
this.#healthCheckFailureThreshold = Number.isInteger(threshold) && threshold > 0
|
|
28
|
+
? threshold : DEFAULT_HEALTH_CHECK_FAILURE_THRESHOLD;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async _open() {
|
|
32
|
+
await this.#healthCheckService.ready();
|
|
33
|
+
this.#subscribeToHealthChecks();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async _close() {
|
|
37
|
+
await this.#healthCheckService.close();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Subscribes to periodic validator health checks.
|
|
42
|
+
* @param {ReadyResource} healthCheckService
|
|
43
|
+
*/
|
|
44
|
+
// TODO: We should consider moving this to ValidatorObserver instead.
|
|
45
|
+
// Keep here only if we forsee having health checks for non-validator connections in the future.
|
|
46
|
+
// For now, it seems that it would be better to keep this logic here.
|
|
47
|
+
#subscribeToHealthChecks() {
|
|
48
|
+
this.#healthCheckService.on(EventType.VALIDATOR_HEALTH_CHECK, async publicKey => {
|
|
49
|
+
if (!this.exists(publicKey) || !this.connected(publicKey)) {
|
|
50
|
+
this.#stopHealthCheck(publicKey);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const connection = this.getConnection(publicKey);
|
|
55
|
+
if (!connection) {
|
|
56
|
+
this.#stopHealthCheck(publicKey);
|
|
57
|
+
this.remove(publicKey);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let success = false;
|
|
62
|
+
try {
|
|
63
|
+
const resultCode = await connection.protocolSessions.validator.sendHealthCheck();
|
|
64
|
+
success = resultCode === ResultCode.OK;
|
|
65
|
+
} catch {
|
|
66
|
+
success = false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// An in-flight health check must not affect a replacement connection.
|
|
70
|
+
if (this.getConnection(publicKey) !== connection) return;
|
|
71
|
+
const publicKeyHex = this._toHexString(publicKey);
|
|
72
|
+
if (!success) {
|
|
73
|
+
const failures = (this.#healthCheckFailures.get(publicKeyHex) ?? 0) + 1;
|
|
74
|
+
this.#healthCheckFailures.set(publicKeyHex, failures);
|
|
75
|
+
if (failures >= this.#healthCheckFailureThreshold) this.remove(publicKey, connection);
|
|
76
|
+
} else {
|
|
77
|
+
this.#healthCheckFailures.delete(publicKeyHex);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
#stopHealthCheck(publicKeyHex) {
|
|
83
|
+
try {
|
|
84
|
+
if (this.#healthCheckService.has(publicKeyHex)) {
|
|
85
|
+
this.#healthCheckService.stop(publicKeyHex);
|
|
86
|
+
}
|
|
87
|
+
} catch {}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async add(publicKey, connection) {
|
|
91
|
+
this.#messages.attachChannel(connection);
|
|
92
|
+
try {
|
|
93
|
+
if (!connection.protocolSessions.validator.isProbed()) {
|
|
94
|
+
await connection.protocolSessions.validator.probe();
|
|
95
|
+
}
|
|
96
|
+
} catch (err) {
|
|
97
|
+
this._logger.error(`failed to probe peer with publicKey ${publicKey}: ${err?.message ?? err}`);
|
|
98
|
+
}
|
|
99
|
+
if (this._add(publicKey, connection)) {
|
|
100
|
+
this.#healthCheckFailures.delete(this._toHexString(publicKey));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (connection.protocolSessions.validator.isHealthCheckSupported()) {
|
|
104
|
+
this.#healthCheckService.start(publicKey);
|
|
105
|
+
} else {
|
|
106
|
+
this.#healthCheckService.stop(publicKey);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
remove(publicKey, connection = null) {
|
|
111
|
+
const publicKeyHex = this._toHexString(publicKey);
|
|
112
|
+
const entry = this._connections.get(publicKeyHex);
|
|
113
|
+
if (!entry) return;
|
|
114
|
+
if (connection && entry.connection !== connection) return;
|
|
115
|
+
|
|
116
|
+
this.#stopHealthCheck(publicKeyHex);
|
|
117
|
+
this.#healthCheckFailures.delete(publicKeyHex);
|
|
118
|
+
this._connections.delete(publicKeyHex);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async sendSingleMessage(message, publicKey) {
|
|
122
|
+
const publicKeyHex = this._toHexString(publicKey);
|
|
123
|
+
if (!this.connected(publicKeyHex)) {
|
|
124
|
+
throw new PeerConnectionManagerError(
|
|
125
|
+
`Cannot send message: peer ${publicKeyToAddress(publicKey, this._config)} is not connected.`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const connection = this.getConnection(publicKeyHex);
|
|
130
|
+
if (!connection) {
|
|
131
|
+
throw new PeerConnectionManagerError(
|
|
132
|
+
`Cannot send message: no valid connection found for peer ${publicKeyToAddress(publicKeyHex, this._config)}.`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return connection.protocolSessions.validator.send(message);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
sendAndForget(publicKey, message) {
|
|
140
|
+
const connection = this.getConnection(publicKey);
|
|
141
|
+
if (!connection) return;
|
|
142
|
+
connection.protocolSessions.validator.sendAndForget(message);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async send(publicKey, message) {
|
|
146
|
+
const connection = this.getConnection(publicKey);
|
|
147
|
+
if (!connection) {
|
|
148
|
+
throw new Error(`PeerConnectionManager: no session for ${this._toHexString(publicKey)}`);
|
|
149
|
+
}
|
|
150
|
+
return connection.protocolSessions.validator.send(message);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
prettyPrint() {
|
|
154
|
+
this._logger.info(`Connection count: ${this.connectionCount()}`);
|
|
155
|
+
this._logger.info(`Validator map keys count: ${this._connections.size}`);
|
|
156
|
+
this._logger.info(`Validator map keys:\n${Array.from(this._connections.entries()).map(([publicKey, val]) => {
|
|
157
|
+
const protocols = val.connection?.protocolSessions?.validator?.preferredProtocol || 'none';
|
|
158
|
+
return `${publicKeyToAddress(publicKey, this._config)}: ${protocols}`;
|
|
159
|
+
}).join('\n')}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export default ValidatorConnectionManager;
|