@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.
Files changed (59) hide show
  1. package/package.json +44 -53
  2. package/runtime/abort/abort.ts +25 -0
  3. package/runtime/buffer/BytesReader.ts +171 -140
  4. package/runtime/buffer/BytesWriter.ts +120 -152
  5. package/runtime/contracts/DeployableOP_20.ts +29 -15
  6. package/runtime/contracts/OP_NET.ts +1 -1
  7. package/runtime/env/BlockchainEnvironment.ts +79 -137
  8. package/runtime/env/classes/Block.ts +4 -8
  9. package/runtime/env/classes/Transaction.ts +14 -7
  10. package/runtime/env/classes/UTXO.ts +4 -2
  11. package/runtime/env/global.ts +49 -20
  12. package/runtime/events/predefined/MintEvent.ts +1 -1
  13. package/runtime/exports/index.ts +29 -8
  14. package/runtime/generic/AddressMap.ts +7 -5
  15. package/runtime/generic/Map.ts +32 -2
  16. package/runtime/generic/MapU256.ts +7 -5
  17. package/runtime/generic/MapUint8Array.ts +93 -0
  18. package/runtime/index.ts +4 -12
  19. package/runtime/math/abi.ts +71 -11
  20. package/runtime/math/bytes.ts +177 -41
  21. package/runtime/memory/AddressMemoryMap.ts +22 -19
  22. package/runtime/memory/FastUint8Array.ts +122 -0
  23. package/runtime/memory/KeyMerger.ts +25 -23
  24. package/runtime/memory/MultiAddressMemoryMap.ts +11 -8
  25. package/runtime/memory/MultiStringMemoryMap.ts +8 -5
  26. package/runtime/memory/StringMemoryMap.ts +15 -15
  27. package/runtime/memory/Uint8ArrayMerger.ts +22 -15
  28. package/runtime/storage/Serializable.ts +19 -20
  29. package/runtime/storage/StoredAddress.ts +16 -15
  30. package/runtime/storage/StoredBoolean.ts +26 -21
  31. package/runtime/storage/StoredString.ts +158 -102
  32. package/runtime/storage/StoredU256.ts +25 -28
  33. package/runtime/storage/StoredU64.ts +23 -35
  34. package/runtime/storage/arrays/StoredAddressArray.ts +88 -179
  35. package/runtime/storage/arrays/StoredBooleanArray.ts +150 -272
  36. package/runtime/storage/arrays/StoredPackedArray.ts +313 -0
  37. package/runtime/storage/arrays/StoredU128Array.ts +38 -373
  38. package/runtime/storage/arrays/StoredU16Array.ts +34 -418
  39. package/runtime/storage/arrays/StoredU256Array.ts +21 -346
  40. package/runtime/storage/arrays/StoredU32Array.ts +37 -438
  41. package/runtime/storage/arrays/StoredU64Array.ts +66 -0
  42. package/runtime/storage/arrays/StoredU8Array.ts +29 -451
  43. package/runtime/types/Address.ts +72 -5
  44. package/runtime/types/index.ts +1 -4
  45. package/runtime/utils/encodings.ts +5 -6
  46. package/runtime/utils/hex.ts +1 -1
  47. package/runtime/interfaces/DeployContractResponse.ts +0 -12
  48. package/runtime/math/cyrb53.ts +0 -48
  49. package/runtime/math/sha256.ts +0 -12
  50. package/runtime/memory/MemorySlot.ts +0 -1
  51. package/runtime/memory/MemorySlotPointer.ts +0 -3
  52. package/runtime/storage/utils/StorageBacked.ts +0 -5
  53. package/runtime/storage/utils/StorageLayout.ts +0 -7
  54. package/runtime/storage/utils/StorageSlot.ts +0 -106
  55. package/runtime/storage/utils/StorageStruct.ts +0 -23
  56. package/runtime/storage/utils/StorageValue.ts +0 -36
  57. package/runtime/tests/assert.ts +0 -11
  58. package/runtime/tests/env.ts +0 -7
  59. 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 u256Pointer: u256;
7
+ private readonly pointerBuffer: Uint8Array;
7
8
 
8
9
  constructor(
9
10
  public pointer: u16,
10
- private defaultValue: bool,
11
+ defaultValue: bool,
11
12
  ) {
12
- this.u256Pointer = u256.from(pointer);
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: u256 = u256.Zero;
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.toBool();
33
+ return this._value[0] === 1;
22
34
  }
23
35
 
24
- @inline
25
36
  public set value(value: bool) {
26
- this._value = value ? u256.One : u256.Zero;
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
- return this;
39
+ Blockchain.setStorageAt(this.pointerBuffer, this._value);
38
40
  }
39
41
 
40
42
  @inline
