@btc-vision/btc-runtime 1.5.6 → 1.5.7

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 CHANGED
@@ -1,46 +1,46 @@
1
1
  {
2
- "name": "@btc-vision/btc-runtime",
3
- "version": "1.5.6",
4
- "description": "Bitcoin Smart Contract Runtime",
5
- "main": "btc/index.ts",
6
- "scripts": {},
7
- "types": "btc/index.ts",
8
- "keywords": [
9
- "bitcoin",
10
- "smart",
11
- "contract",
12
- "runtime",
13
- "opnet",
14
- "OP_NET"
15
- ],
16
- "homepage": "https://opnet.org",
17
- "author": "BlobMaster41",
18
- "license": "MIT",
19
- "devDependencies": {
20
- "@types/node": "^22.13.10",
21
- "assemblyscript": "^0.27.35"
22
- },
23
- "repository": {
24
- "type": "git",
25
- "url": "https://github.com/btc-vision/btc-runtime"
26
- },
27
- "type": "module",
28
- "files": [
29
- "package.json",
30
- "runtime",
31
- "runtime/*.ts",
32
- "runtime/**/*.ts",
33
- "!**/*.js.map",
34
- "!**/*.tsbuildinfo",
35
- "test/*.ts"
36
- ],
37
- "dependencies": {
38
- "@assemblyscript/loader": "^0.27.35",
39
- "@btc-vision/as-bignum": "^0.0.5",
40
- "@eslint/js": "^9.22.0",
41
- "gulplog": "^2.2.0",
42
- "ts-node": "^10.9.2",
43
- "typescript": "^5.8.2",
44
- "typescript-eslint": "^8.26.1"
45
- }
2
+ "name": "@btc-vision/btc-runtime",
3
+ "version": "1.5.7",
4
+ "description": "Bitcoin Smart Contract Runtime",
5
+ "main": "btc/index.ts",
6
+ "scripts": {},
7
+ "types": "btc/index.ts",
8
+ "keywords": [
9
+ "bitcoin",
10
+ "smart",
11
+ "contract",
12
+ "runtime",
13
+ "opnet",
14
+ "OP_NET"
15
+ ],
16
+ "homepage": "https://opnet.org",
17
+ "author": "BlobMaster41",
18
+ "license": "MIT",
19
+ "devDependencies": {
20
+ "@types/node": "^22.13.10",
21
+ "assemblyscript": "^0.27.35"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/btc-vision/btc-runtime"
26
+ },
27
+ "type": "module",
28
+ "files": [
29
+ "package.json",
30
+ "runtime",
31
+ "runtime/*.ts",
32
+ "runtime/**/*.ts",
33
+ "!**/*.js.map",
34
+ "!**/*.tsbuildinfo",
35
+ "test/*.ts"
36
+ ],
37
+ "dependencies": {
38
+ "@assemblyscript/loader": "^0.27.35",
39
+ "@btc-vision/as-bignum": "^0.0.5",
40
+ "@eslint/js": "^9.22.0",
41
+ "gulplog": "^2.2.0",
42
+ "ts-node": "^10.9.2",
43
+ "typescript": "^5.8.2",
44
+ "typescript-eslint": "^8.26.1"
45
+ }
46
46
  }
@@ -39,7 +39,7 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
39
39
 
40
40
  protected readonly _nonceMap: AddressMemoryMap;
41
41
 
