Skip to content

Commit d2ab3bc

Browse files
committed
chore: Separate config vars for prune penalties
We were using the same config variable for the slash penalty for a pruned epoch where the data was and was not made available. This commit adds a new env var so we can set different values for each.
1 parent 49bd6da commit d2ab3bc

File tree

10 files changed

+48
-17
lines changed

10 files changed

+48
-17
lines changed

yarn-project/aztec-node/src/aztec-node/server.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,14 +328,14 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
328328
}
329329

330330
let epochPruneWatcher: EpochPruneWatcher | undefined;
331-
if (config.slashPrunePenalty > 0n) {
331+
if (config.slashPrunePenalty > 0n || config.slashDataWithholdingPenalty > 0n) {
332332
epochPruneWatcher = new EpochPruneWatcher(
333333
archiver,
334334
archiver,
335335
epochCache,
336336
p2pClient.getTxProvider(),
337337
blockBuilder,
338-
config.slashPrunePenalty,
338+
config,
339339
);
340340
await epochPruneWatcher.start();
341341
watchers.push(epochPruneWatcher);

yarn-project/aztec/src/cli/chain_l2_config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ export const testnetIgnitionL2ChainConfig: L2ChainConfig = {
7777
slashInactivityTargetPercentage: 0,
7878
slashInactivityPenalty: 0n,
7979
slashPrunePenalty: 0n,
80+
slashDataWithholdingPenalty: 0n,
8081
slashProposeInvalidAttestationsPenalty: 0n,
8182
slashAttestDescendantOfInvalidPenalty: 0n,
8283
slashBroadcastedInvalidBlockPenalty: 0n,
@@ -153,6 +154,7 @@ export const alphaTestnetL2ChainConfig: L2ChainConfig = {
153154
slashInactivityTargetPercentage: 0.7,
154155
slashInactivityPenalty: DefaultL1ContractsConfig.slashAmountSmall,
155156
slashPrunePenalty: DefaultL1ContractsConfig.slashAmountSmall,
157+
slashDataWithholdingPenalty: DefaultL1ContractsConfig.slashAmountSmall,
156158
slashProposeInvalidAttestationsPenalty: DefaultL1ContractsConfig.slashAmountLarge,
157159
slashAttestDescendantOfInvalidPenalty: DefaultL1ContractsConfig.slashAmountLarge,
158160
slashUnknownPenalty: DefaultL1ContractsConfig.slashAmountSmall,
@@ -322,6 +324,7 @@ export async function enrichEnvironmentWithChainConfig(networkName: NetworkNames
322324
enrichVar('SLASH_MIN_PENALTY_PERCENTAGE', config.slashMinPenaltyPercentage.toString());
323325
enrichVar('SLASH_MAX_PENALTY_PERCENTAGE', config.slashMaxPenaltyPercentage.toString());
324326
enrichVar('SLASH_PRUNE_PENALTY', config.slashPrunePenalty.toString());
327+
enrichVar('SLASH_DATA_WITHHOLDING_PENALTY', config.slashDataWithholdingPenalty.toString());
325328
enrichVar('SLASH_INACTIVITY_TARGET_PERCENTAGE', config.slashInactivityTargetPercentage.toString());
326329
enrichVar('SLASH_INACTIVITY_PENALTY', config.slashInactivityPenalty.toString());
327330
enrichVar('SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY', config.slashProposeInvalidAttestationsPenalty.toString());

yarn-project/end-to-end/src/e2e_p2p/data_withholding_slash.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ describe('e2e_p2p_data_withholding_slash', () => {
103103
const slashingAmount = slashingUnit * 3n;
104104
expect(activationThreshold - slashingAmount).toBeLessThan(ejectionThreshold);
105105

106+
t.ctx.aztecNodeConfig.slashDataWithholdingPenalty = slashingAmount;
106107
t.ctx.aztecNodeConfig.slashPrunePenalty = slashingAmount;
107108
t.ctx.aztecNodeConfig.validatorReexecute = false;
108109
t.ctx.aztecNodeConfig.minTxsPerBlock = 1;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ export type EnvVar =
204204
| 'SLASH_VALIDATORS_ALWAYS'
205205
| 'SLASH_VALIDATORS_NEVER'
206206
| 'SLASH_PRUNE_PENALTY'
207+
| 'SLASH_DATA_WITHHOLDING_PENALTY'
207208
| 'SLASH_INACTIVITY_PENALTY'
208209
| 'SLASH_INACTIVITY_TARGET_PERCENTAGE'
209210
| 'SLASH_INVALID_BLOCK_PENALTY'

yarn-project/slasher/src/config.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export const DefaultSlasherConfig: SlasherConfig = {
1818
slashValidatorsAlways: [], // Empty by default
1919
slashValidatorsNever: [], // Empty by default
2020
slashPrunePenalty: DefaultL1ContractsConfig.slashAmountSmall,
21+
slashDataWithholdingPenalty: DefaultL1ContractsConfig.slashAmountSmall,
2122
slashInactivityTargetPercentage: 0.9,
2223
slashBroadcastedInvalidBlockPenalty: DefaultL1ContractsConfig.slashAmountSmall,
2324
slashInactivityPenalty: DefaultL1ContractsConfig.slashAmountSmall,
@@ -71,9 +72,14 @@ export const slasherConfigMappings: ConfigMappingsType<SlasherConfig> = {
7172
},
7273
slashPrunePenalty: {
7374
env: 'SLASH_PRUNE_PENALTY',
74-
description: 'Penalty amount for slashing validators of a pruned epoch (set to 0 to disable).',
75+
description: 'Penalty amount for slashing validators of a valid pruned epoch (set to 0 to disable).',
7576
...bigintConfigHelper(DefaultSlasherConfig.slashPrunePenalty),
7677
},
78+
slashDataWithholdingPenalty: {
79+
env: 'SLASH_DATA_WITHHOLDING_PENALTY',
80+
description: 'Penalty amount for slashing validators for data withholding (set to 0 to disable).',
81+
...bigintConfigHelper(DefaultSlasherConfig.slashDataWithholdingPenalty),
82+
},
7783
slashBroadcastedInvalidBlockPenalty: {
7884
env: 'SLASH_INVALID_BLOCK_PENALTY',
7985
description: 'Penalty amount for slashing a validator for an invalid block.',

yarn-project/slasher/src/watchers/epoch_prune_watcher.test.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ describe('EpochPruneWatcher', () => {
2828
let txProvider: MockProxy<Pick<ITxProvider, 'getAvailableTxs'>>;
2929
let blockBuilder: MockProxy<IFullNodeBlockBuilder>;
3030
let fork: MockProxy<MerkleTreeWriteOperations>;
31-
const penalty = BigInt(1000000000000000000n);
31+
const validEpochPrunedPenalty = BigInt(1000000000000000000n);
32+
const dataWithholdingPenalty = BigInt(2000000000000000000n);
3233

3334
beforeEach(async () => {
3435
l2BlockSource = new MockL2BlockSource() as unknown as L2BlockSourceEventEmitter;
@@ -40,7 +41,10 @@ describe('EpochPruneWatcher', () => {
4041
fork = mock<MerkleTreeWriteOperations>();
4142
blockBuilder.getFork.mockResolvedValue(fork);
4243

43-
watcher = new EpochPruneWatcher(l2BlockSource, l1ToL2MessageSource, epochCache, txProvider, blockBuilder, penalty);
44+
watcher = new EpochPruneWatcher(l2BlockSource, l1ToL2MessageSource, epochCache, txProvider, blockBuilder, {
45+
slashPrunePenalty: validEpochPrunedPenalty,
46+
slashDataWithholdingPenalty: dataWithholdingPenalty,
47+
});
4448
await watcher.start();
4549
});
4650

@@ -79,13 +83,13 @@ describe('EpochPruneWatcher', () => {
7983
expect(emitSpy).toHaveBeenCalledWith(WANT_TO_SLASH_EVENT, [
8084
{
8185
validator: EthAddress.fromString(committee[0]),
82-
amount: penalty,
86+
amount: dataWithholdingPenalty,
8387
offenseType: OffenseType.DATA_WITHHOLDING,
8488
epochOrSlot: 1n,
8589
},
8690
{
8791
validator: EthAddress.fromString(committee[1]),
88-
amount: penalty,
92+
amount: dataWithholdingPenalty,
8993
offenseType: OffenseType.DATA_WITHHOLDING,
9094
epochOrSlot: 1n,
9195
},
@@ -129,13 +133,13 @@ describe('EpochPruneWatcher', () => {
129133
expect(emitSpy).toHaveBeenCalledWith(WANT_TO_SLASH_EVENT, [
130134
{
131135
validator: EthAddress.fromString(committee[0]),
132-
amount: penalty,
136+
amount: validEpochPrunedPenalty,
133137
offenseType: OffenseType.VALID_EPOCH_PRUNED,
134138
epochOrSlot: 1n,
135139
},
136140
{
137141
validator: EthAddress.fromString(committee[1]),
138-
amount: penalty,
142+
amount: validEpochPrunedPenalty,
139143
offenseType: OffenseType.VALID_EPOCH_PRUNED,
140144
epochOrSlot: 1n,
141145
},

yarn-project/slasher/src/watchers/epoch_prune_watcher.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ import EventEmitter from 'node:events';
2222

2323
import { WANT_TO_SLASH_EVENT, type WantToSlashArgs, type Watcher, type WatcherEmitter } from '../watcher.js';
2424

25+
type EpochPruneWatcherPenalties = {
26+
slashPrunePenalty: bigint;
27+
slashDataWithholdingPenalty: bigint;
28+
};
29+
2530
/**
2631
* This watcher is responsible for detecting chain prunes and creating slashing arguments for the committee.
2732
* It only wants to slash if:
@@ -40,10 +45,12 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
4045
private epochCache: EpochCache,
4146
private txProvider: Pick<ITxProvider, 'getAvailableTxs'>,
4247
private blockBuilder: IFullNodeBlockBuilder,
43-
private penalty: bigint,
48+
private penalties: EpochPruneWatcherPenalties,
4449
) {
4550
super();
46-
this.log.info(`EpochPruneWatcher initialized with penalty ${penalty}`);
51+
this.log.verbose(
52+
`EpochPruneWatcher initialized with penalties: valid epoch pruned=${penalties.slashPrunePenalty} data withholding=${penalties.slashDataWithholdingPenalty}`,
53+
);
4754
}
4855

4956
public start() {
@@ -161,9 +168,13 @@ export class EpochPruneWatcher extends (EventEmitter as new () => WatcherEmitter
161168
offenseType: OffenseType,
162169
epochOrSlot: bigint,
163170
): WantToSlashArgs[] {
171+
const penalty =
172+
offenseType === OffenseType.DATA_WITHHOLDING
173+
? this.penalties.slashDataWithholdingPenalty
174+
: this.penalties.slashPrunePenalty;
164175
return validators.map(v => ({
165176
validator: v,
166-
amount: this.penalty,
177+
amount: penalty,
167178
offenseType,
168179
epochOrSlot,
169180
}));

yarn-project/stdlib/src/interfaces/aztec-node-admin.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ class MockAztecNodeAdmin implements AztecNodeAdmin {
141141
slashValidatorsAlways: [],
142142
slashValidatorsNever: [],
143143
slashPrunePenalty: 1000n,
144+
slashDataWithholdingPenalty: 1000n,
144145
slashInactivityTargetPercentage: 0.5,
145146
slashInactivityPenalty: 1000n,
146147
slashBroadcastedInvalidBlockPenalty: 1n,

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export interface SlasherConfig {
1414
slashValidatorsNever: EthAddress[]; // Array of validator addresses
1515
slashInactivityTargetPercentage: number; // 0-1, 0.9 means 90%. Must be greater than 0
1616
slashPrunePenalty: bigint;
17+
slashDataWithholdingPenalty: bigint;
1718
slashInactivityPenalty: bigint;
1819
slashBroadcastedInvalidBlockPenalty: bigint;
1920
slashProposeInvalidAttestationsPenalty: bigint;
@@ -31,6 +32,7 @@ export const SlasherConfigSchema = z.object({
3132
slashValidatorsAlways: z.array(schemas.EthAddress),
3233
slashValidatorsNever: z.array(schemas.EthAddress),
3334
slashPrunePenalty: schemas.BigInt,
35+
slashDataWithholdingPenalty: schemas.BigInt,
3436
slashInactivityTargetPercentage: z.number(),
3537
slashInactivityPenalty: schemas.BigInt,
3638
slashProposeInvalidAttestationsPenalty: schemas.BigInt,

yarn-project/stdlib/src/slashing/helpers.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,17 @@ export function getPenaltyForOffense(
4848
| 'slashAttestDescendantOfInvalidPenalty'
4949
| 'slashBroadcastedInvalidBlockPenalty'
5050
| 'slashPrunePenalty'
51+
| 'slashDataWithholdingPenalty'
5152
| 'slashUnknownPenalty'
5253
| 'slashInactivityPenalty'
5354
| 'slashProposeInvalidAttestationsPenalty'
5455
>,
5556
) {
5657
switch (offense) {
5758
case OffenseType.VALID_EPOCH_PRUNED:
58-
case OffenseType.DATA_WITHHOLDING:
5959
return config.slashPrunePenalty;
60+
case OffenseType.DATA_WITHHOLDING:
61+
return config.slashDataWithholdingPenalty;
6062
case OffenseType.INACTIVITY:
6163
return config.slashInactivityPenalty;
6264
case OffenseType.PROPOSED_INSUFFICIENT_ATTESTATIONS:
@@ -69,8 +71,8 @@ export function getPenaltyForOffense(
6971
case OffenseType.UNKNOWN:
7072
return config.slashUnknownPenalty;
7173
default: {
72-
const _: never = offense;
73-
throw new Error(`Unknown offense type: ${offense}`);
74+
const _exhaustiveCheck: never = offense;
75+
throw new Error(`Unknown offense type: ${_exhaustiveCheck}`);
7476
}
7577
}
7678
}
@@ -89,8 +91,8 @@ export function getTimeUnitForOffense(offense: OffenseType): 'epoch' | 'slot' {
8991
case OffenseType.VALID_EPOCH_PRUNED:
9092
return 'epoch';
9193
default: {
92-
const _: never = offense;
93-
throw new Error(`Unknown offense type: ${offense}`);
94+
const _exhaustiveCheck: never = offense;
95+
throw new Error(`Unknown offense type: ${_exhaustiveCheck}`);
9496
}
9597
}
9698
}

0 commit comments

Comments
 (0)