@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
package/runtime/generic/Map.ts
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import { Revert } from '../types/Revert';
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export interface IMap<K, V> {
|
|
4
|
+
readonly size: i32;
|
|
5
|
+
|
|
6
|
+
has(key: K): bool;
|
|
7
|
+
|
|
8
|
+
set(key: K, value: V): this;
|
|
9
|
+
|
|
10
|
+
get(key: K): V;
|
|
11
|
+
|
|
12
|
+
delete(key: K): bool;
|
|
13
|
+
|
|
14
|
+
clear(): void;
|
|
15
|
+
|
|
16
|
+
keys(): K[]; // preliminary
|
|
17
|
+
values(): V[]; // preliminary
|
|
18
|
+
toString(): string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class Map<K, V> implements IMap<K, V> {
|
|
4
22
|
protected _keys: K[] = [];
|
|
5
23
|
protected _values: V[] = [];
|
|
6
24
|
|
|
@@ -16,7 +34,7 @@ export class Map<K, V> {
|
|
|
16
34
|
return this._values;
|
|
17
35
|
}
|
|
18
36
|
|
|
19
|
-
public set(key: K, value: V):
|
|
37
|
+
public set(key: K, value: V): this {
|
|
20
38
|
const index: i32 = this.indexOf(key);
|
|
21
39
|
if (index == -1) {
|
|
22
40
|
this._keys.push(key);
|
|
@@ -24,6 +42,8 @@ export class Map<K, V> {
|
|
|
24
42
|
} else {
|
|
25
43
|
this._values[index] = value;
|
|
26
44
|
}
|
|
45
|
+
|
|
46
|
+
return this;
|
|
27
47
|
}
|
|
28
48
|
|
|
29
49
|
public indexOf(key: K): i32 {
|
|
@@ -63,4 +83,14 @@ export class Map<K, V> {
|
|
|
63
83
|
this._keys = [];
|
|
64
84
|
this._values = [];
|
|
65
85
|
}
|
|
86
|
+
|
|
87
|
+
public toString(): string {
|
|
88
|
+
const str: string = ``;
|
|
89
|
+
|
|
90
|
+
for (let i: i32 = 0; i < this._keys.length; i++) {
|
|
91
|
+
str.concat(`[${this._keys[i]}] => [${this._values[i]}]`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return str;
|
|
95
|
+
}
|
|
66
96
|
}
|
|
@@ -3,14 +3,16 @@ import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
|
3
3
|
import { Map } from './Map';
|
|
4
4
|
|
|
5
5
|
export class MapU256 extends Map<u256, u256> {
|
|
6
|
-
public set(key: u256, value: u256):
|
|
7
|
-
const index: i32 = this.
|
|
8
|
-
if (index
|
|
6
|
+
public set(key: u256, value: u256): this {
|
|
7
|
+
const index: i32 = this.indexOf(key);
|
|
8
|
+
if (index === -1) {
|
|
9
9
|
this._keys.push(key);
|
|
10
10
|
this._values.push(value);
|
|
11
11
|
} else {
|
|
12
12
|
this._values[index] = value;
|
|
13
13
|
}
|
|
14
|
+
|
|
15
|
+
return this;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
public indexOf(pointerHash: u256): i32 {
|
|
@@ -37,7 +39,7 @@ export class MapU256 extends Map<u256, u256> {
|
|
|
37
39
|
|
|
38
40
|
public get(key: u256): u256 {
|
|
39
41
|
const index: i32 = this.indexOf(key);
|
|
40
|
-
if (index
|
|
42
|
+
if (index === -1) {
|
|
41
43
|
throw new Revert('Key not found in map (u256)');
|
|
42
44
|
}
|
|
43
45
|
return this._values[index];
|
|
@@ -45,7 +47,7 @@ export class MapU256 extends Map<u256, u256> {
|
|
|
45
47
|
|
|
46
48
|
public delete(key: u256): bool {
|
|
47
49
|
const index: i32 = this.indexOf(key);
|
|
48
|
-
if (index
|
|
50
|
+
if (index === -1) {
|
|
49
51
|
return false;
|
|
50
52
|
}
|
|
51
53
|
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Revert } from '../types/Revert';
|
|
2
|
+
import { IMap } from './Map';
|
|
3
|
+
|
|
4
|
+
export function eqUint(data: Uint8Array, data2: Uint8Array): bool {
|
|
5
|
+
if (data.length !== data2.length) return false;
|
|
6
|
+
|
|
7
|
+
for (let i = 0; i < data.length; i++) {
|
|
8
|
+
if (data[i] !== data2[i]) return false;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@final
|
|
15
|
+
export class MapUint8Array implements IMap<Uint8Array, Uint8Array> {
|
|
16
|
+
protected _keys: Uint8Array[] = [];
|
|
17
|
+
protected _values: Uint8Array[] = [];
|
|
18
|
+
|
|
19
|
+
public get size(): i32 {
|
|
20
|
+
return this._keys.length;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public keys(): Uint8Array[] {
|
|
24
|
+
return this._keys;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public values(): Uint8Array[] {
|
|
28
|
+
return this._values;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public set(key: Uint8Array, value: Uint8Array): this {
|
|
32
|
+
const index: i32 = this.indexOf(key);
|
|
33
|
+
if (index === -1) {
|
|
34
|
+
this._keys.push(key);
|
|
35
|
+
this._values.push(value);
|
|
36
|
+
} else {
|
|
37
|
+
this._values[index] = value;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public indexOf(pointerHash: Uint8Array): i32 {
|
|
44
|
+
for (let i: i32 = 0; i < this._keys.length; i++) {
|
|
45
|
+
const key = this._keys[i];
|
|
46
|
+
|
|
47
|
+
if (eqUint(key, pointerHash)) {
|
|
48
|
+
return i;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return -1;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public has(key: Uint8Array): bool {
|
|
56
|
+
return this.indexOf(key) !== -1;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public get(key: Uint8Array): Uint8Array {
|
|
60
|
+
const index: i32 = this.indexOf(key);
|
|
61
|
+
if (index === -1) {
|
|
62
|
+
throw new Revert('Key not found in map (uint8array)');
|
|
63
|
+
}
|
|
64
|
+
return this._values[index];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public delete(key: Uint8Array): bool {
|
|
68
|
+
const index: i32 = this.indexOf(key);
|
|
69
|
+
if (index === -1) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
this._keys.splice(index, 1);
|
|
74
|
+
this._values.splice(index, 1);
|
|
75
|
+
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public clear(): void {
|
|
80
|
+
this._keys = [];
|
|
81
|
+
this._values = [];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public toString(): string {
|
|
85
|
+
const str: string = ``;
|
|
86
|
+
|
|
87
|
+
for (let i: i32 = 0; i < this._keys.length; i++) {
|
|
88
|
+
str.concat(`[${this._keys[i].toString()}] => [${this._values[i].toString()}]`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return str;
|
|
92
|
+
}
|
|
93
|
+
}
|
package/runtime/index.ts
CHANGED
|
@@ -14,7 +14,6 @@ export * from './buffer/BytesWriter';
|
|
|
14
14
|
|
|
15
15
|
/** Interfaces */
|
|
16
16
|
export * from './interfaces/IBTC';
|
|
17
|
-
export * from './interfaces/DeployContractResponse';
|
|
18
17
|
|
|
19
18
|
/** Events */
|
|
20
19
|
export * from './events/NetEvent';
|
|
@@ -43,16 +42,12 @@ export * from './types/SafeMathI128';
|
|
|
43
42
|
/** Math */
|
|
44
43
|
export * from './math/abi';
|
|
45
44
|
export * from './math/bytes';
|
|
46
|
-
export * from './math/cyrb53';
|
|
47
|
-
export * from './math/sha256';
|
|
48
45
|
export * from './secp256k1/ECPoint';
|
|
49
46
|
|
|
50
47
|
/** Memory */
|
|
51
48
|
export * from './memory/AddressMemoryMap';
|
|
52
49
|
export * from './memory/StringMemoryMap';
|
|
53
50
|
export * from './memory/MultiStringMemoryMap';
|
|
54
|
-
export * from './memory/MemorySlot';
|
|
55
|
-
export * from './memory/MemorySlotPointer';
|
|
56
51
|
export * from './memory/KeyMerger';
|
|
57
52
|
export * from './memory/MultiAddressMemoryMap';
|
|
58
53
|
export * from './memory/Uint8ArrayMerger';
|
|
@@ -67,19 +62,16 @@ export * from './storage/Serializable';
|
|
|
67
62
|
|
|
68
63
|
/** Arrays */
|
|
69
64
|
export * from './storage/arrays/StoredAddressArray';
|
|
65
|
+
export * from './storage/arrays/StoredBooleanArray';
|
|
66
|
+
|
|
70
67
|
export * from './storage/arrays/StoredU8Array';
|
|
71
68
|
export * from './storage/arrays/StoredU16Array';
|
|
72
69
|
export * from './storage/arrays/StoredU32Array';
|
|
73
|
-
export * from './storage/arrays/
|
|
70
|
+
export * from './storage/arrays/StoredU64Array';
|
|
74
71
|
export * from './storage/arrays/StoredU128Array';
|
|
75
72
|
export * from './storage/arrays/StoredU256Array';
|
|
76
73
|
|
|
77
|
-
|
|
78
|
-
export * from './storage/utils/StorageBacked';
|
|
79
|
-
export * from './storage/utils/StorageSlot';
|
|
80
|
-
export * from './storage/utils/StorageStruct';
|
|
81
|
-
export * from './storage/utils/StorageLayout';
|
|
82
|
-
export * from './storage/utils/StorageValue';
|
|
74
|
+
export * from './memory/FastUint8Array';
|
|
83
75
|
|
|
84
76
|
/** Shared libraries */
|
|
85
77
|
export * from './shared-libraries/TransferHelper';
|
package/runtime/math/abi.ts
CHANGED
|
@@ -1,28 +1,88 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { Sha256 } from './sha256';
|
|
1
|
+
import { bytesToU32 } from './bytes';
|
|
2
|
+
import { sha256 } from '../env/global';
|
|
3
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
5
4
|
|
|
6
5
|
export type Selector = u32;
|
|
7
6
|
|
|
8
7
|
export function encodeSelector(name: string): Selector {
|
|
9
8
|
const typed = Uint8Array.wrap(String.UTF8.encode(name));
|
|
10
|
-
const hash =
|
|
9
|
+
const hash = sha256(typed);
|
|
11
10
|
|
|
12
|
-
return
|
|
11
|
+
return bytesToU32(hash);
|
|
13
12
|
}
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Use more gas.
|
|
16
|
+
* @param uniqueIdentifier
|
|
17
|
+
* @param typed
|
|
18
|
+
*/
|
|
19
|
+
export function encodePointerUnknownLength(uniqueIdentifier: u16, typed: Uint8Array): Uint8Array {
|
|
20
|
+
const hash = sha256(typed);
|
|
21
|
+
|
|
22
|
+
return encodePointer(uniqueIdentifier, hash, false);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function ensureAtLeast30Bytes(typed: Uint8Array): Uint8Array {
|
|
26
|
+
if (typed.length >= 30) {
|
|
27
|
+
return typed;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const result = new Uint8Array(30);
|
|
31
|
+
for (let i = 0; i < typed.length; i++) {
|
|
32
|
+
result[i] = typed[i];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@inline
|
|
39
|
+
function toArrayBufferBE(buffer: usize, val: u256): void {
|
|
40
|
+
// Write the upper 3 chunks (each 64 bits) in one shot:
|
|
41
|
+
store<u64>(buffer, bswap(val.hi2), 0); // 0..7
|
|
42
|
+
store<u64>(buffer, bswap(val.hi1), 8); // 8..15
|
|
43
|
+
store<u64>(buffer, bswap(val.lo2), 16); // 16..23
|
|
44
|
+
|
|
45
|
+
// Now handle the final 64 bits (val.lo1) in [32 + 16 + 16] form.
|
|
46
|
+
// - lo1High32 = top 32 bits [bits 63..32]
|
|
47
|
+
// - lo1Mid16 = middle 16 bits [bits 31..16]
|
|
48
|
+
// - lo1Low16 = bottom 16 bits [bits 15..0]
|
|
49
|
+
const lo1High32 = u32(val.lo1 >>> 32);
|
|
50
|
+
const lo1Mid16 = u16((val.lo1 >>> 16) & 0xffff);
|
|
51
|
+
|
|
52
|
+
// Store them in ascending offsets. Because each store is little-endian,
|
|
53
|
+
// we bswap the values so that the final bytes in memory are big-endian.
|
|
54
|
+
|
|
55
|
+
// Offsets 24..27 (4 bytes): top 32 bits of lo1
|
|
56
|
+
store<u32>(buffer, bswap(lo1High32), 24);
|
|
57
|
+
|
|
58
|
+
// Offsets 28..29 (2 bytes): mid 16 bits of lo1
|
|
59
|
+
store<u16>(buffer, bswap(lo1Mid16), 28);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function u256To30Bytes(value: u256): Uint8Array {
|
|
63
|
+
const result = new Uint8Array(30);
|
|
64
|
+
toArrayBufferBE(changetype<usize>(result.dataStart), value);
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Optimized pointer encoding, see encodePointerUnknownLength for a more generic version.
|
|
70
|
+
* @param uniqueIdentifier
|
|
71
|
+
* @param typed
|
|
72
|
+
* @param safe
|
|
73
|
+
*/
|
|
74
|
+
export function encodePointer(uniqueIdentifier: u16, typed: Uint8Array, safe: boolean = true): Uint8Array {
|
|
75
|
+
const array = ensureAtLeast30Bytes(typed);
|
|
76
|
+
|
|
77
|
+
if (safe) assert(array.length === 30, `Pointers must be 30 bytes. Got ${array.length}.`);
|
|
17
78
|
|
|
18
79
|
const finalPointer = new Uint8Array(32);
|
|
19
80
|
finalPointer[0] = uniqueIdentifier & 0xff;
|
|
20
81
|
finalPointer[1] = (uniqueIdentifier >> 8) & 0xff;
|
|
21
82
|
|
|
22
83
|
for (let i = 0; i < 30; i++) {
|
|
23
|
-
|
|
24
|
-
finalPointer[i + 2] = hash[i];
|
|
84
|
+
finalPointer[i + 2] = array[i];
|
|
25
85
|
}
|
|
26
86
|
|
|
27
|
-
return
|
|
87
|
+
return finalPointer;
|
|
28
88
|
}
|
package/runtime/math/bytes.ts
CHANGED
|
@@ -1,57 +1,193 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
import { Revert } from '../types/Revert';
|
|
2
|
+
import { BytesWriter } from '../buffer/BytesWriter';
|
|
3
|
+
import { BytesReader } from '../buffer/BytesReader';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Convert a 4-byte big-endian array into a u32.
|
|
7
|
+
* Index 0 is most significant, index 3 is least significant.
|
|
8
|
+
*/
|
|
9
|
+
@inline
|
|
10
|
+
export function bytesToU32(number: Uint8Array): u32 {
|
|
11
|
+
if (number.length < 4) {
|
|
12
|
+
throw new Error('bytesToU32: input must be at least 4 bytes');
|
|
13
|
+
}
|
|
14
|
+
return (u32(number[0]) << 24) |
|
|
15
|
+
(u32(number[1]) << 16) |
|
|
16
|
+
(u32(number[2]) << 8) |
|
|
17
|
+
u32(number[3]);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// 32-byte buffer of all zeros
|
|
21
|
+
export const EMPTY_BUFFER: Uint8Array = new Uint8Array(32);
|
|
22
|
+
|
|
23
|
+
// 30-byte buffer of all zeros
|
|
24
|
+
export const EMPTY_POINTER: Uint8Array = new Uint8Array(30);
|
|
25
|
+
|
|
26
|
+
// 32-byte buffer representing 1 in big-endian form:
|
|
27
|
+
// index 31 is the least significant byte.
|
|
28
|
+
export const ONE_BUFFER: Uint8Array = new Uint8Array(32);
|
|
29
|
+
ONE_BUFFER[31] = 1;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Return a new 32-byte zero buffer.
|
|
33
|
+
*/
|
|
34
|
+
@inline
|
|
35
|
+
export function GET_EMPTY_BUFFER(): Uint8Array {
|
|
36
|
+
return new Uint8Array(32);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* A helper to add two 32-byte big-endian Uint8Arrays.
|
|
41
|
+
* Returns a new 32-byte Uint8Array with (a + b) mod 2^256.
|
|
42
|
+
*
|
|
43
|
+
* In big-endian, the LSB is at index 31, so we iterate from i = 31 down to 0.
|
|
44
|
+
*/
|
|
45
|
+
@inline
|
|
46
|
+
export function addUint8ArraysBE(a: Uint8Array, b: Uint8Array): Uint8Array {
|
|
47
|
+
if (a.length !== 32 || b.length !== 32) {
|
|
48
|
+
throw new Error('addUint8ArraysBE expects 32-byte inputs');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const result = new Uint8Array(32);
|
|
52
|
+
let carry = 0;
|
|
53
|
+
|
|
54
|
+
// index 31 is least significant byte
|
|
55
|
+
for (let i = 31; i >= 0; i--) {
|
|
56
|
+
const sum = (a[i] as u32) + (b[i] as u32) + carry;
|
|
57
|
+
result[i] = sum & 0xff;
|
|
58
|
+
carry = sum >> 8;
|
|
19
59
|
}
|
|
20
60
|
|
|
21
61
|
return result;
|
|
22
62
|
}
|
|
23
63
|
|
|
24
|
-
|
|
25
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Convert a u64 value to a 32-byte big-endian Uint8Array,
|
|
66
|
+
* placing the u64 in the *last* 8 bytes (indices 24..31).
|
|
67
|
+
* The most significant 24 bytes (indices 0..23) remain 0.
|
|
68
|
+
*/
|
|
69
|
+
@inline
|
|
70
|
+
export function u64ToBE32Bytes(value: u64): Uint8Array {
|
|
71
|
+
const arr = new Uint8Array(32);
|
|
72
|
+
|
|
73
|
+
// Write big-endian into the final 8 bytes:
|
|
74
|
+
for (let i = 0; i < 8; i++) {
|
|
75
|
+
arr[31 - i] = <u8>(value & 0xff);
|
|
76
|
+
value >>= 8;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return arr;
|
|
26
80
|
}
|
|
27
81
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
82
|
+
/**
|
|
83
|
+
* Get the bit at `bitIndex` (0..255) in a 32-byte buffer **in big-endian bit numbering**.
|
|
84
|
+
* - bitIndex = 0 => the MSB of buffer[0].
|
|
85
|
+
* - bitIndex = 7 => the LSB of buffer[0].
|
|
86
|
+
* - bitIndex = 255 => the LSB of buffer[31].
|
|
87
|
+
*/
|
|
88
|
+
@inline
|
|
89
|
+
export function getBit(buffer: Uint8Array, bitIndex: u16): bool {
|
|
90
|
+
if (bitIndex >= 256) {
|
|
91
|
+
throw new Revert('Bit index out of range');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Which byte?
|
|
95
|
+
const byteIndex: u8 = <u8>(bitIndex >>> 3);
|
|
96
|
+
|
|
97
|
+
// Which bit within that byte? (MSB = bit offset 7)
|
|
98
|
+
const offset: u8 = <u8>(7 - (bitIndex & 7));
|
|
99
|
+
|
|
100
|
+
const b: u8 = buffer[byteIndex];
|
|
101
|
+
return ((b >>> offset) & 1) == 1;
|
|
39
102
|
}
|
|
40
103
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
104
|
+
/**
|
|
105
|
+
* Set or clear the bit at `bitIndex` (0..255) in a 32-byte buffer (**big-endian** bit numbering).
|
|
106
|
+
* - bitIndex = 0 => sets the MSB of buffer[0].
|
|
107
|
+
* - bitIndex = 255 => sets the LSB of buffer[31].
|
|
108
|
+
*/
|
|
109
|
+
@inline
|
|
110
|
+
export function setBit(buffer: Uint8Array, bitIndex: u16, bitValue: bool): void {
|
|
111
|
+
if (bitIndex >= 256) {
|
|
112
|
+
throw new Revert('Bit index out of range');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Which byte?
|
|
116
|
+
const byteIndex: u8 = <u8>(bitIndex >>> 3);
|
|
117
|
+
|
|
118
|
+
// Which bit within that byte? (MSB = bit offset 7)
|
|
119
|
+
const offset: u8 = <u8>(7 - (bitIndex & 7));
|
|
120
|
+
|
|
121
|
+
let b: u8 = buffer[byteIndex];
|
|
122
|
+
if (bitValue) {
|
|
123
|
+
b |= 1 << offset;
|
|
124
|
+
} else {
|
|
125
|
+
b &= ~(1 << offset);
|
|
45
126
|
}
|
|
46
127
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
128
|
+
buffer[byteIndex] = b;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Assume the data is at least 16 bytes, read two u64s from it in big-endian order.
|
|
134
|
+
*/
|
|
135
|
+
@inline
|
|
136
|
+
export function readLengthAndStartIndex(data: Uint8Array): u64[] {
|
|
137
|
+
if (data.length < 16) {
|
|
138
|
+
return [0, 0];
|
|
50
139
|
}
|
|
51
140
|
|
|
52
|
-
|
|
141
|
+
const reader = new BytesReader(data);
|
|
142
|
+
const length = reader.readU64();
|
|
143
|
+
const startIndex = reader.readU64();
|
|
144
|
+
|
|
145
|
+
return [length, startIndex];
|
|
53
146
|
}
|
|
54
147
|
|
|
55
|
-
|
|
56
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Write two u64s into a 32-byte buffer in big-endian order
|
|
150
|
+
*/
|
|
151
|
+
@inline
|
|
152
|
+
export function writeLengthAndStartIndex(length: u64, startIndex: u64): Uint8Array {
|
|
153
|
+
const writer = new BytesWriter(32);
|
|
154
|
+
writer.writeU64(length);
|
|
155
|
+
writer.writeU64(startIndex);
|
|
156
|
+
|
|
157
|
+
return writer.getBuffer();
|
|
57
158
|
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Encode a 2-byte pointer + subPointer into a 32-byte buffer in big-endian order.
|
|
162
|
+
*/
|
|
163
|
+
@inline
|
|
164
|
+
export function encodeBasePointer(pointer: u16, subPointer: Uint8Array): Uint8Array {
|
|
165
|
+
const writer = new BytesWriter(32);
|
|
166
|
+
writer.writeU16(pointer);
|
|
167
|
+
writer.writeBytes(subPointer);
|
|
168
|
+
|
|
169
|
+
return writer.getBuffer();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
@inline
|
|
173
|
+
export function bigEndianAdd(base: Uint8Array, increment: u64): Uint8Array {
|
|
174
|
+
const out = new Uint8Array(32);
|
|
175
|
+
|
|
176
|
+
// Copy the base pointer
|
|
177
|
+
for (let i = 0; i < 32; i++) {
|
|
178
|
+
out[i] = base[i];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// If this is truly big-endian, out[0] is the MSB, out[31] is the LSB.
|
|
182
|
+
// So to add `increment`, we start from out[31] backward.
|
|
183
|
+
let carry: u64 = increment;
|
|
184
|
+
for (let i = 31; i >= 0; i--) {
|
|
185
|
+
const sum = <u64>out[i] + (carry & 0xFF);
|
|
186
|
+
out[i] = <u8>(sum & 0xFF);
|
|
187
|
+
carry = sum >> 8;
|
|
188
|
+
if (carry == 0 || i == 0) {
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return out;
|
|
193
|
+
}
|
|
@@ -1,44 +1,50 @@
|
|
|
1
|
-
import { MemorySlotPointer } from './MemorySlotPointer';
|
|
2
1
|
import { Blockchain } from '../env';
|
|
3
2
|
import { encodePointer } from '../math/abi';
|
|
4
|
-
import { MemorySlotData } from './MemorySlot';
|
|
5
|
-
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
6
|
-
import { BytesWriter } from '../buffer/BytesWriter';
|
|
7
3
|
import { Address } from '../types/Address';
|
|
4
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
5
|
+
import { EMPTY_BUFFER } from '../math/bytes';
|
|
8
6
|
|
|
9
7
|
@final
|
|
10
|
-
export class AddressMemoryMap
|
|
8
|
+
export class AddressMemoryMap {
|
|
11
9
|
public pointer: u16;
|
|
12
10
|
|
|
13
11
|
constructor(
|
|
14
12
|
pointer: u16,
|
|
15
|
-
private readonly defaultValue: V,
|
|
16
13
|
) {
|
|
17
14
|
this.pointer = pointer;
|
|
18
15
|
}
|
|
19
16
|
|
|
20
|
-
public
|
|
21
|
-
const keyHash:
|
|
17
|
+
public setAsUint8Array(key: Address, value: Uint8Array): this {
|
|
18
|
+
const keyHash: Uint8Array = this.encodePointer(key);
|
|
22
19
|
Blockchain.setStorageAt(keyHash, value);
|
|
23
20
|
|
|
24
21
|
return this;
|
|
25
22
|
}
|
|
26
23
|
|
|
27
|
-
public
|
|
28
|
-
|
|
24
|
+
public set(key: Address, value: u256): this {
|
|
25
|
+
return this.setAsUint8Array(key, value.toUint8Array(true));
|
|
26
|
+
}
|
|
29
27
|
|
|
30
|
-
|
|
28
|
+
public getAsUint8Array(key: Address): Uint8Array {
|
|
29
|
+
const keyHash: Uint8Array = this.encodePointer(key);
|
|
30
|
+
|
|
31
|
+
return Blockchain.getStorageAt(keyHash);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public get(address: Address): u256 {
|
|
35
|
+
const resp = this.getAsUint8Array(address);
|
|
36
|
+
|
|
37
|
+
return u256.fromUint8ArrayBE(resp);
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
public has(key: Address): bool {
|
|
34
|
-
const keyHash:
|
|
41
|
+
const keyHash: Uint8Array = this.encodePointer(key);
|
|
35
42
|
|
|
36
43
|
return Blockchain.hasStorageAt(keyHash);
|
|
37
44
|
}
|
|
38
45
|
|
|
39
|
-
@unsafe
|
|
40
46
|
public delete(key: Address): bool {
|
|
41
|
-
this.
|
|
47
|
+
this.setAsUint8Array(key, EMPTY_BUFFER);
|
|
42
48
|
|
|
43
49
|
return true;
|
|
44
50
|
}
|
|
@@ -48,10 +54,7 @@ export class AddressMemoryMap<V extends MemorySlotData<u256>> {
|
|
|
48
54
|
throw new Error('Method not implemented.');
|
|
49
55
|
}
|
|
50
56
|
|
|
51
|
-
private encodePointer(key: Address):
|
|
52
|
-
|
|
53
|
-
writer.writeBytes(key);
|
|
54
|
-
|
|
55
|
-
return encodePointer(this.pointer, writer.getBuffer());
|
|
57
|
+
private encodePointer(key: Address): Uint8Array {
|
|
58
|
+
return encodePointer(this.pointer, key.slice(0, 30), true);
|
|
56
59
|
}
|
|
57
60
|
}
|