@typeberry/jam 0.1.3-ca63b35 → 0.2.0-0a3dfd4

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.
@@ -2753,7 +2753,7 @@ module.exports = __nccwpck_require__.p + "e2fdc1b646378dd96eda.js?ed25519_wasm_b
2753
2753
 
2754
2754
  /***/ }),
2755
2755
 
2756
- /***/ 185:
2756
+ /***/ 566:
2757
2757
  /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
2758
2758
 
2759
2759
  module.exports = __nccwpck_require__.p + "ccf8ada94096a8f232f5.js?reed_solomon_wasm_bg.wasm";
@@ -3452,7 +3452,7 @@ async function __wbg_init(module_or_path) {
3452
3452
  if (wasm !== void 0) return wasm;
3453
3453
  if (typeof module_or_path !== "undefined") if (Object.getPrototypeOf(module_or_path) === Object.prototype) ({module_or_path} = module_or_path);
3454
3454
  else console.warn("using deprecated parameters for the initialization function; pass a single object instead");
3455
- if (typeof module_or_path === "undefined") module_or_path = new URL(/* asset import */ __nccwpck_require__(185), __nccwpck_require__.b);
3455
+ if (typeof module_or_path === "undefined") module_or_path = new URL(/* asset import */ __nccwpck_require__(566), __nccwpck_require__.b);
3456
3456
  const imports = __wbg_get_imports();
3457
3457
  if (typeof module_or_path === "string" || typeof Request === "function" && module_or_path instanceof Request || typeof URL === "function" && module_or_path instanceof URL) module_or_path = fetch(module_or_path);
3458
3458
  __wbg_init_memory(imports);
@@ -3540,7 +3540,7 @@ var GpVersion;
3540
3540
  (function (GpVersion) {
3541
3541
  GpVersion["V0_6_7"] = "0.6.7";
3542
3542
  GpVersion["V0_7_0"] = "0.7.0";
3543
- GpVersion["V0_7_1"] = "0.7.1-preview";
3543
+ GpVersion["V0_7_1"] = "0.7.1";
3544
3544
  GpVersion["V0_7_2"] = "0.7.2-preview";
3545
3545
  })(GpVersion || (GpVersion = {}));
3546
3546
  var TestSuite;
@@ -3549,11 +3549,11 @@ var TestSuite;
3549
3549
  TestSuite["JAMDUNA"] = "jamduna";
3550
3550
  })(TestSuite || (TestSuite = {}));
3551
3551
  const DEFAULT_SUITE = TestSuite.W3F_DAVXY;
3552
- const ALL_VERSIONS_IN_ORDER = [GpVersion.V0_6_7, GpVersion.V0_7_0, GpVersion.V0_7_1, GpVersion.V0_7_2];
3552
+ const DEFAULT_VERSION = GpVersion.V0_7_1;
3553
3553
  const env = typeof process === "undefined" ? {} : process.env;
3554
- const DEFAULT_VERSION = GpVersion.V0_7_0;
3555
3554
  let CURRENT_VERSION = parseCurrentVersion(env.GP_VERSION) ?? DEFAULT_VERSION;
3556
3555
  let CURRENT_SUITE = parseCurrentSuite(env.TEST_SUITE) ?? DEFAULT_SUITE;
