@typeberry/jam 0.2.0-8017bfd → 0.2.0-adde0dd

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.
@@ -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
@@ -10943,7 +10943,7 @@ class in_memory_state_InMemoryState extends WithDebug {
10943
10943
  const { kind } = update.action;
10944
10944
  const service = this.services.get(serviceId);
10945
10945
  if (service === undefined) {
10946
- return result_Result.error(in_memory_state_UpdateError.NoService, `Attempting to update storage of non-existing service: ${serviceId}`);
10946
+ return result_Result.error(in_memory_state_UpdateError.NoService, () => `Attempting to update storage of non-existing service: ${serviceId}`);
10947
10947
  }
10948
10948
  if (kind === UpdateStorageKind.Set) {
10949
10949
  const { key, value } = update.action.storage;
@@ -10971,14 +10971,14 @@ class in_memory_state_InMemoryState extends WithDebug {
10971
10971
  for (const [serviceId, updates] of preimagesUpdates.entries()) {
10972
10972
  const service = this.services.get(serviceId);
10973
10973
  if (service === undefined) {
10974
- return result_Result.error(in_memory_state_UpdateError.NoService, `Attempting to update preimage of non-existing service: ${serviceId}`);
10974
+ return result_Result.error(in_memory_state_UpdateError.NoService, () => `Attempting to update preimage of non-existing service: ${serviceId}`);
10975
10975
  }
10976
10976
  for (const update of updates) {
10977
10977
  const { kind } = update.action;
10978
10978
  if (kind === UpdatePreimageKind.Provide) {
10979
10979
  const { preimage, slot } = update.action;
10980
10980
  if (service.data.preimages.has(preimage.hash)) {
10981
- return result_Result.error(in_memory_state_UpdateError.PreimageExists, `Overwriting existing preimage at ${serviceId}: ${preimage}`);
10981
+ return result_Result.error(in_memory_state_UpdateError.PreimageExists, () => `Overwriting existing preimage at ${serviceId}: ${preimage}`);
10982
10982
  }
10983
10983
  service.data.preimages.set(preimage.hash, preimage);
10984
10984
  if (slot !== null) {
@@ -11029,7 +11029,7 @@ class in_memory_state_InMemoryState extends WithDebug {
11029
11029
  if (kind === UpdateServiceKind.Create) {
11030
11030
  const { lookupHistory } = update.action;
11031
11031
  if (this.services.has(serviceId)) {
11032
- 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!`);
11033
11033
  }
11034
11034
  this.services.set(serviceId, new InMemoryService(serviceId, {
11035
11035
  info: account,
@@ -11041,7 +11041,7 @@ class in_memory_state_InMemoryState extends WithDebug {
11041
11041
  else if (kind === UpdateServiceKind.Update) {
11042
11042
  const existingService = this.services.get(serviceId);
11043
11043
  if (existingService === undefined) {
11044
- 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.`);
11045
11045
  }
11046
11046
  existingService.data.info = account;
11047
11047
  }
@@ -12671,13 +12671,13 @@ class LeafDb {
12671
12671
  */
12672
12672
  static fromLeavesBlob(blob, db) {
12673
12673
  if (blob.length % TRIE_NODE_BYTES !== 0) {
12674
- 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}`);
12675
12675
  }
12676
12676
  const leaves = SortedSet.fromArray(leafComparator, []);
12677
12677
  for (const nodeData of blob.chunks(TRIE_NODE_BYTES)) {
12678
12678
  const node = new TrieNode(nodeData.raw);
12679
12679
  if (node.getNodeType() === NodeType.Branch) {
12680
- return result_Result.error(LeafDbError.InvalidLeafData, `Branch node detected: ${nodeData}`);
12680
+ return result_Result.error(LeafDbError.InvalidLeafData, () => `Branch node detected: ${nodeData}`);
12681
12681
  }
12682
12682
  leaves.insert(node.asLeafNode());
12683
12683
  }
@@ -13396,7 +13396,7 @@ class LmdbStates {
13396
13396
  }
13397
13397
  catch (e) {
13398
13398
  logger.error `${e}`;
13399
- return result_Result.error(StateUpdateError.Commit);
13399
+ return result_Result.error(StateUpdateError.Commit, () => `Failed to commit state update: ${e}`);
13400
13400
  }
13401
13401
  return result_Result.ok(result_OK);
13402
13402
  }
@@ -14116,7 +14116,7 @@ class Preimages {
14116
14116
  }
14117
14117
  if (prevPreimage.requester > currPreimage.requester ||
14118
14118
  currPreimage.blob.compare(prevPreimage.blob).isLessOrEqual()) {
14119
- return result_Result.error(PreimagesErrorCode.PreimagesNotSortedUnique);
14119
+ return result_Result.error(PreimagesErrorCode.PreimagesNotSortedUnique, () => `Preimages not sorted/unique at index ${i}`);
14120
14120
  }
14121
14121
  }
14122
14122
  const { preimages, slot } = input;
@@ -14127,14 +14127,14 @@ class Preimages {
14127
14127
  const hash = this.blake2b.hashBytes(blob).asOpaque();
14128
14128
  const service = this.state.getService(requester);
14129
14129
  if (service === null) {
14130
- return result_Result.error(PreimagesErrorCode.AccountNotFound);
14130
+ return result_Result.error(PreimagesErrorCode.AccountNotFound, () => `Service not found: ${requester}`);
14131
14131
  }
14132
14132
  const hasPreimage = service.hasPreimage(hash);
14133
14133
  const slots = service.getLookupHistory(hash, numbers_tryAsU32(blob.length));
14134
14134
  // https://graypaper.fluffylabs.dev/#/5f542d7/181800181900
14135
14135
  // https://graypaper.fluffylabs.dev/#/5f542d7/116f0011a500
14136
14136
  if (hasPreimage || slots === null || !LookupHistoryItem.isRequested(slots)) {
14137
- 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)}`);
14138
14138
  }
14139
14139
  // https://graypaper.fluffylabs.dev/#/5f542d7/18c00018f300
14140
14140
  const updates = pendingChanges.get(requester) ?? [];
@@ -14180,7 +14180,7 @@ class BlockVerifier {
14180
14180
  const headerHash = this.hasher.header(headerView);
14181
14181
  // check if current block is already imported
14182
14182
  if (this.blocks.getHeader(headerHash.hash) !== null) {
14183
- 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.`);
14184
14184
  }
14185
14185
  // Check if parent block exists.
14186
14186
  // https://graypaper.fluffylabs.dev/#/cc517d7/0c82000c8200?v=0.6.5
@@ -14190,14 +14190,14 @@ class BlockVerifier {
14190
14190
  if (!parentHash.isEqualTo(block_verifier_ZERO_HASH)) {
14191
14191
  const parentBlock = this.blocks.getHeader(parentHash);
14192
14192
  if (parentBlock === null) {
14193
- return result_Result.error(BlockVerifierError.ParentNotFound, `Parent ${parentHash.toString()} not found`);
14193
+ return result_Result.error(BlockVerifierError.ParentNotFound, () => `Parent ${parentHash.toString()} not found`);
14194
14194
  }
14195
14195
  // Check if the time slot index is consecutive and not from future.
14196
14196
  // https://graypaper.fluffylabs.dev/#/cc517d7/0c02010c0201?v=0.6.5
14197
14197
  const timeslot = headerView.timeSlotIndex.materialize();
14198
14198
  const parentTimeslot = parentBlock.timeSlotIndex.materialize();
14199
14199
  if (timeslot <= parentTimeslot) {
14200
- 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}`);
14201
14201
  }
14202
14202
  }
14203
14203
  // Check if extrinsic is valid.
@@ -14205,17 +14205,17 @@ class BlockVerifier {
14205
14205
  const extrinsicHash = headerView.extrinsicHash.materialize();
14206
14206
  const extrinsicMerkleCommitment = this.hasher.extrinsic(block.extrinsic.view());
14207
14207
  if (!extrinsicHash.isEqualTo(extrinsicMerkleCommitment.hash)) {
14208
- 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()}`);
14209
14209
  }
14210
14210
  // Check if the state root is valid.
14211
14211
  // https://graypaper.fluffylabs.dev/#/cc517d7/0c18010c1801?v=0.6.5
14212
14212
  const stateRoot = headerView.priorStateRoot.materialize();
14213
14213
  const posteriorStateRoot = this.blocks.getPostStateRoot(parentHash);
14214
14214
  if (posteriorStateRoot === null) {
14215
- 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`);
14216
14216
  }
14217
14217
  if (!stateRoot.isEqualTo(posteriorStateRoot)) {
14218
- 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)`);
14219
14219
  }
14220
14220
  return result_Result.ok(headerHash.hash);
14221
14221
  }
@@ -14340,7 +14340,7 @@ class Disputes {
14340
14340
  // check if culprits are sorted by key
14341
14341
  // https://graypaper.fluffylabs.dev/#/579bd12/12c50112c601
14342
14342
  if (!isUniqueSortedBy(disputes.culprits, "key")) {
14343
- return result_Result.error(DisputesErrorCode.CulpritsNotSortedUnique);
14343
+ return result_Result.error(DisputesErrorCode.CulpritsNotSortedUnique, () => "Culprits are not uniquely sorted by key");
14344
14344
  }
14345
14345
  const culpritsLength = disputes.culprits.length;
14346
14346
  for (let i = 0; i < culpritsLength; i++) {
@@ -14349,24 +14349,24 @@ class Disputes {
14349
14349
  // https://graypaper.fluffylabs.dev/#/579bd12/125501125501
14350
14350
  const isInPunishSet = this.state.disputesRecords.asDictionaries().punishSet.has(key);
14351
14351
  if (isInPunishSet) {
14352
- return result_Result.error(DisputesErrorCode.OffenderAlreadyReported);
14352
+ return result_Result.error(DisputesErrorCode.OffenderAlreadyReported, () => `Offender already reported: culprit ${i}, key=${key}`);
14353
14353
  }
14354
14354
  // check if the guarantor key is correct
14355
14355
  // https://graypaper.fluffylabs.dev/#/85129da/125501125501?v=0.6.3
14356
14356
  if (!allValidatorKeys.has(key)) {
14357
- return result_Result.error(DisputesErrorCode.BadGuarantorKey);
14357
+ return result_Result.error(DisputesErrorCode.BadGuarantorKey, () => `Bad guarantor key: culprit ${i}, key=${key}`);
14358
14358
  }
14359
14359
  // verify if the culprit will be in new bad set
14360
14360
  // https://graypaper.fluffylabs.dev/#/579bd12/124601124601
14361
14361
  const isInNewBadSet = newItems.asDictionaries().badSet.has(workReportHash);
14362
14362
  if (!isInNewBadSet) {
14363
- return result_Result.error(DisputesErrorCode.CulpritsVerdictNotBad);
14363
+ return result_Result.error(DisputesErrorCode.CulpritsVerdictNotBad, () => `Culprit verdict not bad: culprit ${i}, work report=${workReportHash}`);
14364
14364
  }
14365
14365
  // verify culprit signature
14366
14366
  // https://graypaper.fluffylabs.dev/#/579bd12/125c01125c01
14367
14367
  const result = verificationResult.culprits[i];
14368
14368
  if (!result?.isValid) {
14369
- return result_Result.error(DisputesErrorCode.BadSignature, `Invalid signature for culprit: ${i}`);
14369
+ return result_Result.error(DisputesErrorCode.BadSignature, () => `Invalid signature for culprit: ${i}`);
14370
14370
  }
14371
14371
  }
14372
14372
  return result_Result.ok(null);
@@ -14375,7 +14375,7 @@ class Disputes {
14375
14375
  // check if faults are sorted by key
14376
14376
  // https://graypaper.fluffylabs.dev/#/579bd12/12c50112c601
14377
14377
  if (!isUniqueSortedBy(disputes.faults, "key")) {
14378
- return result_Result.error(DisputesErrorCode.FaultsNotSortedUnique);
14378
+ return result_Result.error(DisputesErrorCode.FaultsNotSortedUnique, () => "Faults are not uniquely sorted by key");
14379
14379
  }
14380
14380
  const faultsLength = disputes.faults.length;
14381
14381
  for (let i = 0; i < faultsLength; i++) {
@@ -14384,12 +14384,12 @@ class Disputes {
14384
14384
  // https://graypaper.fluffylabs.dev/#/579bd12/12a20112a201
14385
14385
  const isInPunishSet = this.state.disputesRecords.asDictionaries().punishSet.has(key);
14386
14386
  if (isInPunishSet) {
14387
- return result_Result.error(DisputesErrorCode.OffenderAlreadyReported);
14387
+ return result_Result.error(DisputesErrorCode.OffenderAlreadyReported, () => `Offender already reported: fault ${i}, key=${key}`);
14388
14388
  }
14389
14389
  // check if the auditor key is correct
14390
14390
  // https://graypaper.fluffylabs.dev/#/85129da/12a20112a201?v=0.6.3
14391
14391
  if (!allValidatorKeys.has(key)) {
14392
- return result_Result.error(DisputesErrorCode.BadAuditorKey);
14392
+ return result_Result.error(DisputesErrorCode.BadAuditorKey, () => `Bad auditor key: fault ${i}, key=${key}`);
14393
14393
  }
14394
14394
  // verify if the fault will be included in new good/bad set
14395
14395
  // it may be not correct as in GP there is "iff" what means it should be rather
@@ -14401,14 +14401,14 @@ class Disputes {
14401
14401
  const isInNewGoodSet = goodSet.has(workReportHash);
14402
14402
  const isInNewBadSet = badSet.has(workReportHash);
14403
14403
  if (isInNewGoodSet || !isInNewBadSet) {
14404
- 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}`);
14405
14405
  }
14406
14406
  }
14407
14407
  // verify fault signature. Verification was done earlier, here we only check the result.
14408
14408
  // https://graypaper.fluffylabs.dev/#/579bd12/12a90112a901
14409
14409
  const result = verificationResult.faults[i];
14410
14410
  if (!result.isValid) {
14411
- return result_Result.error(DisputesErrorCode.BadSignature, `Invalid signature for fault: ${i}`);
14411
+ return result_Result.error(DisputesErrorCode.BadSignature, () => `Invalid signature for fault: ${i}`);
14412
14412
  }
14413
14413
  }
14414
14414
  return result_Result.ok(null);
@@ -14417,32 +14417,32 @@ class Disputes {
14417
14417
  // check if verdicts are correctly sorted
14418
14418
  // https://graypaper.fluffylabs.dev/#/579bd12/12c40112c401
14419
14419
  if (!isUniqueSortedBy(disputes.verdicts, "workReportHash")) {
14420
- return result_Result.error(DisputesErrorCode.VerdictsNotSortedUnique);
14420
+ return result_Result.error(DisputesErrorCode.VerdictsNotSortedUnique, () => "Verdicts are not uniquely sorted by work report hash");
14421
14421
  }
14422
14422
  // check if judgement are correctly sorted
14423
14423
  // https://graypaper.fluffylabs.dev/#/579bd12/123702123802
14424
14424
  if (disputes.verdicts.some((verdict) => !isUniqueSortedByIndex(verdict.votes))) {
14425
- return result_Result.error(DisputesErrorCode.JudgementsNotSortedUnique);
14425
+ return result_Result.error(DisputesErrorCode.JudgementsNotSortedUnique, () => "Judgements are not uniquely sorted by index");
14426
14426
  }
14427
14427
  const currentEpoch = Math.floor(this.state.timeslot / this.chainSpec.epochLength);
14428
14428
  let voteSignatureIndex = 0;
14429
14429
  for (const { votesEpoch, votes } of disputes.verdicts) {
14430
14430
  // https://graypaper.fluffylabs.dev/#/579bd12/12bb0012bc00
14431
14431
  if (votesEpoch !== currentEpoch && votesEpoch + 1 !== currentEpoch) {
14432
- return result_Result.error(DisputesErrorCode.BadJudgementAge);
14432
+ return result_Result.error(DisputesErrorCode.BadJudgementAge, () => `Bad judgement age: epoch=${votesEpoch}, current=${currentEpoch}`);
14433
14433
  }
14434
14434
  const k = votesEpoch === currentEpoch ? this.state.currentValidatorData : this.state.previousValidatorData;
14435
14435
  for (const { index } of votes) {
14436
14436
  const key = k[index]?.ed25519;
14437
14437
  // no particular GP fragment but I think we don't believe in ghosts
14438
14438
  if (key === undefined) {
14439
- return result_Result.error(DisputesErrorCode.BadValidatorIndex);
14439
+ return result_Result.error(DisputesErrorCode.BadValidatorIndex, () => `Bad validator index: ${index} in epoch ${votesEpoch}`);
14440
14440
  }
14441
14441
  // verify vote signature. Verification was done earlier, here we only check the result.
14442
14442
  // https://graypaper.fluffylabs.dev/#/579bd12/12cd0012cd00
14443
14443
  const result = verificationResult.judgements[voteSignatureIndex];
14444
14444
  if (!result.isValid) {
14445
- return result_Result.error(DisputesErrorCode.BadSignature, `Invalid signature for judgement: ${voteSignatureIndex}`);
14445
+ return result_Result.error(DisputesErrorCode.BadSignature, () => `Invalid signature for judgement: ${voteSignatureIndex}`);
14446
14446
  }
14447
14447
  voteSignatureIndex += 1;
14448
14448
  }
@@ -14458,7 +14458,7 @@ class Disputes {
14458
14458
  const isInBadSet = badSet.has(verdict.workReportHash);
14459
14459
  const isInWonkySet = wonkySet.has(verdict.workReportHash);
14460
14460
  if (isInGoodSet || isInBadSet || isInWonkySet) {
14461
- return result_Result.error(DisputesErrorCode.AlreadyJudged);
14461
+ return result_Result.error(DisputesErrorCode.AlreadyJudged, () => `Work report already judged: ${verdict.workReportHash}`);
14462
14462
  }
14463
14463
  }
14464
14464
  return result_Result.ok(null);
@@ -14489,7 +14489,7 @@ class Disputes {
14489
14489
  // https://graypaper.fluffylabs.dev/#/579bd12/12f10212fc02
14490
14490
  const f = disputes.faults.find((x) => x.workReportHash.isEqualTo(r));
14491
14491
  if (f === undefined) {
14492
- return result_Result.error(DisputesErrorCode.NotEnoughFaults);
14492
+ return result_Result.error(DisputesErrorCode.NotEnoughFaults, () => `Not enough faults for work report: ${r}`);
14493
14493
  }
14494
14494
  }
14495
14495
  else if (sum === 0) {
@@ -14498,13 +14498,13 @@ class Disputes {
14498
14498
  const c1 = disputes.culprits.find((x) => x.workReportHash.isEqualTo(r));
14499
14499
  const c2 = disputes.culprits.findLast((x) => x.workReportHash.isEqualTo(r));
14500
14500
  if (c1 === c2) {
14501
- return result_Result.error(DisputesErrorCode.NotEnoughCulprits);
14501
+ return result_Result.error(DisputesErrorCode.NotEnoughCulprits, () => `Not enough culprits for work report: ${r}`);
14502
14502
  }
14503
14503
  }
14504
14504
  else if (sum !== this.chainSpec.thirdOfValidators) {
14505
14505
  // positive votes count is not correct
14506
14506
  // https://graypaper.fluffylabs.dev/#/579bd12/125002128102
14507
- 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}`);
14508
14508
  }
14509
14509
  }
14510
14510
  return result_Result.ok(null);
@@ -14592,7 +14592,7 @@ class Disputes {
14592
14592
  const validator = k[j.index];
14593
14593
  // no particular GP fragment but I think we don't believe in ghosts
14594
14594
  if (validator === undefined) {
14595
- return result_Result.error(DisputesErrorCode.BadValidatorIndex);
14595
+ return result_Result.error(DisputesErrorCode.BadValidatorIndex, () => `Bad validator index in signature verification: ${j.index}`);
14596
14596
  }
14597
14597
  const key = validator.ed25519;
14598
14598
  // verify vote signature
@@ -14700,7 +14700,7 @@ const ringCommitmentCache = [];
14700
14700
  async function verifySeal(bandersnatch, authorKey, signature, payload, encodedUnsealedHeader) {
14701
14701
  const sealResult = await bandersnatch.verifySeal(authorKey.raw, signature.raw, payload.raw, encodedUnsealedHeader.raw);
14702
14702
  if (sealResult[RESULT_INDEX] === ResultValues.Error) {
14703
- return result_Result.error(null);
14703
+ return result_Result.error(null, () => "Bandersnatch VRF seal verification failed");
14704
14704
  }
14705
14705
  return result_Result.ok(bytes_Bytes.fromBlob(sealResult.subarray(1), hash_HASH_SIZE).asOpaque());
14706
14706
  }
@@ -14726,7 +14726,7 @@ function getRingCommitment(bandersnatch, validators) {
14726
14726
  async function getRingCommitmentNoCache(bandersnatch, keys) {
14727
14727
  const commitmentResult = await bandersnatch.getRingCommitment(keys.raw);
14728
14728
  if (commitmentResult[RESULT_INDEX] === ResultValues.Error) {
14729
- return result_Result.error(null);
14729
+ return result_Result.error(null, () => "Bandersnatch ring commitment calculation failed");
14730
14730
  }
14731
14731
  return result_Result.ok(bytes_Bytes.fromBlob(commitmentResult.subarray(1), bandersnatch_BANDERSNATCH_RING_ROOT_BYTES).asOpaque());
14732
14732
  }
@@ -14901,7 +14901,7 @@ class Safrole {
14901
14901
  epochRoot: epochRootResult.ok,
14902
14902
  });
14903
14903
  }
14904
- return result_Result.error(SafroleErrorCode.IncorrectData);
14904
+ return result_Result.error(SafroleErrorCode.IncorrectData, () => "Safrole: failed to get epoch root for validator keys");
14905
14905
  }
14906
14906
  /**
14907
14907
  * Ticket sequencer that is used in standard mode
@@ -14992,10 +14992,10 @@ class Safrole {
14992
14992
  for (let i = 1; i < ticketsLength; i++) {
14993
14993
  const order = tickets[i - 1].id.compare(tickets[i].id);
14994
14994
  if (order.isEqual()) {
14995
- return result_Result.error(SafroleErrorCode.DuplicateTicket);
14995
+ return result_Result.error(SafroleErrorCode.DuplicateTicket, () => `Safrole: duplicate ticket found at index ${i}`);
14996
14996
  }
14997
14997
  if (order.isGreater()) {
14998
- return result_Result.error(SafroleErrorCode.BadTicketOrder);
14998
+ return result_Result.error(SafroleErrorCode.BadTicketOrder, () => `Safrole: bad ticket order at index ${i}`);
14999
14999
  }
15000
15000
  }
15001
15001
  return result_Result.ok(null);
@@ -15022,7 +15022,7 @@ class Safrole {
15022
15022
  attempt: ticket.attempt,
15023
15023
  }));
15024
15024
  if (!verificationResult.every((x) => x.isValid)) {
15025
- return result_Result.error(SafroleErrorCode.BadTicketProof);
15025
+ return result_Result.error(SafroleErrorCode.BadTicketProof, () => "Safrole: invalid ticket proof in extrinsic");
15026
15026
  }
15027
15027
  /**
15028
15028
  * Verify if tickets are sorted and unique
@@ -15031,7 +15031,7 @@ class Safrole {
15031
15031
  */
15032
15032
  const ticketsVerifcationResult = this.verifyTickets(tickets);
15033
15033
  if (ticketsVerifcationResult.isError) {
15034
- return result_Result.error(ticketsVerifcationResult.error);
15034
+ return result_Result.error(ticketsVerifcationResult.error, ticketsVerifcationResult.details);
15035
15035
  }
15036
15036
  if (this.isEpochChanged(timeslot)) {
15037
15037
  return result_Result.ok(tickets);
@@ -15040,7 +15040,7 @@ class Safrole {
15040
15040
  const ticketsFromExtrinsic = SortedSet.fromSortedArray(ticketComparator, tickets);
15041
15041
  const mergedTickets = SortedSet.fromTwoSortedCollections(ticketsFromState, ticketsFromExtrinsic);
15042
15042
  if (ticketsFromState.length + ticketsFromExtrinsic.length !== mergedTickets.length) {
15043
- return result_Result.error(SafroleErrorCode.DuplicateTicket);
15043
+ return result_Result.error(SafroleErrorCode.DuplicateTicket, () => "Safrole: duplicate ticket when merging state and extrinsic tickets");
15044
15044
  }
15045
15045
  /**
15046
15046
  * Remove tickets if size of accumulator exceeds E (epoch length).
@@ -15109,24 +15109,24 @@ class Safrole {
15109
15109
  }
15110
15110
  async transition(input) {
15111
15111
  if (this.state.timeslot >= input.slot) {
15112
- 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}`);
15113
15113
  }
15114
15114
  if (!this.isExtrinsicLengthValid(input.slot, input.extrinsic)) {
15115
- return result_Result.error(SafroleErrorCode.UnexpectedTicket);
15115
+ return result_Result.error(SafroleErrorCode.UnexpectedTicket, () => `Safrole: unexpected ticket, invalid extrinsic length ${input.extrinsic.length}`);
15116
15116
  }
15117
15117
  if (!this.areTicketAttemptsValid(input.extrinsic)) {
15118
- return result_Result.error(SafroleErrorCode.BadTicketAttempt);
15118
+ return result_Result.error(SafroleErrorCode.BadTicketAttempt, () => "Safrole: bad ticket attempt value in extrinsic");
15119
15119
  }
15120
15120
  const validatorKeysResult = await this.getValidatorKeys(input.slot, input.punishSet);
15121
15121
  if (validatorKeysResult.isError) {
15122
- return result_Result.error(validatorKeysResult.error);
15122
+ return result_Result.error(validatorKeysResult.error, validatorKeysResult.details);
15123
15123
  }
15124
15124
  const { nextValidatorData, currentValidatorData, previousValidatorData, epochRoot } = validatorKeysResult.ok;
15125
15125
  const entropy = this.getEntropy(input.slot, input.entropy);
15126
15126
  const sealingKeySeries = this.getSlotKeySequence(input.slot, currentValidatorData, entropy[2]);
15127
15127
  const newTicketsAccumulatorResult = await this.getNewTicketAccumulator(input.slot, input.extrinsic, this.state.nextValidatorData, epochRoot, entropy[2]);
15128
15128
  if (newTicketsAccumulatorResult.isError) {
15129
- return result_Result.error(newTicketsAccumulatorResult.error);
15129
+ return result_Result.error(newTicketsAccumulatorResult.error, newTicketsAccumulatorResult.details);
15130
15130
  }
15131
15131
  const stateUpdate = {
15132
15132
  nextValidatorData,
@@ -15160,14 +15160,14 @@ function compareWithEncoding(chainSpec, error, actual, expected, codec) {
15160
15160
  if (actual === null || expected === null) {
15161
15161
  // if one of them is `null`, both need to be.
15162
15162
  if (actual !== expected) {
15163
- return result_Result.error(error, `${SafroleErrorCode[error]} Expected: ${expected}, got: ${actual}`);
15163
+ return result_Result.error(error, () => `${SafroleErrorCode[error]} Expected: ${expected}, got: ${actual}`);
15164
15164
  }
15165
15165
  return result_Result.ok(result_OK);
15166
15166
  }
15167
15167
  // compare the literal encoding.
15168
15168
  const encoded = encoder_Encoder.encodeObject(codec, actual, chainSpec);
15169
15169
  if (!encoded.isEqualTo(expected.encoded())) {
15170
- 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}`);
15171
15171
  }
15172
15172
  return result_Result.ok(result_OK);
15173
15173
  }
@@ -15210,7 +15210,7 @@ class SafroleSeal {
15210
15210
  const blockAuthorKey = state.currentValidatorData.at(blockAuthorIndex)?.bandersnatch;
15211
15211
  const entropySourceResult = await bandersnatch_vrf.verifySeal(await this.bandersnatch, blockAuthorKey ?? BANDERSNATCH_ZERO_KEY, headerView.entropySource.materialize(), payload, bytes_BytesBlob.blobFromNumbers([]));
15212
15212
  if (entropySourceResult.isError) {
15213
- return result_Result.error(SafroleSealError.IncorrectEntropySource);
15213
+ return result_Result.error(SafroleSealError.IncorrectEntropySource, () => "Safrole: incorrect entropy source in header seal");
15214
15214
  }
15215
15215
  return result_Result.ok(entropySourceResult.ok);
15216
15216
  }
@@ -15219,7 +15219,7 @@ class SafroleSeal {
15219
15219
  const validatorIndex = headerView.bandersnatchBlockAuthorIndex.materialize();
15220
15220
  const authorKeys = state.currentValidatorData.at(validatorIndex);
15221
15221
  if (authorKeys === undefined) {
15222
- return result_Result.error(SafroleSealError.InvalidValidatorIndex);
15222
+ return result_Result.error(SafroleSealError.InvalidValidatorIndex, () => `Safrole: invalid validator index ${validatorIndex}`);
15223
15223
  }
15224
15224
  const timeSlot = headerView.timeSlotIndex.materialize();
15225
15225
  const sealingKeys = state.sealingKeySeries;
@@ -15238,10 +15238,10 @@ class SafroleSeal {
15238
15238
  const authorKey = validatorData.bandersnatch;
15239
15239
  const result = await bandersnatch_vrf.verifySeal(await this.bandersnatch, authorKey ?? BANDERSNATCH_ZERO_KEY, headerView.seal.materialize(), payload, encodeUnsealedHeader(headerView));
15240
15240
  if (result.isError) {
15241
- return result_Result.error(SafroleSealError.IncorrectSeal);
15241
+ return result_Result.error(SafroleSealError.IncorrectSeal, () => "Safrole: incorrect seal with ticket");
15242
15242
  }
15243
15243
  if (ticket === undefined || !ticket.id.isEqualTo(result.ok)) {
15244
- return result_Result.error(SafroleSealError.InvalidTicket);
15244
+ return result_Result.error(SafroleSealError.InvalidTicket, () => `Safrole: invalid ticket, expected ${ticket?.id} got ${result.ok}`);
15245
15245
  }
15246
15246
  return result_Result.ok(result.ok);
15247
15247
  }
@@ -15251,13 +15251,13 @@ class SafroleSeal {
15251
15251
  const sealingKey = keys.at(index);
15252
15252
  const authorBandersnatchKey = authorKey.bandersnatch;
15253
15253
  if (sealingKey === undefined || !sealingKey.isEqualTo(authorBandersnatchKey)) {
15254
- return result_Result.error(SafroleSealError.InvalidValidator, `Invalid Validator. Expected: ${sealingKey}, got: ${authorKey.bandersnatch}`);
15254
+ return result_Result.error(SafroleSealError.InvalidValidator, () => `Invalid Validator. Expected: ${sealingKey}, got: ${authorKey.bandersnatch}`);
15255
15255
  }
15256
15256
  // verify seal correctness
15257
15257
  const payload = bytes_BytesBlob.blobFromParts(JAM_FALLBACK_SEAL, entropy.raw);
15258
15258
  const result = await bandersnatch_vrf.verifySeal(await this.bandersnatch, authorBandersnatchKey, headerView.seal.materialize(), payload, encodeUnsealedHeader(headerView));
15259
15259
  if (result.isError) {
15260
- return result_Result.error(SafroleSealError.IncorrectSeal);
15260
+ return result_Result.error(SafroleSealError.IncorrectSeal, () => "Safrole: incorrect seal with keys");
15261
15261
  }
15262
15262
  return result_Result.ok(result.ok);
15263
15263
  }
@@ -15530,11 +15530,11 @@ class PartiallyUpdatedState {
15530
15530
  const overflowBytes = !isU64(bytes);
15531
15531
  // TODO [ToDr] this is not specified in GP, but it seems sensible.
15532
15532
  if (overflowItems || overflowBytes) {
15533
- return result_Result.error(InsufficientFundsError);
15533
+ return result_Result.error(InsufficientFundsError, () => `Storage utilisation overflow: items=${overflowItems}, bytes=${overflowBytes}`);
15534
15534
  }
15535
15535
  const thresholdBalance = ServiceAccountInfo.calculateThresholdBalance(items, bytes, serviceInfo.gratisStorage);
15536
15536
  if (serviceInfo.balance < thresholdBalance) {
15537
- return result_Result.error(InsufficientFundsError);
15537
+ return result_Result.error(InsufficientFundsError, () => `Service balance (${serviceInfo.balance}) below threshold (${thresholdBalance})`);
15538
15538
  }
15539
15539
  // Update service info with new details.
15540
15540
  this.updateServiceInfo(serviceId, ServiceAccountInfo.create({
@@ -17037,7 +17037,7 @@ class ReadablePage extends MemoryPage {
17037
17037
  loadInto(result, startIndex, length) {
17038
17038
  const endIndex = startIndex + length;
17039
17039
  if (endIndex > PAGE_SIZE) {
17040
- 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}`);
17041
17041
  }
17042
17042
  const bytes = this.data.subarray(startIndex, endIndex);
17043
17043
  // we zero the bytes, since data might not yet be initialized at `endIndex`.
@@ -17046,7 +17046,7 @@ class ReadablePage extends MemoryPage {
17046
17046
  return result_Result.ok(result_OK);
17047
17047
  }
17048
17048
  storeFrom(_address, _data) {
17049
- 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}`);
17050
17050
  }
17051
17051
  setData(pageIndex, data) {
17052
17052
  this.data.set(data, pageIndex);
@@ -17080,7 +17080,7 @@ class WriteablePage extends MemoryPage {
17080
17080
  loadInto(result, startIndex, length) {
17081
17081
  const endIndex = startIndex + length;
17082
17082
  if (endIndex > PAGE_SIZE) {
17083
- 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}`);
17084
17084
  }
