@typeberry/lib 0.1.3-707962d → 0.1.3-d3752d8

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 +64 -22
  2. package/index.d.ts +77 -27
  3. package/index.js +64 -22
  4. package/package.json +1 -1
package/index.cjs CHANGED
@@ -332,6 +332,19 @@ const Result$1 = {
332
332
  },
333
333
  };
334
334
 
335
+ // about 2GB, the maximum ArrayBuffer length on Chrome confirmed by several sources:
336
+ // - https://issues.chromium.org/issues/40055619
337
+ // - https://stackoverflow.com/a/72124984
338
+ // - https://onnxruntime.ai/docs/tutorials/web/large-models.html#maximum-size-of-arraybuffer
339
+ const MAX_LENGTH$2 = 2145386496;
340
+ function safeAllocUint8Array(length) {
341
+ if (length > MAX_LENGTH$2) {
342
+ // biome-ignore lint/suspicious/noConsole: can't have a dependency on logger here
343
+ console.warn(`Trying to allocate ${length} bytes, which is greater than the maximum of ${MAX_LENGTH$2}.`);
344
+ }
345
+ return new Uint8Array(Math.min(MAX_LENGTH$2, length));
346
+ }
347
+
335
348
  /**
336
349
  * Utilities for tests.
337
350
  */
