trac-msb 0.2.9 → 0.2.11
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/CODE_OF_CONDUCT.md +128 -0
- package/README.md +33 -18
- package/docker-compose.yml +1 -0
- package/docs/trac_network_http_api.openapi.yaml +889 -0
- package/msb.mjs +4 -21
- package/package.json +16 -12
- package/proto/network/v1/enums/message_type.proto +16 -0
- package/proto/network/v1/enums/result_code.proto +84 -0
- package/proto/network/v1/messages/broadcast_transaction_request.proto +9 -0
- package/proto/network/v1/messages/broadcast_transaction_response.proto +13 -0
- package/proto/network/v1/messages/liveness_request.proto +8 -0
- package/proto/network/v1/messages/liveness_response.proto +11 -0
- package/proto/network/v1/network_message.proto +22 -0
- package/rpc/handlers.js +163 -90
- package/rpc/routes/v1.js +3 -1
- package/rpc/rpc_server.js +3 -3
- package/rpc/rpc_services.js +45 -31
- package/rpc/utils/helpers.js +82 -51
- package/scripts/generate-protobufs.js +37 -12
- package/src/config/args.js +46 -0
- package/src/config/config.js +99 -5
- package/src/config/env.js +86 -7
- package/src/core/network/Network.js +79 -46
- package/src/core/network/protocols/LegacyProtocol.js +21 -11
- package/src/core/network/protocols/NetworkMessages.js +38 -17
- package/src/core/network/protocols/ProtocolInterface.js +14 -2
- package/src/core/network/protocols/ProtocolSession.js +144 -17
- package/src/core/network/protocols/V1Protocol.js +37 -18
- package/src/core/network/protocols/connectionPolicies.js +88 -0
- package/src/core/network/protocols/legacy/NetworkMessageRouter.js +26 -20
- package/src/core/network/protocols/{shared/handlers/base/BaseOperationHandler.js → legacy/handlers/BaseStateOperationHandler.js} +25 -15
- package/src/core/network/protocols/legacy/handlers/{GetRequestHandler.js → LegacyGetRequestHandler.js} +6 -6
- package/src/core/network/protocols/legacy/handlers/LegacyResponseHandler.js +23 -0
- package/src/core/network/protocols/{shared/handlers/RoleOperationHandler.js → legacy/handlers/LegacyRoleOperationHandler.js} +20 -13
- package/src/core/network/protocols/{shared/handlers/SubnetworkOperationHandler.js → legacy/handlers/LegacySubnetworkOperationHandler.js} +29 -18
- package/src/core/network/protocols/{shared/handlers/TransferOperationHandler.js → legacy/handlers/LegacyTransferOperationHandler.js} +18 -12
- package/src/core/network/protocols/legacy/validators/base/BaseResponse.js +1 -1
- package/src/core/network/protocols/shared/errors/SharedValidatorRejectionError.js +27 -0
- package/src/core/network/protocols/shared/validators/{PartialBootstrapDeployment.js → PartialBootstrapDeploymentValidator.js} +9 -4
- package/src/core/network/protocols/shared/validators/{base/PartialOperation.js → PartialOperationValidator.js} +47 -25
- package/src/core/network/protocols/shared/validators/{PartialRoleAccess.js → PartialRoleAccessValidator.js} +51 -17
- package/src/core/network/protocols/shared/validators/{PartialTransaction.js → PartialTransactionValidator.js} +21 -7
- package/src/core/network/protocols/shared/validators/{PartialTransfer.js → PartialTransferValidator.js} +26 -9
- package/src/core/network/protocols/v1/NetworkMessageRouter.js +91 -7
- package/src/core/network/protocols/v1/V1ProtocolError.js +91 -0
- package/src/core/network/protocols/v1/handlers/V1BaseOperationHandler.js +65 -0
- package/src/core/network/protocols/v1/handlers/V1BroadcastTransactionOperationHandler.js +389 -0
- package/src/core/network/protocols/v1/handlers/V1LivenessOperationHandler.js +87 -0
- package/src/core/network/protocols/v1/validators/V1BaseOperation.js +211 -0
- package/src/core/network/protocols/v1/validators/V1BroadcastTransactionRequest.js +26 -0
- package/src/core/network/protocols/v1/validators/V1BroadcastTransactionResponse.js +276 -0
- package/src/core/network/protocols/v1/validators/V1LivenessRequest.js +15 -0
- package/src/core/network/protocols/v1/validators/V1LivenessResponse.js +17 -0
- package/src/core/network/protocols/v1/validators/V1ValidationSchema.js +210 -0
- package/src/core/network/services/ConnectionManager.js +147 -95
- package/src/core/network/services/MessageOrchestrator.js +152 -28
- package/src/core/network/services/PendingRequestService.js +172 -0
- package/src/core/network/services/TransactionCommitService.js +149 -0
- package/src/core/network/services/TransactionPoolService.js +133 -22
- package/src/core/network/services/TransactionRateLimiterService.js +57 -42
- package/src/core/network/services/ValidatorHealthCheckService.js +127 -0
- package/src/core/network/services/ValidatorObserverService.js +23 -32
- package/src/core/state/State.js +72 -22
- package/src/index.js +8 -5
- package/src/messages/network/v1/NetworkMessageBuilder.js +61 -81
- package/src/messages/network/v1/NetworkMessageDirector.js +16 -50
- package/src/messages/state/ApplyStateMessageBuilder.js +1 -1
- package/src/utils/Scheduler.js +0 -8
- package/src/utils/check.js +1 -1
- package/src/utils/constants.js +68 -19
- package/src/utils/deepEqualApplyPayload.js +40 -0
- package/src/utils/fileUtils.js +13 -0
- package/src/utils/helpers.js +10 -1
- package/src/utils/logger.js +25 -0
- package/src/utils/normalizers.js +38 -0
- package/src/utils/protobuf/networkV1.generated.cjs +2460 -0
- package/src/utils/protobuf/operationHelpers.js +24 -3
- package/src/utils/type.js +26 -0
- package/tests/acceptance/v1/account/account.test.mjs +8 -2
- package/tests/acceptance/v1/balance/balance.test.mjs +1 -2
- package/tests/acceptance/v1/broadcast-transaction/broadcast-transaction.test.mjs +26 -30
- package/tests/acceptance/v1/health/health.test.mjs +33 -0
- package/tests/acceptance/v1/rpc.test.mjs +3 -2
- package/tests/acceptance/v1/tx/tx.test.mjs +50 -17
- package/tests/acceptance/v1/tx-details/tx-details.test.mjs +60 -18
- package/tests/fixtures/check.fixtures.js +33 -32
- package/tests/fixtures/networkV1.fixtures.js +2 -27
- package/tests/fixtures/protobuf.fixtures.js +33 -32
- package/tests/helpers/StateNetworkFactory.js +2 -2
- package/tests/helpers/address.js +6 -0
- package/tests/helpers/autobaseTestHelpers.js +2 -1
- package/tests/helpers/config.js +2 -1
- package/tests/helpers/setupApplyTests.js +6 -10
- package/tests/helpers/transactionPayloads.mjs +2 -2
- package/tests/unit/messages/network/NetworkMessageBuilder.test.js +241 -81
- package/tests/unit/messages/network/NetworkMessageDirector.test.js +225 -81
- package/tests/unit/network/LegacyNetworkMessageRouter.test.js +54 -0
- package/tests/unit/network/ProtocolSession.test.js +127 -0
- package/tests/unit/network/networkModule.test.js +4 -1
- package/tests/unit/network/services/ConnectionManager.test.js +450 -0
- package/tests/unit/network/services/MessageOrchestrator.test.js +445 -0
- package/tests/unit/network/services/PendingRequestService.test.js +431 -0
- package/tests/unit/network/services/TransactionCommitService.test.js +246 -0
- package/tests/unit/network/services/TransactionPoolService.test.js +489 -0
- package/tests/unit/network/services/TransactionRateLimiterService.test.js +139 -0
- package/tests/unit/network/services/ValidatorHealthCheckService.test.js +115 -0
- package/tests/unit/network/services/services.test.js +17 -0
- package/tests/unit/network/utils/v1TestUtils.js +153 -0
- package/tests/unit/network/v1/NetworkMessageRouterV1.test.js +151 -0
- package/tests/unit/network/v1/V1BaseOperation.test.js +356 -0
- package/tests/unit/network/v1/V1BroadcastTransactionOperationHandler.test.js +129 -0
- package/tests/unit/network/v1/V1BroadcastTransactionRequest.test.js +53 -0
- package/tests/unit/network/v1/V1BroadcastTransactionResponse.test.js +512 -0
- package/tests/unit/network/v1/V1LivenessRequest.test.js +32 -0
- package/tests/unit/network/v1/V1LivenessResponse.test.js +45 -0
- package/tests/unit/network/v1/V1ResultCode.test.js +84 -0
- package/tests/unit/network/v1/V1ValidationSchema.test.js +13 -0
- package/tests/unit/network/v1/connectionPolicies.test.js +49 -0
- package/tests/unit/network/v1/handlers/V1BaseOperationHandler.test.js +284 -0
- package/tests/unit/network/v1/handlers/V1BroadcastTransactionOperationHandler.test.js +794 -0
- package/tests/unit/network/v1/handlers/V1LivenessOperationHandler.test.js +193 -0
- package/tests/unit/network/v1/v1.handlers.test.js +15 -0
- package/tests/unit/network/v1/v1.test.js +19 -0
- package/tests/unit/network/v1/v1ValidationSchema/broadcastTransactionRequest.test.js +119 -0
- package/tests/unit/network/v1/v1ValidationSchema/broadcastTransactionResponse.test.js +136 -0
- package/tests/unit/network/v1/v1ValidationSchema/common.test.js +308 -0
- package/tests/unit/network/v1/v1ValidationSchema/livenessRequest.test.js +90 -0
- package/tests/unit/network/v1/v1ValidationSchema/livenessResponse.test.js +133 -0
- package/tests/unit/unit.test.js +2 -2
- package/tests/unit/utils/deepEqualApplyPayload/deepEqualApplyPayload.test.js +102 -0
- package/tests/unit/utils/fileUtils/readAddressesFromWhitelistFile.test.js +4 -3
- package/tests/unit/utils/fileUtils/readBalanceMigrationFile.test.js +3 -2
- package/tests/unit/utils/migrationUtils/validateAddressFromIncomingFile.test.js +3 -2
- package/tests/unit/utils/protobuf/operationHelpers.test.js +2 -4
- package/tests/unit/utils/type/type.test.js +25 -0
- package/tests/unit/utils/utils.test.js +2 -0
- package/.github/workflows/acceptance-tests.yml +0 -42
- package/.github/workflows/publish.yml +0 -33
- package/.github/workflows/unit-tests.yml +0 -40
- package/proto/network.proto +0 -74
- package/src/core/network/protocols/legacy/handlers/ResponseHandler.js +0 -37
- package/src/utils/protobuf/network.cjs +0 -840
- package/tests/unit/network/ConnectionManager.test.js +0 -191
package/src/config/env.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { TRAC_NETWORK_MSB_MAINNET_PREFIX } from 'trac-wallet/constants.js';
|
|
1
|
+
import { TRAC_NETWORK_MSB_MAINNET_PREFIX, TRAC_NETWORK_MSB_TESTNET1_PREFIX } from 'trac-wallet/constants.js';
|
|
2
|
+
import { TRAC_NETWORK_TESTNET_ID, TRAC_NETWORK_MAINNET_ID } from 'trac-crypto-api/constants.js';
|
|
2
3
|
import { Config } from './config.js';
|
|
3
4
|
|
|
4
5
|
export const ENV = {
|
|
@@ -6,11 +7,52 @@ export const ENV = {
|
|
|
6
7
|
DEVELOPMENT: 'development',
|
|
7
8
|
TESTNET1: 'testnet1'
|
|
8
9
|
}
|
|
9
|
-
// TODO: CREATE TEST ENV CONFIG SIMILAR TO MAINNET AND USE IT IN TESTS.
|
|
10
|
-
// TODO: CREATE TESTNET1 ENV CONFIG and update npm scripts to run node witn mainnet or testnet1.
|
|
11
10
|
|
|
12
11
|
const configData = {
|
|
12
|
+
[ENV.TESTNET1]: {
|
|
13
|
+
debug: false,
|
|
14
|
+
addressLength: 67,
|
|
15
|
+
addressPrefix: TRAC_NETWORK_MSB_TESTNET1_PREFIX,
|
|
16
|
+
addressPrefixLength: TRAC_NETWORK_MSB_TESTNET1_PREFIX.length,
|
|
17
|
+
bech32mHrpLength: TRAC_NETWORK_MSB_TESTNET1_PREFIX.length + 1, // len(addressPrefix + separator)
|
|
18
|
+
bootstrap: 'a7c0c2cf8e4722129097f89b2a29a092f23d6268fcca3fd9570ba5b702b99b95',
|
|
19
|
+
channel: '1111trac1network1msb1testnet1111',
|
|
20
|
+
dhtBootstrap: ['116.202.214.149:10001', '157.180.12.214:10001', 'node1.hyperdht.org:49737', 'node2.hyperdht.org:49737', 'node3.hyperdht.org:49737'], // these are used to peer discovery
|
|
21
|
+
disableRateLimit: false,
|
|
22
|
+
enableErrorApplyLogs: true,
|
|
23
|
+
enableInteractiveMode: true,
|
|
24
|
+
enableRoleRequester: false,
|
|
25
|
+
enableTxApplyLogs: true,
|
|
26
|
+
enableValidatorObserver: true,
|
|
27
|
+
enableWallet: true,
|
|
28
|
+
maxValidators: 50,
|
|
29
|
+
maxRetries: 3,
|
|
30
|
+
messageThreshold: 3,
|
|
31
|
+
messageValidatorRetryDelay: 1000, //How long to wait before retrying (ms) MESSAGE_VALIDATOR_RETRY_DELAY_MS
|
|
32
|
+
messageValidatorResponseTimeout: 3 * 3 * 1000, //Overall timeout for sending a message (ms). This is 3 * maxRetries * messageValidatorRetryDelay;
|
|
33
|
+
host: 'localhost',
|
|
34
|
+
port: 5000,
|
|
35
|
+
networkId: TRAC_NETWORK_TESTNET_ID,
|
|
36
|
+
maxPeers: 64, // Connectivity constants
|
|
37
|
+
maxParallel: 64, // Connectivity constants
|
|
38
|
+
maxServerConnections: Infinity, // Connectivity constants
|
|
39
|
+
maxClientConnections: Infinity, // Connectivity constants
|
|
40
|
+
maxWritersForAdminIndexerConnection: 10, // Connectivity constants
|
|
41
|
+
processIntervalMs: 50, // Pool constants
|
|
42
|
+
transactionPoolSize: 1000, // Operation handler constants
|
|
43
|
+
rateLimitCleanupIntervalMs: 120_000, // Rate limiting constants
|
|
44
|
+
rateLimitConnectionTimeoutMs: 60_000, // Rate limiting constants
|
|
45
|
+
rateLimitMaxTransactionsPerSecond: 50, // Rate limiting constants
|
|
46
|
+
maxPendingRequestsInPendingRequestsService: 50_000, // Maximum number of pending requests in PendingRequestService (This value should not exceed 256MB)
|
|
47
|
+
pendingRequestTimeout: 3000, // constant after which time the transaction will be considered invalid
|
|
48
|
+
txCommitTimeout: 2200,
|
|
49
|
+
txPoolSize: 1000, // size of transaction pool
|
|
50
|
+
validatorHealthCheckInterval: 5 * 60 * 1000, // How often to check validator health (ms)
|
|
51
|
+
storesDirectory: 'stores/',
|
|
52
|
+
storeName: 'testnet',
|
|
53
|
+
},
|
|
13
54
|
[ENV.MAINNET]: {
|
|
55
|
+
debug: false,
|
|
14
56
|
addressLength: 63,
|
|
15
57
|
addressPrefix: TRAC_NETWORK_MSB_MAINNET_PREFIX,
|
|
16
58
|
addressPrefixLength: TRAC_NETWORK_MSB_MAINNET_PREFIX.length,
|
|
@@ -30,10 +72,29 @@ const configData = {
|
|
|
30
72
|
messageThreshold: 3,
|
|
31
73
|
messageValidatorRetryDelay: 1000, //How long to wait before retrying (ms) MESSAGE_VALIDATOR_RETRY_DELAY_MS
|
|
32
74
|
messageValidatorResponseTimeout: 3 * 3 * 1000, //Overall timeout for sending a message (ms). This is 3 * maxRetries * messageValidatorRetryDelay;
|
|
33
|
-
|
|
75
|
+
host: 'localhost',
|
|
76
|
+
port: 5000,
|
|
77
|
+
networkId: TRAC_NETWORK_MAINNET_ID,
|
|
78
|
+
maxPeers: 64, // Connectivity constants
|
|
79
|
+
maxParallel: 64, // Connectivity constants
|
|
80
|
+
maxServerConnections: Infinity, // Connectivity constants
|
|
81
|
+
maxClientConnections: Infinity, // Connectivity constants
|
|
82
|
+
maxWritersForAdminIndexerConnection: 10, // Connectivity constants
|
|
83
|
+
processIntervalMs: 50, // Pool constants
|
|
84
|
+
transactionPoolSize: 1000, // Operation handler constants
|
|
85
|
+
rateLimitCleanupIntervalMs: 120_000, // Rate limiting constants
|
|
86
|
+
rateLimitConnectionTimeoutMs: 60_000, // Rate limiting constants
|
|
87
|
+
rateLimitMaxTransactionsPerSecond: 50, // Rate limiting constants
|
|
88
|
+
maxPendingRequestsInPendingRequestsService: 50_000, // Maximum number of pending requests in PendingRequestService (This value should not exceed 256MB)
|
|
89
|
+
pendingRequestTimeout: 3000, // constant after which time the transaction will be considered invalid
|
|
90
|
+
txCommitTimeout: 2200,
|
|
91
|
+
txPoolSize: 1000, // size of transaction pool
|
|
92
|
+
validatorHealthCheckInterval: 5 * 60 * 1000, // How often to check validator health (ms)
|
|
34
93
|
storesDirectory: 'stores/',
|
|
94
|
+
storeName: 'mainnet',
|
|
35
95
|
},
|
|
36
96
|
[ENV.DEVELOPMENT]: {
|
|
97
|
+
debug: true,
|
|
37
98
|
addressLength: 63,
|
|
38
99
|
addressPrefix: TRAC_NETWORK_MSB_MAINNET_PREFIX,
|
|
39
100
|
addressPrefixLength: TRAC_NETWORK_MSB_MAINNET_PREFIX.length,
|
|
@@ -49,12 +110,30 @@ const configData = {
|
|
|
49
110
|
enableValidatorObserver: true,
|
|
50
111
|
enableWallet: true,
|
|
51
112
|
maxValidators: 6,
|
|
52
|
-
maxRetries:
|
|
113
|
+
maxRetries: 3,
|
|
53
114
|
messageThreshold: 1000,
|
|
54
115
|
messageValidatorRetryDelay: 1000, //How long to wait before retrying (ms) MESSAGE_VALIDATOR_RETRY_DELAY_MS
|
|
55
116
|
messageValidatorResponseTimeout: 3 * 3 * 1000, //Overall timeout for sending a message (ms). This is 3 * maxRetries * messageValidatorRetryDelay;
|
|
56
|
-
|
|
57
|
-
|
|
117
|
+
host: 'localhost',
|
|
118
|
+
port: 5000,
|
|
119
|
+
networkId: TRAC_NETWORK_TESTNET_ID,
|
|
120
|
+
maxPeers: 64, // Connectivity constants
|
|
121
|
+
maxParallel: 64, // Connectivity constants
|
|
122
|
+
maxServerConnections: Infinity, // Connectivity constants
|
|
123
|
+
maxClientConnections: Infinity, // Connectivity constants
|
|
124
|
+
maxWritersForAdminIndexerConnection: 10, // Connectivity constants
|
|
125
|
+
processIntervalMs: 50, // Pool constants
|
|
126
|
+
transactionPoolSize: 1000, // Operation handler constants
|
|
127
|
+
rateLimitCleanupIntervalMs: 120_000, // Rate limiting constants
|
|
128
|
+
rateLimitConnectionTimeoutMs: 60_000, // Rate limiting constants
|
|
129
|
+
rateLimitMaxTransactionsPerSecond: 50, // Rate limiting constants
|
|
130
|
+
maxPendingRequestsInPendingRequestsService: 50_000, // Maximum number of pending requests in PendingRequestService (This value should not exceed 256MB)
|
|
131
|
+
pendingRequestTimeout: 3000, // constant after which time the transaction will be considered invalid
|
|
132
|
+
txCommitTimeout: 2200,
|
|
133
|
+
txPoolSize: 1000, // size of transaction pool
|
|
134
|
+
validatorHealthCheckInterval: 5 * 60 * 1000, // How often to check validator health (ms)
|
|
135
|
+
storesDirectory: 'stores/',
|
|
136
|
+
storeName: 'development',
|
|
58
137
|
}
|
|
59
138
|
}
|
|
60
139
|
|
|
@@ -8,26 +8,16 @@ import NetworkMessages from './protocols/NetworkMessages.js';
|
|
|
8
8
|
import { sleep } from '../../utils/helpers.js';
|
|
9
9
|
import {
|
|
10
10
|
TRAC_NAMESPACE,
|
|
11
|
-
|
|
12
|
-
MAX_PARALLEL,
|
|
13
|
-
MAX_SERVER_CONNECTIONS,
|
|
14
|
-
MAX_CLIENT_CONNECTIONS,
|
|
15
|
-
NETWORK_MESSAGE_TYPES
|
|
11
|
+
EventType
|
|
16
12
|
} from '../../utils/constants.js';
|
|
17
13
|
import ConnectionManager from './services/ConnectionManager.js';
|
|
18
14
|
import MessageOrchestrator from './services/MessageOrchestrator.js';
|
|
19
15
|
import NetworkWalletFactory from './identity/NetworkWalletFactory.js';
|
|
20
|
-
import { EventType } from '../../utils/constants.js';
|
|
21
|
-
import { networkMessageFactory } from '../../messages/network/v1/networkMessageFactory.js';
|
|
22
16
|
import TransactionRateLimiterService from './services/TransactionRateLimiterService.js';
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (DEBUG) {
|
|
28
|
-
console.log('DEBUG [Network] ==> ', ...args);
|
|
29
|
-
}
|
|
30
|
-
};
|
|
17
|
+
import PendingRequestService from './services/PendingRequestService.js';
|
|
18
|
+
import TransactionCommitService from "./services/TransactionCommitService.js";
|
|
19
|
+
import ValidatorHealthCheckService from './services/ValidatorHealthCheckService.js';
|
|
20
|
+
import { Logger } from '../../utils/logger.js';
|
|
31
21
|
|
|
32
22
|
const wakeup = new w();
|
|
33
23
|
|
|
@@ -44,10 +34,15 @@ class Network extends ReadyResource {
|
|
|
44
34
|
#connectTimeoutMs;
|
|
45
35
|
#maxPendingConnections;
|
|
46
36
|
#rateLimiter;
|
|
37
|
+
#pendingRequestsService;
|
|
38
|
+
#transactionCommitService;
|
|
39
|
+
#wallet;
|
|
40
|
+
#validatorHealthCheckService;
|
|
41
|
+
#logger;
|
|
47
42
|
|
|
48
43
|
/**
|
|
49
44
|
* @param {State} state
|
|
50
|
-
* @param {
|
|
45
|
+
* @param {Config} config
|
|
51
46
|
* @param {string} address
|
|
52
47
|
**/
|
|
53
48
|
constructor(state, config, address = null) {
|
|
@@ -56,11 +51,13 @@ class Network extends ReadyResource {
|
|
|
56
51
|
this.#connectTimeoutMs = config.connectTimeoutMs || 5000;
|
|
57
52
|
this.#maxPendingConnections = config.maxPendingConnections || 50;
|
|
58
53
|
this.#pendingConnections = new Map();
|
|
59
|
-
this.#
|
|
54
|
+
this.#transactionCommitService = new TransactionCommitService(this.#config);
|
|
55
|
+
this.#transactionPoolService = new TransactionPoolService(state, address, this.#transactionCommitService ,this.#config);
|
|
60
56
|
this.#validatorObserverService = new ValidatorObserverService(this, state, address, this.#config);
|
|
61
57
|
this.#validatorConnectionManager = new ConnectionManager(this.#config);
|
|
62
58
|
this.#validatorMessageOrchestrator = new MessageOrchestrator(this.#validatorConnectionManager, state, this.#config);
|
|
63
|
-
|
|
59
|
+
this.#pendingRequestsService = new PendingRequestService(this.#config);
|
|
60
|
+
this.#logger = new Logger(this.#config);
|
|
64
61
|
}
|
|
65
62
|
|
|
66
63
|
get swarm() {
|
|
@@ -84,7 +81,7 @@ class Network extends ReadyResource {
|
|
|
84
81
|
}
|
|
85
82
|
|
|
86
83
|
async _open() {
|
|
87
|
-
|
|
84
|
+
this.#logger.info('Network initialization...');
|
|
88
85
|
|
|
89
86
|
this.setupNetworkListeners();
|
|
90
87
|
|
|
@@ -93,15 +90,19 @@ class Network extends ReadyResource {
|
|
|
93
90
|
}
|
|
94
91
|
|
|
95
92
|
async _close() {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
this.transactionPoolService.stopPool();
|
|
93
|
+
this.#logger.info('Network: closing gracefully...');
|
|
94
|
+
await this.transactionPoolService.stopPool();
|
|
99
95
|
await sleep(100);
|
|
100
|
-
this.#validatorObserverService.stopValidatorObserver();
|
|
96
|
+
await this.#validatorObserverService.stopValidatorObserver();
|
|
101
97
|
await sleep(5_000);
|
|
98
|
+
if (this.#validatorHealthCheckService) {
|
|
99
|
+
await this.#validatorHealthCheckService.close();
|
|
100
|
+
}
|
|
102
101
|
|
|
103
102
|
this.cleanupNetworkListeners();
|
|
104
103
|
this.cleanupPendingConnections();
|
|
104
|
+
this.#pendingRequestsService.close();
|
|
105
|
+
this.#transactionCommitService.close();
|
|
105
106
|
|
|
106
107
|
if (this.#swarm !== null) {
|
|
107
108
|
this.#swarm.destroy();
|
|
@@ -109,23 +110,41 @@ class Network extends ReadyResource {
|
|
|
109
110
|
}
|
|
110
111
|
|
|
111
112
|
setupNetworkListeners() {
|
|
112
|
-
// VALIDATOR_CONNECTION_TIMEOUT
|
|
113
113
|
this.on(EventType.VALIDATOR_CONNECTION_TIMEOUT, ({ publicKey, type, timeoutMs }) => {
|
|
114
|
-
|
|
114
|
+
this.#logger.debug(`Network Event: VALIDATOR_CONNECTION_TIMEOUT | PublicKey: ${publicKey} | Type: ${type} | TimeoutMs: ${timeoutMs}`);
|
|
115
115
|
this.#pendingConnections.delete(publicKey);
|
|
116
116
|
});
|
|
117
117
|
|
|
118
|
-
// VALIDATOR_CONNECTION_READY
|
|
119
118
|
this.on(EventType.VALIDATOR_CONNECTION_READY, async ({ publicKey, type, connection }) => {
|
|
120
|
-
|
|
119
|
+
this.#logger.debug(`Network Event: VALIDATOR_CONNECTION_READY | PublicKey: ${publicKey} | Type: ${type}`);
|
|
121
120
|
const { timeoutId } = this.#pendingConnections.get(publicKey);
|
|
121
|
+
|
|
122
122
|
if (!timeoutId) return;
|
|
123
123
|
|
|
124
124
|
clearTimeout(timeoutId);
|
|
125
125
|
this.#pendingConnections.delete(publicKey);
|
|
126
126
|
|
|
127
127
|
if (type === 'validator') {
|
|
128
|
-
|
|
128
|
+
try {
|
|
129
|
+
await connection.protocolSession.probe();
|
|
130
|
+
} catch (err) {
|
|
131
|
+
this.#logger.debug(`failed to probe peer with publicKey ${publicKey}: ${err?.message ?? err}`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
this.#validatorConnectionManager.addValidator(publicKey, connection);
|
|
135
|
+
|
|
136
|
+
let healthCheckSupported = false;
|
|
137
|
+
try {
|
|
138
|
+
healthCheckSupported = connection.protocolSession.isHealthCheckSupported();
|
|
139
|
+
} catch (err) {
|
|
140
|
+
this.#logger.debug(`health check support unknown for peer with publicKey ${publicKey}: ${err?.message ?? err}`);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (healthCheckSupported) {
|
|
144
|
+
this.#validatorHealthCheckService.start(publicKey);
|
|
145
|
+
} else {
|
|
146
|
+
this.#validatorHealthCheckService.stop(publicKey);
|
|
147
|
+
}
|
|
129
148
|
}
|
|
130
149
|
|
|
131
150
|
});
|
|
@@ -150,27 +169,33 @@ class Network extends ReadyResource {
|
|
|
150
169
|
) {
|
|
151
170
|
if (!this.#swarm) {
|
|
152
171
|
const keyPair = await this.initializeNetworkingKeyPair(store, wallet);
|
|
153
|
-
|
|
172
|
+
this.#wallet = this.#getNetworkWalletWrapper(wallet, keyPair);
|
|
173
|
+
this.#validatorMessageOrchestrator.setWallet(this.#wallet);
|
|
174
|
+
|
|
154
175
|
this.#swarm = new Hyperswarm({
|
|
155
176
|
keyPair,
|
|
156
177
|
bootstrap: this.#config.dhtBootstrap,
|
|
157
|
-
maxPeers:
|
|
158
|
-
maxParallel:
|
|
159
|
-
maxServerConnections:
|
|
160
|
-
maxClientConnections:
|
|
178
|
+
maxPeers: this.#config.maxPeers,
|
|
179
|
+
maxParallel: this.#config.maxParallel,
|
|
180
|
+
maxServerConnections: this.#config.maxServerConnections,
|
|
181
|
+
maxClientConnections: this.#config.maxClientConnections
|
|
161
182
|
});
|
|
162
183
|
|
|
163
|
-
this.#rateLimiter = new TransactionRateLimiterService(this.#swarm);
|
|
184
|
+
this.#rateLimiter = new TransactionRateLimiterService(this.#swarm, this.#config);
|
|
164
185
|
this.#networkMessages = new NetworkMessages(
|
|
165
186
|
state,
|
|
166
|
-
|
|
187
|
+
this.#wallet,
|
|
167
188
|
this.#rateLimiter,
|
|
168
189
|
this.#transactionPoolService,
|
|
169
|
-
this.#
|
|
190
|
+
this.#pendingRequestsService,
|
|
191
|
+
this.#transactionCommitService,
|
|
170
192
|
this.#config
|
|
171
193
|
);
|
|
194
|
+
this.#validatorHealthCheckService = new ValidatorHealthCheckService(this.#config);
|
|
195
|
+
await this.#validatorHealthCheckService.ready();
|
|
196
|
+
this.#validatorConnectionManager.subscribeToHealthChecks(this.#validatorHealthCheckService);
|
|
172
197
|
|
|
173
|
-
|
|
198
|
+
this.#logger.info(`Channel: ${b4a.toString(this.#config.channel)}`);
|
|
174
199
|
|
|
175
200
|
this.#swarm.on('connection', async (connection) => {
|
|
176
201
|
// Per-peer connection initialization:
|
|
@@ -189,12 +214,20 @@ class Network extends ReadyResource {
|
|
|
189
214
|
}
|
|
190
215
|
|
|
191
216
|
connection.on('close', () => {
|
|
217
|
+
this.#pendingRequestsService.rejectPendingRequestsForPeer(
|
|
218
|
+
publicKey,
|
|
219
|
+
new Error('Connection closed before response')
|
|
220
|
+
);
|
|
192
221
|
this.#swarm.leavePeer(connection.remotePublicKey);
|
|
193
222
|
this.#validatorConnectionManager.remove(publicKey);
|
|
194
223
|
connection.protocolSession.close();
|
|
195
224
|
});
|
|
196
225
|
|
|
197
226
|
connection.on('error', (error) => {
|
|
227
|
+
this.#pendingRequestsService.rejectPendingRequestsForPeer(
|
|
228
|
+
publicKey,
|
|
229
|
+
error ?? new Error('Connection error before response')
|
|
230
|
+
);
|
|
198
231
|
if (
|
|
199
232
|
error && error.message && (
|
|
200
233
|
error.message.includes('connection reset by peer') ||
|
|
@@ -204,7 +237,7 @@ class Network extends ReadyResource {
|
|
|
204
237
|
// TODO: decide if we want to handle this error in a specific way. It generates a lot of logs.
|
|
205
238
|
return;
|
|
206
239
|
}
|
|
207
|
-
|
|
240
|
+
this.#logger.error(error?.message ?? 'Unknown network connection error');
|
|
208
241
|
});
|
|
209
242
|
|
|
210
243
|
});
|
|
@@ -236,7 +269,7 @@ class Network extends ReadyResource {
|
|
|
236
269
|
async tryConnect(publicKey, type = null) {
|
|
237
270
|
if (this.#swarm === null) throw new Error('Network swarm is not initialized');
|
|
238
271
|
if (this.#pendingConnections.has(publicKey) || this.#pendingConnections.size >= this.#maxPendingConnections) {
|
|
239
|
-
|
|
272
|
+
this.#logger.debug(`Network.tryConnect: Connection to peer: ${publicKey} as type: ${type} is already pending or max pending connections reached.`);
|
|
240
273
|
return;
|
|
241
274
|
}
|
|
242
275
|
|
|
@@ -254,21 +287,21 @@ class Network extends ReadyResource {
|
|
|
254
287
|
const peerInfo = this.#swarm.peers.get(publicKey);
|
|
255
288
|
if (peerInfo) {
|
|
256
289
|
const connection = this.#swarm._allConnections.get(peerInfo.publicKey);
|
|
257
|
-
|
|
290
|
+
|
|
291
|
+
if (connection &&
|
|
292
|
+
connection.protocolSession &&
|
|
293
|
+
!connection.protocolSession.isProbed() &&
|
|
294
|
+
!this.#pendingRequestsService.isProbePending(connection.remotePublicKey.toString('hex'))
|
|
295
|
+
) {
|
|
258
296
|
await this.#finalizeConnection(publicKey, type, connection);
|
|
259
297
|
}
|
|
260
298
|
}
|
|
261
299
|
}
|
|
262
300
|
|
|
263
|
-
async isConnected(publicKey) {
|
|
264
|
-
return this.#swarm.peers.has(publicKey) &&
|
|
265
|
-
this.#swarm.peers.get(publicKey).connectedTime != -1
|
|
266
|
-
}
|
|
267
|
-
|
|
268
301
|
async #finalizeConnection(publicKey, type, connection) {
|
|
269
302
|
if (!this.#pendingConnections.has(publicKey)) return;
|
|
270
303
|
this.emit(EventType.VALIDATOR_CONNECTION_READY, { publicKey, type, connection });
|
|
271
|
-
|
|
304
|
+
this.#logger.debug(`Network.finalizeConnection: Connected to peer: ${publicKey} as type: ${type}`);
|
|
272
305
|
}
|
|
273
306
|
|
|
274
307
|
#getNetworkWalletWrapper(wallet, keyPair) {
|
|
@@ -9,8 +9,8 @@ class LegacyProtocol extends ProtocolInterface {
|
|
|
9
9
|
#config;
|
|
10
10
|
#router;
|
|
11
11
|
|
|
12
|
-
constructor(router, connection, config) {
|
|
13
|
-
super(router, connection, config);
|
|
12
|
+
constructor(router, connection, pendingRequestServiceInstance = null, config) {
|
|
13
|
+
super(router, connection, pendingRequestServiceInstance, config);
|
|
14
14
|
this.#config = config;
|
|
15
15
|
this.#router = router;
|
|
16
16
|
this.init(connection);
|
|
@@ -41,20 +41,30 @@ class LegacyProtocol extends ProtocolInterface {
|
|
|
41
41
|
this.#session = this.#channel.addMessage({
|
|
42
42
|
encoding: c.json,
|
|
43
43
|
onmessage: async (incomingMessage) => {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
this.#router.route(incomingMessage, connection).catch((err) => {
|
|
45
|
+
console.error(`LegacyProtocol: unhandled router error: ${err.message}`);
|
|
46
|
+
try {
|
|
47
|
+
connection.end();
|
|
48
|
+
} catch {
|
|
49
49
|
}
|
|
50
|
-
}
|
|
51
|
-
console.error(`NetworkMessages: Failed to handle incoming message: ${error.message}`);
|
|
52
|
-
}
|
|
50
|
+
});
|
|
53
51
|
}
|
|
54
52
|
});
|
|
55
53
|
}
|
|
56
54
|
|
|
57
|
-
|
|
55
|
+
// TODO: Legacy protocol does not require encoding. Consider removing this method after refactoring v1 and the protocol interface
|
|
56
|
+
decode(message) {
|
|
57
|
+
// No-op for legacy protocol
|
|
58
|
+
return message;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async send(message) {
|
|
62
|
+
this.sendAndForget(message);
|
|
63
|
+
// TODO: Change 'null' to an appropriate response if needed in the future
|
|
64
|
+
return Promise.resolve(null); // This is to maintain consistency with the ProtocolInterface and v1 protocol.
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
sendAndForget(message) {
|
|
58
68
|
this.#session.send(message);
|
|
59
69
|
}
|
|
60
70
|
|
|
@@ -1,47 +1,68 @@
|
|
|
1
|
-
|
|
2
|
-
import b4a from 'b4a';
|
|
3
1
|
import NetworkMessageRouter from './legacy/NetworkMessageRouter.js';
|
|
4
2
|
import NetworkMessageRouterV1 from './v1/NetworkMessageRouter.js';
|
|
5
3
|
import ProtocolSession from './ProtocolSession.js';
|
|
6
4
|
import LegacyProtocol from './LegacyProtocol.js';
|
|
7
5
|
import V1Protocol from './V1Protocol.js';
|
|
6
|
+
|
|
8
7
|
class NetworkMessages {
|
|
9
8
|
#legacyMessageRouter;
|
|
10
9
|
#v1MessageRouter;
|
|
11
10
|
#config;
|
|
11
|
+
#wallet;
|
|
12
|
+
#pendingRequestsService;
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
constructor(
|
|
15
|
+
state,
|
|
16
|
+
wallet,
|
|
17
|
+
rateLimiterService,
|
|
18
|
+
txPoolService,
|
|
19
|
+
pendingRequestsService,
|
|
20
|
+
transactionCommitService,
|
|
21
|
+
config
|
|
22
|
+
) {
|
|
17
23
|
this.#config = config;
|
|
18
|
-
this.#
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
#initializeMessageRouter(state, wallet, rateLimiterService, txPoolService, connectionManager) {
|
|
24
|
+
this.#wallet = wallet;
|
|
25
|
+
this.#pendingRequestsService = pendingRequestsService;
|
|
22
26
|
this.#legacyMessageRouter = new NetworkMessageRouter(
|
|
23
27
|
state,
|
|
24
28
|
wallet,
|
|
25
29
|
rateLimiterService,
|
|
26
30
|
txPoolService,
|
|
27
|
-
connectionManager,
|
|
28
31
|
this.#config
|
|
29
32
|
);
|
|
30
|
-
|
|
33
|
+
|
|
34
|
+
this.#v1MessageRouter = new NetworkMessageRouterV1(
|
|
35
|
+
state,
|
|
36
|
+
wallet,
|
|
37
|
+
rateLimiterService,
|
|
38
|
+
txPoolService,
|
|
39
|
+
pendingRequestsService,
|
|
40
|
+
transactionCommitService,
|
|
41
|
+
this.#config
|
|
42
|
+
);
|
|
31
43
|
}
|
|
32
44
|
|
|
33
45
|
async setupProtomuxMessages(connection) {
|
|
34
46
|
// Attach a Protomux instance to this Hyperswarm connection.
|
|
35
47
|
// Protomux multiplexes multiple logical protocol channels over a single encrypted stream.
|
|
36
48
|
|
|
37
|
-
const legacyProtocol = new LegacyProtocol(
|
|
38
|
-
|
|
49
|
+
const legacyProtocol = new LegacyProtocol(
|
|
50
|
+
this.#legacyMessageRouter,
|
|
51
|
+
connection,
|
|
52
|
+
null,
|
|
53
|
+
this.#config
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const v1Protocol = new V1Protocol(
|
|
57
|
+
this.#v1MessageRouter,
|
|
58
|
+
connection,
|
|
59
|
+
this.#pendingRequestsService,
|
|
60
|
+
this.#config
|
|
61
|
+
);
|
|
39
62
|
|
|
40
63
|
// ProtocolSession is attached to the Hyperswarm connection so other parts of the system (e.g. tryConnect)
|
|
41
64
|
// can send messages without knowing how Protomux was initialized.
|
|
42
|
-
|
|
43
|
-
connection.protocolSession = protocolSession;
|
|
44
|
-
|
|
65
|
+
connection.protocolSession = new ProtocolSession(legacyProtocol, v1Protocol, this.#wallet, this.#config);
|
|
45
66
|
}
|
|
46
67
|
}
|
|
47
68
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
class ProtocolInterface {
|
|
7
7
|
|
|
8
8
|
// TODO: Refactor this so we don't need to pass a reference for the whole network instance
|
|
9
|
-
constructor(router, connection, config) {
|
|
9
|
+
constructor(router, connection, pendingRequestService, config) {
|
|
10
10
|
if (new.target === ProtocolInterface) {
|
|
11
11
|
throw new Error('ProtocolInterface cannot be instantiated directly');
|
|
12
12
|
}
|
|
@@ -17,11 +17,23 @@ class ProtocolInterface {
|
|
|
17
17
|
throw new Error('init() method must be implemented by subclass');
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
// TODO: This method is only kept here because of v1, but it should be probably removed from the interface
|
|
21
|
+
// Remove it after we finish refactoring v1 protocol
|
|
22
|
+
decode(message) {
|
|
23
|
+
// Abstract method. Need to be implemented by subclasses.
|
|
24
|
+
throw new Error('decode() method must be implemented by subclass');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async send(message) {
|
|
21
28
|
// Abstract method. Need to be implemented by subclasses.
|
|
22
29
|
throw new Error('send() method must be implemented by subclass');
|
|
23
30
|
}
|
|
24
31
|
|
|
32
|
+
sendAndForget(message) {
|
|
33
|
+
// Abstract method. Need to be implemented by subclasses.
|
|
34
|
+
throw new Error('sendAndForget() method must be implemented by subclass');
|
|
35
|
+
}
|
|
36
|
+
|
|
25
37
|
close() {
|
|
26
38
|
// Abstract method. Need to be implemented by subclasses.
|
|
27
39
|
throw new Error('close() method must be implemented by subclass');
|