@btc-vision/btc-runtime 1.4.6 → 1.5.0

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 (59) hide show
  1. package/package.json +44 -53
  2. package/runtime/abort/abort.ts +25 -0
  3. package/runtime/buffer/BytesReader.ts +171 -140
  4. package/runtime/buffer/BytesWriter.ts +120 -152
  5. package/runtime/contracts/DeployableOP_20.ts +29 -15
  6. package/runtime/contracts/OP_NET.ts +1 -1
  7. package/runtime/env/BlockchainEnvironment.ts +79 -137
  8. package/runtime/env/classes/Block.ts +4 -8
  9. package/runtime/env/classes/Transaction.ts +14 -7
  10. package/runtime/env/classes/UTXO.ts +4 -2
  11. package/runtime/env/global.ts +49 -20
  12. package/runtime/events/predefined/MintEvent.ts +1 -1
  13. package/runtime/exports/index.ts +29 -8
  14. package/runtime/generic/AddressMap.ts +7 -5
  15. package/runtime/generic/Map.ts +32 -2
  16. package/runtime/generic/MapU256.ts +7 -5
  17. package/runtime/generic/MapUint8Array.ts +93 -0
  18. package/runtime/index.ts +4 -12
  19. package/runtime/math/abi.ts +71 -11
  20. package/runtime/math/bytes.ts +177 -41
  21. package/runtime/memory/AddressMemoryMap.ts +22 -19
  22. package/runtime/memory/FastUint8Array.ts +122 -0
  23. package/runtime/memory/KeyMerger.ts +25 -23
  24. package/runtime/memory/MultiAddressMemoryMap.ts +11 -8
  25. package/runtime/memory/MultiStringMemoryMap.ts +8 -5
  26. package/runtime/memory/StringMemoryMap.ts +15 -15
  27. package/runtime/memory/Uint8ArrayMerger.ts +22 -15
  28. package/runtime/storage/Serializable.ts +19 -20
  29. package/runtime/storage/StoredAddress.ts +16 -15
  30. package/runtime/storage/StoredBoolean.ts +26 -21
  31. package/runtime/storage/StoredString.ts +158 -102
  32. package/runtime/storage/StoredU256.ts +25 -28
  33. package/runtime/storage/StoredU64.ts +23 -35
  34. package/runtime/storage/arrays/StoredAddressArray.ts +88 -179
  35. package/runtime/storage/arrays/StoredBooleanArray.ts +150 -272
  36. package/runtime/storage/arrays/StoredPackedArray.ts +313 -0
  37. package/runtime/storage/arrays/StoredU128Array.ts +38 -373
  38. package/runtime/storage/arrays/StoredU16Array.ts +34 -418
  39. package/runtime/storage/arrays/StoredU256Array.ts +21 -346
  40. package/runtime/storage/arrays/StoredU32Array.ts +37 -438
  41. package/runtime/storage/arrays/StoredU64Array.ts +66 -0
  42. package/runtime/storage/arrays/StoredU8Array.ts +29 -451
  43. package/runtime/types/Address.ts +72 -5
  44. package/runtime/types/index.ts +1 -4
  45. package/runtime/utils/encodings.ts +5 -6
  46. package/runtime/utils/hex.ts +1 -1
  47. package/runtime/interfaces/DeployContractResponse.ts +0 -12
  48. package/runtime/math/cyrb53.ts +0 -48
  49. package/runtime/math/sha256.ts +0 -12
  50. package/runtime/memory/MemorySlot.ts +0 -1
  51. package/runtime/memory/MemorySlotPointer.ts +0 -3
  52. package/runtime/storage/utils/StorageBacked.ts +0 -5
  53. package/runtime/storage/utils/StorageLayout.ts +0 -7
  54. package/runtime/storage/utils/StorageSlot.ts +0 -106
  55. package/runtime/storage/utils/StorageStruct.ts +0 -23
  56. package/runtime/storage/utils/StorageValue.ts +0 -36
  57. package/runtime/tests/assert.ts +0 -11
  58. package/runtime/tests/env.ts +0 -7
  59. package/runtime/tests/tests.ts +0 -28