17085
17085
  const bytes = this.view.subarray(startIndex, endIndex);
17086
17086
  // we zero the bytes, since the view might not yet be initialized at `endIndex`.
@@ -17166,7 +17166,7 @@ class Memory {
17166
17166
  memory_logger.insane `MEM[${address}] <- ${bytes_BytesBlob.blobFrom(bytes)}`;
17167
17167
  const pagesResult = this.getPages(address, bytes.length, AccessType.WRITE);
17168
17168
  if (pagesResult.isError) {
17169
- return result_Result.error(pagesResult.error);
17169
+ return result_Result.error(pagesResult.error, pagesResult.details);
17170
17170
  }
17171
17171
  const pages = pagesResult.ok;
17172
17172
  let currentPosition = address;
@@ -17191,14 +17191,14 @@ class Memory {
17191
17191
  const pages = [];
17192
17192
  for (const pageNumber of pageRange) {
17193
17193
  if (pageNumber < RESERVED_NUMBER_OF_PAGES) {
17194
- 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}`);
17195
17195
  }
17196
17196
  const page = this.memory.get(pageNumber);
17197
17197
  if (page === undefined) {
17198
- return result_Result.error(PageFault.fromPageNumber(pageNumber));
17198
+ return result_Result.error(PageFault.fromPageNumber(pageNumber), () => `Page fault: page ${pageNumber} not allocated`);
17199
17199
  }
17200
17200
  if (accessType === AccessType.WRITE && !page.isWriteable()) {
17201
- 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}`);
17202
17202
  }
17203
17203
  pages.push(page);
17204
17204
  }
