@btc-vision/btc-runtime 1.4.5 → 1.4.6
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 +2 -2
- package/runtime/buffer/BytesReader.ts +1 -1
- package/runtime/contracts/DeployableOP_20.ts +56 -47
- package/runtime/index.ts +0 -1
- package/runtime/math/bytes.ts +22 -8
- package/runtime/secp256k1/ECPoint.ts +103 -75
- package/runtime/storage/Serializable.ts +13 -10
- package/runtime/storage/arrays/StoredAddressArray.ts +13 -56
- package/runtime/storage/arrays/StoredBooleanArray.ts +17 -64
- package/runtime/storage/arrays/StoredU128Array.ts +13 -60
- package/runtime/storage/arrays/StoredU16Array.ts +11 -57
- package/runtime/storage/arrays/StoredU256Array.ts +23 -63
- package/runtime/storage/arrays/StoredU32Array.ts +11 -23
- package/runtime/storage/arrays/StoredU8Array.ts +11 -56
- package/runtime/types/Address.ts +1 -2
- package/runtime/types/SafeMath.ts +56 -28
- package/runtime/types/SafeMathI128.ts +8 -0
- package/runtime/math/rnd.ts +0 -55
|
@@ -5,7 +5,7 @@ import { Blockchain } from '../env';
|
|
|
5
5
|
import { encodePointer } from '../math/abi';
|
|
6
6
|
import { MemorySlotPointer } from '../memory/MemorySlotPointer';
|
|
7
7
|
import { Revert } from '../types/Revert';
|
|
8
|
-
import { U256_BYTE_LENGTH } from '../utils
|
|
8
|
+
import { U256_BYTE_LENGTH } from '../utils';
|
|
9
9
|
|
|
10
10
|
// Similar to a struct in Solidity. (Use in worst case scenario, consume a lot of gas)
|
|
11
11
|
export abstract class Serializable {
|
|
@@ -54,12 +54,16 @@ export abstract class Serializable {
|
|
|
54
54
|
if (chunks.length !== this.chunkCount) {
|
|
55
55
|
throw new Revert(
|
|
56
56
|
'Invalid chunk count, expected ' +
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
this.chunkCount.toString() +
|
|
58
|
+
' but got ' +
|
|
59
|
+
chunks.length.toString(),
|
|
60
60
|
);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
if (chunks.length > 255) {
|
|
64
|
+
throw new Revert('Too many chunks to save. You may only write up to 8160 bytes per object.');
|
|
65
|
+
}
|
|
66
|
+
|
|
63
67
|
for (let index: u8 = 0; index < u8(chunks.length); index++) {
|
|
64
68
|
Blockchain.setStorageAt(this.getPointer(this.subPointer, index), chunks[index]);
|
|
65
69
|
}
|
|
@@ -69,8 +73,8 @@ export abstract class Serializable {
|
|
|
69
73
|
const chunks: u256[] = [];
|
|
70
74
|
|
|
71
75
|
for (let index: i32 = 0; index < buffer.byteLength; index += 32) {
|
|
72
|
-
if (chunks.length ===
|
|
73
|
-
throw new Revert(
|
|
76
|
+
if (chunks.length === 256) {
|
|
77
|
+
throw new Revert(`Too many chunks to save You may only write up to 8160 bytes per object.`);
|
|
74
78
|
}
|
|
75
79
|
|
|
76
80
|
const chunk = buffer.slice(index, index + 32);
|
|
@@ -81,12 +85,11 @@ export abstract class Serializable {
|
|
|
81
85
|
}
|
|
82
86
|
|
|
83
87
|
protected chunksToBytes(chunks: u256[]): BytesReader {
|
|
84
|
-
if (this.chunkCount
|
|
85
|
-
|
|
86
|
-
throw new Revert('Too many chunks received');
|
|
88
|
+
if (this.chunkCount > u8(255)) {
|
|
89
|
+
throw new Revert(`Too many chunks received. You may only write up to 8160 bytes per object.`);
|
|
87
90
|
}
|
|
88
91
|
|
|
89
|
-
const buffer: Uint8Array = new Uint8Array(this.chunkCount * 32);
|
|
92
|
+
const buffer: Uint8Array = new Uint8Array(i32(this.chunkCount) * i32(32));
|
|
90
93
|
let offset: i32 = 0;
|
|
91
94
|
|
|
92
95
|
for (let indexChunk: i32 = 0; indexChunk < chunks.length; indexChunk++) {
|
|
@@ -65,7 +65,10 @@ export class StoredAddressArray {
|
|
|
65
65
|
*/
|
|
66
66
|
@inline
|
|
67
67
|
public get(index: u64): Address {
|
|
68
|
-
|
|
68
|
+
if (index >= this._length) {
|
|
69
|
+
throw new Revert('Get operation failed: Index out of bounds.');
|
|
70
|
+
}
|
|
71
|
+
|
|
69
72
|
const slotIndex: u32 = <u32>index;
|
|
70
73
|
this.ensureValues(slotIndex);
|
|
71
74
|
const value = this._values.get(slotIndex);
|
|
@@ -80,7 +83,10 @@ export class StoredAddressArray {
|
|
|
80
83
|
*/
|
|
81
84
|
@inline
|
|
82
85
|
public set(index: u64, value: Address): void {
|
|
83
|
-
|
|
86
|
+
if (index > this.MAX_LENGTH) {
|
|
87
|
+
throw new Revert('Set operation failed: Index exceeds maximum allowed value.');
|
|
88
|
+
}
|
|
89
|
+
|
|
84
90
|
const slotIndex: u32 = <u32>index;
|
|
85
91
|
this.ensureValues(slotIndex);
|
|
86
92
|
|
|
@@ -125,7 +131,7 @@ export class StoredAddressArray {
|
|
|
125
131
|
* @param {Address} value - The Address to append.
|
|
126
132
|
*/
|
|
127
133
|
public push(value: Address): void {
|
|
128
|
-
if (this._length
|
|
134
|
+
if (this._length > this.MAX_LENGTH) {
|
|
129
135
|
throw new Revert(
|
|
130
136
|
'Push operation failed: Array has reached its maximum allowed length.',
|
|
131
137
|
);
|
|
@@ -197,37 +203,6 @@ export class StoredAddressArray {
|
|
|
197
203
|
}
|
|
198
204
|
}
|
|
199
205
|
|
|
200
|
-
/**
|
|
201
|
-
* @method shift
|
|
202
|
-
* @description Removes the first element of the array.
|
|
203
|
-
*/
|
|
204
|
-
public shift(): void {
|
|
205
|
-
if (this._length === 0) {
|
|
206
|
-
throw new Revert('Shift operation failed: Array is empty.');
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
const currentStartIndex: u64 = this._startIndex;
|
|
210
|
-
const slotIndex: u32 = <u32>currentStartIndex;
|
|
211
|
-
this.ensureValues(slotIndex);
|
|
212
|
-
|
|
213
|
-
const currentValue = this._values.get(slotIndex);
|
|
214
|
-
if (currentValue != this.defaultValue) {
|
|
215
|
-
this._values.set(slotIndex, this.defaultValue);
|
|
216
|
-
this._isChanged.add(slotIndex);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
this._length -= 1;
|
|
220
|
-
this._isChangedLength = true;
|
|
221
|
-
|
|
222
|
-
// Increment the startIndex with wrap-around
|
|
223
|
-
if (this._startIndex < this.MAX_LENGTH - 1) {
|
|
224
|
-
this._startIndex += 1;
|
|
225
|
-
} else {
|
|
226
|
-
this._startIndex = 0;
|
|
227
|
-
}
|
|
228
|
-
this._isChangedStartIndex = true;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
206
|
/**
|
|
232
207
|
* @method save
|
|
233
208
|
* @description Persists all changes to storage.
|
|
@@ -303,7 +278,10 @@ export class StoredAddressArray {
|
|
|
303
278
|
*/
|
|
304
279
|
@inline
|
|
305
280
|
public getAll(startIndex: u32, count: u32): Address[] {
|
|
306
|
-
|
|
281
|
+
if ((startIndex + count) > this._length) {
|
|
282
|
+
throw new Revert('Requested range exceeds array length');
|
|
283
|
+
}
|
|
284
|
+
|
|
307
285
|
const result: Address[] = new Array<Address>(count);
|
|
308
286
|
for (let i: u32 = 0; i < count; i++) {
|
|
309
287
|
result[i] = this.get(<u64>(startIndex + i));
|
|
@@ -383,27 +361,6 @@ export class StoredAddressArray {
|
|
|
383
361
|
return this._startIndex;
|
|
384
362
|
}
|
|
385
363
|
|
|
386
|
-
/**
|
|
387
|
-
* @method setLength
|
|
388
|
-
* @description Sets the length of the array, truncating if necessary.
|
|
389
|
-
* @param {u64} newLength - The new length.
|
|
390
|
-
*/
|
|
391
|
-
public setLength(newLength: u64): void {
|
|
392
|
-
if (newLength > this.MAX_LENGTH) {
|
|
393
|
-
throw new Revert('SetLength operation failed: Length exceeds maximum allowed value.');
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
if (newLength < this._length) {
|
|
397
|
-
// Truncate the array if newLength is smaller
|
|
398
|
-
for (let i: u64 = newLength; i < this._length; i++) {
|
|
399
|
-
this.delete(i);
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
this._length = newLength;
|
|
404
|
-
this._isChangedLength = true;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
364
|
/**
|
|
408
365
|
* @private
|
|
409
366
|
* @method ensureValues
|
|
@@ -64,7 +64,9 @@ export class StoredBooleanArray {
|
|
|
64
64
|
*/
|
|
65
65
|
@inline
|
|
66
66
|
public get(index: u64): bool {
|
|
67
|
-
|
|
67
|
+
if (index >= this._length) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
68
70
|
|
|
69
71
|
const slotIndex: u64 = index / 256; // Each slot holds 256 bits
|
|
70
72
|
const bitIndex: u16 = <u16>(index % 256); // 0 to 255
|
|
@@ -85,7 +87,10 @@ export class StoredBooleanArray {
|
|
|
85
87
|
*/
|
|
86
88
|
@inline
|
|
87
89
|
public set(index: u64, value: bool): void {
|
|
88
|
-
|
|
90
|
+
if (index > this.MAX_LENGTH) {
|
|
91
|
+
throw new Revert('Set operation failed: Index exceeds maximum allowed value.');
|
|
92
|
+
}
|
|
93
|
+
|
|
89
94
|
const slotIndex: u64 = index / 256;
|
|
90
95
|
const bitIndex: u16 = <u16>(index % 256);
|
|
91
96
|
this.ensureValues(slotIndex);
|
|
@@ -106,7 +111,7 @@ export class StoredBooleanArray {
|
|
|
106
111
|
* @param {bool} value - The boolean value to append.
|
|
107
112
|
*/
|
|
108
113
|
public push(value: bool): void {
|
|
109
|
-
if (this._length
|
|
114
|
+
if (this._length > this.MAX_LENGTH) {
|
|
110
115
|
throw new Revert(
|
|
111
116
|
'Push operation failed: Array has reached its maximum allowed length.',
|
|
112
117
|
);
|
|
@@ -158,43 +163,6 @@ export class StoredBooleanArray {
|
|
|
158
163
|
}
|
|
159
164
|
}
|
|
160
165
|
|
|
161
|
-
/**
|
|
162
|
-
* @method shift
|
|
163
|
-
* @description Removes the first element of the array by setting it to false, decrementing the length, and incrementing the startIndex.
|
|
164
|
-
* If the startIndex reaches the maximum value of u64, it wraps around to 0.
|
|
165
|
-
*/
|
|
166
|
-
public shift(): void {
|
|
167
|
-
if (this._length === 0) {
|
|
168
|
-
throw new Revert('Shift operation failed: Array is empty.');
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const currentStartIndex: u64 = this._startIndex;
|
|
172
|
-
const slotIndex: u64 = currentStartIndex / 256;
|
|
173
|
-
const bitIndex: u16 = <u16>(currentStartIndex % 256);
|
|
174
|
-
this.ensureValues(slotIndex);
|
|
175
|
-
|
|
176
|
-
const slotValue = this._values.get(slotIndex);
|
|
177
|
-
if (slotValue) {
|
|
178
|
-
const oldValue = this.getBit(slotValue, bitIndex);
|
|
179
|
-
if (oldValue != false) {
|
|
180
|
-
this.setBit(slotValue, bitIndex, false);
|
|
181
|
-
this._isChanged.add(slotIndex);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Decrement the length
|
|
186
|
-
this._length -= 1;
|
|
187
|
-
this._isChangedLength = true;
|
|
188
|
-
|
|
189
|
-
// Increment the startIndex with wrap-around
|
|
190
|
-
if (this._startIndex < this.MAX_LENGTH - 1) {
|
|
191
|
-
this._startIndex += 1;
|
|
192
|
-
} else {
|
|
193
|
-
this._startIndex = 0;
|
|
194
|
-
}
|
|
195
|
-
this._isChangedStartIndex = true;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
166
|
/**
|
|
199
167
|
* @method save
|
|
200
168
|
* @description Persists all cached boolean values, the length, and the startIndex to their respective storage slots if any have been modified.
|
|
@@ -272,7 +240,9 @@ export class StoredBooleanArray {
|
|
|
272
240
|
*/
|
|
273
241
|
@inline
|
|
274
242
|
public getAll(startIndex: u64, count: u64): bool[] {
|
|
275
|
-
|
|
243
|
+
if ((startIndex + count) > this._length) {
|
|
244
|
+
throw new Revert('Requested range exceeds array length');
|
|
245
|
+
}
|
|
276
246
|
|
|
277
247
|
if (u32.MAX_VALUE < count) {
|
|
278
248
|
throw new Revert('Requested range exceeds maximum allowed value.');
|
|
@@ -366,27 +336,6 @@ export class StoredBooleanArray {
|
|
|
366
336
|
return this._startIndex;
|
|
367
337
|
}
|
|
368
338
|
|
|
369
|
-
/**
|
|
370
|
-
* @method setLength
|
|
371
|
-
* @description Sets the length of the array.
|
|
372
|
-
* @param {u64} newLength - The new length to set.
|
|
373
|
-
*/
|
|
374
|
-
public setLength(newLength: u64): void {
|
|
375
|
-
if (newLength > this.MAX_LENGTH) {
|
|
376
|
-
throw new Revert('SetLength operation failed: Length exceeds maximum allowed value.');
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
if (newLength < this._length) {
|
|
380
|
-
// Truncate the array if newLength is smaller
|
|
381
|
-
for (let i: u64 = newLength; i < this._length; i++) {
|
|
382
|
-
this.delete(i);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
this._length = newLength;
|
|
387
|
-
this._isChangedLength = true;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
339
|
/**
|
|
391
340
|
* @method deleteLast
|
|
392
341
|
* @description Deletes the last element of the array by setting it to false and decrementing the length.
|
|
@@ -440,7 +389,9 @@ export class StoredBooleanArray {
|
|
|
440
389
|
* @returns {bool} - The value of the bit at the specified index.
|
|
441
390
|
*/
|
|
442
391
|
private getBit(value: u256, bitIndex: u16): bool {
|
|
443
|
-
|
|
392
|
+
if (!(bitIndex < 256)) {
|
|
393
|
+
throw new Revert('Bit index out of range');
|
|
394
|
+
}
|
|
444
395
|
|
|
445
396
|
if (bitIndex < 64) {
|
|
446
397
|
return ((value.lo1 >> bitIndex) & 0b1) == 1;
|
|
@@ -462,7 +413,9 @@ export class StoredBooleanArray {
|
|
|
462
413
|
* @param {bool} bitValue - The value to set (true or false).
|
|
463
414
|
*/
|
|
464
415
|
private setBit(value: u256, bitIndex: u16, bitValue: bool): void {
|
|
465
|
-
|
|
416
|
+
if (!(bitIndex < 256)) {
|
|
417
|
+
throw new Revert('Bit index out of range');
|
|
418
|
+
}
|
|
466
419
|
|
|
467
420
|
if (bitIndex < 64) {
|
|
468
421
|
const mask = u64(1) << bitIndex;
|
|
@@ -64,7 +64,10 @@ export class StoredU128Array {
|
|
|
64
64
|
*/
|
|
65
65
|
@inline
|
|
66
66
|
public get(index: u64): u128 {
|
|
67
|
-
|
|
67
|
+
if (index >= this._length) {
|
|
68
|
+
return u128.Zero;
|
|
69
|
+
}
|
|
70
|
+
|
|
68
71
|
const slotIndex: u32 = <u32>(index / 2); // Each slot holds two u128s
|
|
69
72
|
const subIndex: u8 = <u8>(index % 2); // 0 or 1
|
|
70
73
|
this.ensureValues(slotIndex);
|
|
@@ -84,7 +87,10 @@ export class StoredU128Array {
|
|
|
84
87
|
*/
|
|
85
88
|
@inline
|
|
86
89
|
public set(index: u64, value: u128): void {
|
|
87
|
-
|
|
90
|
+
if (index > this.MAX_LENGTH) {
|
|
91
|
+
throw new Revert('Set operation failed: Index exceeds maximum allowed value.');
|
|
92
|
+
}
|
|
93
|
+
|
|
88
94
|
const slotIndex: u32 = <u32>(index / 2);
|
|
89
95
|
const subIndex: u8 = <u8>(index % 2);
|
|
90
96
|
this.ensureValues(slotIndex);
|
|
@@ -103,7 +109,7 @@ export class StoredU128Array {
|
|
|
103
109
|
* @param {u128} value - The u128 value to append.
|
|
104
110
|
*/
|
|
105
111
|
public push(value: u128): void {
|
|
106
|
-
if (this._length
|
|
112
|
+
if (this._length > this.MAX_LENGTH) {
|
|
107
113
|
throw new Revert(
|
|
108
114
|
'Push operation failed: Array has reached its maximum allowed length.',
|
|
109
115
|
);
|
|
@@ -155,43 +161,6 @@ export class StoredU128Array {
|
|
|
155
161
|
}
|
|
156
162
|
}
|
|
157
163
|
|
|
158
|
-
/**
|
|
159
|
-
* @method shift
|
|
160
|
-
* @description Removes the first element of the array by setting it to zero, decrementing the length, and incrementing the startIndex.
|
|
161
|
-
* If the startIndex reaches the maximum value of u64, it wraps around to 0.
|
|
162
|
-
*/
|
|
163
|
-
public shift(): void {
|
|
164
|
-
if (this._length === 0) {
|
|
165
|
-
throw new Revert('Shift operation failed: Array is empty.');
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const currentStartIndex: u64 = this._startIndex;
|
|
169
|
-
const slotIndex: u32 = <u32>(currentStartIndex / 2);
|
|
170
|
-
const subIndex: u8 = <u8>(currentStartIndex % 2);
|
|
171
|
-
this.ensureValues(slotIndex);
|
|
172
|
-
|
|
173
|
-
const slotValues = this._values.get(slotIndex);
|
|
174
|
-
if (slotValues) {
|
|
175
|
-
// Set the current start element to zero
|
|
176
|
-
if (!u128.eq(slotValues[subIndex], u128.Zero)) {
|
|
177
|
-
slotValues[subIndex] = u128.Zero;
|
|
178
|
-
this._isChanged.add(slotIndex);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Decrement the length
|
|
183
|
-
this._length -= 1;
|
|
184
|
-
this._isChangedLength = true;
|
|
185
|
-
|
|
186
|
-
// Increment the startIndex with wrap-around
|
|
187
|
-
if (this._startIndex < this.MAX_LENGTH - 1) {
|
|
188
|
-
this._startIndex += 1;
|
|
189
|
-
} else {
|
|
190
|
-
this._startIndex = 0;
|
|
191
|
-
}
|
|
192
|
-
this._isChangedStartIndex = true;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
164
|
/**
|
|
196
165
|
* @method save
|
|
197
166
|
* @description Persists all cached u128 values, the length, and the startIndex to their respective storage slots if any have been modified.
|
|
@@ -280,7 +249,10 @@ export class StoredU128Array {
|
|
|
280
249
|
*/
|
|
281
250
|
@inline
|
|
282
251
|
public getAll(startIndex: u32, count: u32): u128[] {
|
|
283
|
-
|
|
252
|
+
if ((startIndex + count) > this._length) {
|
|
253
|
+
throw new Revert('Requested range exceeds array length');
|
|
254
|
+
}
|
|
255
|
+
|
|
284
256
|
const result: u128[] = new Array<u128>(count);
|
|
285
257
|
for (let i: u32 = 0; i < count; i++) {
|
|
286
258
|
result[i] = this.get(<u64>(startIndex + i));
|
|
@@ -353,25 +325,6 @@ export class StoredU128Array {
|
|
|
353
325
|
return this._length;
|
|
354
326
|
}
|
|
355
327
|
|
|
356
|
-
/**
|
|
357
|
-
* @method setLength
|
|
358
|
-
* @description Sets the length of the array.
|
|
359
|
-
* @param {u64} newLength - The new length to set.
|
|
360
|
-
*/
|
|
361
|
-
public setLength(newLength: u64): void {
|
|
362
|
-
if (newLength > this.MAX_LENGTH) {
|
|
363
|
-
throw new Revert('SetLength operation failed: Length exceeds maximum allowed value.');
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
if (newLength > this._startIndex) {
|
|
367
|
-
this._startIndex = newLength;
|
|
368
|
-
this._isChangedStartIndex = true;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
this._length = newLength;
|
|
372
|
-
this._isChangedLength = true;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
328
|
/**
|
|
376
329
|
* @private
|
|
377
330
|
* @method ensureValues
|
|
@@ -64,7 +64,9 @@ export class StoredU16Array {
|
|
|
64
64
|
*/
|
|
65
65
|
@inline
|
|
66
66
|
public get(index: u64): u16 {
|
|
67
|
-
|
|
67
|
+
if (index >= this._length) {
|
|
68
|
+
return 0;
|
|
69
|
+
}
|
|
68
70
|
|
|
69
71
|
const slotIndex: u64 = index / 16; // Each slot holds sixteen u16s
|
|
70
72
|
const subIndex: u8 = <u8>(index % 16); // 0 to 15
|
|
@@ -81,7 +83,10 @@ export class StoredU16Array {
|
|
|
81
83
|
*/
|
|
82
84
|
@inline
|
|
83
85
|
public set(index: u64, value: u16): void {
|
|
84
|
-
|
|
86
|
+
if (index > this.MAX_LENGTH) {
|
|
87
|
+
throw new Revert('Set operation failed: Index exceeds maximum allowed value.');
|
|
88
|
+
}
|
|
89
|
+
|
|
85
90
|
const slotIndex: u64 = index / 16;
|
|
86
91
|
const subIndex: u8 = <u8>(index % 16);
|
|
87
92
|
this.ensureValues(slotIndex);
|
|
@@ -99,7 +104,7 @@ export class StoredU16Array {
|
|
|
99
104
|
* @param {u16} value - The u16 value to append.
|
|
100
105
|
*/
|
|
101
106
|
public push(value: u16): void {
|
|
102
|
-
if (this._length
|
|
107
|
+
if (this._length > this.MAX_LENGTH) {
|
|
103
108
|
throw new Revert(
|
|
104
109
|
'Push operation failed: Array has reached its maximum allowed length.',
|
|
105
110
|
);
|
|
@@ -148,40 +153,6 @@ export class StoredU16Array {
|
|
|
148
153
|
}
|
|
149
154
|
}
|
|
150
155
|
|
|
151
|
-
/**
|
|
152
|
-
* @method shift
|
|
153
|
-
* @description Removes the first element of the array by setting it to zero, decrementing the length, and incrementing the startIndex.
|
|
154
|
-
* If the startIndex reaches the maximum value of u64, it wraps around to 0.
|
|
155
|
-
*/
|
|
156
|
-
public shift(): void {
|
|
157
|
-
if (this._length === 0) {
|
|
158
|
-
throw new Revert('Shift operation failed: Array is empty.');
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const currentStartIndex: u64 = this._startIndex;
|
|
162
|
-
const slotIndex: u64 = currentStartIndex / 16;
|
|
163
|
-
const subIndex: u8 = <u8>(currentStartIndex % 16);
|
|
164
|
-
this.ensureValues(slotIndex);
|
|
165
|
-
|
|
166
|
-
const slotValues = this._values.get(slotIndex);
|
|
167
|
-
if (slotValues && slotValues[subIndex] !== 0) {
|
|
168
|
-
slotValues[subIndex] = 0;
|
|
169
|
-
this._isChanged.add(slotIndex);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Decrement the length
|
|
173
|
-
this._length -= 1;
|
|
174
|
-
this._isChangedLength = true;
|
|
175
|
-
|
|
176
|
-
// Increment the startIndex with wrap-around
|
|
177
|
-
if (this._startIndex < this.MAX_LENGTH - 1) {
|
|
178
|
-
this._startIndex += 1;
|
|
179
|
-
} else {
|
|
180
|
-
this._startIndex = 0;
|
|
181
|
-
}
|
|
182
|
-
this._isChangedStartIndex = true;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
156
|
/**
|
|
186
157
|
* @method save
|
|
187
158
|
* @description Persists all cached u16 values, the length, and the startIndex to their respective storage slots if any have been modified.
|
|
@@ -257,7 +228,9 @@ export class StoredU16Array {
|
|
|
257
228
|
*/
|
|
258
229
|
@inline
|
|
259
230
|
public getAll(startIndex: u64, count: u64): u16[] {
|
|
260
|
-
|
|
231
|
+
if ((startIndex + count) > this._length) {
|
|
232
|
+
throw new Revert('Requested range exceeds array length');
|
|
233
|
+
}
|
|
261
234
|
|
|
262
235
|
if (u32.MAX_VALUE < count) {
|
|
263
236
|
throw new Revert('Requested range exceeds maximum allowed value.');
|
|
@@ -344,25 +317,6 @@ export class StoredU16Array {
|
|
|
344
317
|
return this._startIndex;
|
|
345
318
|
}
|
|
346
319
|
|
|
347
|
-
/**
|
|
348
|
-
* @method setLength
|
|
349
|
-
* @description Sets the length of the array.
|
|
350
|
-
* @param {u64} newLength - The new length to set.
|
|
351
|
-
*/
|
|
352
|
-
public setLength(newLength: u64): void {
|
|
353
|
-
if (newLength > this.MAX_LENGTH) {
|
|
354
|
-
throw new Revert('SetLength operation failed: Length exceeds maximum allowed value.');
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
if (newLength > this._startIndex) {
|
|
358
|
-
this._startIndex = newLength;
|
|
359
|
-
this._isChangedStartIndex = true;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
this._length = newLength;
|
|
363
|
-
this._isChangedLength = true;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
320
|
public deleteLast(): void {
|
|
367
321
|
if (this._length === 0) {
|
|
368
322
|
throw new Revert('DeleteLast operation failed: Array is empty.');
|
|
@@ -19,13 +19,13 @@ export class StoredU256Array {
|
|
|
19
19
|
private _isChanged: Set<u64> = new Set(); // Set of slotIndexes that are modified
|
|
20
20
|
|
|
21
21
|
// Internal variables for length and startIndex management
|
|
22
|
-
private _length: u64 = 0;
|
|
22
|
+
private _length: u64 = 0; // Current length of the array
|
|
23
23
|
private _startIndex: u64 = 0; // Starting index of the array
|
|
24
|
-
private _isChangedLength: bool = false;
|
|
25
|
-
private _isChangedStartIndex: bool = false;
|
|
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
26
|
|
|
27
27
|
// Define a maximum allowed length to prevent excessive storage usage
|
|
28
|
-
private readonly MAX_LENGTH: u64 = u64(u32.MAX_VALUE - 1);
|
|
28
|
+
private readonly MAX_LENGTH: u64 = u64(u32.MAX_VALUE - 1);
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* @constructor
|
|
@@ -52,19 +52,23 @@ export class StoredU256Array {
|
|
|
52
52
|
this.lengthPointer = lengthPointer;
|
|
53
53
|
this.baseU256Pointer = baseU256Pointer;
|
|
54
54
|
|
|
55
|
-
this._length = storedLengthAndStartIndex.lo1;
|
|
55
|
+
this._length = storedLengthAndStartIndex.lo1; // Bytes 0-7: length
|
|
56
56
|
this._startIndex = storedLengthAndStartIndex.lo2; // Bytes 8-15: startIndex
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
60
|
* @method get
|
|
61
61
|
* @description Retrieves the u256 value at the specified global index.
|
|
62
|
+
* Returns zero instead of reverting if the index is out of bounds.
|
|
62
63
|
* @param {u64} index - The global index (0 to ∞) of the u256 value to retrieve.
|
|
63
|
-
* @returns {u256} - The u256 value at the specified index.
|
|
64
|
+
* @returns {u256} - The u256 value at the specified index or zero if out of bounds.
|
|
64
65
|
*/
|
|
65
66
|
@inline
|
|
66
67
|
public get(index: u64): u256 {
|
|
67
|
-
|
|
68
|
+
if (index >= this._length) {
|
|
69
|
+
return u256.Zero;
|
|
70
|
+
}
|
|
71
|
+
|
|
68
72
|
const slotIndex: u32 = <u32>index;
|
|
69
73
|
this.ensureValues(slotIndex);
|
|
70
74
|
const value = this._values.get(slotIndex);
|
|
@@ -79,7 +83,10 @@ export class StoredU256Array {
|
|
|
79
83
|
*/
|
|
80
84
|
@inline
|
|
81
85
|
public set(index: u64, value: u256): void {
|
|
82
|
-
|
|
86
|
+
if (index > this.MAX_LENGTH) {
|
|
87
|
+
throw new Revert('Set operation failed: Index exceeds maximum allowed value.');
|
|
88
|
+
}
|
|
89
|
+
|
|
83
90
|
const slotIndex: u32 = <u32>index;
|
|
84
91
|
this.ensureValues(slotIndex);
|
|
85
92
|
|
|
@@ -96,7 +103,7 @@ export class StoredU256Array {
|
|
|
96
103
|
* @param {u256} value - The u256 value to append.
|
|
97
104
|
*/
|
|
98
105
|
public push(value: u256): void {
|
|
99
|
-
if (this._length
|
|
106
|
+
if (this._length > this.MAX_LENGTH) {
|
|
100
107
|
throw new Revert(
|
|
101
108
|
'Push operation failed: Array has reached its maximum allowed length.',
|
|
102
109
|
);
|
|
@@ -164,42 +171,10 @@ export class StoredU256Array {
|
|
|
164
171
|
}
|
|
165
172
|
}
|
|
166
173
|
|
|
167
|
-
/**
|
|
168
|
-
* @method shift
|
|
169
|
-
* @description Removes the first element of the array by setting it to zero, decrementing the length, and incrementing the startIndex.
|
|
170
|
-
* If the startIndex reaches the maximum value of u64, it wraps around to 0.
|
|
171
|
-
*/
|
|
172
|
-
public shift(): void {
|
|
173
|
-
if (this._length === 0) {
|
|
174
|
-
throw new Revert('Shift operation failed: Array is empty.');
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const currentStartIndex: u64 = this._startIndex;
|
|
178
|
-
const slotIndex: u32 = <u32>currentStartIndex;
|
|
179
|
-
this.ensureValues(slotIndex);
|
|
180
|
-
|
|
181
|
-
const currentValue = this._values.get(slotIndex);
|
|
182
|
-
if (!u256.eq(currentValue, u256.Zero)) {
|
|
183
|
-
this._values.set(slotIndex, u256.Zero);
|
|
184
|
-
this._isChanged.add(slotIndex);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Decrement the length
|
|
188
|
-
this._length -= 1;
|
|
189
|
-
this._isChangedLength = true;
|
|
190
|
-
|
|
191
|
-
// Increment the startIndex with wrap-around
|
|
192
|
-
if (this._startIndex < this.MAX_LENGTH - 1) {
|
|
193
|
-
this._startIndex += 1;
|
|
194
|
-
} else {
|
|
195
|
-
this._startIndex = 0;
|
|
196
|
-
}
|
|
197
|
-
this._isChangedStartIndex = true;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
174
|
/**
|
|
201
175
|
* @method save
|
|
202
|
-
* @description Persists all cached u256 values, the length, and the startIndex to their respective storage slots
|
|
176
|
+
* @description Persists all cached u256 values, the length, and the startIndex to their respective storage slots
|
|
177
|
+
* if any have been modified.
|
|
203
178
|
*/
|
|
204
179
|
public save(): void {
|
|
205
180
|
// Save all changed slots
|
|
@@ -210,6 +185,7 @@ export class StoredU256Array {
|
|
|
210
185
|
const value = this._values.get(slotIndex);
|
|
211
186
|
Blockchain.setStorageAt(storagePointer, value);
|
|
212
187
|
}
|
|
188
|
+
|
|
213
189
|
this._isChanged.clear();
|
|
214
190
|
|
|
215
191
|
// Save length and startIndex if changed
|
|
@@ -239,6 +215,7 @@ export class StoredU256Array {
|
|
|
239
215
|
// Reset the length and startIndex to zero
|
|
240
216
|
const zeroLengthAndStartIndex = u256.Zero;
|
|
241
217
|
Blockchain.setStorageAt(this.lengthPointer, zeroLengthAndStartIndex);
|
|
218
|
+
|
|
242
219
|
this._length = 0;
|
|
243
220
|
this._startIndex = 0;
|
|
244
221
|
this._isChangedLength = false;
|
|
@@ -272,7 +249,9 @@ export class StoredU256Array {
|
|
|
272
249
|
*/
|
|
273
250
|
@inline
|
|
274
251
|
public getAll(startIndex: u32, count: u32): u256[] {
|
|
275
|
-
|
|
252
|
+
if ((startIndex + count) > this._length) {
|
|
253
|
+
throw new Revert('Requested range exceeds array length');
|
|
254
|
+
}
|
|
276
255
|
const result: u256[] = new Array<u256>(count);
|
|
277
256
|
for (let i: u32 = 0; i < count; i++) {
|
|
278
257
|
result[i] = this.get(<u64>(startIndex + i));
|
|
@@ -354,25 +333,6 @@ export class StoredU256Array {
|
|
|
354
333
|
return this._startIndex;
|
|
355
334
|
}
|
|
356
335
|
|
|
357
|
-
/**
|
|
358
|
-
* @method setLength
|
|
359
|
-
* @description Sets the length of the array.
|
|
360
|
-
* @param {u64} newLength - The new length to set.
|
|
361
|
-
*/
|
|
362
|
-
public setLength(newLength: u64): void {
|
|
363
|
-
if (newLength > this.MAX_LENGTH) {
|
|
364
|
-
throw new Revert('SetLength operation failed: Length exceeds maximum allowed value.');
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
if (newLength > this._startIndex) {
|
|
368
|
-
this._startIndex = newLength;
|
|
369
|
-
this._isChangedStartIndex = true;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
this._length = newLength;
|
|
373
|
-
this._isChangedLength = true;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
336
|
/**
|
|
377
337
|
* @private
|
|
378
338
|
* @method ensureValues
|