Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Lazy wasm pt.1 #11371

Merged
merged 15 commits into from
Jan 21, 2025
28 changes: 27 additions & 1 deletion barretenberg/ts/src/barretenberg/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { BarretenbergApi, BarretenbergApiSync } from '../barretenberg_api/index.
import { createMainWorker } from '../barretenberg_wasm/barretenberg_wasm_main/factory/node/index.js';
import { BarretenbergWasmMain, BarretenbergWasmMainWorker } from '../barretenberg_wasm/barretenberg_wasm_main/index.js';
import { getRemoteBarretenbergWasm } from '../barretenberg_wasm/helpers/index.js';
import { BarretenbergWasmWorker, fetchModuleAndThreads } from '../barretenberg_wasm/index.js';
import { BarretenbergWasm, BarretenbergWasmWorker, fetchModuleAndThreads } from '../barretenberg_wasm/index.js';
import createDebug from 'debug';
import { Crs, GrumpkinCrs } from '../crs/index.js';
import { RawBuffer } from '../types/raw_buffer.js';
Expand Down Expand Up @@ -123,6 +123,32 @@ export class BarretenbergSync extends BarretenbergApiSync {
}
}

let barrentenbergLazySingleton: BarretenbergLazy;

export class BarretenbergLazy extends BarretenbergApi {
private constructor(wasm: BarretenbergWasmMain) {
super(wasm);
}

private static async new() {
const wasm = new BarretenbergWasmMain();
const { module, threads } = await fetchModuleAndThreads(1);
await wasm.init(module, threads);
return new BarretenbergLazy(wasm);
}

static async getSingleton() {
if (!barrentenbergLazySingleton) {
barrentenbergLazySingleton = await BarretenbergLazy.new();
}
return barrentenbergLazySingleton;
}

getWasm() {
return this.wasm;
}
}

