@aztec/simulator 0.30.1 → 0.31.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/dest/acvm/oracle/oracle.d.ts +1 -1
- package/dest/acvm/oracle/oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/oracle.js +3 -3
- package/dest/acvm/oracle/typed_oracle.d.ts +1 -1
- package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/typed_oracle.js +2 -2
- package/dest/avm/avm_execution_environment.d.ts +7 -0
- package/dest/avm/avm_execution_environment.d.ts.map +1 -1
- package/dest/avm/avm_execution_environment.js +16 -1
- package/dest/avm/avm_gas_cost.d.ts +18 -0
- package/dest/avm/avm_gas_cost.d.ts.map +1 -0
- package/dest/avm/avm_gas_cost.js +84 -0
- package/dest/avm/avm_machine_state.d.ts +12 -1
- package/dest/avm/avm_machine_state.d.ts.map +1 -1
- package/dest/avm/avm_machine_state.js +31 -2
- package/dest/avm/avm_memory_types.d.ts.map +1 -1
- package/dest/avm/avm_memory_types.js +2 -1
- package/dest/avm/avm_simulator.d.ts.map +1 -1
- package/dest/avm/avm_simulator.js +2 -2
- package/dest/avm/errors.d.ts +4 -0
- package/dest/avm/errors.d.ts.map +1 -1
- package/dest/avm/errors.js +8 -1
- package/dest/avm/fixtures/index.d.ts +7 -1
- package/dest/avm/fixtures/index.d.ts.map +1 -1
- package/dest/avm/fixtures/index.js +20 -6
- package/dest/avm/journal/journal.d.ts.map +1 -1
- package/dest/avm/journal/journal.js +7 -2
- package/dest/avm/opcodes/hashing.d.ts +12 -12
- package/dest/avm/opcodes/hashing.d.ts.map +1 -1
- package/dest/avm/opcodes/hashing.js +24 -23
- package/dest/avm/opcodes/instruction.d.ts +24 -2
- package/dest/avm/opcodes/instruction.d.ts.map +1 -1
- package/dest/avm/opcodes/instruction.js +41 -2
- package/dest/client/private_execution.d.ts.map +1 -1
- package/dest/client/private_execution.js +4 -5
- package/dest/client/unconstrained_execution.js +2 -2
- package/dest/client/view_data_oracle.d.ts +8 -5
- package/dest/client/view_data_oracle.d.ts.map +1 -1
- package/dest/client/view_data_oracle.js +9 -6
- package/dest/index.d.ts +1 -0
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +2 -1
- package/dest/public/db.d.ts +7 -5
- package/dest/public/db.d.ts.map +1 -1
- package/dest/public/executor.d.ts.map +1 -1
- package/dest/public/executor.js +4 -2
- package/dest/public/public_execution_context.d.ts +7 -4
- package/dest/public/public_execution_context.d.ts.map +1 -1
- package/dest/public/public_execution_context.js +9 -6
- package/dest/simulator/acvm_native.d.ts +20 -0
- package/dest/simulator/acvm_native.d.ts.map +1 -0
- package/dest/simulator/acvm_native.js +96 -0
- package/dest/simulator/acvm_wasm.d.ts +7 -0
- package/dest/simulator/acvm_wasm.d.ts.map +1 -0
- package/dest/simulator/acvm_wasm.js +23 -0
- package/dest/simulator/index.d.ts +4 -0
- package/dest/simulator/index.d.ts.map +1 -0
- package/dest/simulator/index.js +4 -0
- package/dest/simulator/simulation_provider.d.ts +9 -0
- package/dest/simulator/simulation_provider.d.ts.map +1 -0
- package/dest/simulator/simulation_provider.js +2 -0
- package/dest/test/utils.d.ts.map +1 -1
- package/dest/test/utils.js +4 -4
- package/package.json +6 -5
- package/src/acvm/oracle/oracle.ts +10 -2
- package/src/acvm/oracle/typed_oracle.ts +5 -1
- package/src/avm/avm_execution_environment.ts +20 -1
- package/src/avm/avm_gas_cost.ts +94 -0
- package/src/avm/avm_machine_state.ts +34 -1
- package/src/avm/avm_memory_types.ts +1 -0
- package/src/avm/avm_simulator.ts +1 -2
- package/src/avm/errors.ts +8 -0
- package/src/avm/fixtures/index.ts +21 -5
- package/src/avm/journal/journal.ts +10 -1
- package/src/avm/opcodes/hashing.ts +27 -20
- package/src/avm/opcodes/instruction.ts +45 -2
- package/src/client/private_execution.ts +3 -4
- package/src/client/unconstrained_execution.ts +1 -1
- package/src/client/view_data_oracle.ts +8 -5
- package/src/index.ts +1 -0
- package/src/public/db.ts +11 -5
- package/src/public/executor.ts +3 -1
- package/src/public/public_execution_context.ts +8 -5
- package/src/simulator/acvm_native.ts +112 -0
- package/src/simulator/acvm_wasm.ts +31 -0
- package/src/simulator/index.ts +3 -0
- package/src/simulator/simulation_provider.ts +10 -0
- package/src/test/utils.ts +2 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/simulator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.31.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": "./dest/index.js",
|
|
6
6
|
"typedocOptions": {
|
|
@@ -30,11 +30,12 @@
|
|
|
30
30
|
"rootDir": "./src"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@aztec/circuit-types": "0.
|
|
34
|
-
"@aztec/circuits.js": "0.
|
|
35
|
-
"@aztec/foundation": "0.
|
|
36
|
-
"@aztec/types": "0.
|
|
33
|
+
"@aztec/circuit-types": "0.31.0",
|
|
34
|
+
"@aztec/circuits.js": "0.31.0",
|
|
35
|
+
"@aztec/foundation": "0.31.0",
|
|
36
|
+
"@aztec/types": "0.31.0",
|
|
37
37
|
"@noir-lang/acvm_js": "portal:../../noir/packages/acvm_js",
|
|
38
|
+
"@noir-lang/types": "portal:../../noir/packages/types",
|
|
38
39
|
"levelup": "^5.1.1",
|
|
39
40
|
"memdown": "^6.1.1",
|
|
40
41
|
"tslib": "^2.4.0"
|
|
@@ -244,8 +244,16 @@ export class Oracle {
|
|
|
244
244
|
return toACVMField(exists);
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
-
async getL1ToL2MembershipWitness(
|
|
248
|
-
|
|
247
|
+
async getL1ToL2MembershipWitness(
|
|
248
|
+
[contractAddress]: ACVMField[],
|
|
249
|
+
[messageHash]: ACVMField[],
|
|
250
|
+
[secret]: ACVMField[],
|
|
251
|
+
): Promise<ACVMField[]> {
|
|
252
|
+
const message = await this.typedOracle.getL1ToL2MembershipWitness(
|
|
253
|
+
AztecAddress.fromString(contractAddress),
|
|
254
|
+
fromACVMField(messageHash),
|
|
255
|
+
fromACVMField(secret),
|
|
256
|
+
);
|
|
249
257
|
return message.toFields().map(toACVMField);
|
|
250
258
|
}
|
|
251
259
|
|
|
@@ -171,7 +171,11 @@ export abstract class TypedOracle {
|
|
|
171
171
|
throw new OracleMethodNotAvailableError('checkNullifierExists');
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
getL1ToL2MembershipWitness(
|
|
174
|
+
getL1ToL2MembershipWitness(
|
|
175
|
+
_contractAddress: AztecAddress,
|
|
176
|
+
_messageHash: Fr,
|
|
177
|
+
_secret: Fr,
|
|
178
|
+
): Promise<MessageLoadOracleInputs<typeof L1_TO_L2_MSG_TREE_HEIGHT>> {
|
|
175
179
|
throw new OracleMethodNotAvailableError('getL1ToL2MembershipWitness');
|
|
176
180
|
}
|
|
177
181
|
|
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import { FunctionSelector, GlobalVariables } from '@aztec/circuits.js';
|
|
2
2
|
import { AztecAddress } from '@aztec/foundation/aztec-address';
|
|
3
|
+
import { pedersenHash } from '@aztec/foundation/crypto';
|
|
3
4
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
5
|
import { Fr } from '@aztec/foundation/fields';
|
|
5
6
|
|
|
7
|
+
export class AvmContextInputs {
|
|
8
|
+
static readonly SIZE = 2;
|
|
9
|
+
|
|
10
|
+
constructor(private selector: Fr, private argsHash: Fr) {}
|
|
11
|
+
|
|
12
|
+
public toFields(): Fr[] {
|
|
13
|
+
return [this.selector, this.argsHash];
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
6
17
|
/**
|
|
7
18
|
* Contains variables that remain constant during AVM execution
|
|
8
19
|
* These variables are provided by the public kernel circuit
|
|
@@ -40,7 +51,15 @@ export class AvmExecutionEnvironment {
|
|
|
40
51
|
// containing all functions, and function selector will become an application-level mechanism
|
|
41
52
|
// (e.g. first few bytes of calldata + compiler-generated jump table)
|
|
42
53
|
public readonly temporaryFunctionSelector: FunctionSelector,
|
|
43
|
-
) {
|
|
54
|
+
) {
|
|
55
|
+
// We encode some extra inputs (AvmContextInputs) in calldata.
|
|
56
|
+
// This will have to go once we move away from one proof per call.
|
|
57
|
+
const inputs = new AvmContextInputs(
|
|
58
|
+
temporaryFunctionSelector.toField(),
|
|
59
|
+
pedersenHash(calldata.map(word => word.toBuffer())),
|
|
60
|
+
);
|
|
61
|
+
this.calldata = [...inputs.toFields(), ...calldata];
|
|
62
|
+
}
|
|
44
63
|
|
|
45
64
|
public deriveEnvironmentForNestedCall(
|
|
46
65
|
address: AztecAddress,
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Opcode } from './serialization/instruction_serialization.js';
|
|
2
|
+
|
|
3
|
+
/** Gas cost in L1, L2, and DA for a given instruction. */
|
|
4
|
+
export type GasCost = {
|
|
5
|
+
l1Gas: number;
|
|
6
|
+
l2Gas: number;
|
|
7
|
+
daGas: number;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/** Gas cost of zero across all gas dimensions. */
|
|
11
|
+
export const EmptyGasCost = {
|
|
12
|
+
l1Gas: 0,
|
|
13
|
+
l2Gas: 0,
|
|
14
|
+
daGas: 0,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/** Dimensions of gas usage: L1, L2, and DA */
|
|
18
|
+
export const GasDimensions = ['l1Gas', 'l2Gas', 'daGas'] as const;
|
|
19
|
+
|
|
20
|
+
/** Temporary default gas cost. We should eventually remove all usage of this variable in favor of actual gas for each opcode. */
|
|
21
|
+
const TemporaryDefaultGasCost = { l1Gas: 0, l2Gas: 10, daGas: 0 };
|
|
22
|
+
|
|
23
|
+
/** Gas costs for each instruction. */
|
|
24
|
+
export const GasCosts: Record<Opcode, GasCost> = {
|
|
25
|
+
[Opcode.ADD]: TemporaryDefaultGasCost,
|
|
26
|
+
[Opcode.SUB]: TemporaryDefaultGasCost,
|
|
27
|
+
[Opcode.MUL]: TemporaryDefaultGasCost,
|
|
28
|
+
[Opcode.DIV]: TemporaryDefaultGasCost,
|
|
29
|
+
[Opcode.FDIV]: TemporaryDefaultGasCost,
|
|
30
|
+
[Opcode.EQ]: TemporaryDefaultGasCost,
|
|
31
|
+
[Opcode.LT]: TemporaryDefaultGasCost,
|
|
32
|
+
[Opcode.LTE]: TemporaryDefaultGasCost,
|
|
33
|
+
[Opcode.AND]: TemporaryDefaultGasCost,
|
|
34
|
+
[Opcode.OR]: TemporaryDefaultGasCost,
|
|
35
|
+
[Opcode.XOR]: TemporaryDefaultGasCost,
|
|
36
|
+
[Opcode.NOT]: TemporaryDefaultGasCost,
|
|
37
|
+
[Opcode.SHL]: TemporaryDefaultGasCost,
|
|
38
|
+
[Opcode.SHR]: TemporaryDefaultGasCost,
|
|
39
|
+
[Opcode.CAST]: TemporaryDefaultGasCost,
|
|
40
|
+
// Execution environment
|
|
41
|
+
[Opcode.ADDRESS]: TemporaryDefaultGasCost,
|
|
42
|
+
[Opcode.STORAGEADDRESS]: TemporaryDefaultGasCost,
|
|
43
|
+
[Opcode.ORIGIN]: TemporaryDefaultGasCost,
|
|
44
|
+
[Opcode.SENDER]: TemporaryDefaultGasCost,
|
|
45
|
+
[Opcode.PORTAL]: TemporaryDefaultGasCost,
|
|
46
|
+
[Opcode.FEEPERL1GAS]: TemporaryDefaultGasCost,
|
|
47
|
+
[Opcode.FEEPERL2GAS]: TemporaryDefaultGasCost,
|
|
48
|
+
[Opcode.FEEPERDAGAS]: TemporaryDefaultGasCost,
|
|
49
|
+
[Opcode.CONTRACTCALLDEPTH]: TemporaryDefaultGasCost,
|
|
50
|
+
[Opcode.CHAINID]: TemporaryDefaultGasCost,
|
|
51
|
+
[Opcode.VERSION]: TemporaryDefaultGasCost,
|
|
52
|
+
[Opcode.BLOCKNUMBER]: TemporaryDefaultGasCost,
|
|
53
|
+
[Opcode.TIMESTAMP]: TemporaryDefaultGasCost,
|
|
54
|
+
[Opcode.COINBASE]: TemporaryDefaultGasCost,
|
|
55
|
+
[Opcode.BLOCKL1GASLIMIT]: TemporaryDefaultGasCost,
|
|
56
|
+
[Opcode.BLOCKL2GASLIMIT]: TemporaryDefaultGasCost,
|
|
57
|
+
[Opcode.BLOCKDAGASLIMIT]: TemporaryDefaultGasCost,
|
|
58
|
+
[Opcode.CALLDATACOPY]: TemporaryDefaultGasCost,
|
|
59
|
+
// Gas
|
|
60
|
+
[Opcode.L1GASLEFT]: TemporaryDefaultGasCost,
|
|
61
|
+
[Opcode.L2GASLEFT]: TemporaryDefaultGasCost,
|
|
62
|
+
[Opcode.DAGASLEFT]: TemporaryDefaultGasCost,
|
|
63
|
+
// Control flow
|
|
64
|
+
[Opcode.JUMP]: TemporaryDefaultGasCost,
|
|
65
|
+
[Opcode.JUMPI]: TemporaryDefaultGasCost,
|
|
66
|
+
[Opcode.INTERNALCALL]: TemporaryDefaultGasCost,
|
|
67
|
+
[Opcode.INTERNALRETURN]: TemporaryDefaultGasCost,
|
|
68
|
+
// Memory
|
|
69
|
+
[Opcode.SET]: TemporaryDefaultGasCost,
|
|
70
|
+
[Opcode.MOV]: TemporaryDefaultGasCost,
|
|
71
|
+
[Opcode.CMOV]: TemporaryDefaultGasCost,
|
|
72
|
+
// World state
|
|
73
|
+
[Opcode.SLOAD]: TemporaryDefaultGasCost,
|
|
74
|
+
[Opcode.SSTORE]: TemporaryDefaultGasCost,
|
|
75
|
+
[Opcode.NOTEHASHEXISTS]: TemporaryDefaultGasCost,
|
|
76
|
+
[Opcode.EMITNOTEHASH]: TemporaryDefaultGasCost,
|
|
77
|
+
[Opcode.NULLIFIEREXISTS]: TemporaryDefaultGasCost,
|
|
78
|
+
[Opcode.EMITNULLIFIER]: TemporaryDefaultGasCost,
|
|
79
|
+
[Opcode.L1TOL2MSGEXISTS]: TemporaryDefaultGasCost,
|
|
80
|
+
[Opcode.HEADERMEMBER]: TemporaryDefaultGasCost,
|
|
81
|
+
[Opcode.EMITUNENCRYPTEDLOG]: TemporaryDefaultGasCost,
|
|
82
|
+
[Opcode.SENDL2TOL1MSG]: TemporaryDefaultGasCost,
|
|
83
|
+
// External calls
|
|
84
|
+
[Opcode.CALL]: TemporaryDefaultGasCost,
|
|
85
|
+
[Opcode.STATICCALL]: TemporaryDefaultGasCost,
|
|
86
|
+
[Opcode.DELEGATECALL]: TemporaryDefaultGasCost,
|
|
87
|
+
[Opcode.RETURN]: TemporaryDefaultGasCost,
|
|
88
|
+
[Opcode.REVERT]: TemporaryDefaultGasCost,
|
|
89
|
+
// Gadgets
|
|
90
|
+
[Opcode.KECCAK]: TemporaryDefaultGasCost,
|
|
91
|
+
[Opcode.POSEIDON]: TemporaryDefaultGasCost,
|
|
92
|
+
[Opcode.SHA256]: TemporaryDefaultGasCost, // temp - may be removed, but alot of contracts rely on i: TemporaryDefaultGasCost,
|
|
93
|
+
[Opcode.PEDERSEN]: TemporaryDefaultGasCost, // temp - may be removed, but alot of contracts rely on i: TemporaryDefaultGasCost,t
|
|
94
|
+
};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Fr } from '@aztec/circuits.js';
|
|
2
2
|
|
|
3
|
+
import { GasCost, GasDimensions } from './avm_gas_cost.js';
|
|
3
4
|
import { TaggedMemory } from './avm_memory_types.js';
|
|
4
5
|
import { AvmContractCallResults } from './avm_message_call_result.js';
|
|
6
|
+
import { OutOfGasError } from './errors.js';
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* A few fields of machine state are initialized from AVM session inputs or call instruction arguments
|
|
@@ -35,7 +37,7 @@ export class AvmMachineState {
|
|
|
35
37
|
/**
|
|
36
38
|
* Signals that execution should end.
|
|
37
39
|
* AvmContext execution continues executing instructions until the machine state signals "halted"
|
|
38
|
-
|
|
40
|
+
*/
|
|
39
41
|
public halted: boolean = false;
|
|
40
42
|
/** Signals that execution has reverted normally (this does not cover exceptional halts) */
|
|
41
43
|
private reverted: boolean = false;
|
|
@@ -52,6 +54,28 @@ export class AvmMachineState {
|
|
|
52
54
|
return new AvmMachineState(state.l1GasLeft, state.l2GasLeft, state.daGasLeft);
|
|
53
55
|
}
|
|
54
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Consumes the given gas.
|
|
59
|
+
* Should any of the gas dimensions get depleted, it sets all gas left to zero and triggers
|
|
60
|
+
* an exceptional halt by throwing an OutOfGasError.
|
|
61
|
+
*/
|
|
62
|
+
public consumeGas(gasCost: Partial<GasCost>) {
|
|
63
|
+
// Assert there is enough gas on every dimension.
|
|
64
|
+
const outOfGasDimensions = GasDimensions.filter(
|
|
65
|
+
dimension => this[`${dimension}Left`] - (gasCost[dimension] ?? 0) < 0,
|
|
66
|
+
);
|
|
67
|
+
// If not, trigger an exceptional halt.
|
|
68
|
+
// See https://yp-aztec.netlify.app/docs/public-vm/execution#gas-checks-and-tracking
|
|
69
|
+
if (outOfGasDimensions.length > 0) {
|
|
70
|
+
this.exceptionalHalt();
|
|
71
|
+
throw new OutOfGasError(outOfGasDimensions);
|
|
72
|
+
}
|
|
73
|
+
// Otherwise, charge the corresponding gas
|
|
74
|
+
for (const dimension of GasDimensions) {
|
|
75
|
+
this[`${dimension}Left`] -= gasCost[dimension] ?? 0;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
55
79
|
/**
|
|
56
80
|
* Most instructions just increment PC before they complete
|
|
57
81
|
*/
|
|
@@ -80,6 +104,15 @@ export class AvmMachineState {
|
|
|
80
104
|
this.output = output;
|
|
81
105
|
}
|
|
82
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Flag an exceptional halt. Clears gas left and sets the reverted flag. No output data.
|
|
109
|
+
*/
|
|
110
|
+
protected exceptionalHalt() {
|
|
111
|
+
GasDimensions.forEach(dimension => (this[`${dimension}Left`] = 0));
|
|
112
|
+
this.reverted = true;
|
|
113
|
+
this.halted = true;
|
|
114
|
+
}
|
|
115
|
+
|
|
83
116
|
/**
|
|
84
117
|
* Get a summary of execution results for a halted machine state
|
|
85
118
|
* @returns summary of execution results
|
|
@@ -229,6 +229,7 @@ export class TaggedMemory {
|
|
|
229
229
|
assert(offset + size < TaggedMemory.MAX_MEMORY_SIZE);
|
|
230
230
|
const value = this._mem.slice(offset, offset + size);
|
|
231
231
|
TaggedMemory.log(`getSlice(${offset}, ${size}) = ${value}`);
|
|
232
|
+
assert(value.length === size, `Expected slice of size ${size}, got ${value.length}.`);
|
|
232
233
|
return value;
|
|
233
234
|
}
|
|
234
235
|
|
package/src/avm/avm_simulator.ts
CHANGED
|
@@ -50,7 +50,6 @@ export class AvmSimulator {
|
|
|
50
50
|
*/
|
|
51
51
|
public async executeInstructions(instructions: Instruction[]): Promise<AvmContractCallResults> {
|
|
52
52
|
assert(instructions.length > 0);
|
|
53
|
-
|
|
54
53
|
try {
|
|
55
54
|
// Execute instruction pointed to by the current program counter
|
|
56
55
|
// continuing until the machine state signifies a halt
|
|
@@ -65,7 +64,7 @@ export class AvmSimulator {
|
|
|
65
64
|
// Execute the instruction.
|
|
66
65
|
// Normal returns and reverts will return normally here.
|
|
67
66
|
// "Exceptional halts" will throw.
|
|
68
|
-
await instruction.
|
|
67
|
+
await instruction.run(this.context);
|
|
69
68
|
|
|
70
69
|
if (this.context.machineState.pc >= instructions.length) {
|
|
71
70
|
this.log('Passed end of program!');
|
package/src/avm/errors.ts
CHANGED
|
@@ -55,3 +55,11 @@ export class TagCheckError extends AvmExecutionError {
|
|
|
55
55
|
this.name = 'TagCheckError';
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
/** Error thrown when out of gas. */
|
|
60
|
+
export class OutOfGasError extends AvmExecutionError {
|
|
61
|
+
constructor(dimensions: string[]) {
|
|
62
|
+
super(`Not enough ${dimensions.map(d => d.toUpperCase()).join(', ')} gas left`);
|
|
63
|
+
this.name = 'OutOfGasError';
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -10,7 +10,7 @@ import merge from 'lodash.merge';
|
|
|
10
10
|
|
|
11
11
|
import { CommitmentsDB, MessageLoadOracleInputs, PublicContractsDB, PublicStateDB } from '../../index.js';
|
|
12
12
|
import { AvmContext } from '../avm_context.js';
|
|
13
|
-
import { AvmExecutionEnvironment } from '../avm_execution_environment.js';
|
|
13
|
+
import { AvmContextInputs, AvmExecutionEnvironment } from '../avm_execution_environment.js';
|
|
14
14
|
import { AvmMachineState } from '../avm_machine_state.js';
|
|
15
15
|
import { HostStorage } from '../journal/host_storage.js';
|
|
16
16
|
import { AvmPersistableStateManager } from '../journal/journal.js';
|
|
@@ -85,13 +85,13 @@ export function initGlobalVariables(overrides?: Partial<GlobalVariables>): Globa
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
/**
|
|
88
|
-
* Create an empty instance of the Machine State where all values are
|
|
88
|
+
* Create an empty instance of the Machine State where all values are set to a large enough amount, unless overridden in the overrides object
|
|
89
89
|
*/
|
|
90
90
|
export function initMachineState(overrides?: Partial<AvmMachineState>): AvmMachineState {
|
|
91
91
|
return AvmMachineState.fromState({
|
|
92
|
-
l1GasLeft: overrides?.l1GasLeft ??
|
|
93
|
-
l2GasLeft: overrides?.l2GasLeft ??
|
|
94
|
-
daGasLeft: overrides?.daGasLeft ??
|
|
92
|
+
l1GasLeft: overrides?.l1GasLeft ?? 1e6,
|
|
93
|
+
l2GasLeft: overrides?.l2GasLeft ?? 1e6,
|
|
94
|
+
daGasLeft: overrides?.daGasLeft ?? 1e6,
|
|
95
95
|
});
|
|
96
96
|
}
|
|
97
97
|
|
|
@@ -113,3 +113,19 @@ export function initL1ToL2MessageOracleInput(
|
|
|
113
113
|
new SiblingPath(L1_TO_L2_MSG_TREE_HEIGHT, Array(L1_TO_L2_MSG_TREE_HEIGHT)),
|
|
114
114
|
);
|
|
115
115
|
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Adjust the user index to account for the AvmContextInputs size.
|
|
119
|
+
* This is a hack for testing, and should go away once AvmContextInputs themselves go away.
|
|
120
|
+
*/
|
|
121
|
+
export function adjustCalldataIndex(userIndex: number): number {
|
|
122
|
+
return userIndex + AvmContextInputs.SIZE;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function anyAvmContextInputs() {
|
|
126
|
+
const tv = [];
|
|
127
|
+
for (let i = 0; i < AvmContextInputs.SIZE; i++) {
|
|
128
|
+
tv.push(expect.any(Fr));
|
|
129
|
+
}
|
|
130
|
+
return tv;
|
|
131
|
+
}
|
|
@@ -156,7 +156,16 @@ export class AvmPersistableStateManager {
|
|
|
156
156
|
public async checkL1ToL2MessageExists(msgHash: Fr, msgLeafIndex: Fr): Promise<boolean> {
|
|
157
157
|
let exists = false;
|
|
158
158
|
try {
|
|
159
|
-
|
|
159
|
+
// The following 2 values are used to compute a message nullifier. Given that here we do not care about getting
|
|
160
|
+
// non-nullified messages we can just pass in random values and the nullifier check will effectively be ignored
|
|
161
|
+
// (no nullifier will be found).
|
|
162
|
+
const ignoredContractAddress = AztecAddress.random();
|
|
163
|
+
const ignoredSecret = Fr.random();
|
|
164
|
+
const gotMessage = await this.hostStorage.commitmentsDb.getL1ToL2MembershipWitness(
|
|
165
|
+
ignoredContractAddress,
|
|
166
|
+
msgHash,
|
|
167
|
+
ignoredSecret,
|
|
168
|
+
);
|
|
160
169
|
exists = gotMessage !== undefined && gotMessage.index == msgLeafIndex.toBigInt();
|
|
161
170
|
} catch {
|
|
162
171
|
// error getting message - doesn't exist!
|
|
@@ -23,21 +23,24 @@ export class Poseidon2 extends Instruction {
|
|
|
23
23
|
constructor(
|
|
24
24
|
private indirect: number,
|
|
25
25
|
private dstOffset: number,
|
|
26
|
-
private
|
|
27
|
-
private
|
|
26
|
+
private messageOffset: number,
|
|
27
|
+
private messageSize: number,
|
|
28
28
|
) {
|
|
29
29
|
super();
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
async execute(context: AvmContext): Promise<void> {
|
|
33
33
|
// We hash a set of field elements
|
|
34
|
-
const [
|
|
34
|
+
const [dstOffset, messageOffset] = Addressing.fromWire(this.indirect).resolve(
|
|
35
|
+
[this.dstOffset, this.messageOffset],
|
|
36
|
+
context.machineState.memory,
|
|
37
|
+
);
|
|
35
38
|
|
|
36
39
|
// Memory pointer will be indirect
|
|
37
|
-
const hashData = context.machineState.memory.getSlice(
|
|
40
|
+
const hashData = context.machineState.memory.getSlice(messageOffset, this.messageSize).map(word => word.toBuffer());
|
|
38
41
|
|
|
39
42
|
const hash = poseidonHash(hashData);
|
|
40
|
-
context.machineState.memory.set(
|
|
43
|
+
context.machineState.memory.set(dstOffset, new Field(hash));
|
|
41
44
|
|
|
42
45
|
context.machineState.incrementPc();
|
|
43
46
|
}
|
|
@@ -59,8 +62,8 @@ export class Keccak extends Instruction {
|
|
|
59
62
|
constructor(
|
|
60
63
|
private indirect: number,
|
|
61
64
|
private dstOffset: number,
|
|
62
|
-
private
|
|
63
|
-
private
|
|
65
|
+
private messageOffset: number,
|
|
66
|
+
private messageSize: number,
|
|
64
67
|
) {
|
|
65
68
|
super();
|
|
66
69
|
}
|
|
@@ -68,12 +71,12 @@ export class Keccak extends Instruction {
|
|
|
68
71
|
// Note hash output is 32 bytes, so takes up two fields
|
|
69
72
|
async execute(context: AvmContext): Promise<void> {
|
|
70
73
|
// We hash a set of field elements
|
|
71
|
-
const [
|
|
72
|
-
[this.
|
|
74
|
+
const [dstOffset, messageOffset] = Addressing.fromWire(this.indirect).resolve(
|
|
75
|
+
[this.dstOffset, this.messageOffset],
|
|
73
76
|
context.machineState.memory,
|
|
74
77
|
);
|
|
75
78
|
|
|
76
|
-
const hashData = context.machineState.memory.getSlice(
|
|
79
|
+
const hashData = context.machineState.memory.getSlice(messageOffset, this.messageSize).map(word => word.toBuffer());
|
|
77
80
|
|
|
78
81
|
const hash = keccak(Buffer.concat(hashData));
|
|
79
82
|
|
|
@@ -104,21 +107,21 @@ export class Sha256 extends Instruction {
|
|
|
104
107
|
constructor(
|
|
105
108
|
private indirect: number,
|
|
106
109
|
private dstOffset: number,
|
|
107
|
-
private
|
|
108
|
-
private
|
|
110
|
+
private messageOffset: number,
|
|
111
|
+
private messageSize: number,
|
|
109
112
|
) {
|
|
110
113
|
super();
|
|
111
114
|
}
|
|
112
115
|
|
|
113
116
|
// Note hash output is 32 bytes, so takes up two fields
|
|
114
117
|
async execute(context: AvmContext): Promise<void> {
|
|
115
|
-
const [
|
|
116
|
-
[this.
|
|
118
|
+
const [dstOffset, messageOffset] = Addressing.fromWire(this.indirect).resolve(
|
|
119
|
+
[this.dstOffset, this.messageOffset],
|
|
117
120
|
context.machineState.memory,
|
|
118
121
|
);
|
|
119
122
|
|
|
120
123
|
// We hash a set of field elements
|
|
121
|
-
const hashData = context.machineState.memory.getSlice(
|
|
124
|
+
const hashData = context.machineState.memory.getSlice(messageOffset, this.messageSize).map(word => word.toBuffer());
|
|
122
125
|
|
|
123
126
|
const hash = sha256(Buffer.concat(hashData));
|
|
124
127
|
|
|
@@ -149,21 +152,25 @@ export class Pedersen extends Instruction {
|
|
|
149
152
|
constructor(
|
|
150
153
|
private indirect: number,
|
|
151
154
|
private dstOffset: number,
|
|
152
|
-
private
|
|
153
|
-
private
|
|
155
|
+
private messageOffset: number,
|
|
156
|
+
private messageSizeOffset: number,
|
|
154
157
|
) {
|
|
155
158
|
super();
|
|
156
159
|
}
|
|
157
160
|
|
|
158
161
|
async execute(context: AvmContext): Promise<void> {
|
|
159
|
-
const [
|
|
162
|
+
const [dstOffset, messageOffset, messageSizeOffset] = Addressing.fromWire(this.indirect).resolve(
|
|
163
|
+
[this.dstOffset, this.messageOffset, this.messageSizeOffset],
|
|
164
|
+
context.machineState.memory,
|
|
165
|
+
);
|
|
160
166
|
|
|
161
167
|
// We hash a set of field elements
|
|
162
|
-
const
|
|
168
|
+
const messageSize = Number(context.machineState.memory.get(messageSizeOffset).toBigInt());
|
|
169
|
+
const hashData = context.machineState.memory.getSlice(messageOffset, messageSize).map(word => word.toBuffer());
|
|
163
170
|
|
|
164
171
|
// No domain sep for now
|
|
165
172
|
const hash = pedersenHash(hashData);
|
|
166
|
-
context.machineState.memory.set(
|
|
173
|
+
context.machineState.memory.set(dstOffset, new Field(hash));
|
|
167
174
|
|
|
168
175
|
context.machineState.incrementPc();
|
|
169
176
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { strict as assert } from 'assert';
|
|
2
2
|
|
|
3
3
|
import type { AvmContext } from '../avm_context.js';
|
|
4
|
+
import { EmptyGasCost, GasCost, GasCosts } from '../avm_gas_cost.js';
|
|
4
5
|
import { BufferCursor } from '../serialization/buffer_cursor.js';
|
|
5
|
-
import { OperandType, deserialize, serialize } from '../serialization/instruction_serialization.js';
|
|
6
|
+
import { Opcode, OperandType, deserialize, serialize } from '../serialization/instruction_serialization.js';
|
|
6
7
|
|
|
7
8
|
type InstructionConstructor = {
|
|
8
9
|
new (...args: any[]): Instruction;
|
|
@@ -14,6 +15,24 @@ type InstructionConstructor = {
|
|
|
14
15
|
* It's most important aspects are execute and (de)serialize.
|
|
15
16
|
*/
|
|
16
17
|
export abstract class Instruction {
|
|
18
|
+
/**
|
|
19
|
+
* Consumes gas and executes the instruction.
|
|
20
|
+
* This is the main entry point for the instruction.
|
|
21
|
+
* @param context - The AvmContext in which the instruction executes.
|
|
22
|
+
*/
|
|
23
|
+
public run(context: AvmContext): Promise<void> {
|
|
24
|
+
context.machineState.consumeGas(this.gasCost());
|
|
25
|
+
return this.execute(context);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Loads default gas cost for the instruction from the GasCosts table.
|
|
30
|
+
* Instruction sub-classes can override this if their gas cost is not fixed.
|
|
31
|
+
*/
|
|
32
|
+
public gasCost(): GasCost {
|
|
33
|
+
return GasCosts[this.opcode] ?? EmptyGasCost;
|
|
34
|
+
}
|
|
35
|
+
|
|
17
36
|
/**
|
|
18
37
|
* Execute the instruction.
|
|
19
38
|
* Instruction sub-classes must implement this.
|
|
@@ -21,7 +40,7 @@ export abstract class Instruction {
|
|
|
21
40
|
* each instruction until the machine state signals "halted".
|
|
22
41
|
* @param context - The AvmContext in which the instruction executes.
|
|
23
42
|
*/
|
|
24
|
-
|
|
43
|
+
protected abstract execute(context: AvmContext): Promise<void>;
|
|
25
44
|
|
|
26
45
|
/**
|
|
27
46
|
* Generate a string representation of the instruction including
|
|
@@ -61,4 +80,28 @@ export abstract class Instruction {
|
|
|
61
80
|
const args = res.slice(1); // Remove opcode.
|
|
62
81
|
return new this(...args);
|
|
63
82
|
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Returns the stringified type of the instruction.
|
|
86
|
+
* Instruction sub-classes should have a static `type` property.
|
|
87
|
+
*/
|
|
88
|
+
public get type(): string {
|
|
89
|
+
const type = 'type' in this.constructor && (this.constructor.type as string);
|
|
90
|
+
if (!type) {
|
|
91
|
+
throw new Error(`Instruction class ${this.constructor.name} does not have a static 'type' property defined.`);
|
|
92
|
+
}
|
|
93
|
+
return type;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Returns the opcode of the instruction.
|
|
98
|
+
* Instruction sub-classes should have a static `opcode` property.
|
|
99
|
+
*/
|
|
100
|
+
public get opcode(): Opcode {
|
|
101
|
+
const opcode = 'opcode' in this.constructor ? (this.constructor.opcode as Opcode) : undefined;
|
|
102
|
+
if (opcode === undefined || Opcode[opcode] === undefined) {
|
|
103
|
+
throw new Error(`Instruction class ${this.constructor.name} does not have a static 'opcode' property defined.`);
|
|
104
|
+
}
|
|
105
|
+
return opcode;
|
|
106
|
+
}
|
|
64
107
|
}
|
|
@@ -3,7 +3,6 @@ import { FunctionArtifactWithDebugMetadata, decodeReturnValues } from '@aztec/fo
|
|
|
3
3
|
import { AztecAddress } from '@aztec/foundation/aztec-address';
|
|
4
4
|
import { Fr } from '@aztec/foundation/fields';
|
|
5
5
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
6
|
-
import { to2Fields } from '@aztec/foundation/serialize';
|
|
7
6
|
|
|
8
7
|
import { extractReturnWitness } from '../acvm/deserialize.js';
|
|
9
8
|
import { Oracle, acvm, extractCallStack } from '../acvm/index.js';
|
|
@@ -24,7 +23,7 @@ export async function executePrivateFunction(
|
|
|
24
23
|
): Promise<ExecutionResult> {
|
|
25
24
|
const functionSelector = functionData.selector;
|
|
26
25
|
log(`Executing external function ${contractAddress}:${functionSelector}(${artifact.name})`);
|
|
27
|
-
const acir =
|
|
26
|
+
const acir = artifact.bytecode;
|
|
28
27
|
const initialWitness = context.getInitialWitness(artifact);
|
|
29
28
|
const acvmCallback = new Oracle(context);
|
|
30
29
|
const { partialWitness } = await acvm(await AcirSimulator.getSolver(), acir, initialWitness, acvmCallback).catch(
|
|
@@ -47,9 +46,9 @@ export async function executePrivateFunction(
|
|
|
47
46
|
const encryptedLogs = context.getEncryptedLogs();
|
|
48
47
|
const unencryptedLogs = context.getUnencryptedLogs();
|
|
49
48
|
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) --> set this in Noir
|
|
50
|
-
publicInputs.encryptedLogsHash =
|
|
49
|
+
publicInputs.encryptedLogsHash = Fr.fromBuffer(encryptedLogs.hash());
|
|
51
50
|
publicInputs.encryptedLogPreimagesLength = new Fr(encryptedLogs.getSerializedLength());
|
|
52
|
-
publicInputs.unencryptedLogsHash =
|
|
51
|
+
publicInputs.unencryptedLogsHash = Fr.fromBuffer(unencryptedLogs.hash());
|
|
53
52
|
publicInputs.unencryptedLogPreimagesLength = new Fr(unencryptedLogs.getSerializedLength());
|
|
54
53
|
|
|
55
54
|
const callStackItem = new PrivateCallStackItem(contractAddress, functionData, publicInputs);
|
|
@@ -25,7 +25,7 @@ export async function executeUnconstrainedFunction(
|
|
|
25
25
|
const functionSelector = functionData.selector;
|
|
26
26
|
log(`Executing unconstrained function ${contractAddress}:${functionSelector}`);
|
|
27
27
|
|
|
28
|
-
const acir =
|
|
28
|
+
const acir = artifact.bytecode;
|
|
29
29
|
const initialWitness = toACVMWitness(0, args);
|
|
30
30
|
const { partialWitness } = await acvm(
|
|
31
31
|
await AcirSimulator.getSolver(),
|
|
@@ -225,12 +225,15 @@ export class ViewDataOracle extends TypedOracle {
|
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
/**
|
|
228
|
-
* Fetches
|
|
229
|
-
* @param
|
|
230
|
-
* @
|
|
228
|
+
* Fetches a message from the db, given its key.
|
|
229
|
+
* @param contractAddress - Address of a contract by which the message was emitted.
|
|
230
|
+
* @param messageHash - Hash of the message.
|
|
231
|
+
* @param secret - Secret used to compute a nullifier.
|
|
232
|
+
* @dev Contract address and secret are only used to compute the nullifier to get non-nullified messages
|
|
233
|
+
* @returns The l1 to l2 membership witness (index of message in the tree and sibling path).
|
|
231
234
|
*/
|
|
232
|
-
public async getL1ToL2MembershipWitness(
|
|
233
|
-
return await this.db.getL1ToL2MembershipWitness(
|
|
235
|
+
public async getL1ToL2MembershipWitness(contractAddress: AztecAddress, messageHash: Fr, secret: Fr) {
|
|
236
|
+
return await this.db.getL1ToL2MembershipWitness(contractAddress, messageHash, secret);
|
|
234
237
|
}
|
|
235
238
|
|
|
236
239
|
/**
|
package/src/index.ts
CHANGED
package/src/public/db.ts
CHANGED
|
@@ -79,12 +79,18 @@ export interface PublicContractsDB {
|
|
|
79
79
|
/** Database interface for providing access to commitment tree, l1 to l2 message tree, and nullifier tree. */
|
|
80
80
|
export interface CommitmentsDB {
|
|
81
81
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* @param
|
|
85
|
-
* @
|
|
82
|
+
* Fetches a message from the db, given its key.
|
|
83
|
+
* @param contractAddress - Address of a contract by which the message was emitted.
|
|
84
|
+
* @param messageHash - Hash of the message.
|
|
85
|
+
* @param secret - Secret used to compute a nullifier.
|
|
86
|
+
* @dev Contract address and secret are only used to compute the nullifier to get non-nullified messages
|
|
87
|
+
* @returns The l1 to l2 membership witness (index of message in the tree and sibling path).
|
|
86
88
|
*/
|
|
87
|
-
getL1ToL2MembershipWitness(
|
|
89
|
+
getL1ToL2MembershipWitness(
|
|
90
|
+
contractAddress: AztecAddress,
|
|
91
|
+
messageHash: Fr,
|
|
92
|
+
secret: Fr,
|
|
93
|
+
): Promise<MessageLoadOracleInputs<typeof L1_TO_L2_MSG_TREE_HEIGHT>>;
|
|
88
94
|
|
|
89
95
|
/**
|
|
90
96
|
* Gets the index of a commitment in the note hash tree.
|
package/src/public/executor.ts
CHANGED
|
@@ -229,13 +229,15 @@ export class PublicExecutor {
|
|
|
229
229
|
const hostStorage = new HostStorage(this.stateDb, this.contractsDb, this.commitmentsDb);
|
|
230
230
|
const worldStateJournal = new AvmPersistableStateManager(hostStorage);
|
|
231
231
|
const executionEnv = temporaryCreateAvmExecutionEnvironment(execution, globalVariables);
|
|
232
|
-
|
|
232
|
+
// TODO(@spalladino) Load initial gas from the public execution request
|
|
233
|
+
const machineState = new AvmMachineState(100_000, 100_000, 100_000);
|
|
233
234
|
|
|
234
235
|
const context = new AvmContext(worldStateJournal, executionEnv, machineState);
|
|
235
236
|
const simulator = new AvmSimulator(context);
|
|
236
237
|
|
|
237
238
|
const result = await simulator.execute();
|
|
238
239
|
const newWorldState = context.persistableState.flush();
|
|
240
|
+
// TODO(@spalladino) Read gas left from machineState and return it
|
|
239
241
|
return temporaryConvertAvmResults(execution, newWorldState, result);
|
|
240
242
|
}
|
|
241
243
|
|