@@ -572,6 +585,7 @@ var index$u = /*#__PURE__*/Object.freeze({
572
585
  DEFAULT_VERSION: DEFAULT_VERSION,
573
586
  ErrorsCollector: ErrorsCollector,
574
587
  get GpVersion () { return GpVersion; },
588
+ MAX_LENGTH: MAX_LENGTH$2,
575
589
  OK: OK,
576
590
  Result: Result$1,
577
591
  TEST_COMPARE_USING: TEST_COMPARE_USING,
@@ -586,6 +600,7 @@ var index$u = /*#__PURE__*/Object.freeze({
586
600
  isBrowser: isBrowser,
587
601
  measure: measure,
588
602
  resultToString: resultToString,
603
+ safeAllocUint8Array: safeAllocUint8Array,
589
604
  seeThrough: seeThrough,
590
605
  workspacePathFix: workspacePathFix
591
606
  });
@@ -609,7 +624,7 @@ class BitVec {
609
624
  * Create new [`BitVec`] with all values set to `false`.
610
625
  */
611
626
  static empty(bitLength) {
612
- const data = new Uint8Array(Math.ceil(bitLength / 8));
627
+ const data = safeAllocUint8Array(Math.ceil(bitLength / 8));
613
628
  return new BitVec(data, bitLength);
614
629
  }
615
630
  byteLength;
@@ -810,7 +825,7 @@ class BytesBlob {
810
825
  static blobFromParts(v, ...rest) {
811
826
  const vArr = v instanceof Uint8Array ? [v] : v;
812
827
  const totalLength = vArr.reduce((a, v) => a + v.length, 0) + rest.reduce((a, v) => a + v.length, 0);
813
- const buffer = new Uint8Array(totalLength);
828
+ const buffer = safeAllocUint8Array(totalLength);
814
829
  let offset = 0;
815
830
  for (const r of vArr) {
816
831
  buffer.set(r, offset);
@@ -883,7 +898,7 @@ class Bytes extends BytesBlob {
883
898
  }
884
899
  /** Create an empty [`Bytes<X>`] of given length. */
885
900
  static zero(len) {
886
- return new Bytes(new Uint8Array(len), len);
901
+ return new Bytes(safeAllocUint8Array(len), len);
887
902
  }
888
903
  // TODO [ToDr] `fill` should have the argments swapped to align with the rest.
889
904
  /** Create a [`Bytes<X>`] with all bytes filled with given input number. */
@@ -3592,7 +3607,7 @@ async function verify(input) {
3592
3607
  return Promise.resolve([]);
3593
3608
  }
3594
3609
  const dataLength = input.reduce((acc, { message, key, signature }) => acc + key.length + signature.length + message.length + 1, 0);
3595
- const data = new Uint8Array(dataLength);
3610
+ const data = safeAllocUint8Array(dataLength);
3596
3611
  let offset = 0;
3597
3612
  for (const { key, message, signature } of input) {
3598
3613
  data.set(key.raw, offset);
@@ -3684,7 +3699,7 @@ class SimpleAllocator {
3684
3699
  /** An allocator that works by allocating larger (continuous) pages of memory. */
3685
3700
  class PageAllocator {
3686
3701
  hashesPerPage;
3687
- page = new Uint8Array(0);
3702
+ page = safeAllocUint8Array(0);
3688
3703
  currentHash = 0;
3689
3704
  // TODO [ToDr] Benchmark the performance!
3690
3705
  constructor(hashesPerPage) {
@@ -3695,7 +3710,7 @@ class PageAllocator {
3695
3710
  resetPage() {
3696
3711
  const pageSizeBytes = this.hashesPerPage * HASH_SIZE;
3697
3712
  this.currentHash = 0;
3698
- this.page = new Uint8Array(pageSizeBytes);
3713
+ this.page = safeAllocUint8Array(pageSizeBytes);
3699
3714
  }
3700
3715
  emptyHash() {
3701
3716
  const startIdx = this.currentHash * HASH_SIZE;
@@ -8731,6 +8746,10 @@ class DisputesRecords {
8731
8746
  static create({ goodSet, badSet, wonkySet, punishSet }) {
8732
8747
  return new DisputesRecords(goodSet, badSet, wonkySet, punishSet);
8733
8748
  }
8749
+ goodSetDict;
8750
+ badSetDict;
8751
+ wonkySetDict;
8752
+ punishSetDict;
8734
8753
  constructor(
8735
8754
  /** `goodSet`: all work-reports hashes which were judged to be correct */
8736
8755
  goodSet,
@@ -8744,6 +8763,18 @@ class DisputesRecords {
8744
8763
  this.badSet = badSet;
8745
8764
  this.wonkySet = wonkySet;
8746
8765
  this.punishSet = punishSet;
8766
+ this.goodSetDict = HashSet.from(goodSet.array);
8767
+ this.badSetDict = HashSet.from(badSet.array);
8768
+ this.wonkySetDict = HashSet.from(wonkySet.array);
8769
+ this.punishSetDict = HashSet.from(punishSet.array);
8770
+ }
8771
+ asDictionaries() {
8772
+ return {
8773
+ goodSet: this.goodSetDict,
8774
+ badSet: this.badSetDict,
8775
+ wonkySet: this.wonkySetDict,
8776
+ punishSet: this.punishSetDict,
8777
+ };
8747
8778
  }
8748
8779
  static fromSortedArrays({ goodSet, badSet, wonkySet, punishSet, }) {
8749
8780
  return new DisputesRecords(SortedSet.fromSortedArray(hashComparator, goodSet), SortedSet.fromSortedArray(hashComparator, badSet), SortedSet.fromSortedArray(hashComparator, wonkySet), SortedSet.fromSortedArray(hashComparator, punishSet));
@@ -10447,7 +10478,7 @@ class SerializedService {
10447
10478
  getStorage(rawKey) {
10448
10479
  if (Compatibility.isLessThan(GpVersion.V0_6_7)) {
10449
10480
  const SERVICE_ID_BYTES = 4;
10450
- const serviceIdAndKey = new Uint8Array(SERVICE_ID_BYTES + rawKey.length);
10481
+ const serviceIdAndKey = safeAllocUint8Array(SERVICE_ID_BYTES + rawKey.length);
10451
10482
  serviceIdAndKey.set(u32AsLeBytes(this.serviceId));
10452
10483
  serviceIdAndKey.set(rawKey.raw, SERVICE_ID_BYTES);
10453
10484
  const key = asOpaqueType(BytesBlob.blobFrom(hashBytes(serviceIdAndKey).raw));
@@ -10532,7 +10563,7 @@ class TrieNode {
10532
10563
  raw;
10533
10564
  constructor(
10534
10565
  /** Exactly 512 bits / 64 bytes */
10535
- raw = new Uint8Array(TRIE_NODE_BYTES)) {
10566
+ raw = safeAllocUint8Array(TRIE_NODE_BYTES)) {
10536
10567
  this.raw = raw;
10537
10568
  }
10538
10569
  /** Returns the type of the node */
@@ -11783,7 +11814,7 @@ function padAndEncodeData(input) {
11783
11814
  const paddedLength = Math.ceil(input.length / PIECE_SIZE) * PIECE_SIZE;
11784
11815
  let padded = input;
11785
11816
  if (input.length !== paddedLength) {
11786
- padded = BytesBlob.blobFrom(new Uint8Array(paddedLength));
11817
+ padded = BytesBlob.blobFrom(safeAllocUint8Array(paddedLength));
11787
11818
  padded.raw.set(input.raw, 0);
11788
11819
  }
11789
11820
  return chunkingFunction(padded);
@@ -11829,7 +11860,7 @@ function decodeData(input) {
11829
11860
  */
11830
11861
  function encodePoints(input) {
11831
11862
  const result = [];
11832
- const data = new Uint8Array(POINT_ALIGNMENT * N_CHUNKS_REQUIRED);
11863
+ const data = safeAllocUint8Array(POINT_ALIGNMENT * N_CHUNKS_REQUIRED);
11833
11864
  // add original shards to the result
11834
11865
  for (let i = 0; i < N_CHUNKS_REQUIRED; i++) {
11835
11866
  const pointStart = POINT_LENGTH * i;
@@ -11845,7 +11876,7 @@ function encodePoints(input) {
11845
11876
  const encodedData = encodedResult.take_data();
11846
11877
  for (let i = 0; i < N_CHUNKS_REDUNDANCY; i++) {
11847
11878
  const pointIndex = i * POINT_ALIGNMENT;
11848
- const redundancyPoint = new Uint8Array(POINT_LENGTH);
11879
+ const redundancyPoint = safeAllocUint8Array(POINT_LENGTH);
11849
11880
  for (let j = 0; j < POINT_LENGTH; j++) {
11850
11881
  redundancyPoint[j] = encodedData[pointIndex + j * HALF_POINT_SIZE];
11851
11882
  }
@@ -11860,7 +11891,7 @@ function encodePoints(input) {
11860
11891
  */
11861
11892
  function decodePiece(input) {
11862
11893
  const result = Bytes.zero(PIECE_SIZE);
11863
- const data = new Uint8Array(N_CHUNKS_REQUIRED * POINT_ALIGNMENT);
11894
+ const data = safeAllocUint8Array(N_CHUNKS_REQUIRED * POINT_ALIGNMENT);
11864
11895
  const indices = new Uint16Array(input.length);
11865
11896
  for (let i = 0; i < N_CHUNKS_REQUIRED; i++) {
11866
11897
  const [index, points] = input[i];
@@ -11976,7 +12007,7 @@ function lace(input) {
11976
12007
  return BytesBlob.empty();
11977
12008
  }
11978
12009
  const n = input[0].length;
11979
- const result = BytesBlob.blobFrom(new Uint8Array(k * n));
12010
+ const result = BytesBlob.blobFrom(safeAllocUint8Array(k * n));
11980
12011
  for (let i = 0; i < k; i++) {
11981
12012
  const entry = input[i].raw;
11982
12013
  for (let j = 0; j < n; j++) {
@@ -13255,7 +13286,7 @@ class Registers {
13255
13286
  bytes;
13256
13287
  asSigned;
13257
13288
  asUnsigned;
13258
- constructor(bytes = new Uint8Array(NO_OF_REGISTERS$1 << REGISTER_SIZE_SHIFT)) {
13289
+ constructor(bytes = safeAllocUint8Array(NO_OF_REGISTERS$1 << REGISTER_SIZE_SHIFT)) {
13259
13290
  this.bytes = bytes;
13260
13291
  check `${bytes.length === NO_OF_REGISTERS$1 << REGISTER_SIZE_SHIFT} Invalid size of registers array.`;
13261
13292
  this.asSigned = new BigInt64Array(bytes.buffer, bytes.byteOffset);
@@ -13327,10 +13358,16 @@ function signExtend32To64(value) {
13327
13358
 
13328
13359
  /** Attempt to convert a number into `HostCallIndex`. */
13329
13360
  const tryAsHostCallIndex = (v) => asOpaqueType(tryAsU32(v));
13361
+ /**
13362
+ * Host-call exit reason.
13363
+ *
13364
+ * https://graypaper.fluffylabs.dev/#/ab2cdbd/24a30124a501?v=0.7.2
13365
+ */
13330
13366
  var PvmExecution;
13331
13367
  (function (PvmExecution) {
13332
13368
  PvmExecution[PvmExecution["Halt"] = 0] = "Halt";
13333
13369
  PvmExecution[PvmExecution["Panic"] = 1] = "Panic";
13370
+ PvmExecution[PvmExecution["OOG"] = 2] = "OOG";
13334
13371
  })(PvmExecution || (PvmExecution = {}));
13335
13372
  /** A utility function to easily trace a bunch of registers. */
13336
13373
  function traceRegisters(...regs) {
@@ -13402,7 +13439,7 @@ class Mask {
13402
13439
  return Math.min(this.lookupTableForward[index] ?? 0, MAX_INSTRUCTION_DISTANCE);
13403
13440
  }
13404
13441
  buildLookupTableForward(mask) {
13405
- const table = new Uint8Array(mask.bitLength);
13442
+ const table = safeAllocUint8Array(mask.bitLength);
13406
13443
  let lastInstructionOffset = 0;
13407
13444
  for (let i = mask.bitLength - 1; i >= 0; i--) {
13408
13445
  if (mask.isSet(i)) {
@@ -16937,7 +16974,7 @@ class HostCalls {
16937
16974
  const regs = pvmInstance.getRegisters();
16938
16975
  const maybeAddress = regs.getLowerU32(7);
16939
16976
  const maybeLength = regs.getLowerU32(8);
16940
- const result = new Uint8Array(maybeLength);
16977
+ const result = safeAllocUint8Array(maybeLength);
16941
16978
  const startAddress = tryAsMemoryIndex(maybeAddress);
16942
16979
  const loadResult = memory.loadInto(result, startAddress);
16943
16980
  if (loadResult.isError) {
@@ -16965,8 +17002,9 @@ class HostCalls {
16965
17002
  const index = tryAsHostCallIndex(hostCallIndex);
16966
17003
  const hostCall = this.hostCalls.get(index);
16967
17004
  const gasBefore = gas.get();
16968
- const gasCost = typeof hostCall.gasCost === "number" ? hostCall.gasCost : hostCall.gasCost(regs);
16969
- const underflow = gas.sub(gasCost);
17005
+ // NOTE: `basicGasCost(regs)` function is for compatibility reasons: pre GP 0.7.2
17006
+ const basicGasCost = typeof hostCall.basicGasCost === "number" ? hostCall.basicGasCost : hostCall.basicGasCost(regs);
17007
+ const underflow = gas.sub(basicGasCost);
16970
17008
  const pcLog = `[PC: ${pvmInstance.getPC()}]`;
16971
17009
  if (underflow) {
16972
17010
  this.hostCalls.traceHostCall(`${pcLog} OOG`, index, hostCall, regs, gas.get());
@@ -16983,6 +17021,10 @@ class HostCalls {
16983
17021
  status = Status.PANIC;
16984
17022
  return this.getReturnValue(status, pvmInstance);
16985
17023
  }
17024
+ if (result === PvmExecution.OOG) {
17025
+ status = Status.OOG;
17026
+ return this.getReturnValue(status, pvmInstance);
17027
+ }
16986
17028
  if (result === undefined) {
16987
17029
  pvmInstance.runProgram();
16988
17030
  status = pvmInstance.getStatus();
@@ -17281,14 +17323,14 @@ class DebuggerAdapter {
17281
17323
  const page = this.pvm.getMemoryPage(pageNumber);
17282
17324
  if (page === null) {
17283
17325
  // page wasn't allocated so we return an empty page
17284
- return new Uint8Array(PAGE_SIZE$1);
17326
+ return safeAllocUint8Array(PAGE_SIZE$1);
17285
17327
  }
17286
17328
  if (page.length === PAGE_SIZE$1) {
17287
17329
  // page was allocated and has a proper size so we can simply return it
17288
17330
  return page;
17289
17331
  }
17290
17332
  // page was allocated but it is shorter than PAGE_SIZE so we have to extend it
17291
- const fullPage = new Uint8Array(PAGE_SIZE$1);
17333
+ const fullPage = safeAllocUint8Array(PAGE_SIZE$1);
17292
17334
  fullPage.set(page);
17293
17335
  return fullPage;
17294
17336
  }
@@ -17432,7 +17474,7 @@ function fisherYatesShuffle(arr, entropy) {
17432
17474
  }
17433
17475
  function hashToNumberSequence(entropy, length) {
17434
17476
  const result = new Array(length);
17435
- const randomBytes = new Uint8Array(ENTROPY_BYTES + 4);
17477
+ const randomBytes = safeAllocUint8Array(ENTROPY_BYTES + 4);
17436
17478
  randomBytes.set(entropy.raw);
17437
17479
  for (let i = 0; i < length; i++) {
17438
17480
  randomBytes.set(u32AsLeBytes(tryAsU32(Math.floor(i / 8))), ENTROPY_BYTES);
@@ -17972,7 +18014,7 @@ class Preimages {
17972
18014
 
17973
18015
  class Missing {
17974
18016
  index = tryAsHostCallIndex(2 ** 32 - 1);
17975
- gasCost = tryAsSmallGas(10);
18017
+ basicGasCost = tryAsSmallGas(10);
17976
18018
  currentServiceId = CURRENT_SERVICE_ID;
17977
18019
  tracedRegisters = traceRegisters(7);
17978
18020
  execute(_gas, regs, _memory) {
package/index.d.ts CHANGED
@@ -420,6 +420,20 @@ declare const Result$2 = {
420
420
  },
421
421
  };
422
422
 
423
+ // about 2GB, the maximum ArrayBuffer length on Chrome confirmed by several sources:
424
+ // - https://issues.chromium.org/issues/40055619
425
+ // - https://stackoverflow.com/a/72124984
426
+ // - https://onnxruntime.ai/docs/tutorials/web/large-models.html#maximum-size-of-arraybuffer
427
+ declare const MAX_LENGTH$1 = 2145386496;
428
+
429
+ declare function safeAllocUint8Array(length: number) {
430
+ if (length > MAX_LENGTH) {
431
+ // biome-ignore lint/suspicious/noConsole: can't have a dependency on logger here
432
+ console.warn(`Trying to allocate ${length} bytes, which is greater than the maximum of ${MAX_LENGTH}.`);
433
+ }
434
+ return new Uint8Array(Math.min(MAX_LENGTH, length));
435
+ }
436
+
423
437
  /**
424
438
  * Utilities for tests.
425
439
  */
@@ -755,11 +769,12 @@ declare const index$u_oomWarningPrinted: typeof oomWarningPrinted;
755
769
  declare const index$u_parseCurrentSuite: typeof parseCurrentSuite;
756
770
  declare const index$u_parseCurrentVersion: typeof parseCurrentVersion;
757
771
  declare const index$u_resultToString: typeof resultToString;
772
+ declare const index$u_safeAllocUint8Array: typeof safeAllocUint8Array;
758
773
  declare const index$u_seeThrough: typeof seeThrough;
759
774
  declare const index$u_trimStack: typeof trimStack;
760
775
  declare const index$u_workspacePathFix: typeof workspacePathFix;
761
776
  declare namespace index$u {
762
- export { index$u_ALL_VERSIONS_IN_ORDER as ALL_VERSIONS_IN_ORDER, index$u_CURRENT_SUITE as CURRENT_SUITE, index$u_CURRENT_VERSION as CURRENT_VERSION, index$u_Compatibility as Compatibility, index$u_DEFAULT_SUITE as DEFAULT_SUITE, index$u_DEFAULT_VERSION as DEFAULT_VERSION, index$u_ErrorsCollector as ErrorsCollector, index$u_GpVersion as GpVersion, Result$2 as Result, index$u_RichTaggedError as RichTaggedError, index$u_TEST_COMPARE_USING as TEST_COMPARE_USING, index$u_TestSuite as TestSuite, index$u_WithDebug as WithDebug, index$u___OPAQUE_TYPE__ as __OPAQUE_TYPE__, index$u_asOpaqueType as asOpaqueType, index$u_assertEmpty as assertEmpty, index$u_assertNever as assertNever, index$u_callCompareFunction as callCompareFunction, index$u_check as check, index$u_deepEqual as deepEqual, index$u_getAllKeysSorted as getAllKeysSorted, index$u_inspect as inspect, index$u_isBrowser as isBrowser, index$u_isResult as isResult, index$u_isTaggedError as isTaggedError, index$u_maybeTaggedErrorToString as maybeTaggedErrorToString, index$u_measure as measure, index$u_oomWarningPrinted as oomWarningPrinted, index$u_parseCurrentSuite as parseCurrentSuite, index$u_parseCurrentVersion as parseCurrentVersion, index$u_resultToString as resultToString, index$u_seeThrough as seeThrough, index$u_trimStack as trimStack, index$u_workspacePathFix as workspacePathFix };
777
+ export { index$u_ALL_VERSIONS_IN_ORDER as ALL_VERSIONS_IN_ORDER, index$u_CURRENT_SUITE as CURRENT_SUITE, index$u_CURRENT_VERSION as CURRENT_VERSION, index$u_Compatibility as Compatibility, index$u_DEFAULT_SUITE as DEFAULT_SUITE, index$u_DEFAULT_VERSION as DEFAULT_VERSION, index$u_ErrorsCollector as ErrorsCollector, index$u_GpVersion as GpVersion, MAX_LENGTH$1 as MAX_LENGTH, Result$2 as Result, index$u_RichTaggedError as RichTaggedError, index$u_TEST_COMPARE_USING as TEST_COMPARE_USING, index$u_TestSuite as TestSuite, index$u_WithDebug as WithDebug, index$u___OPAQUE_TYPE__ as __OPAQUE_TYPE__, index$u_asOpaqueType as asOpaqueType, index$u_assertEmpty as assertEmpty, index$u_assertNever as assertNever, index$u_callCompareFunction as callCompareFunction, index$u_check as check, index$u_deepEqual as deepEqual, index$u_getAllKeysSorted as getAllKeysSorted, index$u_inspect as inspect, index$u_isBrowser as isBrowser, index$u_isResult as isResult, index$u_isTaggedError as isTaggedError, index$u_maybeTaggedErrorToString as maybeTaggedErrorToString, index$u_measure as measure, index$u_oomWarningPrinted as oomWarningPrinted, index$u_parseCurrentSuite as parseCurrentSuite, index$u_parseCurrentVersion as parseCurrentVersion, index$u_resultToString as resultToString, index$u_safeAllocUint8Array as safeAllocUint8Array, index$u_seeThrough as seeThrough, index$u_trimStack as trimStack, index$u_workspacePathFix as workspacePathFix };
763
778
  export type { index$u_DeepEqualOptions as DeepEqualOptions, index$u_EnumMapping as EnumMapping, index$u_ErrorResult as ErrorResult, index$u_OK as OK, index$u_OkResult as OkResult, index$u_Opaque as Opaque, index$u_StringLiteral as StringLiteral, index$u_TaggedError as TaggedError, index$u_TokenOf as TokenOf, index$u_Uninstantiable as Uninstantiable, index$u_WithOpaque as WithOpaque };
764
779
  }
765
780
 
@@ -929,7 +944,7 @@ declare class BytesBlob {
929
944
  static blobFromParts(v: Uint8Array | Uint8Array[], ...rest: Uint8Array[]) {
930
945
  const vArr = v instanceof Uint8Array ? [v] : v;
931
946
  const totalLength = vArr.reduce((a, v) => a + v.length, 0) + rest.reduce((a, v) => a + v.length, 0);
932
- const buffer = new Uint8Array(totalLength);
947
+ const buffer = safeAllocUint8Array(totalLength);
933
948
  let offset = 0;
934
949
  for (const r of vArr) {
935
950
  buffer.set(r, offset);
@@ -1012,7 +1027,7 @@ declare class Bytes<T extends number> extends BytesBlob {
1012
1027
 
1013
1028
  /** Create an empty [`Bytes<X>`] of given length. */
1014
1029
  static zero<X extends number>(len: X): Bytes<X> {
1015
- return new Bytes(new Uint8Array(len), len);
1030
+ return new Bytes(safeAllocUint8Array(len), len);
1016
1031
  }
1017
1032
 
1018
1033
  // TODO [ToDr] `fill` should have the argments swapped to align with the rest.
@@ -1133,7 +1148,7 @@ declare class BitVec {
1133
1148
  * Create new [`BitVec`] with all values set to `false`.
1134
1149
  */
1135
1150
  static empty(bitLength: number) {
1136
- const data = new Uint8Array(Math.ceil(bitLength / 8));
1151
+ const data = safeAllocUint8Array(Math.ceil(bitLength / 8));
1137
1152
  return new BitVec(data, bitLength);
1138
1153
  }
1139
1154
 
@@ -3531,7 +3546,7 @@ declare class SimpleAllocator implements HashAllocator {
3531
3546
 
3532
3547
  /** An allocator that works by allocating larger (continuous) pages of memory. */
3533
3548
  declare class PageAllocator implements HashAllocator {
3534
- private page: Uint8Array = new Uint8Array(0);
3549
+ private page: Uint8Array = safeAllocUint8Array(0);
3535
3550
  private currentHash = 0;
3536
3551
 
3537
3552
  // TODO [ToDr] Benchmark the performance!
@@ -3543,7 +3558,7 @@ declare class PageAllocator implements HashAllocator {
3543
3558
  private resetPage() {
3544
3559
  const pageSizeBytes = this.hashesPerPage * HASH_SIZE;
3545
3560
  this.currentHash = 0;
3546
- this.page = new Uint8Array(pageSizeBytes);
3561
+ this.page = safeAllocUint8Array(pageSizeBytes);
3547
3562
  }
3548
3563
 
3549
3564
  emptyHash(): OpaqueHash {
@@ -4735,7 +4750,7 @@ declare async function verify<T extends BytesBlob>(input: Input<T>[]): Promise<b
4735
4750
  (acc, { message, key, signature }) => acc + key.length + signature.length + message.length + 1,
4736
4751
  0,
4737
4752
  );
4738
- const data = new Uint8Array(dataLength);
4753
+ const data = safeAllocUint8Array(dataLength);
4739
4754
 
4740
4755
  let offset = 0;
4741
4756
 
@@ -8373,7 +8388,7 @@ declare enum NodeType {
8373
8388
  declare class TrieNode {
8374
8389
  constructor(
8375
8390
  /** Exactly 512 bits / 64 bytes */
8376
- public readonly raw: Uint8Array = new Uint8Array(TRIE_NODE_BYTES),
8391
+ public readonly raw: Uint8Array = safeAllocUint8Array(TRIE_NODE_BYTES),
8377
8392
  ) {}
8378
8393
 
8379
8394
  /** Returns the type of the node */
@@ -9196,6 +9211,11 @@ declare class DisputesRecords {
9196
9211
  return new DisputesRecords(goodSet, badSet, wonkySet, punishSet);
9197
9212
  }
9198
9213
 
9214
+ private readonly goodSetDict: ImmutableHashSet<WorkReportHash>;
9215
+ private readonly badSetDict: ImmutableHashSet<WorkReportHash>;
9216
+ private readonly wonkySetDict: ImmutableHashSet<WorkReportHash>;
9217
+ private readonly punishSetDict: ImmutableHashSet<Ed25519Key>;
9218
+
9199
9219
  private constructor(
9200
9220
  /** `goodSet`: all work-reports hashes which were judged to be correct */
9201
9221
  public readonly goodSet: ImmutableSortedSet<WorkReportHash>,
@@ -9205,7 +9225,21 @@ declare class DisputesRecords {
9205
9225
  public readonly wonkySet: ImmutableSortedSet<WorkReportHash>,
9206
9226
  /** `punishSet`: set of Ed25519 keys representing validators which were found to have misjudged a work-report */
9207
9227
  public readonly punishSet: ImmutableSortedSet<Ed25519Key>,
9208
- ) {}
9228
+ ) {
9229
+ this.goodSetDict = HashSet.from(goodSet.array);
9230
+ this.badSetDict = HashSet.from(badSet.array);
9231
+ this.wonkySetDict = HashSet.from(wonkySet.array);
9232
+ this.punishSetDict = HashSet.from(punishSet.array);
9233
+ }
9234
+
9235
+ public asDictionaries() {
9236
+ return {
9237
+ goodSet: this.goodSetDict,
9238
+ badSet: this.badSetDict,
9239
+ wonkySet: this.wonkySetDict,
9240
+ punishSet: this.punishSetDict,
9241
+ };
9242
+ }
9209
9243
 
9210
9244
  static fromSortedArrays({
9211
9245
  goodSet,
@@ -12153,7 +12187,7 @@ declare class SerializedService implements Service {
12153
12187
  getStorage(rawKey: StorageKey): BytesBlob | null {
12154
12188
  if (Compatibility.isLessThan(GpVersion.V0_6_7)) {
12155
12189
  const SERVICE_ID_BYTES = 4;
12156
- const serviceIdAndKey = new Uint8Array(SERVICE_ID_BYTES + rawKey.length);
12190
+ const serviceIdAndKey = safeAllocUint8Array(SERVICE_ID_BYTES + rawKey.length);
12157
12191
  serviceIdAndKey.set(u32AsLeBytes(this.serviceId));
12158
12192
  serviceIdAndKey.set(rawKey.raw, SERVICE_ID_BYTES);
12159
12193
  const key: StorageKey = asOpaqueType(BytesBlob.blobFrom(blake2b.hashBytes(serviceIdAndKey).raw));
@@ -12554,7 +12588,7 @@ declare function padAndEncodeData(input: BytesBlob) {
12554
12588
  const paddedLength = Math.ceil(input.length / PIECE_SIZE) * PIECE_SIZE;
12555
12589
  let padded = input;
12556
12590
  if (input.length !== paddedLength) {
12557
- padded = BytesBlob.blobFrom(new Uint8Array(paddedLength));
12591
+ padded = BytesBlob.blobFrom(safeAllocUint8Array(paddedLength));
12558
12592
  padded.raw.set(input.raw, 0);
12559
12593
  }
12560
12594
  return chunkingFunction(padded);
@@ -12610,7 +12644,7 @@ declare function decodeData(input: FixedSizeArray<[number, BytesBlob], N_CHUNKS_
12610
12644
  */
12611
12645
  declare function encodePoints(input: Bytes<PIECE_SIZE>): FixedSizeArray<Bytes<POINT_LENGTH>, N_CHUNKS_TOTAL> {
12612
12646
  const result: Bytes<POINT_LENGTH>[] = [];
12613
- const data = new Uint8Array(POINT_ALIGNMENT * N_CHUNKS_REQUIRED);
12647
+ const data = safeAllocUint8Array(POINT_ALIGNMENT * N_CHUNKS_REQUIRED);
12614
12648
 
12615
12649
  // add original shards to the result
12616
12650
  for (let i = 0; i < N_CHUNKS_REQUIRED; i++) {
@@ -12630,7 +12664,7 @@ declare function encodePoints(input: Bytes<PIECE_SIZE>): FixedSizeArray<Bytes<PO
12630
12664
  for (let i = 0; i < N_CHUNKS_REDUNDANCY; i++) {
12631
12665
  const pointIndex = i * POINT_ALIGNMENT;
12632
12666
 
12633
- const redundancyPoint = new Uint8Array(POINT_LENGTH);
12667
+ const redundancyPoint = safeAllocUint8Array(POINT_LENGTH);
12634
12668
  for (let j = 0; j < POINT_LENGTH; j++) {
12635
12669
  redundancyPoint[j] = encodedData[pointIndex + j * HALF_POINT_SIZE];
12636
12670
  }
@@ -12650,7 +12684,7 @@ declare function decodePiece(
12650
12684
  ): Bytes<PIECE_SIZE> {
12651
12685
  const result = Bytes.zero(PIECE_SIZE);
12652
12686
 
12653
- const data = new Uint8Array(N_CHUNKS_REQUIRED * POINT_ALIGNMENT);
12687
+ const data = safeAllocUint8Array(N_CHUNKS_REQUIRED * POINT_ALIGNMENT);
12654
12688
  const indices = new Uint16Array(input.length);
12655
12689
 
12656
12690
  for (let i = 0; i < N_CHUNKS_REQUIRED; i++) {
@@ -12777,7 +12811,7 @@ declare function lace<N extends number, K extends number>(input: FixedSizeArray<
12777
12811
  return BytesBlob.empty();
12778
12812
  }
12779
12813
  const n = input[0].length;
12780
- const result = BytesBlob.blobFrom(new Uint8Array(k * n));
12814
+ const result = BytesBlob.blobFrom(safeAllocUint8Array(k * n));
12781
12815
  for (let i = 0; i < k; i++) {
12782
12816
  const entry = input[i].raw;
12783
12817
  for (let j = 0; j < n; j++) {
@@ -13675,13 +13709,12 @@ interface PartialState {
13675
13709
 
13676
13710
  /**
13677
13711
  * Transfer given `amount` of funds to the `destination`,
13678
- * passing `suppliedGas` to invoke `OnTransfer` entry point
13679
- * and given `memo`.
13712
+ * passing `gas` fee for transfer and given `memo`.
13680
13713
  */
13681
13714
  transfer(
13682
13715
  destination: ServiceId | null,
13683
13716
  amount: U64,
13684
- suppliedGas: ServiceGas,
13717
+ gas: ServiceGas,
13685
13718
  memo: Bytes<TRANSFER_MEMO_BYTES>,
13686
13719
  ): Result$2<OK, TransferError>;
13687
13720
 
@@ -13850,7 +13883,7 @@ declare class Mask {
13850
13883
  }
13851
13884
 
13852
13885
  private buildLookupTableForward(mask: BitVec) {
13853
- const table = new Uint8Array(mask.bitLength);
13886
+ const table = safeAllocUint8Array(mask.bitLength);
13854
13887
  let lastInstructionOffset = 0;
13855
13888
  for (let i = mask.bitLength - 1; i >= 0; i--) {
13856
13889
  if (mask.isSet(i)) {
@@ -13994,7 +14027,7 @@ declare class Registers {
13994
14027
  private asSigned: BigInt64Array;
13995
14028
  private asUnsigned: BigUint64Array;
13996
14029
 
13997
- constructor(private readonly bytes = new Uint8Array(NO_OF_REGISTERS << REGISTER_SIZE_SHIFT)) {
14030
+ constructor(private readonly bytes = safeAllocUint8Array(NO_OF_REGISTERS << REGISTER_SIZE_SHIFT)) {
13998
14031
  check`${bytes.length === NO_OF_REGISTERS << REGISTER_SIZE_SHIFT} Invalid size of registers array.`;
13999
14032
  this.asSigned = new BigInt64Array(bytes.buffer, bytes.byteOffset);
14000
14033
  this.asUnsigned = new BigUint64Array(bytes.buffer, bytes.byteOffset);
@@ -18052,9 +18085,15 @@ type HostCallIndex = Opaque<U32, "HostCallIndex[U32]">;
18052
18085
  /** Attempt to convert a number into `HostCallIndex`. */
18053
18086
  declare const tryAsHostCallIndex = (v: number): HostCallIndex => asOpaqueType(tryAsU32(v));
18054
18087
 
18088
+ /**
18089
+ * Host-call exit reason.
18090
+ *
18091
+ * https://graypaper.fluffylabs.dev/#/ab2cdbd/24a30124a501?v=0.7.2
18092
+ */
18055
18093
  declare enum PvmExecution {
18056
18094
  Halt = 0,
18057
18095
  Panic = 1,
18096
+ OOG = 2, // out-of-gas
18058
18097
  }
18059
18098
 
18060
18099
  /** A utility function to easily trace a bunch of registers. */
@@ -18067,8 +18106,12 @@ interface HostCallHandler {
18067
18106
  /** Index of that host call (i.e. what PVM invokes via `ecalli`) */
18068
18107
  readonly index: HostCallIndex;
18069
18108
 
18070
- /** The gas cost of invocation of that host call. */
18071
- readonly gasCost: SmallGas | ((reg: IHostCallRegisters) => Gas);
18109
+ /**
18110
+ * The gas cost of invocation of that host call.
18111
+ *
18112
+ * NOTE: `((reg: IHostCallRegisters) => Gas)` function is for compatibility reasons: pre GP 0.7.2
18113
+ */
18114
+ readonly basicGasCost: SmallGas | ((reg: IHostCallRegisters) => Gas);
18072
18115
 
18073
18116
  /** Currently executing service id. */
18074
18117
  readonly currentServiceId: U32;
@@ -18211,7 +18254,7 @@ declare class HostCalls {
18211
18254
  const maybeAddress = regs.getLowerU32(7);
18212
18255
  const maybeLength = regs.getLowerU32(8);
18213
18256
 
18214
- const result = new Uint8Array(maybeLength);
18257
+ const result = safeAllocUint8Array(maybeLength);
18215
18258
  const startAddress = tryAsMemoryIndex(maybeAddress);
18216
18259
  const loadResult = memory.loadInto(result, startAddress);
18217
18260
 
@@ -18244,8 +18287,10 @@ declare class HostCalls {
18244
18287
 
18245
18288
  const hostCall = this.hostCalls.get(index);
18246
18289
  const gasBefore = gas.get();
18247
- const gasCost = typeof hostCall.gasCost === "number" ? hostCall.gasCost : hostCall.gasCost(regs);
18248
- const underflow = gas.sub(gasCost);
18290
+ // NOTE: `basicGasCost(regs)` function is for compatibility reasons: pre GP 0.7.2
18291
+ const basicGasCost =
18292
+ typeof hostCall.basicGasCost === "number" ? hostCall.basicGasCost : hostCall.basicGasCost(regs);
18293
+ const underflow = gas.sub(basicGasCost);
18249
18294
 
18250
18295
  const pcLog = `[PC: ${pvmInstance.getPC()}]`;
18251
18296
  if (underflow) {
@@ -18272,6 +18317,11 @@ declare class HostCalls {
18272
18317
  return this.getReturnValue(status, pvmInstance);
18273
18318
  }
18274
18319
 
18320
+ if (result === PvmExecution.OOG) {
18321
+ status = Status.OOG;
18322
+ return this.getReturnValue(status, pvmInstance);
18323
+ }
18324
+
18275
18325
  if (result === undefined) {
18276
18326
  pvmInstance.runProgram();
18277
18327
  status = pvmInstance.getStatus();
@@ -18643,7 +18693,7 @@ declare class DebuggerAdapter {
18643
18693
 
18644
18694
  if (page === null) {
18645
18695
  // page wasn't allocated so we return an empty page
18646
- return new Uint8Array(PAGE_SIZE);
18696
+ return safeAllocUint8Array(PAGE_SIZE);
18647
18697
  }
18648
18698
 
18649
18699
  if (page.length === PAGE_SIZE) {
@@ -18652,7 +18702,7 @@ declare class DebuggerAdapter {
18652
18702
  }
18653
18703
 
18654
18704
  // page was allocated but it is shorter than PAGE_SIZE so we have to extend it
18655
- const fullPage = new Uint8Array(PAGE_SIZE);
18705
+ const fullPage = safeAllocUint8Array(PAGE_SIZE);
18656
18706
  fullPage.set(page);
18657
18707
  return fullPage;
18658
18708
  }
package/index.js CHANGED
@@ -329,6 +329,19 @@ const Result$1 = {
329
329
  },
330
330
  };
331
331
 
332
+ // about 2GB, the maximum ArrayBuffer length on Chrome confirmed by several sources:
333
+ // - https://issues.chromium.org/issues/40055619
334
+ // - https://stackoverflow.com/a/72124984
335
+ // - https://onnxruntime.ai/docs/tutorials/web/large-models.html#maximum-size-of-arraybuffer
336
+ const MAX_LENGTH$2 = 2145386496;
337
+ function safeAllocUint8Array(length) {
338
+ if (length > MAX_LENGTH$2) {
339
+ // biome-ignore lint/suspicious/noConsole: can't have a dependency on logger here
340
+ console.warn(`Trying to allocate ${length} bytes, which is greater than the maximum of ${MAX_LENGTH$2}.`);
341
+ }
342
+ return new Uint8Array(Math.min(MAX_LENGTH$2, length));
343
+ }
344
+
332
345
  /**
333
346
  * Utilities for tests.
334
347
  */
@@ -569,6 +582,7 @@ var index$u = /*#__PURE__*/Object.freeze({
569
582
  DEFAULT_VERSION: DEFAULT_VERSION,
570
583
  ErrorsCollector: ErrorsCollector,
571
584
  get GpVersion () { return GpVersion; },
585
+ MAX_LENGTH: MAX_LENGTH$2,
572
586
  OK: OK,
573
587
  Result: Result$1,
574
588
  TEST_COMPARE_USING: TEST_COMPARE_USING,
@@ -583,6 +597,7 @@ var index$u = /*#__PURE__*/Object.freeze({
583
597
  isBrowser: isBrowser,
584
598
  measure: measure,
585
599
  resultToString: resultToString,
600
+ safeAllocUint8Array: safeAllocUint8Array,
586
601
  seeThrough: seeThrough,
587
602
  workspacePathFix: workspacePathFix
588
603
  });
@@ -606,7 +621,7 @@ class BitVec {
606
621
  * Create new [`BitVec`] with all values set to `false`.
607
622
  */
608
623
  static empty(bitLength) {
609
- const data = new Uint8Array(Math.ceil(bitLength / 8));
624
+ const data = safeAllocUint8Array(Math.ceil(bitLength / 8));
610
625
  return new BitVec(data, bitLength);
611
626
  }
612
627
  byteLength;
@@ -807,7 +822,7 @@ class BytesBlob {
807
822
  static blobFromParts(v, ...rest) {
808
823
  const vArr = v instanceof Uint8Array ? [v] : v;
809
824
  const totalLength = vArr.reduce((a, v) => a + v.length, 0) + rest.reduce((a, v) => a + v.length, 0);
810
- const buffer = new Uint8Array(totalLength);
825
+ const buffer = safeAllocUint8Array(totalLength);
811
826
  let offset = 0;
812
827
  for (const r of vArr) {
813
828
  buffer.set(r, offset);
@@ -880,7 +895,7 @@ class Bytes extends BytesBlob {
880
895
  }
881
896
  /** Create an empty [`Bytes<X>`] of given length. */
882
897
  static zero(len) {
883
- return new Bytes(new Uint8Array(len), len);
898
+ return new Bytes(safeAllocUint8Array(len), len);
884
899
  }
885
900
  // TODO [ToDr] `fill` should have the argments swapped to align with the rest.
886
901
  /** Create a [`Bytes<X>`] with all bytes filled with given input number. */
@@ -3589,7 +3604,7 @@ async function verify(input) {
3589
3604
  return Promise.resolve([]);
3590
3605
  }
3591
3606
  const dataLength = input.reduce((acc, { message, key, signature }) => acc + key.length + signature.length + message.length + 1, 0);
3592
- const data = new Uint8Array(dataLength);
3607
+ const data = safeAllocUint8Array(dataLength);
3593
3608
  let offset = 0;
3594
3609
  for (const { key, message, signature } of input) {
3595
3610
  data.set(key.raw, offset);
@@ -3681,7 +3696,7 @@ class SimpleAllocator {
3681
3696
  /** An allocator that works by allocating larger (continuous) pages of memory. */
3682
3697
  class PageAllocator {
3683
3698
  hashesPerPage;
3684
- page = new Uint8Array(0);
3699
+ page = safeAllocUint8Array(0);
3685
3700
  currentHash = 0;
3686
3701
  // TODO [ToDr] Benchmark the performance!
3687
3702
  constructor(hashesPerPage) {
@@ -3692,7 +3707,7 @@ class PageAllocator {
3692
3707
  resetPage() {
3693
3708
  const pageSizeBytes = this.hashesPerPage * HASH_SIZE;
3694
3709
  this.currentHash = 0;
3695
- this.page = new Uint8Array(pageSizeBytes);
3710
+ this.page = safeAllocUint8Array(pageSizeBytes);
3696
3711
  }
3697
3712
  emptyHash() {
3698
3713
  const startIdx = this.currentHash * HASH_SIZE;
@@ -8728,6 +8743,10 @@ class DisputesRecords {
8728
8743
  static create({ goodSet, badSet, wonkySet, punishSet }) {
8729
8744
  return new DisputesRecords(goodSet, badSet, wonkySet, punishSet);
8730
8745
  }
8746
+ goodSetDict;
8747
+ badSetDict;
8748
+ wonkySetDict;
8749
+ punishSetDict;
8731
8750
  constructor(
8732
8751
  /** `goodSet`: all work-reports hashes which were judged to be correct */
8733
8752
  goodSet,
@@ -8741,6 +8760,18 @@ class DisputesRecords {
8741
8760
  this.badSet = badSet;
8742
8761
  this.wonkySet = wonkySet;
8743
8762
  this.punishSet = punishSet;
8763
+ this.goodSetDict = HashSet.from(goodSet.array);
8764
+ this.badSetDict = HashSet.from(badSet.array);
8765
+ this.wonkySetDict = HashSet.from(wonkySet.array);
8766
+ this.punishSetDict = HashSet.from(punishSet.array);
8767
+ }
8768
+ asDictionaries() {
8769
+ return {
8770
+ goodSet: this.goodSetDict,
8771
+ badSet: this.badSetDict,
8772
+ wonkySet: this.wonkySetDict,
8773
+ punishSet: this.punishSetDict,
8774
+ };
8744
8775
  }
8745
8776
  static fromSortedArrays({ goodSet, badSet, wonkySet, punishSet, }) {
8746
8777
  return new DisputesRecords(SortedSet.fromSortedArray(hashComparator, goodSet), SortedSet.fromSortedArray(hashComparator, badSet), SortedSet.fromSortedArray(hashComparator, wonkySet), SortedSet.fromSortedArray(hashComparator, punishSet));
@@ -10444,7 +10475,7 @@ class SerializedService {
10444
10475
  getStorage(rawKey) {
10445
10476
  if (Compatibility.isLessThan(GpVersion.V0_6_7)) {
10446
10477
  const SERVICE_ID_BYTES = 4;
10447
- const serviceIdAndKey = new Uint8Array(SERVICE_ID_BYTES + rawKey.length);
10478
+ const serviceIdAndKey = safeAllocUint8Array(SERVICE_ID_BYTES + rawKey.length);
10448
10479
  serviceIdAndKey.set(u32AsLeBytes(this.serviceId));
10449
10480
  serviceIdAndKey.set(rawKey.raw, SERVICE_ID_BYTES);
10450
10481
  const key = asOpaqueType(BytesBlob.blobFrom(hashBytes(serviceIdAndKey).raw));
@@ -10529,7 +10560,7 @@ class TrieNode {
10529
10560
  raw;
10530
10561
  constructor(
10531
10562
  /** Exactly 512 bits / 64 bytes */
10532
- raw = new Uint8Array(TRIE_NODE_BYTES)) {
10563
+ raw = safeAllocUint8Array(TRIE_NODE_BYTES)) {
10533
10564
  this.raw = raw;
10534
10565
  }
10535
10566
  /** Returns the type of the node */
@@ -11780,7 +11811,7 @@ function padAndEncodeData(input) {
11780
11811
  const paddedLength = Math.ceil(input.length / PIECE_SIZE) * PIECE_SIZE;
11781
11812
  let padded = input;
11782
11813
  if (input.length !== paddedLength) {
11783
- padded = BytesBlob.blobFrom(new Uint8Array(paddedLength));
11814
+ padded = BytesBlob.blobFrom(safeAllocUint8Array(paddedLength));
11784
11815
  padded.raw.set(input.raw, 0);
11785
11816
  }
11786
11817
  return chunkingFunction(padded);
@@ -11826,7 +11857,7 @@ function decodeData(input) {
11826
11857
  */
11827
11858
  function encodePoints(input) {
11828
11859
  const result = [];
11829
- const data = new Uint8Array(POINT_ALIGNMENT * N_CHUNKS_REQUIRED);
11860
+ const data = safeAllocUint8Array(POINT_ALIGNMENT * N_CHUNKS_REQUIRED);
11830
11861
  // add original shards to the result
11831
11862
  for (let i = 0; i < N_CHUNKS_REQUIRED; i++) {
11832
11863
  const pointStart = POINT_LENGTH * i;
@@ -11842,7 +11873,7 @@ function encodePoints(input) {
11842
11873
  const encodedData = encodedResult.take_data();
11843
11874
  for (let i = 0; i < N_CHUNKS_REDUNDANCY; i++) {
11844
11875
  const pointIndex = i * POINT_ALIGNMENT;
11845
- const redundancyPoint = new Uint8Array(POINT_LENGTH);
11876
+ const redundancyPoint = safeAllocUint8Array(POINT_LENGTH);
11846
11877
  for (let j = 0; j < POINT_LENGTH; j++) {
11847
11878
  redundancyPoint[j] = encodedData[pointIndex + j * HALF_POINT_SIZE];
11848
11879
  }
@@ -11857,7 +11888,7 @@ function encodePoints(input) {
11857
11888
  */
11858
11889
  function decodePiece(input) {
11859
11890
  const result = Bytes.zero(PIECE_SIZE);
11860
- const data = new Uint8Array(N_CHUNKS_REQUIRED * POINT_ALIGNMENT);
11891
+ const data = safeAllocUint8Array(N_CHUNKS_REQUIRED * POINT_ALIGNMENT);
11861
11892
  const indices = new Uint16Array(input.length);
11862
11893
  for (let i = 0; i < N_CHUNKS_REQUIRED; i++) {
11863
11894
  const [index, points] = input[i];
@@ -11973,7 +12004,7 @@ function lace(input) {
11973
12004
  return BytesBlob.empty();
11974
12005
  }
11975
12006
  const n = input[0].length;
11976
- const result = BytesBlob.blobFrom(new Uint8Array(k * n));
12007
+ const result = BytesBlob.blobFrom(safeAllocUint8Array(k * n));
11977
12008
  for (let i = 0; i < k; i++) {
11978
12009
  const entry = input[i].raw;
11979
12010
  for (let j = 0; j < n; j++) {
@@ -13252,7 +13283,7 @@ class Registers {
13252
13283
  bytes;
13253
13284
  asSigned;
13254
13285
  asUnsigned;
13255
- constructor(bytes = new Uint8Array(NO_OF_REGISTERS$1 << REGISTER_SIZE_SHIFT)) {
13286
+ constructor(bytes = safeAllocUint8Array(NO_OF_REGISTERS$1 << REGISTER_SIZE_SHIFT)) {
13256
13287
  this.bytes = bytes;
13257
13288
  check `${bytes.length === NO_OF_REGISTERS$1 << REGISTER_SIZE_SHIFT} Invalid size of registers array.`;
13258
13289
  this.asSigned = new BigInt64Array(bytes.buffer, bytes.byteOffset);
@@ -13324,10 +13355,16 @@ function signExtend32To64(value) {
13324
13355
 
13325
13356
  /** Attempt to convert a number into `HostCallIndex`. */
13326
13357
  const tryAsHostCallIndex = (v) => asOpaqueType(tryAsU32(v));
13358
+ /**
13359
+ * Host-call exit reason.
13360
+ *
13361
+ * https://graypaper.fluffylabs.dev/#/ab2cdbd/24a30124a501?v=0.7.2
13362
+ */
13327
13363
  var PvmExecution;
13328
13364
  (function (PvmExecution) {
13329
13365
  PvmExecution[PvmExecution["Halt"] = 0] = "Halt";
13330
13366
  PvmExecution[PvmExecution["Panic"] = 1] = "Panic";
13367
+ PvmExecution[PvmExecution["OOG"] = 2] = "OOG";
13331
13368
  })(PvmExecution || (PvmExecution = {}));
13332
13369
  /** A utility function to easily trace a bunch of registers. */
13333
13370
  function traceRegisters(...regs) {
@@ -13399,7 +13436,7 @@ class Mask {
13399
13436
  return Math.min(this.lookupTableForward[index] ?? 0, MAX_INSTRUCTION_DISTANCE);
13400
13437
  }
13401
13438
  buildLookupTableForward(mask) {
13402
- const table = new Uint8Array(mask.bitLength);
13439
+ const table = safeAllocUint8Array(mask.bitLength);
13403
13440
  let lastInstructionOffset = 0;
13404
13441
  for (let i = mask.bitLength - 1; i >= 0; i--) {
13405
13442
  if (mask.isSet(i)) {
@@ -16934,7 +16971,7 @@ class HostCalls {
16934
16971
  const regs = pvmInstance.getRegisters();
16935
16972
  const maybeAddress = regs.getLowerU32(7);
16936
16973
  const maybeLength = regs.getLowerU32(8);
16937
- const result = new Uint8Array(maybeLength);
16974
+ const result = safeAllocUint8Array(maybeLength);
16938
16975
  const startAddress = tryAsMemoryIndex(maybeAddress);
16939
16976
  const loadResult = memory.loadInto(result, startAddress);
16940
16977
  if (loadResult.isError) {
@@ -16962,8 +16999,9 @@ class HostCalls {
16962
16999
  const index = tryAsHostCallIndex(hostCallIndex);
16963
17000
  const hostCall = this.hostCalls.get(index);
16964
17001
  const gasBefore = gas.get();
16965
- const gasCost = typeof hostCall.gasCost === "number" ? hostCall.gasCost : hostCall.gasCost(regs);
16966
- const underflow = gas.sub(gasCost);
17002
+ // NOTE: `basicGasCost(regs)` function is for compatibility reasons: pre GP 0.7.2
17003
+ const basicGasCost = typeof hostCall.basicGasCost === "number" ? hostCall.basicGasCost : hostCall.basicGasCost(regs);
17004
+ const underflow = gas.sub(basicGasCost);
16967
17005
  const pcLog = `[PC: ${pvmInstance.getPC()}]`;
16968
17006
  if (underflow) {
16969
17007
  this.hostCalls.traceHostCall(`${pcLog} OOG`, index, hostCall, regs, gas.get());
@@ -16980,6 +17018,10 @@ class HostCalls {
16980
17018
  status = Status.PANIC;
16981
17019
  return this.getReturnValue(status, pvmInstance);
16982
17020
  }
17021
+ if (result === PvmExecution.OOG) {
17022
+ status = Status.OOG;
17023
+ return this.getReturnValue(status, pvmInstance);
17024
+ }
16983
17025
  if (result === undefined) {
16984
17026
  pvmInstance.runProgram();
16985
17027
  status = pvmInstance.getStatus();
@@ -17278,14 +17320,14 @@ class DebuggerAdapter {
17278
17320
  const page = this.pvm.getMemoryPage(pageNumber);
17279
17321
  if (page === null) {
17280
17322
  // page wasn't allocated so we return an empty page
17281
- return new Uint8Array(PAGE_SIZE$1);
17323
+ return safeAllocUint8Array(PAGE_SIZE$1);
17282
17324
  }
17283
17325
  if (page.length === PAGE_SIZE$1) {
17284
17326
  // page was allocated and has a proper size so we can simply return it
17285
17327
  return page;
17286
17328
  }
17287
17329
  // page was allocated but it is shorter than PAGE_SIZE so we have to extend it
17288
- const fullPage = new Uint8Array(PAGE_SIZE$1);
17330
+ const fullPage = safeAllocUint8Array(PAGE_SIZE$1);
17289
17331
  fullPage.set(page);
17290
17332
  return fullPage;
17291
17333
  }
@@ -17429,7 +17471,7 @@ function fisherYatesShuffle(arr, entropy) {
17429
17471
  }
17430
17472
  function hashToNumberSequence(entropy, length) {
17431
17473
  const result = new Array(length);
17432
- const randomBytes = new Uint8Array(ENTROPY_BYTES + 4);
17474
+ const randomBytes = safeAllocUint8Array(ENTROPY_BYTES + 4);
17433
17475
  randomBytes.set(entropy.raw);
17434
17476
  for (let i = 0; i < length; i++) {
17435
17477
  randomBytes.set(u32AsLeBytes(tryAsU32(Math.floor(i / 8))), ENTROPY_BYTES);
@@ -17969,7 +18011,7 @@ class Preimages {
17969
18011
 
17970
18012
  class Missing {
17971
18013
  index = tryAsHostCallIndex(2 ** 32 - 1);
17972
- gasCost = tryAsSmallGas(10);
18014
+ basicGasCost = tryAsSmallGas(10);
17973
18015
  currentServiceId = CURRENT_SERVICE_ID;
17974
18016
  tracedRegisters = traceRegisters(7);
17975
18017
  execute(_gas, regs, _memory) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typeberry/lib",
3
- "version": "0.1.3-707962d",
3
+ "version": "0.1.3-d3752d8",
4
4
  "main": "index.js",
5
5
  "author": "Fluffy Labs",
6
6
  "license": "MPL-2.0",