@btc-vision/btc-runtime 1.6.1 → 1.6.3
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/buffer/BytesReader.ts +2 -31
- package/runtime/env/Atomic.ts +51 -0
- package/runtime/env/BlockchainEnvironment.ts +10 -16
- package/runtime/env/classes/Transaction.ts +6 -4
- package/runtime/env/classes/UTXO.ts +23 -3
- package/runtime/env/decoders/TransactionDecoder.ts +66 -0
- package/runtime/env/enums/TransactionFlags.ts +9 -0
- package/runtime/env/global.ts +2 -0
- package/runtime/index.ts +5 -0
- package/runtime/math/bytes.ts +7 -7
- package/runtime/storage/AdvancedStoredString.ts +199 -0
- package/runtime/storage/StoredU32.ts +178 -0
- package/runtime/storage/arrays/StoredAddressArray.ts +20 -279
- package/runtime/storage/arrays/StoredBooleanArray.ts +122 -52
- package/runtime/storage/arrays/StoredPackedArray.ts +125 -49
- package/runtime/storage/arrays/StoredU128Array.ts +6 -6
- package/runtime/storage/arrays/StoredU16Array.ts +6 -6
- package/runtime/storage/arrays/StoredU256Array.ts +5 -5
- package/runtime/storage/arrays/StoredU32Array.ts +5 -5
- package/runtime/storage/arrays/StoredU64Array.ts +14 -7
- package/runtime/storage/arrays/StoredU8Array.ts +5 -5
- package/runtime/storage/maps/StoredMapU256.ts +62 -0
- package/runtime/types/SafeMath.ts +50 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
2
|
+
import { BytesWriter } from '../buffer/BytesWriter';
|
|
3
|
+
import { Blockchain } from '../env';
|
|
4
|
+
import { encodePointer } from '../math/abi';
|
|
5
|
+
import { BytesReader } from '../buffer/BytesReader';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @class StoredU32
|
|
9
|
+
* @description Manages up to height u32 values within a single u256 storage slot.
|
|
10
|
+
*/
|
|
11
|
+
@final
|
|
12
|
+
export class StoredU32 {
|
|
13
|
+
private readonly bufferPointer: Uint8Array;
|
|
14
|
+
|
|
15
|
+
// Internal cache for four u32 values
|
|
16
|
+
private _values: u32[] = [0, 0, 0, 0, 0, 0, 0, 0];
|
|
17
|
+
|
|
18
|
+
// Flag to indicate if values are loaded from storage
|
|
19
|
+
private isLoaded: bool = false;
|
|
20
|
+
|
|
21
|
+
// Flag to indicate if any value has been changed
|
|
22
|
+
private isChanged: bool = false;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @constructor
|
|
26
|
+
* @param {u16} pointer - The primary pointer identifier.
|
|
27
|
+
* @param {Uint8Array} subPointer - The sub-pointer for memory slot addressing.
|
|
28
|
+
*/
|
|
29
|
+
constructor(
|
|
30
|
+
public pointer: u16,
|
|
31
|
+
public subPointer: Uint8Array,
|
|
32
|
+
) {
|
|
33
|
+
assert(
|
|
34
|
+
subPointer.length <= 30,
|
|
35
|
+
`You must pass a 30 bytes sub-pointer. (StoredU32, got ${subPointer.length})`,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
this.bufferPointer = encodePointer(pointer, subPointer);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @method get
|
|
43
|
+
* @description Retrieves the u32 value at the specified offset.
|
|
44
|
+
* @param {u8} index - The index (0 to 7) of the u32 value to retrieve.
|
|
45
|
+
* @returns {u32} - The u32 value at the specified index.
|
|
46
|
+
*/
|
|
47
|
+
@inline
|
|
48
|
+
public get(index: u8): u32 {
|
|
49
|
+
assert(index < 8, 'Index out of bounds for StoredU32 (0-7)');
|
|
50
|
+
this.ensureValues();
|
|
51
|
+
return this._values[index];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @method set
|
|
56
|
+
* @description Sets the u32 value at the specified offset.
|
|
57
|
+
* @param {u8} index - The index (0 to 7) of the u32 value to set.
|
|
58
|
+
* @param {u32} value - The u32 value to assign.
|
|
59
|
+
*/
|
|
60
|
+
@inline
|
|
61
|
+
public set(index: u8, value: u32): void {
|
|
62
|
+
assert(index < 8, 'Index out of bounds for StoredU32 (0-7)');
|
|
63
|
+
this.ensureValues();
|
|
64
|
+
if (this._values[index] != value) {
|
|
65
|
+
this._values[index] = value;
|
|
66
|
+
this.isChanged = true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @method save
|
|
72
|
+
* @description Persists the cached u32 values to storage if any have been modified.
|
|
73
|
+
*/
|
|
74
|
+
public save(): void {
|
|
75
|
+
if (this.isChanged) {
|
|
76
|
+
const packed = this.packValues();
|
|
77
|
+
Blockchain.setStorageAt(this.bufferPointer, packed);
|
|
78
|
+
this.isChanged = false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @method setMultiple
|
|
84
|
+
* @description Sets multiple u32 values at once.
|
|
85
|
+
* @param {[u32, u32, u32, u32,u32, u32, u32, u32]} values - An array of four u32 values to set.
|
|
86
|
+
*/
|
|
87
|
+
@inline
|
|
88
|
+
public setMultiple(values: u32[]): void {
|
|
89
|
+
this.ensureValues();
|
|
90
|
+
let changed = false;
|
|
91
|
+
for (let i: u8 = 0; i < 8; i++) {
|
|
92
|
+
if (this._values[i] != values[i]) {
|
|
93
|
+
this._values[i] = values[i];
|
|
94
|
+
changed = true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (changed) {
|
|
98
|
+
this.isChanged = true;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @method getAll
|
|
104
|
+
* @description Retrieves all height u32 values as a tuple.
|
|
105
|
+
* @returns {[u32, u32, u32, u32,u32, u32, u32, u32]} - A tuple containing all four u32 values.
|
|
106
|
+
*/
|
|
107
|
+
@inline
|
|
108
|
+
public getAll(): u32[] {
|
|
109
|
+
this.ensureValues();
|
|
110
|
+
return this._values;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @method toString
|
|
115
|
+
* @description Returns a string representation of all height u32 values.
|
|
116
|
+
* @returns {string} - A string in the format "[value0, value1, value2, value3, value4, value5, value6, value7]".
|
|
117
|
+
*/
|
|
118
|
+
@inline
|
|
119
|
+
public toString(): string {
|
|
120
|
+
this.ensureValues();
|
|
121
|
+
return `[${this._values[0].toString()}, ${this._values[1].toString()}, ${this._values[2].toString()}, ${this._values[3].toString()},, ${this._values[4].toString()},, ${this._values[5].toString()},, ${this._values[6].toString()},, ${this._values[7].toString()}]`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* @method reset
|
|
126
|
+
* @description Resets the cached values to default and marks as changed.
|
|
127
|
+
*/
|
|
128
|
+
@inline
|
|
129
|
+
public reset(): void {
|
|
130
|
+
this._values = [0, 0, 0, 0, 0, 0, 0, 0];
|
|
131
|
+
this.isChanged = true;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @private
|
|
136
|
+
* @method ensureValues
|
|
137
|
+
* @description Loads and unpacks the u256 value from storage into height u32 cache variables.
|
|
138
|
+
*/
|
|
139
|
+
private ensureValues(): void {
|
|
140
|
+
if (!this.isLoaded) {
|
|
141
|
+
const storedU256: Uint8Array = Blockchain.getStorageAt(this.bufferPointer);
|
|
142
|
+
|
|
143
|
+
const reader = new BytesReader(storedU256);
|
|
144
|
+
|
|
145
|
+
this._values[0] = reader.readU32();
|
|
146
|
+
this._values[1] = reader.readU32();
|
|
147
|
+
this._values[2] = reader.readU32();
|
|
148
|
+
this._values[3] = reader.readU32();
|
|
149
|
+
this._values[4] = reader.readU32();
|
|
150
|
+
this._values[5] = reader.readU32();
|
|
151
|
+
this._values[6] = reader.readU32();
|
|
152
|
+
this._values[7] = reader.readU32();
|
|
153
|
+
|
|
154
|
+
this.isLoaded = true;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* @private
|
|
160
|
+
* @method packValues
|
|
161
|
+
* @description Packs the height cached u32 values into a single u256 for storage.
|
|
162
|
+
* @returns {u256} - The packed u256 value.
|
|
163
|
+
*/
|
|
164
|
+
private packValues(): Uint8Array {
|
|
165
|
+
const writer = new BytesWriter(32);
|
|
166
|
+
|
|
167
|
+
writer.writeU32(this._values[0]);
|
|
168
|
+
writer.writeU32(this._values[1]);
|
|
169
|
+
writer.writeU32(this._values[2]);
|
|
170
|
+
writer.writeU32(this._values[3]);
|
|
171
|
+
writer.writeU32(this._values[4]);
|
|
172
|
+
writer.writeU32(this._values[5]);
|
|
173
|
+
writer.writeU32(this._values[6]);
|
|
174
|
+
writer.writeU32(this._values[7]);
|
|
175
|
+
|
|
176
|
+
return writer.getBuffer();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -1,298 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
addUint8ArraysBE,
|
|
5
|
-
bigEndianAdd,
|
|
6
|
-
encodeBasePointer,
|
|
7
|
-
readLengthAndStartIndex,
|
|
8
|
-
u64ToBE32Bytes,
|
|
9
|
-
} from '../../math/bytes';
|
|
1
|
+
import { DEFAULT_MAX_LENGTH, StoredPackedArray } from './StoredPackedArray';
|
|
2
|
+
import { bigEndianAdd } from '../../math/bytes';
|
|
10
3
|
import { Address } from '../../types/Address';
|
|
11
|
-
import { Revert } from '../../types/Revert';
|
|
12
4
|
|
|
13
5
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
6
|
+
* StoredAddressArray
|
|
7
|
+
*
|
|
8
|
+
* Array of addresses.
|
|
17
9
|
*/
|
|
18
10
|
@final
|
|
19
|
-
export class StoredAddressArray {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
private _values: Map<u64, Address> = new Map(); // slotIndex -> Address
|
|
24
|
-
private _isChanged: Set<u64> = new Set(); // track changed slotIndexes
|
|
25
|
-
|
|
26
|
-
private _length: u64 = 0;
|
|
27
|
-
private _startIndex: u64 = 0;
|
|
28
|
-
private _isChangedLength: bool = false;
|
|
29
|
-
private _isChangedStartIndex: bool = false;
|
|
30
|
-
|
|
31
|
-
private readonly MAX_LENGTH: u64 = u64(u32.MAX_VALUE - 1);
|
|
32
|
-
|
|
33
|
-
private readonly defaultValue: Address = Address.zero();
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* @constructor
|
|
37
|
-
* @param {u16} pointer - The primary pointer identifier.
|
|
38
|
-
* @param {Uint8Array} subPointer - The sub-pointer for memory slot addressing.
|
|
39
|
-
*/
|
|
40
|
-
constructor(public pointer: u16, public subPointer: Uint8Array) {
|
|
41
|
-
assert(
|
|
42
|
-
subPointer.length <= 30,
|
|
43
|
-
`You must pass a 30 bytes sub-pointer. (AddressArray, got ${subPointer.length})`,
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
const basePointer = encodeBasePointer(pointer, subPointer);
|
|
47
|
-
this.lengthPointer = Uint8Array.wrap(basePointer.buffer);
|
|
48
|
-
this.baseU256Pointer = bigEndianAdd(basePointer, 1);
|
|
49
|
-
|
|
50
|
-
const storedLenStart = Blockchain.getStorageAt(basePointer);
|
|
51
|
-
const data = readLengthAndStartIndex(storedLenStart);
|
|
52
|
-
|
|
53
|
-
this._length = data[0];
|
|
54
|
-
this._startIndex = data[1];
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
@inline
|
|
58
|
-
public has(index: u64): bool {
|
|
59
|
-
return index < this._length;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/** Get an element by its global index. */
|
|
63
|
-
@inline
|
|
64
|
-
@operator('[]')
|
|
65
|
-
public get(index: u64): Address {
|
|
66
|
-
if (index >= this._length) {
|
|
67
|
-
throw new Revert('get: index out of range (address array)');
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const physicalIndex = (this._startIndex + index) % this.MAX_LENGTH;
|
|
71
|
-
const slotIndex: u32 = <u32>physicalIndex;
|
|
72
|
-
this.ensureValues(slotIndex);
|
|
73
|
-
|
|
74
|
-
return this._values.get(slotIndex);
|
|
11
|
+
export class StoredAddressArray extends StoredPackedArray<Address> {
|
|
12
|
+
public constructor(pointer: u16, subPointer: Uint8Array, maxLength: u32 = DEFAULT_MAX_LENGTH) {
|
|
13
|
+
super(pointer, subPointer, Address.zero(), maxLength);
|
|
75
14
|
}
|
|
76
15
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
@operator('[]=')
|
|
80
|
-
public set(index: u64, value: Address): void {
|
|
81
|
-
if (index >= this._length) {
|
|
82
|
-
throw new Revert('set: index out of range (address array)');
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const physicalIndex = (this._startIndex + index) % this.MAX_LENGTH;
|
|
86
|
-
const slotIndex: u32 = <u32>physicalIndex;
|
|
87
|
-
this.ensureValues(slotIndex);
|
|
88
|
-
|
|
89
|
-
const currentValue = this._values.get(slotIndex);
|
|
90
|
-
if (currentValue != value) {
|
|
91
|
-
this._values.set(slotIndex, value);
|
|
92
|
-
this._isChanged.add(slotIndex);
|
|
93
|
-
}
|
|
16
|
+
protected getSlotCapacity(): u32 {
|
|
17
|
+
return 1; // 1 x u256 => 32 bytes
|
|
94
18
|
}
|
|
95
19
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
public push(value: Address): void {
|
|
99
|
-
if (this._length >= this.MAX_LENGTH) {
|
|
100
|
-
throw new Revert('push: array reached maximum length (address array)');
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const newLogicalIndex: u64 = this._length;
|
|
104
|
-
const physicalIndex: u64 = (this._startIndex + newLogicalIndex) % this.MAX_LENGTH;
|
|
105
|
-
const slotIndex: u32 = <u32>physicalIndex;
|
|
106
|
-
|
|
107
|
-
this.ensureValues(slotIndex);
|
|
108
|
-
this._values.set(slotIndex, value);
|
|
109
|
-
this._isChanged.add(slotIndex);
|
|
110
|
-
|
|
111
|
-
this._length += 1;
|
|
112
|
-
this._isChangedLength = true;
|
|
20
|
+
protected zeroValue(): Address {
|
|
21
|
+
return Address.zero();
|
|
113
22
|
}
|
|
114
23
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (this._length === 0) {
|
|
118
|
-
throw new Revert('deleteLast: array is empty (address array)');
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const lastLogicalIndex: u64 = this._length - 1;
|
|
122
|
-
const physicalIndex: u64 = (this._startIndex + lastLogicalIndex) % this.MAX_LENGTH;
|
|
123
|
-
const slotIndex: u32 = <u32>physicalIndex;
|
|
124
|
-
this.ensureValues(slotIndex);
|
|
125
|
-
|
|
126
|
-
const currentValue = this._values.get(slotIndex);
|
|
127
|
-
if (currentValue != this.defaultValue) {
|
|
128
|
-
this._values.set(slotIndex, this.defaultValue);
|
|
129
|
-
this._isChanged.add(slotIndex);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
this._length -= 1;
|
|
133
|
-
this._isChangedLength = true;
|
|
24
|
+
protected eq(a: Address, b: Address): bool {
|
|
25
|
+
return a == b;
|
|
134
26
|
}
|
|
135
27
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
this._startIndex = index;
|
|
139
|
-
this._isChangedStartIndex = true;
|
|
28
|
+
protected packSlot(values: Address[]): Uint8Array {
|
|
29
|
+
return values[0];
|
|
140
30
|
}
|
|
141
31
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
public delete(index: u64): void {
|
|
145
|
-
if (index > this.MAX_LENGTH) {
|
|
146
|
-
throw new Revert('delete: index out of range (address array)');
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const physicalIndex: u64 = (this._startIndex + index) % this.MAX_LENGTH;
|
|
150
|
-
const slotIndex: u32 = <u32>physicalIndex;
|
|
151
|
-
this.ensureValues(slotIndex);
|
|
152
|
-
|
|
153
|
-
const currentValue = this._values.get(slotIndex);
|
|
154
|
-
if (currentValue != this.defaultValue) {
|
|
155
|
-
this._values.set(slotIndex, this.defaultValue);
|
|
156
|
-
this._isChanged.add(slotIndex);
|
|
157
|
-
}
|
|
32
|
+
protected unpackSlot(slotData: Uint8Array): Address[] {
|
|
33
|
+
return [Address.fromUint8Array(slotData)];
|
|
158
34
|
}
|
|
159
35
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
* - Store any changed slotIndex -> Address
|
|
163
|
-
* - Store updated length and startIndex if changed
|
|
164
|
-
*/
|
|
165
|
-
@inline
|
|
166
|
-
public save(): void {
|
|
167
|
-
// 1) Save changed slots
|
|
168
|
-
const changed = this._isChanged.values();
|
|
169
|
-
for (let i = 0; i < changed.length; i++) {
|
|
170
|
-
const slotIndex = changed[i];
|
|
171
|
-
const storagePointer = this.calculateStoragePointer(slotIndex);
|
|
172
|
-
|
|
173
|
-
const value = this._values.get(slotIndex);
|
|
174
|
-
Blockchain.setStorageAt(storagePointer, value);
|
|
175
|
-
}
|
|
176
|
-
this._isChanged.clear();
|
|
177
|
-
|
|
178
|
-
// 2) Save length and startIndex if changed
|
|
179
|
-
if (this._isChangedLength || this._isChangedStartIndex) {
|
|
180
|
-
const writer = new BytesWriter(16);
|
|
181
|
-
writer.writeU64(this._length);
|
|
182
|
-
writer.writeU64(this._startIndex);
|
|
183
|
-
|
|
184
|
-
Blockchain.setStorageAt(this.lengthPointer, writer.getBuffer());
|
|
185
|
-
this._isChangedLength = false;
|
|
186
|
-
this._isChangedStartIndex = false;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/** Clear entire array content from storage, reset length and startIndex. */
|
|
191
|
-
public deleteAll(): void {
|
|
192
|
-
const keys = this._values.keys();
|
|
193
|
-
for (let i = 0; i < keys.length; i++) {
|
|
194
|
-
const slotIndex = keys[i];
|
|
195
|
-
const storagePointer = this.calculateStoragePointer(slotIndex);
|
|
196
|
-
Blockchain.setStorageAt(storagePointer, this.defaultValue);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
Blockchain.setStorageAt(this.lengthPointer, new Uint8Array(32));
|
|
200
|
-
|
|
201
|
-
this._length = 0;
|
|
202
|
-
this._startIndex = 0;
|
|
203
|
-
this._isChangedLength = false;
|
|
204
|
-
this._isChangedStartIndex = false;
|
|
205
|
-
|
|
206
|
-
this._values.clear();
|
|
207
|
-
this._isChanged.clear();
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/** Bulk-set multiple addresses starting at `startIndex`. */
|
|
211
|
-
@inline
|
|
212
|
-
public setMultiple(startIndex: u32, values: Address[]): void {
|
|
213
|
-
for (let i: u32 = 0; i < values.length; i++) {
|
|
214
|
-
this.set(<u64>(startIndex + i), values[i]);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/** Retrieve a batch of addresses (range). */
|
|
219
|
-
@inline
|
|
220
|
-
public getAll(startIndex: u32, count: u32): Address[] {
|
|
221
|
-
if (startIndex + count > this._length) {
|
|
222
|
-
throw new Revert('getAll: index out of range (address array)');
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const result = new Array<Address>(count);
|
|
226
|
-
for (let i: u32 = 0; i < count; i++) {
|
|
227
|
-
result[i] = this.get(<u64>(startIndex + i));
|
|
228
|
-
}
|
|
229
|
-
return result;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/** Returns a string of the form "[addr0, addr1, ...]". */
|
|
233
|
-
@inline
|
|
234
|
-
public toString(): string {
|
|
235
|
-
let str = '[';
|
|
236
|
-
for (let i: u32 = 0; i < this._length; i++) {
|
|
237
|
-
const value = this.get(<u64>i);
|
|
238
|
-
str += value.toString();
|
|
239
|
-
if (i !== this._length - 1) {
|
|
240
|
-
str += ', ';
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
str += ']';
|
|
244
|
-
return str;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/** Reset in-memory and persist. */
|
|
248
|
-
@inline
|
|
249
|
-
public reset(): void {
|
|
250
|
-
this._length = 0;
|
|
251
|
-
this._startIndex = 0;
|
|
252
|
-
this._isChangedLength = true;
|
|
253
|
-
this._isChangedStartIndex = true;
|
|
254
|
-
|
|
255
|
-
this._values.clear();
|
|
256
|
-
this._isChanged.clear();
|
|
257
|
-
|
|
258
|
-
this.save();
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/** Current array length. */
|
|
262
|
-
@inline
|
|
263
|
-
public getLength(): u64 {
|
|
264
|
-
return this._length;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/** Current starting index. */
|
|
268
|
-
public startingIndex(): u64 {
|
|
269
|
-
return this._startIndex;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* Ensure the given slot index is loaded into `_values`.
|
|
274
|
-
*/
|
|
275
|
-
private ensureValues(slotIndex: u32): void {
|
|
276
|
-
if (!this._values.has(slotIndex)) {
|
|
277
|
-
const storagePointer = this.calculateStoragePointer(slotIndex);
|
|
278
|
-
|
|
279
|
-
// Load raw bytes from storage
|
|
280
|
-
const stored: Uint8Array = Blockchain.getStorageAt(storagePointer);
|
|
281
|
-
|
|
282
|
-
const storedAddress: Address =
|
|
283
|
-
stored.length == 0 ? this.defaultValue : Address.fromUint8Array(stored);
|
|
284
|
-
|
|
285
|
-
this._values.set(slotIndex, storedAddress);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* Compute a 32-byte storage pointer = basePointer + (slotIndex + 1) big-endian.
|
|
291
|
-
*/
|
|
292
|
-
private calculateStoragePointer(slotIndex: u64): Uint8Array {
|
|
293
|
-
// Convert (slotIndex) to a 32-byte big-endian offset
|
|
294
|
-
const offset = u64ToBE32Bytes(slotIndex);
|
|
295
|
-
|
|
296
|
-
return addUint8ArraysBE(this.baseU256Pointer, offset);
|
|
36
|
+
protected calculateStoragePointer(slotIndex: u64): Uint8Array {
|
|
37
|
+
return bigEndianAdd(this.basePointer, slotIndex);
|
|
297
38
|
}
|
|
298
39
|
}
|