@btc-vision/btc-runtime 1.6.1 → 1.6.2
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/env/Atomic.ts +51 -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
package/package.json
CHANGED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// @ts-ignore
|
|
2
|
+
@external('env', '__atomic_wait32')
|
|
3
|
+
declare function __atomic_wait32(addr: i32, expected: i32, timeout: i64, proof: ArrayBuffer, verifier: ArrayBuffer): i32;
|
|
4
|
+
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
@external('env', '__atomic_wait64')
|
|
7
|
+
declare function __atomic_wait64(addr: i32, expected: i64, timeout: i64, proof: ArrayBuffer, verifier: ArrayBuffer): i32;
|
|
8
|
+
|
|
9
|
+
// @ts-ignore
|
|
10
|
+
@external('env', '__atomic_notify')
|
|
11
|
+
declare function __atomic_notify(addr: i32, count: i32): i32;
|
|
12
|
+
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
@external('env', '__thread_spawn')
|
|
15
|
+
declare function __thread_spawn(): i32;
|
|
16
|
+
|
|
17
|
+
export namespace Atomics {
|
|
18
|
+
export const OK: i32 = 0;
|
|
19
|
+
export const TIMED_OUT: i32 = 1;
|
|
20
|
+
export const NOT_EQUAL: i32 = 2;
|
|
21
|
+
export const NOT_AUTHORIZED: i32 = 3;
|
|
22
|
+
export const FAULT: i32 = -1;
|
|
23
|
+
|
|
24
|
+
/** Waits on `addr` until its value != `expected` or timeout (ns). */
|
|
25
|
+
export function wait32(addr: usize, expected: i32, timeoutNs: i64, proof: Uint8Array, verifier: Uint8Array): i32 {
|
|
26
|
+
WARNING('EXPERIMENTAL: wait32 is not yet stable and may change in the future. This feature is not available in production.');
|
|
27
|
+
|
|
28
|
+
return __atomic_wait32(<i32>addr, expected, timeoutNs, proof.buffer, verifier.buffer);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Waits on `addr` until its value != `expected` or timeout (ns). */
|
|
32
|
+
export function wait64(addr: usize, expected: i64, timeoutNs: i64, proof: Uint8Array, verifier: Uint8Array): i32 {
|
|
33
|
+
WARNING('EXPERIMENTAL: wait64 is not yet stable and may change in the future. This feature is not available in production.');
|
|
34
|
+
|
|
35
|
+
return __atomic_wait64(<i32>addr, expected, timeoutNs, proof.buffer, verifier.buffer);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Wakes up at most `count` waiters. */
|
|
39
|
+
export function notify(addr: usize, count: i32 = 1): i32 {
|
|
40
|
+
WARNING('EXPERIMENTAL: notify is not yet stable and may change in the future. This feature is not available in production.');
|
|
41
|
+
|
|
42
|
+
return __atomic_notify(<i32>addr, count);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Spawns a helper thread. */
|
|
46
|
+
export function spawn(): i32 {
|
|
47
|
+
WARNING('EXPERIMENTAL: spawn is not yet stable and may change in the future. This feature is not available in production.');
|
|
48
|
+
|
|
49
|
+
return __thread_spawn();
|
|
50
|
+
}
|
|
51
|
+
}
|
package/runtime/env/global.ts
CHANGED
package/runtime/index.ts
CHANGED
|
@@ -61,10 +61,15 @@ export * from './nested/codecs/VariableBytesCodec';
|
|
|
61
61
|
/** Storage */
|
|
62
62
|
export * from './storage/StoredU256';
|
|
63
63
|
export * from './storage/StoredU64';
|
|
64
|
+
export * from './storage/StoredU32';
|
|
64
65
|
export * from './storage/StoredString';
|
|
66
|
+
export * from './storage/AdvancedStoredString';
|
|
65
67
|
export * from './storage/StoredAddress';
|
|
66
68
|
export * from './storage/StoredBoolean';
|
|
67
69
|
|
|
70
|
+
/** Maps */
|
|
71
|
+
export * from './storage/maps/StoredMapU256';
|
|
72
|
+
|
|
68
73
|
/** Arrays */
|
|
69
74
|
export * from './storage/arrays/StoredAddressArray';
|
|
70
75
|
export * from './storage/arrays/StoredBooleanArray';
|
package/runtime/math/bytes.ts
CHANGED
|
@@ -133,14 +133,14 @@ export function setBit(buffer: Uint8Array, bitIndex: u16, bitValue: bool): void
|
|
|
133
133
|
* Assume the data is at least 16 bytes, read two u64s from it in big-endian order.
|
|
134
134
|
*/
|
|
135
135
|
@inline
|
|
136
|
-
export function readLengthAndStartIndex(data: Uint8Array):
|
|
136
|
+
export function readLengthAndStartIndex(data: Uint8Array): u32[] {
|
|
137
137
|
if (data.length < 16) {
|
|
138
138
|
return [0, 0];
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
const reader = new BytesReader(data);
|
|
142
|
-
const length = reader.
|
|
143
|
-
const startIndex = reader.
|
|
142
|
+
const length = reader.readU32();
|
|
143
|
+
const startIndex = reader.readU32();
|
|
144
144
|
|
|
145
145
|
return [length, startIndex];
|
|
146
146
|
}
|
|
@@ -149,10 +149,10 @@ export function readLengthAndStartIndex(data: Uint8Array): u64[] {
|
|
|
149
149
|
* Write two u64s into a 32-byte buffer in big-endian order
|
|
150
150
|
*/
|
|
151
151
|
@inline
|
|
152
|
-
export function writeLengthAndStartIndex(length:
|
|
152
|
+
export function writeLengthAndStartIndex(length: u32, startIndex: u32): Uint8Array {
|
|
153
153
|
const writer = new BytesWriter(32);
|
|
154
|
-
writer.
|
|
155
|
-
writer.
|
|
154
|
+
writer.writeU32(length);
|
|
155
|
+
writer.writeU32(startIndex);
|
|
156
156
|
|
|
157
157
|
return writer.getBuffer();
|
|
158
158
|
}
|
|
@@ -174,4 +174,4 @@ export function bigEndianAdd(base: Uint8Array, increment: u64): Uint8Array {
|
|
|
174
174
|
const add = u64ToBE32Bytes(increment);
|
|
175
175
|
|
|
176
176
|
return addUint8ArraysBE(base, add);
|
|
177
|
-
}
|
|
177
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { Blockchain } from '../env';
|
|
2
|
+
import { encodePointer } from '../math/abi';
|
|
3
|
+
import { bigEndianAdd } from '../math/bytes';
|
|
4
|
+
import { Revert } from '../types/Revert';
|
|
5
|
+
|
|
6
|
+
const MAX_LENGTH: u32 = 256;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @class AdvancedStoredString
|
|
10
|
+
* @description
|
|
11
|
+
* Stores a string in a sequence of 32-byte storage slots, in UTF-8 format:
|
|
12
|
+
* - Slot 0: first 4 bytes = length (big-endian), next 28 bytes = partial data
|
|
13
|
+
* - Slot N>0: 32 bytes of data each
|
|
14
|
+
*
|
|
15
|
+
* The maximum is 65,535 bytes in UTF-8 form (not necessarily the same as code points).
|
|
16
|
+
*/
|
|
17
|
+
@final
|
|
18
|
+
export class AdvancedStoredString {
|
|
19
|
+
constructor(
|
|
20
|
+
public pointer: u16,
|
|
21
|
+
private readonly subPointer: Uint8Array,
|
|
22
|
+
) {}
|
|
23
|
+
|
|
24
|
+
private _value: string = '';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Cached string value. If `_value` is empty, we call `load()` on first access.
|
|
28
|
+
*/
|
|
29
|
+
public get value(): string {
|
|
30
|
+
if (!this._value) {
|
|
31
|
+
this.load();
|
|
32
|
+
}
|
|
33
|
+
return this._value;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public set value(v: string) {
|
|
37
|
+
this._value = v;
|
|
38
|
+
|
|
39
|
+
this.save();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Derives a 32-byte pointer for the given chunkIndex and performs big-endian addition.
|
|
44
|
+
* chunkIndex=0 => header slot, 1 => second slot, etc.
|
|
45
|
+
*/
|
|
46
|
+
private getPointer(chunkIndex: u64): Uint8Array {
|
|
47
|
+
const base = encodePointer(this.pointer, this.subPointer);
|
|
48
|
+
return bigEndianAdd(base, chunkIndex);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Reads the first slot and returns the stored byte length (big-endian).
|
|
53
|
+
* Returns 0 if the slot is all zero.
|
|
54
|
+
*/
|
|
55
|
+
private getStoredLength(): u32 {
|
|
56
|
+
const headerSlot = Blockchain.getStorageAt(this.getPointer(0));
|
|
57
|
+
const b0 = <u32>headerSlot[0];
|
|
58
|
+
const b1 = <u32>headerSlot[1];
|
|
59
|
+
const b2 = <u32>headerSlot[2];
|
|
60
|
+
const b3 = <u32>headerSlot[3];
|
|
61
|
+
return (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Clears old data from storage. Based on `oldLength`, determines how many slots
|
|
66
|
+
* were used, and writes zeroed 32-byte arrays to each.
|
|
67
|
+
*/
|
|
68
|
+
private clearOldStorage(oldLength: u32): void {
|
|
69
|
+
if (oldLength == 0) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// We always use at least 1 slot (the header slot).
|
|
74
|
+
let chunkCount: u64 = 1;
|
|
75
|
+
|
|
76
|
+
// In the header slot, we can store up to 28 bytes of data.
|
|
77
|
+
const remaining = oldLength > 28 ? oldLength - 28 : 0;
|
|
78
|
+
if (remaining > 0) {
|
|
79
|
+
// Each additional chunk is 32 bytes.
|
|
80
|
+
// Use integer math ceiling: (remaining + 32 - 1) / 32
|
|
81
|
+
chunkCount += (remaining + 32 - 1) / 32;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Zero out each previously used slot
|
|
85
|
+
for (let i: u64 = 0; i < chunkCount; i++) {
|
|
86
|
+
Blockchain.setStorageAt(this.getPointer(i), new Uint8Array(32));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Saves the current string to storage in UTF-8 form.
|
|
92
|
+
*/
|
|
93
|
+
private save(): void {
|
|
94
|
+
// 1) Clear old data
|
|
95
|
+
const oldLen = this.getStoredLength();
|
|
96
|
+
this.clearOldStorage(oldLen);
|
|
97
|
+
|
|
98
|
+
// 2) Encode new string as UTF-8
|
|
99
|
+
const utf8Data = String.UTF8.encode(this._value, false);
|
|
100
|
+
const length = <u32>utf8Data.byteLength;
|
|
101
|
+
|
|
102
|
+
// Enforce max length
|
|
103
|
+
if (length > MAX_LENGTH) {
|
|
104
|
+
throw new Revert(`StoredString: value is too long (max=${MAX_LENGTH})`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 3) If new string is empty, just store a zeroed header and return
|
|
108
|
+
if (length == 0) {
|
|
109
|
+
// A zeroed 32-byte array => indicates length=0
|
|
110
|
+
Blockchain.setStorageAt(this.getPointer(0), new Uint8Array(32));
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 4) Write the first slot: length + up to 28 bytes
|
|
115
|
+
let remaining: u32 = length;
|
|
116
|
+
let offset: u32 = 0;
|
|
117
|
+
const firstSlot = new Uint8Array(32);
|
|
118
|
+
firstSlot[0] = <u8>((length >> 24) & 0xff);
|
|
119
|
+
firstSlot[1] = <u8>((length >> 16) & 0xff);
|
|
120
|
+
firstSlot[2] = <u8>((length >> 8) & 0xff);
|
|
121
|
+
firstSlot[3] = <u8>(length & 0xff);
|
|
122
|
+
|
|
123
|
+
const bytes = Uint8Array.wrap(utf8Data);
|
|
124
|
+
const firstChunkSize = remaining < 28 ? remaining : 28;
|
|
125
|
+
for (let i: u32 = 0; i < firstChunkSize; i++) {
|
|
126
|
+
firstSlot[4 + i] = bytes[i];
|
|
127
|
+
}
|
|
128
|
+
Blockchain.setStorageAt(this.getPointer(0), firstSlot);
|
|
129
|
+
|
|
130
|
+
remaining -= firstChunkSize;
|
|
131
|
+
offset += firstChunkSize;
|
|
132
|
+
|
|
133
|
+
// 5) Write subsequent slots (32 bytes each)
|
|
134
|
+
let chunkIndex: u64 = 1;
|
|
135
|
+
while (remaining > 0) {
|
|
136
|
+
const slotData = new Uint8Array(32);
|
|
137
|
+
const chunkSize = remaining < u32(32) ? remaining : u32(32);
|
|
138
|
+
for (let i: u32 = 0; i < chunkSize; i++) {
|
|
139
|
+
slotData[i] = bytes[offset + i];
|
|
140
|
+
}
|
|
141
|
+
Blockchain.setStorageAt(this.getPointer(chunkIndex), slotData);
|
|
142
|
+
|
|
143
|
+
remaining -= chunkSize;
|
|
144
|
+
offset += chunkSize;
|
|
145
|
+
chunkIndex++;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Loads the string from storage by reading the stored byte length, then decoding
|
|
151
|
+
* the corresponding UTF-8 data from the slots.
|
|
152
|
+
*/
|
|
153
|
+
private load(): void {
|
|
154
|
+
// Read the header slot first
|
|
155
|
+
const headerSlot = Blockchain.getStorageAt(this.getPointer(0));
|
|
156
|
+
|
|
157
|
+
// Parse the big-endian length
|
|
158
|
+
const b0 = <u32>headerSlot[0];
|
|
159
|
+
const b1 = <u32>headerSlot[1];
|
|
160
|
+
const b2 = <u32>headerSlot[2];
|
|
161
|
+
const b3 = <u32>headerSlot[3];
|
|
162
|
+
const length: u32 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
|
|
163
|
+
|
|
164
|
+
// If length=0, then the string is empty
|
|
165
|
+
if (length == 0) {
|
|
166
|
+
this._value = '';
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Read the UTF-8 bytes from storage
|
|
171
|
+
let remaining: u32 = length;
|
|
172
|
+
let offset: u32 = 0;
|
|
173
|
+
const out = new Uint8Array(length);
|
|
174
|
+
|
|
175
|
+
// First slot can hold up to 28 bytes after the length
|
|
176
|
+
const firstChunkSize = remaining < 28 ? remaining : 28;
|
|
177
|
+
for (let i: u32 = 0; i < firstChunkSize; i++) {
|
|
178
|
+
out[i] = headerSlot[4 + i];
|
|
179
|
+
}
|
|
180
|
+
remaining -= firstChunkSize;
|
|
181
|
+
offset += firstChunkSize;
|
|
182
|
+
|
|
183
|
+
// Read the subsequent slots of 32 bytes each
|
|
184
|
+
let chunkIndex: u64 = 1;
|
|
185
|
+
while (remaining > 0) {
|
|
186
|
+
const slotData = Blockchain.getStorageAt(this.getPointer(chunkIndex));
|
|
187
|
+
const chunkSize = remaining < 32 ? remaining : 32;
|
|
188
|
+
for (let i: u32 = 0; i < chunkSize; i++) {
|
|
189
|
+
out[offset + i] = slotData[i];
|
|
190
|
+
}
|
|
191
|
+
remaining -= chunkSize;
|
|
192
|
+
offset += chunkSize;
|
|
193
|
+
chunkIndex++;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Decode UTF-8 into a normal string
|
|
197
|
+
this._value = String.UTF8.decode(out.buffer, false);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
@@ -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
|
+
}
|