@aztec/simulator 0.26.6 → 0.27.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/dest/acvm/acvm.js +2 -2
- package/dest/acvm/serialize.d.ts.map +1 -1
- package/dest/acvm/serialize.js +8 -3
- package/dest/avm/avm_context.d.ts +3 -3
- package/dest/avm/avm_context.d.ts.map +1 -1
- package/dest/avm/avm_context.js +6 -5
- package/dest/avm/avm_execution_environment.d.ts +3 -3
- package/dest/avm/avm_execution_environment.d.ts.map +1 -1
- package/dest/avm/avm_execution_environment.js +16 -17
- package/dest/avm/avm_memory_types.d.ts +9 -0
- package/dest/avm/avm_memory_types.d.ts.map +1 -1
- package/dest/avm/avm_memory_types.js +34 -4
- package/dest/avm/avm_simulator.d.ts.map +1 -1
- package/dest/avm/avm_simulator.js +3 -3
- package/dest/avm/opcodes/arithmetic.d.ts.map +1 -1
- package/dest/avm/opcodes/arithmetic.js +2 -1
- package/dest/avm/opcodes/comparators.d.ts.map +1 -1
- package/dest/avm/opcodes/comparators.js +5 -7
- package/dest/avm/opcodes/control_flow.d.ts +0 -20
- package/dest/avm/opcodes/control_flow.d.ts.map +1 -1
- package/dest/avm/opcodes/control_flow.js +2 -46
- package/dest/avm/opcodes/external_calls.d.ts +24 -2
- package/dest/avm/opcodes/external_calls.d.ts.map +1 -1
- package/dest/avm/opcodes/external_calls.js +74 -17
- package/dest/avm/serialization/instruction_serialization.d.ts +1 -2
- package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
- package/dest/avm/serialization/instruction_serialization.js +9 -3
- package/dest/avm/temporary_executor_migration.d.ts.map +1 -1
- package/dest/avm/temporary_executor_migration.js +3 -1
- package/dest/client/client_execution_context.d.ts.map +1 -1
- package/dest/client/client_execution_context.js +4 -6
- package/dest/client/simulator.d.ts.map +1 -1
- package/dest/client/simulator.js +3 -3
- package/dest/public/execution.d.ts +2 -0
- package/dest/public/execution.d.ts.map +1 -1
- package/dest/public/execution.js +1 -1
- package/dest/public/executor.d.ts +21 -0
- package/dest/public/executor.d.ts.map +1 -1
- package/dest/public/executor.js +91 -2
- package/dest/public/public_execution_context.d.ts.map +1 -1
- package/dest/public/public_execution_context.js +1 -2
- package/package.json +5 -5
- package/src/acvm/acvm.ts +1 -1
- package/src/acvm/serialize.ts +9 -3
- package/src/avm/avm_context.ts +21 -5
- package/src/avm/avm_execution_environment.ts +27 -12
- package/src/avm/avm_memory_types.ts +36 -3
- package/src/avm/avm_simulator.ts +10 -3
- package/src/avm/opcodes/arithmetic.ts +2 -0
- package/src/avm/opcodes/comparators.ts +4 -6
- package/src/avm/opcodes/control_flow.ts +1 -47
- package/src/avm/opcodes/external_calls.ts +88 -14
- package/src/avm/serialization/instruction_serialization.ts +8 -2
- package/src/avm/temporary_executor_migration.ts +2 -0
- package/src/client/client_execution_context.ts +1 -13
- package/src/client/simulator.ts +1 -2
- package/src/public/execution.ts +2 -0
- package/src/public/executor.ts +103 -0
- package/src/public/public_execution_context.ts +0 -1
|
@@ -36,12 +36,19 @@ export class AvmExecutionEnvironment {
|
|
|
36
36
|
|
|
37
37
|
public readonly calldata: Fr[],
|
|
38
38
|
|
|
39
|
+
// Function selector is temporary since eventually public contract bytecode will be one blob
|
|
40
|
+
// containing all functions, and function selector will become an application-level mechanism
|
|
41
|
+
// (e.g. first few bytes of calldata + compiler-generated jump table)
|
|
39
42
|
public readonly temporaryFunctionSelector: FunctionSelector,
|
|
40
43
|
) {}
|
|
41
44
|
|
|
42
|
-
public deriveEnvironmentForNestedCall(
|
|
45
|
+
public deriveEnvironmentForNestedCall(
|
|
46
|
+
address: AztecAddress,
|
|
47
|
+
calldata: Fr[],
|
|
48
|
+
temporaryFunctionSelector: FunctionSelector = FunctionSelector.empty(),
|
|
49
|
+
): AvmExecutionEnvironment {
|
|
43
50
|
return new AvmExecutionEnvironment(
|
|
44
|
-
|
|
51
|
+
address,
|
|
45
52
|
/*storageAddress=*/ address,
|
|
46
53
|
this.origin,
|
|
47
54
|
this.sender,
|
|
@@ -53,14 +60,18 @@ export class AvmExecutionEnvironment {
|
|
|
53
60
|
this.globals,
|
|
54
61
|
this.isStaticCall,
|
|
55
62
|
this.isDelegateCall,
|
|
56
|
-
|
|
57
|
-
|
|
63
|
+
calldata,
|
|
64
|
+
temporaryFunctionSelector,
|
|
58
65
|
);
|
|
59
66
|
}
|
|
60
67
|
|
|
61
|
-
public deriveEnvironmentForNestedStaticCall(
|
|
68
|
+
public deriveEnvironmentForNestedStaticCall(
|
|
69
|
+
address: AztecAddress,
|
|
70
|
+
calldata: Fr[],
|
|
71
|
+
temporaryFunctionSelector: FunctionSelector = FunctionSelector.empty(),
|
|
72
|
+
): AvmExecutionEnvironment {
|
|
62
73
|
return new AvmExecutionEnvironment(
|
|
63
|
-
|
|
74
|
+
address,
|
|
64
75
|
/*storageAddress=*/ address,
|
|
65
76
|
this.origin,
|
|
66
77
|
this.sender,
|
|
@@ -72,14 +83,18 @@ export class AvmExecutionEnvironment {
|
|
|
72
83
|
this.globals,
|
|
73
84
|
/*isStaticCall=*/ true,
|
|
74
85
|
this.isDelegateCall,
|
|
75
|
-
|
|
76
|
-
|
|
86
|
+
calldata,
|
|
87
|
+
temporaryFunctionSelector,
|
|
77
88
|
);
|
|
78
89
|
}
|
|
79
90
|
|
|
80
|
-
public newDelegateCall(
|
|
91
|
+
public newDelegateCall(
|
|
92
|
+
address: AztecAddress,
|
|
93
|
+
calldata: Fr[],
|
|
94
|
+
temporaryFunctionSelector: FunctionSelector = FunctionSelector.empty(),
|
|
95
|
+
): AvmExecutionEnvironment {
|
|
81
96
|
return new AvmExecutionEnvironment(
|
|
82
|
-
|
|
97
|
+
address,
|
|
83
98
|
this.storageAddress,
|
|
84
99
|
this.origin,
|
|
85
100
|
this.sender,
|
|
@@ -91,8 +106,8 @@ export class AvmExecutionEnvironment {
|
|
|
91
106
|
this.globals,
|
|
92
107
|
this.isStaticCall,
|
|
93
108
|
/*isDelegateCall=*/ true,
|
|
94
|
-
|
|
95
|
-
|
|
109
|
+
calldata,
|
|
110
|
+
temporaryFunctionSelector,
|
|
96
111
|
);
|
|
97
112
|
}
|
|
98
113
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { toBufferBE } from '@aztec/foundation/bigint-buffer';
|
|
2
2
|
import { Fr } from '@aztec/foundation/fields';
|
|
3
|
+
import { DebugLogger, createDebugLogger } from '@aztec/foundation/log';
|
|
3
4
|
|
|
4
5
|
import { strict as assert } from 'assert';
|
|
5
6
|
|
|
@@ -28,6 +29,10 @@ export abstract class MemoryValue {
|
|
|
28
29
|
public toFr(): Fr {
|
|
29
30
|
return new Fr(this.toBigInt());
|
|
30
31
|
}
|
|
32
|
+
|
|
33
|
+
public toString(): string {
|
|
34
|
+
return `${this.constructor.name}(0x${this.toBigInt().toString(16)})`;
|
|
35
|
+
}
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
/** IntegralValue gathers the common operations for all integral memory types. */
|
|
@@ -189,6 +194,8 @@ export enum TypeTag {
|
|
|
189
194
|
|
|
190
195
|
// TODO: Consider automatic conversion when getting undefined values.
|
|
191
196
|
export class TaggedMemory {
|
|
197
|
+
static readonly log: DebugLogger = createDebugLogger('aztec:avm_simulator:memory');
|
|
198
|
+
|
|
192
199
|
// FIXME: memory should be 2^32, but TS doesn't allow for arrays that big.
|
|
193
200
|
static readonly MAX_MEMORY_SIZE = Number((1n << 32n) - 2n);
|
|
194
201
|
private _mem: MemoryValue[];
|
|
@@ -200,25 +207,29 @@ export class TaggedMemory {
|
|
|
200
207
|
|
|
201
208
|
public get(offset: number): MemoryValue {
|
|
202
209
|
assert(offset < TaggedMemory.MAX_MEMORY_SIZE);
|
|
203
|
-
|
|
210
|
+
const value = this.getAs<MemoryValue>(offset);
|
|
211
|
+
return value;
|
|
204
212
|
}
|
|
205
213
|
|
|
206
214
|
public getAs<T>(offset: number): T {
|
|
207
215
|
assert(offset < TaggedMemory.MAX_MEMORY_SIZE);
|
|
208
216
|
const word = this._mem[offset];
|
|
217
|
+
TaggedMemory.log(`get(${offset}) = ${word}`);
|
|
209
218
|
return word as T;
|
|
210
219
|
}
|
|
211
220
|
|
|
212
221
|
public getSlice(offset: number, size: number): MemoryValue[] {
|
|
213
222
|
assert(offset < TaggedMemory.MAX_MEMORY_SIZE);
|
|
214
223
|
assert(offset + size < TaggedMemory.MAX_MEMORY_SIZE);
|
|
215
|
-
|
|
224
|
+
const value = this._mem.slice(offset, offset + size);
|
|
225
|
+
TaggedMemory.log(`getSlice(${offset}, ${size}) = ${value}`);
|
|
226
|
+
return value;
|
|
216
227
|
}
|
|
217
228
|
|
|
218
229
|
public getSliceAs<T>(offset: number, size: number): T[] {
|
|
219
230
|
assert(offset < TaggedMemory.MAX_MEMORY_SIZE);
|
|
220
231
|
assert(offset + size < TaggedMemory.MAX_MEMORY_SIZE);
|
|
221
|
-
return this.
|
|
232
|
+
return this.getSlice(offset, size) as T[];
|
|
222
233
|
}
|
|
223
234
|
|
|
224
235
|
public getSliceTags(offset: number, size: number): TypeTag[] {
|
|
@@ -230,6 +241,7 @@ export class TaggedMemory {
|
|
|
230
241
|
public set(offset: number, v: MemoryValue) {
|
|
231
242
|
assert(offset < TaggedMemory.MAX_MEMORY_SIZE);
|
|
232
243
|
this._mem[offset] = v;
|
|
244
|
+
TaggedMemory.log(`set(${offset}, ${v})`);
|
|
233
245
|
}
|
|
234
246
|
|
|
235
247
|
public setSlice(offset: number, vs: MemoryValue[]) {
|
|
@@ -240,6 +252,7 @@ export class TaggedMemory {
|
|
|
240
252
|
this._mem.length = offset + vs.length;
|
|
241
253
|
}
|
|
242
254
|
this._mem.splice(offset, vs.length, ...vs);
|
|
255
|
+
TaggedMemory.log(`setSlice(${offset}, ${vs})`);
|
|
243
256
|
}
|
|
244
257
|
|
|
245
258
|
public getTag(offset: number): TypeTag {
|
|
@@ -327,4 +340,24 @@ export class TaggedMemory {
|
|
|
327
340
|
throw new Error(`${TypeTag[tag]} is not a valid integral type.`);
|
|
328
341
|
}
|
|
329
342
|
}
|
|
343
|
+
|
|
344
|
+
// Does not truncate. Type constructor will check that it fits.
|
|
345
|
+
public static buildFromTagOrDie(v: bigint | number, tag: TypeTag): MemoryValue {
|
|
346
|
+
switch (tag) {
|
|
347
|
+
case TypeTag.UINT8:
|
|
348
|
+
return new Uint8(v);
|
|
349
|
+
case TypeTag.UINT16:
|
|
350
|
+
return new Uint16(v);
|
|
351
|
+
case TypeTag.UINT32:
|
|
352
|
+
return new Uint32(v);
|
|
353
|
+
case TypeTag.UINT64:
|
|
354
|
+
return new Uint64(v);
|
|
355
|
+
case TypeTag.UINT128:
|
|
356
|
+
return new Uint128(v);
|
|
357
|
+
case TypeTag.FIELD:
|
|
358
|
+
return new Field(v);
|
|
359
|
+
default:
|
|
360
|
+
throw new Error(`${TypeTag[tag]} is not a valid integral type.`);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
330
363
|
}
|
package/src/avm/avm_simulator.ts
CHANGED
|
@@ -9,9 +9,13 @@ import type { Instruction } from './opcodes/index.js';
|
|
|
9
9
|
import { decodeFromBytecode } from './serialization/bytecode_serialization.js';
|
|
10
10
|
|
|
11
11
|
export class AvmSimulator {
|
|
12
|
-
private log: DebugLogger
|
|
12
|
+
private log: DebugLogger;
|
|
13
13
|
|
|
14
|
-
constructor(private context: AvmContext) {
|
|
14
|
+
constructor(private context: AvmContext) {
|
|
15
|
+
this.log = createDebugLogger(
|
|
16
|
+
`aztec:avm_simulator:core(f:${context.environment.temporaryFunctionSelector.toString()})`,
|
|
17
|
+
);
|
|
18
|
+
}
|
|
15
19
|
|
|
16
20
|
/**
|
|
17
21
|
* Fetch the bytecode and execute it in the current context.
|
|
@@ -52,7 +56,10 @@ export class AvmSimulator {
|
|
|
52
56
|
// continuing until the machine state signifies a halt
|
|
53
57
|
while (!this.context.machineState.halted) {
|
|
54
58
|
const instruction = instructions[this.context.machineState.pc];
|
|
55
|
-
assert(
|
|
59
|
+
assert(
|
|
60
|
+
!!instruction,
|
|
61
|
+
'AVM attempted to execute non-existent instruction. This should never happen (invalid bytecode or AVM simulator bug)!',
|
|
62
|
+
);
|
|
56
63
|
|
|
57
64
|
this.log.debug(`@${this.context.machineState.pc} ${instruction.toString()}`);
|
|
58
65
|
// Execute the instruction.
|
|
@@ -11,6 +11,8 @@ export class Add extends ThreeOperandInstruction {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
async execute(context: AvmContext): Promise<void> {
|
|
14
|
+
context.machineState.memory.checkTags(this.inTag, this.aOffset, this.bOffset);
|
|
15
|
+
|
|
14
16
|
const a = context.machineState.memory.get(this.aOffset);
|
|
15
17
|
const b = context.machineState.memory.get(this.bOffset);
|
|
16
18
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AvmContext } from '../avm_context.js';
|
|
2
|
+
import { TaggedMemory } from '../avm_memory_types.js';
|
|
2
3
|
import { Opcode } from '../serialization/instruction_serialization.js';
|
|
3
4
|
import { ThreeOperandInstruction } from './instruction_impl.js';
|
|
4
5
|
|
|
@@ -16,8 +17,7 @@ export class Eq extends ThreeOperandInstruction {
|
|
|
16
17
|
const a = context.machineState.memory.get(this.aOffset);
|
|
17
18
|
const b = context.machineState.memory.get(this.bOffset);
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
const dest = a.build(a.equals(b) ? 1n : 0n);
|
|
20
|
+
const dest = TaggedMemory.buildFromTagOrDie(a.equals(b) ? 1n : 0n, this.inTag);
|
|
21
21
|
context.machineState.memory.set(this.dstOffset, dest);
|
|
22
22
|
|
|
23
23
|
context.machineState.incrementPc();
|
|
@@ -38,8 +38,7 @@ export class Lt extends ThreeOperandInstruction {
|
|
|
38
38
|
const a = context.machineState.memory.get(this.aOffset);
|
|
39
39
|
const b = context.machineState.memory.get(this.bOffset);
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
const dest = a.build(a.lt(b) ? 1n : 0n);
|
|
41
|
+
const dest = TaggedMemory.buildFromTagOrDie(a.lt(b) ? 1n : 0n, this.inTag);
|
|
43
42
|
context.machineState.memory.set(this.dstOffset, dest);
|
|
44
43
|
|
|
45
44
|
context.machineState.incrementPc();
|
|
@@ -60,8 +59,7 @@ export class Lte extends ThreeOperandInstruction {
|
|
|
60
59
|
const a = context.machineState.memory.get(this.aOffset);
|
|
61
60
|
const b = context.machineState.memory.get(this.bOffset);
|
|
62
61
|
|
|
63
|
-
|
|
64
|
-
const dest = a.build(a.equals(b) || a.lt(b) ? 1n : 0n);
|
|
62
|
+
const dest = TaggedMemory.buildFromTagOrDie(a.lt(b) || a.equals(b) ? 1n : 0n, this.inTag);
|
|
65
63
|
context.machineState.memory.set(this.dstOffset, dest);
|
|
66
64
|
|
|
67
65
|
context.machineState.incrementPc();
|
|
@@ -4,52 +4,6 @@ import { InstructionExecutionError } from '../errors.js';
|
|
|
4
4
|
import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
|
|
5
5
|
import { Instruction } from './instruction.js';
|
|
6
6
|
|
|
7
|
-
export class Return extends Instruction {
|
|
8
|
-
static type: string = 'RETURN';
|
|
9
|
-
static readonly opcode: Opcode = Opcode.RETURN;
|
|
10
|
-
// Informs (de)serialization. See Instruction.deserialize.
|
|
11
|
-
static readonly wireFormat: OperandType[] = [
|
|
12
|
-
OperandType.UINT8,
|
|
13
|
-
OperandType.UINT8,
|
|
14
|
-
OperandType.UINT32,
|
|
15
|
-
OperandType.UINT32,
|
|
16
|
-
];
|
|
17
|
-
|
|
18
|
-
constructor(private indirect: number, private returnOffset: number, private copySize: number) {
|
|
19
|
-
super();
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async execute(context: AvmContext): Promise<void> {
|
|
23
|
-
const output = context.machineState.memory.getSlice(this.returnOffset, this.copySize).map(word => word.toFr());
|
|
24
|
-
|
|
25
|
-
context.machineState.return(output);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export class Revert extends Instruction {
|
|
30
|
-
static type: string = 'RETURN';
|
|
31
|
-
static readonly opcode: Opcode = Opcode.REVERT;
|
|
32
|
-
// Informs (de)serialization. See Instruction.deserialize.
|
|
33
|
-
static readonly wireFormat: OperandType[] = [
|
|
34
|
-
OperandType.UINT8,
|
|
35
|
-
OperandType.UINT8,
|
|
36
|
-
OperandType.UINT32,
|
|
37
|
-
OperandType.UINT32,
|
|
38
|
-
];
|
|
39
|
-
|
|
40
|
-
constructor(private indirect: number, private returnOffset: number, private retSize: number) {
|
|
41
|
-
super();
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async execute(context: AvmContext): Promise<void> {
|
|
45
|
-
const output = context.machineState.memory
|
|
46
|
-
.getSlice(this.returnOffset, this.returnOffset + this.retSize)
|
|
47
|
-
.map(word => word.toFr());
|
|
48
|
-
|
|
49
|
-
context.machineState.revert(output);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
7
|
export class Jump extends Instruction {
|
|
54
8
|
static type: string = 'JUMP';
|
|
55
9
|
static readonly opcode: Opcode = Opcode.JUMP;
|
|
@@ -122,7 +76,7 @@ export class InternalReturn extends Instruction {
|
|
|
122
76
|
async execute(context: AvmContext): Promise<void> {
|
|
123
77
|
const jumpOffset = context.machineState.internalCallStack.pop();
|
|
124
78
|
if (jumpOffset === undefined) {
|
|
125
|
-
throw new InstructionExecutionError('Internal call empty!');
|
|
79
|
+
throw new InstructionExecutionError('Internal call stack empty!');
|
|
126
80
|
}
|
|
127
81
|
context.machineState.pc = jumpOffset;
|
|
128
82
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FunctionSelector } from '@aztec/circuits.js';
|
|
2
2
|
|
|
3
3
|
import type { AvmContext } from '../avm_context.js';
|
|
4
|
-
import { Field } from '../avm_memory_types.js';
|
|
4
|
+
import { Field, Uint8 } from '../avm_memory_types.js';
|
|
5
5
|
import { AvmSimulator } from '../avm_simulator.js';
|
|
6
6
|
import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
|
|
7
|
+
import { Addressing } from './addressing_mode.js';
|
|
7
8
|
import { Instruction } from './instruction.js';
|
|
8
9
|
|
|
9
10
|
export class Call extends Instruction {
|
|
@@ -20,6 +21,8 @@ export class Call extends Instruction {
|
|
|
20
21
|
OperandType.UINT32,
|
|
21
22
|
OperandType.UINT32,
|
|
22
23
|
OperandType.UINT32,
|
|
24
|
+
/* temporary function selector */
|
|
25
|
+
OperandType.UINT32,
|
|
23
26
|
];
|
|
24
27
|
|
|
25
28
|
constructor(
|
|
@@ -31,16 +34,30 @@ export class Call extends Instruction {
|
|
|
31
34
|
private retOffset: number,
|
|
32
35
|
private retSize: number,
|
|
33
36
|
private successOffset: number,
|
|
37
|
+
// Function selector is temporary since eventually public contract bytecode will be one blob
|
|
38
|
+
// containing all functions, and function selector will become an application-level mechanism
|
|
39
|
+
// (e.g. first few bytes of calldata + compiler-generated jump table)
|
|
40
|
+
private temporaryFunctionSelectorOffset: number,
|
|
34
41
|
) {
|
|
35
42
|
super();
|
|
36
43
|
}
|
|
37
44
|
|
|
38
45
|
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/3992): there is no concept of remaining / available gas at this moment
|
|
39
46
|
async execute(context: AvmContext): Promise<void> {
|
|
40
|
-
const
|
|
41
|
-
|
|
47
|
+
const [_gasOffset, addrOffset, argsOffset, retOffset, successOffset] = Addressing.fromWire(this.indirect).resolve(
|
|
48
|
+
[this._gasOffset, this.addrOffset, this.argsOffset, this.retOffset, this.successOffset],
|
|
49
|
+
context.machineState.memory,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const callAddress = context.machineState.memory.getAs<Field>(addrOffset);
|
|
53
|
+
const calldata = context.machineState.memory.getSlice(argsOffset, this.argsSize).map(f => f.toFr());
|
|
54
|
+
const functionSelector = context.machineState.memory.getAs<Field>(this.temporaryFunctionSelectorOffset).toFr();
|
|
42
55
|
|
|
43
|
-
const nestedContext = context.createNestedContractCallContext(
|
|
56
|
+
const nestedContext = context.createNestedContractCallContext(
|
|
57
|
+
callAddress.toFr(),
|
|
58
|
+
calldata,
|
|
59
|
+
FunctionSelector.fromField(functionSelector),
|
|
60
|
+
);
|
|
44
61
|
|
|
45
62
|
const nestedCallResults = await new AvmSimulator(nestedContext).execute();
|
|
46
63
|
const success = !nestedCallResults.reverted;
|
|
@@ -50,8 +67,8 @@ export class Call extends Instruction {
|
|
|
50
67
|
const convertedReturnData = returnData.map(f => new Field(f));
|
|
51
68
|
|
|
52
69
|
// Write our return data into memory
|
|
53
|
-
context.machineState.memory.set(
|
|
54
|
-
context.machineState.memory.setSlice(
|
|
70
|
+
context.machineState.memory.set(successOffset, new Uint8(success ? 1 : 0));
|
|
71
|
+
context.machineState.memory.setSlice(retOffset, convertedReturnData);
|
|
55
72
|
|
|
56
73
|
if (success) {
|
|
57
74
|
context.persistableState.acceptNestedCallState(nestedContext.persistableState);
|
|
@@ -77,6 +94,8 @@ export class StaticCall extends Instruction {
|
|
|
77
94
|
OperandType.UINT32,
|
|
78
95
|
OperandType.UINT32,
|
|
79
96
|
OperandType.UINT32,
|
|
97
|
+
/* temporary function selector */
|
|
98
|
+
OperandType.UINT32,
|
|
80
99
|
];
|
|
81
100
|
|
|
82
101
|
constructor(
|
|
@@ -88,17 +107,26 @@ export class StaticCall extends Instruction {
|
|
|
88
107
|
private retOffset: number,
|
|
89
108
|
private retSize: number,
|
|
90
109
|
private successOffset: number,
|
|
110
|
+
private temporaryFunctionSelectorOffset: number,
|
|
91
111
|
) {
|
|
92
112
|
super();
|
|
93
113
|
}
|
|
94
114
|
|
|
95
115
|
async execute(context: AvmContext): Promise<void> {
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
.
|
|
99
|
-
|
|
116
|
+
const [_gasOffset, addrOffset, argsOffset, retOffset, successOffset] = Addressing.fromWire(this.indirect).resolve(
|
|
117
|
+
[this._gasOffset, this.addrOffset, this.argsOffset, this.retOffset, this.successOffset],
|
|
118
|
+
context.machineState.memory,
|
|
119
|
+
);
|
|
100
120
|
|
|
101
|
-
const
|
|
121
|
+
const callAddress = context.machineState.memory.get(addrOffset);
|
|
122
|
+
const calldata = context.machineState.memory.getSlice(argsOffset, this.argsSize).map(f => f.toFr());
|
|
123
|
+
const functionSelector = context.machineState.memory.getAs<Field>(this.temporaryFunctionSelectorOffset).toFr();
|
|
124
|
+
|
|
125
|
+
const nestedContext = context.createNestedContractStaticCallContext(
|
|
126
|
+
callAddress.toFr(),
|
|
127
|
+
calldata,
|
|
128
|
+
FunctionSelector.fromField(functionSelector),
|
|
129
|
+
);
|
|
102
130
|
|
|
103
131
|
const nestedCallResults = await new AvmSimulator(nestedContext).execute();
|
|
104
132
|
const success = !nestedCallResults.reverted;
|
|
@@ -108,8 +136,8 @@ export class StaticCall extends Instruction {
|
|
|
108
136
|
const convertedReturnData = returnData.map(f => new Field(f));
|
|
109
137
|
|
|
110
138
|
// Write our return data into memory
|
|
111
|
-
context.machineState.memory.set(
|
|
112
|
-
context.machineState.memory.setSlice(
|
|
139
|
+
context.machineState.memory.set(successOffset, new Uint8(success ? 1 : 0));
|
|
140
|
+
context.machineState.memory.setSlice(retOffset, convertedReturnData);
|
|
113
141
|
|
|
114
142
|
if (success) {
|
|
115
143
|
context.persistableState.acceptNestedCallState(nestedContext.persistableState);
|
|
@@ -120,3 +148,49 @@ export class StaticCall extends Instruction {
|
|
|
120
148
|
context.machineState.incrementPc();
|
|
121
149
|
}
|
|
122
150
|
}
|
|
151
|
+
|
|
152
|
+
export class Return extends Instruction {
|
|
153
|
+
static type: string = 'RETURN';
|
|
154
|
+
static readonly opcode: Opcode = Opcode.RETURN;
|
|
155
|
+
// Informs (de)serialization. See Instruction.deserialize.
|
|
156
|
+
static readonly wireFormat: OperandType[] = [
|
|
157
|
+
OperandType.UINT8,
|
|
158
|
+
OperandType.UINT8,
|
|
159
|
+
OperandType.UINT32,
|
|
160
|
+
OperandType.UINT32,
|
|
161
|
+
];
|
|
162
|
+
|
|
163
|
+
constructor(private indirect: number, private returnOffset: number, private copySize: number) {
|
|
164
|
+
super();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async execute(context: AvmContext): Promise<void> {
|
|
168
|
+
const output = context.machineState.memory.getSlice(this.returnOffset, this.copySize).map(word => word.toFr());
|
|
169
|
+
|
|
170
|
+
context.machineState.return(output);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export class Revert extends Instruction {
|
|
175
|
+
static type: string = 'RETURN';
|
|
176
|
+
static readonly opcode: Opcode = Opcode.REVERT;
|
|
177
|
+
// Informs (de)serialization. See Instruction.deserialize.
|
|
178
|
+
static readonly wireFormat: OperandType[] = [
|
|
179
|
+
OperandType.UINT8,
|
|
180
|
+
OperandType.UINT8,
|
|
181
|
+
OperandType.UINT32,
|
|
182
|
+
OperandType.UINT32,
|
|
183
|
+
];
|
|
184
|
+
|
|
185
|
+
constructor(private indirect: number, private returnOffset: number, private retSize: number) {
|
|
186
|
+
super();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async execute(context: AvmContext): Promise<void> {
|
|
190
|
+
const output = context.machineState.memory
|
|
191
|
+
.getSlice(this.returnOffset, this.returnOffset + this.retSize)
|
|
192
|
+
.map(word => word.toFr());
|
|
193
|
+
|
|
194
|
+
context.machineState.revert(output);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
@@ -7,6 +7,7 @@ import { BufferCursor } from './buffer_cursor.js';
|
|
|
7
7
|
* Source: https://yp-aztec.netlify.app/docs/public-vm/instruction-set
|
|
8
8
|
*/
|
|
9
9
|
export enum Opcode {
|
|
10
|
+
// Compute
|
|
10
11
|
ADD,
|
|
11
12
|
SUB,
|
|
12
13
|
MUL,
|
|
@@ -21,6 +22,7 @@ export enum Opcode {
|
|
|
21
22
|
SHL,
|
|
22
23
|
SHR,
|
|
23
24
|
CAST,
|
|
25
|
+
// Execution environment
|
|
24
26
|
ADDRESS,
|
|
25
27
|
STORAGEADDRESS,
|
|
26
28
|
ORIGIN,
|
|
@@ -39,16 +41,20 @@ export enum Opcode {
|
|
|
39
41
|
BLOCKL2GASLIMIT,
|
|
40
42
|
BLOCKDAGASLIMIT,
|
|
41
43
|
CALLDATACOPY,
|
|
44
|
+
// Gas
|
|
42
45
|
L1GASLEFT,
|
|
43
46
|
L2GASLEFT,
|
|
44
47
|
DAGASLEFT,
|
|
48
|
+
// Control flow
|
|
45
49
|
JUMP,
|
|
46
50
|
JUMPI,
|
|
47
51
|
INTERNALCALL,
|
|
48
52
|
INTERNALRETURN,
|
|
53
|
+
// Memory
|
|
49
54
|
SET,
|
|
50
55
|
MOV,
|
|
51
56
|
CMOV,
|
|
57
|
+
// World state
|
|
52
58
|
SLOAD,
|
|
53
59
|
SSTORE,
|
|
54
60
|
NOTEHASHEXISTS,
|
|
@@ -59,17 +65,17 @@ export enum Opcode {
|
|
|
59
65
|
HEADERMEMBER,
|
|
60
66
|
EMITUNENCRYPTEDLOG,
|
|
61
67
|
SENDL2TOL1MSG,
|
|
68
|
+
// External calls
|
|
62
69
|
CALL,
|
|
63
70
|
STATICCALL,
|
|
64
71
|
DELEGATECALL,
|
|
65
72
|
RETURN,
|
|
66
73
|
REVERT,
|
|
74
|
+
// Gadgets
|
|
67
75
|
KECCAK,
|
|
68
76
|
POSEIDON,
|
|
69
|
-
// Add new opcodes before this
|
|
70
77
|
SHA256, // temp - may be removed, but alot of contracts rely on it
|
|
71
78
|
PEDERSEN, // temp - may be removed, but alot of contracts rely on it
|
|
72
|
-
TOTAL_OPCODES_NUMBER,
|
|
73
79
|
}
|
|
74
80
|
|
|
75
81
|
// Possible types for an instruction's operand in its wire format. (Keep in sync with CPP code.
|
|
@@ -94,6 +94,7 @@ export function temporaryConvertAvmResults(
|
|
|
94
94
|
// Disabled.
|
|
95
95
|
const nestedExecutions: PublicExecutionResult[] = [];
|
|
96
96
|
const nullifierReadRequests: ReadRequest[] = [];
|
|
97
|
+
const nullifierNonExistentReadRequests: ReadRequest[] = [];
|
|
97
98
|
const newNullifiers: SideEffectLinkedToNoteHash[] = [];
|
|
98
99
|
const unencryptedLogs = FunctionL2Logs.empty();
|
|
99
100
|
const newL2ToL1Messages = newWorldState.newL1Messages.map(() => L2ToL1Message.empty());
|
|
@@ -101,6 +102,7 @@ export function temporaryConvertAvmResults(
|
|
|
101
102
|
return {
|
|
102
103
|
execution,
|
|
103
104
|
nullifierReadRequests,
|
|
105
|
+
nullifierNonExistentReadRequests,
|
|
104
106
|
newNoteHashes,
|
|
105
107
|
newL2ToL1Messages,
|
|
106
108
|
newNullifiers,
|
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
} from '@aztec/circuit-types';
|
|
11
11
|
import {
|
|
12
12
|
CallContext,
|
|
13
|
-
ContractDeploymentData,
|
|
14
13
|
FunctionData,
|
|
15
14
|
FunctionSelector,
|
|
16
15
|
Header,
|
|
@@ -89,8 +88,6 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
89
88
|
* @returns The initial witness.
|
|
90
89
|
*/
|
|
91
90
|
public getInitialWitness(abi: FunctionAbi) {
|
|
92
|
-
const contractDeploymentData = this.txContext.contractDeploymentData;
|
|
93
|
-
|
|
94
91
|
const argumentsSize = countArgumentsSize(abi);
|
|
95
92
|
|
|
96
93
|
const args = this.packedArgsCache.unpack(this.argsHash);
|
|
@@ -102,7 +99,6 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
102
99
|
const fields = [
|
|
103
100
|
...this.callContext.toFields(),
|
|
104
101
|
...this.historicalHeader.toFields(),
|
|
105
|
-
...contractDeploymentData.toFields(),
|
|
106
102
|
|
|
107
103
|
this.txContext.chainId,
|
|
108
104
|
this.txContext.version,
|
|
@@ -348,14 +344,7 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
348
344
|
const targetArtifact = await this.db.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
349
345
|
const targetFunctionData = FunctionData.fromAbi(targetArtifact);
|
|
350
346
|
|
|
351
|
-
const derivedTxContext = new TxContext(
|
|
352
|
-
false,
|
|
353
|
-
false,
|
|
354
|
-
false,
|
|
355
|
-
ContractDeploymentData.empty(),
|
|
356
|
-
this.txContext.chainId,
|
|
357
|
-
this.txContext.version,
|
|
358
|
-
);
|
|
347
|
+
const derivedTxContext = new TxContext(false, false, this.txContext.chainId, this.txContext.version);
|
|
359
348
|
|
|
360
349
|
const derivedCallContext = await this.deriveCallContext(
|
|
361
350
|
targetContractAddress,
|
|
@@ -470,7 +459,6 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
470
459
|
FunctionSelector.fromNameAndParameters(targetArtifact.name, targetArtifact.parameters),
|
|
471
460
|
isDelegateCall,
|
|
472
461
|
isStaticCall,
|
|
473
|
-
false,
|
|
474
462
|
startSideEffectCounter,
|
|
475
463
|
);
|
|
476
464
|
}
|
package/src/client/simulator.ts
CHANGED
|
@@ -92,10 +92,9 @@ export class AcirSimulator {
|
|
|
92
92
|
FunctionSelector.fromNameAndParameters(entryPointArtifact.name, entryPointArtifact.parameters),
|
|
93
93
|
false,
|
|
94
94
|
false,
|
|
95
|
-
request.functionData.isConstructor,
|
|
96
95
|
// TODO: when contract deployment is done in-app, we should only reserve one counter for the tx hash
|
|
97
96
|
// 2 counters are reserved for tx hash and contract deployment nullifier
|
|
98
|
-
|
|
97
|
+
1,
|
|
99
98
|
);
|
|
100
99
|
const context = new ClientExecutionContext(
|
|
101
100
|
contractAddress,
|
package/src/public/execution.ts
CHANGED
|
@@ -30,6 +30,8 @@ export interface PublicExecutionResult {
|
|
|
30
30
|
newNullifiers: SideEffectLinkedToNoteHash[];
|
|
31
31
|
/** The nullifier read requests emitted in this call. */
|
|
32
32
|
nullifierReadRequests: ReadRequest[];
|
|
33
|
+
/** The nullifier non existent read requests emitted in this call. */
|
|
34
|
+
nullifierNonExistentReadRequests: ReadRequest[];
|
|
33
35
|
/** The contract storage reads performed by the function. */
|
|
34
36
|
contractStorageReads: ContractStorageRead[];
|
|
35
37
|
/** The contract storage update requests performed by the function. */
|