Skip to content
Closed
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.

4 changes: 4 additions & 0 deletions yarn-project/end-to-end/src/fixtures/setup_p2p_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ export type CreateNodeConfig = AztecNodeConfig & {
dontStartSequencer?: boolean;
/** Override the private key (instead of deriving from addressIndex). */
validatorPrivateKey?: `0x${string}`;
/** Corrupt only the block proposal at this indexWithinCheckpoint (testing only). */
invalidBlockProposalIndexWithinCheckpoint?: number;
/** Accept proposal gossip regardless of slot timing (testing only). */
skipProposalSlotValidation?: boolean;
};

/** Creates a P2P enabled instance of Aztec Node Service with a validator. */
Expand Down
7 changes: 7 additions & 0 deletions yarn-project/p2p/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,9 @@ export interface P2PConfig

/** Drop incoming block and checkpoint proposals at the libp2p dispatch layer (for testing only) */
skipIncomingProposals?: boolean;

/** Accept proposal gossip regardless of slot timing (for testing only). */
skipProposalSlotValidation?: boolean;
}

export const DEFAULT_P2P_PORT = 40400;
Expand Down Expand Up @@ -530,6 +533,10 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
description: 'Drop incoming block and checkpoint proposals at the libp2p dispatch layer (for testing only)',
...booleanConfigHelper(false),
},
skipProposalSlotValidation: {
description: 'Accept proposal gossip regardless of slot timing (for testing only)',
...booleanConfigHelper(false),
},
minTxPoolAgeMs: {
env: 'P2P_MIN_TX_POOL_AGE_MS',
description: 'Minimum age (ms) a transaction must have been in the pool before it is eligible for block building.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export class BlockProposalValidator implements P2PValidator<BlockProposal> {
maxTxsPerBlock?: number;
maxBlocksPerCheckpoint?: number;
p2pPropagationTime?: number;
skipSlotValidation?: boolean;
signatureContext: CoordinationSignatureContext;
},
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export class CheckpointProposalValidator implements P2PValidator<CheckpointPropo
maxTxsPerBlock?: number;
maxBlocksPerCheckpoint?: number;
p2pPropagationTime?: number;
skipSlotValidation?: boolean;
signatureContext: CoordinationSignatureContext;
},
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export class ProposalValidator {
private maxTxsPerBlock?: number;
private maxBlocksPerCheckpoint?: number;
private pipeliningWindow: PipeliningWindow;
private skipSlotValidation: boolean;
private signatureContext: CoordinationSignatureContext;

constructor(
Expand All @@ -29,6 +30,7 @@ export class ProposalValidator {
maxTxsPerBlock?: number;
maxBlocksPerCheckpoint?: number;
p2pPropagationTime?: number;
skipSlotValidation?: boolean;
signatureContext: CoordinationSignatureContext;
},
loggerName: string,
Expand All @@ -38,6 +40,7 @@ export class ProposalValidator {
this.maxTxsPerBlock = opts.maxTxsPerBlock;
this.maxBlocksPerCheckpoint = opts.maxBlocksPerCheckpoint;
this.pipeliningWindow = new PipeliningWindow(epochCache, { p2pPropagationTime: opts.p2pPropagationTime });
this.skipSlotValidation = opts.skipSlotValidation ?? false;
this.signatureContext = opts.signatureContext;
this.logger = createLogger(loggerName);
}
Expand All @@ -60,7 +63,7 @@ export class ProposalValidator {
const { targetSlot, nextSlot } = this.epochCache.getTargetAndNextSlot();

const slotNumber = proposal.slotNumber;
if (slotNumber !== targetSlot && slotNumber !== nextSlot) {
if (!this.skipSlotValidation && slotNumber !== targetSlot && slotNumber !== nextSlot) {
// When pipelining, accept proposals for the current slot (built in the previous slot)
// if they're still within the shared proposal acceptance window.
if (this.pipeliningWindow.acceptsProposal(slotNumber)) {
Expand Down
1 change: 1 addition & 0 deletions yarn-project/p2p/src/services/libp2p/libp2p_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ export class LibP2PService extends WithTracer implements P2PService {
maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint,
p2pPropagationTime,
skipSlotValidation: config.skipProposalSlotValidation,
signatureContext: {
chainId: config.l1ChainId,
rollupAddress: config.l1Contracts.rollupAddress,
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 @@ -191,6 +191,9 @@ export const sequencerConfigMappings: ConfigMappingsType<SequencerConfig> = {
description: 'Broadcast invalid block proposals with corrupted state (for testing only)',
...booleanConfigHelper(DefaultSequencerConfig.broadcastInvalidBlockProposal),
},
invalidBlockProposalIndexWithinCheckpoint: {
description: 'Broadcast an invalid block proposal only at this indexWithinCheckpoint (for testing only)',
},
injectFakeAttestation: {
description: 'Inject a fake attestation (for testing only)',
...booleanConfigHelper(DefaultSequencerConfig.injectFakeAttestation),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,8 @@ export class CheckpointProposalJob implements Traceable {
);
blocksInCheckpoint = result.blocksInCheckpoint;
blockPendingBroadcast = result.blockPendingBroadcast;
checkpointProposalOptions.broadcastInvalidCheckpointProposal ||=
blocksInCheckpoint.at(-1)?.indexWithinCheckpoint === this.config.invalidBlockProposalIndexWithinCheckpoint;
Comment on lines +610 to +611
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be the blockProposalOptions?

} catch (err) {
// These errors are expected in HA mode, so we yield and let another HA node handle the slot
// The only distinction between the 2 errors is SlashingProtectionError throws when the payload is different,
Expand Down Expand Up @@ -1066,6 +1068,9 @@ export class CheckpointProposalJob implements Traceable {
// `buildSlot` is the wall-clock slot during which the block was actually built.
this.eventEmitter.emit('block-proposed', {
blockNumber: block.number,
blockHash,
checkpointNumber: this.checkpointNumber,
indexWithinCheckpoint: block.indexWithinCheckpoint,
slot: this.targetSlot,
buildSlot: this.slotNow,
});
Expand Down
12 changes: 10 additions & 2 deletions yarn-project/sequencer-client/src/sequencer/events.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
import type { BlockNumber, CheckpointNumber, IndexWithinCheckpoint, SlotNumber } from '@aztec/foundation/branded-types';
import type { BlockHash } from '@aztec/stdlib/block';

import type { Action } from '../publisher/sequencer-publisher.js';
import type { SequencerState } from './utils.js';
Expand All @@ -13,7 +14,14 @@ export type SequencerEvents = {
['proposer-rollup-check-failed']: (args: { reason: string; slot: SlotNumber }) => void;
['block-tx-count-check-failed']: (args: { minTxs: number; availableTxs: number; slot: SlotNumber }) => void;
['block-build-failed']: (args: { reason: string; slot: SlotNumber }) => void;
['block-proposed']: (args: { blockNumber: BlockNumber; slot: SlotNumber; buildSlot: SlotNumber }) => void;
['block-proposed']: (args: {
blockNumber: BlockNumber;
blockHash: BlockHash;
checkpointNumber: CheckpointNumber;
indexWithinCheckpoint: IndexWithinCheckpoint;
slot: SlotNumber;
buildSlot: SlotNumber;
}) => void;
['checkpoint-empty']: (args: { slot: SlotNumber }) => void;
['checkpoint-publish-failed']: (args: {
slot: SlotNumber;
Expand Down
4 changes: 4 additions & 0 deletions yarn-project/stdlib/src/interfaces/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ export interface SequencerConfig {
skipInvalidateBlockAsProposer?: boolean;
/** Broadcast invalid block proposals with corrupted state (for testing only) */
broadcastInvalidBlockProposal?: boolean;
/** Broadcast an invalid block proposal only at this indexWithinCheckpoint (for testing only) */
invalidBlockProposalIndexWithinCheckpoint?: number;
/** Inject a fake attestation (for testing only) */
injectFakeAttestation?: boolean;
/** Inject a malleable attestation with a high-s value (for testing only) */
Expand Down Expand Up @@ -118,6 +120,7 @@ export const SequencerConfigSchema = zodFor<SequencerConfig>()(
secondsBeforeInvalidatingBlockAsCommitteeMember: z.number(),
secondsBeforeInvalidatingBlockAsNonCommitteeMember: z.number(),
broadcastInvalidBlockProposal: z.boolean().optional(),
invalidBlockProposalIndexWithinCheckpoint: z.number().int().nonnegative().optional(),
injectFakeAttestation: z.boolean().optional(),
injectHighSValueAttestation: z.boolean().optional(),
injectUnrecoverableSignatureAttestation: z.boolean().optional(),
Expand Down Expand Up @@ -145,6 +148,7 @@ type SequencerConfigOptionalKeys =
| 'fakeThrowAfterProcessingTxCount'
| 'l1PublishingTime'
| 'txPublicSetupAllowListExtend'
| 'invalidBlockProposalIndexWithinCheckpoint'
| 'minValidTxsPerBlock'
| 'minBlocksForCheckpoint'
| 'maxTxsPerBlock'
Expand Down
13 changes: 12 additions & 1 deletion yarn-project/stdlib/src/interfaces/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ export type ValidatorClientConfig = ValidatorHASignerConfig &
/** Agree to attest to equivocated checkpoint proposals (for testing purposes only) */
attestToEquivocatedProposals?: boolean;

/** Accept proposal validation regardless of slot timing (for testing only) */
skipProposalSlotValidation?: boolean;

/** Maximum L2 gas per block for validation. Proposals exceeding this limit are rejected. */
validateMaxL2BlockGas?: number;

Expand All @@ -80,7 +83,13 @@ export type ValidatorClientConfig = ValidatorHASignerConfig &
};

export type ValidatorClientFullConfig = ValidatorClientConfig &
Pick<SequencerConfig, 'txPublicSetupAllowListExtend' | 'broadcastInvalidBlockProposal' | 'maxBlocksPerCheckpoint'> &
Pick<
SequencerConfig,
| 'txPublicSetupAllowListExtend'
| 'broadcastInvalidBlockProposal'
| 'invalidBlockProposalIndexWithinCheckpoint'
| 'maxBlocksPerCheckpoint'
> &
Pick<
SlasherConfig,
'slashBroadcastedInvalidBlockPenalty' | 'slashDuplicateProposalPenalty' | 'slashDuplicateAttestationPenalty'
Expand All @@ -104,6 +113,7 @@ export const ValidatorClientConfigSchema = zodFor<Omit<ValidatorClientConfig, 'v
skipCheckpointProposalValidation: z.boolean().optional(),
skipPushProposedBlocksToArchiver: z.boolean().optional(),
attestToEquivocatedProposals: z.boolean().optional(),
skipProposalSlotValidation: z.boolean().optional(),
validateMaxL2BlockGas: z.number().optional(),
validateMaxDABlockGas: z.number().optional(),
validateMaxTxsPerBlock: z.number().optional(),
Expand All @@ -115,6 +125,7 @@ export const ValidatorClientFullConfigSchema = zodFor<Omit<ValidatorClientFullCo
ValidatorClientConfigSchema.extend({
txPublicSetupAllowListExtend: z.array(AllowedElementSchema).optional(),
broadcastInvalidBlockProposal: z.boolean().optional(),
invalidBlockProposalIndexWithinCheckpoint: z.number().int().nonnegative().optional(),
maxBlocksPerCheckpoint: z.number().positive().optional(),
slashBroadcastedInvalidBlockPenalty: schemas.BigInt,
slashDuplicateProposalPenalty: schemas.BigInt,
Expand Down
5 changes: 5 additions & 0 deletions yarn-project/stdlib/src/p2p/block_proposal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ export type BlockProposalOptions = {
* Use only for testing.
*/
broadcastInvalidBlockProposal?: boolean;
/**
* Whether to corrupt this specific block proposal.
* Use only for testing.
*/
broadcastInvalidThisBlockProposal?: boolean;
};

/**
Expand Down
4 changes: 4 additions & 0 deletions yarn-project/validator-client/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ export const validatorClientConfigMappings: ConfigMappingsType<ValidatorClientCo
description: 'Agree to attest to equivocated checkpoint proposals (for testing purposes only)',
...booleanConfigHelper(false),
},
skipProposalSlotValidation: {
description: 'Accept proposal validation regardless of slot timing (for testing only)',
...booleanConfigHelper(false),
},
validateMaxL2BlockGas: {
env: 'VALIDATOR_MAX_L2_BLOCK_GAS',
description: 'Maximum L2 block gas for validation. Proposals exceeding this limit are rejected.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export class ValidationService {
options: BlockProposalOptions,
): Promise<BlockProposal> {
// For testing: change the new archive to trigger state_mismatch validation failure
if (options.broadcastInvalidBlockProposal) {
if (options.broadcastInvalidBlockProposal || options.broadcastInvalidThisBlockProposal) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference between the two?

archive = Fr.random();
this.log.warn(`Creating INVALID block proposal for slot ${blockHeader.globalVariables.slotNumber}`);
}
Expand Down
3 changes: 3 additions & 0 deletions yarn-project/validator-client/src/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
txsPermitted: !config.disableTransactions,
maxTxsPerBlock: config.validateMaxTxsPerBlock,
maxBlocksPerCheckpoint: config.maxBlocksPerCheckpoint,
skipSlotValidation: config.skipProposalSlotValidation,
signatureContext: {
chainId: config.l1ChainId,
rollupAddress: config.l1Contracts.rollupAddress,
Expand Down Expand Up @@ -780,6 +781,8 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
{
...options,
broadcastInvalidBlockProposal: this.config.broadcastInvalidBlockProposal,
broadcastInvalidThisBlockProposal:
this.config.invalidBlockProposalIndexWithinCheckpoint === indexWithinCheckpoint,
},
);
this.lastProposedBlock = newProposal;
Expand Down
Loading