@btc-vision/btc-runtime 1.3.14 → 1.3.15
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 +2 -2
- package/runtime/buffer/BytesReader.ts +1 -1
- package/runtime/buffer/BytesWriter.ts +1 -1
- package/runtime/contracts/DeployableOP_20.ts +1 -1
- package/runtime/contracts/OP_20.ts +1 -1
- package/runtime/contracts/interfaces/OP20InitParameters.ts +1 -1
- package/runtime/env/BlockchainEnvironment.ts +1 -1
- package/runtime/env/classes/Block.ts +1 -1
- package/runtime/events/predefined/ApproveEvent.ts +1 -1
- package/runtime/events/predefined/BurnEvent.ts +1 -1
- package/runtime/events/predefined/ClaimEvent.ts +1 -1
- package/runtime/events/predefined/MintEvent.ts +1 -1
- package/runtime/events/predefined/StakeEvent.ts +1 -1
- package/runtime/events/predefined/TransferEvent.ts +1 -1
- package/runtime/events/predefined/UnstakeEvent.ts +1 -1
- package/runtime/generic/MapU256.ts +1 -1
- package/runtime/interfaces/DeployContractResponse.ts +1 -1
- package/runtime/math/bytes.ts +1 -1
- package/runtime/math/i256.ts +1 -1
- package/runtime/math/u160.ts +1 -1
- package/runtime/memory/AddressMemoryMap.ts +1 -1
- package/runtime/memory/KeyMerger.ts +1 -1
- package/runtime/memory/MemorySlotPointer.ts +1 -1
- package/runtime/memory/MultiAddressMemoryMap.ts +1 -1
- package/runtime/memory/MultiStringMemoryMap.ts +1 -1
- package/runtime/memory/StringMemoryMap.ts +1 -1
- package/runtime/memory/Uint8ArrayMerger.ts +1 -1
- package/runtime/secp256k1/ECPoint.ts +1 -1
- package/runtime/shared-libraries/OP20Utils.ts +1 -1
- package/runtime/shared-libraries/TransferHelper.ts +1 -1
- package/runtime/storage/Serializable.ts +1 -1
- package/runtime/storage/StorageBacked.ts +1 -1
- package/runtime/storage/StorageSlot.ts +1 -1
- package/runtime/storage/StorageValue.ts +1 -1
- package/runtime/storage/StoredAddress.ts +1 -1
- package/runtime/storage/StoredAddressArray.ts +410 -0
- package/runtime/storage/StoredBoolean.ts +1 -1
- package/runtime/storage/StoredBooleanArray.ts +1 -1
- package/runtime/storage/StoredString.ts +1 -1
- package/runtime/storage/StoredU128Array.ts +2 -3
- package/runtime/storage/StoredU16Array.ts +3 -3
- package/runtime/storage/StoredU256.ts +1 -1
- package/runtime/storage/StoredU256Array.ts +2 -3
- package/runtime/storage/StoredU64.ts +1 -1
- package/runtime/tests/tests.ts +1 -1
- package/runtime/types/SafeMath.ts +76 -25
- package/runtime/types/index.ts +1 -1
- package/runtime/utils/encodings.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@btc-vision/btc-runtime",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.15",
|
|
4
4
|
"description": "Bitcoin Smart Contract Runtime",
|
|
5
5
|
"main": "btc/index.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
],
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@assemblyscript/loader": "^0.27.30",
|
|
46
|
+
"@btc-vision/as-bignum": "^0.0.2",
|
|
46
47
|
"@eslint/js": "^9.10.0",
|
|
47
|
-
"as-bignum": "^0.3.1",
|
|
48
48
|
"gulplog": "^2.2.0",
|
|
49
49
|
"mocha": "^10.7.3",
|
|
50
50
|
"ts-node": "^10.9.2",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Address, ADDRESS_BYTE_LENGTH } from '../types/Address';
|
|
2
2
|
import { Selector } from '../math/abi';
|
|
3
|
-
import { i128, u128, u256 } from 'as-bignum/assembly';
|
|
3
|
+
import { i128, u128, u256 } from '@btc-vision/as-bignum/assembly';
|
|
4
4
|
import { Revert } from '../types/Revert';
|
|
5
5
|
import { TransactionInput, TransactionOutput } from '../env/classes/UTXO';
|
|
6
6
|
import { i256 } from '../math/i256';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i128, u128, u256 } from 'as-bignum/assembly';
|
|
1
|
+
import { i128, u128, u256 } from '@btc-vision/as-bignum/assembly';
|
|
2
2
|
import { Address, ADDRESS_BYTE_LENGTH } from '../types/Address';
|
|
3
3
|
import { Selector } from '../math/abi';
|
|
4
4
|
import { BytesReader } from './BytesReader';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { u256 } from 'as-bignum/assembly';
|
|
1
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
2
2
|
import { BytesWriter } from '../buffer/BytesWriter';
|
|
3
3
|
import { Blockchain } from '../env';
|
|
4
4
|
import { ApproveEvent, BurnEvent, MintEvent, TransferEvent } from '../events/predefined';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DeployableOP_20 } from './DeployableOP_20';
|
|
2
|
-
import { u256 } from 'as-bignum/assembly';
|
|
2
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
3
3
|
import { OP20InitParameters } from './interfaces/OP20InitParameters';
|
|
4
4
|
|
|
5
5
|
export abstract class OP_20 extends DeployableOP_20 {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Address, ADDRESS_BYTE_LENGTH } from '../types/Address';
|
|
2
2
|
import { MemorySlotPointer } from '../memory/MemorySlotPointer';
|
|
3
3
|
import { MemorySlotData } from '../memory/MemorySlot';
|
|
4
|
-
import { u256 } from 'as-bignum/assembly';
|
|
4
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
5
5
|
import { BytesReader } from '../buffer/BytesReader';
|
|
6
6
|
import { BytesWriter } from '../buffer/BytesWriter';
|
|
7
7
|
import { NetEvent } from '../events/NetEvent';
|
package/runtime/math/bytes.ts
CHANGED
package/runtime/math/i256.ts
CHANGED
package/runtime/math/u160.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { MemorySlotPointer } from './MemorySlotPointer';
|
|
|
2
2
|
import { Blockchain } from '../env';
|
|
3
3
|
import { encodePointer } from '../math/abi';
|
|
4
4
|
import { MemorySlotData } from './MemorySlot';
|
|
5
|
-
import { u256 } from 'as-bignum/assembly';
|
|
5
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
6
6
|
import { BytesWriter } from '../buffer/BytesWriter';
|
|
7
7
|
import { Address } from '../types/Address';
|
|
8
8
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { MemorySlotData } from './MemorySlot';
|
|
2
|
-
import { u256 } from 'as-bignum/assembly';
|
|
2
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
3
3
|
import { Blockchain } from '../env';
|
|
4
4
|
import { MemorySlotPointer } from './MemorySlotPointer';
|
|
5
5
|
import { encodePointer } from '../math/abi';
|
|
@@ -2,7 +2,7 @@ import { MemorySlotPointer } from './MemorySlotPointer';
|
|
|
2
2
|
import { Blockchain } from '../env';
|
|
3
3
|
import { encodePointer } from '../math/abi';
|
|
4
4
|
import { MemorySlotData } from './MemorySlot';
|
|
5
|
-
import { u256 } from 'as-bignum/assembly';
|
|
5
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
6
6
|
import { BytesWriter } from '../buffer/BytesWriter';
|
|
7
7
|
|
|
8
8
|
@final
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { MemorySlotData } from './MemorySlot';
|
|
2
|
-
import { u256 } from 'as-bignum/assembly';
|
|
2
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
3
3
|
import { Blockchain } from '../env';
|
|
4
4
|
import { MemorySlotPointer } from './MemorySlotPointer';
|
|
5
5
|
import { encodePointer } from '../math/abi';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Address, ADDRESS_BYTE_LENGTH } from '../types/Address';
|
|
2
|
-
import { u256 } from 'as-bignum/assembly';
|
|
2
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
3
3
|
import { BytesWriter } from '../buffer/BytesWriter';
|
|
4
4
|
import { Blockchain } from '../env';
|
|
5
5
|
import { encodeSelector, Selector } from '../math/abi';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { u256 } from 'as-bignum/assembly';
|
|
1
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
2
2
|
import { encodeSelector, Selector } from '../math/abi';
|
|
3
3
|
import { Address, ADDRESS_BYTE_LENGTH } from '../types/Address';
|
|
4
4
|
import { BytesWriter } from '../buffer/BytesWriter';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { u256 } from 'as-bignum/assembly';
|
|
1
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
2
2
|
import { BlockchainEnvironment } from '../env/BlockchainEnvironment';
|
|
3
3
|
import { Sha256 } from '../math/sha256';
|
|
4
4
|
import { MemorySlotPointer } from '../memory/MemorySlotPointer';
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
2
|
+
import { Blockchain } from '../env';
|
|
3
|
+
import { BytesWriter } from '../buffer/BytesWriter';
|
|
4
|
+
import { SafeMath } from '../types/SafeMath';
|
|
5
|
+
import { Address } from '../types/Address';
|
|
6
|
+
import { Revert } from '../types/Revert';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @class StoredAddressArray
|
|
10
|
+
* @description Manages an array of u256 values across multiple storage slots. Each slot holds one u256 value.
|
|
11
|
+
*/
|
|
12
|
+
@final
|
|
13
|
+
export class StoredAddressArray {
|
|
14
|
+
private readonly baseU256Pointer: u256;
|
|
15
|
+
private readonly lengthPointer: u256;
|
|
16
|
+
|
|
17
|
+
// Internal cache for storage slots
|
|
18
|
+
private _values: Map<u64, Address> = new Map(); // Map from slotIndex to u256 value
|
|
19
|
+
private _isLoaded: Set<u64> = new Set(); // Set of slotIndexes that are loaded
|
|
20
|
+
private _isChanged: Set<u64> = new Set(); // Set of slotIndexes that are modified
|
|
21
|
+
|
|
22
|
+
// Internal variables for length and startIndex management
|
|
23
|
+
private _length: u64 = 0; // Current length of the array
|
|
24
|
+
private _startIndex: u64 = 0; // Starting index of the array
|
|
25
|
+
private _isChangedLength: bool = false; // Indicates if the length has been modified
|
|
26
|
+
private _isChangedStartIndex: bool = false; // Indicates if the startIndex has been modified
|
|
27
|
+
|
|
28
|
+
// Define a maximum allowed length to prevent excessive storage usage
|
|
29
|
+
private readonly MAX_LENGTH: u64 = u64(u32.MAX_VALUE - 1); // we need to check what happen in overflow situation to be able to set it to u64.MAX_VALUE
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @constructor
|
|
33
|
+
* @param {u16} pointer - The primary pointer identifier.
|
|
34
|
+
* @param {Uint8Array} subPointer - The sub-pointer for memory slot addressing.
|
|
35
|
+
* @param {u256} defaultValue - The default u256 value if storage is uninitialized.
|
|
36
|
+
*/
|
|
37
|
+
constructor(
|
|
38
|
+
public pointer: u16,
|
|
39
|
+
public subPointer: Uint8Array,
|
|
40
|
+
private defaultValue: Address,
|
|
41
|
+
) {
|
|
42
|
+
// Initialize the base u256 pointer using the primary pointer and subPointer
|
|
43
|
+
const writer = new BytesWriter(32);
|
|
44
|
+
writer.writeU16(pointer);
|
|
45
|
+
writer.writeBytes(subPointer);
|
|
46
|
+
|
|
47
|
+
// Initialize the base and length pointers
|
|
48
|
+
const baseU256Pointer = u256.fromBytes(writer.getBuffer(), true);
|
|
49
|
+
const lengthPointer = baseU256Pointer.clone();
|
|
50
|
+
|
|
51
|
+
// Load the current length and startIndex from storage
|
|
52
|
+
const storedLengthAndStartIndex: u256 = Blockchain.getStorageAt(lengthPointer, u256.Zero);
|
|
53
|
+
this.lengthPointer = lengthPointer;
|
|
54
|
+
this.baseU256Pointer = baseU256Pointer;
|
|
55
|
+
|
|
56
|
+
this._length = storedLengthAndStartIndex.lo1; // Bytes 0-7: length
|
|
57
|
+
this._startIndex = storedLengthAndStartIndex.lo2; // Bytes 8-15: startIndex
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @method get
|
|
62
|
+
* @description Retrieves the Address value at the specified global index.
|
|
63
|
+
* @param {u64} index - The global index (0 to ∞) of the Address value to retrieve.
|
|
64
|
+
* @returns {Address} - The Address value at the specified index.
|
|
65
|
+
*/
|
|
66
|
+
@inline
|
|
67
|
+
public get(index: u64): Address {
|
|
68
|
+
assert(index < this._length, 'Index out of bounds');
|
|
69
|
+
const slotIndex: u32 = <u32>index;
|
|
70
|
+
this.ensureValues(slotIndex);
|
|
71
|
+
const value = this._values.get(slotIndex);
|
|
72
|
+
return value ? value : this.defaultValue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @method set
|
|
77
|
+
* @description Sets the Address value at the specified global index.
|
|
78
|
+
* @param {u64} index - The global index (0 to ∞) of the Address value to set.
|
|
79
|
+
* @param {Address} value - The Address value to assign.
|
|
80
|
+
*/
|
|
81
|
+
@inline
|
|
82
|
+
public set(index: u64, value: Address): void {
|
|
83
|
+
assert(index < this._length, 'Index exceeds current array length');
|
|
84
|
+
const slotIndex: u32 = <u32>index;
|
|
85
|
+
this.ensureValues(slotIndex);
|
|
86
|
+
|
|
87
|
+
const currentValue = this._values.get(slotIndex);
|
|
88
|
+
if (currentValue != value) {
|
|
89
|
+
this._values.set(slotIndex, value);
|
|
90
|
+
this._isChanged.add(slotIndex);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @method push
|
|
96
|
+
* @description Appends a new u256 value to the end of the array.
|
|
97
|
+
* @param {u256} value - The u256 value to append.
|
|
98
|
+
*/
|
|
99
|
+
public push(value: Address): void {
|
|
100
|
+
if (this._length >= this.MAX_LENGTH) {
|
|
101
|
+
throw new Revert(
|
|
102
|
+
'Push operation failed: Array has reached its maximum allowed length.',
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const newIndex: u64 = this._length;
|
|
107
|
+
const effectiveIndex: u64 = this._startIndex + newIndex;
|
|
108
|
+
const wrappedIndex: u64 =
|
|
109
|
+
effectiveIndex < this.MAX_LENGTH ? effectiveIndex : effectiveIndex % this.MAX_LENGTH;
|
|
110
|
+
const slotIndex: u32 = <u32>wrappedIndex;
|
|
111
|
+
|
|
112
|
+
// Ensure the slot is loaded
|
|
113
|
+
this.ensureValues(slotIndex);
|
|
114
|
+
|
|
115
|
+
// Set the new value
|
|
116
|
+
this._values.set(slotIndex, value);
|
|
117
|
+
this._isChanged.add(slotIndex);
|
|
118
|
+
|
|
119
|
+
// Increment the length
|
|
120
|
+
this._length += 1;
|
|
121
|
+
this._isChangedLength = true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public deleteLast(): void {
|
|
125
|
+
if (this._length === 0) {
|
|
126
|
+
throw new Revert('Delete operation failed: Array is empty.');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const lastIndex: u64 = this._length - 1;
|
|
130
|
+
const slotIndex: u32 = <u32>(this._startIndex + lastIndex);
|
|
131
|
+
this.ensureValues(slotIndex);
|
|
132
|
+
|
|
133
|
+
const currentValue = this._values.get(slotIndex);
|
|
134
|
+
if (currentValue != this.defaultValue) {
|
|
135
|
+
this._values.set(slotIndex, this.defaultValue);
|
|
136
|
+
this._isChanged.add(slotIndex);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Decrement the length
|
|
140
|
+
this._length -= 1;
|
|
141
|
+
this._isChangedLength = true;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
public setStartingIndex(index: u64): void {
|
|
145
|
+
this._startIndex = index;
|
|
146
|
+
this._isChangedStartIndex = true;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @method delete
|
|
151
|
+
* @description Deletes the Address value at the specified index by setting it to zero. Does not reorder the array.
|
|
152
|
+
* @param {u64} index - The global index of the u256 value to delete.
|
|
153
|
+
*/
|
|
154
|
+
public delete(index: u64): void {
|
|
155
|
+
if (index >= this._length) {
|
|
156
|
+
throw new Revert('Delete operation failed: Index out of bounds.');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const slotIndex: u32 = <u32>index;
|
|
160
|
+
this.ensureValues(slotIndex);
|
|
161
|
+
|
|
162
|
+
const currentValue = this._values.get(slotIndex);
|
|
163
|
+
if (currentValue != this.defaultValue) {
|
|
164
|
+
this._values.set(slotIndex, this.defaultValue);
|
|
165
|
+
this._isChanged.add(slotIndex);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* @method shift
|
|
171
|
+
* @description Removes the first element of the array by setting it to this.defaultValue, decrementing the length, and incrementing the startIndex.
|
|
172
|
+
* If the startIndex reaches the maximum value of u64, it wraps around to 0.
|
|
173
|
+
*/
|
|
174
|
+
public shift(): void {
|
|
175
|
+
if (this._length === 0) {
|
|
176
|
+
throw new Revert('Shift operation failed: Array is empty.');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const currentStartIndex: u64 = this._startIndex;
|
|
180
|
+
const slotIndex: u32 = <u32>currentStartIndex;
|
|
181
|
+
this.ensureValues(slotIndex);
|
|
182
|
+
|
|
183
|
+
const currentValue = this._values.get(slotIndex);
|
|
184
|
+
if (currentValue != this.defaultValue) {
|
|
185
|
+
this._values.set(slotIndex, this.defaultValue);
|
|
186
|
+
this._isChanged.add(slotIndex);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Decrement the length
|
|
190
|
+
this._length -= 1;
|
|
191
|
+
this._isChangedLength = true;
|
|
192
|
+
|
|
193
|
+
// Increment the startIndex with wrap-around
|
|
194
|
+
if (this._startIndex < this.MAX_LENGTH - 1) {
|
|
195
|
+
this._startIndex += 1;
|
|
196
|
+
} else {
|
|
197
|
+
this._startIndex = 0;
|
|
198
|
+
}
|
|
199
|
+
this._isChangedStartIndex = true;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* @method save
|
|
204
|
+
* @description Persists all cached u256 values, the length, and the startIndex to their respective storage slots if any have been modified.
|
|
205
|
+
*/
|
|
206
|
+
public save(): void {
|
|
207
|
+
// Save all changed slots
|
|
208
|
+
const changed = this._isChanged.values();
|
|
209
|
+
for (let i = 0; i < changed.length; i++) {
|
|
210
|
+
const slotIndex = changed[i];
|
|
211
|
+
const storagePointer = this.calculateStoragePointer(slotIndex);
|
|
212
|
+
const value = this._values.get(slotIndex);
|
|
213
|
+
Blockchain.setStorageAt(storagePointer, u256.fromBytes(value));
|
|
214
|
+
}
|
|
215
|
+
this._isChanged.clear();
|
|
216
|
+
|
|
217
|
+
// Save length and startIndex if changed
|
|
218
|
+
if (this._isChangedLength || this._isChangedStartIndex) {
|
|
219
|
+
const packedLengthAndStartIndex = new u256();
|
|
220
|
+
packedLengthAndStartIndex.lo1 = this._length;
|
|
221
|
+
packedLengthAndStartIndex.lo2 = this._startIndex;
|
|
222
|
+
Blockchain.setStorageAt(this.lengthPointer, packedLengthAndStartIndex);
|
|
223
|
+
this._isChangedLength = false;
|
|
224
|
+
this._isChangedStartIndex = false;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* @method deleteAll
|
|
230
|
+
* @description Deletes all storage slots by setting them to this.defaultValue, including the length and startIndex slots.
|
|
231
|
+
*/
|
|
232
|
+
public deleteAll(): void {
|
|
233
|
+
// Iterate over all loaded slots and clear them
|
|
234
|
+
const keys = this._values.keys();
|
|
235
|
+
for (let i = 0; i < keys.length; i++) {
|
|
236
|
+
const slotIndex = keys[i];
|
|
237
|
+
const storagePointer = this.calculateStoragePointer(slotIndex);
|
|
238
|
+
Blockchain.setStorageAt(storagePointer, u256.fromBytes(this.defaultValue));
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Reset the length and startIndex to zero
|
|
242
|
+
const zeroLengthAndStartIndex = u256.Zero;
|
|
243
|
+
Blockchain.setStorageAt(this.lengthPointer, zeroLengthAndStartIndex);
|
|
244
|
+
this._length = 0;
|
|
245
|
+
this._startIndex = 0;
|
|
246
|
+
this._isChangedLength = false;
|
|
247
|
+
this._isChangedStartIndex = false;
|
|
248
|
+
|
|
249
|
+
// Clear internal caches
|
|
250
|
+
this._values.clear();
|
|
251
|
+
this._isLoaded.clear();
|
|
252
|
+
this._isChanged.clear();
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* @method setMultiple
|
|
257
|
+
* @description Sets multiple u256 values starting from a specific global index.
|
|
258
|
+
* @param {u32} startIndex - The starting global index.
|
|
259
|
+
* @param {u256[]} values - An array of u256 values to set.
|
|
260
|
+
*/
|
|
261
|
+
@inline
|
|
262
|
+
public setMultiple(startIndex: u32, values: Address[]): void {
|
|
263
|
+
for (let i: u32 = 0; i < values.length; i++) {
|
|
264
|
+
this.set(<u64>(startIndex + i), values[i]);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* @method getAll
|
|
270
|
+
* @description Retrieves a range of values starting from a specific global index.
|
|
271
|
+
* @param {u32} startIndex - The starting global index.
|
|
272
|
+
* @param {u32} count - The number of values to retrieve.
|
|
273
|
+
* @returns {Address[]} - An array containing the retrieved Address values.
|
|
274
|
+
*/
|
|
275
|
+
@inline
|
|
276
|
+
public getAll(startIndex: u32, count: u32): Address[] {
|
|
277
|
+
assert(startIndex + count <= this._length, 'Requested range exceeds array length');
|
|
278
|
+
const result: Address[] = new Array<Address>(count);
|
|
279
|
+
for (let i: u32 = 0; i < count; i++) {
|
|
280
|
+
result[i] = this.get(<u64>(startIndex + i));
|
|
281
|
+
}
|
|
282
|
+
return result;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* @method toString
|
|
287
|
+
* @description Returns a string representation of all cached values.
|
|
288
|
+
* @returns {string} - A string in the format "[value0, value1, ..., valueN]".
|
|
289
|
+
*/
|
|
290
|
+
@inline
|
|
291
|
+
public toString(): string {
|
|
292
|
+
let str = '[';
|
|
293
|
+
for (let i: u32 = 0; i < this._length; i++) {
|
|
294
|
+
const value = this.get(<u64>i);
|
|
295
|
+
str += value.toString();
|
|
296
|
+
if (i !== this._length - 1) {
|
|
297
|
+
str += ', ';
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
str += ']';
|
|
301
|
+
return str;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* @method toBytes
|
|
306
|
+
* @description Returns the packed Address values as a byte array.
|
|
307
|
+
* @returns {u8[]} - The packed values in byte form.
|
|
308
|
+
*/
|
|
309
|
+
@inline
|
|
310
|
+
public toBytes(): u8[] {
|
|
311
|
+
const bytes: u8[] = new Array<u8>();
|
|
312
|
+
for (let i: u32 = 0; i < this._length; i++) {
|
|
313
|
+
this.ensureValues(i);
|
|
314
|
+
const value = this._values.get(i);
|
|
315
|
+
if (value) {
|
|
316
|
+
const valueBytes = value;
|
|
317
|
+
for (let j: u32 = 0; j < valueBytes.length; j++) {
|
|
318
|
+
bytes.push(valueBytes[j]);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return bytes;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* @method reset
|
|
327
|
+
* @description Resets all cached u256 values to zero and marks them as changed, including resetting the length and startIndex.
|
|
328
|
+
*/
|
|
329
|
+
@inline
|
|
330
|
+
public reset(): void {
|
|
331
|
+
// Reset the length and startIndex to zero
|
|
332
|
+
this._length = 0;
|
|
333
|
+
this._startIndex = 0;
|
|
334
|
+
this._isChangedLength = true;
|
|
335
|
+
this._isChangedStartIndex = true;
|
|
336
|
+
|
|
337
|
+
this.save();
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* @method getLength
|
|
342
|
+
* @description Retrieves the current length of the array.
|
|
343
|
+
* @returns {u64} - The current length.
|
|
344
|
+
*/
|
|
345
|
+
@inline
|
|
346
|
+
public getLength(): u64 {
|
|
347
|
+
return this._length;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* @method startingIndex
|
|
352
|
+
* @description Retrieves the current starting index of the array.
|
|
353
|
+
* @returns {u64} - The starting index.
|
|
354
|
+
*/
|
|
355
|
+
public startingIndex(): u64 {
|
|
356
|
+
return this._startIndex;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* @method setLength
|
|
361
|
+
* @description Sets the length of the array.
|
|
362
|
+
* @param {u64} newLength - The new length to set.
|
|
363
|
+
*/
|
|
364
|
+
public setLength(newLength: u64): void {
|
|
365
|
+
if (newLength > this.MAX_LENGTH) {
|
|
366
|
+
throw new Revert('SetLength operation failed: Length exceeds maximum allowed value.');
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (newLength < this._length) {
|
|
370
|
+
// Truncate the array if newLength is smaller
|
|
371
|
+
for (let i: u64 = newLength; i < this._length; i++) {
|
|
372
|
+
this.delete(i);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
this._length = newLength;
|
|
377
|
+
this._isChangedLength = true;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* @private
|
|
382
|
+
* @method ensureValues
|
|
383
|
+
* @description Loads and caches the u256 value from the specified storage slot.
|
|
384
|
+
* @param {u32} slotIndex - The index of the storage slot.
|
|
385
|
+
*/
|
|
386
|
+
private ensureValues(slotIndex: u32): void {
|
|
387
|
+
if (!this._isLoaded.has(slotIndex)) {
|
|
388
|
+
const storagePointer = this.calculateStoragePointer(slotIndex);
|
|
389
|
+
const storedU256 = Blockchain.getStorageAt(storagePointer, u256.Zero);
|
|
390
|
+
const storedAddress: Address =
|
|
391
|
+
storedU256 === u256.Zero ? this.defaultValue : new Address(storedU256.toBytes());
|
|
392
|
+
this._values.set(slotIndex, storedAddress);
|
|
393
|
+
this._isLoaded.add(slotIndex);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* @private
|
|
399
|
+
* @method calculateStoragePointer
|
|
400
|
+
* @description Calculates the storage pointer for a given slot index by incrementing the base pointer.
|
|
401
|
+
* @param {u32} slotIndex - The index of the storage slot.
|
|
402
|
+
* @returns {u256} - The calculated storage pointer.
|
|
403
|
+
*/
|
|
404
|
+
private calculateStoragePointer(slotIndex: u64): u256 {
|
|
405
|
+
// Each slot is identified by baseU256Pointer + slotIndex + 1
|
|
406
|
+
// Slot 0: baseU256Pointer + 1 (first element)
|
|
407
|
+
// Slot 1: baseU256Pointer + 2, etc.
|
|
408
|
+
return SafeMath.add(this.baseU256Pointer, u256.fromU64(slotIndex + 1));
|
|
409
|
+
}
|
|
410
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { u128, u256 } from 'as-bignum/assembly';
|
|
1
|
+
import { u128, u256 } from '@btc-vision/as-bignum/assembly';
|
|
2
2
|
import { Blockchain } from '../env';
|
|
3
3
|
import { BytesWriter } from '../buffer/BytesWriter';
|
|
4
4
|
import { SafeMath } from '../types/SafeMath';
|
|
@@ -110,9 +110,8 @@ export class StoredU128Array {
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
const newIndex: u64 = this._length;
|
|
113
|
-
const effectiveIndex: u64 = this._startIndex + newIndex;
|
|
114
113
|
const wrappedIndex: u64 =
|
|
115
|
-
|
|
114
|
+
newIndex < this.MAX_LENGTH ? newIndex : newIndex % this.MAX_LENGTH;
|
|
116
115
|
const slotIndex: u32 = <u32>(wrappedIndex / 2);
|
|
117
116
|
const subIndex: u8 = <u8>(wrappedIndex % 2);
|
|
118
117
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { u256 } from 'as-bignum/assembly';
|
|
1
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
2
2
|
import { Blockchain } from '../env';
|
|
3
3
|
import { BytesWriter } from '../buffer/BytesWriter';
|
|
4
4
|
import { SafeMath } from '../types/SafeMath';
|
|
@@ -106,9 +106,9 @@ export class StoredU16Array {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
const newIndex: u64 = this._length;
|
|
109
|
-
const effectiveIndex: u64 = this._startIndex + newIndex;
|
|
110
109
|
const wrappedIndex: u64 =
|
|
111
|
-
|
|
110
|
+
newIndex < this.MAX_LENGTH ? newIndex : newIndex % this.MAX_LENGTH;
|
|
111
|
+
|
|
112
112
|
const slotIndex: u64 = wrappedIndex / 16;
|
|
113
113
|
const subIndex: u8 = <u8>(wrappedIndex % 16);
|
|
114
114
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { u256 } from 'as-bignum/assembly';
|
|
1
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
2
2
|
import { Blockchain } from '../env';
|
|
3
3
|
import { BytesWriter } from '../buffer/BytesWriter';
|
|
4
4
|
import { SafeMath } from '../types/SafeMath';
|
|
@@ -103,9 +103,8 @@ export class StoredU256Array {
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
const newIndex: u64 = this._length;
|
|
106
|
-
const effectiveIndex: u64 = this._startIndex + newIndex;
|
|
107
106
|
const wrappedIndex: u64 =
|
|
108
|
-
|
|
107
|
+
newIndex < this.MAX_LENGTH ? newIndex : newIndex % this.MAX_LENGTH;
|
|
109
108
|
const slotIndex: u32 = <u32>wrappedIndex;
|
|
110
109
|
|
|
111
110
|
// Ensure the slot is loaded
|
|
@@ -2,7 +2,7 @@ import { MemorySlotPointer } from '../memory/MemorySlotPointer';
|
|
|
2
2
|
import { Blockchain } from '../env';
|
|
3
3
|
import { encodePointer } from '../math/abi';
|
|
4
4
|
import { BytesWriter } from '../buffer/BytesWriter';
|
|
5
|
-
import { u256 } from 'as-bignum/assembly';
|
|
5
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* @class StoredU64
|
package/runtime/tests/tests.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { u128, u256 } from 'as-bignum/assembly';
|
|
1
|
+
import { u128, u256 } from '@btc-vision/as-bignum/assembly';
|
|
2
2
|
|
|
3
3
|
export class SafeMath {
|
|
4
4
|
public static ZERO: u256 = u256.fromU32(0);
|
|
@@ -267,17 +267,7 @@ export class SafeMath {
|
|
|
267
267
|
const bitShift = shift % bitsPerSegment;
|
|
268
268
|
|
|
269
269
|
const segments = [value.lo1, value.lo2, value.hi1, value.hi2];
|
|
270
|
-
|
|
271
|
-
const result = new Array<u64>(4).fill(0);
|
|
272
|
-
|
|
273
|
-
for (let i = 0; i < segments.length; i++) {
|
|
274
|
-
if (i + segmentShift < segments.length) {
|
|
275
|
-
result[i + segmentShift] |= segments[i] << bitShift;
|
|
276
|
-
}
|
|
277
|
-
if (bitShift != 0 && i + segmentShift + 1 < segments.length) {
|
|
278
|
-
result[i + segmentShift + 1] |= segments[i] >>> (bitsPerSegment - bitShift);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
270
|
+
const result = SafeMath.shlSegment(segments, segmentShift, bitShift, bitsPerSegment, 4);
|
|
281
271
|
|
|
282
272
|
return new u256(result[0], result[1], result[2], result[3]);
|
|
283
273
|
}
|
|
@@ -302,17 +292,7 @@ export class SafeMath {
|
|
|
302
292
|
const bitShift = shift % bitsPerSegment;
|
|
303
293
|
|
|
304
294
|
const segments = [value.lo, value.hi];
|
|
305
|
-
|
|
306
|
-
const result = new Array<u64>(2).fill(0);
|
|
307
|
-
|
|
308
|
-
for (let i = 0; i < segments.length; i++) {
|
|
309
|
-
if (i + segmentShift < segments.length) {
|
|
310
|
-
result[i + segmentShift] |= segments[i] << bitShift;
|
|
311
|
-
}
|
|
312
|
-
if (bitShift != 0 && i + segmentShift + 1 < segments.length) {
|
|
313
|
-
result[i + segmentShift + 1] |= segments[i] >>> (bitsPerSegment - bitShift);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
295
|
+
const result = SafeMath.shlSegment(segments, segmentShift, bitShift, bitsPerSegment, 2);
|
|
316
296
|
|
|
317
297
|
return new u128(result[0], result[1]);
|
|
318
298
|
}
|
|
@@ -329,8 +309,58 @@ export class SafeMath {
|
|
|
329
309
|
return u256.xor(a, b);
|
|
330
310
|
}
|
|
331
311
|
|
|
332
|
-
public static shr(a: u256,
|
|
333
|
-
|
|
312
|
+
public static shr(a: u256, shift: i32): u256 {
|
|
313
|
+
shift &= 255;
|
|
314
|
+
if (shift == 0) return a;
|
|
315
|
+
|
|
316
|
+
const w = shift >>> 6; // how many full 64-bit words to drop
|
|
317
|
+
const b = shift & 63; // how many bits to shift within a word
|
|
318
|
+
|
|
319
|
+
// Extract the words
|
|
320
|
+
let lo1 = a.lo1;
|
|
321
|
+
let lo2 = a.lo2;
|
|
322
|
+
let hi1 = a.hi1;
|
|
323
|
+
let hi2 = a.hi2;
|
|
324
|
+
|
|
325
|
+
// Shift words down by w words
|
|
326
|
+
// For w = 1, move lo2->lo1, hi1->lo2, hi2->hi1, and hi2 = 0
|
|
327
|
+
// For w = 2, move hi1->lo1, hi2->lo2, and zeros in hi1, hi2
|
|
328
|
+
// For w = 3, move hi2->lo1 and zeros in others
|
|
329
|
+
// For w >= 4, everything is zero.
|
|
330
|
+
if (w >= 4) {
|
|
331
|
+
// Shifting by >= 256 bits zeros out everything
|
|
332
|
+
return u256.Zero;
|
|
333
|
+
} else if (w == 3) {
|
|
334
|
+
lo1 = hi2;
|
|
335
|
+
lo2 = 0;
|
|
336
|
+
hi1 = 0;
|
|
337
|
+
hi2 = 0;
|
|
338
|
+
} else if (w == 2) {
|
|
339
|
+
lo1 = hi1;
|
|
340
|
+
lo2 = hi2;
|
|
341
|
+
hi1 = 0;
|
|
342
|
+
hi2 = 0;
|
|
343
|
+
} else if (w == 1) {
|
|
344
|
+
lo1 = lo2;
|
|
345
|
+
lo2 = hi1;
|
|
346
|
+
hi1 = hi2;
|
|
347
|
+
hi2 = 0;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Now apply the bit shift b
|
|
351
|
+
if (b > 0) {
|
|
352
|
+
// Bring down bits from the higher word
|
|
353
|
+
const carryLo2 = hi1 << (64 - b);
|
|
354
|
+
const carryLo1 = lo2 << (64 - b);
|
|
355
|
+
const carryHi1 = hi2 << (64 - b);
|
|
356
|
+
|
|
357
|
+
lo1 = (lo1 >>> b) | carryLo1;
|
|
358
|
+
lo2 = (lo2 >>> b) | carryLo2;
|
|
359
|
+
hi1 = (hi1 >>> b) | carryHi1;
|
|
360
|
+
hi2 = hi2 >>> b;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return new u256(lo1, lo2, hi1, hi2);
|
|
334
364
|
}
|
|
335
365
|
|
|
336
366
|
/**
|
|
@@ -360,4 +390,25 @@ export class SafeMath {
|
|
|
360
390
|
|
|
361
391
|
return n;
|
|
362
392
|
}
|
|
393
|
+
|
|
394
|
+
private static shlSegment(
|
|
395
|
+
segments: u64[],
|
|
396
|
+
segmentShift: i32,
|
|
397
|
+
bitShift: i32,
|
|
398
|
+
bitsPerSegment: i32,
|
|
399
|
+
fillCount: u8,
|
|
400
|
+
): u64[] {
|
|
401
|
+
const result = new Array<u64>(fillCount).fill(0);
|
|
402
|
+
|
|
403
|
+
for (let i = 0; i < segments.length; i++) {
|
|
404
|
+
if (i + segmentShift < segments.length) {
|
|
405
|
+
result[i + segmentShift] |= segments[i] << bitShift;
|
|
406
|
+
}
|
|
407
|
+
if (bitShift != 0 && i + segmentShift + 1 < segments.length) {
|
|
408
|
+
result[i + segmentShift + 1] |= segments[i] >>> (bitsPerSegment - bitShift);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
return result;
|
|
413
|
+
}
|
|
363
414
|
}
|
package/runtime/types/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Map } from '../generic/Map';
|
|
2
2
|
import { MemorySlotPointer } from '../memory/MemorySlotPointer';
|
|
3
3
|
import { MemorySlotData } from '../memory/MemorySlot';
|
|
4
|
-
import { u256 } from 'as-bignum/assembly';
|
|
4
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
5
5
|
import { BytesReader } from '../buffer/BytesReader';
|
|
6
6
|
|
|
7
7
|
export type PointerStorage = Map<MemorySlotPointer, MemorySlotData<u256>>;
|