@@ -17216,7 +17216,7 @@ class Memory {
17216
17216
  }
17217
17217
  const pagesResult = this.getPages(startAddress, result.length, AccessType.READ);
17218
17218
  if (pagesResult.isError) {
17219
- return result_Result.error(pagesResult.error);
17219
+ return result_Result.error(pagesResult.error, pagesResult.details);
17220
17220
  }
17221
17221
  const pages = pagesResult.ok;
17222
17222
  let currentPosition = startAddress;
@@ -19155,7 +19155,7 @@ class ProgramDecoder {
19155
19155
  }
19156
19156
  catch (e) {
19157
19157
  program_decoder_logger.error `Invalid program: ${e}`;
19158
- return result_Result.error(ProgramDecoderError.InvalidProgramError);
19158
+ return result_Result.error(ProgramDecoderError.InvalidProgramError, () => `Program decoder error: ${e}`);
19159
19159
  }
19160
19160
  }
19161
19161
  }
@@ -19898,10 +19898,10 @@ class AccumulateExternalities {
19898
19898
  const len = existingPreimage.slots.length;
19899
19899
  // https://graypaper.fluffylabs.dev/#/9a08063/380901380901?v=0.6.6
19900
19900
  if (len === PreimageStatusKind.Requested) {
19901
- return result_Result.error(RequestPreimageError.AlreadyRequested);
19901
+ return result_Result.error(RequestPreimageError.AlreadyRequested, () => `Preimage already requested: hash=${hash}`);
19902
19902
  }
19903
19903
  if (len === PreimageStatusKind.Available || len === PreimageStatusKind.Reavailable) {
19904
- return result_Result.error(RequestPreimageError.AlreadyAvailable);
19904
+ return result_Result.error(RequestPreimageError.AlreadyAvailable, () => `Preimage already available: hash=${hash}`);
19905
19905
  }
19906
19906
  // TODO [ToDr] Not sure if we should update the service info in that case,
19907
19907
  // but for now we let that case fall-through.
@@ -19942,7 +19942,7 @@ class AccumulateExternalities {
19942
19942
  const serviceId = this.currentServiceId;
19943
19943
  const status = this.updatedState.getLookupHistory(this.currentTimeslot, this.currentServiceId, hash, length);
19944
19944
  if (status === null) {
19945
- return result_Result.error(ForgetPreimageError.NotFound);
19945
+ return result_Result.error(ForgetPreimageError.NotFound, () => `Preimage not found: hash=${hash}, length=${length}`);
19946
19946
  }
19947
19947
  const s = slotsToPreimageStatus(status.slots);
19948
19948
  const updateStorageUtilisation = () => {
@@ -19955,7 +19955,7 @@ class AccumulateExternalities {
19955
19955
  if (s.status === PreimageStatusKind.Requested) {
19956
19956
  const res = updateStorageUtilisation();
19957
19957
  if (res.isError) {
19958
- return result_Result.error(ForgetPreimageError.StorageUtilisationError);
19958
+ return result_Result.error(ForgetPreimageError.StorageUtilisationError, res.details);
19959
19959
  }
19960
19960
  this.updatedState.updatePreimage(serviceId, UpdatePreimage.remove({
19961
19961
  hash: status.hash,
@@ -19970,7 +19970,7 @@ class AccumulateExternalities {
19970
19970
  if (y < t - this.chainSpec.preimageExpungePeriod) {
19971
19971
  const res = updateStorageUtilisation();
19972
19972
  if (res.isError) {
19973
- return result_Result.error(ForgetPreimageError.StorageUtilisationError);
19973
+ return result_Result.error(ForgetPreimageError.StorageUtilisationError, res.details);
19974
19974
  }
19975
19975
  this.updatedState.updatePreimage(serviceId, UpdatePreimage.remove({
19976
19976
  hash: status.hash,
@@ -19978,7 +19978,7 @@ class AccumulateExternalities {
19978
19978
  }));
19979
19979
  return result_Result.ok(result_OK);
19980
19980
  }
19981
- return result_Result.error(ForgetPreimageError.NotExpired);
19981
+ return result_Result.error(ForgetPreimageError.NotExpired, () => `Preimage not expired: y=${y}, timeslot=${t}, period=${this.chainSpec.preimageExpungePeriod}`);
19982
19982
  }
19983
19983
  // https://graypaper.fluffylabs.dev/#/9a08063/38c80138c801?v=0.6.6
19984
19984
  if (s.status === PreimageStatusKind.Available) {
@@ -19996,7 +19996,7 @@ class AccumulateExternalities {
19996
19996
  }));
19997
19997
  return result_Result.ok(result_OK);
19998
19998
  }
19999
- return result_Result.error(ForgetPreimageError.NotExpired);
19999
+ return result_Result.error(ForgetPreimageError.NotExpired, () => `Preimage not expired: y=${y}, timeslot=${t}, period=${this.chainSpec.preimageExpungePeriod}`);
20000
20000
  }
20001
20001
  debug_assertNever(s);
20002
20002
  }
@@ -20005,17 +20005,17 @@ class AccumulateExternalities {
20005
20005
  const destination = this.getServiceInfo(destinationId);
20006
20006
  /** https://graypaper.fluffylabs.dev/#/9a08063/370401370401?v=0.6.6 */
20007
20007
  if (destination === null || destinationId === null) {
20008
- return result_Result.error(TransferError.DestinationNotFound);
20008
+ return result_Result.error(TransferError.DestinationNotFound, () => `Destination service not found: ${destinationId}`);
20009
20009
  }
20010
20010
  /** https://graypaper.fluffylabs.dev/#/9a08063/371301371301?v=0.6.6 */
20011
20011
  if (gas < destination.onTransferMinGas) {
20012
- return result_Result.error(TransferError.GasTooLow);
20012
+ return result_Result.error(TransferError.GasTooLow, () => `Gas ${gas} below minimum ${destination.onTransferMinGas}`);
20013
20013
  }
20014
20014
  /** https://graypaper.fluffylabs.dev/#/9a08063/371b01371b01?v=0.6.6 */
20015
20015
  const newBalance = source.balance - amount;
20016
20016
  const thresholdBalance = ServiceAccountInfo.calculateThresholdBalance(source.storageUtilisationCount, source.storageUtilisationBytes, source.gratisStorage);
20017
20017
  if (newBalance < thresholdBalance) {
20018
- return result_Result.error(TransferError.BalanceBelowThreshold);
20018
+ return result_Result.error(TransferError.BalanceBelowThreshold, () => `Balance ${newBalance} below threshold ${thresholdBalance}`);
20019
20019
  }
20020
20020
  // outgoing transfer
20021
20021
  this.updatedState.stateUpdate.transfers.push(PendingTransfer.create({
@@ -20042,7 +20042,7 @@ class AccumulateExternalities {
20042
20042
  // check if we are priviledged to set gratis storage
20043
20043
  // https://graypaper.fluffylabs.dev/#/7e6ff6a/369203369603?v=0.6.7
20044
20044
  if (gratisStorage !== numbers_tryAsU64(0) && this.currentServiceId !== this.updatedState.getPrivilegedServices().manager) {
20045
- return result_Result.error(NewServiceError.UnprivilegedService);
20045
+ return result_Result.error(NewServiceError.UnprivilegedService, () => `Service ${this.currentServiceId} not privileged to set gratis storage`);
20046
20046
  }
20047
20047
  // check if we have enough balance
20048
20048
  // https://graypaper.fluffylabs.dev/#/7e6ff6a/369e0336a303?v=0.6.7
@@ -20051,7 +20051,7 @@ class AccumulateExternalities {
20051
20051
  const thresholdForCurrent = ServiceAccountInfo.calculateThresholdBalance(currentService.storageUtilisationCount, currentService.storageUtilisationBytes, currentService.gratisStorage);
20052
20052
  const balanceLeftForCurrent = currentService.balance - thresholdForNew;
20053
20053
  if (balanceLeftForCurrent < thresholdForCurrent || bytes.overflow) {
20054
- return result_Result.error(NewServiceError.InsufficientFunds);
20054
+ return result_Result.error(NewServiceError.InsufficientFunds, () => `Insufficient funds: balance=${currentService.balance}, required=${thresholdForNew}, overflow=${bytes.overflow}`);
20055
20055
  }
20056
20056
  // `a`: https://graypaper.fluffylabs.dev/#/ab2cdbd/366b02366d02?v=0.7.2
20057
20057
  const newAccount = ServiceAccountInfo.create({
@@ -20078,7 +20078,7 @@ class AccumulateExternalities {
20078
20078
  // NOTE: It's safe to cast to `Number` here, bcs here service ID cannot be bigger than 2**16
20079
20079
  const newServiceId = tryAsServiceId(Number(wantedServiceId));
20080
20080
  if (this.getServiceInfo(newServiceId) !== null) {
20081
- return result_Result.error(NewServiceError.RegistrarServiceIdAlreadyTaken);
20081
+ return result_Result.error(NewServiceError.RegistrarServiceIdAlreadyTaken, () => `Service ID ${newServiceId} already taken`);
20082
20082
  }
20083
20083
  // add the new service with selected ID
20084
20084
  // https://graypaper.fluffylabs.dev/#/ab2cdbd/36be0336c003?v=0.7.2
@@ -20118,7 +20118,7 @@ class AccumulateExternalities {
20118
20118
  const currentDelegator = this.updatedState.getPrivilegedServices().delegator;
20119
20119
  if (currentDelegator !== this.currentServiceId) {
20120
20120
  accumulate_externalities_logger.trace `Current service id (${this.currentServiceId}) is not a validators manager. (expected: ${currentDelegator}) and cannot update validators data. Ignoring`;
20121
- return result_Result.error(UnprivilegedError);
20121
+ return result_Result.error(UnprivilegedError, () => `Service ${this.currentServiceId} is not delegator (expected: ${currentDelegator})`);
20122
20122
  }
20123
20123
  this.updatedState.stateUpdate.validatorsData = validatorsData;
20124
20124
  return result_Result.ok(result_OK);
@@ -20133,11 +20133,11 @@ class AccumulateExternalities {
20133
20133
  const currentAssigners = this.updatedState.getPrivilegedServices().assigners[coreIndex];
20134
20134
  if (currentAssigners !== this.currentServiceId) {
20135
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.`;
20136
- return result_Result.error(UpdatePrivilegesError.UnprivilegedService);
20136
+ return result_Result.error(UpdatePrivilegesError.UnprivilegedService, () => `Service ${this.currentServiceId} not assigner for core ${coreIndex} (expected: ${currentAssigners})`);
20137
20137
  }
20138
20138
  if (assigners === null && Compatibility.isGreaterOrEqual(GpVersion.V0_7_1)) {
20139
20139
  accumulate_externalities_logger.trace `The new auth manager is not a valid service id.`;
20140
- return result_Result.error(UpdatePrivilegesError.InvalidServiceId);
20140
+ return result_Result.error(UpdatePrivilegesError.InvalidServiceId, () => `New auth manager is null for core ${coreIndex}`);
20141
20141
  }
20142
20142
  this.updatedState.stateUpdate.authorizationQueues.set(coreIndex, authQueue);
20143
20143
  return result_Result.ok(result_OK);
@@ -20170,10 +20170,10 @@ class AccumulateExternalities {
20170
20170
  const isManager = current.manager === this.currentServiceId;
20171
20171
  if (Compatibility.isLessThan(GpVersion.V0_7_1)) {
20172
20172
  if (!isManager) {
20173
- return result_Result.error(UpdatePrivilegesError.UnprivilegedService);
20173
+ return result_Result.error(UpdatePrivilegesError.UnprivilegedService, () => `Service ${this.currentServiceId} is not manager`);
20174
20174
  }
20175
20175
  if (manager === null || delegator === null) {
20176
- return result_Result.error(UpdatePrivilegesError.InvalidServiceId, "Either manager or delegator is not a valid service id.");
20176
+ return result_Result.error(UpdatePrivilegesError.InvalidServiceId, () => "Either manager or delegator is not a valid service id.");
20177
20177
  }
20178
20178
  this.updatedState.stateUpdate.privilegedServices = PrivilegedServices.create({
20179
20179
  manager,
@@ -20186,7 +20186,7 @@ class AccumulateExternalities {
20186
20186
  }
20187
20187
  const original = this.updatedState.state.privilegedServices;
20188
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.");
20189
+ return result_Result.error(UpdatePrivilegesError.InvalidServiceId, () => "Either manager or delegator or registrar is not a valid service id.");
20190
20190
  }
20191
20191
  const newDelegator = this.updatePrivilegedServiceId(delegator, current.delegator, {
20192
20192
  isManager,
@@ -20226,19 +20226,19 @@ class AccumulateExternalities {
20226
20226
  // TODO [ToDr] what about newly created services?
20227
20227
  const service = serviceId === null ? null : this.updatedState.state.getService(serviceId);
20228
20228
  if (service === null || serviceId === null) {
20229
- return result_Result.error(ProvidePreimageError.ServiceNotFound);
20229
+ return result_Result.error(ProvidePreimageError.ServiceNotFound, () => `Service not found: ${serviceId}`);
20230
20230
  }
20231
20231
  // calculating the hash
20232
20232
  const preimageHash = this.blake2b.hashBytes(preimage).asOpaque();
20233
20233
  // checking service internal lookup
20234
20234
  const stateLookup = this.updatedState.getLookupHistory(this.currentTimeslot, serviceId, preimageHash, numbers_tryAsU64(preimage.length));
20235
20235
  if (stateLookup === null || !LookupHistoryItem.isRequested(stateLookup)) {
20236
- return result_Result.error(ProvidePreimageError.WasNotRequested);
20236
+ return result_Result.error(ProvidePreimageError.WasNotRequested, () => `Preimage was not requested: hash=${preimageHash}, service=${serviceId}`);
20237
20237
  }
20238
20238
  // checking already provided preimages
20239
20239
  const hasPreimage = this.updatedState.hasPreimage(serviceId, preimageHash);
20240
20240
  if (hasPreimage) {
20241
- return result_Result.error(ProvidePreimageError.AlreadyProvided);
20241
+ return result_Result.error(ProvidePreimageError.AlreadyProvided, () => `Preimage already provided: hash=${preimageHash}, service=${serviceId}`);
20242
20242
  }
20243
20243
  // setting up the new preimage
20244
20244
  this.updatedState.updatePreimage(serviceId, UpdatePreimage.provide({
@@ -20253,31 +20253,31 @@ class AccumulateExternalities {
20253
20253
  eject(destination, previousCodeHash) {
20254
20254
  const service = this.getServiceInfo(destination);
20255
20255
  if (service === null || destination === null) {
20256
- return result_Result.error(EjectError.InvalidService, "Service missing");
20256
+ return result_Result.error(EjectError.InvalidService, () => "Service missing");
20257
20257
  }
20258
20258
  const currentService = this.getCurrentServiceInfo();
20259
20259
  // check if the service expects to be ejected by us:
20260
20260
  const expectedCodeHash = bytes_Bytes.zero(hash_HASH_SIZE).asOpaque();
20261
20261
  writeServiceIdAsLeBytes(this.currentServiceId, expectedCodeHash.raw);
20262
20262
  if (!service.codeHash.isEqualTo(expectedCodeHash)) {
20263
- return result_Result.error(EjectError.InvalidService, "Invalid code hash");
20263
+ return result_Result.error(EjectError.InvalidService, () => "Invalid code hash");
20264
20264
  }
20265
20265
  // make sure the service only has required number of storage items?
20266
20266
  if (service.storageUtilisationCount !== REQUIRED_NUMBER_OF_STORAGE_ITEMS_FOR_EJECT) {
20267
- return result_Result.error(EjectError.InvalidPreimage, "Too many storage items");
20267
+ return result_Result.error(EjectError.InvalidPreimage, () => "Too many storage items");
20268
20268
  }
20269
20269
  // storage items length
20270
20270
  const l = numbers_tryAsU64(maxU64(service.storageUtilisationBytes, LOOKUP_HISTORY_ENTRY_BYTES) - LOOKUP_HISTORY_ENTRY_BYTES);
20271
20271
  // check if we have a preimage with the entire storage.
20272
20272
  const [isPreviousCodeExpired, errorReason] = this.isPreviousCodeExpired(destination, previousCodeHash, l);
20273
20273
  if (!isPreviousCodeExpired) {
20274
- return result_Result.error(EjectError.InvalidPreimage, `Previous code available: ${errorReason}`);
20274
+ return result_Result.error(EjectError.InvalidPreimage, () => `Previous code available: ${errorReason}`);
20275
20275
  }
20276
20276
  // compute new balance of the service.
20277
20277
  const newBalance = sumU64(currentService.balance, service.balance);
20278
20278
  // TODO [ToDr] what to do in case of overflow?
20279
20279
  if (newBalance.overflow) {
20280
- return result_Result.error(EjectError.InvalidService, "Balance overflow");
20280
+ return result_Result.error(EjectError.InvalidService, () => "Balance overflow");
20281
20281
  }
20282
20282
  // update current service.
20283
20283
  this.updatedState.updateServiceInfo(this.currentServiceId, ServiceAccountInfo.create({
@@ -20472,10 +20472,10 @@ class Assurances {
20472
20472
  for (const assurance of assurances) {
20473
20473
  const { anchor, validatorIndex, bitfield } = assurance;
20474
20474
  if (!anchor.isEqualTo(input.parentHash)) {
20475
- 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}`);
20476
20476
  }
20477
20477
  if (prevValidatorIndex >= validatorIndex) {
20478
- 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}`);
20479
20479
  }
20480
20480
  prevValidatorIndex = assurance.validatorIndex;
20481
20481
  debug_check `${bitfield.bitLength === coresCount} Invalid bitfield length of ${bitfield.bitLength}`;
@@ -20498,7 +20498,7 @@ class Assurances {
20498
20498
  * https://graypaper.fluffylabs.dev/#/579bd12/14e90014ea00
20499
20499
  */
20500
20500
  if (noOfAssurances > 0 && !isReportPending) {
20501
- 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`);
20502
20502
  }
20503
20503
  /**
20504
20504
  * Remove work report if it's became available or timed out.
@@ -20544,7 +20544,7 @@ class Assurances {
20544
20544
  const v = assurance.view();
20545
20545
  const key = validatorData[v.validatorIndex.materialize()];
20546
20546
  if (key === undefined) {
20547
- return result_Result.error(AssurancesError.InvalidValidatorIndex);
20547
+ return result_Result.error(AssurancesError.InvalidValidatorIndex, () => `Invalid validator index: ${v.validatorIndex.materialize()}`);
20548
20548
  }
20549
20549
  signatures.push({
20550
20550
  signature: v.signature.materialize(),
@@ -20556,7 +20556,7 @@ class Assurances {
20556
20556
  const isAllSignaturesValid = signaturesValid.every((x) => x);
20557
20557
  if (!isAllSignaturesValid) {
20558
20558
  const invalidIndices = signaturesValid.reduce((acc, isValid, idx) => (isValid ? acc : acc.concat(idx)), []);
20559
- return result_Result.error(AssurancesError.InvalidSignature, `invalid signatures at ${invalidIndices.join(", ")}`);
20559
+ return result_Result.error(AssurancesError.InvalidSignature, () => `invalid signatures at ${invalidIndices.join(", ")}`);
20560
20560
  }
20561
20561
  return result_Result.ok(result_OK);
20562
20562
  }
@@ -21167,7 +21167,7 @@ class HostCallMemory {
21167
21167
  return result_Result.ok(result_OK);
21168
21168
  }
21169
21169
  if (address + numbers_tryAsU64(bytes.length) > MEMORY_SIZE) {
21170
- 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`);
21171
21171
  }
21172
21172
  return this.memory.storeFrom(tryAsMemoryIndex(Number(address)), bytes);
21173
21173
  }
@@ -21176,7 +21176,7 @@ class HostCallMemory {
21176
21176
  return result_Result.ok(result_OK);
21177
21177
  }
21178
21178
  if (startAddress + numbers_tryAsU64(result.length) > MEMORY_SIZE) {
21179
- 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`);
21180
21180
  }
21181
21181
  return this.memory.loadInto(result, tryAsMemoryIndex(Number(startAddress)));
21182
21182
  }
@@ -23119,18 +23119,18 @@ class Accumulate {
23119
23119
  const serviceInfo = updatedState.getServiceInfo(serviceId);
23120
23120
  if (serviceInfo === null) {
23121
23121
  accumulate_logger.log `Service with id ${serviceId} not found.`;
23122
- return result_Result.error(PvmInvocationError.NoService);
23122
+ return result_Result.error(PvmInvocationError.NoService, () => `Accumulate: service ${serviceId} not found`);
23123
23123
  }
23124
23124
  const codeHash = serviceInfo.codeHash;
23125
23125
  // TODO [ToDr] Should we check that the preimage is still available?
23126
23126
  const code = updatedState.getPreimage(serviceId, codeHash.asOpaque());
23127
23127
  if (code === null) {
23128
23128
  accumulate_logger.log `Code with hash ${codeHash} not found for service ${serviceId}.`;
23129
- return result_Result.error(PvmInvocationError.NoPreimage);
23129
+ return result_Result.error(PvmInvocationError.NoPreimage, () => `Accumulate: code with hash ${codeHash} not found for service ${serviceId}`);
23130
23130
  }
23131
23131
  if (code.length > W_C) {
23132
23132
  accumulate_logger.log `Code with hash ${codeHash} is too long for service ${serviceId}.`;
23133
- 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}`);
23134
23134
  }
23135
23135
  const nextServiceId = generateNextServiceId({ serviceId, entropy, timeslot: slot }, this.chainSpec, this.blake2b);
23136
23136
  const partialState = new AccumulateExternalities(this.chainSpec, this.blake2b, updatedState, serviceId, nextServiceId, slot);
@@ -23418,7 +23418,7 @@ class Accumulate {
23418
23418
  assertEmpty(stateUpdateRest);
23419
23419
  if (this.hasDuplicatedServiceIdCreated(services.created)) {
23420
23420
  accumulate_logger.trace `Duplicated Service creation detected. Block is invalid.`;
23421
- return result_Result.error(ACCUMULATION_ERROR);
23421
+ return result_Result.error(ACCUMULATION_ERROR, () => "Accumulate: duplicate service created");
23422
23422
  }
23423
23423
  const accStateUpdate = this.getAccumulationStateUpdate(accumulated.toArray(), toAccumulateLater, slot, Array.from(statistics.keys()), services);
23424
23424
  const accumulationOutputUnsorted = Array.from(yieldedRoots.entries()).map(([serviceId, root]) => {
@@ -23499,13 +23499,13 @@ class DeferredTransfers {
23499
23499
  .toSorted((a, b) => a.source - b.source);
23500
23500
  const info = partiallyUpdatedState.getServiceInfo(serviceId);
23501
23501
  if (info === null) {
23502
- return result_Result.error(DeferredTransfersErrorCode.ServiceInfoNotExist);
23502
+ return result_Result.error(DeferredTransfersErrorCode.ServiceInfoNotExist, () => `Deferred transfers: service info not found for ${serviceId}`);
23503
23503
  }
23504
23504
  const codeHash = info.codeHash;
23505
23505
  const code = partiallyUpdatedState.getPreimage(serviceId, codeHash.asOpaque());
23506
23506
  const newBalance = sumU64(info.balance, ...transfers.map((item) => item.amount));
23507
23507
  if (newBalance.overflow) {
23508
- return result_Result.error(DeferredTransfersErrorCode.ServiceBalanceOverflow);
23508
+ return result_Result.error(DeferredTransfersErrorCode.ServiceBalanceOverflow, () => `Deferred transfers: balance overflow for service ${serviceId}`);
23509
23509
  }
23510
23510
  const newInfo = ServiceAccountInfo.create({ ...info, balance: newBalance.value });
23511
23511
  partiallyUpdatedState.updateServiceInfo(serviceId, newInfo);
@@ -23983,7 +23983,7 @@ function verifyReportsBasic(input) {
23983
23983
  const noOfPrerequisites = reportView.context.view().prerequisites.view().length;
23984
23984
  const noOfSegmentRootLookups = reportView.segmentRootLookup.view().length;
23985
23985
  if (noOfPrerequisites + noOfSegmentRootLookups > 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}`);
23986
+ return result_Result.error(ReportsError.TooManyDependencies, () => `Report at ${reportView.coreIndex.materialize()} has too many dependencies. Got ${noOfPrerequisites} + ${noOfSegmentRootLookups}, max: ${MAX_REPORT_DEPENDENCIES}`);
23987
23987
  }
23988
23988
  /**
23989
23989
  * In order to ensure fair use of a block’s extrinsic space,
@@ -24002,7 +24002,7 @@ function verifyReportsBasic(input) {
24002
24002
  totalOutputsSize += item.view().result.view().okBlob?.raw.length ?? 0;
24003
24003
  }
24004
24004
  if (authOutputSize + totalOutputsSize > 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}`);
24005
+ return result_Result.error(ReportsError.WorkReportTooBig, () => `Work report at ${reportView.coreIndex.materialize()} too big. Got ${authOutputSize} + ${totalOutputsSize}, max: ${MAX_WORK_REPORT_SIZE_BYTES}`);
24006
24006
  }
24007
24007
  }
24008
24008
  return result_Result.ok(result_OK);
@@ -24036,12 +24036,12 @@ function verifyContextualValidity(input, state, headerChain, maxLookupAnchorAge)
24036
24036
  for (const result of guarantee.report.results) {
24037
24037
  const service = state.getService(result.serviceId);
24038
24038
  if (service === null) {
24039
- 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}`);
24040
24040
  }
24041
24041
  // check service code hash
24042
24042
  // https://graypaper.fluffylabs.dev/#/5f542d7/154b02154b02
24043
24043
  if (!result.codeHash.isEqualTo(service.getInfo().codeHash)) {
24044
- 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}`);
24045
24045
  }
24046
24046
  }
24047
24047
  }
@@ -24052,7 +24052,7 @@ function verifyContextualValidity(input, state, headerChain, maxLookupAnchorAge)
24052
24052
  * https://graypaper.fluffylabs.dev/#/5f542d7/151f01152101
24053
24053
  */
24054
24054
  if (currentWorkPackages.size !== input.guarantees.length) {
24055
- return result_Result.error(ReportsError.DuplicatePackage, "Duplicate work package detected.");
24055
+ return result_Result.error(ReportsError.DuplicatePackage, () => "Duplicate work package detected.");
24056
24056
  }
24057
24057
  const minLookupSlot = Math.max(0, input.slot - maxLookupAnchorAge);
24058
24058
  const contextResult = verifyRefineContexts(minLookupSlot, contexts, input.recentBlocksPartialUpdate, headerChain);
@@ -24097,7 +24097,7 @@ function verifyContextualValidity(input, state, headerChain, maxLookupAnchorAge)
24097
24097
  : undefined;
24098
24098
  }
24099
24099
  if (root === undefined || !root.segmentTreeRoot.isEqualTo(lookup.segmentTreeRoot)) {
24100
- 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}`);
24101
24101
  }
24102
24102
  }
24103
24103
  }
@@ -24120,16 +24120,16 @@ function verifyRefineContexts(minLookupSlot, contexts, recentBlocksPartialUpdate
24120
24120
  */
24121
24121
  const recentBlock = recentBlocks.get(context.anchor);
24122
24122
  if (recentBlock === undefined) {
24123
- 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.`);
24124
24124
  }
24125
24125
  // check state root
24126
24126
  if (!recentBlock.postStateRoot.isEqualTo(context.stateRoot)) {
24127
- 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}.`);
24128
24128
  }
24129
24129
  // check beefy root
24130
24130
  const beefyRoot = recentBlock.accumulationResult;
24131
24131
  if (!beefyRoot.isEqualTo(context.beefyRoot)) {
24132
- 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}`);
24133
24133
  }
24134
24134
  /**
24135
24135
  * We require that each lookup-anchor block be within the
@@ -24138,7 +24138,7 @@ function verifyRefineContexts(minLookupSlot, contexts, recentBlocksPartialUpdate
24138
24138
  * https://graypaper.fluffylabs.dev/#/5f542d7/154601154701
24139
24139
  */
24140
24140
  if (context.lookupAnchorSlot < minLookupSlot) {
24141
- 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}`);
24142
24142
  }
24143
24143
  /**
24144
24144
  * We also require that we have a record of it; this is one of
@@ -24155,7 +24155,7 @@ function verifyRefineContexts(minLookupSlot, contexts, recentBlocksPartialUpdate
24155
24155
  verify_contextual_logger.warn `Lookup anchor check for ${context.lookupAnchor} would fail, but override is active.`;
24156
24156
  }
24157
24157
  else {
24158
- 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})`);
24159
24159
  }
24160
24160
  }
24161
24161
  }
@@ -24178,7 +24178,7 @@ function verifyDependencies({ currentWorkPackages, recentlyReported, prerequisit
24178
24178
  if (recentlyReported.has(preReqHash)) {
24179
24179
  continue;
24180
24180
  }
24181
- 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.`);
24182
24182
  }
24183
24183
  return result_Result.ok(result_OK);
24184
24184
  };
@@ -24226,7 +24226,7 @@ function verifyWorkPackagesUniqueness(workPackageHashes, state) {
24226
24226
  // let's check if any of our packages is in the pipeline
24227
24227
  const intersection = packagesInPipeline.intersection(workPackageHashes);
24228
24228
  for (const packageHash of intersection) {
24229
- 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})`);
24230
24230
  }
24231
24231
  return result_Result.ok(result_OK);
24232
24232
  }
@@ -24265,7 +24265,7 @@ workReportHashes, slot, getGuarantorAssignment) {
24265
24265
  const credentialsView = guaranteeView.credentials.view();
24266
24266
  if (credentialsView.length < REQUIRED_CREDENTIALS_RANGE[0] ||
24267
24267
  credentialsView.length > REQUIRED_CREDENTIALS_RANGE[1]) {
24268
- 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}`);
24269
24269
  }
24270
24270
  /** Retrieve current core assignment. */
24271
24271
  const timeSlot = guaranteeView.slot.materialize();
@@ -24280,20 +24280,20 @@ workReportHashes, slot, getGuarantorAssignment) {
24280
24280
  const credentialView = credential.view();
24281
24281
  const validatorIndex = credentialView.validatorIndex.materialize();
24282
24282
  if (lastValidatorIndex >= validatorIndex) {
24283
- 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}`);
24284
24284
  }
24285
24285
  lastValidatorIndex = validatorIndex;
24286
24286
  const signature = credentialView.signature.materialize();
24287
24287
  const guarantorData = guarantorAssignments[validatorIndex];
24288
24288
  if (guarantorData === undefined) {
24289
- return result_Result.error(ReportsError.BadValidatorIndex, `Invalid validator index: ${validatorIndex}`);
24289
+ return result_Result.error(ReportsError.BadValidatorIndex, () => `Invalid validator index: ${validatorIndex}`);
24290
24290
  }
24291
24291
  /**
24292
24292
  * Verify core assignment.
24293
24293
  * https://graypaper.fluffylabs.dev/#/5f542d7/14e40214e602
24294
24294
  */
24295
24295
  if (guarantorData.core !== coreIndex) {
24296
- 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}`);
24297
24297
  }
24298
24298
  signaturesToVerify.push({
24299
24299
  signature,
@@ -24331,10 +24331,10 @@ function verifyReportsOrder(input, chainSpec) {
24331
24331
  const reportView = guarantee.view().report.view();
24332
24332
  const coreIndex = reportView.coreIndex.materialize();
24333
24333
  if (lastCoreIndex >= coreIndex) {
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}`);
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}`);
24335
24335
  }
24336
24336
  if (coreIndex >= noOfCores) {
24337
- 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}`);
24338
24338
  }
