diff --git a/yarn-project/CLAUDE.md b/yarn-project/CLAUDE.md index 36f3faa2f7b7..d0f91eb6e4d1 100644 --- a/yarn-project/CLAUDE.md +++ b/yarn-project/CLAUDE.md @@ -92,29 +92,27 @@ env LOG_LEVEL='info; debug:sequencer,archiver' yarn test src/file.test.ts ## Format & Lint -All commands run from `yarn-project`. +**IMPORTANT**: These commands are run from the root of `yarn-project`, NOT the git root. -### Single Package (Preferred) +### Format ```bash -./bootstrap.sh format -./bootstrap.sh lint +./bootstrap.sh format # All packages +./bootstrap.sh format # Single package (faster) +./bootstrap.sh format --check # Check only, no changes ``` -### All Packages - -Only when multiple packages are modified: +### Lint ```bash -./bootstrap.sh format -./bootstrap.sh lint +yarn lint # Same command CI uses - run this before pushing ``` -### Check Mode (No Changes) +For faster iteration during development: ```bash -./bootstrap.sh format --check -./bootstrap.sh lint --check +./bootstrap.sh lint # Single package (faster) +./bootstrap.sh lint # All packages ``` ## Dependency Management diff --git a/yarn-project/end-to-end/src/bench/client_flows/account_deployments.test.ts b/yarn-project/end-to-end/src/bench/client_flows/account_deployments.test.ts index 8c8cec966337..ff7c4cdaa019 100644 --- a/yarn-project/end-to-end/src/bench/client_flows/account_deployments.test.ts +++ b/yarn-project/end-to-end/src/bench/client_flows/account_deployments.test.ts @@ -27,9 +27,9 @@ describe('Deployment benchmark', () => { let userWallet: TestWallet; beforeAll(async () => { - await t.applyBaseSnapshots(); - await t.applyDeploySponsoredFPCSnapshot(); - ({ adminWallet, adminAddress, userWallet, sponsoredFPCInstance } = await t.setup()); + await t.setup(); + await t.applyDeploySponsoredFPC(); + ({ adminWallet, adminAddress, userWallet, sponsoredFPCInstance } = t); // Ensure the ECDSAR1 contract is already registered, to avoid benchmarking an extra call to the ContractClassRegistry // The typical interaction would be for a user to deploy an account contract that is already registered in the // network. diff --git a/yarn-project/end-to-end/src/bench/client_flows/amm.test.ts b/yarn-project/end-to-end/src/bench/client_flows/amm.test.ts index 0a4fdd7b1e11..79283b631bdd 100644 --- a/yarn-project/end-to-end/src/bench/client_flows/amm.test.ts +++ b/yarn-project/end-to-end/src/bench/client_flows/amm.test.ts @@ -47,12 +47,12 @@ describe('AMM benchmark', () => { const config = t.config.amm; beforeAll(async () => { - await t.applyBaseSnapshots(); - await t.applyDeployBananaTokenSnapshot(); - await t.applyFPCSetupSnapshot(); - await t.applyDeployCandyBarTokenSnapshot(); - await t.applyDeployAmmSnapshot(); - await t.applyDeploySponsoredFPCSnapshot(); + await t.setup(); + await t.applyDeployBananaToken(); + await t.applyFPCSetup(); + await t.applyDeployCandyBarToken(); + await t.applyDeployAmm(); + await t.applyDeploySponsoredFPC(); ({ adminWallet, userWallet, @@ -66,7 +66,7 @@ describe('AMM benchmark', () => { ammInstance, liquidityTokenInstance, sponsoredFPCInstance, - } = await t.setup()); + } = t); }); afterAll(async () => { diff --git a/yarn-project/end-to-end/src/bench/client_flows/bridging.test.ts b/yarn-project/end-to-end/src/bench/client_flows/bridging.test.ts index a703ba225802..f62809feb73d 100644 --- a/yarn-project/end-to-end/src/bench/client_flows/bridging.test.ts +++ b/yarn-project/end-to-end/src/bench/client_flows/bridging.test.ts @@ -23,11 +23,11 @@ describe('Bridging benchmark', () => { const config = t.config.bridging; beforeAll(async () => { - await t.applyBaseSnapshots(); - await t.applyDeployBananaTokenSnapshot(); - await t.applyFPCSetupSnapshot(); - await t.applyDeploySponsoredFPCSnapshot(); - ({ userWallet, adminAddress } = await t.setup()); + await t.setup(); + await t.applyDeployBananaToken(); + await t.applyFPCSetup(); + await t.applyDeploySponsoredFPC(); + ({ userWallet, adminAddress } = t); }); afterAll(async () => { diff --git a/yarn-project/end-to-end/src/bench/client_flows/client_flows_benchmark.ts b/yarn-project/end-to-end/src/bench/client_flows/client_flows_benchmark.ts index eaf7e0a31345..d435ee9551be 100644 --- a/yarn-project/end-to-end/src/bench/client_flows/client_flows_benchmark.ts +++ b/yarn-project/end-to-end/src/bench/client_flows/client_flows_benchmark.ts @@ -29,12 +29,7 @@ import { deriveSigningKey } from '@aztec/stdlib/keys'; import { TestWallet } from '@aztec/test-wallet/server'; import { MNEMONIC } from '../../fixtures/fixtures.js'; -import { - type ISnapshotManager, - type SubsystemsContext, - createSnapshotManager, - deployAccounts, -} from '../../fixtures/snapshot_manager.js'; +import { type SubsystemsContext, deployAccounts, setupFromFresh, teardown } from '../../fixtures/snapshot_manager.js'; import { mintTokensToPrivate } from '../../fixtures/token_utils.js'; import { type SetupOptions, setupSponsoredFPC } from '../../fixtures/utils.js'; import { CrossChainTestHarness } from '../../shared/cross_chain_test_harness.js'; @@ -45,15 +40,13 @@ import { import { ProxyLogger } from './benchmark.js'; import { type ClientFlowsConfig, FULL_FLOWS_CONFIG, KEY_FLOWS_CONFIG } from './config.js'; -const { E2E_DATA_PATH: dataPath, BENCHMARK_CONFIG } = process.env; +const { BENCHMARK_CONFIG } = process.env; export type AccountType = 'ecdsar1' | 'schnorr'; export type FeePaymentMethodGetter = (wallet: Wallet, sender: AztecAddress) => Promise; export type BenchmarkingFeePaymentMethod = 'bridged_fee_juice' | 'private_fpc' | 'sponsored_fpc' | 'fee_juice'; export class ClientFlowsBenchmark { - private snapshotManager: ISnapshotManager; - public logger: Logger; public aztecNode!: AztecNode; public cheatCodes!: CheatCodes; @@ -125,33 +118,32 @@ export class ClientFlowsBenchmark { public config: ClientFlowsConfig; private proxyLogger: ProxyLogger; + private setupOptions: Partial; constructor(testName?: string, setupOptions: Partial = {}) { this.logger = createLogger(`bench:client_flows${testName ? `:${testName}` : ''}`); - this.snapshotManager = createSnapshotManager( - `bench_client_flows${testName ? `/${testName}` : ''}`, - dataPath, - { startProverNode: true, ...setupOptions }, - { ...setupOptions }, - ); + this.setupOptions = { startProverNode: true, ...setupOptions }; this.config = BENCHMARK_CONFIG === 'key_flows' ? KEY_FLOWS_CONFIG : FULL_FLOWS_CONFIG; ProxyLogger.create(); this.proxyLogger = ProxyLogger.getInstance(); } async setup() { - const context = await this.snapshotManager.setup(); - await context.aztecNode.setConfig({ feeRecipient: this.sequencerAddress, coinbase: this.coinbase }); + this.logger.info('Setting up subsystems from fresh'); + this.context = await setupFromFresh(this.logger, this.setupOptions, this.setupOptions); + await this.applyBaseSetup(); - const rollupContract = RollupContract.getFromConfig(context.aztecNodeConfig); - this.chainMonitor = new ChainMonitor(rollupContract, context.dateProvider, this.logger, 200).start(); + await this.context.aztecNode.setConfig({ feeRecipient: this.sequencerAddress, coinbase: this.coinbase }); + + const rollupContract = RollupContract.getFromConfig(this.context.aztecNodeConfig); + this.chainMonitor = new ChainMonitor(rollupContract, this.context.dateProvider, this.logger, 200).start(); return this; } async teardown() { await this.chainMonitor.stop(); - await this.snapshotManager.teardown(); + await teardown(this.context); } async mintAndBridgeFeeJuice(address: AztecAddress) { @@ -193,157 +185,120 @@ export class ClientFlowsBenchmark { } } - public async applyBaseSnapshots() { - await this.applyInitialAccountsSnapshot(); - await this.applySetupFeeJuiceSnapshot(); + public async applyBaseSetup() { + await this.applyInitialAccounts(); + await this.applySetupFeeJuice(); } - async applyInitialAccountsSnapshot() { - await this.snapshotManager.snapshot( - 'initial_accounts', - deployAccounts(2, this.logger), - async ( - { deployedAccounts: [{ address: adminAddress }, { address: sequencerAddress }] }, - { wallet, aztecNode, cheatCodes }, - ) => { - this.adminWallet = wallet; - this.aztecNode = aztecNode; - this.cheatCodes = cheatCodes; - - this.adminAddress = adminAddress; - this.sequencerAddress = sequencerAddress; - - const canonicalFeeJuice = await getCanonicalFeeJuice(); - this.feeJuiceContract = FeeJuiceContract.at(canonicalFeeJuice.address, this.adminWallet); - this.coinbase = EthAddress.random(); - - const userPXEConfig = getPXEConfig(); - const userPXEConfigWithContracts = { - ...userPXEConfig, - proverEnabled: this.realProofs, - } as PXEConfig; - - this.userWallet = await TestWallet.create(this.aztecNode, userPXEConfigWithContracts, { - loggers: { - prover: this.proxyLogger.createLogger('pxe:bb:wasm:bundle:proxied'), - }, - }); + async applyInitialAccounts() { + this.logger.info('Applying initial accounts setup'); + const { deployedAccounts } = await deployAccounts( + 2, + this.logger, + )({ + wallet: this.context.wallet, + initialFundedAccounts: this.context.initialFundedAccounts, + }); + + const [{ address: adminAddress }, { address: sequencerAddress }] = deployedAccounts; + + this.adminWallet = this.context.wallet; + this.aztecNode = this.context.aztecNode; + this.cheatCodes = this.context.cheatCodes; + + this.adminAddress = adminAddress; + this.sequencerAddress = sequencerAddress; + + const canonicalFeeJuice = await getCanonicalFeeJuice(); + this.feeJuiceContract = FeeJuiceContract.at(canonicalFeeJuice.address, this.adminWallet); + this.coinbase = EthAddress.random(); + + const userPXEConfig = getPXEConfig(); + const userPXEConfigWithContracts = { + ...userPXEConfig, + proverEnabled: this.realProofs, + } as PXEConfig; + + this.userWallet = await TestWallet.create(this.aztecNode, userPXEConfigWithContracts, { + loggers: { + prover: this.proxyLogger.createLogger('pxe:bb:wasm:bundle:proxied'), }, - ); + }); } - async applySetupFeeJuiceSnapshot() { - await this.snapshotManager.snapshot( - 'setup_fee_juice', - async () => {}, - async (_data, context) => { - this.context = context; - - this.feeJuiceContract = FeeJuiceContract.at(ProtocolContractAddress.FeeJuice, this.adminWallet); - - this.feeJuiceBridgeTestHarness = await FeeJuicePortalTestingHarnessFactory.create({ - aztecNode: context.aztecNode, - aztecNodeAdmin: context.aztecNode, - l1Client: context.deployL1ContractsValues.l1Client, - wallet: this.adminWallet, - logger: this.logger, - }); - }, - ); + async applySetupFeeJuice() { + this.logger.info('Applying fee juice setup'); + this.feeJuiceContract = FeeJuiceContract.at(ProtocolContractAddress.FeeJuice, this.adminWallet); + + this.feeJuiceBridgeTestHarness = await FeeJuicePortalTestingHarnessFactory.create({ + aztecNode: this.context.aztecNode, + aztecNodeAdmin: this.context.aztecNode, + l1Client: this.context.deployL1ContractsValues.l1Client, + wallet: this.adminWallet, + logger: this.logger, + }); } - async applyDeployBananaTokenSnapshot() { - await this.snapshotManager.snapshot( - 'deploy_banana_token', - async () => { - const { contract: bananaCoin, instance: bananaCoinInstance } = await BananaCoin.deploy( - this.adminWallet, - this.adminAddress, - 'BC', - 'BC', - 18n, - ) - .send({ from: this.adminAddress }) - .wait(); - this.logger.info(`BananaCoin deployed at ${bananaCoin.address}`); - return { bananaCoinAddress: bananaCoin.address, bananaCoinInstance }; - }, - ({ bananaCoinAddress, bananaCoinInstance }) => { - this.bananaCoin = BananaCoin.at(bananaCoinAddress, this.adminWallet); - this.bananaCoinInstance = bananaCoinInstance; - return Promise.resolve(); - }, - ); + async applyDeployBananaToken() { + this.logger.info('Applying banana token deployment'); + const { contract: bananaCoin, instance: bananaCoinInstance } = await BananaCoin.deploy( + this.adminWallet, + this.adminAddress, + 'BC', + 'BC', + 18n, + ) + .send({ from: this.adminAddress }) + .wait(); + this.logger.info(`BananaCoin deployed at ${bananaCoin.address}`); + this.bananaCoin = bananaCoin; + this.bananaCoinInstance = bananaCoinInstance; } - async applyDeployCandyBarTokenSnapshot() { - await this.snapshotManager.snapshot( - 'deploy_candy_bar_token', - async () => { - const { contract: candyBarCoin, instance: candyBarCoinInstance } = await TokenContract.deploy( - this.adminWallet, - this.adminAddress, - 'CBC', - 'CBC', - 18n, - ) - .send({ from: this.adminAddress }) - .wait(); - this.logger.info(`CandyBarCoin deployed at ${candyBarCoin.address}`); - return { candyBarCoinAddress: candyBarCoin.address, candyBarCoinInstance }; - }, - ({ candyBarCoinAddress, candyBarCoinInstance }) => { - this.candyBarCoin = TokenContract.at(candyBarCoinAddress, this.adminWallet); - this.candyBarCoinInstance = candyBarCoinInstance; - return Promise.resolve(); - }, - ); + async applyDeployCandyBarToken() { + this.logger.info('Applying candy bar token deployment'); + const { contract: candyBarCoin, instance: candyBarCoinInstance } = await TokenContract.deploy( + this.adminWallet, + this.adminAddress, + 'CBC', + 'CBC', + 18n, + ) + .send({ from: this.adminAddress }) + .wait(); + this.logger.info(`CandyBarCoin deployed at ${candyBarCoin.address}`); + this.candyBarCoin = candyBarCoin; + this.candyBarCoinInstance = candyBarCoinInstance; } - public async applyFPCSetupSnapshot() { - await this.snapshotManager.snapshot( - 'fpc_setup', - async context => { - const feeJuiceContract = this.feeJuiceBridgeTestHarness.feeJuice; - expect((await context.wallet.getContractMetadata(feeJuiceContract.address)).isContractPublished).toBe(true); + public async applyFPCSetup() { + this.logger.info('Applying FPC setup'); + const feeJuiceContract = this.feeJuiceBridgeTestHarness.feeJuice; + expect((await this.context.wallet.getContractMetadata(feeJuiceContract.address)).isContractPublished).toBe(true); - const bananaCoin = this.bananaCoin; - const { contract: bananaFPC, instance: bananaFPCInstance } = await FPCContract.deploy( - this.adminWallet, - bananaCoin.address, - this.adminAddress, - ) - .send({ from: this.adminAddress }) - .wait(); + const bananaCoin = this.bananaCoin; + const { contract: bananaFPC, instance: bananaFPCInstance } = await FPCContract.deploy( + this.adminWallet, + bananaCoin.address, + this.adminAddress, + ) + .send({ from: this.adminAddress }) + .wait(); - this.logger.info(`BananaPay deployed at ${bananaFPC.address}`); + this.logger.info(`BananaPay deployed at ${bananaFPC.address}`); - await this.feeJuiceBridgeTestHarness.bridgeFromL1ToL2(bananaFPC.address, this.adminAddress); + await this.feeJuiceBridgeTestHarness.bridgeFromL1ToL2(bananaFPC.address, this.adminAddress); - return { bananaFPCAddress: bananaFPC.address, bananaFPCInstance }; - }, - data => { - this.bananaFPC = FPCContract.at(data.bananaFPCAddress, this.adminWallet); - this.bananaFPCInstance = data.bananaFPCInstance; - return Promise.resolve(); - }, - ); + this.bananaFPC = bananaFPC; + this.bananaFPCInstance = bananaFPCInstance; } - async applyDeploySponsoredFPCSnapshot() { - await this.snapshotManager.snapshot( - 'deploy_sponsored_fpc', - async () => { - const sponsoredFPCInstance = await setupSponsoredFPC(this.adminWallet); - this.logger.info(`SponsoredFPC at ${sponsoredFPCInstance.address}`); - return { sponsoredFPCAddress: sponsoredFPCInstance.address, sponsoredFPCInstance }; - }, - ({ sponsoredFPCAddress, sponsoredFPCInstance }) => { - this.sponsoredFPC = SponsoredFPCContract.at(sponsoredFPCAddress, this.adminWallet); - this.sponsoredFPCInstance = sponsoredFPCInstance; - return Promise.resolve(); - }, - ); + async applyDeploySponsoredFPC() { + this.logger.info('Applying sponsored FPC deployment'); + const sponsoredFPCInstance = await setupSponsoredFPC(this.adminWallet); + this.logger.info(`SponsoredFPC at ${sponsoredFPCInstance.address}`); + this.sponsoredFPC = SponsoredFPCContract.at(sponsoredFPCInstance.address, this.adminWallet); + this.sponsoredFPCInstance = sponsoredFPCInstance; } public async createCrossChainTestHarness(owner: AztecAddress) { @@ -391,44 +346,31 @@ export class ClientFlowsBenchmark { return accountManager.address; } - public async applyDeployAmmSnapshot() { - await this.snapshotManager.snapshot( - 'deploy_amm', - async () => { - const { contract: liquidityToken, instance: liquidityTokenInstance } = await TokenContract.deploy( - this.adminWallet, - this.adminAddress, - 'LPT', - 'LPT', - 18n, - ) - .send({ from: this.adminAddress }) - .wait(); - const { contract: amm, instance: ammInstance } = await AMMContract.deploy( - this.adminWallet, - this.bananaCoin.address, - this.candyBarCoin.address, - liquidityToken.address, - ) - .send({ from: this.adminAddress }) - .wait(); - this.logger.info(`AMM deployed at ${amm.address}`); - await liquidityToken.methods.set_minter(amm.address, true).send({ from: this.adminAddress }).wait(); - return { - ammAddress: amm.address, - ammInstance, - liquidityTokenAddress: liquidityToken.address, - liquidityTokenInstance, - }; - }, - ({ ammAddress, ammInstance, liquidityTokenAddress, liquidityTokenInstance }) => { - this.liquidityToken = TokenContract.at(liquidityTokenAddress, this.adminWallet); - this.liquidityTokenInstance = liquidityTokenInstance; - this.amm = AMMContract.at(ammAddress, this.adminWallet); - this.ammInstance = ammInstance; - return Promise.resolve(); - }, - ); + public async applyDeployAmm() { + this.logger.info('Applying AMM deployment'); + const { contract: liquidityToken, instance: liquidityTokenInstance } = await TokenContract.deploy( + this.adminWallet, + this.adminAddress, + 'LPT', + 'LPT', + 18n, + ) + .send({ from: this.adminAddress }) + .wait(); + const { contract: amm, instance: ammInstance } = await AMMContract.deploy( + this.adminWallet, + this.bananaCoin.address, + this.candyBarCoin.address, + liquidityToken.address, + ) + .send({ from: this.adminAddress }) + .wait(); + this.logger.info(`AMM deployed at ${amm.address}`); + await liquidityToken.methods.set_minter(amm.address, true).send({ from: this.adminAddress }).wait(); + this.liquidityToken = liquidityToken; + this.liquidityTokenInstance = liquidityTokenInstance; + this.amm = amm; + this.ammInstance = ammInstance; } public async getBridgedFeeJuicePaymentMethodForWallet(_wallet: Wallet, sender: AztecAddress) { diff --git a/yarn-project/end-to-end/src/bench/client_flows/deployments.test.ts b/yarn-project/end-to-end/src/bench/client_flows/deployments.test.ts index 8f6c58d26439..1e9673b2d795 100644 --- a/yarn-project/end-to-end/src/bench/client_flows/deployments.test.ts +++ b/yarn-project/end-to-end/src/bench/client_flows/deployments.test.ts @@ -25,10 +25,10 @@ describe('Deployment benchmark', () => { const config = t.config.deployments; beforeAll(async () => { - await t.applyBaseSnapshots(); - await t.applyDeploySponsoredFPCSnapshot(); + await t.setup(); + await t.applyDeploySponsoredFPC(); - ({ aztecNode: node, userWallet, sponsoredFPCInstance } = await t.setup()); + ({ aztecNode: node, userWallet, sponsoredFPCInstance } = t); }); afterAll(async () => { diff --git a/yarn-project/end-to-end/src/bench/client_flows/transfers.test.ts b/yarn-project/end-to-end/src/bench/client_flows/transfers.test.ts index feee29892f85..b720455fd6d2 100644 --- a/yarn-project/end-to-end/src/bench/client_flows/transfers.test.ts +++ b/yarn-project/end-to-end/src/bench/client_flows/transfers.test.ts @@ -43,11 +43,11 @@ describe('Transfer benchmark', () => { const config = t.config.transfers; beforeAll(async () => { - await t.applyBaseSnapshots(); - await t.applyDeployBananaTokenSnapshot(); - await t.applyFPCSetupSnapshot(); - await t.applyDeployCandyBarTokenSnapshot(); - await t.applyDeploySponsoredFPCSnapshot(); + await t.setup(); + await t.applyDeployBananaToken(); + await t.applyFPCSetup(); + await t.applyDeployCandyBarToken(); + await t.applyDeploySponsoredFPC(); ({ adminWallet, @@ -59,7 +59,7 @@ describe('Transfer benchmark', () => { candyBarCoin, candyBarCoinInstance, sponsoredFPCInstance, - } = await t.setup()); + } = t); }); afterAll(async () => { diff --git a/yarn-project/end-to-end/src/bench/tx_stats_bench.test.ts b/yarn-project/end-to-end/src/bench/tx_stats_bench.test.ts index e3cdccf9b8f3..50a9e54be9ac 100644 --- a/yarn-project/end-to-end/src/bench/tx_stats_bench.test.ts +++ b/yarn-project/end-to-end/src/bench/tx_stats_bench.test.ts @@ -54,8 +54,6 @@ describe('transaction benchmarks', () => { beforeAll(async () => { t.logger.warn(`Running suite with ${REAL_PROOFS ? 'real' : 'fake'} proofs`); - await t.applyBaseSnapshots(); - await t.applyMintSnapshot(); await t.setup(); ({ diff --git a/yarn-project/end-to-end/src/e2e_blacklist_token_contract/access_control.test.ts b/yarn-project/end-to-end/src/e2e_blacklist_token_contract/access_control.test.ts index a6e58ab55c98..74bae3e0400d 100644 --- a/yarn-project/end-to-end/src/e2e_blacklist_token_contract/access_control.test.ts +++ b/yarn-project/end-to-end/src/e2e_blacklist_token_contract/access_control.test.ts @@ -6,7 +6,6 @@ describe('e2e_blacklist_token_contract access control', () => { const t = new BlacklistTokenContractTest('access_control'); beforeAll(async () => { - await t.applyBaseSnapshots(); await t.setup(); }); diff --git a/yarn-project/end-to-end/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts b/yarn-project/end-to-end/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts index 537d04aa1ad0..d8118644f48e 100644 --- a/yarn-project/end-to-end/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +++ b/yarn-project/end-to-end/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts @@ -14,16 +14,14 @@ import type { TestWallet } from '@aztec/test-wallet/server'; import { jest } from '@jest/globals'; import { - type ISnapshotManager, type SubsystemsContext, - createSnapshotManager, deployAccounts, publicDeployAccounts, + setupFromFresh, + teardown, } from '../fixtures/snapshot_manager.js'; import { TokenSimulator } from '../simulators/token_simulator.js'; -const { E2E_DATA_PATH: dataPath } = process.env; - export class Role { private isAdmin = false; private isMinter = false; @@ -55,7 +53,7 @@ export class BlacklistTokenContractTest { // This value MUST match the same value that we have in the contract static CHANGE_ROLES_DELAY = 86400; - private snapshotManager: ISnapshotManager; + context!: SubsystemsContext; logger: Logger; wallet!: TestWallet; asset!: TokenBlacklistContract; @@ -71,7 +69,6 @@ export class BlacklistTokenContractTest { constructor(testName: string) { this.logger = createLogger(`e2e:e2e_blacklist_token_contract:${testName}`); - this.snapshotManager = createSnapshotManager(`e2e_blacklist_token_contract/${testName}`, dataPath); } async crossTimestampOfChange() { @@ -83,86 +80,69 @@ export class BlacklistTokenContractTest { } /** - * Adds two state shifts to snapshot manager. + * Applies base setup: * 1. Add 3 accounts. * 2. Publicly deploy accounts, deploy token contract and a "bad account". */ - async applyBaseSnapshots() { + async applyBaseSetup() { // Adding a timeout of 2 minutes in here such that it is propagated to the underlying tests jest.setTimeout(120_000); - await this.snapshotManager.snapshot( - '3_accounts', - deployAccounts(3, this.logger), - ({ deployedAccounts }, { cheatCodes, aztecNode, sequencer, wallet }) => { - this.cheatCodes = cheatCodes; - this.aztecNode = aztecNode; - this.sequencer = sequencer; - this.wallet = wallet; - this.adminAddress = deployedAccounts[0].address; - this.otherAddress = deployedAccounts[1].address; - this.blacklistedAddress = deployedAccounts[2].address; - return Promise.resolve(); - }, + this.logger.info('Deploying 3 accounts'); + const { deployedAccounts } = await deployAccounts( + 3, + this.logger, + )({ + wallet: this.context.wallet, + initialFundedAccounts: this.context.initialFundedAccounts, + }); + + this.cheatCodes = this.context.cheatCodes; + this.aztecNode = this.context.aztecNode; + this.sequencer = this.context.sequencer; + this.wallet = this.context.wallet; + this.adminAddress = deployedAccounts[0].address; + this.otherAddress = deployedAccounts[1].address; + this.blacklistedAddress = deployedAccounts[2].address; + + this.logger.info('Setting up blacklist token contract'); + // Create the token contract state. + this.logger.verbose(`Public deploy accounts...`); + await publicDeployAccounts(this.wallet, [this.adminAddress, this.otherAddress, this.blacklistedAddress]); + + this.logger.verbose(`Deploying TokenContract...`); + this.asset = await TokenBlacklistContract.deploy(this.wallet, this.adminAddress) + .send({ from: this.adminAddress }) + .deployed(); + this.logger.verbose(`Token deployed to ${this.asset.address}`); + + this.logger.verbose(`Deploying bad account...`); + this.badAccount = await InvalidAccountContract.deploy(this.wallet).send({ from: this.adminAddress }).deployed(); + this.logger.verbose(`Deployed to ${this.badAccount.address}.`); + + await this.crossTimestampOfChange(); + + this.tokenSim = new TokenSimulator( + this.asset as unknown as TokenContract, + this.wallet, + this.adminAddress, + this.logger, + [this.adminAddress, this.otherAddress, this.blacklistedAddress], ); - await this.snapshotManager.snapshot( - 'e2e_blacklist_token_contract', - async () => { - // Create the token contract state. - // Move this account thing to addAccounts above? - this.logger.verbose(`Public deploy accounts...`); - await publicDeployAccounts(this.wallet, [this.adminAddress, this.otherAddress, this.blacklistedAddress]); - - this.logger.verbose(`Deploying TokenContract...`); - this.asset = await TokenBlacklistContract.deploy(this.wallet, this.adminAddress) - .send({ from: this.adminAddress }) - .deployed(); - this.logger.verbose(`Token deployed to ${this.asset.address}`); - - this.logger.verbose(`Deploying bad account...`); - this.badAccount = await InvalidAccountContract.deploy(this.wallet).send({ from: this.adminAddress }).deployed(); - this.logger.verbose(`Deployed to ${this.badAccount.address}.`); - - await this.crossTimestampOfChange(); - - return { tokenContractAddress: this.asset.address, badAccountAddress: this.badAccount.address }; - }, - async ({ tokenContractAddress, badAccountAddress }) => { - // Restore the token contract state. - this.asset = TokenBlacklistContract.at(tokenContractAddress, this.wallet); - this.logger.verbose(`Token contract address: ${this.asset.address}`); - - this.tokenSim = new TokenSimulator( - this.asset as unknown as TokenContract, - this.wallet, - this.adminAddress, - this.logger, - [this.adminAddress, this.otherAddress, this.blacklistedAddress], - ); - - this.badAccount = InvalidAccountContract.at(badAccountAddress, this.wallet); - this.logger.verbose(`Bad account address: ${this.badAccount.address}`); - - expect(await this.asset.methods.get_roles(this.adminAddress).simulate({ from: this.adminAddress })).toEqual( - new Role().withAdmin().toNoirStruct(), - ); - }, + expect(await this.asset.methods.get_roles(this.adminAddress).simulate({ from: this.adminAddress })).toEqual( + new Role().withAdmin().toNoirStruct(), ); } async setup() { - await this.snapshotManager.setup(); + this.logger.info('Setting up fresh context'); + this.context = await setupFromFresh(this.logger); + await this.applyBaseSetup(); } - snapshot = ( - name: string, - apply: (context: SubsystemsContext) => Promise, - restore: (snapshotData: T, context: SubsystemsContext) => Promise = () => Promise.resolve(), - ): Promise => this.snapshotManager.snapshot(name, apply, restore); - async teardown() { - await this.snapshotManager.teardown(); + await teardown(this.context); } async addPendingShieldNoteToPXE( @@ -186,71 +166,59 @@ export class BlacklistTokenContractTest { .simulate({ from: recipient }); } - async applyMintSnapshot() { - await this.snapshotManager.snapshot( - 'mint', - async () => { - const { asset } = this; - const amount = 10000n; - - const adminMinterRole = new Role().withAdmin().withMinter(); - await this.asset.methods - .update_roles(this.adminAddress, adminMinterRole.toNoirStruct()) - .send({ from: this.adminAddress }) - .wait(); - - const blacklistRole = new Role().withBlacklisted(); - await this.asset.methods - .update_roles(this.blacklistedAddress, blacklistRole.toNoirStruct()) - .send({ from: this.adminAddress }) - .wait(); - - await this.crossTimestampOfChange(); - - expect(await this.asset.methods.get_roles(this.adminAddress).simulate({ from: this.adminAddress })).toEqual( - adminMinterRole.toNoirStruct(), - ); - - this.logger.verbose(`Minting ${amount} publicly...`); - await asset.methods.mint_public(this.adminAddress, amount).send({ from: this.adminAddress }).wait(); - - this.logger.verbose(`Minting ${amount} privately...`); - const secret = Fr.random(); - const secretHash = await computeSecretHash(secret); - const receipt = await asset.methods.mint_private(amount, secretHash).send({ from: this.adminAddress }).wait(); - - await this.addPendingShieldNoteToPXE(asset, this.adminAddress, amount, secretHash, receipt.txHash); - const txClaim = asset.methods - .redeem_shield(this.adminAddress, amount, secret) - .send({ from: this.adminAddress }); - await txClaim.wait(); - this.logger.verbose(`Minting complete.`); - - return { amount }; - }, - async ({ amount }) => { - const { asset, tokenSim } = this; - tokenSim.mintPublic(this.adminAddress, amount); - - const publicBalance = await asset.methods - .balance_of_public(this.adminAddress) - .simulate({ from: this.adminAddress }); - this.logger.verbose(`Public balance of wallet 0: ${publicBalance}`); - expect(publicBalance).toEqual(this.tokenSim.balanceOfPublic(this.adminAddress)); - - tokenSim.mintPrivate(this.adminAddress, amount); - const privateBalance = await asset.methods - .balance_of_private(this.adminAddress) - .simulate({ from: this.adminAddress }); - this.logger.verbose(`Private balance of wallet 0: ${privateBalance}`); - expect(privateBalance).toEqual(tokenSim.balanceOfPrivate(this.adminAddress)); - - const totalSupply = await asset.methods.total_supply().simulate({ from: this.adminAddress }); - this.logger.verbose(`Total supply: ${totalSupply}`); - expect(totalSupply).toEqual(tokenSim.totalSupply); - - return Promise.resolve(); - }, + async applyMint() { + this.logger.info('Applying mint setup'); + const { asset, tokenSim } = this; + const amount = 10000n; + + const adminMinterRole = new Role().withAdmin().withMinter(); + await this.asset.methods + .update_roles(this.adminAddress, adminMinterRole.toNoirStruct()) + .send({ from: this.adminAddress }) + .wait(); + + const blacklistRole = new Role().withBlacklisted(); + await this.asset.methods + .update_roles(this.blacklistedAddress, blacklistRole.toNoirStruct()) + .send({ from: this.adminAddress }) + .wait(); + + await this.crossTimestampOfChange(); + + expect(await this.asset.methods.get_roles(this.adminAddress).simulate({ from: this.adminAddress })).toEqual( + adminMinterRole.toNoirStruct(), ); + + this.logger.verbose(`Minting ${amount} publicly...`); + await asset.methods.mint_public(this.adminAddress, amount).send({ from: this.adminAddress }).wait(); + + this.logger.verbose(`Minting ${amount} privately...`); + const secret = Fr.random(); + const secretHash = await computeSecretHash(secret); + const receipt = await asset.methods.mint_private(amount, secretHash).send({ from: this.adminAddress }).wait(); + + await this.addPendingShieldNoteToPXE(asset, this.adminAddress, amount, secretHash, receipt.txHash); + const txClaim = asset.methods.redeem_shield(this.adminAddress, amount, secret).send({ from: this.adminAddress }); + await txClaim.wait(); + this.logger.verbose(`Minting complete.`); + + tokenSim.mintPublic(this.adminAddress, amount); + + const publicBalance = await asset.methods + .balance_of_public(this.adminAddress) + .simulate({ from: this.adminAddress }); + this.logger.verbose(`Public balance of wallet 0: ${publicBalance}`); + expect(publicBalance).toEqual(this.tokenSim.balanceOfPublic(this.adminAddress)); + + tokenSim.mintPrivate(this.adminAddress, amount); + const privateBalance = await asset.methods + .balance_of_private(this.adminAddress) + .simulate({ from: this.adminAddress }); + this.logger.verbose(`Private balance of wallet 0: ${privateBalance}`); + expect(privateBalance).toEqual(tokenSim.balanceOfPrivate(this.adminAddress)); + + const totalSupply = await asset.methods.total_supply().simulate({ from: this.adminAddress }); + this.logger.verbose(`Total supply: ${totalSupply}`); + expect(totalSupply).toEqual(tokenSim.totalSupply); } } diff --git a/yarn-project/end-to-end/src/e2e_blacklist_token_contract/burn.test.ts b/yarn-project/end-to-end/src/e2e_blacklist_token_contract/burn.test.ts index b37e45c9c951..3e011ae34315 100644 --- a/yarn-project/end-to-end/src/e2e_blacklist_token_contract/burn.test.ts +++ b/yarn-project/end-to-end/src/e2e_blacklist_token_contract/burn.test.ts @@ -9,10 +9,9 @@ describe('e2e_blacklist_token_contract burn', () => { let { asset, tokenSim, wallet, adminAddress, otherAddress, blacklistedAddress } = t; beforeAll(async () => { - await t.applyBaseSnapshots(); - // Beware that we are adding the wallet as minter here, which is very slow because it needs multiple blocks. - await t.applyMintSnapshot(); await t.setup(); + // Beware that we are adding the wallet as minter here, which is very slow because it needs multiple blocks. + await t.applyMint(); // Have to destructure again to ensure we have latest refs. ({ asset, tokenSim, wallet, adminAddress, otherAddress, blacklistedAddress } = t); }, 600_000); diff --git a/yarn-project/end-to-end/src/e2e_blacklist_token_contract/minting.test.ts b/yarn-project/end-to-end/src/e2e_blacklist_token_contract/minting.test.ts index b1ab9f91e6f0..83edba59a3c3 100644 --- a/yarn-project/end-to-end/src/e2e_blacklist_token_contract/minting.test.ts +++ b/yarn-project/end-to-end/src/e2e_blacklist_token_contract/minting.test.ts @@ -10,10 +10,9 @@ describe('e2e_blacklist_token_contract mint', () => { let { asset, tokenSim, adminAddress, otherAddress, blacklistedAddress } = t; beforeAll(async () => { - await t.applyBaseSnapshots(); - // Beware that we are adding the admin as minter here, which is very slow because it needs multiple blocks. - await t.applyMintSnapshot(); await t.setup(); + // Beware that we are adding the admin as minter here, which is very slow because it needs multiple blocks. + await t.applyMint(); // Have to destructure again to ensure we have latest refs. ({ asset, tokenSim, adminAddress, otherAddress, blacklistedAddress } = t); }, 600_000); diff --git a/yarn-project/end-to-end/src/e2e_blacklist_token_contract/shielding.test.ts b/yarn-project/end-to-end/src/e2e_blacklist_token_contract/shielding.test.ts index 5d06522ebc9b..f02c2fbde7b5 100644 --- a/yarn-project/end-to-end/src/e2e_blacklist_token_contract/shielding.test.ts +++ b/yarn-project/end-to-end/src/e2e_blacklist_token_contract/shielding.test.ts @@ -9,9 +9,8 @@ describe('e2e_blacklist_token_contract shield + redeem_shield', () => { let { asset, tokenSim, wallet, adminAddress, otherAddress, blacklistedAddress } = t; beforeAll(async () => { - await t.applyBaseSnapshots(); - await t.applyMintSnapshot(); // Beware that we are adding the admin as minter here await t.setup(); + await t.applyMint(); // Beware that we are adding the admin as minter here // Have to destructure again to ensure we have latest refs. ({ asset, tokenSim, wallet, adminAddress, otherAddress, blacklistedAddress } = t); }, 600_000); diff --git a/yarn-project/end-to-end/src/e2e_blacklist_token_contract/transfer_private.test.ts b/yarn-project/end-to-end/src/e2e_blacklist_token_contract/transfer_private.test.ts index 7970e60ad096..a78c9f4caeb3 100644 --- a/yarn-project/end-to-end/src/e2e_blacklist_token_contract/transfer_private.test.ts +++ b/yarn-project/end-to-end/src/e2e_blacklist_token_contract/transfer_private.test.ts @@ -9,10 +9,9 @@ describe('e2e_blacklist_token_contract transfer private', () => { let { asset, tokenSim, wallet, adminAddress, otherAddress, blacklistedAddress } = t; beforeAll(async () => { - await t.applyBaseSnapshots(); - // Beware that we are adding the admin as minter here, which is very slow because it needs multiple blocks. - await t.applyMintSnapshot(); await t.setup(); + // Beware that we are adding the admin as minter here, which is very slow because it needs multiple blocks. + await t.applyMint(); // Have to destructure again to ensure we have latest refs. ({ asset, tokenSim, wallet, adminAddress, otherAddress, blacklistedAddress } = t); }, 600_000); diff --git a/yarn-project/end-to-end/src/e2e_blacklist_token_contract/transfer_public.test.ts b/yarn-project/end-to-end/src/e2e_blacklist_token_contract/transfer_public.test.ts index 98ff87f54b58..b9b9913ee5d1 100644 --- a/yarn-project/end-to-end/src/e2e_blacklist_token_contract/transfer_public.test.ts +++ b/yarn-project/end-to-end/src/e2e_blacklist_token_contract/transfer_public.test.ts @@ -8,10 +8,9 @@ describe('e2e_blacklist_token_contract transfer public', () => { let { asset, tokenSim, wallet, adminAddress, otherAddress, blacklistedAddress } = t; beforeAll(async () => { - await t.applyBaseSnapshots(); - // Beware that we are adding the admin as minter here, which is very slow because it needs multiple blocks. - await t.applyMintSnapshot(); await t.setup(); + // Beware that we are adding the admin as minter here, which is very slow because it needs multiple blocks. + await t.applyMint(); // Have to destructure again to ensure we have latest refs. ({ asset, tokenSim, wallet, adminAddress, otherAddress, blacklistedAddress } = t); }, 600_000); diff --git a/yarn-project/end-to-end/src/e2e_blacklist_token_contract/unshielding.test.ts b/yarn-project/end-to-end/src/e2e_blacklist_token_contract/unshielding.test.ts index 534bf03ed6a5..9c081b443610 100644 --- a/yarn-project/end-to-end/src/e2e_blacklist_token_contract/unshielding.test.ts +++ b/yarn-project/end-to-end/src/e2e_blacklist_token_contract/unshielding.test.ts @@ -9,10 +9,9 @@ describe('e2e_blacklist_token_contract unshielding', () => { let { asset, tokenSim, wallet, adminAddress, otherAddress, blacklistedAddress } = t; beforeAll(async () => { - await t.applyBaseSnapshots(); - // Beware that we are adding the admin as minter here, which is very slow because it needs multiple blocks. - await t.applyMintSnapshot(); await t.setup(); + // Beware that we are adding the admin as minter here, which is very slow because it needs multiple blocks. + await t.applyMint(); // Have to destructure again to ensure we have latest refs. ({ asset, tokenSim, wallet, adminAddress, otherAddress, blacklistedAddress } = t); }, 600_000); diff --git a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts index a186e8f1ed90..983589ea8ee0 100644 --- a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +++ b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts @@ -23,25 +23,24 @@ import type { TestWallet } from '@aztec/test-wallet/server'; import { MNEMONIC } from '../fixtures/fixtures.js'; import { - type ISnapshotManager, type SubsystemsContext, - createSnapshotManager, deployAccounts, publicDeployAccounts, + setupFromFresh, + teardown, } from '../fixtures/snapshot_manager.js'; import type { SetupOptions } from '../fixtures/utils.js'; import { CrossChainTestHarness } from '../shared/cross_chain_test_harness.js'; -const { E2E_DATA_PATH: dataPath } = process.env; - export class CrossChainMessagingTest { - private snapshotManager: ISnapshotManager; private requireEpochProven: boolean; + private setupOptions: SetupOptions; + private deployL1ContractsArgs: Partial; logger: Logger; + context!: SubsystemsContext; aztecNode!: AztecNode; aztecNodeConfig!: AztecNodeConfig; aztecNodeAdmin!: AztecNodeAdmin; - ctx!: SubsystemsContext; l1Client!: ExtendedViemWalletClient | undefined; @@ -67,26 +66,18 @@ export class CrossChainMessagingTest { deployL1ContractsArgs: Partial = {}, ) { this.logger = createLogger(`e2e:e2e_cross_chain_messaging:${testName}`); - this.snapshotManager = createSnapshotManager(`e2e_cross_chain_messaging/${testName}`, dataPath, opts, { + this.setupOptions = opts; + this.deployL1ContractsArgs = { initialValidators: [], ...deployL1ContractsArgs, - }); + }; this.requireEpochProven = opts.startProverNode ?? false; } async setup() { - this.ctx = await this.snapshotManager.setup(); - this.aztecNode = this.ctx.aztecNode; - this.wallet = this.ctx.wallet; - this.aztecNodeConfig = this.ctx.aztecNodeConfig; - this.cheatCodes = this.ctx.cheatCodes; - this.deployL1ContractsValues = this.ctx.deployL1ContractsValues; - this.aztecNodeAdmin = this.ctx.aztecNode; - - if (this.requireEpochProven) { - // Turn off the watcher to prevent it from keep marking blocks as proven. - this.ctx.watcher.setIsMarkingAsProven(false); - } + this.logger.info('Setting up cross chain messaging test'); + this.context = await setupFromFresh(this.logger, this.setupOptions, this.deployL1ContractsArgs); + await this.applyBaseSetup(); } async advanceToEpochProven(l2TxReceipt: TxReceipt): Promise { @@ -108,94 +99,91 @@ export class CrossChainMessagingTest { } } - snapshot = ( - name: string, - apply: (context: SubsystemsContext) => Promise, - restore: (snapshotData: T, context: SubsystemsContext) => Promise = () => Promise.resolve(), - ): Promise => this.snapshotManager.snapshot(name, apply, restore); - async teardown() { - await this.snapshotManager.teardown(); + await teardown(this.context); } - async applyBaseSnapshots() { - // Note that we are using the same `wallet`, `aztecNodeConfig` and `aztecNode` across all snapshots. - // This is to not have issues with different networks. - - await this.snapshotManager.snapshot( - '3_accounts', - deployAccounts(3, this.logger), - ({ deployedAccounts }, { wallet, aztecNodeConfig, aztecNode }) => { - [this.ownerAddress, this.user1Address, this.user2Address] = deployedAccounts.map(a => a.address); - this.wallet = wallet; - this.aztecNode = aztecNode; - this.aztecNodeConfig = aztecNodeConfig; - return Promise.resolve(); - }, + async applyBaseSetup() { + // Set up base context fields + this.aztecNode = this.context.aztecNode; + this.wallet = this.context.wallet; + this.aztecNodeConfig = this.context.aztecNodeConfig; + this.cheatCodes = this.context.cheatCodes; + this.deployL1ContractsValues = this.context.deployL1ContractsValues; + this.aztecNodeAdmin = this.context.aztecNode; + + if (this.requireEpochProven) { + // Turn off the watcher to prevent it from keep marking blocks as proven. + this.context.watcher.setIsMarkingAsProven(false); + } + + // Deploy 3 accounts + this.logger.info('Applying 3_accounts setup'); + const { deployedAccounts } = await deployAccounts( + 3, + this.logger, + )({ + wallet: this.context.wallet, + initialFundedAccounts: this.context.initialFundedAccounts, + }); + [this.ownerAddress, this.user1Address, this.user2Address] = deployedAccounts.map(a => a.address); + + // Set up cross chain messaging + this.logger.info('Applying e2e_cross_chain_messaging setup'); + + // Create the token contract state. + this.logger.verbose(`Public deploy accounts...`); + await publicDeployAccounts(this.wallet, [this.ownerAddress, this.user1Address, this.user2Address]); + + this.l1Client = createExtendedL1Client(this.aztecNodeConfig.l1RpcUrls, MNEMONIC); + + const underlyingERC20Address = await deployL1Contract(this.l1Client, TestERC20Abi, TestERC20Bytecode, [ + 'Underlying', + 'UND', + this.l1Client.account.address, + ]).then(({ address }) => address); + + this.logger.verbose(`Setting up cross chain harness...`); + this.crossChainTestHarness = await CrossChainTestHarness.new( + this.aztecNode, + this.l1Client, + this.wallet, + this.ownerAddress, + this.logger, + underlyingERC20Address, ); - await this.snapshotManager.snapshot( - 'e2e_cross_chain_messaging', - async () => { - // Create the token contract state. - // Move this account thing to addAccounts above? - this.logger.verbose(`Public deploy accounts...`); - await publicDeployAccounts(this.wallet, [this.ownerAddress, this.user1Address, this.user2Address]); - - this.l1Client = createExtendedL1Client(this.aztecNodeConfig.l1RpcUrls, MNEMONIC); - - const underlyingERC20Address = await deployL1Contract(this.l1Client, TestERC20Abi, TestERC20Bytecode, [ - 'Underlying', - 'UND', - this.l1Client.account.address, - ]).then(({ address }) => address); - - this.logger.verbose(`Setting up cross chain harness...`); - this.crossChainTestHarness = await CrossChainTestHarness.new( - this.aztecNode, - this.l1Client, - this.wallet, - this.ownerAddress, - this.logger, - underlyingERC20Address, - ); - - this.logger.verbose(`L2 token deployed to: ${this.crossChainTestHarness.l2Token.address}`); - - return this.crossChainTestHarness.toCrossChainContext(); - }, - crossChainContext => { - this.l2Token = TokenContract.at(crossChainContext.l2Token, this.wallet); - this.l2Bridge = TokenBridgeContract.at(crossChainContext.l2Bridge, this.wallet); - - // There is an issue with the reviver so we are getting strings sometimes. Working around it here. - this.ethAccount = EthAddress.fromString(crossChainContext.ethAccount.toString()); - const tokenPortalAddress = EthAddress.fromString(crossChainContext.tokenPortal.toString()); - - const l1Client = createExtendedL1Client(this.aztecNodeConfig.l1RpcUrls, MNEMONIC); - this.l1Client = l1Client; - - const l1Contracts = this.aztecNodeConfig.l1Contracts; - this.rollup = new RollupContract(l1Client, l1Contracts.rollupAddress.toString()); - this.inbox = new InboxContract(l1Client, l1Contracts.inboxAddress.toString()); - this.outbox = new OutboxContract(l1Client, l1Contracts.outboxAddress.toString()); - - this.crossChainTestHarness = new CrossChainTestHarness( - this.aztecNode, - this.logger, - this.l2Token, - this.l2Bridge, - this.ethAccount, - tokenPortalAddress, - crossChainContext.underlying, - l1Client, - this.aztecNodeConfig.l1Contracts, - this.wallet, - this.ownerAddress, - ); - - return Promise.resolve(); - }, + this.logger.verbose(`L2 token deployed to: ${this.crossChainTestHarness.l2Token.address}`); + + const crossChainContext = this.crossChainTestHarness.toCrossChainContext(); + + this.l2Token = TokenContract.at(crossChainContext.l2Token, this.wallet); + this.l2Bridge = TokenBridgeContract.at(crossChainContext.l2Bridge, this.wallet); + + // There is an issue with the reviver so we are getting strings sometimes. Working around it here. + this.ethAccount = EthAddress.fromString(crossChainContext.ethAccount.toString()); + const tokenPortalAddress = EthAddress.fromString(crossChainContext.tokenPortal.toString()); + + const l1Client = createExtendedL1Client(this.aztecNodeConfig.l1RpcUrls, MNEMONIC); + this.l1Client = l1Client; + + const l1Contracts = this.aztecNodeConfig.l1Contracts; + this.rollup = new RollupContract(l1Client, l1Contracts.rollupAddress.toString()); + this.inbox = new InboxContract(l1Client, l1Contracts.inboxAddress.toString()); + this.outbox = new OutboxContract(l1Client, l1Contracts.outboxAddress.toString()); + + this.crossChainTestHarness = new CrossChainTestHarness( + this.aztecNode, + this.logger, + this.l2Token, + this.l2Bridge, + this.ethAccount, + tokenPortalAddress, + crossChainContext.underlying, + l1Client, + this.aztecNodeConfig.l1Contracts, + this.wallet, + this.ownerAddress, ); } } diff --git a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/l1_to_l2.test.ts b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/l1_to_l2.test.ts index e866e59e5f36..3e43414192d7 100644 --- a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/l1_to_l2.test.ts +++ b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/l1_to_l2.test.ts @@ -32,7 +32,6 @@ describe('e2e_cross_chain_messaging l1_to_l2', () => { { minTxsPerBlock: 1 }, { aztecProofSubmissionEpochs: 2, aztecEpochDuration: 4, inboxLag: 2 }, ); - await t.applyBaseSnapshots(); await t.setup(); ({ logger: log, crossChainTestHarness, wallet, user1Address, aztecNode } = t); @@ -169,7 +168,7 @@ describe('e2e_cross_chain_messaging l1_to_l2', () => { // Stop proving const lastProven = await aztecNode.getBlockNumber(); log.warn(`Stopping proof submission at block ${lastProven} to allow drift`); - t.ctx.watcher.setIsMarkingAsProven(false); + t.context.watcher.setIsMarkingAsProven(false); // Mine several blocks to ensure drift log.warn(`Mining blocks to allow drift`); @@ -211,14 +210,14 @@ describe('e2e_cross_chain_messaging l1_to_l2', () => { // On private, we simulate the tx locally and check that we get a missing message error, then we advance to the next block await expect(() => consume().simulate({ from: user1Address })).rejects.toThrow(/No L1 to L2 message found/); await tryAdvanceBlock(); - await t.ctx.watcher.markAsProven(); + await t.context.watcher.markAsProven(); } else { // On public, we actually send the tx and check that it reverts due to the missing message. // This advances the block too as a side-effect. Note that we do not rely on a simulation since the cross chain messages // do not get added at the beginning of the block during node_simulatePublicCalls (maybe they should?). const { status } = await consume().send({ from: user1Address }).wait({ dontThrowOnRevert: true }); expect(status).toEqual(TxStatus.APP_LOGIC_REVERTED); - await t.ctx.watcher.markAsProven(); + await t.context.watcher.markAsProven(); } }); diff --git a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/l2_to_l1.test.ts b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/l2_to_l1.test.ts index fd8a98deec43..3880c22cb6c0 100644 --- a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/l2_to_l1.test.ts +++ b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/l2_to_l1.test.ts @@ -35,7 +35,6 @@ describe('e2e_cross_chain_messaging l2_to_l1', () => { let contract: TestContract; beforeAll(async () => { - await t.applyBaseSnapshots(); await t.setup(); ({ crossChainTestHarness, aztecNode, aztecNodeAdmin, wallet, user1Address, rollup, outbox } = t); diff --git a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_failure_cases.test.ts b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_failure_cases.test.ts index 7886f799170f..d864b328ceef 100644 --- a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_failure_cases.test.ts +++ b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_failure_cases.test.ts @@ -15,7 +15,6 @@ describe('e2e_cross_chain_messaging token_bridge_failure_cases', () => { let { crossChainTestHarness, ethAccount, l2Bridge, ownerAddress, user1Address, user2Address, rollup } = t; beforeAll(async () => { - await t.applyBaseSnapshots(); await t.setup(); // Have to destructure again to ensure we have latest refs. ({ crossChainTestHarness, user1Address, user2Address, ownerAddress, rollup } = t); diff --git a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_private.test.ts b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_private.test.ts index 4dc5c434280c..faec9c42418f 100644 --- a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_private.test.ts +++ b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_private.test.ts @@ -24,7 +24,6 @@ describe('e2e_cross_chain_messaging token_bridge_private', () => { let user2Address: AztecAddress; beforeAll(async () => { - await t.applyBaseSnapshots(); await t.setup(); // Have to destructure again to ensure we have latest refs. ({ crossChainTestHarness, ethAccount, aztecNode, logger, ownerAddress, l2Bridge, l2Token, wallet, user2Address } = diff --git a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_public.test.ts b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_public.test.ts index f1cccacfcb82..e7e5b54176b3 100644 --- a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_public.test.ts +++ b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/token_bridge_public.test.ts @@ -11,7 +11,6 @@ describe('e2e_cross_chain_messaging token_bridge_public', () => { t; beforeEach(async () => { - await t.applyBaseSnapshots(); await t.setup(); // Have to destructure again to ensure we have latest refs. ({ crossChainTestHarness, wallet, user2Address } = t); diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract/deploy_test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract/deploy_test.ts index 66c5487486e5..4d84fe1da419 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract/deploy_test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract/deploy_test.ts @@ -10,12 +10,10 @@ import type { StatefulTestContract } from '@aztec/noir-test-contracts.js/Statefu import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client'; import type { TestWallet } from '@aztec/test-wallet/server'; -import { type ISnapshotManager, createSnapshotManager, deployAccounts } from '../fixtures/snapshot_manager.js'; - -const { E2E_DATA_PATH: dataPath } = process.env; +import { type SubsystemsContext, deployAccounts, setupFromFresh, teardown } from '../fixtures/snapshot_manager.js'; export class DeployTest { - private snapshotManager: ISnapshotManager; + public context!: SubsystemsContext; public logger: Logger; public wallet!: TestWallet; public defaultAccountAddress!: AztecAddress; @@ -24,26 +22,32 @@ export class DeployTest { constructor(testName: string) { this.logger = createLogger(`e2e:e2e_deploy_contract:${testName}`); - this.snapshotManager = createSnapshotManager(`e2e_deploy_contract/${testName}`, dataPath); } async setup() { - await this.applyInitialAccountSnapshot(); - const context = await this.snapshotManager.setup(); - ({ aztecNode: this.aztecNode, wallet: this.wallet } = context); - this.aztecNodeAdmin = context.aztecNode; + this.logger.info('Setting up test environment'); + this.context = await setupFromFresh(this.logger); + this.aztecNode = this.context.aztecNode; + this.wallet = this.context.wallet; + this.aztecNodeAdmin = this.context.aztecNode; + await this.applyInitialAccount(); return this; } async teardown() { - await this.snapshotManager.teardown(); + await teardown(this.context); } - private async applyInitialAccountSnapshot() { - await this.snapshotManager.snapshot('initial_account', deployAccounts(1, this.logger), ({ deployedAccounts }) => { - this.defaultAccountAddress = deployedAccounts[0].address; - return Promise.resolve(); + private async applyInitialAccount() { + this.logger.info('Applying initial account setup'); + const { deployedAccounts } = await deployAccounts( + 1, + this.logger, + )({ + wallet: this.context.wallet, + initialFundedAccounts: this.context.initialFundedAccounts, }); + this.defaultAccountAddress = deployedAccounts[0].address; } async registerContract( diff --git a/yarn-project/end-to-end/src/e2e_fees/account_init.test.ts b/yarn-project/end-to-end/src/e2e_fees/account_init.test.ts index 0dee83926ae3..8d3bcdc8bd5d 100644 --- a/yarn-project/end-to-end/src/e2e_fees/account_init.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/account_init.test.ts @@ -25,10 +25,10 @@ describe('e2e_fees account_init', () => { const t = new FeesTest('account_init', 1); beforeAll(async () => { - await t.applyBaseSnapshots(); + await t.setup(); await t.applyFundAliceWithBananas(); - await t.applyFPCSetupSnapshot(); - ({ aliceAddress, wallet, bananaCoin, bananaFPC, logger, aztecNode } = await t.setup()); + await t.applyFPCSetup(); + ({ aliceAddress, wallet, bananaCoin, bananaFPC, logger, aztecNode } = t); }); afterAll(async () => { diff --git a/yarn-project/end-to-end/src/e2e_fees/bridging_race.notest.ts b/yarn-project/end-to-end/src/e2e_fees/bridging_race.notest.ts index 70b6ffde03d4..f428299df58f 100644 --- a/yarn-project/end-to-end/src/e2e_fees/bridging_race.notest.ts +++ b/yarn-project/end-to-end/src/e2e_fees/bridging_race.notest.ts @@ -26,11 +26,8 @@ describe('e2e_fees bridging_race', () => { }); beforeAll(async () => { - await t.applyInitialAccountsSnapshot(); - await t.applyPublicDeployAccountsSnapshot(); - await t.applySetupFeeJuiceSnapshot(); - - ({ wallet, logger } = await t.setup()); + await t.setup(); + ({ wallet, logger } = t); }); afterAll(async () => { diff --git a/yarn-project/end-to-end/src/e2e_fees/failures.test.ts b/yarn-project/end-to-end/src/e2e_fees/failures.test.ts index 337b156c4a53..7b528577c2d3 100644 --- a/yarn-project/end-to-end/src/e2e_fees/failures.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/failures.test.ts @@ -28,9 +28,9 @@ describe('e2e_fees failures', () => { const t = new FeesTest('failures', 3, { coinbase }); beforeAll(async () => { - await t.applyBaseSnapshots(); - await t.applyFPCSetupSnapshot(); - ({ wallet, aliceAddress, sequencerAddress, bananaCoin, bananaFPC, gasSettings } = await t.setup()); + await t.setup(); + await t.applyFPCSetup(); + ({ wallet, aliceAddress, sequencerAddress, bananaCoin, bananaFPC, gasSettings } = t); // Prove up until the current state by just marking it as proven. // Then turn off the watcher to prevent it from keep proving diff --git a/yarn-project/end-to-end/src/e2e_fees/fee_juice_payments.test.ts b/yarn-project/end-to-end/src/e2e_fees/fee_juice_payments.test.ts index 8b3391445f36..c61800251abe 100644 --- a/yarn-project/end-to-end/src/e2e_fees/fee_juice_payments.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/fee_juice_payments.test.ts @@ -20,9 +20,9 @@ describe('e2e_fees Fee Juice payments', () => { const t = new FeesTest('fee_juice', 1); beforeAll(async () => { - await t.applyBaseSnapshots(); + await t.setup(); await t.applyFundAliceWithBananas(); - ({ feeJuiceContract, aliceAddress, wallet, bananaCoin, gasSettings } = await t.setup()); + ({ feeJuiceContract, aliceAddress, wallet, bananaCoin, gasSettings } = t); const [bob] = await generateSchnorrAccounts(1); const bobsAccountManager = await wallet.createAccount({ diff --git a/yarn-project/end-to-end/src/e2e_fees/fee_settings.test.ts b/yarn-project/end-to-end/src/e2e_fees/fee_settings.test.ts index b2ceeb00e56e..a9782ee09a73 100644 --- a/yarn-project/end-to-end/src/e2e_fees/fee_settings.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/fee_settings.test.ts @@ -23,9 +23,8 @@ describe('e2e_fees fee settings', () => { const t = new FeesTest('fee_juice', 1); beforeAll(async () => { - await t.applyBaseSnapshots(); - - ({ aliceAddress, wallet, gasSettings, cheatCodes, aztecNode } = await t.setup()); + await t.setup(); + ({ aliceAddress, wallet, gasSettings, cheatCodes, aztecNode } = t); testContract = await TestContract.deploy(wallet).send({ from: aliceAddress }).deployed(); gasSettings = { ...gasSettings, maxFeesPerGas: undefined }; diff --git a/yarn-project/end-to-end/src/e2e_fees/fees_test.ts b/yarn-project/end-to-end/src/e2e_fees/fees_test.ts index c4361da2a244..7896f2dc4bd1 100644 --- a/yarn-project/end-to-end/src/e2e_fees/fees_test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/fees_test.ts @@ -26,25 +26,18 @@ import { getContract } from 'viem'; import { MNEMONIC } from '../fixtures/fixtures.js'; import { - type ISnapshotManager, type SubsystemsContext, - createSnapshotManager, deployAccounts, + publicDeployAccounts, + setupFromFresh, + teardown, } from '../fixtures/snapshot_manager.js'; import { mintTokensToPrivate } from '../fixtures/token_utils.js'; -import { - type BalancesFn, - type SetupOptions, - ensureAccountContractsPublished, - getBalancesFn, - setupSponsoredFPC, -} from '../fixtures/utils.js'; +import { type BalancesFn, type SetupOptions, getBalancesFn, setupSponsoredFPC } from '../fixtures/utils.js'; import { FeeJuicePortalTestingHarnessFactory, type GasBridgingTestHarness } from '../shared/gas_portal_test_harness.js'; -const { E2E_DATA_PATH: dataPath } = process.env; - /** - * Test fixture for testing fees. Provides the following snapshots: + * Test fixture for testing fees. Provides the following setup steps: * InitialAccounts: Initializes 3 Schnorr account contracts. * PublicDeployAccounts: Deploys the accounts publicly. * DeployFeeJuice: Deploys the Fee Juice contract. @@ -54,8 +47,8 @@ const { E2E_DATA_PATH: dataPath } = process.env; * SetupSubscription: Deploys a counter contract and a subscription contract, and mints Fee Juice to the subscription contract. */ export class FeesTest { - private snapshotManager: ISnapshotManager; private accounts: AztecAddress[] = []; + public context!: SubsystemsContext; public logger: Logger; public aztecNode!: AztecNode; @@ -82,7 +75,6 @@ export class FeesTest { public subscriptionContract!: AppSubscriptionContract; public feeJuiceBridgeTestHarness!: GasBridgingTestHarness; - public context!: SubsystemsContext; public chainMonitor!: ChainMonitor; public getCoinbaseBalance!: () => Promise; @@ -99,7 +91,7 @@ export class FeesTest { constructor( testName: string, private numberOfAccounts = 3, - setupOptions: Partial = {}, + private setupOptions: Partial = {}, ) { if (!numberOfAccounts) { throw new Error('There must be at least 1 initial account.'); @@ -107,26 +99,27 @@ export class FeesTest { setupOptions.coinbase ??= EthAddress.random(); this.coinbase = setupOptions.coinbase!; this.logger = createLogger(`e2e:e2e_fees:${testName}`); - this.snapshotManager = createSnapshotManager( - `e2e_fees/${testName}-${numberOfAccounts}`, - dataPath, - { startProverNode: true, ...setupOptions }, - { ...setupOptions }, - ); } async setup() { - const context = await this.snapshotManager.setup(); + this.logger.verbose('Setting up fresh context...'); + this.context = await setupFromFresh( + this.logger, + { startProverNode: true, ...this.setupOptions }, + { ...this.setupOptions }, + ); + + this.rollupContract = RollupContract.getFromConfig(this.context.aztecNodeConfig); + this.chainMonitor = new ChainMonitor(this.rollupContract, this.context.dateProvider, this.logger, 200).start(); - this.rollupContract = RollupContract.getFromConfig(context.aztecNodeConfig); - this.chainMonitor = new ChainMonitor(this.rollupContract, context.dateProvider, this.logger, 200).start(); + await this.applyBaseSetup(); return this; } async teardown() { await this.chainMonitor.stop(); - await this.snapshotManager.teardown(); + await teardown(this.context); } setIsMarkingAsProven(b: boolean) { @@ -176,210 +169,172 @@ export class FeesTest { expect(balanceAfter).toEqual(balanceBefore + amount); } - public async applyBaseSnapshots() { - await this.applyInitialAccountsSnapshot(); - await this.applyPublicDeployAccountsSnapshot(); - await this.applySetupFeeJuiceSnapshot(); - await this.applyDeployBananaTokenSnapshot(); + public async applyBaseSetup() { + await this.applyInitialAccounts(); + await this.applyPublicDeployAccounts(); + await this.applySetupFeeJuice(); + await this.applyDeployBananaToken(); } - async applyInitialAccountsSnapshot() { - await this.snapshotManager.snapshot( - 'initial_accounts', - deployAccounts(this.numberOfAccounts, this.logger), - async ({ deployedAccounts }, { wallet, aztecNode, cheatCodes }) => { - this.wallet = wallet; - this.aztecNode = aztecNode; - this.aztecNodeAdmin = aztecNode; - this.gasSettings = GasSettings.default({ maxFeesPerGas: (await this.aztecNode.getCurrentMinFees()).mul(2) }); - this.cheatCodes = cheatCodes; - this.accounts = deployedAccounts.map(a => a.address); - this.accounts.forEach((a, i) => this.logger.verbose(`Account ${i} address: ${a}`)); - [this.aliceAddress, this.bobAddress, this.sequencerAddress] = this.accounts.slice(0, 3); - - // We set Alice as the FPC admin to avoid the need for deployment of another account. - this.fpcAdmin = this.aliceAddress; - - const canonicalFeeJuice = await getCanonicalFeeJuice(); - this.feeJuiceContract = FeeJuiceContract.at(canonicalFeeJuice.address, this.wallet); - }, - ); + async applyInitialAccounts() { + this.logger.info('Applying initial accounts setup'); + + const { deployedAccounts } = await deployAccounts( + this.numberOfAccounts, + this.logger, + )({ + wallet: this.context.wallet, + initialFundedAccounts: this.context.initialFundedAccounts, + }); + + this.wallet = this.context.wallet; + this.aztecNode = this.context.aztecNode; + this.aztecNodeAdmin = this.context.aztecNode; + this.gasSettings = GasSettings.default({ maxFeesPerGas: (await this.aztecNode.getCurrentMinFees()).mul(2) }); + this.cheatCodes = this.context.cheatCodes; + this.accounts = deployedAccounts.map(a => a.address); + this.accounts.forEach((a, i) => this.logger.verbose(`Account ${i} address: ${a}`)); + [this.aliceAddress, this.bobAddress, this.sequencerAddress] = this.accounts.slice(0, 3); + + // We set Alice as the FPC admin to avoid the need for deployment of another account. + this.fpcAdmin = this.aliceAddress; + + const canonicalFeeJuice = await getCanonicalFeeJuice(); + this.feeJuiceContract = FeeJuiceContract.at(canonicalFeeJuice.address, this.wallet); } - async applyPublicDeployAccountsSnapshot() { - await this.snapshotManager.snapshot('public_deploy_accounts', () => - ensureAccountContractsPublished(this.wallet, this.accounts), - ); + async applyPublicDeployAccounts() { + this.logger.info('Applying public deploy accounts setup'); + await publicDeployAccounts(this.wallet, this.accounts); } - async applySetupFeeJuiceSnapshot() { - await this.snapshotManager.snapshot( - 'setup_fee_juice', - async () => {}, - async (_data, context) => { - this.context = context; - - this.feeJuiceContract = FeeJuiceContract.at(ProtocolContractAddress.FeeJuice, this.wallet); - - this.getGasBalanceFn = getBalancesFn( - '⛽', - this.feeJuiceContract.methods.balance_of_public, - this.aliceAddress, - this.logger, - ); - - this.feeJuiceBridgeTestHarness = await FeeJuicePortalTestingHarnessFactory.create({ - aztecNode: context.aztecNode, - aztecNodeAdmin: context.aztecNode, - l1Client: context.deployL1ContractsValues.l1Client, - wallet: this.wallet, - logger: this.logger, - }); - }, + async applySetupFeeJuice() { + this.logger.info('Applying fee juice setup'); + + this.feeJuiceContract = FeeJuiceContract.at(ProtocolContractAddress.FeeJuice, this.wallet); + + this.getGasBalanceFn = getBalancesFn( + '⛽', + this.feeJuiceContract.methods.balance_of_public, + this.aliceAddress, + this.logger, ); + + this.feeJuiceBridgeTestHarness = await FeeJuicePortalTestingHarnessFactory.create({ + aztecNode: this.context.aztecNode, + aztecNodeAdmin: this.context.aztecNode, + l1Client: this.context.deployL1ContractsValues.l1Client, + wallet: this.wallet, + logger: this.logger, + }); } - async applyDeployBananaTokenSnapshot() { - await this.snapshotManager.snapshot( - 'deploy_banana_token', - async () => { - const bananaCoin = await BananaCoin.deploy(this.wallet, this.aliceAddress, 'BC', 'BC', 18n) - .send({ from: this.aliceAddress }) - .deployed(); - this.logger.info(`BananaCoin deployed at ${bananaCoin.address}`); - return { bananaCoinAddress: bananaCoin.address }; - }, - ({ bananaCoinAddress }) => { - this.bananaCoin = BananaCoin.at(bananaCoinAddress, this.wallet); - const logger = this.logger; - this.getBananaPublicBalanceFn = getBalancesFn( - '🍌.public', - this.bananaCoin.methods.balance_of_public, - this.aliceAddress, - logger, - ); - this.getBananaPrivateBalanceFn = getBalancesFn( - '🍌.private', - this.bananaCoin.methods.balance_of_private, - this.aliceAddress, - logger, - ); - return Promise.resolve(); - }, + async applyDeployBananaToken() { + this.logger.info('Applying deploy banana token setup'); + + const bananaCoin = await BananaCoin.deploy(this.wallet, this.aliceAddress, 'BC', 'BC', 18n) + .send({ from: this.aliceAddress }) + .deployed(); + this.logger.info(`BananaCoin deployed at ${bananaCoin.address}`); + + this.bananaCoin = bananaCoin; + this.getBananaPublicBalanceFn = getBalancesFn( + '🍌.public', + this.bananaCoin.methods.balance_of_public, + this.aliceAddress, + this.logger, + ); + this.getBananaPrivateBalanceFn = getBalancesFn( + '🍌.private', + this.bananaCoin.methods.balance_of_private, + this.aliceAddress, + this.logger, ); } - public async applyFPCSetupSnapshot() { - await this.snapshotManager.snapshot( - 'fpc_setup', - async context => { - const feeJuiceContract = this.feeJuiceBridgeTestHarness.feeJuice; - expect((await context.wallet.getContractMetadata(feeJuiceContract.address)).isContractPublished).toBe(true); - - const bananaCoin = this.bananaCoin; - const bananaFPC = await FPCContract.deploy(this.wallet, bananaCoin.address, this.fpcAdmin) - .send({ from: this.aliceAddress }) - .deployed(); - - this.logger.info(`BananaPay deployed at ${bananaFPC.address}`); - - await this.feeJuiceBridgeTestHarness.bridgeFromL1ToL2(bananaFPC.address, this.aliceAddress); - - return { - bananaFPCAddress: bananaFPC.address, - feeJuiceAddress: feeJuiceContract.address, - l1FeeJuiceAddress: this.feeJuiceBridgeTestHarness.l1FeeJuiceAddress, - rollupAddress: context.deployL1ContractsValues.l1ContractAddresses.rollupAddress, - }; - }, - (data, context) => { - const bananaFPC = FPCContract.at(data.bananaFPCAddress, this.wallet); - this.bananaFPC = bananaFPC; - - this.getCoinbaseBalance = async () => { - const l1Client = createExtendedL1Client(context.aztecNodeConfig.l1RpcUrls, MNEMONIC); - const gasL1 = getContract({ - address: data.l1FeeJuiceAddress.toString(), - abi: TestERC20Abi, - client: l1Client, - }); - return await gasL1.read.balanceOf([this.coinbase.toString()]); - }; - - this.getCoinbaseSequencerRewards = async () => { - return await this.rollupContract.getSequencerRewards(this.coinbase); - }; - - this.getProverFee = async (blockNumber: BlockNumber) => { - const block = await this.aztecNode.getBlock(blockNumber); - - // @todo @lherskind As we deal with #13601 - // Right now the value is from `FeeLib.sol` - const L1_GAS_PER_EPOCH_VERIFIED = 1000000n; - - // We round up - const mulDiv = (a: bigint, b: bigint, c: bigint) => (a * b) / c + ((a * b) % c > 0n ? 1n : 0n); - - const { baseFee } = await this.rollupContract.getL1FeesAt(block!.header.globalVariables.timestamp); - const proverCost = - mulDiv( - mulDiv(L1_GAS_PER_EPOCH_VERIFIED, baseFee, BigInt(await this.rollupContract.getEpochDuration())), - 1n, - await this.rollupContract.getManaTarget(), - ) + (await this.rollupContract.getProvingCostPerMana()); - - const price = await this.rollupContract.getFeeAssetPerEth(); - - const mana = block!.header.totalManaUsed.toBigInt(); - return mulDiv(mana * proverCost, price, 10n ** 9n); - }; - return Promise.resolve(); - }, - ); + public async applyFPCSetup() { + this.logger.info('Applying FPC setup'); + + const feeJuiceContract = this.feeJuiceBridgeTestHarness.feeJuice; + expect((await this.wallet.getContractMetadata(feeJuiceContract.address)).isContractPublished).toBe(true); + + const bananaCoin = this.bananaCoin; + const bananaFPC = await FPCContract.deploy(this.wallet, bananaCoin.address, this.fpcAdmin) + .send({ from: this.aliceAddress }) + .deployed(); + + this.logger.info(`BananaPay deployed at ${bananaFPC.address}`); + + await this.feeJuiceBridgeTestHarness.bridgeFromL1ToL2(bananaFPC.address, this.aliceAddress); + + this.bananaFPC = bananaFPC; + + const l1FeeJuiceAddress = this.feeJuiceBridgeTestHarness.l1FeeJuiceAddress; + + this.getCoinbaseBalance = async () => { + const l1Client = createExtendedL1Client(this.context.aztecNodeConfig.l1RpcUrls, MNEMONIC); + const gasL1 = getContract({ + address: l1FeeJuiceAddress.toString(), + abi: TestERC20Abi, + client: l1Client, + }); + return await gasL1.read.balanceOf([this.coinbase.toString()]); + }; + + this.getCoinbaseSequencerRewards = async () => { + return await this.rollupContract.getSequencerRewards(this.coinbase); + }; + + this.getProverFee = async (blockNumber: BlockNumber) => { + const block = await this.aztecNode.getBlock(blockNumber); + + // @todo @lherskind As we deal with #13601 + // Right now the value is from `FeeLib.sol` + const L1_GAS_PER_EPOCH_VERIFIED = 1000000n; + + // We round up + const mulDiv = (a: bigint, b: bigint, c: bigint) => (a * b) / c + ((a * b) % c > 0n ? 1n : 0n); + + const { baseFee } = await this.rollupContract.getL1FeesAt(block!.header.globalVariables.timestamp); + const proverCost = + mulDiv( + mulDiv(L1_GAS_PER_EPOCH_VERIFIED, baseFee, BigInt(await this.rollupContract.getEpochDuration())), + 1n, + await this.rollupContract.getManaTarget(), + ) + (await this.rollupContract.getProvingCostPerMana()); + + const price = await this.rollupContract.getFeeAssetPerEth(); + + const mana = block!.header.totalManaUsed.toBigInt(); + return mulDiv(mana * proverCost, price, 10n ** 9n); + }; } - public async applySponsoredFPCSetupSnapshot() { - await this.snapshotManager.snapshot( - 'sponsored_fpc_setup', - async context => { - const feeJuiceContract = this.feeJuiceBridgeTestHarness.feeJuice; - expect((await context.wallet.getContractMetadata(feeJuiceContract.address)).isContractPublished).toBe(true); - - const sponsoredFPC = await setupSponsoredFPC(this.wallet); - this.logger.info(`SponsoredFPC at ${sponsoredFPC.address}`); - - return { - sponsoredFPCAddress: sponsoredFPC.address, - }; - }, - data => { - this.sponsoredFPC = SponsoredFPCContract.at(data.sponsoredFPCAddress, this.wallet); - return Promise.resolve(); - }, - ); + public async applySponsoredFPCSetup() { + this.logger.info('Applying sponsored FPC setup'); + + const feeJuiceContract = this.feeJuiceBridgeTestHarness.feeJuice; + expect((await this.wallet.getContractMetadata(feeJuiceContract.address)).isContractPublished).toBe(true); + + const sponsoredFPCInstance = await setupSponsoredFPC(this.wallet); + this.logger.info(`SponsoredFPC at ${sponsoredFPCInstance.address}`); + + this.sponsoredFPC = SponsoredFPCContract.at(sponsoredFPCInstance.address, this.wallet); } public async applyFundAliceWithBananas() { - await this.snapshotManager.snapshot( - 'fund_alice', - async () => { - await this.mintPrivateBananas(this.ALICE_INITIAL_BANANAS, this.aliceAddress); - await this.bananaCoin.methods - .mint_to_public(this.aliceAddress, this.ALICE_INITIAL_BANANAS) - .send({ from: this.aliceAddress }) - .wait(); - }, - () => Promise.resolve(), - ); + this.logger.info('Applying fund Alice with bananas setup'); + + await this.mintPrivateBananas(this.ALICE_INITIAL_BANANAS, this.aliceAddress); + await this.bananaCoin.methods + .mint_to_public(this.aliceAddress, this.ALICE_INITIAL_BANANAS) + .send({ from: this.aliceAddress }) + .wait(); } public async applyFundAliceWithPrivateBananas() { - await this.snapshotManager.snapshot( - 'fund_alice_with_private_bananas', - async () => { - await this.mintPrivateBananas(this.ALICE_INITIAL_BANANAS, this.aliceAddress); - }, - () => Promise.resolve(), - ); + this.logger.info('Applying fund Alice with private bananas setup'); + + await this.mintPrivateBananas(this.ALICE_INITIAL_BANANAS, this.aliceAddress); } } diff --git a/yarn-project/end-to-end/src/e2e_fees/gas_estimation.test.ts b/yarn-project/end-to-end/src/e2e_fees/gas_estimation.test.ts index d212c4009920..b6f42029553b 100644 --- a/yarn-project/end-to-end/src/e2e_fees/gas_estimation.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/gas_estimation.test.ts @@ -31,10 +31,10 @@ describe('e2e_fees gas_estimation', () => { const t = new FeesTest('gas_estimation'); beforeAll(async () => { - await t.applyBaseSnapshots(); - await t.applyFPCSetupSnapshot(); + await t.setup(); + await t.applyFPCSetup(); await t.applyFundAliceWithBananas(); - ({ wallet, aliceAddress, bobAddress, bananaCoin, bananaFPC, gasSettings, logger, aztecNode } = await t.setup()); + ({ wallet, aliceAddress, bobAddress, bananaCoin, bananaFPC, gasSettings, logger, aztecNode } = t); }); beforeEach(async () => { diff --git a/yarn-project/end-to-end/src/e2e_fees/private_payments.test.ts b/yarn-project/end-to-end/src/e2e_fees/private_payments.test.ts index 3f2858995081..879f5360d38b 100644 --- a/yarn-project/end-to-end/src/e2e_fees/private_payments.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/private_payments.test.ts @@ -25,11 +25,10 @@ describe('e2e_fees private_payment', () => { const t = new FeesTest('private_payment'); beforeAll(async () => { - await t.applyBaseSnapshots(); - await t.applyFPCSetupSnapshot(); + await t.setup(); + await t.applyFPCSetup(); await t.applyFundAliceWithBananas(); - ({ wallet, aliceAddress, bobAddress, sequencerAddress, bananaCoin, bananaFPC, gasSettings, aztecNode } = - await t.setup()); + ({ wallet, aliceAddress, bobAddress, sequencerAddress, bananaCoin, bananaFPC, gasSettings, aztecNode } = t); // Prove up until the current state by just marking it as proven. // Then turn off the watcher to prevent it from keep proving diff --git a/yarn-project/end-to-end/src/e2e_fees/public_payments.test.ts b/yarn-project/end-to-end/src/e2e_fees/public_payments.test.ts index 1f5bf0fd3c06..a9a7dddd5f39 100644 --- a/yarn-project/end-to-end/src/e2e_fees/public_payments.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/public_payments.test.ts @@ -22,11 +22,10 @@ describe('e2e_fees public_payment', () => { const t = new FeesTest('public_payment'); beforeAll(async () => { - await t.applyBaseSnapshots(); - await t.applyFPCSetupSnapshot(); + await t.setup(); + await t.applyFPCSetup(); await t.applyFundAliceWithBananas(); - ({ wallet, aliceAddress, bobAddress, sequencerAddress, bananaCoin, bananaFPC, gasSettings, aztecNode } = - await t.setup()); + ({ wallet, aliceAddress, bobAddress, sequencerAddress, bananaCoin, bananaFPC, gasSettings, aztecNode } = t); }); afterAll(async () => { diff --git a/yarn-project/end-to-end/src/e2e_fees/sponsored_payments.test.ts b/yarn-project/end-to-end/src/e2e_fees/sponsored_payments.test.ts index 8f146c6436b4..36c12f13a426 100644 --- a/yarn-project/end-to-end/src/e2e_fees/sponsored_payments.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/sponsored_payments.test.ts @@ -20,11 +20,10 @@ describe('e2e_fees sponsored_public_payment', () => { const t = new FeesTest('sponsored_payment'); beforeAll(async () => { - await t.applyBaseSnapshots(); - await t.applySponsoredFPCSetupSnapshot(); + await t.setup(); + await t.applySponsoredFPCSetup(); await t.applyFundAliceWithBananas(); - ({ aztecNode, aliceAddress, bobAddress, sequencerAddress, sponsoredFPC, bananaCoin, gasSettings } = - await t.setup()); + ({ aztecNode, aliceAddress, bobAddress, sequencerAddress, sponsoredFPC, bananaCoin, gasSettings } = t); }); afterAll(async () => { diff --git a/yarn-project/end-to-end/src/e2e_nested_contract/importer.test.ts b/yarn-project/end-to-end/src/e2e_nested_contract/importer.test.ts index 6b0066f9ba90..4af04de2d7cf 100644 --- a/yarn-project/end-to-end/src/e2e_nested_contract/importer.test.ts +++ b/yarn-project/end-to-end/src/e2e_nested_contract/importer.test.ts @@ -10,7 +10,6 @@ describe('e2e_nested_contract manual', () => { let { wallet, logger, defaultAccountAddress } = t; beforeAll(async () => { - await t.applyBaseSnapshots(); await t.setup(); ({ wallet, logger, defaultAccountAddress } = t); }); diff --git a/yarn-project/end-to-end/src/e2e_nested_contract/manual_private_call.test.ts b/yarn-project/end-to-end/src/e2e_nested_contract/manual_private_call.test.ts index e1ccaf248350..c3b714efab6c 100644 --- a/yarn-project/end-to-end/src/e2e_nested_contract/manual_private_call.test.ts +++ b/yarn-project/end-to-end/src/e2e_nested_contract/manual_private_call.test.ts @@ -5,9 +5,8 @@ describe('e2e_nested_contract manual', () => { let { parentContract, childContract, defaultAccountAddress } = t; beforeAll(async () => { - await t.applyBaseSnapshots(); - await t.applyManualSnapshots(); await t.setup(); + await t.applyManual(); ({ parentContract, childContract, defaultAccountAddress } = t); }); diff --git a/yarn-project/end-to-end/src/e2e_nested_contract/manual_private_enqueue.test.ts b/yarn-project/end-to-end/src/e2e_nested_contract/manual_private_enqueue.test.ts index dc69a8a53156..9d512a0eb8b1 100644 --- a/yarn-project/end-to-end/src/e2e_nested_contract/manual_private_enqueue.test.ts +++ b/yarn-project/end-to-end/src/e2e_nested_contract/manual_private_enqueue.test.ts @@ -13,8 +13,7 @@ describe('e2e_nested_contract manual_enqueue', () => { aztecNode.getPublicStorageAt('latest', child.address, new Fr(1)); beforeAll(async () => { - await t.applyBaseSnapshots(); - // We don't have the manual snapshot because every test requires a fresh setup and teardown + // We don't deploy contracts in beforeAll because every test requires a fresh setup await t.setup(); ({ wallet, defaultAccountAddress, aztecNode } = t); }); diff --git a/yarn-project/end-to-end/src/e2e_nested_contract/manual_public.test.ts b/yarn-project/end-to-end/src/e2e_nested_contract/manual_public.test.ts index 122aaa2a8acd..976dbc513e99 100644 --- a/yarn-project/end-to-end/src/e2e_nested_contract/manual_public.test.ts +++ b/yarn-project/end-to-end/src/e2e_nested_contract/manual_public.test.ts @@ -14,9 +14,8 @@ describe('e2e_nested_contract manual', () => { aztecNode.getPublicStorageAt('latest', child.address, new Fr(1)); beforeAll(async () => { - await t.applyBaseSnapshots(); - await t.applyManualSnapshots(); await t.setup(); + await t.applyManual(); ({ wallet, parentContract, childContract, defaultAccountAddress, aztecNode } = t); }); diff --git a/yarn-project/end-to-end/src/e2e_nested_contract/nested_contract_test.ts b/yarn-project/end-to-end/src/e2e_nested_contract/nested_contract_test.ts index a77055d19f77..3bf2d51101aa 100644 --- a/yarn-project/end-to-end/src/e2e_nested_contract/nested_contract_test.ts +++ b/yarn-project/end-to-end/src/e2e_nested_contract/nested_contract_test.ts @@ -6,17 +6,15 @@ import { ChildContract } from '@aztec/noir-test-contracts.js/Child'; import { ParentContract } from '@aztec/noir-test-contracts.js/Parent'; import { - type ISnapshotManager, type SubsystemsContext, - createSnapshotManager, deployAccounts, publicDeployAccounts, + setupFromFresh, + teardown as teardownSubsystems, } from '../fixtures/snapshot_manager.js'; -const { E2E_DATA_PATH: dataPath } = process.env; - export class NestedContractTest { - private snapshotManager: ISnapshotManager; + context!: SubsystemsContext; logger: Logger; wallet!: Wallet; defaultAccountAddress!: AztecAddress; @@ -30,67 +28,45 @@ export class NestedContractTest { private numberOfAccounts = 1, ) { this.logger = createLogger(`e2e:e2e_nested_contract:${testName}`); - this.snapshotManager = createSnapshotManager(`e2e_nested_contract/${testName}-${numberOfAccounts}`, dataPath); } /** - * Adds two state shifts to snapshot manager. - * 1. Add 3 accounts. - * 2. Publicly deploy accounts + * Applies base setup by deploying accounts and publicly deploying them. */ - async applyBaseSnapshots() { - await this.snapshotManager.snapshot( - 'accounts', - deployAccounts(this.numberOfAccounts, this.logger), - ({ deployedAccounts }, { wallet, aztecNode }) => { - this.wallet = wallet; - [{ address: this.defaultAccountAddress }] = deployedAccounts; - this.aztecNode = aztecNode; - return Promise.resolve(); - }, - ); + async applyBaseSetup() { + this.logger.info('Deploying accounts'); + const { deployedAccounts } = await deployAccounts( + this.numberOfAccounts, + this.logger, + )({ + wallet: this.context.wallet, + initialFundedAccounts: this.context.initialFundedAccounts, + }); + this.wallet = this.context.wallet; + [{ address: this.defaultAccountAddress }] = deployedAccounts; + this.aztecNode = this.context.aztecNode; - await this.snapshotManager.snapshot( - 'public_deploy', - async () => {}, - async () => { - this.logger.verbose(`Public deploy accounts...`); - await publicDeployAccounts(this.wallet, [this.defaultAccountAddress]); - }, - ); + this.logger.info('Public deploy accounts'); + await publicDeployAccounts(this.wallet, [this.defaultAccountAddress]); } async setup() { - await this.snapshotManager.setup(); + this.logger.info('Setting up fresh subsystems'); + this.context = await setupFromFresh(this.logger); + await this.applyBaseSetup(); } async teardown() { - await this.snapshotManager.teardown(); + await teardownSubsystems(this.context); } - snapshot = ( - name: string, - apply: (context: SubsystemsContext) => Promise, - restore: (snapshotData: T, context: SubsystemsContext) => Promise = () => Promise.resolve(), - ): Promise => this.snapshotManager.snapshot(name, apply, restore); - - async applyManualSnapshots() { - await this.snapshotManager.snapshot( - 'manual', - async () => { - const parentContract = await ParentContract.deploy(this.wallet) - .send({ from: this.defaultAccountAddress }) - .deployed(); - const childContract = await ChildContract.deploy(this.wallet) - .send({ from: this.defaultAccountAddress }) - .deployed(); - return { parentContractAddress: parentContract.address, childContractAddress: childContract.address }; - }, - ({ parentContractAddress, childContractAddress }) => { - this.parentContract = ParentContract.at(parentContractAddress, this.wallet); - this.childContract = ChildContract.at(childContractAddress, this.wallet); - return Promise.resolve(); - }, - ); + async applyManual() { + this.logger.info('Deploying parent and child contracts'); + const parentContract = await ParentContract.deploy(this.wallet) + .send({ from: this.defaultAccountAddress }) + .deployed(); + const childContract = await ChildContract.deploy(this.wallet).send({ from: this.defaultAccountAddress }).deployed(); + this.parentContract = parentContract; + this.childContract = childContract; } } diff --git a/yarn-project/end-to-end/src/e2e_p2p/add_rollup.test.ts b/yarn-project/end-to-end/src/e2e_p2p/add_rollup.test.ts index 215c4b2fc206..bbd9263dc515 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/add_rollup.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/add_rollup.test.ts @@ -84,8 +84,8 @@ describe('e2e_p2p_add_rollup', () => { startProverNode: false, // Start one later using p2p. }); - await t.applyBaseSnapshots(); await t.setup(); + await t.applyBaseSetup(); await t.removeInitialNode(); l1TxUtils = createL1TxUtilsFromViemWallet(t.ctx.deployL1ContractsValues.l1Client); diff --git a/yarn-project/end-to-end/src/e2e_p2p/broadcasted_invalid_block_proposal_slash.test.ts b/yarn-project/end-to-end/src/e2e_p2p/broadcasted_invalid_block_proposal_slash.test.ts index 1eb4321f099b..afb44df6ac78 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/broadcasted_invalid_block_proposal_slash.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/broadcasted_invalid_block_proposal_slash.test.ts @@ -70,8 +70,8 @@ describe('e2e_p2p_broadcasted_invalid_block_proposal_slash', () => { }, }); - await t.applyBaseSnapshots(); await t.setup(); + await t.applyBaseSetup(); }); afterEach(async () => { diff --git a/yarn-project/end-to-end/src/e2e_p2p/data_withholding_slash.test.ts b/yarn-project/end-to-end/src/e2e_p2p/data_withholding_slash.test.ts index c5b022992425..917dba22df30 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/data_withholding_slash.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/data_withholding_slash.test.ts @@ -74,8 +74,8 @@ describe('e2e_p2p_data_withholding_slash', () => { }, }); - await t.applyBaseSnapshots(); await t.setup(); + await t.applyBaseSetup(); }); afterEach(async () => { diff --git a/yarn-project/end-to-end/src/e2e_p2p/gossip_network.test.ts b/yarn-project/end-to-end/src/e2e_p2p/gossip_network.test.ts index 119aaef7a602..29f7048f8d4e 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/gossip_network.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/gossip_network.test.ts @@ -69,8 +69,8 @@ describe('e2e_p2p_network', () => { }, }); - await t.applyBaseSnapshots(); await t.setup(); + await t.applyBaseSetup(); }); afterEach(async () => { diff --git a/yarn-project/end-to-end/src/e2e_p2p/gossip_network_no_cheat.test.ts b/yarn-project/end-to-end/src/e2e_p2p/gossip_network_no_cheat.test.ts index 63f7a8e78861..30c075dbdc02 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/gossip_network_no_cheat.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/gossip_network_no_cheat.test.ts @@ -65,8 +65,8 @@ describe('e2e_p2p_network', () => { }, }); - await t.addBootstrapNode(); await t.setup(); + await t.addBootstrapNode(); }); afterEach(async () => { diff --git a/yarn-project/end-to-end/src/e2e_p2p/inactivity_slash_test.ts b/yarn-project/end-to-end/src/e2e_p2p/inactivity_slash_test.ts index d42da68b51e5..59903e4daf20 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/inactivity_slash_test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/inactivity_slash_test.ts @@ -82,8 +82,8 @@ export class P2PInactivityTest { } public async setup() { - await this.test.applyBaseSnapshots(); await this.test.setup(); + await this.test.applyBaseSetup(); // Set slashing penalties for inactivity const { rollup } = await this.test.getContracts(); diff --git a/yarn-project/end-to-end/src/e2e_p2p/mbps_checkpoint_consensus.test.ts b/yarn-project/end-to-end/src/e2e_p2p/mbps_checkpoint_consensus.test.ts index 8a67cc97bd79..f9f1de9faacf 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/mbps_checkpoint_consensus.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/mbps_checkpoint_consensus.test.ts @@ -76,8 +76,8 @@ describe.skip('e2e_p2p_mbps_checkpoint_consensus', () => { }, }); - await t.applyBaseSnapshots(); await t.setup(); + await t.applyBaseSetup(); rollup = RollupContract.getFromConfig(t.ctx.aztecNodeConfig); }); diff --git a/yarn-project/end-to-end/src/e2e_p2p/multiple_validators_sentinel.parallel.test.ts b/yarn-project/end-to-end/src/e2e_p2p/multiple_validators_sentinel.parallel.test.ts index 910f8e387761..1d47f45d237f 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/multiple_validators_sentinel.parallel.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/multiple_validators_sentinel.parallel.test.ts @@ -56,8 +56,8 @@ describe('e2e_p2p_multiple_validators_sentinel', () => { }, }); - await t.applyBaseSnapshots(); await t.setup(); + await t.applyBaseSetup(); rollup = RollupContract.getFromConfig(t.ctx.aztecNodeConfig); diff --git a/yarn-project/end-to-end/src/e2e_p2p/p2p_network.ts b/yarn-project/end-to-end/src/e2e_p2p/p2p_network.ts index 17d56816c479..31a4629aff4a 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/p2p_network.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/p2p_network.ts @@ -39,12 +39,7 @@ import { createValidatorConfig, generatePrivateKeys, } from '../fixtures/setup_p2p_test.js'; -import { - type ISnapshotManager, - type SubsystemsContext, - createSnapshotManager, - deployAccounts, -} from '../fixtures/snapshot_manager.js'; +import { type SubsystemsContext, deployAccounts, setupFromFresh, teardown } from '../fixtures/snapshot_manager.js'; import { type SetupOptions, getPrivateKeyFromIndex, getSponsoredFPCAddress } from '../fixtures/utils.js'; import { getEndToEndTestTelemetryClient } from '../fixtures/with_telemetry_utils.js'; @@ -60,7 +55,7 @@ export const SHORTENED_BLOCK_TIME_CONFIG_NO_PRUNES = { }; export class P2PNetworkTest { - private snapshotManager: ISnapshotManager; + public context!: SubsystemsContext; public baseAccountPrivateKey: `0x${string}`; public baseAccount; @@ -83,6 +78,10 @@ export class P2PNetworkTest { public bootstrapNode?: BootstrapNode; + // Store setup options for use in setup() + private setupOptions: SetupOptions; + private deployL1ContractsArgs: any; + constructor( public readonly testName: string, public bootstrapNodeEnr: string, @@ -107,43 +106,41 @@ export class P2PNetworkTest { const zkPassportParams = ZkPassportProofParams.random(); - this.snapshotManager = createSnapshotManager( - `e2e_p2p_network/${testName}`, - process.env.E2E_DATA_PATH, - { - ...initialValidatorConfig, - ethereumSlotDuration: initialValidatorConfig.ethereumSlotDuration ?? l1ContractsConfig.ethereumSlotDuration, - aztecEpochDuration: initialValidatorConfig.aztecEpochDuration ?? l1ContractsConfig.aztecEpochDuration, - aztecSlotDuration: initialValidatorConfig.aztecSlotDuration ?? l1ContractsConfig.aztecSlotDuration, - aztecProofSubmissionEpochs: - initialValidatorConfig.aztecProofSubmissionEpochs ?? l1ContractsConfig.aztecProofSubmissionEpochs, - slashingRoundSizeInEpochs: - initialValidatorConfig.slashingRoundSizeInEpochs ?? l1ContractsConfig.slashingRoundSizeInEpochs, - slasherFlavor: initialValidatorConfig.slasherFlavor ?? 'tally', - aztecTargetCommitteeSize: numberOfValidators, - metricsPort: metricsPort, - numberOfInitialFundedAccounts: 2, - startProverNode, - }, - { - ...initialValidatorConfig, - aztecEpochDuration: initialValidatorConfig.aztecEpochDuration ?? l1ContractsConfig.aztecEpochDuration, - slashingRoundSizeInEpochs: - initialValidatorConfig.slashingRoundSizeInEpochs ?? l1ContractsConfig.slashingRoundSizeInEpochs, - slasherFlavor: initialValidatorConfig.slasherFlavor ?? 'tally', - - ethereumSlotDuration: initialValidatorConfig.ethereumSlotDuration ?? l1ContractsConfig.ethereumSlotDuration, - aztecSlotDuration: initialValidatorConfig.aztecSlotDuration ?? l1ContractsConfig.aztecSlotDuration, - aztecProofSubmissionEpochs: - initialValidatorConfig.aztecProofSubmissionEpochs ?? l1ContractsConfig.aztecProofSubmissionEpochs, - aztecTargetCommitteeSize: numberOfValidators, - initialValidators: [], - zkPassportArgs: { - zkPassportDomain: zkPassportParams.domain, - zkPassportScope: zkPassportParams.scope, - }, + // Store setup options for later use + this.setupOptions = { + ...initialValidatorConfig, + ethereumSlotDuration: initialValidatorConfig.ethereumSlotDuration ?? l1ContractsConfig.ethereumSlotDuration, + aztecEpochDuration: initialValidatorConfig.aztecEpochDuration ?? l1ContractsConfig.aztecEpochDuration, + aztecSlotDuration: initialValidatorConfig.aztecSlotDuration ?? l1ContractsConfig.aztecSlotDuration, + aztecProofSubmissionEpochs: + initialValidatorConfig.aztecProofSubmissionEpochs ?? l1ContractsConfig.aztecProofSubmissionEpochs, + slashingRoundSizeInEpochs: + initialValidatorConfig.slashingRoundSizeInEpochs ?? l1ContractsConfig.slashingRoundSizeInEpochs, + slasherFlavor: initialValidatorConfig.slasherFlavor ?? 'tally', + aztecTargetCommitteeSize: numberOfValidators, + metricsPort: metricsPort, + numberOfInitialFundedAccounts: 2, + startProverNode, + }; + + this.deployL1ContractsArgs = { + ...initialValidatorConfig, + aztecEpochDuration: initialValidatorConfig.aztecEpochDuration ?? l1ContractsConfig.aztecEpochDuration, + slashingRoundSizeInEpochs: + initialValidatorConfig.slashingRoundSizeInEpochs ?? l1ContractsConfig.slashingRoundSizeInEpochs, + slasherFlavor: initialValidatorConfig.slasherFlavor ?? 'tally', + + ethereumSlotDuration: initialValidatorConfig.ethereumSlotDuration ?? l1ContractsConfig.ethereumSlotDuration, + aztecSlotDuration: initialValidatorConfig.aztecSlotDuration ?? l1ContractsConfig.aztecSlotDuration, + aztecProofSubmissionEpochs: + initialValidatorConfig.aztecProofSubmissionEpochs ?? l1ContractsConfig.aztecProofSubmissionEpochs, + aztecTargetCommitteeSize: numberOfValidators, + initialValidators: [], + zkPassportArgs: { + zkPassportDomain: zkPassportParams.domain, + zkPassportScope: zkPassportParams.scope, }, - ); + }; } static async create({ @@ -187,23 +184,22 @@ export class P2PNetworkTest { get fundedAccount() { if (!this.deployedAccounts[0]) { - throw new Error('Call snapshot t.setupAccount to create a funded account.'); + throw new Error('Call setupAccount to create a funded account.'); } return this.deployedAccounts[0]; } async addBootstrapNode() { - await this.snapshotManager.snapshot('add-bootstrap-node', async ({ aztecNodeConfig }) => { - const telemetry = await getEndToEndTestTelemetryClient(this.metricsPort); - this.bootstrapNode = await createBootstrapNodeFromPrivateKey( - BOOTSTRAP_NODE_PRIVATE_KEY, - this.bootNodePort, - telemetry, - aztecNodeConfig, - ); - // Overwrite enr with updated info - this.bootstrapNodeEnr = this.bootstrapNode.getENR().encodeTxt(); - }); + this.logger.info('Adding bootstrap node'); + const telemetry = await getEndToEndTestTelemetryClient(this.metricsPort); + this.bootstrapNode = await createBootstrapNodeFromPrivateKey( + BOOTSTRAP_NODE_PRIVATE_KEY, + this.bootNodePort, + telemetry, + this.context.aztecNodeConfig, + ); + // Overwrite enr with updated info + this.bootstrapNodeEnr = this.bootstrapNode.getENR().encodeTxt(); } getValidators() { @@ -224,128 +220,114 @@ export class P2PNetworkTest { return { validators }; } - async applyBaseSnapshots() { + async applyBaseSetup() { await this.addBootstrapNode(); - await this.snapshotManager.snapshot('add-validators', async ({ deployL1ContractsValues, cheatCodes }) => { - const rollup = getContract({ - address: deployL1ContractsValues.l1ContractAddresses.rollupAddress.toString(), - abi: RollupAbi, - client: deployL1ContractsValues.l1Client, - }); - this.logger.info(`Adding ${this.numberOfValidators} validators`); + this.logger.info('Adding validators'); + const rollup = getContract({ + address: this.context.deployL1ContractsValues.l1ContractAddresses.rollupAddress.toString(), + abi: RollupAbi, + client: this.context.deployL1ContractsValues.l1Client, + }); - const stakingAsset = getContract({ - address: deployL1ContractsValues.l1ContractAddresses.stakingAssetAddress.toString(), - abi: TestERC20Abi, - client: deployL1ContractsValues.l1Client, - }); + this.logger.info(`Adding ${this.numberOfValidators} validators`); - const { address: multiAdderAddress } = await deployL1Contract( - deployL1ContractsValues.l1Client, - MultiAdderArtifact.contractAbi, - MultiAdderArtifact.contractBytecode, - [rollup.address, deployL1ContractsValues.l1Client.account.address], - ); - - const multiAdder = getContract({ - address: multiAdderAddress.toString(), - abi: MultiAdderArtifact.contractAbi, - client: deployL1ContractsValues.l1Client, - }); + const stakingAsset = getContract({ + address: this.context.deployL1ContractsValues.l1ContractAddresses.stakingAssetAddress.toString(), + abi: TestERC20Abi, + client: this.context.deployL1ContractsValues.l1Client, + }); - const stakeNeeded = (await rollup.read.getActivationThreshold()) * BigInt(this.numberOfValidators); - await Promise.all( - [await stakingAsset.write.mint([multiAdder.address, stakeNeeded], {} as any)].map(txHash => - deployL1ContractsValues.l1Client.waitForTransactionReceipt({ hash: txHash }), - ), - ); - - const { validators } = this.getValidators(); - this.validators = validators; - - const gseAddress = deployL1ContractsValues.l1ContractAddresses.gseAddress!; - if (!gseAddress) { - throw new Error('GSE contract not deployed'); - } - - const gseContract = new GSEContract(deployL1ContractsValues.l1Client, gseAddress.toString()); - - const makeValidatorTuples = async (validator: Operator) => { - const registrationTuple = await gseContract.makeRegistrationTuple(validator.bn254SecretKey.getValue()); - return { - attester: validator.attester.toString() as `0x${string}`, - withdrawer: validator.withdrawer.toString() as `0x${string}`, - ...registrationTuple, - }; - }; - const validatorTuples = await Promise.all(validators.map(makeValidatorTuples)); + const { address: multiAdderAddress } = await deployL1Contract( + this.context.deployL1ContractsValues.l1Client, + MultiAdderArtifact.contractAbi, + MultiAdderArtifact.contractBytecode, + [rollup.address, this.context.deployL1ContractsValues.l1Client.account.address], + ); - await deployL1ContractsValues.l1Client.waitForTransactionReceipt({ - hash: await multiAdder.write.addValidators([validatorTuples]), - }); + const multiAdder = getContract({ + address: multiAdderAddress.toString(), + abi: MultiAdderArtifact.contractAbi, + client: this.context.deployL1ContractsValues.l1Client, + }); - await cheatCodes.rollup.advanceToEpoch( - EpochNumber.fromBigInt( - BigInt(await cheatCodes.rollup.getEpoch()) + (await rollup.read.getLagInEpochsForValidatorSet()) + 1n, - ), - ); + const stakeNeeded = (await rollup.read.getActivationThreshold()) * BigInt(this.numberOfValidators); + await Promise.all( + [await stakingAsset.write.mint([multiAdder.address, stakeNeeded], {} as any)].map(txHash => + this.context.deployL1ContractsValues.l1Client.waitForTransactionReceipt({ hash: txHash }), + ), + ); - // Send and await a tx to make sure we mine a block for the warp to correctly progress. - await this._sendDummyTx(deployL1ContractsValues.l1Client); + const { validators } = this.getValidators(); + this.validators = validators; + + const gseAddress = this.context.deployL1ContractsValues.l1ContractAddresses.gseAddress!; + if (!gseAddress) { + throw new Error('GSE contract not deployed'); + } + + const gseContract = new GSEContract(this.context.deployL1ContractsValues.l1Client, gseAddress.toString()); + + const makeValidatorTuples = async (validator: Operator) => { + const registrationTuple = await gseContract.makeRegistrationTuple(validator.bn254SecretKey.getValue()); + return { + attester: validator.attester.toString() as `0x${string}`, + withdrawer: validator.withdrawer.toString() as `0x${string}`, + ...registrationTuple, + }; + }; + const validatorTuples = await Promise.all(validators.map(makeValidatorTuples)); + + await this.context.deployL1ContractsValues.l1Client.waitForTransactionReceipt({ + hash: await multiAdder.write.addValidators([validatorTuples]), }); + + await this.context.cheatCodes.rollup.advanceToEpoch( + EpochNumber.fromBigInt( + BigInt(await this.context.cheatCodes.rollup.getEpoch()) + + (await rollup.read.getLagInEpochsForValidatorSet()) + + 1n, + ), + ); + + // Send and await a tx to make sure we mine a block for the warp to correctly progress. + await this._sendDummyTx(this.context.deployL1ContractsValues.l1Client); } async setupAccount() { - await this.snapshotManager.snapshot( - 'setup-account', - deployAccounts(1, this.logger), - ({ deployedAccounts }, { wallet }) => { - this.deployedAccounts = deployedAccounts; - [{ address: this.defaultAccountAddress }] = deployedAccounts; - this.wallet = wallet; - return Promise.resolve(); - }, - ); + this.logger.info('Setting up account'); + const { deployedAccounts } = await deployAccounts( + 1, + this.logger, + )({ + wallet: this.context.wallet, + initialFundedAccounts: this.context.initialFundedAccounts, + }); + this.deployedAccounts = deployedAccounts; + [{ address: this.defaultAccountAddress }] = deployedAccounts; + this.wallet = this.context.wallet; } async deploySpamContract() { - await this.snapshotManager.snapshot( - 'add-spam-contract', - async () => { - if (!this.wallet) { - throw new Error('Call snapshot t.setupAccount before deploying account contract'); - } - - const spamContract = await SpamContract.deploy(this.wallet) - .send({ from: this.defaultAccountAddress! }) - .deployed(); - return { contractAddress: spamContract.address }; - }, - ({ contractAddress }) => { - if (!this.wallet) { - throw new Error('Call snapshot t.setupAccount before deploying account contract'); - } - this.spamContract = SpamContract.at(contractAddress, this.wallet); - return Promise.resolve(); - }, - ); + this.logger.info('Deploying spam contract'); + if (!this.wallet) { + throw new Error('Call setupAccount before deploying spam contract'); + } + + const spamContract = await SpamContract.deploy(this.wallet).send({ from: this.defaultAccountAddress! }).deployed(); + this.spamContract = spamContract; } async removeInitialNode() { - await this.snapshotManager.snapshot( - 'remove-initial-validator', - async ({ deployL1ContractsValues, aztecNode, dateProvider }) => { - // Send and await a tx to make sure we mine a block for the warp to correctly progress. - const { receipt } = await this._sendDummyTx(deployL1ContractsValues.l1Client); - const block = await deployL1ContractsValues.l1Client.getBlock({ - blockNumber: receipt.blockNumber, - }); - dateProvider.setTime(Number(block.timestamp) * 1000); - - await aztecNode.stop(); - }, - ); + this.logger.info('Removing initial node'); + // Send and await a tx to make sure we mine a block for the warp to correctly progress. + const { receipt } = await this._sendDummyTx(this.context.deployL1ContractsValues.l1Client); + const block = await this.context.deployL1ContractsValues.l1Client.getBlock({ + blockNumber: receipt.blockNumber, + }); + this.context.dateProvider.setTime(Number(block.timestamp) * 1000); + + await this.context.aztecNode.stop(); } async sendDummyTx() { @@ -361,17 +343,19 @@ export class P2PNetworkTest { } async setup() { - this.ctx = await this.snapshotManager.setup(); + this.logger.info('Setting up subsystems from fresh'); + this.context = await setupFromFresh(this.logger, this.setupOptions, this.deployL1ContractsArgs); + this.ctx = this.context; const sponsoredFPCAddress = await getSponsoredFPCAddress(); - const initialFundedAccounts = [...this.ctx.initialFundedAccounts.map(a => a.address), sponsoredFPCAddress]; + const initialFundedAccounts = [...this.context.initialFundedAccounts.map(a => a.address), sponsoredFPCAddress]; const { prefilledPublicData } = await getGenesisValues(initialFundedAccounts); this.prefilledPublicData = prefilledPublicData; - const rollupContract = RollupContract.getFromL1ContractsValues(this.ctx.deployL1ContractsValues); - this.monitor = new ChainMonitor(rollupContract, this.ctx.dateProvider).start(); - this.monitor.on('l1-block', ({ timestamp }) => this.ctx.dateProvider.setTime(Number(timestamp) * 1000)); + const rollupContract = RollupContract.getFromL1ContractsValues(this.context.deployL1ContractsValues); + this.monitor = new ChainMonitor(rollupContract, this.context.dateProvider).start(); + this.monitor.on('l1-block', ({ timestamp }) => this.context.dateProvider.setTime(Number(timestamp) * 1000)); } async stopNodes(nodes: AztecNodeService[]) { @@ -432,7 +416,7 @@ export class P2PNetworkTest { async teardown() { await this.monitor.stop(); await tryStop(this.bootstrapNode, this.logger); - await this.snapshotManager.teardown(); + await teardown(this.context); } async getContracts(): Promise<{ diff --git a/yarn-project/end-to-end/src/e2e_p2p/preferred_gossip_network.test.ts b/yarn-project/end-to-end/src/e2e_p2p/preferred_gossip_network.test.ts index 31c3845211ee..a97f58400f49 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/preferred_gossip_network.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/preferred_gossip_network.test.ts @@ -141,8 +141,8 @@ describe('e2e_p2p_preferred_network', () => { }, }); - await t.applyBaseSnapshots(); await t.setup(); + await t.applyBaseSetup(); }); afterEach(async () => { diff --git a/yarn-project/end-to-end/src/e2e_p2p/rediscovery.test.ts b/yarn-project/end-to-end/src/e2e_p2p/rediscovery.test.ts index 4dac50600efa..967074be35af 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/rediscovery.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/rediscovery.test.ts @@ -35,8 +35,8 @@ describe('e2e_p2p_rediscovery', () => { listenAddress: '127.0.0.1', }, }); - await t.applyBaseSnapshots(); await t.setup(); + await t.applyBaseSetup(); }); afterEach(async () => { diff --git a/yarn-project/end-to-end/src/e2e_p2p/reex.test.ts b/yarn-project/end-to-end/src/e2e_p2p/reex.test.ts index 800fd4fe9715..181c0a8fd36b 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/reex.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/reex.test.ts @@ -50,12 +50,12 @@ describe('e2e_p2p_reex', () => { }, }); - t.logger.info('Apply base snapshots'); - await t.applyBaseSnapshots(); - - t.logger.info('Setup snapshot manager'); + t.logger.info('Setting up subsystems'); await t.setup(); + t.logger.info('Applying base setup'); + await t.applyBaseSetup(); + t.logger.info('Stopping main node sequencer'); await t.ctx.aztecNode.getSequencer()?.stop(); diff --git a/yarn-project/end-to-end/src/e2e_p2p/reqresp.test.ts b/yarn-project/end-to-end/src/e2e_p2p/reqresp.test.ts index b59c44e2add4..ee28774e6992 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/reqresp.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/reqresp.test.ts @@ -41,8 +41,8 @@ describe('e2e_p2p_reqresp_tx', () => { aztecEpochDuration: 64, // stable committee }, }); - await t.applyBaseSnapshots(); await t.setup(); + await t.applyBaseSetup(); }); afterEach(async () => { diff --git a/yarn-project/end-to-end/src/e2e_p2p/reqresp_no_handshake.test.ts b/yarn-project/end-to-end/src/e2e_p2p/reqresp_no_handshake.test.ts index cd4be668bb02..701ad44054b7 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/reqresp_no_handshake.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/reqresp_no_handshake.test.ts @@ -46,8 +46,8 @@ describe('e2e_p2p_reqresp_tx_no_handshake', () => { aztecEpochDuration: 64, // stable committee }, }); - await t.applyBaseSnapshots(); await t.setup(); + await t.applyBaseSetup(); }); afterEach(async () => { diff --git a/yarn-project/end-to-end/src/e2e_p2p/slash_veto_demo.test.ts b/yarn-project/end-to-end/src/e2e_p2p/slash_veto_demo.test.ts index ce52f857015d..f7cd63e5bfc0 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/slash_veto_demo.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/slash_veto_demo.test.ts @@ -97,8 +97,8 @@ describe('veto slash', () => { }, }); - await t.applyBaseSnapshots(); await t.setup(); + await t.applyBaseSetup(); nodes = await createNodes( t.ctx.aztecNodeConfig, diff --git a/yarn-project/end-to-end/src/e2e_p2p/upgrade_governance_proposer.test.ts b/yarn-project/end-to-end/src/e2e_p2p/upgrade_governance_proposer.test.ts index fe43773d74a4..0eed2f499a95 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/upgrade_governance_proposer.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/upgrade_governance_proposer.test.ts @@ -57,8 +57,8 @@ describe('e2e_p2p_governance_proposer', () => { }, }); - await t.applyBaseSnapshots(); await t.setup(); + await t.applyBaseSetup(); l1TxUtils = createL1TxUtilsFromViemWallet(t.ctx.deployL1ContractsValues.l1Client); }); diff --git a/yarn-project/end-to-end/src/e2e_p2p/valid_epoch_pruned_slash.test.ts b/yarn-project/end-to-end/src/e2e_p2p/valid_epoch_pruned_slash.test.ts index e39c7fe8035a..a7ec2a05cd18 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/valid_epoch_pruned_slash.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/valid_epoch_pruned_slash.test.ts @@ -68,8 +68,8 @@ describe('e2e_p2p_valid_epoch_pruned_slash', () => { }, }); - await t.applyBaseSnapshots(); await t.setup(); + await t.applyBaseSetup(); }); afterEach(async () => { diff --git a/yarn-project/end-to-end/src/e2e_p2p/validators_sentinel.test.ts b/yarn-project/end-to-end/src/e2e_p2p/validators_sentinel.test.ts index 5ffae3209862..0b62ad197753 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/validators_sentinel.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/validators_sentinel.test.ts @@ -53,8 +53,8 @@ describe('e2e_p2p_validators_sentinel', () => { }, }); - await t.applyBaseSnapshots(); await t.setup(); + await t.applyBaseSetup(); nodes = await createNodes( t.ctx.aztecNodeConfig, diff --git a/yarn-project/end-to-end/src/e2e_prover/client.test.ts b/yarn-project/end-to-end/src/e2e_prover/client.test.ts index ae0236853b0d..3a800e7e0cba 100644 --- a/yarn-project/end-to-end/src/e2e_prover/client.test.ts +++ b/yarn-project/end-to-end/src/e2e_prover/client.test.ts @@ -28,8 +28,6 @@ describe('client_prover', () => { beforeAll(async () => { t.logger.warn(`Running suite with ${REAL_PROOFS ? 'real' : 'fake'} proofs`); - await t.applyBaseSnapshots(); - await t.applyMintSnapshot(); await t.setup(); ({ provenAsset, accounts, logger, wallet } = t); diff --git a/yarn-project/end-to-end/src/e2e_prover/full.test.ts b/yarn-project/end-to-end/src/e2e_prover/full.test.ts index d32a2ce043ed..bf0015a3d215 100644 --- a/yarn-project/end-to-end/src/e2e_prover/full.test.ts +++ b/yarn-project/end-to-end/src/e2e_prover/full.test.ts @@ -4,7 +4,7 @@ import { waitForProven } from '@aztec/aztec.js/contracts'; import { Tx, TxReceipt, TxStatus } from '@aztec/aztec.js/tx'; import { RollupContract } from '@aztec/ethereum/contracts'; import type { ExtendedViemWalletClient } from '@aztec/ethereum/types'; -import { BlockNumber } from '@aztec/foundation/branded-types'; +import { CheckpointNumber } from '@aztec/foundation/branded-types'; import { parseBooleanEnv } from '@aztec/foundation/config'; import { getTestData, isGenerateTestDataEnabled } from '@aztec/foundation/testing'; import { updateProtocolCircuitSampleInputs } from '@aztec/foundation/testing/files'; @@ -42,8 +42,6 @@ describe('full_prover', () => { beforeAll(async () => { t.logger.warn(`Running suite with ${REAL_PROOFS ? 'real' : 'fake'} proofs`); - await t.applyBaseSnapshots(); - await t.applyMintSnapshot(); await t.setup(); ({ provenAsset, accounts, tokenSim, logger, cheatCodes, provenWallet, aztecNode } = t); @@ -158,13 +156,17 @@ describe('full_prover', () => { expect(rewardsAfterProver).toBeGreaterThan(rewardsBeforeProver); const reward = await rollup.getCheckpointReward(); - const newProvenBlockNumber = Number(newProvenCheckpointNumber); - const fees = ( - await Promise.all([ - t.aztecNode.getBlock(BlockNumber(newProvenBlockNumber - 1)), - t.aztecNode.getBlock(BlockNumber(newProvenBlockNumber)), - ]) - ).map(b => b!.header.totalFees.toBigInt()); + + // Get all checkpoints that were proven in this epoch + const numCheckpointsProven = Number(newProvenCheckpointNumber) - Number(oldProvenCheckpointNumber); + const publishedCheckpoints = await t.aztecNode.getPublishedCheckpoints( + CheckpointNumber(Number(oldProvenCheckpointNumber) + 1), + numCheckpointsProven, + ); + + // Extract all blocks from all proven checkpoints + const allBlocks = publishedCheckpoints.flatMap(pc => pc.checkpoint.blocks); + const fees = allBlocks.map(b => b.header.totalFees.toBigInt()); const totalRewards = fees.map(fee => fee + reward).reduce((acc, reward) => acc + reward, 0n); const sequencerGain = rewardsAfterCoinbase - rewardsBeforeCoinbase; diff --git a/yarn-project/end-to-end/src/e2e_token_contract/access_control.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/access_control.test.ts index 9a009e343e30..3a249e8bedac 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/access_control.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/access_control.test.ts @@ -4,7 +4,7 @@ describe('e2e_token_contract access control', () => { const t = new TokenContractTest('access_control'); beforeAll(async () => { - await t.applyBaseSnapshots(); + t.applyBaseSnapshots(); await t.setup(); }); diff --git a/yarn-project/end-to-end/src/e2e_token_contract/burn.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/burn.test.ts index aae6c0c08362..91481b2868f3 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/burn.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/burn.test.ts @@ -9,8 +9,8 @@ describe('e2e_token_contract burn', () => { let { asset, tokenSim, wallet, adminAddress, account1Address, account2Address } = t; beforeAll(async () => { - await t.applyBaseSnapshots(); - await t.applyMintSnapshot(); + t.applyBaseSnapshots(); + t.applyMintSnapshot(); await t.setup(); // Have to destructure again to ensure we have latest refs. ({ asset, wallet, adminAddress, tokenSim, adminAddress, account1Address, account2Address } = t); diff --git a/yarn-project/end-to-end/src/e2e_token_contract/minting.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/minting.test.ts index cc26fb6f7d53..472b41547fd5 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/minting.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/minting.test.ts @@ -6,7 +6,7 @@ describe('e2e_token_contract minting', () => { let { asset, tokenSim, adminAddress, account1Address } = t; beforeAll(async () => { - await t.applyBaseSnapshots(); + t.applyBaseSnapshots(); await t.setup(); ({ asset, tokenSim, adminAddress, account1Address } = t); }); diff --git a/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts index 8904c1e69bdf..03de858af594 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts @@ -9,7 +9,7 @@ describe('e2e_token_contract private transfer recursion', () => { let { asset, wallet, adminAddress, account1Address, node } = t; beforeAll(async () => { - await t.applyBaseSnapshots(); + t.applyBaseSnapshots(); await t.setup(); ({ asset, wallet, adminAddress, account1Address, node } = t); }); diff --git a/yarn-project/end-to-end/src/e2e_token_contract/reading_constants.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/reading_constants.test.ts index aa11f767f224..a564a5610fed 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/reading_constants.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/reading_constants.test.ts @@ -7,7 +7,7 @@ describe('e2e_token_contract reading constants', () => { const { TOKEN_DECIMALS, TOKEN_NAME, TOKEN_SYMBOL } = TokenContractTest; beforeAll(async () => { - await t.applyBaseSnapshots(); + t.applyBaseSnapshots(); await t.setup(); }); diff --git a/yarn-project/end-to-end/src/e2e_token_contract/token_contract_test.ts b/yarn-project/end-to-end/src/e2e_token_contract/token_contract_test.ts index ff47d0166d92..63573c95baf4 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/token_contract_test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/token_contract_test.ts @@ -8,23 +8,24 @@ import type { TestWallet } from '@aztec/test-wallet/server'; import { jest } from '@jest/globals'; import { - type ISnapshotManager, type SubsystemsContext, - createSnapshotManager, deployAccounts, publicDeployAccounts, + setupFromFresh, + teardown, } from '../fixtures/snapshot_manager.js'; import { mintTokensToPrivate } from '../fixtures/token_utils.js'; import { TokenSimulator } from '../simulators/token_simulator.js'; -const { E2E_DATA_PATH: dataPath, METRICS_PORT: metricsPort } = process.env; +const { METRICS_PORT: metricsPort } = process.env; export class TokenContractTest { static TOKEN_NAME = 'USDC'; static TOKEN_SYMBOL = 'USD'; static TOKEN_DECIMALS = 18n; - private snapshotManager: ISnapshotManager; + context!: SubsystemsContext; logger: Logger; + metricsPort?: number; asset!: TokenContract; tokenSim!: TokenSimulator; node!: AztecNode; @@ -35,133 +36,123 @@ export class TokenContractTest { account1Address!: AztecAddress; account2Address!: AztecAddress; + private shouldApplyBaseSetup = false; + private shouldApplyMint = false; + constructor(testName: string) { this.logger = createLogger(`e2e:e2e_token_contract:${testName}`); - this.snapshotManager = createSnapshotManager(`e2e_token_contract/${testName}`, dataPath, { - metricsPort: metricsPort ? parseInt(metricsPort) : undefined, - }); + this.metricsPort = metricsPort ? parseInt(metricsPort) : undefined; + } + + /** + * Registers that base setup should be applied during setup(). + * Call this before setup() to deploy 3 accounts, publicly deploy accounts, token contract and a "bad account". + */ + applyBaseSnapshots() { + this.shouldApplyBaseSetup = true; } /** - * Adds two state shifts to snapshot manager. - * 1. Add 3 accounts. - * 2. Publicly deploy accounts, deploy token contract and a "bad account". + * Registers that mint should be applied during setup(). + * Call this before setup() to mint tokens to the admin account. */ - async applyBaseSnapshots() { + applyMintSnapshot() { + this.shouldApplyMint = true; + } + + /** + * Applies base setup: deploys 3 accounts, publicly deploys accounts, token contract and a "bad account". + */ + private async applyBaseSetup() { // Adding a timeout of 2 minutes in here such that it is propagated to the underlying tests jest.setTimeout(120_000); - await this.snapshotManager.snapshot( - '3_accounts', - deployAccounts(3, this.logger), - ({ deployedAccounts }, { wallet, aztecNode }) => { - this.node = aztecNode; - this.wallet = wallet; - [this.adminAddress, this.account1Address, this.account2Address] = deployedAccounts.map(acc => acc.address); - return Promise.resolve(); - }, - ); + this.logger.info('Applying base setup - deploying 3 accounts'); + const { deployedAccounts } = await deployAccounts( + 3, + this.logger, + )({ + wallet: this.context.wallet, + initialFundedAccounts: this.context.initialFundedAccounts, + }); - await this.snapshotManager.snapshot( - 'e2e_token_contract', - async () => { - // Create the token contract state. - // Move this account thing to addAccounts above? - this.logger.verbose(`Public deploy accounts...`); - await publicDeployAccounts(this.wallet, [this.adminAddress, this.account1Address]); - - this.logger.verbose(`Deploying TokenContract...`); - const asset = await TokenContract.deploy( - this.wallet, - this.adminAddress, - TokenContractTest.TOKEN_NAME, - TokenContractTest.TOKEN_SYMBOL, - TokenContractTest.TOKEN_DECIMALS, - ) - .send({ from: this.adminAddress }) - .deployed(); - this.logger.verbose(`Token deployed to ${asset.address}`); - - this.logger.verbose(`Deploying bad account...`); - this.badAccount = await InvalidAccountContract.deploy(this.wallet).send({ from: this.adminAddress }).deployed(); - this.logger.verbose(`Deployed to ${this.badAccount.address}.`); - - return { tokenContractAddress: asset.address, badAccountAddress: this.badAccount.address }; - }, - async ({ tokenContractAddress, badAccountAddress }) => { - // Restore the token contract state. - this.asset = TokenContract.at(tokenContractAddress, this.wallet); - this.logger.verbose(`Token contract address: ${this.asset.address}`); - - this.tokenSim = new TokenSimulator(this.asset, this.wallet, this.adminAddress, this.logger, [ - this.adminAddress, - this.account1Address, - ]); - - this.badAccount = InvalidAccountContract.at(badAccountAddress, this.wallet); - this.logger.verbose(`Bad account address: ${this.badAccount.address}`); - - expect(await this.asset.methods.get_admin().simulate({ from: this.adminAddress })).toBe( - this.adminAddress.toBigInt(), - ); - }, + this.node = this.context.aztecNode; + this.wallet = this.context.wallet; + [this.adminAddress, this.account1Address, this.account2Address] = deployedAccounts.map(acc => acc.address); + + this.logger.info('Applying base setup - deploying token contract'); + this.logger.verbose(`Public deploy accounts...`); + await publicDeployAccounts(this.wallet, [this.adminAddress, this.account1Address]); + + this.logger.verbose(`Deploying TokenContract...`); + this.asset = await TokenContract.deploy( + this.wallet, + this.adminAddress, + TokenContractTest.TOKEN_NAME, + TokenContractTest.TOKEN_SYMBOL, + TokenContractTest.TOKEN_DECIMALS, + ) + .send({ from: this.adminAddress }) + .deployed(); + this.logger.verbose(`Token deployed to ${this.asset.address}`); + + this.logger.verbose(`Deploying bad account...`); + this.badAccount = await InvalidAccountContract.deploy(this.wallet).send({ from: this.adminAddress }).deployed(); + this.logger.verbose(`Deployed to ${this.badAccount.address}.`); + + this.tokenSim = new TokenSimulator(this.asset, this.wallet, this.adminAddress, this.logger, [ + this.adminAddress, + this.account1Address, + ]); + + expect(await this.asset.methods.get_admin().simulate({ from: this.adminAddress })).toBe( + this.adminAddress.toBigInt(), ); - - // TokenContract.artifact.functions.forEach(fn => { - // const sig = decodeFunctionSignature(fn.name, fn.parameters); - // logger.verbose(`Function ${sig} and the selector: ${FunctionSelector.fromNameAndParameters(fn.name, fn.parameters)}`); - // }); } async setup() { - await this.snapshotManager.setup(); - } + this.context = await setupFromFresh(this.logger, { + metricsPort: this.metricsPort, + }); - snapshot = ( - name: string, - apply: (context: SubsystemsContext) => Promise, - restore: (snapshotData: T, context: SubsystemsContext) => Promise = () => Promise.resolve(), - ): Promise => this.snapshotManager.snapshot(name, apply, restore); + if (this.shouldApplyBaseSetup) { + await this.applyBaseSetup(); + } + + if (this.shouldApplyMint) { + await this.applyMint(); + } + } async teardown() { - await this.snapshotManager.teardown(); + await teardown(this.context); } - async applyMintSnapshot() { - await this.snapshotManager.snapshot( - 'mint', - async () => { - const { asset, adminAddress } = this; - const amount = 10000n; - - this.logger.verbose(`Minting ${amount} publicly...`); - await asset.methods.mint_to_public(adminAddress, amount).send({ from: adminAddress }).wait(); - - this.logger.verbose(`Minting ${amount} privately...`); - await mintTokensToPrivate(asset, adminAddress, adminAddress, amount); - this.logger.verbose(`Minting complete.`); - - return { amount }; - }, - async ({ amount }) => { - const { asset, adminAddress, tokenSim } = this; - tokenSim.mintPublic(adminAddress, amount); - - const publicBalance = await asset.methods.balance_of_public(adminAddress).simulate({ from: adminAddress }); - this.logger.verbose(`Public balance of wallet 0: ${publicBalance}`); - expect(publicBalance).toEqual(this.tokenSim.balanceOfPublic(adminAddress)); - - tokenSim.mintPrivate(adminAddress, amount); - const privateBalance = await asset.methods.balance_of_private(adminAddress).simulate({ from: adminAddress }); - this.logger.verbose(`Private balance of wallet 0: ${privateBalance}`); - expect(privateBalance).toEqual(tokenSim.balanceOfPrivate(adminAddress)); - - const totalSupply = await asset.methods.total_supply().simulate({ from: adminAddress }); - this.logger.verbose(`Total supply: ${totalSupply}`); - expect(totalSupply).toEqual(tokenSim.totalSupply); - - return Promise.resolve(); - }, - ); + private async applyMint() { + this.logger.info('Applying mint setup'); + const { asset, adminAddress, tokenSim } = this; + const amount = 10000n; + + this.logger.verbose(`Minting ${amount} publicly...`); + await asset.methods.mint_to_public(adminAddress, amount).send({ from: adminAddress }).wait(); + tokenSim.mintPublic(adminAddress, amount); + + const publicBalance = await asset.methods.balance_of_public(adminAddress).simulate({ from: adminAddress }); + this.logger.verbose(`Public balance of wallet 0: ${publicBalance}`); + expect(publicBalance).toEqual(this.tokenSim.balanceOfPublic(adminAddress)); + + this.logger.verbose(`Minting ${amount} privately...`); + await mintTokensToPrivate(asset, adminAddress, adminAddress, amount); + tokenSim.mintPrivate(adminAddress, amount); + + const privateBalance = await asset.methods.balance_of_private(adminAddress).simulate({ from: adminAddress }); + this.logger.verbose(`Private balance of wallet 0: ${privateBalance}`); + expect(privateBalance).toEqual(tokenSim.balanceOfPrivate(adminAddress)); + + const totalSupply = await asset.methods.total_supply().simulate({ from: adminAddress }); + this.logger.verbose(`Total supply: ${totalSupply}`); + expect(totalSupply).toEqual(tokenSim.totalSupply); + + this.logger.verbose(`Minting complete.`); } } diff --git a/yarn-project/end-to-end/src/e2e_token_contract/transfer.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/transfer.test.ts index 8364fe59f54f..cef22988d725 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/transfer.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/transfer.test.ts @@ -9,8 +9,8 @@ describe('e2e_token_contract transfer private', () => { let { asset, adminAddress, wallet, account1Address, tokenSim } = t; beforeAll(async () => { - await t.applyBaseSnapshots(); - await t.applyMintSnapshot(); + t.applyBaseSnapshots(); + t.applyMintSnapshot(); await t.setup(); ({ asset, adminAddress, wallet, account1Address, tokenSim } = t); }); diff --git a/yarn-project/end-to-end/src/e2e_token_contract/transfer_in_private.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/transfer_in_private.test.ts index f353e4a72e85..e0012bbe6f76 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/transfer_in_private.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/transfer_in_private.test.ts @@ -9,8 +9,8 @@ describe('e2e_token_contract transfer private', () => { let { asset, tokenSim, wallet, adminAddress, account1Address, account2Address, badAccount } = t; beforeAll(async () => { - await t.applyBaseSnapshots(); - await t.applyMintSnapshot(); + t.applyBaseSnapshots(); + t.applyMintSnapshot(); await t.setup(); ({ asset, tokenSim, wallet, adminAddress, account1Address, account2Address, badAccount } = t); }); diff --git a/yarn-project/end-to-end/src/e2e_token_contract/transfer_in_public.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/transfer_in_public.test.ts index 760a59d81e0e..1c3df67965c9 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/transfer_in_public.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/transfer_in_public.test.ts @@ -23,8 +23,8 @@ describe('e2e_token_contract transfer public', () => { let { asset, tokenSim, wallet, adminAddress, account1Address, badAccount } = t; beforeAll(async () => { - await t.applyBaseSnapshots(); - await t.applyMintSnapshot(); + t.applyBaseSnapshots(); + t.applyMintSnapshot(); await t.setup(); // Have to destructure again to ensure we have latest refs. ({ asset, tokenSim, wallet, adminAddress, account1Address, badAccount } = t); diff --git a/yarn-project/end-to-end/src/e2e_token_contract/transfer_to_private.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/transfer_to_private.test.ts index 91a291507c3d..88350c985e9b 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/transfer_to_private.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/transfer_to_private.test.ts @@ -6,8 +6,8 @@ describe('e2e_token_contract transfer_to_private', () => { let { asset, adminAddress, account1Address, tokenSim } = t; beforeAll(async () => { - await t.applyBaseSnapshots(); - await t.applyMintSnapshot(); + t.applyBaseSnapshots(); + t.applyMintSnapshot(); await t.setup(); // Have to destructure again to ensure we have latest refs. ({ asset, adminAddress, account1Address, tokenSim } = t); diff --git a/yarn-project/end-to-end/src/e2e_token_contract/transfer_to_public.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/transfer_to_public.test.ts index d76d82f4e9b4..0e867f10402a 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/transfer_to_public.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/transfer_to_public.test.ts @@ -9,8 +9,8 @@ describe('e2e_token_contract transfer_to_public', () => { let { asset, wallet, adminAddress, account1Address, account2Address, tokenSim } = t; beforeAll(async () => { - await t.applyBaseSnapshots(); - await t.applyMintSnapshot(); + t.applyBaseSnapshots(); + t.applyMintSnapshot(); await t.setup(); // Have to destructure again to ensure we have latest refs. ({ asset, wallet, adminAddress, account1Address, account2Address, tokenSim } = t); diff --git a/yarn-project/end-to-end/src/fixtures/e2e_prover_test.ts b/yarn-project/end-to-end/src/fixtures/e2e_prover_test.ts index 7824106b8ff2..853f05f59677 100644 --- a/yarn-project/end-to-end/src/fixtures/e2e_prover_test.ts +++ b/yarn-project/end-to-end/src/fixtures/e2e_prover_test.ts @@ -30,16 +30,14 @@ import { TokenSimulator } from '../simulators/token_simulator.js'; import { getACVMConfig } from './get_acvm_config.js'; import { getBBConfig } from './get_bb_config.js'; import { - type ISnapshotManager, type SubsystemsContext, - createSnapshotManager, deployAccounts, publicDeployAccounts, + setupFromFresh, + teardown, } from './snapshot_manager.js'; import { getPrivateKeyFromIndex, getSponsoredFPCAddress, setupPXEAndGetWallet } from './utils.js'; -const { E2E_DATA_PATH: dataPath } = process.env; - type ProvenSetup = { wallet: TestWallet; teardown: () => Promise; @@ -56,7 +54,6 @@ export class FullProverTest { static TOKEN_NAME = 'USDC'; static TOKEN_SYMBOL = 'USD'; static TOKEN_DECIMALS = 18n; - private snapshotManager: ISnapshotManager; logger: Logger; wallet!: TestWallet; provenWallet!: TestWallet; @@ -73,91 +70,76 @@ export class FullProverTest { private acvmConfigCleanup?: () => Promise; circuitProofVerifier?: ClientProtocolCircuitVerifier; provenAsset!: TokenContract; - private context!: SubsystemsContext; + context!: SubsystemsContext; private proverNode!: ProverNode; private simulatedProverNode!: ProverNode; public l1Contracts!: DeployAztecL1ContractsReturnType; public proverAddress!: EthAddress; + private minNumberOfTxsPerBlock: number; + private coinbase: EthAddress; + private realProofs: boolean; - constructor( - testName: string, - private minNumberOfTxsPerBlock: number, - coinbase: EthAddress, - private realProofs = true, - ) { + constructor(testName: string, minNumberOfTxsPerBlock: number, coinbase: EthAddress, realProofs = true) { this.logger = createLogger(`e2e:full_prover_test:${testName}`); - this.snapshotManager = createSnapshotManager( - `full_prover_integration/${testName}`, - dataPath, - { startProverNode: true, coinbase }, - { - realVerifier: realProofs, - }, - ); + this.minNumberOfTxsPerBlock = minNumberOfTxsPerBlock; + this.coinbase = coinbase; + this.realProofs = realProofs; } /** - * Adds two state shifts to snapshot manager. - * 1. Add 2 accounts. - * 2. Publicly deploy accounts, deploy token contract + * Applies base setup: deploys 2 accounts and token contract. */ - async applyBaseSnapshots() { - await this.snapshotManager.snapshot( - '2_accounts', - deployAccounts(2, this.logger), - ({ deployedAccounts }, { wallet }) => { - this.deployedAccounts = deployedAccounts; - this.accounts = deployedAccounts.map(a => a.address); - this.wallet = wallet; - return Promise.resolve(); - }, - ); - - await this.snapshotManager.snapshot( - 'client_prover_integration', - async () => { - // Create the token contract state. - // Move this account thing to addAccounts above? - this.logger.verbose(`Public deploy accounts...`); - await publicDeployAccounts(this.wallet, this.accounts.slice(0, 2)); - - this.logger.verbose(`Deploying TokenContract...`); - const { contract: asset, instance } = await TokenContract.deploy( - this.wallet, - this.accounts[0], - FullProverTest.TOKEN_NAME, - FullProverTest.TOKEN_SYMBOL, - FullProverTest.TOKEN_DECIMALS, - ) - .send({ from: this.accounts[0] }) - .wait(); - this.logger.verbose(`Token deployed to ${asset.address}`); - - return { tokenContractAddress: asset.address, tokenContractInstance: instance }; - }, - async ({ tokenContractAddress, tokenContractInstance }) => { - // Restore the token contract state. - this.fakeProofsAsset = TokenContract.at(tokenContractAddress, this.wallet); - this.fakeProofsAssetInstance = tokenContractInstance; - this.logger.verbose(`Token contract address: ${this.fakeProofsAsset.address}`); - - this.tokenSim = new TokenSimulator( - this.fakeProofsAsset, - this.wallet, - this.accounts[0], - this.logger, - this.accounts, - ); - - expect(await this.fakeProofsAsset.methods.get_admin().simulate({ from: this.accounts[0] })).toBe( - this.accounts[0].toBigInt(), - ); - }, + private async applyBaseSetup() { + this.logger.info('Applying base setup: deploying accounts'); + const { deployedAccounts } = await deployAccounts( + 2, + this.logger, + )({ + wallet: this.context.wallet, + initialFundedAccounts: this.context.initialFundedAccounts, + }); + this.deployedAccounts = deployedAccounts; + this.accounts = deployedAccounts.map(a => a.address); + this.wallet = this.context.wallet; + + this.logger.info('Applying base setup: publicly deploying accounts'); + await publicDeployAccounts(this.wallet, this.accounts.slice(0, 2)); + + this.logger.info('Applying base setup: deploying token contract'); + const { contract: asset, instance } = await TokenContract.deploy( + this.wallet, + this.accounts[0], + FullProverTest.TOKEN_NAME, + FullProverTest.TOKEN_SYMBOL, + FullProverTest.TOKEN_DECIMALS, + ) + .send({ from: this.accounts[0] }) + .wait(); + this.logger.verbose(`Token deployed to ${asset.address}`); + + this.fakeProofsAsset = asset; + this.fakeProofsAssetInstance = instance; + this.logger.verbose(`Token contract address: ${this.fakeProofsAsset.address}`); + + this.tokenSim = new TokenSimulator(this.fakeProofsAsset, this.wallet, this.accounts[0], this.logger, this.accounts); + + expect(await this.fakeProofsAsset.methods.get_admin().simulate({ from: this.accounts[0] })).toBe( + this.accounts[0].toBigInt(), ); } async setup() { - this.context = await this.snapshotManager.setup(); + this.logger.info('Setting up subsystems from fresh'); + this.context = await setupFromFresh( + this.logger, + { startProverNode: true, coinbase: this.coinbase }, + { realVerifier: this.realProofs }, + ); + + await this.applyBaseSetup(); + await this.applyMint(); + + this.logger.info(`Enabling proving`, { realProofs: this.realProofs }); // We don't wish to mark as proven automatically, so we set the flag to false this.context.watcher.setIsMarkingAsProven(false); @@ -286,7 +268,7 @@ export class FullProverTest { ); await this.proverNode.start(); - this.logger.warn(`Proofs are now enabled`); + this.logger.warn(`Proofs are now enabled`, { realProofs: this.realProofs }); return this; } @@ -299,15 +281,7 @@ export class FullProverTest { await this.context.deployL1ContractsValues.l1Client.waitForTransactionReceipt({ hash }); } - snapshot = ( - name: string, - apply: (context: SubsystemsContext) => Promise, - restore: (snapshotData: T, context: SubsystemsContext) => Promise = () => Promise.resolve(), - ): Promise => this.snapshotManager.snapshot(name, apply, restore); - async teardown() { - await this.snapshotManager.teardown(); - // Cleanup related to the full prover PXEs for (let i = 0; i < this.provenComponents.length; i++) { await this.provenComponents[i].teardown(); @@ -319,52 +293,45 @@ export class FullProverTest { await Barretenberg.destroySingleton(); await this.bbConfigCleanup?.(); await this.acvmConfigCleanup?.(); - } - - async applyMintSnapshot() { - await this.snapshotManager.snapshot( - 'mint', - async () => { - const { fakeProofsAsset: asset, accounts } = this; - const privateAmount = 10000n; - const publicAmount = 10000n; - - this.logger.verbose(`Minting ${privateAmount + publicAmount} publicly...`); - await asset.methods - .mint_to_public(accounts[0], privateAmount + publicAmount) - .send({ from: accounts[0] }) - .wait(); - this.logger.verbose(`Transferring ${privateAmount} to private...`); - await asset.methods.transfer_to_private(accounts[0], privateAmount).send({ from: accounts[0] }).wait(); - - this.logger.verbose(`Minting complete.`); + await teardown(this.context); + } - return { amount: publicAmount }; - }, - async ({ amount }) => { - const { - fakeProofsAsset: asset, - accounts: [address], - tokenSim, - } = this; - tokenSim.mintPublic(address, amount); - - const publicBalance = await asset.methods.balance_of_public(address).simulate({ from: address }); - this.logger.verbose(`Public balance of wallet 0: ${publicBalance}`); - expect(publicBalance).toEqual(this.tokenSim.balanceOfPublic(address)); - - tokenSim.mintPrivate(address, amount); - const privateBalance = await asset.methods.balance_of_private(address).simulate({ from: address }); - this.logger.verbose(`Private balance of wallet 0: ${privateBalance}`); - expect(privateBalance).toEqual(tokenSim.balanceOfPrivate(address)); - - const totalSupply = await asset.methods.total_supply().simulate({ from: address }); - this.logger.verbose(`Total supply: ${totalSupply}`); - expect(totalSupply).toEqual(tokenSim.totalSupply); - - return Promise.resolve(); - }, - ); + private async applyMint() { + this.logger.info('Applying mint setup'); + const { fakeProofsAsset: asset, accounts } = this; + const privateAmount = 10000n; + const publicAmount = 10000n; + + this.logger.verbose(`Minting ${privateAmount + publicAmount} publicly...`); + await asset.methods + .mint_to_public(accounts[0], privateAmount + publicAmount) + .send({ from: accounts[0] }) + .wait(); + + this.logger.verbose(`Transferring ${privateAmount} to private...`); + await asset.methods.transfer_to_private(accounts[0], privateAmount).send({ from: accounts[0] }).wait(); + + this.logger.info(`Minting complete`); + + const { + fakeProofsAsset, + accounts: [address], + tokenSim, + } = this; + tokenSim.mintPublic(address, publicAmount); + + const publicBalance = await fakeProofsAsset.methods.balance_of_public(address).simulate({ from: address }); + this.logger.verbose(`Public balance of wallet 0: ${publicBalance}`); + expect(publicBalance).toEqual(this.tokenSim.balanceOfPublic(address)); + + tokenSim.mintPrivate(address, publicAmount); + const privateBalance = await fakeProofsAsset.methods.balance_of_private(address).simulate({ from: address }); + this.logger.verbose(`Private balance of wallet 0: ${privateBalance}`); + expect(privateBalance).toEqual(tokenSim.balanceOfPrivate(address)); + + const totalSupply = await fakeProofsAsset.methods.total_supply().simulate({ from: address }); + this.logger.verbose(`Total supply: ${totalSupply}`); + expect(totalSupply).toEqual(tokenSim.totalSupply); } } diff --git a/yarn-project/end-to-end/src/fixtures/snapshot_manager.ts b/yarn-project/end-to-end/src/fixtures/snapshot_manager.ts index e7057de0a7ee..f283ddd754d7 100644 --- a/yarn-project/end-to-end/src/fixtures/snapshot_manager.ts +++ b/yarn-project/end-to-end/src/fixtures/snapshot_manager.ts @@ -18,12 +18,9 @@ import { deployAztecL1Contracts, } from '@aztec/ethereum/deploy-aztec-l1-contracts'; import { EthCheatCodesWithState, startAnvil } from '@aztec/ethereum/test'; -import { asyncMap } from '@aztec/foundation/async-map'; import { SecretValue } from '@aztec/foundation/config'; import { randomBytes } from '@aztec/foundation/crypto/random'; import { tryRmDir } from '@aztec/foundation/fs'; -import { createLogger } from '@aztec/foundation/log'; -import { resolver, reviver } from '@aztec/foundation/serialize'; import { TestDateProvider } from '@aztec/foundation/timer'; import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree'; import { protocolContractsHash } from '@aztec/protocol-contracts'; @@ -31,17 +28,13 @@ import type { ProverNode } from '@aztec/prover-node'; import { getPXEConfig } from '@aztec/pxe/server'; import type { SequencerClient } from '@aztec/sequencer-client'; import { tryStop } from '@aztec/stdlib/interfaces/server'; -import { getConfigEnvVars as getTelemetryConfig, initTelemetryClient } from '@aztec/telemetry-client'; import { TestWallet } from '@aztec/test-wallet/server'; import { getGenesisValues } from '@aztec/world-state/testing'; import type { Anvil } from '@viem/anvil'; -import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'; -import { copySync, removeSync } from 'fs-extra/esm'; import fs from 'fs/promises'; import { tmpdir } from 'os'; -import path, { join } from 'path'; -import type { Hex } from 'viem'; +import path from 'path'; import { mnemonicToAccount } from 'viem/accounts'; import { foundry } from 'viem/chains'; @@ -75,192 +68,10 @@ export type SubsystemsContext = { directoryToCleanup?: string; }; -type SnapshotEntry = { - name: string; - apply: (context: SubsystemsContext) => Promise; - restore: (snapshotData: any, context: SubsystemsContext) => Promise; - snapshotPath: string; -}; - -export function createSnapshotManager( - testName: string, - dataPath?: string, - config: Partial = {}, - deployL1ContractsArgs: Partial = { - initialValidators: [], - }, -) { - return dataPath - ? new SnapshotManager(testName, dataPath, config, deployL1ContractsArgs) - : new MockSnapshotManager(testName, config, deployL1ContractsArgs); -} - -export interface ISnapshotManager { - snapshot( - name: string, - apply: (context: SubsystemsContext) => Promise, - restore?: (snapshotData: T, context: SubsystemsContext) => Promise, - ): Promise; - - setup(): Promise; - - teardown(): Promise; -} - -/** Snapshot manager that does not perform snapshotting, it just applies transition and restoration functions as it receives them. */ -class MockSnapshotManager implements ISnapshotManager { - private context?: SubsystemsContext; - private logger: Logger; - - constructor( - testName: string, - private config: Partial = {}, - private deployL1ContractsArgs: Partial = {}, - ) { - this.logger = createLogger(`e2e:snapshot_manager:${testName}`); - this.logger.warn(`No data path given, will not persist any snapshots.`); - } - - public async snapshot( - name: string, - apply: (context: SubsystemsContext) => Promise, - restore: (snapshotData: T, context: SubsystemsContext) => Promise = () => Promise.resolve(), - ) { - // We are running in disabled mode. Just apply the state. - const context = await this.setup(); - this.logger.verbose(`Applying state transition for ${name}...`); - const snapshotData = await apply(context); - this.logger.verbose(`State transition for ${name} complete.`); - // Execute the restoration function. - await restore(snapshotData, context); - return; - } - - public async setup() { - if (!this.context) { - this.context = await setupFromFresh(undefined, this.logger, this.config, this.deployL1ContractsArgs); - } - return this.context; - } - - public async teardown() { - await teardown(this.context); - this.context = undefined; - } -} - -/** - * Snapshot engine for local e2e tests. Read more: - * https://github.com/AztecProtocol/aztec-packages/pull/5526 - */ -class SnapshotManager implements ISnapshotManager { - private snapshotStack: SnapshotEntry[] = []; - private context?: SubsystemsContext; - private livePath: string; - private logger: Logger; - - constructor( - testName: string, - private dataPath: string, - private config: Partial = {}, - private deployL1ContractsArgs: Partial = {}, - ) { - this.livePath = join(this.dataPath, 'live', testName); - this.logger = createLogger(`e2e:snapshot_manager:${testName}`); - } - - public async snapshot( - name: string, - apply: (context: SubsystemsContext) => Promise, - restore: (snapshotData: T, context: SubsystemsContext) => Promise = () => Promise.resolve(), - ) { - const snapshotPath = join(this.dataPath, 'snapshots', ...this.snapshotStack.map(e => e.name), name, 'snapshot'); - - if (existsSync(snapshotPath)) { - // Snapshot exists. Record entry on stack but do nothing else as we're probably still descending the tree. - // It's the tests responsibility to call setup() before a test to ensure subsystems get created. - this.logger.verbose(`Snapshot exists at ${snapshotPath}. Continuing...`); - this.snapshotStack.push({ name, apply, restore, snapshotPath }); - return; - } - - // Snapshot didn't exist at snapshotPath, and by definition none of the child snapshots can exist. - // If we have no subsystem context yet, create it from the top of the snapshot stack (if it exists). - const context = await this.setup(); - - this.snapshotStack.push({ name, apply, restore, snapshotPath }); - - // Apply current state transition. - this.logger.verbose(`Applying state transition for ${name}...`); - const snapshotData = await apply(context); - this.logger.verbose(`State transition for ${name} complete.`); - - // Execute the restoration function. - await restore(snapshotData, context); - - // Save the snapshot data. - const ethCheatCodes = new EthCheatCodesWithState(context.aztecNodeConfig.l1RpcUrls, context.dateProvider); - const anvilStateFile = `${this.livePath}/anvil.dat`; - await ethCheatCodes.dumpChainState(anvilStateFile); - writeFileSync(`${this.livePath}/${name}.json`, JSON.stringify(snapshotData || {}, resolver)); - - // Copy everything to snapshot path. - // We want it to be atomic, in case multiple processes are racing to create the snapshot. - this.logger.verbose(`Saving snapshot to ${snapshotPath}...`); - if (mkdirSync(snapshotPath, { recursive: true })) { - copySync(this.livePath, snapshotPath); - this.logger.verbose(`Snapshot copied to ${snapshotPath}.`); - } else { - this.logger.verbose(`Snapshot already exists at ${snapshotPath}. Discarding our version.`); - await this.teardown(); - } - } - - /** - * Creates and returns the subsystem context based on the current snapshot stack. - * If the subsystem context already exists, just return it. - * If you want to be sure to get a clean snapshot, be sure to call teardown() before calling setup(). - */ - public async setup() { - // We have no subsystem context yet. - // If one exists on the snapshot stack, create one from that snapshot. - // Otherwise create a fresh one. - if (!this.context) { - removeSync(this.livePath); - mkdirSync(this.livePath, { recursive: true }); - const previousSnapshotPath = this.snapshotStack[this.snapshotStack.length - 1]?.snapshotPath; - if (previousSnapshotPath) { - this.logger.verbose(`Copying snapshot from ${previousSnapshotPath} to ${this.livePath}...`); - copySync(previousSnapshotPath, this.livePath); - this.context = await setupFromState(this.livePath, this.logger); - // Execute each of the previous snapshots restoration functions in turn. - await asyncMap(this.snapshotStack, async e => { - const snapshotData = JSON.parse(readFileSync(`${e.snapshotPath}/${e.name}.json`, 'utf-8'), reviver); - this.logger.verbose(`Executing restoration function for ${e.name}...`); - await e.restore(snapshotData, this.context!); - this.logger.verbose(`Restoration of ${e.name} complete.`); - }); - } else { - this.context = await setupFromFresh(this.livePath, this.logger, this.config, this.deployL1ContractsArgs); - } - } - return this.context; - } - - /** - * Destroys the current subsystem context. - */ - public async teardown() { - await teardown(this.context); - this.context = undefined; - removeSync(this.livePath); - } -} - /** * Destroys the current subsystem context. */ -async function teardown(context: SubsystemsContext | undefined) { +export async function teardown(context: SubsystemsContext | undefined) { if (!context) { return; } @@ -281,11 +92,9 @@ async function teardown(context: SubsystemsContext | undefined) { /** * Initializes a fresh set of subsystems. - * If given a statePath, the state will be written to the path. - * If there is no statePath, in-memory and temporary state locations will be used. + * State is stored in temporary in-memory locations. */ -async function setupFromFresh( - statePath: string | undefined, +export async function setupFromFresh( logger: Logger, { numberOfInitialFundedAccounts = 10, ...opts }: SetupOptions = {}, deployL1ContractsArgs: Partial = { @@ -316,11 +125,7 @@ async function setupFromFresh( // Create a temp directory for all ephemeral state and cleanup afterwards const directoryToCleanup = path.join(tmpdir(), randomBytes(8).toString('hex')); await fs.mkdir(directoryToCleanup, { recursive: true }); - if (statePath === undefined) { - aztecNodeConfig.dataDirectory = directoryToCleanup; - } else { - aztecNodeConfig.dataDirectory = statePath; - } + aztecNodeConfig.dataDirectory = directoryToCleanup; await setupSharedBlobStorage(aztecNodeConfig); @@ -434,17 +239,12 @@ async function setupFromFresh( logger.verbose('Creating pxe...'); const pxeConfig = getPXEConfig(); - pxeConfig.dataDirectory = statePath ?? path.join(directoryToCleanup, randomBytes(8).toString('hex')); + pxeConfig.dataDirectory = path.join(directoryToCleanup, randomBytes(8).toString('hex')); // Only enable proving if specifically requested. pxeConfig.proverEnabled = !!opts.realProofs; const wallet = await TestWallet.create(aztecNode, pxeConfig); const cheatCodes = await CheatCodes.create(aztecNodeConfig.l1RpcUrls, aztecNode, dateProvider); - if (statePath) { - writeFileSync(`${statePath}/aztec_node_config.json`, JSON.stringify(aztecNodeConfig, resolver)); - writeFileSync(`${statePath}/accounts.json`, JSON.stringify(initialFundedAccounts, resolver)); - } - return { aztecNodeConfig, anvil, @@ -464,120 +264,8 @@ async function setupFromFresh( } /** - * Given a statePath, setup the system starting from that state. - */ -async function setupFromState(statePath: string, logger: Logger): Promise { - logger.verbose(`Initializing with saved state at ${statePath}...`); - - const directoryToCleanup = path.join(tmpdir(), randomBytes(8).toString('hex')); - await fs.mkdir(directoryToCleanup, { recursive: true }); - - // TODO: For some reason this is currently the union of a bunch of subsystems. That needs fixing. - const aztecNodeConfig: AztecNodeConfig & SetupOptions = JSON.parse( - readFileSync(`${statePath}/aztec_node_config.json`, 'utf-8'), - reviver, - ); - aztecNodeConfig.dataDirectory = statePath; - aztecNodeConfig.listenAddress = '127.0.0.1'; - - await setupSharedBlobStorage(aztecNodeConfig); - - const initialFundedAccounts: InitialAccountData[] = - JSON.parse(readFileSync(`${statePath}/accounts.json`, 'utf-8'), reviver) || []; - const { prefilledPublicData } = await getGenesisValues(initialFundedAccounts.map(a => a.address)); - - // Start anvil. We go via a wrapper script to ensure if the parent dies, anvil dies. - const { anvil, rpcUrl } = await startAnvil(); - aztecNodeConfig.l1RpcUrls = [rpcUrl]; - // Load anvil state. - const anvilStateFile = `${statePath}/anvil.dat`; - - const dateProvider = new TestDateProvider(); - const ethCheatCodes = new EthCheatCodesWithState(aztecNodeConfig.l1RpcUrls, dateProvider); - await ethCheatCodes.loadChainState(anvilStateFile); - - // TODO: Encapsulate this in a NativeAcvm impl. - const acvmConfig = await getACVMConfig(logger); - if (acvmConfig) { - aztecNodeConfig.acvmWorkingDirectory = acvmConfig.acvmWorkingDirectory; - aztecNodeConfig.acvmBinaryPath = acvmConfig.acvmBinaryPath; - } - - const bbConfig = await getBBConfig(logger); - if (bbConfig) { - aztecNodeConfig.bbBinaryPath = bbConfig.bbBinaryPath; - aztecNodeConfig.bbWorkingDirectory = bbConfig.bbWorkingDirectory; - } - - logger.verbose('Creating ETH clients...'); - const l1Client = createExtendedL1Client(aztecNodeConfig.l1RpcUrls, mnemonicToAccount(MNEMONIC)); - - const watcher = new AnvilTestWatcher( - ethCheatCodes, - aztecNodeConfig.l1Contracts.rollupAddress, - l1Client, - dateProvider, - ); - await watcher.start(); - - const telemetry = await initTelemetryClient(getTelemetryConfig()); - - logger.verbose('Creating aztec node...'); - const aztecNode = await AztecNodeService.createAndSync( - aztecNodeConfig, - { telemetry, dateProvider }, - { prefilledPublicData }, - ); - - let proverNode: ProverNode | undefined = undefined; - if (aztecNodeConfig.startProverNode) { - logger.verbose('Creating and syncing a simulated prover node...'); - const proverNodePrivateKey = getPrivateKeyFromIndex(2); - const proverNodePrivateKeyHex: Hex = `0x${proverNodePrivateKey!.toString('hex')}`; - proverNode = await createAndSyncProverNode( - proverNodePrivateKeyHex, - aztecNodeConfig, - { - ...aztecNodeConfig.proverNodeConfig, - dataDirectory: path.join(directoryToCleanup, randomBytes(8).toString('hex')), - p2pEnabled: false, - }, - aztecNode, - prefilledPublicData, - ); - } - - logger.verbose('Creating pxe...'); - const pxeConfig = getPXEConfig(); - pxeConfig.dataDirectory = statePath; - const wallet = await TestWallet.create(aztecNode, pxeConfig); - const cheatCodes = await CheatCodes.create(aztecNodeConfig.l1RpcUrls, aztecNode, dateProvider); - - return { - aztecNodeConfig, - anvil, - aztecNode, - wallet, - sequencer: aztecNode.getSequencer()!, - acvmConfig, - bbConfig, - proverNode, - deployL1ContractsValues: { - l1Client, - l1ContractAddresses: aztecNodeConfig.l1Contracts, - rollupVersion: aztecNodeConfig.rollupVersion, - }, - watcher, - cheatCodes, - dateProvider, - initialFundedAccounts, - directoryToCleanup, - }; -} - -/** - * Snapshot 'apply' helper function to add accounts. - * The 'restore' function is not provided, as it must be a closure within the test context to capture the results. + * Helper function to deploy accounts. + * Returns deployed account data that can be used by tests. */ export const deployAccounts = (numberOfAccounts: number, logger: Logger) =>