trac-msb 0.3.0-beta.1 → 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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "trac-msb",
3
3
  "main": "msb.mjs",
4
- "version": "0.3.0-beta.1",
4
+ "version": "0.3.0-beta.2",
5
5
  "pear": {
6
6
  "name": "trac-msb",
7
7
  "type": "terminal"
@@ -26,7 +26,7 @@
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 tests/acceptance/v1/htlc/htlc-routing.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",
package/rpc/handlers.js CHANGED
@@ -456,3 +456,21 @@ export async function handleAccountDetails({ msbInstance, respond, req }) {
456
456
  stakedBalance: bufferToBigInt(nodeEntry.stakedBalance).toString(),
457
457
  });
458
458
  }
459
+
460
+ export async function handleCurrentEpoch({ req, msbInstance, respond }) {
461
+ const confirmed = getConfirmedParameter(buildRequestUrl(req));
462
+ if (confirmed === null) {
463
+ return respond(400, { error: 'Parameter "confirmed" must be exactly "true" or "false"' });
464
+ }
465
+ const current_epoch = await msbInstance.getCurrentEpoch(confirmed);
466
+ respond(200, { current_epoch });
467
+ }
468
+
469
+ export async function handleConsensusConfig({ req, msbInstance, respond }) {
470
+ const confirmed = getConfirmedParameter(buildRequestUrl(req));
471
+ if (confirmed === null) {
472
+ return respond(400, { error: 'Parameter "confirmed" must be exactly "true" or "false"' });
473
+ }
474
+ const consensusConfig = await msbInstance.getConsensusConfig(confirmed);
475
+ respond(200, consensusConfig);
476
+ }
package/rpc/routes/v1.js CHANGED
@@ -15,6 +15,8 @@ import {
15
15
  handleHtlcClaim,
16
16
  handleHtlcRefund,
17
17
  handleHtlc,
18
+ handleCurrentEpoch,
19
+ handleConsensusConfig,
18
20
  } from '../handlers.js';
19
21
 
