Skip to content

Commit

Permalink
feat: proving benchmark (#6051)
Browse files Browse the repository at this point in the history
Add a benchmark for running the chain with native bb proving
  • Loading branch information
alexghr authored May 7, 2024
1 parent 0e0fc58 commit 644bd85
Show file tree
Hide file tree
Showing 20 changed files with 299 additions and 114 deletions.
5 changes: 3 additions & 2 deletions yarn-project/Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ deps:
LET packages = $(git ls-files "**/package*.json" package*.json)
LET tsconfigs = $(git ls-files "**/tsconfig*.json" tsconfig*.json)
FROM ../build-images+build
# copy bb-js and noir-packages
# copy bb, bb-js and noir-packages
COPY ../barretenberg/cpp/+preset-release/bin /usr/src/barretenberg/cpp/build/
COPY ../barretenberg/ts/+build/build /usr/src/barretenberg/ts
COPY ../noir/+packages/packages /usr/src/noir/packages
WORKDIR /usr/src/yarn-project
Expand Down Expand Up @@ -100,7 +101,7 @@ end-to-end:
RUN apt-get update && apt-get install -y wget gnupg \
&& wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& echo "deb [arch=$(dpkg --print-architecture)] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list \
&& apt update && apt install nodejs jq google-chrome-stable netcat-openbsd -y \
&& apt update && apt install curl nodejs jq google-chrome-stable netcat-openbsd -y \
&& rm -rf /var/lib/apt/lists/*
ENV CHROME_BIN="/usr/bin/google-chrome-stable"
ENV PATH=/opt/foundry/bin:$PATH
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/aztec-node/src/aztec-node/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type ArchiverConfig, getConfigEnvVars as getArchiverVars } from '@aztec/archiver';
import { type P2PConfig, getP2PConfigEnvVars } from '@aztec/p2p';
import { type ProverConfig, getProverEnvVars } from '@aztec/prover-client';
import { type ProverClientConfig, getProverEnvVars } from '@aztec/prover-client';
import { type SequencerClientConfig, getConfigEnvVars as getSequencerVars } from '@aztec/sequencer-client';
import { getConfigEnvVars as getWorldStateVars } from '@aztec/world-state';

Expand All @@ -9,7 +9,7 @@ import { getConfigEnvVars as getWorldStateVars } from '@aztec/world-state';
*/
export type AztecNodeConfig = ArchiverConfig &
SequencerClientConfig &
ProverConfig &
ProverClientConfig &
P2PConfig & {
/** Whether the sequencer is disabled for this node. */
disableSequencer: boolean;
Expand Down
5 changes: 3 additions & 2 deletions yarn-project/aztec-node/src/aztec-node/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
NullifierMembershipWitness,
type ProcessOutput,
type ProverClient,
type ProverConfig,
PublicDataWitness,
type SequencerConfig,
type SiblingPath,
Expand Down Expand Up @@ -688,9 +689,9 @@ export class AztecNodeService implements AztecNode {
};
}

