@btc-vision/btc-runtime 1.4.7 → 1.5.1
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 +4 -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 +33 -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 +83 -175
- package/runtime/storage/arrays/StoredBooleanArray.ts +146 -271
- package/runtime/storage/arrays/StoredPackedArray.ts +313 -0
- package/runtime/storage/arrays/StoredU128Array.ts +38 -374
- package/runtime/storage/arrays/StoredU16Array.ts +34 -420
- package/runtime/storage/arrays/StoredU256Array.ts +21 -347
- package/runtime/storage/arrays/StoredU32Array.ts +37 -440
- package/runtime/storage/arrays/StoredU64Array.ts +66 -0
- package/runtime/storage/arrays/StoredU8Array.ts +29 -453
- 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
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { Revert } from '../types/Revert';
|
|
2
|
+
import { ArrayBuffer } from 'arraybuffer';
|
|
3
|
+
|
|
4
|
+
export class FastUint8Array {
|
|
5
|
+
public length: i32;
|
|
6
|
+
private ptr: usize;
|
|
7
|
+
|
|
8
|
+
[key: number]: u8;
|
|
9
|
+
|
|
10
|
+
constructor(length: i32) {
|
|
11
|
+
if (length < 0) {
|
|
12
|
+
throw new Revert('Negative length in FastUint8Array constructor');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
this.length = length;
|
|
16
|
+
this.ptr = __alloc(<usize>length);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public static fromUint8Array(arr: Uint8Array): FastUint8Array {
|
|
20
|
+
const buffer = new FastUint8Array(arr.length);
|
|
21
|
+
for (let i: u32 = 0; i < arr.length; i++) {
|
|
22
|
+
buffer[i] = arr[i];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return buffer;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
toArrayBuffer(): ArrayBuffer {
|
|
29
|
+
const arr = new Uint8Array(this.length);
|
|
30
|
+
for (let i: u32 = 0; i < arr.length; i++) {
|
|
31
|
+
arr[i] = this[i];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return arr.buffer;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Fills the buffer with a specified byte value.
|
|
39
|
+
*/
|
|
40
|
+
fill(value: u8): void {
|
|
41
|
+
memory.fill(this.ptr, value, <usize>this.length);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Copies bytes from another FastUint8Array into this one, starting at `destOffset`.
|
|
46
|
+
*/
|
|
47
|
+
copyFrom(source: FastUint8Array, destOffset: i32 = 0): void {
|
|
48
|
+
if (destOffset < 0) {
|
|
49
|
+
throw new Revert(`Negative destOffset in copyFrom: ${destOffset}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let maxBytes = source.length;
|
|
53
|
+
const destRemaining = this.length - destOffset;
|
|
54
|
+
if (destRemaining < maxBytes) {
|
|
55
|
+
maxBytes = destRemaining;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (maxBytes <= 0) return;
|
|
59
|
+
|
|
60
|
+
memory.copy(
|
|
61
|
+
this.ptr + <usize>destOffset,
|
|
62
|
+
source.ptr,
|
|
63
|
+
<usize>maxBytes,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
free(): void {
|
|
68
|
+
if (this.ptr != 0) {
|
|
69
|
+
__free(this.ptr);
|
|
70
|
+
this.ptr = 0;
|
|
71
|
+
this.length = 0;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Safe read operator: buffer[i]
|
|
77
|
+
* Throws on out-of-bounds.
|
|
78
|
+
*/
|
|
79
|
+
@operator('[]')
|
|
80
|
+
private __get(index: i32): u8 {
|
|
81
|
+
if (<u32>index >= <u32>this.length) {
|
|
82
|
+
throw new Revert('Index out of range in __get');
|
|
83
|
+
}
|
|
84
|
+
return load<u8>(this.ptr + <usize>index);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Safe write operator: buffer[i] = value
|
|
89
|
+
* Throws on out-of-bounds.
|
|
90
|
+
*/
|
|
91
|
+
@operator('[]=')
|
|
92
|
+
private __set(index: i32, value: u8): void {
|
|
93
|
+
if (<u32>index >= <u32>this.length) {
|
|
94
|
+
throw new Revert('Index out of range in __set');
|
|
95
|
+
}
|
|
96
|
+
store<u8>(this.ptr + <usize>index, value);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Braces read operator: buffer{i}
|
|
101
|
+
* Now also throws on out-of-bounds for safety.
|
|
102
|
+
*/
|
|
103
|
+
@operator('{}')
|
|
104
|
+
private __uget(index: i32): u8 {
|
|
105
|
+
if (<u32>index >= <u32>this.length) {
|
|
106
|
+
throw new Revert('Index out of range in __uget');
|
|
107
|
+
}
|
|
108
|
+
return load<u8>(this.ptr + <usize>index);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Braces write operator: buffer{i} = value
|
|
113
|
+
* Now also throws on out-of-bounds.
|
|
114
|
+
*/
|
|
115
|
+
@operator('{}=')
|
|
116
|
+
private __uset(index: i32, value: u8): void {
|
|
117
|
+
if (<u32>index >= <u32>this.length) {
|
|
118
|
+
throw new Revert('Index out of range in __uset');
|
|
119
|
+
}
|
|
120
|
+
store<u8>(this.ptr + <usize>index, value);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -1,44 +1,34 @@
|
|
|
1
|
-
import { MemorySlotData } from './MemorySlot';
|
|
2
|
-
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
3
|
-
import { Blockchain } from '../env';
|
|
4
|
-
import { MemorySlotPointer } from './MemorySlotPointer';
|
|
5
|
-
import { encodePointer } from '../math/abi';
|
|
6
1
|
import { BytesWriter } from '../buffer/BytesWriter';
|
|
2
|
+
import { Blockchain } from '../env';
|
|
3
|
+
import { encodePointerUnknownLength } from '../math/abi';
|
|
4
|
+
|
|
7
5
|
|
|
8
6
|
@final
|
|
9
|
-
export class KeyMerger<K extends string, K2 extends string, V extends
|
|
7
|
+
export class KeyMerger<K extends string, K2 extends string, V extends Uint8Array> {
|
|
10
8
|
public parentKey: K;
|
|
11
|
-
|
|
12
9
|
public pointer: u16;
|
|
13
10
|
|
|
14
|
-
constructor(
|
|
15
|
-
parent: K,
|
|
16
|
-
pointer: u16,
|
|
17
|
-
private readonly defaultValue: V,
|
|
18
|
-
) {
|
|
11
|
+
constructor(parent: K, pointer: u16) {
|
|
19
12
|
this.pointer = pointer;
|
|
20
|
-
|
|
21
13
|
this.parentKey = parent;
|
|
22
14
|
}
|
|
23
15
|
|
|
24
16
|
public set(key2: K2, value: V): this {
|
|
25
|
-
const mergedKey: string =
|
|
26
|
-
const keyHash:
|
|
17
|
+
const mergedKey: string = this.mergeKey(key2);
|
|
18
|
+
const keyHash: Uint8Array = this.encodePointer(mergedKey);
|
|
27
19
|
|
|
28
20
|
Blockchain.setStorageAt(keyHash, value);
|
|
29
21
|
|
|
30
22
|
return this;
|
|
31
23
|
}
|
|
32
24
|
|
|
33
|
-
public get(key: K):
|
|
34
|
-
const mergedKey: string =
|
|
35
|
-
|
|
36
|
-
return Blockchain.getStorageAt(this.encodePointer(mergedKey), this.defaultValue);
|
|
25
|
+
public get(key: K): Uint8Array {
|
|
26
|
+
const mergedKey: string = this.mergeKey(key);
|
|
27
|
+
return Blockchain.getStorageAt(this.encodePointer(mergedKey));
|
|
37
28
|
}
|
|
38
29
|
|
|
39
30
|
public has(key: K): bool {
|
|
40
|
-
const mergedKey: string =
|
|
41
|
-
|
|
31
|
+
const mergedKey: string = this.mergeKey(key);
|
|
42
32
|
return Blockchain.hasStorageAt(this.encodePointer(mergedKey));
|
|
43
33
|
}
|
|
44
34
|
|
|
@@ -52,10 +42,22 @@ export class KeyMerger<K extends string, K2 extends string, V extends MemorySlot
|
|
|
52
42
|
throw new Error('Clear method not implemented.');
|
|
53
43
|
}
|
|
54
44
|
|
|
55
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Merges the parentKey and the provided key by prefixing each with its length.
|
|
47
|
+
* This avoids collisions such as:
|
|
48
|
+
* parentKey = "abc", key = "def" => "3:abc3:def"
|
|
49
|
+
* parentKey = "ab", key = "cdef" => "2:ab4:cdef"
|
|
50
|
+
*/
|
|
51
|
+
@inline
|
|
52
|
+
private mergeKey(key: string): string {
|
|
53
|
+
return `${this.parentKey.length}:${this.parentKey}${key.length}:${key}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@inline
|
|
57
|
+
private encodePointer(key: string): Uint8Array {
|
|
56
58
|
const writer = new BytesWriter(key.length);
|
|
57
59
|
writer.writeString(key);
|
|
58
60
|
|
|
59
|
-
return
|
|
61
|
+
return encodePointerUnknownLength(this.pointer, writer.getBuffer());
|
|
60
62
|
}
|
|
61
63
|
}
|
|
@@ -1,51 +1,54 @@
|
|
|
1
|
-
import { MemorySlotData } from './MemorySlot';
|
|
2
|
-
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
3
1
|
import { Uint8ArrayMerger } from './Uint8ArrayMerger';
|
|
4
2
|
import { Address } from '../types/Address';
|
|
5
3
|
|
|
6
4
|
@final
|
|
7
|
-
export class MultiAddressMemoryMap
|
|
5
|
+
export class MultiAddressMemoryMap extends Map<
|
|
8
6
|
Address,
|
|
9
|
-
Uint8ArrayMerger
|
|
7
|
+
Uint8ArrayMerger
|
|
10
8
|
> {
|
|
11
9
|
public pointer: u16;
|
|
12
10
|
|
|
13
11
|
constructor(
|
|
14
12
|
pointer: u16,
|
|
15
|
-
private readonly defaultValue: V,
|
|
16
13
|
) {
|
|
17
14
|
super();
|
|
18
15
|
|
|
19
16
|
this.pointer = pointer;
|
|
20
17
|
}
|
|
21
18
|
|
|
22
|
-
|
|
19
|
+
@inline
|
|
20
|
+
public get(key: Address): Uint8ArrayMerger {
|
|
23
21
|
this.createKeyMerger(key);
|
|
24
22
|
|
|
25
23
|
return super.get(key);
|
|
26
24
|
}
|
|
27
25
|
|
|
28
|
-
|
|
26
|
+
@inline
|
|
27
|
+
public set(key: Address, value: Uint8ArrayMerger): this {
|
|
29
28
|
this.createKeyMerger(key);
|
|
30
29
|
|
|
31
30
|
return <this>super.set(key, value);
|
|
32
31
|
}
|
|
33
32
|
|
|
33
|
+
@inline
|
|
34
34
|
public has(key: Address): bool {
|
|
35
35
|
return super.has(key);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
@inline
|
|
38
39
|
public delete(key: Address): bool {
|
|
39
40
|
return super.delete(key);
|
|
40
41
|
}
|
|
41
42
|
|
|
43
|
+
@inline
|
|
42
44
|
public clear(): void {
|
|
43
45
|
super.clear();
|
|
44
46
|
}
|
|
45
47
|
|
|
48
|
+
@inline
|
|
46
49
|
private createKeyMerger(key: Address): void {
|
|
47
50
|
if (!super.has(key)) {
|
|
48
|
-
super.set(key, new Uint8ArrayMerger
|
|
51
|
+
super.set(key, new Uint8ArrayMerger(key, this.pointer));
|
|
49
52
|
}
|
|
50
53
|
}
|
|
51
54
|
}
|
|
@@ -1,30 +1,29 @@
|
|
|
1
|
-
import { MemorySlotData } from './MemorySlot';
|
|
2
|
-
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
3
1
|
import { KeyMerger } from './KeyMerger';
|
|
4
2
|
|
|
5
3
|
@final
|
|
6
4
|
export class MultiStringMemoryMap<
|
|
7
5
|
K extends string,
|
|
8
6
|
K2 extends string,
|
|
9
|
-
V extends
|
|
7
|
+
V extends Uint8Array,
|
|
10
8
|
> extends Map<K, KeyMerger<K, K2, V>> {
|
|
11
9
|
public pointer: u16;
|
|
12
10
|
|
|
13
11
|
constructor(
|
|
14
12
|
pointer: u16,
|
|
15
|
-
private readonly defaultValue: V,
|
|
16
13
|
) {
|
|
17
14
|
super();
|
|
18
15
|
|
|
19
16
|
this.pointer = pointer;
|
|
20
17
|
}
|
|
21
18
|
|
|
19
|
+
@inline
|
|
22
20
|
public get(key: K): KeyMerger<K, K2, V> {
|
|
23
21
|
this.createKeyMerger(key);
|
|
24
22
|
|
|
25
23
|
return super.get(key);
|
|
26
24
|
}
|
|
27
25
|
|
|
26
|
+
@inline
|
|
28
27
|
public setUpperKey(key: K, key2: K2, value: V): this {
|
|
29
28
|
this.createKeyMerger(key);
|
|
30
29
|
|
|
@@ -36,27 +35,31 @@ export class MultiStringMemoryMap<
|
|
|
36
35
|
return this;
|
|
37
36
|
}
|
|
38
37
|
|
|
38
|
+
@inline
|
|
39
39
|
public set(key: K, value: KeyMerger<K, K2, V>): this {
|
|
40
40
|
this.createKeyMerger(key);
|
|
41
41
|
|
|
42
42
|
return <this>super.set(key, value);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
@inline
|
|
45
46
|
public has(key: K): bool {
|
|
46
47
|
return super.has(key);
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
@inline
|
|
49
51
|
public delete(key: K): bool {
|
|
50
52
|
return super.delete(key);
|
|
51
53
|
}
|
|
52
54
|
|
|
55
|
+
@inline
|
|
53
56
|
public clear(): void {
|
|
54
57
|
super.clear();
|
|
55
58
|
}
|
|
56
59
|
|
|
57
60
|
private createKeyMerger(key: K): void {
|
|
58
61
|
if (!super.has(key)) {
|
|
59
|
-
super.set(key, new KeyMerger<K, K2, V>(key, this.pointer
|
|
62
|
+
super.set(key, new KeyMerger<K, K2, V>(key, this.pointer));
|
|
60
63
|
}
|
|
61
64
|
}
|
|
62
65
|
}
|
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
import { MemorySlotPointer } from './MemorySlotPointer';
|
|
2
1
|
import { Blockchain } from '../env';
|
|
3
|
-
import {
|
|
4
|
-
import { MemorySlotData } from './MemorySlot';
|
|
5
|
-
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
2
|
+
import { encodePointerUnknownLength } from '../math/abi';
|
|
6
3
|
import { BytesWriter } from '../buffer/BytesWriter';
|
|
4
|
+
import { EMPTY_BUFFER } from '../math/bytes';
|
|
7
5
|
|
|
8
6
|
@final
|
|
9
|
-
export class StringMemoryMap<K extends string
|
|
7
|
+
export class StringMemoryMap<K extends string> {
|
|
10
8
|
public pointer: u16;
|
|
11
9
|
|
|
12
10
|
constructor(
|
|
13
11
|
pointer: u16,
|
|
14
|
-
private readonly defaultValue: V,
|
|
15
12
|
) {
|
|
16
13
|
this.pointer = pointer;
|
|
17
14
|
}
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
@inline
|
|
17
|
+
public set(key: K, value: Uint8Array): this {
|
|
18
|
+
const keyHash: Uint8Array = this.encodePointer(key);
|
|
21
19
|
Blockchain.setStorageAt(keyHash, value);
|
|
22
20
|
|
|
23
21
|
return this;
|
|
24
22
|
}
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
@inline
|
|
25
|
+
public get(key: K): Uint8Array {
|
|
26
|
+
const keyHash: Uint8Array = this.encodePointer(key);
|
|
28
27
|
|
|
29
|
-
return Blockchain.getStorageAt(keyHash
|
|
28
|
+
return Blockchain.getStorageAt(keyHash);
|
|
30
29
|
}
|
|
31
30
|
|
|
31
|
+
@inline
|
|
32
32
|
public has(key: K): bool {
|
|
33
|
-
const keyHash:
|
|
33
|
+
const keyHash: Uint8Array = this.encodePointer(key);
|
|
34
34
|
|
|
35
35
|
return Blockchain.hasStorageAt(keyHash);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
@unsafe
|
|
39
39
|
public delete(key: K): bool {
|
|
40
|
-
this.set(key,
|
|
40
|
+
this.set(key, EMPTY_BUFFER);
|
|
41
41
|
|
|
42
42
|
return true;
|
|
43
43
|
}
|
|
@@ -47,10 +47,10 @@ export class StringMemoryMap<K extends string, V extends MemorySlotData<u256>> {
|
|
|
47
47
|
throw new Error('Method not implemented.');
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
private encodePointer(key: K):
|
|
50
|
+
private encodePointer(key: K): Uint8Array {
|
|
51
51
|
const writer = new BytesWriter(key.length);
|
|
52
52
|
writer.writeString(key);
|
|
53
53
|
|
|
54
|
-
return
|
|
54
|
+
return encodePointerUnknownLength(this.pointer, writer.getBuffer());
|
|
55
55
|
}
|
|
56
56
|
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import { MemorySlotData } from './MemorySlot';
|
|
2
|
-
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
3
1
|
import { Blockchain } from '../env';
|
|
4
|
-
import {
|
|
5
|
-
import { encodePointer } from '../math/abi';
|
|
2
|
+
import { encodePointerUnknownLength } from '../math/abi';
|
|
6
3
|
import { BytesWriter } from '../buffer/BytesWriter';
|
|
4
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
7
5
|
|
|
8
6
|
@final
|
|
9
|
-
export class Uint8ArrayMerger
|
|
7
|
+
export class Uint8ArrayMerger {
|
|
10
8
|
public parentKey: Uint8Array;
|
|
11
9
|
|
|
12
10
|
public pointer: u16;
|
|
@@ -14,28 +12,37 @@ export class Uint8ArrayMerger<V extends MemorySlotData<u256>> {
|
|
|
14
12
|
constructor(
|
|
15
13
|
parent: Uint8Array,
|
|
16
14
|
pointer: u16,
|
|
17
|
-
private readonly defaultValue: V,
|
|
18
15
|
) {
|
|
19
16
|
this.pointer = pointer;
|
|
20
17
|
|
|
21
18
|
this.parentKey = parent;
|
|
22
19
|
}
|
|
23
20
|
|
|
24
|
-
public
|
|
25
|
-
const keyHash:
|
|
21
|
+
public setAsUint8Array(key: Uint8Array, value: Uint8Array): this {
|
|
22
|
+
const keyHash: Uint8Array = this.getKeyHash(key);
|
|
26
23
|
Blockchain.setStorageAt(keyHash, value);
|
|
27
24
|
|
|
28
25
|
return this;
|
|
29
26
|
}
|
|
30
27
|
|
|
31
|
-
public
|
|
32
|
-
|
|
28
|
+
public set(key: Uint8Array, value: u256): this {
|
|
29
|
+
return this.setAsUint8Array(key, value.toUint8Array(true));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public getAsUint8Array(key: Uint8Array): Uint8Array {
|
|
33
|
+
const keyHash: Uint8Array = this.getKeyHash(key);
|
|
34
|
+
|
|
35
|
+
return Blockchain.getStorageAt(keyHash);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public get(key: Uint8Array): u256 {
|
|
39
|
+
const data = this.getAsUint8Array(key);
|
|
33
40
|
|
|
34
|
-
return
|
|
41
|
+
return u256.fromUint8ArrayBE(data);
|
|
35
42
|
}
|
|
36
43
|
|
|
37
44
|
public has(key: Uint8Array): bool {
|
|
38
|
-
const mergedKey:
|
|
45
|
+
const mergedKey: Uint8Array = this.getKeyHash(key);
|
|
39
46
|
|
|
40
47
|
return Blockchain.hasStorageAt(mergedKey);
|
|
41
48
|
}
|
|
@@ -50,7 +57,7 @@ export class Uint8ArrayMerger<V extends MemorySlotData<u256>> {
|
|
|
50
57
|
throw new Error('Clear method not implemented.');
|
|
51
58
|
}
|
|
52
59
|
|
|
53
|
-
private getKeyHash(key: Uint8Array):
|
|
60
|
+
private getKeyHash(key: Uint8Array): Uint8Array {
|
|
54
61
|
const writer: BytesWriter = new BytesWriter(key.byteLength + this.parentKey.byteLength);
|
|
55
62
|
|
|
56
63
|
writer.writeBytes(this.parentKey);
|
|
@@ -59,7 +66,7 @@ export class Uint8ArrayMerger<V extends MemorySlotData<u256>> {
|
|
|
59
66
|
return this.encodePointer(writer);
|
|
60
67
|
}
|
|
61
68
|
|
|
62
|
-
private encodePointer(writer: BytesWriter):
|
|
63
|
-
return
|
|
69
|
+
private encodePointer(writer: BytesWriter): Uint8Array {
|
|
70
|
+
return encodePointerUnknownLength(this.pointer, writer.getBuffer());
|
|
64
71
|
}
|
|
65
72
|
}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
2
1
|
import { BytesReader } from '../buffer/BytesReader';
|
|
3
2
|
import { BytesWriter } from '../buffer/BytesWriter';
|
|
4
3
|
import { Blockchain } from '../env';
|
|
5
4
|
import { encodePointer } from '../math/abi';
|
|
6
|
-
import { MemorySlotPointer } from '../memory/MemorySlotPointer';
|
|
7
5
|
import { Revert } from '../types/Revert';
|
|
8
|
-
|
|
6
|
+
|
|
7
|
+
export const SERIALIZED_POINTER_LENGTH: u8 = 29;
|
|
9
8
|
|
|
10
9
|
// Similar to a struct in Solidity. (Use in worst case scenario, consume a lot of gas)
|
|
11
10
|
export abstract class Serializable {
|
|
12
11
|
protected pointer: u16;
|
|
13
|
-
protected subPointer:
|
|
12
|
+
protected subPointer: Uint8Array;
|
|
13
|
+
|
|
14
|
+
protected constructor(pointer: u16, subPointer: Uint8Array) {
|
|
15
|
+
if (subPointer.length !== SERIALIZED_POINTER_LENGTH) throw new Revert(`Sub pointer length must be ${SERIALIZED_POINTER_LENGTH} bytes.`);
|
|
14
16
|
|
|
15
|
-
protected constructor(pointer: u16, subPointer: MemorySlotPointer) {
|
|
16
17
|
this.pointer = pointer;
|
|
17
18
|
this.subPointer = subPointer;
|
|
18
19
|
}
|
|
@@ -24,14 +25,14 @@ export abstract class Serializable {
|
|
|
24
25
|
|
|
25
26
|
public abstract readFromBuffer(reader: BytesReader): void;
|
|
26
27
|
|
|
27
|
-
public abstract exists(chunk:
|
|
28
|
+
public abstract exists(chunk: Uint8Array, index: u8): boolean;
|
|
28
29
|
|
|
29
30
|
public load(): boolean {
|
|
30
|
-
const chunks:
|
|
31
|
+
const chunks: Uint8Array[] = [];
|
|
31
32
|
|
|
32
33
|
for (let index: u8 = 0; index < this.chunkCount; index++) {
|
|
33
34
|
const pointer = this.getPointer(this.subPointer, index);
|
|
34
|
-
const chunk:
|
|
35
|
+
const chunk: Uint8Array = Blockchain.getStorageAt(pointer);
|
|
35
36
|
|
|
36
37
|
if (!this.exists(chunk, index)) {
|
|
37
38
|
return false;
|
|
@@ -49,7 +50,7 @@ export abstract class Serializable {
|
|
|
49
50
|
public save(): void {
|
|
50
51
|
const writer: BytesWriter = this.writeToBuffer();
|
|
51
52
|
const buffer = writer.getBuffer();
|
|
52
|
-
const chunks:
|
|
53
|
+
const chunks: Uint8Array[] = this.bytesToChunks(buffer);
|
|
53
54
|
|
|
54
55
|
if (chunks.length !== this.chunkCount) {
|
|
55
56
|
throw new Revert(
|
|
@@ -69,8 +70,8 @@ export abstract class Serializable {
|
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
72
|
|
|
72
|
-
protected bytesToChunks(buffer: Uint8Array):
|
|
73
|
-
const chunks:
|
|
73
|
+
protected bytesToChunks(buffer: Uint8Array): Uint8Array[] {
|
|
74
|
+
const chunks: Uint8Array[] = [];
|
|
74
75
|
|
|
75
76
|
for (let index: i32 = 0; index < buffer.byteLength; index += 32) {
|
|
76
77
|
if (chunks.length === 256) {
|
|
@@ -78,13 +79,13 @@ export abstract class Serializable {
|
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
const chunk = buffer.slice(index, index + 32);
|
|
81
|
-
chunks.push(
|
|
82
|
+
chunks.push(chunk);
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
return chunks;
|
|
85
86
|
}
|
|
86
87
|
|
|
87
|
-
protected chunksToBytes(chunks:
|
|
88
|
+
protected chunksToBytes(chunks: Uint8Array[]): BytesReader {
|
|
88
89
|
if (this.chunkCount > u8(255)) {
|
|
89
90
|
throw new Revert(`Too many chunks received. You may only write up to 8160 bytes per object.`);
|
|
90
91
|
}
|
|
@@ -93,7 +94,7 @@ export abstract class Serializable {
|
|
|
93
94
|
let offset: i32 = 0;
|
|
94
95
|
|
|
95
96
|
for (let indexChunk: i32 = 0; indexChunk < chunks.length; indexChunk++) {
|
|
96
|
-
const bytes:
|
|
97
|
+
const bytes: Uint8Array = chunks[indexChunk];
|
|
97
98
|
for (let indexByte: i32 = 0; indexByte < bytes.length; indexByte++) {
|
|
98
99
|
buffer[offset++] = bytes[indexByte];
|
|
99
100
|
}
|
|
@@ -102,12 +103,10 @@ export abstract class Serializable {
|
|
|
102
103
|
return new BytesReader(buffer);
|
|
103
104
|
}
|
|
104
105
|
|
|
105
|
-
protected getPointer(subPointer:
|
|
106
|
-
const writer = new BytesWriter(
|
|
107
|
-
writer.
|
|
108
|
-
|
|
109
|
-
// Discard the first byte for offset.
|
|
110
|
-
writer.writeU8At(index, 0);
|
|
106
|
+
protected getPointer(subPointer: Uint8Array, index: u8): Uint8Array {
|
|
107
|
+
const writer = new BytesWriter(30);
|
|
108
|
+
writer.writeU8(index);
|
|
109
|
+
writer.writeBytes(subPointer);
|
|
111
110
|
|
|
112
111
|
return encodePointer(this.pointer, writer.getBuffer());
|
|
113
112
|
}
|
|
@@ -1,31 +1,28 @@
|
|
|
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';
|
|
5
3
|
import { Address } from '../types/Address';
|
|
4
|
+
import { EMPTY_POINTER } from '../math/bytes';
|
|
5
|
+
import { eqUint } from '../generic/MapUint8Array';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Default is Address.dead();
|
|
9
|
+
*/
|
|
7
10
|
@final
|
|
8
11
|
export class StoredAddress {
|
|
9
|
-
private readonly addressPointer:
|
|
10
|
-
private readonly defaultValue: u256;
|
|
12
|
+
private readonly addressPointer: Uint8Array;
|
|
11
13
|
|
|
12
|
-
constructor(public pointer: u16
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
this.defaultValue = u256.fromBytes(defaultValue);
|
|
16
|
-
this.addressPointer = encodePointer(pointer, writer.getBuffer());
|
|
14
|
+
constructor(public pointer: u16) {
|
|
15
|
+
this.addressPointer = encodePointer(pointer, EMPTY_POINTER);
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
private _value: Address =
|
|
18
|
+
private _value: Address = Address.dead();
|
|
20
19
|
|
|
21
|
-
@inline
|
|
22
20
|
public get value(): Address {
|
|
23
21
|
this.ensureValue();
|
|
24
22
|
|
|
25
23
|
return this._value;
|
|
26
24
|
}
|
|
27
25
|
|
|
28
|
-
@inline
|
|
29
26
|
public set value(value: Address) {
|
|
30
27
|
if (value === this.value) {
|
|
31
28
|
return;
|
|
@@ -33,11 +30,15 @@ export class StoredAddress {
|
|
|
33
30
|
|
|
34
31
|
this._value = value;
|
|
35
32
|
|
|
36
|
-
Blockchain.setStorageAt(this.addressPointer,
|
|
33
|
+
Blockchain.setStorageAt(this.addressPointer, this._value);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public isDead(): bool {
|
|
37
|
+
return eqUint(Address.dead(), this.value);
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
private ensureValue(): void {
|
|
40
|
-
const value = Blockchain.getStorageAt(this.addressPointer
|
|
41
|
-
this._value.set(value
|
|
41
|
+
const value = Blockchain.getStorageAt(this.addressPointer);
|
|
42
|
+
this._value.set(value);
|
|
42
43
|
}
|
|
43
44
|
}
|