@aztec/end-to-end 0.82.2-alpha-testnet.4 → 0.82.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/bench/client_flows/client_flows_benchmark.d.ts +52 -0
- package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -0
- package/dest/bench/client_flows/client_flows_benchmark.js +236 -0
- package/dest/bench/client_flows/data_extractor.d.ts +23 -0
- package/dest/bench/client_flows/data_extractor.d.ts.map +1 -0
- package/dest/bench/client_flows/data_extractor.js +199 -0
- package/dest/bench/utils.d.ts +0 -12
- package/dest/bench/utils.d.ts.map +1 -1
- package/dest/bench/utils.js +0 -26
- package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts +0 -12
- package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts.map +1 -1
- package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.js +1 -13
- package/dest/e2e_fees/fees_test.d.ts.map +1 -1
- package/dest/e2e_fees/fees_test.js +1 -10
- package/dest/e2e_p2p/p2p_network.d.ts +5 -0
- package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
- package/dest/e2e_p2p/p2p_network.js +12 -3
- package/dest/e2e_p2p/shared.d.ts.map +1 -1
- package/dest/e2e_p2p/shared.js +1 -0
- package/dest/fixtures/token_utils.d.ts +2 -1
- package/dest/fixtures/token_utils.d.ts.map +1 -1
- package/dest/fixtures/token_utils.js +14 -1
- package/dest/sample-dapp/contracts.js +4 -4
- package/dest/shared/capture_private_execution_steps.d.ts +2 -2
- package/dest/shared/capture_private_execution_steps.d.ts.map +1 -1
- package/dest/shared/capture_private_execution_steps.js +24 -6
- package/dest/shared/cross_chain_test_harness.d.ts +11 -0
- package/dest/shared/cross_chain_test_harness.d.ts.map +1 -1
- package/dest/shared/cross_chain_test_harness.js +12 -1
- package/package.json +32 -32
- package/src/bench/client_flows/client_flows_benchmark.ts +331 -0
- package/src/bench/client_flows/data_extractor.ts +217 -0
- package/src/bench/utils.ts +0 -28
- package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +1 -25
- package/src/e2e_fees/fees_test.ts +1 -11
- package/src/e2e_p2p/p2p_network.ts +9 -5
- package/src/e2e_p2p/shared.ts +1 -0
- package/src/fixtures/token_utils.ts +22 -2
- package/src/sample-dapp/contracts.mjs +4 -4
- package/src/shared/capture_private_execution_steps.ts +43 -6
- package/src/shared/cross_chain_test_harness.ts +24 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import { EcdsaRAccountContractArtifact, getEcdsaRAccount } from '@aztec/accounts/ecdsa';
|
|
2
|
+
import { SchnorrAccountContractArtifact, getSchnorrAccount, getSchnorrWallet } from '@aztec/accounts/schnorr';
|
|
3
|
+
import {
|
|
4
|
+
type AccountWallet,
|
|
5
|
+
AztecAddress,
|
|
6
|
+
type AztecNode,
|
|
7
|
+
FeeJuicePaymentMethodWithClaim,
|
|
8
|
+
type Logger,
|
|
9
|
+
type PXE,
|
|
10
|
+
createLogger,
|
|
11
|
+
} from '@aztec/aztec.js';
|
|
12
|
+
import { CheatCodes } from '@aztec/aztec.js/testing';
|
|
13
|
+
import { FEE_FUNDING_FOR_TESTER_ACCOUNT } from '@aztec/constants';
|
|
14
|
+
import { type DeployL1ContractsArgs, RollupContract, createL1Clients, deployL1Contract } from '@aztec/ethereum';
|
|
15
|
+
import { ChainMonitor } from '@aztec/ethereum/test';
|
|
16
|
+
import { randomBytes } from '@aztec/foundation/crypto';
|
|
17
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
18
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
19
|
+
import { TestERC20Abi } from '@aztec/l1-artifacts/TestERC20Abi';
|
|
20
|
+
import { TestERC20Bytecode } from '@aztec/l1-artifacts/TestERC20Bytecode';
|
|
21
|
+
import { AMMContract } from '@aztec/noir-contracts.js/AMM';
|
|
22
|
+
import { FPCContract } from '@aztec/noir-contracts.js/FPC';
|
|
23
|
+
import { FeeJuiceContract } from '@aztec/noir-contracts.js/FeeJuice';
|
|
24
|
+
import { TokenContract as BananaCoin, TokenContract } from '@aztec/noir-contracts.js/Token';
|
|
25
|
+
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
26
|
+
import { getCanonicalFeeJuice } from '@aztec/protocol-contracts/fee-juice';
|
|
27
|
+
import { type PXEServiceConfig, createPXEService, getPXEServiceConfig } from '@aztec/pxe/server';
|
|
28
|
+
import { deriveSigningKey } from '@aztec/stdlib/keys';
|
|
29
|
+
|
|
30
|
+
import { MNEMONIC } from '../../fixtures/fixtures.js';
|
|
31
|
+
import {
|
|
32
|
+
type ISnapshotManager,
|
|
33
|
+
type SubsystemsContext,
|
|
34
|
+
createSnapshotManager,
|
|
35
|
+
deployAccounts,
|
|
36
|
+
} from '../../fixtures/snapshot_manager.js';
|
|
37
|
+
import { mintTokensToPrivate } from '../../fixtures/token_utils.js';
|
|
38
|
+
import { type SetupOptions, setupCanonicalFeeJuice } from '../../fixtures/utils.js';
|
|
39
|
+
import { CrossChainTestHarness } from '../../shared/cross_chain_test_harness.js';
|
|
40
|
+
import {
|
|
41
|
+
FeeJuicePortalTestingHarnessFactory,
|
|
42
|
+
type GasBridgingTestHarness,
|
|
43
|
+
} from '../../shared/gas_portal_test_harness.js';
|
|
44
|
+
|
|
45
|
+
const { E2E_DATA_PATH: dataPath } = process.env;
|
|
46
|
+
|
|
47
|
+
export type AccountType = 'ecdsar1' | 'schnorr';
|
|
48
|
+
|
|
49
|
+
export class ClientFlowsBenchmark {
|
|
50
|
+
private snapshotManager: ISnapshotManager;
|
|
51
|
+
|
|
52
|
+
public logger: Logger;
|
|
53
|
+
public pxe!: PXE;
|
|
54
|
+
public aztecNode!: AztecNode;
|
|
55
|
+
public cheatCodes!: CheatCodes;
|
|
56
|
+
public context!: SubsystemsContext;
|
|
57
|
+
public chainMonitor!: ChainMonitor;
|
|
58
|
+
public feeJuiceBridgeTestHarness!: GasBridgingTestHarness;
|
|
59
|
+
|
|
60
|
+
// The admin that aids in the setup of the test
|
|
61
|
+
public adminWallet!: AccountWallet;
|
|
62
|
+
public adminAddress!: AztecAddress;
|
|
63
|
+
|
|
64
|
+
// Aztec Node config
|
|
65
|
+
public sequencerAddress!: AztecAddress;
|
|
66
|
+
public coinbase!: EthAddress;
|
|
67
|
+
|
|
68
|
+
// Contracts
|
|
69
|
+
public feeJuiceContract!: FeeJuiceContract;
|
|
70
|
+
// Asset in which fees are paid via FPC
|
|
71
|
+
public bananaCoin!: BananaCoin;
|
|
72
|
+
public bananaFPC!: FPCContract;
|
|
73
|
+
// Random asset we want to trade
|
|
74
|
+
public candyBarCoin!: TokenContract;
|
|
75
|
+
// AMM contract
|
|
76
|
+
public amm!: AMMContract;
|
|
77
|
+
// Liquidity token for AMM
|
|
78
|
+
public liquidityToken!: TokenContract;
|
|
79
|
+
|
|
80
|
+
// PXE used by the benchmarking user. It can be set up with client-side proving enabled
|
|
81
|
+
public userPXE!: PXE;
|
|
82
|
+
|
|
83
|
+
constructor(testName?: string, setupOptions: Partial<SetupOptions & DeployL1ContractsArgs> = {}) {
|
|
84
|
+
this.logger = createLogger(`bench:client_flows${testName ? `:${testName}` : ''}`);
|
|
85
|
+
this.snapshotManager = createSnapshotManager(
|
|
86
|
+
`bench_client_flows${testName ? `/${testName}` : ''}`,
|
|
87
|
+
dataPath,
|
|
88
|
+
{ startProverNode: true, ...setupOptions },
|
|
89
|
+
{ ...setupOptions },
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async setup() {
|
|
94
|
+
const context = await this.snapshotManager.setup();
|
|
95
|
+
await context.aztecNode.setConfig({ feeRecipient: this.sequencerAddress, coinbase: this.coinbase });
|
|
96
|
+
|
|
97
|
+
const rollupContract = RollupContract.getFromConfig(context.aztecNodeConfig);
|
|
98
|
+
this.chainMonitor = new ChainMonitor(rollupContract, this.logger, 200).start();
|
|
99
|
+
|
|
100
|
+
return this;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async teardown() {
|
|
104
|
+
this.chainMonitor.stop();
|
|
105
|
+
await this.snapshotManager.teardown();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async mintAndBridgeFeeJuice(address: AztecAddress, amount: bigint) {
|
|
109
|
+
const claim = await this.feeJuiceBridgeTestHarness.prepareTokensOnL1(amount, address);
|
|
110
|
+
const { claimSecret: secret, messageLeafIndex: index } = claim;
|
|
111
|
+
await this.feeJuiceContract.methods.claim(address, amount, secret, index).send().wait();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Admin mints bananaCoin tokens privately to the target address and redeems them. */
|
|
115
|
+
async mintPrivateBananas(amount: bigint, address: AztecAddress) {
|
|
116
|
+
const balanceBefore = await this.bananaCoin.methods.balance_of_private(address).simulate();
|
|
117
|
+
|
|
118
|
+
await mintTokensToPrivate(this.bananaCoin, this.adminWallet, address, amount);
|
|
119
|
+
|
|
120
|
+
const balanceAfter = await this.bananaCoin.methods.balance_of_private(address).simulate();
|
|
121
|
+
expect(balanceAfter).toEqual(balanceBefore + amount);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async createBenchmarkingAccountManager(type: 'ecdsar1' | 'schnorr') {
|
|
125
|
+
const benchysSecretKey = Fr.random();
|
|
126
|
+
const salt = Fr.random();
|
|
127
|
+
|
|
128
|
+
let benchysPrivateSigningKey;
|
|
129
|
+
let benchysAccountManager;
|
|
130
|
+
if (type === 'schnorr') {
|
|
131
|
+
benchysPrivateSigningKey = deriveSigningKey(benchysSecretKey);
|
|
132
|
+
benchysAccountManager = await getSchnorrAccount(this.userPXE, benchysSecretKey, benchysPrivateSigningKey, salt);
|
|
133
|
+
} else if (type === 'ecdsar1') {
|
|
134
|
+
benchysPrivateSigningKey = randomBytes(32);
|
|
135
|
+
benchysAccountManager = await getEcdsaRAccount(this.userPXE, benchysSecretKey, benchysPrivateSigningKey, salt);
|
|
136
|
+
} else {
|
|
137
|
+
throw new Error(`Unknown account type: ${type}`);
|
|
138
|
+
}
|
|
139
|
+
await benchysAccountManager.register();
|
|
140
|
+
return benchysAccountManager;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
public async applyBaseSnapshots() {
|
|
144
|
+
await this.applyInitialAccountsSnapshot();
|
|
145
|
+
await this.applySetupFeeJuiceSnapshot();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async applyInitialAccountsSnapshot() {
|
|
149
|
+
await this.snapshotManager.snapshot(
|
|
150
|
+
'initial_accounts',
|
|
151
|
+
deployAccounts(2, this.logger),
|
|
152
|
+
async ({ deployedAccounts }, { pxe, aztecNode, aztecNodeConfig }) => {
|
|
153
|
+
this.pxe = pxe;
|
|
154
|
+
|
|
155
|
+
this.aztecNode = aztecNode;
|
|
156
|
+
this.cheatCodes = await CheatCodes.create(aztecNodeConfig.l1RpcUrls, pxe);
|
|
157
|
+
|
|
158
|
+
const deployedWallets = await Promise.all(
|
|
159
|
+
deployedAccounts.map(a => getSchnorrWallet(pxe, a.address, a.signingKey)),
|
|
160
|
+
);
|
|
161
|
+
[this.adminWallet] = deployedWallets;
|
|
162
|
+
this.adminAddress = this.adminWallet.getAddress();
|
|
163
|
+
this.sequencerAddress = deployedWallets[1].getAddress();
|
|
164
|
+
|
|
165
|
+
const canonicalFeeJuice = await getCanonicalFeeJuice();
|
|
166
|
+
this.feeJuiceContract = await FeeJuiceContract.at(canonicalFeeJuice.address, this.adminWallet);
|
|
167
|
+
this.coinbase = EthAddress.random();
|
|
168
|
+
|
|
169
|
+
const userPXEConfig = getPXEServiceConfig();
|
|
170
|
+
const l1Contracts = await aztecNode.getL1ContractAddresses();
|
|
171
|
+
const userPXEConfigWithContracts = {
|
|
172
|
+
...userPXEConfig,
|
|
173
|
+
proverEnabled: ['true', '1'].includes(process.env.REAL_PROOFS ?? ''),
|
|
174
|
+
l1Contracts,
|
|
175
|
+
} as PXEServiceConfig;
|
|
176
|
+
|
|
177
|
+
this.userPXE = await createPXEService(this.aztecNode, userPXEConfigWithContracts, 'pxe-user');
|
|
178
|
+
},
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async applySetupFeeJuiceSnapshot() {
|
|
183
|
+
await this.snapshotManager.snapshot(
|
|
184
|
+
'setup_fee_juice',
|
|
185
|
+
async context => {
|
|
186
|
+
await setupCanonicalFeeJuice(context.pxe);
|
|
187
|
+
},
|
|
188
|
+
async (_data, context) => {
|
|
189
|
+
this.context = context;
|
|
190
|
+
|
|
191
|
+
this.feeJuiceContract = await FeeJuiceContract.at(ProtocolContractAddress.FeeJuice, this.adminWallet);
|
|
192
|
+
|
|
193
|
+
this.feeJuiceBridgeTestHarness = await FeeJuicePortalTestingHarnessFactory.create({
|
|
194
|
+
aztecNode: context.aztecNode,
|
|
195
|
+
aztecNodeAdmin: context.aztecNode,
|
|
196
|
+
pxeService: context.pxe,
|
|
197
|
+
publicClient: context.deployL1ContractsValues.publicClient,
|
|
198
|
+
walletClient: context.deployL1ContractsValues.walletClient,
|
|
199
|
+
wallet: this.adminWallet,
|
|
200
|
+
logger: this.logger,
|
|
201
|
+
});
|
|
202
|
+
},
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
async applyDeployBananaTokenSnapshot() {
|
|
207
|
+
await this.snapshotManager.snapshot(
|
|
208
|
+
'deploy_banana_token',
|
|
209
|
+
async () => {
|
|
210
|
+
const bananaCoin = await BananaCoin.deploy(this.adminWallet, this.adminAddress, 'BC', 'BC', 18n)
|
|
211
|
+
.send()
|
|
212
|
+
.deployed();
|
|
213
|
+
this.logger.info(`BananaCoin deployed at ${bananaCoin.address}`);
|
|
214
|
+
return { bananaCoinAddress: bananaCoin.address };
|
|
215
|
+
},
|
|
216
|
+
async ({ bananaCoinAddress }) => {
|
|
217
|
+
this.bananaCoin = await BananaCoin.at(bananaCoinAddress, this.adminWallet);
|
|
218
|
+
},
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async applyDeployCandyBarTokenSnapshot() {
|
|
223
|
+
await this.snapshotManager.snapshot(
|
|
224
|
+
'deploy_candy_bar_token',
|
|
225
|
+
async () => {
|
|
226
|
+
const candyBarCoin = await TokenContract.deploy(this.adminWallet, this.adminAddress, 'CBC', 'CBC', 18n)
|
|
227
|
+
.send()
|
|
228
|
+
.deployed();
|
|
229
|
+
this.logger.info(`CandyBarCoin deployed at ${candyBarCoin.address}`);
|
|
230
|
+
return { candyBarCoinAddress: candyBarCoin.address };
|
|
231
|
+
},
|
|
232
|
+
async ({ candyBarCoinAddress }) => {
|
|
233
|
+
this.candyBarCoin = await TokenContract.at(candyBarCoinAddress, this.adminWallet);
|
|
234
|
+
},
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
public async applyFPCSetupSnapshot() {
|
|
239
|
+
await this.snapshotManager.snapshot(
|
|
240
|
+
'fpc_setup',
|
|
241
|
+
async context => {
|
|
242
|
+
const feeJuiceContract = this.feeJuiceBridgeTestHarness.feeJuice;
|
|
243
|
+
expect((await context.pxe.getContractMetadata(feeJuiceContract.address)).isContractPubliclyDeployed).toBe(true);
|
|
244
|
+
|
|
245
|
+
const bananaCoin = this.bananaCoin;
|
|
246
|
+
const bananaFPC = await FPCContract.deploy(this.adminWallet, bananaCoin.address, this.adminAddress)
|
|
247
|
+
.send()
|
|
248
|
+
.deployed();
|
|
249
|
+
|
|
250
|
+
this.logger.info(`BananaPay deployed at ${bananaFPC.address}`);
|
|
251
|
+
|
|
252
|
+
await this.feeJuiceBridgeTestHarness.bridgeFromL1ToL2(FEE_FUNDING_FOR_TESTER_ACCOUNT, bananaFPC.address);
|
|
253
|
+
|
|
254
|
+
return { bananaFPCAddress: bananaFPC.address };
|
|
255
|
+
},
|
|
256
|
+
async data => {
|
|
257
|
+
this.bananaFPC = await FPCContract.at(data.bananaFPCAddress, this.adminWallet);
|
|
258
|
+
},
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
public async createCrossChainTestHarness(owner: AccountWallet) {
|
|
263
|
+
const { publicClient, walletClient } = createL1Clients(this.context.aztecNodeConfig.l1RpcUrls, MNEMONIC);
|
|
264
|
+
|
|
265
|
+
const underlyingERC20Address = await deployL1Contract(walletClient, publicClient, TestERC20Abi, TestERC20Bytecode, [
|
|
266
|
+
'Underlying',
|
|
267
|
+
'UND',
|
|
268
|
+
walletClient.account.address,
|
|
269
|
+
]).then(({ address }) => address);
|
|
270
|
+
|
|
271
|
+
this.logger.verbose(`Setting up cross chain harness...`);
|
|
272
|
+
const crossChainTestHarness = await CrossChainTestHarness.new(
|
|
273
|
+
this.aztecNode,
|
|
274
|
+
this.pxe,
|
|
275
|
+
publicClient,
|
|
276
|
+
walletClient,
|
|
277
|
+
owner,
|
|
278
|
+
this.logger,
|
|
279
|
+
underlyingERC20Address,
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
this.logger.verbose(`L2 token deployed to: ${crossChainTestHarness.l2Token.address}`);
|
|
283
|
+
|
|
284
|
+
return crossChainTestHarness;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
public async createAndFundBenchmarkingWallet(accountType: AccountType) {
|
|
288
|
+
const benchysAccountManager = await this.createBenchmarkingAccountManager(accountType);
|
|
289
|
+
const benchysWallet = await benchysAccountManager.getWallet();
|
|
290
|
+
const benchysAddress = benchysAccountManager.getAddress();
|
|
291
|
+
const claim = await this.feeJuiceBridgeTestHarness.prepareTokensOnL1(
|
|
292
|
+
FEE_FUNDING_FOR_TESTER_ACCOUNT,
|
|
293
|
+
benchysAddress,
|
|
294
|
+
);
|
|
295
|
+
const paymentMethod = new FeeJuicePaymentMethodWithClaim(benchysWallet, claim);
|
|
296
|
+
await benchysAccountManager.deploy({ fee: { paymentMethod } }).wait();
|
|
297
|
+
// Register benchy on admin's PXE so we can check its balances
|
|
298
|
+
await this.pxe.registerContract({
|
|
299
|
+
instance: benchysAccountManager.getInstance(),
|
|
300
|
+
artifact: accountType === 'ecdsar1' ? EcdsaRAccountContractArtifact : SchnorrAccountContractArtifact,
|
|
301
|
+
});
|
|
302
|
+
await this.pxe.registerAccount(benchysWallet.getSecretKey(), benchysWallet.getCompleteAddress().partialAddress);
|
|
303
|
+
return benchysWallet;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
public async applyDeployAmmSnapshot() {
|
|
307
|
+
await this.snapshotManager.snapshot(
|
|
308
|
+
'deploy_amm',
|
|
309
|
+
async () => {
|
|
310
|
+
const liquidityToken = await TokenContract.deploy(this.adminWallet, this.adminAddress, 'LPT', 'LPT', 18n)
|
|
311
|
+
.send()
|
|
312
|
+
.deployed();
|
|
313
|
+
const amm = await AMMContract.deploy(
|
|
314
|
+
this.adminWallet,
|
|
315
|
+
this.bananaCoin.address,
|
|
316
|
+
this.candyBarCoin.address,
|
|
317
|
+
liquidityToken.address,
|
|
318
|
+
)
|
|
319
|
+
.send()
|
|
320
|
+
.deployed();
|
|
321
|
+
this.logger.info(`AMM deployed at ${amm.address}`);
|
|
322
|
+
await liquidityToken.methods.set_minter(amm.address, true).send().wait();
|
|
323
|
+
return { ammAddress: amm.address, liquidityTokenAddress: liquidityToken.address };
|
|
324
|
+
},
|
|
325
|
+
async ({ ammAddress, liquidityTokenAddress }) => {
|
|
326
|
+
this.liquidityToken = await TokenContract.at(liquidityTokenAddress, this.adminWallet);
|
|
327
|
+
this.amm = await AMMContract.at(ammAddress, this.adminWallet);
|
|
328
|
+
},
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import type { Logger } from '@aztec/aztec.js';
|
|
2
|
+
import { BBNativePrivateKernelProver } from '@aztec/bb-prover';
|
|
3
|
+
import { BBWASMBundlePrivateKernelProver } from '@aztec/bb-prover/wasm/bundle';
|
|
4
|
+
import { createLogger, logger } from '@aztec/foundation/log';
|
|
5
|
+
import { WASMSimulator } from '@aztec/simulator/client';
|
|
6
|
+
import type { PrivateExecutionStep } from '@aztec/stdlib/kernel';
|
|
7
|
+
|
|
8
|
+
import { decode } from '@msgpack/msgpack';
|
|
9
|
+
import assert from 'node:assert';
|
|
10
|
+
import { readFile, readdir, writeFile } from 'node:fs/promises';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
|
|
13
|
+
const logLevel = ['silent', 'fatal', 'error', 'warn', 'info', 'verbose', 'debug', 'trace'] as const;
|
|
14
|
+
type LogLevel = (typeof logLevel)[number];
|
|
15
|
+
|
|
16
|
+
type Log = {
|
|
17
|
+
type: LogLevel;
|
|
18
|
+
timestamp: number;
|
|
19
|
+
prefix: string;
|
|
20
|
+
message: string;
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
|
+
data: any;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const GATE_TYPES = [
|
|
26
|
+
'ecc_op',
|
|
27
|
+
'busread',
|
|
28
|
+
'lookup',
|
|
29
|
+
'pub_inputs',
|
|
30
|
+
'arithmetic',
|
|
31
|
+
'delta_range',
|
|
32
|
+
'elliptic',
|
|
33
|
+
'aux',
|
|
34
|
+
'poseidon2_external',
|
|
35
|
+
'poseidon2_internal',
|
|
36
|
+
'overflow',
|
|
37
|
+
] as const;
|
|
38
|
+
|
|
39
|
+
type GateType = (typeof GATE_TYPES)[number];
|
|
40
|
+
|
|
41
|
+
type StructuredTrace = {
|
|
42
|
+
[k in GateType]: number;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export class ProxyLogger {
|
|
46
|
+
private static instance: ProxyLogger;
|
|
47
|
+
private logs: Log[] = [];
|
|
48
|
+
|
|
49
|
+
private constructor() {}
|
|
50
|
+
|
|
51
|
+
static create() {
|
|
52
|
+
ProxyLogger.instance = new ProxyLogger();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static getInstance() {
|
|
56
|
+
return ProxyLogger.instance;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
createLogger(prefix: string): Logger {
|
|
60
|
+
return new Proxy(createLogger(prefix), {
|
|
61
|
+
get: (target: Logger, prop: keyof Logger) => {
|
|
62
|
+
if (logLevel.includes(prop as (typeof logLevel)[number])) {
|
|
63
|
+
return function (this: Logger, ...data: Parameters<Logger[LogLevel]>) {
|
|
64
|
+
const loggingFn = prop as LogLevel;
|
|
65
|
+
const args = [loggingFn, prefix, ...data] as Parameters<ProxyLogger['handleLog']>;
|
|
66
|
+
ProxyLogger.getInstance().handleLog(...args);
|
|
67
|
+
target[loggingFn].call(this, ...[data[0], data[1]]);
|
|
68
|
+
};
|
|
69
|
+
} else {
|
|
70
|
+
return target[prop];
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private handleLog(type: (typeof logLevel)[number], prefix: string, message: string, data: any) {
|
|
77
|
+
this.logs.unshift({ type, prefix, message, data, timestamp: Date.now() });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public flushLogs() {
|
|
81
|
+
this.logs = [];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public getLogs() {
|
|
85
|
+
return this.logs;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
type NativeProverConfig = { bbBinaryPath?: string; bbWorkingDirectory?: string };
|
|
90
|
+
|
|
91
|
+
type ProverType = 'wasm' | 'native';
|
|
92
|
+
|
|
93
|
+
type Step = { fnName: string; gateCount: number; accGateCount?: number };
|
|
94
|
+
|
|
95
|
+
async function createProver(config: NativeProverConfig = {}, log: Logger) {
|
|
96
|
+
const simulationProvider = new WASMSimulator();
|
|
97
|
+
if (!config.bbBinaryPath || !config.bbWorkingDirectory) {
|
|
98
|
+
return { prover: new BBWASMBundlePrivateKernelProver(simulationProvider, 16, log), type: 'wasm' as ProverType };
|
|
99
|
+
} else {
|
|
100
|
+
const bbConfig = config as Required<NativeProverConfig>;
|
|
101
|
+
return {
|
|
102
|
+
prover: await BBNativePrivateKernelProver.new({ bbSkipCleanup: false, ...bbConfig }, simulationProvider, log),
|
|
103
|
+
type: 'native' as ProverType,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function getMinimumTrace(logs: Log[], proverType: ProverType): StructuredTrace {
|
|
109
|
+
const minimumMessage = 'Minimum required block sizes for structured trace:';
|
|
110
|
+
const minimumMessageIndex = logs.findIndex(log => log.message.includes(minimumMessage));
|
|
111
|
+
const candidateLogs = logs.slice(minimumMessageIndex - GATE_TYPES.length, minimumMessageIndex);
|
|
112
|
+
const traceLogs =
|
|
113
|
+
proverType === 'wasm'
|
|
114
|
+
? candidateLogs.map(log => log.message)
|
|
115
|
+
: logs
|
|
116
|
+
.slice(minimumMessageIndex - GATE_TYPES.length, minimumMessageIndex)
|
|
117
|
+
.filter(log => GATE_TYPES.some(type => log.message.includes(`bb - ${type}`)))
|
|
118
|
+
.map(log => log.message.split('\n'))
|
|
119
|
+
.flat();
|
|
120
|
+
const traceSizes = traceLogs.map(log => {
|
|
121
|
+
const [gateType, gateSizeStr] = log
|
|
122
|
+
.replace(/\n.*\)$/, '')
|
|
123
|
+
.replace(/bb - /, '')
|
|
124
|
+
.split(':')
|
|
125
|
+
.map(s => s.trim());
|
|
126
|
+
const gateSize = parseInt(gateSizeStr);
|
|
127
|
+
assert(GATE_TYPES.includes(gateType as GateType), `Gate type ${gateType} is not recognized`);
|
|
128
|
+
return { [gateType]: gateSize };
|
|
129
|
+
});
|
|
130
|
+
assert(traceSizes.length === GATE_TYPES.length, 'Decoded trace sizes do not match expected amount of gate types');
|
|
131
|
+
return traceSizes.reduce((acc, curr) => ({ ...acc, ...curr }), {}) as StructuredTrace;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function main() {
|
|
135
|
+
ProxyLogger.create();
|
|
136
|
+
const proxyLogger = ProxyLogger.getInstance();
|
|
137
|
+
const ivcFolder = process.env.CAPTURE_IVC_FOLDER;
|
|
138
|
+
if (!ivcFolder) {
|
|
139
|
+
throw new Error('CAPTURE_IVC_FOLDER is not set');
|
|
140
|
+
}
|
|
141
|
+
const flows = await readdir(ivcFolder);
|
|
142
|
+
logger.info(`Flows in ${ivcFolder}: \n${flows.map(flowName => `\t- ${flowName}`).join('\n')}`);
|
|
143
|
+
const { prover, type: proverType } = await createProver(
|
|
144
|
+
{ bbBinaryPath: process.env.BB_BINARY_PATH, bbWorkingDirectory: process.env.BB_WORKING_DIRECTORY },
|
|
145
|
+
proxyLogger.createLogger('bb:prover'),
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
const userLog = createLogger('client_ivc_flows:data_processor');
|
|
149
|
+
|
|
150
|
+
for (const flow of flows) {
|
|
151
|
+
userLog.info(`Processing flow ${flow}`);
|
|
152
|
+
const bytecode = await readFile(join(ivcFolder, flow, 'acir.msgpack'));
|
|
153
|
+
const acirStack = decode(bytecode) as Buffer[];
|
|
154
|
+
const witnesses = await readFile(join(ivcFolder, flow, 'witnesses.json'));
|
|
155
|
+
const witnessStack = JSON.parse(witnesses.toString()).map((witnessMap: Record<string, string>) => {
|
|
156
|
+
return new Map<number, string>(Object.entries(witnessMap).map(([k, v]) => [Number(k), v]));
|
|
157
|
+
});
|
|
158
|
+
const stepsFile = await readFile(join(ivcFolder, flow, 'steps.json'));
|
|
159
|
+
const executionSteps = JSON.parse(stepsFile.toString()) as { fnName: string; gateCount: number }[];
|
|
160
|
+
const privateExecutionSteps: PrivateExecutionStep[] = executionSteps.map((step, i) => ({
|
|
161
|
+
functionName: step.fnName,
|
|
162
|
+
gateCount: step.gateCount,
|
|
163
|
+
bytecode: acirStack[i],
|
|
164
|
+
witness: witnessStack[i],
|
|
165
|
+
}));
|
|
166
|
+
let minimumTrace: StructuredTrace | undefined;
|
|
167
|
+
let stats: { duration: number; eventName: string; proofSize: number } | undefined;
|
|
168
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
169
|
+
let error: any | undefined;
|
|
170
|
+
let currentLogs: Log[] = [];
|
|
171
|
+
try {
|
|
172
|
+
await prover.createClientIvcProof(privateExecutionSteps);
|
|
173
|
+
} catch (e) {
|
|
174
|
+
userLog.error(`Failed to generate client ivc proof for ${flow}`, e);
|
|
175
|
+
error = (e as Error).message;
|
|
176
|
+
}
|
|
177
|
+
// Extract logs from this run from the proxy and write them to disk unconditionally
|
|
178
|
+
currentLogs = proxyLogger.getLogs();
|
|
179
|
+
await writeFile(join(ivcFolder, flow, 'logs.json'), JSON.stringify(currentLogs, null, 2));
|
|
180
|
+
|
|
181
|
+
if (!error) {
|
|
182
|
+
minimumTrace = getMinimumTrace(currentLogs, proverType);
|
|
183
|
+
stats = currentLogs[0].data as { duration: number; eventName: string; proofSize: number };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const steps = executionSteps.reduce<Step[]>((acc, step, i) => {
|
|
187
|
+
const previousAccGateCount = i === 0 ? 0 : acc[i - 1].accGateCount!;
|
|
188
|
+
return [
|
|
189
|
+
...acc,
|
|
190
|
+
{
|
|
191
|
+
fnName: step.fnName,
|
|
192
|
+
gateCount: step.gateCount,
|
|
193
|
+
accGateCount: previousAccGateCount + step.gateCount,
|
|
194
|
+
},
|
|
195
|
+
];
|
|
196
|
+
}, []);
|
|
197
|
+
const totalGateCount = steps[steps.length - 1].accGateCount;
|
|
198
|
+
const benchmark = {
|
|
199
|
+
proverType,
|
|
200
|
+
minimumTrace: minimumTrace,
|
|
201
|
+
totalGateCount,
|
|
202
|
+
stats,
|
|
203
|
+
steps,
|
|
204
|
+
error,
|
|
205
|
+
};
|
|
206
|
+
await writeFile(join(ivcFolder, flow, 'benchmark.json'), JSON.stringify(benchmark, null, 2));
|
|
207
|
+
proxyLogger.flushLogs();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
try {
|
|
212
|
+
await main();
|
|
213
|
+
} catch (e) {
|
|
214
|
+
// eslint-disable-next-line no-console
|
|
215
|
+
console.error(e);
|
|
216
|
+
process.exit(1);
|
|
217
|
+
}
|
package/src/bench/utils.ts
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import type { AztecNodeService } from '@aztec/aztec-node';
|
|
2
2
|
import { type AztecNode, BatchCall, INITIAL_L2_BLOCK_NUM, type SentTx, type WaitOpts } from '@aztec/aztec.js';
|
|
3
3
|
import { mean, stdDev, times } from '@aztec/foundation/collection';
|
|
4
|
-
import { randomInt } from '@aztec/foundation/crypto';
|
|
5
4
|
import { BenchmarkingContract } from '@aztec/noir-contracts.js/Benchmarking';
|
|
6
5
|
import { type PXEService, type PXEServiceConfig, createPXEService } from '@aztec/pxe/server';
|
|
7
6
|
import type { MetricsType } from '@aztec/telemetry-client';
|
|
8
7
|
import type { BenchmarkDataPoint, BenchmarkMetricsType, BenchmarkTelemetryClient } from '@aztec/telemetry-client/bench';
|
|
9
8
|
|
|
10
9
|
import { writeFileSync } from 'fs';
|
|
11
|
-
import { mkdirpSync } from 'fs-extra';
|
|
12
|
-
import { globSync } from 'glob';
|
|
13
|
-
import { join } from 'path';
|
|
14
10
|
|
|
15
11
|
import { type EndToEndContext, type SetupOptions, setup } from '../fixtures/utils.js';
|
|
16
12
|
|
|
@@ -94,30 +90,6 @@ function getMetricValues(points: BenchmarkDataPoint[]) {
|
|
|
94
90
|
}
|
|
95
91
|
}
|
|
96
92
|
|
|
97
|
-
/**
|
|
98
|
-
* Creates and returns a directory with the current job name and a random number.
|
|
99
|
-
* @param index - Index to merge into the dir path.
|
|
100
|
-
* @returns A path to a created dir.
|
|
101
|
-
*/
|
|
102
|
-
export function makeDataDirectory(index: number) {
|
|
103
|
-
const testName = expect.getState().currentTestName!.split(' ')[0].replaceAll('/', '_');
|
|
104
|
-
const db = join('data', testName, index.toString(), `${randomInt(99)}`);
|
|
105
|
-
mkdirpSync(db);
|
|
106
|
-
return db;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Returns the size in disk of a folder.
|
|
111
|
-
* @param path - Path to the folder.
|
|
112
|
-
* @returns Size in bytes.
|
|
113
|
-
*/
|
|
114
|
-
export function getFolderSize(path: string): number {
|
|
115
|
-
return globSync('**', { stat: true, cwd: path, nodir: true, withFileTypes: true }).reduce(
|
|
116
|
-
(accum, file) => accum + (file as any as { /** Size */ size: number }).size,
|
|
117
|
-
0,
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
93
|
/**
|
|
122
94
|
* Returns a call to the benchmark contract. Each call has a private execution (account entrypoint),
|
|
123
95
|
* a nested private call (create_note), a public call (increment_balance), and a nested public
|
|
@@ -132,7 +132,7 @@ export class CrossChainMessagingTest {
|
|
|
132
132
|
|
|
133
133
|
this.logger.verbose(`L2 token deployed to: ${this.crossChainTestHarness.l2Token.address}`);
|
|
134
134
|
|
|
135
|
-
return this.toCrossChainContext();
|
|
135
|
+
return this.crossChainTestHarness.toCrossChainContext();
|
|
136
136
|
},
|
|
137
137
|
async crossChainContext => {
|
|
138
138
|
this.l2Token = await TokenContract.at(crossChainContext.l2Token, this.user1Wallet);
|
|
@@ -177,28 +177,4 @@ export class CrossChainMessagingTest {
|
|
|
177
177
|
},
|
|
178
178
|
);
|
|
179
179
|
}
|
|
180
|
-
|
|
181
|
-
toCrossChainContext(): CrossChainContext {
|
|
182
|
-
return {
|
|
183
|
-
l2Token: this.crossChainTestHarness.l2Token.address,
|
|
184
|
-
l2Bridge: this.crossChainTestHarness.l2Bridge.address,
|
|
185
|
-
tokenPortal: this.crossChainTestHarness.tokenPortalAddress,
|
|
186
|
-
underlying: this.crossChainTestHarness.underlyingERC20Address,
|
|
187
|
-
ethAccount: this.crossChainTestHarness.ethAccount,
|
|
188
|
-
ownerAddress: this.crossChainTestHarness.ownerAddress,
|
|
189
|
-
inbox: this.crossChainTestHarness.l1ContractAddresses.inboxAddress,
|
|
190
|
-
outbox: this.crossChainTestHarness.l1ContractAddresses.outboxAddress,
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
180
|
}
|
|
194
|
-
|
|
195
|
-
type CrossChainContext = {
|
|
196
|
-
l2Token: AztecAddress;
|
|
197
|
-
l2Bridge: AztecAddress;
|
|
198
|
-
tokenPortal: EthAddress;
|
|
199
|
-
underlying: EthAddress;
|
|
200
|
-
ethAccount: EthAddress;
|
|
201
|
-
ownerAddress: AztecAddress;
|
|
202
|
-
inbox: EthAddress;
|
|
203
|
-
outbox: EthAddress;
|
|
204
|
-
};
|
|
@@ -168,7 +168,7 @@ export class FeesTest {
|
|
|
168
168
|
await this.snapshotManager.snapshot(
|
|
169
169
|
'initial_accounts',
|
|
170
170
|
deployAccounts(this.numberOfAccounts, this.logger),
|
|
171
|
-
async ({ deployedAccounts }, { pxe, aztecNode, aztecNodeConfig
|
|
171
|
+
async ({ deployedAccounts }, { pxe, aztecNode, aztecNodeConfig }) => {
|
|
172
172
|
this.pxe = pxe;
|
|
173
173
|
|
|
174
174
|
this.aztecNode = aztecNode;
|
|
@@ -185,16 +185,6 @@ export class FeesTest {
|
|
|
185
185
|
const canonicalFeeJuice = await getCanonicalFeeJuice();
|
|
186
186
|
this.feeJuiceContract = await FeeJuiceContract.at(canonicalFeeJuice.address, this.aliceWallet);
|
|
187
187
|
this.coinbase = EthAddress.random();
|
|
188
|
-
|
|
189
|
-
this.feeJuiceBridgeTestHarness = await FeeJuicePortalTestingHarnessFactory.create({
|
|
190
|
-
aztecNode,
|
|
191
|
-
aztecNodeAdmin: aztecNode,
|
|
192
|
-
pxeService: pxe,
|
|
193
|
-
publicClient: deployL1ContractsValues.publicClient,
|
|
194
|
-
walletClient: deployL1ContractsValues.walletClient,
|
|
195
|
-
wallet: this.aliceWallet,
|
|
196
|
-
logger: this.logger,
|
|
197
|
-
});
|
|
198
188
|
},
|
|
199
189
|
);
|
|
200
190
|
}
|