// If we're in ESM environment, use top level await. CJS users need to call it manually.
// Need to ignore for cjs build.
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
Expand Down
3 changes: 2 additions & 1 deletion barretenberg/ts/src/barretenberg_api/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// WARNING: FILE CODE GENERATED BY BINDGEN UTILITY. DO NOT EDIT!
/* eslint-disable @typescript-eslint/no-unused-vars */
import { BarretenbergWasmMain } from '../barretenberg_wasm/barretenberg_wasm_main/index.js';
import { BarretenbergWasmWorker, BarretenbergWasm } from '../barretenberg_wasm/index.js';
import {
BufferDeserializer,
Expand All @@ -13,7 +14,7 @@ import {
import { Fr, Fq, Point, Buffer32, Buffer128, Ptr } from '../types/index.js';

export class BarretenbergApi {
constructor(protected wasm: BarretenbergWasmWorker) {}
constructor(protected wasm: BarretenbergWasmWorker | BarretenbergWasmMain) {}

async pedersenCommit(inputsBuffer: Fr[], ctxIndex: number): Promise<Point> {
const inArgs = [inputsBuffer, ctxIndex].map(serializeBufferable);
Expand Down
1 change: 1 addition & 0 deletions barretenberg/ts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export {
BackendOptions,
Barretenberg,
BarretenbergSync,
BarretenbergLazy,
BarretenbergVerifier,
UltraPlonkBackend,
UltraHonkBackend,
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/archiver/src/archiver/archiver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ describe('Archiver', () => {

const GENESIS_ROOT = new Fr(GENESIS_ARCHIVE_ROOT).toString();

beforeEach(() => {
beforeEach(async () => {
logger = createLogger('archiver:test');
now = +new Date();
publicClient = mock<PublicClient<HttpTransport, Chain>>({
Expand Down Expand Up @@ -117,7 +117,7 @@ describe('Archiver', () => {
l1Constants,
);

blocks = blockNumbers.map(x => L2Block.random(x, txsPerBlock, x + 1, 2));
blocks = await Promise.all(blockNumbers.map(x => L2Block.random(x, txsPerBlock, x + 1, 2)));
blocks.forEach(block => {
block.body.txEffects.forEach((txEffect, i) => {
txEffect.privateLogs = Array(getNumPrivateLogsForTx(block.number, i))
Expand Down
35 changes: 18 additions & 17 deletions yarn-project/archiver/src/archiver/archiver_store_test_suite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
makeExecutablePrivateFunctionWithMembershipProof,
makeUnconstrainedFunctionWithMembershipProof,
} from '@aztec/circuits.js/testing';
import { times } from '@aztec/foundation/collection';
import { times, timesParallel } from '@aztec/foundation/collection';
import { randomInt } from '@aztec/foundation/crypto';

import { type ArchiverDataStore, type ArchiverL1SynchPoint } from './archiver_store.js';
Expand Down Expand Up @@ -51,9 +51,9 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch
},
});

beforeEach(() => {
beforeEach(async () => {
store = getStore();
blocks = times(10, i => makeL1Published(L2Block.random(i + 1), i + 10));
blocks = await timesParallel(10, async i => makeL1Published(await L2Block.random(i + 1), i + 10));
});

describe('addBlocks', () => {
Expand Down Expand Up @@ -81,7 +81,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch
});

it('can unwind multiple empty blocks', async () => {
const emptyBlocks = times(10, i => makeL1Published(L2Block.random(i + 1, 0), i + 10));
const emptyBlocks = await timesParallel(10, async i => makeL1Published(await L2Block.random(i + 1, 0), i + 10));
await store.addBlocks(emptyBlocks);
expect(await store.getSynchedL2BlockNumber()).toBe(10);

Expand Down Expand Up @@ -276,7 +276,8 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch
const blockNum = 10;

beforeEach(async () => {
contractInstance = { ...SerializableContractInstance.random(), address: AztecAddress.random() };
const randomInstance = await SerializableContractInstance.random();
contractInstance = { ...randomInstance, address: await AztecAddress.random() };
await store.addContractInstances([contractInstance], blockNum);
});

Expand All @@ -285,7 +286,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch
});

it('returns undefined if contract instance is not found', async () => {
await expect(store.getContractInstance(AztecAddress.random())).resolves.toBeUndefined();
await expect(store.getContractInstance(await AztecAddress.random())).resolves.toBeUndefined();
});

it('returns undefined if previously stored contract instances was deleted', async () => {
Expand Down Expand Up @@ -408,12 +409,12 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch
});
};

const mockBlockWithLogs = (blockNumber: number): L1Published<L2Block> => {
const block = L2Block.random(blockNumber);
const mockBlockWithLogs = async (blockNumber: number): Promise<L1Published<L2Block>> => {
const block = await L2Block.random(blockNumber);
block.header.globalVariables.blockNumber = new Fr(blockNumber);

block.body.txEffects = times(numTxsPerBlock, (txIndex: number) => {
const txEffect = TxEffect.random();
block.body.txEffects = await timesParallel(numTxsPerBlock, async (txIndex: number) => {
const txEffect = await TxEffect.random();
txEffect.privateLogs = mockPrivateLogs(blockNumber, txIndex);
txEffect.publicLogs = mockPublicLogs(blockNumber, txIndex);
return txEffect;
Expand All @@ -426,7 +427,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch
};

beforeEach(async () => {
blocks = times(numBlocks, (index: number) => mockBlockWithLogs(index));
blocks = await timesParallel(numBlocks, (index: number) => mockBlockWithLogs(index));

await store.addBlocks(blocks);
await store.addLogs(blocks.map(b => b.data));
Expand Down Expand Up @@ -482,7 +483,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch

// Create a block containing logs that have the same tag as the blocks before.
const newBlockNumber = numBlocks;
const newBlock = mockBlockWithLogs(newBlockNumber);
const newBlock = await mockBlockWithLogs(newBlockNumber);
const newLog = newBlock.data.body.txEffects[1].privateLogs[1];
newLog.fields[0] = tags[0];
newBlock.data.body.txEffects[1].privateLogs[1] = newLog;
Expand Down Expand Up @@ -545,7 +546,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch

// Create a block containing these invalid logs
const newBlockNumber = numBlocks;
const newBlock = mockBlockWithLogs(newBlockNumber);
const newBlock = await mockBlockWithLogs(newBlockNumber);
newBlock.data.body.txEffects[0].publicLogs = invalidLogs;
await store.addBlocks([newBlock]);
await store.addLogs([newBlock.data]);
Expand All @@ -565,8 +566,8 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch
let blocks: L1Published<L2Block>[];

beforeEach(async () => {
blocks = times(numBlocks, (index: number) => ({
data: L2Block.random(index + 1, txsPerBlock, numPublicFunctionCalls, numPublicLogs),
blocks = await timesParallel(numBlocks, async (index: number) => ({
data: await L2Block.random(index + 1, txsPerBlock, numPublicFunctionCalls, numPublicLogs),
l1: { blockNumber: BigInt(index), blockHash: `0x${index}`, timestamp: BigInt(index) },
}));

Expand Down Expand Up @@ -748,8 +749,8 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch
const numBlocks = 10;
const nullifiersPerBlock = new Map<number, Fr[]>();

beforeEach(() => {
blocks = times(numBlocks, (index: number) => L2Block.random(index + 1, 1));
beforeEach(async () => {
blocks = await timesParallel(numBlocks, (index: number) => L2Block.random(index + 1, 1));

blocks.forEach((block, blockIndex) => {
nullifiersPerBlock.set(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { L2Block } from '@aztec/circuit-types';
import { times } from '@aztec/foundation/collection';
import { timesParallel } from '@aztec/foundation/collection';

import { type ArchiverDataStore } from '../archiver_store.js';
import { describeArchiverDataStore } from '../archiver_store_test_suite.js';
Expand All @@ -18,8 +18,8 @@ describe('MemoryArchiverStore', () => {
it('does not return more than "maxLogs" logs', async () => {
const maxLogs = 5;
archiverStore = new MemoryArchiverStore(maxLogs);
const blocks = times(10, (index: number) => ({
data: L2Block.random(index + 1, 4, 3, 2),
const blocks = await timesParallel(10, async (index: number) => ({
data: await L2Block.random(index + 1, 4, 3, 2),
l1: { blockNumber: BigInt(index), blockHash: `0x${index}`, timestamp: BigInt(index) },
}));

Expand Down
1 change: 1 addition & 0 deletions yarn-project/archiver/src/test/mock_archiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@ export class MockPrefilledArchiver extends MockArchiver {

const fromBlock = this.l2Blocks.length;
this.addBlocks(this.precomputed.slice(fromBlock, fromBlock + numBlocks));
return Promise.resolve();
}
}
4 changes: 2 additions & 2 deletions yarn-project/archiver/src/test/mock_l2_block_source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ export class MockL2BlockSource implements L2BlockSource {

private log = createLogger('archiver:mock_l2_block_source');

public createBlocks(numBlocks: number) {
public async createBlocks(numBlocks: number) {
for (let i = 0; i < numBlocks; i++) {
const blockNum = this.l2Blocks.length + 1;
const block = L2Block.random(blockNum);
const block = await L2Block.random(blockNum);
this.l2Blocks.push(block);
}

Expand Down
31 changes: 16 additions & 15 deletions yarn-project/aztec.js/src/contract/contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,6 @@ describe('Contract Class', () => {
governanceProposerAddress: EthAddress.random(),
slashFactoryAddress: EthAddress.random(),
};
const mockNodeInfo: NodeInfo = {
nodeVersion: 'vx.x.x',
l1ChainId: 1,
protocolVersion: 2,
l1ContractAddresses: l1Addresses,
enr: undefined,
protocolContractAddresses: {
classRegisterer: AztecAddress.random(),
feeJuice: AztecAddress.random(),
instanceDeployer: AztecAddress.random(),
multiCallEntrypoint: AztecAddress.random(),
},
};

const defaultArtifact: ContractArtifact = {
name: 'FooContract',
Expand Down Expand Up @@ -141,11 +128,25 @@ describe('Contract Class', () => {
notes: {},
};

beforeEach(() => {
contractAddress = AztecAddress.random();
beforeEach(async () => {
contractAddress = await AztecAddress.random();
account = CompleteAddress.random();
contractInstance = { address: contractAddress } as ContractInstanceWithAddress;

const mockNodeInfo: NodeInfo = {
nodeVersion: 'vx.x.x',
l1ChainId: 1,
protocolVersion: 2,
l1ContractAddresses: l1Addresses,
enr: undefined,
protocolContractAddresses: {
classRegisterer: await AztecAddress.random(),
feeJuice: await AztecAddress.random(),
instanceDeployer: await AztecAddress.random(),
multiCallEntrypoint: await AztecAddress.random(),
},
};

wallet = mock<Wallet>();
wallet.simulateTx.mockResolvedValue(mockTxSimulationResult);
wallet.createTxExecutionRequest.mockResolvedValue(mockTxRequest);
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/aztec.js/src/contract/get_gas_limits.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { getGasLimits } from './get_gas_limits.js';
describe('getGasLimits', () => {
let txSimulationResult: TxSimulationResult;

beforeEach(() => {
txSimulationResult = mockSimulatedTx();
beforeEach(async () => {
txSimulationResult = await mockSimulatedTx();

const tx = mockTxForRollup();
tx.data.gasUsed = Gas.from({ daGas: 100, l2Gas: 200 });
Expand Down
14 changes: 10 additions & 4 deletions yarn-project/bb-prover/src/avm_proving.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ describe('AVM WitGen, "check circuit" tests', () => {
it(
'call the max number of unique contract classes',
async () => {
const contractDataSource = new MockedAvmTestContractDataSource();
const contractDataSource = await MockedAvmTestContractDataSource.create();
// args is initialized to MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS contract addresses with unique class IDs
const args = Array.from(contractDataSource.contractInstances.values())
.map(instance => instance.address.toField())
Expand All @@ -130,7 +130,7 @@ describe('AVM WitGen, "check circuit" tests', () => {
it(
'attempt too many calls to unique contract class ids',
async () => {
const contractDataSource = new MockedAvmTestContractDataSource();
const contractDataSource = await MockedAvmTestContractDataSource.create();
// args is initialized to MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS+1 contract addresses with unique class IDs
// should fail because we are trying to call MAX+1 unique class IDs
const args = Array.from(contractDataSource.contractInstances.values()).map(instance =>
Expand Down Expand Up @@ -301,8 +301,11 @@ async function proveAndVerifyAvmTestContractSimple(
args: Fr[] = [],
expectRevert = false,
skipContractDeployments = false,
contractDataSource = new MockedAvmTestContractDataSource(skipContractDeployments),
contractDataSource?: MockedAvmTestContractDataSource,
) {
if (!contractDataSource) {
contractDataSource = await MockedAvmTestContractDataSource.create(skipContractDeployments);
}
await proveAndVerifyAvmTestContract(
checkCircuitOnly,
/*setupFunctionNames=*/ [],
Expand Down Expand Up @@ -330,8 +333,11 @@ async function proveAndVerifyAvmTestContract(
teardownArgs: Fr[] = [],
expectRevert = false,
skipContractDeployments = false,
contractDataSource = new MockedAvmTestContractDataSource(skipContractDeployments),
contractDataSource?: MockedAvmTestContractDataSource,
) {
if (!contractDataSource) {
contractDataSource = await MockedAvmTestContractDataSource.create(skipContractDeployments);
}
const avmCircuitInputs = await simulateAvmTestContractGenerateCircuitInputs(
setupFunctionNames,
setupArgs,
Expand Down
12 changes: 6 additions & 6 deletions yarn-project/circuit-types/src/body.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { Fr } from '@aztec/circuits.js';
import { Body } from './body.js';

describe('Body', () => {
it('converts to and from buffer', () => {
const body = Body.random();
it('converts to and from buffer', async () => {
const body = await Body.random();
const buf = body.toBuffer();
expect(Body.fromBuffer(buf)).toEqual(body);
});

it('converts to and from fields', () => {
const body = Body.random();
it('converts to and from fields', async () => {
const body = await Body.random();
const fields = body.toBlobFields();
// TODO(#8954): When logs are refactored into fields, we won't need to inject them here
expect(Body.fromBlobFields(fields, body.contractClassLogs)).toEqual(body);
Expand All @@ -22,8 +22,8 @@ describe('Body', () => {
expect(Body.fromBlobFields(fields)).toEqual(body);
});

it('fails with invalid fields', () => {
const body = Body.random();
it('fails with invalid fields', async () => {
const body = await Body.random();
const fields = body.toBlobFields();
// Replace the initial field with an invalid encoding
fields[0] = new Fr(12);
Expand Down
7 changes: 5 additions & 2 deletions yarn-project/circuit-types/src/body.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { type Fr } from '@aztec/circuits.js';
import { timesParallel } from '@aztec/foundation/collection';
import { type ZodFor } from '@aztec/foundation/schemas';
import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';

Expand Down Expand Up @@ -88,8 +89,10 @@ export class Body {
return new ContractClass2BlockL2Logs(logs);
}

static random(txsPerBlock = 4, numPublicCallsPerTx = 3, numPublicLogsPerCall = 1) {
const txEffects = [...new Array(txsPerBlock)].map(_ => TxEffect.random(numPublicCallsPerTx, numPublicLogsPerCall));
static async random(txsPerBlock = 4, numPublicCallsPerTx = 3, numPublicLogsPerCall = 1) {
const txEffects = await timesParallel(txsPerBlock, () =>
TxEffect.random(numPublicCallsPerTx, numPublicLogsPerCall),
);

return new Body(txEffects);
}
Expand Down
Loading
Loading