Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion yarn-project/accounts/src/testing/create_account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ export async function createAccounts(
let skipClassRegistration = true;
if (index === 0) {
// for the first account, check if the contract class is already registered, otherwise we should register now
if (!(await pxe.isContractClassPubliclyRegistered(account.getInstance().contractClassId))) {
if (
!(await pxe.getContractClassMetadata(account.getInstance().contractClassId)).isContractClassPubliclyRegistered
) {
skipClassRegistration = false;
}
}
Expand Down
6 changes: 5 additions & 1 deletion yarn-project/aztec.js/src/contract/contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,11 @@ describe('Contract Class', () => {
wallet = mock<Wallet>();
wallet.simulateTx.mockResolvedValue(mockTxSimulationResult);
wallet.createTxExecutionRequest.mockResolvedValue(mockTxRequest);
wallet.getContractInstance.mockResolvedValue(contractInstance);
wallet.getContractMetadata.mockResolvedValue({
contractInstance,
isContractInitialized: true,
isContractPubliclyDeployed: true,
});
wallet.sendTx.mockResolvedValue(mockTxHash);
wallet.simulateUnconstrained.mockResolvedValue(mockUnconstrainedResultValue as any as AbiDecoded);
wallet.getTxReceipt.mockResolvedValue(mockTxReceipt);
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/aztec.js/src/contract/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class Contract extends ContractBase {
* @returns A promise that resolves to a new Contract instance.
*/
public static async at(address: AztecAddress, artifact: ContractArtifact, wallet: Wallet): Promise<Contract> {
const instance = await wallet.getContractInstance(address);
const instance = (await wallet.getContractMetadata(address)).contractInstance;
if (instance === undefined) {
throw new Error(`Contract instance at ${address.toString()} has not been registered in the wallet's PXE`);
}
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/aztec.js/src/contract/deploy_method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export class DeployMethod<TContract extends ContractBase = Contract> extends Bas

// Register the contract class if it hasn't been published already.
if (!options.skipClassRegistration) {
if (await this.wallet.isContractClassPubliclyRegistered(contractClass.id)) {
if ((await this.wallet.getContractClassMetadata(contractClass.id)).isContractClassPubliclyRegistered) {
this.log.debug(
`Skipping registration of already registered contract class ${contractClass.id.toString()} for ${instance.address.toString()}`,
);
Expand Down
27 changes: 8 additions & 19 deletions yarn-project/aztec.js/src/wallet/base_wallet.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import {
type AuthWitness,
type ContractClassMetadata,
type ContractMetadata,
type EventMetadataDefinition,
type ExtendedNote,
type GetContractClassLogsResponse,
Expand All @@ -22,7 +24,6 @@ import {
import {
type AztecAddress,
type CompleteAddress,
type ContractClassWithId,
type ContractInstanceWithAddress,
type Fr,
type GasFees,
Expand Down Expand Up @@ -66,15 +67,6 @@ export abstract class BaseWallet implements Wallet {
getAddress() {
return this.getCompleteAddress().address;
}
getContractInstance(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
return this.pxe.getContractInstance(address);
}
getContractClass(id: Fr): Promise<ContractClassWithId | undefined> {
return this.pxe.getContractClass(id);
}
getContractArtifact(id: Fr): Promise<ContractArtifact | undefined> {
return this.pxe.getContractArtifact(id);
}
addCapsule(capsule: Fr[]): Promise<void> {
return this.pxe.addCapsule(capsule);
}
Expand Down Expand Up @@ -182,18 +174,15 @@ export abstract class BaseWallet implements Wallet {
getAuthWitness(messageHash: Fr) {
return this.pxe.getAuthWitness(messageHash);
}
isContractClassPubliclyRegistered(id: Fr): Promise<boolean> {
return this.pxe.isContractClassPubliclyRegistered(id);
}
isContractPubliclyDeployed(address: AztecAddress): Promise<boolean> {
return this.pxe.isContractPubliclyDeployed(address);
}
isContractInitialized(address: AztecAddress): Promise<boolean> {
return this.pxe.isContractInitialized(address);
}
getPXEInfo(): Promise<PXEInfo> {
return this.pxe.getPXEInfo();
}
getContractClassMetadata(id: Fr, includeArtifact: boolean = false): Promise<ContractClassMetadata> {
return this.pxe.getContractClassMetadata(id, includeArtifact);
}
getContractMetadata(address: AztecAddress): Promise<ContractMetadata> {
return this.pxe.getContractMetadata(address);
}
getPrivateEvents<T>(
event: EventMetadataDefinition,
from: number,
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/bot/src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export class BotFactory {
const salt = Fr.ONE;
const signingKey = deriveSigningKey(this.config.senderPrivateKey);
const account = await getSchnorrAccount(this.pxe, this.config.senderPrivateKey, signingKey, salt);
const isInit = await this.pxe.isContractInitialized(account.getAddress());
const isInit = (await this.pxe.getContractMetadata(account.getAddress())).isContractInitialized;
if (isInit) {
this.log.info(`Account at ${account.getAddress().toString()} already initialized`);
const wallet = await account.register();
Expand Down Expand Up @@ -112,7 +112,7 @@ export class BotFactory {
}

const address = (await deploy.getInstance(deployOpts)).address;
if (await this.pxe.isContractPubliclyDeployed(address)) {
if ((await this.pxe.getContractMetadata(address)).isContractPubliclyDeployed) {
this.log.info(`Token at ${address.toString()} already deployed`);
return deploy.register();
} else {
Expand Down
83 changes: 35 additions & 48 deletions yarn-project/circuit-types/src/interfaces/pxe.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {
AztecAddress,
ClientIvcProof,
CompleteAddress,
type ContractClassWithId,
type ContractInstanceWithAddress,
EthAddress,
Fr,
Expand Down Expand Up @@ -48,7 +47,14 @@ import { SiblingPath } from '../sibling_path/sibling_path.js';
import { Tx, TxHash, TxProvingResult, TxReceipt, TxSimulationResult } from '../tx/index.js';
import { TxEffect } from '../tx_effect.js';
import { TxExecutionRequest } from '../tx_execution_request.js';
import { type EventMetadataDefinition, type PXE, type PXEInfo, PXESchema } from './pxe.js';
import {
type ContractClassMetadata,
type ContractMetadata,
type EventMetadataDefinition,
type PXE,
type PXEInfo,
PXESchema,
} from './pxe.js';

jest.setTimeout(12_000);

Expand Down Expand Up @@ -275,39 +281,28 @@ describe('PXESchema', () => {
expect(result).toEqual(await handler.getPXEInfo());
});

it('getContractInstance', async () => {
const result = await context.client.getContractInstance(address);
expect(result).toEqual(instance);
it('getContractMetadata', async () => {
const { contractInstance, isContractInitialized, isContractPubliclyDeployed } =
await context.client.getContractMetadata(address);
expect(contractInstance).toEqual(instance);
expect(isContractInitialized).toEqual(true);
expect(isContractPubliclyDeployed).toEqual(true);
});

it('getContractClass', async () => {
const result = await context.client.getContractClass(Fr.random());
it('getContractClassMetadata', async () => {
const {
contractClass,
isContractClassPubliclyRegistered,
artifact: contractArtifact,
} = await context.client.getContractClassMetadata(Fr.random(), true);
const expected = omit(
await getContractClassFromArtifact(artifact),
'privateFunctionsRoot',
'publicBytecodeCommitment',
);
expect(result).toEqual(expected);
});

it('getContractArtifact', async () => {
const result = await context.client.getContractArtifact(Fr.random());
deepStrictEqual(result, artifact);
});

it('isContractClassPubliclyRegistered', async () => {
const result = await context.client.isContractClassPubliclyRegistered(Fr.random());
expect(result).toBe(true);
});

it('isContractPubliclyDeployed', async () => {
const result = await context.client.isContractPubliclyDeployed(address);
expect(result).toBe(true);
});

it('isContractInitialized', async () => {
const result = await context.client.isContractInitialized(address);
expect(result).toBe(true);
expect(contractClass).toEqual(expected);
expect(isContractClassPubliclyRegistered).toEqual(true);
deepStrictEqual(contractArtifact, artifact);
});

it('getPrivateEvents', async () => {
Expand Down Expand Up @@ -520,30 +515,22 @@ class MockPXE implements PXE {
pxeVersion: '1.0',
});
}
getContractInstance(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
expect(address).toEqual(this.address);
return Promise.resolve(this.instance);
}
async getContractClass(id: Fr): Promise<ContractClassWithId | undefined> {
async getContractClassMetadata(id: Fr, includeArtifact: boolean = false): Promise<ContractClassMetadata> {
expect(id).toBeInstanceOf(Fr);
const contractClass = await getContractClassFromArtifact(this.artifact);
return contractClass;
}
getContractArtifact(id: Fr): Promise<ContractArtifact | undefined> {
expect(id).toBeInstanceOf(Fr);
return Promise.resolve(this.artifact);
}
isContractClassPubliclyRegistered(id: Fr): Promise<boolean> {
expect(id).toBeInstanceOf(Fr);
return Promise.resolve(true);
}
isContractPubliclyDeployed(address: AztecAddress): Promise<boolean> {
expect(address).toEqual(this.address);
return Promise.resolve(true);
return Promise.resolve({
contractClass,
isContractClassPubliclyRegistered: true,
artifact: includeArtifact ? this.artifact : undefined,
});
}
isContractInitialized(address: AztecAddress): Promise<boolean> {
getContractMetadata(address: AztecAddress): Promise<ContractMetadata> {
expect(address).toEqual(this.address);
return Promise.resolve(true);
return Promise.resolve({
contractInstance: this.instance,
isContractInitialized: true,
isContractPubliclyDeployed: true,
});
}
getPrivateEvents<T>(
_eventMetadata: EventMetadataDefinition,
Expand Down
91 changes: 43 additions & 48 deletions yarn-project/circuit-types/src/interfaces/pxe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,49 +353,33 @@ export interface PXE {
getPXEInfo(): Promise<PXEInfo>;

/**
* Returns a Contract Instance given its address, which includes the contract class identifier,
* initialization hash, deployment salt, and public keys hash.
* Returns the contract metadata given an address.
* The metadata consists of its contract instance, which includes the contract class identifier,
* initialization hash, deployment salt, and public keys hash; whether the contract instance has been initialized;
* and whether the contract instance with the given address has been publicly deployed.
* @remark - it queries the node to check whether the contract instance has been initialized / publicly deployed through a node.
* This query is not dependent on the PXE.
* @param address - The address that the contract instance resides at.
* @returns - It returns the contract metadata
* TODO(@spalladino): Should we return the public keys in plain as well here?
* @param address - Deployment address of the contract.
*/
getContractInstance(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined>;
getContractMetadata(address: AztecAddress): Promise<ContractMetadata>;

/**
* Returns a Contract Class given its identifier.
* Returns the contract class metadata given a contract class id.
* The metadata consists of its contract class, whether it has been publicly registered, and its artifact.
* @remark - it queries the node to check whether the contract class with the given id has been publicly registered.
* @param id - Identifier of the class.
* @param includeArtifact - Identifier of the class.
* @returns - It returns the contract class metadata, with the artifact field being optional, and will only be returned if true is passed in
* for `includeArtifact`
* TODO(@spalladino): The PXE actually holds artifacts and not classes, what should we return? Also,
* should the pxe query the node for contract public info, and merge it with its own definitions?
* @param id - Identifier of the class.
*/
getContractClass(id: Fr): Promise<ContractClassWithId | undefined>;

/**
* Returns the contract artifact associated to a contract class.
* @param id - Identifier of the class.
*/
getContractArtifact(id: Fr): Promise<ContractArtifact | undefined>;

/**
* Queries the node to check whether the contract class with the given id has been publicly registered.
* TODO(@spalladino): This method is strictly needed to decide whether to publicly register a class or not
* during a public deployment. We probably want a nicer and more general API for this, but it'll have to
* do for the time being.
* @param id - Identifier of the class.
*/
isContractClassPubliclyRegistered(id: Fr): Promise<boolean>;

/**
* Queries the node to check whether the contract instance with the given address has been publicly deployed,
* regardless of whether this PXE knows about the contract or not.
* TODO(@spalladino): Same notes as above.
*/
isContractPubliclyDeployed(address: AztecAddress): Promise<boolean>;

/**
* Queries the node to check whether the contract instance with the given address has been initialized,
* by checking the standard initialization nullifier.
* @param address - Address of the contract to check.
*/
isContractInitialized(address: AztecAddress): Promise<boolean>;
getContractClassMetadata(id: Fr, includeArtifact?: boolean): Promise<ContractClassMetadata>;

/**
* Returns the private events given search parameters.
Expand Down Expand Up @@ -444,6 +428,30 @@ export interface PXEInfo {
protocolContractAddresses: ProtocolContractAddresses;
}

export interface ContractMetadata {
contractInstance?: ContractInstanceWithAddress | undefined;
isContractInitialized: boolean;
isContractPubliclyDeployed: boolean;
}

export interface ContractClassMetadata {
contractClass?: ContractClassWithId | undefined;
isContractClassPubliclyRegistered: boolean;
artifact?: ContractArtifact | undefined;
}

const ContractMetadataSchema = z.object({
contractInstance: z.union([ContractInstanceWithAddressSchema, z.undefined()]),
isContractInitialized: z.boolean(),
isContractPubliclyDeployed: z.boolean(),
}) satisfies ZodFor<ContractMetadata>;

const ContractClassMetadataSchema = z.object({
contractClass: z.union([ContractClassWithIdSchema, z.undefined()]),
isContractClassPubliclyRegistered: z.boolean(),
artifact: z.union([ContractArtifactSchema, z.undefined()]),
}) satisfies ZodFor<ContractClassMetadata>;

const PXEInfoSchema = z.object({
pxeVersion: z.string(),
protocolContractAddresses: ProtocolContractAddressesSchema,
Expand Down Expand Up @@ -521,21 +529,8 @@ export const PXESchema: ApiSchemaFor<PXE> = {
getProvenBlockNumber: z.function().returns(z.number()),
getNodeInfo: z.function().returns(NodeInfoSchema),
getPXEInfo: z.function().returns(PXEInfoSchema),
getContractInstance: z
.function()
.args(schemas.AztecAddress)
.returns(z.union([ContractInstanceWithAddressSchema, z.undefined()])),
getContractClass: z
.function()
.args(schemas.Fr)
.returns(z.union([ContractClassWithIdSchema, z.undefined()])),
getContractArtifact: z
.function()
.args(schemas.Fr)
.returns(z.union([ContractArtifactSchema, z.undefined()])),
isContractClassPubliclyRegistered: z.function().args(schemas.Fr).returns(z.boolean()),
isContractPubliclyDeployed: z.function().args(schemas.AztecAddress).returns(z.boolean()),
isContractInitialized: z.function().args(schemas.AztecAddress).returns(z.boolean()),
getContractMetadata: z.function().args(schemas.AztecAddress).returns(ContractMetadataSchema),
getContractClassMetadata: z.function().args(schemas.Fr, optional(z.boolean())).returns(ContractClassMetadataSchema),
getPrivateEvents: z
.function()
.args(EventMetadataDefinitionSchema, z.number(), z.number(), z.array(schemas.Point))
Expand Down
11 changes: 7 additions & 4 deletions yarn-project/cli/src/cmds/pxe/get_contract_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ export async function getContractData(
log: LogFn,
) {
const client = await createCompatibleClient(rpcUrl, debugLogger);
const instance = await client.getContractInstance(contractAddress);
const contractClass = includeBytecode && instance && (await client.getContractClass(instance?.contractClassId));
const {
contractInstance: instance,
isContractInitialized: isInitialized,
isContractPubliclyDeployed: isPubliclyDeployed,
} = await client.getContractMetadata(contractAddress);
const contractClass =
includeBytecode && instance && (await client.getContractClassMetadata(instance?.contractClassId)).contractClass;

const isPrivatelyDeployed = !!instance;
const isPubliclyDeployed = await client.isContractPubliclyDeployed(contractAddress);
const isInitialized = await client.isContractInitialized(contractAddress);
const initStr = isInitialized ? 'initialized' : 'not initialized';
const addrStr = contractAddress.toString();

Expand Down
Loading
Loading