From aaff2f4d5ddefbb62cadefbb32e28304817b0eca Mon Sep 17 00:00:00 2001 From: Charlie Lye <5764343+charlielye@users.noreply.github.com> Date: Mon, 31 Mar 2025 10:19:21 +0000 Subject: [PATCH 1/2] trying to fix EADDRINUSE --- yarn-project/end-to-end/scripts/run_test.sh | 3 ++- yarn-project/end-to-end/src/e2e_p2p/gossip_network.test.ts | 1 + yarn-project/end-to-end/src/e2e_p2p/rediscovery.test.ts | 1 + yarn-project/end-to-end/src/e2e_p2p/reex.test.ts | 6 +++++- yarn-project/end-to-end/src/e2e_p2p/reqresp.test.ts | 1 + yarn-project/end-to-end/src/e2e_p2p/slashing.test.ts | 1 + .../src/e2e_p2p/upgrade_governance_proposer.test.ts | 1 + .../end-to-end/src/e2e_p2p/validators_sentinel.test.ts | 1 + yarn-project/ethereum/src/test/start_anvil.ts | 4 ++-- yarn-project/p2p/src/services/discv5/discv5_service.test.ts | 2 +- yarn-project/p2p/src/test-helpers/reqresp-nodes.ts | 6 +++--- 11 files changed, 19 insertions(+), 8 deletions(-) diff --git a/yarn-project/end-to-end/scripts/run_test.sh b/yarn-project/end-to-end/scripts/run_test.sh index 043b26f70c61..5ea235b9af23 100755 --- a/yarn-project/end-to-end/scripts/run_test.sh +++ b/yarn-project/end-to-end/scripts/run_test.sh @@ -40,7 +40,8 @@ case "$type" in -e LOG_LEVEL \ -e COLLECT_METRICS \ --workdir "$repo_dir/yarn-project/end-to-end" \ - aztecprotocol/build:3.0 ./scripts/test_simple.sh $TEST + aztecprotocol/build:3.0 ./scripts/test_simple.sh $TEST & + wait $! ;; "compose") # Strip leading non alpha numerics and replace / and . with _. 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 42214e8f20f1..7c64c73402a2 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 @@ -48,6 +48,7 @@ describe('e2e_p2p_network', () => { metricsPort: shouldCollectMetrics(), initialConfig: { ...SHORTENED_BLOCK_TIME_CONFIG, + listenAddress: '127.0.0.1', }, }); 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 cfd6674f1bf3..60e53f03e0a6 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 @@ -30,6 +30,7 @@ describe('e2e_p2p_rediscovery', () => { metricsPort: shouldCollectMetrics(), initialConfig: { ...SHORTENED_BLOCK_TIME_CONFIG, + listenAddress: '127.0.0.1', }, }); await t.setupAccount(); 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 32b8e624dfc3..e2ab59827aa8 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 @@ -37,7 +37,11 @@ describe('e2e_p2p_reex', () => { basePort: bootNodeUdpPort, // To collect metrics - run in aztec-packages `docker compose --profile metrics up` and set COLLECT_METRICS=true metricsPort: shouldCollectMetrics(), - initialConfig: { enforceTimeTable: true, txTimeoutMs: 30_000 }, + initialConfig: { + enforceTimeTable: true, + txTimeoutMs: 30_000, + listenAddress: '127.0.0.1', + }, }); t.logger.info('Setup account'); 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 8d95f8866901..e85dd3b0ec1f 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 @@ -32,6 +32,7 @@ describe('e2e_p2p_reqresp_tx', () => { metricsPort: shouldCollectMetrics(), initialConfig: { ...SHORTENED_BLOCK_TIME_CONFIG, + listenAddress: '127.0.0.1', }, }); await t.setupAccount(); diff --git a/yarn-project/end-to-end/src/e2e_p2p/slashing.test.ts b/yarn-project/end-to-end/src/e2e_p2p/slashing.test.ts index 47a0d6eb7d6a..dbb720f4e373 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/slashing.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/slashing.test.ts @@ -38,6 +38,7 @@ describe('e2e_p2p_slashing', () => { basePort: BOOT_NODE_UDP_PORT, metricsPort: shouldCollectMetrics(), initialConfig: { + listenAddress: '127.0.0.1', aztecEpochDuration: 1, ethereumSlotDuration: 4, aztecSlotDuration: 12, 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 64f88090b68c..4f286f5b5099 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 @@ -47,6 +47,7 @@ describe('e2e_p2p_governance_proposer', () => { metricsPort: shouldCollectMetrics(), initialConfig: { ...SHORTENED_BLOCK_TIME_CONFIG, + listenAddress: '127.0.0.1', }, }); 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 bc766de90ad9..aad0b2d11daa 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 @@ -29,6 +29,7 @@ describe('e2e_p2p_validators_sentinel', () => { basePort: BOOT_NODE_UDP_PORT, initialConfig: { ...SHORTENED_BLOCK_TIME_CONFIG, + listenAddress: '127.0.0.1', minTxsPerBlock: 0, aztecEpochDuration: 48, validatorReexecute: false, diff --git a/yarn-project/ethereum/src/test/start_anvil.ts b/yarn-project/ethereum/src/test/start_anvil.ts index b61b663af7db..fc3c703fc500 100644 --- a/yarn-project/ethereum/src/test/start_anvil.ts +++ b/yarn-project/ethereum/src/test/start_anvil.ts @@ -23,7 +23,7 @@ export async function startAnvil( const anvil = createAnvil({ anvilBinary, host: '127.0.0.1', - port: 0, + port: 8545, blockTime: opts.l1BlockTime, stopTimeout: 1000, }); @@ -48,6 +48,6 @@ export async function startAnvil( } // Monkeypatch the anvil instance to include the actually assigned port - Object.defineProperty(anvil, 'port', { value: port, writable: false }); + // Object.defineProperty(anvil, 'port', { value: port, writable: false }); return { anvil, stop: () => anvil.stop(), rpcUrl: `http://127.0.0.1:${port}` }; } diff --git a/yarn-project/p2p/src/services/discv5/discv5_service.test.ts b/yarn-project/p2p/src/services/discv5/discv5_service.test.ts index f2b945cea8ca..051340b38445 100644 --- a/yarn-project/p2p/src/services/discv5/discv5_service.test.ts +++ b/yarn-project/p2p/src/services/discv5/discv5_service.test.ts @@ -41,7 +41,7 @@ describe('Discv5Service', () => { const baseConfig: BootnodeConfig = { p2pIp: '127.0.0.1', p2pPort: basePort + 100, - listenAddress: '0.0.0.0', + listenAddress: '127.0.0.1', dataDirectory: undefined, dataStoreMapSizeKB: 0, bootstrapNodes: [], diff --git a/yarn-project/p2p/src/test-helpers/reqresp-nodes.ts b/yarn-project/p2p/src/test-helpers/reqresp-nodes.ts index fe2967cc7e67..0378a585e0ef 100644 --- a/yarn-project/p2p/src/test-helpers/reqresp-nodes.ts +++ b/yarn-project/p2p/src/test-helpers/reqresp-nodes.ts @@ -55,8 +55,8 @@ export async function createLibp2pNode( const options: Libp2pOptions = { start, addresses: { - listen: [`/ip4/0.0.0.0/tcp/${port}`], - announce: [`/ip4/0.0.0.0/tcp/${port}`], + listen: [`/ip4/127.0.0.1/tcp/${port}`], + announce: [`/ip4/127.0.0.1/tcp/${port}`], }, connectionEncryption: [noise()], streamMuxers: [yamux()], @@ -239,7 +239,7 @@ export function createBootstrapNodeConfig(privateKey: string, port: number, chai dataDirectory: undefined, dataStoreMapSizeKB: 0, bootstrapNodes: [], - listenAddress: '0.0.0.0', + listenAddress: '127.0.0.1', }; } From db9b9921c2f1bd461e80abd7e71a93729d0f97e9 Mon Sep 17 00:00:00 2001 From: Charlie Lye <5764343+charlielye@users.noreply.github.com> Date: Mon, 31 Mar 2025 12:44:11 +0000 Subject: [PATCH 2/2] wip --- yarn-project/bootstrap.sh | 1 - .../src/e2e_contract_updates.test.ts | 2 +- .../end-to-end/src/e2e_outbox.test.ts | 2 +- yarn-project/end-to-end/src/fixtures/utils.ts | 463 +++++++++--------- .../src/test/fallback_transport.test.ts | 6 +- .../ethereum/src/test/start_anvil.test.ts | 4 +- yarn-project/ethereum/src/test/start_anvil.ts | 3 +- yarn-project/scripts/run_test.sh | 3 +- 8 files changed, 245 insertions(+), 239 deletions(-) diff --git a/yarn-project/bootstrap.sh b/yarn-project/bootstrap.sh index 496a6578e053..df519140e219 100755 --- a/yarn-project/bootstrap.sh +++ b/yarn-project/bootstrap.sh @@ -108,7 +108,6 @@ function test_cmds { else echo "$hash ISOLATE=1 yarn-project/scripts/run_test.sh $test" fi - done # Enable real proofs in prover-client integration tests only on CI full diff --git a/yarn-project/end-to-end/src/e2e_contract_updates.test.ts b/yarn-project/end-to-end/src/e2e_contract_updates.test.ts index eb1ee5494f3c..0cba9e58323b 100644 --- a/yarn-project/end-to-end/src/e2e_contract_updates.test.ts +++ b/yarn-project/end-to-end/src/e2e_contract_updates.test.ts @@ -89,7 +89,7 @@ describe('e2e_contract_updates', () => { } }; - afterAll(() => teardown()); + afterEach(() => teardown()); it('should update the contract', async () => { expect(await contract.methods.get_private_value().simulate()).toEqual(1n); diff --git a/yarn-project/end-to-end/src/e2e_outbox.test.ts b/yarn-project/end-to-end/src/e2e_outbox.test.ts index 46ba992b58a0..5d3e1da9615f 100644 --- a/yarn-project/end-to-end/src/e2e_outbox.test.ts +++ b/yarn-project/end-to-end/src/e2e_outbox.test.ts @@ -43,7 +43,7 @@ describe('E2E Outbox Tests', () => { contract = receipt.contract; }); - afterAll(() => teardown()); + afterEach(() => teardown()); it('Inserts a new transaction with two out messages, and verifies sibling paths of both the new messages', async () => { // recipient2 = msg.sender, so we can consume it later diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index e88969abf0e8..822c15d687be 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -357,271 +357,276 @@ export async function setup( pxeOpts: Partial = {}, chain: Chain = foundry, ): Promise { - const config = { ...getConfigEnvVars(), ...opts }; - config.peerCheckIntervalMS = TEST_PEER_CHECK_INTERVAL_MS; - // For tests we only want proving enabled if specifically requested - config.realProofs = !!opts.realProofs; - - const logger = getLogger(); - - // Create a temp directory for any services that need it and cleanup later - const directoryToCleanup = path.join(tmpdir(), randomBytes(8).toString('hex')); - await fs.mkdir(directoryToCleanup, { recursive: true }); - if (!config.dataDirectory) { - config.dataDirectory = directoryToCleanup; - } - let anvil: Anvil | undefined; - - if (!config.l1RpcUrls?.length) { - if (!isAnvilTestChain(chain.id)) { - throw new Error(`No ETHEREUM_HOSTS set but non anvil chain requested`); - } - if (PXE_URL) { - throw new Error( - `PXE_URL provided but no ETHEREUM_HOSTS set. Refusing to run, please set both variables so tests can deploy L1 contracts to the same Anvil instance`, - ); + try { + const config = { ...getConfigEnvVars(), ...opts }; + config.peerCheckIntervalMS = TEST_PEER_CHECK_INTERVAL_MS; + // For tests we only want proving enabled if specifically requested + config.realProofs = !!opts.realProofs; + + const logger = getLogger(); + + // Create a temp directory for any services that need it and cleanup later + const directoryToCleanup = path.join(tmpdir(), randomBytes(8).toString('hex')); + await fs.mkdir(directoryToCleanup, { recursive: true }); + if (!config.dataDirectory) { + config.dataDirectory = directoryToCleanup; } - const res = await startAnvil({ l1BlockTime: opts.ethereumSlotDuration }); - anvil = res.anvil; - config.l1RpcUrls = [res.rpcUrl]; - } - - // Enable logging metrics to a local file named after the test suite - if (isMetricsLoggingRequested()) { - const filename = path.join('log', getJobName() + '.jsonl'); - logger.info(`Logging metrics to ${filename}`); - setupMetricsLogger(filename); - } - - const ethCheatCodes = new EthCheatCodesWithState(config.l1RpcUrls); - - if (opts.stateLoad) { - await ethCheatCodes.loadChainState(opts.stateLoad); - } - - if (opts.l1StartTime) { - await ethCheatCodes.warp(opts.l1StartTime); - } - - let publisherPrivKey = undefined; - let publisherHdAccount = undefined; - - if (config.publisherPrivateKey && config.publisherPrivateKey != NULL_KEY) { - publisherHdAccount = privateKeyToAccount(config.publisherPrivateKey); - } else if (!MNEMONIC) { - throw new Error(`Mnemonic not provided and no publisher private key`); - } else { - publisherHdAccount = mnemonicToAccount(MNEMONIC, { addressIndex: 0 }); - const publisherPrivKeyRaw = publisherHdAccount.getHdKey().privateKey; - publisherPrivKey = publisherPrivKeyRaw === null ? null : Buffer.from(publisherPrivKeyRaw); - config.publisherPrivateKey = `0x${publisherPrivKey!.toString('hex')}`; - } - - // Made as separate values such that keys can change, but for test they will be the same. - config.validatorPrivateKey = config.publisherPrivateKey; - - if (PXE_URL) { - // we are setting up against a remote environment, l1 contracts are assumed to already be deployed - return await setupWithRemoteEnvironment(publisherHdAccount!, config, logger, numberOfAccounts); - } - - const initialFundedAccounts = - opts.initialFundedAccounts ?? - (await generateSchnorrAccounts(opts.numberOfInitialFundedAccounts ?? numberOfAccounts)); - const { genesisBlockHash, genesisArchiveRoot, prefilledPublicData } = await getGenesisValues( - initialFundedAccounts.map(a => a.address), - opts.initialAccountFeeJuice, - opts.genesisPublicData, - ); + if (!config.l1RpcUrls?.length) { + if (!isAnvilTestChain(chain.id)) { + throw new Error(`No ETHEREUM_HOSTS set but non anvil chain requested`); + } + if (PXE_URL) { + throw new Error( + `PXE_URL provided but no ETHEREUM_HOSTS set. Refusing to run, please set both variables so tests can deploy L1 contracts to the same Anvil instance`, + ); + } - const deployL1ContractsValues = - opts.deployL1ContractsValues ?? - (await setupL1Contracts( - config.l1RpcUrls, - publisherHdAccount!, - logger, - { ...opts, genesisArchiveRoot, genesisBlockHash }, - chain, - )); + const res = await startAnvil({ l1BlockTime: opts.ethereumSlotDuration }); + anvil = res.anvil; + config.l1RpcUrls = [res.rpcUrl]; + } - config.l1Contracts = deployL1ContractsValues.l1ContractAddresses; + // Enable logging metrics to a local file named after the test suite + if (isMetricsLoggingRequested()) { + const filename = path.join('log', getJobName() + '.jsonl'); + logger.info(`Logging metrics to ${filename}`); + setupMetricsLogger(filename); + } - if (opts.fundRewardDistributor) { - // Mints block rewards for 10000 blocks to the rewardDistributor contract + const ethCheatCodes = new EthCheatCodesWithState(config.l1RpcUrls); - const rewardDistributor = getContract({ - address: deployL1ContractsValues.l1ContractAddresses.rewardDistributorAddress.toString(), - abi: l1Artifacts.rewardDistributor.contractAbi, - client: deployL1ContractsValues.publicClient, - }); + if (opts.stateLoad) { + await ethCheatCodes.loadChainState(opts.stateLoad); + } - const blockReward = await rewardDistributor.read.BLOCK_REWARD(); - const mintAmount = 10_000n * (blockReward as bigint); + if (opts.l1StartTime) { + await ethCheatCodes.warp(opts.l1StartTime); + } - const feeJuice = getContract({ - address: deployL1ContractsValues.l1ContractAddresses.feeJuiceAddress.toString(), - abi: l1Artifacts.feeAsset.contractAbi, - client: deployL1ContractsValues.walletClient, - }); + let publisherPrivKey = undefined; + let publisherHdAccount = undefined; + + if (config.publisherPrivateKey && config.publisherPrivateKey != NULL_KEY) { + publisherHdAccount = privateKeyToAccount(config.publisherPrivateKey); + } else if (!MNEMONIC) { + throw new Error(`Mnemonic not provided and no publisher private key`); + } else { + publisherHdAccount = mnemonicToAccount(MNEMONIC, { addressIndex: 0 }); + const publisherPrivKeyRaw = publisherHdAccount.getHdKey().privateKey; + publisherPrivKey = publisherPrivKeyRaw === null ? null : Buffer.from(publisherPrivKeyRaw); + config.publisherPrivateKey = `0x${publisherPrivKey!.toString('hex')}`; + } - const rewardDistributorMintTxHash = await feeJuice.write.mint([rewardDistributor.address, mintAmount], {} as any); - await deployL1ContractsValues.publicClient.waitForTransactionReceipt({ hash: rewardDistributorMintTxHash }); - logger.info(`Funding rewardDistributor in ${rewardDistributorMintTxHash}`); - } + // Made as separate values such that keys can change, but for test they will be the same. + config.validatorPrivateKey = config.publisherPrivateKey; - if (opts.l2StartTime) { - // This should only be used in synching test or when you need to have a stable - // timestamp for the first l2 block. - await ethCheatCodes.warp(opts.l2StartTime); - } + if (PXE_URL) { + // we are setting up against a remote environment, l1 contracts are assumed to already be deployed + return await setupWithRemoteEnvironment(publisherHdAccount!, config, logger, numberOfAccounts); + } - const dateProvider = new TestDateProvider(); + const initialFundedAccounts = + opts.initialFundedAccounts ?? + (await generateSchnorrAccounts(opts.numberOfInitialFundedAccounts ?? numberOfAccounts)); + const { genesisBlockHash, genesisArchiveRoot, prefilledPublicData } = await getGenesisValues( + initialFundedAccounts.map(a => a.address), + opts.initialAccountFeeJuice, + opts.genesisPublicData, + ); - const watcher = new AnvilTestWatcher( - new EthCheatCodesWithState(config.l1RpcUrls), - deployL1ContractsValues.l1ContractAddresses.rollupAddress, - deployL1ContractsValues.publicClient, - dateProvider, - ); + const deployL1ContractsValues = + opts.deployL1ContractsValues ?? + (await setupL1Contracts( + config.l1RpcUrls, + publisherHdAccount!, + logger, + { ...opts, genesisArchiveRoot, genesisBlockHash }, + chain, + )); + + config.l1Contracts = deployL1ContractsValues.l1ContractAddresses; + + if (opts.fundRewardDistributor) { + // Mints block rewards for 10000 blocks to the rewardDistributor contract + + const rewardDistributor = getContract({ + address: deployL1ContractsValues.l1ContractAddresses.rewardDistributorAddress.toString(), + abi: l1Artifacts.rewardDistributor.contractAbi, + client: deployL1ContractsValues.publicClient, + }); + + const blockReward = await rewardDistributor.read.BLOCK_REWARD(); + const mintAmount = 10_000n * (blockReward as bigint); + + const feeJuice = getContract({ + address: deployL1ContractsValues.l1ContractAddresses.feeJuiceAddress.toString(), + abi: l1Artifacts.feeAsset.contractAbi, + client: deployL1ContractsValues.walletClient, + }); + + const rewardDistributorMintTxHash = await feeJuice.write.mint([rewardDistributor.address, mintAmount], {} as any); + await deployL1ContractsValues.publicClient.waitForTransactionReceipt({ hash: rewardDistributorMintTxHash }); + logger.info(`Funding rewardDistributor in ${rewardDistributorMintTxHash}`); + } - await watcher.start(); + if (opts.l2StartTime) { + // This should only be used in synching test or when you need to have a stable + // timestamp for the first l2 block. + await ethCheatCodes.warp(opts.l2StartTime); + } - const telemetry = getTelemetryClient(opts.telemetryConfig); + const dateProvider = new TestDateProvider(); - // Blob sink service - blobs get posted here and served from here - const blobSinkPort = await getPort(); - const blobSink = await createBlobSinkServer( - { - l1ChainId: config.l1ChainId, - l1RpcUrls: config.l1RpcUrls, - rollupAddress: config.l1Contracts.rollupAddress, - port: blobSinkPort, - dataDirectory: config.dataDirectory, - dataStoreMapSizeKB: config.dataStoreMapSizeKB, - }, - telemetry, - ); - await blobSink.start(); - config.blobSinkUrl = `http://localhost:${blobSinkPort}`; + const watcher = new AnvilTestWatcher( + new EthCheatCodesWithState(config.l1RpcUrls), + deployL1ContractsValues.l1ContractAddresses.rollupAddress, + deployL1ContractsValues.publicClient, + dateProvider, + ); - logger.verbose('Creating and synching an aztec node...'); + await watcher.start(); + + const telemetry = getTelemetryClient(opts.telemetryConfig); + + // Blob sink service - blobs get posted here and served from here + const blobSinkPort = await getPort(); + const blobSink = await createBlobSinkServer( + { + l1ChainId: config.l1ChainId, + l1RpcUrls: config.l1RpcUrls, + rollupAddress: config.l1Contracts.rollupAddress, + port: blobSinkPort, + dataDirectory: config.dataDirectory, + dataStoreMapSizeKB: config.dataStoreMapSizeKB, + }, + telemetry, + ); + await blobSink.start(); + config.blobSinkUrl = `http://localhost:${blobSinkPort}`; - const acvmConfig = await getACVMConfig(logger); - if (acvmConfig) { - config.acvmWorkingDirectory = acvmConfig.acvmWorkingDirectory; - config.acvmBinaryPath = acvmConfig.acvmBinaryPath; - } + logger.verbose('Creating and synching an aztec node...'); - const bbConfig = await getBBConfig(logger); - if (bbConfig) { - config.bbBinaryPath = bbConfig.bbBinaryPath; - config.bbWorkingDirectory = bbConfig.bbWorkingDirectory; - } - config.l1PublishRetryIntervalMS = 100; - - const blobSinkClient = createBlobSinkClient(config); - const aztecNode = await AztecNodeService.createAndSync( - config, - { dateProvider, blobSinkClient, telemetry }, - { prefilledPublicData }, - ); - const sequencer = aztecNode.getSequencer(); + const acvmConfig = await getACVMConfig(logger); + if (acvmConfig) { + config.acvmWorkingDirectory = acvmConfig.acvmWorkingDirectory; + config.acvmBinaryPath = acvmConfig.acvmBinaryPath; + } - if (sequencer) { - const publisher = (sequencer as TestSequencerClient).sequencer.publisher; - publisher.l1TxUtils = DelayedTxUtils.fromL1TxUtils(publisher.l1TxUtils, config.ethereumSlotDuration); - } + const bbConfig = await getBBConfig(logger); + if (bbConfig) { + config.bbBinaryPath = bbConfig.bbBinaryPath; + config.bbWorkingDirectory = bbConfig.bbWorkingDirectory; + } + config.l1PublishRetryIntervalMS = 100; - let proverNode: ProverNode | undefined = undefined; - if (opts.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, + const blobSinkClient = createBlobSinkClient(config); + const aztecNode = await AztecNodeService.createAndSync( config, - aztecNode, - path.join(directoryToCleanup, randomBytes(8).toString('hex')), + { dateProvider, blobSinkClient, telemetry }, + { prefilledPublicData }, ); - } - - logger.verbose('Creating a pxe...'); - const { pxe, teardown: pxeTeardown } = await setupPXEService(aztecNode!, pxeOpts, logger); - - if (!config.skipProtocolContracts) { - logger.verbose('Setting up Fee Juice...'); - await setupCanonicalFeeJuice(pxe); - } + const sequencer = aztecNode.getSequencer(); - const accountManagers = await deployFundedSchnorrAccounts(pxe, initialFundedAccounts.slice(0, numberOfAccounts)); - const wallets = await Promise.all(accountManagers.map(account => account.getWallet())); - if (initialFundedAccounts.length < numberOfAccounts) { - // TODO: Create (numberOfAccounts - initialFundedAccounts.length) wallets without funds. - throw new Error( - `Unable to deploy ${numberOfAccounts} accounts. Only ${initialFundedAccounts.length} accounts were funded.`, - ); - } + if (sequencer) { + const publisher = (sequencer as TestSequencerClient).sequencer.publisher; + publisher.l1TxUtils = DelayedTxUtils.fromL1TxUtils(publisher.l1TxUtils, config.ethereumSlotDuration); + } - const cheatCodes = await CheatCodes.create(config.l1RpcUrls, pxe!); + let proverNode: ProverNode | undefined = undefined; + if (opts.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, + config, + aztecNode, + path.join(directoryToCleanup, randomBytes(8).toString('hex')), + ); + } - const teardown = async () => { - await pxeTeardown(); + logger.verbose('Creating a pxe...'); + const { pxe, teardown: pxeTeardown } = await setupPXEService(aztecNode!, pxeOpts, logger); - if (aztecNode instanceof AztecNodeService) { - await aztecNode?.stop(); + if (!config.skipProtocolContracts) { + logger.verbose('Setting up Fee Juice...'); + await setupCanonicalFeeJuice(pxe); } - if (proverNode) { - await proverNode.stop(); + const accountManagers = await deployFundedSchnorrAccounts(pxe, initialFundedAccounts.slice(0, numberOfAccounts)); + const wallets = await Promise.all(accountManagers.map(account => account.getWallet())); + if (initialFundedAccounts.length < numberOfAccounts) { + // TODO: Create (numberOfAccounts - initialFundedAccounts.length) wallets without funds. + throw new Error( + `Unable to deploy ${numberOfAccounts} accounts. Only ${initialFundedAccounts.length} accounts were funded.`, + ); } - if (acvmConfig?.cleanup) { - // remove the temp directory created for the acvm - logger.verbose(`Cleaning up ACVM state`); - await acvmConfig.cleanup(); - } + const cheatCodes = await CheatCodes.create(config.l1RpcUrls, pxe!); - if (bbConfig?.cleanup) { - // remove the temp directory created for the acvm - logger.verbose(`Cleaning up BB state`); - await bbConfig.cleanup(); - } + const teardown = async () => { + await pxeTeardown(); - await anvil?.stop().catch(err => getLogger().error(err)); - await watcher.stop(); - await blobSink?.stop(); + if (aztecNode instanceof AztecNodeService) { + await aztecNode?.stop(); + } - if (directoryToCleanup) { - try { - logger.verbose(`Cleaning up data directory at ${directoryToCleanup}`); - await fs.rm(directoryToCleanup, { recursive: true, force: true, maxRetries: 3 }); - } catch (err) { - logger.warn(`Failed to delete data directory at ${directoryToCleanup}: ${err}`); + if (proverNode) { + await proverNode.stop(); } - } - }; - return { - aztecNode, - aztecNodeAdmin: aztecNode, - blobSink, - cheatCodes, - config, - dateProvider, - deployL1ContractsValues, - initialFundedAccounts, - logger, - proverNode, - pxe, - sequencer, - teardown, - telemetryClient: telemetry, - wallet: wallets[0], - wallets, - watcher, - }; + if (acvmConfig?.cleanup) { + // remove the temp directory created for the acvm + logger.verbose(`Cleaning up ACVM state`); + await acvmConfig.cleanup(); + } + + if (bbConfig?.cleanup) { + // remove the temp directory created for the acvm + logger.verbose(`Cleaning up BB state`); + await bbConfig.cleanup(); + } + + await anvil?.stop().catch(err => getLogger().error(err)); + await watcher.stop(); + await blobSink?.stop(); + + if (directoryToCleanup) { + try { + logger.verbose(`Cleaning up data directory at ${directoryToCleanup}`); + await fs.rm(directoryToCleanup, { recursive: true, force: true, maxRetries: 3 }); + } catch (err) { + logger.warn(`Failed to delete data directory at ${directoryToCleanup}: ${err}`); + } + } + }; + + return { + aztecNode, + aztecNodeAdmin: aztecNode, + blobSink, + cheatCodes, + config, + dateProvider, + deployL1ContractsValues, + initialFundedAccounts, + logger, + proverNode, + pxe, + sequencer, + teardown, + telemetryClient: telemetry, + wallet: wallets[0], + wallets, + watcher, + }; + } catch (err) { + // TODO: Just hoisted anvil for now to ensure cleanup. Prob need to hoist the rest. + await anvil?.stop(); + throw err; + } } /** diff --git a/yarn-project/ethereum/src/test/fallback_transport.test.ts b/yarn-project/ethereum/src/test/fallback_transport.test.ts index 92d1934f8da1..57ba156cdf50 100644 --- a/yarn-project/ethereum/src/test/fallback_transport.test.ts +++ b/yarn-project/ethereum/src/test/fallback_transport.test.ts @@ -43,15 +43,15 @@ describe('fallback_transport', () => { let anvil1: Anvil; let anvil2: Anvil; - afterAll(async () => { + afterEach(async () => { await anvil1.stop(); await anvil2.stop(); }, 5_000); beforeEach(async () => { // Start two separate Anvil instances - const anvil1Result = await startAnvil(); - const anvil2Result = await startAnvil(); + const anvil1Result = await startAnvil({ port: 8545 }); + const anvil2Result = await startAnvil({ port: 8546 }); anvil1 = anvil1Result.anvil; anvil2 = anvil2Result.anvil; diff --git a/yarn-project/ethereum/src/test/start_anvil.test.ts b/yarn-project/ethereum/src/test/start_anvil.test.ts index 7c46245457a0..1762d43f5b30 100644 --- a/yarn-project/ethereum/src/test/start_anvil.test.ts +++ b/yarn-project/ethereum/src/test/start_anvil.test.ts @@ -26,8 +26,8 @@ describe('start_anvil', () => { expect(anvil.status).toEqual('idle'); }); - it('does not reuse ports when starting multiple instances', async () => { - const anvils = await Promise.all(times(20, () => startAnvil())); + it('can start multiple anvils on different ports', async () => { + const anvils = await Promise.all(times(20, i => startAnvil({ port: 8545 + i }))); const ports = anvils.map(({ rpcUrl }) => parseInt(new URL(rpcUrl).port)); expect(new Set(ports).size).toEqual(20); await Promise.all(anvils.map(({ anvil }) => anvil.stop())); diff --git a/yarn-project/ethereum/src/test/start_anvil.ts b/yarn-project/ethereum/src/test/start_anvil.ts index fc3c703fc500..f57fdb31f042 100644 --- a/yarn-project/ethereum/src/test/start_anvil.ts +++ b/yarn-project/ethereum/src/test/start_anvil.ts @@ -9,6 +9,7 @@ import { dirname, resolve } from 'path'; */ export async function startAnvil( opts: { + port?: number; l1BlockTime?: number; } = {}, ): Promise<{ anvil: Anvil; rpcUrl: string; stop: () => Promise }> { @@ -23,7 +24,7 @@ export async function startAnvil( const anvil = createAnvil({ anvilBinary, host: '127.0.0.1', - port: 8545, + port: opts.port ?? 8545, blockTime: opts.l1BlockTime, stopTimeout: 1000, }); diff --git a/yarn-project/scripts/run_test.sh b/yarn-project/scripts/run_test.sh index 9b1336ce7820..305bda1810a5 100755 --- a/yarn-project/scripts/run_test.sh +++ b/yarn-project/scripts/run_test.sh @@ -30,7 +30,8 @@ if [ "${ISOLATE:-0}" -eq 1 ]; then -e NODE_OPTIONS="--no-warnings --experimental-vm-modules --loader @swc-node/register" \ -e LOG_LEVEL \ aztecprotocol/build:3.0 \ - node ../node_modules/.bin/jest --forceExit --runInBand $test + node ../node_modules/.bin/jest --forceExit --runInBand $test & + wait $! else export NODE_OPTIONS="--no-warnings --experimental-vm-modules --loader @swc-node/register" cd ../$dir