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
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ describe('multi-node/invalid-attestations/invalidate_block', () => {
// Uses multiple-blocks-per-slot timing configuration.
test = await MultiNodeTestContext.setup({
...MOCK_GOSSIP_MULTI_VALIDATOR_OPTS,
ethereumSlotDuration: 8,
ethereumSlotDuration: 12,
aztecSlotDuration: 36,
blockDurationMs: 6000,
initialValidators: validators,
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/end-to-end/src/p2p/reqresp/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export async function createReqrespTest(options: ReqrespOptions = {}): Promise<P
// To collect metrics - run in aztec-packages `docker compose --profile metrics up`
metricsPort: shouldCollectMetrics(),
initialConfig: {
ethereumSlotDuration: 8,
ethereumSlotDuration: 12,
aztecSlotDuration: 36,
blockDurationMs: 6000,
minTxsPerBlock: 1,
Expand Down
37 changes: 37 additions & 0 deletions yarn-project/ethereum/src/config.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { assertValidSlotDurations, validateSlotDurations } from './config.js';

describe('validateSlotDurations', () => {
it('returns no errors for a sound config', () => {
expect(validateSlotDurations({ ethereumSlotDuration: 12, aztecSlotDuration: 36 })).toEqual([]);
});

it('errors when aztecSlotDuration is not a multiple of ethereumSlotDuration', () => {
expect(validateSlotDurations({ ethereumSlotDuration: 8, aztecSlotDuration: 36 })).toContainEqual(
expect.stringContaining('must be a multiple'),
);
});

it('errors when ethereumSlotDuration is non-positive', () => {
expect(validateSlotDurations({ ethereumSlotDuration: 0, aztecSlotDuration: 36 })).toContainEqual(
expect.stringContaining('ethereumSlotDuration must be positive'),
);
});

it('errors when aztecSlotDuration is non-positive', () => {
expect(validateSlotDurations({ ethereumSlotDuration: 12, aztecSlotDuration: 0 })).toContainEqual(
expect.stringContaining('aztecSlotDuration must be positive'),
);
});
});

describe('assertValidSlotDurations', () => {
it('does not throw for a sound config', () => {
expect(() => assertValidSlotDurations({ ethereumSlotDuration: 12, aztecSlotDuration: 36 })).not.toThrow();
});

it('throws when aztecSlotDuration is not a multiple of ethereumSlotDuration', () => {
expect(() => assertValidSlotDurations({ ethereumSlotDuration: 8, aztecSlotDuration: 36 })).toThrow(
/must be a multiple/,
);
});
});
35 changes: 35 additions & 0 deletions yarn-project/ethereum/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,41 @@ export const l1ContractsConfigMappings: ConfigMappingsType<L1ContractsConfig> =
*/
export const DefaultL1ContractsConfig = getDefaultConfig(l1ContractsConfigMappings);

/**
* Validates that `ethereumSlotDuration` and `aztecSlotDuration` are positive and that the L2 slot is an exact
* multiple of the L1 slot. Every L2 slot boundary must land on an L1 slot boundary; a non-multiple pairing
* desyncs the epoch/checkpoint timing math throughout the sequencer, validator client, and timetables. Returns
* a list of error messages (empty when valid).
*/
export function validateSlotDurations(
config: Pick<L1ContractsConfig, 'ethereumSlotDuration' | 'aztecSlotDuration'>,
): string[] {
const errors: string[] = [];
if (config.ethereumSlotDuration <= 0) {
errors.push(`ethereumSlotDuration must be positive (got ${config.ethereumSlotDuration})`);
}
if (config.aztecSlotDuration <= 0) {
errors.push(`aztecSlotDuration must be positive (got ${config.aztecSlotDuration})`);
}
if (config.ethereumSlotDuration > 0 && config.aztecSlotDuration % config.ethereumSlotDuration !== 0) {
errors.push(
`aztecSlotDuration (${config.aztecSlotDuration}s) must be a multiple of ethereumSlotDuration ` +
`(${config.ethereumSlotDuration}s)`,
);
}
return errors;
}

/** Throws if {@link validateSlotDurations} reports any errors. */
export function assertValidSlotDurations(
config: Pick<L1ContractsConfig, 'ethereumSlotDuration' | 'aztecSlotDuration'>,
): void {
const errors = validateSlotDurations(config);
if (errors.length > 0) {
throw new Error(`Invalid slot duration configuration:\n${errors.map(e => ` - ${e}`).join('\n')}`);
}
}

export const genesisStateConfigMappings: ConfigMappingsType<GenesisStateConfig> = {
testAccounts: {
env: 'TEST_ACCOUNTS',
Expand Down
3 changes: 2 additions & 1 deletion yarn-project/ethereum/src/deploy_aztec_l1_contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { mainnet, sepolia } from 'viem/chains';

import { createEthereumChain, isAnvilTestChain } from './chain.js';
import { createExtendedL1Client } from './client.js';
import type { L1ContractsConfig } from './config.js';
import { type L1ContractsConfig, assertValidSlotDurations } from './config.js';
import { deployMulticall3 } from './contracts/multicall.js';
import { RollupContract } from './contracts/rollup.js';
import type { L1ContractAddresses } from './l1_contract_addresses.js';
Expand Down Expand Up @@ -282,6 +282,7 @@ export async function deployAztecL1Contracts(
args: DeployAztecL1ContractsArgs,
): Promise<DeployAztecL1ContractsReturnType> {
logger.info(`Deploying L1 contracts with config: ${jsonStringify(args)}`);
assertValidSlotDurations(args);
if (args.initialValidators && args.initialValidators.length > 0 && args.existingTokenAddress) {
throw new Error(
'Cannot deploy with both initialValidators and existingTokenAddress. ' +
Expand Down
15 changes: 2 additions & 13 deletions yarn-project/stdlib/src/config/network-consensus-config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type L1ContractsConfig, l1ContractsConfigMappings } from '@aztec/ethereum/config';
import { type L1ContractsConfig, l1ContractsConfigMappings, validateSlotDurations } from '@aztec/ethereum/config';
import { type EnvVar, pickConfigMappings } from '@aztec/foundation/config';

import type { SequencerConfig } from '../interfaces/configs.js';
Expand Down Expand Up @@ -156,21 +156,10 @@ export function validateNetworkConsensusConfig(config: NetworkConsensusConfig):
return errors;
}

if (config.ethereumSlotDuration <= 0) {
errors.push(`ethereumSlotDuration must be positive (got ${config.ethereumSlotDuration})`);
}
errors.push(...validateSlotDurations(config));
if (config.blockDurationMs <= 0) {
errors.push(`blockDurationMs must be positive (got ${config.blockDurationMs})`);
}
if (config.aztecSlotDuration <= 0) {
errors.push(`aztecSlotDuration must be positive (got ${config.aztecSlotDuration})`);
}
if (config.ethereumSlotDuration > 0 && config.aztecSlotDuration % config.ethereumSlotDuration !== 0) {
errors.push(
`aztecSlotDuration (${config.aztecSlotDuration}s) must be a multiple of ethereumSlotDuration ` +
`(${config.ethereumSlotDuration}s)`,
);
}
if (config.blockDurationMs / 1000 > config.aztecSlotDuration) {
errors.push(
`blockDurationMs (${config.blockDurationMs}ms) exceeds aztecSlotDuration (${config.aztecSlotDuration}s)`,
Expand Down
Loading