41
43
  public toUint8Array(): Uint8Array {
42
- return this._value.toUint8Array(true);
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.u256Pointer,
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
- constructor(public pointer: u16, private defaultValue?: string) {}
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
- @inline
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
- @inline
24
- public set value(value: string) {
25
- this._value = value;
41
+ public set value(v: string) {
42
+ this._value = v;
43
+
26
44
  this.save();
27
45
  }
28
46
 
29
- private min(a: u32, b: u32): u32 {
30
- return a < b ? a : b;
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
- private getPointer(key: u256): u256 {
34
- const buf = new BytesWriter(U256_BYTE_LENGTH);
35
- buf.writeU256(key);
36
-
37
- return encodePointer(this.pointer, buf.getBuffer());
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
- private save(): void {
41
- const length: u32 = this._value.length;
42
- if (length == 0) {
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
- if (length > 2048) {
47
- throw new Error('StoredString: value is too long');
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
- let currentPointer: u256 = u256.Zero;
55
- let remainingLength: u32 = length;
56
- let offset: u32 = 0;
57
-
58
- // Save the initial chunk (first 28 bytes) in the header
59
- let bytesToWrite: u32 = this.min(remainingLength, 28);
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
- // Helper method to save a chunk of the string into the storage slot
85
- private saveChunk(
86
- storage: u256,
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
- private load(): void {
101
- const header: u256 = Blockchain.getStorageAt(this.getPointer(u256.Zero), u256.Zero);
102
- if (u256.eq(header, u256.Zero)) {
103
- if (this.defaultValue) {
104
- this.value = this.defaultValue;
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
- return;
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
- // the length of the string is stored in the first 4 bytes of the header
111
- const bits: u256 = u256.shr(header, 224);
112
- const length: u32 = bits.toU32();
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 rest contains the string itself
115
- let currentPointer: u256 = u256.Zero;
116
- let remainingLength: u32 = length;
117
- let currentStorage: u256 = header;
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
- const bytesToRead: u32 = this.min(remainingLength, 28);
120
- let str: string = this.loadChunk(currentStorage, 4, bytesToRead);
121
- remainingLength -= bytesToRead;
148
+ remaining -= chunkSize;
149
+ offset += chunkSize;
150
+ chunkIndex++;
151
+ }
152
+ }
122
153
 
123
- while (remainingLength > 0) {
124
- // Move to the next storage slot
125
- currentPointer = u256.add(currentPointer, u256.One);
126
- currentStorage = Blockchain.getStorageAt(this.getPointer(currentPointer), u256.Zero);
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
- // Extract the relevant portion of the string from the current storage slot
129
- const bytesToRead: u32 = this.min(remainingLength, 32);
130
- str += this.loadChunk(currentStorage, 0, bytesToRead);
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
- remainingLength -= bytesToRead;
169
+ // If length=0, then the string is empty
170
+ if (length == 0) {
171
+ this._value = '';
172
+ return;
133
173
  }
134
174
 
135
- this._value = str;
136
- }
137
-
138
- private loadChunk(value: u256, offset: u32, length: u32): string {
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
- let str: string = '';
142
- for (let i: u32 = 0; i < length; i++) {
143
- str += String.fromCharCode(bytes[i + offset]);
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
- return str;
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 u256Pointer: u256;
8
+ private readonly pointerBuffer: Uint8Array;
12
9
 
13
10
  constructor(
14
11
  public pointer: u16,
15
- public subPointer: MemorySlotPointer,
16
- private defaultValue: u256,
12
+ public subPointer: Uint8Array,
17
13
  ) {
18
- const writer = new BytesWriter(U256_BYTE_LENGTH);
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.u256Pointer = encodePointer(pointer, writer.getBuffer());
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.u256Pointer, this._value);
34
+ Blockchain.setStorageAt(this.pointerBuffer, this.__value);
42
35
  }
43
36
 
44
- @inline
45
37
  public get toBytes(): Uint8Array {
46
- return this._value.toUint8Array(false);
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.u256Pointer, this._value);
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.u256Pointer, this._value);
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.u256Pointer, this._value);
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.u256Pointer, this._value);
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.u256Pointer, this._value);
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.u256Pointer, this._value);
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.u256Pointer, this._value);
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.u256Pointer, this._value);
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.u256Pointer, this._value);
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.u256Pointer, this._value);
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.u256Pointer, this._value);
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.u256Pointer, this._value);
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.u256Pointer, this._value);
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
- this._value = Blockchain.getStorageAt(this.u256Pointer, this.defaultValue);
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 { MemorySlotPointer } from '../memory/MemorySlotPointer';
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 u256Pointer: u256;
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 {MemorySlotPointer} subPointer - The sub-pointer for memory slot addressing.
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: MemorySlotPointer,
34
- private defaultValue: u256,
31
+ public subPointer: Uint8Array,
35
32
  ) {
36
- const writer = new BytesWriter(U256_BYTE_LENGTH);
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.u256Pointer = encodePointer(pointer, writer.getBuffer());
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.u256Pointer, packed);
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: u256 = Blockchain.getStorageAt(this.u256Pointer, this.defaultValue);
139
+ const storedU256: Uint8Array = Blockchain.getStorageAt(this.bufferPointer);
140
+
141
+ const reader = new BytesReader(storedU256);
155
142
 
156
- // Unpack the stored u256 into four u64s
157
- this._values[0] = storedU256.lo1;
158
- this._values[1] = storedU256.lo2;
159
- this._values[2] = storedU256.hi1;
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(): u256 {
173
- return new u256(
174
- this._values[0], // lo1
175
- this._values[1], // lo2
176
- this._values[2], // hi1
177
- this._values[3], // hi2
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
  }