42
- protected constructor(params: OP20InitParameters | null = null) {
42
+ public constructor(params: OP20InitParameters | null = null) {
43
43
  super();
44
44
 
45
45
  // Initialize main storage structures
@@ -3,7 +3,7 @@ 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 {
6
- protected constructor(maxSupply: u256, decimals: u8, name: string, symbol: string) {
6
+ public constructor(maxSupply: u256, decimals: u8, name: string, symbol: string) {
7
7
  super(new OP20InitParameters(maxSupply, decimals, name, symbol));
8
8
  }
9
9
  }
@@ -25,13 +25,10 @@ import { eqUint, MapUint8Array } from '../generic/MapUint8Array';
25
25
  import { EMPTY_BUFFER } from '../math/bytes';
26
26
  import { Plugin } from '../plugins/Plugin';
27
27
  import { Calldata } from '../types';
28
+ import { Revert } from '../types/Revert';
28
29
 
29
30
  export * from '../env/global';
30
31
 
31
- export function runtimeError(msg: string): Error {
32
- return new Error(`RuntimeException: ${msg}`);
33
- }
34
-
35
32
  @final
36
33
  export class BlockchainEnvironment {
37
34
  private static readonly MAX_U16: u16 = 65535;
@@ -47,7 +44,7 @@ export class BlockchainEnvironment {
47
44
  @inline
48
45
  public get block(): Block {
49
46
  if (!this._block) {
50
- throw this.error('Block is required');
47
+ throw new Revert('Block is required');
51
48
  }
52
49
 
53
50
  return this._block as Block;
@@ -58,7 +55,7 @@ export class BlockchainEnvironment {
58
55
  @inline
59
56
  public get tx(): Transaction {
60
57
  if (!this._tx) {
61
- throw this.error('Transaction is required');
58
+ throw new Revert('Transaction is required');
62
59
  }
63
60
 
64
61
  return this._tx as Transaction;
@@ -80,7 +77,7 @@ export class BlockchainEnvironment {
80
77
 
81
78
  public get nextPointer(): u16 {
82
79
  if (this._nextPointer === BlockchainEnvironment.MAX_U16) {
83
- throw this.error(`Out of storage pointer.`);
80
+ throw new Revert(`Out of storage pointer.`);
84
81
  }
85
82
 
86
83
  this._nextPointer += 1;
@@ -92,7 +89,7 @@ export class BlockchainEnvironment {
92
89
 
93
90
  public get contractDeployer(): Address {
94
91
  if (!this._contractDeployer) {
95
- throw this.error('Deployer is required');
92
+ throw new Revert('Deployer is required');
96
93
  }
97
94
 
98
95
  return this._contractDeployer as Address;
@@ -102,7 +99,7 @@ export class BlockchainEnvironment {
102
99
 
103
100
  public get contractAddress(): Address {
104
101
  if (!this._contractAddress) {
105
- throw this.error('Contract address is required');
102
+ throw new Revert('Contract address is required');
106
103
  }
107
104
 
108
105
  return this._contractAddress as Address;
@@ -171,12 +168,8 @@ export class BlockchainEnvironment {
171
168
  }
172
169
 
173
170
  public call(destinationContract: Address, calldata: BytesWriter): BytesReader {
174
- if (destinationContract === this.contractAddress) {
175
- throw this.error('Cannot call self');
176
- }
177
-
178
171
  if (!destinationContract) {
179
- throw this.error('Destination contract is required');
172
+ throw new Revert('Destination contract is required');
180
173
  }
181
174
 
182
175
  const resultLengthBuffer = new ArrayBuffer(32);
@@ -234,7 +227,7 @@ export class BlockchainEnvironment {
234
227
  );
235
228
 
236
229
  if (status !== 0) {
237
- throw this.error('Failed to deploy contract');
230
+ throw new Revert('Failed to deploy contract');
238
231
  }
239
232
 
240
233
  const contractAddressReader = new BytesReader(Uint8Array.wrap(resultAddressBuffer));
@@ -283,7 +276,7 @@ export class BlockchainEnvironment {
283
276
 
284
277
  private createContractIfNotExists(): void {
285
278
  if (!this._contract) {
286
- throw this.error('Contract is required');
279
+ throw new Revert('Contract is required');
287
280
  }
288
281
 
289
282
  if (!this._selfContract) {
@@ -291,10 +284,6 @@ export class BlockchainEnvironment {
291
284
  }
292
285
  }
293
286
 
294
- private error(msg: string): Error {
295
- return runtimeError(msg);
296
- }
297
-
298
287
  private _internalSetStorageAt(pointerHash: Uint8Array, value: Uint8Array): void {
299
288
  this.storage.set(pointerHash, value);
300
289
 
@@ -49,7 +49,7 @@ export abstract class StoredPackedArray<T> {
49
49
  */
50
50
  protected readonly MAX_LENGTH: u64 = <u64>(u32.MAX_VALUE - 1);
51
51
 
52
- protected constructor(public pointer: u16, public subPointer: Uint8Array) {
52
+ protected constructor(public pointer: u16, public subPointer: Uint8Array, protected defaultValue: T) {
53
53
  assert(subPointer.length <= 30, `You must pass a 30 bytes sub-pointer. (Array, got ${subPointer.length})`);
54
54
 
55
55
  const basePointer = encodeBasePointer(pointer, subPointer);
@@ -66,6 +66,24 @@ export abstract class StoredPackedArray<T> {
66
66
  @inline
67
67
  @operator('[]')
68
68
  public get(index: u64): T {
69
+ // max length used on purpose to prevent unbounded usage
70
+ if (index > this.MAX_LENGTH) {
71
+ throw new Revert('get: out of range');
72
+ }
73
+
74
+ const realIndex = (this._startIndex + index) % this.MAX_LENGTH;
75
+ const cap = this.getSlotCapacity();
76
+ const slotIndex = realIndex / cap;
77
+ const subIndex = <u32>(realIndex % cap);
78
+
79
+ const slotData = this.ensureSlot(slotIndex);
80
+ const arr = this.unpackSlot(slotData);
81
+
82
+ return arr[subIndex];
83
+ }
84
+
85
+ @inline
86
+ public get_physical(index: u64): T {
69
87
  if (index > this.MAX_LENGTH) {
70
88
  throw new Revert('get: index exceeds MAX_LENGTH (packed array)');
71
89
  }
@@ -74,11 +92,9 @@ export abstract class StoredPackedArray<T> {
74
92
  const slotIndex = index / cap;
75
93
  const subIndex = <u32>(index % cap);
76
94
 
77
- // Load the slot if not cached
78
95
  const slotData = this.ensureSlot(slotIndex);
79
-
80
- // Unpack and return the subIndex
81
96
  const arr = this.unpackSlot(slotData);
97
+
82
98
  return arr[subIndex];
83
99
  }
84
100
 
@@ -89,6 +105,28 @@ export abstract class StoredPackedArray<T> {
89
105
  throw new Revert('set: index exceeds MAX_LENGTH (packed array)');
90
106
  }
91
107
 
108
+ const realIndex = (this._startIndex + index) % this.MAX_LENGTH;
109
+ const cap = this.getSlotCapacity();
110
+ const slotIndex = realIndex / cap;
111
+ const subIndex = <u32>(realIndex % cap);
112
+
113
+ let slotData = this.ensureSlot(slotIndex);
114
+ const arr = this.unpackSlot(slotData);
115
+
116
+ if (!this.eq(arr[subIndex], value)) {
117
+ arr[subIndex] = value;
118
+ slotData = this.packSlot(arr);
119
+ this._slots.set(slotIndex, slotData);
120
+ this._isChanged.add(slotIndex);
121
+ }
122
+ }
123
+
124
+ @inline
125
+ public set_physical(index: u64, value: T): void {
126
+ if (index > this.MAX_LENGTH) {
127
+ throw new Revert('set: index exceeds MAX_LENGTH (packed array)');
128
+ }
129
+
92
130
  const cap = this.getSlotCapacity();
93
131
  const slotIndex = index / cap;
94
132
  const subIndex = <u32>(index % cap);
@@ -105,15 +143,15 @@ export abstract class StoredPackedArray<T> {
105
143
  }
106
144
 
107
145
  @inline
108
- public push(value: T): void {
146
+ public push(value: T, isPhysical: bool = false): void {
109
147
  if (this._length >= this.MAX_LENGTH) {
110
- throw new Revert('push: array has reached MAX_LENGTH (packed array)');
148
+ throw new Revert('push: array has reached MAX_LENGTH');
111
149
  }
112
150
 
113
- const newIndex = this._length;
151
+ const realIndex = ((isPhysical ? 0 : this._startIndex) + this._length) % this.MAX_LENGTH;
114
152
  const cap = this.getSlotCapacity();
115
- const slotIndex = newIndex / cap;
116
- const subIndex = <u32>(newIndex % cap);
153
+ const slotIndex = realIndex / cap;
154
+ const subIndex = <u32>(realIndex % cap);
117
155
 
118
156
  let slotData = this.ensureSlot(slotIndex);
119
157
  const arr = this.unpackSlot(slotData);
@@ -129,12 +167,70 @@ export abstract class StoredPackedArray<T> {
129
167
  this._isChangedLength = true;
130
168
  }
131
169
 
170
+ /**
171
+ * Remove the first element by zeroing it and shifting all other elements.
172
+ */
173
+ @inline
174
+ public shift(): T {
175
+ if (this._length == 0) {
176
+ throw new Revert('shift: array is empty (packed array)');
177
+ }
178
+
179
+ const newIndex = this._startIndex;
180
+ const cap = this.getSlotCapacity();
181
+ const slotIndex = newIndex / cap;
182
+ const subIndex = <u32>(newIndex % cap);
183
+
184
+ let slotData = this.ensureSlot(slotIndex);
185
+
186
+ const arr = this.unpackSlot(slotData);
187
+ const currentData = arr[subIndex];
188
+
189
+ if (!this.eq(currentData, this.defaultValue)) {
190
+ arr[subIndex] = this.defaultValue;
191
+ slotData = this.packSlot(arr);
192
+
193
+ this._slots.set(slotIndex, slotData);
194
+ this._isChanged.add(slotIndex);
195
+ }
196
+
197
+ this._length -= 1;
198
+ this._startIndex += 1;
199
+ this._isChangedLength = true;
200
+ this._isChangedStartIndex = true;
201
+
202
+ return currentData;
203
+ }
204
+
132
205
  /**
133
206
  * "Delete" by zeroing out the element at `index`,
134
207
  * but does not reduce the length.
135
208
  */
136
209
  @inline
137
210
  public delete(index: u64): void {
211
+ const realIndex = (this._startIndex + index) % this.MAX_LENGTH;
212
+ const cap = this.getSlotCapacity();
213
+ const slotIndex = realIndex / cap;
214
+ const subIndex = <u32>(realIndex % cap);
215
+
216
+ let slotData = this.ensureSlot(slotIndex);
217
+ const arr = this.unpackSlot(slotData);
218
+
219
+ const zeroVal = this.zeroValue();
220
+ if (!this.eq(arr[subIndex], zeroVal)) {
221
+ arr[subIndex] = zeroVal;
222
+ slotData = this.packSlot(arr);
223
+ this._slots.set(slotIndex, slotData);
224
+ this._isChanged.add(slotIndex);
225
+ }
226
+ }
227
+
228
+ /**
229
+ * "Delete" by zeroing out the element at `index`,
230
+ * but does not reduce the length.
231
+ */
232
+ @inline
233
+ public delete_physical(index: u64): void {
138
234
  const cap = this.getSlotCapacity();
139
235
  const slotIndex = index / cap;
140
236
  const subIndex = <u32>(index % cap);
@@ -10,7 +10,7 @@ import { bigEndianAdd } from '../../math/bytes';
10
10
  @final
11
11
  export class StoredU128Array extends StoredPackedArray<u128> {
12
12
  public constructor(pointer: u16, subPointer: Uint8Array) {
13
- super(pointer, subPointer);
13
+ super(pointer, subPointer, u128.Zero);
14
14
  }
15
15
 
16
16
  protected getSlotCapacity(): u64 {
@@ -7,7 +7,7 @@ import { bigEndianAdd } from '../../math/bytes';
7
7
  @final
8
8
  export class StoredU16Array extends StoredPackedArray<u16> {
9
9
  public constructor(pointer: u16, subPointer: Uint8Array) {
10
- super(pointer, subPointer);
10
+ super(pointer, subPointer, 0);
11
11
  }
12
12
 
13
13
  protected getSlotCapacity(): u64 {
@@ -9,7 +9,7 @@ import { bigEndianAdd } from '../../math/bytes';
9
9
  @final
10
10
  export class StoredU256Array extends StoredPackedArray<u256> {
11
11
  public constructor(pointer: u16, subPointer: Uint8Array) {
12
- super(pointer, subPointer);
12
+ super(pointer, subPointer, u256.Zero);
13
13
  }
14
14
 
15
15
  protected getSlotCapacity(): u64 {
@@ -8,7 +8,7 @@ import { bigEndianAdd } from '../../math/bytes';
8
8
  @final
9
9
  export class StoredU32Array extends StoredPackedArray<u32> {
10
10
  public constructor(pointer: u16, subPointer: Uint8Array) {
11
- super(pointer, subPointer);
11
+ super(pointer, subPointer, 0);
12
12
  }
13
13
 
14
14
  protected getSlotCapacity(): u64 {
@@ -8,7 +8,7 @@ import { bigEndianAdd } from '../../math/bytes';
8
8
  @final
9
9
  export class StoredU64Array extends StoredPackedArray<u64> {
10
10
  public constructor(pointer: u16, subPointer: Uint8Array) {
11
- super(pointer, subPointer);
11
+ super(pointer, subPointer, 0);
12
12
  }
13
13
 
14
14
  protected getSlotCapacity(): u64 {
@@ -8,7 +8,7 @@ import { bigEndianAdd } from '../../math/bytes';
8
8
  @final
9
9
  export class StoredU8Array extends StoredPackedArray<u8> {
10
10
  public constructor(pointer: u16, subPointer: Uint8Array) {
11
- super(pointer, subPointer);
11
+ super(pointer, subPointer, 0);
12
12
  }
13
13
 
14
14
  protected getSlotCapacity(): u64 {