3556
+ const ALL_VERSIONS_IN_ORDER = [GpVersion.V0_6_7, GpVersion.V0_7_0, GpVersion.V0_7_1, GpVersion.V0_7_2];
3557
3557
  function parseCurrentVersion(env) {
3558
3558
  if (env === undefined) {
3559
3559
  return undefined;
@@ -3840,7 +3840,7 @@ function resultToString(res) {
3840
3840
  if (res.isOk) {
3841
3841
  return `OK: ${typeof res.ok === "symbol" ? res.ok.toString() : res.ok}`;
3842
3842
  }
3843
- return `${res.details}\nError: ${maybeTaggedErrorToString(res.error)}`;
3843
+ return `${res.details()}\nError: ${maybeTaggedErrorToString(res.error)}`;
3844
3844
  }
3845
3845
  /** An indication of two possible outcomes returned from a function. */
3846
3846
  const result_Result = {
@@ -3854,7 +3854,7 @@ const result_Result = {
3854
3854
  };
3855
3855
  },
3856
3856
  /** Create new [`Result`] with `Error` status. */
3857
- error: (error, details = "") => {
3857
+ error: (error, details) => {
3858
3858
  debug_check `${error !== undefined} 'Error' type cannot be undefined.`;
3859
3859
  return {
3860
3860
  isOk: false,
@@ -3973,7 +3973,7 @@ function deepEqual(actual, expected, { context = [], errorsCollector, ignore = [
3973
3973
  }
3974
3974
  if (actual.isError && expected.isError) {
3975
3975
  deepEqual(actual.error, expected.error, { context: ctx.concat(["error"]), errorsCollector: errors, ignore });
3976
- deepEqual(actual.details, expected.details, {
3976
+ deepEqual(actual.details(), expected.details(), {
3977
3977
  context: ctx.concat(["details"]),
3978
3978
  errorsCollector: errors,
3979
3979
  // display details when error does not match
@@ -4521,7 +4521,7 @@ const BANDERSNATCH_KEY_BYTES = 32;
4521
4521
  /** Bandersnatch VRF signature size */
4522
4522
  const BANDERSNATCH_VRF_SIGNATURE_BYTES = 96;
4523
4523
  /** Bandersnatch ring commitment size */
4524
- const BANDERSNATCH_RING_ROOT_BYTES = 144;
4524
+ const bandersnatch_BANDERSNATCH_RING_ROOT_BYTES = 144;
4525
4525
  /** Bandersnatch proof size */
4526
4526
  const BANDERSNATCH_PROOF_BYTES = 784;
4527
4527
  /** BLS public key size. */
@@ -6198,6 +6198,9 @@ class ObjectView {
6198
6198
  toString() {
6199
6199
  return `View<${this.materializedConstructor.name}>(cache: ${this.cache.size})`;
6200
6200
  }
6201
+ [TEST_COMPARE_USING]() {
6202
+ return this.materialize();
6203
+ }
6201
6204
  }
6202
6205
  /**
6203
6206
  * A lazy-evaluated decoder of a sequence.
@@ -6330,7 +6333,7 @@ const TYPICAL_DICTIONARY_LENGTH = 32;
6330
6333
  * It's not true in a general case, but should be good enough for us.
6331
6334
  *
6332
6335
  */
6333
- function readonlyArray(desc) {
6336
+ function descriptors_readonlyArray(desc) {
6334
6337
  return desc.convert((x) => {
6335
6338
  debug_check `
6336
6339
  ${Array.isArray(x)}
@@ -6492,7 +6495,15 @@ var descriptors_codec;
6492
6495
  /** Custom encoding / decoding logic. */
6493
6496
  codec.custom = ({ name, sizeHint = { bytes: 0, isExact: false }, }, encode, decode, skip) => Descriptor.new(name, sizeHint, encode, decode, skip);
6494
6497
  /** Choose a descriptor depending on the encoding/decoding context. */
6495
- codec.select = ({ name, sizeHint, }, chooser) => Descriptor.withView(name, sizeHint, (e, x) => chooser(e.getContext()).encode(e, x), (d) => chooser(d.getContext()).decode(d), (s) => chooser(s.decoder.getContext()).skip(s), chooser(null).View);
6498
+ codec.select = ({ name, sizeHint, }, chooser) => {
6499
+ const Self = chooser(null);
6500
+ return Descriptor.withView(name, sizeHint, (e, x) => chooser(e.getContext()).encode(e, x), (d) => chooser(d.getContext()).decode(d), (s) => chooser(s.decoder.getContext()).skip(s), hasUniqueView(Self)
6501
+ ? codec.select({
6502
+ name: Self.View.name,
6503
+ sizeHint: Self.View.sizeHint,
6504
+ }, (ctx) => chooser(ctx).View)
6505
+ : Self.View);
6506
+ };
6496
6507
  /**
6497
6508
  * A descriptor for a more complex POJO.
6498
6509
  *
@@ -7610,9 +7621,9 @@ function codecWithContext(chooser) {
7610
7621
  /** Codec for a known-size array with length validation. */
7611
7622
  const codecKnownSizeArray = (val, options, _id) => {
7612
7623
  if ("fixedLength" in options) {
7613
- return readonlyArray(descriptors_codec.sequenceFixLen(val, options.fixedLength)).convert(seeThrough, sized_array_asKnownSize);
7624
+ return descriptors_readonlyArray(descriptors_codec.sequenceFixLen(val, options.fixedLength)).convert(seeThrough, sized_array_asKnownSize);
7614
7625
  }
7615
- return readonlyArray(descriptors_codec.sequenceVarLen(val, options)).convert(seeThrough, sized_array_asKnownSize);
7626
+ return descriptors_readonlyArray(descriptors_codec.sequenceVarLen(val, options)).convert(seeThrough, sized_array_asKnownSize);
7616
7627
  };
7617
7628
  /** Codec for a fixed-size array with length validation. */
7618
7629
  const codecFixedSizeArray = (val, len) => {
@@ -7749,7 +7760,7 @@ function tryAsPerValidator(array, spec) {
7749
7760
  `;
7750
7761
  return sized_array_asKnownSize(array);
7751
7762
  }
7752
- const codecPerValidator = (val) => codecWithContext((context) => {
7763
+ const common_codecPerValidator = (val) => codecWithContext((context) => {
7753
7764
  return codecKnownSizeArray(val, {
7754
7765
  fixedLength: context.validatorsCount,
7755
7766
  });
@@ -7876,7 +7887,7 @@ class Verdict extends WithDebug {
7876
7887
  workReportHash: descriptors_codec.bytes(hash_HASH_SIZE).asOpaque(),
7877
7888
  votesEpoch: descriptors_codec.u32.asOpaque(),
7878
7889
  votes: codecWithContext((context) => {
7879
- return readonlyArray(descriptors_codec.sequenceFixLen(Judgement.Codec, context.validatorsSuperMajority)).convert(seeThrough, sized_array_asKnownSize);
7890
+ return descriptors_readonlyArray(descriptors_codec.sequenceFixLen(Judgement.Codec, context.validatorsSuperMajority)).convert(seeThrough, sized_array_asKnownSize);
7880
7891
  }),
7881
7892
  });
7882
7893
  static create({ workReportHash, votesEpoch, votes }) {
@@ -8568,7 +8579,7 @@ const WorkReportCodec = descriptors_codec.Class(WorkReportNoCodec, {
8568
8579
  authorizerHash: descriptors_codec.bytes(hash_HASH_SIZE).asOpaque(),
8569
8580
  authorizationGasUsed: descriptors_codec.varU64.asOpaque(),
8570
8581
  authorizationOutput: descriptors_codec.blob,
8571
- segmentRootLookup: readonlyArray(descriptors_codec.sequenceVarLen(WorkPackageInfo.Codec)),
8582
+ segmentRootLookup: descriptors_readonlyArray(descriptors_codec.sequenceVarLen(WorkPackageInfo.Codec)),
8572
8583
  results: descriptors_codec.sequenceVarLen(WorkResult.Codec).convert((x) => x, (items) => FixedSizeArray.new(items, tryAsWorkItemsCount(items.length))),
8573
8584
  });
8574
8585
  const WorkReportCodecPre070 = descriptors_codec.Class(WorkReportNoCodec, {
@@ -8582,7 +8593,7 @@ const WorkReportCodecPre070 = descriptors_codec.Class(WorkReportNoCodec, {
8582
8593
  }),
8583
8594
  authorizerHash: descriptors_codec.bytes(hash_HASH_SIZE).asOpaque(),
8584
8595
  authorizationOutput: descriptors_codec.blob,
8585
- segmentRootLookup: readonlyArray(descriptors_codec.sequenceVarLen(WorkPackageInfo.Codec)),
8596
+ segmentRootLookup: descriptors_readonlyArray(descriptors_codec.sequenceVarLen(WorkPackageInfo.Codec)),
8586
8597
  results: descriptors_codec.sequenceVarLen(WorkResult.Codec).convert((x) => x, (items) => FixedSizeArray.new(items, tryAsWorkItemsCount(items.length))),
8587
8598
  authorizationGasUsed: descriptors_codec.varU64.asOpaque(),
8588
8599
  });
@@ -8700,16 +8711,16 @@ class SignedTicket extends WithDebug {
8700
8711
  }
8701
8712
  }
8702
8713
  /** Anonymous? entry into the ticket contest. */
8703
- class Ticket extends WithDebug {
8714
+ class tickets_Ticket extends WithDebug {
8704
8715
  id;
8705
8716
  attempt;
8706
- static Codec = descriptors_codec.Class(Ticket, {
8717
+ static Codec = descriptors_codec.Class(tickets_Ticket, {
8707
8718
  id: descriptors_codec.bytes(hash_HASH_SIZE),
8708
8719
  // TODO [ToDr] we should verify that attempt is either 0|1|2.
8709
8720
  attempt: descriptors_codec.u8.asOpaque(),
8710
8721
  });
8711
8722
  static create({ id, attempt }) {
8712
- return new Ticket(id, attempt);
8723
+ return new tickets_Ticket(id, attempt);
8713
8724
  }
8714
8725
  constructor(
8715
8726
  /**
@@ -8778,7 +8789,7 @@ class ValidatorKeys extends WithDebug {
8778
8789
  class TicketsMarker extends WithDebug {
8779
8790
  tickets;
8780
8791
  static Codec = descriptors_codec.Class(TicketsMarker, {
8781
- tickets: codecPerEpochBlock(Ticket.Codec),
8792
+ tickets: codecPerEpochBlock(tickets_Ticket.Codec),
8782
8793
  });
8783
8794
  static create({ tickets }) {
8784
8795
  return new TicketsMarker(tickets);
@@ -8802,7 +8813,7 @@ class EpochMarker extends WithDebug {
8802
8813
  static Codec = descriptors_codec.Class(EpochMarker, {
8803
8814
  entropy: descriptors_codec.bytes(hash_HASH_SIZE).asOpaque(),
8804
8815
  ticketsEntropy: descriptors_codec.bytes(hash_HASH_SIZE).asOpaque(),
8805
- validators: codecPerValidator(ValidatorKeys.Codec),
8816
+ validators: common_codecPerValidator(ValidatorKeys.Codec),
8806
8817
  });
8807
8818
  static create({ entropy, ticketsEntropy, validators }) {
8808
8819
  return new EpochMarker(entropy, ticketsEntropy, validators);
@@ -9074,6 +9085,19 @@ function emptyBlock(slot = tryAsTimeSlot(0)) {
9074
9085
  });
9075
9086
  }
9076
9087
 
9088
+ ;// CONCATENATED MODULE: ./packages/jam/block/utils.ts
9089
+
9090
+ /**
9091
+ * Take an input data and re-encode that data as view.
9092
+ *
9093
+ * NOTE: this function should NEVER be used in any production code,
9094
+ * it's only a test helper.
9095
+ */
9096
+ function reencodeAsView(codec, object, chainSpec) {
9097
+ const encoded = encoder_Encoder.encodeObject(codec, object, chainSpec);
9098
+ return decoder_Decoder.decodeObject(codec.View, encoded, chainSpec);
9099
+ }
9100
+
9077
9101
  ;// CONCATENATED MODULE: ./packages/jam/block/index.ts
9078
9102
 
9079
9103
 
@@ -9092,6 +9116,7 @@ function emptyBlock(slot = tryAsTimeSlot(0)) {
9092
9116
 
9093
9117
 
9094
9118
 
9119
+
9095
9120
  ;// CONCATENATED MODULE: ./packages/jam/database-lmdb/blocks.ts
9096
9121
 
9097
9122
 
@@ -9443,10 +9468,129 @@ function accumulationOutputComparator(a, b) {
9443
9468
  return Ordering.Equal;
9444
9469
  }
9445
9470
 
9471
+ ;// CONCATENATED MODULE: ./packages/jam/block/gp-constants.ts
9472
+
9473
+
9474
+ /**
9475
+ * This file lists all of the constants defined in the GrayPaper appendix.
9476
+ *
9477
+ * NOTE: Avoid using the constants directly, prefer "named" constants defined
9478
+ * in a semantical proximity to where they are used.
9479
+ *
9480
+ * NOTE: This file will most likely be removed in the future. The constants
9481
+ * here are only temporarily for convenience. When we figure out better names
9482
+ * and places for these this file will be eradicated.
9483
+ *
9484
+ * https://graypaper.fluffylabs.dev/#/ab2cdbd/442300442300?v=0.7.2
9485
+ */
9486
+ /** `G_I`: The gas allocated to invoke a work-package’s Is-Authorized logic. */
9487
+ const G_I = 50_000_000;
9488
+ /** `I`: Maximum number of work items in a package. */
9489
+ const gp_constants_I = (/* unused pure expression or super */ null && (MAX_NUMBER_OF_WORK_ITEMS));
9490
+ /** `O`: Maximum number of items in the authorizations pool. */
9491
+ const O = 8;
9492
+ /** `Q`: The number of items in the authorizations queue. */
9493
+ const Q = 80;
9494
+ /** `S`: The maximum number of entries in the accumulation queue. */
9495
+ const S = 1024;
9496
+ /** `T`: The maximum number of extrinsics in a work-package. */
9497
+ const T = 128;
9498
+ /** `W_A`: The maximum size of is-authorized code in octets. */
9499
+ const W_A = 64_000;
9500
+ /** `W_B`: The maximum size of the concatenated variable-size blobs, extrinsics and imported segments of a work-package, in octets */
9501
+ const W_B = Compatibility.isGreaterOrEqual(GpVersion.V0_7_2) ? 13_791_360 : 13_794_305;
9502
+ /** `W_C`: The maximum size of service code in octets. */
9503
+ const W_C = 4_000_000;
9504
+ /** `W_M`: The maximum number of imports in a work-package. */
9505
+ const W_M = 3_072;
9506
+ /** `W_R`: The maximum total size of all output blobs in a work-report, in octets. */
9507
+ const W_R = 49_152;
9508
+ /** `W_T`: The size of a transfer memo in octets. */
9509
+ const W_T = 128;
9510
+ /** `W_M`: The maximum number of exports in a work-package. */
9511
+ const W_X = 3_072;
9512
+ // TODO [ToDr] Not sure where these should live yet :(
9513
+ /**
9514
+ * `S`: The minimum public service index.
9515
+ * Services of indices below these may only be created by the Registrar.
9516
+ *
9517
+ * https://graypaper.fluffylabs.dev/#/ab2cdbd/447a00447a00?v=0.7.2
9518
+ */
9519
+ const MIN_PUBLIC_SERVICE_INDEX = 2 ** 16;
9520
+ /**
9521
+ * `J`: The maximum sum of dependency items in a work-report.
9522
+ *
9523
+ * https://graypaper.fluffylabs.dev/#/5f542d7/416a00416a00?v=0.6.2
9524
+ */
9525
+ const MAX_REPORT_DEPENDENCIES = 8;
9526
+
9527
+ ;// CONCATENATED MODULE: ./packages/jam/state/accumulation-queue.ts
9528
+
9529
+
9530
+
9531
+
9532
+
9533
+
9534
+
9535
+ /**
9536
+ * Ready (i.e. available and/or audited) but not-yet-accumulated work-reports.
9537
+ *
9538
+ * https://graypaper.fluffylabs.dev/#/5f542d7/165300165400
9539
+ */
9540
+ class NotYetAccumulatedReport extends WithDebug {
9541
+ report;
9542
+ dependencies;
9543
+ static Codec = descriptors_codec.Class(NotYetAccumulatedReport, {
9544
+ report: WorkReport.Codec,
9545
+ dependencies: codecKnownSizeArray(descriptors_codec.bytes(hash_HASH_SIZE).asOpaque(), {
9546
+ typicalLength: MAX_REPORT_DEPENDENCIES / 2,
9547
+ maxLength: MAX_REPORT_DEPENDENCIES,
9548
+ minLength: 0,
9549
+ }),
9550
+ });
9551
+ static create({ report, dependencies }) {
9552
+ return new NotYetAccumulatedReport(report, dependencies);
9553
+ }
9554
+ constructor(
9555
+ /**
9556
+ * Each of these were made available at most one epoch ago
9557
+ * but have or had unfulfilled dependencies.
9558
+ */
9559
+ report,
9560
+ /**
9561
+ * Alongside the work-report itself, we retain its un-accumulated
9562
+ * dependencies, a set of work-package hashes.
9563
+ *
9564
+ * https://graypaper.fluffylabs.dev/#/5f542d7/165800165800
9565
+ */
9566
+ dependencies) {
9567
+ super();
9568
+ this.report = report;
9569
+ this.dependencies = dependencies;
9570
+ }
9571
+ }
9572
+ const accumulationQueueCodec = codecPerEpochBlock(descriptors_readonlyArray(descriptors_codec.sequenceVarLen(NotYetAccumulatedReport.Codec)));
9573
+
9574
+ ;// CONCATENATED MODULE: ./packages/jam/state/common.ts
9575
+
9576
+
9577
+ /** Check if given array has correct length before casting to the opaque type. */
9578
+ function tryAsPerCore(array, spec) {
9579
+ debug_check `
9580
+ ${array.length === spec.coresCount}
9581
+ Invalid per-core array length. Expected ${spec.coresCount}, got: ${array.length}
9582
+ `;
9583
+ return opaque_asOpaqueType(array);
9584
+ }
9585
+ const codecPerCore = (val) => codecWithContext((context) => {
9586
+ return codecKnownSizeArray(val, { fixedLength: context.coresCount });
9587
+ });
9588
+
9446
9589
  ;// CONCATENATED MODULE: ./packages/jam/state/assurances.ts
9447
9590
 
9448
9591
 
9449
9592
 
9593
+
9450
9594
  /**
9451
9595
  * Assignment of particular work report to a core.
9452
9596
  *
@@ -9475,27 +9619,30 @@ class AvailabilityAssignment extends WithDebug {
9475
9619
  this.timeout = timeout;
9476
9620
  }
9477
9621
  }
9622
+ const availabilityAssignmentsCodec = codecPerCore(descriptors_codec.optional(AvailabilityAssignment.Codec));
9478
9623
 
9479
- ;// CONCATENATED MODULE: ./packages/jam/state/common.ts
9624
+ ;// CONCATENATED MODULE: ./packages/jam/state/auth.ts
9480
9625
 
9481
9626
 
9482
- /** Check if given array has correct length before casting to the opaque type. */
9483
- function tryAsPerCore(array, spec) {
9484
- debug_check `
9485
- ${array.length === spec.coresCount}
9486
- Invalid per-core array length. Expected ${spec.coresCount}, got: ${array.length}
9487
- `;
9488
- return opaque_asOpaqueType(array);
9489
- }
9490
- const codecPerCore = (val) => codecWithContext((context) => {
9491
- return codecKnownSizeArray(val, { fixedLength: context.coresCount });
9492
- });
9627
+
9628
+
9629
+
9630
+ /** `O`: Maximal authorization pool size. */
9631
+ const MAX_AUTH_POOL_SIZE = O;
9632
+ /** `Q`: Size of the authorization queue. */
9633
+ const AUTHORIZATION_QUEUE_SIZE = Q;
9634
+ const authPoolsCodec = codecPerCore(codecKnownSizeArray(descriptors_codec.bytes(hash_HASH_SIZE).asOpaque(), {
9635
+ minLength: 0,
9636
+ maxLength: MAX_AUTH_POOL_SIZE,
9637
+ typicalLength: MAX_AUTH_POOL_SIZE,
9638
+ }));
9639
+ const authQueuesCodec = codecPerCore(codecFixedSizeArray(descriptors_codec.bytes(hash_HASH_SIZE).asOpaque(), AUTHORIZATION_QUEUE_SIZE));
9493
9640
 
9494
9641
  ;// CONCATENATED MODULE: ./packages/jam/state/disputes.ts
9495
9642
 
9496
9643
 
9497
9644
 
9498
- const sortedSetCodec = () => readonlyArray(descriptors_codec.sequenceVarLen(descriptors_codec.bytes(hash_HASH_SIZE))).convert((input) => input.array, (output) => {
9645
+ const sortedSetCodec = () => descriptors_readonlyArray(descriptors_codec.sequenceVarLen(descriptors_codec.bytes(hash_HASH_SIZE))).convert((input) => input.array, (output) => {
9499
9646
  const typed = output.map((x) => x.asOpaque());
9500
9647
  return SortedSet.fromSortedArray(hashComparator, typed);
9501
9648
  });
@@ -9557,65 +9704,6 @@ function hashComparator(a, b) {
9557
9704
  return a.compare(b);
9558
9705
  }
9559
9706
 
9560
- ;// CONCATENATED MODULE: ./packages/jam/block/gp-constants.ts
9561
-
9562
- /**
9563
- * This file lists all of the constants defined in the GrayPaper appendix.
9564
- *
9565
- * NOTE: Avoid using the constants directly, prefer "named" constants defined
9566
- * in a semantical proximity to where they are used.
9567
- *
9568
- * NOTE: This file will most likely be removed in the future. The constants
9569
- * here are only temporarily for convenience. When we figure out better names
9570
- * and places for these this file will be eradicated.
9571
- *
9572
- * https://graypaper.fluffylabs.dev/#/579bd12/413000413000
9573
- */
9574
- /** `G_I`: The gas allocated to invoke a work-package’s Is-Authorized logic. */
9575
- const G_I = 50_000_000;
9576
- /** `I`: Maximum number of work items in a package. */
9577
- const gp_constants_I = (/* unused pure expression or super */ null && (MAX_NUMBER_OF_WORK_ITEMS));
9578
- /** `O`: Maximum number of items in the authorizations pool. */
9579
- const O = 8;
9580
- /** `Q`: The number of items in the authorizations queue. */
9581
- const Q = 80;
9582
- /** `S`: The maximum number of entries in the accumulation queue. */
9583
- const S = 1024;
9584
- /** `T`: The maximum number of extrinsics in a work-package. */
9585
- const T = 128;
9586
- /** `W_A`: The maximum size of is-authorized code in octets. */
9587
- const W_A = 64_000;
9588
- /** `W_B`: The maximum size of an encoded work-package with extrinsic data and imports. */
9589
- const W_B = 13_794_305;
9590
- /** `W_C`: The maximum size of service code in octets. */
9591
- const W_C = 4_000_000;
9592
- /** `W_M`: The maximum number of imports in a work-package. */
9593
- const W_M = 3_072;
9594
- /** `W_R`: The maximum total size of all output blobs in a work-report, in octets. */
9595
- const W_R = 49_152;
9596
- /** `W_T`: The size of a transfer memo in octets. */
9597
- const W_T = 128;
9598
- /** `W_M`: The maximum number of exports in a work-package. */
9599
- const W_X = 3_072;
9600
- // TODO [ToDr] Not sure where these should live yet :(
9601
- /**
9602
- * `S`: The minimum public service index.
9603
- * Services of indices below these may only be created by the Registrar.
9604
- *
9605
- * https://graypaper.fluffylabs.dev/#/ab2cdbd/447a00447a00?v=0.7.2
9606
- */
9607
- const MIN_PUBLIC_SERVICE_INDEX = 2 ** 16;
9608
- /**
9609
- * `J`: The maximum sum of dependency items in a work-report.
9610
- *
9611
- * https://graypaper.fluffylabs.dev/#/5f542d7/416a00416a00?v=0.6.2
9612
- */
9613
- const MAX_REPORT_DEPENDENCIES = 8;
9614
- /** `Q`: Size of the authorization queue. */
9615
- const AUTHORIZATION_QUEUE_SIZE = Q;
9616
- /** `O`: Maximal authorization pool size. */
9617
- const MAX_AUTH_POOL_SIZE = O;
9618
-
9619
9707
  ;// CONCATENATED MODULE: ./packages/core/pvm-interpreter/ops/math-consts.ts
9620
9708
  const MAX_VALUE = 4294967295;
9621
9709
  const math_consts_MAX_VALUE_U64 = (/* unused pure expression or super */ null && (2n ** 63n));
@@ -9623,7 +9711,7 @@ const MIN_VALUE = -(2 ** 31);
9623
9711
  const MAX_SHIFT_U32 = 32;
9624
9712
  const MAX_SHIFT_U64 = 64n;
9625
9713
 
9626
- ;// CONCATENATED MODULE: ./packages/jam/state/service.ts
9714
+ ;// CONCATENATED MODULE: ./packages/jam/state/recent-blocks.ts
9627
9715
 
9628
9716
 
9629
9717
 
@@ -9631,26 +9719,270 @@ const MAX_SHIFT_U64 = 64n;
9631
9719
 
9632
9720
 
9633
9721
  /**
9634
- * `B_S`: The basic minimum balance which all services require.
9635
- *
9636
- * https://graypaper.fluffylabs.dev/#/7e6ff6a/445800445800?v=0.6.7
9637
- */
9638
- const BASE_SERVICE_BALANCE = 100n;
9639
- /**
9640
- * `B_I`: The additional minimum balance required per item of elective service state.
9722
+ * `H = 8`: The size of recent history, in blocks.
9641
9723
  *
9642
- * https://graypaper.fluffylabs.dev/#/7e6ff6a/445000445000?v=0.6.7
9724
+ * https://graypaper.fluffylabs.dev/#/579bd12/416300416500
9643
9725
  */
9644
- const ELECTIVE_ITEM_BALANCE = 10n;
9726
+ const MAX_RECENT_HISTORY = 8;
9727
+ /** Recent history of a single block. */
9728
+ class BlockState extends WithDebug {
9729
+ headerHash;
9730
+ accumulationResult;
9731
+ postStateRoot;
9732
+ reported;
9733
+ static Codec = descriptors_codec.Class(BlockState, {
9734
+ headerHash: descriptors_codec.bytes(hash_HASH_SIZE).asOpaque(),
9735
+ accumulationResult: descriptors_codec.bytes(hash_HASH_SIZE),
9736
+ postStateRoot: descriptors_codec.bytes(hash_HASH_SIZE).asOpaque(),
9737
+ reported: codecHashDictionary(WorkPackageInfo.Codec, (x) => x.workPackageHash),
9738
+ });
9739
+ static create({ headerHash, accumulationResult, postStateRoot, reported }) {
9740
+ return new BlockState(headerHash, accumulationResult, postStateRoot, reported);
9741
+ }
9742
+ constructor(
9743
+ /** Header hash. */
9744
+ headerHash,
9745
+ /** Merkle mountain belt of accumulation result. */
9746
+ accumulationResult,
9747
+ /** Posterior state root filled in with a 1-block delay. */
9748
+ postStateRoot,
9749
+ /** Reported work packages (no more than number of cores). */
9750
+ reported) {
9751
+ super();
9752
+ this.headerHash = headerHash;
9753
+ this.accumulationResult = accumulationResult;
9754
+ this.postStateRoot = postStateRoot;
9755
+ this.reported = reported;
9756
+ }
9757
+ }
9645
9758
  /**
9646
- * `B_L`: The additional minimum balance required per octet of elective service state.
9759
+ * Recent history of blocks.
9647
9760
  *
9648
- * https://graypaper.fluffylabs.dev/#/7e6ff6a/445400445400?v=0.6.7
9761
+ * https://graypaper.fluffylabs.dev/#/7e6ff6a/0fc9010fc901?v=0.6.7
9649
9762
  */
9650
- const ELECTIVE_BYTE_BALANCE = 1n;
9651
- const zeroSizeHint = {
9652
- bytes: 0,
9653
- isExact: true,
9763
+ class RecentBlocks extends WithDebug {
9764
+ blocks;
9765
+ accumulationLog;
9766
+ static Codec = descriptors_codec.Class(RecentBlocks, {
9767
+ blocks: codecKnownSizeArray(BlockState.Codec, {
9768
+ minLength: 0,
9769
+ maxLength: MAX_RECENT_HISTORY,
9770
+ typicalLength: MAX_RECENT_HISTORY,
9771
+ }),
9772
+ accumulationLog: descriptors_codec.object({
9773
+ peaks: descriptors_readonlyArray(descriptors_codec.sequenceVarLen(descriptors_codec.optional(descriptors_codec.bytes(hash_HASH_SIZE)))),
9774
+ }),
9775
+ });
9776
+ static empty() {
9777
+ return new RecentBlocks(sized_array_asKnownSize([]), {
9778
+ peaks: [],
9779
+ });
9780
+ }
9781
+ static create(a) {
9782
+ return new RecentBlocks(a.blocks, a.accumulationLog);
9783
+ }
9784
+ constructor(
9785
+ /**
9786
+ * Most recent blocks.
9787
+ * https://graypaper.fluffylabs.dev/#/7e6ff6a/0fea010fea01?v=0.6.7
9788
+ */
9789
+ blocks,
9790
+ /**
9791
+ * Accumulation output log.
9792
+ * https://graypaper.fluffylabs.dev/#/7e6ff6a/0f02020f0202?v=0.6.7
9793
+ */
9794
+ accumulationLog) {
9795
+ super();
9796
+ this.blocks = blocks;
9797
+ this.accumulationLog = accumulationLog;
9798
+ }
9799
+ }
9800
+
9801
+ ;// CONCATENATED MODULE: ./packages/jam/state/recently-accumulated.ts
9802
+
9803
+
9804
+
9805
+
9806
+ const recentlyAccumulatedCodec = codecPerEpochBlock(descriptors_codec.sequenceVarLen(descriptors_codec.bytes(hash_HASH_SIZE).asOpaque()).convert((x) => Array.from(x), (x) => HashSet.from(x)));
9807
+
9808
+ ;// CONCATENATED MODULE: ./packages/jam/state/validator-data.ts
9809
+
9810
+
9811
+
9812
+
9813
+ /**
9814
+ * Fixed size of validator metadata.
9815
+ *
9816
+ * https://graypaper.fluffylabs.dev/#/5f542d7/0d55010d5501
9817
+ */
9818
+ const VALIDATOR_META_BYTES = 128;
9819
+ /**
9820
+ * Details about validators' identity.
9821
+ *
9822
+ * https://graypaper.fluffylabs.dev/#/5f542d7/0d4b010d4c01
9823
+ */
9824
+ class validator_data_ValidatorData extends WithDebug {
9825
+ bandersnatch;
9826
+ ed25519;
9827
+ bls;
9828
+ metadata;
9829
+ static Codec = descriptors_codec.Class(validator_data_ValidatorData, {
9830
+ bandersnatch: descriptors_codec.bytes(BANDERSNATCH_KEY_BYTES).asOpaque(),
9831
+ ed25519: descriptors_codec.bytes(ED25519_KEY_BYTES).asOpaque(),
9832
+ bls: descriptors_codec.bytes(BLS_KEY_BYTES).asOpaque(),
9833
+ metadata: descriptors_codec.bytes(VALIDATOR_META_BYTES),
9834
+ });
9835
+ static create({ ed25519, bandersnatch, bls, metadata }) {
9836
+ return new validator_data_ValidatorData(bandersnatch, ed25519, bls, metadata);
9837
+ }
9838
+ constructor(
9839
+ /** Bandersnatch public key. */
9840
+ bandersnatch,
9841
+ /** ED25519 key data. */
9842
+ ed25519,
9843
+ /** BLS public key. */
9844
+ bls,
9845
+ /** Validator-defined additional metdata. */
9846
+ metadata) {
9847
+ super();
9848
+ this.bandersnatch = bandersnatch;
9849
+ this.ed25519 = ed25519;
9850
+ this.bls = bls;
9851
+ this.metadata = metadata;
9852
+ }
9853
+ }
9854
+ const validatorsDataCodec = common_codecPerValidator(validator_data_ValidatorData.Codec);
9855
+
9856
+ ;// CONCATENATED MODULE: ./packages/jam/state/safrole-data.ts
9857
+
9858
+
9859
+
9860
+
9861
+
9862
+
9863
+
9864
+
9865
+
9866
+
9867
+
9868
+ var SafroleSealingKeysKind;
9869
+ (function (SafroleSealingKeysKind) {
9870
+ SafroleSealingKeysKind[SafroleSealingKeysKind["Tickets"] = 0] = "Tickets";
9871
+ SafroleSealingKeysKind[SafroleSealingKeysKind["Keys"] = 1] = "Keys";
9872
+ })(SafroleSealingKeysKind || (SafroleSealingKeysKind = {}));
9873
+ const codecBandersnatchKey = descriptors_codec.bytes(BANDERSNATCH_KEY_BYTES).asOpaque();
9874
+ class safrole_data_SafroleSealingKeysData extends WithDebug {
9875
+ kind;
9876
+ keys;
9877
+ tickets;
9878
+ static Codec = codecWithContext((context) => {
9879
+ return descriptors_codec.custom({
9880
+ name: "SafroleSealingKeys",
9881
+ sizeHint: { bytes: 1 + hash_HASH_SIZE * context.epochLength, isExact: false },
9882
+ }, (e, x) => {
9883
+ e.varU32(numbers_tryAsU32(x.kind));
9884
+ if (x.kind === SafroleSealingKeysKind.Keys) {
9885
+ e.sequenceFixLen(codecBandersnatchKey, x.keys);
9886
+ }
9887
+ else {
9888
+ e.sequenceFixLen(tickets_Ticket.Codec, x.tickets);
9889
+ }
9890
+ }, (d) => {
9891
+ const epochLength = context.epochLength;
9892
+ const kind = d.varU32();
9893
+ if (kind === SafroleSealingKeysKind.Keys) {
9894
+ const keys = d.sequenceFixLen(codecBandersnatchKey, epochLength);
9895
+ return safrole_data_SafroleSealingKeysData.keys(tryAsPerEpochBlock(keys, context));
9896
+ }
9897
+ if (kind === SafroleSealingKeysKind.Tickets) {
9898
+ const tickets = d.sequenceFixLen(tickets_Ticket.Codec, epochLength);
9899
+ return safrole_data_SafroleSealingKeysData.tickets(tryAsPerEpochBlock(tickets, context));
9900
+ }
9901
+ throw new Error(`Unexpected safrole sealing keys kind: ${kind}`);
9902
+ }, (s) => {
9903
+ const kind = s.decoder.varU32();
9904
+ if (kind === SafroleSealingKeysKind.Keys) {
9905
+ s.sequenceFixLen(codecBandersnatchKey, context.epochLength);
9906
+ return;
9907
+ }
9908
+ if (kind === SafroleSealingKeysKind.Tickets) {
9909
+ s.sequenceFixLen(tickets_Ticket.Codec, context.epochLength);
9910
+ return;
9911
+ }
9912
+ throw new Error(`Unexpected safrole sealing keys kind: ${kind}`);
9913
+ });
9914
+ });
9915
+ static keys(keys) {
9916
+ return new safrole_data_SafroleSealingKeysData(SafroleSealingKeysKind.Keys, keys, undefined);
9917
+ }
9918
+ static tickets(tickets) {
9919
+ return new safrole_data_SafroleSealingKeysData(SafroleSealingKeysKind.Tickets, undefined, tickets);
9920
+ }
9921
+ constructor(kind, keys, tickets) {
9922
+ super();
9923
+ this.kind = kind;
9924
+ this.keys = keys;
9925
+ this.tickets = tickets;
9926
+ }
9927
+ }
9928
+ class SafroleData {
9929
+ nextValidatorData;
9930
+ epochRoot;
9931
+ sealingKeySeries;
9932
+ ticketsAccumulator;
9933
+ static Codec = descriptors_codec.Class(SafroleData, {
9934
+ nextValidatorData: common_codecPerValidator(validator_data_ValidatorData.Codec),
9935
+ epochRoot: descriptors_codec.bytes(bandersnatch_BANDERSNATCH_RING_ROOT_BYTES).asOpaque(),
9936
+ sealingKeySeries: safrole_data_SafroleSealingKeysData.Codec,
9937
+ ticketsAccumulator: descriptors_readonlyArray(descriptors_codec.sequenceVarLen(tickets_Ticket.Codec)).convert(seeThrough, sized_array_asKnownSize),
9938
+ });
9939
+ static create({ nextValidatorData, epochRoot, sealingKeySeries, ticketsAccumulator }) {
9940
+ return new SafroleData(nextValidatorData, epochRoot, sealingKeySeries, ticketsAccumulator);
9941
+ }
9942
+ constructor(
9943
+ /** gamma_k */
9944
+ nextValidatorData,
9945
+ /** gamma_z */
9946
+ epochRoot,
9947
+ /** gamma_s */
9948
+ sealingKeySeries,
9949
+ /** gamma_a */
9950
+ ticketsAccumulator) {
9951
+ this.nextValidatorData = nextValidatorData;
9952
+ this.epochRoot = epochRoot;
9953
+ this.sealingKeySeries = sealingKeySeries;
9954
+ this.ticketsAccumulator = ticketsAccumulator;
9955
+ }
9956
+ }
9957
+
9958
+ ;// CONCATENATED MODULE: ./packages/jam/state/service.ts
9959
+
9960
+
9961
+
9962
+
9963
+
9964
+
9965
+ /**
9966
+ * `B_S`: The basic minimum balance which all services require.
9967
+ *
9968
+ * https://graypaper.fluffylabs.dev/#/7e6ff6a/445800445800?v=0.6.7
9969
+ */
9970
+ const BASE_SERVICE_BALANCE = 100n;
9971
+ /**
9972
+ * `B_I`: The additional minimum balance required per item of elective service state.
9973
+ *
9974
+ * https://graypaper.fluffylabs.dev/#/7e6ff6a/445000445000?v=0.6.7
9975
+ */
9976
+ const ELECTIVE_ITEM_BALANCE = 10n;
9977
+ /**
9978
+ * `B_L`: The additional minimum balance required per octet of elective service state.
9979
+ *
9980
+ * https://graypaper.fluffylabs.dev/#/7e6ff6a/445400445400?v=0.6.7
9981
+ */
9982
+ const ELECTIVE_BYTE_BALANCE = 1n;
9983
+ const zeroSizeHint = {
9984
+ bytes: 0,
9985
+ isExact: true,
9654
9986
  };
9655
9987
  /** 0-byte read, return given default value */
9656
9988
  const ignoreValueWithDefault = (defaultValue) => Descriptor.new("ignoreValue", zeroSizeHint, (_e, _v) => { }, (_d) => defaultValue, (_s) => { });
@@ -9813,358 +10145,418 @@ class LookupHistoryItem {
9813
10145
  }
9814
10146
  }
9815
10147
 
9816
- ;// CONCATENATED MODULE: ./packages/jam/state/privileged-services.ts
10148
+ ;// CONCATENATED MODULE: ./packages/jam/state/statistics.ts
9817
10149
 
9818
10150
 
9819
10151
 
9820
10152
 
9821
10153
 
9822
- /** Dictionary entry of services that auto-accumulate every block. */
9823
- class AutoAccumulate {
9824
- service;
9825
- gasLimit;
9826
- static Codec = descriptors_codec.Class(AutoAccumulate, {
9827
- service: descriptors_codec.u32.asOpaque(),
9828
- gasLimit: descriptors_codec.u64.asOpaque(),
10154
+
10155
+ const codecServiceId = Compatibility.isSuite(TestSuite.W3F_DAVXY) || Compatibility.isSuite(TestSuite.JAMDUNA, GpVersion.V0_6_7)
10156
+ ? descriptors_codec.u32.asOpaque()
10157
+ : descriptors_codec.varU32.convert((s) => numbers_tryAsU32(s), (i) => tryAsServiceId(i));
10158
+ /**
10159
+ * Activity Record of a single validator.
10160
+ *
10161
+ * https://graypaper.fluffylabs.dev/#/579bd12/183701183701
10162
+ */
10163
+ class ValidatorStatistics {
10164
+ blocks;
10165
+ tickets;
10166
+ preImages;
10167
+ preImagesSize;
10168
+ guarantees;
10169
+ assurances;
10170
+ static Codec = descriptors_codec.Class(ValidatorStatistics, {
10171
+ blocks: descriptors_codec.u32,
10172
+ tickets: descriptors_codec.u32,
10173
+ preImages: descriptors_codec.u32,
10174
+ preImagesSize: descriptors_codec.u32,
10175
+ guarantees: descriptors_codec.u32,
10176
+ assurances: descriptors_codec.u32,
9829
10177
  });
9830
- static create({ service, gasLimit }) {
9831
- return new AutoAccumulate(service, gasLimit);
10178
+ static create({ blocks, tickets, preImages, preImagesSize, guarantees, assurances, }) {
10179
+ return new ValidatorStatistics(blocks, tickets, preImages, preImagesSize, guarantees, assurances);
9832
10180
  }
9833
10181
  constructor(
9834
- /** Service id that auto-accumulates. */
9835
- service,
9836
- /** Gas limit for auto-accumulation. */
9837
- gasLimit) {
9838
- this.service = service;
9839
- this.gasLimit = gasLimit;
9840
- }
9841
- }
9842
- /**
9843
- * https://graypaper.fluffylabs.dev/#/ab2cdbd/114402114402?v=0.7.2
9844
- */
9845
- class PrivilegedServices {
9846
- manager;
9847
- delegator;
9848
- registrar;
9849
- assigners;
9850
- autoAccumulateServices;
9851
- /** https://graypaper.fluffylabs.dev/#/ab2cdbd/3bbd023bcb02?v=0.7.2 */
9852
- static Codec = descriptors_codec.Class(PrivilegedServices, {
9853
- manager: descriptors_codec.u32.asOpaque(),
9854
- assigners: codecPerCore(descriptors_codec.u32.asOpaque()),
9855
- delegator: descriptors_codec.u32.asOpaque(),
9856
- registrar: Compatibility.isGreaterOrEqual(GpVersion.V0_7_1)
9857
- ? descriptors_codec.u32.asOpaque()
9858
- : ignoreValueWithDefault(tryAsServiceId(2 ** 32 - 1)),
9859
- autoAccumulateServices: readonlyArray(descriptors_codec.sequenceVarLen(AutoAccumulate.Codec)),
9860
- });
9861
- static create(a) {
9862
- return new PrivilegedServices(a.manager, a.delegator, a.registrar, a.assigners, a.autoAccumulateServices);
10182
+ /** The number of blocks produced by the validator. */
10183
+ blocks,
10184
+ /** The number of tickets introduced by the validator. */
10185
+ tickets,
10186
+ /** The number of preimages introduced by the validator. */
10187
+ preImages,
10188
+ /** The total number of octets across all preimages introduced by the validator. */
10189
+ preImagesSize,
10190
+ /** The number of reports guaranteed by the validator. */
10191
+ guarantees,
10192
+ /** The number of availability assurances made by the validator. */
10193
+ assurances) {
10194
+ this.blocks = blocks;
10195
+ this.tickets = tickets;
10196
+ this.preImages = preImages;
10197
+ this.preImagesSize = preImagesSize;
10198
+ this.guarantees = guarantees;
10199
+ this.assurances = assurances;
9863
10200
  }
9864
- constructor(
9865
- /**
9866
- * `χ_M`: Manages alteration of χ from block to block,
9867
- * as well as bestow services with storage deposit credits.
9868
- * https://graypaper.fluffylabs.dev/#/ab2cdbd/111502111902?v=0.7.2
9869
- */
9870
- manager,
9871
- /** `χ_V`: Managers validator keys. */
9872
- delegator,
9873
- /**
9874
- * `χ_R`: Manages the creation of services in protected range.
9875
- *
9876
- * https://graypaper.fluffylabs.dev/#/ab2cdbd/111b02111d02?v=0.7.2
9877
- */
9878
- registrar,
9879
- /** `χ_A`: Manages authorization queue one for each core. */
9880
- assigners,
9881
- /** `χ_Z`: Dictionary of services that auto-accumulate every block with their gas limit. */
9882
- autoAccumulateServices) {
9883
- this.manager = manager;
9884
- this.delegator = delegator;
9885
- this.registrar = registrar;
9886
- this.assigners = assigners;
9887
- this.autoAccumulateServices = autoAccumulateServices;
10201
+ static empty() {
10202
+ const zero = numbers_tryAsU32(0);
10203
+ return new ValidatorStatistics(zero, zero, zero, zero, zero, zero);
9888
10204
  }
9889
10205
  }
9890
-
9891
- ;// CONCATENATED MODULE: ./packages/jam/state/recent-blocks.ts
9892
-
9893
-
9894
-
9895
-
9896
-
9897
-
10206
+ const codecVarU16 = descriptors_codec.varU32.convert((i) => numbers_tryAsU32(i), (o) => numbers_tryAsU16(o));
10207
+ /** Encode/decode unsigned gas. */
10208
+ const codecVarGas = descriptors_codec.varU64.convert((g) => numbers_tryAsU64(g), (i) => tryAsServiceGas(i));
9898
10209
  /**
9899
- * `H = 8`: The size of recent history, in blocks.
10210
+ * Single core statistics.
10211
+ * Updated per block, based on incoming work reports (`w`).
9900
10212
  *
9901
- * https://graypaper.fluffylabs.dev/#/579bd12/416300416500
10213
+ * https://graypaper.fluffylabs.dev/#/68eaa1f/18f10318f103?v=0.6.4
10214
+ * https://github.com/gavofyork/graypaper/blob/9bffb08f3ea7b67832019176754df4fb36b9557d/text/statistics.tex#L65
9902
10215
  */
9903
- const MAX_RECENT_HISTORY = 8;
9904
- /** Recent history of a single block. */
9905
- class BlockState extends WithDebug {
9906
- headerHash;
9907
- accumulationResult;
9908
- postStateRoot;
9909
- reported;
9910
- static Codec = descriptors_codec.Class(BlockState, {
9911
- headerHash: descriptors_codec.bytes(hash_HASH_SIZE).asOpaque(),
9912
- accumulationResult: descriptors_codec.bytes(hash_HASH_SIZE),
9913
- postStateRoot: descriptors_codec.bytes(hash_HASH_SIZE).asOpaque(),
9914
- reported: codecHashDictionary(WorkPackageInfo.Codec, (x) => x.workPackageHash),
9915
- });
9916
- static create({ headerHash, accumulationResult, postStateRoot, reported }) {
9917
- return new BlockState(headerHash, accumulationResult, postStateRoot, reported);
10216
+ class CoreStatistics {
10217
+ dataAvailabilityLoad;
10218
+ popularity;
10219
+ imports;
10220
+ exports;
10221
+ extrinsicSize;
10222
+ extrinsicCount;
10223
+ bundleSize;
10224
+ gasUsed;
10225
+ static Codec = Compatibility.isGreaterOrEqual(GpVersion.V0_7_0)
10226
+ ? descriptors_codec.Class(CoreStatistics, {
10227
+ dataAvailabilityLoad: descriptors_codec.varU32,
10228
+ popularity: codecVarU16,
10229
+ imports: codecVarU16,
10230
+ extrinsicCount: codecVarU16,
10231
+ extrinsicSize: descriptors_codec.varU32,
10232
+ exports: codecVarU16,
10233
+ bundleSize: descriptors_codec.varU32,
10234
+ gasUsed: codecVarGas,
10235
+ })
10236
+ : descriptors_codec.Class(CoreStatistics, {
10237
+ dataAvailabilityLoad: descriptors_codec.varU32,
10238
+ popularity: codecVarU16,
10239
+ imports: codecVarU16,
10240
+ exports: codecVarU16,
10241
+ extrinsicSize: descriptors_codec.varU32,
10242
+ extrinsicCount: codecVarU16,
10243
+ bundleSize: descriptors_codec.varU32,
10244
+ gasUsed: codecVarGas,
10245
+ });
10246
+ static create(v) {
10247
+ return new CoreStatistics(v.dataAvailabilityLoad, v.popularity, v.imports, v.exports, v.extrinsicSize, v.extrinsicCount, v.bundleSize, v.gasUsed);
9918
10248
  }
9919
10249
  constructor(
9920
- /** Header hash. */
9921
- headerHash,
9922
- /** Merkle mountain belt of accumulation result. */
9923
- accumulationResult,
9924
- /** Posterior state root filled in with a 1-block delay. */
9925
- postStateRoot,
9926
- /** Reported work packages (no more than number of cores). */
9927
- reported) {
9928
- super();
9929
- this.headerHash = headerHash;
9930
- this.accumulationResult = accumulationResult;
9931
- this.postStateRoot = postStateRoot;
9932
- this.reported = reported;
9933
- }
9934
- }
9935
- class RecentBlocks extends WithDebug {
9936
- blocks;
9937
- accumulationLog;
9938
- static Codec = descriptors_codec.Class(RecentBlocks, {
9939
- blocks: codecKnownSizeArray(BlockState.Codec, {
9940
- minLength: 0,
9941
- maxLength: MAX_RECENT_HISTORY,
9942
- typicalLength: MAX_RECENT_HISTORY,
9943
- }),
9944
- accumulationLog: descriptors_codec.object({
9945
- peaks: readonlyArray(descriptors_codec.sequenceVarLen(descriptors_codec.optional(descriptors_codec.bytes(hash_HASH_SIZE)))),
9946
- }),
9947
- });
9948
- static create(a) {
9949
- return new RecentBlocks(a.blocks, a.accumulationLog);
10250
+ /** `d` */
10251
+ dataAvailabilityLoad,
10252
+ /** `p` */
10253
+ popularity,
10254
+ /** `i` */
10255
+ imports,
10256
+ /** `e` */
10257
+ exports,
10258
+ /** `z` */
10259
+ extrinsicSize,
10260
+ /** `x` */
10261
+ extrinsicCount,
10262
+ /** `b` */
10263
+ bundleSize,
10264
+ /** `u` */
10265
+ gasUsed) {
10266
+ this.dataAvailabilityLoad = dataAvailabilityLoad;
10267
+ this.popularity = popularity;
10268
+ this.imports = imports;
10269
+ this.exports = exports;
10270
+ this.extrinsicSize = extrinsicSize;
10271
+ this.extrinsicCount = extrinsicCount;
10272
+ this.bundleSize = bundleSize;
10273
+ this.gasUsed = gasUsed;
9950
10274
  }
9951
- constructor(
9952
- /**
9953
- * Most recent blocks.
9954
- * https://graypaper.fluffylabs.dev/#/7e6ff6a/0fea010fea01?v=0.6.7
9955
- */
9956
- blocks,
9957
- /**
9958
- * Accumulation output log.
9959
- * https://graypaper.fluffylabs.dev/#/7e6ff6a/0f02020f0202?v=0.6.7
9960
- */
9961
- accumulationLog) {
9962
- super();
9963
- this.blocks = blocks;
9964
- this.accumulationLog = accumulationLog;
10275
+ static empty() {
10276
+ const zero = numbers_tryAsU32(0);
10277
+ const zero16 = numbers_tryAsU16(0);
10278
+ const zeroGas = tryAsServiceGas(0);
10279
+ return new CoreStatistics(zero, zero16, zero16, zero16, zero, zero16, zero, zeroGas);
9965
10280
  }
9966
10281
  }
9967
10282
  /**
9968
- * Recent history of blocks.
10283
+ * Service statistics.
10284
+ * Updated per block, based on available work reports (`W`).
9969
10285
  *
9970
- * https://graypaper.fluffylabs.dev/#/7e6ff6a/0fc9010fc901?v=0.6.7
10286
+ * https://graypaper.fluffylabs.dev/#/1c979cb/199802199802?v=0.7.1
9971
10287
  */
9972
- class RecentBlocksHistory extends WithDebug {
9973
- current;
9974
- static Codec = Descriptor.new("RecentBlocksHistory", RecentBlocks.Codec.sizeHint, (encoder, value) => RecentBlocks.Codec.encode(encoder, value.asCurrent()), (decoder) => {
9975
- const recentBlocks = RecentBlocks.Codec.decode(decoder);
9976
- return RecentBlocksHistory.create(recentBlocks);
9977
- }, (skip) => {
9978
- return RecentBlocks.Codec.skip(skip);
10288
+ class ServiceStatistics {
10289
+ providedCount;
10290
+ providedSize;
10291
+ refinementCount;
10292
+ refinementGasUsed;
10293
+ imports;
10294
+ exports;
10295
+ extrinsicSize;
10296
+ extrinsicCount;
10297
+ accumulateCount;
10298
+ accumulateGasUsed;
10299
+ onTransfersCount;
10300
+ onTransfersGasUsed;
10301
+ static Codec = Compatibility.selectIfGreaterOrEqual({
10302
+ fallback: descriptors_codec.Class(ServiceStatistics, {
10303
+ providedCount: codecVarU16,
10304
+ providedSize: descriptors_codec.varU32,
10305
+ refinementCount: descriptors_codec.varU32,
10306
+ refinementGasUsed: codecVarGas,
10307
+ imports: codecVarU16,
10308
+ exports: codecVarU16,
10309
+ extrinsicSize: descriptors_codec.varU32,
10310
+ extrinsicCount: codecVarU16,
10311
+ accumulateCount: descriptors_codec.varU32,
10312
+ accumulateGasUsed: codecVarGas,
10313
+ onTransfersCount: descriptors_codec.varU32,
10314
+ onTransfersGasUsed: codecVarGas,
10315
+ }),
10316
+ versions: {
10317
+ [GpVersion.V0_7_0]: descriptors_codec.Class(ServiceStatistics, {
10318
+ providedCount: codecVarU16,
10319
+ providedSize: descriptors_codec.varU32,
10320
+ refinementCount: descriptors_codec.varU32,
10321
+ refinementGasUsed: codecVarGas,
10322
+ imports: codecVarU16,
10323
+ extrinsicCount: codecVarU16,
10324
+ extrinsicSize: descriptors_codec.varU32,
10325
+ exports: codecVarU16,
10326
+ accumulateCount: descriptors_codec.varU32,
10327
+ accumulateGasUsed: codecVarGas,
10328
+ onTransfersCount: descriptors_codec.varU32,
10329
+ onTransfersGasUsed: codecVarGas,
10330
+ }),
10331
+ [GpVersion.V0_7_1]: descriptors_codec.Class(ServiceStatistics, {
10332
+ providedCount: codecVarU16,
10333
+ providedSize: descriptors_codec.varU32,
10334
+ refinementCount: descriptors_codec.varU32,
10335
+ refinementGasUsed: codecVarGas,
10336
+ imports: codecVarU16,
10337
+ extrinsicCount: codecVarU16,
10338
+ extrinsicSize: descriptors_codec.varU32,
10339
+ exports: codecVarU16,
10340
+ accumulateCount: descriptors_codec.varU32,
10341
+ accumulateGasUsed: codecVarGas,
10342
+ onTransfersCount: ignoreValueWithDefault(numbers_tryAsU32(0)),
10343
+ onTransfersGasUsed: ignoreValueWithDefault(tryAsServiceGas(0)),
10344
+ }),
10345
+ },
9979
10346
  });
9980
- static create(recentBlocks) {
9981
- return new RecentBlocksHistory(recentBlocks);
10347
+ static create(v) {
10348
+ return new ServiceStatistics(v.providedCount, v.providedSize, v.refinementCount, v.refinementGasUsed, v.imports, v.exports, v.extrinsicSize, v.extrinsicCount, v.accumulateCount, v.accumulateGasUsed, v.onTransfersCount, v.onTransfersGasUsed);
10349
+ }
10350
+ constructor(
10351
+ /** `p.0` */
10352
+ providedCount,
10353
+ /** `p.1` */
10354
+ providedSize,
10355
+ /** `r.0` */
10356
+ refinementCount,
10357
+ /** `r.1` */
10358
+ refinementGasUsed,
10359
+ /** `i` */
10360
+ imports,
10361
+ /** `e` */
10362
+ exports,
10363
+ /** `z` */
10364
+ extrinsicSize,
10365
+ /** `x` */
10366
+ extrinsicCount,
10367
+ /** `a.0` */
10368
+ accumulateCount,
10369
+ /** `a.1` */
10370
+ accumulateGasUsed,
10371
+ /** `t.0` @deprecated since 0.7.1 */
10372
+ onTransfersCount,
10373
+ /** `t.1` @deprecated since 0.7.1 */
10374
+ onTransfersGasUsed) {
10375
+ this.providedCount = providedCount;
10376
+ this.providedSize = providedSize;
10377
+ this.refinementCount = refinementCount;
10378
+ this.refinementGasUsed = refinementGasUsed;
10379
+ this.imports = imports;
10380
+ this.exports = exports;
10381
+ this.extrinsicSize = extrinsicSize;
10382
+ this.extrinsicCount = extrinsicCount;
10383
+ this.accumulateCount = accumulateCount;
10384
+ this.accumulateGasUsed = accumulateGasUsed;
10385
+ this.onTransfersCount = onTransfersCount;
10386
+ this.onTransfersGasUsed = onTransfersGasUsed;
9982
10387
  }
9983
10388
  static empty() {
9984
- return RecentBlocksHistory.create(RecentBlocks.create({
9985
- blocks: sized_array_asKnownSize([]),
9986
- accumulationLog: { peaks: [] },
9987
- }));
10389
+ const zero = numbers_tryAsU32(0);
10390
+ const zero16 = numbers_tryAsU16(0);
10391
+ const zeroGas = tryAsServiceGas(0);
10392
+ return new ServiceStatistics(zero16, zero, zero, zeroGas, zero16, zero16, zero, zero16, zero, zeroGas, zero, zeroGas);
9988
10393
  }
9989
- /**
9990
- * Returns the block's BEEFY super peak.
9991
- */
9992
- static accumulationResult(block) {
9993
- return block.accumulationResult;
10394
+ }
10395
+ /** `pi`: Statistics of each validator, cores statistics and services statistics. */
10396
+ class StatisticsData {
10397
+ current;
10398
+ previous;
10399
+ cores;
10400
+ services;
10401
+ static Codec = descriptors_codec.Class(StatisticsData, {
10402
+ current: common_codecPerValidator(ValidatorStatistics.Codec),
10403
+ previous: common_codecPerValidator(ValidatorStatistics.Codec),
10404
+ cores: codecPerCore(CoreStatistics.Codec),
10405
+ services: descriptors_codec.dictionary(codecServiceId, ServiceStatistics.Codec, {
10406
+ sortKeys: (a, b) => a - b,
10407
+ }),
10408
+ });
10409
+ static create(v) {
10410
+ return new StatisticsData(v.current, v.previous, v.cores, v.services);
9994
10411
  }
9995
- constructor(current) {
9996
- super();
10412
+ constructor(current, previous, cores, services) {
9997
10413
  this.current = current;
9998
- }
9999
- /** History of recent blocks with maximum size of `MAX_RECENT_HISTORY` */
10000
- get blocks() {
10001
- if (this.current !== null) {
10002
- return this.current.blocks;
10003
- }
10004
- throw new Error("RecentBlocksHistory is in invalid state");
10005
- }
10006
- asCurrent() {
10007
- if (this.current === null) {
10008
- throw new Error("Cannot access current RecentBlocks format");
10009
- }
10010
- return this.current;
10011
- }
10012
- updateBlocks(blocks) {
10013
- if (this.current !== null) {
10014
- return RecentBlocksHistory.create(RecentBlocks.create({
10015
- ...this.current,
10016
- blocks: opaque_asOpaqueType(blocks),
10017
- }));
10018
- }
10019
- throw new Error("RecentBlocksHistory is in invalid state. Cannot be updated!");
10414
+ this.previous = previous;
10415
+ this.cores = cores;
10416
+ this.services = services;
10020
10417
  }
10021
10418
  }
10022
10419
 
10023
- ;// CONCATENATED MODULE: ./packages/jam/state/validator-data.ts
10420
+ ;// CONCATENATED MODULE: ./packages/jam/state/in-memory-state-view.ts
10024
10421
 
10025
10422
 
10026
10423
 
10027
- /**
10028
- * Fixed size of validator metadata.
10029
- *
10030
- * https://graypaper.fluffylabs.dev/#/5f542d7/0d55010d5501
10031
- */
10032
- const VALIDATOR_META_BYTES = 128;
10033
- /**
10034
- * Details about validators' identity.
10035
- *
10036
- * https://graypaper.fluffylabs.dev/#/5f542d7/0d4b010d4c01
10037
- */
10038
- class ValidatorData extends WithDebug {
10039
- bandersnatch;
10040
- ed25519;
10041
- bls;
10042
- metadata;
10043
- static Codec = descriptors_codec.Class(ValidatorData, {
10044
- bandersnatch: descriptors_codec.bytes(BANDERSNATCH_KEY_BYTES).asOpaque(),
10045
- ed25519: descriptors_codec.bytes(ED25519_KEY_BYTES).asOpaque(),
10046
- bls: descriptors_codec.bytes(BLS_KEY_BYTES).asOpaque(),
10047
- metadata: descriptors_codec.bytes(VALIDATOR_META_BYTES),
10048
- });
10049
- static create({ ed25519, bandersnatch, bls, metadata }) {
10050
- return new ValidatorData(bandersnatch, ed25519, bls, metadata);
10051
- }
10052
- constructor(
10053
- /** Bandersnatch public key. */
10054
- bandersnatch,
10055
- /** ED25519 key data. */
10056
- ed25519,
10057
- /** BLS public key. */
10058
- bls,
10059
- /** Validator-defined additional metdata. */
10060
- metadata) {
10061
- super();
10062
- this.bandersnatch = bandersnatch;
10063
- this.ed25519 = ed25519;
10064
- this.bls = bls;
10065
- this.metadata = metadata;
10066
- }
10067
- }
10068
10424
 
10069
- ;// CONCATENATED MODULE: ./packages/jam/state/safrole-data.ts
10070
10425
 
10071
10426
 
10072
10427
 
10073
10428
 
10074
10429
 
10075
10430
 
10431
+ class InMemoryStateView {
10432
+ chainSpec;
10433
+ state;
10434
+ constructor(chainSpec, state) {
10435
+ this.chainSpec = chainSpec;
10436
+ this.state = state;
10437
+ }
10438
+ availabilityAssignmentView() {
10439
+ return reencodeAsView(availabilityAssignmentsCodec, this.state.availabilityAssignment, this.chainSpec);
10440
+ }
10441
+ designatedValidatorDataView() {
10442
+ return reencodeAsView(validatorsDataCodec, this.state.designatedValidatorData, this.chainSpec);
10443
+ }
10444
+ currentValidatorDataView() {
10445
+ return reencodeAsView(validatorsDataCodec, this.state.currentValidatorData, this.chainSpec);
10446
+ }
10447
+ previousValidatorDataView() {
10448
+ return reencodeAsView(validatorsDataCodec, this.state.previousValidatorData, this.chainSpec);
10449
+ }
10450
+ authPoolsView() {
10451
+ return reencodeAsView(authPoolsCodec, this.state.authPools, this.chainSpec);
10452
+ }
10453
+ authQueuesView() {
10454
+ return reencodeAsView(authQueuesCodec, this.state.authQueues, this.chainSpec);
10455
+ }
10456
+ recentBlocksView() {
10457
+ return reencodeAsView(RecentBlocks.Codec, this.state.recentBlocks, this.chainSpec);
10458
+ }
10459
+ statisticsView() {
10460
+ return reencodeAsView(StatisticsData.Codec, this.state.statistics, this.chainSpec);
10461
+ }
10462
+ accumulationQueueView() {
10463
+ return reencodeAsView(accumulationQueueCodec, this.state.accumulationQueue, this.chainSpec);
10464
+ }
10465
+ recentlyAccumulatedView() {
10466
+ return reencodeAsView(recentlyAccumulatedCodec, this.state.recentlyAccumulated, this.chainSpec);
10467
+ }
10468
+ safroleDataView() {
10469
+ // TODO [ToDr] Consider exposting `safrole` from state
10470
+ // instead of individual fields
10471
+ const safrole = SafroleData.create({
10472
+ nextValidatorData: this.state.nextValidatorData,
10473
+ epochRoot: this.state.epochRoot,
10474
+ sealingKeySeries: this.state.sealingKeySeries,
10475
+ ticketsAccumulator: this.state.ticketsAccumulator,
10476
+ });
10477
+ return reencodeAsView(SafroleData.Codec, safrole, this.chainSpec);
10478
+ }
10479
+ getServiceInfoView(id) {
10480
+ const service = this.state.getService(id);
10481
+ if (service === null) {
10482
+ return null;
10483
+ }
10484
+ return reencodeAsView(ServiceAccountInfo.Codec, service.getInfo(), this.chainSpec);
10485
+ }
10486
+ }
10076
10487
 
10488
+ ;// CONCATENATED MODULE: ./packages/jam/state/privileged-services.ts
10077
10489
 
10078
10490
 
10079
10491
 
10080
10492
 
10081
- var SafroleSealingKeysKind;
10082
- (function (SafroleSealingKeysKind) {
10083
- SafroleSealingKeysKind[SafroleSealingKeysKind["Tickets"] = 0] = "Tickets";
10084
- SafroleSealingKeysKind[SafroleSealingKeysKind["Keys"] = 1] = "Keys";
10085
- })(SafroleSealingKeysKind || (SafroleSealingKeysKind = {}));
10086
- const codecBandersnatchKey = descriptors_codec.bytes(BANDERSNATCH_KEY_BYTES).asOpaque();
10087
- class SafroleSealingKeysData extends WithDebug {
10088
- kind;
10089
- keys;
10090
- tickets;
10091
- static Codec = codecWithContext((context) => {
10092
- return descriptors_codec.custom({
10093
- name: "SafroleSealingKeys",
10094
- sizeHint: { bytes: 1 + hash_HASH_SIZE * context.epochLength, isExact: false },
10095
- }, (e, x) => {
10096
- e.varU32(numbers_tryAsU32(x.kind));
10097
- if (x.kind === SafroleSealingKeysKind.Keys) {
10098
- e.sequenceFixLen(codecBandersnatchKey, x.keys);
10099
- }
10100
- else {
10101
- e.sequenceFixLen(Ticket.Codec, x.tickets);
10102
- }
10103
- }, (d) => {
10104
- const epochLength = context.epochLength;
10105
- const kind = d.varU32();
10106
- if (kind === SafroleSealingKeysKind.Keys) {
10107
- const keys = d.sequenceFixLen(codecBandersnatchKey, epochLength);
10108
- return SafroleSealingKeysData.keys(tryAsPerEpochBlock(keys, context));
10109
- }
10110
- if (kind === SafroleSealingKeysKind.Tickets) {
10111
- const tickets = d.sequenceFixLen(Ticket.Codec, epochLength);
10112
- return SafroleSealingKeysData.tickets(tryAsPerEpochBlock(tickets, context));
10113
- }
10114
- throw new Error(`Unexpected safrole sealing keys kind: ${kind}`);
10115
- }, (s) => {
10116
- const kind = s.decoder.varU32();
10117
- if (kind === SafroleSealingKeysKind.Keys) {
10118
- s.sequenceFixLen(codecBandersnatchKey, context.epochLength);
10119
- return;
10120
- }
10121
- if (kind === SafroleSealingKeysKind.Tickets) {
10122
- s.sequenceFixLen(Ticket.Codec, context.epochLength);
10123
- return;
10124
- }
10125
- throw new Error(`Unexpected safrole sealing keys kind: ${kind}`);
10126
- });
10493
+
10494
+ /** Dictionary entry of services that auto-accumulate every block. */
10495
+ class AutoAccumulate {
10496
+ service;
10497
+ gasLimit;
10498
+ static Codec = descriptors_codec.Class(AutoAccumulate, {
10499
+ service: descriptors_codec.u32.asOpaque(),
10500
+ gasLimit: descriptors_codec.u64.asOpaque(),
10127
10501
  });
10128
- static keys(keys) {
10129
- return new SafroleSealingKeysData(SafroleSealingKeysKind.Keys, keys, undefined);
10130
- }
10131
- static tickets(tickets) {
10132
- return new SafroleSealingKeysData(SafroleSealingKeysKind.Tickets, undefined, tickets);
10502
+ static create({ service, gasLimit }) {
10503
+ return new AutoAccumulate(service, gasLimit);
10133
10504
  }
10134
- constructor(kind, keys, tickets) {
10135
- super();
10136
- this.kind = kind;
10137
- this.keys = keys;
10138
- this.tickets = tickets;
10505
+ constructor(
10506
+ /** Service id that auto-accumulates. */
10507
+ service,
10508
+ /** Gas limit for auto-accumulation. */
10509
+ gasLimit) {
10510
+ this.service = service;
10511
+ this.gasLimit = gasLimit;
10139
10512
  }
10140
10513
  }
10141
- class SafroleData {
10142
- nextValidatorData;
10143
- epochRoot;
10144
- sealingKeySeries;
10145
- ticketsAccumulator;
10146
- static Codec = descriptors_codec.Class(SafroleData, {
10147
- nextValidatorData: codecPerValidator(ValidatorData.Codec),
10148
- epochRoot: descriptors_codec.bytes(BANDERSNATCH_RING_ROOT_BYTES).asOpaque(),
10149
- sealingKeySeries: SafroleSealingKeysData.Codec,
10150
- ticketsAccumulator: readonlyArray(descriptors_codec.sequenceVarLen(Ticket.Codec)).convert(seeThrough, sized_array_asKnownSize),
10514
+ /**
10515
+ * https://graypaper.fluffylabs.dev/#/ab2cdbd/114402114402?v=0.7.2
10516
+ */
10517
+ class PrivilegedServices {
10518
+ manager;
10519
+ delegator;
10520
+ registrar;
10521
+ assigners;
10522
+ autoAccumulateServices;
10523
+ /** https://graypaper.fluffylabs.dev/#/ab2cdbd/3bbd023bcb02?v=0.7.2 */
10524
+ static Codec = descriptors_codec.Class(PrivilegedServices, {
10525
+ manager: descriptors_codec.u32.asOpaque(),
10526
+ assigners: codecPerCore(descriptors_codec.u32.asOpaque()),
10527
+ delegator: descriptors_codec.u32.asOpaque(),
10528
+ registrar: Compatibility.isGreaterOrEqual(GpVersion.V0_7_1)
10529
+ ? descriptors_codec.u32.asOpaque()
10530
+ : ignoreValueWithDefault(tryAsServiceId(2 ** 32 - 1)),
10531
+ autoAccumulateServices: descriptors_readonlyArray(descriptors_codec.sequenceVarLen(AutoAccumulate.Codec)),
10151
10532
  });
10152
- static create({ nextValidatorData, epochRoot, sealingKeySeries, ticketsAccumulator }) {
10153
- return new SafroleData(nextValidatorData, epochRoot, sealingKeySeries, ticketsAccumulator);
10533
+ static create(a) {
10534
+ return new PrivilegedServices(a.manager, a.delegator, a.registrar, a.assigners, a.autoAccumulateServices);
10154
10535
  }
10155
10536
  constructor(
10156
- /** gamma_k */
10157
- nextValidatorData,
10158
- /** gamma_z */
10159
- epochRoot,
10160
- /** gamma_s */
10161
- sealingKeySeries,
10162
- /** gamma_a */
10163
- ticketsAccumulator) {
10164
- this.nextValidatorData = nextValidatorData;
10165
- this.epochRoot = epochRoot;
10166
- this.sealingKeySeries = sealingKeySeries;
10167
- this.ticketsAccumulator = ticketsAccumulator;
10537
+ /**
10538
+ * `χ_M`: Manages alteration of χ from block to block,
10539
+ * as well as bestow services with storage deposit credits.
10540
+ * https://graypaper.fluffylabs.dev/#/ab2cdbd/111502111902?v=0.7.2
10541
+ */
10542
+ manager,
10543
+ /** `χ_V`: Managers validator keys. */
10544
+ delegator,
10545
+ /**
10546
+ * `χ_R`: Manages the creation of services in protected range.
10547
+ *
10548
+ * https://graypaper.fluffylabs.dev/#/ab2cdbd/111b02111d02?v=0.7.2
10549
+ */
10550
+ registrar,
10551
+ /** `χ_A`: Manages authorization queue one for each core. */
10552
+ assigners,
10553
+ /** `χ_Z`: Dictionary of services that auto-accumulate every block with their gas limit. */
10554
+ autoAccumulateServices) {
10555
+ this.manager = manager;
10556
+ this.delegator = delegator;
10557
+ this.registrar = registrar;
10558
+ this.assigners = assigners;
10559
+ this.autoAccumulateServices = autoAccumulateServices;
10168
10560
  }
10169
10561
  }
10170
10562
 
@@ -10205,31 +10597,29 @@ var UpdatePreimageKind;
10205
10597
  * 3. Update `LookupHistory` with given value.
10206
10598
  */
10207
10599
  class UpdatePreimage {
10208
- serviceId;
10209
10600
  action;
10210
- constructor(serviceId, action) {
10211
- this.serviceId = serviceId;
10601
+ constructor(action) {
10212
10602
  this.action = action;
10213
10603
  }
10214
10604
  /** A preimage is provided. We should update the lookuphistory and add the preimage to db. */
10215
- static provide({ serviceId, preimage, slot, }) {
10216
- return new UpdatePreimage(serviceId, {
10605
+ static provide({ preimage, slot }) {
10606
+ return new UpdatePreimage({
10217
10607
  kind: UpdatePreimageKind.Provide,
10218
10608
  preimage,
10219
10609
  slot,
10220
10610
  });
10221
10611
  }
10222
10612
  /** The preimage should be removed completely from the database. */
10223
- static remove({ serviceId, hash, length }) {
10224
- return new UpdatePreimage(serviceId, {
10613
+ static remove({ hash, length }) {
10614
+ return new UpdatePreimage({
10225
10615
  kind: UpdatePreimageKind.Remove,
10226
10616
  hash,
10227
10617
  length,
10228
10618
  });
10229
10619
  }
10230
10620
  /** Update the lookup history of some preimage or add a new one (request). */
10231
- static updateOrAdd({ serviceId, lookupHistory }) {
10232
- return new UpdatePreimage(serviceId, {
10621
+ static updateOrAdd({ lookupHistory }) {
10622
+ return new UpdatePreimage({
10233
10623
  kind: UpdatePreimageKind.UpdateOrAdd,
10234
10624
  item: lookupHistory,
10235
10625
  });
@@ -10266,23 +10656,21 @@ var UpdateServiceKind;
10266
10656
  UpdateServiceKind[UpdateServiceKind["Create"] = 1] = "Create";
10267
10657
  })(UpdateServiceKind || (UpdateServiceKind = {}));
10268
10658
  /**
10269
- * Update service info of a particular `ServiceId` or create a new one.
10659
+ * Update service info or create a new one.
10270
10660
  */
10271
10661
  class UpdateService {
10272
- serviceId;
10273
10662
  action;
10274
- constructor(serviceId, action) {
10275
- this.serviceId = serviceId;
10663
+ constructor(action) {
10276
10664
  this.action = action;
10277
10665
  }
10278
- static update({ serviceId, serviceInfo }) {
10279
- return new UpdateService(serviceId, {
10666
+ static update({ serviceInfo }) {
10667
+ return new UpdateService({
10280
10668
  kind: UpdateServiceKind.Update,
10281
10669
  account: serviceInfo,
10282
10670
  });
10283
10671
  }
10284
- static create({ serviceId, serviceInfo, lookupHistory, }) {
10285
- return new UpdateService(serviceId, {
10672
+ static create({ serviceInfo, lookupHistory, }) {
10673
+ return new UpdateService({
10286
10674
  kind: UpdateServiceKind.Create,
10287
10675
  account: serviceInfo,
10288
10676
  lookupHistory,
@@ -10299,288 +10687,31 @@ var UpdateStorageKind;
10299
10687
  })(UpdateStorageKind || (UpdateStorageKind = {}));
10300
10688
  /**
10301
10689
  * Update service storage item.
10302
- *
10303
- * Can either create/modify an entry or remove it.
10304
- */
10305
- class UpdateStorage {
10306
- serviceId;
10307
- action;
10308
- constructor(serviceId, action) {
10309
- this.serviceId = serviceId;
10310
- this.action = action;
10311
- }
10312
- static set({ serviceId, storage }) {
10313
- return new UpdateStorage(serviceId, { kind: UpdateStorageKind.Set, storage });
10314
- }
10315
- static remove({ serviceId, key }) {
10316
- return new UpdateStorage(serviceId, { kind: UpdateStorageKind.Remove, key });
10317
- }
10318
- get key() {
10319
- if (this.action.kind === UpdateStorageKind.Remove) {
10320
- return this.action.key;
10321
- }
10322
- return this.action.storage.key;
10323
- }
10324
- get value() {
10325
- if (this.action.kind === UpdateStorageKind.Remove) {
10326
- return null;
10327
- }
10328
- return this.action.storage.value;
10329
- }
10330
- }
10331
-
10332
- ;// CONCATENATED MODULE: ./packages/jam/state/statistics.ts
10333
-
10334
-
10335
-
10336
-
10337
-
10338
- const codecServiceId = Compatibility.isSuite(TestSuite.W3F_DAVXY) || Compatibility.isSuite(TestSuite.JAMDUNA, GpVersion.V0_6_7)
10339
- ? descriptors_codec.u32.asOpaque()
10340
- : descriptors_codec.varU32.convert((s) => numbers_tryAsU32(s), (i) => tryAsServiceId(i));
10341
- /**
10342
- * Activity Record of a single validator.
10343
- *
10344
- * https://graypaper.fluffylabs.dev/#/579bd12/183701183701
10345
- */
10346
- class ValidatorStatistics {
10347
- blocks;
10348
- tickets;
10349
- preImages;
10350
- preImagesSize;
10351
- guarantees;
10352
- assurances;
10353
- static Codec = descriptors_codec.Class(ValidatorStatistics, {
10354
- blocks: descriptors_codec.u32,
10355
- tickets: descriptors_codec.u32,
10356
- preImages: descriptors_codec.u32,
10357
- preImagesSize: descriptors_codec.u32,
10358
- guarantees: descriptors_codec.u32,
10359
- assurances: descriptors_codec.u32,
10360
- });
10361
- static create({ blocks, tickets, preImages, preImagesSize, guarantees, assurances, }) {
10362
- return new ValidatorStatistics(blocks, tickets, preImages, preImagesSize, guarantees, assurances);
10363
- }
10364
- constructor(
10365
- /** The number of blocks produced by the validator. */
10366
- blocks,
10367
- /** The number of tickets introduced by the validator. */
10368
- tickets,
10369
- /** The number of preimages introduced by the validator. */
10370
- preImages,
10371
- /** The total number of octets across all preimages introduced by the validator. */
10372
- preImagesSize,
10373
- /** The number of reports guaranteed by the validator. */
10374
- guarantees,
10375
- /** The number of availability assurances made by the validator. */
10376
- assurances) {
10377
- this.blocks = blocks;
10378
- this.tickets = tickets;
10379
- this.preImages = preImages;
10380
- this.preImagesSize = preImagesSize;
10381
- this.guarantees = guarantees;
10382
- this.assurances = assurances;
10383
- }
10384
- static empty() {
10385
- const zero = numbers_tryAsU32(0);
10386
- return new ValidatorStatistics(zero, zero, zero, zero, zero, zero);
10387
- }
10388
- }
10389
- const codecVarU16 = descriptors_codec.varU32.convert((i) => numbers_tryAsU32(i), (o) => numbers_tryAsU16(o));
10390
- /** Encode/decode unsigned gas. */
10391
- const codecVarGas = descriptors_codec.varU64.convert((g) => numbers_tryAsU64(g), (i) => tryAsServiceGas(i));
10392
- /**
10393
- * Single core statistics.
10394
- * Updated per block, based on incoming work reports (`w`).
10395
- *
10396
- * https://graypaper.fluffylabs.dev/#/68eaa1f/18f10318f103?v=0.6.4
10397
- * https://github.com/gavofyork/graypaper/blob/9bffb08f3ea7b67832019176754df4fb36b9557d/text/statistics.tex#L65
10398
- */
10399
- class CoreStatistics {
10400
- dataAvailabilityLoad;
10401
- popularity;
10402
- imports;
10403
- exports;
10404
- extrinsicSize;
10405
- extrinsicCount;
10406
- bundleSize;
10407
- gasUsed;
10408
- static Codec = Compatibility.isGreaterOrEqual(GpVersion.V0_7_0)
10409
- ? descriptors_codec.Class(CoreStatistics, {
10410
- dataAvailabilityLoad: descriptors_codec.varU32,
10411
- popularity: codecVarU16,
10412
- imports: codecVarU16,
10413
- extrinsicCount: codecVarU16,
10414
- extrinsicSize: descriptors_codec.varU32,
10415
- exports: codecVarU16,
10416
- bundleSize: descriptors_codec.varU32,
10417
- gasUsed: codecVarGas,
10418
- })
10419
- : descriptors_codec.Class(CoreStatistics, {
10420
- dataAvailabilityLoad: descriptors_codec.varU32,
10421
- popularity: codecVarU16,
10422
- imports: codecVarU16,
10423
- exports: codecVarU16,
10424
- extrinsicSize: descriptors_codec.varU32,
10425
- extrinsicCount: codecVarU16,
10426
- bundleSize: descriptors_codec.varU32,
10427
- gasUsed: codecVarGas,
10428
- });
10429
- static create(v) {
10430
- return new CoreStatistics(v.dataAvailabilityLoad, v.popularity, v.imports, v.exports, v.extrinsicSize, v.extrinsicCount, v.bundleSize, v.gasUsed);
10431
- }
10432
- constructor(
10433
- /** `d` */
10434
- dataAvailabilityLoad,
10435
- /** `p` */
10436
- popularity,
10437
- /** `i` */
10438
- imports,
10439
- /** `e` */
10440
- exports,
10441
- /** `z` */
10442
- extrinsicSize,
10443
- /** `x` */
10444
- extrinsicCount,
10445
- /** `b` */
10446
- bundleSize,
10447
- /** `u` */
10448
- gasUsed) {
10449
- this.dataAvailabilityLoad = dataAvailabilityLoad;
10450
- this.popularity = popularity;
10451
- this.imports = imports;
10452
- this.exports = exports;
10453
- this.extrinsicSize = extrinsicSize;
10454
- this.extrinsicCount = extrinsicCount;
10455
- this.bundleSize = bundleSize;
10456
- this.gasUsed = gasUsed;
10457
- }
10458
- static empty() {
10459
- const zero = numbers_tryAsU32(0);
10460
- const zero16 = numbers_tryAsU16(0);
10461
- const zeroGas = tryAsServiceGas(0);
10462
- return new CoreStatistics(zero, zero16, zero16, zero16, zero, zero16, zero, zeroGas);
10463
- }
10464
- }
10465
- /**
10466
- * Service statistics.
10467
- * Updated per block, based on available work reports (`W`).
10468
- *
10469
- * https://graypaper.fluffylabs.dev/#/68eaa1f/185104185104?v=0.6.4
10470
- * https://github.com/gavofyork/graypaper/blob/9bffb08f3ea7b67832019176754df4fb36b9557d/text/statistics.tex#L77
10471
- */
10472
- class ServiceStatistics {
10473
- providedCount;
10474
- providedSize;
10475
- refinementCount;
10476
- refinementGasUsed;
10477
- imports;
10478
- exports;
10479
- extrinsicSize;
10480
- extrinsicCount;
10481
- accumulateCount;
10482
- accumulateGasUsed;
10483
- onTransfersCount;
10484
- onTransfersGasUsed;
10485
- static Codec = Compatibility.isGreaterOrEqual(GpVersion.V0_7_0)
10486
- ? descriptors_codec.Class(ServiceStatistics, {
10487
- providedCount: codecVarU16,
10488
- providedSize: descriptors_codec.varU32,
10489
- refinementCount: descriptors_codec.varU32,
10490
- refinementGasUsed: codecVarGas,
10491
- imports: codecVarU16,
10492
- extrinsicCount: codecVarU16,
10493
- extrinsicSize: descriptors_codec.varU32,
10494
- exports: codecVarU16,
10495
- accumulateCount: descriptors_codec.varU32,
10496
- accumulateGasUsed: codecVarGas,
10497
- onTransfersCount: descriptors_codec.varU32,
10498
- onTransfersGasUsed: codecVarGas,
10499
- })
10500
- : descriptors_codec.Class(ServiceStatistics, {
10501
- providedCount: codecVarU16,
10502
- providedSize: descriptors_codec.varU32,
10503
- refinementCount: descriptors_codec.varU32,
10504
- refinementGasUsed: codecVarGas,
10505
- imports: codecVarU16,
10506
- exports: codecVarU16,
10507
- extrinsicSize: descriptors_codec.varU32,
10508
- extrinsicCount: codecVarU16,
10509
- accumulateCount: descriptors_codec.varU32,
10510
- accumulateGasUsed: codecVarGas,
10511
- onTransfersCount: descriptors_codec.varU32,
10512
- onTransfersGasUsed: codecVarGas,
10513
- });
10514
- static create(v) {
10515
- return new ServiceStatistics(v.providedCount, v.providedSize, v.refinementCount, v.refinementGasUsed, v.imports, v.exports, v.extrinsicSize, v.extrinsicCount, v.accumulateCount, v.accumulateGasUsed, v.onTransfersCount, v.onTransfersGasUsed);
10516
- }
10517
- constructor(
10518
- /** `p.0` */
10519
- providedCount,
10520
- /** `p.1` */
10521
- providedSize,
10522
- /** `r.0` */
10523
- refinementCount,
10524
- /** `r.1` */
10525
- refinementGasUsed,
10526
- /** `i` */
10527
- imports,
10528
- /** `e` */
10529
- exports,
10530
- /** `z` */
10531
- extrinsicSize,
10532
- /** `x` */
10533
- extrinsicCount,
10534
- /** `a.0` */
10535
- accumulateCount,
10536
- /** `a.1` */
10537
- accumulateGasUsed,
10538
- /** `t.0` */
10539
- onTransfersCount,
10540
- /** `t.1` */
10541
- onTransfersGasUsed) {
10542
- this.providedCount = providedCount;
10543
- this.providedSize = providedSize;
10544
- this.refinementCount = refinementCount;
10545
- this.refinementGasUsed = refinementGasUsed;
10546
- this.imports = imports;
10547
- this.exports = exports;
10548
- this.extrinsicSize = extrinsicSize;
10549
- this.extrinsicCount = extrinsicCount;
10550
- this.accumulateCount = accumulateCount;
10551
- this.accumulateGasUsed = accumulateGasUsed;
10552
- this.onTransfersCount = onTransfersCount;
10553
- this.onTransfersGasUsed = onTransfersGasUsed;
10690
+ *
10691
+ * Can either create/modify an entry or remove it.
10692
+ */
10693
+ class UpdateStorage {
10694
+ action;
10695
+ constructor(action) {
10696
+ this.action = action;
10554
10697
  }
10555
- static empty() {
10556
- const zero = numbers_tryAsU32(0);
10557
- const zero16 = numbers_tryAsU16(0);
10558
- const zeroGas = tryAsServiceGas(0);
10559
- return new ServiceStatistics(zero16, zero, zero, zeroGas, zero16, zero16, zero, zero16, zero, zeroGas, zero, zeroGas);
10698
+ static set({ storage }) {
10699
+ return new UpdateStorage({ kind: UpdateStorageKind.Set, storage });
10560
10700
  }
10561
- }
10562
- /** `pi`: Statistics of each validator, cores statistics and services statistics. */
10563
- class StatisticsData {
10564
- current;
10565
- previous;
10566
- cores;
10567
- services;
10568
- static Codec = descriptors_codec.Class(StatisticsData, {
10569
- current: codecPerValidator(ValidatorStatistics.Codec),
10570
- previous: codecPerValidator(ValidatorStatistics.Codec),
10571
- cores: codecPerCore(CoreStatistics.Codec),
10572
- services: descriptors_codec.dictionary(codecServiceId, ServiceStatistics.Codec, {
10573
- sortKeys: (a, b) => a - b,
10574
- }),
10575
- });
10576
- static create(v) {
10577
- return new StatisticsData(v.current, v.previous, v.cores, v.services);
10701
+ static remove({ key }) {
10702
+ return new UpdateStorage({ kind: UpdateStorageKind.Remove, key });
10578
10703
  }
10579
- constructor(current, previous, cores, services) {
10580
- this.current = current;
10581
- this.previous = previous;
10582
- this.cores = cores;
10583
- this.services = services;
10704
+ get key() {
10705
+ if (this.action.kind === UpdateStorageKind.Remove) {
10706
+ return this.action.key;
10707
+ }
10708
+ return this.action.storage.key;
10709
+ }
10710
+ get value() {
10711
+ if (this.action.kind === UpdateStorageKind.Remove) {
10712
+ return null;
10713
+ }
10714
+ return this.action.storage.value;
10584
10715
  }
10585
10716
  }
10586
10717
 
@@ -10605,6 +10736,7 @@ class StatisticsData {
10605
10736
 
10606
10737
 
10607
10738
 
10739
+
10608
10740
 
10609
10741
 
10610
10742
  var in_memory_state_UpdateError;
@@ -10705,10 +10837,11 @@ class InMemoryService extends WithDebug {
10705
10837
  /**
10706
10838
  * A special version of state, stored fully in-memory.
10707
10839
  */
10708
- class InMemoryState extends WithDebug {
10840
+ class in_memory_state_InMemoryState extends WithDebug {
10841
+ chainSpec;
10709
10842
  /** Create a new `InMemoryState` by providing all required fields. */
10710
- static create(state) {
10711
- return new InMemoryState(state);
10843
+ static new(chainSpec, state) {
10844
+ return new in_memory_state_InMemoryState(chainSpec, state);
10712
10845
  }
10713
10846
  /**
10714
10847
  * Create a new `InMemoryState` with a partial state override.
@@ -10717,14 +10850,14 @@ class InMemoryState extends WithDebug {
10717
10850
  * not-necessarily coherent values.
10718
10851
  */
10719
10852
  static partial(spec, partial) {
10720
- const state = InMemoryState.empty(spec);
10853
+ const state = in_memory_state_InMemoryState.empty(spec);
10721
10854
  Object.assign(state, partial);
10722
10855
  return state;
10723
10856
  }
10724
10857
  /**
10725
10858
  * Create a new `InMemoryState` from some other state object.
10726
10859
  */
10727
- static copyFrom(other, servicesData) {
10860
+ static copyFrom(chainSpec, other, servicesData) {
10728
10861
  const services = new Map();
10729
10862
  for (const [id, entries] of servicesData.entries()) {
10730
10863
  const service = other.getService(id);
@@ -10734,7 +10867,7 @@ class InMemoryState extends WithDebug {
10734
10867
  const inMemService = InMemoryService.copyFrom(service, entries);
10735
10868
  services.set(id, inMemService);
10736
10869
  }
10737
- return InMemoryState.create({
10870
+ return in_memory_state_InMemoryState.new(chainSpec, {
10738
10871
  availabilityAssignment: other.availabilityAssignment,
10739
10872
  accumulationQueue: other.accumulationQueue,
10740
10873
  designatedValidatorData: other.designatedValidatorData,
@@ -10775,12 +10908,12 @@ class InMemoryState extends WithDebug {
10775
10908
  * Modify the state and apply a single state update.
10776
10909
  */
10777
10910
  applyUpdate(update) {
10778
- const { servicesRemoved, servicesUpdates, preimages, storage, ...rest } = update;
10911
+ const { removed, created: _, updated, preimages, storage, ...rest } = update;
10779
10912
  // just assign all other variables
10780
10913
  Object.assign(this, rest);
10781
10914
  // and update the services state
10782
10915
  let result;
10783
- result = this.updateServices(servicesUpdates);
10916
+ result = this.updateServices(updated);
10784
10917
  if (result.isError) {
10785
10918
  return result;
10786
10919
  }
@@ -10792,7 +10925,7 @@ class InMemoryState extends WithDebug {
10792
10925
  if (result.isError) {
10793
10926
  return result;
10794
10927
  }
10795
- this.removeServices(servicesRemoved);
10928
+ this.removeServices(removed);
10796
10929
  return result_Result.ok(result_OK);
10797
10930
  }
10798
10931
  removeServices(servicesRemoved) {
@@ -10801,89 +10934,102 @@ class InMemoryState extends WithDebug {
10801
10934
  this.services.delete(serviceId);
10802
10935
  }
10803
10936
  }
10804
- updateStorage(storage) {
10805
- for (const { serviceId, action } of storage ?? []) {
10806
- const { kind } = action;
10807
- const service = this.services.get(serviceId);
10808
- if (service === undefined) {
10809
- return result_Result.error(in_memory_state_UpdateError.NoService, `Attempting to update storage of non-existing service: ${serviceId}`);
10810
- }
10811
- if (kind === UpdateStorageKind.Set) {
10812
- const { key, value } = action.storage;
10813
- service.data.storage.set(key.toString(), StorageItem.create({ key, value }));
10814
- }
10815
- else if (kind === UpdateStorageKind.Remove) {
10816
- const { key } = action;
10817
- debug_check `
10937
+ updateStorage(storageUpdates) {
10938
+ if (storageUpdates === undefined) {
10939
+ return result_Result.ok(result_OK);
10940
+ }
10941
+ for (const [serviceId, updates] of storageUpdates.entries()) {
10942
+ for (const update of updates) {
10943
+ const { kind } = update.action;
10944
+ const service = this.services.get(serviceId);
10945
+ if (service === undefined) {
10946
+ return result_Result.error(in_memory_state_UpdateError.NoService, () => `Attempting to update storage of non-existing service: ${serviceId}`);
10947
+ }
10948
+ if (kind === UpdateStorageKind.Set) {
10949
+ const { key, value } = update.action.storage;
10950
+ service.data.storage.set(key.toString(), StorageItem.create({ key, value }));
10951
+ }
10952
+ else if (kind === UpdateStorageKind.Remove) {
10953
+ const { key } = update.action;
10954
+ debug_check `
10818
10955
  ${service.data.storage.has(key.toString())}
10819
- Attempting to remove non-existing storage item at ${serviceId}: ${action.key}
10956
+ Attempting to remove non-existing storage item at ${serviceId}: ${update.action.key}
10820
10957
  `;
10821
- service.data.storage.delete(key.toString());
10822
- }
10823
- else {
10824
- debug_assertNever(kind);
10958
+ service.data.storage.delete(key.toString());
10959
+ }
10960
+ else {
10961
+ debug_assertNever(kind);
10962
+ }
10825
10963
  }
10826
10964
  }
10827
10965
  return result_Result.ok(result_OK);
10828
10966
  }
10829
- updatePreimages(preimages) {
10830
- for (const { serviceId, action } of preimages ?? []) {
10967
+ updatePreimages(preimagesUpdates) {
10968
+ if (preimagesUpdates === undefined) {
10969
+ return result_Result.ok(result_OK);
10970
+ }
10971
+ for (const [serviceId, updates] of preimagesUpdates.entries()) {
10831
10972
  const service = this.services.get(serviceId);
10832
10973
  if (service === undefined) {
10833
- return result_Result.error(in_memory_state_UpdateError.NoService, `Attempting to update preimage of non-existing service: ${serviceId}`);
10834
- }
10835
- const { kind } = action;
10836
- if (kind === UpdatePreimageKind.Provide) {
10837
- const { preimage, slot } = action;
10838
- if (service.data.preimages.has(preimage.hash)) {
10839
- return result_Result.error(in_memory_state_UpdateError.PreimageExists, `Overwriting existing preimage at ${serviceId}: ${preimage}`);
10840
- }
10841
- service.data.preimages.set(preimage.hash, preimage);
10842
- if (slot !== null) {
10843
- const lookupHistory = service.data.lookupHistory.get(preimage.hash);
10844
- const length = numbers_tryAsU32(preimage.blob.length);
10845
- const lookup = new LookupHistoryItem(preimage.hash, length, tryAsLookupHistorySlots([slot]));
10846
- if (lookupHistory === undefined) {
10847
- // no lookup history for that preimage at all (edge case, should be requested)
10848
- service.data.lookupHistory.set(preimage.hash, [lookup]);
10974
+ return result_Result.error(in_memory_state_UpdateError.NoService, () => `Attempting to update preimage of non-existing service: ${serviceId}`);
10975
+ }
10976
+ for (const update of updates) {
10977
+ const { kind } = update.action;
10978
+ if (kind === UpdatePreimageKind.Provide) {
10979
+ const { preimage, slot } = update.action;
10980
+ if (service.data.preimages.has(preimage.hash)) {
10981
+ return result_Result.error(in_memory_state_UpdateError.PreimageExists, () => `Overwriting existing preimage at ${serviceId}: ${preimage}`);
10982
+ }
10983
+ service.data.preimages.set(preimage.hash, preimage);
10984
+ if (slot !== null) {
10985
+ const lookupHistory = service.data.lookupHistory.get(preimage.hash);
10986
+ const length = numbers_tryAsU32(preimage.blob.length);
10987
+ const lookup = new LookupHistoryItem(preimage.hash, length, tryAsLookupHistorySlots([slot]));
10988
+ if (lookupHistory === undefined) {
10989
+ // no lookup history for that preimage at all (edge case, should be requested)
10990
+ service.data.lookupHistory.set(preimage.hash, [lookup]);
10991
+ }
10992
+ else {
10993
+ // insert or replace exiting entry
10994
+ const index = lookupHistory.map((x) => x.length).indexOf(length);
10995
+ lookupHistory.splice(index, index === -1 ? 0 : 1, lookup);
10996
+ }
10849
10997
  }
10850
- else {
10851
- // insert or replace exiting entry
10852
- const index = lookupHistory.map((x) => x.length).indexOf(length);
10853
- lookupHistory.splice(index, index === -1 ? 0 : 1, lookup);
10998
+ }
10999
+ else if (kind === UpdatePreimageKind.Remove) {
11000
+ const { hash, length } = update.action;
11001
+ service.data.preimages.delete(hash);
11002
+ const history = service.data.lookupHistory.get(hash) ?? [];
11003
+ const idx = history.map((x) => x.length).indexOf(length);
11004
+ if (idx !== -1) {
11005
+ history.splice(idx, 1);
10854
11006
  }
10855
11007
  }
10856
- }
10857
- else if (kind === UpdatePreimageKind.Remove) {
10858
- const { hash, length } = action;
10859
- service.data.preimages.delete(hash);
10860
- const history = service.data.lookupHistory.get(hash) ?? [];
10861
- const idx = history.map((x) => x.length).indexOf(length);
10862
- if (idx !== -1) {
10863
- history.splice(idx, 1);
11008
+ else if (kind === UpdatePreimageKind.UpdateOrAdd) {
11009
+ const { item } = update.action;
11010
+ const history = service.data.lookupHistory.get(item.hash) ?? [];
11011
+ const existingIdx = history.map((x) => x.length).indexOf(item.length);
11012
+ const removeCount = existingIdx === -1 ? 0 : 1;
11013
+ history.splice(existingIdx, removeCount, item);
11014
+ service.data.lookupHistory.set(item.hash, history);
11015
+ }
11016
+ else {
11017
+ debug_assertNever(kind);
10864
11018
  }
10865
- }
10866
- else if (kind === UpdatePreimageKind.UpdateOrAdd) {
10867
- const { item } = action;
10868
- const history = service.data.lookupHistory.get(item.hash) ?? [];
10869
- const existingIdx = history.map((x) => x.length).indexOf(item.length);
10870
- const removeCount = existingIdx === -1 ? 0 : 1;
10871
- history.splice(existingIdx, removeCount, item);
10872
- service.data.lookupHistory.set(item.hash, history);
10873
- }
10874
- else {
10875
- debug_assertNever(kind);
10876
11019
  }
10877
11020
  }
10878
11021
  return result_Result.ok(result_OK);
10879
11022
  }
10880
11023
  updateServices(servicesUpdates) {
10881
- for (const { serviceId, action } of servicesUpdates ?? []) {
10882
- const { kind, account } = action;
11024
+ if (servicesUpdates === undefined) {
11025
+ return result_Result.ok(result_OK);
11026
+ }
11027
+ for (const [serviceId, update] of servicesUpdates.entries()) {
11028
+ const { kind, account } = update.action;
10883
11029
  if (kind === UpdateServiceKind.Create) {
10884
- const { lookupHistory } = action;
11030
+ const { lookupHistory } = update.action;
10885
11031
  if (this.services.has(serviceId)) {
10886
- return result_Result.error(in_memory_state_UpdateError.DuplicateService, `${serviceId} already exists!`);
11032
+ return result_Result.error(in_memory_state_UpdateError.DuplicateService, () => `${serviceId} already exists!`);
10887
11033
  }
10888
11034
  this.services.set(serviceId, new InMemoryService(serviceId, {
10889
11035
  info: account,
@@ -10895,7 +11041,7 @@ class InMemoryState extends WithDebug {
10895
11041
  else if (kind === UpdateServiceKind.Update) {
10896
11042
  const existingService = this.services.get(serviceId);
10897
11043
  if (existingService === undefined) {
10898
- return result_Result.error(in_memory_state_UpdateError.NoService, `Cannot update ${serviceId} because it does not exist.`);
11044
+ return result_Result.error(in_memory_state_UpdateError.NoService, () => `Cannot update ${serviceId} because it does not exist.`);
10899
11045
  }
10900
11046
  existingService.data.info = account;
10901
11047
  }
@@ -10931,8 +11077,9 @@ class InMemoryState extends WithDebug {
10931
11077
  getService(id) {
10932
11078
  return this.services.get(id) ?? null;
10933
11079
  }
10934
- constructor(s) {
11080
+ constructor(chainSpec, s) {
10935
11081
  super();
11082
+ this.chainSpec = chainSpec;
10936
11083
  this.availabilityAssignment = s.availabilityAssignment;
10937
11084
  this.designatedValidatorData = s.designatedValidatorData;
10938
11085
  this.nextValidatorData = s.nextValidatorData;
@@ -10954,31 +11101,34 @@ class InMemoryState extends WithDebug {
10954
11101
  this.accumulationOutputLog = s.accumulationOutputLog;
10955
11102
  this.services = s.services;
10956
11103
  }
11104
+ view() {
11105
+ return new InMemoryStateView(this.chainSpec, this);
11106
+ }
10957
11107
  /**
10958
11108
  * Create an empty and possibly incoherent `InMemoryState`.
10959
11109
  */
10960
11110
  static empty(spec) {
10961
- return new InMemoryState({
11111
+ return new in_memory_state_InMemoryState(spec, {
10962
11112
  availabilityAssignment: tryAsPerCore(Array.from({ length: spec.coresCount }, () => null), spec),
10963
- designatedValidatorData: tryAsPerValidator(Array.from({ length: spec.validatorsCount }, () => ValidatorData.create({
11113
+ designatedValidatorData: tryAsPerValidator(Array.from({ length: spec.validatorsCount }, () => validator_data_ValidatorData.create({
10964
11114
  bandersnatch: bytes_Bytes.zero(BANDERSNATCH_KEY_BYTES).asOpaque(),
10965
11115
  bls: bytes_Bytes.zero(BLS_KEY_BYTES).asOpaque(),
10966
11116
  ed25519: bytes_Bytes.zero(ED25519_KEY_BYTES).asOpaque(),
10967
11117
  metadata: bytes_Bytes.zero(VALIDATOR_META_BYTES).asOpaque(),
10968
11118
  })), spec),
10969
- nextValidatorData: tryAsPerValidator(Array.from({ length: spec.validatorsCount }, () => ValidatorData.create({
11119
+ nextValidatorData: tryAsPerValidator(Array.from({ length: spec.validatorsCount }, () => validator_data_ValidatorData.create({
10970
11120
  bandersnatch: bytes_Bytes.zero(BANDERSNATCH_KEY_BYTES).asOpaque(),
10971
11121
  bls: bytes_Bytes.zero(BLS_KEY_BYTES).asOpaque(),
10972
11122
  ed25519: bytes_Bytes.zero(ED25519_KEY_BYTES).asOpaque(),
10973
11123
  metadata: bytes_Bytes.zero(VALIDATOR_META_BYTES).asOpaque(),
10974
11124
  })), spec),
10975
- currentValidatorData: tryAsPerValidator(Array.from({ length: spec.validatorsCount }, () => ValidatorData.create({
11125
+ currentValidatorData: tryAsPerValidator(Array.from({ length: spec.validatorsCount }, () => validator_data_ValidatorData.create({
10976
11126
  bandersnatch: bytes_Bytes.zero(BANDERSNATCH_KEY_BYTES).asOpaque(),
10977
11127
  bls: bytes_Bytes.zero(BLS_KEY_BYTES).asOpaque(),
10978
11128
  ed25519: bytes_Bytes.zero(ED25519_KEY_BYTES).asOpaque(),
10979
11129
  metadata: bytes_Bytes.zero(VALIDATOR_META_BYTES).asOpaque(),
10980
11130
  })), spec),
10981
- previousValidatorData: tryAsPerValidator(Array.from({ length: spec.validatorsCount }, () => ValidatorData.create({
11131
+ previousValidatorData: tryAsPerValidator(Array.from({ length: spec.validatorsCount }, () => validator_data_ValidatorData.create({
10982
11132
  bandersnatch: bytes_Bytes.zero(BANDERSNATCH_KEY_BYTES).asOpaque(),
10983
11133
  bls: bytes_Bytes.zero(BLS_KEY_BYTES).asOpaque(),
10984
11134
  ed25519: bytes_Bytes.zero(ED25519_KEY_BYTES).asOpaque(),
@@ -10994,7 +11144,7 @@ class InMemoryState extends WithDebug {
10994
11144
  entropy: FixedSizeArray.fill(() => bytes_Bytes.zero(hash_HASH_SIZE).asOpaque(), ENTROPY_ENTRIES),
10995
11145
  authPools: tryAsPerCore(Array.from({ length: spec.coresCount }, () => sized_array_asKnownSize([])), spec),
10996
11146
  authQueues: tryAsPerCore(Array.from({ length: spec.coresCount }, () => FixedSizeArray.fill(() => bytes_Bytes.zero(hash_HASH_SIZE).asOpaque(), AUTHORIZATION_QUEUE_SIZE)), spec),
10997
- recentBlocks: RecentBlocksHistory.empty(),
11147
+ recentBlocks: RecentBlocks.empty(),
10998
11148
  statistics: StatisticsData.create({
10999
11149
  current: tryAsPerValidator(Array.from({ length: spec.validatorsCount }, () => ValidatorStatistics.empty()), spec),
11000
11150
  previous: tryAsPerValidator(Array.from({ length: spec.validatorsCount }, () => ValidatorStatistics.empty()), spec),
@@ -11004,8 +11154,8 @@ class InMemoryState extends WithDebug {
11004
11154
  accumulationQueue: tryAsPerEpochBlock(Array.from({ length: spec.epochLength }, () => []), spec),
11005
11155
  recentlyAccumulated: tryAsPerEpochBlock(Array.from({ length: spec.epochLength }, () => HashSet.new()), spec),
11006
11156
  ticketsAccumulator: sized_array_asKnownSize([]),
11007
- sealingKeySeries: SafroleSealingKeysData.keys(tryAsPerEpochBlock(Array.from({ length: spec.epochLength }, () => bytes_Bytes.zero(BANDERSNATCH_KEY_BYTES).asOpaque()), spec)),
11008
- epochRoot: bytes_Bytes.zero(BANDERSNATCH_RING_ROOT_BYTES).asOpaque(),
11157
+ sealingKeySeries: safrole_data_SafroleSealingKeysData.keys(tryAsPerEpochBlock(Array.from({ length: spec.epochLength }, () => bytes_Bytes.zero(BANDERSNATCH_KEY_BYTES).asOpaque()), spec)),
11158
+ epochRoot: bytes_Bytes.zero(bandersnatch_BANDERSNATCH_RING_ROOT_BYTES).asOpaque(),
11009
11159
  privilegedServices: PrivilegedServices.create({
11010
11160
  manager: tryAsServiceId(0),
11011
11161
  assigners: tryAsPerCore(new Array(spec.coresCount).fill(tryAsServiceId(0)), spec),
@@ -11045,51 +11195,10 @@ const serviceDataCodec = descriptors_codec.dictionary(descriptors_codec.u32.asOp
11045
11195
 
11046
11196
 
11047
11197
 
11048
- ;// CONCATENATED MODULE: ./packages/jam/state/not-yet-accumulated.ts
11049
-
11050
-
11051
11198
 
11052
11199
 
11053
11200
 
11054
11201
 
11055
- /**
11056
- * Ready (i.e. available and/or audited) but not-yet-accumulated work-reports.
11057
- *
11058
- * https://graypaper.fluffylabs.dev/#/5f542d7/165300165400
11059
- */
11060
- class NotYetAccumulatedReport extends WithDebug {
11061
- report;
11062
- dependencies;
11063
- static Codec = descriptors_codec.Class(NotYetAccumulatedReport, {
11064
- report: WorkReport.Codec,
11065
- dependencies: codecKnownSizeArray(descriptors_codec.bytes(hash_HASH_SIZE).asOpaque(), {
11066
- typicalLength: MAX_REPORT_DEPENDENCIES / 2,
11067
- maxLength: MAX_REPORT_DEPENDENCIES,
11068
- minLength: 0,
11069
- }),
11070
- });
11071
- static create({ report, dependencies }) {
11072
- return new NotYetAccumulatedReport(report, dependencies);
11073
- }
11074
- constructor(
11075
- /**
11076
- * Each of these were made available at most one epoch ago
11077
- * but have or had unfulfilled dependencies.
11078
- */
11079
- report,
11080
- /**
11081
- * Alongside the work-report itself, we retain its un-accumulated
11082
- * dependencies, a set of work-package hashes.
11083
- *
11084
- * https://graypaper.fluffylabs.dev/#/5f542d7/165800165800
11085
- */
11086
- dependencies) {
11087
- super();
11088
- this.report = report;
11089
- this.dependencies = dependencies;
11090
- }
11091
- }
11092
-
11093
11202
  ;// CONCATENATED MODULE: ./packages/jam/state-merkleization/serialize.ts
11094
11203
 
11095
11204
 
@@ -11102,26 +11211,19 @@ class NotYetAccumulatedReport extends WithDebug {
11102
11211
 
11103
11212
 
11104
11213
 
11105
-
11106
-
11107
-
11108
11214
  /** Serialization for particular state entries. */
11109
- var serialize;
11215
+ var serialize_serialize;
11110
11216
  (function (serialize) {
11111
11217
  /** C(1): https://graypaper.fluffylabs.dev/#/7e6ff6a/3b15013b1501?v=0.6.7 */
11112
11218
  serialize.authPools = {
11113
11219
  key: stateKeys.index(StateKeyIdx.Alpha),
11114
- Codec: codecPerCore(codecKnownSizeArray(descriptors_codec.bytes(hash_HASH_SIZE).asOpaque(), {
11115
- minLength: 0,
11116
- maxLength: MAX_AUTH_POOL_SIZE,
11117
- typicalLength: MAX_AUTH_POOL_SIZE,
11118
- })),
11220
+ Codec: authPoolsCodec,
11119
11221
  extract: (s) => s.authPools,
11120
11222
  };
11121
11223
  /** C(2): https://graypaper.fluffylabs.dev/#/7e6ff6a/3b31013b3101?v=0.6.7 */
11122
11224
  serialize.authQueues = {
11123
11225
  key: stateKeys.index(StateKeyIdx.Phi),
11124
- Codec: codecPerCore(codecFixedSizeArray(descriptors_codec.bytes(hash_HASH_SIZE).asOpaque(), AUTHORIZATION_QUEUE_SIZE)),
11226
+ Codec: authQueuesCodec,
11125
11227
  extract: (s) => s.authQueues,
11126
11228
  };
11127
11229
  /**
@@ -11130,7 +11232,7 @@ var serialize;
11130
11232
  */
11131
11233
  serialize.recentBlocks = {
11132
11234
  key: stateKeys.index(StateKeyIdx.Beta),
11133
- Codec: RecentBlocksHistory.Codec,
11235
+ Codec: RecentBlocks.Codec,
11134
11236
  extract: (s) => s.recentBlocks,
11135
11237
  };
11136
11238
  /** C(4): https://graypaper.fluffylabs.dev/#/7e6ff6a/3b63013b6301?v=0.6.7 */
@@ -11159,25 +11261,25 @@ var serialize;
11159
11261
  /** C(7): https://graypaper.fluffylabs.dev/#/7e6ff6a/3b00023b0002?v=0.6.7 */
11160
11262
  serialize.designatedValidators = {
11161
11263
  key: stateKeys.index(StateKeyIdx.Iota),
11162
- Codec: codecPerValidator(ValidatorData.Codec),
11264
+ Codec: validatorsDataCodec,
11163
11265
  extract: (s) => s.designatedValidatorData,
11164
11266
  };
11165
11267
  /** C(8): https://graypaper.fluffylabs.dev/#/7e6ff6a/3b0d023b0d02?v=0.6.7 */
11166
11268
  serialize.currentValidators = {
11167
11269
  key: stateKeys.index(StateKeyIdx.Kappa),
11168
- Codec: codecPerValidator(ValidatorData.Codec),
11270
+ Codec: validatorsDataCodec,
11169
11271
  extract: (s) => s.currentValidatorData,
11170
11272
  };
11171
11273
  /** C(9): https://graypaper.fluffylabs.dev/#/7e6ff6a/3b1a023b1a02?v=0.6.7 */
11172
11274
  serialize.previousValidators = {
11173
11275
  key: stateKeys.index(StateKeyIdx.Lambda),
11174
- Codec: codecPerValidator(ValidatorData.Codec),
11276
+ Codec: validatorsDataCodec,
11175
11277
  extract: (s) => s.previousValidatorData,
11176
11278
  };
11177
11279
  /** C(10): https://graypaper.fluffylabs.dev/#/7e6ff6a/3b27023b2702?v=0.6.7 */
11178
11280
  serialize.availabilityAssignment = {
11179
11281
  key: stateKeys.index(StateKeyIdx.Rho),
11180
- Codec: codecPerCore(descriptors_codec.optional(AvailabilityAssignment.Codec)),
11282
+ Codec: availabilityAssignmentsCodec,
11181
11283
  extract: (s) => s.availabilityAssignment,
11182
11284
  };
11183
11285
  /** C(11): https://graypaper.fluffylabs.dev/#/7e6ff6a/3b3e023b3e02?v=0.6.7 */
@@ -11201,13 +11303,13 @@ var serialize;
11201
11303
  /** C(14): https://graypaper.fluffylabs.dev/#/1c979cb/3bf0023bf002?v=0.7.1 */
11202
11304
  serialize.accumulationQueue = {
11203
11305
  key: stateKeys.index(StateKeyIdx.Omega),
11204
- Codec: codecPerEpochBlock(readonlyArray(descriptors_codec.sequenceVarLen(NotYetAccumulatedReport.Codec))),
11306
+ Codec: accumulationQueueCodec,
11205
11307
  extract: (s) => s.accumulationQueue,
11206
11308
  };
11207
11309
  /** C(15): https://graypaper.fluffylabs.dev/#/7e6ff6a/3b96023b9602?v=0.6.7 */
11208
11310
  serialize.recentlyAccumulated = {
11209
11311
  key: stateKeys.index(StateKeyIdx.Xi),
11210
- Codec: codecPerEpochBlock(descriptors_codec.sequenceVarLen(descriptors_codec.bytes(hash_HASH_SIZE).asOpaque()).convert((x) => Array.from(x), (x) => HashSet.from(x))),
11312
+ Codec: recentlyAccumulatedCodec,
11211
11313
  extract: (s) => s.recentlyAccumulated,
11212
11314
  };
11213
11315
  /** C(16): https://graypaper.fluffylabs.dev/#/38c4e62/3b46033b4603?v=0.7.0 */
@@ -11236,9 +11338,9 @@ var serialize;
11236
11338
  /** https://graypaper.fluffylabs.dev/#/85129da/387603387603?v=0.6.3 */
11237
11339
  serialize.serviceLookupHistory = (blake2b, serviceId, hash, len) => ({
11238
11340
  key: stateKeys.serviceLookupHistory(blake2b, serviceId, hash, len),
11239
- Codec: readonlyArray(descriptors_codec.sequenceVarLen(descriptors_codec.u32)),
11341
+ Codec: descriptors_readonlyArray(descriptors_codec.sequenceVarLen(descriptors_codec.u32)),
11240
11342
  });
11241
- })(serialize || (serialize = {}));
11343
+ })(serialize_serialize || (serialize_serialize = {}));
11242
11344
  /**
11243
11345
  * Just dump the entire terminal blob as-is.
11244
11346
  *
@@ -11248,6 +11350,87 @@ var serialize;
11248
11350
  */
11249
11351
  const dumpCodec = Descriptor.new("Dump", { bytes: 64, isExact: false }, (e, v) => e.bytes(bytes_Bytes.fromBlob(v.raw, v.raw.length)), (d) => bytes_BytesBlob.blobFrom(d.bytes(d.source.length - d.bytesRead()).raw), (s) => s.bytes(s.decoder.source.length - s.decoder.bytesRead()));
11250
11352
 
11353
+ ;// CONCATENATED MODULE: ./packages/jam/state-merkleization/serialized-state-view.ts
11354
+
11355
+
11356
+ class SerializedStateView {
11357
+ spec;
11358
+ backend;
11359
+ recentlyUsedServices;
11360
+ viewCache;
11361
+ constructor(spec, backend,
11362
+ /** Best-effort list of recently active services. */
11363
+ recentlyUsedServices, viewCache) {
11364
+ this.spec = spec;
11365
+ this.backend = backend;
11366
+ this.recentlyUsedServices = recentlyUsedServices;
11367
+ this.viewCache = viewCache;
11368
+ }
11369
+ retrieveView({ key, Codec }, description) {
11370
+ const cached = this.viewCache.get(key);
11371
+ if (cached !== undefined) {
11372
+ return cached;
11373
+ }
11374
+ const bytes = this.backend.get(key);
11375
+ if (bytes === null) {
11376
+ throw new Error(`Required state entry for ${description} is missing!. Accessing view of key: ${key}`);
11377
+ }
11378
+ // NOTE [ToDr] we are not using `Decoder.decodeObject` here because
11379
+ // it needs to get to the end of the data (skip), yet that's expensive.
11380
+ // we assume that the state data is correct and coherent anyway, so
11381
+ // for performance reasons we simply create the view here.
11382
+ const d = decoder_Decoder.fromBytesBlob(bytes);
11383
+ d.attachContext(this.spec);
11384
+ const view = Codec.View.decode(d);
11385
+ this.viewCache.set(key, view);
11386
+ return view;
11387
+ }
11388
+ availabilityAssignmentView() {
11389
+ return this.retrieveView(serialize_serialize.availabilityAssignment, "availabilityAssignmentView");
11390
+ }
11391
+ designatedValidatorDataView() {
11392
+ return this.retrieveView(serialize_serialize.designatedValidators, "designatedValidatorsView");
11393
+ }
11394
+ currentValidatorDataView() {
11395
+ return this.retrieveView(serialize_serialize.currentValidators, "currentValidatorsView");
11396
+ }
11397
+ previousValidatorDataView() {
11398
+ return this.retrieveView(serialize_serialize.previousValidators, "previousValidatorsView");
11399
+ }
11400
+ authPoolsView() {
11401
+ return this.retrieveView(serialize_serialize.authPools, "authPoolsView");
11402
+ }
11403
+ authQueuesView() {
11404
+ return this.retrieveView(serialize_serialize.authQueues, "authQueuesView");
11405
+ }
11406
+ recentBlocksView() {
11407
+ return this.retrieveView(serialize_serialize.recentBlocks, "recentBlocksView");
11408
+ }
11409
+ statisticsView() {
11410
+ return this.retrieveView(serialize_serialize.statistics, "statisticsView");
11411
+ }
11412
+ accumulationQueueView() {
11413
+ return this.retrieveView(serialize_serialize.accumulationQueue, "accumulationQueueView");
11414
+ }
11415
+ recentlyAccumulatedView() {
11416
+ return this.retrieveView(serialize_serialize.recentlyAccumulated, "recentlyAccumulatedView");
11417
+ }
11418
+ safroleDataView() {
11419
+ return this.retrieveView(serialize_serialize.safrole, "safroleDataView");
11420
+ }
11421
+ getServiceInfoView(id) {
11422
+ const serviceData = serialize_serialize.serviceData(id);
11423
+ const bytes = this.backend.get(serviceData.key);
11424
+ if (bytes === null) {
11425
+ return null;
11426
+ }
11427
+ if (!this.recentlyUsedServices.includes(id)) {
11428
+ this.recentlyUsedServices.push(id);
11429
+ }
11430
+ return decoder_Decoder.decodeObject(serviceData.Codec.View, bytes, this.spec);
11431
+ }
11432
+ }
11433
+
11251
11434
  ;// CONCATENATED MODULE: ./packages/jam/state-merkleization/serialized-state.ts
11252
11435
 
11253
11436
 
@@ -11256,6 +11439,8 @@ const dumpCodec = Descriptor.new("Dump", { bytes: 64, isExact: false }, (e, v) =
11256
11439
 
11257
11440
 
11258
11441
 
11442
+
11443
+
11259
11444
  /**
11260
11445
  * State object which reads it's entries from some backend.
11261
11446
  *
@@ -11268,7 +11453,7 @@ class serialized_state_SerializedState {
11268
11453
  spec;
11269
11454
  blake2b;
11270
11455
  backend;
11271
- _recentServiceIds;
11456
+ recentlyUsedServices;
11272
11457
  /** Create a state-like object from collection of serialized entries. */
11273
11458
  static fromStateEntries(spec, blake2b, state, recentServices = []) {
11274
11459
  return new serialized_state_SerializedState(spec, blake2b, state, recentServices);
@@ -11277,106 +11462,120 @@ class serialized_state_SerializedState {
11277
11462
  static new(spec, blake2b, db, recentServices = []) {
11278
11463
  return new serialized_state_SerializedState(spec, blake2b, db, recentServices);
11279
11464
  }
11465
+ dataCache = hash_dictionary_HashDictionary.new();
11466
+ viewCache = hash_dictionary_HashDictionary.new();
11280
11467
  constructor(spec, blake2b, backend,
11281
11468
  /** Best-effort list of recently active services. */
11282
- _recentServiceIds) {
11469
+ recentlyUsedServices) {
11283
11470
  this.spec = spec;
11284
11471
  this.blake2b = blake2b;
11285
11472
  this.backend = backend;
11286
- this._recentServiceIds = _recentServiceIds;
11473
+ this.recentlyUsedServices = recentlyUsedServices;
11287
11474
  }
11288
11475
  /** Comparing the serialized states, just means comparing their backends. */
11289
11476
  [TEST_COMPARE_USING]() {
11290
11477
  return this.backend;
11291
11478
  }
11479
+ /** Return a non-decoding version of the state. */
11480
+ view() {
11481
+ return new SerializedStateView(this.spec, this.backend, this.recentlyUsedServices, this.viewCache);
11482
+ }
11292
11483
  // TODO [ToDr] Temporary method to update the state,
11293
11484
  // without changing references.
11294
11485
  updateBackend(newBackend) {
11295
11486
  this.backend = newBackend;
11487
+ this.dataCache = hash_dictionary_HashDictionary.new();
11488
+ this.viewCache = hash_dictionary_HashDictionary.new();
11296
11489
  }
11297
11490
  recentServiceIds() {
11298
- return this._recentServiceIds;
11491
+ return this.recentlyUsedServices;
11299
11492
  }
11300
11493
  getService(id) {
11301
- const serviceData = this.retrieveOptional(serialize.serviceData(id));
11494
+ const serviceData = this.retrieveOptional(serialize_serialize.serviceData(id));
11302
11495
  if (serviceData === undefined) {
11303
11496
  return null;
11304
11497
  }
11305
- if (!this._recentServiceIds.includes(id)) {
11306
- this._recentServiceIds.push(id);
11498
+ if (!this.recentlyUsedServices.includes(id)) {
11499
+ this.recentlyUsedServices.push(id);
11307
11500
  }
11308
11501
  return new SerializedService(this.blake2b, id, serviceData, (key) => this.retrieveOptional(key));
11309
11502
  }
11310
- retrieve({ key, Codec }, description) {
11311
- const bytes = this.backend.get(key);
11312
- if (bytes === null) {
11313
- throw new Error(`Required state entry for ${description} is missing!. Accessing key: ${key}`);
11503
+ retrieve(k, description) {
11504
+ const data = this.retrieveOptional(k);
11505
+ if (data === undefined) {
11506
+ throw new Error(`Required state entry for ${description} is missing!. Accessing key: ${k.key}`);
11314
11507
  }
11315
- return decoder_Decoder.decodeObject(Codec, bytes, this.spec);
11508
+ return data;
11316
11509
  }
11317
11510
  retrieveOptional({ key, Codec }) {
11511
+ const cached = this.dataCache.get(key);
11512
+ if (cached !== undefined) {
11513
+ return cached;
11514
+ }
11318
11515
  const bytes = this.backend.get(key);
11319
11516
  if (bytes === null) {
11320
11517
  return undefined;
11321
11518
  }
11322
- return decoder_Decoder.decodeObject(Codec, bytes, this.spec);
11519
+ const data = decoder_Decoder.decodeObject(Codec, bytes, this.spec);
11520
+ this.dataCache.set(key, data);
11521
+ return data;
11323
11522
  }
11324
11523
  get availabilityAssignment() {
11325
- return this.retrieve(serialize.availabilityAssignment, "availabilityAssignment");
11524
+ return this.retrieve(serialize_serialize.availabilityAssignment, "availabilityAssignment");
11326
11525
  }
11327
11526
  get designatedValidatorData() {
11328
- return this.retrieve(serialize.designatedValidators, "designatedValidatorData");
11527
+ return this.retrieve(serialize_serialize.designatedValidators, "designatedValidatorData");
11329
11528
  }
11330
11529
  get nextValidatorData() {
11331
- return this.retrieve(serialize.safrole, "safroleData.nextValidatorData").nextValidatorData;
11530
+ return this.retrieve(serialize_serialize.safrole, "safroleData.nextValidatorData").nextValidatorData;
11332
11531
  }
11333
11532
  get currentValidatorData() {
11334
- return this.retrieve(serialize.currentValidators, "currentValidators");
11533
+ return this.retrieve(serialize_serialize.currentValidators, "currentValidators");
11335
11534
  }
11336
11535
  get previousValidatorData() {
11337
- return this.retrieve(serialize.previousValidators, "previousValidators");
11536
+ return this.retrieve(serialize_serialize.previousValidators, "previousValidators");
11338
11537
  }
11339
11538
  get disputesRecords() {
11340
- return this.retrieve(serialize.disputesRecords, "disputesRecords");
11539
+ return this.retrieve(serialize_serialize.disputesRecords, "disputesRecords");
11341
11540
  }
11342
11541
  get timeslot() {
11343
- return this.retrieve(serialize.timeslot, "timeslot");
11542
+ return this.retrieve(serialize_serialize.timeslot, "timeslot");
11344
11543
  }
11345
11544
  get entropy() {
11346
- return this.retrieve(serialize.entropy, "entropy");
11545
+ return this.retrieve(serialize_serialize.entropy, "entropy");
11347
11546
  }
11348
11547
  get authPools() {
11349
- return this.retrieve(serialize.authPools, "authPools");
11548
+ return this.retrieve(serialize_serialize.authPools, "authPools");
11350
11549
  }
11351
11550
  get authQueues() {
11352
- return this.retrieve(serialize.authQueues, "authQueues");
11551
+ return this.retrieve(serialize_serialize.authQueues, "authQueues");
11353
11552
  }
11354
11553
  get recentBlocks() {
11355
- return this.retrieve(serialize.recentBlocks, "recentBlocks");
11554
+ return this.retrieve(serialize_serialize.recentBlocks, "recentBlocks");
11356
11555
  }
11357
11556
  get statistics() {
11358
- return this.retrieve(serialize.statistics, "statistics");
11557
+ return this.retrieve(serialize_serialize.statistics, "statistics");
11359
11558
  }
11360
11559
  get accumulationQueue() {
11361
- return this.retrieve(serialize.accumulationQueue, "accumulationQueue");
11560
+ return this.retrieve(serialize_serialize.accumulationQueue, "accumulationQueue");
11362
11561
  }
11363
11562
  get recentlyAccumulated() {
11364
- return this.retrieve(serialize.recentlyAccumulated, "recentlyAccumulated");
11563
+ return this.retrieve(serialize_serialize.recentlyAccumulated, "recentlyAccumulated");
11365
11564
  }
11366
11565
  get ticketsAccumulator() {
11367
- return this.retrieve(serialize.safrole, "safroleData.ticketsAccumulator").ticketsAccumulator;
11566
+ return this.retrieve(serialize_serialize.safrole, "safroleData.ticketsAccumulator").ticketsAccumulator;
11368
11567
  }
11369
11568
  get sealingKeySeries() {
11370
- return this.retrieve(serialize.safrole, "safrole.sealingKeySeries").sealingKeySeries;
11569
+ return this.retrieve(serialize_serialize.safrole, "safrole.sealingKeySeries").sealingKeySeries;
11371
11570
  }
11372
11571
  get epochRoot() {
11373
- return this.retrieve(serialize.safrole, "safrole.epochRoot").epochRoot;
11572
+ return this.retrieve(serialize_serialize.safrole, "safrole.epochRoot").epochRoot;
11374
11573
  }
11375
11574
  get privilegedServices() {
11376
- return this.retrieve(serialize.privilegedServices, "privilegedServices");
11575
+ return this.retrieve(serialize_serialize.privilegedServices, "privilegedServices");
11377
11576
  }
11378
11577
  get accumulationOutputLog() {
11379
- return this.retrieve(serialize.accumulationOutputLog, "accumulationOutputLog");
11578
+ return this.retrieve(serialize_serialize.accumulationOutputLog, "accumulationOutputLog");
11380
11579
  }
11381
11580
  }
11382
11581
  /** Service data representation on a serialized state. */
@@ -11405,9 +11604,9 @@ class SerializedService {
11405
11604
  serviceIdAndKey.set(numbers_u32AsLeBytes(this.serviceId));
11406
11605
  serviceIdAndKey.set(rawKey.raw, SERVICE_ID_BYTES);
11407
11606
  const key = opaque_asOpaqueType(bytes_BytesBlob.blobFrom(this.blake2b.hashBytes(serviceIdAndKey).raw));
11408
- return this.retrieveOptional(serialize.serviceStorage(this.blake2b, this.serviceId, key)) ?? null;
11607
+ return this.retrieveOptional(serialize_serialize.serviceStorage(this.blake2b, this.serviceId, key)) ?? null;
11409
11608
  }
11410
- return this.retrieveOptional(serialize.serviceStorage(this.blake2b, this.serviceId, rawKey)) ?? null;
11609
+ return this.retrieveOptional(serialize_serialize.serviceStorage(this.blake2b, this.serviceId, rawKey)) ?? null;
11411
11610
  }
11412
11611
  /**
11413
11612
  * Check if preimage is present in the DB.
@@ -11416,15 +11615,15 @@ class SerializedService {
11416
11615
  */
11417
11616
  hasPreimage(hash) {
11418
11617
  // TODO [ToDr] consider optimizing to avoid fetching the whole data.
11419
- return this.retrieveOptional(serialize.servicePreimages(this.blake2b, this.serviceId, hash)) !== undefined;
11618
+ return this.retrieveOptional(serialize_serialize.servicePreimages(this.blake2b, this.serviceId, hash)) !== undefined;
11420
11619
  }
11421
11620
  /** Retrieve preimage from the DB. */
11422
11621
  getPreimage(hash) {
11423
- return this.retrieveOptional(serialize.servicePreimages(this.blake2b, this.serviceId, hash)) ?? null;
11622
+ return this.retrieveOptional(serialize_serialize.servicePreimages(this.blake2b, this.serviceId, hash)) ?? null;
11424
11623
  }
11425
11624
  /** Retrieve preimage lookup history. */
11426
11625
  getLookupHistory(hash, len) {
11427
- const rawSlots = this.retrieveOptional(serialize.serviceLookupHistory(this.blake2b, this.serviceId, hash, len));
11626
+ const rawSlots = this.retrieveOptional(serialize_serialize.serviceLookupHistory(this.blake2b, this.serviceId, hash, len));
11428
11627
  if (rawSlots === undefined) {
11429
11628
  return null;
11430
11629
  }
@@ -12089,7 +12288,6 @@ function getKeccakTrieHasher(hasher) {
12089
12288
 
12090
12289
 
12091
12290
 
12092
-
12093
12291
  /** What should be done with that key? */
12094
12292
  var StateEntryUpdateAction;
12095
12293
  (function (StateEntryUpdateAction) {
@@ -12105,83 +12303,95 @@ function* serializeStateUpdate(spec, blake2b, update) {
12105
12303
  yield* serializeBasicKeys(spec, update);
12106
12304
  const encode = (codec, val) => encoder_Encoder.encodeObject(codec, val, spec);
12107
12305
  // then let's proceed with service updates
12108
- yield* serializeServiceUpdates(update.servicesUpdates, encode, blake2b);
12306
+ yield* serializeServiceUpdates(update.updated, encode, blake2b);
12109
12307
  yield* serializePreimages(update.preimages, encode, blake2b);
12110
12308
  yield* serializeStorage(update.storage, blake2b);
12111
- yield* serializeRemovedServices(update.servicesRemoved);
12309
+ yield* serializeRemovedServices(update.removed);
12112
12310
  }
12113
12311
  function* serializeRemovedServices(servicesRemoved) {
12114
- for (const serviceId of servicesRemoved ?? []) {
12312
+ if (servicesRemoved === undefined) {
12313
+ return;
12314
+ }
12315
+ for (const serviceId of servicesRemoved) {
12115
12316
  // TODO [ToDr] what about all data associated with a service?
12116
- const codec = serialize.serviceData(serviceId);
12317
+ const codec = serialize_serialize.serviceData(serviceId);
12117
12318
  yield [StateEntryUpdateAction.Remove, codec.key, EMPTY_BLOB];
12118
12319
  }
12119
12320
  }
12120
- function* serializeStorage(storage, blake2b) {
12121
- for (const { action, serviceId } of storage ?? []) {
12122
- switch (action.kind) {
12123
- case UpdateStorageKind.Set: {
12124
- const key = action.storage.key;
12125
- const codec = serialize.serviceStorage(blake2b, serviceId, key);
12126
- yield [StateEntryUpdateAction.Insert, codec.key, action.storage.value];
12127
- break;
12128
- }
12129
- case UpdateStorageKind.Remove: {
12130
- const key = action.key;
12131
- const codec = serialize.serviceStorage(blake2b, serviceId, key);
12132
- yield [StateEntryUpdateAction.Remove, codec.key, EMPTY_BLOB];
12133
- break;
12321
+ function* serializeStorage(storageUpdates, blake2b) {
12322
+ if (storageUpdates === undefined) {
12323
+ return;
12324
+ }
12325
+ for (const [serviceId, updates] of storageUpdates.entries()) {
12326
+ for (const { action } of updates) {
12327
+ switch (action.kind) {
12328
+ case UpdateStorageKind.Set: {
12329
+ const key = action.storage.key;
12330
+ const codec = serialize_serialize.serviceStorage(blake2b, serviceId, key);
12331
+ yield [StateEntryUpdateAction.Insert, codec.key, action.storage.value];
12332
+ break;
12333
+ }
12334
+ case UpdateStorageKind.Remove: {
12335
+ const key = action.key;
12336
+ const codec = serialize_serialize.serviceStorage(blake2b, serviceId, key);
12337
+ yield [StateEntryUpdateAction.Remove, codec.key, EMPTY_BLOB];
12338
+ break;
12339
+ }
12134
12340
  }
12135
- default:
12136
- debug_assertNever(action);
12137
12341
  }
12138
12342
  }
12139
12343
  }
12140
- function* serializePreimages(preimages, encode, blake2b) {
12141
- for (const { action, serviceId } of preimages ?? []) {
12142
- switch (action.kind) {
12143
- case UpdatePreimageKind.Provide: {
12144
- const { hash, blob } = action.preimage;
12145
- const codec = serialize.servicePreimages(blake2b, serviceId, hash);
12146
- yield [StateEntryUpdateAction.Insert, codec.key, blob];
12147
- if (action.slot !== null) {
12148
- const codec2 = serialize.serviceLookupHistory(blake2b, serviceId, hash, numbers_tryAsU32(blob.length));
12149
- yield [
12150
- StateEntryUpdateAction.Insert,
12151
- codec2.key,
12152
- encode(codec2.Codec, tryAsLookupHistorySlots([action.slot])),
12153
- ];
12344
+ function* serializePreimages(preimagesUpdates, encode, blake2b) {
12345
+ if (preimagesUpdates === undefined) {
12346
+ return;
12347
+ }
12348
+ for (const [serviceId, updates] of preimagesUpdates.entries()) {
12349
+ for (const { action } of updates) {
12350
+ switch (action.kind) {
12351
+ case UpdatePreimageKind.Provide: {
12352
+ const { hash, blob } = action.preimage;
12353
+ const codec = serialize_serialize.servicePreimages(blake2b, serviceId, hash);
12354
+ yield [StateEntryUpdateAction.Insert, codec.key, blob];
12355
+ if (action.slot !== null) {
12356
+ const codec2 = serialize_serialize.serviceLookupHistory(blake2b, serviceId, hash, numbers_tryAsU32(blob.length));
12357
+ yield [
12358
+ StateEntryUpdateAction.Insert,
12359
+ codec2.key,
12360
+ encode(codec2.Codec, tryAsLookupHistorySlots([action.slot])),
12361
+ ];
12362
+ }
12363
+ break;
12364
+ }
12365
+ case UpdatePreimageKind.UpdateOrAdd: {
12366
+ const { hash, length, slots } = action.item;
12367
+ const codec = serialize_serialize.serviceLookupHistory(blake2b, serviceId, hash, length);
12368
+ yield [StateEntryUpdateAction.Insert, codec.key, encode(codec.Codec, slots)];
12369
+ break;
12370
+ }
12371
+ case UpdatePreimageKind.Remove: {
12372
+ const { hash, length } = action;
12373
+ const codec = serialize_serialize.servicePreimages(blake2b, serviceId, hash);
12374
+ yield [StateEntryUpdateAction.Remove, codec.key, EMPTY_BLOB];
12375
+ const codec2 = serialize_serialize.serviceLookupHistory(blake2b, serviceId, hash, length);
12376
+ yield [StateEntryUpdateAction.Remove, codec2.key, EMPTY_BLOB];
12377
+ break;
12154
12378
  }
12155
- break;
12156
- }
12157
- case UpdatePreimageKind.UpdateOrAdd: {
12158
- const { hash, length, slots } = action.item;
12159
- const codec = serialize.serviceLookupHistory(blake2b, serviceId, hash, length);
12160
- yield [StateEntryUpdateAction.Insert, codec.key, encode(codec.Codec, slots)];
12161
- break;
12162
- }
12163
- case UpdatePreimageKind.Remove: {
12164
- const { hash, length } = action;
12165
- const codec = serialize.servicePreimages(blake2b, serviceId, hash);
12166
- yield [StateEntryUpdateAction.Remove, codec.key, EMPTY_BLOB];
12167
- const codec2 = serialize.serviceLookupHistory(blake2b, serviceId, hash, length);
12168
- yield [StateEntryUpdateAction.Remove, codec2.key, EMPTY_BLOB];
12169
- break;
12170
12379
  }
12171
- default:
12172
- debug_assertNever(action);
12173
12380
  }
12174
12381
  }
12175
12382
  }
12176
12383
  function* serializeServiceUpdates(servicesUpdates, encode, blake2b) {
12177
- for (const { action, serviceId } of servicesUpdates ?? []) {
12384
+ if (servicesUpdates === undefined) {
12385
+ return;
12386
+ }
12387
+ for (const [serviceId, { action }] of servicesUpdates.entries()) {
12178
12388
  // new service being created or updated
12179
- const codec = serialize.serviceData(serviceId);
12389
+ const codec = serialize_serialize.serviceData(serviceId);
12180
12390
  yield [StateEntryUpdateAction.Insert, codec.key, encode(codec.Codec, action.account)];
12181
12391
  // additional lookup history update
12182
12392
  if (action.kind === UpdateServiceKind.Create && action.lookupHistory !== null) {
12183
12393
  const { lookupHistory } = action;
12184
- const codec2 = serialize.serviceLookupHistory(blake2b, serviceId, lookupHistory.hash, lookupHistory.length);
12394
+ const codec2 = serialize_serialize.serviceLookupHistory(blake2b, serviceId, lookupHistory.hash, lookupHistory.length);
12185
12395
  yield [StateEntryUpdateAction.Insert, codec2.key, encode(codec2.Codec, lookupHistory.slots)];
12186
12396
  }
12187
12397
  }
@@ -12191,53 +12401,53 @@ function* serializeBasicKeys(spec, update) {
12191
12401
  return [StateEntryUpdateAction.Insert, codec.key, encoder_Encoder.encodeObject(codec.Codec, val, spec)];
12192
12402
  }
12193
12403
  if (update.authPools !== undefined) {
12194
- yield doSerialize(update.authPools, serialize.authPools); // C(1)
12404
+ yield doSerialize(update.authPools, serialize_serialize.authPools); // C(1)
12195
12405
  }
12196
12406
  if (update.authQueues !== undefined) {
12197
- yield doSerialize(update.authQueues, serialize.authQueues); // C(2)
12407
+ yield doSerialize(update.authQueues, serialize_serialize.authQueues); // C(2)
12198
12408
  }
12199
12409
  if (update.recentBlocks !== undefined) {
12200
- yield doSerialize(update.recentBlocks, serialize.recentBlocks); // C(3)
12410
+ yield doSerialize(update.recentBlocks, serialize_serialize.recentBlocks); // C(3)
12201
12411
  }
12202
12412
  const safroleData = getSafroleData(update.nextValidatorData, update.epochRoot, update.sealingKeySeries, update.ticketsAccumulator);
12203
12413
  if (safroleData !== undefined) {
12204
- yield doSerialize(safroleData, serialize.safrole); // C(4)
12414
+ yield doSerialize(safroleData, serialize_serialize.safrole); // C(4)
12205
12415
  }
12206
12416
  if (update.disputesRecords !== undefined) {
12207
- yield doSerialize(update.disputesRecords, serialize.disputesRecords); // C(5)
12417
+ yield doSerialize(update.disputesRecords, serialize_serialize.disputesRecords); // C(5)
12208
12418
  }
12209
12419
  if (update.entropy !== undefined) {
12210
- yield doSerialize(update.entropy, serialize.entropy); // C(6)
12420
+ yield doSerialize(update.entropy, serialize_serialize.entropy); // C(6)
12211
12421
  }
12212
12422
  if (update.designatedValidatorData !== undefined) {
12213
- yield doSerialize(update.designatedValidatorData, serialize.designatedValidators); // C(7)
12423
+ yield doSerialize(update.designatedValidatorData, serialize_serialize.designatedValidators); // C(7)
12214
12424
  }
12215
12425
  if (update.currentValidatorData !== undefined) {
12216
- yield doSerialize(update.currentValidatorData, serialize.currentValidators); // C(8)
12426
+ yield doSerialize(update.currentValidatorData, serialize_serialize.currentValidators); // C(8)
12217
12427
  }
12218
12428
  if (update.previousValidatorData !== undefined) {
12219
- yield doSerialize(update.previousValidatorData, serialize.previousValidators); // C(9)
12429
+ yield doSerialize(update.previousValidatorData, serialize_serialize.previousValidators); // C(9)
12220
12430
  }
12221
12431
  if (update.availabilityAssignment !== undefined) {
12222
- yield doSerialize(update.availabilityAssignment, serialize.availabilityAssignment); // C(10)
12432
+ yield doSerialize(update.availabilityAssignment, serialize_serialize.availabilityAssignment); // C(10)
12223
12433
  }
12224
12434
  if (update.timeslot !== undefined) {
12225
- yield doSerialize(update.timeslot, serialize.timeslot); // C(11)
12435
+ yield doSerialize(update.timeslot, serialize_serialize.timeslot); // C(11)
12226
12436
  }
12227
12437
  if (update.privilegedServices !== undefined) {
12228
- yield doSerialize(update.privilegedServices, serialize.privilegedServices); // C(12)
12438
+ yield doSerialize(update.privilegedServices, serialize_serialize.privilegedServices); // C(12)
12229
12439
  }
12230
12440
  if (update.statistics !== undefined) {
12231
- yield doSerialize(update.statistics, serialize.statistics); // C(13)
12441
+ yield doSerialize(update.statistics, serialize_serialize.statistics); // C(13)
12232
12442
  }
12233
12443
  if (update.accumulationQueue !== undefined) {
12234
- yield doSerialize(update.accumulationQueue, serialize.accumulationQueue); // C(14)
12444
+ yield doSerialize(update.accumulationQueue, serialize_serialize.accumulationQueue); // C(14)
12235
12445
  }
12236
12446
  if (update.recentlyAccumulated !== undefined) {
12237
- yield doSerialize(update.recentlyAccumulated, serialize.recentlyAccumulated); // C(15)
12447
+ yield doSerialize(update.recentlyAccumulated, serialize_serialize.recentlyAccumulated); // C(15)
12238
12448
  }
12239
12449
  if (update.accumulationOutputLog !== undefined) {
12240
- yield doSerialize(update.accumulationOutputLog, serialize.accumulationOutputLog); // C(16)
12450
+ yield doSerialize(update.accumulationOutputLog, serialize_serialize.accumulationOutputLog); // C(16)
12241
12451
  }
12242
12452
  }
12243
12453
  function getSafroleData(nextValidatorData, epochRoot, sealingKeySeries, ticketsAccumulator) {
@@ -12350,41 +12560,41 @@ function convertInMemoryStateToDictionary(spec, blake2b, state) {
12350
12560
  function doSerialize(codec) {
12351
12561
  serialized.set(codec.key, encoder_Encoder.encodeObject(codec.Codec, codec.extract(state), spec));
12352
12562
  }
12353
- doSerialize(serialize.authPools); // C(1)
12354
- doSerialize(serialize.authQueues); // C(2)
12355
- doSerialize(serialize.recentBlocks); // C(3)
12356
- doSerialize(serialize.safrole); // C(4)
12357
- doSerialize(serialize.disputesRecords); // C(5)
12358
- doSerialize(serialize.entropy); // C(6)
12359
- doSerialize(serialize.designatedValidators); // C(7)
12360
- doSerialize(serialize.currentValidators); // C(8)
12361
- doSerialize(serialize.previousValidators); // C(9)
12362
- doSerialize(serialize.availabilityAssignment); // C(10)
12363
- doSerialize(serialize.timeslot); // C(11)
12364
- doSerialize(serialize.privilegedServices); // C(12)
12365
- doSerialize(serialize.statistics); // C(13)
12366
- doSerialize(serialize.accumulationQueue); // C(14)
12367
- doSerialize(serialize.recentlyAccumulated); // C(15)
12368
- doSerialize(serialize.accumulationOutputLog); // C(16)
12563
+ doSerialize(serialize_serialize.authPools); // C(1)
12564
+ doSerialize(serialize_serialize.authQueues); // C(2)
12565
+ doSerialize(serialize_serialize.recentBlocks); // C(3)
12566
+ doSerialize(serialize_serialize.safrole); // C(4)
12567
+ doSerialize(serialize_serialize.disputesRecords); // C(5)
12568
+ doSerialize(serialize_serialize.entropy); // C(6)
12569
+ doSerialize(serialize_serialize.designatedValidators); // C(7)
12570
+ doSerialize(serialize_serialize.currentValidators); // C(8)
12571
+ doSerialize(serialize_serialize.previousValidators); // C(9)
12572
+ doSerialize(serialize_serialize.availabilityAssignment); // C(10)
12573
+ doSerialize(serialize_serialize.timeslot); // C(11)
12574
+ doSerialize(serialize_serialize.privilegedServices); // C(12)
12575
+ doSerialize(serialize_serialize.statistics); // C(13)
12576
+ doSerialize(serialize_serialize.accumulationQueue); // C(14)
12577
+ doSerialize(serialize_serialize.recentlyAccumulated); // C(15)
12578
+ doSerialize(serialize_serialize.accumulationOutputLog); // C(16)
12369
12579
  // services
12370
12580
  for (const [serviceId, service] of state.services.entries()) {
12371
12581
  // data
12372
- const { key, Codec } = serialize.serviceData(serviceId);
12582
+ const { key, Codec } = serialize_serialize.serviceData(serviceId);
12373
12583
  serialized.set(key, encoder_Encoder.encodeObject(Codec, service.getInfo()));
12374
12584
  // preimages
12375
12585
  for (const preimage of service.data.preimages.values()) {
12376
- const { key, Codec } = serialize.servicePreimages(blake2b, serviceId, preimage.hash);
12586
+ const { key, Codec } = serialize_serialize.servicePreimages(blake2b, serviceId, preimage.hash);
12377
12587
  serialized.set(key, encoder_Encoder.encodeObject(Codec, preimage.blob));
12378
12588
  }
12379
12589
  // storage
12380
12590
  for (const storage of service.data.storage.values()) {
12381
- const { key, Codec } = serialize.serviceStorage(blake2b, serviceId, storage.key);
12591
+ const { key, Codec } = serialize_serialize.serviceStorage(blake2b, serviceId, storage.key);
12382
12592
  serialized.set(key, encoder_Encoder.encodeObject(Codec, storage.value));
12383
12593
  }
12384
12594
  // lookup history
12385
12595
  for (const lookupHistoryList of service.data.lookupHistory.values()) {
12386
12596
  for (const lookupHistory of lookupHistoryList) {
12387
- const { key, Codec } = serialize.serviceLookupHistory(blake2b, serviceId, lookupHistory.hash, lookupHistory.length);
12597
+ const { key, Codec } = serialize_serialize.serviceLookupHistory(blake2b, serviceId, lookupHistory.hash, lookupHistory.length);
12388
12598
  serialized.set(key, encoder_Encoder.encodeObject(Codec, lookupHistory.slots.slice()));
12389
12599
  }
12390
12600
  }
@@ -12434,6 +12644,7 @@ function loadState(spec, blake2b, entries) {
12434
12644
 
12435
12645
 
12436
12646
 
12647
+
12437
12648
  ;// CONCATENATED MODULE: ./packages/jam/database/leaf-db.ts
12438
12649
 
12439
12650
 
@@ -12460,13 +12671,13 @@ class LeafDb {
12460
12671
  */
12461
12672
  static fromLeavesBlob(blob, db) {
12462
12673
  if (blob.length % TRIE_NODE_BYTES !== 0) {
12463
- return result_Result.error(LeafDbError.InvalidLeafData, `${blob.length} is not a multiply of ${TRIE_NODE_BYTES}: ${blob}`);
12674
+ return result_Result.error(LeafDbError.InvalidLeafData, () => `${blob.length} is not a multiply of ${TRIE_NODE_BYTES}: ${blob}`);
12464
12675
  }
12465
12676
  const leaves = SortedSet.fromArray(leafComparator, []);
12466
12677
  for (const nodeData of blob.chunks(TRIE_NODE_BYTES)) {
12467
12678
  const node = new TrieNode(nodeData.raw);
12468
12679
  if (node.getNodeType() === NodeType.Branch) {
12469
- return result_Result.error(LeafDbError.InvalidLeafData, `Branch node detected: ${nodeData}`);
12680
+ return result_Result.error(LeafDbError.InvalidLeafData, () => `Branch node detected: ${nodeData}`);
12470
12681
  }
12471
12682
  leaves.insert(node.asLeafNode());
12472
12683
  }
@@ -12592,7 +12803,7 @@ const codecMap = (value, extractKey, { typicalLength = TYPICAL_DICTIONARY_LENGTH
12592
12803
  const lookupHistoryItemCodec = descriptors_codec.object({
12593
12804
  hash: descriptors_codec.bytes(hash_HASH_SIZE).asOpaque(),
12594
12805
  length: descriptors_codec.u32,
12595
- slots: readonlyArray(descriptors_codec.sequenceVarLen(descriptors_codec.u32.asOpaque())).convert(seeThrough, tryAsLookupHistorySlots),
12806
+ slots: descriptors_readonlyArray(descriptors_codec.sequenceVarLen(descriptors_codec.u32.asOpaque())).convert(seeThrough, tryAsLookupHistorySlots),
12596
12807
  }, "LookupHistoryItem", ({ hash, length, slots }) => new LookupHistoryItem(hash, length, slots));
12597
12808
  const lookupHistoryEntryCodec = descriptors_codec.object({
12598
12809
  key: descriptors_codec.bytes(hash_HASH_SIZE).asOpaque(),
@@ -12635,7 +12846,11 @@ class ServiceWithCodec extends InMemoryService {
12635
12846
  return new ServiceWithCodec(serviceId, data);
12636
12847
  }
12637
12848
  }
12638
- const in_memory_state_codec_inMemoryStateCodec = descriptors_codec.Class(InMemoryState, {
12849
+ const in_memory_state_codec_inMemoryStateCodec = (spec) => codec.Class(class State extends InMemoryState {
12850
+ static create(data) {
12851
+ return InMemoryState.new(spec, data);
12852
+ }
12853
+ }, {
12639
12854
  // alpha
12640
12855
  authPools: serialize.authPools.Codec,
12641
12856
  // phi
@@ -12645,11 +12860,11 @@ const in_memory_state_codec_inMemoryStateCodec = descriptors_codec.Class(InMemor
12645
12860
  // gamma_k
12646
12861
  nextValidatorData: codecPerValidator(ValidatorData.Codec),
12647
12862
  // gamma_z
12648
- epochRoot: descriptors_codec.bytes(BANDERSNATCH_RING_ROOT_BYTES).asOpaque(),
12863
+ epochRoot: codec.bytes(BANDERSNATCH_RING_ROOT_BYTES).asOpaque(),
12649
12864
  // gamma_s
12650
12865
  sealingKeySeries: SafroleSealingKeysData.Codec,
12651
12866
  // gamma_a
12652
- ticketsAccumulator: readonlyArray(descriptors_codec.sequenceVarLen(Ticket.Codec)).convert((x) => x, sized_array_asKnownSize),
12867
+ ticketsAccumulator: readonlyArray(codec.sequenceVarLen(Ticket.Codec)).convert((x) => x, asKnownSize),
12653
12868
  // psi
12654
12869
  disputesRecords: serialize.disputesRecords.Codec,
12655
12870
  // eta
@@ -12675,7 +12890,7 @@ const in_memory_state_codec_inMemoryStateCodec = descriptors_codec.Class(InMemor
12675
12890
  // theta
12676
12891
  accumulationOutputLog: serialize.accumulationOutputLog.Codec,
12677
12892
  // delta
12678
- services: descriptors_codec.dictionary(descriptors_codec.u32.asOpaque(), ServiceWithCodec.Codec, {
12893
+ services: codec.dictionary(codec.u32.asOpaque(), ServiceWithCodec.Codec, {
12679
12894
  sortKeys: (a, b) => a - b,
12680
12895
  }),
12681
12896
  });
@@ -12722,7 +12937,7 @@ class InMemoryStates {
12722
12937
  }
12723
12938
  /** Insert a full state into the database. */
12724
12939
  async insertState(headerHash, state) {
12725
- const encoded = Encoder.encodeObject(inMemoryStateCodec, state, this.spec);
12940
+ const encoded = Encoder.encodeObject(inMemoryStateCodec(this.spec), state, this.spec);
12726
12941
  this.db.set(headerHash, encoded);
12727
12942
  return Result.ok(OK);
12728
12943
  }
@@ -12731,7 +12946,7 @@ class InMemoryStates {
12731
12946
  if (encodedState === undefined) {
12732
12947
  return null;
12733
12948
  }
12734
- return Decoder.decodeObject(inMemoryStateCodec, encodedState, this.spec);
12949
+ return Decoder.decodeObject(inMemoryStateCodec(this.spec), encodedState, this.spec);
12735
12950
  }
12736
12951
  }
12737
12952
 
@@ -13181,7 +13396,7 @@ class LmdbStates {
13181
13396
  }
13182
13397
  catch (e) {
13183
13398
  logger.error `${e}`;
13184
- return result_Result.error(StateUpdateError.Commit);
13399
+ return result_Result.error(StateUpdateError.Commit, () => `Failed to commit state update: ${e}`);
13185
13400
  }
13186
13401
  return result_Result.ok(result_OK);
13187
13402
  }
@@ -13839,21 +14054,21 @@ class TransitionHasher {
13839
14054
  */
13840
14055
  extrinsic(extrinsicView) {
13841
14056
  // https://graypaper.fluffylabs.dev/#/cc517d7/0cfb000cfb00?v=0.6.5
13842
- const guarantees = extrinsicView.guarantees
14057
+ const guaranteesCount = numbers_tryAsU32(extrinsicView.guarantees.view().length);
14058
+ const countEncoded = encoder_Encoder.encodeObject(descriptors_codec.varU32, guaranteesCount);
14059
+ const guaranteesBlobs = extrinsicView.guarantees
13843
14060
  .view()
13844
14061
  .map((g) => g.view())
13845
- .map((guarantee) => {
14062
+ .reduce((aggregated, guarantee) => {
13846
14063
  const reportHash = this.blake2b.hashBytes(guarantee.report.encoded()).asOpaque();
13847
- return bytes_BytesBlob.blobFromParts([
13848
- reportHash.raw,
13849
- guarantee.slot.encoded().raw,
13850
- guarantee.credentials.encoded().raw,
13851
- ]);
13852
- });
13853
- const guaranteeBlob = encoder_Encoder.encodeObject(descriptors_codec.sequenceVarLen(dumpCodec), guarantees, this.context);
14064
+ aggregated.push(reportHash.raw);
14065
+ aggregated.push(guarantee.slot.encoded().raw);
14066
+ aggregated.push(guarantee.credentials.encoded().raw);
14067
+ return aggregated;
14068
+ }, [countEncoded.raw]);
13854
14069
  const et = this.blake2b.hashBytes(extrinsicView.tickets.encoded()).asOpaque();
13855
14070
  const ep = this.blake2b.hashBytes(extrinsicView.preimages.encoded()).asOpaque();
13856
- const eg = this.blake2b.hashBytes(guaranteeBlob).asOpaque();
14071
+ const eg = this.blake2b.hashBlobs(guaranteesBlobs).asOpaque();
13857
14072
  const ea = this.blake2b.hashBytes(extrinsicView.assurances.encoded()).asOpaque();
13858
14073
  const ed = this.blake2b.hashBytes(extrinsicView.disputes.encoded()).asOpaque();
13859
14074
  const encoded = bytes_BytesBlob.blobFromParts([et.raw, ep.raw, eg.raw, ea.raw, ed.raw]);
@@ -13901,32 +14116,33 @@ class Preimages {
13901
14116
  }
13902
14117
  if (prevPreimage.requester > currPreimage.requester ||
13903
14118
  currPreimage.blob.compare(prevPreimage.blob).isLessOrEqual()) {
13904
- return result_Result.error(PreimagesErrorCode.PreimagesNotSortedUnique);
14119
+ return result_Result.error(PreimagesErrorCode.PreimagesNotSortedUnique, () => `Preimages not sorted/unique at index ${i}`);
13905
14120
  }
13906
14121
  }
13907
14122
  const { preimages, slot } = input;
13908
- const pendingChanges = [];
14123
+ const pendingChanges = new Map();
13909
14124
  // select preimages for integration
13910
14125
  for (const preimage of preimages) {
13911
14126
  const { requester, blob } = preimage;
13912
14127
  const hash = this.blake2b.hashBytes(blob).asOpaque();
13913
14128
  const service = this.state.getService(requester);
13914
14129
  if (service === null) {
13915
- return result_Result.error(PreimagesErrorCode.AccountNotFound);
14130
+ return result_Result.error(PreimagesErrorCode.AccountNotFound, () => `Service not found: ${requester}`);
13916
14131
  }
13917
14132
  const hasPreimage = service.hasPreimage(hash);
13918
14133
  const slots = service.getLookupHistory(hash, numbers_tryAsU32(blob.length));
13919
14134
  // https://graypaper.fluffylabs.dev/#/5f542d7/181800181900
13920
14135
  // https://graypaper.fluffylabs.dev/#/5f542d7/116f0011a500
13921
14136
  if (hasPreimage || slots === null || !LookupHistoryItem.isRequested(slots)) {
13922
- return result_Result.error(PreimagesErrorCode.PreimageUnneeded);
14137
+ return result_Result.error(PreimagesErrorCode.PreimageUnneeded, () => `Preimage unneeded: requester=${requester}, hash=${hash}, hasPreimage=${hasPreimage}, isRequested=${slots !== null && LookupHistoryItem.isRequested(slots)}`);
13923
14138
  }
13924
14139
  // https://graypaper.fluffylabs.dev/#/5f542d7/18c00018f300
13925
- pendingChanges.push(UpdatePreimage.provide({
13926
- serviceId: requester,
14140
+ const updates = pendingChanges.get(requester) ?? [];
14141
+ updates.push(UpdatePreimage.provide({
13927
14142
  preimage: PreimageItem.create({ hash, blob }),
13928
14143
  slot,
13929
14144
  }));
14145
+ pendingChanges.set(requester, updates);
13930
14146
  }
13931
14147
  return result_Result.ok({
13932
14148
  preimages: pendingChanges,
@@ -13964,7 +14180,7 @@ class BlockVerifier {
13964
14180
  const headerHash = this.hasher.header(headerView);
13965
14181
  // check if current block is already imported
13966
14182
  if (this.blocks.getHeader(headerHash.hash) !== null) {
13967
- return result_Result.error(BlockVerifierError.AlreadyImported, `Block ${headerHash.hash} is already imported.`);
14183
+ return result_Result.error(BlockVerifierError.AlreadyImported, () => `Block ${headerHash.hash} is already imported.`);
13968
14184
  }
13969
14185
  // Check if parent block exists.
13970
14186
  // https://graypaper.fluffylabs.dev/#/cc517d7/0c82000c8200?v=0.6.5
@@ -13974,14 +14190,14 @@ class BlockVerifier {
13974
14190
  if (!parentHash.isEqualTo(block_verifier_ZERO_HASH)) {
13975
14191
  const parentBlock = this.blocks.getHeader(parentHash);
13976
14192
  if (parentBlock === null) {
13977
- return result_Result.error(BlockVerifierError.ParentNotFound, `Parent ${parentHash.toString()} not found`);
14193
+ return result_Result.error(BlockVerifierError.ParentNotFound, () => `Parent ${parentHash.toString()} not found`);
13978
14194
  }
13979
14195
  // Check if the time slot index is consecutive and not from future.
13980
14196
  // https://graypaper.fluffylabs.dev/#/cc517d7/0c02010c0201?v=0.6.5
13981
14197
  const timeslot = headerView.timeSlotIndex.materialize();
13982
14198
  const parentTimeslot = parentBlock.timeSlotIndex.materialize();
13983
14199
  if (timeslot <= parentTimeslot) {
13984
- return result_Result.error(BlockVerifierError.InvalidTimeSlot, `Invalid time slot index: ${timeslot}, expected > ${parentTimeslot}`);
14200
+ return result_Result.error(BlockVerifierError.InvalidTimeSlot, () => `Invalid time slot index: ${timeslot}, expected > ${parentTimeslot}`);
13985
14201
  }
13986
14202
  }
13987
14203
  // Check if extrinsic is valid.
@@ -13989,17 +14205,17 @@ class BlockVerifier {
13989
14205
  const extrinsicHash = headerView.extrinsicHash.materialize();
13990
14206
  const extrinsicMerkleCommitment = this.hasher.extrinsic(block.extrinsic.view());
13991
14207
  if (!extrinsicHash.isEqualTo(extrinsicMerkleCommitment.hash)) {
13992
- return result_Result.error(BlockVerifierError.InvalidExtrinsic, `Invalid extrinsic hash: ${extrinsicHash.toString()}, expected ${extrinsicMerkleCommitment.hash.toString()}`);
14208
+ return result_Result.error(BlockVerifierError.InvalidExtrinsic, () => `Invalid extrinsic hash: ${extrinsicHash.toString()}, expected ${extrinsicMerkleCommitment.hash.toString()}`);
13993
14209
  }
13994
14210
  // Check if the state root is valid.
13995
14211
  // https://graypaper.fluffylabs.dev/#/cc517d7/0c18010c1801?v=0.6.5
13996
14212
  const stateRoot = headerView.priorStateRoot.materialize();
13997
14213
  const posteriorStateRoot = this.blocks.getPostStateRoot(parentHash);
13998
14214
  if (posteriorStateRoot === null) {
13999
- return result_Result.error(BlockVerifierError.StateRootNotFound, `Posterior state root ${parentHash.toString()} not found`);
14215
+ return result_Result.error(BlockVerifierError.StateRootNotFound, () => `Posterior state root ${parentHash.toString()} not found`);
14000
14216
  }
14001
14217
  if (!stateRoot.isEqualTo(posteriorStateRoot)) {
14002
- return result_Result.error(BlockVerifierError.InvalidStateRoot, `Invalid prior state root: ${stateRoot.toString()}, expected ${posteriorStateRoot.toString()} (ours)`);
14218
+ return result_Result.error(BlockVerifierError.InvalidStateRoot, () => `Invalid prior state root: ${stateRoot.toString()}, expected ${posteriorStateRoot.toString()} (ours)`);
14003
14219
  }
14004
14220
  return result_Result.ok(headerHash.hash);
14005
14221
  }
@@ -14124,7 +14340,7 @@ class Disputes {
14124
14340
  // check if culprits are sorted by key
14125
14341
  // https://graypaper.fluffylabs.dev/#/579bd12/12c50112c601
14126
14342
  if (!isUniqueSortedBy(disputes.culprits, "key")) {
14127
- return result_Result.error(DisputesErrorCode.CulpritsNotSortedUnique);
14343
+ return result_Result.error(DisputesErrorCode.CulpritsNotSortedUnique, () => "Culprits are not uniquely sorted by key");
14128
14344
  }
14129
14345
  const culpritsLength = disputes.culprits.length;
14130
14346
  for (let i = 0; i < culpritsLength; i++) {
@@ -14133,24 +14349,24 @@ class Disputes {
14133
14349
  // https://graypaper.fluffylabs.dev/#/579bd12/125501125501
14134
14350
  const isInPunishSet = this.state.disputesRecords.asDictionaries().punishSet.has(key);
14135
14351
  if (isInPunishSet) {
14136
- return result_Result.error(DisputesErrorCode.OffenderAlreadyReported);
14352
+ return result_Result.error(DisputesErrorCode.OffenderAlreadyReported, () => `Offender already reported: culprit ${i}, key=${key}`);
14137
14353
  }
14138
14354
  // check if the guarantor key is correct
14139
14355
  // https://graypaper.fluffylabs.dev/#/85129da/125501125501?v=0.6.3
14140
14356
  if (!allValidatorKeys.has(key)) {
14141
- return result_Result.error(DisputesErrorCode.BadGuarantorKey);
14357
+ return result_Result.error(DisputesErrorCode.BadGuarantorKey, () => `Bad guarantor key: culprit ${i}, key=${key}`);
14142
14358
  }
14143
14359
  // verify if the culprit will be in new bad set
14144
14360
  // https://graypaper.fluffylabs.dev/#/579bd12/124601124601
14145
14361
  const isInNewBadSet = newItems.asDictionaries().badSet.has(workReportHash);
14146
14362
  if (!isInNewBadSet) {
14147
- return result_Result.error(DisputesErrorCode.CulpritsVerdictNotBad);
14363
+ return result_Result.error(DisputesErrorCode.CulpritsVerdictNotBad, () => `Culprit verdict not bad: culprit ${i}, work report=${workReportHash}`);
14148
14364
  }
14149
14365
  // verify culprit signature
14150
14366
  // https://graypaper.fluffylabs.dev/#/579bd12/125c01125c01
14151
14367
  const result = verificationResult.culprits[i];
14152
14368
  if (!result?.isValid) {
14153
- return result_Result.error(DisputesErrorCode.BadSignature, `Invalid signature for culprit: ${i}`);
14369
+ return result_Result.error(DisputesErrorCode.BadSignature, () => `Invalid signature for culprit: ${i}`);
14154
14370
  }
14155
14371
  }
14156
14372
  return result_Result.ok(null);
@@ -14159,7 +14375,7 @@ class Disputes {
14159
14375
  // check if faults are sorted by key
14160
14376
  // https://graypaper.fluffylabs.dev/#/579bd12/12c50112c601
14161
14377
  if (!isUniqueSortedBy(disputes.faults, "key")) {
14162
- return result_Result.error(DisputesErrorCode.FaultsNotSortedUnique);
14378
+ return result_Result.error(DisputesErrorCode.FaultsNotSortedUnique, () => "Faults are not uniquely sorted by key");
14163
14379
  }
14164
14380
  const faultsLength = disputes.faults.length;
14165
14381
  for (let i = 0; i < faultsLength; i++) {
@@ -14168,12 +14384,12 @@ class Disputes {
14168
14384
  // https://graypaper.fluffylabs.dev/#/579bd12/12a20112a201
14169
14385
  const isInPunishSet = this.state.disputesRecords.asDictionaries().punishSet.has(key);
14170
14386
  if (isInPunishSet) {
14171
- return result_Result.error(DisputesErrorCode.OffenderAlreadyReported);
14387
+ return result_Result.error(DisputesErrorCode.OffenderAlreadyReported, () => `Offender already reported: fault ${i}, key=${key}`);
14172
14388
  }
14173
14389
  // check if the auditor key is correct
14174
14390
  // https://graypaper.fluffylabs.dev/#/85129da/12a20112a201?v=0.6.3
14175
14391
  if (!allValidatorKeys.has(key)) {
14176
- return result_Result.error(DisputesErrorCode.BadAuditorKey);
14392
+ return result_Result.error(DisputesErrorCode.BadAuditorKey, () => `Bad auditor key: fault ${i}, key=${key}`);
14177
14393
  }
14178
14394
  // verify if the fault will be included in new good/bad set
14179
14395
  // it may be not correct as in GP there is "iff" what means it should be rather
@@ -14185,14 +14401,14 @@ class Disputes {
14185
14401
  const isInNewGoodSet = goodSet.has(workReportHash);
14186
14402
  const isInNewBadSet = badSet.has(workReportHash);
14187
14403
  if (isInNewGoodSet || !isInNewBadSet) {
14188
- return result_Result.error(DisputesErrorCode.FaultVerdictWrong);
14404
+ return result_Result.error(DisputesErrorCode.FaultVerdictWrong, () => `Fault verdict wrong: fault ${i}, work report=${workReportHash}, inGood=${isInNewGoodSet}, inBad=${isInNewBadSet}`);
14189
14405
  }
14190
14406
  }
14191
14407
  // verify fault signature. Verification was done earlier, here we only check the result.
14192
14408
  // https://graypaper.fluffylabs.dev/#/579bd12/12a90112a901
14193
14409
  const result = verificationResult.faults[i];
14194
14410
  if (!result.isValid) {
14195
- return result_Result.error(DisputesErrorCode.BadSignature, `Invalid signature for fault: ${i}`);
14411
+ return result_Result.error(DisputesErrorCode.BadSignature, () => `Invalid signature for fault: ${i}`);
14196
14412
  }
14197
14413
  }
14198
14414
  return result_Result.ok(null);
@@ -14201,32 +14417,32 @@ class Disputes {
14201
14417
  // check if verdicts are correctly sorted
14202
14418
  // https://graypaper.fluffylabs.dev/#/579bd12/12c40112c401
14203
14419
  if (!isUniqueSortedBy(disputes.verdicts, "workReportHash")) {
14204
- return result_Result.error(DisputesErrorCode.VerdictsNotSortedUnique);
14420
+ return result_Result.error(DisputesErrorCode.VerdictsNotSortedUnique, () => "Verdicts are not uniquely sorted by work report hash");
14205
14421
  }
14206
14422
  // check if judgement are correctly sorted
14207
14423
  // https://graypaper.fluffylabs.dev/#/579bd12/123702123802
14208
14424
  if (disputes.verdicts.some((verdict) => !isUniqueSortedByIndex(verdict.votes))) {
14209
- return result_Result.error(DisputesErrorCode.JudgementsNotSortedUnique);
14425
+ return result_Result.error(DisputesErrorCode.JudgementsNotSortedUnique, () => "Judgements are not uniquely sorted by index");
14210
14426
  }
14211
14427
  const currentEpoch = Math.floor(this.state.timeslot / this.chainSpec.epochLength);
14212
14428
  let voteSignatureIndex = 0;
14213
14429
  for (const { votesEpoch, votes } of disputes.verdicts) {
14214
14430
  // https://graypaper.fluffylabs.dev/#/579bd12/12bb0012bc00
14215
14431
  if (votesEpoch !== currentEpoch && votesEpoch + 1 !== currentEpoch) {
14216
- return result_Result.error(DisputesErrorCode.BadJudgementAge);
14432
+ return result_Result.error(DisputesErrorCode.BadJudgementAge, () => `Bad judgement age: epoch=${votesEpoch}, current=${currentEpoch}`);
14217
14433
  }
14218
14434
  const k = votesEpoch === currentEpoch ? this.state.currentValidatorData : this.state.previousValidatorData;
14219
14435
  for (const { index } of votes) {
14220
14436
  const key = k[index]?.ed25519;
14221
14437
  // no particular GP fragment but I think we don't believe in ghosts
14222
14438
  if (key === undefined) {
14223
- return result_Result.error(DisputesErrorCode.BadValidatorIndex);
14439
+ return result_Result.error(DisputesErrorCode.BadValidatorIndex, () => `Bad validator index: ${index} in epoch ${votesEpoch}`);
14224
14440
  }
14225
14441
  // verify vote signature. Verification was done earlier, here we only check the result.
14226
14442
  // https://graypaper.fluffylabs.dev/#/579bd12/12cd0012cd00
14227
14443
  const result = verificationResult.judgements[voteSignatureIndex];
14228
14444
  if (!result.isValid) {
14229
- return result_Result.error(DisputesErrorCode.BadSignature, `Invalid signature for judgement: ${voteSignatureIndex}`);
14445
+ return result_Result.error(DisputesErrorCode.BadSignature, () => `Invalid signature for judgement: ${voteSignatureIndex}`);
14230
14446
  }
14231
14447
  voteSignatureIndex += 1;
14232
14448
  }
@@ -14242,7 +14458,7 @@ class Disputes {
14242
14458
  const isInBadSet = badSet.has(verdict.workReportHash);
14243
14459
  const isInWonkySet = wonkySet.has(verdict.workReportHash);
14244
14460
  if (isInGoodSet || isInBadSet || isInWonkySet) {
14245
- return result_Result.error(DisputesErrorCode.AlreadyJudged);
14461
+ return result_Result.error(DisputesErrorCode.AlreadyJudged, () => `Work report already judged: ${verdict.workReportHash}`);
14246
14462
  }
14247
14463
  }
14248
14464
  return result_Result.ok(null);
@@ -14273,7 +14489,7 @@ class Disputes {
14273
14489
  // https://graypaper.fluffylabs.dev/#/579bd12/12f10212fc02
14274
14490
  const f = disputes.faults.find((x) => x.workReportHash.isEqualTo(r));
14275
14491
  if (f === undefined) {
14276
- return result_Result.error(DisputesErrorCode.NotEnoughFaults);
14492
+ return result_Result.error(DisputesErrorCode.NotEnoughFaults, () => `Not enough faults for work report: ${r}`);
14277
14493
  }
14278
14494
  }
14279
14495
  else if (sum === 0) {
@@ -14282,13 +14498,13 @@ class Disputes {
14282
14498
  const c1 = disputes.culprits.find((x) => x.workReportHash.isEqualTo(r));
14283
14499
  const c2 = disputes.culprits.findLast((x) => x.workReportHash.isEqualTo(r));
14284
14500
  if (c1 === c2) {
14285
- return result_Result.error(DisputesErrorCode.NotEnoughCulprits);
14501
+ return result_Result.error(DisputesErrorCode.NotEnoughCulprits, () => `Not enough culprits for work report: ${r}`);
14286
14502
  }
14287
14503
  }
14288
14504
  else if (sum !== this.chainSpec.thirdOfValidators) {
14289
14505
  // positive votes count is not correct
14290
14506
  // https://graypaper.fluffylabs.dev/#/579bd12/125002128102
14291
- return result_Result.error(DisputesErrorCode.BadVoteSplit);
14507
+ return result_Result.error(DisputesErrorCode.BadVoteSplit, () => `Bad vote split: sum=${sum}, expected=${this.chainSpec.thirdOfValidators} for work report ${r}`);
14292
14508
  }
14293
14509
  }
14294
14510
  return result_Result.ok(null);
@@ -14376,7 +14592,7 @@ class Disputes {
14376
14592
  const validator = k[j.index];
14377
14593
  // no particular GP fragment but I think we don't believe in ghosts
14378
14594
  if (validator === undefined) {
14379
- return result_Result.error(DisputesErrorCode.BadValidatorIndex);
14595
+ return result_Result.error(DisputesErrorCode.BadValidatorIndex, () => `Bad validator index in signature verification: ${j.index}`);
14380
14596
  }
14381
14597
  const key = validator.ed25519;
14382
14598
  // verify vote signature
@@ -14484,7 +14700,7 @@ const ringCommitmentCache = [];
14484
14700
  async function verifySeal(bandersnatch, authorKey, signature, payload, encodedUnsealedHeader) {
14485
14701
  const sealResult = await bandersnatch.verifySeal(authorKey.raw, signature.raw, payload.raw, encodedUnsealedHeader.raw);
14486
14702
  if (sealResult[RESULT_INDEX] === ResultValues.Error) {
14487
- return result_Result.error(null);
14703
+ return result_Result.error(null, () => "Bandersnatch VRF seal verification failed");
14488
14704
  }
14489
14705
  return result_Result.ok(bytes_Bytes.fromBlob(sealResult.subarray(1), hash_HASH_SIZE).asOpaque());
14490
14706
  }
@@ -14510,9 +14726,9 @@ function getRingCommitment(bandersnatch, validators) {
14510
14726
  async function getRingCommitmentNoCache(bandersnatch, keys) {
14511
14727
  const commitmentResult = await bandersnatch.getRingCommitment(keys.raw);
14512
14728
  if (commitmentResult[RESULT_INDEX] === ResultValues.Error) {
14513
- return result_Result.error(null);
14729
+ return result_Result.error(null, () => "Bandersnatch ring commitment calculation failed");
14514
14730
  }
14515
- return result_Result.ok(bytes_Bytes.fromBlob(commitmentResult.subarray(1), BANDERSNATCH_RING_ROOT_BYTES).asOpaque());
14731
+ return result_Result.ok(bytes_Bytes.fromBlob(commitmentResult.subarray(1), bandersnatch_BANDERSNATCH_RING_ROOT_BYTES).asOpaque());
14516
14732
  }
14517
14733
  // One byte for result discriminator (`ResultValues`) and the rest is entropy hash.
14518
14734
  const TICKET_RESULT_LENGTH = 1 + hash_HASH_SIZE;
@@ -14666,7 +14882,7 @@ class Safrole {
14666
14882
  * https://graypaper.fluffylabs.dev/#/5f542d7/0ea2000ea200
14667
14883
  */
14668
14884
  if (isOffender) {
14669
- return ValidatorData.create({
14885
+ return validator_data_ValidatorData.create({
14670
14886
  bandersnatch: bytes_Bytes.zero(BANDERSNATCH_KEY_BYTES).asOpaque(),
14671
14887
  ed25519: bytes_Bytes.zero(ED25519_KEY_BYTES).asOpaque(),
14672
14888
  bls: bytes_Bytes.zero(BLS_KEY_BYTES).asOpaque(),
@@ -14685,7 +14901,7 @@ class Safrole {
14685
14901
  epochRoot: epochRootResult.ok,
14686
14902
  });
14687
14903
  }
14688
- return result_Result.error(SafroleErrorCode.IncorrectData);
14904
+ return result_Result.error(SafroleErrorCode.IncorrectData, () => "Safrole: failed to get epoch root for validator keys");
14689
14905
  }
14690
14906
  /**
14691
14907
  * Ticket sequencer that is used in standard mode
@@ -14744,13 +14960,13 @@ class Safrole {
14744
14960
  if (this.isNextEpoch(timeslot) &&
14745
14961
  m >= this.chainSpec.contestLength &&
14746
14962
  this.state.ticketsAccumulator.length === this.chainSpec.epochLength) {
14747
- return SafroleSealingKeysData.tickets(this.outsideInSequencer(this.state.ticketsAccumulator).tickets);
14963
+ return safrole_data_SafroleSealingKeysData.tickets(this.outsideInSequencer(this.state.ticketsAccumulator).tickets);
14748
14964
  }
14749
14965
  if (this.isSameEpoch(timeslot)) {
14750
14966
  return this.state.sealingKeySeries;
14751
14967
  }
14752
14968
  // TODO [MaSi]: the result of fallback sequencer should be cached
14753
- return SafroleSealingKeysData.keys(this.fallbackKeySequencer(newEntropy, newValidators));
14969
+ return safrole_data_SafroleSealingKeysData.keys(this.fallbackKeySequencer(newEntropy, newValidators));
14754
14970
  }
14755
14971
  /**
14756
14972
  * Returns epoch markers if the epoch is changed and null otherwise
@@ -14776,10 +14992,10 @@ class Safrole {
14776
14992
  for (let i = 1; i < ticketsLength; i++) {
14777
14993
  const order = tickets[i - 1].id.compare(tickets[i].id);
14778
14994
  if (order.isEqual()) {
14779
- return result_Result.error(SafroleErrorCode.DuplicateTicket);
14995
+ return result_Result.error(SafroleErrorCode.DuplicateTicket, () => `Safrole: duplicate ticket found at index ${i}`);
14780
14996
  }
14781
14997
  if (order.isGreater()) {
14782
- return result_Result.error(SafroleErrorCode.BadTicketOrder);
14998
+ return result_Result.error(SafroleErrorCode.BadTicketOrder, () => `Safrole: bad ticket order at index ${i}`);
14783
14999
  }
14784
15000
  }
14785
15001
  return result_Result.ok(null);
@@ -14806,7 +15022,7 @@ class Safrole {
14806
15022
  attempt: ticket.attempt,
14807
15023
  }));
14808
15024
  if (!verificationResult.every((x) => x.isValid)) {
14809
- return result_Result.error(SafroleErrorCode.BadTicketProof);
15025
+ return result_Result.error(SafroleErrorCode.BadTicketProof, () => "Safrole: invalid ticket proof in extrinsic");
14810
15026
  }
14811
15027
  /**
14812
15028
  * Verify if tickets are sorted and unique
@@ -14815,7 +15031,7 @@ class Safrole {
14815
15031
  */
14816
15032
  const ticketsVerifcationResult = this.verifyTickets(tickets);
14817
15033
  if (ticketsVerifcationResult.isError) {
14818
- return result_Result.error(ticketsVerifcationResult.error);
15034
+ return result_Result.error(ticketsVerifcationResult.error, ticketsVerifcationResult.details);
14819
15035
  }
14820
15036
  if (this.isEpochChanged(timeslot)) {
14821
15037
  return result_Result.ok(tickets);
@@ -14824,7 +15040,7 @@ class Safrole {
14824
15040
  const ticketsFromExtrinsic = SortedSet.fromSortedArray(ticketComparator, tickets);
14825
15041
  const mergedTickets = SortedSet.fromTwoSortedCollections(ticketsFromState, ticketsFromExtrinsic);
14826
15042
  if (ticketsFromState.length + ticketsFromExtrinsic.length !== mergedTickets.length) {
14827
- return result_Result.error(SafroleErrorCode.DuplicateTicket);
15043
+ return result_Result.error(SafroleErrorCode.DuplicateTicket, () => "Safrole: duplicate ticket when merging state and extrinsic tickets");
14828
15044
  }
14829
15045
  /**
14830
15046
  * Remove tickets if size of accumulator exceeds E (epoch length).
@@ -14893,24 +15109,24 @@ class Safrole {
14893
15109
  }
14894
15110
  async transition(input) {
14895
15111
  if (this.state.timeslot >= input.slot) {
14896
- return result_Result.error(SafroleErrorCode.BadSlot);
15112
+ return result_Result.error(SafroleErrorCode.BadSlot, () => `Safrole: bad slot, state timeslot ${this.state.timeslot} >= input slot ${input.slot}`);
14897
15113
  }
14898
15114
  if (!this.isExtrinsicLengthValid(input.slot, input.extrinsic)) {
14899
- return result_Result.error(SafroleErrorCode.UnexpectedTicket);
15115
+ return result_Result.error(SafroleErrorCode.UnexpectedTicket, () => `Safrole: unexpected ticket, invalid extrinsic length ${input.extrinsic.length}`);
14900
15116
  }
14901
15117
  if (!this.areTicketAttemptsValid(input.extrinsic)) {
14902
- return result_Result.error(SafroleErrorCode.BadTicketAttempt);
15118
+ return result_Result.error(SafroleErrorCode.BadTicketAttempt, () => "Safrole: bad ticket attempt value in extrinsic");
14903
15119
  }
14904
15120
  const validatorKeysResult = await this.getValidatorKeys(input.slot, input.punishSet);
14905
15121
  if (validatorKeysResult.isError) {
14906
- return result_Result.error(validatorKeysResult.error);
15122
+ return result_Result.error(validatorKeysResult.error, validatorKeysResult.details);
14907
15123
  }
14908
15124
  const { nextValidatorData, currentValidatorData, previousValidatorData, epochRoot } = validatorKeysResult.ok;
14909
15125
  const entropy = this.getEntropy(input.slot, input.entropy);
14910
15126
  const sealingKeySeries = this.getSlotKeySequence(input.slot, currentValidatorData, entropy[2]);
14911
15127
  const newTicketsAccumulatorResult = await this.getNewTicketAccumulator(input.slot, input.extrinsic, this.state.nextValidatorData, epochRoot, entropy[2]);
14912
15128
  if (newTicketsAccumulatorResult.isError) {
14913
- return result_Result.error(newTicketsAccumulatorResult.error);
15129
+ return result_Result.error(newTicketsAccumulatorResult.error, newTicketsAccumulatorResult.details);
14914
15130
  }
14915
15131
  const stateUpdate = {
14916
15132
  nextValidatorData,
@@ -14944,14 +15160,14 @@ function compareWithEncoding(chainSpec, error, actual, expected, codec) {
14944
15160
  if (actual === null || expected === null) {
14945
15161
  // if one of them is `null`, both need to be.
14946
15162
  if (actual !== expected) {
14947
- return result_Result.error(error, `${SafroleErrorCode[error]} Expected: ${expected}, got: ${actual}`);
15163
+ return result_Result.error(error, () => `${SafroleErrorCode[error]} Expected: ${expected}, got: ${actual}`);
14948
15164
  }
14949
15165
  return result_Result.ok(result_OK);
14950
15166
  }
14951
15167
  // compare the literal encoding.
14952
15168
  const encoded = encoder_Encoder.encodeObject(codec, actual, chainSpec);
14953
15169
  if (!encoded.isEqualTo(expected.encoded())) {
14954
- return result_Result.error(error, `${SafroleErrorCode[error]} Expected: ${expected.encoded()}, got: ${encoded}`);
15170
+ return result_Result.error(error, () => `${SafroleErrorCode[error]} Expected: ${expected.encoded()}, got: ${encoded}`);
14955
15171
  }
14956
15172
  return result_Result.ok(result_OK);
14957
15173
  }
@@ -14994,55 +15210,54 @@ class SafroleSeal {
14994
15210
  const blockAuthorKey = state.currentValidatorData.at(blockAuthorIndex)?.bandersnatch;
14995
15211
  const entropySourceResult = await bandersnatch_vrf.verifySeal(await this.bandersnatch, blockAuthorKey ?? BANDERSNATCH_ZERO_KEY, headerView.entropySource.materialize(), payload, bytes_BytesBlob.blobFromNumbers([]));
14996
15212
  if (entropySourceResult.isError) {
14997
- return result_Result.error(SafroleSealError.IncorrectEntropySource);
15213
+ return result_Result.error(SafroleSealError.IncorrectEntropySource, () => "Safrole: incorrect entropy source in header seal");
14998
15214
  }
14999
15215
  return result_Result.ok(entropySourceResult.ok);
15000
15216
  }
15001
15217
  async verifySeal(headerView, state) {
15002
15218
  // we use transitioned keys already
15003
- const validators = state.currentValidatorData;
15004
15219
  const validatorIndex = headerView.bandersnatchBlockAuthorIndex.materialize();
15005
- const authorKey = validators[validatorIndex];
15006
- if (authorKey === undefined) {
15007
- return result_Result.error(SafroleSealError.InvalidValidatorIndex);
15220
+ const authorKeys = state.currentValidatorData.at(validatorIndex);
15221
+ if (authorKeys === undefined) {
15222
+ return result_Result.error(SafroleSealError.InvalidValidatorIndex, () => `Safrole: invalid validator index ${validatorIndex}`);
15008
15223
  }
15009
15224
  const timeSlot = headerView.timeSlotIndex.materialize();
15010
15225
  const sealingKeys = state.sealingKeySeries;
15011
15226
  const entropy = state.currentEntropy;
15012
15227
  if (sealingKeys.kind === SafroleSealingKeysKind.Tickets) {
15013
- return await this.verifySealWithTicket(sealingKeys.tickets, timeSlot, entropy, validators, validatorIndex, headerView);
15228
+ return await this.verifySealWithTicket(sealingKeys.tickets, timeSlot, entropy, authorKeys, headerView);
15014
15229
  }
15015
- return await this.verifySealWithKeys(sealingKeys.keys, authorKey, timeSlot, entropy, validators, validatorIndex, headerView);
15230
+ return await this.verifySealWithKeys(sealingKeys.keys, timeSlot, entropy, authorKeys, headerView);
15016
15231
  }
15017
15232
  /** Regular (non-fallback) mode of Safrole. */
15018
- async verifySealWithTicket(tickets, timeSlot, entropy, validators, validatorIndex, headerView) {
15233
+ async verifySealWithTicket(tickets, timeSlot, entropy, validatorData, headerView) {
15019
15234
  const index = timeSlot % tickets.length;
15020
- const { id, attempt } = tickets[index];
15021
- const payload = bytes_BytesBlob.blobFromParts(JAM_TICKET_SEAL, entropy.raw, new Uint8Array([attempt]));
15235
+ const ticket = tickets.at(index);
15236
+ const payload = bytes_BytesBlob.blobFromParts(JAM_TICKET_SEAL, entropy.raw, new Uint8Array([ticket?.attempt ?? 0]));
15022
15237
  // verify seal correctness
15023
- const authorKey = validators.at(validatorIndex)?.bandersnatch;
15238
+ const authorKey = validatorData.bandersnatch;
15024
15239
  const result = await bandersnatch_vrf.verifySeal(await this.bandersnatch, authorKey ?? BANDERSNATCH_ZERO_KEY, headerView.seal.materialize(), payload, encodeUnsealedHeader(headerView));
15025
15240
  if (result.isError) {
15026
- return result_Result.error(SafroleSealError.IncorrectSeal);
15241
+ return result_Result.error(SafroleSealError.IncorrectSeal, () => "Safrole: incorrect seal with ticket");
15027
15242
  }
15028
- if (!id.isEqualTo(result.ok)) {
15029
- return result_Result.error(SafroleSealError.InvalidTicket);
15243
+ if (ticket === undefined || !ticket.id.isEqualTo(result.ok)) {
15244
+ return result_Result.error(SafroleSealError.InvalidTicket, () => `Safrole: invalid ticket, expected ${ticket?.id} got ${result.ok}`);
15030
15245
  }
15031
15246
  return result_Result.ok(result.ok);
15032
15247
  }
15033
15248
  /** Fallback mode of Safrole. */
15034
- async verifySealWithKeys(keys, authorKey, timeSlot, entropy, validators, validatorIndex, headerView) {
15249
+ async verifySealWithKeys(keys, timeSlot, entropy, authorKey, headerView) {
15035
15250
  const index = timeSlot % keys.length;
15036
- const sealingKey = keys[index];
15037
- if (!sealingKey.isEqualTo(authorKey.bandersnatch)) {
15038
- return result_Result.error(SafroleSealError.InvalidValidator, `Invalid Validator. Expected: ${sealingKey}, got: ${authorKey.bandersnatch}`);
15251
+ const sealingKey = keys.at(index);
15252
+ const authorBandersnatchKey = authorKey.bandersnatch;
15253
+ if (sealingKey === undefined || !sealingKey.isEqualTo(authorBandersnatchKey)) {
15254
+ return result_Result.error(SafroleSealError.InvalidValidator, () => `Invalid Validator. Expected: ${sealingKey}, got: ${authorKey.bandersnatch}`);
15039
15255
  }
15040
15256
  // verify seal correctness
15041
15257
  const payload = bytes_BytesBlob.blobFromParts(JAM_FALLBACK_SEAL, entropy.raw);
15042
- const blockAuthorKey = validators.at(validatorIndex)?.bandersnatch;
15043
- const result = await bandersnatch_vrf.verifySeal(await this.bandersnatch, blockAuthorKey ?? BANDERSNATCH_ZERO_KEY, headerView.seal.materialize(), payload, encodeUnsealedHeader(headerView));
15258
+ const result = await bandersnatch_vrf.verifySeal(await this.bandersnatch, authorBandersnatchKey, headerView.seal.materialize(), payload, encodeUnsealedHeader(headerView));
15044
15259
  if (result.isError) {
15045
- return result_Result.error(SafroleSealError.IncorrectSeal);
15260
+ return result_Result.error(SafroleSealError.IncorrectSeal, () => "Safrole: incorrect seal with keys");
15046
15261
  }
15047
15262
  return result_Result.ok(result.ok);
15048
15263
  }
@@ -15085,6 +15300,14 @@ async function getRootHash(yieldedRoots) {
15085
15300
 
15086
15301
 
15087
15302
  const InsufficientFundsError = "insufficient funds";
15303
+ /** Deep clone of a map with array. */
15304
+ function deepCloneMapWithArray(map) {
15305
+ const cloned = [];
15306
+ for (const [k, v] of map.entries()) {
15307
+ cloned.push([k, v.slice()]);
15308
+ }
15309
+ return new Map(cloned);
15310
+ }
15088
15311
  /**
15089
15312
  * State updates that currently accumulating service produced.
15090
15313
  *
@@ -15114,10 +15337,11 @@ class AccumulationStateUpdate {
15114
15337
  /** Create new empty state update. */
15115
15338
  static empty() {
15116
15339
  return new AccumulationStateUpdate({
15117
- servicesUpdates: [],
15118
- servicesRemoved: [],
15119
- preimages: [],
15120
- storage: [],
15340
+ created: [],
15341
+ updated: new Map(),
15342
+ removed: [],
15343
+ preimages: new Map(),
15344
+ storage: new Map(),
15121
15345
  }, []);
15122
15346
  }
15123
15347
  /** Create a state update with some existing, yet uncommited services updates. */
@@ -15129,10 +15353,13 @@ class AccumulationStateUpdate {
15129
15353
  /** Create a copy of another `StateUpdate`. Used by checkpoints. */
15130
15354
  static copyFrom(from) {
15131
15355
  const serviceUpdates = {
15132
- servicesUpdates: [...from.services.servicesUpdates],
15133
- servicesRemoved: [...from.services.servicesRemoved],
15134
- preimages: [...from.services.preimages],
15135
- storage: [...from.services.storage],
15356
+ // shallow copy
15357
+ created: [...from.services.created],
15358
+ updated: new Map(from.services.updated),
15359
+ removed: [...from.services.removed],
15360
+ // deep copy
15361
+ preimages: deepCloneMapWithArray(from.services.preimages),
15362
+ storage: deepCloneMapWithArray(from.services.storage),
15136
15363
  };
15137
15364
  const transfers = [...from.transfers];
15138
15365
  const update = new AccumulationStateUpdate(serviceUpdates, transfers, new Map(from.yieldedRoots));
@@ -15151,6 +15378,12 @@ class AccumulationStateUpdate {
15151
15378
  }
15152
15379
  return update;
15153
15380
  }
15381
+ /** Retrieve and clear pending transfers. */
15382
+ takeTransfers() {
15383
+ const transfers = this.transfers;
15384
+ this.transfers = [];
15385
+ return transfers;
15386
+ }
15154
15387
  }
15155
15388
  class PartiallyUpdatedState {
15156
15389
  state;
@@ -15174,9 +15407,9 @@ class PartiallyUpdatedState {
15174
15407
  if (destination === null) {
15175
15408
  return null;
15176
15409
  }
15177
- const maybeNewService = this.stateUpdate.services.servicesUpdates.find((update) => update.serviceId === destination);
15178
- if (maybeNewService !== undefined) {
15179
- return maybeNewService.action.account;
15410
+ const maybeUpdatedServiceInfo = this.stateUpdate.services.updated.get(destination);
15411
+ if (maybeUpdatedServiceInfo !== undefined) {
15412
+ return maybeUpdatedServiceInfo.action.account;
15180
15413
  }
15181
15414
  const maybeService = this.state.getService(destination);
15182
15415
  if (maybeService === null) {
@@ -15185,7 +15418,8 @@ class PartiallyUpdatedState {
15185
15418
  return maybeService.getInfo();
15186
15419
  }
15187
15420
  getStorage(serviceId, rawKey) {
15188
- const item = this.stateUpdate.services.storage.find((x) => x.serviceId === serviceId && x.key.isEqualTo(rawKey));
15421
+ const storages = this.stateUpdate.services.storage.get(serviceId) ?? [];
15422
+ const item = storages.find((x) => x.key.isEqualTo(rawKey));
15189
15423
  if (item !== undefined) {
15190
15424
  return item.value;
15191
15425
  }
@@ -15200,10 +15434,11 @@ class PartiallyUpdatedState {
15200
15434
  * the existence in `preimages` map.
15201
15435
  */
15202
15436
  hasPreimage(serviceId, hash) {
15203
- const providedPreimage = this.stateUpdate.services.preimages.find(
15437
+ const preimages = this.stateUpdate.services.preimages.get(serviceId) ?? [];
15438
+ const providedPreimage = preimages.find(
15204
15439
  // we ignore the action here, since if there is <any> update on that
15205
15440
  // hash it means it has to exist, right?
15206
- (p) => p.serviceId === serviceId && p.hash.isEqualTo(hash));
15441
+ (p) => p.hash.isEqualTo(hash));
15207
15442
  if (providedPreimage !== undefined) {
15208
15443
  return true;
15209
15444
  }
@@ -15216,7 +15451,8 @@ class PartiallyUpdatedState {
15216
15451
  }
15217
15452
  getPreimage(serviceId, hash) {
15218
15453
  // TODO [ToDr] Should we verify availability here?
15219
- const freshlyProvided = this.stateUpdate.services.preimages.find((x) => x.serviceId === serviceId && x.hash.isEqualTo(hash));
15454
+ const preimages = this.stateUpdate.services.preimages.get(serviceId) ?? [];
15455
+ const freshlyProvided = preimages.find((x) => x.hash.isEqualTo(hash));
15220
15456
  if (freshlyProvided !== undefined && freshlyProvided.action.kind === UpdatePreimageKind.Provide) {
15221
15457
  return freshlyProvided.action.preimage.blob;
15222
15458
  }
@@ -15225,10 +15461,11 @@ class PartiallyUpdatedState {
15225
15461
  }
15226
15462
  /** Get status of a preimage of current service taking into account any updates. */
15227
15463
  getLookupHistory(currentTimeslot, serviceId, hash, length) {
15464
+ const preimages = this.stateUpdate.services.preimages.get(serviceId) ?? [];
15228
15465
  // TODO [ToDr] This is most likely wrong. We may have `provide` and `remove` within
15229
15466
  // the same state update. We should however switch to proper "updated state"
15230
15467
  // representation soon.
15231
- const updatedPreimage = this.stateUpdate.services.preimages.findLast((update) => update.serviceId === serviceId && update.hash.isEqualTo(hash) && BigInt(update.length) === length);
15468
+ const updatedPreimage = preimages.findLast((update) => update.hash.isEqualTo(hash) && BigInt(update.length) === length);
15232
15469
  const stateFallback = () => {
15233
15470
  // fallback to state lookup
15234
15471
  const service = this.state.getService(serviceId);
@@ -15265,14 +15502,15 @@ class PartiallyUpdatedState {
15265
15502
  /* State update functions. */
15266
15503
  updateStorage(serviceId, key, value) {
15267
15504
  const update = value === null
15268
- ? UpdateStorage.remove({ serviceId, key })
15505
+ ? UpdateStorage.remove({ key })
15269
15506
  : UpdateStorage.set({
15270
- serviceId,
15271
15507
  storage: StorageItem.create({ key, value }),
15272
15508
  });
15273
- const index = this.stateUpdate.services.storage.findIndex((x) => x.serviceId === update.serviceId && x.key.isEqualTo(key));
15509
+ const storages = this.stateUpdate.services.storage.get(serviceId) ?? [];
15510
+ const index = storages.findIndex((x) => x.key.isEqualTo(key));
15274
15511
  const count = index === -1 ? 0 : 1;
15275
- this.stateUpdate.services.storage.splice(index, count, update);
15512
+ storages.splice(index, count, update);
15513
+ this.stateUpdate.services.storage.set(serviceId, storages);
15276
15514
  }
15277
15515
  /**
15278
15516
  * Update a preimage.
@@ -15280,8 +15518,10 @@ class PartiallyUpdatedState {
15280
15518
  * Note we store all previous entries as well, since there might be a sequence of:
15281
15519
  * `provide` -> `remove` and both should update the end state somehow.
15282
15520
  */
15283
- updatePreimage(newUpdate) {
15284
- this.stateUpdate.services.preimages.push(newUpdate);
15521
+ updatePreimage(serviceId, newUpdate) {
15522
+ const updatePreimages = this.stateUpdate.services.preimages.get(serviceId) ?? [];
15523
+ updatePreimages.push(newUpdate);
15524
+ this.stateUpdate.services.preimages.set(serviceId, updatePreimages);
15285
15525
  }
15286
15526
  updateServiceStorageUtilisation(serviceId, items, bytes, serviceInfo) {
15287
15527
  debug_check `${items >= 0} storageUtilisationCount has to be a positive number, got: ${items}`;
@@ -15290,11 +15530,11 @@ class PartiallyUpdatedState {
15290
15530
  const overflowBytes = !isU64(bytes);
15291
15531
  // TODO [ToDr] this is not specified in GP, but it seems sensible.
15292
15532
  if (overflowItems || overflowBytes) {
15293
- return result_Result.error(InsufficientFundsError);
15533
+ return result_Result.error(InsufficientFundsError, () => `Storage utilisation overflow: items=${overflowItems}, bytes=${overflowBytes}`);
15294
15534
  }
15295
15535
  const thresholdBalance = ServiceAccountInfo.calculateThresholdBalance(items, bytes, serviceInfo.gratisStorage);
15296
15536
  if (serviceInfo.balance < thresholdBalance) {
15297
- return result_Result.error(InsufficientFundsError);
15537
+ return result_Result.error(InsufficientFundsError, () => `Service balance (${serviceInfo.balance}) below threshold (${thresholdBalance})`);
15298
15538
  }
15299
15539
  // Update service info with new details.
15300
15540
  this.updateServiceInfo(serviceId, ServiceAccountInfo.create({
@@ -15305,20 +15545,23 @@ class PartiallyUpdatedState {
15305
15545
  return result_Result.ok(result_OK);
15306
15546
  }
15307
15547
  updateServiceInfo(serviceId, newInfo) {
15308
- const idx = this.stateUpdate.services.servicesUpdates.findIndex((x) => x.serviceId === serviceId);
15309
- const toRemove = idx === -1 ? 0 : 1;
15310
- const existingItem = this.stateUpdate.services.servicesUpdates[idx];
15311
- if (existingItem?.action.kind === UpdateServiceKind.Create) {
15312
- this.stateUpdate.services.servicesUpdates.splice(idx, toRemove, UpdateService.create({
15313
- serviceId,
15548
+ const existingUpdate = this.stateUpdate.services.updated.get(serviceId);
15549
+ if (existingUpdate?.action.kind === UpdateServiceKind.Create) {
15550
+ this.stateUpdate.services.updated.set(serviceId, UpdateService.create({
15314
15551
  serviceInfo: newInfo,
15315
- lookupHistory: existingItem.action.lookupHistory,
15552
+ lookupHistory: existingUpdate.action.lookupHistory,
15316
15553
  }));
15317
15554
  return;
15318
15555
  }
15319
- this.stateUpdate.services.servicesUpdates.splice(idx, toRemove, UpdateService.update({
15320
- serviceId,
15556
+ this.stateUpdate.services.updated.set(serviceId, UpdateService.update({
15557
+ serviceInfo: newInfo,
15558
+ }));
15559
+ }
15560
+ createService(serviceId, newInfo, newLookupHistory) {
15561
+ this.stateUpdate.services.created.push(serviceId);
15562
+ this.stateUpdate.services.updated.set(serviceId, UpdateService.create({
15321
15563
  serviceInfo: newInfo,
15564
+ lookupHistory: newLookupHistory,
15322
15565
  }));
15323
15566
  }
15324
15567
  getPrivilegedServices() {
@@ -16794,7 +17037,7 @@ class ReadablePage extends MemoryPage {
16794
17037
  loadInto(result, startIndex, length) {
16795
17038
  const endIndex = startIndex + length;
16796
17039
  if (endIndex > PAGE_SIZE) {
16797
- return result_Result.error(PageFault.fromMemoryIndex(this.start + PAGE_SIZE));
17040
+ return result_Result.error(PageFault.fromMemoryIndex(this.start + PAGE_SIZE), () => `Page fault: read beyond page boundary at ${this.start + PAGE_SIZE}`);
16798
17041
  }
16799
17042
  const bytes = this.data.subarray(startIndex, endIndex);
16800
17043
  // we zero the bytes, since data might not yet be initialized at `endIndex`.
@@ -16803,7 +17046,7 @@ class ReadablePage extends MemoryPage {
16803
17046
  return result_Result.ok(result_OK);
16804
17047
  }
16805
17048
  storeFrom(_address, _data) {
16806
- return result_Result.error(PageFault.fromMemoryIndex(this.start, true));
17049
+ return result_Result.error(PageFault.fromMemoryIndex(this.start, true), () => `Page fault: attempted to write to read-only page at ${this.start}`);
16807
17050
  }
16808
17051
  setData(pageIndex, data) {
16809
17052
  this.data.set(data, pageIndex);
@@ -16837,7 +17080,7 @@ class WriteablePage extends MemoryPage {
16837
17080
  loadInto(result, startIndex, length) {
16838
17081
  const endIndex = startIndex + length;
16839
17082
  if (endIndex > PAGE_SIZE) {
16840
- return result_Result.error(PageFault.fromMemoryIndex(this.start + PAGE_SIZE));
17083
+ return result_Result.error(PageFault.fromMemoryIndex(this.start + PAGE_SIZE), () => `Page fault: read beyond page boundary at ${this.start + PAGE_SIZE}`);
16841
17084
  }
16842
17085
  const bytes = this.view.subarray(startIndex, endIndex);
16843
17086
  // we zero the bytes, since the view might not yet be initialized at `endIndex`.
@@ -16923,7 +17166,7 @@ class Memory {
16923
17166
  memory_logger.insane `MEM[${address}] <- ${bytes_BytesBlob.blobFrom(bytes)}`;
16924
17167
  const pagesResult = this.getPages(address, bytes.length, AccessType.WRITE);
16925
17168
  if (pagesResult.isError) {
16926
- return result_Result.error(pagesResult.error);
17169
+ return result_Result.error(pagesResult.error, pagesResult.details);
16927
17170
  }
16928
17171
  const pages = pagesResult.ok;
16929
17172
  let currentPosition = address;
@@ -16948,14 +17191,14 @@ class Memory {
16948
17191
  const pages = [];
16949
17192
  for (const pageNumber of pageRange) {
16950
17193
  if (pageNumber < RESERVED_NUMBER_OF_PAGES) {
16951
- return result_Result.error(PageFault.fromPageNumber(pageNumber, true));
17194
+ return result_Result.error(PageFault.fromPageNumber(pageNumber, true), () => `Page fault: attempted to access reserved page ${pageNumber}`);
16952
17195
  }
16953
17196
  const page = this.memory.get(pageNumber);
16954
17197
  if (page === undefined) {
16955
- return result_Result.error(PageFault.fromPageNumber(pageNumber));
17198
+ return result_Result.error(PageFault.fromPageNumber(pageNumber), () => `Page fault: page ${pageNumber} not allocated`);
16956
17199
  }
16957
17200
  if (accessType === AccessType.WRITE && !page.isWriteable()) {
16958
- return result_Result.error(PageFault.fromPageNumber(pageNumber, true));
17201
+ return result_Result.error(PageFault.fromPageNumber(pageNumber, true), () => `Page fault: attempted to write to read-only page ${pageNumber}`);
16959
17202
  }
16960
17203
  pages.push(page);
16961
17204
  }
@@ -16973,7 +17216,7 @@ class Memory {
16973
17216
  }
16974
17217
  const pagesResult = this.getPages(startAddress, result.length, AccessType.READ);
16975
17218
  if (pagesResult.isError) {
16976
- return result_Result.error(pagesResult.error);
17219
+ return result_Result.error(pagesResult.error, pagesResult.details);
16977
17220
  }
16978
17221
  const pages = pagesResult.ok;
16979
17222
  let currentPosition = startAddress;
@@ -18912,7 +19155,7 @@ class ProgramDecoder {
18912
19155
  }
18913
19156
  catch (e) {
18914
19157
  program_decoder_logger.error `Invalid program: ${e}`;
18915
- return result_Result.error(ProgramDecoderError.InvalidProgramError);
19158
+ return result_Result.error(ProgramDecoderError.InvalidProgramError, () => `Program decoder error: ${e}`);
18916
19159
  }
18917
19160
  }
18918
19161
  }
@@ -19190,6 +19433,24 @@ class Interpreter {
19190
19433
  getMemoryPage(pageNumber) {
19191
19434
  return this.memory.getPageDump(tryAsPageNumber(pageNumber));
19192
19435
  }
19436
+ calculateBlockGasCost() {
19437
+ const codeLength = this.code.length;
19438
+ const blocks = new Map();
19439
+ let currentBlock = "0";
19440
+ let gasCost = 0;
19441
+ const getNextIstructionIndex = (index) => index + 1 + this.mask.getNoOfBytesToNextInstruction(index + 1);
19442
+ for (let index = 0; index < codeLength; index = getNextIstructionIndex(index)) {
19443
+ const instruction = this.code[index];
19444
+ if (this.basicBlocks.isBeginningOfBasicBlock(index)) {
19445
+ blocks.set(currentBlock, gasCost);
19446
+ currentBlock = index.toString();
19447
+ gasCost = 0;
19448
+ }
19449
+ gasCost += instructionGasMap[instruction];
19450
+ }
19451
+ blocks.set(currentBlock, gasCost);
19452
+ return blocks;
19453
+ }
19193
19454
  }
19194
19455
 
19195
19456
  ;// CONCATENATED MODULE: ./packages/core/pvm-interpreter/index.ts
@@ -19637,10 +19898,10 @@ class AccumulateExternalities {
19637
19898
  const len = existingPreimage.slots.length;
19638
19899
  // https://graypaper.fluffylabs.dev/#/9a08063/380901380901?v=0.6.6
19639
19900
  if (len === PreimageStatusKind.Requested) {
19640
- return result_Result.error(RequestPreimageError.AlreadyRequested);
19901
+ return result_Result.error(RequestPreimageError.AlreadyRequested, () => `Preimage already requested: hash=${hash}`);
19641
19902
  }
19642
19903
  if (len === PreimageStatusKind.Available || len === PreimageStatusKind.Reavailable) {
19643
- return result_Result.error(RequestPreimageError.AlreadyAvailable);
19904
+ return result_Result.error(RequestPreimageError.AlreadyAvailable, () => `Preimage already available: hash=${hash}`);
19644
19905
  }
19645
19906
  // TODO [ToDr] Not sure if we should update the service info in that case,
19646
19907
  // but for now we let that case fall-through.
@@ -19665,15 +19926,13 @@ class AccumulateExternalities {
19665
19926
  const clampedLength = clampU64ToU32(length);
19666
19927
  if (existingPreimage === null) {
19667
19928
  // https://graypaper.fluffylabs.dev/#/9a08063/38a60038a600?v=0.6.6
19668
- this.updatedState.updatePreimage(UpdatePreimage.updateOrAdd({
19669
- serviceId: this.currentServiceId,
19929
+ this.updatedState.updatePreimage(this.currentServiceId, UpdatePreimage.updateOrAdd({
19670
19930
  lookupHistory: new LookupHistoryItem(hash, clampedLength, tryAsLookupHistorySlots([])),
19671
19931
  }));
19672
19932
  }
19673
19933
  else {
19674
19934
  /** https://graypaper.fluffylabs.dev/#/9a08063/38ca0038ca00?v=0.6.6 */
19675
- this.updatedState.updatePreimage(UpdatePreimage.updateOrAdd({
19676
- serviceId: this.currentServiceId,
19935
+ this.updatedState.updatePreimage(this.currentServiceId, UpdatePreimage.updateOrAdd({
19677
19936
  lookupHistory: new LookupHistoryItem(hash, clampedLength, tryAsLookupHistorySlots([...existingPreimage.slots, this.currentTimeslot])),
19678
19937
  }));
19679
19938
  }
@@ -19683,7 +19942,7 @@ class AccumulateExternalities {
19683
19942
  const serviceId = this.currentServiceId;
19684
19943
  const status = this.updatedState.getLookupHistory(this.currentTimeslot, this.currentServiceId, hash, length);
19685
19944
  if (status === null) {
19686
- return result_Result.error(ForgetPreimageError.NotFound);
19945
+ return result_Result.error(ForgetPreimageError.NotFound, () => `Preimage not found: hash=${hash}, length=${length}`);
19687
19946
  }
19688
19947
  const s = slotsToPreimageStatus(status.slots);
19689
19948
  const updateStorageUtilisation = () => {
@@ -19696,10 +19955,9 @@ class AccumulateExternalities {
19696
19955
  if (s.status === PreimageStatusKind.Requested) {
19697
19956
  const res = updateStorageUtilisation();
19698
19957
  if (res.isError) {
19699
- return result_Result.error(ForgetPreimageError.StorageUtilisationError);
19958
+ return result_Result.error(ForgetPreimageError.StorageUtilisationError, res.details);
19700
19959
  }
19701
- this.updatedState.updatePreimage(UpdatePreimage.remove({
19702
- serviceId,
19960
+ this.updatedState.updatePreimage(serviceId, UpdatePreimage.remove({
19703
19961
  hash: status.hash,
19704
19962
  length: status.length,
19705
19963
  }));
@@ -19712,21 +19970,19 @@ class AccumulateExternalities {
19712
19970
  if (y < t - this.chainSpec.preimageExpungePeriod) {
19713
19971
  const res = updateStorageUtilisation();
19714
19972
  if (res.isError) {
19715
- return result_Result.error(ForgetPreimageError.StorageUtilisationError);
19973
+ return result_Result.error(ForgetPreimageError.StorageUtilisationError, res.details);
19716
19974
  }
19717
- this.updatedState.updatePreimage(UpdatePreimage.remove({
19718
- serviceId,
19975
+ this.updatedState.updatePreimage(serviceId, UpdatePreimage.remove({
19719
19976
  hash: status.hash,
19720
19977
  length: status.length,
19721
19978
  }));
19722
19979
  return result_Result.ok(result_OK);
19723
19980
  }
19724
- return result_Result.error(ForgetPreimageError.NotExpired);
19981
+ return result_Result.error(ForgetPreimageError.NotExpired, () => `Preimage not expired: y=${y}, timeslot=${t}, period=${this.chainSpec.preimageExpungePeriod}`);
19725
19982
  }
19726
19983
  // https://graypaper.fluffylabs.dev/#/9a08063/38c80138c801?v=0.6.6
19727
19984
  if (s.status === PreimageStatusKind.Available) {
19728
- this.updatedState.updatePreimage(UpdatePreimage.updateOrAdd({
19729
- serviceId,
19985
+ this.updatedState.updatePreimage(serviceId, UpdatePreimage.updateOrAdd({
19730
19986
  lookupHistory: new LookupHistoryItem(status.hash, status.length, tryAsLookupHistorySlots([s.data[0], t])),
19731
19987
  }));
19732
19988
  return result_Result.ok(result_OK);
@@ -19735,13 +19991,12 @@ class AccumulateExternalities {
19735
19991
  if (s.status === PreimageStatusKind.Reavailable) {
19736
19992
  const y = s.data[1];
19737
19993
  if (y < t - this.chainSpec.preimageExpungePeriod) {
19738
- this.updatedState.updatePreimage(UpdatePreimage.updateOrAdd({
19739
- serviceId,
19994
+ this.updatedState.updatePreimage(serviceId, UpdatePreimage.updateOrAdd({
19740
19995
  lookupHistory: new LookupHistoryItem(status.hash, status.length, tryAsLookupHistorySlots([s.data[2], t])),
19741
19996
  }));
19742
19997
  return result_Result.ok(result_OK);
19743
19998
  }
19744
- return result_Result.error(ForgetPreimageError.NotExpired);
19999
+ return result_Result.error(ForgetPreimageError.NotExpired, () => `Preimage not expired: y=${y}, timeslot=${t}, period=${this.chainSpec.preimageExpungePeriod}`);
19745
20000
  }
19746
20001
  debug_assertNever(s);
19747
20002
  }
@@ -19750,17 +20005,17 @@ class AccumulateExternalities {
19750
20005
  const destination = this.getServiceInfo(destinationId);
19751
20006
  /** https://graypaper.fluffylabs.dev/#/9a08063/370401370401?v=0.6.6 */
19752
20007
  if (destination === null || destinationId === null) {
19753
- return result_Result.error(TransferError.DestinationNotFound);
20008
+ return result_Result.error(TransferError.DestinationNotFound, () => `Destination service not found: ${destinationId}`);
19754
20009
  }
19755
20010
  /** https://graypaper.fluffylabs.dev/#/9a08063/371301371301?v=0.6.6 */
19756
20011
  if (gas < destination.onTransferMinGas) {
19757
- return result_Result.error(TransferError.GasTooLow);
20012
+ return result_Result.error(TransferError.GasTooLow, () => `Gas ${gas} below minimum ${destination.onTransferMinGas}`);
19758
20013
  }
19759
20014
  /** https://graypaper.fluffylabs.dev/#/9a08063/371b01371b01?v=0.6.6 */
19760
20015
  const newBalance = source.balance - amount;
19761
20016
  const thresholdBalance = ServiceAccountInfo.calculateThresholdBalance(source.storageUtilisationCount, source.storageUtilisationBytes, source.gratisStorage);
19762
20017
  if (newBalance < thresholdBalance) {
19763
- return result_Result.error(TransferError.BalanceBelowThreshold);
20018
+ return result_Result.error(TransferError.BalanceBelowThreshold, () => `Balance ${newBalance} below threshold ${thresholdBalance}`);
19764
20019
  }
19765
20020
  // outgoing transfer
19766
20021
  this.updatedState.stateUpdate.transfers.push(PendingTransfer.create({
@@ -19787,7 +20042,7 @@ class AccumulateExternalities {
19787
20042
  // check if we are priviledged to set gratis storage
19788
20043
  // https://graypaper.fluffylabs.dev/#/7e6ff6a/369203369603?v=0.6.7
19789
20044
  if (gratisStorage !== numbers_tryAsU64(0) && this.currentServiceId !== this.updatedState.getPrivilegedServices().manager) {
19790
- return result_Result.error(NewServiceError.UnprivilegedService);
20045
+ return result_Result.error(NewServiceError.UnprivilegedService, () => `Service ${this.currentServiceId} not privileged to set gratis storage`);
19791
20046
  }
19792
20047
  // check if we have enough balance
19793
20048
  // https://graypaper.fluffylabs.dev/#/7e6ff6a/369e0336a303?v=0.6.7
@@ -19796,7 +20051,7 @@ class AccumulateExternalities {
19796
20051
  const thresholdForCurrent = ServiceAccountInfo.calculateThresholdBalance(currentService.storageUtilisationCount, currentService.storageUtilisationBytes, currentService.gratisStorage);
19797
20052
  const balanceLeftForCurrent = currentService.balance - thresholdForNew;
19798
20053
  if (balanceLeftForCurrent < thresholdForCurrent || bytes.overflow) {
19799
- return result_Result.error(NewServiceError.InsufficientFunds);
20054
+ return result_Result.error(NewServiceError.InsufficientFunds, () => `Insufficient funds: balance=${currentService.balance}, required=${thresholdForNew}, overflow=${bytes.overflow}`);
19800
20055
  }
19801
20056
  // `a`: https://graypaper.fluffylabs.dev/#/ab2cdbd/366b02366d02?v=0.7.2
19802
20057
  const newAccount = ServiceAccountInfo.create({
@@ -19823,15 +20078,11 @@ class AccumulateExternalities {
19823
20078
  // NOTE: It's safe to cast to `Number` here, bcs here service ID cannot be bigger than 2**16
19824
20079
  const newServiceId = tryAsServiceId(Number(wantedServiceId));
19825
20080
  if (this.getServiceInfo(newServiceId) !== null) {
19826
- return result_Result.error(NewServiceError.RegistrarServiceIdAlreadyTaken);
20081
+ return result_Result.error(NewServiceError.RegistrarServiceIdAlreadyTaken, () => `Service ID ${newServiceId} already taken`);
19827
20082
  }
19828
20083
  // add the new service with selected ID
19829
20084
  // https://graypaper.fluffylabs.dev/#/ab2cdbd/36be0336c003?v=0.7.2
19830
- this.updatedState.stateUpdate.services.servicesUpdates.push(UpdateService.create({
19831
- serviceId: newServiceId,
19832
- serviceInfo: newAccount,
19833
- lookupHistory: newLookupItem,
19834
- }));
20085
+ this.updatedState.createService(newServiceId, newAccount, newLookupItem);
19835
20086
  // update the balance of current service
19836
20087
  // https://graypaper.fluffylabs.dev/#/ab2cdbd/36c20336c403?v=0.7.2
19837
20088
  this.updatedState.updateServiceInfo(this.currentServiceId, updatedCurrentAccount);
@@ -19842,12 +20093,8 @@ class AccumulateExternalities {
19842
20093
  }
19843
20094
  const newServiceId = this.nextNewServiceId;
19844
20095
  // add the new service
19845
- // https://graypaper.fluffylabs.dev/#/ab2cdbd/36e70336e903?v=0.7.2
19846
- this.updatedState.stateUpdate.services.servicesUpdates.push(UpdateService.create({
19847
- serviceId: newServiceId,
19848
- serviceInfo: newAccount,
19849
- lookupHistory: newLookupItem,
19850
- }));
20096
+ // https://graypaper.fluffylabs.dev/#/7e6ff6a/36cb0236cb02?v=0.6.7
20097
+ this.updatedState.createService(newServiceId, newAccount, newLookupItem);
19851
20098
  // update the balance of current service
19852
20099
  // https://graypaper.fluffylabs.dev/#/ab2cdbd/36ec0336ee03?v=0.7.2
19853
20100
  this.updatedState.updateServiceInfo(this.currentServiceId, updatedCurrentAccount);
@@ -19871,7 +20118,7 @@ class AccumulateExternalities {
19871
20118
  const currentDelegator = this.updatedState.getPrivilegedServices().delegator;
19872
20119
  if (currentDelegator !== this.currentServiceId) {
19873
20120
  accumulate_externalities_logger.trace `Current service id (${this.currentServiceId}) is not a validators manager. (expected: ${currentDelegator}) and cannot update validators data. Ignoring`;
19874
- return result_Result.error(UnprivilegedError);
20121
+ return result_Result.error(UnprivilegedError, () => `Service ${this.currentServiceId} is not delegator (expected: ${currentDelegator})`);
19875
20122
  }
19876
20123
  this.updatedState.stateUpdate.validatorsData = validatorsData;
19877
20124
  return result_Result.ok(result_OK);
@@ -19886,33 +20133,87 @@ class AccumulateExternalities {
19886
20133
  const currentAssigners = this.updatedState.getPrivilegedServices().assigners[coreIndex];
19887
20134
  if (currentAssigners !== this.currentServiceId) {
19888
20135
  accumulate_externalities_logger.trace `Current service id (${this.currentServiceId}) is not an auth manager of core ${coreIndex} (expected: ${currentAssigners}) and cannot update authorization queue.`;
19889
- return result_Result.error(UpdatePrivilegesError.UnprivilegedService);
20136
+ return result_Result.error(UpdatePrivilegesError.UnprivilegedService, () => `Service ${this.currentServiceId} not assigner for core ${coreIndex} (expected: ${currentAssigners})`);
19890
20137
  }
19891
20138
  if (assigners === null && Compatibility.isGreaterOrEqual(GpVersion.V0_7_1)) {
19892
20139
  accumulate_externalities_logger.trace `The new auth manager is not a valid service id.`;
19893
- return result_Result.error(UpdatePrivilegesError.InvalidServiceId);
20140
+ return result_Result.error(UpdatePrivilegesError.InvalidServiceId, () => `New auth manager is null for core ${coreIndex}`);
19894
20141
  }
19895
20142
  this.updatedState.stateUpdate.authorizationQueues.set(coreIndex, authQueue);
19896
20143
  return result_Result.ok(result_OK);
19897
20144
  }
20145
+ updatePrivilegedServiceId(
20146
+ // The id that privileged service wants to be updated to
20147
+ newId,
20148
+ // Current id of privileged service (updated state)
20149
+ currentId, {
20150
+ // is current service id a manager (can update anything)
20151
+ isManager,
20152
+ // is current service attempting to update itself (privileged are owned)
20153
+ isSelf,
20154
+ // is the service id already changed in this block
20155
+ isAlreadyChanged, }) {
20156
+ if (isManager) {
20157
+ return newId;
20158
+ }
20159
+ // current service can update itself, only if it was a privileged
20160
+ // service at the start of the block. I.e. owned privileges cannot
20161
+ // be transfered multiple times in a block.
20162
+ if (isSelf && !isAlreadyChanged) {
20163
+ return newId;
20164
+ }
20165
+ return currentId;
20166
+ }
19898
20167
  updatePrivilegedServices(manager, authorizers, delegator, registrar, autoAccumulate) {
19899
20168
  /** https://graypaper.fluffylabs.dev/#/7e6ff6a/36d90036de00?v=0.6.7 */
19900
- const currentManager = this.updatedState.getPrivilegedServices().manager;
19901
- if (currentManager !== this.currentServiceId) {
19902
- return result_Result.error(UpdatePrivilegesError.UnprivilegedService);
19903
- }
19904
- if (manager === null || delegator === null) {
19905
- return result_Result.error(UpdatePrivilegesError.InvalidServiceId, "Either manager or delegator is not valid service id.");
20169
+ const current = this.updatedState.getPrivilegedServices();
20170
+ const isManager = current.manager === this.currentServiceId;
20171
+ if (Compatibility.isLessThan(GpVersion.V0_7_1)) {
20172
+ if (!isManager) {
20173
+ return result_Result.error(UpdatePrivilegesError.UnprivilegedService, () => `Service ${this.currentServiceId} is not manager`);
20174
+ }
20175
+ if (manager === null || delegator === null) {
20176
+ return result_Result.error(UpdatePrivilegesError.InvalidServiceId, () => "Either manager or delegator is not a valid service id.");
20177
+ }
20178
+ this.updatedState.stateUpdate.privilegedServices = PrivilegedServices.create({
20179
+ manager,
20180
+ assigners: authorizers,
20181
+ delegator: delegator,
20182
+ registrar: registrar ?? tryAsServiceId(0),
20183
+ autoAccumulateServices: autoAccumulate.map(([service, gasLimit]) => AutoAccumulate.create({ service, gasLimit })),
20184
+ });
20185
+ return result_Result.ok(result_OK);
19906
20186
  }
19907
- if (Compatibility.isGreaterOrEqual(GpVersion.V0_7_1) && registrar === null) {
19908
- return result_Result.error(UpdatePrivilegesError.InvalidServiceId, "Register manager is not valid service id.");
20187
+ const original = this.updatedState.state.privilegedServices;
20188
+ if (manager === null || delegator === null || registrar === null) {
20189
+ return result_Result.error(UpdatePrivilegesError.InvalidServiceId, () => "Either manager or delegator or registrar is not a valid service id.");
19909
20190
  }
20191
+ const newDelegator = this.updatePrivilegedServiceId(delegator, current.delegator, {
20192
+ isManager,
20193
+ isSelf: this.currentServiceId === current.delegator,
20194
+ isAlreadyChanged: current.delegator !== original.delegator,
20195
+ });
20196
+ const newRegistrar = this.updatePrivilegedServiceId(registrar, current.registrar, {
20197
+ isManager,
20198
+ isSelf: this.currentServiceId === current.registrar,
20199
+ isAlreadyChanged: current.registrar !== original.registrar,
20200
+ });
20201
+ const newAssigners = current.assigners.map((currentAssigner, index) => this.updatePrivilegedServiceId(authorizers[index], currentAssigner, {
20202
+ isManager,
20203
+ isSelf: this.currentServiceId === currentAssigner,
20204
+ isAlreadyChanged: currentAssigner !== original.assigners[index],
20205
+ }));
20206
+ const newManager = isManager ? manager : current.manager;
20207
+ const newAutoAccumulateServices = isManager
20208
+ ? autoAccumulate.map(([service, gasLimit]) => AutoAccumulate.create({ service, gasLimit }))
20209
+ : current.autoAccumulateServices;
20210
+ // finally update the privileges
19910
20211
  this.updatedState.stateUpdate.privilegedServices = PrivilegedServices.create({
19911
- manager,
19912
- assigners: authorizers,
19913
- delegator,
19914
- registrar: registrar ?? tryAsServiceId(0), // introduced in 0.7.1
19915
- autoAccumulateServices: autoAccumulate.map(([service, gasLimit]) => AutoAccumulate.create({ service, gasLimit })),
20212
+ manager: newManager,
20213
+ assigners: tryAsPerCore(newAssigners, this.chainSpec),
20214
+ delegator: newDelegator,
20215
+ registrar: newRegistrar,
20216
+ autoAccumulateServices: newAutoAccumulateServices,
19916
20217
  });
19917
20218
  return result_Result.ok(result_OK);
19918
20219
  }
@@ -19925,23 +20226,22 @@ class AccumulateExternalities {
19925
20226
  // TODO [ToDr] what about newly created services?
19926
20227
  const service = serviceId === null ? null : this.updatedState.state.getService(serviceId);
19927
20228
  if (service === null || serviceId === null) {
19928
- return result_Result.error(ProvidePreimageError.ServiceNotFound);
20229
+ return result_Result.error(ProvidePreimageError.ServiceNotFound, () => `Service not found: ${serviceId}`);
19929
20230
  }
19930
20231
  // calculating the hash
19931
20232
  const preimageHash = this.blake2b.hashBytes(preimage).asOpaque();
19932
20233
  // checking service internal lookup
19933
20234
  const stateLookup = this.updatedState.getLookupHistory(this.currentTimeslot, serviceId, preimageHash, numbers_tryAsU64(preimage.length));
19934
20235
  if (stateLookup === null || !LookupHistoryItem.isRequested(stateLookup)) {
19935
- return result_Result.error(ProvidePreimageError.WasNotRequested);
20236
+ return result_Result.error(ProvidePreimageError.WasNotRequested, () => `Preimage was not requested: hash=${preimageHash}, service=${serviceId}`);
19936
20237
  }
19937
20238
  // checking already provided preimages
19938
20239
  const hasPreimage = this.updatedState.hasPreimage(serviceId, preimageHash);
19939
20240
  if (hasPreimage) {
19940
- return result_Result.error(ProvidePreimageError.AlreadyProvided);
20241
+ return result_Result.error(ProvidePreimageError.AlreadyProvided, () => `Preimage already provided: hash=${preimageHash}, service=${serviceId}`);
19941
20242
  }
19942
20243
  // setting up the new preimage
19943
- this.updatedState.updatePreimage(UpdatePreimage.provide({
19944
- serviceId,
20244
+ this.updatedState.updatePreimage(serviceId, UpdatePreimage.provide({
19945
20245
  preimage: PreimageItem.create({
19946
20246
  hash: preimageHash,
19947
20247
  blob: preimage,
@@ -19953,31 +20253,31 @@ class AccumulateExternalities {
19953
20253
  eject(destination, previousCodeHash) {
19954
20254
  const service = this.getServiceInfo(destination);
19955
20255
  if (service === null || destination === null) {
19956
- return result_Result.error(EjectError.InvalidService, "Service missing");
20256
+ return result_Result.error(EjectError.InvalidService, () => "Service missing");
19957
20257
  }
19958
20258
  const currentService = this.getCurrentServiceInfo();
19959
20259
  // check if the service expects to be ejected by us:
19960
20260
  const expectedCodeHash = bytes_Bytes.zero(hash_HASH_SIZE).asOpaque();
19961
20261
  writeServiceIdAsLeBytes(this.currentServiceId, expectedCodeHash.raw);
19962
20262
  if (!service.codeHash.isEqualTo(expectedCodeHash)) {
19963
- return result_Result.error(EjectError.InvalidService, "Invalid code hash");
20263
+ return result_Result.error(EjectError.InvalidService, () => "Invalid code hash");
19964
20264
  }
19965
20265
  // make sure the service only has required number of storage items?
19966
20266
  if (service.storageUtilisationCount !== REQUIRED_NUMBER_OF_STORAGE_ITEMS_FOR_EJECT) {
19967
- return result_Result.error(EjectError.InvalidPreimage, "Too many storage items");
20267
+ return result_Result.error(EjectError.InvalidPreimage, () => "Too many storage items");
19968
20268
  }
19969
20269
  // storage items length
19970
20270
  const l = numbers_tryAsU64(maxU64(service.storageUtilisationBytes, LOOKUP_HISTORY_ENTRY_BYTES) - LOOKUP_HISTORY_ENTRY_BYTES);
19971
20271
  // check if we have a preimage with the entire storage.
19972
20272
  const [isPreviousCodeExpired, errorReason] = this.isPreviousCodeExpired(destination, previousCodeHash, l);
19973
20273
  if (!isPreviousCodeExpired) {
19974
- return result_Result.error(EjectError.InvalidPreimage, `Previous code available: ${errorReason}`);
20274
+ return result_Result.error(EjectError.InvalidPreimage, () => `Previous code available: ${errorReason}`);
19975
20275
  }
19976
20276
  // compute new balance of the service.
19977
20277
  const newBalance = sumU64(currentService.balance, service.balance);
19978
20278
  // TODO [ToDr] what to do in case of overflow?
19979
20279
  if (newBalance.overflow) {
19980
- return result_Result.error(EjectError.InvalidService, "Balance overflow");
20280
+ return result_Result.error(EjectError.InvalidService, () => "Balance overflow");
19981
20281
  }
19982
20282
  // update current service.
19983
20283
  this.updatedState.updateServiceInfo(this.currentServiceId, ServiceAccountInfo.create({
@@ -19985,11 +20285,13 @@ class AccumulateExternalities {
19985
20285
  balance: newBalance.value,
19986
20286
  }));
19987
20287
  // and finally add an ejected service.
19988
- this.updatedState.stateUpdate.services.servicesRemoved.push(destination);
20288
+ this.updatedState.stateUpdate.services.removed.push(destination);
19989
20289
  // take care of the code preimage and its lookup history
19990
20290
  // Safe, because we know the preimage is valid, and it's the code of the service, which is bounded by maximal service code size anyway (much smaller than 2**32 bytes).
19991
20291
  const preimageLength = numbers_tryAsU32(Number(l));
19992
- this.updatedState.stateUpdate.services.preimages.push(UpdatePreimage.remove({ serviceId: destination, hash: previousCodeHash, length: preimageLength }));
20292
+ const preimages = this.updatedState.stateUpdate.services.preimages.get(destination) ?? [];
20293
+ preimages.push(UpdatePreimage.remove({ hash: previousCodeHash, length: preimageLength }));
20294
+ this.updatedState.stateUpdate.services.preimages.set(destination, preimages);
19993
20295
  return result_Result.ok(result_OK);
19994
20296
  }
19995
20297
  read(serviceId, rawKey) {
@@ -20170,10 +20472,10 @@ class Assurances {
20170
20472
  for (const assurance of assurances) {
20171
20473
  const { anchor, validatorIndex, bitfield } = assurance;
20172
20474
  if (!anchor.isEqualTo(input.parentHash)) {
20173
- return result_Result.error(AssurancesError.InvalidAnchor, `anchor: expected: ${input.parentHash}, got ${anchor}`);
20475
+ return result_Result.error(AssurancesError.InvalidAnchor, () => `anchor: expected: ${input.parentHash}, got ${anchor}`);
20174
20476
  }
20175
20477
  if (prevValidatorIndex >= validatorIndex) {
20176
- return result_Result.error(AssurancesError.InvalidOrder, `order: expected: ${prevValidatorIndex + 1}, got: ${validatorIndex}`);
20478
+ return result_Result.error(AssurancesError.InvalidOrder, () => `order: expected: ${prevValidatorIndex + 1}, got: ${validatorIndex}`);
20177
20479
  }
20178
20480
  prevValidatorIndex = assurance.validatorIndex;
20179
20481
  debug_check `${bitfield.bitLength === coresCount} Invalid bitfield length of ${bitfield.bitLength}`;
@@ -20196,7 +20498,7 @@ class Assurances {
20196
20498
  * https://graypaper.fluffylabs.dev/#/579bd12/14e90014ea00
20197
20499
  */
20198
20500
  if (noOfAssurances > 0 && !isReportPending) {
20199
- return result_Result.error(AssurancesError.NoReportPending, `no report pending for core ${c} yet we got an assurance`);
20501
+ return result_Result.error(AssurancesError.NoReportPending, () => `no report pending for core ${c} yet we got an assurance`);
20200
20502
  }
20201
20503
  /**
20202
20504
  * Remove work report if it's became available or timed out.
@@ -20242,7 +20544,7 @@ class Assurances {
20242
20544
  const v = assurance.view();
20243
20545
  const key = validatorData[v.validatorIndex.materialize()];
20244
20546
  if (key === undefined) {
20245
- return result_Result.error(AssurancesError.InvalidValidatorIndex);
20547
+ return result_Result.error(AssurancesError.InvalidValidatorIndex, () => `Invalid validator index: ${v.validatorIndex.materialize()}`);
20246
20548
  }
20247
20549
  signatures.push({
20248
20550
  signature: v.signature.materialize(),
@@ -20254,7 +20556,7 @@ class Assurances {
20254
20556
  const isAllSignaturesValid = signaturesValid.every((x) => x);
20255
20557
  if (!isAllSignaturesValid) {
20256
20558
  const invalidIndices = signaturesValid.reduce((acc, isValid, idx) => (isValid ? acc : acc.concat(idx)), []);
20257
- return result_Result.error(AssurancesError.InvalidSignature, `invalid signatures at ${invalidIndices.join(", ")}`);
20559
+ return result_Result.error(AssurancesError.InvalidSignature, () => `invalid signatures at ${invalidIndices.join(", ")}`);
20258
20560
  }
20259
20561
  return result_Result.ok(result_OK);
20260
20562
  }
@@ -20865,7 +21167,7 @@ class HostCallMemory {
20865
21167
  return result_Result.ok(result_OK);
20866
21168
  }
20867
21169
  if (address + numbers_tryAsU64(bytes.length) > MEMORY_SIZE) {
20868
- return result_Result.error(new OutOfBounds());
21170
+ return result_Result.error(new OutOfBounds(), () => `Memory access out of bounds: address ${address} + length ${bytes.length} exceeds memory size`);
20869
21171
  }
20870
21172
  return this.memory.storeFrom(tryAsMemoryIndex(Number(address)), bytes);
20871
21173
  }
@@ -20874,13 +21176,10 @@ class HostCallMemory {
20874
21176
  return result_Result.ok(result_OK);
20875
21177
  }
20876
21178
  if (startAddress + numbers_tryAsU64(result.length) > MEMORY_SIZE) {
20877
- return result_Result.error(new OutOfBounds());
21179
+ return result_Result.error(new OutOfBounds(), () => `Memory access out of bounds: address ${startAddress} + length ${result.length} exceeds memory size`);
20878
21180
  }
20879
21181
  return this.memory.loadInto(result, tryAsMemoryIndex(Number(startAddress)));
20880
21182
  }
20881
- getMemory() {
20882
- return this.memory;
20883
- }
20884
21183
  }
20885
21184
 
20886
21185
  ;// CONCATENATED MODULE: ./packages/core/pvm-host-calls/host-call-registers.ts
@@ -21159,7 +21458,7 @@ class Assign {
21159
21458
  // NOTE: Here we know the core index is valid
21160
21459
  const coreIndex = tryAsCoreIndex(Number(maybeCoreIndex));
21161
21460
  const decoder = decoder_Decoder.fromBlob(res);
21162
- const authQueue = decoder.sequenceFixLen(descriptors_codec.bytes(hash_HASH_SIZE), AUTHORIZATION_QUEUE_SIZE);
21461
+ const authQueue = decoder.sequenceFixLen(descriptors_codec.bytes(hash_HASH_SIZE).asOpaque(), AUTHORIZATION_QUEUE_SIZE);
21163
21462
  const fixedSizeAuthQueue = FixedSizeArray.new(authQueue, AUTHORIZATION_QUEUE_SIZE);
21164
21463
  const result = this.partialState.updateAuthorizationQueue(coreIndex, fixedSizeAuthQueue, assigners);
21165
21464
  if (result.isOk) {
@@ -21271,6 +21570,7 @@ class Bless {
21271
21570
  return;
21272
21571
  }
21273
21572
  const e = updateResult.error;
21573
+ // NOTE: `UpdatePrivilegesError.UnprivilegedService` won't happen in 0.7.1+
21274
21574
  if (e === UpdatePrivilegesError.UnprivilegedService) {
21275
21575
  logger_logger.trace `BLESS(${manager}, ${authorizers}, ${delegator}, ${registrar}, ${autoAccumulateEntries}) <- HUH`;
21276
21576
  regs.set(bless_IN_OUT_REG, HostCallResult.HUH);
@@ -21354,7 +21654,7 @@ class Checkpoint {
21354
21654
 
21355
21655
 
21356
21656
  const designate_IN_OUT_REG = 7;
21357
- const VALIDATOR_DATA_BYTES = tryAsExactBytes(ValidatorData.Codec.sizeHint);
21657
+ const VALIDATOR_DATA_BYTES = tryAsExactBytes(validator_data_ValidatorData.Codec.sizeHint);
21358
21658
  /**
21359
21659
  * Designate a new set of validator keys.
21360
21660
  *
@@ -21383,7 +21683,7 @@ class Designate {
21383
21683
  return PvmExecution.Panic;
21384
21684
  }
21385
21685
  const decoder = decoder_Decoder.fromBlob(res);
21386
- const validatorsData = decoder.sequenceFixLen(ValidatorData.Codec, this.chainSpec.validatorsCount);
21686
+ const validatorsData = decoder.sequenceFixLen(validator_data_ValidatorData.Codec, this.chainSpec.validatorsCount);
21387
21687
  const result = this.partialState.updateValidatorsData(tryAsPerValidator(validatorsData, this.chainSpec));
21388
21688
  if (result.isError) {
21389
21689
  logger_logger.trace `DESIGNATE([${validatorsData[0]}, ${validatorsData[1]}, ...]) <- HUH`;
@@ -22265,7 +22565,7 @@ class Lookup {
22265
22565
  }
22266
22566
  // v
22267
22567
  const preImage = this.account.lookup(serviceId, preImageHash);
22268
- logger_logger.trace `LOOKUP(${serviceId}, ${preImageHash}) <- ${preImage?.toStringTruncated()}...`;
22568
+ logger_logger.trace `LOOKUP(${serviceId}, ${preImageHash}) <- ${preImage?.toStringTruncated() ?? "<missing>"}...`;
22269
22569
  const preImageLength = preImage === null ? numbers_tryAsU64(0) : numbers_tryAsU64(preImage.raw.length);
22270
22570
  const preimageBlobOffset = regs.get(10);
22271
22571
  const lengthToWrite = regs.get(11);
@@ -22815,25 +23115,25 @@ class Accumulate {
22815
23115
  *
22816
23116
  * https://graypaper.fluffylabs.dev/#/7e6ff6a/2fdb012fdb01?v=0.6.7
22817
23117
  */
22818
- async pvmAccumulateInvocation(slot, serviceId, transfers, operands, gas, entropy, inputStateUpdate) {
22819
- const service = this.state.getService(serviceId);
22820
- if (service === null) {
23118
+ async pvmAccumulateInvocation(slot, serviceId, transfers, operands, gas, entropy, updatedState) {
23119
+ const serviceInfo = updatedState.getServiceInfo(serviceId);
23120
+ if (serviceInfo === null) {
22821
23121
  accumulate_logger.log `Service with id ${serviceId} not found.`;
22822
- return result_Result.error(PvmInvocationError.NoService);
23122
+ return result_Result.error(PvmInvocationError.NoService, () => `Accumulate: service ${serviceId} not found`);
22823
23123
  }
22824
- const codeHash = service.getInfo().codeHash;
23124
+ const codeHash = serviceInfo.codeHash;
22825
23125
  // TODO [ToDr] Should we check that the preimage is still available?
22826
- const code = service.getPreimage(codeHash.asOpaque());
23126
+ const code = updatedState.getPreimage(serviceId, codeHash.asOpaque());
22827
23127
  if (code === null) {
22828
23128
  accumulate_logger.log `Code with hash ${codeHash} not found for service ${serviceId}.`;
22829
- return result_Result.error(PvmInvocationError.NoPreimage);
23129
+ return result_Result.error(PvmInvocationError.NoPreimage, () => `Accumulate: code with hash ${codeHash} not found for service ${serviceId}`);
22830
23130
  }
22831
23131
  if (code.length > W_C) {
22832
23132
  accumulate_logger.log `Code with hash ${codeHash} is too long for service ${serviceId}.`;
22833
- return result_Result.error(PvmInvocationError.PreimageTooLong);
23133
+ return result_Result.error(PvmInvocationError.PreimageTooLong, () => `Accumulate: code length ${code.length} exceeds max ${W_C} for service ${serviceId}`);
22834
23134
  }
22835
23135
  const nextServiceId = generateNextServiceId({ serviceId, entropy, timeslot: slot }, this.chainSpec, this.blake2b);
22836
- const partialState = new AccumulateExternalities(this.chainSpec, this.blake2b, new PartiallyUpdatedState(this.state, inputStateUpdate), serviceId, nextServiceId, slot);
23136
+ const partialState = new AccumulateExternalities(this.chainSpec, this.blake2b, updatedState, serviceId, nextServiceId, slot);
22837
23137
  const fetchExternalities = Compatibility.isGreaterOrEqual(GpVersion.V0_7_1)
22838
23138
  ? FetchExternalities.createForAccumulate({ entropy, transfers, operands }, this.chainSpec)
22839
23139
  : FetchExternalities.createForPre071Accumulate({ entropy, operands }, this.chainSpec);
@@ -22887,11 +23187,28 @@ class Accumulate {
22887
23187
  */
22888
23188
  async accumulateSingleService(serviceId, transfers, operands, gasCost, slot, entropy, inputStateUpdate) {
22889
23189
  accumulate_logger.log `Accumulating service ${serviceId}, transfers: ${transfers.length} operands: ${operands.length} at slot: ${slot}.`;
22890
- const result = await this.pvmAccumulateInvocation(slot, serviceId, transfers, operands, gasCost, entropy, inputStateUpdate);
23190
+ const updatedState = new PartiallyUpdatedState(this.state, inputStateUpdate);
23191
+ // update service balance from incoming transfers
23192
+ if (Compatibility.isGreaterOrEqual(GpVersion.V0_7_1)) {
23193
+ const serviceInfo = updatedState.getServiceInfo(serviceId);
23194
+ if (serviceInfo !== null) {
23195
+ // update the balance from incoming tranfsers
23196
+ const newBalance = sumU64(serviceInfo.balance, ...transfers.map((item) => item.amount));
23197
+ if (newBalance.overflow) {
23198
+ accumulate_logger.log `Accumulation failed because of overflowing balance ${serviceId}.`;
23199
+ return { stateUpdate: null, consumedGas: 0n };
23200
+ }
23201
+ const newInfo = ServiceAccountInfo.create({ ...serviceInfo, balance: newBalance.value });
23202
+ updatedState.updateServiceInfo(serviceId, newInfo);
23203
+ }
23204
+ }
23205
+ const result = await this.pvmAccumulateInvocation(slot, serviceId, transfers, operands, gasCost, entropy, updatedState);
22891
23206
  if (result.isError) {
22892
- // https://graypaper.fluffylabs.dev/#/7e6ff6a/2fb6012fb601?v=0.6.7
23207
+ // https://graypaper.fluffylabs.dev/#/ab2cdbd/2fc9032fc903?v=0.7.2
22893
23208
  accumulate_logger.log `Accumulation failed for ${serviceId}.`;
22894
- return { stateUpdate: null, consumedGas: 0n };
23209
+ // even though accumulation failed, we still need to make sure that
23210
+ // incoming transfers updated the balance, hence we pass state update here
23211
+ return { stateUpdate: updatedState.stateUpdate, consumedGas: 0n };
22895
23212
  }
22896
23213
  accumulate_logger.log `Accumulation successful for ${serviceId}. Consumed: ${result.ok.consumedGas}`;
22897
23214
  return result.ok;
@@ -22949,7 +23266,7 @@ class Accumulate {
22949
23266
  const accumulateData = new AccumulateData(reportsToAccumulateInParallel, transfers, autoAccumulateServices);
22950
23267
  const reportsToAccumulateSequentially = reports.subview(i);
22951
23268
  const { gasCost, state: stateAfterParallelAcc, ...rest } = await this.accumulateInParallel(accumulateData, slot, entropy, statistics, stateUpdate);
22952
- const newTransfers = stateAfterParallelAcc.transfers;
23269
+ const newTransfers = stateAfterParallelAcc.takeTransfers();
22953
23270
  assertEmpty(rest);
22954
23271
  // NOTE [ToDr] recursive invocation
22955
23272
  const { accumulatedReports, gasCost: seqGasCost, state, ...seqRest } = await this.accumulateSequentially(tryAsServiceGas(gasLimit - gasCost), reportsToAccumulateSequentially, newTransfers, slot, entropy, statistics, stateAfterParallelAcc, []);
@@ -22977,12 +23294,19 @@ class Accumulate {
22977
23294
  const currentManager = (inputStateUpdate.privilegedServices ?? this.state.privilegedServices).manager;
22978
23295
  for (const serviceId of serviceIds) {
22979
23296
  const checkpoint = AccumulationStateUpdate.copyFrom(currentState);
22980
- const { consumedGas, stateUpdate } = await this.accumulateSingleService(serviceId, accumulateData.getTransfers(serviceId), accumulateData.getOperands(serviceId), accumulateData.getGasCost(serviceId), slot, entropy, currentState);
23297
+ const operands = accumulateData.getOperands(serviceId);
23298
+ const { consumedGas, stateUpdate } = await this.accumulateSingleService(serviceId, accumulateData.getTransfers(serviceId), operands, accumulateData.getGasCost(serviceId), slot, entropy, currentState);
22981
23299
  gasCost = tryAsServiceGas(gasCost + consumedGas);
23300
+ // https://graypaper.fluffylabs.dev/#/ab2cdbd/193b05193b05?v=0.7.2
22982
23301
  const serviceStatistics = statistics.get(serviceId) ?? { count: numbers_tryAsU32(0), gasUsed: tryAsServiceGas(0) };
22983
- serviceStatistics.count = numbers_tryAsU32(serviceStatistics.count + accumulateData.getReportsLength(serviceId));
22984
- serviceStatistics.gasUsed = tryAsServiceGas(serviceStatistics.gasUsed + consumedGas);
22985
- statistics.set(serviceId, serviceStatistics);
23302
+ const count = accumulateData.getReportsLength(serviceId);
23303
+ // [0.7.1]: do not update statistics, if the service only had incoming transfers
23304
+ if ((Compatibility.isLessThan(GpVersion.V0_7_2) && count > 0) ||
23305
+ (Compatibility.isGreaterOrEqual(GpVersion.V0_7_2) && (count > 0 || consumedGas > 0n))) {
23306
+ serviceStatistics.count = numbers_tryAsU32(serviceStatistics.count + count);
23307
+ serviceStatistics.gasUsed = tryAsServiceGas(serviceStatistics.gasUsed + consumedGas);
23308
+ statistics.set(serviceId, serviceStatistics);
23309
+ }
22986
23310
  currentState = stateUpdate === null ? checkpoint : stateUpdate;
22987
23311
  if (Compatibility.is(GpVersion.V0_7_0) && serviceId === currentManager) {
22988
23312
  const newV = currentState.privilegedServices?.delegator;
@@ -23017,9 +23341,10 @@ class Accumulate {
23017
23341
  const recentlyAccumulated = tryAsPerEpochBlock(newRecentlyAccumulated, this.chainSpec);
23018
23342
  const accumulationQueue = this.state.accumulationQueue.slice();
23019
23343
  accumulationQueue[phaseIndex] = pruneQueue(toAccumulateLater, accumulatedSet);
23344
+ const timeslot = this.state.timeslot;
23020
23345
  for (let i = 1; i < epochLength; i++) {
23021
23346
  const queueIndex = (phaseIndex + epochLength - i) % epochLength;
23022
- if (i < slot - this.state.timeslot) {
23347
+ if (i < slot - timeslot) {
23023
23348
  accumulationQueue[queueIndex] = [];
23024
23349
  }
23025
23350
  else {
@@ -23034,6 +23359,7 @@ class Accumulate {
23034
23359
  const info = partialStateUpdate.getServiceInfo(serviceId);
23035
23360
  if (info === null) {
23036
23361
  // NOTE If there is no service, we dont update it.
23362
+ accumulate_logger.log `Skipping update of ${serviceId}, because we have no service info.`;
23037
23363
  continue;
23038
23364
  }
23039
23365
  // δ‡
@@ -23059,19 +23385,16 @@ class Accumulate {
23059
23385
  const gasLimit = tryAsServiceGas(this.chainSpec.maxBlockGas > calculatedGasLimit ? this.chainSpec.maxBlockGas : calculatedGasLimit);
23060
23386
  return tryAsServiceGas(gasLimit);
23061
23387
  }
23062
- hasDuplicatedServicesCreated(updateServices) {
23063
- const createdServiceIds = new Set();
23064
- for (const update of updateServices) {
23065
- if (update.action.kind === UpdateServiceKind.Create) {
23066
- const serviceId = update.serviceId;
23067
- if (createdServiceIds.has(serviceId)) {
23068
- accumulate_logger.log `Duplicated Service creation detected ${serviceId}. Block is invalid.`;
23069
- return true;
23070
- }
23071
- createdServiceIds.add(serviceId);
23072
- }
23073
- }
23074
- return false;
23388
+ /**
23389
+ * Detects the very unlikely situation where multiple services are created with the same ID.
23390
+ *
23391
+ * https://graypaper.fluffylabs.dev/#/ab2cdbd/30f20330f403?v=0.7.2
23392
+ *
23393
+ * NOTE: This is public only for testing purposes and should not be used outside of accumulation.
23394
+ */
23395
+ hasDuplicatedServiceIdCreated(createdIds) {
23396
+ const uniqueIds = new Set(createdIds);
23397
+ return uniqueIds.size !== createdIds.length;
23075
23398
  }
23076
23399
  async transition({ reports, slot, entropy }) {
23077
23400
  const statistics = new Map();
@@ -23093,8 +23416,9 @@ class Accumulate {
23093
23416
  const accumulated = accumulatableReports.subview(0, accumulatedReports);
23094
23417
  const { services, yieldedRoots, transfers, validatorsData, privilegedServices, authorizationQueues, ...stateUpdateRest } = state;
23095
23418
  assertEmpty(stateUpdateRest);
23096
- if (this.hasDuplicatedServicesCreated(services.servicesUpdates)) {
23097
- return result_Result.error(ACCUMULATION_ERROR);
23419
+ if (this.hasDuplicatedServiceIdCreated(services.created)) {
23420
+ accumulate_logger.trace `Duplicated Service creation detected. Block is invalid.`;
23421
+ return result_Result.error(ACCUMULATION_ERROR, () => "Accumulate: duplicate service created");
23098
23422
  }
23099
23423
  const accStateUpdate = this.getAccumulationStateUpdate(accumulated.toArray(), toAccumulateLater, slot, Array.from(statistics.keys()), services);
23100
23424
  const accumulationOutputUnsorted = Array.from(yieldedRoots.entries()).map(([serviceId, root]) => {
@@ -23175,13 +23499,13 @@ class DeferredTransfers {
23175
23499
  .toSorted((a, b) => a.source - b.source);
23176
23500
  const info = partiallyUpdatedState.getServiceInfo(serviceId);
23177
23501
  if (info === null) {
23178
- return result_Result.error(DeferredTransfersErrorCode.ServiceInfoNotExist);
23502
+ return result_Result.error(DeferredTransfersErrorCode.ServiceInfoNotExist, () => `Deferred transfers: service info not found for ${serviceId}`);
23179
23503
  }
23180
23504
  const codeHash = info.codeHash;
23181
23505
  const code = partiallyUpdatedState.getPreimage(serviceId, codeHash.asOpaque());
23182
23506
  const newBalance = sumU64(info.balance, ...transfers.map((item) => item.amount));
23183
23507
  if (newBalance.overflow) {
23184
- return result_Result.error(DeferredTransfersErrorCode.ServiceBalanceOverflow);
23508
+ return result_Result.error(DeferredTransfersErrorCode.ServiceBalanceOverflow, () => `Deferred transfers: balance overflow for service ${serviceId}`);
23185
23509
  }
23186
23510
  const newInfo = ServiceAccountInfo.create({ ...info, balance: newBalance.value });
23187
23511
  partiallyUpdatedState.updateServiceInfo(serviceId, newInfo);
@@ -23230,7 +23554,6 @@ class DeferredTransfers {
23230
23554
 
23231
23555
 
23232
23556
 
23233
-
23234
23557
  /**
23235
23558
  * Maintain a list of available authorizations per core.
23236
23559
  *
@@ -23259,11 +23582,12 @@ class Authorization {
23259
23582
  */
23260
23583
  transition(input) {
23261
23584
  const authPoolsUpdate = this.state.authPools.slice();
23585
+ const authQueues = this.state.authQueues;
23262
23586
  // we transition authorizations for each core.
23263
23587
  for (let coreIndex = tryAsCoreIndex(0); coreIndex < this.chainSpec.coresCount; coreIndex++) {
23264
23588
  let pool = authPoolsUpdate[coreIndex].slice();
23265
23589
  // the queue is only read (we should most likely use `ArrayView` here).
23266
- const queue = this.state.authQueues[coreIndex];
23590
+ const queue = authQueues[coreIndex];
23267
23591
  // if there were any used hashes - remove them
23268
23592
  const usedHashes = input.used.get(coreIndex);
23269
23593
  if (usedHashes !== undefined) {
@@ -23437,14 +23761,18 @@ class RecentHistory {
23437
23761
  * https://graypaper.fluffylabs.dev/#/1c979cb/0f55020f5502?v=0.7.1
23438
23762
  */
23439
23763
  partialTransition(input) {
23440
- const recentBlocks = this.state.recentBlocks.blocks.slice();
23764
+ const stateBlocks = this.state.recentBlocks;
23765
+ const recentBlocks = stateBlocks.blocks.slice();
23441
23766
  const lastState = recentBlocks.length > 0 ? recentBlocks[recentBlocks.length - 1] : null;
23442
23767
  // update the posterior root of previous state.
23443
23768
  if (lastState !== null) {
23444
23769
  lastState.postStateRoot = input.priorStateRoot;
23445
23770
  }
23446
23771
  return {
23447
- recentBlocks: this.state.recentBlocks.updateBlocks(recentBlocks), // β_H†
23772
+ recentBlocks: RecentBlocks.create({
23773
+ blocks: sized_array_asKnownSize(recentBlocks),
23774
+ accumulationLog: stateBlocks.accumulationLog,
23775
+ }), // β_H†
23448
23776
  };
23449
23777
  }
23450
23778
  /**
@@ -23456,8 +23784,8 @@ class RecentHistory {
23456
23784
  transition(input) {
23457
23785
  const recentBlocks = input.partial.recentBlocks.blocks.slice();
23458
23786
  // `β′_B`
23459
- const mmr = this.state.recentBlocks.asCurrent().accumulationLog !== null
23460
- ? MerkleMountainRange.fromPeaks(this.hasher, this.state.recentBlocks.asCurrent().accumulationLog)
23787
+ const mmr = this.state.recentBlocks.accumulationLog !== null
23788
+ ? MerkleMountainRange.fromPeaks(this.hasher, this.state.recentBlocks.accumulationLog)
23461
23789
  : MerkleMountainRange.empty(this.hasher);
23462
23790
  // append the accumulation root
23463
23791
  mmr.append(input.accumulateRoot);
@@ -23475,7 +23803,7 @@ class RecentHistory {
23475
23803
  }
23476
23804
  // write back to the state.
23477
23805
  return {
23478
- recentBlocks: RecentBlocksHistory.create(RecentBlocks.create({
23806
+ recentBlocks: RecentBlocks.create(RecentBlocks.create({
23479
23807
  blocks: sized_array_asKnownSize(recentBlocks),
23480
23808
  accumulationLog: peaks,
23481
23809
  })),
@@ -23655,7 +23983,7 @@ function verifyReportsBasic(input) {
23655
23983
  const noOfPrerequisites = reportView.context.view().prerequisites.view().length;
23656
23984
  const noOfSegmentRootLookups = reportView.segmentRootLookup.view().length;
23657
23985
  if (noOfPrerequisites + noOfSegmentRootLookups > MAX_REPORT_DEPENDENCIES) {
23658
- return result_Result.error(ReportsError.TooManyDependencies, `Report at ${reportView.coreIndex.materialize()} has too many dependencies. Got ${noOfPrerequisites} + ${noOfSegmentRootLookups}, max: ${MAX_REPORT_DEPENDENCIES}`);
23986
+ return result_Result.error(ReportsError.TooManyDependencies, () => `Report at ${reportView.coreIndex.materialize()} has too many dependencies. Got ${noOfPrerequisites} + ${noOfSegmentRootLookups}, max: ${MAX_REPORT_DEPENDENCIES}`);
23659
23987
  }
23660
23988
  /**
23661
23989
  * In order to ensure fair use of a block’s extrinsic space,
@@ -23674,7 +24002,7 @@ function verifyReportsBasic(input) {
23674
24002
  totalOutputsSize += item.view().result.view().okBlob?.raw.length ?? 0;
23675
24003
  }
23676
24004
  if (authOutputSize + totalOutputsSize > MAX_WORK_REPORT_SIZE_BYTES) {
23677
- return result_Result.error(ReportsError.WorkReportTooBig, `Work report at ${reportView.coreIndex.materialize()} too big. Got ${authOutputSize} + ${totalOutputsSize}, max: ${MAX_WORK_REPORT_SIZE_BYTES}`);
24005
+ return result_Result.error(ReportsError.WorkReportTooBig, () => `Work report at ${reportView.coreIndex.materialize()} too big. Got ${authOutputSize} + ${totalOutputsSize}, max: ${MAX_WORK_REPORT_SIZE_BYTES}`);
23678
24006
  }
23679
24007
  }
23680
24008
  return result_Result.ok(result_OK);
@@ -23687,7 +24015,6 @@ function verifyReportsBasic(input) {
23687
24015
 
23688
24016
 
23689
24017
 
23690
-
23691
24018
  const verify_contextual_logger = Logger.new(import.meta.filename, "stf:reports");
23692
24019
  /** https://graypaper.fluffylabs.dev/#/7e6ff6a/15eb0115eb01?v=0.6.7 */
23693
24020
  function verifyContextualValidity(input, state, headerChain, maxLookupAnchorAge) {
@@ -23709,12 +24036,12 @@ function verifyContextualValidity(input, state, headerChain, maxLookupAnchorAge)
23709
24036
  for (const result of guarantee.report.results) {
23710
24037
  const service = state.getService(result.serviceId);
23711
24038
  if (service === null) {
23712
- return result_Result.error(ReportsError.BadServiceId, `No service with id: ${result.serviceId}`);
24039
+ return result_Result.error(ReportsError.BadServiceId, () => `No service with id: ${result.serviceId}`);
23713
24040
  }
23714
24041
  // check service code hash
23715
24042
  // https://graypaper.fluffylabs.dev/#/5f542d7/154b02154b02
23716
24043
  if (!result.codeHash.isEqualTo(service.getInfo().codeHash)) {
23717
- return result_Result.error(ReportsError.BadCodeHash, `Service (${result.serviceId}) code hash mismatch. Got: ${result.codeHash}, expected: ${service.getInfo().codeHash}`);
24044
+ return result_Result.error(ReportsError.BadCodeHash, () => `Service (${result.serviceId}) code hash mismatch. Got: ${result.codeHash}, expected: ${service.getInfo().codeHash}`);
23718
24045
  }
23719
24046
  }
23720
24047
  }
@@ -23725,7 +24052,7 @@ function verifyContextualValidity(input, state, headerChain, maxLookupAnchorAge)
23725
24052
  * https://graypaper.fluffylabs.dev/#/5f542d7/151f01152101
23726
24053
  */
23727
24054
  if (currentWorkPackages.size !== input.guarantees.length) {
23728
- return result_Result.error(ReportsError.DuplicatePackage, "Duplicate work package detected.");
24055
+ return result_Result.error(ReportsError.DuplicatePackage, () => "Duplicate work package detected.");
23729
24056
  }
23730
24057
  const minLookupSlot = Math.max(0, input.slot - maxLookupAnchorAge);
23731
24058
  const contextResult = verifyRefineContexts(minLookupSlot, contexts, input.recentBlocksPartialUpdate, headerChain);
@@ -23770,7 +24097,7 @@ function verifyContextualValidity(input, state, headerChain, maxLookupAnchorAge)
23770
24097
  : undefined;
23771
24098
  }
23772
24099
  if (root === undefined || !root.segmentTreeRoot.isEqualTo(lookup.segmentTreeRoot)) {
23773
- return result_Result.error(ReportsError.SegmentRootLookupInvalid, `Mismatching segment tree root for package ${lookup.workPackageHash}. Got: ${lookup.segmentTreeRoot}, expected: ${root?.segmentTreeRoot}`);
24100
+ return result_Result.error(ReportsError.SegmentRootLookupInvalid, () => `Mismatching segment tree root for package ${lookup.workPackageHash}. Got: ${lookup.segmentTreeRoot}, expected: ${root?.segmentTreeRoot}`);
23774
24101
  }
23775
24102
  }
23776
24103
  }
@@ -23793,16 +24120,16 @@ function verifyRefineContexts(minLookupSlot, contexts, recentBlocksPartialUpdate
23793
24120
  */
23794
24121
  const recentBlock = recentBlocks.get(context.anchor);
23795
24122
  if (recentBlock === undefined) {
23796
- return result_Result.error(ReportsError.AnchorNotRecent, `Anchor block ${context.anchor} not found in recent blocks.`);
24123
+ return result_Result.error(ReportsError.AnchorNotRecent, () => `Anchor block ${context.anchor} not found in recent blocks.`);
23797
24124
  }
23798
24125
  // check state root
23799
24126
  if (!recentBlock.postStateRoot.isEqualTo(context.stateRoot)) {
23800
- return result_Result.error(ReportsError.BadStateRoot, `Anchor state root mismatch. Got: ${context.stateRoot}, expected: ${recentBlock.postStateRoot}.`);
24127
+ return result_Result.error(ReportsError.BadStateRoot, () => `Anchor state root mismatch. Got: ${context.stateRoot}, expected: ${recentBlock.postStateRoot}.`);
23801
24128
  }
23802
24129
  // check beefy root
23803
- const beefyRoot = RecentBlocksHistory.accumulationResult(recentBlock);
24130
+ const beefyRoot = recentBlock.accumulationResult;
23804
24131
  if (!beefyRoot.isEqualTo(context.beefyRoot)) {
23805
- return result_Result.error(ReportsError.BadBeefyMmrRoot, `Invalid BEEFY super peak hash. Got: ${context.beefyRoot}, expected: ${beefyRoot}. Anchor: ${recentBlock.headerHash}`);
24132
+ return result_Result.error(ReportsError.BadBeefyMmrRoot, () => `Invalid BEEFY super peak hash. Got: ${context.beefyRoot}, expected: ${beefyRoot}. Anchor: ${recentBlock.headerHash}`);
23806
24133
  }
23807
24134
  /**
23808
24135
  * We require that each lookup-anchor block be within the
@@ -23811,7 +24138,7 @@ function verifyRefineContexts(minLookupSlot, contexts, recentBlocksPartialUpdate
23811
24138
  * https://graypaper.fluffylabs.dev/#/5f542d7/154601154701
23812
24139
  */
23813
24140
  if (context.lookupAnchorSlot < minLookupSlot) {
23814
- return result_Result.error(ReportsError.SegmentRootLookupInvalid, `Lookup anchor slot's too old. Got: ${context.lookupAnchorSlot}, minimal: ${minLookupSlot}`);
24141
+ return result_Result.error(ReportsError.SegmentRootLookupInvalid, () => `Lookup anchor slot's too old. Got: ${context.lookupAnchorSlot}, minimal: ${minLookupSlot}`);
23815
24142
  }
23816
24143
  /**
23817
24144
  * We also require that we have a record of it; this is one of
@@ -23828,7 +24155,7 @@ function verifyRefineContexts(minLookupSlot, contexts, recentBlocksPartialUpdate
23828
24155
  verify_contextual_logger.warn `Lookup anchor check for ${context.lookupAnchor} would fail, but override is active.`;
23829
24156
  }
23830
24157
  else {
23831
- return result_Result.error(ReportsError.SegmentRootLookupInvalid, `Lookup anchor is not found in chain. Hash: ${context.lookupAnchor} (slot: ${context.lookupAnchorSlot})`);
24158
+ return result_Result.error(ReportsError.SegmentRootLookupInvalid, () => `Lookup anchor is not found in chain. Hash: ${context.lookupAnchor} (slot: ${context.lookupAnchorSlot})`);
23832
24159
  }
23833
24160
  }
23834
24161
  }
@@ -23851,7 +24178,7 @@ function verifyDependencies({ currentWorkPackages, recentlyReported, prerequisit
23851
24178
  if (recentlyReported.has(preReqHash)) {
23852
24179
  continue;
23853
24180
  }
23854
- return result_Result.error(isSegmentRoot ? ReportsError.SegmentRootLookupInvalid : ReportsError.DependencyMissing, `Missing work package ${preReqHash} in current extrinsic or recent history.`);
24181
+ return result_Result.error(isSegmentRoot ? ReportsError.SegmentRootLookupInvalid : ReportsError.DependencyMissing, () => `Missing work package ${preReqHash} in current extrinsic or recent history.`);
23855
24182
  }
23856
24183
  return result_Result.ok(result_OK);
23857
24184
  };
@@ -23899,7 +24226,7 @@ function verifyWorkPackagesUniqueness(workPackageHashes, state) {
23899
24226
  // let's check if any of our packages is in the pipeline
23900
24227
  const intersection = packagesInPipeline.intersection(workPackageHashes);
23901
24228
  for (const packageHash of intersection) {
23902
- return result_Result.error(ReportsError.DuplicatePackage, `The same work package hash found in the pipeline (workPackageHash: ${packageHash})`);
24229
+ return result_Result.error(ReportsError.DuplicatePackage, () => `The same work package hash found in the pipeline (workPackageHash: ${packageHash})`);
23903
24230
  }
23904
24231
  return result_Result.ok(result_OK);
23905
24232
  }
@@ -23938,7 +24265,7 @@ workReportHashes, slot, getGuarantorAssignment) {
23938
24265
  const credentialsView = guaranteeView.credentials.view();
23939
24266
  if (credentialsView.length < REQUIRED_CREDENTIALS_RANGE[0] ||
23940
24267
  credentialsView.length > REQUIRED_CREDENTIALS_RANGE[1]) {
23941
- return result_Result.error(ReportsError.InsufficientGuarantees, `Invalid number of credentials. Expected ${REQUIRED_CREDENTIALS_RANGE}, got ${credentialsView.length}`);
24268
+ return result_Result.error(ReportsError.InsufficientGuarantees, () => `Invalid number of credentials. Expected ${REQUIRED_CREDENTIALS_RANGE}, got ${credentialsView.length}`);
23942
24269
  }
23943
24270
  /** Retrieve current core assignment. */
23944
24271
  const timeSlot = guaranteeView.slot.materialize();
@@ -23953,20 +24280,20 @@ workReportHashes, slot, getGuarantorAssignment) {
23953
24280
  const credentialView = credential.view();
23954
24281
  const validatorIndex = credentialView.validatorIndex.materialize();
23955
24282
  if (lastValidatorIndex >= validatorIndex) {
23956
- return result_Result.error(ReportsError.NotSortedOrUniqueGuarantors, `Credentials must be sorted by validator index. Got ${validatorIndex}, expected at least ${lastValidatorIndex + 1}`);
24283
+ return result_Result.error(ReportsError.NotSortedOrUniqueGuarantors, () => `Credentials must be sorted by validator index. Got ${validatorIndex}, expected at least ${lastValidatorIndex + 1}`);
23957
24284
  }
23958
24285
  lastValidatorIndex = validatorIndex;
23959
24286
  const signature = credentialView.signature.materialize();
23960
24287
  const guarantorData = guarantorAssignments[validatorIndex];
23961
24288
  if (guarantorData === undefined) {
23962
- return result_Result.error(ReportsError.BadValidatorIndex, `Invalid validator index: ${validatorIndex}`);
24289
+ return result_Result.error(ReportsError.BadValidatorIndex, () => `Invalid validator index: ${validatorIndex}`);
23963
24290
  }
23964
24291
  /**
23965
24292
  * Verify core assignment.
23966
24293
  * https://graypaper.fluffylabs.dev/#/5f542d7/14e40214e602
23967
24294
  */
23968
24295
  if (guarantorData.core !== coreIndex) {
23969
- return result_Result.error(ReportsError.WrongAssignment, `Invalid core assignment for validator ${validatorIndex}. Expected: ${guarantorData.core}, got: ${coreIndex}`);
24296
+ return result_Result.error(ReportsError.WrongAssignment, () => `Invalid core assignment for validator ${validatorIndex}. Expected: ${guarantorData.core}, got: ${coreIndex}`);
23970
24297
  }
23971
24298
  signaturesToVerify.push({
23972
24299
  signature,
@@ -24004,10 +24331,10 @@ function verifyReportsOrder(input, chainSpec) {
24004
24331
  const reportView = guarantee.view().report.view();
24005
24332
  const coreIndex = reportView.coreIndex.materialize();
24006
24333
  if (lastCoreIndex >= coreIndex) {
24007
- return result_Result.error(ReportsError.OutOfOrderGuarantee, `Core indices of work reports are not unique or in order. Got: ${coreIndex}, expected at least: ${lastCoreIndex + 1}`);
24334
+ return result_Result.error(ReportsError.OutOfOrderGuarantee, () => `Core indices of work reports are not unique or in order. Got: ${coreIndex}, expected at least: ${lastCoreIndex + 1}`);
24008
24335
  }
24009
24336
  if (coreIndex >= noOfCores) {
24010
- return result_Result.error(ReportsError.BadCoreIndex, `Invalid core index. Got: ${coreIndex}, max: ${noOfCores}`);
24337
+ return result_Result.error(ReportsError.BadCoreIndex, () => `Invalid core index. Got: ${coreIndex}, max: ${noOfCores}`);
24011
24338
  }
24012
24339
  lastCoreIndex = coreIndex;
24013
24340
  }
@@ -24032,7 +24359,7 @@ function verifyPostSignatureChecks(input, availabilityAssignment, authPools, ser
24032
24359
  * https://graypaper.fluffylabs.dev/#/5f542d7/15ea0015ea00
24033
24360
  */
24034
24361
  if (availabilityAssignment[coreIndex] !== null) {
24035
- return result_Result.error(ReportsError.CoreEngaged, `Report pending availability at core: ${coreIndex}`);
24362
+ return result_Result.error(ReportsError.CoreEngaged, () => `Report pending availability at core: ${coreIndex}`);
24036
24363
  }
24037
24364
  /**
24038
24365
  * A report is valid only if the authorizer hash is present
@@ -24042,9 +24369,10 @@ function verifyPostSignatureChecks(input, availabilityAssignment, authPools, ser
24042
24369
  * https://graypaper.fluffylabs.dev/#/5f542d7/15eb0015ed00
24043
24370
  */
24044
24371
  const authorizerHash = report.authorizerHash;
24045
- const authorizerPool = authPools[coreIndex];
24046
- if (authorizerPool.find((hash) => hash.isEqualTo(authorizerHash)) === undefined) {
24047
- return result_Result.error(ReportsError.CoreUnauthorized, `Authorizer hash not found in the pool of core ${coreIndex}: ${authorizerHash}`);
24372
+ const authorizerPool = authPools.get(coreIndex);
24373
+ const pool = authorizerPool?.materialize() ?? [];
24374
+ if (pool.find((hash) => hash.isEqualTo(authorizerHash)) === undefined) {
24375
+ return result_Result.error(ReportsError.CoreUnauthorized, () => `Authorizer hash not found in the pool of core ${coreIndex}: ${authorizerHash}`);
24048
24376
  }
24049
24377
  /**
24050
24378
  * We require that the gas allotted for accumulation of each
@@ -24056,17 +24384,17 @@ function verifyPostSignatureChecks(input, availabilityAssignment, authPools, ser
24056
24384
  for (const result of report.results) {
24057
24385
  const service = services(result.serviceId);
24058
24386
  if (service === null) {
24059
- return result_Result.error(ReportsError.BadServiceId, `No service with id: ${result.serviceId}`);
24387
+ return result_Result.error(ReportsError.BadServiceId, () => `No service with id: ${result.serviceId}`);
24060
24388
  }
24061
24389
  const info = service.getInfo();
24062
24390
  // check minimal accumulation gas
24063
24391
  if (result.gas < info.accumulateMinGas) {
24064
- return result_Result.error(ReportsError.ServiceItemGasTooLow, `Service (${result.serviceId}) gas is less than minimal. Got: ${result.gas}, expected at least: ${info.accumulateMinGas}`);
24392
+ return result_Result.error(ReportsError.ServiceItemGasTooLow, () => `Service (${result.serviceId}) gas is less than minimal. Got: ${result.gas}, expected at least: ${info.accumulateMinGas}`);
24065
24393
  }
24066
24394
  }
24067
24395
  const totalGas = sumU64(...report.results.map((x) => x.gas));
24068
24396
  if (totalGas.overflow || totalGas.value > G_A) {
24069
- return result_Result.error(ReportsError.WorkReportGasTooHigh, `Total gas too high. Got: ${totalGas.value} (ovfl: ${totalGas.overflow}), maximal: ${G_A}`);
24397
+ return result_Result.error(ReportsError.WorkReportGasTooHigh, () => `Total gas too high. Got: ${totalGas.value} (ovfl: ${totalGas.overflow}), maximal: ${G_A}`);
24070
24398
  }
24071
24399
  }
24072
24400
  return result_Result.ok(result_OK);
@@ -24152,7 +24480,7 @@ class Reports {
24152
24480
  }
24153
24481
  const reporters = SortedSet.fromArray(bytesBlobComparator, signaturesToVerify.ok.map((x) => x.key)).slice();
24154
24482
  if (hasAnyOffenders(reporters, input.offenders)) {
24155
- return result_Result.error(ReportsError.BannedValidator);
24483
+ return result_Result.error(ReportsError.BannedValidator, () => "One or more reporters are banned validators");
24156
24484
  }
24157
24485
  return result_Result.ok({
24158
24486
  stateUpdate: {
@@ -24173,7 +24501,8 @@ class Reports {
24173
24501
  return verifyCredentials(input.guarantees, workReportHashes, input.slot, (headerTimeSlot, guaranteeTimeSlot) => this.getGuarantorAssignment(headerTimeSlot, guaranteeTimeSlot, input.newEntropy));
24174
24502
  }
24175
24503
  verifyPostSignatureChecks(input, assurancesAvailAssignment) {
24176
- return verifyPostSignatureChecks(input, assurancesAvailAssignment, this.state.authPools, (id) => this.state.getService(id));
24504
+ const authPoolsView = this.state.view().authPoolsView();
24505
+ return verifyPostSignatureChecks(input, assurancesAvailAssignment, authPoolsView, (id) => this.state.getService(id));
24177
24506
  }
24178
24507
  verifyContextualValidity(input) {
24179
24508
  return verifyContextualValidity(input, this.state, this.headerChain, this.chainSpec.maxLookupAnchorAge);
@@ -24191,7 +24520,7 @@ class Reports {
24191
24520
  return signaturesToVerify[idx].key;
24192
24521
  })
24193
24522
  .filter((x) => x !== null);
24194
- return result_Result.error(ReportsError.BadSignature, `Invalid signatures for validators with keys: ${invalidKeys.join(", ")}`);
24523
+ return result_Result.error(ReportsError.BadSignature, () => `Invalid signatures for validators with keys: ${invalidKeys.join(", ")}`);
24195
24524
  }
24196
24525
  /**
24197
24526
  * Get the guarantor assignment (both core and validator data)
@@ -24207,10 +24536,10 @@ class Reports {
24207
24536
  const minTimeSlot = Math.max(0, headerRotation - 1) * rotationPeriod;
24208
24537
  // https://graypaper.fluffylabs.dev/#/5f542d7/155e00156900
24209
24538
  if (guaranteeTimeSlot > headerTimeSlot) {
24210
- return result_Result.error(ReportsError.FutureReportSlot, `Report slot is in future. Block ${headerTimeSlot}, Report: ${guaranteeTimeSlot}`);
24539
+ return result_Result.error(ReportsError.FutureReportSlot, () => `Report slot is in future. Block ${headerTimeSlot}, Report: ${guaranteeTimeSlot}`);
24211
24540
  }
24212
24541
  if (guaranteeTimeSlot < minTimeSlot) {
24213
- return result_Result.error(ReportsError.ReportEpochBeforeLast, `Report slot is too old. Block ${headerTimeSlot}, Report: ${guaranteeTimeSlot}`);
24542
+ return result_Result.error(ReportsError.ReportEpochBeforeLast, () => `Report slot is too old. Block ${headerTimeSlot}, Report: ${guaranteeTimeSlot}`);
24214
24543
  }
24215
24544
  // TODO [ToDr] [opti] below code needs cache.
24216
24545
  // The `G` and `G*` sets should only be computed once per rotation.
@@ -24746,6 +25075,9 @@ class OnChain {
24746
25075
  servicesUpdate = servicesUpdateFromDeferredTransfers;
24747
25076
  assertEmpty(deferredTransfersRest);
24748
25077
  }
25078
+ else {
25079
+ debug_check `${pendingTransfers.length === 0} All transfers should be already accumulated.`;
25080
+ }
24749
25081
  const accumulateRoot = await this.accumulateOutput.transition({ accumulationOutputLog });
24750
25082
  // recent history
24751
25083
  const recentHistoryUpdate = this.recentHistory.transition({
@@ -24775,6 +25107,16 @@ class OnChain {
24775
25107
  });
24776
25108
  const { statistics, ...statisticsRest } = statisticsUpdate;
24777
25109
  assertEmpty(statisticsRest);
25110
+ // Concat accumulatePreimages updates with preimages
25111
+ for (const [serviceId, accPreimageUpdates] of accumulatePreimages.entries()) {
25112
+ const preimagesUpdates = preimages.get(serviceId);
25113
+ if (preimagesUpdates === undefined) {
25114
+ preimages.set(serviceId, accPreimageUpdates);
25115
+ }
25116
+ else {
25117
+ preimages.set(serviceId, preimagesUpdates.concat(accPreimageUpdates));
25118
+ }
25119
+ }
24778
25120
  return result_Result.ok({
24779
25121
  ...(maybeAuthorizationQueues !== undefined ? { authQueues: maybeAuthorizationQueues } : {}),
24780
25122
  ...(maybeDesignatedValidatorData !== undefined ? { designatedValidatorData: maybeDesignatedValidatorData } : {}),
@@ -24796,7 +25138,7 @@ class OnChain {
24796
25138
  recentlyAccumulated,
24797
25139
  accumulationOutputLog,
24798
25140
  ...servicesUpdate,
24799
- preimages: preimages.concat(accumulatePreimages),
25141
+ preimages,
24800
25142
  });
24801
25143
  }
24802
25144
  getUsedAuthorizerHashes(guarantees) {
@@ -24813,11 +25155,11 @@ class OnChain {
24813
25155
  }
24814
25156
  function checkOffendersMatch(offendersMark, headerOffendersMark) {
24815
25157
  if (offendersMark.size !== headerOffendersMark.length) {
24816
- return result_Result.error(OFFENDERS_ERROR, `Length mismatch: ${offendersMark.size} vs ${headerOffendersMark.length}`);
25158
+ return result_Result.error(OFFENDERS_ERROR, () => `Length mismatch: ${offendersMark.size} vs ${headerOffendersMark.length}`);
24817
25159
  }
24818
25160
  for (const key of headerOffendersMark) {
24819
25161
  if (!offendersMark.has(key)) {
24820
- return result_Result.error(OFFENDERS_ERROR, `Missing key: ${key}`);
25162
+ return result_Result.error(OFFENDERS_ERROR, () => `Missing key: ${key}`);
24821
25163
  }
24822
25164
  }
24823
25165
  return result_Result.ok(result_OK);
@@ -24899,7 +25241,7 @@ class Importer {
24899
25241
  if (!this.currentHash.isEqualTo(parentHash)) {
24900
25242
  const state = this.states.getState(parentHash);
24901
25243
  if (state === null) {
24902
- const e = result_Result.error(BlockVerifierError.StateRootNotFound);
25244
+ const e = result_Result.error(BlockVerifierError.StateRootNotFound, () => `State not found for parent block ${parentHash}`);
24903
25245
  if (!e.isError) {
24904
25246
  throw new Error("unreachable, just adding to make compiler happy");
24905
25247
  }
@@ -25095,7 +25437,7 @@ const importBlockResultCodec = descriptors_codec.custom({
25095
25437
  }
25096
25438
  if (kind === 1) {
25097
25439
  const error = d.bytesBlob();
25098
- return result_Result.error(error.asText());
25440
+ return result_Result.error(error.asText(), () => error.asText());
25099
25441
  }
25100
25442
  throw new Error(`Invalid Result: ${kind}`);
25101
25443
  }, (s) => {
@@ -25146,7 +25488,7 @@ class MainReady extends State {
25146
25488
  if (res instanceof Uint8Array) {
25147
25489
  return decoder_Decoder.decodeObject(importBlockResultCodec, res);
25148
25490
  }
25149
- return result_Result.error("Invalid worker response.");
25491
+ return result_Result.error("Invalid worker response.", () => "Invalid worker response: expected Uint8Array");
25150
25492
  }
25151
25493
  async getStateEntries(port, hash) {
25152
25494
  const res = await port.sendRequest("getStateEntries", hash, [hash.buffer]);
@@ -25258,13 +25600,13 @@ class ImporterReady extends State {
25258
25600
  response = result_Result.ok(this.importer.getBestStateRootHash() ?? ZERO_HASH.asOpaque());
25259
25601
  }
25260
25602
  else {
25261
- response = result_Result.error(resultToString(res));
25603
+ response = result_Result.error(resultToString(res), () => resultToString(res));
25262
25604
  }
25263
25605
  }
25264
25606
  catch (e) {
25265
25607
  state_machine_logger.error `Failed to import block: ${e}`;
25266
25608
  state_machine_logger.error `${e instanceof Error ? e.stack : ""}`;
25267
- response = result_Result.error(`${e}`);
25609
+ response = result_Result.error(`${e}`, () => `${e}`);
25268
25610
  }
25269
25611
  const encoded = encoder_Encoder.encodeObject(importBlockResultCodec, response);
25270
25612
  return {