Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Large diffs are not rendered by default.

38 changes: 37 additions & 1 deletion yarn-project/end-to-end/src/e2e_epochs/epochs_test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { Archiver } from '@aztec/archiver';
import { type AztecNodeConfig, AztecNodeService } from '@aztec/aztec-node';
import { getTimestampRangeForEpoch } from '@aztec/aztec.js/block';
import { getContractInstanceFromInstantiationParams } from '@aztec/aztec.js/contracts';
Expand Down Expand Up @@ -319,7 +320,10 @@ export class EpochsTestContext {
this.logger.info(`Waiting until last slot of submission window for epoch ${epochNumber} at ${date}`, {
oneSlotBefore,
});
await waitUntilL1Timestamp(this.l1Client, oneSlotBefore);
// Use a timeout that accounts for the full proof submission window
const proofSubmissionWindowDuration =
this.constants.proofSubmissionEpochs * this.epochDuration * this.L2_SLOT_DURATION_IN_S;
await waitUntilL1Timestamp(this.l1Client, oneSlotBefore, undefined, proofSubmissionWindowDuration * 2);
}

/** Waits for the aztec node to sync to the target block number. */
Expand Down Expand Up @@ -394,6 +398,38 @@ export class EpochsTestContext {
expect(result).toBe(expectedSuccess);
}

/** Verifies at least one checkpoint has the target number of blocks (for MBPS validation). */
public async assertMultipleBlocksPerSlot(targetBlockCount: number) {
const archiver = (this.context.aztecNode as AztecNodeService).getBlockSource() as Archiver;
const checkpoints = await archiver.getCheckpoints(CheckpointNumber(1), 50);

this.logger.warn(`Retrieved ${checkpoints.length} checkpoints from archiver`, {
checkpoints: checkpoints.map(pc => pc.checkpoint.getStats()),
});

let expectedBlockNumber = checkpoints[0].checkpoint.blocks[0].number;
let targetFound = false;

for (const checkpoint of checkpoints) {
const blockCount = checkpoint.checkpoint.blocks.length;
targetFound = targetFound || blockCount >= targetBlockCount;

this.logger.verbose(`Checkpoint ${checkpoint.checkpoint.number} has ${blockCount} blocks`, {
checkpoint: checkpoint.checkpoint.getStats(),
});

for (let i = 0; i < blockCount; i++) {
const block = checkpoint.checkpoint.blocks[i];
expect(block.indexWithinCheckpoint).toBe(i);
expect(block.checkpointNumber).toBe(checkpoint.checkpoint.number);
expect(block.number).toBe(expectedBlockNumber);
expectedBlockNumber++;
}
}

expect(targetFound).toBe(true);
}

public watchSequencerEvents(
sequencers: SequencerClient[],
getMetadata: (i: number) => Record<string, any> = () => ({}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,18 @@ import 'jest-extended';
import os from 'os';
import path from 'path';

import { getBootNodeUdpPort } from '../fixtures/fixtures.js';
import { createNodes, createNonValidatorNode } from '../fixtures/setup_p2p_test.js';
import { P2PNetworkTest } from './p2p_network.js';

const NUM_NODES = 2;
const VALIDATORS_PER_NODE = 3;
const NUM_VALIDATORS = NUM_NODES * VALIDATORS_PER_NODE;
const BOOT_NODE_UDP_PORT = 4500;
const BOOT_NODE_UDP_PORT = getBootNodeUdpPort();
const SLOT_COUNT = 3;
const EPOCH_DURATION = 2;
const ETHEREUM_SLOT_DURATION = 4;
const AZTEC_SLOT_DURATION = 8;
const ETHEREUM_SLOT_DURATION = 8;
const AZTEC_SLOT_DURATION = 36;

const DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), 'validators-sentinel-'));

