Skip to content

Commit 864bc6f

Browse files
authored
feat: Lazy wasm pt.1 (#11371)
Starts the transition towards no top level await when importing wasm in any client bundle, so that browsers don't have to load +8MB right away. This PR introduces a `BarretembergLazy` class that behaves as `Barretenberg` (in the sense that methods are async), but it's intended to be initialized with a single thread to perform common operations, such as Field math or hashes. Since it's a big change, this PR focuses on a single thing: making `Fr.sqrt()` async. This of course had terrible ramifications, since that operation is used to assert validity of Grumpkin points that ultimately is what our `AztecAddresses` are. This leaked into the `AztecAddress.random()` method, so most tests in the repo are affected. However and even though this PR seems gigantic, that's the only thing that has changed, and as stated affects mostly tests. After this, more asynchronification on the client will happen, but hopefully will result in smaller diffs. `BarretenbergSync` will probably be kept around for server stuff, but `bb.js` will be split so that it's not imported all the time.
1 parent 79f810d commit 864bc6f

131 files changed

Lines changed: 1092 additions & 837 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

barretenberg/ts/src/barretenberg/index.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { BarretenbergApi, BarretenbergApiSync } from '../barretenberg_api/index.
33
import { createMainWorker } from '../barretenberg_wasm/barretenberg_wasm_main/factory/node/index.js';
44
import { BarretenbergWasmMain, BarretenbergWasmMainWorker } from '../barretenberg_wasm/barretenberg_wasm_main/index.js';
55
import { getRemoteBarretenbergWasm } from '../barretenberg_wasm/helpers/index.js';
6-
import { BarretenbergWasmWorker, fetchModuleAndThreads } from '../barretenberg_wasm/index.js';
6+
import { BarretenbergWasm, BarretenbergWasmWorker, fetchModuleAndThreads } from '../barretenberg_wasm/index.js';
77
import createDebug from 'debug';
88
import { Crs, GrumpkinCrs } from '../crs/index.js';
99
import { RawBuffer } from '../types/raw_buffer.js';
@@ -123,6 +123,32 @@ export class BarretenbergSync extends BarretenbergApiSync {
123123
}
124124
}
125125

126+
let barrentenbergLazySingleton: BarretenbergLazy;
127+
128+
export class BarretenbergLazy extends BarretenbergApi {
129+
private constructor(wasm: BarretenbergWasmMain) {
130+
super(wasm);
131+
}
132+
133+
private static async new() {
134+
const wasm = new BarretenbergWasmMain();
135+
const { module, threads } = await fetchModuleAndThreads(1);
136+
await wasm.init(module, threads);
137+
return new BarretenbergLazy(wasm);
138+
}
139+
140+
static async getSingleton() {
141+
if (!barrentenbergLazySingleton) {
142+
barrentenbergLazySingleton = await BarretenbergLazy.new();
143+
}
144+
return barrentenbergLazySingleton;
145+
}
146+
147+
getWasm() {
148+
return this.wasm;
149+
}
150+
}
151+
126152
// If we're in ESM environment, use top level await. CJS users need to call it manually.
127153
// Need to ignore for cjs build.
128154
// eslint-disable-next-line @typescript-eslint/ban-ts-comment

