@btc-vision/btc-runtime 1.3.9 → 1.3.10
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 +1 -1
- package/runtime/contracts/DeployableOP_20.ts +0 -1
- package/runtime/env/BlockchainEnvironment.ts +17 -0
- package/runtime/env/global.ts +4 -0
- package/runtime/storage/StoredU128Array.ts +253 -88
- package/runtime/storage/StoredU16Array.ts +307 -116
- package/runtime/storage/StoredU256Array.ts +206 -124
package/package.json
CHANGED
|
@@ -284,7 +284,6 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
284
284
|
protected _transfer(to: Address, value: u256): boolean {
|
|
285
285
|
const sender = Blockchain.tx.sender;
|
|
286
286
|
|
|
287
|
-
if (!this.balanceOfMap.has(sender)) throw new Revert();
|
|
288
287
|
if (this.isSelf(sender)) throw new Revert('Can not transfer from self account');
|
|
289
288
|
|
|
290
289
|
if (u256.eq(value, u256.Zero)) {
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
nextPointerGreaterThan,
|
|
20
20
|
storePointer,
|
|
21
21
|
validateBitcoinAddress,
|
|
22
|
+
verifySchnorrSignature,
|
|
22
23
|
} from './global';
|
|
23
24
|
import { DeployContractResponse } from '../interfaces/DeployContractResponse';
|
|
24
25
|
import { MapU256 } from '../generic/MapU256';
|
|
@@ -248,6 +249,22 @@ export class BlockchainEnvironment {
|
|
|
248
249
|
return reader.readU256();
|
|
249
250
|
}
|
|
250
251
|
|
|
252
|
+
public verifySchnorrSignature(
|
|
253
|
+
publicKey: Address,
|
|
254
|
+
signature: Uint8Array,
|
|
255
|
+
hash: Uint8Array,
|
|
256
|
+
): boolean {
|
|
257
|
+
const writer = new BytesWriter(128);
|
|
258
|
+
writer.writeBytes(publicKey);
|
|
259
|
+
writer.writeBytes(signature);
|
|
260
|
+
writer.writeBytes(hash);
|
|
261
|
+
|
|
262
|
+
const result: Uint8Array = verifySchnorrSignature(writer.getBuffer());
|
|
263
|
+
|
|
264
|
+
const reader = new BytesReader(result);
|
|
265
|
+
return reader.readBoolean();
|
|
266
|
+
}
|
|
267
|
+
|
|
251
268
|
public hasStorageAt(pointerHash: MemorySlotPointer): bool {
|
|
252
269
|
// We mark zero as the default value for the storage, if something is 0, the storage slot get deleted or is non-existent
|
|
253
270
|
const val: u256 = this.getStorageAt(pointerHash, u256.Zero);
|
package/runtime/env/global.ts
CHANGED
|
@@ -53,3 +53,7 @@ export declare function inputs(): Uint8Array;
|
|
|
53
53
|
// @ts-ignore
|
|
54
54
|
@external('env', 'outputs')
|
|
55
55
|
export declare function outputs(): Uint8Array;
|
|
56
|
+
|
|
57
|
+
// @ts-ignore
|
|
58
|
+
@external('env', 'verifySchnorrSignature')
|
|
59
|
+
export declare function verifySchnorrSignature(data: Uint8Array): Uint8Array;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { u128, u256 } from 'as-bignum/assembly';
|
|
2
2
|
import { Blockchain } from '../env';
|
|
3
|
-
import { encodePointer } from '../math/abi';
|
|
4
3
|
import { BytesWriter } from '../buffer/BytesWriter';
|
|
5
|
-
import { u128, u256 } from 'as-bignum/assembly';
|
|
6
4
|
import { SafeMath } from '../types/SafeMath';
|
|
5
|
+
import { Revert } from '../types/Revert';
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* @class StoredU128Array
|
|
@@ -12,92 +11,239 @@ import { SafeMath } from '../types/SafeMath';
|
|
|
12
11
|
@final
|
|
13
12
|
export class StoredU128Array {
|
|
14
13
|
private readonly baseU256Pointer: u256;
|
|
14
|
+
private readonly lengthPointer: u256;
|
|
15
|
+
|
|
16
|
+
// Internal cache for storage slots, each holding two u128 values
|
|
17
|
+
private _values: Map<u64, u128[]> = new Map(); // Map from slotIndex to array of two u128s
|
|
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
|
|
15
20
|
|
|
16
|
-
// Internal
|
|
17
|
-
private
|
|
18
|
-
private
|
|
19
|
-
private
|
|
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.MAX_VALUE - 1;
|
|
20
29
|
|
|
21
30
|
/**
|
|
22
31
|
* @constructor
|
|
23
32
|
* @param {u16} pointer - The primary pointer identifier.
|
|
24
|
-
* @param {
|
|
33
|
+
* @param {Uint8Array} subPointer - The sub-pointer for memory slot addressing.
|
|
25
34
|
* @param {u256} defaultValue - The default u256 value if storage is uninitialized.
|
|
26
35
|
*/
|
|
27
36
|
constructor(
|
|
28
37
|
public pointer: u16,
|
|
29
|
-
public subPointer:
|
|
38
|
+
public subPointer: Uint8Array,
|
|
30
39
|
private defaultValue: u256,
|
|
31
40
|
) {
|
|
32
41
|
// Initialize the base u256 pointer using the primary pointer and subPointer
|
|
33
42
|
const writer = new BytesWriter(32);
|
|
34
|
-
writer.
|
|
35
|
-
|
|
43
|
+
writer.writeU16(pointer);
|
|
44
|
+
writer.writeBytes(subPointer);
|
|
45
|
+
|
|
46
|
+
// Initialize the length pointer (slot 0) where both length and startIndex are stored
|
|
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
|
|
36
57
|
}
|
|
37
58
|
|
|
38
59
|
/**
|
|
39
60
|
* @method get
|
|
40
61
|
* @description Retrieves the u128 value at the specified global index.
|
|
41
|
-
* @param {
|
|
62
|
+
* @param {u64} index - The global index (0 to ∞) of the u128 value to retrieve.
|
|
42
63
|
* @returns {u128} - The u128 value at the specified index.
|
|
43
64
|
*/
|
|
44
65
|
@inline
|
|
45
|
-
public get(index:
|
|
46
|
-
|
|
66
|
+
public get(index: u64): u128 {
|
|
67
|
+
assert(index < this._length, 'Index out of bounds');
|
|
68
|
+
const slotIndex: u32 = <u32>(index / 2); // Each slot holds two u128s
|
|
47
69
|
const subIndex: u8 = <u8>(index % 2); // 0 or 1
|
|
48
70
|
this.ensureValues(slotIndex);
|
|
49
|
-
|
|
71
|
+
const slotValues = this._values.get(slotIndex);
|
|
72
|
+
if (slotValues) {
|
|
73
|
+
return slotValues[subIndex];
|
|
74
|
+
} else {
|
|
75
|
+
return u128.Zero; // Should not happen, as ensureValues should have loaded it
|
|
76
|
+
}
|
|
50
77
|
}
|
|
51
78
|
|
|
52
79
|
/**
|
|
53
80
|
* @method set
|
|
54
81
|
* @description Sets the u128 value at the specified global index.
|
|
55
|
-
* @param {
|
|
82
|
+
* @param {u64} index - The global index (0 to ∞) of the u128 value to set.
|
|
56
83
|
* @param {u128} value - The u128 value to assign.
|
|
57
84
|
*/
|
|
58
85
|
@inline
|
|
59
|
-
public set(index:
|
|
60
|
-
|
|
86
|
+
public set(index: u64, value: u128): void {
|
|
87
|
+
assert(index < this._length, 'Index exceeds current array length');
|
|
88
|
+
const slotIndex: u32 = <u32>(index / 2);
|
|
61
89
|
const subIndex: u8 = <u8>(index % 2);
|
|
62
90
|
this.ensureValues(slotIndex);
|
|
91
|
+
const slotValues = this._values.get(slotIndex);
|
|
92
|
+
if (slotValues) {
|
|
93
|
+
if (!u128.eq(slotValues[subIndex], value)) {
|
|
94
|
+
slotValues[subIndex] = value;
|
|
95
|
+
this._isChanged.add(slotIndex);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @method push
|
|
102
|
+
* @description Appends a new u128 value to the end of the array.
|
|
103
|
+
* @param {u128} value - The u128 value to append.
|
|
104
|
+
*/
|
|
105
|
+
public push(value: u128): 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 effectiveIndex: u64 = this._startIndex + newIndex;
|
|
114
|
+
const wrappedIndex: u64 =
|
|
115
|
+
effectiveIndex < this.MAX_LENGTH ? effectiveIndex : effectiveIndex % this.MAX_LENGTH;
|
|
116
|
+
const slotIndex: u32 = <u32>(wrappedIndex / 2);
|
|
117
|
+
const subIndex: u8 = <u8>(wrappedIndex % 2);
|
|
118
|
+
|
|
119
|
+
// Ensure the slot is loaded
|
|
120
|
+
this.ensureValues(slotIndex);
|
|
121
|
+
|
|
122
|
+
// Set the new value in the appropriate sub-index
|
|
123
|
+
const slotValues = this._values.get(slotIndex);
|
|
124
|
+
if (slotValues) {
|
|
125
|
+
slotValues[subIndex] = value;
|
|
126
|
+
this._isChanged.add(slotIndex);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Increment the length
|
|
130
|
+
this._length += 1;
|
|
131
|
+
this._isChangedLength = true;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @method delete
|
|
136
|
+
* @description Deletes the u128 value at the specified index by setting it to zero. Does not reorder the array.
|
|
137
|
+
* @param {u64} index - The global index of the u128 value to delete.
|
|
138
|
+
*/
|
|
139
|
+
public delete(index: u64): void {
|
|
140
|
+
if (index >= this._length) {
|
|
141
|
+
// If the index is out of bounds, revert the transaction
|
|
142
|
+
throw new Revert('Delete operation failed: Index out of bounds.');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const slotIndex: u32 = <u32>(index / 2);
|
|
146
|
+
const subIndex: u8 = <u8>(index % 2);
|
|
147
|
+
this.ensureValues(slotIndex);
|
|
148
|
+
|
|
149
|
+
const slotValues = this._values.get(slotIndex);
|
|
150
|
+
if (slotValues) {
|
|
151
|
+
// Set the targeted u128 to zero
|
|
152
|
+
if (!u128.eq(slotValues[subIndex], u128.Zero)) {
|
|
153
|
+
slotValues[subIndex] = u128.Zero;
|
|
154
|
+
this._isChanged.add(slotIndex);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* @method shift
|
|
161
|
+
* @description Removes the first element of the array by setting it to zero, decrementing the length, and incrementing the startIndex.
|
|
162
|
+
* If the startIndex reaches the maximum value of u64, it wraps around to 0.
|
|
163
|
+
*/
|
|
164
|
+
public shift(): void {
|
|
165
|
+
if (this._length === 0) {
|
|
166
|
+
throw new Revert('Shift operation failed: Array is empty.');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const currentStartIndex: u64 = this._startIndex;
|
|
170
|
+
const slotIndex: u32 = <u32>(currentStartIndex / 2);
|
|
171
|
+
const subIndex: u8 = <u8>(currentStartIndex % 2);
|
|
172
|
+
this.ensureValues(slotIndex);
|
|
173
|
+
|
|
174
|
+
const slotValues = this._values.get(slotIndex);
|
|
175
|
+
if (slotValues) {
|
|
176
|
+
// Set the current start element to zero
|
|
177
|
+
if (!u128.eq(slotValues[subIndex], u128.Zero)) {
|
|
178
|
+
slotValues[subIndex] = u128.Zero;
|
|
179
|
+
this._isChanged.add(slotIndex);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Decrement the length
|
|
184
|
+
this._length -= 1;
|
|
185
|
+
this._isChangedLength = true;
|
|
63
186
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
this.
|
|
187
|
+
// Increment the startIndex with wrap-around
|
|
188
|
+
if (this._startIndex < this.MAX_LENGTH - 1) {
|
|
189
|
+
this._startIndex += 1;
|
|
190
|
+
} else {
|
|
191
|
+
this._startIndex = 0;
|
|
67
192
|
}
|
|
193
|
+
this._isChangedStartIndex = true;
|
|
68
194
|
}
|
|
69
195
|
|
|
70
196
|
/**
|
|
71
197
|
* @method save
|
|
72
|
-
* @description Persists all cached u128 values to their respective storage slots if any have been modified.
|
|
198
|
+
* @description Persists all cached u128 values, the length, and the startIndex to their respective storage slots if any have been modified.
|
|
73
199
|
*/
|
|
74
200
|
public save(): void {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
for (let
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
201
|
+
// Save all changed slots
|
|
202
|
+
const values = this._isChanged.values();
|
|
203
|
+
for (let i: u32 = 0; i < <u32>values.length; i++) {
|
|
204
|
+
const slotIndex = values[i];
|
|
205
|
+
const packed = this.packValues(slotIndex);
|
|
206
|
+
const storagePointer = this.calculateStoragePointer(slotIndex);
|
|
207
|
+
Blockchain.setStorageAt(storagePointer, packed);
|
|
208
|
+
}
|
|
209
|
+
this._isChanged.clear();
|
|
210
|
+
|
|
211
|
+
// Save length and startIndex if changed
|
|
212
|
+
if (this._isChangedLength || this._isChangedStartIndex) {
|
|
213
|
+
const packedLengthAndStartIndex = new u256();
|
|
214
|
+
packedLengthAndStartIndex.lo1 = this._length;
|
|
215
|
+
packedLengthAndStartIndex.lo2 = this._startIndex;
|
|
216
|
+
Blockchain.setStorageAt(this.lengthPointer, packedLengthAndStartIndex);
|
|
217
|
+
this._isChangedLength = false;
|
|
218
|
+
this._isChangedStartIndex = false;
|
|
84
219
|
}
|
|
85
220
|
}
|
|
86
221
|
|
|
87
222
|
/**
|
|
88
|
-
* @method
|
|
89
|
-
* @description Deletes all storage slots by setting them to zero.
|
|
223
|
+
* @method deleteAll
|
|
224
|
+
* @description Deletes all storage slots by setting them to zero, including the length and startIndex slots.
|
|
90
225
|
*/
|
|
91
|
-
public
|
|
92
|
-
|
|
93
|
-
|
|
226
|
+
public deleteAll(): void {
|
|
227
|
+
// Iterate over all loaded slots and clear them
|
|
228
|
+
const keys = this._values.keys();
|
|
229
|
+
for (let i = 0; i < keys.length; i++) {
|
|
230
|
+
const slotIndex = keys[i];
|
|
94
231
|
const storagePointer = this.calculateStoragePointer(slotIndex);
|
|
95
232
|
Blockchain.setStorageAt(storagePointer, u256.Zero);
|
|
96
233
|
}
|
|
234
|
+
|
|
235
|
+
// Reset the length and startIndex to zero
|
|
236
|
+
const zeroLengthAndStartIndex = u256.Zero;
|
|
237
|
+
Blockchain.setStorageAt(this.lengthPointer, zeroLengthAndStartIndex);
|
|
238
|
+
this._length = 0;
|
|
239
|
+
this._startIndex = 0;
|
|
240
|
+
this._isChangedLength = false;
|
|
241
|
+
this._isChangedStartIndex = false;
|
|
242
|
+
|
|
97
243
|
// Clear internal caches
|
|
98
|
-
this._values
|
|
99
|
-
this._isLoaded
|
|
100
|
-
this._isChanged
|
|
244
|
+
this._values.clear();
|
|
245
|
+
this._isLoaded.clear();
|
|
246
|
+
this._isChanged.clear();
|
|
101
247
|
}
|
|
102
248
|
|
|
103
249
|
/**
|
|
@@ -109,7 +255,7 @@ export class StoredU128Array {
|
|
|
109
255
|
@inline
|
|
110
256
|
public setMultiple(startIndex: u32, values: u128[]): void {
|
|
111
257
|
for (let i: u32 = 0; i < values.length; i++) {
|
|
112
|
-
this.set(startIndex + i, values[i]);
|
|
258
|
+
this.set(<u64>(startIndex + i), values[i]);
|
|
113
259
|
}
|
|
114
260
|
}
|
|
115
261
|
|
|
@@ -122,9 +268,10 @@ export class StoredU128Array {
|
|
|
122
268
|
*/
|
|
123
269
|
@inline
|
|
124
270
|
public getAll(startIndex: u32, count: u32): u128[] {
|
|
271
|
+
assert(startIndex + count <= this._length, 'Requested range exceeds array length');
|
|
125
272
|
const result: u128[] = new Array<u128>(count);
|
|
126
273
|
for (let i: u32 = 0; i < count; i++) {
|
|
127
|
-
result[i] = this.get(startIndex + i);
|
|
274
|
+
result[i] = this.get(<u64>(startIndex + i));
|
|
128
275
|
}
|
|
129
276
|
return result;
|
|
130
277
|
}
|
|
@@ -137,13 +284,11 @@ export class StoredU128Array {
|
|
|
137
284
|
@inline
|
|
138
285
|
public toString(): string {
|
|
139
286
|
let str = '[';
|
|
140
|
-
for (let
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
str += ', ';
|
|
146
|
-
}
|
|
287
|
+
for (let i: u32 = 0; i < this._length; i++) {
|
|
288
|
+
const value = this.get(<u64>i);
|
|
289
|
+
str += value.toString();
|
|
290
|
+
if (i !== this._length - 1) {
|
|
291
|
+
str += ', ';
|
|
147
292
|
}
|
|
148
293
|
}
|
|
149
294
|
str += ']';
|
|
@@ -158,11 +303,14 @@ export class StoredU128Array {
|
|
|
158
303
|
@inline
|
|
159
304
|
public toBytes(): u8[] {
|
|
160
305
|
const bytes: u8[] = new Array<u8>();
|
|
161
|
-
|
|
162
|
-
|
|
306
|
+
const slotCount: u32 = <u32>((this._length + 1) / 2);
|
|
307
|
+
|
|
308
|
+
for (let i: u32 = 0; i < slotCount; i++) {
|
|
309
|
+
this.ensureValues(i);
|
|
310
|
+
const packed = this.packValues(i);
|
|
163
311
|
const slotBytes = packed.toBytes();
|
|
164
|
-
for (let
|
|
165
|
-
bytes.push(slotBytes[
|
|
312
|
+
for (let j: u32 = 0; j < slotBytes.length; j++) {
|
|
313
|
+
bytes.push(slotBytes[j]);
|
|
166
314
|
}
|
|
167
315
|
}
|
|
168
316
|
return bytes;
|
|
@@ -170,40 +318,63 @@ export class StoredU128Array {
|
|
|
170
318
|
|
|
171
319
|
/**
|
|
172
320
|
* @method reset
|
|
173
|
-
* @description Resets all cached u128 values to zero and marks them as changed.
|
|
321
|
+
* @description Resets all cached u128 values to zero and marks them as changed, including resetting the length and startIndex.
|
|
174
322
|
*/
|
|
175
323
|
@inline
|
|
176
324
|
public reset(): void {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
325
|
+
// Reset the length and startIndex to zero
|
|
326
|
+
this._length = 0;
|
|
327
|
+
this._startIndex = 0;
|
|
328
|
+
this._isChangedLength = true;
|
|
329
|
+
this._isChangedStartIndex = true;
|
|
330
|
+
|
|
331
|
+
this.save();
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* @method getLength
|
|
336
|
+
* @description Retrieves the current length of the array.
|
|
337
|
+
* @returns {u64} - The current length.
|
|
338
|
+
*/
|
|
339
|
+
@inline
|
|
340
|
+
public getLength(): u64 {
|
|
341
|
+
return this._length;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* @method setLength
|
|
346
|
+
* @description Sets the length of the array.
|
|
347
|
+
* @param {u64} newLength - The new length to set.
|
|
348
|
+
*/
|
|
349
|
+
public setLength(newLength: u64): void {
|
|
350
|
+
if (newLength > this.MAX_LENGTH) {
|
|
351
|
+
throw new Revert('SetLength operation failed: Length exceeds maximum allowed value.');
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (newLength < this._length) {
|
|
355
|
+
// Truncate the array if newLength is smaller
|
|
356
|
+
for (let i: u64 = newLength; i < this._length; i++) {
|
|
357
|
+
this.delete(i);
|
|
180
358
|
}
|
|
181
|
-
this._isChanged[slotIndex] = true;
|
|
182
359
|
}
|
|
360
|
+
|
|
361
|
+
this._length = newLength;
|
|
362
|
+
this._isChangedLength = true;
|
|
183
363
|
}
|
|
184
364
|
|
|
185
365
|
/**
|
|
186
366
|
* @private
|
|
187
367
|
* @method ensureValues
|
|
188
|
-
* @description Loads and
|
|
368
|
+
* @description Loads and caches the u128 values from the specified storage slot.
|
|
189
369
|
* @param {u32} slotIndex - The index of the storage slot.
|
|
190
370
|
*/
|
|
191
371
|
private ensureValues(slotIndex: u32): void {
|
|
192
|
-
|
|
193
|
-
while (slotIndex >= <u32>this._isLoaded.length) {
|
|
194
|
-
this._isLoaded.push(false);
|
|
195
|
-
this._isChanged.push(false);
|
|
196
|
-
const newSlotValues: u128[] = new Array<u128>(2);
|
|
197
|
-
newSlotValues[0] = u128.Zero;
|
|
198
|
-
newSlotValues[1] = u128.Zero;
|
|
199
|
-
this._values.push(newSlotValues);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
if (!this._isLoaded[slotIndex]) {
|
|
372
|
+
if (!this._isLoaded.has(slotIndex)) {
|
|
203
373
|
const storagePointer = this.calculateStoragePointer(slotIndex);
|
|
204
374
|
const storedU256: u256 = Blockchain.getStorageAt(storagePointer, this.defaultValue);
|
|
205
|
-
|
|
206
|
-
this.
|
|
375
|
+
const slotValues = this.unpackU256(storedU256);
|
|
376
|
+
this._values.set(slotIndex, slotValues);
|
|
377
|
+
this._isLoaded.add(slotIndex);
|
|
207
378
|
}
|
|
208
379
|
}
|
|
209
380
|
|
|
@@ -211,19 +382,17 @@ export class StoredU128Array {
|
|
|
211
382
|
* @private
|
|
212
383
|
* @method packValues
|
|
213
384
|
* @description Packs the two cached u128 values into a single u256 for storage.
|
|
214
|
-
* @param {
|
|
385
|
+
* @param {u64} slotIndex - The index of the storage slot.
|
|
215
386
|
* @returns {u256} - The packed u256 value.
|
|
216
387
|
*/
|
|
217
|
-
private packValues(slotIndex:
|
|
218
|
-
const values = this._values
|
|
388
|
+
private packValues(slotIndex: u64): u256 {
|
|
389
|
+
const values = this._values.get(slotIndex);
|
|
390
|
+
if (!values) {
|
|
391
|
+
// Should not happen, as ensureValues should have loaded it
|
|
392
|
+
return u256.Zero;
|
|
393
|
+
}
|
|
219
394
|
const packed = new u256();
|
|
220
395
|
|
|
221
|
-
// Each u256 has lo1, lo2, hi1, hi2 as u64s
|
|
222
|
-
// Each u128 consists of two u64s
|
|
223
|
-
// Assign values accordingly:
|
|
224
|
-
// values[0] -> lo1 (first u64), lo2 (second u64)
|
|
225
|
-
// values[1] -> hi1 (third u64), hi2 (fourth u64)
|
|
226
|
-
|
|
227
396
|
// Assign first u128
|
|
228
397
|
packed.lo1 = values[0].lo;
|
|
229
398
|
packed.lo2 = values[0].hi;
|
|
@@ -257,15 +426,11 @@ export class StoredU128Array {
|
|
|
257
426
|
/**
|
|
258
427
|
* @private
|
|
259
428
|
* @method calculateStoragePointer
|
|
260
|
-
* @description Calculates the storage pointer for a given slot index by incrementing the
|
|
261
|
-
* @param {
|
|
429
|
+
* @description Calculates the storage pointer for a given slot index by incrementing the base pointer.
|
|
430
|
+
* @param {u64} slotIndex - The index of the storage slot.
|
|
262
431
|
* @returns {u256} - The calculated storage pointer.
|
|
263
432
|
*/
|
|
264
|
-
private calculateStoragePointer(slotIndex:
|
|
265
|
-
|
|
266
|
-
const modifiedSubPointer = this.baseU256Pointer.clone();
|
|
267
|
-
SafeMath.add(modifiedSubPointer, u256.fromU32(slotIndex));
|
|
268
|
-
|
|
269
|
-
return modifiedSubPointer;
|
|
433
|
+
private calculateStoragePointer(slotIndex: u64): u256 {
|
|
434
|
+
return SafeMath.add(this.baseU256Pointer, u256.fromU64(slotIndex + 1));
|
|
270
435
|
}
|
|
271
436
|
}
|