Skip to content

Commit

Permalink
refactor: only store function names
Browse files Browse the repository at this point in the history
  • Loading branch information
alexghr committed Dec 16, 2024
1 parent 5e4b46d commit 72a9a67
Show file tree
Hide file tree
Showing 17 changed files with 73 additions and 122 deletions.
16 changes: 4 additions & 12 deletions yarn-project/archiver/src/archiver/archiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import {
isValidUnconstrainedFunctionMembershipProof,
} from '@aztec/circuits.js';
import { createEthereumChain } from '@aztec/ethereum';
import { type ContractArtifact } from '@aztec/foundation/abi';
import { type AztecAddress } from '@aztec/foundation/aztec-address';
import { type EthAddress } from '@aztec/foundation/eth-address';
import { Fr } from '@aztec/foundation/fields';
Expand Down Expand Up @@ -766,12 +765,8 @@ export class Archiver implements ArchiveSource, Traceable {
return;
}

addContractArtifact(address: AztecAddress, artifact: ContractArtifact): Promise<void> {
return this.store.addContractArtifact(address, artifact);
}

getContractArtifact(address: AztecAddress): Promise<ContractArtifact | undefined> {
return this.store.getContractArtifact(address);
registerContractFunctionNames(address: AztecAddress, names: Record<string, string>): Promise<void> {
return this.store.registerContractFunctionName(address, names);
}

getContractFunctionName(address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
Expand Down Expand Up @@ -1078,11 +1073,8 @@ class ArchiverStoreHelper
getContractClassIds(): Promise<Fr[]> {
return this.store.getContractClassIds();
}
addContractArtifact(address: AztecAddress, contract: ContractArtifact): Promise<void> {
return this.store.addContractArtifact(address, contract);
}
getContractArtifact(address: AztecAddress): Promise<ContractArtifact | undefined> {
return this.store.getContractArtifact(address);
registerContractFunctionName(address: AztecAddress, names: Record<string, string>): Promise<void> {
return this.store.registerContractFunctionName(address, names);
}
getContractFunctionName(address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
return this.store.getContractFunctionName(address, selector);
Expand Down
4 changes: 1 addition & 3 deletions yarn-project/archiver/src/archiver/archiver_store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,12 +261,10 @@ export interface ArchiverDataStore {
/** Returns the list of all class ids known by the archiver. */
getContractClassIds(): Promise<Fr[]>;

addContractArtifact(address: AztecAddress, contract: ContractArtifact): Promise<void>;
getContractArtifact(address: AztecAddress): Promise<ContractArtifact | undefined>;

// TODO: These function names are in memory only as they are for development/debugging. They require the full contract
// artifact supplied to the node out of band. This should be reviewed and potentially removed as part of
// the node api cleanup process.
registerContractFunctionName(address: AztecAddress, names: Record<string, string>): Promise<void>;
getContractFunctionName(address: AztecAddress, selector: FunctionSelector): Promise<string | undefined>;

/**
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
type PrivateLog,
type UnconstrainedFunctionWithMembershipProof,
} from '@aztec/circuits.js';
import { type ContractArtifact, FunctionSelector } from '@aztec/foundation/abi';
import { FunctionSelector } from '@aztec/foundation/abi';
import { type AztecAddress } from '@aztec/foundation/aztec-address';
import { createLogger } from '@aztec/foundation/log';
import { type AztecKVStore } from '@aztec/kv-store';
Expand All @@ -26,7 +26,6 @@ import { type ArchiverDataStore, type ArchiverL1SynchPoint } from '../archiver_s
import { type DataRetrieval } from '../structs/data_retrieval.js';
import { type L1Published } from '../structs/published.js';
import { BlockStore } from './block_store.js';
import { ContractArtifactsStore } from './contract_artifacts_store.js';
import { ContractClassStore } from './contract_class_store.js';
import { ContractInstanceStore } from './contract_instance_store.js';
import { LogStore } from './log_store.js';
Expand All @@ -43,7 +42,6 @@ export class KVArchiverDataStore implements ArchiverDataStore {
#messageStore: MessageStore;
#contractClassStore: ContractClassStore;
#contractInstanceStore: ContractInstanceStore;
#contractArtifactStore: ContractArtifactsStore;
private functionNames = new Map<string, string>();

#log = createLogger('archiver:data-store');
Expand All @@ -54,27 +52,22 @@ export class KVArchiverDataStore implements ArchiverDataStore {
this.#messageStore = new MessageStore(db);
this.#contractClassStore = new ContractClassStore(db);
this.#contractInstanceStore = new ContractInstanceStore(db);
this.#contractArtifactStore = new ContractArtifactsStore(db);
this.#nullifierStore = new NullifierStore(db);
}

getContractArtifact(address: AztecAddress): Promise<ContractArtifact | undefined> {
return Promise.resolve(this.#contractArtifactStore.getContractArtifact(address));
}

// TODO: These function names are in memory only as they are for development/debugging. They require the full contract
// artifact supplied to the node out of band. This should be reviewed and potentially removed as part of
// the node api cleanup process.
getContractFunctionName(address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
getContractFunctionName(_address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
return Promise.resolve(this.functionNames.get(selector.toString()));
}

async addContractArtifact(address: AztecAddress, contract: ContractArtifact): Promise<void> {
await this.#contractArtifactStore.addContractArtifact(address, contract);
// Building tup this map of selectors to function names save expensive re-hydration of contract artifacts later
contract.functions.forEach(f => {
this.functionNames.set(FunctionSelector.fromNameAndParameters(f.name, f.parameters).toString(), f.name);
});
async registerContractFunctionName(_address: AztecAddress, names: Record<string, string>): Promise<void> {
for (const [selector, name] of Object.entries(names)) {
this.functionNames.set(selector, name);
}

return Promise.resolve();
}

getContractClass(id: Fr): Promise<ContractClassPublic | undefined> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ export class MemoryArchiverStore implements ArchiverDataStore {
private lastProvenL2BlockNumber: number = 0;
private lastProvenL2EpochNumber: number = 0;

private functionNames = new Map<string, string>();

#log = createLogger('archiver:data-store');

constructor(
Expand Down Expand Up @@ -739,17 +741,16 @@ export class MemoryArchiverStore implements ArchiverDataStore {
return Promise.resolve(this.contractArtifacts.get(address.toString()));
}

async getContractFunctionName(address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
const artifact = await this.getContractArtifact(address);
public getContractFunctionName(_address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
return Promise.resolve(this.functionNames.get(selector.toString()));
}

if (!artifact) {
return undefined;
public registerContractFunctionName(_address: AztecAddress, names: Record<string, string>): Promise<void> {
for (const [selector, name] of Object.entries(names)) {
this.functionNames.set(selector, name);
}

const func = artifact.functions.find(f =>
FunctionSelector.fromNameAndParameters({ name: f.name, parameters: f.parameters }).equals(selector),
);
return Promise.resolve(func?.name);
return Promise.resolve();
}

public estimateSize(): { mappingSize: number; actualSize: number; numItems: number } {
Expand Down
11 changes: 10 additions & 1 deletion yarn-project/archiver/src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
computePublicBytecodeCommitment,
getContractClassFromArtifact,
} from '@aztec/circuits.js';
import { FunctionSelector, FunctionType } from '@aztec/foundation/abi';
import { createLogger } from '@aztec/foundation/log';
import { type Maybe } from '@aztec/foundation/types';
import { type DataStoreConfig } from '@aztec/kv-store/config';
Expand Down Expand Up @@ -43,7 +44,15 @@ async function registerProtocolContracts(store: KVArchiverDataStore) {
privateFunctions: [],
unconstrainedFunctions: [],
};
await store.addContractArtifact(contract.address, contract.artifact);

const functionNames: Record<string, string> = {};
for (const fn of contract.artifact.functions) {
if (fn.functionType === FunctionType.PUBLIC) {
functionNames[FunctionSelector.fromNameAndParameters(fn.name, fn.parameters).toString()] = fn.name;
}
}

await store.registerContractFunctionName(contract.address, functionNames);
const bytecodeCommitment = computePublicBytecodeCommitment(contractClassPublic.packedBytecode);
await store.addContractClasses([contractClassPublic], [bytecodeCommitment], blockNumber);
await store.addContractInstances([contract.instance], blockNumber);
Expand Down
6 changes: 2 additions & 4 deletions yarn-project/aztec-node/src/aztec-node/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -903,10 +903,8 @@ export class AztecNodeService implements AztecNode, Traceable {
return this.contractDataSource.addContractClass(contractClass);
}

public addContractArtifact(address: AztecAddress, artifact: ContractArtifact): Promise<void> {
this.log.info(`Adding contract artifact ${artifact.name} for ${address.toString()} via API`);
// TODO: Node should validate the artifact before accepting it
return this.contractDataSource.addContractArtifact(address, artifact);
public registerContractFunctionNames(_address: AztecAddress, names: Record<string, string>): Promise<void> {
return this.contractDataSource.registerContractFunctionNames(names);
}

public flushTxs(): Promise<void> {
Expand Down
17 changes: 6 additions & 11 deletions yarn-project/circuit-types/src/interfaces/archiver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { type JsonRpcTestContext, createJsonRpcTestSetup } from '@aztec/foundati
import { fileURLToPath } from '@aztec/foundation/url';
import { loadContractArtifact } from '@aztec/types/abi';

import { deepStrictEqual } from 'assert';
import { readFileSync } from 'fs';
import omit from 'lodash.omit';
import { resolve } from 'path';
Expand Down Expand Up @@ -223,15 +222,12 @@ describe('ArchiverApiSchema', () => {
expect(result).toBe(1n);
});

it('getContractArtifact', async () => {
const result = await context.client.getContractArtifact(AztecAddress.random());
deepStrictEqual(result, artifact);
it('addFunctionName', async () => {
await context.client.registerContractFunctionNames(AztecAddress.random(), {
[FunctionSelector.random().toString()]: 'test_fn',
});
});

it('addContractArtifact', async () => {
await context.client.addContractArtifact(AztecAddress.random(), artifact);
}, 20_000);

it('getContract', async () => {
const address = AztecAddress.random();
const result = await context.client.getContract(address);
Expand Down Expand Up @@ -378,10 +374,9 @@ class MockArchiver implements ArchiverApi {
expect(address).toBeInstanceOf(AztecAddress);
return Promise.resolve(this.artifact);
}
addContractArtifact(address: AztecAddress, contract: ContractArtifact): Promise<void> {
registerContractFunctionNames(address: AztecAddress, names: Record<string, string>): Promise<void> {
expect(address).toBeInstanceOf(AztecAddress);
// We use node's native assertion because jest's is too slow
deepStrictEqual(contract, this.artifact);
expect(names).toEqual(expect.any(Object));
return Promise.resolve();
}
getL1ToL2Messages(blockNumber: bigint): Promise<Fr[]> {
Expand Down
7 changes: 4 additions & 3 deletions yarn-project/circuit-types/src/interfaces/archiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
PrivateLog,
PublicFunctionSchema,
} from '@aztec/circuits.js';
import { ContractArtifactSchema } from '@aztec/foundation/abi';
import { type ApiSchemaFor, optional, schemas } from '@aztec/foundation/schemas';

import { z } from 'zod';
Expand Down Expand Up @@ -69,8 +68,10 @@ export const ArchiverApiSchema: ApiSchemaFor<ArchiverApi> = {
getBytecodeCommitment: z.function().args(schemas.Fr).returns(schemas.Fr),
getContract: z.function().args(schemas.AztecAddress).returns(ContractInstanceWithAddressSchema.optional()),
getContractClassIds: z.function().args().returns(z.array(schemas.Fr)),
getContractArtifact: z.function().args(schemas.AztecAddress).returns(ContractArtifactSchema.optional()),
addContractArtifact: z.function().args(schemas.AztecAddress, ContractArtifactSchema).returns(z.void()),
registerContractFunctionNames: z
.function()
.args(schemas.AztecAddress, z.record(z.string(), z.string()))
.returns(z.void()),
getL1ToL2Messages: z.function().args(schemas.BigInt).returns(z.array(schemas.Fr)),
getL1ToL2MessageIndex: z.function().args(schemas.Fr).returns(schemas.BigInt.optional()),
// TODO(#10007): Remove this method
Expand Down
14 changes: 7 additions & 7 deletions yarn-project/circuit-types/src/interfaces/aztec-node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
getContractClassFromArtifact,
} from '@aztec/circuits.js';
import { type L1ContractAddresses, L1ContractsNames } from '@aztec/ethereum';
import { type ContractArtifact } from '@aztec/foundation/abi';
import { type ContractArtifact, FunctionSelector } from '@aztec/foundation/abi';
import { memoize } from '@aztec/foundation/decorators';
import { type JsonRpcTestContext, createJsonRpcTestSetup } from '@aztec/foundation/json-rpc/test';
import { fileURLToPath } from '@aztec/foundation/url';
Expand Down Expand Up @@ -224,9 +224,11 @@ describe('AztecNodeApiSchema', () => {
expect(response).toEqual(Object.fromEntries(ProtocolContractsNames.map(name => [name, expect.any(AztecAddress)])));
});

it('addContractArtifact', async () => {
await context.client.addContractArtifact(AztecAddress.random(), artifact);
}, 20_000);
it('registerContractFunctionNames', async () => {
await context.client.registerContractFunctionNames(AztecAddress.random(), {
[FunctionSelector.random().toString()]: 'test_fn',
});
});

it('getPrivateLogs', async () => {
const response = await context.client.getPrivateLogs(1, 1);
Expand Down Expand Up @@ -505,9 +507,7 @@ class MockAztecNode implements AztecNode {
) as ProtocolContractAddresses,
);
}
addContractArtifact(address: AztecAddress, artifact: ContractArtifact): Promise<void> {
expect(address).toBeInstanceOf(AztecAddress);
deepStrictEqual(artifact, this.artifact);
registerContractFunctionNames(_address: AztecAddress, _names: Record<string, string>): Promise<void> {
return Promise.resolve();
}
getPrivateLogs(_from: number, _limit: number): Promise<PrivateLog[]> {
Expand Down
7 changes: 5 additions & 2 deletions yarn-project/circuit-types/src/interfaces/aztec-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ export interface AztecNode
* @param aztecAddress
* @param artifact
*/
addContractArtifact(address: AztecAddress, artifact: ContractArtifact): Promise<void>;
registerContractFunctionNames(address: AztecAddress, names: Record<string, string>): Promise<void>;

/**
* Retrieves all private logs from up to `limit` blocks, starting from the block number `from`.
Expand Down Expand Up @@ -533,7 +533,10 @@ export const AztecNodeApiSchema: ApiSchemaFor<AztecNode> = {

getProtocolContractAddresses: z.function().returns(ProtocolContractAddressesSchema),

addContractArtifact: z.function().args(schemas.AztecAddress, ContractArtifactSchema).returns(z.void()),
registerContractFunctionNames: z
.function()
.args(schemas.AztecAddress, z.record(z.string(), z.string()))
.returns(z.void()),

getPrivateLogs: z.function().args(z.number(), z.number()).returns(z.array(PrivateLog.schema)),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,8 @@ export interface ContractDataSource {
*/
getContractClassIds(): Promise<Fr[]>;

/** Returns a contract artifact. */
getContractArtifact(address: AztecAddress): Promise<ContractArtifact | undefined>;

/** Returns a function's name */
getContractFunctionName(address: AztecAddress, selector: FunctionSelector): Promise<string | undefined>;
/** Registers a a contract artifact. */
addContractArtifact(address: AztecAddress, contract: ContractArtifact): Promise<void>;
/** Registers a function names. Useful for debugging. */
registerContractFunctionNames(address: AztecAddress, names: Record<string, string>): Promise<void>;
}
11 changes: 9 additions & 2 deletions yarn-project/pxe/src/pxe_service/pxe_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import {
type ContractArtifact,
EventSelector,
FunctionSelector,
FunctionType,
encodeArguments,
} from '@aztec/foundation/abi';
import { Fr, type Point } from '@aztec/foundation/fields';
Expand Down Expand Up @@ -242,8 +243,14 @@ export class PXEService implements PXE {

await this.db.addContractArtifact(contractClassId, artifact);

// TODO: PXE may not want to broadcast the artifact to the network
await this.node.addContractArtifact(instance.address, artifact);
const functionNames: Record<string, string> = {};
for (const fn of artifact.functions) {
if (fn.functionType === FunctionType.PUBLIC) {
functionNames[FunctionSelector.fromNameAndParameters(fn.name, fn.parameters).toString()] = fn.name;
}
}

await this.node.registerContractFunctionNames(instance.address, functionNames);

// TODO(#10007): Node should get public contract class from the registration event, not from PXE registration
await this.node.addContractClass({ ...contractClass, privateFunctions: [], unconstrainedFunctions: [] });
Expand Down
Loading

0 comments on commit 72a9a67

Please sign in to comment.