@btc-vision/btc-runtime 1.3.15 → 1.3.16

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@btc-vision/btc-runtime",
3
- "version": "1.3.15",
3
+ "version": "1.3.16",
4
4
  "description": "Bitcoin Smart Contract Runtime",
5
5
  "main": "btc/index.ts",
6
6
  "scripts": {
@@ -10,13 +10,11 @@ import { OP_NET } from '../contracts/OP_NET';
10
10
  import { PointerStorage } from '../types';
11
11
  import {
12
12
  callContract,
13
- deploy,
14
13
  deployFromAddress,
15
14
  emit,
16
15
  encodeAddress,
17
16
  loadPointer,
18
17
  log,
19
- nextPointerGreaterThan,
20
18
  storePointer,
21
19
  validateBitcoinAddress,
22
20
  verifySchnorrSignature,
@@ -186,7 +184,7 @@ export class BlockchainEnvironment {
186
184
  return reader.readAddress();
187
185
  }
188
186
 
189
- public deployContract(hash: u256, bytecode: Uint8Array): DeployContractResponse {
187
+ /*public deployContract(hash: u256, bytecode: Uint8Array): DeployContractResponse {
190
188
  const writer = new BytesWriter(32 + bytecode.length);
191
189
  writer.writeU256(hash);
192
190
  writer.writeBytes(bytecode);
@@ -199,7 +197,7 @@ export class BlockchainEnvironment {
199
197
  const contractAddress: Address = reader.readAddress();
200
198
 
201
199
  return new DeployContractResponse(virtualAddress, contractAddress);
202
- }
200
+ }*/
203
201
 
204
202
  public deployContractFromExisting(
205
203
  existingAddress: Address,
@@ -220,6 +218,7 @@ export class BlockchainEnvironment {
220
218
  return new DeployContractResponse(virtualAddress, contractAddress);
221
219
  }
222
220
 
221
+ // TODO: Change MemorySlotData type to a Uint8Array instead of a u256.
223
222
  public getStorageAt(
224
223
  pointerHash: MemorySlotPointer,
225
224
  defaultValue: MemorySlotData<u256>,
@@ -233,7 +232,7 @@ export class BlockchainEnvironment {
233
232
  return defaultValue;
234
233
  }
235
234
 
236
- public getNextPointerGreaterThan(
235
+ /*public getNextPointerGreaterThan(
237
236
  targetPointer: MemorySlotPointer,
238
237
  valueAtLeast: u256,
239
238
  lte: boolean = true,
@@ -247,7 +246,7 @@ export class BlockchainEnvironment {
247
246
  const reader: BytesReader = new BytesReader(result);
248
247
 
249
248
  return reader.readU256();
250
- }
249
+ }*/
251
250
 
252
251
  public verifySchnorrSignature(
253
252
  publicKey: Address,
@@ -265,6 +264,7 @@ export class BlockchainEnvironment {
265
264
  return reader.readBoolean();
266
265
  }
267
266
 
267
+ // TODO: Change MemorySlotData type to a Uint8Array instead of a u256.
268
268
  public hasStorageAt(pointerHash: MemorySlotPointer): bool {
269
269
  // We mark zero as the default value for the storage, if something is 0, the storage slot get deleted or is non-existent
270
270
  const val: u256 = this.getStorageAt(pointerHash, u256.Zero);
package/runtime/index.ts CHANGED
@@ -70,6 +70,7 @@ export * from './storage/StoredString';
70
70
  export * from './storage/StoredAddress';
71
71
  export * from './storage/StoredBoolean';
72
72
  export * from './storage/Serializable';
73
+ export * from './storage/StoredAddressArray';
73
74
 
74
75
  export * from './storage/StorageBacked';
75
76
  export * from './storage/StorageSlot';
@@ -7,7 +7,8 @@ import { Revert } from '../types/Revert';
7
7
 
8
8
  /**
9
9
  * @class StoredAddressArray
10
- * @description Manages an array of u256 values across multiple storage slots. Each slot holds one u256 value.
10
+ * @description Manages an array of Address values across multiple storage slots.
11
+ * Each slot holds one Address (stored as u256 in storage).
11
12
  */
12
13
  @final
13
14
  export class StoredAddressArray {
@@ -15,7 +16,7 @@ export class StoredAddressArray {
15
16
  private readonly lengthPointer: u256;
16
17
 
17
18
  // Internal cache for storage slots
18
- private _values: Map<u64, Address> = new Map(); // Map from slotIndex to u256 value
19
+ private _values: Map<u64, Address> = new Map(); // Map from slotIndex to Address value
19
20
  private _isLoaded: Set<u64> = new Set(); // Set of slotIndexes that are loaded
20
21
  private _isChanged: Set<u64> = new Set(); // Set of slotIndexes that are modified
21
22
 
@@ -26,25 +27,24 @@ export class StoredAddressArray {
26
27
  private _isChangedStartIndex: bool = false; // Indicates if the startIndex has been modified
27
28
 
28
29
  // Define a maximum allowed length to prevent excessive storage usage
29
- private readonly MAX_LENGTH: u64 = u64(u32.MAX_VALUE - 1); // we need to check what happen in overflow situation to be able to set it to u64.MAX_VALUE
30
+ private readonly MAX_LENGTH: u64 = u64(u32.MAX_VALUE - 1);
30
31
 
31
32
  /**
32
33
  * @constructor
33
34
  * @param {u16} pointer - The primary pointer identifier.
34
35
  * @param {Uint8Array} subPointer - The sub-pointer for memory slot addressing.
35
- * @param {u256} defaultValue - The default u256 value if storage is uninitialized.
36
+ * @param {Address} defaultValue - The default Address value if storage is uninitialized.
36
37
  */
37
38
  constructor(
38
39
  public pointer: u16,
39
40
  public subPointer: Uint8Array,
40
41
  private defaultValue: Address,
41
42
  ) {
42
- // Initialize the base u256 pointer using the primary pointer and subPointer
43
+ // Initialize the base pointer
43
44
  const writer = new BytesWriter(32);
44
45
  writer.writeU16(pointer);
45
46
  writer.writeBytes(subPointer);
46
47
 
47
- // Initialize the base and length pointers
48
48
  const baseU256Pointer = u256.fromBytes(writer.getBuffer(), true);
49
49
  const lengthPointer = baseU256Pointer.clone();
50
50
 
@@ -60,7 +60,7 @@ export class StoredAddressArray {
60
60
  /**
61
61
  * @method get
62
62
  * @description Retrieves the Address value at the specified global index.
63
- * @param {u64} index - The global index (0 to ∞) of the Address value to retrieve.
63
+ * @param {u64} index - The global index of the Address to retrieve.
64
64
  * @returns {Address} - The Address value at the specified index.
65
65
  */
66
66
  @inline
@@ -75,7 +75,7 @@ export class StoredAddressArray {
75
75
  /**
76
76
  * @method set
77
77
  * @description Sets the Address value at the specified global index.
78
- * @param {u64} index - The global index (0 to ∞) of the Address value to set.
78
+ * @param {u64} index - The global index of the Address to set.
79
79
  * @param {Address} value - The Address value to assign.
80
80
  */
81
81
  @inline
@@ -91,10 +91,38 @@ export class StoredAddressArray {
91
91
  }
92
92
  }
93
93
 
94
+ /**
95
+ * @method indexOf
96
+ * @description Searches for the first occurrence of the specified Address value and returns its index.
97
+ * @param {Address} value - The Address to locate.
98
+ * @returns {i64} - The index of the first occurrence, or -1 if not found.
99
+ */
100
+ @inline
101
+ public indexOf(value: Address): i64 {
102
+ for (let i: u64 = 0; i < this._length; i++) {
103
+ const currentValue = this.get(i);
104
+ if (currentValue == value) {
105
+ return i64(i);
106
+ }
107
+ }
108
+ return -1;
109
+ }
110
+
111
+ /**
112
+ * @method contains
113
+ * @description Determines whether the array contains the specified Address value.
114
+ * @param {Address} value - The Address to locate.
115
+ * @returns {boolean} - True if found; otherwise, false.
116
+ */
117
+ @inline
118
+ public contains(value: Address): boolean {
119
+ return this.indexOf(value) !== -1;
120
+ }
121
+
94
122
  /**
95
123
  * @method push
96
- * @description Appends a new u256 value to the end of the array.
97
- * @param {u256} value - The u256 value to append.
124
+ * @description Appends a new Address value to the end of the array.
125
+ * @param {Address} value - The Address to append.
98
126
  */
99
127
  public push(value: Address): void {
100
128
  if (this._length >= this.MAX_LENGTH) {
@@ -104,23 +132,22 @@ export class StoredAddressArray {
104
132
  }
105
133
 
106
134
  const newIndex: u64 = this._length;
107
- const effectiveIndex: u64 = this._startIndex + newIndex;
108
135
  const wrappedIndex: u64 =
109
- effectiveIndex < this.MAX_LENGTH ? effectiveIndex : effectiveIndex % this.MAX_LENGTH;
136
+ newIndex < this.MAX_LENGTH ? newIndex : newIndex % this.MAX_LENGTH;
110
137
  const slotIndex: u32 = <u32>wrappedIndex;
111
138
 
112
- // Ensure the slot is loaded
113
139
  this.ensureValues(slotIndex);
114
-
115
- // Set the new value
116
140
  this._values.set(slotIndex, value);
117
141
  this._isChanged.add(slotIndex);
118
142
 
119
- // Increment the length
120
143
  this._length += 1;
121
144
  this._isChangedLength = true;
122
145
  }
123
146
 
147
+ /**
148
+ * @method deleteLast
149
+ * @description Deletes the last element from the array.
150
+ */
124
151
  public deleteLast(): void {
125
152
  if (this._length === 0) {
126
153
  throw new Revert('Delete operation failed: Array is empty.');
@@ -136,11 +163,15 @@ export class StoredAddressArray {
136
163
  this._isChanged.add(slotIndex);
137
164
  }
138
165
 
139
- // Decrement the length
140
166
  this._length -= 1;
141
167
  this._isChangedLength = true;
142
168
  }
143
169
 
170
+ /**
171
+ * @method setStartingIndex
172
+ * @description Sets the starting index of the array.
173
+ * @param {u64} index - The new starting index.
174
+ */
144
175
  public setStartingIndex(index: u64): void {
145
176
  this._startIndex = index;
146
177
  this._isChangedStartIndex = true;
@@ -148,8 +179,8 @@ export class StoredAddressArray {
148
179
 
149
180
  /**
150
181
  * @method delete
151
- * @description Deletes the Address value at the specified index by setting it to zero. Does not reorder the array.
152
- * @param {u64} index - The global index of the u256 value to delete.
182
+ * @description Deletes the Address value at the specified index by setting it to defaultValue.
183
+ * @param {u64} index - The global index of the Address value to delete.
153
184
  */
154
185
  public delete(index: u64): void {
155
186
  if (index >= this._length) {
@@ -168,8 +199,7 @@ export class StoredAddressArray {
168
199
 
169
200
  /**
170
201
  * @method shift
171
- * @description Removes the first element of the array by setting it to this.defaultValue, decrementing the length, and incrementing the startIndex.
172
- * If the startIndex reaches the maximum value of u64, it wraps around to 0.
202
+ * @description Removes the first element of the array.
173
203
  */
174
204
  public shift(): void {
175
205
  if (this._length === 0) {
@@ -186,7 +216,6 @@ export class StoredAddressArray {
186
216
  this._isChanged.add(slotIndex);
187
217
  }
188
218
 
189
- // Decrement the length
190
219
  this._length -= 1;
191
220
  this._isChangedLength = true;
192
221
 
@@ -201,7 +230,7 @@ export class StoredAddressArray {
201
230
 
202
231
  /**
203
232
  * @method save
204
- * @description Persists all cached u256 values, the length, and the startIndex to their respective storage slots if any have been modified.
233
+ * @description Persists all changes to storage.
205
234
  */
206
235
  public save(): void {
207
236
  // Save all changed slots
@@ -227,10 +256,10 @@ export class StoredAddressArray {
227
256
 
228
257
  /**
229
258
  * @method deleteAll
230
- * @description Deletes all storage slots by setting them to this.defaultValue, including the length and startIndex slots.
259
+ * @description Deletes the entire array and resets length and startIndex.
231
260
  */
232
261
  public deleteAll(): void {
233
- // Iterate over all loaded slots and clear them
262
+ // Clear all loaded slots
234
263
  const keys = this._values.keys();
235
264
  for (let i = 0; i < keys.length; i++) {
236
265
  const slotIndex = keys[i];
@@ -238,7 +267,7 @@ export class StoredAddressArray {
238
267
  Blockchain.setStorageAt(storagePointer, u256.fromBytes(this.defaultValue));
239
268
  }
240
269
 
241
- // Reset the length and startIndex to zero
270
+ // Reset the length and startIndex
242
271
  const zeroLengthAndStartIndex = u256.Zero;
243
272
  Blockchain.setStorageAt(this.lengthPointer, zeroLengthAndStartIndex);
244
273
  this._length = 0;
@@ -254,9 +283,9 @@ export class StoredAddressArray {
254
283
 
255
284
  /**
256
285
  * @method setMultiple
257
- * @description Sets multiple u256 values starting from a specific global index.
286
+ * @description Sets multiple Address values starting from a specific global index.
258
287
  * @param {u32} startIndex - The starting global index.
259
- * @param {u256[]} values - An array of u256 values to set.
288
+ * @param {Address[]} values - An array of Address values to set.
260
289
  */
261
290
  @inline
262
291
  public setMultiple(startIndex: u32, values: Address[]): void {
@@ -267,10 +296,10 @@ export class StoredAddressArray {
267
296
 
268
297
  /**
269
298
  * @method getAll
270
- * @description Retrieves a range of values starting from a specific global index.
271
- * @param {u32} startIndex - The starting global index.
272
- * @param {u32} count - The number of values to retrieve.
273
- * @returns {Address[]} - An array containing the retrieved Address values.
299
+ * @description Retrieves a range of Address values.
300
+ * @param {u32} startIndex - The start index.
301
+ * @param {u32} count - The number of items to get.
302
+ * @returns {Address[]} - The requested Address values.
274
303
  */
275
304
  @inline
276
305
  public getAll(startIndex: u32, count: u32): Address[] {
@@ -284,8 +313,8 @@ export class StoredAddressArray {
284
313
 
285
314
  /**
286
315
  * @method toString
287
- * @description Returns a string representation of all cached values.
288
- * @returns {string} - A string in the format "[value0, value1, ..., valueN]".
316
+ * @description Returns a string representation of the array.
317
+ * @returns {string} - A string of the form "[addr0, addr1, ...]".
289
318
  */
290
319
  @inline
291
320
  public toString(): string {
@@ -304,7 +333,7 @@ export class StoredAddressArray {
304
333
  /**
305
334
  * @method toBytes
306
335
  * @description Returns the packed Address values as a byte array.
307
- * @returns {u8[]} - The packed values in byte form.
336
+ * @returns {u8[]} - The packed byte array.
308
337
  */
309
338
  @inline
310
339
  public toBytes(): u8[] {
@@ -313,7 +342,7 @@ export class StoredAddressArray {
313
342
  this.ensureValues(i);
314
343
  const value = this._values.get(i);
315
344
  if (value) {
316
- const valueBytes = value;
345
+ const valueBytes = value; // Address is assumed to be or contain a Uint8Array
317
346
  for (let j: u32 = 0; j < valueBytes.length; j++) {
318
347
  bytes.push(valueBytes[j]);
319
348
  }
@@ -324,16 +353,14 @@ export class StoredAddressArray {
324
353
 
325
354
  /**
326
355
  * @method reset
327
- * @description Resets all cached u256 values to zero and marks them as changed, including resetting the length and startIndex.
356
+ * @description Resets the array by clearing all elements and resetting length and startIndex to zero.
328
357
  */
329
358
  @inline
330
359
  public reset(): void {
331
- // Reset the length and startIndex to zero
332
360
  this._length = 0;
333
361
  this._startIndex = 0;
334
362
  this._isChangedLength = true;
335
363
  this._isChangedStartIndex = true;
336
-
337
364
  this.save();
338
365
  }
339
366
 
@@ -358,8 +385,8 @@ export class StoredAddressArray {
358
385
 
359
386
  /**
360
387
  * @method setLength
361
- * @description Sets the length of the array.
362
- * @param {u64} newLength - The new length to set.
388
+ * @description Sets the length of the array, truncating if necessary.
389
+ * @param {u64} newLength - The new length.
363
390
  */
364
391
  public setLength(newLength: u64): void {
365
392
  if (newLength > this.MAX_LENGTH) {
@@ -380,15 +407,15 @@ export class StoredAddressArray {
380
407
  /**
381
408
  * @private
382
409
  * @method ensureValues
383
- * @description Loads and caches the u256 value from the specified storage slot.
410
+ * @description Loads and caches the Address from the specified storage slot if not already loaded.
384
411
  * @param {u32} slotIndex - The index of the storage slot.
385
412
  */
386
413
  private ensureValues(slotIndex: u32): void {
387
414
  if (!this._isLoaded.has(slotIndex)) {
388
415
  const storagePointer = this.calculateStoragePointer(slotIndex);
389
- const storedU256 = Blockchain.getStorageAt(storagePointer, u256.Zero);
416
+ const storedU256: u256 = Blockchain.getStorageAt(storagePointer, u256.Zero);
390
417
  const storedAddress: Address =
391
- storedU256 === u256.Zero ? this.defaultValue : new Address(storedU256.toBytes());
418
+ storedU256 == u256.Zero ? this.defaultValue : new Address(storedU256.toBytes());
392
419
  this._values.set(slotIndex, storedAddress);
393
420
  this._isLoaded.add(slotIndex);
394
421
  }
@@ -397,13 +424,13 @@ export class StoredAddressArray {
397
424
  /**
398
425
  * @private
399
426
  * @method calculateStoragePointer
400
- * @description Calculates the storage pointer for a given slot index by incrementing the base pointer.
401
- * @param {u32} slotIndex - The index of the storage slot.
427
+ * @description Calculates the storage pointer for a given slot index.
428
+ * @param {u64} slotIndex - The index of the storage slot.
402
429
  * @returns {u256} - The calculated storage pointer.
403
430
  */
404
431
  private calculateStoragePointer(slotIndex: u64): u256 {
405
432
  // Each slot is identified by baseU256Pointer + slotIndex + 1
406
- // Slot 0: baseU256Pointer + 1 (first element)
433
+ // Slot 0: baseU256Pointer + 1
407
434
  // Slot 1: baseU256Pointer + 2, etc.
408
435
  return SafeMath.add(this.baseU256Pointer, u256.fromU64(slotIndex + 1));
409
436
  }