Skip to content

Commit 1c4f126

Browse files
committed
refactor(pxe): decompose PXEOracleInterface
Deprecate `PXEOracleInterface` in favor of more granular and explicit dependencies. I apologize in advance for the length of this PR, the commits show the progression that led to this final form, and prove that the end result didn't come to me OTOH, but it was the result of dozens of stepwise refactors. At the current state it is possible to spin multiple little PRs off this one if that's deemed saner, it just wasn't clear that would be the case when I originally set out to do this. ## New service layer To replace `PXEOracleInterface` (aka `ExecutionDataProvider`), and at the same time keep oracle classes relatively lean and concerns separated, I'm introducing a service layer on top of the existing providers layer. Due to this PR being big enough as is, and there being more pressing issues to address, I'm not applying this idea to completion, just using it where it helps me untangle things. I do think going further in this direction would help make everything be more unit testable. The core rules of thumb behind this (long term) are: - Providers shouldn't talk to each other. This is a simplicity forcing function. Providers are database abstractions. - Services can talk to each other, and to the provider(s) they encapsulate. Each provider should only be accessed by one service, but one service can manage multiple data providers. So: services get other read/write data needs met by talking to other services. - The rest of the app talks to services instead of directly to providers. Again, I'm not tackling that here because the PR is big enough as is, but it's an architecture we could slowly move towards. ## Capsules as plumbing Something that became clear along the way of this refactor is that capsule state management in many cases is a transport concern, and as such code becomes much more cohesive if we separate the code that deals with that, from the code that actually operates on the contents. Maybe the nicest example of that can be seen in `utilityBulkRetrieveLogs`. ## Working with Anchor blocks I think most of the places where we now consume `AnchorBlockDataProvider` to get the current anchor block, should be modified to instead receive the anchor block as param, which will make it easier to see that in reality the anchor block is pinned for a given `ContractFunctionSimulator` activation. That, in turn, should make the work on DB integrity easier, and it will also be helpful to eventually adopt a less conservative approach towards concurrency. ## Temporary complexity increase (waiting for new tagging sync work) There are some parts of the app that might look a bit more convoluted with this refactor, mostly due to porting sync tagging functionality to make things compile and pass tests. Note that @benesjan is overhauling sync tagging, so I'm deliberately not investing effort on simplifying those parts and will instead wait and see what's necessary once that work is available. Some specific cases of this situation are found on: - Test setup of `oracle_version_is_checked.test.ts`: it got much more complex given `ContractFunctionSimulator` now receives all the data providers it needs to operate instead of hiding everything under `PXEOracleInterface`. A lot of this complexity is probably derived from the old tag sync'ing logic and I'm expecting it to just disintegrate. - `private_execution.test.ts`: I'm hoping a lot of the boilerplate will be unnecessary once the new work on tagging lands. - `LogService` and its tests Fixes #17776
1 parent 1776329 commit 1c4f126

35 files changed

+2848
-2677
lines changed

