@aztec/simulator 0.80.0 → 0.82.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/common/db_interfaces.d.ts +30 -17
- package/dest/common/db_interfaces.d.ts.map +1 -1
- package/dest/common/db_interfaces.js +1 -1
- package/dest/common/debug_fn_name.d.ts +2 -2
- package/dest/common/debug_fn_name.d.ts.map +1 -1
- package/dest/common/message_load_oracle_inputs.d.ts +4 -0
- package/dest/common/message_load_oracle_inputs.d.ts.map +1 -1
- package/dest/common/message_load_oracle_inputs.js +9 -0
- package/dest/private/acvm/acvm.d.ts +6 -1
- package/dest/private/acvm/acvm.d.ts.map +1 -1
- package/dest/private/acvm/acvm.js +7 -13
- package/dest/private/acvm/deserialize.d.ts +19 -18
- package/dest/private/acvm/deserialize.d.ts.map +1 -1
- package/dest/private/acvm/deserialize.js +31 -23
- package/dest/private/acvm/oracle/oracle.d.ts +36 -34
- package/dest/private/acvm/oracle/oracle.d.ts.map +1 -1
- package/dest/private/acvm/oracle/oracle.js +134 -79
- package/dest/private/acvm/oracle/typed_oracle.d.ts +3 -2
- package/dest/private/acvm/oracle/typed_oracle.d.ts.map +1 -1
- package/dest/private/acvm/oracle/typed_oracle.js +5 -2
- package/dest/private/acvm/serialize.d.ts +11 -0
- package/dest/private/acvm/serialize.d.ts.map +1 -1
- package/dest/private/acvm/serialize.js +27 -0
- package/dest/private/execution_data_provider.d.ts +15 -13
- package/dest/private/execution_data_provider.d.ts.map +1 -1
- package/dest/private/private_execution.d.ts +2 -2
- package/dest/private/private_execution.d.ts.map +1 -1
- package/dest/private/private_execution.js +4 -5
- package/dest/private/private_execution_oracle.d.ts.map +1 -1
- package/dest/private/private_execution_oracle.js +1 -1
- package/dest/private/providers/acvm_native.d.ts +6 -4
- package/dest/private/providers/acvm_native.d.ts.map +1 -1
- package/dest/private/providers/acvm_native.js +6 -3
- package/dest/private/providers/acvm_wasm.d.ts +6 -7
- package/dest/private/providers/acvm_wasm.d.ts.map +1 -1
- package/dest/private/providers/acvm_wasm.js +13 -15
- package/dest/private/providers/acvm_wasm_with_blobs.d.ts +5 -5
- package/dest/private/providers/acvm_wasm_with_blobs.d.ts.map +1 -1
- package/dest/private/providers/acvm_wasm_with_blobs.js +7 -9
- package/dest/private/providers/circuit_recording/circuit_recorder.d.ts +90 -0
- package/dest/private/providers/circuit_recording/circuit_recorder.d.ts.map +1 -0
- package/dest/private/providers/circuit_recording/circuit_recorder.js +246 -0
- package/dest/private/providers/circuit_recording/simulation_provider_recorder_wrapper.d.ts +18 -0
- package/dest/private/providers/circuit_recording/simulation_provider_recorder_wrapper.d.ts.map +1 -0
- package/dest/private/providers/circuit_recording/simulation_provider_recorder_wrapper.js +39 -0
- package/dest/private/providers/simulation_provider.d.ts +21 -7
- package/dest/private/providers/simulation_provider.d.ts.map +1 -1
- package/dest/private/simulator.d.ts +3 -2
- package/dest/private/simulator.d.ts.map +1 -1
- package/dest/private/simulator.js +2 -2
- package/dest/private/unconstrained_execution.d.ts +2 -2
- package/dest/private/unconstrained_execution.d.ts.map +1 -1
- package/dest/private/unconstrained_execution.js +1 -2
- package/dest/private/unconstrained_execution_oracle.d.ts +5 -3
- package/dest/private/unconstrained_execution_oracle.d.ts.map +1 -1
- package/dest/private/unconstrained_execution_oracle.js +9 -5
- package/dest/public/avm/avm_simulator.d.ts.map +1 -1
- package/dest/public/avm/avm_simulator.js +0 -2
- package/dest/public/avm/fixtures/avm_simulation_tester.d.ts.map +1 -1
- package/dest/public/avm/fixtures/avm_simulation_tester.js +5 -5
- package/dest/public/avm/fixtures/index.d.ts +4 -4
- package/dest/public/avm/fixtures/index.d.ts.map +1 -1
- package/dest/public/avm/fixtures/index.js +9 -6
- package/dest/public/avm/fixtures/simple_contract_data_source.d.ts +1 -2
- package/dest/public/avm/fixtures/simple_contract_data_source.d.ts.map +1 -1
- package/dest/public/avm/fixtures/simple_contract_data_source.js +0 -3
- package/dest/public/avm/journal/journal.d.ts +16 -70
- package/dest/public/avm/journal/journal.d.ts.map +1 -1
- package/dest/public/avm/journal/journal.js +88 -210
- package/dest/public/avm/journal/nullifiers.d.ts +2 -2
- package/dest/public/avm/journal/nullifiers.d.ts.map +1 -1
- package/dest/public/avm/journal/public_storage.d.ts +2 -2
- package/dest/public/avm/journal/public_storage.d.ts.map +1 -1
- package/dest/public/avm/test_utils.d.ts +10 -13
- package/dest/public/avm/test_utils.d.ts.map +1 -1
- package/dest/public/avm/test_utils.js +8 -13
- package/dest/public/fixtures/public_tx_simulation_tester.d.ts +3 -3
- package/dest/public/fixtures/public_tx_simulation_tester.d.ts.map +1 -1
- package/dest/public/fixtures/public_tx_simulation_tester.js +10 -9
- package/dest/public/hinting_db_sources.d.ts +19 -0
- package/dest/public/hinting_db_sources.d.ts.map +1 -0
- package/dest/public/hinting_db_sources.js +36 -0
- package/dest/public/public_db_sources.d.ts +46 -22
- package/dest/public/public_db_sources.d.ts.map +1 -1
- package/dest/public/public_db_sources.js +82 -27
- package/dest/public/public_processor/public_processor.d.ts +5 -5
- package/dest/public/public_processor/public_processor.d.ts.map +1 -1
- package/dest/public/public_processor/public_processor.js +21 -20
- package/dest/public/public_tx_simulator/public_tx_context.d.ts +9 -14
- package/dest/public/public_tx_simulator/public_tx_context.d.ts.map +1 -1
- package/dest/public/public_tx_simulator/public_tx_context.js +15 -19
- package/dest/public/public_tx_simulator/public_tx_simulator.d.ts +9 -6
- package/dest/public/public_tx_simulator/public_tx_simulator.d.ts.map +1 -1
- package/dest/public/public_tx_simulator/public_tx_simulator.js +28 -14
- package/dest/public/side_effect_trace.d.ts +6 -22
- package/dest/public/side_effect_trace.d.ts.map +1 -1
- package/dest/public/side_effect_trace.js +11 -70
- package/dest/public/side_effect_trace_interface.d.ts +5 -19
- package/dest/public/side_effect_trace_interface.d.ts.map +1 -1
- package/dest/testing.d.ts +2 -0
- package/dest/testing.d.ts.map +1 -0
- package/dest/testing.js +1 -0
- package/package.json +15 -14
- package/src/common/db_interfaces.ts +32 -18
- package/src/common/debug_fn_name.ts +2 -2
- package/src/common/message_load_oracle_inputs.ts +8 -0
- package/src/private/acvm/acvm.ts +8 -24
- package/src/private/acvm/deserialize.ts +35 -29
- package/src/private/acvm/oracle/oracle.ts +171 -129
- package/src/private/acvm/oracle/typed_oracle.ts +7 -3
- package/src/private/acvm/serialize.ts +28 -0
- package/src/private/execution_data_provider.ts +19 -14
- package/src/private/private_execution.ts +11 -7
- package/src/private/private_execution_oracle.ts +5 -1
- package/src/private/providers/acvm_native.ts +17 -6
- package/src/private/providers/acvm_wasm.ts +27 -20
- package/src/private/providers/acvm_wasm_with_blobs.ts +15 -12
- package/src/private/providers/circuit_recording/circuit_recorder.ts +283 -0
- package/src/private/providers/circuit_recording/simulation_provider_recorder_wrapper.ts +82 -0
- package/src/private/providers/simulation_provider.ts +30 -5
- package/src/private/simulator.ts +5 -3
- package/src/private/unconstrained_execution.ts +8 -4
- package/src/private/unconstrained_execution_oracle.ts +15 -9
- package/src/public/avm/avm_simulator.ts +0 -2
- package/src/public/avm/fixtures/avm_simulation_tester.ts +8 -5
- package/src/public/avm/fixtures/index.ts +16 -10
- package/src/public/avm/fixtures/simple_contract_data_source.ts +1 -10
- package/src/public/avm/journal/journal.ts +119 -353
- package/src/public/avm/journal/nullifiers.ts +2 -2
- package/src/public/avm/journal/public_storage.ts +2 -2
- package/src/public/avm/test_utils.ts +20 -29
- package/src/public/fixtures/public_tx_simulation_tester.ts +9 -12
- package/src/public/hinting_db_sources.ts +71 -0
- package/src/public/public_db_sources.ts +134 -32
- package/src/public/public_processor/public_processor.ts +22 -21
- package/src/public/public_tx_simulator/public_tx_context.ts +30 -38
- package/src/public/public_tx_simulator/public_tx_simulator.ts +47 -17
- package/src/public/side_effect_trace.ts +8 -172
- package/src/public/side_effect_trace_interface.ts +4 -55
- package/src/testing.ts +1 -0
- package/dest/public/avm/bytecode_utils.d.ts +0 -5
- package/dest/public/avm/bytecode_utils.d.ts.map +0 -1
- package/dest/public/avm/bytecode_utils.js +0 -17
- package/src/public/avm/bytecode_utils.ts +0 -17
|
@@ -10,12 +10,11 @@ import { poseidon2Hash } from '@aztec/foundation/crypto';
|
|
|
10
10
|
import { Fr } from '@aztec/foundation/fields';
|
|
11
11
|
import { jsonStringify } from '@aztec/foundation/json-rpc';
|
|
12
12
|
import { createLogger } from '@aztec/foundation/log';
|
|
13
|
-
import type { IndexedTreeLeafPreimage } from '@aztec/foundation/trees';
|
|
14
13
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
15
|
-
import {
|
|
14
|
+
import { PublicDataWrite } from '@aztec/stdlib/avm';
|
|
16
15
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
17
16
|
import { SerializableContractInstance } from '@aztec/stdlib/contract';
|
|
18
|
-
import type { ContractClassWithCommitment } from '@aztec/stdlib/contract';
|
|
17
|
+
import type { ContractClassWithCommitment, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
19
18
|
import {
|
|
20
19
|
computeNoteHashNonce,
|
|
21
20
|
computePublicDataTreeLeafSlot,
|
|
@@ -23,38 +22,20 @@ import {
|
|
|
23
22
|
siloNoteHash,
|
|
24
23
|
siloNullifier,
|
|
25
24
|
} from '@aztec/stdlib/hash';
|
|
26
|
-
import type { IndexedTreeId, MerkleTreeWriteOperations } from '@aztec/stdlib/interfaces/server';
|
|
27
25
|
import type { PublicCallRequest } from '@aztec/stdlib/kernel';
|
|
28
26
|
import { SharedMutableValues, SharedMutableValuesWithHash } from '@aztec/stdlib/shared-mutable';
|
|
29
|
-
import { MerkleTreeId
|
|
27
|
+
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
30
28
|
|
|
31
29
|
import { strict as assert } from 'assert';
|
|
32
|
-
import cloneDeep from 'lodash.clonedeep';
|
|
33
30
|
|
|
34
31
|
import { getPublicFunctionDebugName } from '../../../common/debug_fn_name.js';
|
|
35
|
-
import type {
|
|
32
|
+
import type { PublicTreesDB } from '../../../public/public_db_sources.js';
|
|
33
|
+
import type { PublicContractsDBInterface } from '../../../server.js';
|
|
36
34
|
import type { PublicSideEffectTraceInterface } from '../../side_effect_trace_interface.js';
|
|
37
35
|
import type { AvmExecutionEnvironment } from '../avm_execution_environment.js';
|
|
38
36
|
import { NullifierCollisionError, NullifierManager } from './nullifiers.js';
|
|
39
37
|
import { PublicStorage } from './public_storage.js';
|
|
40
38
|
|
|
41
|
-
/**
|
|
42
|
-
* The result of fetching a leaf from an indexed tree. Contains the preimage and wether the leaf was already present
|
|
43
|
-
* or it's a low leaf.
|
|
44
|
-
*/
|
|
45
|
-
type GetLeafResult<T extends IndexedTreeLeafPreimage> = {
|
|
46
|
-
preimage: T;
|
|
47
|
-
leafOrLowLeafIndex: bigint;
|
|
48
|
-
alreadyPresent: boolean;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
type NullifierMembershipResult = {
|
|
52
|
-
exists: boolean;
|
|
53
|
-
leafOrLowLeafPreimage: NullifierLeafPreimage;
|
|
54
|
-
leafOrLowLeafIndex: bigint;
|
|
55
|
-
leafOrLowLeafPath: Fr[];
|
|
56
|
-
};
|
|
57
|
-
|
|
58
39
|
/**
|
|
59
40
|
* A class to manage persistable AVM state for contract calls.
|
|
60
41
|
* Maintains a cache of the current world state,
|
|
@@ -71,57 +52,50 @@ export class AvmPersistableStateManager {
|
|
|
71
52
|
private alreadyMergedIntoParent = false;
|
|
72
53
|
|
|
73
54
|
constructor(
|
|
74
|
-
|
|
75
|
-
private readonly
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
/** Public storage, including cached writes */
|
|
80
|
-
private readonly publicStorage: PublicStorage = new PublicStorage(worldStateDB),
|
|
81
|
-
/** Nullifier set, including cached/recently-emitted nullifiers */
|
|
82
|
-
private readonly nullifiers: NullifierManager = new NullifierManager(worldStateDB),
|
|
55
|
+
private readonly treesDB: PublicTreesDB,
|
|
56
|
+
private readonly contractsDB: PublicContractsDBInterface,
|
|
57
|
+
private readonly trace: PublicSideEffectTraceInterface,
|
|
58
|
+
private readonly firstNullifier: Fr, // Needed for note hashes.
|
|
59
|
+
private readonly blockNumber: number, // Needed for contract updates.
|
|
83
60
|
private readonly doMerkleOperations: boolean = false,
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
public readonly firstNullifier: Fr,
|
|
61
|
+
private readonly publicStorage: PublicStorage = new PublicStorage(treesDB),
|
|
62
|
+
private readonly nullifiers: NullifierManager = new NullifierManager(treesDB),
|
|
87
63
|
) {}
|
|
88
64
|
|
|
89
65
|
/**
|
|
90
66
|
* Create a new state manager
|
|
91
67
|
*/
|
|
92
68
|
public static create(
|
|
93
|
-
|
|
69
|
+
treesDB: PublicTreesDB,
|
|
70
|
+
contractsDB: PublicContractsDBInterface,
|
|
94
71
|
trace: PublicSideEffectTraceInterface,
|
|
95
72
|
doMerkleOperations: boolean = false,
|
|
96
73
|
firstNullifier: Fr,
|
|
74
|
+
blockNumber: number,
|
|
97
75
|
): AvmPersistableStateManager {
|
|
98
|
-
|
|
99
|
-
|
|
76
|
+
return new AvmPersistableStateManager(treesDB, contractsDB, trace, firstNullifier, blockNumber, doMerkleOperations);
|
|
77
|
+
}
|
|
100
78
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
/*nullifiers=*/ new NullifierManager(worldStateDB),
|
|
106
|
-
/*doMerkleOperations=*/ doMerkleOperations,
|
|
107
|
-
db,
|
|
108
|
-
firstNullifier,
|
|
109
|
-
);
|
|
79
|
+
// DO NOT USE!
|
|
80
|
+
// FIXME(fcarreiro): refactor and remove this.
|
|
81
|
+
public deprecatedGetTreesForPIGeneration() {
|
|
82
|
+
return this.treesDB;
|
|
110
83
|
}
|
|
111
84
|
|
|
112
85
|
/**
|
|
113
86
|
* Create a new state manager forked from this one
|
|
114
87
|
*/
|
|
115
88
|
public async fork() {
|
|
116
|
-
await this.
|
|
89
|
+
await this.treesDB.createCheckpoint();
|
|
117
90
|
return new AvmPersistableStateManager(
|
|
118
|
-
this.
|
|
91
|
+
this.treesDB,
|
|
92
|
+
this.contractsDB,
|
|
119
93
|
this.trace.fork(),
|
|
94
|
+
this.firstNullifier,
|
|
95
|
+
this.blockNumber,
|
|
96
|
+
this.doMerkleOperations,
|
|
120
97
|
this.publicStorage.fork(),
|
|
121
98
|
this.nullifiers.fork(),
|
|
122
|
-
this.doMerkleOperations,
|
|
123
|
-
this.db,
|
|
124
|
-
this.firstNullifier,
|
|
125
99
|
);
|
|
126
100
|
}
|
|
127
101
|
|
|
@@ -150,15 +124,17 @@ export class AvmPersistableStateManager {
|
|
|
150
124
|
this.nullifiers.acceptAndMerge(forkedState.nullifiers);
|
|
151
125
|
this.trace.merge(forkedState.trace, reverted);
|
|
152
126
|
if (reverted) {
|
|
153
|
-
await this.
|
|
127
|
+
await this.treesDB.revertCheckpoint();
|
|
154
128
|
if (this.doMerkleOperations) {
|
|
155
129
|
this.log.trace(
|
|
156
|
-
`Rolled back nullifier tree to root ${new Fr(
|
|
130
|
+
`Rolled back nullifier tree to root ${new Fr(
|
|
131
|
+
(await this.treesDB.getTreeInfo(MerkleTreeId.NULLIFIER_TREE)).root,
|
|
132
|
+
)}`,
|
|
157
133
|
);
|
|
158
134
|
}
|
|
159
135
|
} else {
|
|
160
136
|
this.log.trace('Merging forked state into parent...');
|
|
161
|
-
await this.
|
|
137
|
+
await this.treesDB.commitCheckpoint();
|
|
162
138
|
}
|
|
163
139
|
}
|
|
164
140
|
|
|
@@ -176,56 +152,19 @@ export class AvmPersistableStateManager {
|
|
|
176
152
|
if (this.doMerkleOperations) {
|
|
177
153
|
// write to native merkle trees
|
|
178
154
|
const publicDataWrite = new PublicDataWrite(leafSlot, value);
|
|
179
|
-
const result = await this.
|
|
155
|
+
const result = await this.treesDB.sequentialInsert(MerkleTreeId.PUBLIC_DATA_TREE, [publicDataWrite.toBuffer()]);
|
|
180
156
|
assert(result !== undefined, 'Public data tree insertion error. You might want to disable doMerkleOperations.');
|
|
181
157
|
this.log.trace(`Inserted public data tree leaf at leafSlot ${leafSlot}, value: ${value}`);
|
|
182
|
-
|
|
183
|
-
// low leaf hint
|
|
184
|
-
const lowLeafPreimage = result.lowLeavesWitnessData[0].leafPreimage as PublicDataTreeLeafPreimage;
|
|
185
|
-
const lowLeafIndex = result.lowLeavesWitnessData[0].index;
|
|
186
|
-
const lowLeafPath = result.lowLeavesWitnessData[0].siblingPath.toFields();
|
|
187
|
-
// new leaf insertion
|
|
188
|
-
const newLeafPreimage: PublicDataTreeLeafPreimage = cloneDeep(lowLeafPreimage);
|
|
189
|
-
let insertionPath: Fr[] | undefined;
|
|
190
|
-
|
|
191
|
-
if (result.insertionWitnessData.length === 0) {
|
|
192
|
-
assert(
|
|
193
|
-
newLeafPreimage.value.equals(value),
|
|
194
|
-
`Value mismatch when performing public data write (got value: ${value}, value in tree: ${newLeafPreimage.value})`,
|
|
195
|
-
);
|
|
196
|
-
} else {
|
|
197
|
-
// The new leaf preimage should have the new value and slot
|
|
198
|
-
newLeafPreimage.slot = leafSlot;
|
|
199
|
-
newLeafPreimage.value = value;
|
|
200
|
-
// TODO: is this necessary?! Why doesn't sequentialInsert return the newLeafPreimage via
|
|
201
|
-
// result.insertionWitnessData[0].leafPreimage?
|
|
202
|
-
|
|
203
|
-
this.log.trace(
|
|
204
|
-
`newLeafPreimage.slot: ${newLeafPreimage.slot}, newLeafPreimage.value: ${newLeafPreimage.value}, insertionIndex: ${result.insertionWitnessData[0].index}`,
|
|
205
|
-
);
|
|
206
|
-
insertionPath = result.insertionWitnessData[0].siblingPath.toFields();
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
await this.trace.tracePublicStorageWrite(
|
|
210
|
-
contractAddress,
|
|
211
|
-
slot,
|
|
212
|
-
value,
|
|
213
|
-
protocolWrite,
|
|
214
|
-
lowLeafPreimage,
|
|
215
|
-
new Fr(lowLeafIndex),
|
|
216
|
-
lowLeafPath,
|
|
217
|
-
newLeafPreimage,
|
|
218
|
-
insertionPath,
|
|
219
|
-
);
|
|
220
158
|
} else {
|
|
221
159
|
// Cache storage writes for later reference/reads
|
|
222
160
|
this.publicStorage.write(contractAddress, slot, value);
|
|
223
|
-
await this.trace.tracePublicStorageWrite(contractAddress, slot, value, protocolWrite);
|
|
224
161
|
}
|
|
162
|
+
|
|
163
|
+
await this.trace.tracePublicStorageWrite(contractAddress, slot, value, protocolWrite);
|
|
225
164
|
}
|
|
226
165
|
|
|
227
166
|
/**
|
|
228
|
-
* Read from public storage
|
|
167
|
+
* Read from public storage.
|
|
229
168
|
*
|
|
230
169
|
* @param contractAddress - the address of the contract whose storage is being read from
|
|
231
170
|
* @param slot - the slot in the contract's storage being read from
|
|
@@ -233,78 +172,18 @@ export class AvmPersistableStateManager {
|
|
|
233
172
|
*/
|
|
234
173
|
public async readStorage(contractAddress: AztecAddress, slot: Fr): Promise<Fr> {
|
|
235
174
|
if (this.doMerkleOperations) {
|
|
236
|
-
const
|
|
237
|
-
this.trace.tracePublicStorageRead(contractAddress, slot, value, leafPreimage, leafIndex, leafPath);
|
|
175
|
+
const value = await this.treesDB.storageRead(contractAddress, slot);
|
|
238
176
|
return value;
|
|
239
177
|
} else {
|
|
178
|
+
// TODO(fcarreiro): I don't get this. PublicStorage CAN end up reading the tree. Why is it in the "dont do merkle operations" branch?
|
|
240
179
|
const read = await this.publicStorage.read(contractAddress, slot);
|
|
241
180
|
this.log.trace(
|
|
242
181
|
`Storage read results (address=${contractAddress}, slot=${slot}): value=${read.value}, cached=${read.cached}`,
|
|
243
182
|
);
|
|
244
|
-
this.trace.tracePublicStorageRead(contractAddress, slot, read.value);
|
|
245
183
|
return read.value;
|
|
246
184
|
}
|
|
247
185
|
}
|
|
248
186
|
|
|
249
|
-
async getPublicDataMembership(
|
|
250
|
-
contractAddress: AztecAddress,
|
|
251
|
-
slot: Fr,
|
|
252
|
-
): Promise<{
|
|
253
|
-
value: Fr;
|
|
254
|
-
leafPreimage: PublicDataTreeLeafPreimage;
|
|
255
|
-
leafIndex: Fr;
|
|
256
|
-
leafPath: Fr[];
|
|
257
|
-
}> {
|
|
258
|
-
const leafSlot = await computePublicDataTreeLeafSlot(contractAddress, slot);
|
|
259
|
-
const treeId = MerkleTreeId.PUBLIC_DATA_TREE;
|
|
260
|
-
|
|
261
|
-
// Get leaf if present, low leaf if absent
|
|
262
|
-
// If leaf is present, hint/trace it. Otherwise, hint/trace the low leaf.
|
|
263
|
-
const { preimage, leafOrLowLeafIndex, alreadyPresent } = await this.getLeafOrLowLeafInfo<
|
|
264
|
-
typeof treeId,
|
|
265
|
-
PublicDataTreeLeafPreimage
|
|
266
|
-
>(treeId, leafSlot.toBigInt());
|
|
267
|
-
// The index and preimage here is either the low leaf or the leaf itself (depending on the value of update flag)
|
|
268
|
-
// In either case, we just want the sibling path to this leaf - it's up to the avm to distinguish if it's a low leaf or not
|
|
269
|
-
const leafPath = await this.db.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, leafOrLowLeafIndex);
|
|
270
|
-
const leafPreimage = preimage as PublicDataTreeLeafPreimage;
|
|
271
|
-
|
|
272
|
-
const value = alreadyPresent ? leafPreimage.value : Fr.zero(); // default value of 0
|
|
273
|
-
if (!alreadyPresent) {
|
|
274
|
-
this.log.trace(`Slot has never been written before!`);
|
|
275
|
-
// Sanity check that the leaf slot is skipped by low leaf when it doesn't exist
|
|
276
|
-
assert(
|
|
277
|
-
leafPreimage.slot.toBigInt() < leafSlot.toBigInt() &&
|
|
278
|
-
(leafPreimage.nextIndex === 0n || leafPreimage.nextSlot.toBigInt() > leafSlot.toBigInt()),
|
|
279
|
-
'Public data tree low leaf should skip the target leaf slot when the target leaf does not exist or is the max value.',
|
|
280
|
-
);
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
this.log.trace(
|
|
284
|
-
`Storage read results (address=${contractAddress}, slot=${slot}, leafSlot=${leafSlot}): value=${value}, previouslyWritten=${alreadyPresent}`,
|
|
285
|
-
);
|
|
286
|
-
|
|
287
|
-
return {
|
|
288
|
-
value,
|
|
289
|
-
leafPreimage,
|
|
290
|
-
leafIndex: new Fr(leafOrLowLeafIndex),
|
|
291
|
-
leafPath: leafPath.toFields(),
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Read from public storage, don't trace the read.
|
|
297
|
-
*
|
|
298
|
-
* @param contractAddress - the address of the contract whose storage is being read from
|
|
299
|
-
* @param slot - the slot in the contract's storage being read from
|
|
300
|
-
* @returns the latest value written to slot, or 0 if never written to before
|
|
301
|
-
*/
|
|
302
|
-
public async peekStorage(contractAddress: AztecAddress, slot: Fr): Promise<Fr> {
|
|
303
|
-
const { value, cached } = await this.publicStorage.read(contractAddress, slot);
|
|
304
|
-
this.log.trace(`Storage peek (address=${contractAddress}, slot=${slot}): value=${value}, cached=${cached}`);
|
|
305
|
-
return Promise.resolve(value);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
187
|
// TODO(4886): We currently don't silo note hashes.
|
|
309
188
|
/**
|
|
310
189
|
* Check if a note hash exists at the given leaf index, trace the check.
|
|
@@ -315,17 +194,11 @@ export class AvmPersistableStateManager {
|
|
|
315
194
|
* @returns true if the note hash exists at the given leaf index, false otherwise
|
|
316
195
|
*/
|
|
317
196
|
public async checkNoteHashExists(contractAddress: AztecAddress, noteHash: Fr, leafIndex: Fr): Promise<boolean> {
|
|
318
|
-
const gotLeafValue = (await this.
|
|
197
|
+
const gotLeafValue = (await this.treesDB.getNoteHash(leafIndex.toBigInt())) ?? Fr.ZERO;
|
|
319
198
|
const exists = gotLeafValue.equals(noteHash);
|
|
320
199
|
this.log.trace(
|
|
321
200
|
`noteHashes(${contractAddress})@${noteHash} ?? leafIndex: ${leafIndex} | gotLeafValue: ${gotLeafValue}, exists: ${exists}.`,
|
|
322
201
|
);
|
|
323
|
-
if (this.doMerkleOperations) {
|
|
324
|
-
const path = await this.db.getSiblingPath(MerkleTreeId.NOTE_HASH_TREE, leafIndex.toBigInt());
|
|
325
|
-
this.trace.traceNoteHashCheck(contractAddress, gotLeafValue, leafIndex, exists, path.toFields());
|
|
326
|
-
} else {
|
|
327
|
-
this.trace.traceNoteHashCheck(contractAddress, gotLeafValue, leafIndex, exists);
|
|
328
|
-
}
|
|
329
202
|
return Promise.resolve(exists);
|
|
330
203
|
}
|
|
331
204
|
|
|
@@ -336,7 +209,6 @@ export class AvmPersistableStateManager {
|
|
|
336
209
|
public async writeNoteHash(contractAddress: AztecAddress, noteHash: Fr): Promise<void> {
|
|
337
210
|
this.log.trace(`noteHashes(${contractAddress}) += ${noteHash}.`);
|
|
338
211
|
const siloedNoteHash = await siloNoteHash(contractAddress, noteHash);
|
|
339
|
-
|
|
340
212
|
await this.writeSiloedNoteHash(siloedNoteHash);
|
|
341
213
|
}
|
|
342
214
|
|
|
@@ -347,7 +219,6 @@ export class AvmPersistableStateManager {
|
|
|
347
219
|
public async writeSiloedNoteHash(siloedNoteHash: Fr): Promise<void> {
|
|
348
220
|
const nonce = await computeNoteHashNonce(this.firstNullifier, this.trace.getNoteHashCount());
|
|
349
221
|
const uniqueNoteHash = await computeUniqueNoteHash(nonce, siloedNoteHash);
|
|
350
|
-
|
|
351
222
|
await this.writeUniqueNoteHash(uniqueNoteHash);
|
|
352
223
|
}
|
|
353
224
|
|
|
@@ -357,17 +228,10 @@ export class AvmPersistableStateManager {
|
|
|
357
228
|
*/
|
|
358
229
|
public async writeUniqueNoteHash(uniqueNoteHash: Fr): Promise<void> {
|
|
359
230
|
this.log.trace(`noteHashes += @${uniqueNoteHash}.`);
|
|
360
|
-
|
|
361
231
|
if (this.doMerkleOperations) {
|
|
362
|
-
|
|
363
|
-
const treeInfo = await this.db.getTreeInfo(MerkleTreeId.NOTE_HASH_TREE);
|
|
364
|
-
const leafIndex = new Fr(treeInfo.size);
|
|
365
|
-
await this.db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, [uniqueNoteHash]);
|
|
366
|
-
const insertionPath = await this.db.getSiblingPath(MerkleTreeId.NOTE_HASH_TREE, leafIndex.toBigInt());
|
|
367
|
-
this.trace.traceNewNoteHash(uniqueNoteHash, leafIndex, insertionPath.toFields());
|
|
368
|
-
} else {
|
|
369
|
-
this.trace.traceNewNoteHash(uniqueNoteHash);
|
|
232
|
+
await this.treesDB.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, [uniqueNoteHash]);
|
|
370
233
|
}
|
|
234
|
+
this.trace.traceNewNoteHash(uniqueNoteHash);
|
|
371
235
|
}
|
|
372
236
|
|
|
373
237
|
/**
|
|
@@ -381,66 +245,17 @@ export class AvmPersistableStateManager {
|
|
|
381
245
|
const siloedNullifier = await siloNullifier(contractAddress, nullifier);
|
|
382
246
|
|
|
383
247
|
if (this.doMerkleOperations) {
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
this.trace.traceNullifierCheck(
|
|
387
|
-
siloedNullifier,
|
|
388
|
-
exists,
|
|
389
|
-
leafOrLowLeafPreimage,
|
|
390
|
-
new Fr(leafOrLowLeafIndex!),
|
|
391
|
-
leafOrLowLeafPath,
|
|
392
|
-
);
|
|
248
|
+
const exists = (await this.treesDB.getNullifierIndex(siloedNullifier)) !== undefined;
|
|
249
|
+
this.log.trace(`Checked siloed nullifier ${siloedNullifier} (exists=${exists})`);
|
|
393
250
|
return Promise.resolve(exists);
|
|
394
251
|
} else {
|
|
252
|
+
// TODO: same here, this CAN hit the db.
|
|
395
253
|
const { exists, cacheHit } = await this.nullifiers.checkExists(siloedNullifier);
|
|
396
254
|
this.log.trace(`Checked siloed nullifier ${siloedNullifier} (exists=${exists}), cacheHit=${cacheHit}`);
|
|
397
|
-
this.trace.traceNullifierCheck(siloedNullifier, exists);
|
|
398
255
|
return Promise.resolve(exists);
|
|
399
256
|
}
|
|
400
257
|
}
|
|
401
258
|
|
|
402
|
-
/**
|
|
403
|
-
* Helper to get membership information for a siloed nullifier when checking its existence.
|
|
404
|
-
* Optionally trace the nullifier check.
|
|
405
|
-
*
|
|
406
|
-
* @param siloedNullifier - the siloed nullifier to get membership information for
|
|
407
|
-
* @returns
|
|
408
|
-
* - exists - whether the nullifier exists in the nullifier set
|
|
409
|
-
* - leafOrLowLeafPreimage - the preimage of the nullifier leaf or its low-leaf if it doesn't exist
|
|
410
|
-
* - leafOrLowLeafIndex - the leaf index of the nullifier leaf or its low-leaf if it doesn't exist
|
|
411
|
-
* - leafOrLowLeafPath - the sibling path of the nullifier leaf or its low-leaf if it doesn't exist
|
|
412
|
-
*/
|
|
413
|
-
private async getNullifierMembership(siloedNullifier: Fr): Promise<NullifierMembershipResult> {
|
|
414
|
-
// Get leaf if present, low leaf if absent
|
|
415
|
-
// If leaf is present, hint/trace it. Otherwise, hint/trace the low leaf.
|
|
416
|
-
const treeId = MerkleTreeId.NULLIFIER_TREE;
|
|
417
|
-
const {
|
|
418
|
-
preimage: leafPreimage,
|
|
419
|
-
leafOrLowLeafIndex,
|
|
420
|
-
alreadyPresent,
|
|
421
|
-
} = await this.getLeafOrLowLeafInfo<typeof treeId, NullifierLeafPreimage>(treeId, siloedNullifier.toBigInt());
|
|
422
|
-
this.log.trace(`Checked siloed nullifier ${siloedNullifier} (exists=${alreadyPresent})`);
|
|
423
|
-
|
|
424
|
-
const leafPath = await this.db.getSiblingPath(treeId, leafOrLowLeafIndex!);
|
|
425
|
-
|
|
426
|
-
if (alreadyPresent) {
|
|
427
|
-
this.log.trace(`Siloed nullifier ${siloedNullifier} exists at leafIndex=${leafOrLowLeafIndex}`);
|
|
428
|
-
} else {
|
|
429
|
-
// Sanity check that the leaf value is skipped by low leaf when it doesn't exist
|
|
430
|
-
assert(
|
|
431
|
-
leafPreimage.nullifier.toBigInt() < siloedNullifier.toBigInt() &&
|
|
432
|
-
(leafPreimage.nextIndex === 0n || leafPreimage.nextNullifier.toBigInt() > siloedNullifier.toBigInt()),
|
|
433
|
-
'Nullifier tree low leaf should skip the target leaf nullifier when the target leaf does not exist.',
|
|
434
|
-
);
|
|
435
|
-
}
|
|
436
|
-
return {
|
|
437
|
-
exists: alreadyPresent,
|
|
438
|
-
leafOrLowLeafPreimage: leafPreimage,
|
|
439
|
-
leafOrLowLeafIndex,
|
|
440
|
-
leafOrLowLeafPath: leafPath.toFields(),
|
|
441
|
-
};
|
|
442
|
-
}
|
|
443
|
-
|
|
444
259
|
/**
|
|
445
260
|
* Write a nullifier to the nullifier set, trace the write.
|
|
446
261
|
* @param contractAddress - address of the contract that the nullifier is associated with
|
|
@@ -460,50 +275,22 @@ export class AvmPersistableStateManager {
|
|
|
460
275
|
this.log.trace(`Inserting siloed nullifier=${siloedNullifier}`);
|
|
461
276
|
|
|
462
277
|
if (this.doMerkleOperations) {
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
alreadyPresent,
|
|
468
|
-
} = await this.getLeafOrLowLeafInfo<typeof treeId, NullifierLeafPreimage>(treeId, siloedNullifier.toBigInt());
|
|
469
|
-
|
|
470
|
-
if (alreadyPresent) {
|
|
471
|
-
this.log.verbose(`Siloed nullifier ${siloedNullifier} already present in tree at index ${leafOrLowLeafIndex}!`);
|
|
472
|
-
// If the nullifier is already present, we should not insert it again
|
|
473
|
-
// instead we provide the direct membership path
|
|
474
|
-
const membershipPath = await this.db.getSiblingPath(treeId, leafOrLowLeafIndex);
|
|
475
|
-
// This just becomes a nullifier read hint
|
|
476
|
-
this.trace.traceNullifierCheck(
|
|
477
|
-
siloedNullifier,
|
|
478
|
-
/*exists=*/ alreadyPresent,
|
|
479
|
-
leafPreimage,
|
|
480
|
-
new Fr(leafOrLowLeafIndex),
|
|
481
|
-
membershipPath.toFields(),
|
|
482
|
-
);
|
|
278
|
+
const index = await this.treesDB.getNullifierIndex(siloedNullifier);
|
|
279
|
+
|
|
280
|
+
if (index !== undefined) {
|
|
281
|
+
this.log.verbose(`Siloed nullifier ${siloedNullifier} already present in tree at index ${index}!`);
|
|
483
282
|
throw new NullifierCollisionError(
|
|
484
283
|
`Siloed nullifier ${siloedNullifier} already exists in parent cache or host.`,
|
|
485
284
|
);
|
|
486
285
|
} else {
|
|
487
|
-
|
|
488
|
-
const lowLeafWitnessData = appendResult.lowLeavesWitnessData![0];
|
|
489
|
-
const lowLeafPreimage = lowLeafWitnessData.leafPreimage as NullifierLeafPreimage;
|
|
490
|
-
const lowLeafIndex = lowLeafWitnessData.index;
|
|
491
|
-
const lowLeafPath = lowLeafWitnessData.siblingPath.toFields();
|
|
492
|
-
const insertionPath = appendResult.insertionWitnessData[0].siblingPath.toFields();
|
|
493
|
-
|
|
494
|
-
this.trace.traceNewNullifier(
|
|
495
|
-
siloedNullifier,
|
|
496
|
-
lowLeafPreimage,
|
|
497
|
-
new Fr(lowLeafIndex),
|
|
498
|
-
lowLeafPath,
|
|
499
|
-
insertionPath,
|
|
500
|
-
);
|
|
286
|
+
await this.treesDB.sequentialInsert(MerkleTreeId.NULLIFIER_TREE, [siloedNullifier.toBuffer()]);
|
|
501
287
|
}
|
|
502
288
|
} else {
|
|
503
289
|
// Cache pending nullifiers for later access
|
|
504
290
|
await this.nullifiers.append(siloedNullifier);
|
|
505
|
-
this.trace.traceNewNullifier(siloedNullifier);
|
|
506
291
|
}
|
|
292
|
+
|
|
293
|
+
this.trace.traceNewNullifier(siloedNullifier);
|
|
507
294
|
}
|
|
508
295
|
|
|
509
296
|
public async writeSiloedNullifiersFromPrivate(siloedNullifiers: Fr[]) {
|
|
@@ -523,18 +310,11 @@ export class AvmPersistableStateManager {
|
|
|
523
310
|
msgHash: Fr,
|
|
524
311
|
msgLeafIndex: Fr,
|
|
525
312
|
): Promise<boolean> {
|
|
526
|
-
const valueAtIndex = (await this.
|
|
313
|
+
const valueAtIndex = (await this.treesDB.getL1ToL2LeafValue(msgLeafIndex.toBigInt())) ?? Fr.ZERO;
|
|
527
314
|
const exists = valueAtIndex.equals(msgHash);
|
|
528
315
|
this.log.trace(
|
|
529
316
|
`l1ToL2Messages(@${msgLeafIndex}) ?? exists: ${exists}, expected: ${msgHash}, found: ${valueAtIndex}.`,
|
|
530
317
|
);
|
|
531
|
-
|
|
532
|
-
if (this.doMerkleOperations) {
|
|
533
|
-
const path = await this.db.getSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, msgLeafIndex.toBigInt());
|
|
534
|
-
this.trace.traceL1ToL2MessageCheck(contractAddress, valueAtIndex, msgLeafIndex, exists, path.toFields());
|
|
535
|
-
} else {
|
|
536
|
-
this.trace.traceL1ToL2MessageCheck(contractAddress, valueAtIndex, msgLeafIndex, exists);
|
|
537
|
-
}
|
|
538
318
|
return Promise.resolve(exists);
|
|
539
319
|
}
|
|
540
320
|
|
|
@@ -566,20 +346,18 @@ export class AvmPersistableStateManager {
|
|
|
566
346
|
*/
|
|
567
347
|
public async getContractInstance(contractAddress: AztecAddress): Promise<SerializableContractInstance | undefined> {
|
|
568
348
|
this.log.trace(`Getting contract instance for address ${contractAddress}`);
|
|
569
|
-
const instanceWithAddress = await this.
|
|
349
|
+
const instanceWithAddress = await this.contractsDB.getContractInstance(contractAddress, this.blockNumber);
|
|
570
350
|
const exists = instanceWithAddress !== undefined;
|
|
571
351
|
|
|
572
352
|
const instance = exists ? new SerializableContractInstance(instanceWithAddress) : undefined;
|
|
573
353
|
if (!exists) {
|
|
574
354
|
this.log.debug(`Contract instance NOT FOUND (address=${contractAddress})`);
|
|
575
|
-
this.trace.traceGetContractInstance(contractAddress, exists);
|
|
576
355
|
return undefined;
|
|
577
356
|
}
|
|
578
357
|
|
|
579
358
|
this.log.trace(`Got contract instance (address=${contractAddress}): instance=${jsonStringify(instance!)}`);
|
|
580
|
-
// Canonical addresses do not trigger nullifier
|
|
359
|
+
// Canonical addresses do not trigger nullifier and update checks.
|
|
581
360
|
if (contractAddressIsCanonical(contractAddress)) {
|
|
582
|
-
this.trace.traceGetContractInstance(contractAddress, exists, instance);
|
|
583
361
|
return instance;
|
|
584
362
|
}
|
|
585
363
|
|
|
@@ -590,19 +368,70 @@ export class AvmPersistableStateManager {
|
|
|
590
368
|
);
|
|
591
369
|
assert(
|
|
592
370
|
exists == nullifierExistsInTree,
|
|
593
|
-
'
|
|
371
|
+
'treesDB contains contract instance, but nullifier tree does not contain contract address (or vice versa).... This is a bug!',
|
|
594
372
|
);
|
|
595
373
|
|
|
374
|
+
// All that is left is tocheck that the contract updatability information is correct.
|
|
375
|
+
// That is, that the current and original contract class ids are correct.
|
|
376
|
+
await this.checkContractUpdateInformation(instanceWithAddress);
|
|
377
|
+
|
|
378
|
+
return instance;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
private async checkContractUpdateInformation(instance: ContractInstanceWithAddress): Promise<void> {
|
|
382
|
+
// If "merkle operations" are not requested, we trust the DB.
|
|
383
|
+
// Otherwise we check that the contract updatability information is correct.
|
|
384
|
+
// That is, that the current and original contract class ids are correct.
|
|
385
|
+
// All failures are fatal and the simulation is not expected to be provable.
|
|
596
386
|
if (this.doMerkleOperations) {
|
|
597
|
-
//
|
|
598
|
-
|
|
387
|
+
// Conceptually, we want to do the following:
|
|
388
|
+
// * Read a SharedMutable at the contract update slot.
|
|
389
|
+
// * Obtain the expected current class id from the SharedMutable, at the current block.
|
|
390
|
+
// * if expectedId == 0 then currentClassId should be original contract class id
|
|
391
|
+
// * if expectedId != 0 then currentClassId should be expectedId
|
|
392
|
+
//
|
|
393
|
+
// However, we will also be checking the hash of the shared mutable values.
|
|
394
|
+
// This is a bit of a leak of information, since the circuit will use it to prove
|
|
395
|
+
// one public read insted of N of the shared mutable values.
|
|
396
|
+
const { sharedMutableSlot, sharedMutableHashSlot } = await SharedMutableValuesWithHash.getContractUpdateSlots(
|
|
397
|
+
instance.address,
|
|
398
|
+
);
|
|
399
|
+
const readDeployerStorage = async (storageSlot: Fr) =>
|
|
400
|
+
await this.readStorage(ProtocolContractAddress.ContractInstanceDeployer, storageSlot);
|
|
599
401
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
}
|
|
402
|
+
const hash = await readDeployerStorage(sharedMutableHashSlot);
|
|
403
|
+
const sharedMutableValues = await SharedMutableValues.readFromTree(sharedMutableSlot, readDeployerStorage);
|
|
404
|
+
const preImage = sharedMutableValues.toFields();
|
|
604
405
|
|
|
605
|
-
|
|
406
|
+
// 1) update never scheduled: hash == 0 and preimage should be empty (but poseidon2hash(preimage) will not be 0s)
|
|
407
|
+
if (hash.isZero()) {
|
|
408
|
+
assert(
|
|
409
|
+
preImage.every(f => f.isZero()),
|
|
410
|
+
`Found updatability hash 0 but preimage is not empty for contract instance ${instance.address}.`,
|
|
411
|
+
);
|
|
412
|
+
assert(
|
|
413
|
+
instance.currentContractClassId.equals(instance.originalContractClassId),
|
|
414
|
+
`Found updatability hash 0 for contract instance ${instance.address} but original class id ${instance.originalContractClassId} != current class id ${instance.currentContractClassId}.`,
|
|
415
|
+
);
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// 2) At this point we know that the hash is not zero and this means that an update has at some point been scheduled.
|
|
420
|
+
const computedHash = await poseidon2Hash(preImage);
|
|
421
|
+
assert(
|
|
422
|
+
hash.equals(computedHash),
|
|
423
|
+
`Shared mutable values hash mismatch for contract instance ${instance.address}. Expected: ${hash}, computed: ${computedHash}`,
|
|
424
|
+
);
|
|
425
|
+
|
|
426
|
+
// We now check that, depending on the current block, the current class id is correct.
|
|
427
|
+
const expectedClassIdRaw = sharedMutableValues.svc.getCurrentAt(this.blockNumber).at(0)!;
|
|
428
|
+
const expectedClassId = expectedClassIdRaw.isZero() ? instance.originalContractClassId : expectedClassIdRaw;
|
|
429
|
+
assert(
|
|
430
|
+
instance.currentContractClassId.equals(expectedClassId),
|
|
431
|
+
`Current class id mismatch
|
|
432
|
+
for contract instance ${instance.address}. Expected: ${expectedClassId}, current: ${instance.currentContractClassId}`,
|
|
433
|
+
);
|
|
434
|
+
}
|
|
606
435
|
}
|
|
607
436
|
|
|
608
437
|
/**
|
|
@@ -612,7 +441,7 @@ export class AvmPersistableStateManager {
|
|
|
612
441
|
*/
|
|
613
442
|
public async getContractClass(classId: Fr): Promise<ContractClassWithCommitment | undefined> {
|
|
614
443
|
this.log.trace(`Getting contract class for id ${classId}`);
|
|
615
|
-
const klass = await this.
|
|
444
|
+
const klass = await this.contractsDB.getContractClass(classId);
|
|
616
445
|
const exists = klass !== undefined;
|
|
617
446
|
let extendedClass: ContractClassWithCommitment | undefined = undefined;
|
|
618
447
|
|
|
@@ -621,7 +450,7 @@ export class AvmPersistableStateManager {
|
|
|
621
450
|
if (exists) {
|
|
622
451
|
this.log.trace(`Got contract class (id=${classId})`);
|
|
623
452
|
// Extend class information with public bytecode commitment.
|
|
624
|
-
const bytecodeCommitment = await this.
|
|
453
|
+
const bytecodeCommitment = await this.contractsDB.getBytecodeCommitment(classId);
|
|
625
454
|
assert(
|
|
626
455
|
bytecodeCommitment,
|
|
627
456
|
`Bytecode commitment was not found in DB for contract class (${classId}). This should not happen!`,
|
|
@@ -634,7 +463,7 @@ export class AvmPersistableStateManager {
|
|
|
634
463
|
this.log.debug(`Contract instance NOT FOUND (id=${classId})`);
|
|
635
464
|
}
|
|
636
465
|
|
|
637
|
-
this.trace.traceGetContractClass(classId, exists
|
|
466
|
+
this.trace.traceGetContractClass(classId, exists);
|
|
638
467
|
return extendedClass;
|
|
639
468
|
}
|
|
640
469
|
|
|
@@ -655,78 +484,15 @@ export class AvmPersistableStateManager {
|
|
|
655
484
|
`Contract class not found in DB, but a contract instance was found with this class ID (${contractInstance.currentContractClassId}). This should not happen!`,
|
|
656
485
|
);
|
|
657
486
|
|
|
658
|
-
// NOTE: If the contract instance is not found, we assume it has not been deployed.
|
|
659
|
-
// It doesnt matter what the values of the contract instance are in this case, as long as we tag it with exists=false.
|
|
660
|
-
// This will hint to the avm circuit to just perform the non-membership check on the address and disregard the bytecode hash
|
|
661
487
|
return contractClass.packedBytecode;
|
|
662
488
|
}
|
|
663
489
|
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
contractAddress,
|
|
667
|
-
);
|
|
668
|
-
|
|
669
|
-
const {
|
|
670
|
-
value: hash,
|
|
671
|
-
leafPreimage,
|
|
672
|
-
leafIndex,
|
|
673
|
-
leafPath,
|
|
674
|
-
} = await this.getPublicDataMembership(ProtocolContractAddress.ContractInstanceDeployer, sharedMutableHashSlot);
|
|
675
|
-
const updateMembership = new AvmPublicDataReadTreeHint(leafPreimage, leafIndex, leafPath);
|
|
676
|
-
|
|
677
|
-
const readStorage = async (storageSlot: Fr) =>
|
|
678
|
-
(await this.publicStorage.read(ProtocolContractAddress.ContractInstanceDeployer, storageSlot)).value;
|
|
679
|
-
|
|
680
|
-
const sharedMutableValues = await SharedMutableValues.readFromTree(sharedMutableSlot, readStorage);
|
|
681
|
-
|
|
682
|
-
const updatePreimage = sharedMutableValues.toFields();
|
|
683
|
-
|
|
684
|
-
if (!hash.isZero()) {
|
|
685
|
-
const hashed = await poseidon2Hash(updatePreimage);
|
|
686
|
-
if (!hashed.equals(hash)) {
|
|
687
|
-
throw new Error(`Update hint hash mismatch: ${hash} != ${hashed}`);
|
|
688
|
-
}
|
|
689
|
-
this.log.trace(`Non empty update hint found for contract ${contractAddress}`);
|
|
690
|
-
} else {
|
|
691
|
-
if (updatePreimage.some(f => !f.isZero())) {
|
|
692
|
-
throw new Error(`Update hint hash is zero, but update preimage is not: ${updatePreimage}`);
|
|
693
|
-
}
|
|
694
|
-
this.log.trace(`No update hint found for contract ${contractAddress}`);
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
return {
|
|
698
|
-
updateMembership,
|
|
699
|
-
updatePreimage,
|
|
700
|
-
};
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
public traceEnqueuedCall(publicCallRequest: PublicCallRequest, calldata: Fr[], reverted: boolean) {
|
|
704
|
-
this.trace.traceEnqueuedCall(publicCallRequest, calldata, reverted);
|
|
490
|
+
public traceEnqueuedCall(publicCallRequest: PublicCallRequest) {
|
|
491
|
+
this.trace.traceEnqueuedCall(publicCallRequest);
|
|
705
492
|
}
|
|
706
493
|
|
|
707
494
|
public async getPublicFunctionDebugName(avmEnvironment: AvmExecutionEnvironment): Promise<string> {
|
|
708
|
-
return await getPublicFunctionDebugName(this.
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
public async getLeafOrLowLeafInfo<ID extends IndexedTreeId, T extends IndexedTreeLeafPreimage>(
|
|
712
|
-
treeId: ID,
|
|
713
|
-
key: bigint,
|
|
714
|
-
): Promise<GetLeafResult<T>> {
|
|
715
|
-
// "key" is siloed slot (leafSlot) or siloed nullifier
|
|
716
|
-
const leafOrLowLeafInfo = await this.db.getPreviousValueIndex(treeId, key);
|
|
717
|
-
assert(
|
|
718
|
-
leafOrLowLeafInfo !== undefined,
|
|
719
|
-
`${MerkleTreeId[treeId]} low leaf index should always be found (even if target leaf does not exist)`,
|
|
720
|
-
);
|
|
721
|
-
const { index: leafOrLowLeafIndex, alreadyPresent } = leafOrLowLeafInfo;
|
|
722
|
-
|
|
723
|
-
const leafPreimage = await this.db.getLeafPreimage(treeId, leafOrLowLeafIndex);
|
|
724
|
-
assert(
|
|
725
|
-
leafPreimage !== undefined,
|
|
726
|
-
`${MerkleTreeId[treeId]} low leaf preimage should never be undefined (even if target leaf does not exist)`,
|
|
727
|
-
);
|
|
728
|
-
|
|
729
|
-
return { preimage: leafPreimage as T, leafOrLowLeafIndex, alreadyPresent };
|
|
495
|
+
return await getPublicFunctionDebugName(this.contractsDB, avmEnvironment.address, avmEnvironment.calldata);
|
|
730
496
|
}
|
|
731
497
|
}
|
|
732
498
|
|