Skip to content
7 changes: 5 additions & 2 deletions yarn-project/end-to-end/src/automine/pxe.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ describe('automine/pxe', () => {
let contract: TestContract;

beforeAll(async () => {
const test = await AutomineTestContext.setup({ numberOfAccounts: 1 });
({
teardown,
wallet,
accounts: [defaultAccountAddress],
} = (await AutomineTestContext.setup({ numberOfAccounts: 1 })).context);
({ contract } = await TestContract.deploy(wallet).send({ from: defaultAccountAddress }));
} = test.context);
// The test only calls the noinitcheck private `emit_nullifier`, so register the contract instead of
// deploying it — this avoids a deployment tx and its checkpoint cycle.
contract = await test.registerContract(wallet, TestContract);
});

afterAll(() => teardown());
Expand Down
25 changes: 16 additions & 9 deletions yarn-project/end-to-end/src/fixtures/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,12 @@ export async function registerSponsoredFPC(wallet: Wallet): Promise<void> {
await wallet.registerContract(await getSponsoredFPCInstance(), SponsoredFPCContract.artifact);
}

export async function waitForProvenChain(node: AztecNode, targetBlock?: BlockNumber, timeoutSec = 60, intervalSec = 1) {
export async function waitForProvenChain(
node: AztecNode,
targetBlock?: BlockNumber,
timeoutSec = 60,
intervalSec = 0.25,
) {
targetBlock ??= await node.getBlockNumber();

await retryUntil(
Expand Down Expand Up @@ -923,14 +928,16 @@ export async function expectMappingDelta<K, V extends number | bigint>(
* surface as generic "Assertion failed:" and tests that match on the real message fail).
*/
export async function ensureAuthRegistryPublished(wallet: Wallet, from: AztecAddress) {
const { instance, contractClass } = await getStandardAuthRegistry();
if (!(await wallet.getContractClassMetadata(contractClass.id)).isContractClassPubliclyRegistered) {
await (await publishContractClass(wallet, AuthRegistryArtifact)).send({ from });
}
if (!(await wallet.getContractMetadata(instance.address)).isContractPublished) {
await publishInstance(wallet, instance).send({ from });
}
await wallet.registerContract(instance, AuthRegistryArtifact);
await testSpan('setup:auth-registry', async () => {
const { instance, contractClass } = await getStandardAuthRegistry();
if (!(await wallet.getContractClassMetadata(contractClass.id)).isContractClassPubliclyRegistered) {
await (await publishContractClass(wallet, AuthRegistryArtifact)).send({ from });
}
if (!(await wallet.getContractMetadata(instance.address)).isContractPublished) {
await publishInstance(wallet, instance).send({ from });
}
await wallet.registerContract(instance, AuthRegistryArtifact);
});
}

/**
Expand Down
23 changes: 13 additions & 10 deletions yarn-project/end-to-end/src/fixtures/wait_helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export type WaitForBlockOpts = {
compare?: (actual: number, target: number) => boolean;
/** Seconds before the poll rejects; defaults to 60. */
timeout?: number;
/** Seconds between polls; defaults to 1. */
/** Seconds between polls; defaults to 0.25. */
interval?: number;
};

Expand All @@ -45,7 +45,7 @@ export function waitForBlockNumber(node: AztecNode, target: number, opts: WaitFo
},
`block ${tag} ${compare} ${target}`,
opts.timeout ?? 60,
opts.interval ?? 1,
opts.interval ?? 0.25,
).then(({ blockNumber }) => blockNumber),
);
}
Expand Down Expand Up @@ -118,7 +118,10 @@ export function waitForNodeProvenCheckpoint(
* {@link waitForTx}; resolves with the receipts in input order.
*/
export function waitForTxs(node: AztecNode, txHashes: TxHash[], opts?: WaitOpts): Promise<TxReceipt[]> {
return testSpan('wait:tx-mined', () => Promise.all(txHashes.map(txHash => waitForTx(node, txHash, opts))));
const optsWithInterval = { ...opts, interval: opts?.interval ?? 0.25 };
return testSpan('wait:tx-mined', () =>
Promise.all(txHashes.map(txHash => waitForTx(node, txHash, optsWithInterval))),
);
}

/** Options for {@link waitForBlocksAtSlots}. */
Expand All @@ -129,7 +132,7 @@ export type WaitForBlocksAtSlotsOpts = {
limit?: number;
/** Seconds before the poll rejects; defaults to 20. */
timeout?: number;
/** Seconds between polls; defaults to 1. */
/** Seconds between polls; defaults to 0.25. */
interval?: number;
};

Expand All @@ -153,7 +156,7 @@ export async function waitForBlocksAtSlots(
},
`blocks at slots ${slots.join(', ')}`,
opts.timeout ?? 20,
opts.interval ?? 1,
opts.interval ?? 0.25,
),
);
}
Expand All @@ -174,7 +177,7 @@ export function waitForL2ToL1Witness(
() => node.getL2ToL1MembershipWitness(txHash, message),
`L2-to-L1 membership witness for ${txHash.toString()}`,
opts.timeout ?? 30,
opts.interval ?? 1,
opts.interval ?? 0.25,
),
);
}
Expand All @@ -183,7 +186,7 @@ export function waitForL2ToL1Witness(
export type WaitForTxReceiptOpts = {
/** Seconds before the poll rejects; defaults to 30. */
timeout?: number;
/** Seconds between polls; defaults to 1. */
/** Seconds between polls; defaults to 0.25. */
interval?: number;
};

Expand All @@ -207,7 +210,7 @@ export function waitForTxReceipt(
},
`tx receipt for ${txHash.toString()}`,
opts.timeout ?? 30,
opts.interval ?? 1,
opts.interval ?? 0.25,
).then(({ receipt }) => receipt),
);
}
Expand All @@ -231,7 +234,7 @@ export type WaitForPendingTxCountOpts = {
compare?: PendingTxCountComparator;
/** Seconds before the poll rejects; defaults to 30. */
timeout?: number;
/** Seconds between polls; defaults to 1. */
/** Seconds between polls; defaults to 0.25. */
interval?: number;
};

