Skip to content

Commit

Permalink
refactor: read function names from contract classes (#10753)
Browse files Browse the repository at this point in the history
This PR removes contract artifacts from the archiver as they were only
used for dubugging purposes. Function names are now (optionally) emitted
when registereing contract classes.

I have created #10752 to remove function names from the contract class
once we don't need this debug information

---------

Co-authored-by: Santiago Palladino <[email protected]>
  • Loading branch information
alexghr and spalladino authored Dec 18, 2024
1 parent 26c87a9 commit 921febb
Show file tree
Hide file tree
Showing 17 changed files with 76 additions and 139 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
6 changes: 2 additions & 4 deletions yarn-project/archiver/src/archiver/archiver_store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
type PrivateLog,
type UnconstrainedFunctionWithMembershipProof,
} from '@aztec/circuits.js';
import { type ContractArtifact, type FunctionSelector } from '@aztec/foundation/abi';
import { type FunctionSelector } from '@aztec/foundation/abi';
import { type AztecAddress } from '@aztec/foundation/aztec-address';

import { type DataRetrieval } from './structs/data_retrieval.js';
Expand Down 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 { type 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);
});
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 @@ -28,7 +28,7 @@ import {
type PrivateLog,
type UnconstrainedFunctionWithMembershipProof,
} from '@aztec/circuits.js';
import { type ContractArtifact, FunctionSelector } from '@aztec/foundation/abi';
import { type FunctionSelector } from '@aztec/foundation/abi';
import { type AztecAddress } from '@aztec/foundation/aztec-address';
import { createLogger } from '@aztec/foundation/log';

Expand Down Expand Up @@ -68,8 +68,6 @@ export class MemoryArchiverStore implements ArchiverDataStore {
*/
private l1ToL2Messages = new L1ToL2MessageStore();

private contractArtifacts: Map<string, ContractArtifact> = new Map();

private contractClasses: Map<string, ContractClassPublicWithBlockNumber> = new Map();

private bytecodeCommitments: Map<string, Fr> = new Map();
Expand All @@ -86,6 +84,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 @@ -730,26 +730,16 @@ export class MemoryArchiverStore implements ArchiverDataStore {
});
}

public addContractArtifact(address: AztecAddress, contract: ContractArtifact): Promise<void> {
this.contractArtifacts.set(address.toString(), contract);
return Promise.resolve();
}

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

async getContractFunctionName(address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
const artifact = await this.getContractArtifact(address);

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 @@ -45,7 +46,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
7 changes: 2 additions & 5 deletions yarn-project/aztec-node/src/aztec-node/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ import {
} from '@aztec/circuits.js';
import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash';
import { type L1ContractAddresses, createEthereumChain } from '@aztec/ethereum';
import { type ContractArtifact } from '@aztec/foundation/abi';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { padArrayEnd } from '@aztec/foundation/collection';
import { type Logger, createLogger } from '@aztec/foundation/log';
Expand Down Expand Up @@ -901,10 +900,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(_address, 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('registerContractFunctionNames', 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
15 changes: 7 additions & 8 deletions yarn-project/circuit-types/src/interfaces/aztec-node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,12 @@ 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';
import { loadContractArtifact } from '@aztec/types/abi';

import { deepStrictEqual } from 'assert';
import { readFileSync } from 'fs';
import omit from 'lodash.omit';
import times from 'lodash.times';
Expand Down Expand Up @@ -224,9 +223,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 +506,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
Loading

0 comments on commit 921febb

Please sign in to comment.