trac-msb 0.2.26 → 0.3.0-beta.1
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 +103 -0
- package/rpc/routes/v1.js +8 -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 +1789 -173
- 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 +255 -65
- 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/index.js
CHANGED
|
@@ -2,40 +2,54 @@ import ReadyResource from "ready-resource";
|
|
|
2
2
|
import Corestore from "corestore";
|
|
3
3
|
import tracCryptoApi from "trac-crypto-api";
|
|
4
4
|
import b4a from "b4a";
|
|
5
|
+
import _ from "lodash";
|
|
5
6
|
import { sleep, isHexString } from "./utils/helpers.js";
|
|
6
7
|
import { applyStateMessageFactory } from "./messages/state/applyStateMessageFactory.js";
|
|
7
|
-
import { isAddressValid } from "./core/state/utils/address.js";
|
|
8
|
+
import { isAddressValid, bufferToAddress } from "./core/state/utils/address.js";
|
|
8
9
|
import Network from "./core/network/Network.js";
|
|
9
|
-
import Check from "./utils/check.js";
|
|
10
10
|
import State from "./core/state/State.js";
|
|
11
11
|
import {
|
|
12
|
-
EventType,
|
|
13
12
|
WHITELIST_SLEEP_INTERVAL,
|
|
14
13
|
BOOTSTRAP_HEXSTRING_LENGTH,
|
|
15
|
-
CustomEventType,
|
|
16
14
|
BALANCE_MIGRATION_SLEEP_INTERVAL,
|
|
17
15
|
WHITELIST_MIGRATION_DIR,
|
|
18
|
-
OperationType
|
|
16
|
+
OperationType,
|
|
17
|
+
EntryType,
|
|
18
|
+
HTLC_LOCK_ID_BYTE_LENGTH,
|
|
19
|
+
ConsensusVersion,
|
|
20
|
+
MAX_VDF_DIFFICULTY,
|
|
21
|
+
VDF_PROOF_BYTE_LENGTHS
|
|
19
22
|
} from "./utils/constants.js";
|
|
20
23
|
import { decimalStringToBigInt, bigIntTo16ByteBuffer, bufferToBigInt, bigIntToDecimalString } from "./utils/amountSerialization.js"
|
|
21
24
|
import {
|
|
22
25
|
normalizeDecodedPayloadForJson,
|
|
23
26
|
normalizeTransactionOperation,
|
|
24
|
-
normalizeTransferOperation
|
|
27
|
+
normalizeTransferOperation,
|
|
28
|
+
normalizeMessageByOperationType
|
|
25
29
|
} from "./utils/normalizers.js";
|
|
30
|
+
import { operationToPayload } from "./utils/applyOperations.js";
|
|
31
|
+
import PartialHtlcValidator from "./core/network/protocols/validators/shared/validators/PartialHtlcValidator.js";
|
|
32
|
+
import { V1ProtocolError } from "./core/network/protocols/validators/v1/V1ProtocolError.js";
|
|
33
|
+
import * as escrowEntryUtils from "./core/state/utils/escrowEntry.js";
|
|
26
34
|
import fileUtils from './utils/fileUtils.js';
|
|
27
35
|
import migrationUtils from './utils/migrationUtils.js';
|
|
28
|
-
import {
|
|
29
|
-
|
|
30
|
-
|
|
36
|
+
import {
|
|
37
|
+
encodeApplyOperation,
|
|
38
|
+
encodeConsensusConfig,
|
|
39
|
+
safeDecodeApplyOperation,
|
|
40
|
+
safeEncodeApplyOperation
|
|
41
|
+
} from "./codecs/apply/applyOperationCodec.js";
|
|
42
|
+
import { encodeVdfConfig } from "./codecs/consensus/v1/vdfConfigCodec.js";
|
|
43
|
+
import PartialTransactionValidator from "./core/network/protocols/validators/shared/validators/PartialTransactionValidator.js";
|
|
44
|
+
import PartialTransferValidator from "./core/network/protocols/validators/shared/validators/PartialTransferValidator.js";
|
|
31
45
|
import { BroadcastError, ValidationError } from "./utils/errors.js";
|
|
46
|
+
import { uint8ToBuffer, uint16ToBuffer, uint32ToBuffer } from "./utils/buffer.js";
|
|
32
47
|
|
|
33
48
|
export class MainSettlementBus extends ReadyResource {
|
|
34
49
|
#store;
|
|
35
50
|
#wallet;
|
|
36
51
|
#network;
|
|
37
52
|
#state;
|
|
38
|
-
#isClosing = false;
|
|
39
53
|
#config
|
|
40
54
|
|
|
41
55
|
/**
|
|
@@ -47,7 +61,6 @@ export class MainSettlementBus extends ReadyResource {
|
|
|
47
61
|
this.#config = config
|
|
48
62
|
this.#wallet = wallet;
|
|
49
63
|
this.#store = new Corestore(this.#config.storesFullPath);
|
|
50
|
-
this.check = new Check(this.#config);
|
|
51
64
|
}
|
|
52
65
|
|
|
53
66
|
get config() {
|
|
@@ -71,27 +84,18 @@ export class MainSettlementBus extends ReadyResource {
|
|
|
71
84
|
|
|
72
85
|
async _open() {
|
|
73
86
|
this.#state = new State(this.#store, this.#wallet, this.#config);
|
|
74
|
-
this.#network = new Network(this.#state, this.#config, this.#wallet
|
|
87
|
+
this.#network = new Network(this.#state, this.#store, this.#config, this.#wallet);
|
|
75
88
|
|
|
76
89
|
await this.#state.ready();
|
|
77
90
|
await this.#network.ready();
|
|
78
|
-
await this.#stateEventsListener();
|
|
79
91
|
|
|
80
92
|
if (this.#wallet) {
|
|
81
93
|
this.#printWalletInfo();
|
|
82
94
|
}
|
|
83
95
|
|
|
84
|
-
await this.#network.replicate(
|
|
85
|
-
this.#state,
|
|
86
|
-
this.#store,
|
|
87
|
-
this.#wallet,
|
|
88
|
-
);
|
|
89
|
-
|
|
90
96
|
const adminEntry = await this.#state.getAdminEntry();
|
|
91
97
|
await this.#setUpRoleAutomatically(adminEntry);
|
|
92
98
|
|
|
93
|
-
|
|
94
|
-
|
|
95
99
|
console.log(`isIndexer: ${this.#state.isIndexer()}`);
|
|
96
100
|
console.log(`isWriter: ${this.#state.isWritable()}`);
|
|
97
101
|
console.log("MSB Unsigned Length:", this.#state.getUnsignedLength());
|
|
@@ -105,7 +109,6 @@ export class MainSettlementBus extends ReadyResource {
|
|
|
105
109
|
async _close() {
|
|
106
110
|
console.log("Closing everything gracefully... This may take a moment.");
|
|
107
111
|
|
|
108
|
-
this.#isClosing = true;
|
|
109
112
|
await this.#network.close();
|
|
110
113
|
|
|
111
114
|
await sleep(100);
|
|
@@ -129,6 +132,58 @@ export class MainSettlementBus extends ReadyResource {
|
|
|
129
132
|
return await this.#network.validatorMessageOrchestrator.send(partialTransactionPayload);
|
|
130
133
|
}
|
|
131
134
|
|
|
135
|
+
async htlcLock(payload) {
|
|
136
|
+
if (payload?.type !== OperationType.HTLC_LOCK) {
|
|
137
|
+
throw new ValidationError('HTLC lock payload is required.');
|
|
138
|
+
}
|
|
139
|
+
return this.broadcastTransaction(payload);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async htlcClaim(payload) {
|
|
143
|
+
if (payload?.type !== OperationType.HTLC_CLAIM) {
|
|
144
|
+
throw new ValidationError('HTLC claim payload is required.');
|
|
145
|
+
}
|
|
146
|
+
return this.broadcastTransaction(payload);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async htlcRefund(payload) {
|
|
150
|
+
if (payload?.type !== OperationType.HTLC_REFUND) {
|
|
151
|
+
throw new ValidationError('HTLC refund payload is required.');
|
|
152
|
+
}
|
|
153
|
+
return this.broadcastTransaction(payload);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async getHtlc(lockId, confirmed = true) {
|
|
157
|
+
if (typeof lockId !== 'string' || lockId.length !== HTLC_LOCK_ID_BYTE_LENGTH * 2 || !isHexString(lockId)) {
|
|
158
|
+
throw new ValidationError('Invalid HTLC lock ID.');
|
|
159
|
+
}
|
|
160
|
+
const normalizedId = lockId.toLowerCase();
|
|
161
|
+
const key = EntryType.HTLC_ESCROW + normalizedId;
|
|
162
|
+
const entry = confirmed ? await this.#state.getSigned(key) : await this.#state.get(key);
|
|
163
|
+
if (!entry) return null;
|
|
164
|
+
|
|
165
|
+
const escrow = escrowEntryUtils.decode(entry, this.#config.addressPrefix);
|
|
166
|
+
if (!escrow || b4a.toString(escrow.lockId, 'hex') !== normalizedId) {
|
|
167
|
+
throw new Error('Stored HTLC escrow is invalid.');
|
|
168
|
+
}
|
|
169
|
+
const address = value => value ? bufferToAddress(value, this.#config.addressPrefix) : null;
|
|
170
|
+
const hex = value => value ? b4a.toString(value, 'hex') : null;
|
|
171
|
+
return {
|
|
172
|
+
lockId: normalizedId,
|
|
173
|
+
status: Object.keys(escrowEntryUtils.Status).find(name => escrowEntryUtils.Status[name] === escrow.status),
|
|
174
|
+
lockerAddress: address(escrow.lockerAddress),
|
|
175
|
+
claimRecipientAddress: address(escrow.claimRecipientAddress),
|
|
176
|
+
refundRecipientAddress: address(escrow.refundRecipientAddress),
|
|
177
|
+
amount: bufferToBigInt(escrow.amount).toString(),
|
|
178
|
+
additionalFeeAmount: bufferToBigInt(escrow.additionalFeeAmount).toString(),
|
|
179
|
+
additionalFeeRecipientAddress: address(escrow.additionalFeeRecipientAddress),
|
|
180
|
+
hashLock: hex(escrow.hashLock),
|
|
181
|
+
refundEpoch: escrow.refundEpoch.readBigUInt64BE(0).toString(),
|
|
182
|
+
metadata: hex(escrow.metadata),
|
|
183
|
+
preimage: hex(escrow.preimage),
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
132
187
|
async validateTransfer(payload) {
|
|
133
188
|
const partialTransferValidator = new PartialTransferValidator(this.#state, null, this.#config);
|
|
134
189
|
return await partialTransferValidator.validate(payload);
|
|
@@ -140,6 +195,11 @@ export class MainSettlementBus extends ReadyResource {
|
|
|
140
195
|
return await partialTransactionValidator.validate(payload);
|
|
141
196
|
}
|
|
142
197
|
|
|
198
|
+
async validateHtlc(payload) {
|
|
199
|
+
const validator = new PartialHtlcValidator(this.#state, null, this.#config);
|
|
200
|
+
return validator.validate(payload);
|
|
201
|
+
}
|
|
202
|
+
|
|
143
203
|
async broadcastTransaction(payload) {
|
|
144
204
|
if (!payload) {
|
|
145
205
|
throw new ValidationError("Transaction payload is required for broadcasting.");
|
|
@@ -161,6 +221,21 @@ export class MainSettlementBus extends ReadyResource {
|
|
|
161
221
|
throw new ValidationError("Invalid transaction payload.");
|
|
162
222
|
}
|
|
163
223
|
hash = b4a.toString(normalizedPayload.txo.tx, "hex");
|
|
224
|
+
} else if ([OperationType.HTLC_LOCK, OperationType.HTLC_CLAIM, OperationType.HTLC_REFUND].includes(payload.type)) {
|
|
225
|
+
try {
|
|
226
|
+
normalizedPayload = normalizeMessageByOperationType(payload, this.#config);
|
|
227
|
+
} catch (error) {
|
|
228
|
+
throw new ValidationError(error.message || 'Invalid HTLC payload.');
|
|
229
|
+
}
|
|
230
|
+
try {
|
|
231
|
+
await this.validateHtlc(normalizedPayload);
|
|
232
|
+
} catch (error) {
|
|
233
|
+
if (error instanceof V1ProtocolError) throw new ValidationError(error.message);
|
|
234
|
+
throw error;
|
|
235
|
+
}
|
|
236
|
+
hash = b4a.toString(normalizedPayload[operationToPayload(payload.type)].tx, 'hex');
|
|
237
|
+
} else {
|
|
238
|
+
throw new ValidationError('Unsupported transaction operation.');
|
|
164
239
|
}
|
|
165
240
|
|
|
166
241
|
const success = await this.broadcastPartialTransaction(payload);
|
|
@@ -202,37 +277,6 @@ export class MainSettlementBus extends ReadyResource {
|
|
|
202
277
|
return nodeEntry?.isWhitelisted && !this.isAdmin(adminEntry);
|
|
203
278
|
}
|
|
204
279
|
|
|
205
|
-
async #stateEventsListener() {
|
|
206
|
-
this.#state.on(CustomEventType.IS_INDEXER, (publicKey) => {
|
|
207
|
-
if (this.#isClosing) return;
|
|
208
|
-
this.#network.disconnectValidatorPeer(publicKey, 'peer promoted to indexer');
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
this.#state.on(CustomEventType.UNWRITABLE, (publicKey) => {
|
|
212
|
-
if (this.#isClosing) return;
|
|
213
|
-
this.#network.disconnectValidatorPeer(publicKey, 'peer became unwritable');
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
this.#state.base.on(EventType.IS_INDEXER, () => {
|
|
217
|
-
console.log("Current node is an indexer");
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
this.#state.base.on(EventType.IS_NON_INDEXER, async () => {
|
|
221
|
-
// Prevent further actions if closing is in progress
|
|
222
|
-
// The reason is that getNodeEntry is async and may cause issues if we will access state after closing
|
|
223
|
-
if (this.#isClosing) return;
|
|
224
|
-
console.log("Current node is not an indexer anymore");
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
this.#state.base.on(EventType.WRITABLE, async () => {
|
|
228
|
-
console.log("Current node is writable");
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
this.#state.base.on(EventType.UNWRITABLE, async () => {
|
|
232
|
-
console.log("Current node is unwritable");
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
|
|
236
280
|
async getConfirmedTxInfo(txHash) {
|
|
237
281
|
const payload = await this.#state.getSigned(txHash);
|
|
238
282
|
if (!payload) return null
|
|
@@ -257,7 +301,7 @@ export class MainSettlementBus extends ReadyResource {
|
|
|
257
301
|
return { payload, decoded }
|
|
258
302
|
}
|
|
259
303
|
|
|
260
|
-
handleGetFee() {
|
|
304
|
+
handleGetFee() {
|
|
261
305
|
const fee = this.#state.getFee();
|
|
262
306
|
return bufferToBigInt(fee);
|
|
263
307
|
}
|
|
@@ -297,7 +341,7 @@ export class MainSettlementBus extends ReadyResource {
|
|
|
297
341
|
let dagSystem = await this.#state.base.system.core.treeHash();
|
|
298
342
|
let lengthdagSystem = this.#state.base.system.core.length;
|
|
299
343
|
const wl = await this.#state.getWriterLength();
|
|
300
|
-
|
|
344
|
+
|
|
301
345
|
console.log("---------- node & network stats ----------");
|
|
302
346
|
console.log("wallet.publicKey:", this.#wallet?.publicKey?.toString("hex") ?? "unset");
|
|
303
347
|
console.log("wallet.address:", this.#wallet?.address ?? "unset");
|
|
@@ -332,6 +376,9 @@ export class MainSettlementBus extends ReadyResource {
|
|
|
332
376
|
console.log("- /add_indexer <address>: Change a role of the selected writer node to indexer role. Charges a fee.");
|
|
333
377
|
console.log("- /remove_indexer <address>: Change a role of the selected indexer node to default role. Charges a fee.");
|
|
334
378
|
console.log("- /ban_writer <address>: Demote a whitelisted writer to default role and remove it from the whitelist. Charges a fee.");
|
|
379
|
+
console.log("- /init_genesis: Initialize genesis epoch.");
|
|
380
|
+
console.log("- /set_consensus_config: Set new configuration data for a specific consensus schema version from JSON.");
|
|
381
|
+
console.log("- /set_vdf_params: Update VDF difficulty and discriminant bit size.");
|
|
335
382
|
}
|
|
336
383
|
console.log("Available commands:");
|
|
337
384
|
console.log("- /add_writer: Add yourself as a validator to this MSB once whitelisted. Requires a fee + 10x the fee as a stake in $TNK.");
|
|
@@ -746,45 +793,45 @@ export class MainSettlementBus extends ReadyResource {
|
|
|
746
793
|
}
|
|
747
794
|
}
|
|
748
795
|
|
|
749
|
-
async banValidator(
|
|
796
|
+
async banValidator(addressToBan) {
|
|
750
797
|
if (!this.#config.enableWallet) {
|
|
751
798
|
throw new Error(
|
|
752
|
-
`Can not ban writer with address: ${
|
|
799
|
+
`Can not ban writer with address: ${addressToBan} - wallet is not enabled.`
|
|
753
800
|
);
|
|
754
801
|
}
|
|
755
802
|
const adminEntry = await this.#state.getAdminEntry();
|
|
756
803
|
|
|
757
804
|
if (!adminEntry) {
|
|
758
805
|
throw new Error(
|
|
759
|
-
`Can not ban writer with address: ${
|
|
806
|
+
`Can not ban writer with address: ${addressToBan} - admin entry has not been initialized.`
|
|
760
807
|
);
|
|
761
808
|
}
|
|
762
809
|
|
|
763
|
-
if (!isAddressValid(
|
|
810
|
+
if (!isAddressValid(addressToBan, this.#config.addressPrefix)) {
|
|
764
811
|
throw new Error(
|
|
765
|
-
`Can not ban writer with address: ${
|
|
812
|
+
`Can not ban writer with address: ${addressToBan} - invalid address.`
|
|
766
813
|
);
|
|
767
814
|
}
|
|
768
815
|
|
|
769
816
|
if (!this.isAdmin(adminEntry)) {
|
|
770
817
|
throw new Error(
|
|
771
|
-
`Can not ban writer with address: ${
|
|
818
|
+
`Can not ban writer with address: ${addressToBan} - You are not an admin.`
|
|
772
819
|
);
|
|
773
820
|
}
|
|
774
821
|
|
|
775
|
-
const isWhitelisted = await this.#state.isAddressWhitelisted(
|
|
776
|
-
const nodeEntry = await this.#state.getNodeEntry(
|
|
822
|
+
const isWhitelisted = await this.#state.isAddressWhitelisted(addressToBan);
|
|
823
|
+
const nodeEntry = await this.#state.getNodeEntry(addressToBan);
|
|
777
824
|
|
|
778
825
|
if (!isWhitelisted || null === nodeEntry || nodeEntry.isIndexer === true) {
|
|
779
826
|
throw new Error(
|
|
780
|
-
`Can not ban writer with address: ${
|
|
827
|
+
`Can not ban writer with address: ${addressToBan} - node is not whitelisted or is an indexer.`
|
|
781
828
|
);
|
|
782
829
|
}
|
|
783
830
|
const txValidity = await this.#state.getIndexerSequenceState();
|
|
784
831
|
const assembledBanValidatorMessage = await applyStateMessageFactory(this.#wallet, this.#config)
|
|
785
832
|
.buildCompleteBanWriterMessage(
|
|
786
833
|
this.#wallet.address,
|
|
787
|
-
|
|
834
|
+
addressToBan,
|
|
788
835
|
txValidity,
|
|
789
836
|
)
|
|
790
837
|
const encodedPayload = safeEncodeApplyOperation(assembledBanValidatorMessage)
|
|
@@ -1100,6 +1147,149 @@ export class MainSettlementBus extends ReadyResource {
|
|
|
1100
1147
|
const encodedPayload = safeEncodeApplyOperation(payload);
|
|
1101
1148
|
await this.#state.append(encodedPayload);
|
|
1102
1149
|
}
|
|
1150
|
+
|
|
1151
|
+
async handleEpochGenesisInitialization(consensusConfig) {
|
|
1152
|
+
if (!this.#config.enableWallet) {
|
|
1153
|
+
throw new Error("Can not initialize genesis epoch - wallet is not enabled.");
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
const adminEntry = await this.#state.getAdminEntry();
|
|
1157
|
+
|
|
1158
|
+
if (!adminEntry) {
|
|
1159
|
+
throw new Error(
|
|
1160
|
+
"Can not initialize genesis epoch - admin has not been initialized."
|
|
1161
|
+
);
|
|
1162
|
+
}
|
|
1163
|
+
if (!this.#wallet) {
|
|
1164
|
+
throw new Error("Can not initialize genesis epoch - wallet is not initialized.");
|
|
1165
|
+
}
|
|
1166
|
+
if (!this.isAdmin(adminEntry)) {
|
|
1167
|
+
throw new Error("Can not initialize genesis epoch - you are not the admin.");
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
const existingConsensusConfig = await this.#state.getSignedConsensusConfig();
|
|
1171
|
+
if (existingConsensusConfig) {
|
|
1172
|
+
throw new Error("Can not initialize genesis epoch - consensus config already exists.");
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
const encodedConsensusConfig = this.#validateAndEncodeConsensusConfig(consensusConfig);
|
|
1176
|
+
|
|
1177
|
+
const txValidity = await this.#state.getIndexerSequenceState();
|
|
1178
|
+
const payload = await applyStateMessageFactory(this.#wallet, this.#config)
|
|
1179
|
+
.buildCompleteSetGenesisEpochMessage(
|
|
1180
|
+
this.#wallet.address,
|
|
1181
|
+
txValidity,
|
|
1182
|
+
encodedConsensusConfig,
|
|
1183
|
+
)
|
|
1184
|
+
const encodedPayload = encodeApplyOperation(payload);
|
|
1185
|
+
await this.#state.append(encodedPayload);
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
async handleSetConsensusConfig(consensusConfig) {
|
|
1189
|
+
if (!this.#config.enableWallet) {
|
|
1190
|
+
throw new Error("Can not set consensus config - wallet is not enabled.");
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
const adminEntry = await this.#state.getAdminEntry();
|
|
1194
|
+
|
|
1195
|
+
if (!adminEntry) {
|
|
1196
|
+
throw new Error("Can not set consensus config - admin has not been initialized.");
|
|
1197
|
+
}
|
|
1198
|
+
if (!this.#wallet) {
|
|
1199
|
+
throw new Error("Can not set consensus config - wallet is not initialized.");
|
|
1200
|
+
}
|
|
1201
|
+
if (!this.isAdmin(adminEntry)) {
|
|
1202
|
+
throw new Error("Can not set consensus config - you are not the admin.");
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
const encodedConsensusConfig = this.#validateAndEncodeConsensusConfig(consensusConfig);
|
|
1206
|
+
|
|
1207
|
+
const txValidity = await this.#state.getIndexerSequenceState();
|
|
1208
|
+
const payload = await applyStateMessageFactory(this.#wallet, this.#config)
|
|
1209
|
+
.buildCompleteSetConsensusConfigMessage(
|
|
1210
|
+
this.#wallet.address,
|
|
1211
|
+
txValidity,
|
|
1212
|
+
encodedConsensusConfig
|
|
1213
|
+
);
|
|
1214
|
+
const encodedPayload = encodeApplyOperation(payload);
|
|
1215
|
+
await this.#state.append(encodedPayload);
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
#validateAndEncodeConsensusConfig(consensusConfig) {
|
|
1219
|
+
if (!this.#hasExactKeys(consensusConfig, ["schemaVersion", "configData"])) {
|
|
1220
|
+
throw new Error(
|
|
1221
|
+
"Consensus config must contain only schemaVersion and configData."
|
|
1222
|
+
);
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
const { schemaVersion, configData } = consensusConfig;
|
|
1226
|
+
if (
|
|
1227
|
+
!Number.isInteger(schemaVersion) ||
|
|
1228
|
+
schemaVersion <= 0 ||
|
|
1229
|
+
schemaVersion > 0xFF
|
|
1230
|
+
) {
|
|
1231
|
+
throw new Error(
|
|
1232
|
+
"Consensus config schemaVersion must be an integer from 1 to 255."
|
|
1233
|
+
);
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
let encodedConfigData;
|
|
1237
|
+
switch (schemaVersion) {
|
|
1238
|
+
case ConsensusVersion.VDF_V1:
|
|
1239
|
+
encodedConfigData = this.#encodeVdfV1ConfigData(configData);
|
|
1240
|
+
break;
|
|
1241
|
+
default:
|
|
1242
|
+
throw new Error(
|
|
1243
|
+
`Unsupported consensus config schema version: ${schemaVersion}.`
|
|
1244
|
+
);
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
return encodeConsensusConfig({
|
|
1248
|
+
sv: uint8ToBuffer(schemaVersion),
|
|
1249
|
+
cd: encodedConfigData
|
|
1250
|
+
});
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
// TODO: REFACTOR - In the future, this function should be extracted into another module.
|
|
1254
|
+
#encodeVdfV1ConfigData(configData) {
|
|
1255
|
+
if (!this.#hasExactKeys(configData, ["difficulty", "discriminantBitSize"])) {
|
|
1256
|
+
throw new Error(
|
|
1257
|
+
"Consensus config schema version 1 configData must contain only difficulty and discriminantBitSize."
|
|
1258
|
+
);
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
if (
|
|
1262
|
+
!Number.isInteger(configData.difficulty) ||
|
|
1263
|
+
configData.difficulty <= 0 ||
|
|
1264
|
+
configData.difficulty > MAX_VDF_DIFFICULTY
|
|
1265
|
+
) {
|
|
1266
|
+
throw new Error(
|
|
1267
|
+
"VDF difficulty must be a positive unsigned 32-bit integer."
|
|
1268
|
+
);
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
if (
|
|
1272
|
+
!Number.isInteger(configData.discriminantBitSize) ||
|
|
1273
|
+
!Object.hasOwn(VDF_PROOF_BYTE_LENGTHS, configData.discriminantBitSize)
|
|
1274
|
+
) {
|
|
1275
|
+
throw new Error(
|
|
1276
|
+
"VDF discriminant bit size must be one of: 1024, 2048, 4096."
|
|
1277
|
+
);
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
return encodeVdfConfig({
|
|
1281
|
+
difficulty: uint32ToBuffer(configData.difficulty),
|
|
1282
|
+
discriminantBitSize: uint16ToBuffer(configData.discriminantBitSize)
|
|
1283
|
+
});
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
#hasExactKeys(value, expectedKeys) {
|
|
1287
|
+
return (
|
|
1288
|
+
_.isPlainObject(value) &&
|
|
1289
|
+
Object.keys(value).length === expectedKeys.length &&
|
|
1290
|
+
expectedKeys.every(key => Object.hasOwn(value, key))
|
|
1291
|
+
);
|
|
1292
|
+
}
|
|
1103
1293
|
}
|
|
1104
1294
|
|
|
1105
1295
|
export default MainSettlementBus;
|