Skip to content

Commit f3fff5b

Browse files
author
danielntmd
committed
fix: validators use timetable to calculate re-execution deadline
1 parent 8b8e4ca commit f3fff5b

File tree

11 files changed

+114
-14
lines changed

11 files changed

+114
-14
lines changed

yarn-project/foundation/src/config/env_var.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,6 @@ export type EnvVar =
305305
| 'K8S_POD_NAME'
306306
| 'K8S_POD_UID'
307307
| 'K8S_NAMESPACE_NAME'
308-
| 'VALIDATOR_REEXECUTE_DEADLINE_MS'
309308
| 'AUTO_UPDATE'
310309
| 'AUTO_UPDATE_URL'
311310
| 'WEB3_SIGNER_URL'

yarn-project/p2p/src/client/p2p_client.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
type CheckpointProposal,
2323
type P2PClientType,
2424
} from '@aztec/stdlib/p2p';
25+
import { getCheckpointFinalizationTimeMs } from '@aztec/stdlib/timetable';
2526
import type { Tx, TxHash } from '@aztec/stdlib/tx';
2627
import { Attributes, type TelemetryClient, WithTracer, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
2728

@@ -116,10 +117,17 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
116117
// validator-client code into here so we can validate a proposal is reasonable.
117118
this.registerBlockProposalHandler(async (block, sender) => {
118119
this.log.debug(`Received block proposal from ${sender.toString()}`);
119-
// TODO(palla/txs): Need to subtract validatorReexecuteDeadlineMs from this deadline (see ValidatorClient.getReexecutionDeadline)
120120
const constants = this.txCollection.getConstants();
121121
const nextSlotTimestampSeconds = Number(getTimestampForSlot(SlotNumber(block.slotNumber + 1), constants));
122-
const deadline = new Date(nextSlotTimestampSeconds * 1000);
122+
const deadline = new Date(
123+
nextSlotTimestampSeconds * 1000 -
124+
getCheckpointFinalizationTimeMs({
125+
ethereumSlotDuration: constants.ethereumSlotDuration,
126+
// default mirrors sequencer defaults
127+
l1PublishingTime: this.config.l1PublishingTime,
128+
p2pPropagationTime: this.config.attestationPropagationTime,
129+
}),
130+
);
123131
const parentBlock = await this.l2BlockSource.getBlockHeaderByArchive(block.blockHeader.lastArchive.root);
124132
if (!parentBlock) {
125133
this.log.debug(`Cannot collect txs for proposal as parent block not found`);

yarn-project/p2p/src/config.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,12 @@ export interface P2PConfig extends P2PReqRespConfig, ChainConfig, TxCollectionCo
167167

168168
/** Whether to run in fisherman mode: validates all proposals and attestations but does not broadcast attestations or participate in consensus */
169169
fishermanMode: boolean;
170+
171+
/** One-way p2p propagation time (seconds). */
172+
attestationPropagationTime?: number;
173+
174+
/** Time reserved for L1 publishing (seconds). */
175+
l1PublishingTime?: number;
170176
}
171177

172178
export const DEFAULT_P2P_PORT = 40400;
@@ -431,6 +437,12 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
431437
'Whether to run in fisherman mode: validates all proposals and attestations but does not broadcast attestations or participate in consensus.',
432438
...booleanConfigHelper(false),
433439
},
440+
attestationPropagationTime: {
441+
description: 'One-way p2p propagation time (seconds).',
442+
},
443+
l1PublishingTime: {
444+
description: 'Time reserved for L1 publishing (seconds).',
445+
},
434446
...p2pReqRespConfigMappings,
435447
...chainConfigMappings,
436448
...txCollectionConfigMappings,

yarn-project/sequencer-client/src/config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { type P2PConfig, p2pConfigMappings } from '@aztec/p2p/config';
1313
import { AztecAddress } from '@aztec/stdlib/aztec-address';
1414
import { type ChainConfig, type SequencerConfig, chainConfigMappings } from '@aztec/stdlib/config';
1515
import type { ResolvedSequencerConfig } from '@aztec/stdlib/interfaces/server';
16+
import { DEFAULT_ATTESTATION_PROPAGATION_TIME_SECONDS } from '@aztec/stdlib/timetable/constants';
1617
import { type ValidatorClientConfig, validatorClientConfigMappings } from '@aztec/validator-client/config';
1718

1819
import {
@@ -25,7 +26,7 @@ import {
2526
export * from './publisher/config.js';
2627
export type { SequencerConfig };
2728

28-
export const DEFAULT_ATTESTATION_PROPAGATION_TIME = 2;
29+
export const DEFAULT_ATTESTATION_PROPAGATION_TIME = DEFAULT_ATTESTATION_PROPAGATION_TIME_SECONDS;
2930

3031
/**
3132
* Default values for SequencerConfig.

yarn-project/sequencer-client/src/sequencer/timetable.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
import { createLogger } from '@aztec/aztec.js/log';
2+
import { getCheckpointFinalizationTimeSeconds } from '@aztec/stdlib/timetable';
3+
import {
4+
DEFAULT_CHECKPOINT_ASSEMBLE_TIME_SECONDS,
5+
TEST_CHECKPOINT_ASSEMBLE_TIME_SECONDS,
6+
TEST_FAST_TIMING_ETHEREUM_SLOT_THRESHOLD_SECONDS,
7+
} from '@aztec/stdlib/timetable/constants';
28

39
import { DEFAULT_ATTESTATION_PROPAGATION_TIME as DEFAULT_P2P_PROPAGATION_TIME } from '../config.js';
410
import { SequencerTooSlowError } from './errors.js';
@@ -7,7 +13,7 @@ import { SequencerState } from './utils.js';
713

814
export const MIN_EXECUTION_TIME = 2;
915
export const CHECKPOINT_INITIALIZATION_TIME = 1;
10-
export const CHECKPOINT_ASSEMBLE_TIME = 1;
16+
export const CHECKPOINT_ASSEMBLE_TIME = DEFAULT_CHECKPOINT_ASSEMBLE_TIME_SECONDS;
1117

1218
export class SequencerTimetable {
1319
/**
@@ -89,9 +95,9 @@ export class SequencerTimetable {
8995
this.enforce = opts.enforce;
9096

9197
// Assume zero-cost propagation time and faster runs in test environments where L1 slot duration is shortened
92-
if (this.ethereumSlotDuration < 8) {
98+
if (this.ethereumSlotDuration < TEST_FAST_TIMING_ETHEREUM_SLOT_THRESHOLD_SECONDS) {
9399
this.p2pPropagationTime = 0;
94-
this.checkpointAssembleTime = 0.5;
100+
this.checkpointAssembleTime = TEST_CHECKPOINT_ASSEMBLE_TIME_SECONDS;
95101
this.checkpointInitializationTime = 0.5;
96102
this.minExecutionTime = 1;
97103
}
@@ -106,10 +112,11 @@ export class SequencerTimetable {
106112
this.initializationOffset = this.checkpointInitializationTime;
107113

108114
// Calculate total checkpoint finalization time (assembly + attestations + L1 publishing)
109-
this.checkpointFinalizationTime =
110-
this.checkpointAssembleTime +
111-
this.p2pPropagationTime * 2 + // Round-trip propagation
112-
this.l1PublishingTime; // L1 publishing
115+
this.checkpointFinalizationTime = getCheckpointFinalizationTimeSeconds({
116+
ethereumSlotDuration: this.ethereumSlotDuration,
117+
l1PublishingTime: this.l1PublishingTime,
118+
p2pPropagationTime: this.p2pPropagationTime,
119+
});
113120

114121
// Calculate maximum number of blocks that fit in this slot
115122
if (!this.blockDuration) {

yarn-project/stdlib/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
"./interfaces/prover-config": "./dest/interfaces/prover-client.js",
5151
"./interfaces/api-limit": "./dest/interfaces/api_limit.js",
5252
"./epoch-helpers": "./dest/epoch-helpers/index.js",
53+
"./timetable": "./dest/timetable/index.js",
54+
"./timetable/constants": "./dest/timetable/constants.js",
5355
"./config": "./dest/config/index.js",
5456
"./testing/jest": "./dest/tests/jest.js",
5557
"./database-version": "./dest/database-version/index.js",

yarn-project/stdlib/src/interfaces/validator.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,10 @@ export type ValidatorClientConfig = ValidatorHASignerConfig & {
5959
};
6060

6161
export type ValidatorClientFullConfig = ValidatorClientConfig &
62-
Pick<SequencerConfig, 'txPublicSetupAllowList' | 'broadcastInvalidBlockProposal'> &
62+
Pick<
63+
SequencerConfig,
64+
'txPublicSetupAllowList' | 'broadcastInvalidBlockProposal' | 'attestationPropagationTime' | 'l1PublishingTime'
65+
> &
6366
Pick<SlasherConfig, 'slashBroadcastedInvalidBlockPenalty'> & {
6467
/**
6568
* Whether transactions are disabled for this node
@@ -86,6 +89,8 @@ export const ValidatorClientFullConfigSchema = zodFor<Omit<ValidatorClientFullCo
8689
ValidatorClientConfigSchema.extend({
8790
txPublicSetupAllowList: z.array(AllowedElementSchema).optional(),
8891
broadcastInvalidBlockProposal: z.boolean().optional(),
92+
attestationPropagationTime: z.number().optional(),
93+
l1PublishingTime: z.number().optional(),
8994
slashBroadcastedInvalidBlockPenalty: schemas.BigInt,
9095
disableTransactions: z.boolean().optional(),
9196
}),
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Shared timing defaults used by the sequencer timetable and validator/p2p deadline cutoffs.
3+
*
4+
* Keep these in stdlib so components can agree on timing without importing sequencer-client
5+
* (which would create dependency cycles).
6+
*/
7+
8+
/** Default one-way p2p propagation time (seconds). */
9+
export const DEFAULT_ATTESTATION_PROPAGATION_TIME_SECONDS = 2;
10+
11+
/** Default time spent assembling a checkpoint after building the last block (seconds). */
12+
export const DEFAULT_CHECKPOINT_ASSEMBLE_TIME_SECONDS = 1;
13+
14+
/**
15+
* In test environments we often shorten the L1 slot duration; the sequencer timetable assumes
16+
* faster propagation/assembly in that case. This threshold matches that behavior.
17+
*/
18+
export const TEST_FAST_TIMING_ETHEREUM_SLOT_THRESHOLD_SECONDS = 8;
19+
20+
/** Checkpoint assembly time (seconds) when running with shortened L1 slots (test mode). */
21+
export const TEST_CHECKPOINT_ASSEMBLE_TIME_SECONDS = 0.5;
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import {
2+
DEFAULT_ATTESTATION_PROPAGATION_TIME_SECONDS,
3+
DEFAULT_CHECKPOINT_ASSEMBLE_TIME_SECONDS,
4+
TEST_CHECKPOINT_ASSEMBLE_TIME_SECONDS,
5+
TEST_FAST_TIMING_ETHEREUM_SLOT_THRESHOLD_SECONDS,
6+
} from './constants.js';
7+
8+
export * from './constants.js';
9+
10+
/**
11+
* Returns the amount of time reserved at the end of an Aztec slot (in seconds) for checkpoint finalization.
12+
*/
13+
export function getCheckpointFinalizationTimeSeconds(opts: {
14+
ethereumSlotDuration: number;
15+
l1PublishingTime?: number;
16+
p2pPropagationTime?: number;
17+
}): number {
18+
const l1PublishingTime = opts.l1PublishingTime ?? opts.ethereumSlotDuration;
19+
let p2pPropagationTime = opts.p2pPropagationTime ?? DEFAULT_ATTESTATION_PROPAGATION_TIME_SECONDS;
20+
let checkpointAssembleTime = DEFAULT_CHECKPOINT_ASSEMBLE_TIME_SECONDS;
21+
22+
// Assume zero-cost propagation and faster runs in test environments where L1 slot duration is shortened
23+
if (opts.ethereumSlotDuration < TEST_FAST_TIMING_ETHEREUM_SLOT_THRESHOLD_SECONDS) {
24+
p2pPropagationTime = 0;
25+
checkpointAssembleTime = TEST_CHECKPOINT_ASSEMBLE_TIME_SECONDS;
26+
}
27+
28+
return checkpointAssembleTime + p2pPropagationTime * 2 + l1PublishingTime;
29+
}
30+
31+
/** Convenience helper: checkpoint finalization window in milliseconds. */
32+
export function getCheckpointFinalizationTimeMs(opts: {
33+
ethereumSlotDuration: number;
34+
l1PublishingTime?: number;
35+
p2pPropagationTime?: number;
36+
}): number {
37+
return Math.ceil(getCheckpointFinalizationTimeSeconds(opts) * 1000);
38+
}

yarn-project/validator-client/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,6 @@ Time | Proposer | Validator
161161
| `fishermanMode` | Validate proposals but don't broadcast attestations (monitoring only) |
162162
| `alwaysReexecuteBlockProposals` | Force re-execution even when not in committee |
163163
| `slashBroadcastedInvalidBlockPenalty` | Penalty amount for invalid proposals (0 = disabled) |
164-
| `validatorReexecuteDeadlineMs` | Time reserved at end of slot for propagation/publishing |
165164
| `attestationPollingIntervalMs` | How often to poll for attestations when collecting |
166165
| `disabledValidators` | Validator addresses to exclude from duties |
167166

0 commit comments

Comments
 (0)