@aztec/simulator 0.34.0 → 0.35.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.
Files changed (168) hide show
  1. package/dest/acvm/acvm.d.ts +4 -1
  2. package/dest/acvm/acvm.d.ts.map +1 -1
  3. package/dest/acvm/acvm.js +5 -5
  4. package/dest/acvm/deserialize.d.ts +3 -5
  5. package/dest/acvm/deserialize.d.ts.map +1 -1
  6. package/dest/acvm/deserialize.js +6 -9
  7. package/dest/acvm/oracle/oracle.d.ts +2 -0
  8. package/dest/acvm/oracle/oracle.d.ts.map +1 -1
  9. package/dest/acvm/oracle/oracle.js +12 -4
  10. package/dest/acvm/oracle/typed_oracle.d.ts +2 -0
  11. package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
  12. package/dest/acvm/oracle/typed_oracle.js +7 -1
  13. package/dest/avm/avm_execution_environment.d.ts +4 -2
  14. package/dest/avm/avm_execution_environment.d.ts.map +1 -1
  15. package/dest/avm/avm_execution_environment.js +7 -5
  16. package/dest/avm/avm_gas.js +2 -2
  17. package/dest/avm/avm_machine_state.d.ts +2 -0
  18. package/dest/avm/avm_machine_state.d.ts.map +1 -1
  19. package/dest/avm/avm_machine_state.js +24 -6
  20. package/dest/avm/avm_memory_types.js +2 -2
  21. package/dest/avm/avm_simulator.js +2 -2
  22. package/dest/avm/fixtures/index.d.ts +3 -0
  23. package/dest/avm/fixtures/index.d.ts.map +1 -1
  24. package/dest/avm/fixtures/index.js +11 -4
  25. package/dest/avm/journal/journal.d.ts +1 -0
  26. package/dest/avm/journal/journal.d.ts.map +1 -1
  27. package/dest/avm/journal/journal.js +12 -1
  28. package/dest/avm/opcodes/accrued_substate.d.ts +2 -1
  29. package/dest/avm/opcodes/accrued_substate.d.ts.map +1 -1
  30. package/dest/avm/opcodes/accrued_substate.js +13 -5
  31. package/dest/avm/opcodes/context_getters.js +2 -2
  32. package/dest/avm/opcodes/external_calls.d.ts +2 -2
  33. package/dest/avm/opcodes/external_calls.d.ts.map +1 -1
  34. package/dest/avm/opcodes/external_calls.js +7 -6
  35. package/dest/avm/opcodes/hashing.d.ts +8 -8
  36. package/dest/avm/opcodes/hashing.d.ts.map +1 -1
  37. package/dest/avm/opcodes/hashing.js +35 -43
  38. package/dest/avm/serialization/instruction_serialization.d.ts +1 -1
  39. package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
  40. package/dest/avm/serialization/instruction_serialization.js +2 -2
  41. package/dest/client/client_execution_context.d.ts +13 -3
  42. package/dest/client/client_execution_context.d.ts.map +1 -1
  43. package/dest/client/client_execution_context.js +23 -8
  44. package/dest/client/private_execution.d.ts.map +1 -1
  45. package/dest/client/private_execution.js +8 -6
  46. package/dest/client/simulator.d.ts.map +1 -1
  47. package/dest/client/simulator.js +6 -5
  48. package/dest/client/unconstrained_execution.d.ts.map +1 -1
  49. package/dest/client/unconstrained_execution.js +5 -4
  50. package/dest/common/index.d.ts +1 -1
  51. package/dest/common/index.d.ts.map +1 -1
  52. package/dest/common/index.js +2 -2
  53. package/dest/common/packed_values_cache.d.ts +28 -0
  54. package/dest/common/packed_values_cache.d.ts.map +1 -0
  55. package/dest/common/packed_values_cache.js +50 -0
  56. package/dest/index.d.ts +1 -0
  57. package/dest/index.d.ts.map +1 -1
  58. package/dest/index.js +2 -1
  59. package/dest/mocks/fixtures.d.ts +42 -0
  60. package/dest/mocks/fixtures.d.ts.map +1 -0
  61. package/dest/mocks/fixtures.js +84 -0
  62. package/dest/mocks/index.d.ts +2 -0
  63. package/dest/mocks/index.d.ts.map +1 -0
  64. package/dest/mocks/index.js +2 -0
  65. package/dest/public/abstract_phase_manager.d.ts +82 -0
  66. package/dest/public/abstract_phase_manager.d.ts.map +1 -0
  67. package/dest/public/abstract_phase_manager.js +320 -0
  68. package/dest/public/app_logic_phase_manager.d.ts +29 -0
  69. package/dest/public/app_logic_phase_manager.d.ts.map +1 -0
  70. package/dest/public/app_logic_phase_manager.js +50 -0
  71. package/dest/public/execution.d.ts +3 -0
  72. package/dest/public/execution.d.ts.map +1 -1
  73. package/dest/public/execution.js +1 -1
  74. package/dest/public/executor.d.ts.map +1 -1
  75. package/dest/public/executor.js +17 -13
  76. package/dest/public/hints_builder.d.ts +23 -0
  77. package/dest/public/hints_builder.d.ts.map +1 -0
  78. package/dest/public/hints_builder.js +62 -0
  79. package/dest/public/index.d.ts +5 -0
  80. package/dest/public/index.d.ts.map +1 -1
  81. package/dest/public/index.js +6 -1
  82. package/dest/public/phase_manager_factory.d.ts +18 -0
  83. package/dest/public/phase_manager_factory.d.ts.map +1 -0
  84. package/dest/public/phase_manager_factory.js +56 -0
  85. package/dest/public/public_execution_context.d.ts +15 -5
  86. package/dest/public/public_execution_context.d.ts.map +1 -1
  87. package/dest/public/public_execution_context.js +28 -12
  88. package/dest/public/public_executor.d.ts +79 -0
  89. package/dest/public/public_executor.d.ts.map +1 -0
  90. package/dest/public/public_executor.js +198 -0
  91. package/dest/public/public_kernel.d.ts +37 -0
  92. package/dest/public/public_kernel.d.ts.map +1 -0
  93. package/dest/public/public_kernel.js +97 -0
  94. package/dest/public/public_kernel_circuit_simulator.d.ts +31 -0
  95. package/dest/public/public_kernel_circuit_simulator.d.ts.map +1 -0
  96. package/dest/public/public_kernel_circuit_simulator.js +2 -0
  97. package/dest/public/public_processor.d.ts +53 -0
  98. package/dest/public/public_processor.d.ts.map +1 -0
  99. package/dest/public/public_processor.js +144 -0
  100. package/dest/public/setup_phase_manager.d.ts +30 -0
  101. package/dest/public/setup_phase_manager.d.ts.map +1 -0
  102. package/dest/public/setup_phase_manager.js +46 -0
  103. package/dest/public/tail_phase_manager.d.ts +30 -0
  104. package/dest/public/tail_phase_manager.d.ts.map +1 -0
  105. package/dest/public/tail_phase_manager.js +60 -0
  106. package/dest/public/teardown_phase_manager.d.ts +30 -0
  107. package/dest/public/teardown_phase_manager.d.ts.map +1 -0
  108. package/dest/public/teardown_phase_manager.js +46 -0
  109. package/dest/public/transitional_adaptors.d.ts +2 -1
  110. package/dest/public/transitional_adaptors.d.ts.map +1 -1
  111. package/dest/public/transitional_adaptors.js +11 -10
  112. package/dest/public/utils.d.ts +8 -0
  113. package/dest/public/utils.d.ts.map +1 -0
  114. package/dest/public/utils.js +29 -0
  115. package/dest/simulator/acvm_native.d.ts +19 -3
  116. package/dest/simulator/acvm_native.d.ts.map +1 -1
  117. package/dest/simulator/acvm_native.js +75 -48
  118. package/dest/simulator/acvm_wasm.d.ts.map +1 -1
  119. package/dest/simulator/acvm_wasm.js +3 -4
  120. package/package.json +8 -5
  121. package/src/acvm/acvm.ts +8 -5
  122. package/src/acvm/deserialize.ts +5 -9
  123. package/src/acvm/oracle/oracle.ts +13 -3
  124. package/src/acvm/oracle/typed_oracle.ts +8 -0
  125. package/src/avm/avm_execution_environment.ts +9 -1
  126. package/src/avm/avm_gas.ts +1 -1
  127. package/src/avm/avm_machine_state.ts +26 -5
  128. package/src/avm/avm_memory_types.ts +1 -1
  129. package/src/avm/avm_simulator.ts +1 -1
  130. package/src/avm/fixtures/index.ts +13 -1
  131. package/src/avm/journal/journal.ts +13 -0
  132. package/src/avm/opcodes/accrued_substate.ts +16 -4
  133. package/src/avm/opcodes/context_getters.ts +1 -1
  134. package/src/avm/opcodes/external_calls.ts +8 -5
  135. package/src/avm/opcodes/hashing.ts +38 -54
  136. package/src/avm/serialization/instruction_serialization.ts +1 -1
  137. package/src/client/client_execution_context.ts +25 -6
  138. package/src/client/private_execution.ts +7 -6
  139. package/src/client/simulator.ts +7 -3
  140. package/src/client/unconstrained_execution.ts +4 -3
  141. package/src/common/index.ts +1 -1
  142. package/src/common/packed_values_cache.ts +55 -0
  143. package/src/index.ts +1 -0
  144. package/src/mocks/fixtures.ts +169 -0
  145. package/src/mocks/index.ts +1 -0
  146. package/src/public/abstract_phase_manager.ts +571 -0
  147. package/src/public/app_logic_phase_manager.ts +76 -0
  148. package/src/public/execution.ts +4 -0
  149. package/src/public/executor.ts +18 -13
  150. package/src/public/hints_builder.ts +119 -0
  151. package/src/public/index.ts +5 -0
  152. package/src/public/phase_manager_factory.ts +126 -0
  153. package/src/public/public_execution_context.ts +29 -18
  154. package/src/public/public_executor.ts +267 -0
  155. package/src/public/public_kernel.ts +139 -0
  156. package/src/public/public_kernel_circuit_simulator.ts +36 -0
  157. package/src/public/public_processor.ts +212 -0
  158. package/src/public/setup_phase_manager.ts +66 -0
  159. package/src/public/tail_phase_manager.ts +120 -0
  160. package/src/public/teardown_phase_manager.ts +66 -0
  161. package/src/public/transitional_adaptors.ts +14 -5
  162. package/src/public/utils.ts +31 -0
  163. package/src/simulator/acvm_native.ts +94 -47
  164. package/src/simulator/acvm_wasm.ts +7 -3
  165. package/dest/common/packed_args_cache.d.ts +0 -28
  166. package/dest/common/packed_args_cache.d.ts.map +0 -1
  167. package/dest/common/packed_args_cache.js +0 -50
  168. package/src/common/packed_args_cache.ts +0 -55
