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,20 +1,18 @@
|
|
|
1
1
|
import Protomux from 'protomux';
|
|
2
2
|
import ProtocolInterface from './ProtocolInterface.js';
|
|
3
|
+
import b4a from 'b4a';
|
|
3
4
|
import c from 'compact-encoding';
|
|
4
|
-
import {encodeV1networkOperation, decodeV1networkOperation} from '../../../utils/protobuf/operationHelpers.js';
|
|
5
5
|
|
|
6
6
|
class V1Protocol extends ProtocolInterface {
|
|
7
7
|
#channel;
|
|
8
8
|
#session;
|
|
9
|
+
#config;
|
|
9
10
|
#router;
|
|
10
|
-
#publicKeyHex;
|
|
11
|
-
#pendingRequestService;
|
|
12
11
|
|
|
13
|
-
constructor(router, connection,
|
|
14
|
-
super(router, connection,
|
|
12
|
+
constructor(router, connection, config) {
|
|
13
|
+
super(router, connection, config);
|
|
14
|
+
this.#config = config;
|
|
15
15
|
this.#router = router;
|
|
16
|
-
this.#publicKeyHex = connection.remotePublicKey.toString('hex');
|
|
17
|
-
this.#pendingRequestService = pendingRequestService;
|
|
18
16
|
this.init(connection);
|
|
19
17
|
}
|
|
20
18
|
|
|
@@ -32,47 +30,30 @@ class V1Protocol extends ProtocolInterface {
|
|
|
32
30
|
|
|
33
31
|
this.#channel = mux.createChannel({
|
|
34
32
|
protocol: 'network/v1',
|
|
35
|
-
onopen() {
|
|
36
|
-
}
|
|
37
|
-
onclose() {
|
|
38
|
-
}
|
|
33
|
+
onopen() { },
|
|
34
|
+
onclose() { }
|
|
39
35
|
});
|
|
40
36
|
|
|
41
37
|
this.#channel.open();
|
|
42
38
|
|
|
43
39
|
this.#session = this.#channel.addMessage({
|
|
44
40
|
encoding: c.raw,
|
|
45
|
-
onmessage: (incomingMessage) => {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
41
|
+
onmessage: async (incomingMessage) => {
|
|
42
|
+
try {
|
|
43
|
+
if (b4a.isBuffer(incomingMessage)) {
|
|
44
|
+
await this.#router.route(incomingMessage, connection, this.#session);
|
|
45
|
+
} else {
|
|
46
|
+
throw new Error('NetworkMessages: v1 message must be a buffer');
|
|
51
47
|
}
|
|
52
|
-
})
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error(`NetworkMessages: Failed to handle incoming v1 message: ${error.message}`);
|
|
50
|
+
}
|
|
53
51
|
}
|
|
54
52
|
});
|
|
55
53
|
}
|
|
56
54
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
decode(message) {
|
|
60
|
-
return decodeV1networkOperation(message);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async send(message) {
|
|
64
|
-
const encodedMessage = encodeV1networkOperation(message);
|
|
65
|
-
const msgReplyPromise = this.#pendingRequestService.registerPendingRequest(this.#publicKeyHex, message);
|
|
66
|
-
try {
|
|
67
|
-
this.#session.send(encodedMessage);
|
|
68
|
-
} catch (error) {
|
|
69
|
-
this.#pendingRequestService.rejectPendingRequest(message.id, error);
|
|
70
|
-
}
|
|
71
|
-
return msgReplyPromise;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
sendAndForget(message) {
|
|
75
|
-
this.#session.send(encodeV1networkOperation(message));
|
|
55
|
+
send(message) {
|
|
56
|
+
this.#session.send(message);
|
|
76
57
|
}
|
|
77
58
|
|
|
78
59
|
close() {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import b4a from "b4a";
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import LegacyTransferOperationHandler from "./handlers/LegacyTransferOperationHandler.js";
|
|
2
|
+
import GetRequestHandler from "./handlers/GetRequestHandler.js";
|
|
3
|
+
import ResponseHandler from "./handlers/ResponseHandler.js";
|
|
4
|
+
import RoleOperationHandler from "../shared/handlers/RoleOperationHandler.js";
|
|
5
|
+
import SubnetworkOperationHandler from "../shared/handlers/SubnetworkOperationHandler.js";
|
|
6
|
+
import TransferOperationHandler from "../shared/handlers/TransferOperationHandler.js";
|
|
8
7
|
import { NETWORK_MESSAGE_TYPES } from '../../../../utils/constants.js';
|
|
9
8
|
import * as operation from '../../../../utils/applyOperations.js';
|
|
9
|
+
import State from "../../../state/State.js";
|
|
10
|
+
import PeerWallet from "trac-wallet";
|
|
10
11
|
|
|
11
12
|
class NetworkMessageRouter {
|
|
12
13
|
#handlers;
|
|
@@ -17,32 +18,29 @@ class NetworkMessageRouter {
|
|
|
17
18
|
* @param {PeerWallet} wallet
|
|
18
19
|
* @param {TransactionRateLimiterService} rateLimiterService
|
|
19
20
|
* @param {TransactionPoolService} txPoolService
|
|
21
|
+
* @param {ConnectionManager} connectionManager
|
|
20
22
|
* @param {Config} config
|
|
21
23
|
**/
|
|
22
|
-
constructor(state, wallet, rateLimiterService, txPoolService, config) {
|
|
24
|
+
constructor(state, wallet, rateLimiterService, txPoolService, connectionManager, config) {
|
|
23
25
|
this.#config = config;
|
|
24
26
|
|
|
25
27
|
this.#handlers = {
|
|
26
|
-
get: new
|
|
27
|
-
response: new
|
|
28
|
-
roleTransaction: new
|
|
29
|
-
subNetworkTransaction: new
|
|
30
|
-
tracNetworkTransaction: new
|
|
31
|
-
|
|
28
|
+
get: new GetRequestHandler(wallet, state),
|
|
29
|
+
response: new ResponseHandler(state, wallet, connectionManager, this.#config),
|
|
30
|
+
roleTransaction: new RoleOperationHandler(state, wallet, rateLimiterService, txPoolService, this.#config),
|
|
31
|
+
subNetworkTransaction: new SubnetworkOperationHandler(state, wallet, rateLimiterService, txPoolService, this.#config),
|
|
32
|
+
tracNetworkTransaction: new TransferOperationHandler(state, wallet, rateLimiterService, txPoolService, this.#config),
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
// NOTE: messageProtomux can be deleted, ad this is a session, and we can extract this from connection
|
|
37
|
+
async route(incomingMessage, connection, messageProtomux) {
|
|
37
38
|
const channelString = b4a.toString(this.#config.channel, 'utf8');
|
|
38
|
-
|
|
39
|
-
// We received a legacy message, so we set the connection protocol accordingly
|
|
40
|
-
connection.protocolSession.setLegacyAsPreferredProtocol();
|
|
41
39
|
if (this.#isGetRequest(incomingMessage)) {
|
|
42
|
-
await this.#handlers.get.handle(incomingMessage, connection, channelString);
|
|
40
|
+
await this.#handlers.get.handle(incomingMessage, messageProtomux, connection, channelString);
|
|
43
41
|
}
|
|
44
42
|
else if (this.#isResponse(incomingMessage)) {
|
|
45
|
-
await this.#handlers.response.handle(incomingMessage, channelString);
|
|
43
|
+
await this.#handlers.response.handle(incomingMessage, connection, channelString);
|
|
46
44
|
}
|
|
47
45
|
else if (this.#isRoleAccessOperation(incomingMessage)) {
|
|
48
46
|
await this.#handlers.roleTransaction.handle(incomingMessage, connection);
|
|
@@ -56,18 +54,14 @@ class NetworkMessageRouter {
|
|
|
56
54
|
else {
|
|
57
55
|
throw new Error(`Failed to route message. Pubkey of requester is ${connection.remotePublicKey ? b4a.toString(connection.remotePublicKey, 'hex') : 'unknown'}`);
|
|
58
56
|
}
|
|
59
|
-
}
|
|
60
57
|
|
|
61
|
-
#preValidate(message) {
|
|
62
|
-
if (!_.isPlainObject(message) && typeof message !== 'string') {
|
|
63
|
-
throw new Error('Invalid message format: expected object or string.');
|
|
64
|
-
}
|
|
65
58
|
}
|
|
66
59
|
|
|
67
60
|
#isGetRequest(message) {
|
|
68
61
|
return Object.values(NETWORK_MESSAGE_TYPES.GET).includes(message);
|
|
69
62
|
}
|
|
70
63
|
|
|
64
|
+
|
|
71
65
|
#isResponse(message) {
|
|
72
66
|
return Object.values(NETWORK_MESSAGE_TYPES.RESPONSE).includes(message.op);
|
|
73
67
|
}
|
|
@@ -2,7 +2,7 @@ import { NETWORK_MESSAGE_TYPES } from '../../../../../utils/constants.js';
|
|
|
2
2
|
import PeerWallet from 'trac-wallet';
|
|
3
3
|
import b4a from 'b4a';
|
|
4
4
|
|
|
5
|
-
class
|
|
5
|
+
class GetRequestHandler {
|
|
6
6
|
#wallet;
|
|
7
7
|
#state;
|
|
8
8
|
|
|
@@ -15,17 +15,17 @@ class LegacyGetRequestHandler {
|
|
|
15
15
|
return this.#state;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
async handle(message, connection, channelString) {
|
|
18
|
+
async handle(message, messageProtomux, connection, channelString) {
|
|
19
19
|
switch (message) {
|
|
20
20
|
case NETWORK_MESSAGE_TYPES.GET.VALIDATOR:
|
|
21
|
-
await this.handleGetValidatorResponse(connection, channelString);
|
|
21
|
+
await this.handleGetValidatorResponse(messageProtomux, connection, channelString);
|
|
22
22
|
break;
|
|
23
23
|
default:
|
|
24
24
|
throw new Error(`Unhandled GET type: ${message}`);
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
async handleGetValidatorResponse(connection, channelString) {
|
|
28
|
+
async handleGetValidatorResponse(messageProtomux, connection, channelString) {
|
|
29
29
|
const nonce = PeerWallet.generateNonce().toString('hex');
|
|
30
30
|
const payload = {
|
|
31
31
|
op: 'validatorResponse',
|
|
@@ -46,8 +46,8 @@ class LegacyGetRequestHandler {
|
|
|
46
46
|
...payload,
|
|
47
47
|
sig: sig.toString('hex'),
|
|
48
48
|
};
|
|
49
|
-
|
|
49
|
+
messageProtomux.send(responseMessage);
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
export default
|
|
53
|
+
export default GetRequestHandler;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import ValidatorResponse from '../validators/ValidatorResponse.js';
|
|
2
|
+
import PeerWallet from 'trac-wallet';
|
|
3
|
+
|
|
4
|
+
class ResponseHandler {
|
|
5
|
+
#responseValidator;
|
|
6
|
+
#connectionManager;
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
constructor(state, wallet, connectionManager ,config) {
|
|
10
|
+
this.#responseValidator = new ValidatorResponse(state, wallet, config);
|
|
11
|
+
this.#connectionManager = connectionManager;
|
|
12
|
+
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async handle(message, connection, channelString) {
|
|
16
|
+
await this.#handleValidatorResponse(message, connection, channelString);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async #handleValidatorResponse(message, connection, channelString) {
|
|
20
|
+
const isValid = await this.#responseValidator.validate(message, channelString);
|
|
21
|
+
if (isValid) {
|
|
22
|
+
const validatorAddressString = message.address;
|
|
23
|
+
const validatorPublicKey = PeerWallet.decodeBech32m(validatorAddressString);
|
|
24
|
+
|
|
25
|
+
if (this.#connectionManager.connected(validatorPublicKey)) {
|
|
26
|
+
return;
|
|
27
|
+
// TODO: What we should return? Or maybe we should throw?
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
this.#connectionManager.addValidator(validatorPublicKey, connection)
|
|
31
|
+
} else {
|
|
32
|
+
throw new Error("Validator response verification failed");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default ResponseHandler;
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import {OperationType} from '../../../../../utils/constants.js';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
2
|
+
import PartialRoleAccess from "../validators/PartialRoleAccess.js";
|
|
3
|
+
import BaseOperationHandler from './base/BaseOperationHandler.js';
|
|
4
4
|
import {applyStateMessageFactory} from "../../../../../messages/state/applyStateMessageFactory.js";
|
|
5
5
|
import {safeEncodeApplyOperation} from "../../../../../utils/protobuf/operationHelpers.js";
|
|
6
6
|
import {normalizeRoleAccessOperation} from "../../../../../utils/normalizers.js";
|
|
7
|
-
import { publicKeyToAddress } from "../../../../../utils/helpers.js"
|
|
8
|
-
import b4a from "b4a";
|
|
9
7
|
|
|
10
|
-
class
|
|
8
|
+
class RoleOperationHandler extends BaseOperationHandler {
|
|
11
9
|
#partialRoleAccessValidator;
|
|
12
10
|
#wallet;
|
|
13
11
|
#config;
|
|
12
|
+
#txPoolService;
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
15
|
* @param {State} state
|
|
@@ -23,7 +22,8 @@ class LegacyRoleOperationHandler extends BaseStateOperationHandler {
|
|
|
23
22
|
super(state, wallet, rateLimiter, txPoolService, config);
|
|
24
23
|
this.#wallet = wallet;
|
|
25
24
|
this.#config = config;
|
|
26
|
-
this.#partialRoleAccessValidator = new
|
|
25
|
+
this.#partialRoleAccessValidator = new PartialRoleAccess(state, this.#wallet.address ,this.#config)
|
|
26
|
+
this.#txPoolService = txPoolService;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
get partialRoleAccessValidator() {
|
|
@@ -35,8 +35,7 @@ class LegacyRoleOperationHandler extends BaseStateOperationHandler {
|
|
|
35
35
|
const isValid = await this.partialRoleAccessValidator.validate(normalizedPartialRoleAccessPayload)
|
|
36
36
|
let completePayload = null
|
|
37
37
|
if (!isValid) {
|
|
38
|
-
throw new Error(
|
|
39
|
-
`OperationHandler: partial role access payload validation failed. Requested by ${publicKeyToAddress(connection.remotePublicKey, this.#config)}`);
|
|
38
|
+
throw new Error("OperationHandler: partial role access payload validation failed.");
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
switch (normalizedPartialRoleAccessPayload.type) {
|
|
@@ -75,21 +74,15 @@ class LegacyRoleOperationHandler extends BaseStateOperationHandler {
|
|
|
75
74
|
)
|
|
76
75
|
break;
|
|
77
76
|
default:
|
|
78
|
-
throw new Error(
|
|
79
|
-
`OperationHandler: Assembling complete role access operation failed due to unsupported operation type. Requested by ${publicKeyToAddress(connection.remotePublicKey, this.#config)}`
|
|
80
|
-
);
|
|
77
|
+
throw new Error("OperationHandler: Assembling complete role access operation failed due to unsupported operation type.");
|
|
81
78
|
}
|
|
82
79
|
|
|
83
80
|
if (!completePayload) {
|
|
84
|
-
throw new Error(
|
|
85
|
-
`OperationHandler: Assembling complete role access operation failed. Requested by ${publicKeyToAddress(connection.remotePublicKey, this.#config)}`
|
|
86
|
-
);
|
|
81
|
+
throw new Error("OperationHandler: Assembling complete role access operation failed.");
|
|
87
82
|
}
|
|
88
83
|
|
|
89
|
-
|
|
90
|
-
const txHash = b4a.toString(completePayload.rao.tx, 'hex');
|
|
91
|
-
this.enqueueTransaction(txHash, encodedOperation);
|
|
84
|
+
this.#txPoolService.addTransaction(safeEncodeApplyOperation(completePayload))
|
|
92
85
|
}
|
|
93
86
|
}
|
|
94
87
|
|
|
95
|
-
export default
|
|
88
|
+
export default RoleOperationHandler;
|
|
@@ -1,24 +1,23 @@
|
|
|
1
|
-
import
|
|
1
|
+
import BaseOperationHandler from './base/BaseOperationHandler.js';
|
|
2
2
|
import {
|
|
3
3
|
OperationType
|
|
4
4
|
} from '../../../../../utils/constants.js';
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import PartialBootstrapDeployment from "../validators/PartialBootstrapDeployment.js";
|
|
6
|
+
import PartialTransaction from "../validators/PartialTransaction.js";
|
|
7
7
|
import {applyStateMessageFactory} from "../../../../../messages/state/applyStateMessageFactory.js";
|
|
8
8
|
import {safeEncodeApplyOperation} from "../../../../../utils/protobuf/operationHelpers.js";
|
|
9
9
|
import {
|
|
10
10
|
normalizeBootstrapDeploymentOperation,
|
|
11
11
|
normalizeTransactionOperation
|
|
12
12
|
} from "../../../../../utils/normalizers.js";
|
|
13
|
-
import b4a from "b4a";
|
|
14
|
-
import {publicKeyToAddress} from "../../../../../utils/helpers.js";
|
|
15
13
|
|
|
16
14
|
|
|
17
|
-
class
|
|
15
|
+
class SubnetworkOperationHandler extends BaseOperationHandler {
|
|
18
16
|
#partialBootstrapDeploymentValidator;
|
|
19
17
|
#partialTransactionValidator;
|
|
20
18
|
#config;
|
|
21
19
|
#wallet;
|
|
20
|
+
#txPoolService;
|
|
22
21
|
|
|
23
22
|
/**
|
|
24
23
|
* @param {State} state
|
|
@@ -27,23 +26,22 @@ class LegacySubnetworkOperationHandler extends BaseStateOperationHandler {
|
|
|
27
26
|
* @param {TransactionPoolService} txPoolService
|
|
28
27
|
* @param {Config} config
|
|
29
28
|
**/
|
|
30
|
-
constructor(state, wallet, rateLimiter, txPoolService, config) {
|
|
29
|
+
constructor( state, wallet, rateLimiter, txPoolService, config) {
|
|
31
30
|
super(state, wallet, rateLimiter, txPoolService, config);
|
|
32
31
|
this.#config = config;
|
|
33
32
|
this.#wallet = wallet
|
|
34
|
-
this.#partialBootstrapDeploymentValidator = new
|
|
35
|
-
this.#partialTransactionValidator = new
|
|
33
|
+
this.#partialBootstrapDeploymentValidator = new PartialBootstrapDeployment(state, this.#wallet.address, config);
|
|
34
|
+
this.#partialTransactionValidator = new PartialTransaction(state, this.#wallet.address, config);
|
|
35
|
+
this.#txPoolService = txPoolService;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
async handleOperation(payload, connection)
|
|
38
|
+
async handleOperation(payload, connection) {
|
|
39
39
|
if (payload.type === OperationType.TX) {
|
|
40
40
|
await this.#partialTransactionSubHandler(payload, connection);
|
|
41
41
|
} else if (payload.type === OperationType.BOOTSTRAP_DEPLOYMENT) {
|
|
42
42
|
await this.#partialBootstrapDeploymentSubHandler(payload, connection);
|
|
43
43
|
} else {
|
|
44
|
-
throw new Error(
|
|
45
|
-
`Unsupported operation type for LegacySubnetworkOperationHandler. Requested by ${publicKeyToAddress(connection.remotePublicKey, this.#config)} `
|
|
46
|
-
);
|
|
44
|
+
throw new Error('Unsupported operation type for SubnetworkOperationHandler');
|
|
47
45
|
}
|
|
48
46
|
}
|
|
49
47
|
|
|
@@ -51,12 +49,10 @@ class LegacySubnetworkOperationHandler extends BaseStateOperationHandler {
|
|
|
51
49
|
const normalizedPayload = normalizeTransactionOperation(payload, this.#config);
|
|
52
50
|
const isValid = await this.#partialTransactionValidator.validate(normalizedPayload);
|
|
53
51
|
if (!isValid) {
|
|
54
|
-
throw new Error(
|
|
55
|
-
SubnetworkHandler: Transaction validation failed. Requested by ${publicKeyToAddress(connection.remotePublicKey, this.#config)}`
|
|
56
|
-
);
|
|
52
|
+
throw new Error("SubnetworkHandler: Transaction validation failed.");
|
|
57
53
|
}
|
|
58
54
|
|
|
59
|
-
const completeTransactionOperation = await applyStateMessageFactory(this.#wallet,
|
|
55
|
+
const completeTransactionOperation = await applyStateMessageFactory(this.#wallet,this.#config)
|
|
60
56
|
.buildCompleteTransactionOperationMessage(
|
|
61
57
|
normalizedPayload.address,
|
|
62
58
|
normalizedPayload.txo.tx,
|
|
@@ -68,19 +64,14 @@ class LegacySubnetworkOperationHandler extends BaseStateOperationHandler {
|
|
|
68
64
|
normalizedPayload.txo.bs,
|
|
69
65
|
normalizedPayload.txo.mbs
|
|
70
66
|
)
|
|
71
|
-
|
|
72
|
-
const txHash = b4a.toString(normalizedPayload.txo.tx, 'hex');
|
|
73
|
-
this.enqueueTransaction(txHash, encodedOperation);
|
|
74
|
-
|
|
67
|
+
this.#txPoolService.addTransaction(safeEncodeApplyOperation(completeTransactionOperation));
|
|
75
68
|
}
|
|
76
69
|
|
|
77
70
|
async #partialBootstrapDeploymentSubHandler(payload, connection) {
|
|
78
71
|
const normalizedPayload = normalizeBootstrapDeploymentOperation(payload, this.#config);
|
|
79
72
|
const isValid = await this.#partialBootstrapDeploymentValidator.validate(normalizedPayload);
|
|
80
73
|
if (!isValid) {
|
|
81
|
-
throw new Error(
|
|
82
|
-
`SubnetworkHandler: Bootstrap deployment validation failed. Requested by ${publicKeyToAddress(connection.remotePublicKey, this.#config)}`
|
|
83
|
-
);
|
|
74
|
+
throw new Error("SubnetworkHandler: Bootstrap deployment validation failed.");
|
|
84
75
|
}
|
|
85
76
|
|
|
86
77
|
|
|
@@ -94,11 +85,9 @@ class LegacySubnetworkOperationHandler extends BaseStateOperationHandler {
|
|
|
94
85
|
normalizedPayload.bdo.in,
|
|
95
86
|
normalizedPayload.bdo.is
|
|
96
87
|
)
|
|
97
|
-
|
|
98
|
-
const txHash = b4a.toString(normalizedPayload.bdo.tx, 'hex');
|
|
99
|
-
this.enqueueTransaction(txHash, encodedOperation);
|
|
88
|
+
this.#txPoolService.addTransaction(safeEncodeApplyOperation(completeBootstrapDeploymentOperation));
|
|
100
89
|
|
|
101
90
|
}
|
|
102
91
|
}
|
|
103
92
|
|
|
104
|
-
export default
|
|
93
|
+
export default SubnetworkOperationHandler;
|
|
@@ -1,36 +1,33 @@
|
|
|
1
|
-
import
|
|
1
|
+
import BaseOperationHandler from './base/BaseOperationHandler.js';
|
|
2
2
|
import {OperationType} from '../../../../../utils/constants.js';
|
|
3
|
-
import
|
|
3
|
+
import PartialTransfer from "../validators/PartialTransfer.js";
|
|
4
4
|
import {normalizeTransferOperation} from "../../../../../utils/normalizers.js"
|
|
5
5
|
import {applyStateMessageFactory} from "../../../../../messages/state/applyStateMessageFactory.js";
|
|
6
6
|
import {safeEncodeApplyOperation} from "../../../../../utils/protobuf/operationHelpers.js";
|
|
7
|
-
import b4a from "b4a";
|
|
8
|
-
import {publicKeyToAddress} from "../../../../../utils/helpers.js";
|
|
9
7
|
|
|
10
|
-
class
|
|
8
|
+
class TransferOperationHandler extends BaseOperationHandler {
|
|
11
9
|
#partialTransferValidator;
|
|
12
10
|
#config;
|
|
13
11
|
#wallet;
|
|
12
|
+
#txPoolService;
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
15
|
* @param {State} state
|
|
17
16
|
* @param {PeerWallet} wallet
|
|
18
17
|
* @param {TransactionRateLimiterService} rateLimiter
|
|
19
|
-
* @param {TransactionPoolService} txPoolService
|
|
20
18
|
* @param {Config} config
|
|
21
19
|
**/
|
|
22
20
|
constructor(state, wallet, rateLimiter, txPoolService, config) {
|
|
23
21
|
super(state, wallet, rateLimiter, txPoolService, config);
|
|
24
22
|
this.#config = config;
|
|
25
23
|
this.#wallet = wallet;
|
|
26
|
-
this.#partialTransferValidator = new
|
|
24
|
+
this.#partialTransferValidator = new PartialTransfer(state, this.#wallet.address, this.#config);
|
|
25
|
+
this.#txPoolService = txPoolService;
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
async handleOperation(payload, connection) {
|
|
30
29
|
if (payload.type !== OperationType.TRANSFER) {
|
|
31
|
-
throw new Error(
|
|
32
|
-
`Unsupported operation type for LegacyTransferOperationHandler. Requested by ${publicKeyToAddress(connection.remotePublicKey, this.#config)}`
|
|
33
|
-
);
|
|
30
|
+
throw new Error('Unsupported operation type for TransferOperationHandler');
|
|
34
31
|
}
|
|
35
32
|
await this.#handleTransfer(payload, connection);
|
|
36
33
|
}
|
|
@@ -39,9 +36,7 @@ class LegacyTransferOperationHandler extends BaseStateOperationHandler {
|
|
|
39
36
|
const normalizedPayload = normalizeTransferOperation(payload, this.#config);
|
|
40
37
|
const isValid = await this.#partialTransferValidator.validate(normalizedPayload);
|
|
41
38
|
if (!isValid) {
|
|
42
|
-
throw new Error(
|
|
43
|
-
`TransferHandler: Transfer validation failed. Requested by ${publicKeyToAddress(connection.remotePublicKey, this.#config)}`
|
|
44
|
-
);
|
|
39
|
+
throw new Error("TransferHandler: Transfer validation failed.");
|
|
45
40
|
}
|
|
46
41
|
|
|
47
42
|
const completeTransferOperation = await applyStateMessageFactory(this.#wallet, this.#config)
|
|
@@ -54,10 +49,9 @@ class LegacyTransferOperationHandler extends BaseStateOperationHandler {
|
|
|
54
49
|
normalizedPayload.tro.am,
|
|
55
50
|
normalizedPayload.tro.is
|
|
56
51
|
)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
this.enqueueTransaction(txHash, encodedOperation);
|
|
52
|
+
|
|
53
|
+
this.#txPoolService.addTransaction(safeEncodeApplyOperation(completeTransferOperation));
|
|
60
54
|
}
|
|
61
55
|
}
|
|
62
56
|
|
|
63
|
-
export default
|
|
57
|
+
export default TransferOperationHandler;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import b4a from 'b4a';
|
|
2
|
-
import {publicKeyToAddress} from "../../../../../utils/helpers.js";
|
|
3
2
|
|
|
4
|
-
class
|
|
3
|
+
class BaseOperationHandler {
|
|
5
4
|
#state;
|
|
6
5
|
#wallet;
|
|
7
6
|
#rateLimiter;
|
|
@@ -16,8 +15,8 @@ class BaseStateOperationHandler {
|
|
|
16
15
|
* @param {Config} config
|
|
17
16
|
**/
|
|
18
17
|
constructor(state, wallet, rateLimiter, txPoolService, config) {
|
|
19
|
-
if (new.target ===
|
|
20
|
-
throw new Error('
|
|
18
|
+
if (new.target === BaseOperationHandler) {
|
|
19
|
+
throw new Error('BaseOperationHandler is abstract and cannot be instantiated directly');
|
|
21
20
|
}
|
|
22
21
|
this.#state = state;
|
|
23
22
|
this.#wallet = wallet;
|
|
@@ -38,18 +37,18 @@ class BaseStateOperationHandler {
|
|
|
38
37
|
throw new Error('OperationHandler: State is not writable or is an indexer without admin privileges.');
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
this.#txPoolService.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
if (this.#txPoolService.tx_pool.length >= this.#config.transactionPoolSize) {
|
|
41
|
+
throw new Error("OperationHandler: Transaction pool is full, ignoring incoming transaction.");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (b4a.byteLength(JSON.stringify(payload)) > this.#config.maxPartialTxPayloadByteSize) {
|
|
45
|
+
throw new Error(`OperationHandler: Payload size exceeds maximum limit of ${this.#config.maxPartialTxPayloadByteSize} bytes by ${b4a.byteLength(JSON.stringify(payload)) - this.#config.maxPartialTxPayloadByteSize} bytes.`);
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
if (!this.#config.disableRateLimit) {
|
|
48
|
-
const shouldDisconnect = this.#rateLimiter.
|
|
49
|
+
const shouldDisconnect = this.#rateLimiter.handleRateLimit(connection);
|
|
49
50
|
if (shouldDisconnect) {
|
|
50
|
-
throw new Error(
|
|
51
|
-
`OperationHandler: Rate limit exceeded for ${publicKeyToAddress(connection.remotePublicKey, this.#config)}. Disconnecting...`
|
|
52
|
-
);
|
|
51
|
+
throw new Error(`OperationHandler: Rate limit exceeded for peer ${b4a.toString(connection.remotePublicKey, 'hex')}. Disconnecting...`);
|
|
53
52
|
}
|
|
54
53
|
}
|
|
55
54
|
}
|
|
@@ -59,19 +58,9 @@ class BaseStateOperationHandler {
|
|
|
59
58
|
await this.handleOperation(payload, connection);
|
|
60
59
|
}
|
|
61
60
|
|
|
62
|
-
enqueueTransaction(txHash, encodedOperation) {
|
|
63
|
-
try {
|
|
64
|
-
this.#txPoolService.addTransaction(txHash, encodedOperation);
|
|
65
|
-
} catch (error) {
|
|
66
|
-
throw new Error(
|
|
67
|
-
`${this.constructor.name}: Failed to add transaction ${txHash} to transaction pool: ${error?.message ?? String(error)}`
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
61
|
async handleOperation(payload, connection) {
|
|
73
62
|
throw new Error('handleOperation must be implemented by child class');
|
|
74
63
|
}
|
|
75
64
|
|
|
76
65
|
}
|
|
77
|
-
export default
|
|
66
|
+
export default BaseOperationHandler;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {ResultCode} from "../../../../../utils/constants.js";
|
|
3
|
-
import SharedValidatorRejectionError from '../errors/SharedValidatorRejectionError.js';
|
|
1
|
+
import PartialOperation from './base/PartialOperation.js';
|
|
4
2
|
|
|
5
|
-
class
|
|
3
|
+
class PartialBootstrapDeployment extends PartialOperation {
|
|
6
4
|
constructor(state, selfAddress , config) {
|
|
7
5
|
super(state, selfAddress , config);
|
|
8
6
|
}
|
|
@@ -28,12 +26,9 @@ class PartialBootstrapDeploymentValidator extends PartialOperationValidator {
|
|
|
28
26
|
async validateBootstrapRegistration(payload) {
|
|
29
27
|
const bootstrapString = payload.bdo.bs.toString('hex');
|
|
30
28
|
if (null !== await this.state.getRegisteredBootstrapEntryUnsigned(bootstrapString)) {
|
|
31
|
-
throw new
|
|
32
|
-
ResultCode.BOOTSTRAP_ALREADY_EXISTS,
|
|
33
|
-
`Bootstrap with hash ${bootstrapString} already exists in the state. Bootstrap must be unique.`
|
|
34
|
-
);
|
|
29
|
+
throw new Error(`Bootstrap with hash ${bootstrapString} already exists in the state. Bootstrap must be unique.`);
|
|
35
30
|
}
|
|
36
31
|
}
|
|
37
32
|
}
|
|
38
33
|
|
|
39
|
-
export default
|
|
34
|
+
export default PartialBootstrapDeployment;
|