24339
24339
  lastCoreIndex = coreIndex;
24340
24340
  }
@@ -24359,7 +24359,7 @@ function verifyPostSignatureChecks(input, availabilityAssignment, authPools, ser
24359
24359
  * https://graypaper.fluffylabs.dev/#/5f542d7/15ea0015ea00
24360
24360
  */
24361
24361
  if (availabilityAssignment[coreIndex] !== null) {
24362
- 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}`);
24363
24363
  }
24364
24364
  /**
24365
24365
  * A report is valid only if the authorizer hash is present
@@ -24372,7 +24372,7 @@ function verifyPostSignatureChecks(input, availabilityAssignment, authPools, ser
24372
24372
  const authorizerPool = authPools.get(coreIndex);
24373
24373
  const pool = authorizerPool?.materialize() ?? [];
24374
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}`);
24375
+ return result_Result.error(ReportsError.CoreUnauthorized, () => `Authorizer hash not found in the pool of core ${coreIndex}: ${authorizerHash}`);
24376
24376
  }
24377
24377
  /**
24378
24378
  * We require that the gas allotted for accumulation of each
@@ -24384,17 +24384,17 @@ function verifyPostSignatureChecks(input, availabilityAssignment, authPools, ser
24384
24384
  for (const result of report.results) {
24385
24385
  const service = services(result.serviceId);
24386
24386
  if (service === null) {
24387
- 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}`);
24388
24388
  }
24389
24389
  const info = service.getInfo();
24390
24390
  // check minimal accumulation gas
24391
24391
  if (result.gas < 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}`);
24392
+ return result_Result.error(ReportsError.ServiceItemGasTooLow, () => `Service (${result.serviceId}) gas is less than minimal. Got: ${result.gas}, expected at least: ${info.accumulateMinGas}`);
24393
24393
  }
24394
24394
  }
24395
24395
  const totalGas = sumU64(...report.results.map((x) => x.gas));
24396
24396
  if (totalGas.overflow || totalGas.value > G_A) {
24397
- 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}`);
24398
24398
  }
24399
24399
  }
24400
24400
  return result_Result.ok(result_OK);
@@ -24480,7 +24480,7 @@ class Reports {
24480
24480
  }
24481
24481
  const reporters = SortedSet.fromArray(bytesBlobComparator, signaturesToVerify.ok.map((x) => x.key)).slice();
24482
24482
  if (hasAnyOffenders(reporters, input.offenders)) {
24483
- return result_Result.error(ReportsError.BannedValidator);
24483
+ return result_Result.error(ReportsError.BannedValidator, () => "One or more reporters are banned validators");
24484
24484
  }
24485
24485
  return result_Result.ok({
24486
24486
  stateUpdate: {
@@ -24520,7 +24520,7 @@ class Reports {
24520
24520
  return signaturesToVerify[idx].key;
24521
24521
  })
24522
24522
  .filter((x) => x !== null);
24523
- 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(", ")}`);
24524
24524
  }
24525
24525
  /**
24526
24526
  * Get the guarantor assignment (both core and validator data)
@@ -24536,10 +24536,10 @@ class Reports {
24536
24536
  const minTimeSlot = Math.max(0, headerRotation - 1) * rotationPeriod;
24537
24537
  // https://graypaper.fluffylabs.dev/#/5f542d7/155e00156900
24538
24538
  if (guaranteeTimeSlot > headerTimeSlot) {
24539
- 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}`);
24540
24540
  }
24541
24541
  if (guaranteeTimeSlot < minTimeSlot) {
24542
- 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}`);
24543
24543
  }
24544
24544
  // TODO [ToDr] [opti] below code needs cache.
24545
24545
  // The `G` and `G*` sets should only be computed once per rotation.
@@ -25155,11 +25155,11 @@ class OnChain {
25155
25155
  }
25156
25156
  function checkOffendersMatch(offendersMark, headerOffendersMark) {
25157
25157
  if (offendersMark.size !== headerOffendersMark.length) {
25158
- 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}`);
25159
25159
  }
25160
25160
  for (const key of headerOffendersMark) {
25161
25161
  if (!offendersMark.has(key)) {
25162
- return result_Result.error(OFFENDERS_ERROR, `Missing key: ${key}`);
25162
+ return result_Result.error(OFFENDERS_ERROR, () => `Missing key: ${key}`);
25163
25163
  }
25164
25164
  }
25165
25165
  return result_Result.ok(result_OK);
@@ -25241,7 +25241,7 @@ class Importer {
25241
25241
  if (!this.currentHash.isEqualTo(parentHash)) {
25242
25242
  const state = this.states.getState(parentHash);
25243
25243
  if (state === null) {
25244
- const e = result_Result.error(BlockVerifierError.StateRootNotFound);
25244
+ const e = result_Result.error(BlockVerifierError.StateRootNotFound, () => `State not found for parent block ${parentHash}`);
25245
25245
  if (!e.isError) {
25246
25246
  throw new Error("unreachable, just adding to make compiler happy");
25247
25247
  }
@@ -25437,7 +25437,7 @@ const importBlockResultCodec = descriptors_codec.custom({
25437
25437
  }
25438
25438
  if (kind === 1) {
25439
25439
  const error = d.bytesBlob();
25440
- return result_Result.error(error.asText());
25440
+ return result_Result.error(error.asText(), () => error.asText());
25441
25441
  }
25442
25442
  throw new Error(`Invalid Result: ${kind}`);
25443
25443
  }, (s) => {
@@ -25488,7 +25488,7 @@ class MainReady extends State {
25488
25488
  if (res instanceof Uint8Array) {
25489
25489
  return decoder_Decoder.decodeObject(importBlockResultCodec, res);
25490
25490
  }
25491
- return result_Result.error("Invalid worker response.");
25491
+ return result_Result.error("Invalid worker response.", () => "Invalid worker response: expected Uint8Array");
25492
25492
  }
25493
25493
  async getStateEntries(port, hash) {
25494
25494
  const res = await port.sendRequest("getStateEntries", hash, [hash.buffer]);
@@ -25600,13 +25600,13 @@ class ImporterReady extends State {
25600
25600
  response = result_Result.ok(this.importer.getBestStateRootHash() ?? ZERO_HASH.asOpaque());
25601
25601
  }
25602
25602
  else {
25603
- response = result_Result.error(resultToString(res));
25603
+ response = result_Result.error(resultToString(res), () => resultToString(res));
25604
25604
  }
25605
25605
  }
25606
25606
  catch (e) {
25607
25607
  state_machine_logger.error `Failed to import block: ${e}`;
25608
25608
  state_machine_logger.error `${e instanceof Error ? e.stack : ""}`;
25609
- response = result_Result.error(`${e}`);
25609
+ response = result_Result.error(`${e}`, () => `${e}`);
25610
25610
  }
25611
25611
  const encoded = encoder_Encoder.encodeObject(importBlockResultCodec, response);
25612
25612
  return {