diff --git a/docs/docs/aztec/smart_contracts/functions/attributes.md b/docs/docs/aztec/smart_contracts/functions/attributes.md index c4cdc2b23f83..d958d4740897 100644 --- a/docs/docs/aztec/smart_contracts/functions/attributes.md +++ b/docs/docs/aztec/smart_contracts/functions/attributes.md @@ -86,7 +86,7 @@ When an unconstrained function is called, it prompts the ACIR simulator to 1. generate the execution environment 2. execute the function within this environment -To generate the environment, the simulator gets the blockheader from the [PXE database](../../concepts/pxe/index.md#database) and passes it along with the contract address to `ViewDataOracle`. This creates a context that simulates the state of the blockchain at a specific block, allowing the unconstrained function to access and interact with blockchain data as it would appear in that block, but without affecting the actual blockchain state. +To generate the environment, the simulator gets the blockheader from the [PXE database](../../concepts/pxe/index.md#database) and passes it along with the contract address to `UnconstrainedExecutionOracle`. This creates a context that simulates the state of the blockchain at a specific block, allowing the unconstrained function to access and interact with blockchain data as it would appear in that block, but without affecting the actual blockchain state. Once the execution environment is created, `execute_unconstrained_function` is invoked: diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index e73fa04e14b7..4b5bc2519b68 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -814,7 +814,7 @@ export class AztecNodeService implements AztecNode, Traceable { * @param blockNumber - The block number at which to get the data or 'latest'. * @returns Storage value at the given contract slot. */ - public async getPublicStorageAt(contract: AztecAddress, slot: Fr, blockNumber: L2BlockNumber): Promise { + public async getPublicStorageAt(blockNumber: L2BlockNumber, contract: AztecAddress, slot: Fr): Promise { const committedDb = await this.#getWorldState(blockNumber); const leafSlot = await computePublicDataTreeLeafSlot(contract, slot); diff --git a/yarn-project/pxe/src/contract_data_oracle/index.ts b/yarn-project/pxe/src/contract_data_provider/contract_data_provider.ts similarity index 96% rename from yarn-project/pxe/src/contract_data_oracle/index.ts rename to yarn-project/pxe/src/contract_data_provider/contract_data_provider.ts index 6c5166efca4f..a6003000942d 100644 --- a/yarn-project/pxe/src/contract_data_oracle/index.ts +++ b/yarn-project/pxe/src/contract_data_provider/contract_data_provider.ts @@ -11,18 +11,18 @@ import { import type { AztecAddress } from '@aztec/stdlib/aztec-address'; import type { ContractClass, ContractInstance } from '@aztec/stdlib/contract'; -import type { ContractArtifactDatabase } from '../database/contracts/contract_artifact_db.js'; -import type { ContractInstanceDatabase } from '../database/contracts/contract_instance_db.js'; +import type { ContractArtifactDatabase } from '../database/interfaces/contract_artifact_db.js'; +import type { ContractInstanceDatabase } from '../database/interfaces/contract_instance_db.js'; import { PrivateFunctionsTree } from './private_functions_tree.js'; /** - * ContractDataOracle serves as a data manager and retriever for Aztec.nr contracts. + * ContractDataProvider serves as a data manager and retriever for Aztec.nr contracts. * It provides methods to obtain contract addresses, function ABI, bytecode, and membership witnesses * from a given contract address and function selector. The class maintains a cache of ContractTree instances * to efficiently serve the requested data. It interacts with the ContractDatabase and AztecNode to fetch * the required information and facilitate cryptographic proof generation. */ -export class ContractDataOracle { +export class ContractDataProvider { /** Map from contract class id to private function tree. */ private contractClasses: Map = new Map(); diff --git a/yarn-project/pxe/src/contract_data_provider/index.ts b/yarn-project/pxe/src/contract_data_provider/index.ts new file mode 100644 index 000000000000..ed2797ed6f8b --- /dev/null +++ b/yarn-project/pxe/src/contract_data_provider/index.ts @@ -0,0 +1,2 @@ +export { ContractDataProvider } from './contract_data_provider.js'; +export { PrivateFunctionsTree } from './private_functions_tree.js'; diff --git a/yarn-project/pxe/src/contract_data_oracle/private_functions_tree.ts b/yarn-project/pxe/src/contract_data_provider/private_functions_tree.ts similarity index 100% rename from yarn-project/pxe/src/contract_data_oracle/private_functions_tree.ts rename to yarn-project/pxe/src/contract_data_provider/private_functions_tree.ts diff --git a/yarn-project/pxe/src/database/index.ts b/yarn-project/pxe/src/database/index.ts index e01c18032417..933d0356eed1 100644 --- a/yarn-project/pxe/src/database/index.ts +++ b/yarn-project/pxe/src/database/index.ts @@ -1,2 +1,2 @@ -export * from './pxe_database.js'; export * from './kv_pxe_database.js'; +export * from './interfaces/index.js'; diff --git a/yarn-project/pxe/src/database/contracts/contract_artifact_db.ts b/yarn-project/pxe/src/database/interfaces/contract_artifact_db.ts similarity index 100% rename from yarn-project/pxe/src/database/contracts/contract_artifact_db.ts rename to yarn-project/pxe/src/database/interfaces/contract_artifact_db.ts diff --git a/yarn-project/pxe/src/database/contracts/contract_instance_db.ts b/yarn-project/pxe/src/database/interfaces/contract_instance_db.ts similarity index 100% rename from yarn-project/pxe/src/database/contracts/contract_instance_db.ts rename to yarn-project/pxe/src/database/interfaces/contract_instance_db.ts diff --git a/yarn-project/pxe/src/database/interfaces/index.ts b/yarn-project/pxe/src/database/interfaces/index.ts new file mode 100644 index 000000000000..1a772fe87508 --- /dev/null +++ b/yarn-project/pxe/src/database/interfaces/index.ts @@ -0,0 +1,3 @@ +export type { ContractArtifactDatabase } from './contract_artifact_db.js'; +export type { ContractInstanceDatabase } from './contract_instance_db.js'; +export type { PxeDatabase } from './pxe_database.js'; diff --git a/yarn-project/pxe/src/database/pxe_database.ts b/yarn-project/pxe/src/database/interfaces/pxe_database.ts similarity index 97% rename from yarn-project/pxe/src/database/pxe_database.ts rename to yarn-project/pxe/src/database/interfaces/pxe_database.ts index e7f035edf0e3..ccb000397b7c 100644 --- a/yarn-project/pxe/src/database/pxe_database.ts +++ b/yarn-project/pxe/src/database/interfaces/pxe_database.ts @@ -8,9 +8,9 @@ import type { IndexedTaggingSecret } from '@aztec/stdlib/logs'; import type { NotesFilter } from '@aztec/stdlib/note'; import type { BlockHeader } from '@aztec/stdlib/tx'; -import type { ContractArtifactDatabase } from './contracts/contract_artifact_db.js'; -import type { ContractInstanceDatabase } from './contracts/contract_instance_db.js'; -import type { NoteDao } from './note_dao.js'; +import type { NoteDao } from '../note_dao.js'; +import type { ContractArtifactDatabase } from './contract_artifact_db.js'; +import type { ContractInstanceDatabase } from './contract_instance_db.js'; /** * A database interface that provides methods for retrieving, adding, and removing transactional data related to Aztec diff --git a/yarn-project/pxe/src/database/pxe_database_test_suite.ts b/yarn-project/pxe/src/database/interfaces/pxe_database_test_suite.ts similarity index 99% rename from yarn-project/pxe/src/database/pxe_database_test_suite.ts rename to yarn-project/pxe/src/database/interfaces/pxe_database_test_suite.ts index 1e4653a13dd8..f6ae11547613 100644 --- a/yarn-project/pxe/src/database/pxe_database_test_suite.ts +++ b/yarn-project/pxe/src/database/interfaces/pxe_database_test_suite.ts @@ -13,7 +13,7 @@ import { makeHeader, randomTxHash } from '@aztec/stdlib/testing'; import times from 'lodash.times'; -import { NoteDao } from './note_dao.js'; +import { NoteDao } from '../note_dao.js'; import type { PxeDatabase } from './pxe_database.js'; /** diff --git a/yarn-project/pxe/src/database/kv_pxe_database.test.ts b/yarn-project/pxe/src/database/kv_pxe_database.test.ts index 613a55200d81..294f219fa628 100644 --- a/yarn-project/pxe/src/database/kv_pxe_database.test.ts +++ b/yarn-project/pxe/src/database/kv_pxe_database.test.ts @@ -1,7 +1,7 @@ import { openTmpStore } from '@aztec/kv-store/lmdb-v2'; +import { describePxeDatabase } from './interfaces/pxe_database_test_suite.js'; import { KVPxeDatabase } from './kv_pxe_database.js'; -import { describePxeDatabase } from './pxe_database_test_suite.js'; describe('KVPxeDatabase', () => { let database: KVPxeDatabase; diff --git a/yarn-project/pxe/src/database/kv_pxe_database.ts b/yarn-project/pxe/src/database/kv_pxe_database.ts index 7fc685ec207e..55b7a086b0a1 100644 --- a/yarn-project/pxe/src/database/kv_pxe_database.ts +++ b/yarn-project/pxe/src/database/kv_pxe_database.ts @@ -24,8 +24,8 @@ import { NoteStatus, type NotesFilter } from '@aztec/stdlib/note'; import { MerkleTreeId } from '@aztec/stdlib/trees'; import { BlockHeader } from '@aztec/stdlib/tx'; +import type { PxeDatabase } from './interfaces/pxe_database.js'; import { NoteDao } from './note_dao.js'; -import type { PxeDatabase } from './pxe_database.js'; /** * A PXE database backed by LMDB. diff --git a/yarn-project/pxe/src/database/outgoing_note_dao.ts b/yarn-project/pxe/src/database/outgoing_note_dao.ts deleted file mode 100644 index 6b2a8d905648..000000000000 --- a/yarn-project/pxe/src/database/outgoing_note_dao.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; -import { Fr, Point } from '@aztec/foundation/fields'; -import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; -import { NoteSelector } from '@aztec/stdlib/abi'; -import { AztecAddress } from '@aztec/stdlib/aztec-address'; -import type { PublicKey } from '@aztec/stdlib/keys'; -import { Note } from '@aztec/stdlib/note'; -import { TxHash } from '@aztec/stdlib/tx'; - -/** - * A note with contextual data which was decrypted as outgoing. - */ -export class OutgoingNoteDao { - constructor( - /** The note as emitted from the Noir contract. */ - public note: Note, - /** The contract address this note is created in. */ - public contractAddress: AztecAddress, - /** The specific storage location of the note on the contract. */ - public storageSlot: Fr, - /** The note type identifier for the contract. */ - public noteTypeId: NoteSelector, - /** The hash of the tx the note was created in. */ - public txHash: TxHash, - /** The L2 block number in which the tx with this note was included. */ - public l2BlockNumber: number, - /** The L2 block hash in which the tx with this note was included. */ - public l2BlockHash: string, - /** The nonce of the note. */ - public nonce: Fr, - /** - * A hash of the note. This is customizable by the app circuit. - * We can use this value to compute unique note hash and then siloed note hash. - */ - public noteHash: Fr, - /** The location of the relevant note in the note hash tree. */ - public index: bigint, - /** The public key with which the note was encrypted. */ - public ovpkM: PublicKey, - ) {} - - toBuffer(): Buffer { - return serializeToBuffer([ - this.note, - this.contractAddress, - this.storageSlot, - this.noteTypeId, - this.txHash, - this.l2BlockNumber, - Fr.fromHexString(this.l2BlockHash), - this.nonce, - this.noteHash, - this.index, - this.ovpkM, - ]); - } - static fromBuffer(buffer: Buffer | BufferReader) { - const reader = BufferReader.asReader(buffer); - - const note = Note.fromBuffer(reader); - const contractAddress = AztecAddress.fromBuffer(reader); - const storageSlot = Fr.fromBuffer(reader); - const noteTypeId = reader.readObject(NoteSelector); - const txHash = reader.readObject(TxHash); - const l2BlockNumber = reader.readNumber(); - const l2BlockHash = Fr.fromBuffer(reader).toString(); - const nonce = Fr.fromBuffer(reader); - const noteHash = Fr.fromBuffer(reader); - const index = toBigIntBE(reader.readBytes(32)); - const publicKey = Point.fromBuffer(reader); - - return new OutgoingNoteDao( - note, - contractAddress, - storageSlot, - noteTypeId, - txHash, - l2BlockNumber, - l2BlockHash, - nonce, - noteHash, - index, - publicKey, - ); - } - - toString() { - return '0x' + this.toBuffer().toString('hex'); - } - - static fromString(str: string) { - const hex = str.replace(/^0x/, ''); - return OutgoingNoteDao.fromBuffer(Buffer.from(hex, 'hex')); - } - - /** - * Returns the size in bytes of the Note Dao. - * @returns - Its size in bytes. - */ - public getSize() { - const noteSize = 4 + this.note.items.length * Fr.SIZE_IN_BYTES; - return noteSize + AztecAddress.SIZE_IN_BYTES + Fr.SIZE_IN_BYTES * 2 + TxHash.SIZE + Point.SIZE_IN_BYTES; - } - - static async random({ - note = Note.random(), - contractAddress = undefined, - txHash = TxHash.random(), - storageSlot = Fr.random(), - noteTypeId = NoteSelector.random(), - nonce = Fr.random(), - l2BlockNumber = Math.floor(Math.random() * 1000), - l2BlockHash = Fr.random().toString(), - noteHash = Fr.random(), - index = Fr.random().toBigInt(), - ovpkM = undefined, - }: Partial = {}) { - return new OutgoingNoteDao( - note, - contractAddress ?? (await AztecAddress.random()), - storageSlot, - noteTypeId, - txHash, - l2BlockNumber, - l2BlockHash, - nonce, - noteHash, - index, - ovpkM ?? (await Point.random()), - ); - } -} diff --git a/yarn-project/pxe/src/index.ts b/yarn-project/pxe/src/index.ts index f6144626be4b..950af4ae067a 100644 --- a/yarn-project/pxe/src/index.ts +++ b/yarn-project/pxe/src/index.ts @@ -5,6 +5,5 @@ export * from './config/index.js'; export * from './utils/create_pxe_service.js'; export * from './database/index.js'; -export { ContractDataOracle } from './contract_data_oracle/index.js'; -export { PrivateFunctionsTree } from './contract_data_oracle/private_functions_tree.js'; -export { SimulatorOracle } from './simulator_oracle/index.js'; +export { PXEDataProvider } from './pxe_data_provider/index.js'; +export * from './contract_data_provider/index.js'; diff --git a/yarn-project/pxe/src/kernel_oracle/index.ts b/yarn-project/pxe/src/kernel_oracle/index.ts index 00c9409b7977..72da149e1e2b 100644 --- a/yarn-project/pxe/src/kernel_oracle/index.ts +++ b/yarn-project/pxe/src/kernel_oracle/index.ts @@ -17,7 +17,7 @@ import { SharedMutableValues, SharedMutableValuesWithHash } from '@aztec/stdlib/ import type { NullifierMembershipWitness } from '@aztec/stdlib/trees'; import type { VerificationKeyAsFields } from '@aztec/stdlib/vks'; -import type { ContractDataOracle } from '../contract_data_oracle/index.js'; +import type { ContractDataProvider } from '../contract_data_provider/index.js'; import type { ProvingDataOracle } from './../kernel_prover/proving_data_oracle.js'; // TODO: Block number should not be "latest". @@ -27,7 +27,7 @@ import type { ProvingDataOracle } from './../kernel_prover/proving_data_oracle.j */ export class KernelOracle implements ProvingDataOracle { constructor( - private contractDataOracle: ContractDataOracle, + private contractDataProvider: ContractDataProvider, private keyStore: KeyStore, private node: AztecNode, private blockNumber: L2BlockNumber = 'latest', @@ -35,7 +35,7 @@ export class KernelOracle implements ProvingDataOracle { ) {} public async getContractAddressPreimage(address: AztecAddress) { - const instance = await this.contractDataOracle.getContractInstance(address); + const instance = await this.contractDataProvider.getContractInstance(address); return { saltedInitializationHash: await computeSaltedInitializationHash(instance), ...instance, @@ -43,12 +43,12 @@ export class KernelOracle implements ProvingDataOracle { } public async getContractClassIdPreimage(contractClassId: Fr) { - const contractClass = await this.contractDataOracle.getContractClass(contractClassId); + const contractClass = await this.contractDataProvider.getContractClass(contractClassId); return computeContractClassIdPreimage(contractClass); } public async getFunctionMembershipWitness(contractClassId: Fr, selector: FunctionSelector) { - return await this.contractDataOracle.getFunctionMembershipWitness(contractClassId, selector); + return await this.contractDataProvider.getFunctionMembershipWitness(contractClassId, selector); } public getVkMembershipWitness(vk: VerificationKeyAsFields) { @@ -82,7 +82,7 @@ export class KernelOracle implements ProvingDataOracle { } public getDebugFunctionName(contractAddress: AztecAddress, selector: FunctionSelector): Promise { - return this.contractDataOracle.getDebugFunctionName(contractAddress, selector); + return this.contractDataProvider.getDebugFunctionName(contractAddress, selector); } public async getUpdatedClassIdHints(contractAddress: AztecAddress): Promise { @@ -101,7 +101,7 @@ export class KernelOracle implements ProvingDataOracle { } const readStorage = (storageSlot: Fr) => - this.node.getPublicStorageAt(ProtocolContractAddress.ContractInstanceDeployer, storageSlot, this.blockNumber); + this.node.getPublicStorageAt(this.blockNumber, ProtocolContractAddress.ContractInstanceDeployer, storageSlot); const sharedMutableValues = await SharedMutableValues.readFromTree(sharedMutableSlot, readStorage); return new UpdatedClassIdHints( diff --git a/yarn-project/pxe/src/note_decryption_utils/add_public_values_to_payload.ts b/yarn-project/pxe/src/note_decryption_utils/add_public_values_to_payload.ts index 6afae34f600d..17c911040fee 100644 --- a/yarn-project/pxe/src/note_decryption_utils/add_public_values_to_payload.ts +++ b/yarn-project/pxe/src/note_decryption_utils/add_public_values_to_payload.ts @@ -2,7 +2,7 @@ import { ContractNotFoundError } from '@aztec/simulator/client'; import type { L1NotePayload } from '@aztec/stdlib/logs'; import { Note } from '@aztec/stdlib/note'; -import type { PxeDatabase } from '../database/pxe_database.js'; +import type { PxeDatabase } from '../database/interfaces/pxe_database.js'; /** * Merges privately and publicly delivered note values. diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/pxe_data_provider/index.ts similarity index 95% rename from yarn-project/pxe/src/simulator_oracle/index.ts rename to yarn-project/pxe/src/pxe_data_provider/index.ts index 967544f00314..8a7374c67289 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/pxe_data_provider/index.ts @@ -10,7 +10,7 @@ import { Fr } from '@aztec/foundation/fields'; import { createLogger } from '@aztec/foundation/log'; import { BufferReader } from '@aztec/foundation/serialize'; import type { KeyStore } from '@aztec/key-store'; -import type { AcirSimulator, DBOracle, SimulationProvider } from '@aztec/simulator/client'; +import { AcirSimulator, type ExecutionDataProvider, type SimulationProvider } from '@aztec/simulator/client'; import { MessageLoadOracleInputs } from '@aztec/simulator/client'; import { type FunctionArtifact, @@ -42,24 +42,23 @@ import { MerkleTreeId, type NullifierMembershipWitness, PublicDataWitness } from import type { BlockHeader } from '@aztec/stdlib/tx'; import { TxHash } from '@aztec/stdlib/tx'; -import { ContractDataOracle } from '../contract_data_oracle/index.js'; +import { ContractDataProvider } from '../contract_data_provider/index.js'; import type { PxeDatabase } from '../database/index.js'; import { NoteDao } from '../database/note_dao.js'; import { getOrderedNoteItems } from '../note_decryption_utils/add_public_values_to_payload.js'; -import { getAcirSimulator } from '../simulator/index.js'; import { WINDOW_HALF_SIZE, getIndexedTaggingSecretsForTheWindow, getInitialIndexesMap } from './tagging_utils.js'; /** - * A data oracle that provides information needed for simulating a transaction. + * A data layer that provides and stores information needed for simulating/proving a transaction. */ -export class SimulatorOracle implements DBOracle { +export class PXEDataProvider implements ExecutionDataProvider { constructor( - private contractDataOracle: ContractDataOracle, private db: PxeDatabase, private keyStore: KeyStore, private aztecNode: AztecNode, private simulationProvider: SimulationProvider, - private log = createLogger('pxe:simulator_oracle'), + private contractDataProvider: ContractDataProvider, + private log = createLogger('pxe:pxe_data_provider'), ) {} getKeyValidationRequest(pkMHash: Fr, contractAddress: AztecAddress): Promise { @@ -113,8 +112,8 @@ export class SimulatorOracle implements DBOracle { } async getFunctionArtifact(contractAddress: AztecAddress, selector: FunctionSelector): Promise { - const artifact = await this.contractDataOracle.getFunctionArtifact(contractAddress, selector); - const debug = await this.contractDataOracle.getFunctionDebugMetadata(contractAddress, selector); + const artifact = await this.contractDataProvider.getFunctionArtifact(contractAddress, selector); + const debug = await this.contractDataProvider.getFunctionDebugMetadata(contractAddress, selector); return { ...artifact, debug, @@ -125,8 +124,8 @@ export class SimulatorOracle implements DBOracle { contractAddress: AztecAddress, functionName: string, ): Promise { - const instance = await this.contractDataOracle.getContractInstance(contractAddress); - const artifact = await this.contractDataOracle.getContractArtifact(instance.currentContractClassId); + const instance = await this.contractDataProvider.getContractInstance(contractAddress); + const artifact = await this.contractDataProvider.getContractArtifact(instance.currentContractClassId); return artifact && getFunctionArtifact(artifact, functionName); } @@ -234,6 +233,10 @@ export class SimulatorOracle implements DBOracle { return await this.aztecNode.getPublicDataTreeWitness(blockNumber, leafSlot); } + public async getPublicStorageAt(blockNumber: number, contract: AztecAddress, slot: Fr): Promise { + return await this.aztecNode.getPublicStorageAt(blockNumber, contract, slot); + } + /** * Retrieve the databases view of the Block Header object. * This structure is fed into the circuits simulator and is used to prove against certain historical roots. @@ -252,8 +255,24 @@ export class SimulatorOracle implements DBOracle { return await this.aztecNode.getBlockNumber(); } + /** + * Fetches the current chain id. + * @returns The chain id. + */ + public async getChainId(): Promise { + return await this.aztecNode.getChainId(); + } + + /** + * Fetches the current version. + * @returns The version. + */ + public async getVersion(): Promise { + return await this.aztecNode.getVersion(); + } + public getDebugFunctionName(contractAddress: AztecAddress, selector: FunctionSelector): Promise { - return this.contractDataOracle.getDebugFunctionName(contractAddress, selector); + return this.contractDataProvider.getDebugFunctionName(contractAddress, selector); } /** @@ -299,7 +318,7 @@ export class SimulatorOracle implements DBOracle { recipient: AztecAddress, ): Promise { const secret = await this.#calculateAppTaggingSecret(contractAddress, sender, recipient); - const contractName = await this.contractDataOracle.getDebugContractName(contractAddress); + const contractName = await this.contractDataProvider.getDebugContractName(contractAddress); this.log.debug(`Incrementing app tagging secret at ${contractName}(${contractAddress})`, { secret, sender, @@ -401,7 +420,7 @@ export class SimulatorOracle implements DBOracle { numConsecutiveEmptyLogs = WINDOW_SIZE - indexOfLastLog - 1; } while (numConsecutiveEmptyLogs < MIN_CONSECUTIVE_EMPTY_LOGS); - const contractName = await this.contractDataOracle.getDebugContractName(contractAddress); + const contractName = await this.contractDataProvider.getDebugContractName(contractAddress); if (currentIndex !== oldIndex) { await this.db.setTaggingSecretsIndexesAsSender([new IndexedTaggingSecret(appTaggingSecret, currentIndex)]); @@ -443,7 +462,7 @@ export class SimulatorOracle implements DBOracle { // due to us having a sliding window that "looks back" for logs as well. (We look back as there is no guarantee // that a logs will be received ordered by a given tax index and that the tags won't be reused). const logsMap = new Map(); - const contractName = await this.contractDataOracle.getDebugContractName(contractAddress); + const contractName = await this.contractDataProvider.getDebugContractName(contractAddress); for (const recipient of recipients) { const logsForRecipient: TxScopedL2Log[] = []; @@ -817,7 +836,7 @@ export class SimulatorOracle implements DBOracle { recipient: AztecAddress, simulator?: AcirSimulator, ) { - const artifact: FunctionArtifact | undefined = await new ContractDataOracle(this.db).getFunctionArtifactByName( + const artifact: FunctionArtifact | undefined = await new ContractDataProvider(this.db).getFunctionArtifactByName( contractAddress, 'process_log', ); @@ -844,10 +863,7 @@ export class SimulatorOracle implements DBOracle { returnTypes: artifact.returnTypes, }; - await ( - simulator ?? - getAcirSimulator(this.db, this.aztecNode, this.keyStore, this.simulationProvider, this.contractDataOracle) - ).runUnconstrained( + await (simulator ?? new AcirSimulator(this, this.simulationProvider)).runUnconstrained( execRequest, contractAddress, selector, diff --git a/yarn-project/pxe/src/simulator_oracle/simulator_oracle.test.ts b/yarn-project/pxe/src/pxe_data_provider/pxe_data_provider.test.ts similarity index 95% rename from yarn-project/pxe/src/simulator_oracle/simulator_oracle.test.ts rename to yarn-project/pxe/src/pxe_data_provider/pxe_data_provider.test.ts index 71984a8b87ae..e491e2132fb9 100644 --- a/yarn-project/pxe/src/simulator_oracle/simulator_oracle.test.ts +++ b/yarn-project/pxe/src/pxe_data_provider/pxe_data_provider.test.ts @@ -19,10 +19,10 @@ import { TxEffect, TxHash } from '@aztec/stdlib/tx'; import { jest } from '@jest/globals'; import { type MockProxy, mock } from 'jest-mock-extended'; +import { ContractDataProvider } from '../contract_data_provider/index.js'; import type { PxeDatabase } from '../database/index.js'; import { KVPxeDatabase } from '../database/kv_pxe_database.js'; -import { ContractDataOracle } from '../index.js'; -import { SimulatorOracle } from './index.js'; +import { PXEDataProvider } from './index.js'; import { WINDOW_HALF_SIZE } from './tagging_utils.js'; const TXS_PER_BLOCK = 4; @@ -102,11 +102,11 @@ async function computeSiloedTagForIndex( return poseidon2Hash([contractAddress, tag]); } -describe('Simulator oracle', () => { +describe('PXE data provider', () => { let aztecNode: MockProxy; let database: PxeDatabase; - let contractDataOracle: ContractDataOracle; - let simulatorOracle: SimulatorOracle; + let contractDataProvider: ContractDataProvider; + let pxeDataProvider: PXEDataProvider; let keyStore: KeyStore; let simulationProvider: SimulationProvider; @@ -117,11 +117,11 @@ describe('Simulator oracle', () => { const db = await openTmpStore('test'); aztecNode = mock(); database = await KVPxeDatabase.create(db); - contractDataOracle = new ContractDataOracle(database); - jest.spyOn(contractDataOracle, 'getDebugContractName').mockImplementation(() => Promise.resolve('TestContract')); + contractDataProvider = new ContractDataProvider(database); + jest.spyOn(contractDataProvider, 'getDebugContractName').mockImplementation(() => Promise.resolve('TestContract')); keyStore = new KeyStore(db); simulationProvider = new WASMSimulator(); - simulatorOracle = new SimulatorOracle(contractDataOracle, database, keyStore, aztecNode, simulationProvider); + pxeDataProvider = new PXEDataProvider(database, keyStore, aztecNode, simulationProvider, contractDataProvider); // Set up contract address contractAddress = await AztecAddress.random(); // Set up recipient account @@ -225,7 +225,7 @@ describe('Simulator oracle', () => { it('should sync tagged logs', async () => { const tagIndex = 0; await generateMockLogs(tagIndex); - const syncedLogs = await simulatorOracle.syncTaggedLogs(contractAddress, 3); + const syncedLogs = await pxeDataProvider.syncTaggedLogs(contractAddress, 3); // We expect to have all logs intended for the recipient, one per sender + 1 with a duplicated tag for the first // one + half of the logs for the second index expect(syncedLogs.get(recipient.address.toString())).toHaveLength(NUM_SENDERS + 1 + NUM_SENDERS / 2); @@ -285,7 +285,7 @@ describe('Simulator oracle', () => { expect(aztecNode.getLogsByTags.mock.calls.length).toBe(0); for (let i = 0; i < senders.length; i++) { - await simulatorOracle.syncTaggedLogsAsSender( + await pxeDataProvider.syncTaggedLogsAsSender( contractAddress, senders[i].completeAddress.address, recipient.address, @@ -304,7 +304,7 @@ describe('Simulator oracle', () => { tagIndex = 11; await generateMockLogs(tagIndex); for (let i = 0; i < senders.length; i++) { - await simulatorOracle.syncTaggedLogsAsSender( + await pxeDataProvider.syncTaggedLogsAsSender( contractAddress, senders[i].completeAddress.address, recipient.address, @@ -320,7 +320,7 @@ describe('Simulator oracle', () => { it('should sync tagged logs with a sender index offset', async () => { const tagIndex = 5; await generateMockLogs(tagIndex); - const syncedLogs = await simulatorOracle.syncTaggedLogs(contractAddress, 3); + const syncedLogs = await pxeDataProvider.syncTaggedLogs(contractAddress, 3); // We expect to have all logs intended for the recipient, one per sender + 1 with a duplicated tag for the first one + half of the logs for the second index expect(syncedLogs.get(recipient.address.toString())).toHaveLength(NUM_SENDERS + 1 + NUM_SENDERS / 2); @@ -370,7 +370,7 @@ describe('Simulator oracle', () => { // Increase our indexes to 2 await database.setTaggingSecretsIndexesAsRecipient(secrets.map(secret => new IndexedTaggingSecret(secret, 2))); - const syncedLogs = await simulatorOracle.syncTaggedLogs(contractAddress, 3); + const syncedLogs = await pxeDataProvider.syncTaggedLogs(contractAddress, 3); // Even if our index as recipient is higher than what the sender sent, we should be able to find the logs // since the window starts at Math.max(0, 2 - window_size) = 0 @@ -412,7 +412,7 @@ describe('Simulator oracle', () => { secrets.map(secret => new IndexedTaggingSecret(secret, WINDOW_HALF_SIZE + 1)), ); - const syncedLogs = await simulatorOracle.syncTaggedLogs(contractAddress, 3); + const syncedLogs = await pxeDataProvider.syncTaggedLogs(contractAddress, 3); // Only half of the logs should be synced since we start from index 1 = (11 - window_size), the other half should be skipped expect(syncedLogs.get(recipient.address.toString())).toHaveLength(NUM_SENDERS / 2); @@ -448,7 +448,7 @@ describe('Simulator oracle', () => { secrets.map(secret => new IndexedTaggingSecret(secret, WINDOW_HALF_SIZE + 2)), ); - let syncedLogs = await simulatorOracle.syncTaggedLogs(contractAddress, 3); + let syncedLogs = await pxeDataProvider.syncTaggedLogs(contractAddress, 3); // No logs should be synced since we start from index 2 = 12 - window_size expect(syncedLogs.get(recipient.address.toString())).toHaveLength(0); @@ -461,7 +461,7 @@ describe('Simulator oracle', () => { // Wipe the database await database.resetNoteSyncData(); - syncedLogs = await simulatorOracle.syncTaggedLogs(contractAddress, 3); + syncedLogs = await pxeDataProvider.syncTaggedLogs(contractAddress, 3); // First sender should have 2 logs, but keep index 1 since they were built using the same tag // Next 4 senders should also have index 1 = offset + 1 @@ -479,7 +479,7 @@ describe('Simulator oracle', () => { it('should not sync tagged logs with a blockNumber > maxBlockNumber', async () => { const tagIndex = 0; await generateMockLogs(tagIndex); - const syncedLogs = await simulatorOracle.syncTaggedLogs(contractAddress, 1); + const syncedLogs = await pxeDataProvider.syncTaggedLogs(contractAddress, 1); // Only NUM_SENDERS + 1 logs should be synched, since the rest have blockNumber > 1 expect(syncedLogs.get(recipient.address.toString())).toHaveLength(NUM_SENDERS + 1); @@ -500,7 +500,7 @@ describe('Simulator oracle', () => { aztecNode.getLogsByTags.mockImplementation(tags => { return Promise.resolve(tags.map(tag => logs[tag.toString()] ?? [])); }); - const syncedLogs = await simulatorOracle.syncTaggedLogs(contractAddress, 1); + const syncedLogs = await pxeDataProvider.syncTaggedLogs(contractAddress, 1); // We expect the above log to be discarded, and so none to be synced expect(syncedLogs.get(recipient.address.toString())).toHaveLength(0); @@ -632,7 +632,7 @@ describe('Simulator oracle', () => { const taggedLogs = await mockTaggedLogs(requests); - await simulatorOracle.processTaggedLogs(taggedLogs, recipient.address, simulator); + await pxeDataProvider.processTaggedLogs(taggedLogs, recipient.address, simulator); // We test that a call to `processLog` is made with the correct function artifact and contract address expect(runUnconstrainedSpy).toHaveBeenCalledTimes(3); @@ -653,7 +653,7 @@ describe('Simulator oracle', () => { const taggedLogs = await mockTaggedLogs(requests); - await simulatorOracle.processTaggedLogs(taggedLogs, recipient.address, simulator); + await pxeDataProvider.processTaggedLogs(taggedLogs, recipient.address, simulator); expect(addNotesSpy).toHaveBeenCalledTimes(0); }); @@ -675,7 +675,7 @@ describe('Simulator oracle', () => { return [await wrapInBlock(1n, await L2Block.random(2)), undefined, undefined]; }); - await simulatorOracle.removeNullifiedNotes(contractAddress); + await pxeDataProvider.removeNullifiedNotes(contractAddress); expect(removeNullifiedNotesSpy).toHaveBeenCalledTimes(1); expect(removeNullifiedNotesSpy).toHaveBeenCalledWith( diff --git a/yarn-project/pxe/src/simulator_oracle/tagging_utils.ts b/yarn-project/pxe/src/pxe_data_provider/tagging_utils.ts similarity index 100% rename from yarn-project/pxe/src/simulator_oracle/tagging_utils.ts rename to yarn-project/pxe/src/pxe_data_provider/tagging_utils.ts diff --git a/yarn-project/pxe/src/pxe_service/error_enriching.ts b/yarn-project/pxe/src/pxe_service/error_enriching.ts index 9ea24c9bbe0f..d50e3b7b347a 100644 --- a/yarn-project/pxe/src/pxe_service/error_enriching.ts +++ b/yarn-project/pxe/src/pxe_service/error_enriching.ts @@ -6,7 +6,8 @@ import { FunctionSelector } from '@aztec/stdlib/abi'; import { AztecAddress } from '@aztec/stdlib/aztec-address'; import { type SimulationError, isNoirCallStackUnresolved } from '@aztec/stdlib/errors'; -import type { ContractDataOracle, PxeDatabase } from '../index.js'; +import { ContractDataProvider } from '../contract_data_provider/index.js'; +import type { PxeDatabase } from '../database/interfaces/pxe_database.js'; /** * Adds contract and function names to a simulation error, if they @@ -57,7 +58,7 @@ export async function enrichSimulationError(err: SimulationError, db: PxeDatabas export async function enrichPublicSimulationError( err: SimulationError, - contractDataOracle: ContractDataOracle, + contractDataProvider: ContractDataProvider, db: PxeDatabase, logger: Logger, ) { @@ -68,7 +69,7 @@ export async function enrichPublicSimulationError( // no matter what the call stack selector points to (since we've modified it to point to the target function). // We should remove this because the AVM (or public protocol) shouldn't be aware of the public dispatch calling convention. - const artifact = await contractDataOracle.getFunctionArtifact( + const artifact = await contractDataProvider.getFunctionArtifact( originalFailingFunction.contractAddress, FunctionSelector.fromField(new Fr(PUBLIC_DISPATCH_SELECTOR)), ); @@ -77,7 +78,7 @@ export async function enrichPublicSimulationError( err.setOriginalMessage(err.getOriginalMessage() + `${assertionMessage}`); } - const debugInfo = await contractDataOracle.getFunctionDebugMetadata( + const debugInfo = await contractDataProvider.getFunctionDebugMetadata( originalFailingFunction.contractAddress, FunctionSelector.fromField(new Fr(PUBLIC_DISPATCH_SELECTOR)), ); diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index c63dc568bc04..0e1f5d52f404 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -10,7 +10,7 @@ import { type ProtocolContractsProvider, protocolContractNames, } from '@aztec/protocol-contracts'; -import { type AcirSimulator, type SimulationProvider, readCurrentClassId } from '@aztec/simulator/client'; +import { AcirSimulator, type SimulationProvider, readCurrentClassId } from '@aztec/simulator/client'; import { type AbiDecoded, type ContractArtifact, @@ -67,11 +67,11 @@ import { inspect } from 'util'; import type { PXEServiceConfig } from '../config/index.js'; import { getPackageInfo } from '../config/package_info.js'; -import { ContractDataOracle } from '../contract_data_oracle/index.js'; +import { ContractDataProvider } from '../contract_data_provider/index.js'; import type { PxeDatabase } from '../database/index.js'; import { KernelOracle } from '../kernel_oracle/index.js'; import { KernelProver, type ProvingConfig } from '../kernel_prover/kernel_prover.js'; -import { getAcirSimulator } from '../simulator/index.js'; +import { PXEDataProvider } from '../pxe_data_provider/index.js'; import { Synchronizer } from '../synchronizer/index.js'; import { enrichPublicSimulationError, enrichSimulationError } from './error_enriching.js'; @@ -80,7 +80,8 @@ import { enrichPublicSimulationError, enrichSimulationError } from './error_enri */ export class PXEService implements PXE { private synchronizer: Synchronizer; - private contractDataOracle: ContractDataOracle; + private contractDataProvider: ContractDataProvider; + private pxeDataProvider: PXEDataProvider; private simulator: AcirSimulator; private log: Logger; private packageVersion: string; @@ -92,7 +93,7 @@ export class PXEService implements PXE { private db: PxeDatabase, tipsStore: L2TipsStore, private proofCreator: PrivateKernelProver, - private simulationProvider: SimulationProvider, + simulationProvider: SimulationProvider, private protocolContractsProvider: ProtocolContractsProvider, config: PXEServiceConfig, loggerOrSuffix?: string | Logger, @@ -102,8 +103,16 @@ export class PXEService implements PXE { ? createLogger(loggerOrSuffix ? `pxe:service:${loggerOrSuffix}` : `pxe:service`) : loggerOrSuffix; this.synchronizer = new Synchronizer(node, db, tipsStore, config, loggerOrSuffix); - this.contractDataOracle = new ContractDataOracle(db); - this.simulator = getAcirSimulator(db, node, keyStore, this.simulationProvider, this.contractDataOracle); + this.contractDataProvider = new ContractDataProvider(db); + this.pxeDataProvider = new PXEDataProvider( + db, + keyStore, + node, + simulationProvider, + this.contractDataProvider, + this.log, + ); + this.simulator = new AcirSimulator(this.pxeDataProvider, simulationProvider); this.packageVersion = getPackageInfo().version; this.proverEnabled = !!config.proverEnabled; } @@ -296,7 +305,7 @@ export class PXEService implements PXE { const currentClassId = await readCurrentClassId( contractAddress, currentInstance, - this.node, + this.pxeDataProvider, header.globalVariables.blockNumber.toNumber(), ); if (!contractClass.id.equals(currentClassId)) { @@ -325,7 +334,7 @@ export class PXEService implements PXE { if (!(await this.getContractInstance(contract))) { throw new Error(`Contract ${contract.toString()} is not deployed`); } - return await this.node.getPublicStorageAt(contract, slot, 'latest'); + return await this.node.getPublicStorageAt('latest', contract, slot); } public async getNotes(filter: NotesFilter): Promise { @@ -660,7 +669,7 @@ export class PXEService implements PXE { /** * Simulate an unconstrained transaction on the given contract, without considering constraints set by ACIR. - * The simulation parameters are fetched using ContractDataOracle and executed using AcirSimulator. + * The simulation parameters are fetched using ContractDataProvider and executed using AcirSimulator. * Returns the simulation result containing the outputs of the unconstrained function. * * @param execRequest - The transaction request object containing the target contract and function data. @@ -702,7 +711,7 @@ export class PXEService implements PXE { } catch (err) { if (err instanceof SimulationError) { try { - await enrichPublicSimulationError(err, this.contractDataOracle, this.db, this.log); + await enrichPublicSimulationError(err, this.contractDataProvider, this.db, this.log); } catch (enrichErr) { this.log.error(`Failed to enrich public simulation error: ${enrichErr}`); } @@ -730,7 +739,7 @@ export class PXEService implements PXE { // use the block the tx was simulated against const block = privateExecutionResult.entrypoint.publicInputs.historicalHeader.globalVariables.blockNumber.toNumber(); - const kernelOracle = new KernelOracle(this.contractDataOracle, this.keyStore, this.node, block); + const kernelOracle = new KernelOracle(this.contractDataProvider, this.keyStore, this.node, block); const kernelProver = new KernelProver(kernelOracle, proofCreator, !this.proverEnabled); this.log.debug(`Executing kernel prover (simulate: ${simulate}, profile: ${profile})...`); return await kernelProver.prove(txExecutionRequest.toTxRequest(), privateExecutionResult, { diff --git a/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts b/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts index 363a97696b89..e0e26b7d4917 100644 --- a/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts +++ b/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts @@ -15,8 +15,8 @@ import { TxEffect } from '@aztec/stdlib/tx'; import { type MockProxy, mock } from 'jest-mock-extended'; +import type { PxeDatabase } from '../../database/interfaces/pxe_database.js'; import { KVPxeDatabase } from '../../database/kv_pxe_database.js'; -import type { PxeDatabase } from '../../database/pxe_database.js'; import type { PXEServiceConfig } from '../../index.js'; import { PXEService } from '../pxe_service.js'; import { pxeTestSuite } from './pxe_test_suite.js'; diff --git a/yarn-project/pxe/src/simulator/index.ts b/yarn-project/pxe/src/simulator/index.ts deleted file mode 100644 index 2e588225e42e..000000000000 --- a/yarn-project/pxe/src/simulator/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { KeyStore } from '@aztec/key-store'; -import { AcirSimulator, type SimulationProvider } from '@aztec/simulator/client'; -import type { AztecNode } from '@aztec/stdlib/interfaces/client'; - -import { ContractDataOracle } from '../contract_data_oracle/index.js'; -import type { PxeDatabase } from '../database/pxe_database.js'; -import { SimulatorOracle } from '../simulator_oracle/index.js'; - -/** - * Helper method to create an instance of the acir simulator. - */ -export function getAcirSimulator( - db: PxeDatabase, - aztecNode: AztecNode, - keyStore: KeyStore, - simulationProvider: SimulationProvider, - contractDataOracle?: ContractDataOracle, -) { - const simulatorOracle = new SimulatorOracle( - contractDataOracle ?? new ContractDataOracle(db), - db, - keyStore, - aztecNode, - simulationProvider, - ); - return new AcirSimulator(simulatorOracle, aztecNode, simulationProvider); -} diff --git a/yarn-project/simulator/src/private/db_oracle.ts b/yarn-project/simulator/src/private/execution_data_provider.ts similarity index 93% rename from yarn-project/simulator/src/private/db_oracle.ts rename to yarn-project/simulator/src/private/execution_data_provider.ts index 7acade9a6ed2..d2913e529c11 100644 --- a/yarn-project/simulator/src/private/db_oracle.ts +++ b/yarn-project/simulator/src/private/execution_data_provider.ts @@ -31,9 +31,9 @@ export class ContractClassNotFoundError extends Error { } /** - * The database oracle interface. + * The interface for the data layer required to perform private and unconstrained execution. */ -export interface DBOracle extends CommitmentsDB { +export interface ExecutionDataProvider extends CommitmentsDB { /** * Returns a contract instance associated with an address, if available. * @param address - Address. @@ -159,6 +159,20 @@ export interface DBOracle extends CommitmentsDB { */ getPublicDataTreeWitness(blockNumber: number, leafSlot: Fr): Promise; + /** + * Gets the storage value at the given contract storage slot. + * + * @remarks The storage slot here refers to the slot as it is defined in Noir not the index in the merkle tree. + * Aztec's version of `eth_getStorageAt`. + * + * @param blockNumber - The block number at which to get the data. + * @param contract - Address of the contract to query. + * @param slot - Slot to query. + * @returns Storage value at the given contract slot. + * @throws If the contract is not deployed. + */ + getPublicStorageAt(blockNumber: number, contract: AztecAddress, slot: Fr): Promise; + /** * Fetch a block corresponding to the given block number. * @param blockNumber - The block number of a block to fetch. @@ -172,6 +186,18 @@ export interface DBOracle extends CommitmentsDB { */ getBlockNumber(): Promise; + /** + * Fetches the current chain id. + * @returns The chain id. + */ + getChainId(): Promise; + + /** + * Fetches the current chain id. + * @returns The chain id. + */ + getVersion(): Promise; + /** * Returns the tagging secret for a given sender and recipient pair. For this to work, the ivsk_m of the sender must be known. * Includes the next index to be used used for tagging with this secret. diff --git a/yarn-project/simulator/src/private/index.ts b/yarn-project/simulator/src/private/index.ts index 974baa5f0394..196cedb230d6 100644 --- a/yarn-project/simulator/src/private/index.ts +++ b/yarn-project/simulator/src/private/index.ts @@ -1,6 +1,10 @@ export { AcirSimulator } from './simulator.js'; -export { ViewDataOracle } from './view_data_oracle.js'; -export { type DBOracle, ContractClassNotFoundError, ContractNotFoundError } from './db_oracle.js'; +export { UnconstrainedExecutionOracle } from './unconstrained_execution_oracle.js'; +export { + type ExecutionDataProvider, + ContractClassNotFoundError, + ContractNotFoundError, +} from './execution_data_provider.js'; export * from './pick_notes.js'; export { ExecutionNoteCache } from './execution_note_cache.js'; export { extractPrivateCircuitPublicInputs, readCurrentClassId } from './private_execution.js'; diff --git a/yarn-project/simulator/src/private/private_execution.test.ts b/yarn-project/simulator/src/private/private_execution.test.ts index 18bf593d395d..7c725e8495b7 100644 --- a/yarn-project/simulator/src/private/private_execution.test.ts +++ b/yarn-project/simulator/src/private/private_execution.test.ts @@ -45,7 +45,6 @@ import { deriveStorageSlotInMap, siloNoteHash, } from '@aztec/stdlib/hash'; -import type { AztecNode } from '@aztec/stdlib/interfaces/client'; import { KeyValidationRequest, getNonEmptyItems } from '@aztec/stdlib/kernel'; import { computeAppNullifierSecretKey, deriveKeys } from '@aztec/stdlib/keys'; import { IndexedTaggingSecret, TxScopedL2Log } from '@aztec/stdlib/logs'; @@ -71,7 +70,7 @@ import { toFunctionSelector } from 'viem'; import { MessageLoadOracleInputs } from '../common/message_load_oracle_inputs.js'; import { buildL1ToL2Message } from '../test/utils.js'; -import type { DBOracle } from './db_oracle.js'; +import type { ExecutionDataProvider } from './execution_data_provider.js'; import { WASMSimulator } from './providers/acvm_wasm.js'; import { AcirSimulator } from './simulator.js'; @@ -80,8 +79,7 @@ jest.setTimeout(60_000); describe('Private Execution test suite', () => { const simulationProvider = new WASMSimulator(); - let oracle: MockProxy; - let node: MockProxy; + let executionDataProvider: MockProxy; let acirSimulator: AcirSimulator; let header = BlockHeader.empty(); @@ -123,7 +121,7 @@ describe('Private Execution test suite', () => { contracts[address.toString()] = artifact; const contractClass = await getContractClassFromArtifact(artifact); - oracle.getContractInstance.calledWith(aztecAddressMatcher(address)).mockResolvedValue({ + executionDataProvider.getContractInstance.calledWith(aztecAddressMatcher(address)).mockResolvedValue({ currentContractClassId: contractClass.id, originalContractClassId: contractClass.id, } as ContractInstance); @@ -235,34 +233,36 @@ describe('Private Execution test suite', () => { beforeEach(async () => { trees = {}; - oracle = mock(); + executionDataProvider = mock(); contracts = {}; - oracle.getKeyValidationRequest.mockImplementation(async (pkMHash: Fr, contractAddress: AztecAddress) => { - if (pkMHash.equals(await ownerCompleteAddress.publicKeys.masterNullifierPublicKey.hash())) { - return Promise.resolve( - new KeyValidationRequest( - ownerCompleteAddress.publicKeys.masterNullifierPublicKey, - await computeAppNullifierSecretKey(ownerNskM, contractAddress), - ), - ); - } - if (pkMHash.equals(await recipientCompleteAddress.publicKeys.masterNullifierPublicKey.hash())) { - return Promise.resolve( - new KeyValidationRequest( - recipientCompleteAddress.publicKeys.masterNullifierPublicKey, - await computeAppNullifierSecretKey(recipientNskM, contractAddress), - ), - ); - } - throw new Error(`Unknown master public key hash: ${pkMHash}`); - }); + executionDataProvider.getKeyValidationRequest.mockImplementation( + async (pkMHash: Fr, contractAddress: AztecAddress) => { + if (pkMHash.equals(await ownerCompleteAddress.publicKeys.masterNullifierPublicKey.hash())) { + return Promise.resolve( + new KeyValidationRequest( + ownerCompleteAddress.publicKeys.masterNullifierPublicKey, + await computeAppNullifierSecretKey(ownerNskM, contractAddress), + ), + ); + } + if (pkMHash.equals(await recipientCompleteAddress.publicKeys.masterNullifierPublicKey.hash())) { + return Promise.resolve( + new KeyValidationRequest( + recipientCompleteAddress.publicKeys.masterNullifierPublicKey, + await computeAppNullifierSecretKey(recipientNskM, contractAddress), + ), + ); + } + throw new Error(`Unknown master public key hash: ${pkMHash}`); + }, + ); // We call insertLeaves here with no leaves to populate empty public data tree root --> this is necessary to be // able to get ivpk_m during execution await insertLeaves([], 'publicData'); - oracle.getBlockHeader.mockResolvedValue(header); + executionDataProvider.getBlockHeader.mockResolvedValue(header); - oracle.getCompleteAddress.mockImplementation((address: AztecAddress) => { + executionDataProvider.getCompleteAddress.mockImplementation((address: AztecAddress) => { if (address.equals(owner)) { return Promise.resolve(ownerCompleteAddress); } @@ -272,13 +272,13 @@ describe('Private Execution test suite', () => { throw new Error(`Unknown address: ${address}. Recipient: ${recipient}, Owner: ${owner}`); }); - oracle.getIndexedTaggingSecretAsSender.mockImplementation( + executionDataProvider.getIndexedTaggingSecretAsSender.mockImplementation( (_contractAddress: AztecAddress, _sender: AztecAddress, _recipient: AztecAddress) => { const secret = Fr.random(); return Promise.resolve(new IndexedTaggingSecret(secret, 0)); }, ); - oracle.getFunctionArtifact.mockImplementation(async (address, selector) => { + executionDataProvider.getFunctionArtifact.mockImplementation(async (address, selector) => { const contract = contracts[address.toString()]; if (!contract) { throw new Error(`Contract not found: ${address}`); @@ -290,7 +290,7 @@ describe('Private Execution test suite', () => { return Promise.resolve(artifact); }); - oracle.getFunctionArtifactByName.mockImplementation((address, name) => { + executionDataProvider.getFunctionArtifactByName.mockImplementation((address, name) => { const contract = contracts[address.toString()]; if (!contract) { throw new Error(`Contract not found: ${address}`); @@ -302,17 +302,18 @@ describe('Private Execution test suite', () => { return Promise.resolve(artifact); }); - oracle.syncTaggedLogs.mockImplementation((_, __, ___) => Promise.resolve(new Map())); - oracle.loadCapsule.mockImplementation((_, __) => Promise.resolve(null)); + executionDataProvider.syncTaggedLogs.mockImplementation((_, __, ___) => + Promise.resolve(new Map()), + ); + executionDataProvider.loadCapsule.mockImplementation((_, __) => Promise.resolve(null)); - node = mock(); - node.getPublicStorageAt.mockImplementation( - (_address: AztecAddress, _storageSlot: Fr, _blockNumber: L2BlockNumber) => { + executionDataProvider.getPublicStorageAt.mockImplementation( + (_blockNumber: L2BlockNumber, _address: AztecAddress, _storageSlot: Fr) => { return Promise.resolve(Fr.ZERO); }, ); - acirSimulator = new AcirSimulator(oracle, node, simulationProvider); + acirSimulator = new AcirSimulator(executionDataProvider, simulationProvider); }); describe('no constructor', () => { @@ -377,7 +378,7 @@ describe('Private Execution test suite', () => { const instance = await getContractInstanceFromDeployParams(StatefulTestContractArtifact, { constructorArgs: initArgs, }); - oracle.getContractInstance.mockResolvedValue(instance); + executionDataProvider.getContractInstance.mockResolvedValue(instance); const executionResult = await runSimulator({ args: initArgs, artifact: StatefulTestContractArtifact, @@ -432,9 +433,9 @@ describe('Private Execution test suite', () => { buildNote(60n, ownerCompleteAddress.address, storageSlot, valueNoteTypeId), buildNote(80n, ownerCompleteAddress.address, storageSlot, valueNoteTypeId), ]); - oracle.syncTaggedLogs.mockResolvedValue(new Map()); - oracle.processTaggedLogs.mockResolvedValue(); - oracle.getNotes.mockResolvedValue(notes); + executionDataProvider.syncTaggedLogs.mockResolvedValue(new Map()); + executionDataProvider.processTaggedLogs.mockResolvedValue(); + executionDataProvider.getNotes.mockResolvedValue(notes); const consumedNotes = await asyncMap(notes, async ({ note, nonce }) => { const noteHash = await computeNoteHash(note, storageSlot); @@ -484,9 +485,9 @@ describe('Private Execution test suite', () => { const storageSlot = await deriveStorageSlotInMap(new Fr(1n), owner); const notes = await Promise.all([buildNote(balance, ownerCompleteAddress.address, storageSlot, valueNoteTypeId)]); - oracle.syncTaggedLogs.mockResolvedValue(new Map()); - oracle.processTaggedLogs.mockResolvedValue(); - oracle.getNotes.mockResolvedValue(notes); + executionDataProvider.syncTaggedLogs.mockResolvedValue(new Map()); + executionDataProvider.processTaggedLogs.mockResolvedValue(); + executionDataProvider.getNotes.mockResolvedValue(notes); const consumedNotes = await asyncMap(notes, async ({ note, nonce }) => { const noteHash = await computeNoteHash(note, storageSlot); @@ -553,7 +554,7 @@ describe('Private Execution test suite', () => { expect(result.returnValues).toEqual([new Fr(privateIncrement)]); // First fetch of the function artifact is the parent contract - expect(oracle.getFunctionArtifact.mock.calls[1]).toEqual([childAddress, childSelector]); + expect(executionDataProvider.getFunctionArtifact.mock.calls[1]).toEqual([childAddress, childSelector]); expect(result.nestedExecutions).toHaveLength(1); expect(result.nestedExecutions[0].returnValues).toEqual([new Fr(privateIncrement)]); expect(result.publicInputs.privateCallRequests[0].callContext).toEqual( @@ -608,7 +609,7 @@ describe('Private Execution test suite', () => { }); expect(result.returnValues).toEqual([argsHash]); - expect(oracle.getFunctionArtifact.mock.calls[1]).toEqual([testAddress, testCodeGenSelector]); + expect(executionDataProvider.getFunctionArtifact.mock.calls[1]).toEqual([testAddress, testCodeGenSelector]); expect(result.nestedExecutions).toHaveLength(1); expect(result.nestedExecutions[0].returnValues).toEqual([argsHash]); }); @@ -659,11 +660,11 @@ describe('Private Execution test suite', () => { const mockOracles = async (updateHeader = true) => { const tree = await insertLeaves([preimage.hash()], 'l1ToL2Messages'); - oracle.getL1ToL2MembershipWitness.mockImplementation(async () => { + executionDataProvider.getL1ToL2MembershipWitness.mockImplementation(async () => { return Promise.resolve(new MessageLoadOracleInputs(0n, await tree.getSiblingPath(0n, true))); }); if (updateHeader) { - oracle.getBlockHeader.mockResolvedValue(header); + executionDataProvider.getBlockHeader.mockResolvedValue(header); } }; @@ -713,7 +714,7 @@ describe('Private Execution test suite', () => { await mockOracles(); // Update state - oracle.getBlockHeader.mockResolvedValue(header); + executionDataProvider.getBlockHeader.mockResolvedValue(header); await expect( runSimulator({ @@ -734,7 +735,7 @@ describe('Private Execution test suite', () => { await mockOracles(); // Update state - oracle.getBlockHeader.mockResolvedValue(header); + executionDataProvider.getBlockHeader.mockResolvedValue(header); await expect( runSimulator({ @@ -754,7 +755,7 @@ describe('Private Execution test suite', () => { await mockOracles(); // Update state - oracle.getBlockHeader.mockResolvedValue(header); + executionDataProvider.getBlockHeader.mockResolvedValue(header); await expect( runSimulator({ @@ -774,7 +775,7 @@ describe('Private Execution test suite', () => { await mockOracles(); // Update state - oracle.getBlockHeader.mockResolvedValue(header); + executionDataProvider.getBlockHeader.mockResolvedValue(header); await expect( runSimulator({ @@ -795,7 +796,7 @@ describe('Private Execution test suite', () => { await mockOracles(); // Update state - oracle.getBlockHeader.mockResolvedValue(header); + executionDataProvider.getBlockHeader.mockResolvedValue(header); await expect( runSimulator({ @@ -816,7 +817,7 @@ describe('Private Execution test suite', () => { await mockOracles(); // Update state - oracle.getBlockHeader.mockResolvedValue(header); + executionDataProvider.getBlockHeader.mockResolvedValue(header); await expect( runSimulator({ @@ -918,9 +919,9 @@ describe('Private Execution test suite', () => { }); it('should be able to insert, read, and nullify pending note hashes in one call', async () => { - oracle.syncTaggedLogs.mockResolvedValue(new Map()); - oracle.processTaggedLogs.mockResolvedValue(); - oracle.getNotes.mockResolvedValue([]); + executionDataProvider.syncTaggedLogs.mockResolvedValue(new Map()); + executionDataProvider.processTaggedLogs.mockResolvedValue(); + executionDataProvider.getNotes.mockResolvedValue([]); const amountToTransfer = 100n; @@ -971,9 +972,9 @@ describe('Private Execution test suite', () => { }); it('should be able to insert, read, and nullify pending note hashes in nested calls', async () => { - oracle.syncTaggedLogs.mockResolvedValue(new Map()); - oracle.processTaggedLogs.mockResolvedValue(); - oracle.getNotes.mockResolvedValue([]); + executionDataProvider.syncTaggedLogs.mockResolvedValue(new Map()); + executionDataProvider.processTaggedLogs.mockResolvedValue(); + executionDataProvider.getNotes.mockResolvedValue([]); const amountToTransfer = 100n; @@ -1043,9 +1044,9 @@ describe('Private Execution test suite', () => { }); it('cant read a commitment that is inserted later in same call', async () => { - oracle.syncTaggedLogs.mockResolvedValue(new Map()); - oracle.processTaggedLogs.mockResolvedValue(); - oracle.getNotes.mockResolvedValue([]); + executionDataProvider.syncTaggedLogs.mockResolvedValue(new Map()); + executionDataProvider.processTaggedLogs.mockResolvedValue(); + executionDataProvider.getNotes.mockResolvedValue([]); const amountToTransfer = 100n; @@ -1069,7 +1070,7 @@ describe('Private Execution test suite', () => { const args = [completeAddress.address]; const pubKey = completeAddress.publicKeys.masterIncomingViewingPublicKey; - oracle.getCompleteAddress.mockResolvedValue(completeAddress); + executionDataProvider.getCompleteAddress.mockResolvedValue(completeAddress); const { entrypoint: result } = await runSimulator({ artifact: TestContractArtifact, functionName: 'get_master_incoming_viewing_public_key', @@ -1082,9 +1083,9 @@ describe('Private Execution test suite', () => { describe('Get notes', () => { it('fails if returning no notes', async () => { const args = [2n, true]; - oracle.syncTaggedLogs.mockResolvedValue(new Map()); - oracle.processTaggedLogs.mockResolvedValue(); - oracle.getNotes.mockResolvedValue([]); + executionDataProvider.syncTaggedLogs.mockResolvedValue(new Map()); + executionDataProvider.processTaggedLogs.mockResolvedValue(); + executionDataProvider.getNotes.mockResolvedValue([]); await expect(() => runSimulator({ artifact: TestContractArtifact, functionName: 'call_get_notes', args }), @@ -1161,8 +1162,8 @@ describe('Private Execution test suite', () => { beforeEach(() => { header = makeHeader(); - oracle.getBlockHeader.mockClear(); - oracle.getBlockHeader.mockResolvedValue(header); + executionDataProvider.getBlockHeader.mockClear(); + executionDataProvider.getBlockHeader.mockResolvedValue(header); }); it('Header is correctly set', async () => { diff --git a/yarn-project/simulator/src/private/private_execution.ts b/yarn-project/simulator/src/private/private_execution.ts index 9d11abca1b30..51bbfa26f5cf 100644 --- a/yarn-project/simulator/src/private/private_execution.ts +++ b/yarn-project/simulator/src/private/private_execution.ts @@ -6,7 +6,6 @@ import { ProtocolContractAddress } from '@aztec/protocol-contracts'; import { type FunctionArtifact, type FunctionSelector, countArgumentsSize } from '@aztec/stdlib/abi'; import type { AztecAddress } from '@aztec/stdlib/aztec-address'; import type { ContractInstance } from '@aztec/stdlib/contract'; -import type { AztecNode } from '@aztec/stdlib/interfaces/client'; import { PrivateCircuitPublicInputs } from '@aztec/stdlib/kernel'; import { SharedMutableValues, SharedMutableValuesWithHash } from '@aztec/stdlib/shared-mutable'; import type { CircuitWitnessGenerationStats } from '@aztec/stdlib/stats'; @@ -15,7 +14,8 @@ import { PrivateCallExecutionResult } from '@aztec/stdlib/tx'; import { ExecutionError, resolveAssertionMessageFromError } from '../common/errors.js'; import { fromACVMField, witnessMapToFields } from './acvm/deserialize.js'; import { type ACVMWitness, Oracle, extractCallStack } from './acvm/index.js'; -import type { ClientExecutionContext } from './client_execution_context.js'; +import type { ExecutionDataProvider } from './execution_data_provider.js'; +import type { PrivateExecutionOracle } from './private_execution_oracle.js'; import type { SimulationProvider } from './providers/simulation_provider.js'; /** @@ -23,17 +23,17 @@ import type { SimulationProvider } from './providers/simulation_provider.js'; */ export async function executePrivateFunction( simulator: SimulationProvider, - context: ClientExecutionContext, + privateExecutionOracle: PrivateExecutionOracle, artifact: FunctionArtifact, contractAddress: AztecAddress, functionSelector: FunctionSelector, log = createLogger('simulator:private_execution'), ): Promise { - const functionName = await context.getDebugFunctionName(); + const functionName = await privateExecutionOracle.getDebugFunctionName(); log.verbose(`Executing private function ${functionName}`, { contract: contractAddress }); const acir = artifact.bytecode; - const initialWitness = context.getInitialWitness(artifact); - const acvmCallback = new Oracle(context); + const initialWitness = privateExecutionOracle.getInitialWitness(artifact); + const acvmCallback = new Oracle(privateExecutionOracle); const timer = new Timer(); const acirExecutionResult = await simulator .executeUserCircuit(acir, initialWitness, acvmCallback) @@ -64,16 +64,16 @@ export async function executePrivateFunction( appCircuitName: functionName, } satisfies CircuitWitnessGenerationStats); - const contractClassLogs = context.getContractClassLogs(); + const contractClassLogs = privateExecutionOracle.getContractClassLogs(); - const rawReturnValues = await context.loadFromExecutionCache(publicInputs.returnsHash); + const rawReturnValues = await privateExecutionOracle.loadFromExecutionCache(publicInputs.returnsHash); - const noteHashLeafIndexMap = context.getNoteHashLeafIndexMap(); - const newNotes = context.getNewNotes(); - const noteHashNullifierCounterMap = context.getNoteHashNullifierCounterMap(); - const nestedExecutions = context.getNestedExecutions(); - const enqueuedPublicFunctionCalls = context.getEnqueuedPublicFunctionCalls(); - const publicTeardownFunctionCall = context.getPublicTeardownFunctionCall(); + const noteHashLeafIndexMap = privateExecutionOracle.getNoteHashLeafIndexMap(); + const newNotes = privateExecutionOracle.getNewNotes(); + const noteHashNullifierCounterMap = privateExecutionOracle.getNoteHashNullifierCounterMap(); + const nestedExecutions = privateExecutionOracle.getNestedExecutions(); + const enqueuedPublicFunctionCalls = privateExecutionOracle.getEnqueuedPublicFunctionCalls(); + const publicTeardownFunctionCall = privateExecutionOracle.getPublicTeardownFunctionCall(); log.debug(`Returning from call to ${contractAddress.toString()}:${functionSelector}`); @@ -120,12 +120,12 @@ export function extractPrivateCircuitPublicInputs( export async function readCurrentClassId( contractAddress: AztecAddress, instance: ContractInstance, - node: AztecNode, + executionDataProvider: ExecutionDataProvider, blockNumber: number, ) { const { sharedMutableSlot } = await SharedMutableValuesWithHash.getContractUpdateSlots(contractAddress); const sharedMutableValues = await SharedMutableValues.readFromTree(sharedMutableSlot, slot => - node.getPublicStorageAt(ProtocolContractAddress.ContractInstanceDeployer, slot, blockNumber), + executionDataProvider.getPublicStorageAt(blockNumber, ProtocolContractAddress.ContractInstanceDeployer, slot), ); let currentClassId = sharedMutableValues.svc.getCurrentAt(blockNumber)[0]; if (currentClassId.isZero()) { @@ -136,11 +136,12 @@ export async function readCurrentClassId( export async function verifyCurrentClassId( contractAddress: AztecAddress, - instance: ContractInstance, - node: AztecNode, - blockNumber: number, + executionDataProvider: ExecutionDataProvider, + blockNumber?: number, ) { - const currentClassId = await readCurrentClassId(contractAddress, instance, node, blockNumber); + const instance = await executionDataProvider.getContractInstance(contractAddress); + blockNumber = blockNumber ?? (await executionDataProvider.getBlockNumber()); + const currentClassId = await readCurrentClassId(contractAddress, instance, executionDataProvider, blockNumber); if (!instance.currentContractClassId.equals(currentClassId)) { throw new Error( `Contract ${contractAddress} is outdated, current class id is ${currentClassId}, local class id is ${instance.currentContractClassId}`, diff --git a/yarn-project/simulator/src/private/client_execution_context.ts b/yarn-project/simulator/src/private/private_execution_oracle.ts similarity index 93% rename from yarn-project/simulator/src/private/client_execution_context.ts rename to yarn-project/simulator/src/private/private_execution_oracle.ts index 5a8b80dc3ebf..4fe6836b755f 100644 --- a/yarn-project/simulator/src/private/client_execution_context.ts +++ b/yarn-project/simulator/src/private/private_execution_oracle.ts @@ -11,7 +11,6 @@ import { import type { AuthWitness } from '@aztec/stdlib/auth-witness'; import { AztecAddress } from '@aztec/stdlib/aztec-address'; import { computeUniqueNoteHash, siloNoteHash } from '@aztec/stdlib/hash'; -import type { AztecNode } from '@aztec/stdlib/interfaces/client'; import { PrivateContextInputs } from '@aztec/stdlib/kernel'; import type { ContractClassLog } from '@aztec/stdlib/logs'; import { Note, type NoteStatus } from '@aztec/stdlib/note'; @@ -28,18 +27,18 @@ import { } from '@aztec/stdlib/tx'; import { type NoteData, toACVMWitness } from './acvm/index.js'; -import type { DBOracle } from './db_oracle.js'; +import type { ExecutionDataProvider } from './execution_data_provider.js'; import type { ExecutionNoteCache } from './execution_note_cache.js'; import type { HashedValuesCache } from './hashed_values_cache.js'; import { pickNotes } from './pick_notes.js'; import { executePrivateFunction, verifyCurrentClassId } from './private_execution.js'; import type { SimulationProvider } from './providers/simulation_provider.js'; -import { ViewDataOracle } from './view_data_oracle.js'; +import { UnconstrainedExecutionOracle } from './unconstrained_execution_oracle.js'; /** - * The execution context for a client tx simulation. + * The execution oracle for the private part of a transaction. */ -export class ClientExecutionContext extends ViewDataOracle { +export class PrivateExecutionOracle extends UnconstrainedExecutionOracle { /** * New notes created during this execution. * It's possible that a note in this list has been nullified (in the same or other executions) and doesn't exist in the ExecutionNoteCache and the final proof data. @@ -75,14 +74,13 @@ export class ClientExecutionContext extends ViewDataOracle { capsules: Capsule[], private readonly executionCache: HashedValuesCache, private readonly noteCache: ExecutionNoteCache, - db: DBOracle, - private node: AztecNode, + executionDataProvider: ExecutionDataProvider, private provider: SimulationProvider, protected sideEffectCounter: number = 0, log = createLogger('simulator:client_execution_context'), scopes?: AztecAddress[], ) { - super(callContext.contractAddress, authWitnesses, capsules, db, node, log, scopes); + super(callContext.contractAddress, authWitnesses, capsules, executionDataProvider, log, scopes); } // We still need this function until we can get user-defined ordering of structs for fn arguments @@ -221,7 +219,12 @@ export class ClientExecutionContext extends ViewDataOracle { const pendingNotes = this.noteCache.getNotes(this.callContext.contractAddress, storageSlot); const pendingNullifiers = this.noteCache.getNullifiers(this.callContext.contractAddress); - const dbNotes = await this.db.getNotes(this.callContext.contractAddress, storageSlot, status, this.scopes); + const dbNotes = await this.executionDataProvider.getNotes( + this.callContext.contractAddress, + storageSlot, + status, + this.scopes, + ); const dbNotesFiltered = dbNotes.filter(n => !pendingNullifiers.has((n.siloedNullifier as Fr).value)); const notes = pickNotes([...dbNotesFiltered, ...pendingNotes], { @@ -382,18 +385,20 @@ export class ClientExecutionContext extends ViewDataOracle { await verifyCurrentClassId( targetContractAddress, - await this.db.getContractInstance(targetContractAddress), - this.node, + this.executionDataProvider, this.historicalHeader.globalVariables.blockNumber.toNumber(), ); - const targetArtifact = await this.db.getFunctionArtifact(targetContractAddress, functionSelector); + const targetArtifact = await this.executionDataProvider.getFunctionArtifact( + targetContractAddress, + functionSelector, + ); const derivedTxContext = this.txContext.clone(); const derivedCallContext = await this.deriveCallContext(targetContractAddress, targetArtifact, isStaticCall); - const context = new ClientExecutionContext( + const context = new PrivateExecutionOracle( argsHash, derivedTxContext, derivedCallContext, @@ -402,8 +407,7 @@ export class ClientExecutionContext extends ViewDataOracle { this.capsules, this.executionCache, this.noteCache, - this.db, - this.node, + this.executionDataProvider, this.provider, sideEffectCounter, this.log, @@ -448,7 +452,10 @@ export class ClientExecutionContext extends ViewDataOracle { sideEffectCounter: number, isStaticCall: boolean, ) { - const targetArtifact = await this.db.getFunctionArtifact(targetContractAddress, functionSelector); + const targetArtifact = await this.executionDataProvider.getFunctionArtifact( + targetContractAddress, + functionSelector, + ); const derivedCallContext = await this.deriveCallContext(targetContractAddress, targetArtifact, isStaticCall); const args = this.executionCache.getPreimage(argsHash); @@ -578,23 +585,23 @@ export class ClientExecutionContext extends ViewDataOracle { } public getDebugFunctionName() { - return this.db.getDebugFunctionName(this.contractAddress, this.callContext.functionSelector); + return this.executionDataProvider.getDebugFunctionName(this.contractAddress, this.callContext.functionSelector); } public override async incrementAppTaggingSecretIndexAsSender(sender: AztecAddress, recipient: AztecAddress) { - await this.db.incrementAppTaggingSecretIndexAsSender(this.contractAddress, sender, recipient); + await this.executionDataProvider.incrementAppTaggingSecretIndexAsSender(this.contractAddress, sender, recipient); } public override async syncNotes() { - const taggedLogsByRecipient = await this.db.syncTaggedLogs( + const taggedLogsByRecipient = await this.executionDataProvider.syncTaggedLogs( this.contractAddress, this.historicalHeader.globalVariables.blockNumber.toNumber(), this.scopes, ); for (const [recipient, taggedLogs] of taggedLogsByRecipient.entries()) { - await this.db.processTaggedLogs(taggedLogs, AztecAddress.fromString(recipient)); + await this.executionDataProvider.processTaggedLogs(taggedLogs, AztecAddress.fromString(recipient)); } - await this.db.removeNullifiedNotes(this.contractAddress); + await this.executionDataProvider.removeNullifiedNotes(this.contractAddress); } } diff --git a/yarn-project/simulator/src/private/simulator.ts b/yarn-project/simulator/src/private/simulator.ts index 5f2b7cca4444..c7da62bdc54f 100644 --- a/yarn-project/simulator/src/private/simulator.ts +++ b/yarn-project/simulator/src/private/simulator.ts @@ -3,18 +3,17 @@ import { type Logger, createLogger } from '@aztec/foundation/log'; import type { FunctionCall } from '@aztec/stdlib/abi'; import { FunctionSelector, FunctionType } from '@aztec/stdlib/abi'; import { AztecAddress } from '@aztec/stdlib/aztec-address'; -import type { AztecNode } from '@aztec/stdlib/interfaces/client'; import { CallContext, PrivateExecutionResult, TxExecutionRequest } from '@aztec/stdlib/tx'; import { createSimulationError } from '../common/errors.js'; -import { ClientExecutionContext } from './client_execution_context.js'; -import type { DBOracle } from './db_oracle.js'; +import type { ExecutionDataProvider } from './execution_data_provider.js'; import { ExecutionNoteCache } from './execution_note_cache.js'; import { HashedValuesCache } from './hashed_values_cache.js'; import { executePrivateFunction, verifyCurrentClassId } from './private_execution.js'; +import { PrivateExecutionOracle } from './private_execution_oracle.js'; import type { SimulationProvider } from './providers/simulation_provider.js'; import { executeUnconstrainedFunction } from './unconstrained_execution.js'; -import { ViewDataOracle } from './view_data_oracle.js'; +import { UnconstrainedExecutionOracle } from './unconstrained_execution_oracle.js'; /** * The ACIR simulator. @@ -22,7 +21,7 @@ import { ViewDataOracle } from './view_data_oracle.js'; export class AcirSimulator { private log: Logger; - constructor(private db: DBOracle, private node: AztecNode, private simulationProvider: SimulationProvider) { + constructor(private executionDataProvider: ExecutionDataProvider, private simulationProvider: SimulationProvider) { this.log = createLogger('simulator'); } @@ -42,15 +41,10 @@ export class AcirSimulator { msgSender = AztecAddress.fromField(Fr.MAX_FIELD_VALUE), scopes?: AztecAddress[], ): Promise { - const header = await this.db.getBlockHeader(); + const header = await this.executionDataProvider.getBlockHeader(); - await verifyCurrentClassId( - contractAddress, - await this.db.getContractInstance(contractAddress), - this.node, - header.globalVariables.blockNumber.toNumber(), - ); - const entryPointArtifact = await this.db.getFunctionArtifact(contractAddress, selector); + await verifyCurrentClassId(contractAddress, this.executionDataProvider); + const entryPointArtifact = await this.executionDataProvider.getFunctionArtifact(contractAddress, selector); if (entryPointArtifact.functionType !== FunctionType.PRIVATE) { throw new Error(`Cannot run ${entryPointArtifact.functionType} function as private`); @@ -75,7 +69,7 @@ export class AcirSimulator { const txRequestHash = await request.toTxRequest().hash(); const noteCache = new ExecutionNoteCache(txRequestHash); - const context = new ClientExecutionContext( + const context = new PrivateExecutionOracle( request.firstCallArgsHash, request.txContext, callContext, @@ -84,8 +78,7 @@ export class AcirSimulator { request.capsules, HashedValuesCache.create(request.argsOfCalls), noteCache, - this.db, - this.node, + this.executionDataProvider, this.simulationProvider, startSideEffectCounter, undefined, @@ -121,19 +114,21 @@ export class AcirSimulator { selector: FunctionSelector, scopes?: AztecAddress[], ) { - await verifyCurrentClassId( - contractAddress, - await this.db.getContractInstance(contractAddress), - this.node, - await this.node.getBlockNumber(), - ); - const entryPointArtifact = await this.db.getFunctionArtifact(contractAddress, selector); + await verifyCurrentClassId(contractAddress, this.executionDataProvider); + const entryPointArtifact = await this.executionDataProvider.getFunctionArtifact(contractAddress, selector); if (entryPointArtifact.functionType !== FunctionType.UNCONSTRAINED) { throw new Error(`Cannot run ${entryPointArtifact.functionType} function as unconstrained`); } - const context = new ViewDataOracle(contractAddress, [], [], this.db, this.node, undefined, scopes); + const context = new UnconstrainedExecutionOracle( + contractAddress, + [], + [], + this.executionDataProvider, + undefined, + scopes, + ); try { return await executeUnconstrainedFunction( diff --git a/yarn-project/simulator/src/private/unconstrained_execution.test.ts b/yarn-project/simulator/src/private/unconstrained_execution.test.ts index 2ceb2c00caca..01d7d57b6b2a 100644 --- a/yarn-project/simulator/src/private/unconstrained_execution.test.ts +++ b/yarn-project/simulator/src/private/unconstrained_execution.test.ts @@ -3,33 +3,30 @@ import { StatefulTestContractArtifact } from '@aztec/noir-contracts.js/StatefulT import { FunctionCall, FunctionSelector, FunctionType, encodeArguments } from '@aztec/stdlib/abi'; import { AztecAddress } from '@aztec/stdlib/aztec-address'; import { CompleteAddress, type ContractInstance } from '@aztec/stdlib/contract'; -import type { AztecNode } from '@aztec/stdlib/interfaces/client'; import type { TxScopedL2Log } from '@aztec/stdlib/logs'; import { Note } from '@aztec/stdlib/note'; import { BlockHeader } from '@aztec/stdlib/tx'; import { mock } from 'jest-mock-extended'; -import type { DBOracle } from './db_oracle.js'; +import type { ExecutionDataProvider } from './execution_data_provider.js'; import { WASMSimulator } from './providers/acvm_wasm.js'; import { AcirSimulator } from './simulator.js'; describe('Unconstrained Execution test suite', () => { const simulationProvider = new WASMSimulator(); - let oracle: ReturnType>; - let node: ReturnType>; + let executionDataProvider: ReturnType>; let acirSimulator: AcirSimulator; beforeEach(() => { - oracle = mock(); + executionDataProvider = mock(); - node = mock(); - node.getBlockNumber.mockResolvedValue(42); - node.getChainId.mockResolvedValue(1); - node.getVersion.mockResolvedValue(1); + executionDataProvider.getBlockNumber.mockResolvedValue(42); + executionDataProvider.getChainId.mockResolvedValue(1); + executionDataProvider.getVersion.mockResolvedValue(1); - acirSimulator = new AcirSimulator(oracle, node, simulationProvider); + acirSimulator = new AcirSimulator(executionDataProvider, simulationProvider); }); describe('private token contract', () => { @@ -45,7 +42,7 @@ describe('Unconstrained Execution test suite', () => { const ownerCompleteAddress = await CompleteAddress.fromSecretKeyAndPartialAddress(ownerSecretKey, Fr.random()); owner = ownerCompleteAddress.address; - oracle.getCompleteAddress.mockImplementation((account: AztecAddress) => { + executionDataProvider.getCompleteAddress.mockImplementation((account: AztecAddress) => { if (account.equals(owner)) { return Promise.resolve(ownerCompleteAddress); } @@ -59,17 +56,17 @@ describe('Unconstrained Execution test suite', () => { const notes: Note[] = [...Array(5).fill(buildNote(1n, owner)), ...Array(2).fill(buildNote(2n, owner))]; - node.getBlockNumber.mockResolvedValue(27); - node.getPublicStorageAt.mockResolvedValue(Fr.ZERO); - oracle.getFunctionArtifact.mockResolvedValue(artifact); - oracle.getContractInstance.mockResolvedValue({ + executionDataProvider.getBlockNumber.mockResolvedValue(27); + executionDataProvider.getPublicStorageAt.mockResolvedValue(Fr.ZERO); + executionDataProvider.getFunctionArtifact.mockResolvedValue(artifact); + executionDataProvider.getContractInstance.mockResolvedValue({ currentContractClassId: new Fr(42), originalContractClassId: new Fr(42), } as ContractInstance); - oracle.syncTaggedLogs.mockResolvedValue(new Map()); - oracle.processTaggedLogs.mockResolvedValue(); - oracle.getBlockHeader.mockResolvedValue(BlockHeader.empty()); - oracle.getNotes.mockResolvedValue( + executionDataProvider.syncTaggedLogs.mockResolvedValue(new Map()); + executionDataProvider.processTaggedLogs.mockResolvedValue(); + executionDataProvider.getBlockHeader.mockResolvedValue(BlockHeader.empty()); + executionDataProvider.getNotes.mockResolvedValue( notes.map((note, index) => ({ contractAddress, storageSlot: Fr.random(), @@ -82,8 +79,10 @@ describe('Unconstrained Execution test suite', () => { })), ); - oracle.syncTaggedLogs.mockImplementation((_, __, ___) => Promise.resolve(new Map())); - oracle.loadCapsule.mockImplementation((_, __) => Promise.resolve(null)); + executionDataProvider.syncTaggedLogs.mockImplementation((_, __, ___) => + Promise.resolve(new Map()), + ); + executionDataProvider.loadCapsule.mockImplementation((_, __) => Promise.resolve(null)); const execRequest: FunctionCall = { name: artifact.name, diff --git a/yarn-project/simulator/src/private/unconstrained_execution.ts b/yarn-project/simulator/src/private/unconstrained_execution.ts index dde178bf8aad..01574ec7092d 100644 --- a/yarn-project/simulator/src/private/unconstrained_execution.ts +++ b/yarn-project/simulator/src/private/unconstrained_execution.ts @@ -7,7 +7,7 @@ import { ExecutionError, resolveAssertionMessageFromError } from '../common/erro import { witnessMapToFields } from './acvm/deserialize.js'; import { Oracle, extractCallStack, toACVMWitness } from './acvm/index.js'; import type { SimulationProvider } from './providers/simulation_provider.js'; -import type { ViewDataOracle } from './view_data_oracle.js'; +import type { UnconstrainedExecutionOracle } from './unconstrained_execution_oracle.js'; // docs:start:execute_unconstrained_function /** @@ -15,7 +15,7 @@ import type { ViewDataOracle } from './view_data_oracle.js'; */ export async function executeUnconstrainedFunction( simulatorProvider: SimulationProvider, - oracle: ViewDataOracle, + oracle: UnconstrainedExecutionOracle, artifact: FunctionArtifact, contractAddress: AztecAddress, functionSelector: FunctionSelector, diff --git a/yarn-project/simulator/src/private/view_data_oracle.ts b/yarn-project/simulator/src/private/unconstrained_execution_oracle.ts similarity index 82% rename from yarn-project/simulator/src/private/view_data_oracle.ts rename to yarn-project/simulator/src/private/unconstrained_execution_oracle.ts index 953cd7c7f2b1..770c4a703b23 100644 --- a/yarn-project/simulator/src/private/view_data_oracle.ts +++ b/yarn-project/simulator/src/private/unconstrained_execution_oracle.ts @@ -5,7 +5,6 @@ import type { AuthWitness } from '@aztec/stdlib/auth-witness'; import { AztecAddress } from '@aztec/stdlib/aztec-address'; import type { CompleteAddress, ContractInstance } from '@aztec/stdlib/contract'; import { siloNullifier } from '@aztec/stdlib/hash'; -import type { AztecNode } from '@aztec/stdlib/interfaces/client'; import type { KeyValidationRequest } from '@aztec/stdlib/kernel'; import { IndexedTaggingSecret, LogWithTxData } from '@aztec/stdlib/logs'; import type { NoteStatus } from '@aztec/stdlib/note'; @@ -13,21 +12,19 @@ import { type MerkleTreeId, type NullifierMembershipWitness, PublicDataWitness } import type { BlockHeader, Capsule } from '@aztec/stdlib/tx'; import { type NoteData, TypedOracle } from './acvm/index.js'; -import type { DBOracle } from './db_oracle.js'; +import type { ExecutionDataProvider } from './execution_data_provider.js'; import { pickNotes } from './pick_notes.js'; /** - * The execution context for a client view tx simulation. - * It only reads data from data sources. Nothing will be updated or created during this simulation. + * The oracle for an unconstrained function execution. */ -export class ViewDataOracle extends TypedOracle { +export class UnconstrainedExecutionOracle extends TypedOracle { constructor( protected readonly contractAddress: AztecAddress, /** List of transient auth witnesses to be used during this simulation */ protected readonly authWitnesses: AuthWitness[], protected readonly capsules: Capsule[], - protected readonly db: DBOracle, - protected readonly aztecNode: AztecNode, + protected readonly executionDataProvider: ExecutionDataProvider, protected log = createLogger('simulator:client_view_context'), protected readonly scopes?: AztecAddress[], ) { @@ -35,7 +32,7 @@ export class ViewDataOracle extends TypedOracle { } public override getBlockNumber(): Promise { - return this.aztecNode.getBlockNumber(); + return this.executionDataProvider.getBlockNumber(); } public override getContractAddress(): Promise { @@ -43,11 +40,11 @@ export class ViewDataOracle extends TypedOracle { } public override getChainId(): Promise { - return Promise.resolve(this.aztecNode.getChainId().then(id => new Fr(id))); + return Promise.resolve(this.executionDataProvider.getChainId().then(id => new Fr(id))); } public override getVersion(): Promise { - return Promise.resolve(this.aztecNode.getVersion().then(v => new Fr(v))); + return Promise.resolve(this.executionDataProvider.getVersion().then(v => new Fr(v))); } /** @@ -57,7 +54,7 @@ export class ViewDataOracle extends TypedOracle { * @throws If the keys are not registered in the key store. */ public override getKeyValidationRequest(pkMHash: Fr): Promise { - return this.db.getKeyValidationRequest(pkMHash, this.contractAddress); + return this.executionDataProvider.getKeyValidationRequest(pkMHash, this.contractAddress); } /** @@ -68,7 +65,7 @@ export class ViewDataOracle extends TypedOracle { * @returns The index and sibling path concatenated [index, sibling_path] */ public override getMembershipWitness(blockNumber: number, treeId: MerkleTreeId, leafValue: Fr): Promise { - return this.db.getMembershipWitness(blockNumber, treeId, leafValue); + return this.executionDataProvider.getMembershipWitness(blockNumber, treeId, leafValue); } /** @@ -81,7 +78,7 @@ export class ViewDataOracle extends TypedOracle { blockNumber: number, nullifier: Fr, ): Promise { - return await this.db.getNullifierMembershipWitness(blockNumber, nullifier); + return await this.executionDataProvider.getNullifierMembershipWitness(blockNumber, nullifier); } /** @@ -97,7 +94,7 @@ export class ViewDataOracle extends TypedOracle { blockNumber: number, nullifier: Fr, ): Promise { - return await this.db.getLowNullifierMembershipWitness(blockNumber, nullifier); + return await this.executionDataProvider.getLowNullifierMembershipWitness(blockNumber, nullifier); } /** @@ -110,7 +107,7 @@ export class ViewDataOracle extends TypedOracle { blockNumber: number, leafSlot: Fr, ): Promise { - return await this.db.getPublicDataTreeWitness(blockNumber, leafSlot); + return await this.executionDataProvider.getPublicDataTreeWitness(blockNumber, leafSlot); } /** @@ -119,7 +116,7 @@ export class ViewDataOracle extends TypedOracle { * @returns Block extracted from a block with block number `blockNumber`. */ public override async getBlockHeader(blockNumber: number): Promise { - const block = await this.db.getBlock(blockNumber); + const block = await this.executionDataProvider.getBlock(blockNumber); if (!block) { return undefined; } @@ -133,7 +130,7 @@ export class ViewDataOracle extends TypedOracle { * @throws An error if the account is not registered in the database. */ public override getCompleteAddress(account: AztecAddress): Promise { - return this.db.getCompleteAddress(account); + return this.executionDataProvider.getCompleteAddress(account); } /** @@ -142,7 +139,7 @@ export class ViewDataOracle extends TypedOracle { * @returns A contract instance. */ public override getContractInstance(address: AztecAddress): Promise { - return this.db.getContractInstance(address); + return this.executionDataProvider.getContractInstance(address); } /** @@ -153,7 +150,8 @@ export class ViewDataOracle extends TypedOracle { */ public override getAuthWitness(messageHash: Fr): Promise { return Promise.resolve( - this.authWitnesses.find(w => w.requestHash.equals(messageHash))?.witness ?? this.db.getAuthWitness(messageHash), + this.authWitnesses.find(w => w.requestHash.equals(messageHash))?.witness ?? + this.executionDataProvider.getAuthWitness(messageHash), ); } @@ -194,7 +192,7 @@ export class ViewDataOracle extends TypedOracle { offset: number, status: NoteStatus, ): Promise { - const dbNotes = await this.db.getNotes(this.contractAddress, storageSlot, status, this.scopes); + const dbNotes = await this.executionDataProvider.getNotes(this.contractAddress, storageSlot, status, this.scopes); return pickNotes(dbNotes, { selects: selectByIndexes.slice(0, numSelects).map((index, i) => ({ selector: { index, offset: selectByOffsets[i], length: selectByLengths[i] }, @@ -217,12 +215,12 @@ export class ViewDataOracle extends TypedOracle { */ public override async checkNullifierExists(innerNullifier: Fr) { const nullifier = await siloNullifier(this.contractAddress, innerNullifier!); - const index = await this.db.getNullifierIndex(nullifier); + const index = await this.executionDataProvider.getNullifierIndex(nullifier); return index !== undefined; } /** - * Fetches a message from the db, given its key. + * Fetches a message from the executionDataProvider, given its key. * @param contractAddress - Address of a contract by which the message was emitted. * @param messageHash - Hash of the message. * @param secret - Secret used to compute a nullifier. @@ -230,7 +228,7 @@ export class ViewDataOracle extends TypedOracle { * @returns The l1 to l2 membership witness (index of message in the tree and sibling path). */ public override async getL1ToL2MembershipWitness(contractAddress: AztecAddress, messageHash: Fr, secret: Fr) { - return await this.db.getL1ToL2MembershipWitness(contractAddress, messageHash, secret); + return await this.executionDataProvider.getL1ToL2MembershipWitness(contractAddress, messageHash, secret); } /** @@ -249,7 +247,7 @@ export class ViewDataOracle extends TypedOracle { const values = []; for (let i = 0n; i < numberOfElements; i++) { const storageSlot = new Fr(startStorageSlot.value + i); - const value = await this.aztecNode.getPublicStorageAt(contractAddress, storageSlot, blockNumber); + const value = await this.executionDataProvider.getPublicStorageAt(blockNumber, contractAddress, storageSlot); this.log.debug( `Oracle storage read: slot=${storageSlot.toString()} address-${contractAddress.toString()} value=${value}`, @@ -279,21 +277,21 @@ export class ViewDataOracle extends TypedOracle { sender: AztecAddress, recipient: AztecAddress, ): Promise { - return await this.db.getIndexedTaggingSecretAsSender(this.contractAddress, sender, recipient); + return await this.executionDataProvider.getIndexedTaggingSecretAsSender(this.contractAddress, sender, recipient); } public override async syncNotes() { - const taggedLogsByRecipient = await this.db.syncTaggedLogs( + const taggedLogsByRecipient = await this.executionDataProvider.syncTaggedLogs( this.contractAddress, - await this.aztecNode.getBlockNumber(), + await this.executionDataProvider.getBlockNumber(), this.scopes, ); for (const [recipient, taggedLogs] of taggedLogsByRecipient.entries()) { - await this.db.processTaggedLogs(taggedLogs, AztecAddress.fromString(recipient)); + await this.executionDataProvider.processTaggedLogs(taggedLogs, AztecAddress.fromString(recipient)); } - await this.db.removeNullifiedNotes(this.contractAddress); + await this.executionDataProvider.removeNullifiedNotes(this.contractAddress); } public override async deliverNote( @@ -311,11 +309,20 @@ export class ViewDataOracle extends TypedOracle { throw new Error(`Got a note delivery request from ${contractAddress}, expected ${this.contractAddress}`); } - await this.db.deliverNote(contractAddress, storageSlot, nonce, content, noteHash, nullifier, txHash, recipient); + await this.executionDataProvider.deliverNote( + contractAddress, + storageSlot, + nonce, + content, + noteHash, + nullifier, + txHash, + recipient, + ); } public override getLogByTag(tag: Fr): Promise { - return this.db.getLogByTag(tag); + return this.executionDataProvider.getLogByTag(tag); } public override storeCapsule(contractAddress: AztecAddress, slot: Fr, capsule: Fr[]): Promise { @@ -323,7 +330,7 @@ export class ViewDataOracle extends TypedOracle { // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`); } - return this.db.storeCapsule(this.contractAddress, slot, capsule); + return this.executionDataProvider.storeCapsule(this.contractAddress, slot, capsule); } public override async loadCapsule(contractAddress: AztecAddress, slot: Fr): Promise { @@ -333,7 +340,7 @@ export class ViewDataOracle extends TypedOracle { } return ( this.capsules.find(c => c.contractAddress.equals(contractAddress) && c.storageSlot.equals(slot))?.data ?? - (await this.db.loadCapsule(this.contractAddress, slot)) + (await this.executionDataProvider.loadCapsule(this.contractAddress, slot)) ); } @@ -342,7 +349,7 @@ export class ViewDataOracle extends TypedOracle { // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`); } - return this.db.deleteCapsule(this.contractAddress, slot); + return this.executionDataProvider.deleteCapsule(this.contractAddress, slot); } public override copyCapsule( @@ -355,7 +362,7 @@ export class ViewDataOracle extends TypedOracle { // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`); } - return this.db.copyCapsule(this.contractAddress, srcSlot, dstSlot, numEntries); + return this.executionDataProvider.copyCapsule(this.contractAddress, srcSlot, dstSlot, numEntries); } // TODO(#11849): consider replacing this oracle with a pure Noir implementation of aes decryption. diff --git a/yarn-project/stdlib/src/interfaces/aztec-node.test.ts b/yarn-project/stdlib/src/interfaces/aztec-node.test.ts index d91cab0fa129..cb9c8d13ad40 100644 --- a/yarn-project/stdlib/src/interfaces/aztec-node.test.ts +++ b/yarn-project/stdlib/src/interfaces/aztec-node.test.ts @@ -282,7 +282,7 @@ describe('AztecNodeApiSchema', () => { }); it('getPublicStorageAt', async () => { - const response = await context.client.getPublicStorageAt(await AztecAddress.random(), Fr.random(), 1); + const response = await context.client.getPublicStorageAt(1, await AztecAddress.random(), Fr.random()); expect(response).toBeInstanceOf(Fr); }); @@ -570,7 +570,7 @@ class MockAztecNode implements AztecNode { expect(txHashes[0]).toBeInstanceOf(TxHash); return [await Tx.random()]; } - getPublicStorageAt(contract: AztecAddress, slot: Fr, _blockNumber: number | 'latest'): Promise { + getPublicStorageAt(_blockNumber: number | 'latest', contract: AztecAddress, slot: Fr): Promise { expect(contract).toBeInstanceOf(AztecAddress); expect(slot).toBeInstanceOf(Fr); return Promise.resolve(Fr.random()); diff --git a/yarn-project/stdlib/src/interfaces/aztec-node.ts b/yarn-project/stdlib/src/interfaces/aztec-node.ts index a8e8e3806eea..59ae3d6cf38c 100644 --- a/yarn-project/stdlib/src/interfaces/aztec-node.ts +++ b/yarn-project/stdlib/src/interfaces/aztec-node.ts @@ -396,7 +396,7 @@ export interface AztecNode * @param blockNumber - The block number at which to get the data or 'latest'. * @returns Storage value at the given contract slot. */ - getPublicStorageAt(contract: AztecAddress, slot: Fr, blockNumber: L2BlockNumber): Promise; + getPublicStorageAt(blockNumber: L2BlockNumber, contract: AztecAddress, slot: Fr): Promise; /** * Returns the currently committed block header. @@ -573,7 +573,7 @@ export const AztecNodeApiSchema: ApiSchemaFor = { getTxsByHash: z.function().args(z.array(TxHash.schema)).returns(z.array(Tx.schema)), - getPublicStorageAt: z.function().args(schemas.AztecAddress, schemas.Fr, L2BlockNumberSchema).returns(schemas.Fr), + getPublicStorageAt: z.function().args(L2BlockNumberSchema, schemas.AztecAddress, schemas.Fr).returns(schemas.Fr), getBlockHeader: z.function().args(optional(L2BlockNumberSchema)).returns(BlockHeader.schema.optional()), diff --git a/yarn-project/txe/src/node/txe_node.ts b/yarn-project/txe/src/node/txe_node.ts index 9863013b3720..0e446b3d6ad6 100644 --- a/yarn-project/txe/src/node/txe_node.ts +++ b/yarn-project/txe/src/node/txe_node.ts @@ -582,7 +582,7 @@ export class TXENode implements AztecNode { * @param blockNumber - The block number at which to get the data or 'latest'. * @returns Storage value at the given contract slot. */ - async getPublicStorageAt(contract: AztecAddress, slot: Fr, blockNumber: L2BlockNumber): Promise { + async getPublicStorageAt(blockNumber: L2BlockNumber, contract: AztecAddress, slot: Fr): Promise { const db: MerkleTreeReadOperations = blockNumber === (await this.getBlockNumber()) || blockNumber === 'latest' || blockNumber === undefined ? this.baseFork diff --git a/yarn-project/txe/src/oracle/txe_oracle.ts b/yarn-project/txe/src/oracle/txe_oracle.ts index 41b997211ab9..ff21500e1c79 100644 --- a/yarn-project/txe/src/oracle/txe_oracle.ts +++ b/yarn-project/txe/src/oracle/txe_oracle.ts @@ -16,7 +16,7 @@ import { Fr } from '@aztec/foundation/fields'; import { type LogFn, type Logger, applyStringFormatting, createDebugOnlyLogger } from '@aztec/foundation/log'; import { Timer } from '@aztec/foundation/timer'; import type { KeyStore } from '@aztec/key-store'; -import { ContractDataOracle, SimulatorOracle, enrichPublicSimulationError } from '@aztec/pxe'; +import { ContractDataProvider, PXEDataProvider, enrichPublicSimulationError } from '@aztec/pxe'; import { ExecutionNoteCache, type HashedValuesCache, @@ -24,7 +24,7 @@ import { type NoteData, Oracle, type TypedOracle, - ViewDataOracle, + UnconstrainedExecutionOracle, WASMSimulator, extractCallStack, extractPrivateCircuitPublicInputs, @@ -99,9 +99,9 @@ export class TXE implements TypedOracle { // Return/revert data of the latest nested call. private nestedCallReturndata: Fr[] = []; - private contractDataOracle: ContractDataOracle; - private simulatorOracle: SimulatorOracle; - private viewDataOracle: ViewDataOracle; + private contractDataProvider: ContractDataProvider; + private pxeDataProvider: PXEDataProvider; + private viewDataOracle: UnconstrainedExecutionOracle; private publicDataWrites: PublicDataWrite[] = []; private uniqueNoteHashesFromPublic: Fr[] = []; @@ -132,26 +132,25 @@ export class TXE implements TypedOracle { private baseFork: MerkleTreeWriteOperations, ) { this.noteCache = new ExecutionNoteCache(this.getTxRequestHash()); - this.contractDataOracle = new ContractDataOracle(txeDatabase); + this.contractDataProvider = new ContractDataProvider(txeDatabase); this.node = new TXENode(this.blockNumber, this.VERSION, this.CHAIN_ID, nativeWorldStateService, baseFork); // Default msg_sender (for entrypoints) is now Fr.max_value rather than 0 addr (see #7190 & #7404) this.msgSender = AztecAddress.fromField(Fr.MAX_FIELD_VALUE); - this.simulatorOracle = new SimulatorOracle( - this.contractDataOracle, + this.pxeDataProvider = new PXEDataProvider( txeDatabase, keyStore, this.node, this.simulationProvider, + this.contractDataProvider, ); - this.viewDataOracle = new ViewDataOracle( + this.viewDataOracle = new UnconstrainedExecutionOracle( this.contractAddress, [] /* authWitnesses */, [] /* capsules */, - this.simulatorOracle, // note: SimulatorOracle implements DBOracle - this.node, + this.pxeDataProvider, // note: PXEDataProvider implements ExecutionDataProvider /* log, */ /* scopes, */ ); @@ -229,8 +228,8 @@ export class TXE implements TypedOracle { this.node.setBlockNumber(blockNumber); } - getContractDataOracle() { - return this.contractDataOracle; + getContractDataProvider() { + return this.contractDataProvider; } getTXEDatabase() { @@ -381,7 +380,7 @@ export class TXE implements TypedOracle { } async getContractInstance(address: AztecAddress): Promise { - const contractInstance = await this.contractDataOracle.getContractInstance(address); + const contractInstance = await this.contractDataProvider.getContractInstance(address); if (!contractInstance) { throw new Error(`Contract instance not found for address ${address}`); } @@ -528,7 +527,7 @@ export class TXE implements TypedOracle { const pendingNotes = this.noteCache.getNotes(this.contractAddress, storageSlot); const pendingNullifiers = this.noteCache.getNullifiers(this.contractAddress); - const dbNotes = await this.simulatorOracle.getNotes(this.contractAddress, storageSlot, status); + const dbNotes = await this.pxeDataProvider.getNotes(this.contractAddress, storageSlot, status); const dbNotesFiltered = dbNotes.filter(n => !pendingNullifiers.has((n.siloedNullifier as Fr).value)); const notes = pickNotes([...dbNotesFiltered, ...pendingNotes], { @@ -786,7 +785,7 @@ export class TXE implements TypedOracle { this.setContractAddress(targetContractAddress); this.setFunctionSelector(functionSelector); - const artifact = await this.contractDataOracle.getFunctionArtifact(targetContractAddress, functionSelector); + const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector); const acir = artifact.bytecode; const initialWitness = await this.getInitialWitness(artifact, argsHash, sideEffectCounter, isStaticCall); @@ -862,11 +861,11 @@ export class TXE implements TypedOracle { } public async getDebugFunctionName(address: AztecAddress, selector: FunctionSelector): Promise { - const instance = await this.contractDataOracle.getContractInstance(address); + const instance = await this.contractDataProvider.getContractInstance(address); if (!instance) { return undefined; } - const artifact = await this.contractDataOracle.getContractArtifact(instance!.currentContractClassId); + const artifact = await this.contractDataProvider.getContractArtifact(instance!.currentContractClassId); if (!artifact) { return undefined; } @@ -988,7 +987,7 @@ export class TXE implements TypedOracle { if (executionResult.revertReason && executionResult.revertReason instanceof SimulationError) { await enrichPublicSimulationError( executionResult.revertReason, - this.contractDataOracle, + this.contractDataProvider, this.txeDatabase, this.logger, ); @@ -1064,17 +1063,17 @@ export class TXE implements TypedOracle { } async syncNotes() { - const taggedLogsByRecipient = await this.simulatorOracle.syncTaggedLogs( + const taggedLogsByRecipient = await this.pxeDataProvider.syncTaggedLogs( this.contractAddress, await this.getBlockNumber(), undefined, ); for (const [recipient, taggedLogs] of taggedLogsByRecipient.entries()) { - await this.simulatorOracle.processTaggedLogs(taggedLogs, AztecAddress.fromString(recipient)); + await this.pxeDataProvider.processTaggedLogs(taggedLogs, AztecAddress.fromString(recipient)); } - await this.simulatorOracle.removeNullifiedNotes(this.contractAddress); + await this.pxeDataProvider.removeNullifiedNotes(this.contractAddress); return Promise.resolve(); } @@ -1093,7 +1092,7 @@ export class TXE implements TypedOracle { } async getLogByTag(tag: Fr): Promise { - return await this.simulatorOracle.getLogByTag(tag); + return await this.pxeDataProvider.getLogByTag(tag); } // AVM oracles diff --git a/yarn-project/txe/src/txe_service/txe_service.ts b/yarn-project/txe/src/txe_service/txe_service.ts index 27aeba46f068..4b7042fc4d16 100644 --- a/yarn-project/txe/src/txe_service/txe_service.ts +++ b/yarn-project/txe/src/txe_service/txe_service.ts @@ -714,7 +714,7 @@ export class TXEService { if (result.revertReason && result.revertReason instanceof SimulationError) { await enrichPublicSimulationError( result.revertReason, - (this.typedOracle as TXE).getContractDataOracle(), + (this.typedOracle as TXE).getContractDataProvider(), (this.typedOracle as TXE).getTXEDatabase(), this.logger, ); @@ -744,7 +744,7 @@ export class TXEService { if (result.revertReason && result.revertReason instanceof SimulationError) { await enrichPublicSimulationError( result.revertReason, - (this.typedOracle as TXE).getContractDataOracle(), + (this.typedOracle as TXE).getContractDataProvider(), (this.typedOracle as TXE).getTXEDatabase(), this.logger, ); diff --git a/yarn-project/txe/src/util/txe_public_contract_data_source.ts b/yarn-project/txe/src/util/txe_public_contract_data_source.ts index b98083453fbd..6014dd3b3faf 100644 --- a/yarn-project/txe/src/util/txe_public_contract_data_source.ts +++ b/yarn-project/txe/src/util/txe_public_contract_data_source.ts @@ -17,7 +17,7 @@ export class TXEPublicContractDataSource implements ContractDataSource { constructor(private txeOracle: TXE) {} async getPublicFunction(address: AztecAddress, selector: FunctionSelector): Promise { - const bytecode = await this.txeOracle.getContractDataOracle().getBytecode(address, selector); + const bytecode = await this.txeOracle.getContractDataProvider().getBytecode(address, selector); if (!bytecode) { return undefined; } @@ -29,8 +29,8 @@ export class TXEPublicContractDataSource implements ContractDataSource { } async getContractClass(id: Fr): Promise { - const contractClass = await this.txeOracle.getContractDataOracle().getContractClass(id); - const artifact = await this.txeOracle.getContractDataOracle().getContractArtifact(id); + const contractClass = await this.txeOracle.getContractDataProvider().getContractClass(id); + const artifact = await this.txeOracle.getContractDataProvider().getContractArtifact(id); const tree = await PrivateFunctionsTree.create(artifact); const privateFunctionsRoot = await tree.getFunctionTreeRoot(); @@ -55,12 +55,12 @@ export class TXEPublicContractDataSource implements ContractDataSource { } async getBytecodeCommitment(id: Fr): Promise { - const contractClass = await this.txeOracle.getContractDataOracle().getContractClass(id); + const contractClass = await this.txeOracle.getContractDataProvider().getContractClass(id); return computePublicBytecodeCommitment(contractClass.packedBytecode); } async getContract(address: AztecAddress): Promise { - const instance = await this.txeOracle.getContractDataOracle().getContractInstance(address); + const instance = await this.txeOracle.getContractDataProvider().getContractInstance(address); return { ...instance, address }; } @@ -69,8 +69,8 @@ export class TXEPublicContractDataSource implements ContractDataSource { } async getContractArtifact(address: AztecAddress): Promise { - const instance = await this.txeOracle.getContractDataOracle().getContractInstance(address); - return this.txeOracle.getContractDataOracle().getContractArtifact(instance.currentContractClassId); + const instance = await this.txeOracle.getContractDataProvider().getContractInstance(address); + return this.txeOracle.getContractDataProvider().getContractArtifact(instance.currentContractClassId); } async getContractFunctionName(address: AztecAddress, selector: FunctionSelector): Promise {