20
22
  export const v1Routes = [
@@ -34,4 +36,6 @@ export const v1Routes = [
34
36
  { method: 'POST', path: '/tx-payloads-bulk', handler: handleFetchBulkTxPayloads },
35
37
  { method: 'GET', path: '/tx/details', handler: handleTransactionExtendedDetails },
36
38
  { method: 'GET', path: '/account', handler: handleAccountDetails },
39
+ { method: 'GET', path: '/current-epoch', exact: true, handler: handleCurrentEpoch },
40
+ { method: 'GET', path: '/consensus-config', exact: true, handler: handleConsensusConfig },
37
41
  ];
@@ -676,6 +676,12 @@ class State extends ReadyResource {
676
676
  for await (const entry of historyStream) {
677
677
  if (isTransactionRecordPut(entry)) {
678
678
  hashes.push({ hash: entry.key, confirmed_length: entry.seq });
679
+ } else if (entry.type === 'put' && entry.key.startsWith(EntryType.EPOCH_HASH)) {
680
+ // Epoch records share this history, but have their own key namespace.
681
+ const hash = entry.key.slice(EntryType.EPOCH_HASH.length);
682
+ if (hash.length === HASH_BYTE_LENGTH * 2 && isHexString(hash)) {
683
+ hashes.push({ hash, confirmed_length: entry.seq });
684
+ }
679
685
  }
680
686
  }
681
687
 
@@ -5561,6 +5567,28 @@ class State extends ReadyResource {
5561
5567
  return Status.SUCCESS;
5562
5568
  }
5563
5569
 
5570
+ async getUnsignedConsensusConfig() {
5571
+ // Keep the pointer and record in the same view while unsigned state can change.
5572
+ const snapshot = this.#base.view.snapshot();
5573
+ try {
5574
+ const currentConfigPointer = (await snapshot.get(EntryType.CONSENSUS_CONFIG_CURRENT))?.value;
5575
+ if (_.isNil(currentConfigPointer)) return null;
5576
+
5577
+ if (!b4a.isBuffer(currentConfigPointer) || currentConfigPointer.length !== CONSENSUS_CONFIG_INDEX_SIZE) {
5578
+ throw new Error('Invalid current consensus config pointer.');
5579
+ }
5580
+
5581
+ const currentConfigIndex = currentConfigPointer.readUInt32BE(0);
5582
+ const encodedConsensusConfig = (await snapshot.get(EntryType.CONSENSUS_CONFIG_RECORD + currentConfigIndex))?.value;
5583
+ if (_.isNil(encodedConsensusConfig)) {
5584
+ throw new Error(`Consensus config record ${currentConfigIndex} does not exist.`);
5585
+ }
5586
+
5587
+ return decodeVersionedConsensusConfig(encodedConsensusConfig);
5588
+ } finally {
5589
+ await snapshot.close();
5590
+ }
5591
+ }
5564
5592
  }
5565
5593
 
5566
5594
  export default State;
package/src/index.js CHANGED
@@ -37,7 +37,8 @@ import {
37
37
  encodeApplyOperation,
38
38
  encodeConsensusConfig,
39
39
  safeDecodeApplyOperation,
40
- safeEncodeApplyOperation
40
+ safeEncodeApplyOperation,
41
+ decodeEpochRecord
41
42
  } from "./codecs/apply/applyOperationCodec.js";
42
43
  import { encodeVdfConfig } from "./codecs/consensus/v1/vdfConfigCodec.js";
43
44
  import PartialTransactionValidator from "./core/network/protocols/validators/shared/validators/PartialTransactionValidator.js";
@@ -425,7 +426,16 @@ export class MainSettlementBus extends ReadyResource {
425
426
 
426
427
  async fetchBulkTxPayloads(hashes) {
427
428
  const response = { results: [], missing: [] };
428
- const results = await Promise.all(hashes.map((hash) => this.getConfirmedTxInfo(hash)));
429
+ const results = await Promise.all(hashes.map(async (hash) => {
430
+ const transaction = await this.getConfirmedTxInfo(hash);
431
+ if (transaction) return transaction.decoded;
432
+
433
+ const epochRecord = await this.#state.getEpochProof(hash);
434
+ if (epochRecord === null) return null;
435
+
436
+ // This hash identifies the stored epoch record, not an original transaction.
437
+ return { type: OperationType.SET_EPOCH, seo: decodeEpochRecord(epochRecord) };
438
+ }));
429
439
 
430
440
  results.forEach((result, index) => {
431
441
  const hash = hashes[index];
@@ -434,7 +444,7 @@ export class MainSettlementBus extends ReadyResource {
434
444
  return;
435
445
  }
436
446
 
437
- const decodedResult = normalizeDecodedPayloadForJson(result.decoded, this.#config);
447
+ const decodedResult = normalizeDecodedPayloadForJson(result, this.#config);
438
448
  response.results.push({ hash, payload: decodedResult });
439
449
  });
440
450
 
@@ -1290,6 +1300,19 @@ export class MainSettlementBus extends ReadyResource {
1290
1300
  expectedKeys.every(key => Object.hasOwn(value, key))
1291
1301
  );
1292
1302
  }
1303
+
1304
+ async getCurrentEpoch(confirmed = true) {
1305
+ const epoch = confirmed
1306
+ ? await this.#state.getCurrentEpoch()
1307
+ : await this.#state.getCurrentEpochUnsigned();
1308
+ return epoch === null ? null : epoch.toString();
1309
+ }
1310
+
1311
+ async getConsensusConfig(confirmed = true) {
1312
+ return confirmed
1313
+ ? this.#state.getSignedConsensusConfig()
1314
+ : this.#state.getUnsignedConsensusConfig();
1315
+ }
1293
1316
  }
1294
1317
 
1295
1318
  export default MainSettlementBus;