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.
Files changed (136) hide show
  1. package/SECURITY.md +2 -2
  2. package/cli/commandHandler.js +317 -20
  3. package/cli/handlers.js +9 -1
  4. package/cli/interactive.js +4 -3
  5. package/cli/tokenSupplyAudit.js +90 -0
  6. package/msb.mjs +1 -0
  7. package/package.json +15 -6
  8. package/rpc/create_server.js +12 -3
  9. package/rpc/handlers.js +103 -0
  10. package/rpc/routes/v1.js +8 -0
  11. package/src/codecs/apply/applyOperationCodec.js +334 -0
  12. package/src/codecs/apply/applyOperations.generated.cjs +6380 -0
  13. package/src/codecs/consensus/v1/consensusV1.generated.cjs +3508 -0
  14. package/src/codecs/consensus/v1/consensusV1OperationCodec.js +161 -0
  15. package/src/codecs/consensus/v1/vdfConfigCodec.js +83 -0
  16. package/src/{utils/protobuf → codecs/network/v1}/networkV1.generated.cjs +664 -393
  17. package/src/codecs/network/v1/networkV1OperationCodec.js +25 -0
  18. package/src/codecs/protobufRuntime.cjs +95 -0
  19. package/src/codecs/state/escrowEntryCodec.js +45 -0
  20. package/src/codecs/state/state.generated.cjs +659 -0
  21. package/src/config/args.js +0 -1
  22. package/src/config/config.js +41 -7
  23. package/src/config/env.js +33 -9
  24. package/src/core/consensus/epochAppenderSelection/EpochAppenderSelectionError.js +55 -0
  25. package/src/core/consensus/epochAppenderSelection/EpochAppenderSelectionOperations.js +118 -0
  26. package/src/core/consensus/epochAppenderSelection/EpochAppenderSelector.js +1042 -0
  27. package/src/core/consensus/epochAppenderSelection/createEpochAppenderSelector.js +23 -0
  28. package/src/core/consensus/epochAppenderSelection/epochAppenderSelectionLedgerReader.js +274 -0
  29. package/src/core/consensus/epochAppenderSelection/epochAppenderSelectionState.js +488 -0
  30. package/src/core/consensus/epochAppenderSelection/epochAppenderSelectionStorage.js +93 -0
  31. package/src/core/consensus/quorum.js +11 -0
  32. package/src/core/consensus/services/EpochCoordinationRound.js +839 -0
  33. package/src/core/consensus/services/EpochCoordinatorOperations.js +211 -0
  34. package/src/core/consensus/services/EpochCoordinatorService.js +335 -0
  35. package/src/core/consensus/services/EpochRoundListeners.js +116 -0
  36. package/src/core/consensus/services/EpochStateMachine.js +141 -0
  37. package/src/core/consensus/services/VDFBare.js +291 -0
  38. package/src/core/consensus/services/VDFNode.js +111 -0
  39. package/src/core/consensus/services/VDFProgressWatchdog.js +79 -0
  40. package/src/core/consensus/services/VDFService.js +87 -0
  41. package/src/core/consensus/services/VDFServiceManager.js +147 -0
  42. package/src/core/consensus/services/createVDFService.js +16 -0
  43. package/src/core/consensus/services/vdf-guardian.js +32 -0
  44. package/src/core/consensus/services/vdf-worker.js +90 -0
  45. package/src/core/network/Network.js +327 -238
  46. package/src/core/network/protocols/consensus/IndexerMessages.js +72 -0
  47. package/src/core/network/protocols/consensus/v1/ConsensusV1ConnectionPolicy.js +57 -0
  48. package/src/core/network/protocols/consensus/v1/ConsensusV1MessageRouter.js +147 -0
  49. package/src/core/network/protocols/consensus/v1/ConsensusV1Protocol.js +72 -0
  50. package/src/core/network/protocols/consensus/v1/IndexerPendingRequestService.js +108 -0
  51. package/src/core/network/protocols/consensus/v1/V1ConsensusProtocolError.js +29 -0
  52. package/src/core/network/protocols/consensus/v1/handlers/V1EpochAppendOperationHandler.js +68 -0
  53. package/src/core/network/protocols/consensus/v1/handlers/V1EpochProofProposalOperationHandler.js +226 -0
  54. package/src/core/network/protocols/consensus/v1/validators/ConsensusValidationSchema.js +192 -0
  55. package/src/core/network/protocols/consensus/v1/validators/V1BaseConsensusOperation.js +428 -0
  56. package/src/core/network/protocols/consensus/v1/validators/V1EpochAppendReply.js +47 -0
  57. package/src/core/network/protocols/consensus/v1/validators/V1EpochAppendRequest.js +17 -0
  58. package/src/core/network/protocols/consensus/v1/validators/V1EpochProofProposalApproval.js +116 -0
  59. package/src/core/network/protocols/consensus/v1/validators/V1EpochProofProposalRequest.js +152 -0
  60. package/src/core/network/protocols/consensus/v1/validators/consensusValidationSchemaHelpers.js +145 -0
  61. package/src/core/network/protocols/shared/ConnectionOperationHandler.js +27 -0
  62. package/src/core/network/protocols/{NetworkMessages.js → validators/ValidatorMessages.js} +24 -14
  63. package/src/core/network/protocols/{ProtocolSession.js → validators/ValidatorProtocolSession.js} +22 -25
  64. package/src/core/network/protocols/{legacy/NetworkMessageRouter.js → validators/legacy/ValidatorLegacyMessageRouter.js} +6 -6
  65. package/src/core/network/protocols/{LegacyProtocol.js → validators/legacy/ValidatorLegacyProtocol.js} +9 -7
  66. package/src/core/network/protocols/{legacy → validators/legacy}/handlers/BaseStateOperationHandler.js +1 -1
  67. package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyGetRequestHandler.js +5 -5
  68. package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyRoleOperationHandler.js +5 -5
  69. package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacySubnetworkOperationHandler.js +5 -5
  70. package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyTransferOperationHandler.js +5 -5
  71. package/src/core/network/protocols/{ProtocolInterface.js → validators/shared/ValidatorProtocolInterface.js} +5 -5
  72. package/src/core/network/protocols/{shared → validators/shared}/validators/PartialBootstrapDeploymentValidator.js +1 -1
  73. package/src/core/network/protocols/validators/shared/validators/PartialHtlcValidator.js +325 -0
  74. package/src/core/network/protocols/{shared → validators/shared}/validators/PartialOperationValidator.js +44 -21
  75. package/src/core/network/protocols/{shared → validators/shared}/validators/PartialRoleAccessValidator.js +3 -3
  76. package/src/core/network/protocols/{shared → validators/shared}/validators/PartialTransactionValidator.js +3 -3
  77. package/src/core/network/protocols/{shared → validators/shared}/validators/PartialTransferValidator.js +4 -4
  78. package/src/core/network/protocols/{v1 → validators/v1}/V1ProtocolError.js +1 -1
  79. package/src/core/network/{services/PendingRequestService.js → protocols/validators/v1/ValidatorPendingRequestService.js} +19 -82
  80. package/src/core/network/protocols/{v1/NetworkMessageRouter.js → validators/v1/ValidatorV1MessageRouter.js} +9 -9
  81. package/src/core/network/protocols/{V1Protocol.js → validators/v1/ValidatorV1Protocol.js} +10 -8
  82. package/src/core/network/protocols/{connectionPolicies.js → validators/v1/connectionPolicies.js} +1 -1
  83. package/src/core/network/protocols/{v1 → validators/v1}/handlers/V1BaseOperationHandler.js +6 -23
  84. package/src/core/network/protocols/{v1 → validators/v1}/handlers/V1BroadcastTransactionOperationHandler.js +14 -9
  85. package/src/core/network/protocols/{v1 → validators/v1}/handlers/V1LivenessOperationHandler.js +5 -4
  86. package/src/core/network/protocols/{v1 → validators/v1}/handlers/broadcastTransaction/BroadcastTransactionErrorMapper.js +3 -3
  87. package/src/core/network/protocols/{v1 → validators/v1}/handlers/broadcastTransaction/BroadcastTransactionOperationStrategies.js +44 -1
  88. package/src/core/network/protocols/{v1 → validators/v1}/handlers/broadcastTransaction/BroadcastTransactionPayloadUtils.js +1 -1
  89. package/src/core/network/protocols/{v1 → validators/v1}/validators/V1BaseOperation.js +19 -15
  90. package/src/core/network/protocols/{v1 → validators/v1}/validators/V1BroadcastTransactionRequest.js +2 -2
  91. package/src/core/network/protocols/{v1 → validators/v1}/validators/V1BroadcastTransactionResponse.js +34 -18
  92. package/src/core/network/protocols/{v1 → validators/v1}/validators/V1ValidationSchema.js +3 -3
  93. package/src/core/network/services/IndexerConnectionManager.js +88 -0
  94. package/src/core/network/services/TransactionPoolService.js +11 -18
  95. package/src/core/network/services/TransactionRateLimiterService.js +1 -1
  96. package/src/core/network/services/ValidatorConnectionManager.js +163 -0
  97. package/src/core/network/services/{MessageOrchestrator.js → ValidatorMessageOrchestrator.js} +34 -42
  98. package/src/core/network/services/ValidatorObserverService.js +21 -36
  99. package/src/core/network/shared/BasePendingRequestService.js +67 -0
  100. package/src/core/network/shared/PeerConnectionManager.js +185 -0
  101. package/src/core/state/State.js +1789 -173
  102. package/src/core/state/StateEventQueue.js +69 -0
  103. package/src/core/state/utils/address.js +10 -6
  104. package/src/core/state/utils/epochProof.js +109 -0
  105. package/src/core/state/utils/escrowEntry.js +178 -0
  106. package/src/core/state/validators/StateValidationSchema.js +757 -0
  107. package/src/core/state/validators/stateValidationRules.js +312 -0
  108. package/src/index.js +255 -65
  109. package/src/messages/consensus/v1/ConsensusMessageBuilder.js +368 -0
  110. package/src/messages/consensus/v1/ConsensusMessageDirector.js +142 -0
  111. package/src/messages/consensus/v1/consensusMessageFactory.js +12 -0
  112. package/src/messages/consensus/v1/epochAppendMessage.js +58 -0
  113. package/src/messages/network/v1/NetworkMessageBuilder.js +15 -7
  114. package/src/messages/state/ApplyStateMessageBuilder.js +499 -13
  115. package/src/messages/state/ApplyStateMessageDirector.js +261 -2
  116. package/src/utils/StateMachine.js +125 -0
  117. package/src/utils/applyOperations.js +45 -2
  118. package/src/utils/buffer.js +239 -59
  119. package/src/utils/consensusConfig.js +76 -0
  120. package/src/utils/constants.js +174 -73
  121. package/src/utils/helpers.js +0 -25
  122. package/src/utils/htlcLock.js +122 -0
  123. package/src/utils/logger.js +10 -4
  124. package/src/utils/migrationUtils.js +2 -1
  125. package/src/utils/normalizers.js +113 -0
  126. package/src/utils/scheduler/SchedulableService.js +107 -0
  127. package/src/utils/{Scheduler.js → scheduler/Scheduler.js} +56 -17
  128. package/src/core/network/services/ConnectionManager.js +0 -406
  129. package/src/utils/check.js +0 -525
  130. package/src/utils/protobuf/applyOperations.cjs +0 -1373
  131. package/src/utils/protobuf/operationHelpers.js +0 -81
  132. /package/src/core/network/protocols/{legacy → validators/legacy}/handlers/LegacyResponseHandler.js +0 -0
  133. /package/src/core/network/protocols/{legacy → validators/legacy}/validators/ValidatorResponse.js +0 -0
  134. /package/src/core/network/protocols/{legacy → validators/legacy}/validators/base/BaseResponse.js +0 -0
  135. /package/src/core/network/protocols/{v1 → validators/v1}/validators/V1LivenessRequest.js +0 -0
  136. /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 {safeDecodeApplyOperation, safeEncodeApplyOperation} from "./utils/protobuf/operationHelpers.js";
29
- import PartialTransactionValidator from "./core/network/protocols/shared/validators/PartialTransactionValidator.js";
30
- import PartialTransferValidator from "./core/network/protocols/shared/validators/PartialTransferValidator.js";
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?.address ?? null);
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(addresstToBan) {
796
+ async banValidator(addressToBan) {
750
797
  if (!this.#config.enableWallet) {
751
798
  throw new Error(
752
- `Can not ban writer with address: ${addresstToBan} - wallet is not enabled.`
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: ${addresstToBan} - admin entry has not been initialized.`
806
+ `Can not ban writer with address: ${addressToBan} - admin entry has not been initialized.`
760
807
  );
761
808
  }
762
809
 
763
- if (!isAddressValid(addresstToBan, this.#config.addressPrefix)) {
810
+ if (!isAddressValid(addressToBan, this.#config.addressPrefix)) {
764
811
  throw new Error(
765
- `Can not ban writer with address: ${addresstToBan} - invalid 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: ${addresstToBan} - You are not an admin.`
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(addresstToBan);
776
- const nodeEntry = await this.#state.getNodeEntry(addresstToBan);
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: ${addresstToBan} - node is not whitelisted or is an indexer.`
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
- addresstToBan,
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;