yarn-project/pxe/src/contract_function_simulator/contract_function_simulator.ts

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { poseidon2Hash } from '@aztec/foundation/crypto/poseidon';
2121
import { Fr } from '@aztec/foundation/curves/bn254';
2222
import { type Logger, createLogger } from '@aztec/foundation/log';
2323
import { Timer } from '@aztec/foundation/timer';
24+
import type { KeyStore } from '@aztec/key-store';
2425
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
2526
import { protocolContractsHash } from '@aztec/protocol-contracts';
2627
import {
@@ -44,6 +45,7 @@ import {
4445
siloNoteHash,
4546
siloNullifier,
4647
} from '@aztec/stdlib/hash';
48+
import type { AztecNode } from '@aztec/stdlib/interfaces/server';
4749
import {
4850
PartialPrivateTailPublicInputsForPublic,
4951
PartialPrivateTailPublicInputsForRollup,
@@ -69,15 +71,22 @@ import {
6971
getFinalMinRevertibleSideEffectCounter,
7072
} from '@aztec/stdlib/tx';
7173

72-
import type { ContractDataProvider } from '../storage/index.js';
73-
import type { ExecutionDataProvider } from './execution_data_provider.js';
74+
import type { AddressDataProvider } from '../storage/address_data_provider/address_data_provider.js';
75+
import type { AnchorBlockDataProvider } from '../storage/anchor_block_data_provider/anchor_block_data_provider.js';
76+
import type { CapsuleDataProvider } from '../storage/capsule_data_provider/capsule_data_provider.js';
77+
import type { ContractDataProvider } from '../storage/contract_data_provider/contract_data_provider.js';
78+
import type { NoteDataProvider } from '../storage/note_data_provider/note_data_provider.js';
79+
import type { PrivateEventDataProvider } from '../storage/private_event_data_provider/private_event_data_provider.js';
80+
import type { RecipientTaggingDataProvider } from '../storage/tagging_data_provider/recipient_tagging_data_provider.js';
81+
import type { SenderTaggingDataProvider } from '../storage/tagging_data_provider/sender_tagging_data_provider.js';
7482
import { ExecutionNoteCache } from './execution_note_cache.js';
7583
import { ExecutionTaggingIndexCache } from './execution_tagging_index_cache.js';
7684
import { HashedValuesCache } from './hashed_values_cache.js';
7785
import { Oracle } from './oracle/oracle.js';
7886
import { executePrivateFunction, verifyCurrentClassId } from './oracle/private_execution.js';
7987
import { PrivateExecutionOracle } from './oracle/private_execution_oracle.js';
8088
import { UtilityExecutionOracle } from './oracle/utility_execution_oracle.js';
89+
import type { ProxiedNode } from './proxied_node.js';
8190

8291
/**
8392
* The contract function simulator.
@@ -86,7 +95,16 @@ export class ContractFunctionSimulator {
8695
private log: Logger;
8796

8897
constructor(
89-
private executionDataProvider: ExecutionDataProvider,
98+
private contractDataProvider: ContractDataProvider,
99+
private noteDataProvider: NoteDataProvider,
100+
private keyStore: KeyStore,
101+
private addressDataProvider: AddressDataProvider,
102+
private aztecNode: AztecNode,
103+
private anchorBlockDataProvider: AnchorBlockDataProvider,
104+
private senderTaggingDataProvider: SenderTaggingDataProvider,
105+
private recipientTaggingDataProvider: RecipientTaggingDataProvider,
106+
private capsuleDataProvider: CapsuleDataProvider,
107+
private privateEventDataProvider: PrivateEventDataProvider,
90108
private simulator: CircuitSimulator,
91109
) {
92110
this.log = createLogger('simulator');
@@ -116,9 +134,12 @@ export class ContractFunctionSimulator {
116134
): Promise<PrivateExecutionResult> {
117135
const simulatorSetupTimer = new Timer();
118136

119-
await verifyCurrentClassId(contractAddress, this.executionDataProvider, anchorBlockHeader);
137+
await verifyCurrentClassId(contractAddress, this.aztecNode, this.contractDataProvider, anchorBlockHeader);
120138

121-
const entryPointArtifact = await this.executionDataProvider.getFunctionArtifact(contractAddress, selector);
139+
const entryPointArtifact = await this.contractDataProvider.getFunctionArtifactWithDebugMetadata(
140+
contractAddress,
141+
selector,
142+
);
122143

123144
if (entryPointArtifact.functionType !== FunctionType.PRIVATE) {
124145
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as private`);
@@ -154,7 +175,16 @@ export class ContractFunctionSimulator {
154175
HashedValuesCache.create(request.argsOfCalls),
155176
noteCache,
156177
taggingIndexCache,
157-
this.executionDataProvider,
178+
this.contractDataProvider,
179+
this.noteDataProvider,
180+
this.keyStore,
181+
this.addressDataProvider,
182+
this.aztecNode,
183+
this.anchorBlockDataProvider,
184+
this.senderTaggingDataProvider,
185+
this.recipientTaggingDataProvider,
186+
this.capsuleDataProvider,
187+
this.privateEventDataProvider,
158188
0, // totalPublicArgsCount
159189
startSideEffectCounter,
160190
undefined, // log
@@ -226,9 +256,12 @@ export class ContractFunctionSimulator {
226256
anchorBlockHeader: BlockHeader,
227257
scopes?: AztecAddress[],
228258
): Promise<Fr[]> {
229-
await verifyCurrentClassId(call.to, this.executionDataProvider, anchorBlockHeader);
259+
await verifyCurrentClassId(call.to, this.aztecNode, this.contractDataProvider, anchorBlockHeader);
230260

231-
const entryPointArtifact = await this.executionDataProvider.getFunctionArtifact(call.to, call.selector);
261+
const entryPointArtifact = await this.contractDataProvider.getFunctionArtifactWithDebugMetadata(
262+
call.to,
263+
call.selector,
264+
);
232265

233266
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
234267
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
@@ -239,7 +272,16 @@ export class ContractFunctionSimulator {
239272
authwits,
240273
[],
241274
anchorBlockHeader,
242-
this.executionDataProvider,
275+
this.contractDataProvider,
276+
this.noteDataProvider,
277+
this.keyStore,
278+
this.addressDataProvider,
279+
this.aztecNode,
280+
this.anchorBlockDataProvider,
281+
this.senderTaggingDataProvider,
282+
this.recipientTaggingDataProvider,
283+
this.capsuleDataProvider,
284+
this.privateEventDataProvider,
243285
undefined,
244286
scopes,
245287
);
@@ -274,8 +316,15 @@ export class ContractFunctionSimulator {
274316
}
275317
// docs:end:execute_utility_function
276318

319+
/**
320+
* Returns the execution statistics collected during the simulator run.
321+
* @returns The execution statistics.
322+
*/
277323
getStats() {
278-
return this.executionDataProvider.getStats();
324+
const nodeRPCCalls =
325+
typeof (this.aztecNode as ProxiedNode).getStats === 'function' ? (this.aztecNode as ProxiedNode).getStats() : {};
326+
327+
return { nodeRPCCalls };
279328
}
280329
}
281330

0 commit comments

Comments
 (0)