barretenberg/ts/src/barretenberg_api/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// WARNING: FILE CODE GENERATED BY BINDGEN UTILITY. DO NOT EDIT!
22
/* eslint-disable @typescript-eslint/no-unused-vars */
3+
import { BarretenbergWasmMain } from '../barretenberg_wasm/barretenberg_wasm_main/index.js';
34
import { BarretenbergWasmWorker, BarretenbergWasm } from '../barretenberg_wasm/index.js';
45
import {
56
BufferDeserializer,
@@ -13,7 +14,7 @@ import {
1314
import { Fr, Fq, Point, Buffer32, Buffer128, Ptr } from '../types/index.js';
1415

1516
export class BarretenbergApi {
16-
constructor(protected wasm: BarretenbergWasmWorker) {}
17+
constructor(protected wasm: BarretenbergWasmWorker | BarretenbergWasmMain) {}
1718

1819
async pedersenCommit(inputsBuffer: Fr[], ctxIndex: number): Promise<Point> {
1920
const inArgs = [inputsBuffer, ctxIndex].map(serializeBufferable);

barretenberg/ts/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export {
33
BackendOptions,
44
Barretenberg,
55
BarretenbergSync,
6+
BarretenbergLazy,
67
BarretenbergVerifier,
78
UltraPlonkBackend,
89
UltraHonkBackend,

yarn-project/archiver/src/archiver/archiver.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ describe('Archiver', () => {
7171

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

74-
beforeEach(() => {
74+
beforeEach(async () => {
7575
logger = createLogger('archiver:test');
7676
now = +new Date();
7777
publicClient = mock<PublicClient<HttpTransport, Chain>>({
@@ -117,7 +117,7 @@ describe('Archiver', () => {
117117
l1Constants,
118118
);
119119

120-
blocks = blockNumbers.map(x => L2Block.random(x, txsPerBlock, x + 1, 2));
120+
blocks = await Promise.all(blockNumbers.map(x => L2Block.random(x, txsPerBlock, x + 1, 2)));
121121
blocks.forEach(block => {
122122
block.body.txEffects.forEach((txEffect, i) => {
123123
txEffect.privateLogs = Array(getNumPrivateLogsForTx(block.number, i))

yarn-project/archiver/src/archiver/archiver_store_test_suite.ts

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
makeExecutablePrivateFunctionWithMembershipProof,
2121
makeUnconstrainedFunctionWithMembershipProof,
2222
} from '@aztec/circuits.js/testing';
23-
import { times } from '@aztec/foundation/collection';
23+
import { times, timesParallel } from '@aztec/foundation/collection';
2424
import { randomInt } from '@aztec/foundation/crypto';
2525

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

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

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

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

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

278278
beforeEach(async () => {
279-
contractInstance = { ...SerializableContractInstance.random(), address: AztecAddress.random() };
279+
const randomInstance = await SerializableContractInstance.random();
280+
contractInstance = { ...randomInstance, address: await AztecAddress.random() };
280281
await store.addContractInstances([contractInstance], blockNum);
281282
});
282283

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

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

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

411-
const mockBlockWithLogs = (blockNumber: number): L1Published<L2Block> => {
412-
const block = L2Block.random(blockNumber);
412+
const mockBlockWithLogs = async (blockNumber: number): Promise<L1Published<L2Block>> => {
413+
const block = await L2Block.random(blockNumber);
413414
block.header.globalVariables.blockNumber = new Fr(blockNumber);
414415

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

428429
beforeEach(async () => {
429-
blocks = times(numBlocks, (index: number) => mockBlockWithLogs(index));
430+
blocks = await timesParallel(numBlocks, (index: number) => mockBlockWithLogs(index));
430431

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

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

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

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

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

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

754755
blocks.forEach((block, blockIndex) => {
755756
nullifiersPerBlock.set(

yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { L2Block } from '@aztec/circuit-types';
2-
import { times } from '@aztec/foundation/collection';
2+
import { timesParallel } from '@aztec/foundation/collection';
33

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

yarn-project/archiver/src/test/mock_archiver.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,6 @@ export class MockPrefilledArchiver extends MockArchiver {
5151

5252
const fromBlock = this.l2Blocks.length;
5353
this.addBlocks(this.precomputed.slice(fromBlock, fromBlock + numBlocks));
54+
return Promise.resolve();
5455
}
5556
}

yarn-project/archiver/src/test/mock_l2_block_source.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ export class MockL2BlockSource implements L2BlockSource {
2424

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

27-
public createBlocks(numBlocks: number) {
27+
public async createBlocks(numBlocks: number) {
2828
for (let i = 0; i < numBlocks; i++) {
2929
const blockNum = this.l2Blocks.length + 1;
30-
const block = L2Block.random(blockNum);
30+
const block = await L2Block.random(blockNum);
3131
this.l2Blocks.push(block);
3232
}
3333

yarn-project/aztec.js/src/contract/contract.test.ts

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,6 @@ describe('Contract Class', () => {
4949
governanceProposerAddress: EthAddress.random(),
5050
slashFactoryAddress: EthAddress.random(),
5151
};
52-
const mockNodeInfo: NodeInfo = {
53-
nodeVersion: 'vx.x.x',
54-
l1ChainId: 1,
55-
protocolVersion: 2,
56-
l1ContractAddresses: l1Addresses,
57-
enr: undefined,
58-
protocolContractAddresses: {
59-
classRegisterer: AztecAddress.random(),
60-
feeJuice: AztecAddress.random(),
61-
instanceDeployer: AztecAddress.random(),
62-
multiCallEntrypoint: AztecAddress.random(),
63-
},
64-
};
6552

6653
const defaultArtifact: ContractArtifact = {
6754
name: 'FooContract',
@@ -141,11 +128,25 @@ describe('Contract Class', () => {
141128
notes: {},
142129
};
143130

144-
beforeEach(() => {
145-
contractAddress = AztecAddress.random();
131+
beforeEach(async () => {
132+
contractAddress = await AztecAddress.random();
146133
account = CompleteAddress.random();
147134
contractInstance = { address: contractAddress } as ContractInstanceWithAddress;
148135

136+
const mockNodeInfo: NodeInfo = {
137+
nodeVersion: 'vx.x.x',
138+
l1ChainId: 1,
139+
protocolVersion: 2,
140+
l1ContractAddresses: l1Addresses,
141+
enr: undefined,
142+
protocolContractAddresses: {
143+
classRegisterer: await AztecAddress.random(),
144+
feeJuice: await AztecAddress.random(),
145+
instanceDeployer: await AztecAddress.random(),
146+
multiCallEntrypoint: await AztecAddress.random(),
147+
},
148+
};
149+
149150
wallet = mock<Wallet>();
150151
wallet.simulateTx.mockResolvedValue(mockTxSimulationResult);
151152
wallet.createTxExecutionRequest.mockResolvedValue(mockTxRequest);

yarn-project/aztec.js/src/contract/get_gas_limits.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import { getGasLimits } from './get_gas_limits.js';
66
describe('getGasLimits', () => {
77
let txSimulationResult: TxSimulationResult;
88

9-
beforeEach(() => {
10-
txSimulationResult = mockSimulatedTx();
9+
beforeEach(async () => {
10+
txSimulationResult = await mockSimulatedTx();
1111

1212
const tx = mockTxForRollup();
1313
tx.data.gasUsed = Gas.from({ daGas: 100, l2Gas: 200 });

0 commit comments

Comments
 (0)