@@ -0,0 +1,267 @@
1
+ import { MerkleTreeId, NullifierMembershipWitness, type Tx } from '@aztec/circuit-types';
2
+ import {
3
+ type AztecAddress,
4
+ ContractClassRegisteredEvent,
5
+ ContractInstanceDeployedEvent,
6
+ type EthAddress,
7
+ Fr,
8
+ type FunctionSelector,
9
+ type L1_TO_L2_MSG_TREE_HEIGHT,
10
+ type NULLIFIER_TREE_HEIGHT,
11
+ type NullifierLeafPreimage,
12
+ type PublicDataTreeLeafPreimage,
13
+ } from '@aztec/circuits.js';
14
+ import { computeL1ToL2MessageNullifier, computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash';
15
+ import { createDebugLogger } from '@aztec/foundation/log';
16
+ import { getCanonicalClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer';
17
+ import {
18
+ type CommitmentsDB,
19
+ MessageLoadOracleInputs,
20
+ type PublicContractsDB,
21
+ type PublicStateDB,
22
+ } from '@aztec/simulator';
23
+ import {
24
+ type ContractClassPublic,
25
+ type ContractDataSource,
26
+ type ContractInstanceWithAddress,
27
+ } from '@aztec/types/contracts';
28
+ import { type MerkleTreeOperations } from '@aztec/world-state';
29
+
30
+ /**
31
+ * Implements the PublicContractsDB using a ContractDataSource.
32
+ * Progressively records contracts in transaction as they are processed in a block.
33
+ */
34
+ export class ContractsDataSourcePublicDB implements PublicContractsDB {
35
+ private instanceCache = new Map<string, ContractInstanceWithAddress>();
36
+ private classCache = new Map<string, ContractClassPublic>();
37
+
38
+ private log = createDebugLogger('aztec:sequencer:contracts-data-source');
39
+
40
+ constructor(private db: ContractDataSource) {}
41
+
42
+ /**
43
+ * Add new contracts from a transaction
44
+ * @param tx - The transaction to add contracts from.
45
+ */
46
+ public addNewContracts(tx: Tx): Promise<void> {
47
+ // Extract contract class and instance data from logs and add to cache for this block
48
+ const logs = tx.unencryptedLogs.unrollLogs();
49
+ ContractClassRegisteredEvent.fromLogs(logs, getCanonicalClassRegistererAddress()).forEach(e => {
50
+ this.log.debug(`Adding class ${e.contractClassId.toString()} to public execution contract cache`);
51
+ this.classCache.set(e.contractClassId.toString(), e.toContractClassPublic());
52
+ });
53
+ ContractInstanceDeployedEvent.fromLogs(logs).forEach(e => {
54
+ this.log.debug(
55
+ `Adding instance ${e.address.toString()} with class ${e.contractClassId.toString()} to public execution contract cache`,
56
+ );
57
+ this.instanceCache.set(e.address.toString(), e.toContractInstance());
58
+ });
59
+
60
+ return Promise.resolve();
61
+ }
62
+
63
+ /**
64
+ * Removes new contracts added from transactions
65
+ * @param tx - The tx's contracts to be removed
66
+ */
67
+ public removeNewContracts(tx: Tx): Promise<void> {
68
+ // TODO(@spalladino): Can this inadvertently delete a valid contract added by another tx?
69
+ // Let's say we have two txs adding the same contract on the same block. If the 2nd one reverts,
70
+ // wouldn't that accidentally remove the contract added on the first one?
71
+ const logs = tx.unencryptedLogs.unrollLogs();
72
+ ContractClassRegisteredEvent.fromLogs(logs, getCanonicalClassRegistererAddress()).forEach(e =>
73
+ this.classCache.delete(e.contractClassId.toString()),
74
+ );
75
+ ContractInstanceDeployedEvent.fromLogs(logs).forEach(e => this.instanceCache.delete(e.address.toString()));
76
+ return Promise.resolve();
77
+ }
78
+
79
+ public async getContractInstance(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
80
+ return this.instanceCache.get(address.toString()) ?? (await this.db.getContract(address));
81
+ }
82
+
83
+ public async getContractClass(contractClassId: Fr): Promise<ContractClassPublic | undefined> {
84
+ return this.classCache.get(contractClassId.toString()) ?? (await this.db.getContractClass(contractClassId));
85
+ }
86
+
87
+ async getBytecode(address: AztecAddress, selector: FunctionSelector): Promise<Buffer | undefined> {
88
+ const instance = await this.getContractInstance(address);
89
+ if (!instance) {
90
+ throw new Error(`Contract ${address.toString()} not found`);
91
+ }
92
+ const contractClass = await this.getContractClass(instance.contractClassId);
93
+ if (!contractClass) {
94
+ throw new Error(`Contract class ${instance.contractClassId.toString()} for ${address.toString()} not found`);
95
+ }
96
+ return contractClass.publicFunctions.find(f => f.selector.equals(selector))?.bytecode;
97
+ }
98
+
99
+ async getPortalContractAddress(address: AztecAddress): Promise<EthAddress | undefined> {
100
+ const contract = await this.getContractInstance(address);
101
+ return contract?.portalContractAddress;
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Implements the PublicStateDB using a world-state database.
107
+ */
108
+ export class WorldStatePublicDB implements PublicStateDB {
109
+ private committedWriteCache: Map<bigint, Fr> = new Map();
110
+ private checkpointedWriteCache: Map<bigint, Fr> = new Map();
111
+ private uncommittedWriteCache: Map<bigint, Fr> = new Map();
112
+
113
+ constructor(private db: MerkleTreeOperations) {}
114
+
115
+ /**
116
+ * Reads a value from public storage, returning zero if none.
117
+ * @param contract - Owner of the storage.
118
+ * @param slot - Slot to read in the contract storage.
119
+ * @returns The current value in the storage slot.
120
+ */
121
+ public async storageRead(contract: AztecAddress, slot: Fr): Promise<Fr> {
122
+ const leafSlot = computePublicDataTreeLeafSlot(contract, slot).value;
123
+ const uncommitted = this.uncommittedWriteCache.get(leafSlot);
124
+ if (uncommitted !== undefined) {
125
+ return uncommitted;
126
+ }
127
+ const checkpointed = this.checkpointedWriteCache.get(leafSlot);
128
+ if (checkpointed !== undefined) {
129
+ return checkpointed;
130
+ }
131
+ const committed = this.committedWriteCache.get(leafSlot);
132
+ if (committed !== undefined) {
133
+ return committed;
134
+ }
135
+
136
+ const lowLeafResult = await this.db.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot);
137
+ if (!lowLeafResult || !lowLeafResult.alreadyPresent) {
138
+ return Fr.ZERO;
139
+ }
140
+
141
+ const preimage = (await this.db.getLeafPreimage(
142
+ MerkleTreeId.PUBLIC_DATA_TREE,
143
+ lowLeafResult.index,
144
+ )) as PublicDataTreeLeafPreimage;
145
+
146
+ return preimage.value;
147
+ }
148
+
149
+ /**
150
+ * Records a write to public storage.
151
+ * @param contract - Owner of the storage.
152
+ * @param slot - Slot to read in the contract storage.
153
+ * @param newValue - The new value to store.
154
+ */
155
+ public storageWrite(contract: AztecAddress, slot: Fr, newValue: Fr): Promise<void> {
156
+ const index = computePublicDataTreeLeafSlot(contract, slot).value;
157
+ this.uncommittedWriteCache.set(index, newValue);
158
+ return Promise.resolve();
159
+ }
160
+
161
+ /**
162
+ * Commit the pending changes to the DB.
163
+ * @returns Nothing.
164
+ */
165
+ commit(): Promise<void> {
166
+ for (const [k, v] of this.checkpointedWriteCache) {
167
+ this.committedWriteCache.set(k, v);
168
+ }
169
+ // uncommitted writes take precedence over checkpointed writes
170
+ // since they are the most recent
171
+ for (const [k, v] of this.uncommittedWriteCache) {
172
+ this.committedWriteCache.set(k, v);
173
+ }
174
+ return this.rollbackToCommit();
175
+ }
176
+
177
+ /**
178
+ * Rollback the pending changes.
179
+ * @returns Nothing.
180
+ */
181
+ async rollbackToCommit(): Promise<void> {
182
+ await this.rollbackToCheckpoint();
183
+ this.checkpointedWriteCache = new Map<bigint, Fr>();
184
+ return Promise.resolve();
185
+ }
186
+
187
+ checkpoint(): Promise<void> {
188
+ for (const [k, v] of this.uncommittedWriteCache) {
189
+ this.checkpointedWriteCache.set(k, v);
190
+ }
191
+ return this.rollbackToCheckpoint();
192
+ }
193
+
194
+ rollbackToCheckpoint(): Promise<void> {
195
+ this.uncommittedWriteCache = new Map<bigint, Fr>();
196
+ return Promise.resolve();
197
+ }
198
+ }
199
+
200
+ /**
201
+ * Implements WorldState db using a world state database.
202
+ */
203
+ export class WorldStateDB implements CommitmentsDB {
204
+ constructor(private db: MerkleTreeOperations) {}
205
+
206
+ public async getNullifierMembershipWitnessAtLatestBlock(
207
+ nullifier: Fr,
208
+ ): Promise<NullifierMembershipWitness | undefined> {
209
+ const index = await this.db.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
210
+ if (!index) {
211
+ return undefined;
212
+ }
213
+
214
+ const leafPreimagePromise = this.db.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index);
215
+ const siblingPathPromise = this.db.getSiblingPath<typeof NULLIFIER_TREE_HEIGHT>(
216
+ MerkleTreeId.NULLIFIER_TREE,
217
+ BigInt(index),
218
+ );
219
+
220
+ const [leafPreimage, siblingPath] = await Promise.all([leafPreimagePromise, siblingPathPromise]);
221
+
222
+ if (!leafPreimage) {
223
+ return undefined;
224
+ }
225
+
226
+ return new NullifierMembershipWitness(BigInt(index), leafPreimage as NullifierLeafPreimage, siblingPath);
227
+ }
228
+
229
+ public async getL1ToL2MembershipWitness(
230
+ contractAddress: AztecAddress,
231
+ messageHash: Fr,
232
+ secret: Fr,
233
+ ): Promise<MessageLoadOracleInputs<typeof L1_TO_L2_MSG_TREE_HEIGHT>> {
234
+ let nullifierIndex: bigint | undefined;
235
+ let messageIndex: bigint | undefined;
236
+ let startIndex = 0n;
237
+
238
+ // We iterate over messages until we find one whose nullifier is not in the nullifier tree --> we need to check
239
+ // for nullifiers because messages can have duplicates.
240
+ do {
241
+ messageIndex = (await this.db.findLeafIndexAfter(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, messageHash, startIndex))!;
242
+ if (messageIndex === undefined) {
243
+ throw new Error(`No non-nullified L1 to L2 message found for message hash ${messageHash.toString()}`);
244
+ }
245
+
246
+ const messageNullifier = computeL1ToL2MessageNullifier(contractAddress, messageHash, secret, messageIndex);
247
+ nullifierIndex = await this.getNullifierIndex(messageNullifier);
248
+
249
+ startIndex = messageIndex + 1n;
250
+ } while (nullifierIndex !== undefined);
251
+
252
+ const siblingPath = await this.db.getSiblingPath<typeof L1_TO_L2_MSG_TREE_HEIGHT>(
253
+ MerkleTreeId.L1_TO_L2_MESSAGE_TREE,
254
+ messageIndex,
255
+ );
256
+
257
+ return new MessageLoadOracleInputs<typeof L1_TO_L2_MSG_TREE_HEIGHT>(messageIndex, siblingPath);
258
+ }
259
+
260
+ public async getCommitmentIndex(commitment: Fr): Promise<bigint | undefined> {
261
+ return await this.db.findLeafIndex(MerkleTreeId.NOTE_HASH_TREE, commitment);
262
+ }
263
+
264
+ public async getNullifierIndex(nullifier: Fr): Promise<bigint | undefined> {
265
+ return await this.db.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
266
+ }
267
+ }
@@ -0,0 +1,139 @@
1
+ import { type CircuitSimulationStats } from '@aztec/circuit-types/stats';
2
+ import {
3
+ type KernelCircuitPublicInputs,
4
+ type PublicKernelCircuitPrivateInputs,
5
+ type PublicKernelCircuitPublicInputs,
6
+ type PublicKernelTailCircuitPrivateInputs,
7
+ } from '@aztec/circuits.js';
8
+ import { createDebugLogger } from '@aztec/foundation/log';
9
+ import { elapsed } from '@aztec/foundation/timer';
10
+ import {
11
+ PublicKernelAppLogicArtifact,
12
+ PublicKernelSetupArtifact,
13
+ PublicKernelTailArtifact,
14
+ PublicKernelTeardownArtifact,
15
+ convertPublicInnerRollupInputsToWitnessMap,
16
+ convertPublicInnerRollupOutputFromWitnessMap,
17
+ convertPublicSetupRollupInputsToWitnessMap,
18
+ convertPublicSetupRollupOutputFromWitnessMap,
19
+ convertPublicTailInputsToWitnessMap,
20
+ convertPublicTailOutputFromWitnessMap,
21
+ convertPublicTeardownRollupInputsToWitnessMap,
22
+ convertPublicTeardownRollupOutputFromWitnessMap,
23
+ } from '@aztec/noir-protocol-circuits-types';
24
+ import { type SimulationProvider, WASMSimulator } from '@aztec/simulator';
25
+
26
+ import { type PublicKernelCircuitSimulator } from './public_kernel_circuit_simulator.js';
27
+
28
+ /**
29
+ * Implements the PublicKernelCircuitSimulator.
30
+ */
31
+ export class RealPublicKernelCircuitSimulator implements PublicKernelCircuitSimulator {
32
+ private log = createDebugLogger('aztec:public-kernel-simulator');
33
+
34
+ // Some circuits are so small it is faster to use WASM
35
+ private wasmSimulator: WASMSimulator = new WASMSimulator();
36
+
37
+ constructor(private simulator: SimulationProvider) {}
38
+
39
+ /**
40
+ * Simulates the public kernel setup circuit from its inputs.
41
+ * @param input - Inputs to the circuit.
42
+ * @returns The public inputs as outputs of the simulation.
43
+ */
44
+ public async publicKernelCircuitSetup(
45
+ input: PublicKernelCircuitPrivateInputs,
46
+ ): Promise<PublicKernelCircuitPublicInputs> {
47
+ if (!input.previousKernel.publicInputs.needsSetup) {
48
+ throw new Error(`Expected previous kernel inputs to need setup`);
49
+ }
50
+ const inputWitness = convertPublicSetupRollupInputsToWitnessMap(input);
51
+ const [duration, witness] = await elapsed(() =>
52
+ this.wasmSimulator.simulateCircuit(inputWitness, PublicKernelSetupArtifact),
53
+ );
54
+ const result = convertPublicSetupRollupOutputFromWitnessMap(witness);
55
+ this.log.debug(`Simulated public kernel setup circuit`, {
56
+ eventName: 'circuit-simulation',
57
+ circuitName: 'public-kernel-setup',
58
+ duration,
59
+ inputSize: input.toBuffer().length,
60
+ outputSize: result.toBuffer().length,
61
+ } satisfies CircuitSimulationStats);
62
+ return result;
63
+ }
64
+
65
+ /**
66
+ * Simulates the public kernel app logic circuit from its inputs.
67
+ * @param input - Inputs to the circuit.
68
+ * @returns The public inputs as outputs of the simulation.
69
+ */
70
+ public async publicKernelCircuitAppLogic(
71
+ input: PublicKernelCircuitPrivateInputs,
72
+ ): Promise<PublicKernelCircuitPublicInputs> {
73
+ if (!input.previousKernel.publicInputs.needsAppLogic) {
74
+ throw new Error(`Expected previous kernel inputs to need app logic`);
75
+ }
76
+ const inputWitness = convertPublicInnerRollupInputsToWitnessMap(input);
77
+ const [duration, witness] = await elapsed(() =>
78
+ this.wasmSimulator.simulateCircuit(inputWitness, PublicKernelAppLogicArtifact),
79
+ );
80
+ const result = convertPublicInnerRollupOutputFromWitnessMap(witness);
81
+ this.log.debug(`Simulated public kernel app logic circuit`, {
82
+ eventName: 'circuit-simulation',
83
+ circuitName: 'public-kernel-app-logic',
84
+ duration,
85
+ inputSize: input.toBuffer().length,
86
+ outputSize: result.toBuffer().length,
87
+ } satisfies CircuitSimulationStats);
88
+ return result;
89
+ }
90
+
91
+ /**
92
+ * Simulates the public kernel teardown circuit from its inputs.
93
+ * @param input - Inputs to the circuit.
94
+ * @returns The public inputs as outputs of the simulation.
95
+ */
96
+ public async publicKernelCircuitTeardown(
97
+ input: PublicKernelCircuitPrivateInputs,
98
+ ): Promise<PublicKernelCircuitPublicInputs> {
99
+ if (!input.previousKernel.publicInputs.needsTeardown) {
100
+ throw new Error(`Expected previous kernel inputs to need teardown`);
101
+ }
102
+ const inputWitness = convertPublicTeardownRollupInputsToWitnessMap(input);
103
+ const [duration, witness] = await elapsed(() =>
104
+ this.wasmSimulator.simulateCircuit(inputWitness, PublicKernelTeardownArtifact),
105
+ );
106
+ const result = convertPublicTeardownRollupOutputFromWitnessMap(witness);
107
+ this.log.debug(`Simulated public kernel teardown circuit`, {
108
+ eventName: 'circuit-simulation',
109
+ circuitName: 'public-kernel-teardown',
110
+ duration,
111
+ inputSize: input.toBuffer().length,
112
+ outputSize: result.toBuffer().length,
113
+ } satisfies CircuitSimulationStats);
114
+ return result;
115
+ }
116
+
117
+ /**
118
+ * Simulates the public kernel tail circuit from its inputs.
119
+ * @param input - Inputs to the circuit.
120
+ * @returns The public inputs as outputs of the simulation.
121
+ */
122
+ public async publicKernelCircuitTail(
123
+ input: PublicKernelTailCircuitPrivateInputs,
124
+ ): Promise<KernelCircuitPublicInputs> {
125
+ const inputWitness = convertPublicTailInputsToWitnessMap(input);
126
+ const [duration, witness] = await elapsed(() =>
127
+ this.wasmSimulator.simulateCircuit(inputWitness, PublicKernelTailArtifact),
128
+ );
129
+ const result = convertPublicTailOutputFromWitnessMap(witness);
130
+ this.log.debug(`Simulated public kernel tail circuit`, {
131
+ eventName: 'circuit-simulation',
132
+ circuitName: 'public-kernel-tail',
133
+ duration,
134
+ inputSize: input.toBuffer().length,
135
+ outputSize: result.toBuffer().length,
136
+ } satisfies CircuitSimulationStats);
137
+ return result;
138
+ }
139
+ }
@@ -0,0 +1,36 @@
1
+ import {
2
+ type KernelCircuitPublicInputs,
3
+ type PublicKernelCircuitPrivateInputs,
4
+ type PublicKernelCircuitPublicInputs,
5
+ type PublicKernelTailCircuitPrivateInputs,
6
+ } from '@aztec/circuits.js';
7
+
8
+ /**
9
+ * Circuit simulator for the public kernel circuits.
10
+ */
11
+ export interface PublicKernelCircuitSimulator {
12
+ /**
13
+ * Simulates the public kernel setup circuit from its inputs.
14
+ * @param inputs - Inputs to the circuit.
15
+ * @returns The public inputs as outputs of the simulation.
16
+ */
17
+ publicKernelCircuitSetup(inputs: PublicKernelCircuitPrivateInputs): Promise<PublicKernelCircuitPublicInputs>;
18
+ /**
19
+ * Simulates the public kernel app logic circuit from its inputs.
20
+ * @param inputs - Inputs to the circuit.
21
+ * @returns The public inputs as outputs of the simulation.
22
+ */
23
+ publicKernelCircuitAppLogic(inputs: PublicKernelCircuitPrivateInputs): Promise<PublicKernelCircuitPublicInputs>;
24
+ /**
25
+ * Simulates the public kernel teardown circuit from its inputs.
26
+ * @param inputs - Inputs to the circuit.
27
+ * @returns The public inputs as outputs of the simulation.
28
+ */
29
+ publicKernelCircuitTeardown(inputs: PublicKernelCircuitPrivateInputs): Promise<PublicKernelCircuitPublicInputs>;
30
+ /**
31
+ * Simulates the public kernel tail circuit from its inputs.
32
+ * @param inputs - Inputs to the circuit.
33
+ * @returns The public inputs as outputs of the simulation.
34
+ */
35
+ publicKernelCircuitTail(inputs: PublicKernelTailCircuitPrivateInputs): Promise<KernelCircuitPublicInputs>;
36
+ }
@@ -0,0 +1,212 @@
1
+ import {
2
+ type BlockProver,
3
+ type FailedTx,
4
+ type ProcessedTx,
5
+ type PublicKernelRequest,
6
+ type SimulationError,
7
+ Tx,
8
+ type TxValidator,
9
+ makeEmptyProcessedTx,
10
+ makeProcessedTx,
11
+ toTxEffect,
12
+ validateProcessedTx,
13
+ } from '@aztec/circuit-types';
14
+ import { type TxSequencerProcessingStats } from '@aztec/circuit-types/stats';
15
+ import { type GlobalVariables, type Header, type KernelCircuitPublicInputs } from '@aztec/circuits.js';
16
+ import { type ProcessReturnValues } from '@aztec/foundation/abi';
17
+ import { createDebugLogger } from '@aztec/foundation/log';
18
+ import { Timer } from '@aztec/foundation/timer';
19
+ import { PublicExecutor, type PublicStateDB, type SimulationProvider } from '@aztec/simulator';
20
+ import { type ContractDataSource } from '@aztec/types/contracts';
21
+ import { type MerkleTreeOperations } from '@aztec/world-state';
22
+
23
+ import { type AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js';
24
+ import { PhaseManagerFactory } from './phase_manager_factory.js';
25
+ import { ContractsDataSourcePublicDB, WorldStateDB, WorldStatePublicDB } from './public_executor.js';
26
+ import { RealPublicKernelCircuitSimulator } from './public_kernel.js';
27
+ import { type PublicKernelCircuitSimulator } from './public_kernel_circuit_simulator.js';
28
+
29
+ /**
30
+ * Creates new instances of PublicProcessor given the provided merkle tree db and contract data source.
31
+ */
32
+ export class PublicProcessorFactory {
33
+ constructor(
34
+ private merkleTree: MerkleTreeOperations,
35
+ private contractDataSource: ContractDataSource,
36
+ private simulator: SimulationProvider,
37
+ ) {}
38
+
39
+ /**
40
+ * Creates a new instance of a PublicProcessor.
41
+ * @param historicalHeader - The header of a block previous to the one in which the tx is included.
42
+ * @param globalVariables - The global variables for the block being processed.
43
+ * @param newContracts - Provides access to contract bytecode for public executions.
44
+ * @returns A new instance of a PublicProcessor.
45
+ */
46
+ public async create(
47
+ historicalHeader: Header | undefined,
48
+ globalVariables: GlobalVariables,
49
+ ): Promise<PublicProcessor> {
50
+ historicalHeader = historicalHeader ?? (await this.merkleTree.buildInitialHeader());
51
+
52
+ const publicContractsDB = new ContractsDataSourcePublicDB(this.contractDataSource);
53
+ const worldStatePublicDB = new WorldStatePublicDB(this.merkleTree);
54
+ const worldStateDB = new WorldStateDB(this.merkleTree);
55
+ const publicExecutor = new PublicExecutor(worldStatePublicDB, publicContractsDB, worldStateDB, historicalHeader);
56
+ return new PublicProcessor(
57
+ this.merkleTree,
58
+ publicExecutor,
59
+ new RealPublicKernelCircuitSimulator(this.simulator),
60
+ globalVariables,
61
+ historicalHeader,
62
+ publicContractsDB,
63
+ worldStatePublicDB,
64
+ );
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Converts Txs lifted from the P2P module into ProcessedTx objects by executing
70
+ * any public function calls in them. Txs with private calls only are unaffected.
71
+ */
72
+ export class PublicProcessor {
73
+ constructor(
74
+ protected db: MerkleTreeOperations,
75
+ protected publicExecutor: PublicExecutor,
76
+ protected publicKernel: PublicKernelCircuitSimulator,
77
+ protected globalVariables: GlobalVariables,
78
+ protected historicalHeader: Header,
79
+ protected publicContractsDB: ContractsDataSourcePublicDB,
80
+ protected publicStateDB: PublicStateDB,
81
+
82
+ private log = createDebugLogger('aztec:sequencer:public-processor'),
83
+ ) {}
84
+
85
+ /**
86
+ * Run each tx through the public circuit and the public kernel circuit if needed.
87
+ * @param txs - Txs to process.
88
+ * @returns The list of processed txs with their circuit simulation outputs.
89
+ */
90
+ public async process(
91
+ txs: Tx[],
92
+ maxTransactions = txs.length,
93
+ blockProver?: BlockProver,
94
+ txValidator?: TxValidator<ProcessedTx>,
95
+ ): Promise<[ProcessedTx[], FailedTx[], ProcessReturnValues[]]> {
96
+ // The processor modifies the tx objects in place, so we need to clone them.
97
+ txs = txs.map(tx => Tx.clone(tx));
98
+ const result: ProcessedTx[] = [];
99
+ const failed: FailedTx[] = [];
100
+ const returns: ProcessReturnValues[] = [];
101
+
102
+ for (const tx of txs) {
103
+ // only process up to the limit of the block
104
+ if (result.length >= maxTransactions) {
105
+ break;
106
+ }
107
+ try {
108
+ const [processedTx, returnValues] = !tx.hasPublicCalls()
109
+ ? [makeProcessedTx(tx, tx.data.toKernelCircuitPublicInputs(), tx.proof, [])]
110
+ : await this.processTxWithPublicCalls(tx);
111
+ validateProcessedTx(processedTx);
112
+ // Re-validate the transaction
113
+ if (txValidator) {
114
+ // Only accept processed transactions that are not double-spends,
115
+ // public functions emitting nullifiers would pass earlier check but fail here.
116
+ // Note that we're checking all nullifiers generated in the private execution twice,
117
+ // we could store the ones already checked and skip them here as an optimization.
118
+ const [_, invalid] = await txValidator.validateTxs([processedTx]);
119
+ if (invalid.length) {
120
+ throw new Error(`Transaction ${invalid[0].hash} invalid after processing public functions`);
121
+ }
122
+ }
123
+ // if we were given a prover then send the transaction to it for proving
124
+ if (blockProver) {
125
+ await blockProver.addNewTx(processedTx);
126
+ }
127
+ result.push(processedTx);
128
+ returns.push(returnValues);
129
+ } catch (err: any) {
130
+ const errorMessage = err instanceof Error ? err.message : 'Unknown error';
131
+ this.log.warn(`Failed to process tx ${tx.getTxHash()}: ${errorMessage}`);
132
+
133
+ failed.push({
134
+ tx,
135
+ error: err instanceof Error ? err : new Error(errorMessage),
136
+ });
137
+ returns.push([]);
138
+ }
139
+ }
140
+
141
+ return [result, failed, returns];
142
+ }
143
+
144
+ /**
145
+ * Makes an empty processed tx. Useful for padding a block to a power of two number of txs.
146
+ * @returns A processed tx with empty data.
147
+ */
148
+ public makeEmptyProcessedTx(): ProcessedTx {
149
+ const { chainId, version } = this.globalVariables;
150
+ return makeEmptyProcessedTx(this.historicalHeader.clone(), chainId, version);
151
+ }
152
+
153
+ private async processTxWithPublicCalls(tx: Tx): Promise<[ProcessedTx, ProcessReturnValues | undefined]> {
154
+ let returnValues: ProcessReturnValues = undefined;
155
+ const publicRequests: PublicKernelRequest[] = [];
156
+ let phase: AbstractPhaseManager | undefined = PhaseManagerFactory.phaseFromTx(
157
+ tx,
158
+ this.db,
159
+ this.publicExecutor,
160
+ this.publicKernel,
161
+ this.globalVariables,
162
+ this.historicalHeader,
163
+ this.publicContractsDB,
164
+ this.publicStateDB,
165
+ );
166
+ this.log.debug(`Beginning processing in phase ${phase?.phase} for tx ${tx.getTxHash()}`);
167
+ let proof = tx.proof;
168
+ let publicKernelPublicInput = tx.data.toPublicKernelCircuitPublicInputs();
169
+ let finalKernelOutput: KernelCircuitPublicInputs | undefined;
170
+ let revertReason: SimulationError | undefined;
171
+ const timer = new Timer();
172
+ while (phase) {
173
+ const output = await phase.handle(tx, publicKernelPublicInput, proof);
174
+ if (phase.phase === PublicKernelPhase.APP_LOGIC) {
175
+ returnValues = output.returnValues;
176
+ }
177
+ publicRequests.push(...output.kernelRequests);
178
+ publicKernelPublicInput = output.publicKernelOutput;
179
+ finalKernelOutput = output.finalKernelOutput;
180
+ proof = output.publicKernelProof;
181
+ revertReason ??= output.revertReason;
182
+ phase = PhaseManagerFactory.phaseFromOutput(
183
+ publicKernelPublicInput,
184
+ phase,
185
+ this.db,
186
+ this.publicExecutor,
187
+ this.publicKernel,
188
+ this.globalVariables,
189
+ this.historicalHeader,
190
+ this.publicContractsDB,
191
+ this.publicStateDB,
192
+ );
193
+ }
194
+
195
+ if (!finalKernelOutput) {
196
+ throw new Error('Final public kernel was not executed.');
197
+ }
198
+
199
+ const processedTx = makeProcessedTx(tx, finalKernelOutput, proof, publicRequests, revertReason);
200
+
201
+ this.log.debug(`Processed public part of ${tx.getTxHash()}`, {
202
+ eventName: 'tx-sequencer-processing',
203
+ duration: timer.ms(),
204
+ effectsSize: toTxEffect(processedTx).toBuffer().length,
205
+ publicDataUpdateRequests:
206
+ processedTx.data.end.publicDataUpdateRequests.filter(x => !x.leafSlot.isZero()).length ?? 0,
207
+ ...tx.getStats(),
208
+ } satisfies TxSequencerProcessingStats);
209
+
210
+ return [processedTx, returnValues];
211
+ }
212
+ }