@btc-vision/btc-runtime 1.4.6 → 1.5.0
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 +44 -53
- package/runtime/abort/abort.ts +25 -0
- package/runtime/buffer/BytesReader.ts +171 -140
- package/runtime/buffer/BytesWriter.ts +120 -152
- package/runtime/contracts/DeployableOP_20.ts +29 -15
- package/runtime/contracts/OP_NET.ts +1 -1
- package/runtime/env/BlockchainEnvironment.ts +79 -137
- package/runtime/env/classes/Block.ts +4 -8
- package/runtime/env/classes/Transaction.ts +14 -7
- package/runtime/env/classes/UTXO.ts +4 -2
- package/runtime/env/global.ts +49 -20
- package/runtime/events/predefined/MintEvent.ts +1 -1
- package/runtime/exports/index.ts +29 -8
- package/runtime/generic/AddressMap.ts +7 -5
- package/runtime/generic/Map.ts +32 -2
- package/runtime/generic/MapU256.ts +7 -5
- package/runtime/generic/MapUint8Array.ts +93 -0
- package/runtime/index.ts +4 -12
- package/runtime/math/abi.ts +71 -11
- package/runtime/math/bytes.ts +177 -41
- package/runtime/memory/AddressMemoryMap.ts +22 -19
- package/runtime/memory/FastUint8Array.ts +122 -0
- package/runtime/memory/KeyMerger.ts +25 -23
- package/runtime/memory/MultiAddressMemoryMap.ts +11 -8
- package/runtime/memory/MultiStringMemoryMap.ts +8 -5
- package/runtime/memory/StringMemoryMap.ts +15 -15
- package/runtime/memory/Uint8ArrayMerger.ts +22 -15
- package/runtime/storage/Serializable.ts +19 -20
- package/runtime/storage/StoredAddress.ts +16 -15
- package/runtime/storage/StoredBoolean.ts +26 -21
- package/runtime/storage/StoredString.ts +158 -102
- package/runtime/storage/StoredU256.ts +25 -28
- package/runtime/storage/StoredU64.ts +23 -35
- package/runtime/storage/arrays/StoredAddressArray.ts +88 -179
- package/runtime/storage/arrays/StoredBooleanArray.ts +150 -272
- package/runtime/storage/arrays/StoredPackedArray.ts +313 -0
- package/runtime/storage/arrays/StoredU128Array.ts +38 -373
- package/runtime/storage/arrays/StoredU16Array.ts +34 -418
- package/runtime/storage/arrays/StoredU256Array.ts +21 -346
- package/runtime/storage/arrays/StoredU32Array.ts +37 -438
- package/runtime/storage/arrays/StoredU64Array.ts +66 -0
- package/runtime/storage/arrays/StoredU8Array.ts +29 -451
- package/runtime/types/Address.ts +72 -5
- package/runtime/types/index.ts +1 -4
- package/runtime/utils/encodings.ts +5 -6
- package/runtime/utils/hex.ts +1 -1
- package/runtime/interfaces/DeployContractResponse.ts +0 -12
- package/runtime/math/cyrb53.ts +0 -48
- package/runtime/math/sha256.ts +0 -12
- package/runtime/memory/MemorySlot.ts +0 -1
- package/runtime/memory/MemorySlotPointer.ts +0 -3
- package/runtime/storage/utils/StorageBacked.ts +0 -5
- package/runtime/storage/utils/StorageLayout.ts +0 -7
- package/runtime/storage/utils/StorageSlot.ts +0 -106
- package/runtime/storage/utils/StorageStruct.ts +0 -23
- package/runtime/storage/utils/StorageValue.ts +0 -36
- package/runtime/tests/assert.ts +0 -11
- package/runtime/tests/env.ts +0 -7
- package/runtime/tests/tests.ts +0 -28
|
@@ -1,51 +1,56 @@
|
|
|
1
|
-
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
2
1
|
import { Blockchain } from '../env';
|
|
2
|
+
import { GET_EMPTY_BUFFER } from '../math/bytes';
|
|
3
|
+
import { Revert } from '../types/Revert';
|
|
3
4
|
|
|
4
5
|
@final
|
|
5
6
|
export class StoredBoolean {
|
|
6
|
-
private readonly
|
|
7
|
+
private readonly pointerBuffer: Uint8Array;
|
|
7
8
|
|
|
8
9
|
constructor(
|
|
9
10
|
public pointer: u16,
|
|
10
|
-
|
|
11
|
+
defaultValue: bool,
|
|
11
12
|
) {
|
|
12
|
-
|
|
13
|
+
const pointerBuffer = GET_EMPTY_BUFFER();
|
|
14
|
+
pointerBuffer[0] = pointer & 255;
|
|
15
|
+
pointerBuffer[1] = (pointer << 8) & 255;
|
|
16
|
+
|
|
17
|
+
this.pointerBuffer = pointerBuffer;
|
|
18
|
+
|
|
19
|
+
const value = GET_EMPTY_BUFFER();
|
|
20
|
+
if (defaultValue) {
|
|
21
|
+
value[0] = 1;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
this._value = value;
|
|
13
25
|
}
|
|
14
26
|
|
|
15
|
-
private _value:
|
|
27
|
+
private _value: Uint8Array;
|
|
16
28
|
|
|
17
29
|
@inline
|
|
18
30
|
public get value(): bool {
|
|
19
31
|
this.ensureValue();
|
|
20
32
|
|
|
21
|
-
return this._value
|
|
33
|
+
return this._value[0] === 1;
|
|
22
34
|
}
|
|
23
35
|
|
|
24
|
-
@inline
|
|
25
36
|
public set value(value: bool) {
|
|
26
|
-
this._value = value ?
|
|
27
|
-
|
|
28
|
-
Blockchain.setStorageAt(this.u256Pointer, this._value);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
@inline
|
|
32
|
-
public set(value: u256): this {
|
|
33
|
-
this._value = value;
|
|
34
|
-
|
|
35
|
-
Blockchain.setStorageAt(this.u256Pointer, this._value);
|
|
37
|
+
this._value[0] = value ? 1 : 0;
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
Blockchain.setStorageAt(this.pointerBuffer, this._value);
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
@inline
|
|
41
43
|
public toUint8Array(): Uint8Array {
|
|
42
|
-
|
|
44
|
+
if (!this._value) {
|
|
45
|
+
throw new Revert(`Not defined.`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return this._value;
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
private ensureValue(): void {
|
|
46
52
|
this._value = Blockchain.getStorageAt(
|
|
47
|
-
this.
|
|
48
|
-
this.defaultValue ? u256.One : u256.Zero,
|
|
53
|
+
this.pointerBuffer,
|
|
49
54
|
);
|
|
50
55
|
}
|
|
51
56
|
}
|
|
@@ -1,148 +1,204 @@
|
|
|
1
|
-
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
2
|
-
import { BytesWriter } from '../buffer/BytesWriter';
|
|
3
1
|
import { Blockchain } from '../env';
|
|
4
2
|
import { encodePointer } from '../math/abi';
|
|
3
|
+
import { bigEndianAdd } from '../math/bytes';
|
|
4
|
+
import { Revert } from '../types/Revert';
|
|
5
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
5
6
|
import { SafeMath } from '../types/SafeMath';
|
|
6
|
-
import { U256_BYTE_LENGTH } from '../utils/lengths';
|
|
7
7
|
|
|
8
|
+
const MAX_LENGTH = <u32>u16.MAX_VALUE;
|
|
9
|
+
const MAX_LENGTH_U256 = u256.fromU32(<u32>MAX_LENGTH);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @class StoredString
|
|
13
|
+
* @description
|
|
14
|
+
* Stores a string in a sequence of 32-byte storage slots, in UTF-8 format:
|
|
15
|
+
* - Slot 0: first 4 bytes = length (big-endian), next 28 bytes = partial data
|
|
16
|
+
* - Slot N>0: 32 bytes of data each
|
|
17
|
+
*
|
|
18
|
+
* The maximum is 65,535 bytes in UTF-8 form (not necessarily the same as code points).
|
|
19
|
+
*/
|
|
8
20
|
@final
|
|
9
21
|
export class StoredString {
|
|
10
|
-
|
|
22
|
+
private readonly subPointer: Uint8Array;
|
|
23
|
+
|
|
24
|
+
constructor(public pointer: u16, index: u64 = 0) {
|
|
25
|
+
const indexed = SafeMath.mul(u256.fromU64(index), MAX_LENGTH_U256);
|
|
26
|
+
this.subPointer = indexed.toUint8Array(true).slice(0, 30);
|
|
27
|
+
}
|
|
11
28
|
|
|
12
29
|
private _value: string = '';
|
|
13
30
|
|
|
14
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Cached string value. If `_value` is empty, we call `load()` on first access.
|
|
33
|
+
*/
|
|
15
34
|
public get value(): string {
|
|
16
35
|
if (!this._value) {
|
|
17
36
|
this.load();
|
|
18
37
|
}
|
|
19
|
-
|
|
20
38
|
return this._value;
|
|
21
39
|
}
|
|
22
40
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
41
|
+
public set value(v: string) {
|
|
42
|
+
this._value = v;
|
|
43
|
+
|
|
26
44
|
this.save();
|
|
27
45
|
}
|
|
28
46
|
|
|
29
|
-
|
|
30
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Derives a 32-byte pointer for the given chunkIndex and performs big-endian addition.
|
|
49
|
+
* chunkIndex=0 => header slot, 1 => second slot, etc.
|
|
50
|
+
*/
|
|
51
|
+
private getPointer(chunkIndex: u64): Uint8Array {
|
|
52
|
+
const base = encodePointer(this.pointer, this.subPointer);
|
|
53
|
+
return bigEndianAdd(base, chunkIndex);
|
|
31
54
|
}
|
|
32
55
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Reads the first slot and returns the stored byte length (big-endian).
|
|
58
|
+
* Returns 0 if the slot is all zero.
|
|
59
|
+
*/
|
|
60
|
+
private getStoredLength(): u32 {
|
|
61
|
+
const headerSlot = Blockchain.getStorageAt(this.getPointer(0));
|
|
62
|
+
const b0 = <u32>headerSlot[0];
|
|
63
|
+
const b1 = <u32>headerSlot[1];
|
|
64
|
+
const b2 = <u32>headerSlot[2];
|
|
65
|
+
const b3 = <u32>headerSlot[3];
|
|
66
|
+
return (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
|
|
38
67
|
}
|
|
39
68
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
69
|
+
/**
|
|
70
|
+
* Clears old data from storage. Based on `oldLength`, determines how many slots
|
|
71
|
+
* were used, and writes zeroed 32-byte arrays to each.
|
|
72
|
+
*/
|
|
73
|
+
private clearOldStorage(oldLength: u32): void {
|
|
74
|
+
if (oldLength == 0) {
|
|
43
75
|
return;
|
|
44
76
|
}
|
|
45
77
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Prepare the header with the length of the string in the first 4 bytes
|
|
51
|
-
let header: u256 = u256.fromU32(length);
|
|
52
|
-
header = SafeMath.shl(header, 224);
|
|
78
|
+
// We always use at least 1 slot (the header slot).
|
|
79
|
+
let chunkCount: u64 = 1;
|
|
53
80
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
header = this.saveChunk(header, this._value, offset, bytesToWrite, 4);
|
|
61
|
-
Blockchain.setStorageAt(this.getPointer(currentPointer), header);
|
|
62
|
-
|
|
63
|
-
remainingLength -= bytesToWrite;
|
|
64
|
-
offset += bytesToWrite;
|
|
65
|
-
|
|
66
|
-
// Save the remaining chunks in subsequent storage slots
|
|
67
|
-
while (remainingLength > 0) {
|
|
68
|
-
bytesToWrite = this.min(remainingLength, 32);
|
|
69
|
-
const storageValue: u256 = this.saveChunk(
|
|
70
|
-
u256.Zero,
|
|
71
|
-
this._value,
|
|
72
|
-
offset,
|
|
73
|
-
bytesToWrite,
|
|
74
|
-
0,
|
|
75
|
-
);
|
|
76
|
-
currentPointer = u256.add(currentPointer, u256.One);
|
|
77
|
-
Blockchain.setStorageAt(this.getPointer(currentPointer), storageValue);
|
|
78
|
-
|
|
79
|
-
remainingLength -= bytesToWrite;
|
|
80
|
-
offset += bytesToWrite;
|
|
81
|
+
// In the header slot, we can store up to 28 bytes of data.
|
|
82
|
+
const remaining = oldLength > 28 ? oldLength - 28 : 0;
|
|
83
|
+
if (remaining > 0) {
|
|
84
|
+
// Each additional chunk is 32 bytes.
|
|
85
|
+
// Use integer math ceiling: (remaining + 32 - 1) / 32
|
|
86
|
+
chunkCount += (remaining + 32 - 1) / 32;
|
|
81
87
|
}
|
|
82
|
-
}
|
|
83
88
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
value: string,
|
|
88
|
-
offset: u32,
|
|
89
|
-
length: u32,
|
|
90
|
-
storageOffset: u32,
|
|
91
|
-
): u256 {
|
|
92
|
-
const bytes = storage.toBytes(true);
|
|
93
|
-
for (let i: u32 = 0; i < length; i++) {
|
|
94
|
-
const index: i32 = i32(offset + i);
|
|
95
|
-
bytes[i + storageOffset] = u8(value.charCodeAt(index));
|
|
89
|
+
// Zero out each previously used slot
|
|
90
|
+
for (let i: u64 = 0; i < chunkCount; i++) {
|
|
91
|
+
Blockchain.setStorageAt(this.getPointer(i), new Uint8Array(32));
|
|
96
92
|
}
|
|
97
|
-
return u256.fromBytes(bytes, true);
|
|
98
93
|
}
|
|
99
94
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Saves the current string to storage in UTF-8 form.
|
|
97
|
+
*/
|
|
98
|
+
private save(): void {
|
|
99
|
+
// 1) Clear old data
|
|
100
|
+
const oldLen = this.getStoredLength();
|
|
101
|
+
this.clearOldStorage(oldLen);
|
|
106
102
|
|
|
107
|
-
|
|
103
|
+
// 2) Encode new string as UTF-8
|
|
104
|
+
const utf8Data = String.UTF8.encode(this._value, false);
|
|
105
|
+
const length = <u32>utf8Data.byteLength;
|
|
106
|
+
|
|
107
|
+
// Enforce max length
|
|
108
|
+
if (length > MAX_LENGTH) {
|
|
109
|
+
throw new Revert(`StoredString: value is too long (max=${MAX_LENGTH})`);
|
|
108
110
|
}
|
|
109
111
|
|
|
110
|
-
//
|
|
111
|
-
|
|
112
|
-
|
|
112
|
+
// 3) If new string is empty, just store a zeroed header and return
|
|
113
|
+
if (length == 0) {
|
|
114
|
+
// A zeroed 32-byte array => indicates length=0
|
|
115
|
+
Blockchain.setStorageAt(this.getPointer(0), new Uint8Array(32));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
113
118
|
|
|
114
|
-
// the
|
|
115
|
-
let
|
|
116
|
-
let
|
|
117
|
-
|
|
119
|
+
// 4) Write the first slot: length + up to 28 bytes
|
|
120
|
+
let remaining: u32 = length;
|
|
121
|
+
let offset: u32 = 0;
|
|
122
|
+
const firstSlot = new Uint8Array(32);
|
|
123
|
+
firstSlot[0] = <u8>((length >> 24) & 0xff);
|
|
124
|
+
firstSlot[1] = <u8>((length >> 16) & 0xff);
|
|
125
|
+
firstSlot[2] = <u8>((length >> 8) & 0xff);
|
|
126
|
+
firstSlot[3] = <u8>(length & 0xff);
|
|
127
|
+
|
|
128
|
+
const bytes = Uint8Array.wrap(utf8Data);
|
|
129
|
+
const firstChunkSize = remaining < 28 ? remaining : 28;
|
|
130
|
+
for (let i: u32 = 0; i < firstChunkSize; i++) {
|
|
131
|
+
firstSlot[4 + i] = bytes[i];
|
|
132
|
+
}
|
|
133
|
+
Blockchain.setStorageAt(this.getPointer(0), firstSlot);
|
|
134
|
+
|
|
135
|
+
remaining -= firstChunkSize;
|
|
136
|
+
offset += firstChunkSize;
|
|
137
|
+
|
|
138
|
+
// 5) Write subsequent slots (32 bytes each)
|
|
139
|
+
let chunkIndex: u64 = 1;
|
|
140
|
+
while (remaining > 0) {
|
|
141
|
+
const slotData = new Uint8Array(32);
|
|
142
|
+
const chunkSize = remaining < u32(32) ? remaining : u32(32);
|
|
143
|
+
for (let i: u32 = 0; i < chunkSize; i++) {
|
|
144
|
+
slotData[i] = bytes[offset + i];
|
|
145
|
+
}
|
|
146
|
+
Blockchain.setStorageAt(this.getPointer(chunkIndex), slotData);
|
|
118
147
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
148
|
+
remaining -= chunkSize;
|
|
149
|
+
offset += chunkSize;
|
|
150
|
+
chunkIndex++;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
122
153
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
154
|
+
/**
|
|
155
|
+
* Loads the string from storage by reading the stored byte length, then decoding
|
|
156
|
+
* the corresponding UTF-8 data from the slots.
|
|
157
|
+
*/
|
|
158
|
+
private load(): void {
|
|
159
|
+
// Read the header slot first
|
|
160
|
+
const headerSlot = Blockchain.getStorageAt(this.getPointer(0));
|
|
127
161
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
162
|
+
// Parse the big-endian length
|
|
163
|
+
const b0 = <u32>headerSlot[0];
|
|
164
|
+
const b1 = <u32>headerSlot[1];
|
|
165
|
+
const b2 = <u32>headerSlot[2];
|
|
166
|
+
const b3 = <u32>headerSlot[3];
|
|
167
|
+
const length: u32 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
|
|
131
168
|
|
|
132
|
-
|
|
169
|
+
// If length=0, then the string is empty
|
|
170
|
+
if (length == 0) {
|
|
171
|
+
this._value = '';
|
|
172
|
+
return;
|
|
133
173
|
}
|
|
134
174
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const bytes = value.toBytes(true);
|
|
175
|
+
// Read the UTF-8 bytes from storage
|
|
176
|
+
let remaining: u32 = length;
|
|
177
|
+
let offset: u32 = 0;
|
|
178
|
+
const out = new Uint8Array(length);
|
|
140
179
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
180
|
+
// First slot can hold up to 28 bytes after the length
|
|
181
|
+
const firstChunkSize = remaining < 28 ? remaining : 28;
|
|
182
|
+
for (let i: u32 = 0; i < firstChunkSize; i++) {
|
|
183
|
+
out[i] = headerSlot[4 + i];
|
|
184
|
+
}
|
|
185
|
+
remaining -= firstChunkSize;
|
|
186
|
+
offset += firstChunkSize;
|
|
187
|
+
|
|
188
|
+
// Read the subsequent slots of 32 bytes each
|
|
189
|
+
let chunkIndex: u64 = 1;
|
|
190
|
+
while (remaining > 0) {
|
|
191
|
+
const slotData = Blockchain.getStorageAt(this.getPointer(chunkIndex));
|
|
192
|
+
const chunkSize = remaining < 32 ? remaining : 32;
|
|
193
|
+
for (let i: u32 = 0; i < chunkSize; i++) {
|
|
194
|
+
out[offset + i] = slotData[i];
|
|
195
|
+
}
|
|
196
|
+
remaining -= chunkSize;
|
|
197
|
+
offset += chunkSize;
|
|
198
|
+
chunkIndex++;
|
|
144
199
|
}
|
|
145
200
|
|
|
146
|
-
|
|
201
|
+
// Decode UTF-8 into a normal string
|
|
202
|
+
this._value = String.UTF8.decode(out.buffer, false);
|
|
147
203
|
}
|
|
148
|
-
}
|
|
204
|
+
}
|
|
@@ -1,36 +1,29 @@
|
|
|
1
1
|
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
2
|
-
import { BytesWriter } from '../buffer/BytesWriter';
|
|
3
2
|
import { Blockchain } from '../env';
|
|
4
3
|
import { encodePointer } from '../math/abi';
|
|
5
|
-
import { MemorySlotPointer } from '../memory/MemorySlotPointer';
|
|
6
4
|
import { SafeMath } from '../types/SafeMath';
|
|
7
|
-
import { U256_BYTE_LENGTH } from '../utils/lengths';
|
|
8
5
|
|
|
9
6
|
@final
|
|
10
7
|
export class StoredU256 {
|
|
11
|
-
private readonly
|
|
8
|
+
private readonly pointerBuffer: Uint8Array;
|
|
12
9
|
|
|
13
10
|
constructor(
|
|
14
11
|
public pointer: u16,
|
|
15
|
-
public subPointer:
|
|
16
|
-
private defaultValue: u256,
|
|
12
|
+
public subPointer: Uint8Array,
|
|
17
13
|
) {
|
|
18
|
-
|
|
19
|
-
writer.writeU256(subPointer);
|
|
14
|
+
assert(subPointer.length <= 30, `You must pass a 30 bytes sub-pointer. (Address, got ${subPointer.length})`);
|
|
20
15
|
|
|
21
|
-
this.
|
|
16
|
+
this.pointerBuffer = encodePointer(pointer, subPointer);
|
|
22
17
|
}
|
|
23
18
|
|
|
24
19
|
private _value: u256 = u256.Zero;
|
|
25
20
|
|
|
26
|
-
@inline
|
|
27
21
|
public get value(): u256 {
|
|
28
22
|
this.ensureValue();
|
|
29
23
|
|
|
30
24
|
return this._value;
|
|
31
25
|
}
|
|
32
26
|
|
|
33
|
-
@inline
|
|
34
27
|
public set value(value: u256) {
|
|
35
28
|
if (u256.eq(value, this._value)) {
|
|
36
29
|
return;
|
|
@@ -38,12 +31,15 @@ export class StoredU256 {
|
|
|
38
31
|
|
|
39
32
|
this._value = value;
|
|
40
33
|
|
|
41
|
-
Blockchain.setStorageAt(this.
|
|
34
|
+
Blockchain.setStorageAt(this.pointerBuffer, this.__value);
|
|
42
35
|
}
|
|
43
36
|
|
|
44
|
-
@inline
|
|
45
37
|
public get toBytes(): Uint8Array {
|
|
46
|
-
return this._value.toUint8Array(
|
|
38
|
+
return this._value.toUint8Array(true);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private get __value(): Uint8Array {
|
|
42
|
+
return this._value.toUint8Array(true);
|
|
47
43
|
}
|
|
48
44
|
|
|
49
45
|
@inline
|
|
@@ -57,7 +53,7 @@ export class StoredU256 {
|
|
|
57
53
|
this.ensureValue();
|
|
58
54
|
|
|
59
55
|
this._value = SafeMath.add(this._value, value);
|
|
60
|
-
Blockchain.setStorageAt(this.
|
|
56
|
+
Blockchain.setStorageAt(this.pointerBuffer, this.__value);
|
|
61
57
|
|
|
62
58
|
return this;
|
|
63
59
|
}
|
|
@@ -78,7 +74,7 @@ export class StoredU256 {
|
|
|
78
74
|
|
|
79
75
|
@inline
|
|
80
76
|
public commit(): this {
|
|
81
|
-
Blockchain.setStorageAt(this.
|
|
77
|
+
Blockchain.setStorageAt(this.pointerBuffer, this.__value);
|
|
82
78
|
|
|
83
79
|
return this;
|
|
84
80
|
}
|
|
@@ -89,7 +85,7 @@ export class StoredU256 {
|
|
|
89
85
|
this.ensureValue();
|
|
90
86
|
|
|
91
87
|
this._value = SafeMath.sub(this._value, value);
|
|
92
|
-
Blockchain.setStorageAt(this.
|
|
88
|
+
Blockchain.setStorageAt(this.pointerBuffer, this.__value);
|
|
93
89
|
|
|
94
90
|
return this;
|
|
95
91
|
}
|
|
@@ -100,7 +96,7 @@ export class StoredU256 {
|
|
|
100
96
|
this.ensureValue();
|
|
101
97
|
|
|
102
98
|
this._value = SafeMath.mul(this._value, value);
|
|
103
|
-
Blockchain.setStorageAt(this.
|
|
99
|
+
Blockchain.setStorageAt(this.pointerBuffer, this.__value);
|
|
104
100
|
|
|
105
101
|
return this;
|
|
106
102
|
}
|
|
@@ -159,7 +155,7 @@ export class StoredU256 {
|
|
|
159
155
|
this.ensureValue();
|
|
160
156
|
|
|
161
157
|
this._value = u256.shr(this._value, value);
|
|
162
|
-
Blockchain.setStorageAt(this.
|
|
158
|
+
Blockchain.setStorageAt(this.pointerBuffer, this.__value);
|
|
163
159
|
|
|
164
160
|
return this;
|
|
165
161
|
}
|
|
@@ -170,7 +166,7 @@ export class StoredU256 {
|
|
|
170
166
|
this.ensureValue();
|
|
171
167
|
|
|
172
168
|
this._value = u256.and(this._value, value);
|
|
173
|
-
Blockchain.setStorageAt(this.
|
|
169
|
+
Blockchain.setStorageAt(this.pointerBuffer, this.__value);
|
|
174
170
|
|
|
175
171
|
return this;
|
|
176
172
|
}
|
|
@@ -181,7 +177,7 @@ export class StoredU256 {
|
|
|
181
177
|
this.ensureValue();
|
|
182
178
|
|
|
183
179
|
this._value = u256.or(this._value, value);
|
|
184
|
-
Blockchain.setStorageAt(this.
|
|
180
|
+
Blockchain.setStorageAt(this.pointerBuffer, this.__value);
|
|
185
181
|
|
|
186
182
|
return this;
|
|
187
183
|
}
|
|
@@ -192,7 +188,7 @@ export class StoredU256 {
|
|
|
192
188
|
this.ensureValue();
|
|
193
189
|
|
|
194
190
|
this._value = u256.xor(this._value, value);
|
|
195
|
-
Blockchain.setStorageAt(this.
|
|
191
|
+
Blockchain.setStorageAt(this.pointerBuffer, this.__value);
|
|
196
192
|
|
|
197
193
|
return this;
|
|
198
194
|
}
|
|
@@ -203,7 +199,7 @@ export class StoredU256 {
|
|
|
203
199
|
this.ensureValue();
|
|
204
200
|
|
|
205
201
|
this._value = SafeMath.pow(this._value, exponent);
|
|
206
|
-
Blockchain.setStorageAt(this.
|
|
202
|
+
Blockchain.setStorageAt(this.pointerBuffer, this.__value);
|
|
207
203
|
|
|
208
204
|
return this;
|
|
209
205
|
}
|
|
@@ -214,7 +210,7 @@ export class StoredU256 {
|
|
|
214
210
|
this.ensureValue();
|
|
215
211
|
|
|
216
212
|
this._value = SafeMath.mod(this._value, value);
|
|
217
|
-
Blockchain.setStorageAt(this.
|
|
213
|
+
Blockchain.setStorageAt(this.pointerBuffer, this.__value);
|
|
218
214
|
|
|
219
215
|
return this;
|
|
220
216
|
}
|
|
@@ -225,7 +221,7 @@ export class StoredU256 {
|
|
|
225
221
|
this.ensureValue();
|
|
226
222
|
|
|
227
223
|
this._value = SafeMath.add(this._value, u256.One);
|
|
228
|
-
Blockchain.setStorageAt(this.
|
|
224
|
+
Blockchain.setStorageAt(this.pointerBuffer, this.__value);
|
|
229
225
|
|
|
230
226
|
return this;
|
|
231
227
|
}
|
|
@@ -236,7 +232,7 @@ export class StoredU256 {
|
|
|
236
232
|
this.ensureValue();
|
|
237
233
|
|
|
238
234
|
this._value = SafeMath.sub(this._value, u256.One);
|
|
239
|
-
Blockchain.setStorageAt(this.
|
|
235
|
+
Blockchain.setStorageAt(this.pointerBuffer, this.__value);
|
|
240
236
|
|
|
241
237
|
return this;
|
|
242
238
|
}
|
|
@@ -245,7 +241,7 @@ export class StoredU256 {
|
|
|
245
241
|
public set(value: u256): this {
|
|
246
242
|
this._value = value;
|
|
247
243
|
|
|
248
|
-
Blockchain.setStorageAt(this.
|
|
244
|
+
Blockchain.setStorageAt(this.pointerBuffer, this.__value);
|
|
249
245
|
|
|
250
246
|
return this;
|
|
251
247
|
}
|
|
@@ -256,6 +252,7 @@ export class StoredU256 {
|
|
|
256
252
|
}
|
|
257
253
|
|
|
258
254
|
private ensureValue(): void {
|
|
259
|
-
|
|
255
|
+
const value = Blockchain.getStorageAt(this.pointerBuffer);
|
|
256
|
+
this._value = u256.fromUint8ArrayBE(value);
|
|
260
257
|
}
|
|
261
258
|
}
|
|
@@ -2,8 +2,7 @@ import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
|
2
2
|
import { BytesWriter } from '../buffer/BytesWriter';
|
|
3
3
|
import { Blockchain } from '../env';
|
|
4
4
|
import { encodePointer } from '../math/abi';
|
|
5
|
-
import {
|
|
6
|
-
import { U256_BYTE_LENGTH } from '../utils/lengths';
|
|
5
|
+
import { BytesReader } from '../buffer/BytesReader';
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* @class StoredU64
|
|
@@ -11,7 +10,7 @@ import { U256_BYTE_LENGTH } from '../utils/lengths';
|
|
|
11
10
|
*/
|
|
12
11
|
@final
|
|
13
12
|
export class StoredU64 {
|
|
14
|
-
private readonly
|
|
13
|
+
private readonly bufferPointer: Uint8Array;
|
|
15
14
|
|
|
16
15
|
// Internal cache for four u64 values: [lo1, lo2, hi1, hi2]
|
|
17
16
|
private _values: u64[] = [0, 0, 0, 0];
|
|
@@ -25,18 +24,15 @@ export class StoredU64 {
|
|
|
25
24
|
/**
|
|
26
25
|
* @constructor
|
|
27
26
|
* @param {u16} pointer - The primary pointer identifier.
|
|
28
|
-
* @param {
|
|
29
|
-
* @param {u256} defaultValue - The default u256 value if storage is uninitialized.
|
|
27
|
+
* @param {Uint8Array} subPointer - The sub-pointer for memory slot addressing.
|
|
30
28
|
*/
|
|
31
29
|
constructor(
|
|
32
30
|
public pointer: u16,
|
|
33
|
-
public subPointer:
|
|
34
|
-
private defaultValue: u256,
|
|
31
|
+
public subPointer: Uint8Array,
|
|
35
32
|
) {
|
|
36
|
-
|
|
37
|
-
writer.writeU256(subPointer);
|
|
33
|
+
assert(subPointer.length <= 30, `You must pass a 30 bytes sub-pointer. (StoredU64, got ${subPointer.length})`);
|
|
38
34
|
|
|
39
|
-
this.
|
|
35
|
+
this.bufferPointer = encodePointer(pointer, subPointer);
|
|
40
36
|
}
|
|
41
37
|
|
|
42
38
|
/**
|
|
@@ -75,7 +71,7 @@ export class StoredU64 {
|
|
|
75
71
|
public save(): void {
|
|
76
72
|
if (this.isChanged) {
|
|
77
73
|
const packed = this.packValues();
|
|
78
|
-
Blockchain.setStorageAt(this.
|
|
74
|
+
Blockchain.setStorageAt(this.bufferPointer, packed);
|
|
79
75
|
this.isChanged = false;
|
|
80
76
|
}
|
|
81
77
|
}
|
|
@@ -122,17 +118,6 @@ export class StoredU64 {
|
|
|
122
118
|
return `[${this._values[0].toString()}, ${this._values[1].toString()}, ${this._values[2].toString()}, ${this._values[3].toString()}]`;
|
|
123
119
|
}
|
|
124
120
|
|
|
125
|
-
/**
|
|
126
|
-
* @method toBytes
|
|
127
|
-
* @description Returns the packed u256 value as a byte array.
|
|
128
|
-
* @returns {Uint8Array} - The packed u256 value in byte form.
|
|
129
|
-
*/
|
|
130
|
-
@inline
|
|
131
|
-
public toBytes(): u8[] {
|
|
132
|
-
this.ensureValues();
|
|
133
|
-
const packed = this.packValues();
|
|
134
|
-
return packed.toBytes();
|
|
135
|
-
}
|
|
136
121
|
|
|
137
122
|
/**
|
|
138
123
|
* @method reset
|
|
@@ -151,13 +136,14 @@ export class StoredU64 {
|
|
|
151
136
|
*/
|
|
152
137
|
private ensureValues(): void {
|
|
153
138
|
if (!this.isLoaded) {
|
|
154
|
-
const storedU256:
|
|
139
|
+
const storedU256: Uint8Array = Blockchain.getStorageAt(this.bufferPointer);
|
|
140
|
+
|
|
141
|
+
const reader = new BytesReader(storedU256);
|
|
155
142
|
|
|
156
|
-
|
|
157
|
-
this._values[
|
|
158
|
-
this._values[
|
|
159
|
-
this._values[
|
|
160
|
-
this._values[3] = storedU256.hi2;
|
|
143
|
+
this._values[0] = reader.readU64();
|
|
144
|
+
this._values[1] = reader.readU64();
|
|
145
|
+
this._values[2] = reader.readU64();
|
|
146
|
+
this._values[3] = reader.readU64();
|
|
161
147
|
|
|
162
148
|
this.isLoaded = true;
|
|
163
149
|
}
|
|
@@ -169,12 +155,14 @@ export class StoredU64 {
|
|
|
169
155
|
* @description Packs the four cached u64 values into a single u256 for storage.
|
|
170
156
|
* @returns {u256} - The packed u256 value.
|
|
171
157
|
*/
|
|
172
|
-
private packValues():
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
);
|
|
158
|
+
private packValues(): Uint8Array {
|
|
159
|
+
const writer = new BytesWriter(32);
|
|
160
|
+
|
|
161
|
+
writer.writeU64(this._values[0]);
|
|
162
|
+
writer.writeU64(this._values[1]);
|
|
163
|
+
writer.writeU64(this._values[2]);
|
|
164
|
+
writer.writeU64(this._values[3]);
|
|
165
|
+
|
|
166
|
+
return writer.getBuffer();
|
|
179
167
|
}
|
|
180
168
|
}
|