public setConfig(config: Partial<SequencerConfig>): Promise<void> {
public async setConfig(config: Partial<SequencerConfig & ProverConfig>): Promise<void> {
this.sequencer?.updateSequencerConfig(config);
return Promise.resolve();
await this.prover.updateProverConfig(config);
}

/**
Expand Down
4 changes: 4 additions & 0 deletions yarn-project/aztec/src/cli/cmds/start_prover.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { type ProvingJobSource } from '@aztec/circuit-types';
import { ProverPool, createProvingJobSourceClient } from '@aztec/prover-client/prover-pool';

import { tmpdir } from 'node:os';

import { type ServiceStarter, parseModuleOptions } from '../util.js';

type ProverOptions = Partial<{
Expand Down Expand Up @@ -35,6 +37,8 @@ export const startProver: ServiceStarter = async (options, signalHandlers, logge
{
acvmBinaryPath: proverOptions.acvmBinaryPath,
bbBinaryPath: proverOptions.bbBinaryPath,
acvmWorkingDirectory: tmpdir(),
bbWorkingDirectory: tmpdir(),
},
agentCount,
);
Expand Down
3 changes: 2 additions & 1 deletion yarn-project/circuit-types/src/interfaces/aztec-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { type TxEffect } from '../tx_effect.js';
import { type SequencerConfig } from './configs.js';
import { type L2BlockNumber } from './l2_block_number.js';
import { type NullifierMembershipWitness } from './nullifier_tree.js';
import { type ProverConfig } from './prover-client.js';
import { type PublicDataWitness } from './public_data_tree.js';

/**
Expand Down Expand Up @@ -288,7 +289,7 @@ export interface AztecNode {
* Updates the configuration of this node.
* @param config - Updated configuration to be merged with the current one.
*/
setConfig(config: Partial<SequencerConfig>): Promise<void>;
setConfig(config: Partial<SequencerConfig & ProverConfig>): Promise<void>;

/**
* Returns a registered contract class given its id.
Expand Down
10 changes: 10 additions & 0 deletions yarn-project/circuit-types/src/interfaces/prover-client.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { type BlockProver } from './block-prover.js';
import { type ProvingJobSource } from './proving-job.js';

/**
* The prover configuration.
*/
export type ProverConfig = {
/** How many agents to run */
proverAgents: number;
};

/**
* The interface to the prover client.
* Provides the ability to generate proofs and build rollups.
Expand All @@ -11,4 +19,6 @@ export interface ProverClient extends BlockProver {
stop(): Promise<void>;

getProvingJobSource(): ProvingJobSource;

updateProverConfig(config: Partial<ProverConfig>): Promise<void>;
}
8 changes: 8 additions & 0 deletions yarn-project/end-to-end/Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,11 @@ bench-tx-size:
ARG COMMIT_HASH
DO +E2E_COMPOSE_TEST --test=benchmarks/bench_tx_size_fees.test.ts --debug="aztec:benchmarks:*,aztec:sequencer,aztec:sequencer:*,aztec:world_state,aztec:merkle_trees" --enable_gas=1 --compose_file=./scripts/docker-compose-no-sandbox.yml
DO +UPLOAD_LOGS --e2e_mode=$e2e_mode --PULL_REQUEST=$PULL_REQUEST --BRANCH=$BRANCH --COMMIT_HASH=$COMMIT_HASH

bench-proving:
ARG e2e_mode=local
ARG PULL_REQUEST
ARG BRANCH
ARG COMMIT_HASH
DO +E2E_COMPOSE_TEST --test=bench_proving --debug="aztec:benchmarks:*,aztec:prover*,aztec:bb*" --e2e_mode=$e2e_mode --enable_gas=1 --compose_file=./scripts/docker-compose-no-sandbox.yml
DO +UPLOAD_LOGS --e2e_mode=$e2e_mode --PULL_REQUEST=$PULL_REQUEST --BRANCH=$BRANCH --COMMIT_HASH=$COMMIT_HASH
124 changes: 124 additions & 0 deletions yarn-project/end-to-end/src/benchmarks/bench_proving.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { type AztecNodeService } from '@aztec/aztec-node';
import { type AccountWallet, EthAddress, PublicFeePaymentMethod, TxStatus } from '@aztec/aztec.js';
import { GasSettings } from '@aztec/circuits.js';
import { FPCContract, GasTokenContract, TestContract, TokenContract } from '@aztec/noir-contracts.js';
import { getCanonicalGasTokenAddress } from '@aztec/protocol-contracts/gas-token';
import { ProverPool } from '@aztec/prover-client/prover-pool';

import { jest } from '@jest/globals';

import { getACVMConfig } from '../fixtures/get_acvm_config.js';
import { getBBConfig } from '../fixtures/get_bb_config.js';
import { type EndToEndContext, publicDeployAccounts, setup } from '../fixtures/utils.js';

jest.setTimeout(600_000);

const txTimeoutSec = 600;

describe('benchmarks/proving', () => {
let ctx: EndToEndContext;
let wallet: AccountWallet;
let testContract: TestContract;
let tokenContract: TokenContract;
let fpContract: FPCContract;
let acvmCleanup: () => Promise<void>;
let bbCleanup: () => Promise<void>;
let proverPool: ProverPool;

// setup the environment quickly using fake proofs
beforeAll(async () => {
ctx = await setup(
1,
{
// do setup with fake proofs
realProofs: false,
proverAgents: 4,
proverAgentPollInterval: 10,
minTxsPerBlock: 1,
},
{},
true, // enable gas
);

wallet = ctx.wallet;

await publicDeployAccounts(wallet, ctx.wallets);

testContract = await TestContract.deploy(wallet).send().deployed();
tokenContract = await TokenContract.deploy(wallet, wallet.getAddress(), 'test', 't', 18).send().deployed();
const gas = await GasTokenContract.at(
getCanonicalGasTokenAddress(ctx.deployL1ContractsValues.l1ContractAddresses.gasPortalAddress),
wallet,
);
fpContract = await FPCContract.deploy(wallet, tokenContract.address, gas.address).send().deployed();

await Promise.all([
gas.methods.mint_public(fpContract.address, 1e12).send().wait(),
tokenContract.methods.mint_public(wallet.getAddress(), 1e12).send().wait(),
]);
});

// remove the fake prover and setup the real one
beforeAll(async () => {
const [acvmConfig, bbConfig] = await Promise.all([getACVMConfig(ctx.logger), getBBConfig(ctx.logger)]);
if (!acvmConfig || !bbConfig) {
throw new Error('Missing ACVM or BB config');
}

acvmCleanup = acvmConfig.cleanup;
bbCleanup = bbConfig.cleanup;

proverPool = ProverPool.nativePool(
{
...acvmConfig,
...bbConfig,
},
4,
10,
);

ctx.logger.info('Stopping fake provers');
await ctx.aztecNode.setConfig({
// stop the fake provers
proverAgents: 0,
// 4-tx blocks so that we have at least one merge level
minTxsPerBlock: 4,
});

ctx.logger.info('Starting real provers');
await proverPool.start((ctx.aztecNode as AztecNodeService).getProver().getProvingJobSource());
});

afterAll(async () => {
await proverPool.stop();
await ctx.teardown();
await acvmCleanup();
await bbCleanup();
});

it('builds a full block', async () => {
const txs = [
// fully private tx
testContract.methods.emit_nullifier(42).send(),
// tx with setup, app, teardown
testContract.methods.emit_unencrypted(43).send({
fee: {
gasSettings: GasSettings.default(),
paymentMethod: new PublicFeePaymentMethod(tokenContract.address, fpContract.address, wallet),
},
}),
// tx with messages
testContract.methods.create_l2_to_l1_message_public(45, 46, EthAddress.random()).send(),
// tx with private and public exec
testContract.methods.set_tx_max_block_number(100, true).send({
fee: {
gasSettings: GasSettings.default(),
paymentMethod: new PublicFeePaymentMethod(tokenContract.address, fpContract.address, wallet),
},
}),
];

const receipts = await Promise.all(txs.map(tx => tx.wait({ timeout: txTimeoutSec })));
expect(receipts.every(r => r.status === TxStatus.MINED)).toBe(true);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,16 @@ import {
import { TokenContract } from '@aztec/noir-contracts.js';
import { BBNativeProofCreator, type PXEService } from '@aztec/pxe';

import * as fs from 'fs/promises';

import { waitRegisteredAccountSynced } from '../benchmarks/utils.js';
import { getBBConfig } from '../fixtures/get_bb_config.js';
import {
type ISnapshotManager,
type SubsystemsContext,
addAccounts,
createSnapshotManager,
publicDeployAccounts,
} from '../fixtures/snapshot_manager.js';
import { getBBConfig, setupPXEService } from '../fixtures/utils.js';
import { setupPXEService } from '../fixtures/utils.js';
import { TokenSimulator } from '../simulators/token_simulator.js';

const { E2E_DATA_PATH: dataPath } = process.env;
Expand Down Expand Up @@ -55,7 +54,7 @@ export class ClientProverTest {
fullProverPXE!: PXEService;
provenAsset!: TokenContract;
provenPXETeardown?: () => Promise<void>;
private directoryToCleanup?: string;
private bbConfigCleanup?: () => Promise<void>;
proofCreator?: BBNativeProofCreator;

constructor(testName: string) {
Expand Down Expand Up @@ -121,21 +120,21 @@ export class ClientProverTest {

// Configure a full prover PXE
const bbConfig = await getBBConfig(this.logger);
this.directoryToCleanup = bbConfig?.directoryToCleanup;
this.bbConfigCleanup = bbConfig?.cleanup;

if (!bbConfig?.bbWorkingDirectory || !bbConfig?.expectedBBPath) {
if (!bbConfig?.bbWorkingDirectory || !bbConfig?.bbBinaryPath) {
throw new Error(`Test must be run with BB native configuration`);
}

this.proofCreator = new BBNativeProofCreator(bbConfig?.expectedBBPath, bbConfig?.bbWorkingDirectory);
this.proofCreator = new BBNativeProofCreator(bbConfig.bbBinaryPath, bbConfig.bbWorkingDirectory);

this.logger.debug(`Main setup completed, initializing full prover PXE...`);
({ pxe: this.fullProverPXE, teardown: this.provenPXETeardown } = await setupPXEService(
0,
this.aztecNode,
{
proverEnabled: false,
bbBinaryPath: bbConfig?.expectedBBPath,
bbBinaryPath: bbConfig?.bbBinaryPath,
bbWorkingDirectory: bbConfig?.bbWorkingDirectory,
},
undefined,
Expand Down Expand Up @@ -180,9 +179,7 @@ export class ClientProverTest {
// Cleanup related to the second 'full prover' PXE
await this.provenPXETeardown?.();

if (this.directoryToCleanup) {
await fs.rm(this.directoryToCleanup, { recursive: true, force: true });
}
await this.bbConfigCleanup?.();
}

async addPendingShieldNoteToPXE(accountIndex: number, amount: bigint, secretHash: Fr, txHash: TxHash) {
Expand Down
17 changes: 12 additions & 5 deletions yarn-project/end-to-end/src/fixtures/get_acvm_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,21 @@ const {
} = process.env;

// Determines if we have access to the acvm binary and a tmp folder for temp files
export async function getACVMConfig(logger: DebugLogger) {
export async function getACVMConfig(logger: DebugLogger): Promise<
| {
acvmWorkingDirectory: string;
acvmBinaryPath: string;
cleanup: () => Promise<void>;
}
| undefined
> {
try {
const expectedAcvmPath = ACVM_BINARY_PATH ? ACVM_BINARY_PATH : `../../noir/${NOIR_RELEASE_DIR}/acvm`;
await fs.access(expectedAcvmPath, fs.constants.R_OK);
const acvmBinaryPath = ACVM_BINARY_PATH ? ACVM_BINARY_PATH : `../../noir/${NOIR_RELEASE_DIR}/acvm`;
await fs.access(acvmBinaryPath, fs.constants.R_OK);
const tempWorkingDirectory = `${TEMP_DIR}/${randomBytes(4).toString('hex')}`;
const acvmWorkingDirectory = ACVM_WORKING_DIRECTORY ? ACVM_WORKING_DIRECTORY : `${tempWorkingDirectory}/acvm`;
await fs.mkdir(acvmWorkingDirectory, { recursive: true });
logger.verbose(`Using native ACVM binary at ${expectedAcvmPath} with working directory ${acvmWorkingDirectory}`);
logger.verbose(`Using native ACVM binary at ${acvmBinaryPath} with working directory ${acvmWorkingDirectory}`);

const directoryToCleanup = ACVM_WORKING_DIRECTORY ? undefined : tempWorkingDirectory;

Expand All @@ -33,7 +40,7 @@ export async function getACVMConfig(logger: DebugLogger) {

return {
acvmWorkingDirectory,
expectedAcvmPath,
acvmBinaryPath,
cleanup,
};
} catch (err) {
Expand Down
46 changes: 46 additions & 0 deletions yarn-project/end-to-end/src/fixtures/get_bb_config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { type DebugLogger, fileURLToPath } from '@aztec/aztec.js';

import fs from 'node:fs/promises';
import { tmpdir } from 'node:os';
import path from 'path';

const {
BB_RELEASE_DIR = 'barretenberg/cpp/build/bin',
BB_BINARY_PATH,
TEMP_DIR = tmpdir(),
BB_WORKING_DIRECTORY = '',
} = process.env;

export const getBBConfig = async (
logger: DebugLogger,
): Promise<{ bbBinaryPath: string; bbWorkingDirectory: string; cleanup: () => Promise<void> } | undefined> => {
try {
const bbBinaryPath =
BB_BINARY_PATH ??
path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../', BB_RELEASE_DIR, 'bb');
await fs.access(bbBinaryPath, fs.constants.R_OK);

let bbWorkingDirectory: string;
let directoryToCleanup: string | undefined;

if (BB_WORKING_DIRECTORY) {
bbWorkingDirectory = BB_WORKING_DIRECTORY;
} else {
bbWorkingDirectory = await fs.mkdtemp(path.join(TEMP_DIR, 'bb-'));
directoryToCleanup = bbWorkingDirectory;
}

await fs.mkdir(bbWorkingDirectory, { recursive: true });

const cleanup = async () => {
if (directoryToCleanup) {
await fs.rm(directoryToCleanup, { recursive: true, force: true });
}
};

return { bbBinaryPath, bbWorkingDirectory, cleanup };
} catch (err) {
logger.error(`Native BB not available, error: ${err}`);
return undefined;
}
};
Loading

0 comments on commit 644bd85

Please sign in to comment.