@aztec/simulator 0.62.0 → 0.63.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.d.ts +2 -16
- package/dest/acvm/acvm.d.ts.map +1 -1
- package/dest/acvm/acvm.js +2 -70
- package/dest/acvm/oracle/oracle.d.ts +4 -4
- package/dest/acvm/oracle/oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/oracle.js +10 -11
- package/dest/acvm/oracle/typed_oracle.d.ts +5 -5
- package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/typed_oracle.js +8 -8
- package/dest/avm/avm_gas.d.ts.map +1 -1
- package/dest/avm/avm_gas.js +2 -1
- package/dest/avm/avm_machine_state.d.ts +27 -8
- package/dest/avm/avm_machine_state.d.ts.map +1 -1
- package/dest/avm/avm_machine_state.js +6 -10
- package/dest/avm/avm_memory_types.d.ts +8 -0
- package/dest/avm/avm_memory_types.d.ts.map +1 -1
- package/dest/avm/avm_memory_types.js +5 -1
- package/dest/avm/avm_simulator.d.ts +2 -19
- package/dest/avm/avm_simulator.d.ts.map +1 -1
- package/dest/avm/avm_simulator.js +12 -14
- package/dest/avm/avm_tree.d.ts +249 -0
- package/dest/avm/avm_tree.d.ts.map +1 -0
- package/dest/avm/avm_tree.js +637 -0
- package/dest/avm/errors.d.ts +4 -17
- package/dest/avm/errors.d.ts.map +1 -1
- package/dest/avm/errors.js +21 -50
- package/dest/avm/fixtures/index.d.ts +7 -2
- package/dest/avm/fixtures/index.d.ts.map +1 -1
- package/dest/avm/fixtures/index.js +12 -12
- package/dest/avm/index.d.ts +1 -0
- package/dest/avm/index.d.ts.map +1 -1
- package/dest/avm/index.js +2 -1
- package/dest/avm/journal/journal.d.ts +43 -24
- package/dest/avm/journal/journal.d.ts.map +1 -1
- package/dest/avm/journal/journal.js +172 -39
- package/dest/avm/journal/nullifiers.d.ts +5 -4
- package/dest/avm/journal/nullifiers.d.ts.map +1 -1
- package/dest/avm/journal/nullifiers.js +2 -3
- package/dest/avm/journal/public_storage.d.ts +6 -5
- package/dest/avm/journal/public_storage.d.ts.map +1 -1
- package/dest/avm/journal/public_storage.js +1 -1
- package/dest/avm/opcodes/accrued_substate.d.ts.map +1 -1
- package/dest/avm/opcodes/accrued_substate.js +4 -10
- package/dest/avm/opcodes/arithmetic.d.ts +4 -1
- package/dest/avm/opcodes/arithmetic.d.ts.map +1 -1
- package/dest/avm/opcodes/arithmetic.js +18 -4
- package/dest/avm/opcodes/bitwise.d.ts.map +1 -1
- package/dest/avm/opcodes/bitwise.js +1 -3
- package/dest/avm/opcodes/comparators.d.ts.map +1 -1
- package/dest/avm/opcodes/comparators.js +1 -2
- package/dest/avm/opcodes/contract.d.ts.map +1 -1
- package/dest/avm/opcodes/contract.js +2 -3
- package/dest/avm/opcodes/control_flow.d.ts +4 -0
- package/dest/avm/opcodes/control_flow.d.ts.map +1 -1
- package/dest/avm/opcodes/control_flow.js +21 -6
- package/dest/avm/opcodes/conversion.d.ts.map +1 -1
- package/dest/avm/opcodes/conversion.js +1 -2
- package/dest/avm/opcodes/ec_add.d.ts.map +1 -1
- package/dest/avm/opcodes/ec_add.js +5 -11
- package/dest/avm/opcodes/environment_getters.d.ts.map +1 -1
- package/dest/avm/opcodes/environment_getters.js +1 -2
- package/dest/avm/opcodes/external_calls.d.ts +4 -2
- package/dest/avm/opcodes/external_calls.d.ts.map +1 -1
- package/dest/avm/opcodes/external_calls.js +38 -22
- package/dest/avm/opcodes/hashing.d.ts.map +1 -1
- package/dest/avm/opcodes/hashing.js +1 -4
- package/dest/avm/opcodes/instruction.d.ts +4 -0
- package/dest/avm/opcodes/instruction.d.ts.map +1 -1
- package/dest/avm/opcodes/instruction.js +7 -1
- package/dest/avm/opcodes/memory.d.ts.map +1 -1
- package/dest/avm/opcodes/memory.js +1 -7
- package/dest/avm/opcodes/misc.js +3 -3
- package/dest/avm/opcodes/multi_scalar_mul.d.ts.map +1 -1
- package/dest/avm/opcodes/multi_scalar_mul.js +6 -5
- package/dest/avm/opcodes/storage.d.ts.map +1 -1
- package/dest/avm/opcodes/storage.js +2 -4
- package/dest/avm/serialization/bytecode_serialization.d.ts +1 -6
- package/dest/avm/serialization/bytecode_serialization.d.ts.map +1 -1
- package/dest/avm/serialization/bytecode_serialization.js +24 -20
- package/dest/client/client_execution_context.d.ts +7 -11
- package/dest/client/client_execution_context.d.ts.map +1 -1
- package/dest/client/client_execution_context.js +18 -20
- package/dest/client/db_oracle.d.ts +17 -10
- package/dest/client/db_oracle.d.ts.map +1 -1
- package/dest/client/db_oracle.js +1 -1
- package/dest/client/private_execution.d.ts.map +1 -1
- package/dest/client/private_execution.js +5 -4
- package/dest/client/unconstrained_execution.d.ts.map +1 -1
- package/dest/client/unconstrained_execution.js +3 -2
- package/dest/client/view_data_oracle.d.ts +6 -12
- package/dest/client/view_data_oracle.d.ts.map +1 -1
- package/dest/client/view_data_oracle.js +10 -12
- package/dest/common/errors.d.ts +15 -2
- package/dest/common/errors.d.ts.map +1 -1
- package/dest/common/errors.js +85 -4
- package/dest/mocks/fixtures.d.ts +9 -28
- package/dest/mocks/fixtures.d.ts.map +1 -1
- package/dest/mocks/fixtures.js +12 -57
- package/dest/public/dual_side_effect_trace.d.ts +34 -26
- package/dest/public/dual_side_effect_trace.d.ts.map +1 -1
- package/dest/public/dual_side_effect_trace.js +48 -36
- package/dest/public/enqueued_call_side_effect_trace.d.ts +96 -33
- package/dest/public/enqueued_call_side_effect_trace.d.ts.map +1 -1
- package/dest/public/enqueued_call_side_effect_trace.js +212 -138
- package/dest/public/execution.d.ts +50 -17
- package/dest/public/execution.d.ts.map +1 -1
- package/dest/public/execution.js +1 -29
- package/dest/public/executor.d.ts +28 -11
- package/dest/public/executor.d.ts.map +1 -1
- package/dest/public/executor.js +33 -33
- package/dest/public/index.d.ts +4 -5
- package/dest/public/index.d.ts.map +1 -1
- package/dest/public/index.js +4 -5
- package/dest/public/public_db_sources.d.ts +1 -0
- package/dest/public/public_db_sources.d.ts.map +1 -1
- package/dest/public/public_db_sources.js +12 -5
- package/dest/public/public_processor.d.ts +7 -11
- package/dest/public/public_processor.d.ts.map +1 -1
- package/dest/public/public_processor.js +60 -42
- package/dest/public/public_processor_metrics.d.ts +3 -3
- package/dest/public/public_processor_metrics.d.ts.map +1 -1
- package/dest/public/public_processor_metrics.js +1 -1
- package/dest/public/public_tx_context.d.ts +130 -0
- package/dest/public/public_tx_context.d.ts.map +1 -0
- package/dest/public/public_tx_context.js +293 -0
- package/dest/public/public_tx_simulator.d.ts +36 -0
- package/dest/public/public_tx_simulator.d.ts.map +1 -0
- package/dest/public/public_tx_simulator.js +148 -0
- package/dest/public/side_effect_trace.d.ts +30 -15
- package/dest/public/side_effect_trace.d.ts.map +1 -1
- package/dest/public/side_effect_trace.js +70 -16
- package/dest/public/side_effect_trace_interface.d.ts +43 -12
- package/dest/public/side_effect_trace_interface.d.ts.map +1 -1
- package/dest/public/transitional_adapters.d.ts +9 -0
- package/dest/public/transitional_adapters.d.ts.map +1 -0
- package/dest/public/transitional_adapters.js +127 -0
- package/dest/public/utils.d.ts +5 -0
- package/dest/public/utils.d.ts.map +1 -0
- package/dest/public/utils.js +30 -0
- package/package.json +12 -9
- package/src/acvm/acvm.ts +3 -94
- package/src/acvm/oracle/oracle.ts +9 -14
- package/src/acvm/oracle/typed_oracle.ts +8 -8
- package/src/avm/avm_gas.ts +1 -0
- package/src/avm/avm_machine_state.ts +28 -12
- package/src/avm/avm_memory_types.ts +5 -0
- package/src/avm/avm_simulator.ts +13 -16
- package/src/avm/avm_tree.ts +785 -0
- package/src/avm/errors.ts +25 -48
- package/src/avm/fixtures/index.ts +16 -12
- package/src/avm/index.ts +1 -0
- package/src/avm/journal/journal.ts +291 -52
- package/src/avm/journal/nullifiers.ts +7 -7
- package/src/avm/journal/public_storage.ts +5 -5
- package/src/avm/opcodes/accrued_substate.ts +3 -9
- package/src/avm/opcodes/arithmetic.ts +26 -4
- package/src/avm/opcodes/bitwise.ts +0 -2
- package/src/avm/opcodes/comparators.ts +0 -1
- package/src/avm/opcodes/contract.ts +1 -2
- package/src/avm/opcodes/control_flow.ts +24 -5
- package/src/avm/opcodes/conversion.ts +0 -1
- package/src/avm/opcodes/ec_add.ts +6 -9
- package/src/avm/opcodes/environment_getters.ts +0 -1
- package/src/avm/opcodes/external_calls.ts +39 -21
- package/src/avm/opcodes/hashing.ts +0 -3
- package/src/avm/opcodes/instruction.ts +7 -0
- package/src/avm/opcodes/memory.ts +0 -6
- package/src/avm/opcodes/misc.ts +2 -2
- package/src/avm/opcodes/multi_scalar_mul.ts +5 -4
- package/src/avm/opcodes/storage.ts +1 -3
- package/src/avm/serialization/bytecode_serialization.ts +31 -22
- package/src/client/client_execution_context.ts +22 -23
- package/src/client/db_oracle.ts +22 -11
- package/src/client/private_execution.ts +5 -4
- package/src/client/unconstrained_execution.ts +2 -1
- package/src/client/view_data_oracle.ts +14 -13
- package/src/common/errors.ts +119 -3
- package/src/mocks/fixtures.ts +15 -106
- package/src/public/dual_side_effect_trace.ts +138 -50
- package/src/public/enqueued_call_side_effect_trace.ts +352 -212
- package/src/public/execution.ts +58 -42
- package/src/public/executor.ts +52 -67
- package/src/public/index.ts +7 -5
- package/src/public/public_db_sources.ts +12 -4
- package/src/public/public_processor.ts +111 -73
- package/src/public/public_processor_metrics.ts +3 -3
- package/src/public/public_tx_context.ts +411 -0
- package/src/public/public_tx_simulator.ts +232 -0
- package/src/public/side_effect_trace.ts +154 -28
- package/src/public/side_effect_trace_interface.ts +92 -14
- package/src/public/transitional_adapters.ts +347 -0
- package/src/public/utils.ts +32 -0
- package/dest/public/enqueued_call_simulator.d.ts +0 -43
- package/dest/public/enqueued_call_simulator.d.ts.map +0 -1
- package/dest/public/enqueued_call_simulator.js +0 -156
- package/dest/public/enqueued_calls_processor.d.ts +0 -43
- package/dest/public/enqueued_calls_processor.d.ts.map +0 -1
- package/dest/public/enqueued_calls_processor.js +0 -209
- package/dest/public/hints_builder.d.ts +0 -29
- package/dest/public/hints_builder.d.ts.map +0 -1
- package/dest/public/hints_builder.js +0 -75
- package/dest/public/public_kernel.d.ts +0 -30
- package/dest/public/public_kernel.d.ts.map +0 -1
- package/dest/public/public_kernel.js +0 -67
- package/dest/public/public_kernel_circuit_simulator.d.ts +0 -25
- package/dest/public/public_kernel_circuit_simulator.d.ts.map +0 -1
- package/dest/public/public_kernel_circuit_simulator.js +0 -2
- package/dest/public/public_kernel_tail_simulator.d.ts +0 -15
- package/dest/public/public_kernel_tail_simulator.d.ts.map +0 -1
- package/dest/public/public_kernel_tail_simulator.js +0 -39
- package/src/public/enqueued_call_simulator.ts +0 -360
- package/src/public/enqueued_calls_processor.ts +0 -372
- package/src/public/hints_builder.ts +0 -168
- package/src/public/public_kernel.ts +0 -100
- package/src/public/public_kernel_circuit_simulator.ts +0 -32
- package/src/public/public_kernel_tail_simulator.ts +0 -97
|
@@ -1,11 +1,18 @@
|
|
|
1
|
+
import { type IndexedTreeId, MerkleTreeId, type MerkleTreeWriteOperations } from '@aztec/circuit-types';
|
|
1
2
|
import {
|
|
2
|
-
AztecAddress,
|
|
3
|
+
type AztecAddress,
|
|
3
4
|
type Gas,
|
|
5
|
+
type NullifierLeafPreimage,
|
|
6
|
+
type PublicCallRequest,
|
|
7
|
+
PublicDataTreeLeaf,
|
|
8
|
+
PublicDataTreeLeafPreimage,
|
|
4
9
|
SerializableContractInstance,
|
|
5
10
|
computePublicBytecodeCommitment,
|
|
6
11
|
} from '@aztec/circuits.js';
|
|
12
|
+
import { computePublicDataTreeLeafSlot, siloNoteHash, siloNullifier } from '@aztec/circuits.js/hash';
|
|
7
13
|
import { Fr } from '@aztec/foundation/fields';
|
|
8
14
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
15
|
+
import { type IndexedTreeLeafPreimage } from '@aztec/foundation/trees';
|
|
9
16
|
|
|
10
17
|
import assert from 'assert';
|
|
11
18
|
|
|
@@ -29,17 +36,31 @@ import { PublicStorage } from './public_storage.js';
|
|
|
29
36
|
export class AvmPersistableStateManager {
|
|
30
37
|
private readonly log = createDebugLogger('aztec:avm_simulator:state_manager');
|
|
31
38
|
|
|
39
|
+
/** Interface to perform merkle tree operations */
|
|
40
|
+
public merkleTrees: MerkleTreeWriteOperations;
|
|
41
|
+
|
|
42
|
+
/** Make sure a forked state is never merged twice. */
|
|
43
|
+
private alreadyMergedIntoParent = false;
|
|
44
|
+
|
|
32
45
|
constructor(
|
|
33
46
|
/** Reference to node storage */
|
|
34
47
|
private readonly worldStateDB: WorldStateDB,
|
|
35
48
|
/** Side effect trace */
|
|
36
|
-
private readonly trace: PublicSideEffectTraceInterface,
|
|
37
|
-
/** Public storage, including cached writes */
|
|
38
49
|
// TODO(5818): make private once no longer accessed in executor
|
|
39
|
-
public readonly
|
|
50
|
+
public readonly trace: PublicSideEffectTraceInterface,
|
|
51
|
+
/** Public storage, including cached writes */
|
|
52
|
+
private readonly publicStorage: PublicStorage = new PublicStorage(worldStateDB),
|
|
40
53
|
/** Nullifier set, including cached/recently-emitted nullifiers */
|
|
41
|
-
private readonly nullifiers: NullifierManager,
|
|
42
|
-
|
|
54
|
+
private readonly nullifiers: NullifierManager = new NullifierManager(worldStateDB),
|
|
55
|
+
private readonly doMerkleOperations: boolean = false,
|
|
56
|
+
merkleTrees?: MerkleTreeWriteOperations,
|
|
57
|
+
) {
|
|
58
|
+
if (merkleTrees) {
|
|
59
|
+
this.merkleTrees = merkleTrees;
|
|
60
|
+
} else {
|
|
61
|
+
this.merkleTrees = worldStateDB.getMerkleInterface();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
43
64
|
|
|
44
65
|
/**
|
|
45
66
|
* Create a new state manager with some preloaded pending siloed nullifiers
|
|
@@ -67,9 +88,40 @@ export class AvmPersistableStateManager {
|
|
|
67
88
|
this.trace.fork(),
|
|
68
89
|
this.publicStorage.fork(),
|
|
69
90
|
this.nullifiers.fork(),
|
|
91
|
+
this.doMerkleOperations,
|
|
70
92
|
);
|
|
71
93
|
}
|
|
72
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Accept forked world state modifications & traced side effects / hints
|
|
97
|
+
*/
|
|
98
|
+
public merge(forkedState: AvmPersistableStateManager) {
|
|
99
|
+
this._merge(forkedState, /*reverted=*/ false);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Reject forked world state modifications & traced side effects, keep traced hints
|
|
104
|
+
*/
|
|
105
|
+
public reject(forkedState: AvmPersistableStateManager) {
|
|
106
|
+
this._merge(forkedState, /*reverted=*/ true);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Commit cached storage writes to the DB.
|
|
111
|
+
* Keeps public storage up to date from tx to tx within a block.
|
|
112
|
+
*/
|
|
113
|
+
public async commitStorageWritesToDB() {
|
|
114
|
+
await this.publicStorage.commitToDB();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private _merge(forkedState: AvmPersistableStateManager, reverted: boolean) {
|
|
118
|
+
// sanity check to avoid merging the same forked trace twice
|
|
119
|
+
assert(!this.alreadyMergedIntoParent, 'Cannot merge forked state that has already been merged into its parent!');
|
|
120
|
+
this.publicStorage.acceptAndMerge(forkedState.publicStorage);
|
|
121
|
+
this.nullifiers.acceptAndMerge(forkedState.nullifiers);
|
|
122
|
+
this.trace.merge(forkedState.trace, reverted);
|
|
123
|
+
}
|
|
124
|
+
|
|
73
125
|
/**
|
|
74
126
|
* Write to public storage, journal/trace the write.
|
|
75
127
|
*
|
|
@@ -77,11 +129,46 @@ export class AvmPersistableStateManager {
|
|
|
77
129
|
* @param slot - the slot in the contract's storage being written to
|
|
78
130
|
* @param value - the value being written to the slot
|
|
79
131
|
*/
|
|
80
|
-
public writeStorage(contractAddress:
|
|
132
|
+
public async writeStorage(contractAddress: AztecAddress, slot: Fr, value: Fr): Promise<void> {
|
|
81
133
|
this.log.debug(`Storage write (address=${contractAddress}, slot=${slot}): value=${value}`);
|
|
82
134
|
// Cache storage writes for later reference/reads
|
|
83
135
|
this.publicStorage.write(contractAddress, slot, value);
|
|
84
|
-
|
|
136
|
+
const leafSlot = computePublicDataTreeLeafSlot(contractAddress, slot);
|
|
137
|
+
if (this.doMerkleOperations) {
|
|
138
|
+
const result = await this.merkleTrees.batchInsert(
|
|
139
|
+
MerkleTreeId.PUBLIC_DATA_TREE,
|
|
140
|
+
[new PublicDataTreeLeaf(leafSlot, value).toBuffer()],
|
|
141
|
+
0,
|
|
142
|
+
);
|
|
143
|
+
assert(result !== undefined, 'Public data tree insertion error. You might want to disable skipMerkleOperations.');
|
|
144
|
+
this.log.debug(`Inserted public data tree leaf at leafSlot ${leafSlot}, value: ${value}`);
|
|
145
|
+
|
|
146
|
+
const lowLeafInfo = result.lowLeavesWitnessData![0];
|
|
147
|
+
const lowLeafPreimage = lowLeafInfo.leafPreimage as PublicDataTreeLeafPreimage;
|
|
148
|
+
const lowLeafIndex = lowLeafInfo.index;
|
|
149
|
+
const lowLeafPath = lowLeafInfo.siblingPath.toFields();
|
|
150
|
+
|
|
151
|
+
const insertionPath = result.newSubtreeSiblingPath.toFields();
|
|
152
|
+
const newLeafPreimage = new PublicDataTreeLeafPreimage(
|
|
153
|
+
leafSlot,
|
|
154
|
+
value,
|
|
155
|
+
lowLeafPreimage.nextSlot,
|
|
156
|
+
lowLeafPreimage.nextIndex,
|
|
157
|
+
);
|
|
158
|
+
// FIXME: Why do we need to hint both preimages for public data writes, but not for nullifier insertions?
|
|
159
|
+
this.trace.tracePublicStorageWrite(
|
|
160
|
+
contractAddress,
|
|
161
|
+
slot,
|
|
162
|
+
value,
|
|
163
|
+
lowLeafPreimage,
|
|
164
|
+
new Fr(lowLeafIndex),
|
|
165
|
+
lowLeafPath,
|
|
166
|
+
newLeafPreimage,
|
|
167
|
+
insertionPath,
|
|
168
|
+
);
|
|
169
|
+
} else {
|
|
170
|
+
this.trace.tracePublicStorageWrite(contractAddress, slot, value);
|
|
171
|
+
}
|
|
85
172
|
}
|
|
86
173
|
|
|
87
174
|
/**
|
|
@@ -91,12 +178,46 @@ export class AvmPersistableStateManager {
|
|
|
91
178
|
* @param slot - the slot in the contract's storage being read from
|
|
92
179
|
* @returns the latest value written to slot, or 0 if never written to before
|
|
93
180
|
*/
|
|
94
|
-
public async readStorage(contractAddress:
|
|
181
|
+
public async readStorage(contractAddress: AztecAddress, slot: Fr): Promise<Fr> {
|
|
95
182
|
const { value, exists, cached } = await this.publicStorage.read(contractAddress, slot);
|
|
96
183
|
this.log.debug(
|
|
97
184
|
`Storage read (address=${contractAddress}, slot=${slot}): value=${value}, exists=${exists}, cached=${cached}`,
|
|
98
185
|
);
|
|
99
|
-
|
|
186
|
+
|
|
187
|
+
const leafSlot = computePublicDataTreeLeafSlot(contractAddress, slot);
|
|
188
|
+
|
|
189
|
+
if (this.doMerkleOperations) {
|
|
190
|
+
// Get leaf if present, low leaf if absent
|
|
191
|
+
// If leaf is present, hint/trace it. Otherwise, hint/trace the low leaf.
|
|
192
|
+
const [leafIndex, leafPreimage, leafPath, _alreadyPresent] = await getLeafOrLowLeaf<PublicDataTreeLeafPreimage>(
|
|
193
|
+
MerkleTreeId.PUBLIC_DATA_TREE,
|
|
194
|
+
leafSlot.toBigInt(),
|
|
195
|
+
this.merkleTrees,
|
|
196
|
+
);
|
|
197
|
+
// FIXME: cannot have this assertion until "caching" is done via ephemeral merkle writes
|
|
198
|
+
//assert(alreadyPresent == exists, 'WorldStateDB contains public data leaf, but merkle tree does not.... This is a bug!');
|
|
199
|
+
this.log.debug(
|
|
200
|
+
`leafPreimage.nextSlot: ${leafPreimage.nextSlot}, leafPreimage.nextIndex: ${Number(leafPreimage.nextIndex)}`,
|
|
201
|
+
);
|
|
202
|
+
this.log.debug(`leafPreimage.slot: ${leafPreimage.slot}, leafPreimage.value: ${leafPreimage.value}`);
|
|
203
|
+
|
|
204
|
+
if (!exists) {
|
|
205
|
+
// Sanity check that the leaf slot is skipped by low leaf when it doesn't exist
|
|
206
|
+
assert(
|
|
207
|
+
leafSlot.toBigInt() > leafPreimage.slot.toBigInt() && leafSlot.toBigInt() < leafPreimage.nextSlot.toBigInt(),
|
|
208
|
+
'Public data tree low leaf should skip the target leaf slot when the target leaf does not exist.',
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
this.log.debug(
|
|
212
|
+
`Tracing storage leaf preimage slot=${slot}, leafSlot=${leafSlot}, value=${value}, nextKey=${leafPreimage.nextSlot}, nextIndex=${leafPreimage.nextIndex}`,
|
|
213
|
+
);
|
|
214
|
+
// On non-existence, AVM circuit will need to recognize that leafPreimage.slot != leafSlot,
|
|
215
|
+
// prove that this is a low leaf that skips leafSlot, and then prove memebership of the leaf.
|
|
216
|
+
this.trace.tracePublicStorageRead(contractAddress, slot, value, leafPreimage, new Fr(leafIndex), leafPath);
|
|
217
|
+
} else {
|
|
218
|
+
this.trace.tracePublicStorageRead(contractAddress, slot, value);
|
|
219
|
+
}
|
|
220
|
+
|
|
100
221
|
return Promise.resolve(value);
|
|
101
222
|
}
|
|
102
223
|
|
|
@@ -107,7 +228,7 @@ export class AvmPersistableStateManager {
|
|
|
107
228
|
* @param slot - the slot in the contract's storage being read from
|
|
108
229
|
* @returns the latest value written to slot, or 0 if never written to before
|
|
109
230
|
*/
|
|
110
|
-
public async peekStorage(contractAddress:
|
|
231
|
+
public async peekStorage(contractAddress: AztecAddress, slot: Fr): Promise<Fr> {
|
|
111
232
|
const { value, exists, cached } = await this.publicStorage.read(contractAddress, slot);
|
|
112
233
|
this.log.debug(
|
|
113
234
|
`Storage peek (address=${contractAddress}, slot=${slot}): value=${value}, exists=${exists}, cached=${cached}`,
|
|
@@ -124,15 +245,20 @@ export class AvmPersistableStateManager {
|
|
|
124
245
|
* @param leafIndex - the leaf index being checked
|
|
125
246
|
* @returns true if the note hash exists at the given leaf index, false otherwise
|
|
126
247
|
*/
|
|
127
|
-
public async checkNoteHashExists(contractAddress:
|
|
248
|
+
public async checkNoteHashExists(contractAddress: AztecAddress, noteHash: Fr, leafIndex: Fr): Promise<boolean> {
|
|
128
249
|
const gotLeafValue = (await this.worldStateDB.getCommitmentValue(leafIndex.toBigInt())) ?? Fr.ZERO;
|
|
129
250
|
const exists = gotLeafValue.equals(noteHash);
|
|
130
251
|
this.log.debug(
|
|
131
252
|
`noteHashes(${contractAddress})@${noteHash} ?? leafIndex: ${leafIndex} | gotLeafValue: ${gotLeafValue}, exists: ${exists}.`,
|
|
132
253
|
);
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
254
|
+
if (this.doMerkleOperations) {
|
|
255
|
+
// TODO(8287): We still return exists here, but we need to transmit both the requested noteHash and the gotLeafValue
|
|
256
|
+
// such that the VM can constrain the equality and decide on exists based on that.
|
|
257
|
+
const path = await this.merkleTrees.getSiblingPath(MerkleTreeId.NOTE_HASH_TREE, leafIndex.toBigInt());
|
|
258
|
+
this.trace.traceNoteHashCheck(contractAddress, gotLeafValue, leafIndex, exists, path.toFields());
|
|
259
|
+
} else {
|
|
260
|
+
this.trace.traceNoteHashCheck(contractAddress, gotLeafValue, leafIndex, exists);
|
|
261
|
+
}
|
|
136
262
|
return Promise.resolve(exists);
|
|
137
263
|
}
|
|
138
264
|
|
|
@@ -140,9 +266,22 @@ export class AvmPersistableStateManager {
|
|
|
140
266
|
* Write a note hash, trace the write.
|
|
141
267
|
* @param noteHash - the unsiloed note hash to write
|
|
142
268
|
*/
|
|
143
|
-
public writeNoteHash(contractAddress:
|
|
269
|
+
public async writeNoteHash(contractAddress: AztecAddress, noteHash: Fr): Promise<void> {
|
|
144
270
|
this.log.debug(`noteHashes(${contractAddress}) += @${noteHash}.`);
|
|
145
|
-
|
|
271
|
+
|
|
272
|
+
if (this.doMerkleOperations) {
|
|
273
|
+
// TODO: We should track this globally here in the state manager
|
|
274
|
+
const info = await this.merkleTrees.getTreeInfo(MerkleTreeId.NOTE_HASH_TREE);
|
|
275
|
+
const leafIndex = new Fr(info.size + 1n);
|
|
276
|
+
|
|
277
|
+
const path = await this.merkleTrees.getSiblingPath(MerkleTreeId.NOTE_HASH_TREE, leafIndex.toBigInt());
|
|
278
|
+
const siloedNoteHash = siloNoteHash(contractAddress, noteHash);
|
|
279
|
+
|
|
280
|
+
await this.merkleTrees.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, [siloedNoteHash]);
|
|
281
|
+
this.trace.traceNewNoteHash(contractAddress, noteHash, leafIndex, path.toFields());
|
|
282
|
+
} else {
|
|
283
|
+
this.trace.traceNewNoteHash(contractAddress, noteHash);
|
|
284
|
+
}
|
|
146
285
|
}
|
|
147
286
|
|
|
148
287
|
/**
|
|
@@ -151,12 +290,52 @@ export class AvmPersistableStateManager {
|
|
|
151
290
|
* @param nullifier - the unsiloed nullifier to check
|
|
152
291
|
* @returns exists - whether the nullifier exists in the nullifier set
|
|
153
292
|
*/
|
|
154
|
-
public async checkNullifierExists(contractAddress:
|
|
155
|
-
const [exists, isPending,
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
this.
|
|
293
|
+
public async checkNullifierExists(contractAddress: AztecAddress, nullifier: Fr): Promise<boolean> {
|
|
294
|
+
const [exists, isPending, _] = await this.nullifiers.checkExists(contractAddress, nullifier);
|
|
295
|
+
|
|
296
|
+
const siloedNullifier = siloNullifier(contractAddress, nullifier);
|
|
297
|
+
|
|
298
|
+
if (this.doMerkleOperations) {
|
|
299
|
+
// Get leaf if present, low leaf if absent
|
|
300
|
+
// If leaf is present, hint/trace it. Otherwise, hint/trace the low leaf.
|
|
301
|
+
const [leafIndex, leafPreimage, leafPath, alreadyPresent] = await getLeafOrLowLeaf<NullifierLeafPreimage>(
|
|
302
|
+
MerkleTreeId.NULLIFIER_TREE,
|
|
303
|
+
siloedNullifier.toBigInt(),
|
|
304
|
+
this.merkleTrees,
|
|
305
|
+
);
|
|
306
|
+
assert(
|
|
307
|
+
alreadyPresent == exists,
|
|
308
|
+
'WorldStateDB contains nullifier leaf, but merkle tree does not.... This is a bug!',
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
this.log.debug(
|
|
312
|
+
`nullifiers(${contractAddress})@${nullifier} ?? leafIndex: ${leafIndex}, exists: ${exists}, pending: ${isPending}.`,
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
if (!exists) {
|
|
316
|
+
// Sanity check that the leaf value is skipped by low leaf when it doesn't exist
|
|
317
|
+
assert(
|
|
318
|
+
siloedNullifier.toBigInt() > leafPreimage.nullifier.toBigInt() &&
|
|
319
|
+
siloedNullifier.toBigInt() < leafPreimage.nextNullifier.toBigInt(),
|
|
320
|
+
'Nullifier tree low leaf should skip the target leaf nullifier when the target leaf does not exist.',
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
this.trace.traceNullifierCheck(
|
|
325
|
+
contractAddress,
|
|
326
|
+
nullifier, // FIXME: Should this be siloed?
|
|
327
|
+
exists,
|
|
328
|
+
leafPreimage,
|
|
329
|
+
new Fr(leafIndex),
|
|
330
|
+
leafPath,
|
|
331
|
+
);
|
|
332
|
+
} else {
|
|
333
|
+
this.trace.traceNullifierCheck(
|
|
334
|
+
contractAddress,
|
|
335
|
+
nullifier, // FIXME: Should this be siloed?
|
|
336
|
+
exists,
|
|
337
|
+
);
|
|
338
|
+
}
|
|
160
339
|
return Promise.resolve(exists);
|
|
161
340
|
}
|
|
162
341
|
|
|
@@ -165,12 +344,44 @@ export class AvmPersistableStateManager {
|
|
|
165
344
|
* @param contractAddress - address of the contract that the nullifier is associated with
|
|
166
345
|
* @param nullifier - the unsiloed nullifier to write
|
|
167
346
|
*/
|
|
168
|
-
public async writeNullifier(contractAddress:
|
|
347
|
+
public async writeNullifier(contractAddress: AztecAddress, nullifier: Fr) {
|
|
169
348
|
this.log.debug(`nullifiers(${contractAddress}) += ${nullifier}.`);
|
|
170
349
|
// Cache pending nullifiers for later access
|
|
171
350
|
await this.nullifiers.append(contractAddress, nullifier);
|
|
172
|
-
|
|
173
|
-
|
|
351
|
+
|
|
352
|
+
const siloedNullifier = siloNullifier(contractAddress, nullifier);
|
|
353
|
+
|
|
354
|
+
if (this.doMerkleOperations) {
|
|
355
|
+
// Trace all nullifier creations, even duplicate insertions that fail
|
|
356
|
+
const alreadyPresent = await this.merkleTrees.getPreviousValueIndex(
|
|
357
|
+
MerkleTreeId.NULLIFIER_TREE,
|
|
358
|
+
siloedNullifier.toBigInt(),
|
|
359
|
+
);
|
|
360
|
+
if (alreadyPresent) {
|
|
361
|
+
this.log.verbose(`Nullifier already present in tree: ${nullifier} at index ${alreadyPresent.index}.`);
|
|
362
|
+
}
|
|
363
|
+
const insertionResult = await this.merkleTrees.batchInsert(
|
|
364
|
+
MerkleTreeId.NULLIFIER_TREE,
|
|
365
|
+
[siloedNullifier.toBuffer()],
|
|
366
|
+
0,
|
|
367
|
+
);
|
|
368
|
+
const lowLeafInfo = insertionResult.lowLeavesWitnessData![0];
|
|
369
|
+
const lowLeafPreimage = lowLeafInfo.leafPreimage as NullifierLeafPreimage;
|
|
370
|
+
const lowLeafIndex = lowLeafInfo.index;
|
|
371
|
+
const lowLeafPath = lowLeafInfo.siblingPath.toFields();
|
|
372
|
+
const insertionPath = insertionResult.newSubtreeSiblingPath.toFields();
|
|
373
|
+
|
|
374
|
+
this.trace.traceNewNullifier(
|
|
375
|
+
contractAddress,
|
|
376
|
+
nullifier,
|
|
377
|
+
lowLeafPreimage,
|
|
378
|
+
new Fr(lowLeafIndex),
|
|
379
|
+
lowLeafPath,
|
|
380
|
+
insertionPath,
|
|
381
|
+
);
|
|
382
|
+
} else {
|
|
383
|
+
this.trace.traceNewNullifier(contractAddress, nullifier);
|
|
384
|
+
}
|
|
174
385
|
}
|
|
175
386
|
|
|
176
387
|
/**
|
|
@@ -179,15 +390,25 @@ export class AvmPersistableStateManager {
|
|
|
179
390
|
* @param msgLeafIndex - the message leaf index to use in the check
|
|
180
391
|
* @returns exists - whether the message exists in the L1 to L2 Messages tree
|
|
181
392
|
*/
|
|
182
|
-
public async checkL1ToL2MessageExists(
|
|
393
|
+
public async checkL1ToL2MessageExists(
|
|
394
|
+
contractAddress: AztecAddress,
|
|
395
|
+
msgHash: Fr,
|
|
396
|
+
msgLeafIndex: Fr,
|
|
397
|
+
): Promise<boolean> {
|
|
183
398
|
const valueAtIndex = (await this.worldStateDB.getL1ToL2LeafValue(msgLeafIndex.toBigInt())) ?? Fr.ZERO;
|
|
184
399
|
const exists = valueAtIndex.equals(msgHash);
|
|
185
400
|
this.log.debug(
|
|
186
401
|
`l1ToL2Messages(@${msgLeafIndex}) ?? exists: ${exists}, expected: ${msgHash}, found: ${valueAtIndex}.`,
|
|
187
402
|
);
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
403
|
+
|
|
404
|
+
if (this.doMerkleOperations) {
|
|
405
|
+
// TODO(8287): We still return exists here, but we need to transmit both the requested msgHash and the value
|
|
406
|
+
// such that the VM can constrain the equality and decide on exists based on that.
|
|
407
|
+
const path = await this.merkleTrees.getSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, msgLeafIndex.toBigInt());
|
|
408
|
+
this.trace.traceL1ToL2MessageCheck(contractAddress, valueAtIndex, msgLeafIndex, exists, path.toFields());
|
|
409
|
+
} else {
|
|
410
|
+
this.trace.traceL1ToL2MessageCheck(contractAddress, valueAtIndex, msgLeafIndex, exists);
|
|
411
|
+
}
|
|
191
412
|
return Promise.resolve(exists);
|
|
192
413
|
}
|
|
193
414
|
|
|
@@ -197,7 +418,7 @@ export class AvmPersistableStateManager {
|
|
|
197
418
|
* @param recipient - L1 contract address to send the message to.
|
|
198
419
|
* @param content - Message content.
|
|
199
420
|
*/
|
|
200
|
-
public writeL2ToL1Message(contractAddress:
|
|
421
|
+
public writeL2ToL1Message(contractAddress: AztecAddress, recipient: Fr, content: Fr) {
|
|
201
422
|
this.log.debug(`L2ToL1Messages(${contractAddress}) += (recipient: ${recipient}, content: ${content}).`);
|
|
202
423
|
this.trace.traceNewL2ToL1Message(contractAddress, recipient, content);
|
|
203
424
|
}
|
|
@@ -208,7 +429,7 @@ export class AvmPersistableStateManager {
|
|
|
208
429
|
* @param event - log event selector
|
|
209
430
|
* @param log - log contents
|
|
210
431
|
*/
|
|
211
|
-
public writeUnencryptedLog(contractAddress:
|
|
432
|
+
public writeUnencryptedLog(contractAddress: AztecAddress, log: Fr[]) {
|
|
212
433
|
this.log.debug(`UnencryptedL2Log(${contractAddress}) += event with ${log.length} fields.`);
|
|
213
434
|
this.trace.traceUnencryptedLog(contractAddress, log);
|
|
214
435
|
}
|
|
@@ -218,11 +439,12 @@ export class AvmPersistableStateManager {
|
|
|
218
439
|
* @param contractAddress - address of the contract instance to retrieve.
|
|
219
440
|
* @returns the contract instance or undefined if it does not exist.
|
|
220
441
|
*/
|
|
221
|
-
public async getContractInstance(contractAddress:
|
|
442
|
+
public async getContractInstance(contractAddress: AztecAddress): Promise<SerializableContractInstance | undefined> {
|
|
222
443
|
this.log.debug(`Getting contract instance for address ${contractAddress}`);
|
|
223
|
-
const instanceWithAddress = await this.worldStateDB.getContractInstance(
|
|
444
|
+
const instanceWithAddress = await this.worldStateDB.getContractInstance(contractAddress);
|
|
224
445
|
const exists = instanceWithAddress !== undefined;
|
|
225
446
|
|
|
447
|
+
// TODO: nullifier check!
|
|
226
448
|
if (exists) {
|
|
227
449
|
const instance = new SerializableContractInstance(instanceWithAddress);
|
|
228
450
|
this.log.debug(
|
|
@@ -238,14 +460,6 @@ export class AvmPersistableStateManager {
|
|
|
238
460
|
}
|
|
239
461
|
}
|
|
240
462
|
|
|
241
|
-
/**
|
|
242
|
-
* Accept nested world state modifications
|
|
243
|
-
*/
|
|
244
|
-
public acceptNestedCallState(nestedState: AvmPersistableStateManager) {
|
|
245
|
-
this.publicStorage.acceptAndMerge(nestedState.publicStorage);
|
|
246
|
-
this.nullifiers.acceptAndMerge(nestedState.nullifiers);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
463
|
/**
|
|
250
464
|
* Get a contract's bytecode from the contracts DB, also trace the contract class and instance
|
|
251
465
|
*/
|
|
@@ -286,20 +500,14 @@ export class AvmPersistableStateManager {
|
|
|
286
500
|
}
|
|
287
501
|
}
|
|
288
502
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
*/
|
|
292
|
-
public async processNestedCall(
|
|
293
|
-
nestedState: AvmPersistableStateManager,
|
|
503
|
+
public async traceNestedCall(
|
|
504
|
+
forkedState: AvmPersistableStateManager,
|
|
294
505
|
nestedEnvironment: AvmExecutionEnvironment,
|
|
295
506
|
startGasLeft: Gas,
|
|
296
507
|
endGasLeft: Gas,
|
|
297
508
|
bytecode: Buffer,
|
|
298
509
|
avmCallResults: AvmContractCallResult,
|
|
299
510
|
) {
|
|
300
|
-
if (!avmCallResults.reverted) {
|
|
301
|
-
this.acceptNestedCallState(nestedState);
|
|
302
|
-
}
|
|
303
511
|
const functionName = await getPublicFunctionDebugName(
|
|
304
512
|
this.worldStateDB,
|
|
305
513
|
nestedEnvironment.address,
|
|
@@ -307,10 +515,10 @@ export class AvmPersistableStateManager {
|
|
|
307
515
|
nestedEnvironment.calldata,
|
|
308
516
|
);
|
|
309
517
|
|
|
310
|
-
this.log.verbose(`[AVM]
|
|
518
|
+
this.log.verbose(`[AVM] Tracing nested external contract call ${functionName}`);
|
|
311
519
|
|
|
312
520
|
this.trace.traceNestedCall(
|
|
313
|
-
|
|
521
|
+
forkedState.trace,
|
|
314
522
|
nestedEnvironment,
|
|
315
523
|
startGasLeft,
|
|
316
524
|
endGasLeft,
|
|
@@ -319,4 +527,35 @@ export class AvmPersistableStateManager {
|
|
|
319
527
|
functionName,
|
|
320
528
|
);
|
|
321
529
|
}
|
|
530
|
+
|
|
531
|
+
public traceEnqueuedCall(publicCallRequest: PublicCallRequest, calldata: Fr[], reverted: boolean) {
|
|
532
|
+
this.trace.traceEnqueuedCall(publicCallRequest, calldata, reverted);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Get leaf if present, low leaf if absent
|
|
538
|
+
*/
|
|
539
|
+
export async function getLeafOrLowLeaf<TreePreimageType extends IndexedTreeLeafPreimage>(
|
|
540
|
+
treeId: IndexedTreeId,
|
|
541
|
+
key: bigint,
|
|
542
|
+
merkleTrees: MerkleTreeWriteOperations,
|
|
543
|
+
) {
|
|
544
|
+
// "key" is siloed slot (leafSlot) or siloed nullifier
|
|
545
|
+
const previousValueIndex = await merkleTrees.getPreviousValueIndex(treeId, key);
|
|
546
|
+
assert(
|
|
547
|
+
previousValueIndex !== undefined,
|
|
548
|
+
`${MerkleTreeId[treeId]} low leaf index should always be found (even if target leaf does not exist)`,
|
|
549
|
+
);
|
|
550
|
+
const { index: leafIndex, alreadyPresent } = previousValueIndex;
|
|
551
|
+
|
|
552
|
+
const leafPreimage = await merkleTrees.getLeafPreimage(treeId, leafIndex);
|
|
553
|
+
assert(
|
|
554
|
+
leafPreimage !== undefined,
|
|
555
|
+
`${MerkleTreeId[treeId]} low leaf preimage should never be undefined (even if target leaf does not exist)`,
|
|
556
|
+
);
|
|
557
|
+
|
|
558
|
+
const leafPath = await merkleTrees.getSiblingPath(treeId, leafIndex);
|
|
559
|
+
|
|
560
|
+
return [leafIndex, leafPreimage as TreePreimageType, leafPath.toFields(), alreadyPresent] as const;
|
|
322
561
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AztecAddress } from '@aztec/circuits.js';
|
|
1
|
+
import { type AztecAddress } from '@aztec/circuits.js';
|
|
2
2
|
import { siloNullifier } from '@aztec/circuits.js/hash';
|
|
3
3
|
import { Fr } from '@aztec/foundation/fields';
|
|
4
4
|
|
|
@@ -41,7 +41,7 @@ export class NullifierManager {
|
|
|
41
41
|
* @param nullifier - the nullifier to check for
|
|
42
42
|
* @returns exists: whether the nullifier exists in cache here or in parent's
|
|
43
43
|
*/
|
|
44
|
-
private checkExistsHereOrParent(contractAddress:
|
|
44
|
+
private checkExistsHereOrParent(contractAddress: AztecAddress, nullifier: Fr): boolean {
|
|
45
45
|
// First check this cache
|
|
46
46
|
let existsAsPending = this.cache.exists(contractAddress, nullifier);
|
|
47
47
|
// Then try parent's nullifier cache
|
|
@@ -66,7 +66,7 @@ export class NullifierManager {
|
|
|
66
66
|
* leafIndex: the nullifier's leaf index if it exists and is not pending (comes from host state).
|
|
67
67
|
*/
|
|
68
68
|
public async checkExists(
|
|
69
|
-
contractAddress:
|
|
69
|
+
contractAddress: AztecAddress,
|
|
70
70
|
nullifier: Fr,
|
|
71
71
|
): Promise<[/*exists=*/ boolean, /*isPending=*/ boolean, /*leafIndex=*/ Fr]> {
|
|
72
72
|
// Check this cache and parent's (recursively)
|
|
@@ -89,7 +89,7 @@ export class NullifierManager {
|
|
|
89
89
|
* @param contractAddress - the address of the contract that the nullifier is associated with
|
|
90
90
|
* @param nullifier - the nullifier to stage
|
|
91
91
|
*/
|
|
92
|
-
public async append(contractAddress:
|
|
92
|
+
public async append(contractAddress: AztecAddress, nullifier: Fr) {
|
|
93
93
|
const [exists, ,] = await this.checkExists(contractAddress, nullifier);
|
|
94
94
|
if (exists) {
|
|
95
95
|
throw new NullifierCollisionError(
|
|
@@ -139,10 +139,10 @@ export class NullifierCache {
|
|
|
139
139
|
* @param nullifier - the nullifier to check existence of
|
|
140
140
|
* @returns whether the nullifier is found in the cache
|
|
141
141
|
*/
|
|
142
|
-
public exists(contractAddress:
|
|
142
|
+
public exists(contractAddress: AztecAddress, nullifier: Fr): boolean {
|
|
143
143
|
const exists =
|
|
144
144
|
this.cachePerContract.get(contractAddress.toBigInt())?.has(nullifier.toBigInt()) ||
|
|
145
|
-
this.siloedNullifiers.has(siloNullifier(
|
|
145
|
+
this.siloedNullifiers.has(siloNullifier(contractAddress, nullifier).toBigInt());
|
|
146
146
|
return !!exists;
|
|
147
147
|
}
|
|
148
148
|
|
|
@@ -152,7 +152,7 @@ export class NullifierCache {
|
|
|
152
152
|
* @param contractAddress - the address of the contract that the nullifier is associated with
|
|
153
153
|
* @param nullifier - the nullifier to stage
|
|
154
154
|
*/
|
|
155
|
-
public append(contractAddress:
|
|
155
|
+
public append(contractAddress: AztecAddress, nullifier: Fr) {
|
|
156
156
|
if (this.exists(contractAddress, nullifier)) {
|
|
157
157
|
throw new NullifierCollisionError(
|
|
158
158
|
`Nullifier ${nullifier} at contract ${contractAddress} already exists in cache.`,
|
|
@@ -49,7 +49,7 @@ export class PublicStorage {
|
|
|
49
49
|
* @param slot - the slot in the contract's storage being read from
|
|
50
50
|
* @returns value: the latest value written according to this cache or the parent's. undefined on cache miss.
|
|
51
51
|
*/
|
|
52
|
-
public readHereOrParent(contractAddress:
|
|
52
|
+
public readHereOrParent(contractAddress: AztecAddress, slot: Fr): Fr | undefined {
|
|
53
53
|
// First try check this storage cache
|
|
54
54
|
let value = this.cache.read(contractAddress, slot);
|
|
55
55
|
// Then try parent's storage cache
|
|
@@ -71,7 +71,7 @@ export class PublicStorage {
|
|
|
71
71
|
* @param slot - the slot in the contract's storage being read from
|
|
72
72
|
* @returns exists: whether the slot has EVER been written to before, value: the latest value written to slot, or 0 if never written to before
|
|
73
73
|
*/
|
|
74
|
-
public async read(contractAddress:
|
|
74
|
+
public async read(contractAddress: AztecAddress, slot: Fr): Promise<PublicStorageReadResult> {
|
|
75
75
|
let cached = false;
|
|
76
76
|
// Check this cache and parent's (recursively)
|
|
77
77
|
let value = this.readHereOrParent(contractAddress, slot);
|
|
@@ -97,7 +97,7 @@ export class PublicStorage {
|
|
|
97
97
|
* @param slot - the slot in the contract's storage being written to
|
|
98
98
|
* @param value - the value being written to the slot
|
|
99
99
|
*/
|
|
100
|
-
public write(contractAddress:
|
|
100
|
+
public write(contractAddress: AztecAddress, slot: Fr, value: Fr) {
|
|
101
101
|
this.cache.write(contractAddress, slot, value);
|
|
102
102
|
}
|
|
103
103
|
|
|
@@ -143,7 +143,7 @@ class PublicStorageCache {
|
|
|
143
143
|
* @param slot - the slot in the contract's storage being read from
|
|
144
144
|
* @returns the latest value written to slot, or undefined if no value has been written
|
|
145
145
|
*/
|
|
146
|
-
public read(contractAddress:
|
|
146
|
+
public read(contractAddress: AztecAddress, slot: Fr): Fr | undefined {
|
|
147
147
|
return this.cachePerContract.get(contractAddress.toBigInt())?.get(slot.toBigInt());
|
|
148
148
|
}
|
|
149
149
|
|
|
@@ -154,7 +154,7 @@ class PublicStorageCache {
|
|
|
154
154
|
* @param slot - the slot in the contract's storage being written to
|
|
155
155
|
* @param value - the value being written to the slot
|
|
156
156
|
*/
|
|
157
|
-
public write(contractAddress:
|
|
157
|
+
public write(contractAddress: AztecAddress, slot: Fr, value: Fr) {
|
|
158
158
|
let cacheAtContract = this.cachePerContract.get(contractAddress.toBigInt());
|
|
159
159
|
if (!cacheAtContract) {
|
|
160
160
|
// If this contract's storage has no staged modifications, create a new inner map to store them
|
|
@@ -43,7 +43,6 @@ export class NoteHashExists extends Instruction {
|
|
|
43
43
|
memory.set(existsOffset, exists ? new Uint1(1) : new Uint1(0));
|
|
44
44
|
|
|
45
45
|
memory.assert({ reads: 2, writes: 1, addressing });
|
|
46
|
-
context.machineState.incrementPc();
|
|
47
46
|
}
|
|
48
47
|
}
|
|
49
48
|
|
|
@@ -71,10 +70,9 @@ export class EmitNoteHash extends Instruction {
|
|
|
71
70
|
}
|
|
72
71
|
|
|
73
72
|
const noteHash = memory.get(noteHashOffset).toFr();
|
|
74
|
-
context.persistableState.writeNoteHash(context.environment.address, noteHash);
|
|
73
|
+
await context.persistableState.writeNoteHash(context.environment.address, noteHash);
|
|
75
74
|
|
|
76
75
|
memory.assert({ reads: 1, addressing });
|
|
77
|
-
context.machineState.incrementPc();
|
|
78
76
|
}
|
|
79
77
|
}
|
|
80
78
|
|
|
@@ -109,13 +107,12 @@ export class NullifierExists extends Instruction {
|
|
|
109
107
|
memory.checkTags(TypeTag.FIELD, nullifierOffset, addressOffset);
|
|
110
108
|
|
|
111
109
|
const nullifier = memory.get(nullifierOffset).toFr();
|
|
112
|
-
const address = memory.get(addressOffset).
|
|
110
|
+
const address = memory.get(addressOffset).toAztecAddress();
|
|
113
111
|
const exists = await context.persistableState.checkNullifierExists(address, nullifier);
|
|
114
112
|
|
|
115
113
|
memory.set(existsOffset, exists ? new Uint1(1) : new Uint1(0));
|
|
116
114
|
|
|
117
115
|
memory.assert({ reads: 2, writes: 1, addressing });
|
|
118
|
-
context.machineState.incrementPc();
|
|
119
116
|
}
|
|
120
117
|
}
|
|
121
118
|
|
|
@@ -157,7 +154,6 @@ export class EmitNullifier extends Instruction {
|
|
|
157
154
|
}
|
|
158
155
|
|
|
159
156
|
memory.assert({ reads: 1, addressing });
|
|
160
|
-
context.machineState.incrementPc();
|
|
161
157
|
}
|
|
162
158
|
}
|
|
163
159
|
|
|
@@ -201,7 +197,6 @@ export class L1ToL2MessageExists extends Instruction {
|
|
|
201
197
|
memory.set(existsOffset, exists ? new Uint1(1) : new Uint1(0));
|
|
202
198
|
|
|
203
199
|
memory.assert({ reads: 2, writes: 1, addressing });
|
|
204
|
-
context.machineState.incrementPc();
|
|
205
200
|
}
|
|
206
201
|
}
|
|
207
202
|
|
|
@@ -236,7 +231,6 @@ export class EmitUnencryptedLog extends Instruction {
|
|
|
236
231
|
context.persistableState.writeUnencryptedLog(contractAddress, log);
|
|
237
232
|
|
|
238
233
|
memory.assert({ reads: 1 + logSize, addressing });
|
|
239
|
-
context.machineState.incrementPc();
|
|
240
234
|
}
|
|
241
235
|
}
|
|
242
236
|
|
|
@@ -261,12 +255,12 @@ export class SendL2ToL1Message extends Instruction {
|
|
|
261
255
|
const operands = [this.recipientOffset, this.contentOffset];
|
|
262
256
|
const addressing = Addressing.fromWire(this.indirect, operands.length);
|
|
263
257
|
const [recipientOffset, contentOffset] = addressing.resolve(operands, memory);
|
|
258
|
+
memory.checkTags(TypeTag.FIELD, recipientOffset, contentOffset);
|
|
264
259
|
|
|
265
260
|
const recipient = memory.get(recipientOffset).toFr();
|
|
266
261
|
const content = memory.get(contentOffset).toFr();
|
|
267
262
|
context.persistableState.writeL2ToL1Message(context.environment.address, recipient, content);
|
|
268
263
|
|
|
269
264
|
memory.assert({ reads: 2, addressing });
|
|
270
|
-
context.machineState.incrementPc();
|
|
271
265
|
}
|
|
272
266
|
}
|