trac-msb 0.2.26 → 0.3.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +121 -0
  10. package/rpc/routes/v1.js +12 -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 +1803 -159
  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 +280 -67
  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/SECURITY.md CHANGED
@@ -6,9 +6,9 @@ The following table shows which versions of this project are currently receiving
6
6
 
7
7
  | Version | Supported | Pear compatibility |
8
8
  | -------- | ------------------ | ------------------ |
9
- | 0.2.21 | :white_check_mark: | Pear v2 and v3 |
9
+ | 0.3.0 | :white_check_mark: | Pear v2 and v3 |
10
10
  | main | :warning: unstable | Pear v2 and v3 |
11
- | < 0.2.21 | :x: | N/A |
11
+ | < 0.3.0 | :x: | N/A |
12
12
 
13
13
  Versions older than 0.2.21 are deprecated.
14
14
  Please upgrade to the latest release to ensure you receive security fixes.
@@ -1,7 +1,23 @@
1
1
  import { randomBytes } from "hypercore-crypto";
2
+ import _ from "lodash";
2
3
  import { Handlers } from "./handlers.js";
3
4
  import { isHexString } from "../src/utils/helpers.js";
4
5
  import { bigIntToDecimalString } from "../src/utils/amountSerialization.js";
6
+ import {
7
+ MAX_VDF_DIFFICULTY,
8
+ VDF_PROOF_BYTE_LENGTHS
9
+ } from "../src/utils/constants.js";
10
+
11
+ const OPERATIONS = {
12
+ CONFIRMATION: "confirmation",
13
+ GENESIS_DIFFICULTY: "genesis-difficulty",
14
+ GENESIS_DISCRIMINANT_BIT_SIZE: "genesis-discriminant-bit-size",
15
+ CONSENSUS_CONFIG: "consensus-config",
16
+ VDF_DIFFICULTY: "vdf-difficulty",
17
+ VDF_DISCRIMINANT_BIT_SIZE: "vdf-discriminant-bit-size",
18
+ GENESIS_PREFIX: "genesis-",
19
+ VDF_PREFIX: "vdf-"
20
+ };
5
21
 