Expand All @@ -256,7 +259,7 @@ export function waitForPendingTxCount(
},
`pending tx count ${compare} ${target}`,
opts.timeout ?? 30,
opts.interval ?? 1,
opts.interval ?? 0.25,
).then(({ count }) => count),
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const COMMITTEE_SIZE = VALIDATOR_COUNT - 2;
// Tests that a single AztecNodeService hosting multiple validator keys correctly signs attestations
// and filters signing to only active committee members. One node, 5 validators staked, committee
// size 3. Uses MultiNodeTestContext on the mock-gossip bus: all 5 validators on a single physical
// node, ethSlot=8s, aztecSlot=36s, epoch=2, proofSubEpochs=NO_REORG_SUBMISSION_EPOCHS. Each it is an isolated CI job
// node, ethSlot=8s, aztecSlot=16s, epoch=2, proofSubEpochs=NO_REORG_SUBMISSION_EPOCHS. Each it is an isolated CI job
// (parallel convention).
describe('multi-node/block-production/multi_validator_node', () => {
jest.setTimeout(15 * 60 * 1000);
Expand All @@ -51,10 +51,10 @@ describe('multi-node/block-production/multi_validator_node', () => {
aztecTargetCommitteeSize: COMMITTEE_SIZE,
aztecEpochDuration: 2,
ethereumSlotDuration: 8,
aztecSlotDuration: 36,
aztecSlotDuration: 16,
aztecProofSubmissionEpochs: NO_REORG_SUBMISSION_EPOCHS,
anvilSlotsInAnEpoch: 4,
blockDurationMs: 6000,
blockDurationMs: 2000,
minTxsPerBlock: 0,
inboxLag: 2,
});
Expand Down
12 changes: 12 additions & 0 deletions yarn-project/end-to-end/src/multi-node/block-production/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { TxStatus } from '@aztec/stdlib/tx';
import { jest } from '@jest/globals';

import { sendL1ToL2Message } from '../../fixtures/l1_to_l2_messaging.js';
import { testSpan } from '../../fixtures/timing.js';
import type { EndToEndContext } from '../../fixtures/utils.js';
import { waitForBlockNumber, waitForTxs } from '../../fixtures/wait_helpers.js';
import type { TestWallet } from '../../test-wallet/test_wallet.js';
Expand Down Expand Up @@ -209,6 +210,17 @@ export async function waitForProvenCheckpoint(
logger.warn(`Stopping validator sequencers before waiting for checkpoint ${targetCheckpoint} to be proven`);
await Promise.all(nodes.map(n => n.getSequencer()?.stop()));

// With the sequencers stopped, no further blocks are produced, so waiting out the rest of the epoch in
// wall-clock is dead time. Warp the L1 clock forward past the epoch boundary so the epoch containing
// targetCheckpoint closes and the fake prover can prove+submit it; the subsequent wait then only covers
// the (real-time) proving+submission. A single next-epoch jump stays inside the proof-submission window
// (proofSubmissionEpochs >= 1), so it never crosses the submission deadline. Skipped if already proven,
// and forward-only since advanceToNextEpoch never rewinds.
const { proven } = await test.context.cheatCodes.rollup.getTips();
if (proven < targetCheckpoint) {
await testSpan('warp:proven-checkpoint-epoch', () => test.context.cheatCodes.rollup.advanceToNextEpoch());
}

const provenTimeout = test.L2_SLOT_DURATION_IN_S * test.epochDuration * 4;
logger.warn(`Waiting for checkpoint ${targetCheckpoint} to be proven (timeout=${provenTimeout}s)`);
await test.waitUntilProvenCheckpointNumber(targetCheckpoint, provenTimeout);
Expand Down
23 changes: 15 additions & 8 deletions yarn-project/end-to-end/src/shared/cross_chain_test_harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { TokenBridgeContract } from '@aztec/noir-contracts.js/TokenBridge';

import { type Hex, getContract } from 'viem';

import { testSpan } from '../fixtures/timing.js';
import { mintTokensToPrivate } from '../fixtures/token_utils.js';
import { waitForL1ToL2MessageSeen } from './wait_for_l1_to_l2_message.js';

Expand Down Expand Up @@ -76,14 +77,18 @@ export async function deployAndInitializeTokenAndBridgeContracts(
});

// deploy l2 token
const { contract: token } = await TokenContract.deploy(wallet, owner, 'TokenName', 'TokenSymbol', 18).send({
from: owner,
});
const { contract: token } = await testSpan('deploy:token', () =>
TokenContract.deploy(wallet, owner, 'TokenName', 'TokenSymbol', 18).send({
from: owner,
}),
);

// deploy l2 token bridge and attach to the portal
const { contract: bridge } = await TokenBridgeContract.deploy(wallet, token.address, tokenPortalAddress).send({
from: owner,
});
const { contract: bridge } = await testSpan('deploy:bridge', () =>
TokenBridgeContract.deploy(wallet, token.address, tokenPortalAddress).send({
from: owner,
}),
);

if ((await token.methods.get_admin().simulate({ from: owner })).result !== owner.toBigInt()) {
throw new Error(`Token admin is not ${owner}`);
Expand Down Expand Up @@ -241,11 +246,13 @@ export class CrossChainTestHarness {

async mintTokensPublicOnL2(amount: bigint) {
this.logger.info('Minting tokens on L2 publicly');
await this.l2Token.methods.mint_to_public(this.ownerAddress, amount).send({ from: this.ownerAddress });
await testSpan('tx:mint', () =>
this.l2Token.methods.mint_to_public(this.ownerAddress, amount).send({ from: this.ownerAddress }),
);
}

async mintTokensPrivateOnL2(amount: bigint) {
await mintTokensToPrivate(this.l2Token, this.ownerAddress, this.ownerAddress, amount);
await testSpan('tx:mint', () => mintTokensToPrivate(this.l2Token, this.ownerAddress, this.ownerAddress, amount));
}

async sendL2PublicTransfer(transferAmount: bigint, receiverAddress: AztecAddress) {
Expand Down
18 changes: 13 additions & 5 deletions yarn-project/end-to-end/src/shared/gas_portal_test_harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { FeeJuiceContract } from '@aztec/noir-contracts.js/FeeJuice';
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
import type { AztecNodeAdmin, AztecNodeDebug } from '@aztec/stdlib/interfaces/client';

import { testSpan } from '../fixtures/timing.js';
import { waitForL1ToL2MessageSeen } from './wait_for_l1_to_l2_message.js';

/** Aztec node that may expose the debug mining API in local e2e setups. */
Expand Down Expand Up @@ -159,11 +160,13 @@ export class GasBridgingTestHarness implements IGasBridgingTestHarness {
}

async bridgeFromL1ToL2(owner: AztecAddress, claimer: AztecAddress) {
// Prepare the tokens on the L1 side
const claim = await this.prepareTokensOnL1(owner);
await testSpan('setup:bridge', async () => {
// Prepare the tokens on the L1 side
const claim = await this.prepareTokensOnL1(owner);

// Consume L1 -> L2 message and claim tokens privately on L2
await this.consumeMessageOnAztecAndClaimPrivately(owner, claimer, claim);
// Consume L1 -> L2 message and claim tokens privately on L2
await this.consumeMessageOnAztecAndClaimPrivately(owner, claimer, claim);
});
}

private async advanceL2Block() {
Expand All @@ -181,7 +184,12 @@ export class GasBridgingTestHarness implements IGasBridgingTestHarness {
}

try {
await retryUntil(async () => (await this.aztecNode.getBlockNumber()) >= initialBlockNumber + 1);
await retryUntil(
async () => (await this.aztecNode.getBlockNumber()) >= initialBlockNumber + 1,
'gas portal block advance',
0,
0.25,
);
} finally {
if (this.aztecNodeAdmin && minTxsPerBlock !== undefined) {
await this.aztecNodeAdmin.setConfig({ minTxsPerBlock });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ export function waitForL1ToL2MessageSeen(
async () => (await node.getL1ToL2MessageCheckpoint(l1ToL2MessageHash)) !== undefined,
`L1 to L2 message ${l1ToL2MessageHash.toString()} seen`,
opts.timeoutSeconds,
1,
0.25,
);
}
32 changes: 21 additions & 11 deletions yarn-project/end-to-end/src/single-node/fees/fees_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { getContract } from 'viem';

import { L1_DIRECT_WRITE_ACCOUNT_INDEX, MNEMONIC, getPaddedMaxFeesPerGas } from '../../fixtures/fixtures.js';
import { type SetupOptions, ensureAuthRegistryPublished, setup } from '../../fixtures/setup.js';
import { testSpan } from '../../fixtures/timing.js';
import { mintTokensToPrivate } from '../../fixtures/token_utils.js';
import { type BalancesFn, getBalancesFn, setupSponsoredFPC } from '../../fixtures/utils.js';
import {
Expand Down Expand Up @@ -158,7 +159,9 @@ export class FeesTest extends SingleNodeTestContext {
async mintAndBridgeFeeJuice(minter: AztecAddress, recipient: AztecAddress) {
const claim = await this.feeJuiceBridgeTestHarness.prepareTokensOnL1(recipient);
const { claimSecret: secret, messageLeafIndex: index } = claim;
await this.feeJuiceContract.methods.claim(recipient, claim.claimAmount, secret, index).send({ from: minter });
await testSpan('setup:bridge', () =>
this.feeJuiceContract.methods.claim(recipient, claim.claimAmount, secret, index).send({ from: minter }),
);
}

/** Alice mints bananaCoin tokens privately to the target address and redeems them. */
Expand All @@ -167,7 +170,7 @@ export class FeesTest extends SingleNodeTestContext {
.balance_of_private(address)
.simulate({ from: address });

await mintTokensToPrivate(this.bananaCoin, this.aliceAddress, address, amount);
await testSpan('tx:mint', () => mintTokensToPrivate(this.bananaCoin, this.aliceAddress, address, amount));

const { result: balanceAfter } = await this.bananaCoin.methods
.balance_of_private(address)
Expand Down Expand Up @@ -236,9 +239,11 @@ export class FeesTest extends SingleNodeTestContext {
async applyDeployBananaToken() {
this.logger.info('Applying deploy banana token setup');

const { contract: bananaCoin } = await BananaCoin.deploy(this.wallet, this.aliceAddress, 'BC', 'BC', 18n).send({
from: this.aliceAddress,
});
const { contract: bananaCoin } = await testSpan('deploy:token', () =>
BananaCoin.deploy(this.wallet, this.aliceAddress, 'BC', 'BC', 18n).send({
from: this.aliceAddress,
}),
);
this.logger.info(`BananaCoin deployed at ${bananaCoin.address}`);

this.bananaCoin = bananaCoin;
Expand All @@ -257,12 +262,15 @@ export class FeesTest extends SingleNodeTestContext {
expect((await this.wallet.getContractMetadata(feeJuiceContract.address)).isContractPublished).toBe(true);

const bananaCoin = this.bananaCoin;
const { contract: bananaFPC } = await FPCContract.deploy(this.wallet, bananaCoin.address, this.fpcAdmin).send({
from: this.aliceAddress,
});
const { contract: bananaFPC } = await testSpan('deploy:fpc', () =>
FPCContract.deploy(this.wallet, bananaCoin.address, this.fpcAdmin).send({
from: this.aliceAddress,
}),
);

this.logger.info(`BananaPay deployed at ${bananaFPC.address}`);

// bridgeFromL1ToL2 carries its own setup:bridge span.
await this.feeJuiceBridgeTestHarness.bridgeFromL1ToL2(bananaFPC.address, this.aliceAddress);

this.bananaFPC = bananaFPC;
Expand Down Expand Up @@ -345,9 +353,11 @@ export class FeesTest extends SingleNodeTestContext {
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 });
await testSpan('tx:mint', () =>
this.bananaCoin.methods.mint_to_public(this.aliceAddress, this.ALICE_INITIAL_BANANAS).send({
from: this.aliceAddress,
}),
);
}

public async applyFundAliceWithPrivateBananas() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,12 @@ describe('single-node/proving/multi_proof', () => {
const proverIds = test.proverNodes.map(node => node.getProverNode()!.getProverId());
logger.info(`Prover nodes running with ids ${proverIds.map(id => id.toString()).join(', ')}`);

// Anchor on a freshly-started epoch with the provers already running, then wait for it to fully
// elapse. We can't use epoch 0: under CI load the sequencer can come up after the chain has already
// Anchor on a freshly-started epoch with the provers already running, then warp past it so it fully
// elapses. We can't use epoch 0: under CI load the sequencer can come up after the chain has already
// advanced past epoch 0's slots, leaving it with no blocks, and the snapshot below would then have
// nothing to read. Anchoring on the next epoch guarantees its full slot range is ahead of us.
const epoch = await test.waitUntilNextEpochStarts();
await test.waitUntilEpochStarts(epoch + 1);
await test.warpToEpochStart(epoch + 1);

// Snapshot the anchored epoch's checkpoints. The epoch is now closed on L1 (no more epoch-N
// checkpoints can land once epoch N+1 has begun), but the node's archiver may still be catching up.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ describe('single-node/proving/upload_failed_proof', () => {
return url;
};

// Wait until the start of epoch one so prover node starts proving epoch 0,
// Warp to the start of epoch one so prover node starts proving epoch 0,
// and wait for the data to be uploaded to the remote file store
await test.waitUntilEpochStarts(1);
await test.warpToEpochStart(1);
const epochUploadUrl = await epochUploaded;

// Stop everything, we're going to prove on a fresh instance
Expand Down
Loading
Loading