@@ -1,364 +1,39 @@
1
+ import { StoredPackedArray } from './StoredPackedArray';
1
2
  import { u256 } from '@btc-vision/as-bignum/assembly';
2
- import { Blockchain } from '../../env';
3
- import { BytesWriter } from '../../buffer/BytesWriter';
4
- import { SafeMath } from '../../types/SafeMath';
5
- import { Revert } from '../../types/Revert';
3
+ import { bigEndianAdd } from '../../math/bytes';
6
4
 
7
5
  /**
8
- * @class StoredU256Array
9
- * @description Manages an array of u256 values across multiple storage slots. Each slot holds one u256 value.
6
+ * StoredU256Array
7
+ * - 1 item of type `u256` fits in one 32-byte slot.
10
8
  */
11
9
  @final
12
- export class StoredU256Array {
13
- private readonly baseU256Pointer: u256;
14
- private readonly lengthPointer: u256;
15
-
16
- // Internal cache for storage slots
17
- private _values: Map<u64, u256> = new Map(); // Map from slotIndex to u256 value
18
- private _isLoaded: Set<u64> = new Set(); // Set of slotIndexes that are loaded
19
- private _isChanged: Set<u64> = new Set(); // Set of slotIndexes that are modified
20
-
21
- // Internal variables for length and startIndex management
22
- private _length: u64 = 0; // Current length of the array
23
- private _startIndex: u64 = 0; // Starting index of the array
24
- private _isChangedLength: bool = false; // Indicates if the length has been modified
25
- private _isChangedStartIndex: bool = false; // Indicates if the startIndex has been modified
26
-
27
- // Define a maximum allowed length to prevent excessive storage usage
28
- private readonly MAX_LENGTH: u64 = u64(u32.MAX_VALUE - 1);
29
-
30
- /**
31
- * @constructor
32
- * @param {u16} pointer - The primary pointer identifier.
33
- * @param {Uint8Array} subPointer - The sub-pointer for memory slot addressing.
34
- * @param {u256} defaultValue - The default u256 value if storage is uninitialized.
35
- */
36
- constructor(
37
- public pointer: u16,
38
- public subPointer: Uint8Array,
39
- private defaultValue: u256,
40
- ) {
41
- // Initialize the base u256 pointer using the primary pointer and subPointer
42
- const writer = new BytesWriter(32);
43
- writer.writeU16(pointer);
44
- writer.writeBytes(subPointer);
45
-
46
- // Initialize the base and length pointers
47
- const baseU256Pointer = u256.fromBytes(writer.getBuffer(), true);
48
- const lengthPointer = baseU256Pointer.clone();
49
-
50
- // Load the current length and startIndex from storage
51
- const storedLengthAndStartIndex: u256 = Blockchain.getStorageAt(lengthPointer, u256.Zero);
52
- this.lengthPointer = lengthPointer;
53
- this.baseU256Pointer = baseU256Pointer;
54
-
55
- this._length = storedLengthAndStartIndex.lo1; // Bytes 0-7: length
56
- this._startIndex = storedLengthAndStartIndex.lo2; // Bytes 8-15: startIndex
57
- }
58
-
59
- /**
60
- * @method get
61
- * @description Retrieves the u256 value at the specified global index.
62
- * Returns zero instead of reverting if the index is out of bounds.
63
- * @param {u64} index - The global index (0 to ∞) of the u256 value to retrieve.
64
- * @returns {u256} - The u256 value at the specified index or zero if out of bounds.
65
- */
66
- @inline
67
- public get(index: u64): u256 {
68
- if (index >= this._length) {
69
- return u256.Zero;
70
- }
71
-
72
- const slotIndex: u32 = <u32>index;
73
- this.ensureValues(slotIndex);
74
- const value = this._values.get(slotIndex);
75
- return value ? value : u256.Zero;
76
- }
77
-
78
- /**
79
- * @method set
80
- * @description Sets the u256 value at the specified global index.
81
- * @param {u64} index - The global index (0 to ∞) of the u256 value to set.
82
- * @param {u256} value - The u256 value to assign.
83
- */
84
- @inline
85
- public set(index: u64, value: u256): void {
86
- if (index > this.MAX_LENGTH) {
87
- throw new Revert('Set operation failed: Index exceeds maximum allowed value.');
88
- }
89
-
90
- const slotIndex: u32 = <u32>index;
91
- this.ensureValues(slotIndex);
92
-
93
- const currentValue = this._values.get(slotIndex);
94
- if (!u256.eq(currentValue, value)) {
95
- this._values.set(slotIndex, value);
96
- this._isChanged.add(slotIndex);
97
- }
98
- }
99
-
100
- /**
101
- * @method push
102
- * @description Appends a new u256 value to the end of the array.
103
- * @param {u256} value - The u256 value to append.
104
- */
105
- public push(value: u256): void {
106
- if (this._length > this.MAX_LENGTH) {
107
- throw new Revert(
108
- 'Push operation failed: Array has reached its maximum allowed length.',
109
- );
110
- }
111
-
112
- const newIndex: u64 = this._length;
113
- const wrappedIndex: u64 =
114
- newIndex < this.MAX_LENGTH ? newIndex : newIndex % this.MAX_LENGTH;
115
- const slotIndex: u32 = <u32>wrappedIndex;
116
-
117
- // Ensure the slot is loaded
118
- this.ensureValues(slotIndex);
119
-
120
- // Set the new value
121
- this._values.set(slotIndex, value);
122
- this._isChanged.add(slotIndex);
123
-
124
- // Increment the length
125
- this._length += 1;
126
- this._isChangedLength = true;
10
+ export class StoredU256Array extends StoredPackedArray<u256> {
11
+ public constructor(pointer: u16, subPointer: Uint8Array) {
12
+ super(pointer, subPointer);
127
13
  }
128
14
 
129
- public deleteLast(): void {
130
- if (this._length === 0) {
131
- throw new Revert('Delete operation failed: Array is empty.');
132
- }
133
-
134
- const lastIndex: u64 = this._length - 1;
135
- const slotIndex: u32 = <u32>(this._startIndex + lastIndex);
136
- this.ensureValues(slotIndex);
137
-
138
- const currentValue = this._values.get(slotIndex);
139
- if (!u256.eq(currentValue, u256.Zero)) {
140
- this._values.set(slotIndex, u256.Zero);
141
- this._isChanged.add(slotIndex);
142
- }
143
-
144
- // Decrement the length
145
- this._length -= 1;
146
- this._isChangedLength = true;
15
+ protected getSlotCapacity(): u64 {
16
+ return 1; // 1 x u256 => 32 bytes
147
17
  }
148
18
 
149
- public setStartingIndex(index: u64): void {
150
- this._startIndex = index;
151
- this._isChangedStartIndex = true;
152
- }
153
-
154
- /**
155
- * @method delete
156
- * @description Deletes the u256 value at the specified index by setting it to zero. Does not reorder the array.
157
- * @param {u64} index - The global index of the u256 value to delete.
158
- */
159
- public delete(index: u64): void {
160
- if (index >= this._length) {
161
- throw new Revert('Delete operation failed: Index out of bounds.');
162
- }
163
-
164
- const slotIndex: u32 = <u32>index;
165
- this.ensureValues(slotIndex);
166
-
167
- const currentValue = this._values.get(slotIndex);
168
- if (!u256.eq(currentValue, u256.Zero)) {
169
- this._values.set(slotIndex, u256.Zero);
170
- this._isChanged.add(slotIndex);
171
- }
172
- }
173
-
174
- /**
175
- * @method save
176
- * @description Persists all cached u256 values, the length, and the startIndex to their respective storage slots
177
- * if any have been modified.
178
- */
179
- public save(): void {
180
- // Save all changed slots
181
- const changed = this._isChanged.values();
182
- for (let i = 0; i < changed.length; i++) {
183
- const slotIndex = changed[i];
184
- const storagePointer = this.calculateStoragePointer(slotIndex);
185
- const value = this._values.get(slotIndex);
186
- Blockchain.setStorageAt(storagePointer, value);
187
- }
188
-
189
- this._isChanged.clear();
190
-
191
- // Save length and startIndex if changed
192
- if (this._isChangedLength || this._isChangedStartIndex) {
193
- const packedLengthAndStartIndex = new u256();
194
- packedLengthAndStartIndex.lo1 = this._length;
195
- packedLengthAndStartIndex.lo2 = this._startIndex;
196
- Blockchain.setStorageAt(this.lengthPointer, packedLengthAndStartIndex);
197
- this._isChangedLength = false;
198
- this._isChangedStartIndex = false;
199
- }
200
- }
201
-
202
- /**
203
- * @method deleteAll
204
- * @description Deletes all storage slots by setting them to zero, including the length and startIndex slots.
205
- */
206
- public deleteAll(): void {
207
- // Iterate over all loaded slots and clear them
208
- const keys = this._values.keys();
209
- for (let i = 0; i < keys.length; i++) {
210
- const slotIndex = keys[i];
211
- const storagePointer = this.calculateStoragePointer(slotIndex);
212
- Blockchain.setStorageAt(storagePointer, u256.Zero);
213
- }
214
-
215
- // Reset the length and startIndex to zero
216
- const zeroLengthAndStartIndex = u256.Zero;
217
- Blockchain.setStorageAt(this.lengthPointer, zeroLengthAndStartIndex);
218
-
219
- this._length = 0;
220
- this._startIndex = 0;
221
- this._isChangedLength = false;
222
- this._isChangedStartIndex = false;
223
-
224
- // Clear internal caches
225
- this._values.clear();
226
- this._isLoaded.clear();
227
- this._isChanged.clear();
228
- }
229
-
230
- /**
231
- * @method setMultiple
232
- * @description Sets multiple u256 values starting from a specific global index.
233
- * @param {u32} startIndex - The starting global index.
234
- * @param {u256[]} values - An array of u256 values to set.
235
- */
236
- @inline
237
- public setMultiple(startIndex: u32, values: u256[]): void {
238
- for (let i: u32 = 0; i < values.length; i++) {
239
- this.set(<u64>(startIndex + i), values[i]);
240
- }
241
- }
242
-
243
- /**
244
- * @method getAll
245
- * @description Retrieves a range of u256 values starting from a specific global index.
246
- * @param {u32} startIndex - The starting global index.
247
- * @param {u32} count - The number of u256 values to retrieve.
248
- * @returns {u256[]} - An array containing the retrieved u256 values.
249
- */
250
- @inline
251
- public getAll(startIndex: u32, count: u32): u256[] {
252
- if ((startIndex + count) > this._length) {
253
- throw new Revert('Requested range exceeds array length');
254
- }
255
- const result: u256[] = new Array<u256>(count);
256
- for (let i: u32 = 0; i < count; i++) {
257
- result[i] = this.get(<u64>(startIndex + i));
258
- }
259
- return result;
260
- }
261
-
262
- /**
263
- * @method toString
264
- * @description Returns a string representation of all cached u256 values.
265
- * @returns {string} - A string in the format "[value0, value1, ..., valueN]".
266
- */
267
- @inline
268
- public toString(): string {
269
- let str = '[';
270
- for (let i: u32 = 0; i < this._length; i++) {
271
- const value = this.get(<u64>i);
272
- str += value.toString();
273
- if (i !== this._length - 1) {
274
- str += ', ';
275
- }
276
- }
277
- str += ']';
278
- return str;
279
- }
280
-
281
- /**
282
- * @method toBytes
283
- * @description Returns the packed u256 values as a byte array.
284
- * @returns {u8[]} - The packed u256 values in byte form.
285
- */
286
- @inline
287
- public toBytes(): u8[] {
288
- const bytes: u8[] = new Array<u8>();
289
- for (let i: u32 = 0; i < this._length; i++) {
290
- this.ensureValues(i);
291
- const value = this._values.get(i);
292
- if (value) {
293
- const valueBytes = value.toBytes();
294
- for (let j: u32 = 0; j < valueBytes.length; j++) {
295
- bytes.push(valueBytes[j]);
296
- }
297
- }
298
- }
299
- return bytes;
300
- }
301
-
302
- /**
303
- * @method reset
304
- * @description Resets all cached u256 values to zero and marks them as changed, including resetting the length and startIndex.
305
- */
306
- @inline
307
- public reset(): void {
308
- // Reset the length and startIndex to zero
309
- this._length = 0;
310
- this._startIndex = 0;
311
- this._isChangedLength = true;
312
- this._isChangedStartIndex = true;
313
-
314
- this.save();
19
+ protected zeroValue(): u256 {
20
+ return u256.Zero;
315
21
  }
316
22
 
317
- /**
318
- * @method getLength
319
- * @description Retrieves the current length of the array.
320
- * @returns {u64} - The current length.
321
- */
322
- @inline
323
- public getLength(): u64 {
324
- return this._length;
23
+ protected eq(a: u256, b: u256): bool {
24
+ return a == b;
325
25
  }
326
26
 
327
- /**
328
- * @method startingIndex
329
- * @description Retrieves the current starting index of the array.
330
- * @returns {u64} - The starting index.
331
- */
332
- public startingIndex(): u64 {
333
- return this._startIndex;
27
+ protected packSlot(values: u256[]): Uint8Array {
28
+ return values[0].toUint8Array(true);
334
29
  }
335
30
 
336
- /**
337
- * @private
338
- * @method ensureValues
339
- * @description Loads and caches the u256 value from the specified storage slot.
340
- * @param {u32} slotIndex - The index of the storage slot.
341
- */
342
- private ensureValues(slotIndex: u32): void {
343
- if (!this._isLoaded.has(slotIndex)) {
344
- const storagePointer = this.calculateStoragePointer(slotIndex);
345
- const storedU256: u256 = Blockchain.getStorageAt(storagePointer, this.defaultValue);
346
- this._values.set(slotIndex, storedU256);
347
- this._isLoaded.add(slotIndex);
348
- }
31
+ protected unpackSlot(slotData: Uint8Array): u256[] {
32
+ const val = u256.fromBytes(slotData, true);
33
+ return [val];
349
34
  }
350
35
 
351
- /**
352
- * @private
353
- * @method calculateStoragePointer
354
- * @description Calculates the storage pointer for a given slot index by incrementing the base pointer.
355
- * @param {u32} slotIndex - The index of the storage slot.
356
- * @returns {u256} - The calculated storage pointer.
357
- */
358
- private calculateStoragePointer(slotIndex: u64): u256 {
359
- // Each slot is identified by baseU256Pointer + slotIndex + 1
360
- // Slot 0: baseU256Pointer + 1 (first element)
361
- // Slot 1: baseU256Pointer + 2, etc.
362
- return SafeMath.add(this.baseU256Pointer, u256.fromU64(slotIndex + 1));
36
+ protected calculateStoragePointer(slotIndex: u64): Uint8Array {
37
+ return bigEndianAdd(this.basePointer, slotIndex + 1);
363
38
  }
364
- }
39
+ }