6
22
  export const COMMANDS = {
7
23
  HELP: "/help",
@@ -14,6 +30,7 @@ export const COMMANDS = {
14
30
  CORE: "/core",
15
31
  INDEXERS_LIST: "/indexers_list",
16
32
  VALIDATOR_POOL: "/validator_pool",
33
+ INDEXER_POOL: "/indexer_pool",
17
34
  STATS: "/stats",
18
35
  BALANCE_MIGRATION: "/balance_migration",
19
36
  DISABLE_INITIALIZATION: "/disable_initialization",
@@ -36,7 +53,10 @@ export const COMMANDS = {
36
53
  UNCONFIRMED_LENGTH: "/unconfirmed_length",
37
54
  GET_TXS_HASHES: "/get_txs_hashes",
38
55
  GET_TX_DETAILS: "/get_tx_details",
39
- GET_EXTENDED_TX_DETAILS: "/get_extended_tx_details"
56
+ GET_EXTENDED_TX_DETAILS: "/get_extended_tx_details",
57
+ EPOCH_GENESIS_INITIALIZATION: "/init_genesis",
58
+ SET_CONSENSUS_CONFIG: "/set_consensus_config",
59
+ SET_VDF_PARAMS: "/set_vdf_params"
40
60
  };
41
61
 
42
62
  export class CommandHandler {
@@ -44,7 +64,6 @@ export class CommandHandler {
44
64
  #closeCli;
45
65
  #wallet;
46
66
  #handlers;
47
- #pendingConfirmation = null;
48
67
 
49
68
  constructor({ config, msb, handleClose, wallet }) {
50
69
  this.#msb = msb;
@@ -53,23 +72,35 @@ export class CommandHandler {
53
72
  this.#handlers = new Handlers(msb, config);
54
73
  }
55
74
 
56
- async handle(input) {
57
- if (this.#pendingConfirmation !== null) {
58
- return this.#handlePendingConfirmation(input);
59
- }
60
-
75
+ async handle(input, context) {
61
76
  const [command, ...parts] = input.split(" ");
62
- const context = { command, input, parts };
77
+ const handlerContext = { command, input, parts, context };
63
78
  const handlers = this.#getHandlers();
64
- const handler = handlers.find(({ evaluate }) => evaluate(context));
79
+ const handler = handlers.find(({ evaluate }) => evaluate(handlerContext));
65
80
 
66
81
  if (handler) {
67
- return handler.process(context);
82
+ return handler.process(handlerContext);
68
83
  }
69
84
  }
70
85
 
71
86
  #getHandlers() {
72
87
  return [
88
+ {
89
+ evaluate: ({ context }) => context.pending?.op === OPERATIONS.CONFIRMATION,
90
+ process: async ({ input, context }) => this.#handlePendingConfirmation(input, context)
91
+ },
92
+ {
93
+ evaluate: ({ context }) => context.pending?.op.startsWith(OPERATIONS.GENESIS_PREFIX),
94
+ process: async ({ input, context }) => this.#handlePendingGenesisInitialization(input, context)
95
+ },
96
+ {
97
+ evaluate: ({ context }) => context.pending?.op === OPERATIONS.CONSENSUS_CONFIG,
98
+ process: async ({ input, context }) => this.#handlePendingSetConsensusConfig(input, context)
99
+ },
100
+ {
101
+ evaluate: ({ context }) => context.pending?.op.startsWith(OPERATIONS.VDF_PREFIX),
102
+ process: async ({ input, context }) => this.#handlePendingSetVdfParams(input, context)
103
+ },
73
104
  {
74
105
  evaluate: ({ command }) => command === COMMANDS.HELP,
75
106
  process: async () => {
@@ -115,6 +146,10 @@ export class CommandHandler {
115
146
  evaluate: ({ command }) => command === COMMANDS.VALIDATOR_POOL,
116
147
  process: async () => this.#msb.network.validatorConnectionManager.prettyPrint()
117
148
  },
149
+ {
150
+ evaluate: ({ command }) => command === COMMANDS.INDEXER_POOL,
151
+ process: async () => this.#msb.network.indexerConnectionManager.prettyPrint()
152
+ },
118
153
  {
119
154
  evaluate: ({ command }) => command === COMMANDS.STATS,
120
155
  process: async () => this.#msb.verifyDag()
@@ -167,7 +202,7 @@ export class CommandHandler {
167
202
  },
168
203
  {
169
204
  evaluate: ({ input }) => input.startsWith(COMMANDS.TRANSFER),
170
- process: async ({ parts }) => this.#queueTransferConfirmation(parts[0], parts[1])
205
+ process: async ({ parts, context }) => this.#queueTransferConfirmation(parts[0], parts[1], context)
171
206
  },
172
207
  {
173
208
  evaluate: ({ input }) => input.startsWith(COMMANDS.GET_BALANCE),
@@ -215,16 +250,28 @@ export class CommandHandler {
215
250
  {
216
251
  evaluate: ({ input }) => input.startsWith(COMMANDS.GET_EXTENDED_TX_DETAILS),
217
252
  process: async ({ parts }) => this.#handlers.handleExtendedTxDetails(parts[0], parts[1] === "true")
253
+ },
254
+ {
255
+ evaluate: ({ input }) => input.startsWith(COMMANDS.EPOCH_GENESIS_INITIALIZATION),
256
+ process: async ({ context }) => this.#queueEpochGenesisInitialization(context)
257
+ },
258
+ {
259
+ evaluate: ({ command }) => command === COMMANDS.SET_CONSENSUS_CONFIG,
260
+ process: async ({ context }) => this.#queueSetConsensusConfig(context)
261
+ },
262
+ {
263
+ evaluate: ({ command }) => command === COMMANDS.SET_VDF_PARAMS,
264
+ process: async ({ context }) => this.#queueSetVdfParams(context)
218
265
  }
219
266
  ];
220
267
  }
221
268
 
222
- async #handlePendingConfirmation(input) {
269
+ async #handlePendingConfirmation(input, context) {
223
270
  const normalizedInput = input.trim().toLowerCase();
224
- const pendingConfirmation = this.#pendingConfirmation;
271
+ const pendingConfirmation = context.pending;
225
272
 
226
273
  if (normalizedInput === "y" || normalizedInput === "yes") {
227
- this.#pendingConfirmation = null;
274
+ context.pending = null;
228
275
 
229
276
  try {
230
277
  return await pendingConfirmation.onConfirm();
@@ -232,7 +279,8 @@ export class CommandHandler {
232
279
  const errorMessage = typeof error === "object" && error !== null && "message" in error
233
280
  ? error.message
234
281
  : `${error}`;
235
- console.error(`Transaction submission failed: ${errorMessage}`);
282
+ const failureMessage = pendingConfirmation.failureMessage || "Transaction submission failed";
283
+ console.error(`${failureMessage}: ${errorMessage}`);
236
284
  console.log("Try again or use /help.");
237
285
  }
238
286
 
@@ -240,15 +288,15 @@ export class CommandHandler {
240
288
  }
241
289
 
242
290
  if (normalizedInput === "n" || normalizedInput === "no") {
243
- this.#pendingConfirmation = null;
291
+ context.pending = null;
244
292
  return pendingConfirmation.onDecline();
245
293
  }
246
294
 
247
- console.log('Invalid input. Please answer "y" or "n".');
295
+ console.log(pendingConfirmation.invalidMessage || 'Invalid input. Please answer "y" or "n".');
248
296
  console.log(pendingConfirmation.prompt);
249
297
  }
250
298
 
251
- async #queueTransferConfirmation(recipientAddress, amount) {
299
+ async #queueTransferConfirmation(recipientAddress, amount, context) {
252
300
  const preparedTransfer = await this.#msb.prepareTransferOperation(recipientAddress, amount);
253
301
 
254
302
  console.info("Transfer Details:");
@@ -261,12 +309,261 @@ export class CommandHandler {
261
309
  console.info(`Current balance: ${bigIntToDecimalString(preparedTransfer.senderBalance)}`);
262
310
  console.info(`Balance after transaction: ${bigIntToDecimalString(preparedTransfer.expectedNewBalance)}`);
263
311
 
264
- this.#pendingConfirmation = {
312
+ context.pending = {
313
+ op: OPERATIONS.CONFIRMATION,
265
314
  prompt: "Do you want to proceed? (y/n)",
266
315
  onConfirm: async () => this.#msb.submitPreparedTransferOperation(preparedTransfer),
267
316
  onDecline: async () => this.#msb.printHelp()
268
317
  };
269
318
 
270
- console.log(this.#pendingConfirmation.prompt);
319
+ console.log(context.pending.prompt);
320
+ }
321
+
322
+ #queueEpochGenesisInitialization(context) {
323
+ context.pending = {
324
+ op: OPERATIONS.GENESIS_DIFFICULTY
325
+ };
326
+
327
+ console.log(this.#getGenesisDifficultyPrompt());
328
+ }
329
+
330
+ #handlePendingGenesisInitialization(input, context) {
331
+ const pendingGenesisInitialization = context.pending;
332
+
333
+ if (pendingGenesisInitialization.op === OPERATIONS.GENESIS_DIFFICULTY) {
334
+ const difficulty = this.#parsePositiveInteger(input, BigInt(MAX_VDF_DIFFICULTY));
335
+ if (!difficulty) {
336
+ console.log("Invalid difficulty. Please enter a positive integer (example 55_000_000).");
337
+ console.log(this.#getGenesisDifficultyPrompt());
338
+ return;
339
+ }
340
+
341
+ pendingGenesisInitialization.difficulty = difficulty;
342
+ pendingGenesisInitialization.op = OPERATIONS.GENESIS_DISCRIMINANT_BIT_SIZE;
343
+ console.log(this.#getGenesisDiscriminantBitSizePrompt());
344
+ return;
345
+ }
346
+
347
+ const discriminantBitSize = this.#parseVdfDiscriminantBitSize(input);
348
+ if (!discriminantBitSize) {
349
+ console.log("Invalid discriminant bit size. Please enter one of: 1024, 2048, 4096.");
350
+ console.log(this.#getGenesisDiscriminantBitSizePrompt());
351
+ return;
352
+ }
353
+
354
+ const difficulty = pendingGenesisInitialization.difficulty;
355
+ context.pending = null;
356
+
357
+ return this.#queueEpochGenesisConfirmation({
358
+ difficulty,
359
+ discriminantBitSize
360
+ }, context);
361
+ }
362
+
363
+ #queueEpochGenesisConfirmation({ difficulty, discriminantBitSize }, context) {
364
+ const consensusConfig = {
365
+ schemaVersion: 1,
366
+ configData: {
367
+ difficulty: Number(difficulty.value),
368
+ discriminantBitSize: Number(discriminantBitSize.value)
369
+ }
370
+ };
371
+
372
+ console.info("Genesis Epoch Initialization Parameters:");
373
+ console.info(`VDF difficulty: ${difficulty.display}`);
374
+ console.info(`VDF discriminant bit size: ${discriminantBitSize.display}`);
375
+
376
+ context.pending = {
377
+ op: OPERATIONS.CONFIRMATION,
378
+ prompt: "Do you want to proceed? (yes/no)",
379
+ invalidMessage: 'Invalid input. Please answer "yes" or "no".',
380
+ failureMessage: "Genesis epoch initialization failed",
381
+ onConfirm: async () => this.#handlers.handleEpochGenesisInitialization(consensusConfig),
382
+ onDecline: async () => console.log("Genesis epoch initialization cancelled.")
383
+ };
384
+
385
+ console.log(context.pending.prompt);
386
+ }
387
+
388
+ #queueSetConsensusConfig(context) {
389
+ context.pending = { op: OPERATIONS.CONSENSUS_CONFIG };
390
+
391
+ console.log(this.#getSetConsensusConfigPrompt());
392
+ }
393
+
394
+ #handlePendingSetConsensusConfig(input, context) {
395
+ if (input.trim().toLowerCase() === "/cancel") {
396
+ context.pending = null;
397
+ console.log("Consensus config update cancelled.");
398
+ return;
399
+ }
400
+
401
+ const consensusConfig = this.#parseConsensusConfig(input);
402
+ if (!consensusConfig) {
403
+ console.log(
404
+ 'Invalid consensus config. Please enter a JSON object containing only "schemaVersion" and "configData".'
405
+ );
406
+ console.log(this.#getSetConsensusConfigPrompt());
407
+ return;
408
+ }
409
+
410
+ context.pending = null;
411
+ return this.#queueSetConsensusConfigConfirmation(consensusConfig, context);
412
+ }
413
+
414
+ #queueSetConsensusConfigConfirmation(consensusConfig, context) {
415
+ console.info("Consensus Config Update:");
416
+ console.info(JSON.stringify(consensusConfig, null, 2));
417
+
418
+ context.pending = {
419
+ op: OPERATIONS.CONFIRMATION,
420
+ prompt: "Do you want to proceed? (yes/no)",
421
+ invalidMessage: 'Invalid input. Please answer "yes" or "no".',
422
+ failureMessage: "Consensus config update failed",
423
+ onConfirm: async () => this.#handlers.handleSetConsensusConfig(consensusConfig),
424
+ onDecline: async () => console.log("Consensus config update cancelled.")
425
+ };
426
+
427
+ console.log(context.pending.prompt);
428
+ }
429
+
430
+ #queueSetVdfParams(context) {
431
+ context.pending = {
432
+ op: OPERATIONS.VDF_DIFFICULTY
433
+ };
434
+
435
+ console.log(this.#getSetVdfParamsDifficultyPrompt());
436
+ }
437
+
438
+ #handlePendingSetVdfParams(input, context) {
439
+ if (input.trim().toLowerCase() === "/cancel") {
440
+ context.pending = null;
441
+ console.log("VDF params update cancelled.");
442
+ return;
443
+ }
444
+
445
+ const pendingSetVdfParams = context.pending;
446
+
447
+ if (pendingSetVdfParams.op === OPERATIONS.VDF_DIFFICULTY) {
448
+ const difficulty = this.#parsePositiveInteger(input, BigInt(MAX_VDF_DIFFICULTY));
449
+ if (!difficulty) {
450
+ console.log(
451
+ "Invalid difficulty. Please enter an integer between 1 and 4_294_967_295."
452
+ );
453
+ console.log(this.#getSetVdfParamsDifficultyPrompt());
454
+ return;
455
+ }
456
+
457
+ pendingSetVdfParams.difficulty = difficulty;
458
+ pendingSetVdfParams.op = OPERATIONS.VDF_DISCRIMINANT_BIT_SIZE;
459
+ console.log(this.#getSetVdfParamsDiscriminantBitSizePrompt());
460
+ return;
461
+ }
462
+
463
+ const discriminantBitSize = this.#parseVdfDiscriminantBitSize(input);
464
+ if (!discriminantBitSize) {
465
+ console.log(
466
+ "Invalid discriminant bit size. Please enter one of: 1024, 2048, 4096."
467
+ );
468
+ console.log(this.#getSetVdfParamsDiscriminantBitSizePrompt());
469
+ return;
470
+ }
471
+
472
+ const difficulty = pendingSetVdfParams.difficulty;
473
+ context.pending = null;
474
+ return this.#queueSetVdfParamsConfirmation({
475
+ difficulty,
476
+ discriminantBitSize
477
+ }, context);
478
+ }
479
+
480
+ #queueSetVdfParamsConfirmation({ difficulty, discriminantBitSize }, context) {
481
+ const consensusConfig = {
482
+ schemaVersion: 1,
483
+ configData: {
484
+ difficulty: Number(difficulty.value),
485
+ discriminantBitSize: Number(discriminantBitSize.value)
486
+ }
487
+ };
488
+
489
+ console.info("VDF Params Update:");
490
+ console.info(`VDF difficulty: ${difficulty.display}`);
491
+ console.info(`VDF discriminant bit size: ${discriminantBitSize.display}`);
492
+
493
+ context.pending = {
494
+ op: OPERATIONS.CONFIRMATION,
495
+ prompt: "Do you want to proceed? (yes/no)",
496
+ invalidMessage: 'Invalid input. Please answer "yes" or "no".',
497
+ failureMessage: "VDF params update failed",
498
+ onConfirm: async () => this.#handlers.handleSetConsensusConfig(consensusConfig),
499
+ onDecline: async () => console.log("VDF params update cancelled.")
500
+ };
501
+
502
+ console.log(context.pending.prompt);
503
+ }
504
+
505
+ #parseConsensusConfig(input) {
506
+ try {
507
+ const parsed = JSON.parse(input);
508
+ if (
509
+ !_.isPlainObject(parsed) ||
510
+ Object.keys(parsed).length !== 2 ||
511
+ !Object.hasOwn(parsed, "schemaVersion") ||
512
+ !Object.hasOwn(parsed, "configData")
513
+ ) {
514
+ return null;
515
+ }
516
+
517
+ return parsed;
518
+ } catch {
519
+ return null;
520
+ }
521
+ }
522
+
523
+ #parsePositiveInteger(input, maximum = null) {
524
+ const display = input.trim();
525
+ if (!/^[0-9]+(?:_[0-9]+)*$/.test(display)) {
526
+ return null;
527
+ }
528
+
529
+ const value = display.replaceAll("_", "");
530
+ const integer = BigInt(value);
531
+ if (integer <= 0n || (maximum !== null && integer > maximum)) {
532
+ return null;
533
+ }
534
+
535
+ return { display, value };
536
+ }
537
+
538
+ #parseVdfDiscriminantBitSize(input) {
539
+ const parsed = this.#parsePositiveInteger(input);
540
+ if (
541
+ parsed === null ||
542
+ !Object.hasOwn(VDF_PROOF_BYTE_LENGTHS, Number(parsed.value))
543
+ ) {
544
+ return null;
545
+ }
546
+
547
+ return parsed;
548
+ }
549
+
550
+ #getGenesisDifficultyPrompt() {
551
+ return "Set VDF difficulty (example 55_000_000):";
552
+ }
553
+
554
+ #getGenesisDiscriminantBitSizePrompt() {
555
+ return "Set VDF discriminant bit size (example 2048):";
556
+ }
557
+
558
+ #getSetConsensusConfigPrompt() {
559
+ return 'Set consensus config as JSON, or enter /cancel (example {"schemaVersion":1,"configData":{"difficulty":60000000,"discriminantBitSize":2048}}):';
560
+ }
561
+
562
+ #getSetVdfParamsDifficultyPrompt() {
563
+ return "Set new VDF difficulty (example 55_000_000):";
564
+ }
565
+
566
+ #getSetVdfParamsDiscriminantBitSizePrompt() {
567
+ return "Set new VDF discriminant bit size (example 2048):";
271
568
  }
272
569
  }