Expand All @@ -46,6 +47,9 @@ describe('e2e_p2p_multiple_validators_sentinel', () => {
aztecTargetCommitteeSize: NUM_VALIDATORS,
aztecSlotDuration: AZTEC_SLOT_DURATION,
ethereumSlotDuration: ETHEREUM_SLOT_DURATION,
blockDurationMs: 6000,
l1PublishingTime: 8,
enforceTimeTable: true,
aztecProofSubmissionEpochs: 1024, // effectively do not reorg
listenAddress: '127.0.0.1',
minTxsPerBlock: 0,
Expand Down
44 changes: 36 additions & 8 deletions yarn-project/end-to-end/src/e2e_p2p/reqresp/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,24 @@ import { createLogger } from '@aztec/aztec.js/log';
import { waitForTx } from '@aztec/aztec.js/node';
import { Tx } from '@aztec/aztec.js/tx';
import { RollupContract } from '@aztec/ethereum/contracts';
import { SlotNumber } from '@aztec/foundation/branded-types';
import { CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
import { timesAsync } from '@aztec/foundation/collection';
import { retryUntil } from '@aztec/foundation/retry';

import { jest } from '@jest/globals';
import { expect, jest } from '@jest/globals';
import fs from 'fs';
import os from 'os';
import path from 'path';

import { shouldCollectMetrics } from '../../fixtures/fixtures.js';
import { getBootNodeUdpPort, shouldCollectMetrics } from '../../fixtures/fixtures.js';
import { createNodes } from '../../fixtures/setup_p2p_test.js';
import { P2PNetworkTest, SHORTENED_BLOCK_TIME_CONFIG_NO_PRUNES, WAIT_FOR_TX_TIMEOUT } from '../p2p_network.js';
import { P2PNetworkTest, WAIT_FOR_TX_TIMEOUT } from '../p2p_network.js';
import { prepareTransactions } from '../shared.js';

// Don't set this to a higher value than 9 because each node will use a different L1 publisher account and anvil seeds
export const NUM_VALIDATORS = 6;
export const NUM_TXS_PER_NODE = 2;
export const BOOT_NODE_UDP_PORT = 4500;
export const NUM_TXS_PER_NODE = 4;
export const BOOT_NODE_UDP_PORT = getBootNodeUdpPort();

export const createReqrespDataDir = () => fs.mkdtempSync(path.join(os.tmpdir(), 'reqresp-'));

Expand All @@ -38,8 +38,14 @@ export async function createReqrespTest(options: ReqrespOptions = {}): Promise<P
// To collect metrics - run in aztec-packages `docker compose --profile metrics up`
metricsPort: shouldCollectMetrics(),
initialConfig: {
...SHORTENED_BLOCK_TIME_CONFIG_NO_PRUNES,
aztecSlotDuration: 24,
ethereumSlotDuration: 8,
aztecSlotDuration: 36,
blockDurationMs: 6000,
l1PublishingTime: 8,
minTxsPerBlock: 1,
maxTxsPerBlock: 2,
enforceTimeTable: true,
aztecProofSubmissionEpochs: 1024, // effectively do not reorg
...(disableStatusHandshake ? { p2pDisableStatusHandshake: true } : {}),
listenAddress: '127.0.0.1',
aztecEpochDuration: 64, // stable committee
Expand Down Expand Up @@ -170,6 +176,28 @@ export async function runReqrespTxTest(params: {

t.logger.info('All transactions mined');

// Assert that multiple blocks were built for at least one slot
t.logger.info('Verifying multiple blocks for at least one checkpoint');
const checkpoints = await nodes[0].getCheckpoints(CheckpointNumber(1), 50);
expect(checkpoints.length).toBeGreaterThan(0);

let mbpsFound = false;
let expectedBlockNumber = checkpoints[0].checkpoint.blocks[0].number;

for (const published of checkpoints) {
const blockCount = published.checkpoint.blocks.length;
mbpsFound = mbpsFound || blockCount >= 2;

for (let i = 0; i < blockCount; i++) {
const block = published.checkpoint.blocks[i];
expect(block.indexWithinCheckpoint).toBe(i);
expect(block.checkpointNumber).toBe(published.checkpoint.number);
expect(block.number).toBe(expectedBlockNumber);
expectedBlockNumber++;
}
}

expect(mbpsFound).toBe(true);
return nodes;
}

Expand Down
10 changes: 10 additions & 0 deletions yarn-project/end-to-end/src/fixtures/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ export const shouldCollectMetrics = () => {
return undefined;
};

/** Returns the boot node UDP port from environment variable or default value. */
export function getBootNodeUdpPort(): number {
return process.env.BOOT_NODE_UDP_PORT ? parseInt(process.env.BOOT_NODE_UDP_PORT, 10) : 4500;
}

/** Returns the anvil port from environment variable or default value. */
export function getAnvilPort(): number {
return process.env.ANVIL_PORT ? parseInt(process.env.ANVIL_PORT, 10) : 8545;
}

export const TEST_PEER_CHECK_INTERVAL_MS = 1000;
export const TEST_MAX_PENDING_TX_POOL_COUNT = 10_000; // Number of max pending TXs ~ 1.56GB

Expand Down
1 change: 1 addition & 0 deletions yarn-project/prover-node/src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,5 +231,6 @@ export async function createProverNode(
proverNodeConfig,
telemetry,
delayer,
dateProvider,
);
}
2 changes: 1 addition & 1 deletion yarn-project/prover-node/src/prover-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ type DataStoreOptions = Pick<DataStoreConfig, 'dataDirectory'> & Pick<ChainConfi
*/
export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable {
private log = createLogger('prover-node');
private dateProvider = new DateProvider();

private jobs: Map<string, EpochProvingJob> = new Map();
private config: ProverNodeOptions;
Expand All @@ -81,6 +80,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
config: Partial<ProverNodeOptions> = {},
protected readonly telemetryClient: TelemetryClient = getTelemetryClient(),
private delayer?: Delayer,
private readonly dateProvider: DateProvider = new DateProvider(),
) {
this.config = {
proverNodePollingIntervalMs: 1_000,
Expand Down
3 changes: 3 additions & 0 deletions yarn-project/sequencer-client/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ export const sequencerConfigMappings: ConfigMappingsType<SequencerConfig> = {
description: 'Skip pushing proposed blocks to archiver (default: true)',
...booleanConfigHelper(DefaultSequencerConfig.skipPushProposedBlocksToArchiver),
},
minBlocksForCheckpoint: {
description: 'Minimum number of blocks required for a checkpoint proposal (test only)',
},
...pickConfigMappings(p2pConfigMappings, ['txPublicSetupAllowList']),
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,15 @@ export class CheckpointProposalJob implements Traceable {
return undefined;
}

const minBlocksForCheckpoint = this.config.minBlocksForCheckpoint;
if (minBlocksForCheckpoint !== undefined && blocksInCheckpoint.length < minBlocksForCheckpoint) {
this.log.warn(
`Checkpoint has fewer blocks than minimum (${blocksInCheckpoint.length} < ${minBlocksForCheckpoint}), skipping proposal`,
{ slot: this.slot, blocksBuilt: blocksInCheckpoint.length, minBlocksForCheckpoint },
);
return undefined;
}

// Assemble and broadcast the checkpoint proposal, including the last block that was not
// broadcasted yet, and wait to collect the committee attestations.
this.setStateFn(SequencerState.ASSEMBLING_CHECKPOINT, this.slot);
Expand Down
6 changes: 5 additions & 1 deletion yarn-project/stdlib/src/interfaces/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ export interface SequencerConfig {
buildCheckpointIfEmpty?: boolean;
/** Skip pushing proposed blocks to archiver (default: false) */
skipPushProposedBlocksToArchiver?: boolean;
/** Minimum number of blocks required for a checkpoint proposal (test only, defaults to undefined = no minimum) */
minBlocksForCheckpoint?: number;
}

export const SequencerConfigSchema = zodFor<SequencerConfig>()(
Expand Down Expand Up @@ -103,6 +105,7 @@ export const SequencerConfigSchema = zodFor<SequencerConfig>()(
blockDurationMs: z.number().positive().optional(),
buildCheckpointIfEmpty: z.boolean().optional(),
skipPushProposedBlocksToArchiver: z.boolean().optional(),
minBlocksForCheckpoint: z.number().positive().optional(),
}),
);

Expand All @@ -117,7 +120,8 @@ type SequencerConfigOptionalKeys =
| 'fakeThrowAfterProcessingTxCount'
| 'l1PublishingTime'
| 'txPublicSetupAllowList'
| 'minValidTxsPerBlock';
| 'minValidTxsPerBlock'
| 'minBlocksForCheckpoint';

export type ResolvedSequencerConfig = Prettify<
Required<Omit<SequencerConfig, SequencerConfigOptionalKeys>> & Pick<SequencerConfig, SequencerConfigOptionalKeys>
Expand Down
Loading