@typeberry/lib 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.
Files changed (4) hide show
  1. package/index.cjs +26 -26
  2. package/index.d.ts +49 -24
  3. package/index.js +26 -26
  4. package/package.json +1 -1
package/index.cjs CHANGED
@@ -304,7 +304,7 @@ function resultToString(res) {
304
304
  if (res.isOk) {
305
305
  return `OK: ${typeof res.ok === "symbol" ? res.ok.toString() : res.ok}`;
306
306
  }
307
- return `${res.details}\nError: ${maybeTaggedErrorToString(res.error)}`;
307
+ return `${res.details()}\nError: ${maybeTaggedErrorToString(res.error)}`;
308
308
  }
309
309
  /** An indication of two possible outcomes returned from a function. */
310
310
  const Result$1 = {
@@ -318,7 +318,7 @@ const Result$1 = {
318
318
  };
319
319
  },
320
320
  /** Create new [`Result`] with `Error` status. */
321
- error: (error, details = "") => {
321
+ error: (error, details) => {
322
322
  check `${error !== undefined} 'Error' type cannot be undefined.`;
323
323
  return {
324
324
  isOk: false,
@@ -431,7 +431,7 @@ function deepEqual(actual, expected, { context = [], errorsCollector, ignore = [
431
431
  }
432
432
  if (actual.isError && expected.isError) {
433
433
  deepEqual(actual.error, expected.error, { context: ctx.concat(["error"]), errorsCollector: errors, ignore });
434
- deepEqual(actual.details, expected.details, {
434
+ deepEqual(actual.details(), expected.details(), {
435
435
  context: ctx.concat(["details"]),
436
436
  errorsCollector: errors,
437
437
  // display details when error does not match
@@ -9386,7 +9386,7 @@ class InMemoryState extends WithDebug {
9386
9386
  const { kind } = update.action;
9387
9387
  const service = this.services.get(serviceId);
9388
9388
  if (service === undefined) {
9389
- return Result$1.error(UpdateError.NoService, `Attempting to update storage of non-existing service: ${serviceId}`);
9389
+ return Result$1.error(UpdateError.NoService, () => `Attempting to update storage of non-existing service: ${serviceId}`);
9390
9390
  }
9391
9391
  if (kind === UpdateStorageKind.Set) {
9392
9392
  const { key, value } = update.action.storage;
@@ -9414,14 +9414,14 @@ class InMemoryState extends WithDebug {
9414
9414
  for (const [serviceId, updates] of preimagesUpdates.entries()) {
9415
9415
  const service = this.services.get(serviceId);
9416
9416
  if (service === undefined) {
9417
- return Result$1.error(UpdateError.NoService, `Attempting to update preimage of non-existing service: ${serviceId}`);
9417
+ return Result$1.error(UpdateError.NoService, () => `Attempting to update preimage of non-existing service: ${serviceId}`);
9418
9418
  }
9419
9419
  for (const update of updates) {
9420
9420
  const { kind } = update.action;
9421
9421
  if (kind === UpdatePreimageKind.Provide) {
9422
9422
  const { preimage, slot } = update.action;
9423
9423
  if (service.data.preimages.has(preimage.hash)) {
9424
- return Result$1.error(UpdateError.PreimageExists, `Overwriting existing preimage at ${serviceId}: ${preimage}`);
9424
+ return Result$1.error(UpdateError.PreimageExists, () => `Overwriting existing preimage at ${serviceId}: ${preimage}`);
9425
9425
  }
9426
9426
  service.data.preimages.set(preimage.hash, preimage);
9427
9427
  if (slot !== null) {
@@ -9472,7 +9472,7 @@ class InMemoryState extends WithDebug {
9472
9472
  if (kind === UpdateServiceKind.Create) {
9473
9473
  const { lookupHistory } = update.action;
9474
9474
  if (this.services.has(serviceId)) {
9475
- return Result$1.error(UpdateError.DuplicateService, `${serviceId} already exists!`);
9475
+ return Result$1.error(UpdateError.DuplicateService, () => `${serviceId} already exists!`);
9476
9476
  }
9477
9477
  this.services.set(serviceId, new InMemoryService(serviceId, {
9478
9478
  info: account,
@@ -9484,7 +9484,7 @@ class InMemoryState extends WithDebug {
9484
9484
  else if (kind === UpdateServiceKind.Update) {
9485
9485
  const existingService = this.services.get(serviceId);
9486
9486
  if (existingService === undefined) {
9487
- return Result$1.error(UpdateError.NoService, `Cannot update ${serviceId} because it does not exist.`);
9487
+ return Result$1.error(UpdateError.NoService, () => `Cannot update ${serviceId} because it does not exist.`);
9488
9488
  }
9489
9489
  existingService.data.info = account;
9490
9490
  }
@@ -11095,13 +11095,13 @@ class LeafDb {
11095
11095
  */
11096
11096
  static fromLeavesBlob(blob, db) {
11097
11097
  if (blob.length % TRIE_NODE_BYTES !== 0) {
11098
- return Result$1.error(LeafDbError.InvalidLeafData, `${blob.length} is not a multiply of ${TRIE_NODE_BYTES}: ${blob}`);
11098
+ return Result$1.error(LeafDbError.InvalidLeafData, () => `${blob.length} is not a multiply of ${TRIE_NODE_BYTES}: ${blob}`);
11099
11099
  }
11100
11100
  const leaves = SortedSet.fromArray(leafComparator, []);
11101
11101
  for (const nodeData of blob.chunks(TRIE_NODE_BYTES)) {
11102
11102
  const node = new TrieNode(nodeData.raw);
11103
11103
  if (node.getNodeType() === NodeType.Branch) {
11104
- return Result$1.error(LeafDbError.InvalidLeafData, `Branch node detected: ${nodeData}`);
11104
+ return Result$1.error(LeafDbError.InvalidLeafData, () => `Branch node detected: ${nodeData}`);
11105
11105
  }
11106
11106
  leaves.insert(node.asLeafNode());
11107
11107
  }
@@ -12646,11 +12646,11 @@ class PartiallyUpdatedState {
12646
12646
  const overflowBytes = !isU64(bytes);
12647
12647
  // TODO [ToDr] this is not specified in GP, but it seems sensible.
12648
12648
  if (overflowItems || overflowBytes) {
12649
- return Result$1.error(InsufficientFundsError);
12649
+ return Result$1.error(InsufficientFundsError, () => `Storage utilisation overflow: items=${overflowItems}, bytes=${overflowBytes}`);
12650
12650
  }
12651
12651
  const thresholdBalance = ServiceAccountInfo.calculateThresholdBalance(items, bytes, serviceInfo.gratisStorage);
12652
12652
  if (serviceInfo.balance < thresholdBalance) {
12653
- return Result$1.error(InsufficientFundsError);
12653
+ return Result$1.error(InsufficientFundsError, () => `Service balance (${serviceInfo.balance}) below threshold (${thresholdBalance})`);
12654
12654
  }
12655
12655
  // Update service info with new details.
12656
12656
  this.updateServiceInfo(serviceId, ServiceAccountInfo.create({
@@ -14298,7 +14298,7 @@ class ReadablePage extends MemoryPage {
14298
14298
  loadInto(result, startIndex, length) {
14299
14299
  const endIndex = startIndex + length;
14300
14300
  if (endIndex > PAGE_SIZE$1) {
14301
- return Result$1.error(PageFault.fromMemoryIndex(this.start + PAGE_SIZE$1));
14301
+ return Result$1.error(PageFault.fromMemoryIndex(this.start + PAGE_SIZE$1), () => `Page fault: read beyond page boundary at ${this.start + PAGE_SIZE$1}`);
14302
14302
  }
14303
14303
  const bytes = this.data.subarray(startIndex, endIndex);
14304
14304
  // we zero the bytes, since data might not yet be initialized at `endIndex`.
@@ -14307,7 +14307,7 @@ class ReadablePage extends MemoryPage {
14307
14307
  return Result$1.ok(OK);
14308
14308
  }
14309
14309
  storeFrom(_address, _data) {
14310
- return Result$1.error(PageFault.fromMemoryIndex(this.start, true));
14310
+ return Result$1.error(PageFault.fromMemoryIndex(this.start, true), () => `Page fault: attempted to write to read-only page at ${this.start}`);
14311
14311
  }
14312
14312
  setData(pageIndex, data) {
14313
14313
  this.data.set(data, pageIndex);
@@ -14336,7 +14336,7 @@ class WriteablePage extends MemoryPage {
14336
14336
  loadInto(result, startIndex, length) {
14337
14337
  const endIndex = startIndex + length;
14338
14338
  if (endIndex > PAGE_SIZE$1) {
14339
- return Result$1.error(PageFault.fromMemoryIndex(this.start + PAGE_SIZE$1));
14339
+ return Result$1.error(PageFault.fromMemoryIndex(this.start + PAGE_SIZE$1), () => `Page fault: read beyond page boundary at ${this.start + PAGE_SIZE$1}`);
14340
14340
  }
14341
14341
  const bytes = this.view.subarray(startIndex, endIndex);
14342
14342
  // we zero the bytes, since the view might not yet be initialized at `endIndex`.
@@ -14406,7 +14406,7 @@ class Memory {
14406
14406
  logger$3.insane `MEM[${address}] <- ${BytesBlob.blobFrom(bytes)}`;
14407
14407
  const pagesResult = this.getPages(address, bytes.length, AccessType.WRITE);
14408
14408
  if (pagesResult.isError) {
14409
- return Result$1.error(pagesResult.error);
14409
+ return Result$1.error(pagesResult.error, pagesResult.details);
14410
14410
  }
14411
14411
  const pages = pagesResult.ok;
14412
14412
  let currentPosition = address;
@@ -14431,14 +14431,14 @@ class Memory {
14431
14431
  const pages = [];
14432
14432
  for (const pageNumber of pageRange) {
14433
14433
  if (pageNumber < RESERVED_NUMBER_OF_PAGES) {
14434
- return Result$1.error(PageFault.fromPageNumber(pageNumber, true));
14434
+ return Result$1.error(PageFault.fromPageNumber(pageNumber, true), () => `Page fault: attempted to access reserved page ${pageNumber}`);
14435
14435
  }
14436
14436
  const page = this.memory.get(pageNumber);
14437
14437
  if (page === undefined) {
14438
- return Result$1.error(PageFault.fromPageNumber(pageNumber));
14438
+ return Result$1.error(PageFault.fromPageNumber(pageNumber), () => `Page fault: page ${pageNumber} not allocated`);
14439
14439
  }
14440
14440
  if (accessType === AccessType.WRITE && !page.isWriteable()) {
14441
- return Result$1.error(PageFault.fromPageNumber(pageNumber, true));
14441
+ return Result$1.error(PageFault.fromPageNumber(pageNumber, true), () => `Page fault: attempted to write to read-only page ${pageNumber}`);
14442
14442
  }
14443
14443
  pages.push(page);
14444
14444
  }
@@ -14456,7 +14456,7 @@ class Memory {
14456
14456
  }
14457
14457
  const pagesResult = this.getPages(startAddress, result.length, AccessType.READ);
14458
14458
  if (pagesResult.isError) {
14459
- return Result$1.error(pagesResult.error);
14459
+ return Result$1.error(pagesResult.error, pagesResult.details);
14460
14460
  }
14461
14461
  const pages = pagesResult.ok;
14462
14462
  let currentPosition = startAddress;
@@ -16261,7 +16261,7 @@ class ProgramDecoder {
16261
16261
  }
16262
16262
  catch (e) {
16263
16263
  logger$2.error `Invalid program: ${e}`;
16264
- return Result$1.error(ProgramDecoderError.InvalidProgramError);
16264
+ return Result$1.error(ProgramDecoderError.InvalidProgramError, () => `Program decoder error: ${e}`);
16265
16265
  }
16266
16266
  }
16267
16267
  }
@@ -16542,7 +16542,7 @@ class HostCallMemory {
16542
16542
  return Result$1.ok(OK);
16543
16543
  }
16544
16544
  if (address + tryAsU64(bytes.length) > MEMORY_SIZE) {
16545
- return Result$1.error(new OutOfBounds());
16545
+ return Result$1.error(new OutOfBounds(), () => `Memory access out of bounds: address ${address} + length ${bytes.length} exceeds memory size`);
16546
16546
  }
16547
16547
  return this.memory.storeFrom(tryAsMemoryIndex(Number(address)), bytes);
16548
16548
  }
@@ -16551,7 +16551,7 @@ class HostCallMemory {
16551
16551
  return Result$1.ok(OK);
16552
16552
  }
16553
16553
  if (startAddress + tryAsU64(result.length) > MEMORY_SIZE) {
16554
- return Result$1.error(new OutOfBounds());
16554
+ return Result$1.error(new OutOfBounds(), () => `Memory access out of bounds: address ${startAddress} + length ${result.length} exceeds memory size`);
16555
16555
  }
16556
16556
  return this.memory.loadInto(result, tryAsMemoryIndex(Number(startAddress)));
16557
16557
  }
@@ -17642,7 +17642,7 @@ class Preimages {
17642
17642
  }
17643
17643
  if (prevPreimage.requester > currPreimage.requester ||
17644
17644
  currPreimage.blob.compare(prevPreimage.blob).isLessOrEqual()) {
17645
- return Result$1.error(PreimagesErrorCode.PreimagesNotSortedUnique);
17645
+ return Result$1.error(PreimagesErrorCode.PreimagesNotSortedUnique, () => `Preimages not sorted/unique at index ${i}`);
17646
17646
  }
17647
17647
  }
17648
17648
  const { preimages, slot } = input;
@@ -17653,14 +17653,14 @@ class Preimages {
17653
17653
  const hash = this.blake2b.hashBytes(blob).asOpaque();
17654
17654
  const service = this.state.getService(requester);
17655
17655
  if (service === null) {
17656
- return Result$1.error(PreimagesErrorCode.AccountNotFound);
17656
+ return Result$1.error(PreimagesErrorCode.AccountNotFound, () => `Service not found: ${requester}`);
17657
17657
  }
17658
17658
  const hasPreimage = service.hasPreimage(hash);
17659
17659
  const slots = service.getLookupHistory(hash, tryAsU32(blob.length));
17660
17660
  // https://graypaper.fluffylabs.dev/#/5f542d7/181800181900
17661
17661
  // https://graypaper.fluffylabs.dev/#/5f542d7/116f0011a500
17662
17662
  if (hasPreimage || slots === null || !LookupHistoryItem.isRequested(slots)) {
17663
- return Result$1.error(PreimagesErrorCode.PreimageUnneeded);
17663
+ return Result$1.error(PreimagesErrorCode.PreimageUnneeded, () => `Preimage unneeded: requester=${requester}, hash=${hash}, hasPreimage=${hasPreimage}, isRequested=${slots !== null && LookupHistoryItem.isRequested(slots)}`);
17664
17664
  }
17665
17665
  // https://graypaper.fluffylabs.dev/#/5f542d7/18c00018f300
17666
17666
  const updates = pendingChanges.get(requester) ?? [];
package/index.d.ts CHANGED
@@ -322,7 +322,7 @@ type ErrorResult<Error> = {
322
322
  isOk: false;
323
323
  isError: true;
324
324
  error: Error;
325
- details: string;
325
+ details: () => string;
326
326
  };
327
327
 
328
328
  /**
@@ -383,7 +383,7 @@ declare function resultToString<Ok, Error>(res: Result$2<Ok, Error>) {
383
383
  if (res.isOk) {
384
384
  return `OK: ${typeof res.ok === "symbol" ? res.ok.toString() : res.ok}`;
385
385
  }
386
- return `${res.details}\nError: ${maybeTaggedErrorToString(res.error)}`;
386
+ return `${res.details()}\nError: ${maybeTaggedErrorToString(res.error)}`;
387
387
  }
388
388
 
389
389
  /** An indication of two possible outcomes returned from a function. */
@@ -402,7 +402,7 @@ declare const Result$2 = {
402
402
  },
403
403
 
404
404
  /** Create new [`Result`] with `Error` status. */
405
- error: <Error>(error: Error, details = ""): ErrorResult<Error> => {
405
+ error: <Error>(error: Error, details: () => string): ErrorResult<Error> => {
406
406
  check`${error !== undefined} 'Error' type cannot be undefined.`;
407
407
  return {
408
408
  isOk: false,
@@ -556,7 +556,7 @@ declare function deepEqual<T>(
556
556
 
557
557
  if (actual.isError && expected.isError) {
558
558
  deepEqual(actual.error, expected.error, { context: ctx.concat(["error"]), errorsCollector: errors, ignore });
559
- deepEqual(actual.details, expected.details, {
559
+ deepEqual(actual.details(), expected.details(), {
560
560
  context: ctx.concat(["details"]),
561
561
  errorsCollector: errors,
562
562
  // display details when error does not match
@@ -11070,7 +11070,7 @@ declare class InMemoryState extends WithDebug implements State, WithStateView, E
11070
11070
  if (service === undefined) {
11071
11071
  return Result.error(
11072
11072
  UpdateError.NoService,
11073
- `Attempting to update storage of non-existing service: ${serviceId}`,
11073
+ () => `Attempting to update storage of non-existing service: ${serviceId}`,
11074
11074
  );
11075
11075
  }
11076
11076
 
@@ -11101,7 +11101,7 @@ declare class InMemoryState extends WithDebug implements State, WithStateView, E
11101
11101
  if (service === undefined) {
11102
11102
  return Result.error(
11103
11103
  UpdateError.NoService,
11104
- `Attempting to update preimage of non-existing service: ${serviceId}`,
11104
+ () => `Attempting to update preimage of non-existing service: ${serviceId}`,
11105
11105
  );
11106
11106
  }
11107
11107
  for (const update of updates) {
@@ -11111,7 +11111,7 @@ declare class InMemoryState extends WithDebug implements State, WithStateView, E
11111
11111
  if (service.data.preimages.has(preimage.hash)) {
11112
11112
  return Result.error(
11113
11113
  UpdateError.PreimageExists,
11114
- `Overwriting existing preimage at ${serviceId}: ${preimage}`,
11114
+ () => `Overwriting existing preimage at ${serviceId}: ${preimage}`,
11115
11115
  );
11116
11116
  }
11117
11117
  service.data.preimages.set(preimage.hash, preimage);
@@ -11160,7 +11160,7 @@ declare class InMemoryState extends WithDebug implements State, WithStateView, E
11160
11160
  if (kind === UpdateServiceKind.Create) {
11161
11161
  const { lookupHistory } = update.action;
11162
11162
  if (this.services.has(serviceId)) {
11163
- return Result.error(UpdateError.DuplicateService, `${serviceId} already exists!`);
11163
+ return Result.error(UpdateError.DuplicateService, () => `${serviceId} already exists!`);
11164
11164
  }
11165
11165
  this.services.set(
11166
11166
  serviceId,
@@ -11176,7 +11176,7 @@ declare class InMemoryState extends WithDebug implements State, WithStateView, E
11176
11176
  } else if (kind === UpdateServiceKind.Update) {
11177
11177
  const existingService = this.services.get(serviceId);
11178
11178
  if (existingService === undefined) {
11179
- return Result.error(UpdateError.NoService, `Cannot update ${serviceId} because it does not exist.`);
11179
+ return Result.error(UpdateError.NoService, () => `Cannot update ${serviceId} because it does not exist.`);
11180
11180
  }
11181
11181
  existingService.data.info = account;
11182
11182
  } else {
@@ -12682,7 +12682,7 @@ declare class LeafDb implements SerializedStateBackend {
12682
12682
  if (blob.length % TRIE_NODE_BYTES !== 0) {
12683
12683
  return Result.error(
12684
12684
  LeafDbError.InvalidLeafData,
12685
- `${blob.length} is not a multiply of ${TRIE_NODE_BYTES}: ${blob}`,
12685
+ () => `${blob.length} is not a multiply of ${TRIE_NODE_BYTES}: ${blob}`,
12686
12686
  );
12687
12687
  }
12688
12688
 
@@ -12690,7 +12690,7 @@ declare class LeafDb implements SerializedStateBackend {
12690
12690
  for (const nodeData of blob.chunks(TRIE_NODE_BYTES)) {
12691
12691
  const node = new TrieNode(nodeData.raw);
12692
12692
  if (node.getNodeType() === NodeType.Branch) {
12693
- return Result.error(LeafDbError.InvalidLeafData, `Branch node detected: ${nodeData}`);
12693
+ return Result.error(LeafDbError.InvalidLeafData, () => `Branch node detected: ${nodeData}`);
12694
12694
  }
12695
12695
  leaves.insert(node.asLeafNode());
12696
12696
  }
@@ -15502,7 +15502,7 @@ declare class Memory {
15502
15502
  const pagesResult = this.getPages(address, bytes.length, AccessType.WRITE);
15503
15503
 
15504
15504
  if (pagesResult.isError) {
15505
- return Result.error(pagesResult.error);
15505
+ return Result.error(pagesResult.error, pagesResult.details);
15506
15506
  }
15507
15507
 
15508
15508
  const pages = pagesResult.ok;
@@ -15535,17 +15535,23 @@ declare class Memory {
15535
15535
 
15536
15536
  for (const pageNumber of pageRange) {
15537
15537
  if (pageNumber < RESERVED_NUMBER_OF_PAGES) {
15538
- return Result.error(PageFault.fromPageNumber(pageNumber, true));
15538
+ return Result.error(
15539
+ PageFault.fromPageNumber(pageNumber, true),
15540
+ () => `Page fault: attempted to access reserved page ${pageNumber}`,
15541
+ );
15539
15542
  }
15540
15543
 
15541
15544
  const page = this.memory.get(pageNumber);
15542
15545
 
15543
15546
  if (page === undefined) {
15544
- return Result.error(PageFault.fromPageNumber(pageNumber));
15547
+ return Result.error(PageFault.fromPageNumber(pageNumber), () => `Page fault: page ${pageNumber} not allocated`);
15545
15548
  }
15546
15549
 
15547
15550
  if (accessType === AccessType.WRITE && !page.isWriteable()) {
15548
- return Result.error(PageFault.fromPageNumber(pageNumber, true));
15551
+ return Result.error(
15552
+ PageFault.fromPageNumber(pageNumber, true),
15553
+ () => `Page fault: attempted to write to read-only page ${pageNumber}`,
15554
+ );
15549
15555
  }
15550
15556
 
15551
15557
  pages.push(page);
@@ -15567,7 +15573,7 @@ declare class Memory {
15567
15573
  const pagesResult = this.getPages(startAddress, result.length, AccessType.READ);
15568
15574
 
15569
15575
  if (pagesResult.isError) {
15570
- return Result.error(pagesResult.error);
15576
+ return Result.error(pagesResult.error, pagesResult.details);
15571
15577
  }
15572
15578
 
15573
15579
  const pages = pagesResult.ok;
@@ -17552,7 +17558,7 @@ declare class ProgramDecoder {
17552
17558
  return Result.ok(new ProgramDecoder(program));
17553
17559
  } catch (e) {
17554
17560
  logger.error`Invalid program: ${e}`;
17555
- return Result.error(ProgramDecoderError.InvalidProgramError);
17561
+ return Result.error(ProgramDecoderError.InvalidProgramError, () => `Program decoder error: ${e}`);
17556
17562
  }
17557
17563
  }
17558
17564
  }
@@ -17910,7 +17916,10 @@ declare class HostCallMemory implements IHostCallMemory {
17910
17916
  }
17911
17917
 
17912
17918
  if (address + tryAsU64(bytes.length) > MEMORY_SIZE) {
17913
- return Result.error(new OutOfBounds());
17919
+ return Result.error(
17920
+ new OutOfBounds(),
17921
+ () => `Memory access out of bounds: address ${address} + length ${bytes.length} exceeds memory size`,
17922
+ );
17914
17923
  }
17915
17924
 
17916
17925
  return this.memory.storeFrom(tryAsMemoryIndex(Number(address)), bytes);
@@ -17922,7 +17931,10 @@ declare class HostCallMemory implements IHostCallMemory {
17922
17931
  }
17923
17932
 
17924
17933
  if (startAddress + tryAsU64(result.length) > MEMORY_SIZE) {
17925
- return Result.error(new OutOfBounds());
17934
+ return Result.error(
17935
+ new OutOfBounds(),
17936
+ () => `Memory access out of bounds: address ${startAddress} + length ${result.length} exceeds memory size`,
17937
+ );
17926
17938
  }
17927
17939
 
17928
17940
  return this.memory.loadInto(result, tryAsMemoryIndex(Number(startAddress)));
@@ -18679,12 +18691,18 @@ declare class PartiallyUpdatedState<T extends StateSlice = StateSlice> {
18679
18691
 
18680
18692
  // TODO [ToDr] this is not specified in GP, but it seems sensible.
18681
18693
  if (overflowItems || overflowBytes) {
18682
- return Result.error(InsufficientFundsError);
18694
+ return Result.error(
18695
+ InsufficientFundsError,
18696
+ () => `Storage utilisation overflow: items=${overflowItems}, bytes=${overflowBytes}`,
18697
+ );
18683
18698
  }
18684
18699
 
18685
18700
  const thresholdBalance = ServiceAccountInfo.calculateThresholdBalance(items, bytes, serviceInfo.gratisStorage);
18686
18701
  if (serviceInfo.balance < thresholdBalance) {
18687
- return Result.error(InsufficientFundsError);
18702
+ return Result.error(
18703
+ InsufficientFundsError,
18704
+ () => `Service balance (${serviceInfo.balance}) below threshold (${thresholdBalance})`,
18705
+ );
18688
18706
  }
18689
18707
 
18690
18708
  // Update service info with new details.
@@ -20124,7 +20142,10 @@ declare class Preimages {
20124
20142
  prevPreimage.requester > currPreimage.requester ||
20125
20143
  currPreimage.blob.compare(prevPreimage.blob).isLessOrEqual()
20126
20144
  ) {
20127
- return Result.error(PreimagesErrorCode.PreimagesNotSortedUnique);
20145
+ return Result.error(
20146
+ PreimagesErrorCode.PreimagesNotSortedUnique,
20147
+ () => `Preimages not sorted/unique at index ${i}`,
20148
+ );
20128
20149
  }
20129
20150
  }
20130
20151
 
@@ -20138,7 +20159,7 @@ declare class Preimages {
20138
20159
 
20139
20160
  const service = this.state.getService(requester);
20140
20161
  if (service === null) {
20141
- return Result.error(PreimagesErrorCode.AccountNotFound);
20162
+ return Result.error(PreimagesErrorCode.AccountNotFound, () => `Service not found: ${requester}`);
20142
20163
  }
20143
20164
 
20144
20165
  const hasPreimage = service.hasPreimage(hash);
@@ -20146,7 +20167,11 @@ declare class Preimages {
20146
20167
  // https://graypaper.fluffylabs.dev/#/5f542d7/181800181900
20147
20168
  // https://graypaper.fluffylabs.dev/#/5f542d7/116f0011a500
20148
20169
  if (hasPreimage || slots === null || !LookupHistoryItem.isRequested(slots)) {
20149
- return Result.error(PreimagesErrorCode.PreimageUnneeded);
20170
+ return Result.error(
20171
+ PreimagesErrorCode.PreimageUnneeded,
20172
+ () =>
20173
+ `Preimage unneeded: requester=${requester}, hash=${hash}, hasPreimage=${hasPreimage}, isRequested=${slots !== null && LookupHistoryItem.isRequested(slots)}`,
20174
+ );
20150
20175
  }
20151
20176
 
20152
20177
  // https://graypaper.fluffylabs.dev/#/5f542d7/18c00018f300
package/index.js CHANGED
@@ -301,7 +301,7 @@ function resultToString(res) {
301
301
  if (res.isOk) {
302
302
  return `OK: ${typeof res.ok === "symbol" ? res.ok.toString() : res.ok}`;
303
303
  }
304
- return `${res.details}\nError: ${maybeTaggedErrorToString(res.error)}`;
304
+ return `${res.details()}\nError: ${maybeTaggedErrorToString(res.error)}`;
305
305
  }
306
306
  /** An indication of two possible outcomes returned from a function. */
307
307
  const Result$1 = {
@@ -315,7 +315,7 @@ const Result$1 = {
315
315
  };
316
316
  },
317
317
  /** Create new [`Result`] with `Error` status. */
318
- error: (error, details = "") => {
318
+ error: (error, details) => {
319
319
  check `${error !== undefined} 'Error' type cannot be undefined.`;
320
320
  return {
321
321
  isOk: false,
@@ -428,7 +428,7 @@ function deepEqual(actual, expected, { context = [], errorsCollector, ignore = [
428
428
  }
429
429
  if (actual.isError && expected.isError) {
430
430
  deepEqual(actual.error, expected.error, { context: ctx.concat(["error"]), errorsCollector: errors, ignore });
431
- deepEqual(actual.details, expected.details, {
431
+ deepEqual(actual.details(), expected.details(), {
432
432
  context: ctx.concat(["details"]),
433
433
  errorsCollector: errors,
434
434
  // display details when error does not match
@@ -9383,7 +9383,7 @@ class InMemoryState extends WithDebug {
9383
9383
  const { kind } = update.action;
9384
9384
  const service = this.services.get(serviceId);
9385
9385
  if (service === undefined) {
9386
- return Result$1.error(UpdateError.NoService, `Attempting to update storage of non-existing service: ${serviceId}`);
9386
+ return Result$1.error(UpdateError.NoService, () => `Attempting to update storage of non-existing service: ${serviceId}`);
9387
9387
  }
9388
9388
  if (kind === UpdateStorageKind.Set) {
9389
9389
  const { key, value } = update.action.storage;
@@ -9411,14 +9411,14 @@ class InMemoryState extends WithDebug {
9411
9411
  for (const [serviceId, updates] of preimagesUpdates.entries()) {
9412
9412
  const service = this.services.get(serviceId);
9413
9413
  if (service === undefined) {
9414
- return Result$1.error(UpdateError.NoService, `Attempting to update preimage of non-existing service: ${serviceId}`);
9414
+ return Result$1.error(UpdateError.NoService, () => `Attempting to update preimage of non-existing service: ${serviceId}`);
9415
9415
  }
9416
9416
  for (const update of updates) {
9417
9417
  const { kind } = update.action;
9418
9418
  if (kind === UpdatePreimageKind.Provide) {
9419
9419
  const { preimage, slot } = update.action;
9420
9420
  if (service.data.preimages.has(preimage.hash)) {
9421
- return Result$1.error(UpdateError.PreimageExists, `Overwriting existing preimage at ${serviceId}: ${preimage}`);
9421
+ return Result$1.error(UpdateError.PreimageExists, () => `Overwriting existing preimage at ${serviceId}: ${preimage}`);
9422
9422
  }
9423
9423
  service.data.preimages.set(preimage.hash, preimage);
9424
9424
  if (slot !== null) {
@@ -9469,7 +9469,7 @@ class InMemoryState extends WithDebug {
9469
9469
  if (kind === UpdateServiceKind.Create) {
9470
9470
  const { lookupHistory } = update.action;
9471
9471
  if (this.services.has(serviceId)) {
9472
- return Result$1.error(UpdateError.DuplicateService, `${serviceId} already exists!`);
9472
+ return Result$1.error(UpdateError.DuplicateService, () => `${serviceId} already exists!`);
9473
9473
  }
9474
9474
  this.services.set(serviceId, new InMemoryService(serviceId, {
9475
9475
  info: account,
@@ -9481,7 +9481,7 @@ class InMemoryState extends WithDebug {
9481
9481
  else if (kind === UpdateServiceKind.Update) {
9482
9482
  const existingService = this.services.get(serviceId);
9483
9483
  if (existingService === undefined) {
9484
- return Result$1.error(UpdateError.NoService, `Cannot update ${serviceId} because it does not exist.`);
9484
+ return Result$1.error(UpdateError.NoService, () => `Cannot update ${serviceId} because it does not exist.`);
9485
9485
  }
9486
9486
  existingService.data.info = account;
9487
9487
  }
@@ -11092,13 +11092,13 @@ class LeafDb {
11092
11092
  */
11093
11093
  static fromLeavesBlob(blob, db) {
11094
11094
  if (blob.length % TRIE_NODE_BYTES !== 0) {
11095
- return Result$1.error(LeafDbError.InvalidLeafData, `${blob.length} is not a multiply of ${TRIE_NODE_BYTES}: ${blob}`);
11095
+ return Result$1.error(LeafDbError.InvalidLeafData, () => `${blob.length} is not a multiply of ${TRIE_NODE_BYTES}: ${blob}`);
11096
11096
  }
11097
11097
  const leaves = SortedSet.fromArray(leafComparator, []);
11098
11098
  for (const nodeData of blob.chunks(TRIE_NODE_BYTES)) {
11099
11099
  const node = new TrieNode(nodeData.raw);
11100
11100
  if (node.getNodeType() === NodeType.Branch) {
11101
- return Result$1.error(LeafDbError.InvalidLeafData, `Branch node detected: ${nodeData}`);
11101
+ return Result$1.error(LeafDbError.InvalidLeafData, () => `Branch node detected: ${nodeData}`);
11102
11102
  }
11103
11103
  leaves.insert(node.asLeafNode());
11104
11104
  }
@@ -12643,11 +12643,11 @@ class PartiallyUpdatedState {
12643
12643
  const overflowBytes = !isU64(bytes);
12644
12644
  // TODO [ToDr] this is not specified in GP, but it seems sensible.
12645
12645
  if (overflowItems || overflowBytes) {
12646
- return Result$1.error(InsufficientFundsError);
12646
+ return Result$1.error(InsufficientFundsError, () => `Storage utilisation overflow: items=${overflowItems}, bytes=${overflowBytes}`);
12647
12647
  }
12648
12648
  const thresholdBalance = ServiceAccountInfo.calculateThresholdBalance(items, bytes, serviceInfo.gratisStorage);
12649
12649
  if (serviceInfo.balance < thresholdBalance) {
12650
- return Result$1.error(InsufficientFundsError);
12650
+ return Result$1.error(InsufficientFundsError, () => `Service balance (${serviceInfo.balance}) below threshold (${thresholdBalance})`);
12651
12651
  }
12652
12652
  // Update service info with new details.
12653
12653
  this.updateServiceInfo(serviceId, ServiceAccountInfo.create({
@@ -14295,7 +14295,7 @@ class ReadablePage extends MemoryPage {
14295
14295
  loadInto(result, startIndex, length) {
14296
14296
  const endIndex = startIndex + length;
14297
14297
  if (endIndex > PAGE_SIZE$1) {
14298
- return Result$1.error(PageFault.fromMemoryIndex(this.start + PAGE_SIZE$1));
14298
+ return Result$1.error(PageFault.fromMemoryIndex(this.start + PAGE_SIZE$1), () => `Page fault: read beyond page boundary at ${this.start + PAGE_SIZE$1}`);
14299
14299
  }
14300
14300
  const bytes = this.data.subarray(startIndex, endIndex);
14301
14301
  // we zero the bytes, since data might not yet be initialized at `endIndex`.
@@ -14304,7 +14304,7 @@ class ReadablePage extends MemoryPage {
14304
14304
  return Result$1.ok(OK);
14305
14305
  }
14306
14306
  storeFrom(_address, _data) {
14307
- return Result$1.error(PageFault.fromMemoryIndex(this.start, true));
14307
+ return Result$1.error(PageFault.fromMemoryIndex(this.start, true), () => `Page fault: attempted to write to read-only page at ${this.start}`);
14308
14308
  }
14309
14309
  setData(pageIndex, data) {
14310
14310
  this.data.set(data, pageIndex);
@@ -14333,7 +14333,7 @@ class WriteablePage extends MemoryPage {
14333
14333
  loadInto(result, startIndex, length) {
14334
14334
  const endIndex = startIndex + length;
14335
14335
  if (endIndex > PAGE_SIZE$1) {
14336
- return Result$1.error(PageFault.fromMemoryIndex(this.start + PAGE_SIZE$1));
14336
+ return Result$1.error(PageFault.fromMemoryIndex(this.start + PAGE_SIZE$1), () => `Page fault: read beyond page boundary at ${this.start + PAGE_SIZE$1}`);
14337
14337
  }
14338
14338
  const bytes = this.view.subarray(startIndex, endIndex);
14339
14339
  // we zero the bytes, since the view might not yet be initialized at `endIndex`.
@@ -14403,7 +14403,7 @@ class Memory {
14403
14403
  logger$3.insane `MEM[${address}] <- ${BytesBlob.blobFrom(bytes)}`;
14404
14404
  const pagesResult = this.getPages(address, bytes.length, AccessType.WRITE);
14405
14405
  if (pagesResult.isError) {
14406
- return Result$1.error(pagesResult.error);
14406
+ return Result$1.error(pagesResult.error, pagesResult.details);
14407
14407
  }
14408
14408
  const pages = pagesResult.ok;
14409
14409
  let currentPosition = address;
@@ -14428,14 +14428,14 @@ class Memory {
14428
14428
  const pages = [];
14429
14429
  for (const pageNumber of pageRange) {
14430
14430
  if (pageNumber < RESERVED_NUMBER_OF_PAGES) {
14431
- return Result$1.error(PageFault.fromPageNumber(pageNumber, true));
14431
+ return Result$1.error(PageFault.fromPageNumber(pageNumber, true), () => `Page fault: attempted to access reserved page ${pageNumber}`);
14432
14432
  }
14433
14433
  const page = this.memory.get(pageNumber);
14434
14434
  if (page === undefined) {
14435
- return Result$1.error(PageFault.fromPageNumber(pageNumber));
14435
+ return Result$1.error(PageFault.fromPageNumber(pageNumber), () => `Page fault: page ${pageNumber} not allocated`);
14436
14436
  }
14437
14437
  if (accessType === AccessType.WRITE && !page.isWriteable()) {
14438
- return Result$1.error(PageFault.fromPageNumber(pageNumber, true));
14438
+ return Result$1.error(PageFault.fromPageNumber(pageNumber, true), () => `Page fault: attempted to write to read-only page ${pageNumber}`);
14439
14439
  }
14440
14440
  pages.push(page);
14441
14441
  }
@@ -14453,7 +14453,7 @@ class Memory {
14453
14453
  }
14454
14454
  const pagesResult = this.getPages(startAddress, result.length, AccessType.READ);
14455
14455
  if (pagesResult.isError) {
14456
- return Result$1.error(pagesResult.error);
14456
+ return Result$1.error(pagesResult.error, pagesResult.details);
14457
14457
  }
14458
14458
  const pages = pagesResult.ok;
14459
14459
  let currentPosition = startAddress;
@@ -16258,7 +16258,7 @@ class ProgramDecoder {
16258
16258
  }
16259
16259
  catch (e) {
16260
16260
  logger$2.error `Invalid program: ${e}`;
16261
- return Result$1.error(ProgramDecoderError.InvalidProgramError);
16261
+ return Result$1.error(ProgramDecoderError.InvalidProgramError, () => `Program decoder error: ${e}`);
16262
16262
  }
16263
16263
  }
16264
16264
  }
@@ -16539,7 +16539,7 @@ class HostCallMemory {
16539
16539
  return Result$1.ok(OK);
16540
16540
  }
16541
16541
  if (address + tryAsU64(bytes.length) > MEMORY_SIZE) {
16542
- return Result$1.error(new OutOfBounds());
16542
+ return Result$1.error(new OutOfBounds(), () => `Memory access out of bounds: address ${address} + length ${bytes.length} exceeds memory size`);
16543
16543
  }
16544
16544
  return this.memory.storeFrom(tryAsMemoryIndex(Number(address)), bytes);
16545
16545
  }
@@ -16548,7 +16548,7 @@ class HostCallMemory {
16548
16548
  return Result$1.ok(OK);
16549
16549
  }
16550
16550
  if (startAddress + tryAsU64(result.length) > MEMORY_SIZE) {
16551
- return Result$1.error(new OutOfBounds());
16551
+ return Result$1.error(new OutOfBounds(), () => `Memory access out of bounds: address ${startAddress} + length ${result.length} exceeds memory size`);
16552
16552
  }
16553
16553
  return this.memory.loadInto(result, tryAsMemoryIndex(Number(startAddress)));
16554
16554
  }
@@ -17639,7 +17639,7 @@ class Preimages {
17639
17639
  }
17640
17640
  if (prevPreimage.requester > currPreimage.requester ||
17641
17641
  currPreimage.blob.compare(prevPreimage.blob).isLessOrEqual()) {
17642
- return Result$1.error(PreimagesErrorCode.PreimagesNotSortedUnique);
17642
+ return Result$1.error(PreimagesErrorCode.PreimagesNotSortedUnique, () => `Preimages not sorted/unique at index ${i}`);
17643
17643
  }
17644
17644
  }
17645
17645
  const { preimages, slot } = input;
@@ -17650,14 +17650,14 @@ class Preimages {
17650
17650
  const hash = this.blake2b.hashBytes(blob).asOpaque();
17651
17651
  const service = this.state.getService(requester);
17652
17652
  if (service === null) {
17653
- return Result$1.error(PreimagesErrorCode.AccountNotFound);
17653
+ return Result$1.error(PreimagesErrorCode.AccountNotFound, () => `Service not found: ${requester}`);
17654
17654
  }
17655
17655
  const hasPreimage = service.hasPreimage(hash);
17656
17656
  const slots = service.getLookupHistory(hash, tryAsU32(blob.length));
17657
17657
  // https://graypaper.fluffylabs.dev/#/5f542d7/181800181900
17658
17658
  // https://graypaper.fluffylabs.dev/#/5f542d7/116f0011a500
17659
17659
  if (hasPreimage || slots === null || !LookupHistoryItem.isRequested(slots)) {
17660
- return Result$1.error(PreimagesErrorCode.PreimageUnneeded);
17660
+ return Result$1.error(PreimagesErrorCode.PreimageUnneeded, () => `Preimage unneeded: requester=${requester}, hash=${hash}, hasPreimage=${hasPreimage}, isRequested=${slots !== null && LookupHistoryItem.isRequested(slots)}`);
17661
17661
  }
17662
17662
  // https://graypaper.fluffylabs.dev/#/5f542d7/18c00018f300
17663
17663
  const updates = pendingChanges.get(requester) ?? [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typeberry/lib",
3
- "version": "0.2.0-8017bfd",
3
+ "version": "0.2.0-adde0dd",
4
4
  "main": "index.js",
5
5
  "author": "Fluffy Labs",
6
6
  "license": "MPL-2.0",