package/cli/handlers.js CHANGED
@@ -3,7 +3,7 @@ import { bigIntToDecimalString, bufferToBigInt } from "../src/utils/amountSerial
3
3
  import { EntryType } from "../src/utils/constants.js";
4
4
  import { bufferToAddress } from "../src/core/state/utils/address.js";
5
5
  import deploymentEntryUtils from "../src/core/state/utils/deploymentEntry.js";
6
- import { safeDecodeApplyOperation } from "../src/utils/protobuf/operationHelpers.js";
6
+ import { safeDecodeApplyOperation } from "../src/codecs/apply/applyOperationCodec.js";
7
7
 
8
8
  export class Handlers {
9
9
  #msb
@@ -207,4 +207,12 @@ export class Handlers {
207
207
 
208
208
  return txDetails;
209
209
  }
210
+
211
+ async handleEpochGenesisInitialization(consensusConfig) {
212
+ return this.#msb.handleEpochGenesisInitialization(consensusConfig);
213
+ }
214
+
215
+ async handleSetConsensusConfig(consensusConfig) {
216
+ return this.#msb.handleSetConsensusConfig(consensusConfig);
217
+ }
210
218
  }
@@ -59,6 +59,7 @@ class Cli extends ReadyResource {
59
59
 
60
60
  startInteractiveMode() {
61
61
  console.log('RPC server will not be started.');
62
+ const context = { pending: null };
62
63
 
63
64
  this.#commandHandlers = new CommandHandler({
64
65
  config: this.#config,
@@ -71,7 +72,7 @@ class Cli extends ReadyResource {
71
72
 
72
73
  this.#readlineInstance.on("line", async (input) => {
73
74
  try {
74
- await this.#handleCommand(input.trim());
75
+ await this.#handleCommand(input.trim(), context);
75
76
  } catch (err) {
76
77
  console.error(`${err}`);
77
78
  }
@@ -81,8 +82,8 @@ class Cli extends ReadyResource {
81
82
  this.#readlineInstance.prompt();
82
83
  }
83
84
 
84
- async #handleCommand(input) {
85
- return this.#commandHandlers.handle(input);
85
+ async #handleCommand(input, context) {
86
+ return this.#commandHandlers.handle(input, context);
86
87
  }
87
88
 
88
89
  #completeCommand(line) {
@@ -0,0 +1,90 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { decimalStringToBigInt } from '../src/utils/amountSerialization.js';
4
+ import { auditJSON, formatAuditAmount } from '../src/core/state/audit/supply.js';
5
+
6
+ let running = false;
7
+
8
+ export async function runTokenSupplyAudit(msb, expectedNetIssuedText) {
9
+ if (running) throw new Error('A TNK supply audit is already running');
10
+ const expectedNetIssued = expectedNetIssuedText === undefined ? undefined : decimalStringToBigInt(expectedNetIssuedText);
11
+ running = true;
12
+ const reportPath = path.resolve(`tnk-supply-audit-${Date.now()}.jsonl`);
13
+ let output;
14
+ let fileError;
15
+ let lines = [];
16
+ const flush = async () => {
17
+ if (fileError) throw fileError;
18
+ if (!lines.length) return;
19
+ const text = lines.join('');
20
+ lines = [];
21
+ await new Promise((resolve, reject) => output.write(text, error => error ? reject(error) : resolve()));
22
+ };
23
+ const record = async value => {
24
+ lines.push(auditJSON(value) + '\n');
25
+ if (lines.length >= 100 || ['header', 'current-supply', 'summary', 'incomplete'].includes(value.kind)) await flush();
26
+ if (value.kind === 'current-supply') {
27
+ console.log(`Current confirmed supply: ${formatAuditAmount(value.actualSupply)} TNK ` +
28
+ `(spendable ${formatAuditAmount(value.spendableSupply)}, staked ${formatAuditAmount(value.stakedSupply)}). ` +
29
+ 'History reconciliation is still pending.');
30
+ }
31
+ };
32
+ try {
33
+ output = fs.createWriteStream(reportPath, { flags: 'wx' });
34
+ output.on('error', error => { fileError = error; });
35
+ console.log(`TNK supply audit report: ${reportPath}`);
36
+ console.log('Checking one signed snapshot. All amounts use exact 18-decimal TNK arithmetic.');
37
+ const audit = await msb.getTokenSupplyAudit({
38
+ expectedNetIssued,
39
+ onRecord: record,
40
+ progressInterval: 1_000,
41
+ onProgress: event => {
42
+ if (event.phase === 'start') console.log(`Confirmed length: ${event.confirmedLength}`);
43
+ if (event.phase === 'state') console.log(`Scanning state: ${event.currentEntries} entries, ${event.nodeEntries} accounts.`);
44
+ if (event.phase === 'history') console.log(`Checking history: ${event.historyEntries}/${event.confirmedLength - 1}, ${event.receipts} receipts.`);
45
+ if (event.phase === 'waiting' && event.idleMs >= 5_000) console.log(`Waiting for ${event.scan} data (${Math.floor(event.idleMs / 1000)}s), next ${event.cursor ?? '(start)'}.`);
46
+ if (event.phase === 'read-retry') console.log(`Retrying ${event.scan} read at ${event.cursor ?? '(start)'} (${event.retry}/${event.maxRetries}); processed entries are retained.`);
47
+ if (event.phase === 'process-pause') console.log(`Detected a process pause (${Math.floor(event.pauseMs / 1000)}s); continuing ${event.scan} from ${event.cursor ?? '(start)'}.`);
48
+ if (event.phase === 'report-error') console.error(`Could not complete the audit report: ${event.message}`);
49
+ }
50
+ });
51
+ await flush();
52
+ await new Promise((resolve, reject) => {
53
+ output.once('error', reject);
54
+ output.end(resolve);
55
+ });
56
+ if (fileError) throw fileError;
57
+ console.log('TNK Supply Audit:', {
58
+ Status: audit.status,
59
+ ConfirmedLength: audit.confirmedLength,
60
+ Accounts: audit.nodeEntries,
61
+ VerifiedReceipts: audit.receipts,
62
+ SpendableTNK: formatAuditAmount(audit.spendableSupply),
63
+ StakedTNK: formatAuditAmount(audit.stakedSupply),
64
+ ActualSupplyTNK: formatAuditAmount(audit.actualSupply),
65
+ NetIssuedTNK: formatAuditAmount(audit.netIssued),
66
+ ReceiptFeeBurnTNK: formatAuditAmount(audit.feeBurn),
67
+ ExpectedSupplyAfterReceiptFeesTNK: formatAuditAmount(audit.expectedSupplyAfterReceiptFees),
68
+ UnexplainedDifferenceTNK: formatAuditAmount(audit.unexplainedDifference),
69
+ PositiveOperationDifferencesTNK: formatAuditAmount(audit.positiveOperationDifferences),
70
+ NegativeOperationDifferencesTNK: formatAuditAmount(audit.negativeOperationDifferences),
71
+ MismatchingOperations: audit.mismatchingOperations,
72
+ AccountsWithUnverifiedAdjustments: audit.accountsWithUnverifiedAdjustments,
73
+ MismatchingAccounts: audit.mismatchingAccounts,
74
+ TrailingUnreceiptedChanges: audit.trailingUnreceiptedChanges.length,
75
+ ApprovedNetIssuanceMatches: audit.approvedNetIssuanceMatches ?? 'NOT PROVIDED',
76
+ Report: reportPath,
77
+ });
78
+ console.log(audit.status === 'RECONCILED'
79
+ ? 'All checked receipt economics and account balances reconcile at this signed height.'
80
+ : 'Review required. Inspect operation/account differences in the report; this is not a clean supply verdict.');
81
+ for (const limitation of audit.limitations) console.log(limitation);
82
+ return audit;
83
+ } catch (error) {
84
+ console.error(`TNK audit INCOMPLETE: ${error.message}. No complete supply verdict. Report path: ${reportPath}`);
85
+ throw error;
86
+ } finally {
87
+ output?.destroy();
88
+ running = false;
89
+ }
90
+ }
package/msb.mjs CHANGED
@@ -13,3 +13,4 @@ const start = async () => {
13
13
  }
14
14
 
15
15
  start()
16
+ // WIP
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "trac-msb",
3
3
  "main": "msb.mjs",
4
- "version": "0.2.26",
4
+ "version": "0.3.0-beta.2",
5
5
  "pear": {
6
6
  "name": "trac-msb",
7
7
  "type": "terminal"
@@ -26,23 +26,35 @@
26
26
  "lint:fix": "eslint . --fix",
27
27
  "protobuf": "node scripts/generate-protobufs.js",
28
28
  "docs:check": "node scripts/docs/docs-checker.js",
29
- "test:acceptance": "node --experimental-vm-modules node_modules/jest/bin/jest.js --testTimeout=200000 tests/acceptance/v1/rpc.test.mjs --runInBand",
29
+ "test:acceptance": "node --experimental-vm-modules node_modules/jest/bin/jest.js --testTimeout=200000 tests/acceptance/v1/rpc.test.mjs tests/acceptance/v1/htlc/htlc-routing.test.mjs tests/acceptance/v1/current-epoch/current-epoch-routing.test.mjs tests/acceptance/v1/consensus-config/consensus-config-routing.test.mjs --runInBand",
30
30
  "test:integration": "brittle-node -t 1200000 tests/integration/integration.test.js",
31
31
  "test:unit:node": "brittle-node -t 60000 tests/unit/unit.test.js",
32
32
  "test:unit:bare": "brittle-bare -t 60000 tests/unit/unit.test.js",
33
33
  "test:unit:pear": "BRITTLE='-t 60000' brittle-pear tests/unit/unit.test.js",
34
34
  "test:pear-runner": "node --test tests/runner/pear-runner.test.js",
35
35
  "test:unit:all": "(npm run test:unit:node && npm run test:unit:bare && npm run test:pear-runner) || exit 1",
36
- "test:unit:node:cov": "brittle-node -c -t 60000 tests/unit/unit.test.js"
36
+ "test:unit:node:cov": "brittle-node -c -t 60000 tests/unit/unit.test.js",
37
+ "test:integration:consensus:node": "brittle-node -t 180000 tests/integration/consensus/consensus.test.js",
38
+ "test:integration:consensus:bare": "brittle-bare -t 180000 tests/integration/consensus/consensus.test.js",
39
+ "test:integration:consensus": "npm run test:integration:consensus:node && npm run test:integration:consensus:bare"
37
40
  },
38
41
  "dependencies": {
42
+ "@tracsystems/trac-vdf": "^0.0.3",
39
43
  "autobase": "7.20.1",
40
44
  "b4a": "1.6.7",
45
+ "bare-channel": "^5.2.3",
41
46
  "bare-crypto": "1.12.0",
42
47
  "bare-fs": "4.5.0",
48
+ "bare-hrtime": "^2.1.1",
43
49
  "bare-http1": "4.1.5",
50
+ "bare-os": "^3.6.1",
51
+ "bare-pipe": "^4.1.0",
44
52
  "bare-readline": "1.0.7",
53
+ "bare-runtime": "^1.31.0",
54
+ "bare-subprocess": "^5.1.5",
55
+ "bare-thread": "^1.2.2",
45
56
  "bare-tty": "5.0.2",
57
+ "bare-url": "^2.4.3",
46
58
  "bare-utils": "1.5.1",
47
59
  "bech32": "2.0.0",
48
60
  "compact-encoding": "2.18.0",
@@ -62,7 +74,6 @@
62
74
  "pear-runtime": "1.3.1",
63
75
  "process": "npm:bare-process@4.2.2",
64
76
  "protobufjs": "^7.5.4",
65
- "protocol-buffers-encodings": "1.2.0",
66
77
  "protomux": "3.10.1",
67
78
  "protomux-wakeup": "2.4.0",
68
79
  "readline": "npm:bare-node-readline",
@@ -74,14 +85,12 @@
74
85
  },
75
86
  "devDependencies": {
76
87
  "bare-module": "^6.1.3",
77
- "bare-os": "^3.6.1",
78
88
  "bip39-mnemonic": "^2.4.0",
79
89
  "brittle": "^3.19.1",
80
90
  "eslint": "^9.39.4",
81
91
  "esmock": "^2.7.2",
82
92
  "jest": "^30.1.3",
83
93
  "protobufjs-cli": "^1.2.0",
84
- "protocol-buffers": "^4.2.0",
85
94
  "sinon": "^21.0.0",
86
95
  "supertest": "^7.1.4"
87
96
  },