Skip to content

Commit c661ad6

Browse files
authored
fix: Default slashing to tally in all networks (#16929)
- Sets a common slashing config for all deployments in `chain_l2_config` (tally slashing, no vetoer, fast execution, sentinel enabled). - Disables inactivity offenses if their penalty is set to zero. - Defaults `slashInactivityTargetPercentage` to a valid value (it was zero on some configs). - Defaults `slashInactivityConsecutiveEpochThreshold` to 1 (may change in the near future). - Handles slasher being `none` in `yarn-project/ethereum/src/queries.ts` - Caches slasher address in the slasher clients - Renames `getSlasher` to `getSlasherAddress` to differentiate it from `getSlasherContract`.
2 parents 5be698d + 553043f commit c661ad6

File tree

13 files changed

+85
-117
lines changed

13 files changed

+85
-117
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ export class Sentinel extends (EventEmitter as new () => WatcherEmitter) impleme
190190
}
191191

192192
protected async handleProvenPerformance(epoch: bigint, performance: ValidatorsEpochPerformance) {
193+
if (this.config.slashInactivityPenalty === 0n) {
194+
return;
195+
}
196+
193197
const inactiveValidators = getEntries(performance)
194198
.filter(([_, { missed, total }]) => missed / total >= this.config.slashInactivityTargetPercentage)
195199
.map(([address]) => address);

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

Lines changed: 37 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,40 @@ export type L2ChainConfig = L1ContractsConfig &
3434
sentinelEnabled: boolean;
3535
};
3636

37+
const DefaultSlashConfig = {
38+
/** Tally-style slashing */
39+
slasherFlavor: 'tally',
40+
/** Allow one round for vetoing */
41+
slashingExecutionDelayInRounds: 1,
42+
/** How long for a slash payload to be executed */
43+
slashingLifetimeInRounds: 5,
44+
/** Allow 2 rounds to discover faults */
45+
slashingOffsetInRounds: 2,
46+
/** No slash vetoer */
47+
slashingVetoer: EthAddress.ZERO,
48+
/** Use default slash amounts */
49+
slashAmountSmall: DefaultL1ContractsConfig.slashAmountSmall,
50+
slashAmountMedium: DefaultL1ContractsConfig.slashAmountMedium,
51+
slashAmountLarge: DefaultL1ContractsConfig.slashAmountLarge,
52+
53+
// Slashing stuff
54+
slashMinPenaltyPercentage: 0.5,
55+
slashMaxPenaltyPercentage: 2.0,
56+
slashInactivityTargetPercentage: 0.7,
57+
slashInactivityConsecutiveEpochThreshold: 1,
58+
slashInactivityPenalty: DefaultL1ContractsConfig.slashAmountSmall,
59+
slashPrunePenalty: DefaultL1ContractsConfig.slashAmountSmall,
60+
slashDataWithholdingPenalty: DefaultL1ContractsConfig.slashAmountSmall,
61+
slashProposeInvalidAttestationsPenalty: DefaultL1ContractsConfig.slashAmountLarge,
62+
slashAttestDescendantOfInvalidPenalty: DefaultL1ContractsConfig.slashAmountLarge,
63+
slashUnknownPenalty: DefaultL1ContractsConfig.slashAmountSmall,
64+
slashBroadcastedInvalidBlockPenalty: DefaultL1ContractsConfig.slashAmountMedium,
65+
slashMaxPayloadSize: 50,
66+
slashGracePeriodL2Slots: 32 * 2, // Two epochs from genesis
67+
slashOffenseExpirationRounds: 8,
68+
sentinelEnabled: true,
69+
} satisfies Partial<L2ChainConfig>;
70+
3771
export const stagingIgnitionL2ChainConfig: L2ChainConfig = {
3872
l1ChainId: 11155111,
3973
testAccounts: true,
@@ -55,6 +89,7 @@ export const stagingIgnitionL2ChainConfig: L2ChainConfig = {
5589
publicMetricsCollectFrom: ['sequencer'],
5690

5791
...DefaultL1ContractsConfig,
92+
...DefaultSlashConfig,
5893

5994
/** How many seconds an L1 slot lasts. */
6095
ethereumSlotDuration: 12,
@@ -70,26 +105,6 @@ export const stagingIgnitionL2ChainConfig: L2ChainConfig = {
70105
manaTarget: 0n,
71106
/** The proving cost per mana */
72107
provingCostPerMana: 0n,
73-
74-
slasherFlavor: 'none',
75-
slashAmountSmall: 0n,
76-
slashAmountMedium: 0n,
77-
slashAmountLarge: 0n,
78-
slashMinPenaltyPercentage: 0.5,
79-
slashMaxPenaltyPercentage: 200,
80-
slashInactivityTargetPercentage: 0,
81-
slashInactivityConsecutiveEpochThreshold: 1,
82-
slashInactivityPenalty: 0n,
83-
slashPrunePenalty: 0n,
84-
slashDataWithholdingPenalty: 0n,
85-
slashProposeInvalidAttestationsPenalty: 0n,
86-
slashAttestDescendantOfInvalidPenalty: 0n,
87-
slashBroadcastedInvalidBlockPenalty: 0n,
88-
slashMaxPayloadSize: 50,
89-
slashGracePeriodL2Slots: 0,
90-
slashUnknownPenalty: 0n,
91-
slashOffenseExpirationRounds: 10,
92-
sentinelEnabled: false,
93108
};
94109

95110
export const stagingPublicL2ChainConfig: L2ChainConfig = {
@@ -139,37 +154,8 @@ export const stagingPublicL2ChainConfig: L2ChainConfig = {
139154
provingCostPerMana: DefaultL1ContractsConfig.provingCostPerMana,
140155
/** Exit delay for stakers */
141156
exitDelaySeconds: DefaultL1ContractsConfig.exitDelaySeconds,
142-
/** Tally-style slashing */
143-
slasherFlavor: 'tally',
144-
/** Allow one round for vetoing */
145-
slashingExecutionDelayInRounds: 1,
146-
/** How long for a slash payload to be executed */
147-
slashingLifetimeInRounds: 5,
148-
/** Allow 2 rounds to discover faults */
149-
slashingOffsetInRounds: 2,
150-
/** No slash vetoer */
151-
slashingVetoer: EthAddress.ZERO,
152-
/** Use default slash amounts */
153-
slashAmountSmall: DefaultL1ContractsConfig.slashAmountSmall,
154-
slashAmountMedium: DefaultL1ContractsConfig.slashAmountMedium,
155-
slashAmountLarge: DefaultL1ContractsConfig.slashAmountLarge,
156157

157-
// Slashing stuff
158-
slashMinPenaltyPercentage: 0.5,
159-
slashMaxPenaltyPercentage: 2.0,
160-
slashInactivityTargetPercentage: 0.7,
161-
slashInactivityConsecutiveEpochThreshold: 1,
162-
slashInactivityPenalty: DefaultL1ContractsConfig.slashAmountSmall,
163-
slashPrunePenalty: DefaultL1ContractsConfig.slashAmountSmall,
164-
slashDataWithholdingPenalty: DefaultL1ContractsConfig.slashAmountSmall,
165-
slashProposeInvalidAttestationsPenalty: DefaultL1ContractsConfig.slashAmountLarge,
166-
slashAttestDescendantOfInvalidPenalty: DefaultL1ContractsConfig.slashAmountLarge,
167-
slashUnknownPenalty: DefaultL1ContractsConfig.slashAmountSmall,
168-
slashBroadcastedInvalidBlockPenalty: DefaultL1ContractsConfig.slashAmountMedium,
169-
slashMaxPayloadSize: 50,
170-
slashGracePeriodL2Slots: 32 * 2, // Two epochs from genesis
171-
slashOffenseExpirationRounds: 8,
172-
sentinelEnabled: true,
158+
...DefaultSlashConfig,
173159
};
174160

175161
export const testnetL2ChainConfig: L2ChainConfig = {
@@ -219,37 +205,8 @@ export const testnetL2ChainConfig: L2ChainConfig = {
219205
provingCostPerMana: DefaultL1ContractsConfig.provingCostPerMana,
220206
/** Exit delay for stakers */
221207
exitDelaySeconds: DefaultL1ContractsConfig.exitDelaySeconds,
222-
/** Tally-style slashing */
223-
slasherFlavor: 'tally',
224-
/** Allow one round for vetoing */
225-
slashingExecutionDelayInRounds: 1,
226-
/** How long for a slash payload to be executed */
227-
slashingLifetimeInRounds: 5,
228-
/** Allow 2 rounds to discover faults */
229-
slashingOffsetInRounds: 2,
230-
/** No slash vetoer */
231-
slashingVetoer: EthAddress.ZERO,
232-
/** Use default slash amounts */
233-
slashAmountSmall: DefaultL1ContractsConfig.slashAmountSmall,
234-
slashAmountMedium: DefaultL1ContractsConfig.slashAmountMedium,
235-
slashAmountLarge: DefaultL1ContractsConfig.slashAmountLarge,
236208

237-
// Slashing stuff
238-
slashMinPenaltyPercentage: 0.5,
239-
slashMaxPenaltyPercentage: 2.0,
240-
slashInactivityTargetPercentage: 0.7,
241-
slashInactivityConsecutiveEpochThreshold: 1,
242-
slashInactivityPenalty: DefaultL1ContractsConfig.slashAmountSmall,
243-
slashPrunePenalty: DefaultL1ContractsConfig.slashAmountSmall,
244-
slashDataWithholdingPenalty: DefaultL1ContractsConfig.slashAmountSmall,
245-
slashProposeInvalidAttestationsPenalty: DefaultL1ContractsConfig.slashAmountLarge,
246-
slashAttestDescendantOfInvalidPenalty: DefaultL1ContractsConfig.slashAmountLarge,
247-
slashUnknownPenalty: DefaultL1ContractsConfig.slashAmountSmall,
248-
slashBroadcastedInvalidBlockPenalty: DefaultL1ContractsConfig.slashAmountMedium,
249-
slashMaxPayloadSize: 50,
250-
slashGracePeriodL2Slots: 32 * 2, // Two epochs from genesis
251-
slashOffenseExpirationRounds: 8,
252-
sentinelEnabled: true,
209+
...DefaultSlashConfig,
253210
};
254211

255212
const BOOTNODE_CACHE_DURATION_MS = 60 * 60 * 1000; // 1 hour;

yarn-project/end-to-end/src/e2e_p2p/p2p_network.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ export class P2PNetworkTest {
415415
);
416416

417417
const slasherContract = getContract({
418-
address: getAddress(await rollup.getSlasher()),
418+
address: getAddress(await rollup.getSlasherAddress()),
419419
abi: SlasherAbi,
420420
client: this.ctx.deployL1ContractsValues.l1Client,
421421
});

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ describe('veto slash', () => {
284284

285285
await t.ctx.cheatCodes.eth.stopImpersonating(t.ctx.deployL1ContractsValues.l1ContractAddresses.governanceAddress);
286286

287-
const slasherAddress = await rollup.getSlasher();
287+
const slasherAddress = await rollup.getSlasherAddress();
288288
expect(slasherAddress.toLowerCase()).toEqual(newSlasherAddress.toString().toLowerCase());
289289
debugLogger.info(`\n\nnew slasher address: ${slasherAddress}\n\n`);
290290
const slasher = getContract({
@@ -352,7 +352,7 @@ describe('veto slash', () => {
352352
//##############################//
353353

354354
if (shouldVeto) {
355-
const slasherAddress = await rollup.getSlasher();
355+
const slasherAddress = await rollup.getSlasherAddress();
356356
const { receipt } = await vetoerL1TxUtils.sendAndMonitorTransaction({
357357
to: slasherAddress,
358358
data: encodeFunctionData({

yarn-project/ethereum/src/contracts/empire_slashing_proposer.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,14 @@ export class EmpireSlashingProposerContract extends EventEmitter implements IEmp
3333

3434
constructor(
3535
public readonly client: ViemClient,
36-
address: Hex,
36+
address: Hex | EthAddress,
3737
) {
3838
super();
39-
this.proposer = getContract({ address, abi: EmpireSlashingProposerAbi, client });
39+
this.proposer = getContract({
40+
address: typeof address === 'string' ? address : address.toString(),
41+
abi: EmpireSlashingProposerAbi,
42+
client,
43+
});
4044
}
4145

4246
public get address() {

yarn-project/ethereum/src/contracts/rollup.ts

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { EthAddress } from '@aztec/foundation/eth-address';
33
import type { ViemSignature } from '@aztec/foundation/eth-signature';
44
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
55
import { RollupStorage } from '@aztec/l1-artifacts/RollupStorage';
6-
import { SlasherAbi } from '@aztec/l1-artifacts/SlasherAbi';
76

87
import chunk from 'lodash.chunk';
98
import {
@@ -12,7 +11,6 @@ import {
1211
type Hex,
1312
type StateOverride,
1413
encodeFunctionData,
15-
getAddress,
1614
getContract,
1715
hexToBigInt,
1816
keccak256,
@@ -160,13 +158,12 @@ export class RollupContract {
160158
public async getSlashingProposer(): Promise<
161159
EmpireSlashingProposerContract | TallySlashingProposerContract | undefined
162160
> {
163-
const slasherAddress = await this.rollup.read.getSlasher();
164-
if (EthAddress.fromString(slasherAddress).isZero()) {
161+
const slasher = await this.getSlasherContract();
162+
if (!slasher) {
165163
return undefined;
166164
}
167165

168-
const slasher = getContract({ address: slasherAddress, abi: SlasherAbi, client: this.client });
169-
const proposerAddress = await slasher.read.PROPOSER();
166+
const proposerAddress = await slasher.getProposer();
170167
const proposerAbi = [
171168
{
172169
type: 'function',
@@ -177,7 +174,7 @@ export class RollupContract {
177174
},
178175
] as const;
179176

180-
const proposer = getContract({ address: proposerAddress, abi: proposerAbi, client: this.client });
177+
const proposer = getContract({ address: proposerAddress.toString(), abi: proposerAbi, client: this.client });
181178
const proposerType = await proposer.read.SLASHING_PROPOSER_TYPE();
182179
if (proposerType === SlashingProposerType.Tally.valueOf()) {
183180
return new TallySlashingProposerContract(this.client, proposerAddress);
@@ -298,16 +295,19 @@ export class RollupContract {
298295
};
299296
}
300297

301-
getSlasher() {
298+
getSlasherAddress() {
302299
return this.rollup.read.getSlasher();
303300
}
304301

305302
/**
306303
* Returns a SlasherContract instance for interacting with the slasher contract.
307304
*/
308-
async getSlasherContract(): Promise<SlasherContract> {
309-
const slasherAddress = await this.getSlasher();
310-
return new SlasherContract(this.client, EthAddress.fromString(slasherAddress));
305+
async getSlasherContract(): Promise<SlasherContract | undefined> {
306+
const slasherAddress = EthAddress.fromString(await this.getSlasherAddress());
307+
if (slasherAddress.isZero()) {
308+
return undefined;
309+
}
310+
return new SlasherContract(this.client, slasherAddress);
311311
}
312312

313313
getOwner() {
@@ -319,13 +319,11 @@ export class RollupContract {
319319
}
320320

321321
public async getSlashingProposerAddress() {
322-
const slasherAddress = await this.getSlasher();
323-
const slasher = getContract({
324-
address: getAddress(slasherAddress.toString()),
325-
abi: SlasherAbi,
326-
client: this.client,
327-
});
328-
return EthAddress.fromString(await slasher.read.PROPOSER());
322+
const slasher = await this.getSlasherContract();
323+
if (!slasher) {
324+
return EthAddress.ZERO;
325+
}
326+
return await slasher.getProposer();
329327
}
330328

331329
getBlockReward() {

yarn-project/ethereum/src/deploy_l1_contracts.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1143,7 +1143,7 @@ export const deployL1Contracts = async (
11431143

11441144
// Include Slasher and SlashingProposer (if deployed) in verification data
11451145
try {
1146-
const slasherAddrHex = await rollup.getSlasher();
1146+
const slasherAddrHex = await rollup.getSlasherAddress();
11471147
const slasherAddr = EthAddress.fromString(slasherAddrHex);
11481148
if (!slasherAddr.isZero()) {
11491149
// Slasher constructor: (address _vetoer, address _governance)

yarn-project/ethereum/src/queries.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
import { EthAddress } from '@aztec/foundation/eth-address';
2-
import { SlasherAbi } from '@aztec/l1-artifacts/SlasherAbi';
3-
4-
import { getContract } from 'viem';
52

63
import type { L1ContractsConfig } from './config.js';
74
import { ReadOnlyGovernanceContract } from './contracts/governance.js';
@@ -27,8 +24,7 @@ export async function getL1ContractsConfig(
2724
const rollupAddress = addresses.rollupAddress ?? (await governanceProposer.getRollupAddress());
2825
const rollup = new RollupContract(publicClient, rollupAddress.toString());
2926
const slasherProposer = await rollup.getSlashingProposer();
30-
const slasherAddress = await rollup.getSlasher();
31-
const slasher = getContract({ address: slasherAddress, abi: SlasherAbi, client: publicClient });
27+
const slasher = await rollup.getSlasherContract();
3228

3329
const [
3430
l1StartBlock,
@@ -72,7 +68,7 @@ export async function getL1ContractsConfig(
7268
slasherProposer?.getExecutionDelayInRounds() ?? 0n,
7369
slasherProposer?.type === 'tally' ? slasherProposer.getSlashOffsetInRounds() : 0n,
7470
slasherProposer?.type === 'tally' ? slasherProposer.getSlashingAmounts() : [0n, 0n, 0n],
75-
slasher.read.VETOER(),
71+
slasher?.getVetoer() ?? EthAddress.ZERO,
7672
rollup.getManaTarget(),
7773
rollup.getProvingCostPerMana(),
7874
rollup.getVersion(),
@@ -96,7 +92,7 @@ export async function getL1ContractsConfig(
9692
slashingRoundSizeInEpochs: Number(slashingRoundSize / aztecEpochDuration),
9793
slashingLifetimeInRounds: Number(slashingLifetimeInRounds),
9894
slashingExecutionDelayInRounds: Number(slashingExecutionDelayInRounds),
99-
slashingVetoer: EthAddress.fromString(slashingVetoer),
95+
slashingVetoer,
10096
manaTarget: manaTarget,
10197
provingCostPerMana: provingCostPerMana,
10298
rollupVersion: Number(rollupVersion),

yarn-project/slasher/src/empire_slasher_client.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ describe('EmpireSlasherClient', () => {
173173
settings,
174174
slashFactoryContract,
175175
slashingProposer,
176+
slasherContract,
176177
rollupContract,
177178
[dummyWatcher],
178179
dateProvider,
@@ -641,6 +642,7 @@ class TestEmpireSlasherClient extends EmpireSlasherClient {
641642
settings: EmpireSlasherSettings,
642643
slashFactoryContract: SlashFactoryContract,
643644
slashingProposer: EmpireSlashingProposerContract,
645+
slasher: SlasherContract,
644646
rollup: RollupContract,
645647
watchers: Watcher[],
646648
dateProvider: DateProvider,
@@ -653,6 +655,7 @@ class TestEmpireSlasherClient extends EmpireSlasherClient {
653655
settings,
654656
slashFactoryContract,
655657
slashingProposer,
658+
slasher,
656659
rollup,
657660
watchers,
658661
dateProvider,

yarn-project/slasher/src/empire_slasher_client.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { EmpireSlashingProposerContract, RollupContract } from '@aztec/ethereum';
1+
import { EmpireSlashingProposerContract, RollupContract, SlasherContract } from '@aztec/ethereum';
22
import { sumBigint } from '@aztec/foundation/bigint';
33
import { compactArray, filterAsync, maxBy, pick } from '@aztec/foundation/collection';
44
import { EthAddress } from '@aztec/foundation/eth-address';
@@ -121,6 +121,7 @@ export class EmpireSlasherClient implements ProposerSlashActionProvider, Slasher
121121
private settings: EmpireSlasherSettings,
122122
private slashFactoryContract: SlashFactoryContract,
123123
private slashingProposer: EmpireSlashingProposerContract,
124+
private slasher: SlasherContract,
124125
private rollup: RollupContract,
125126
watchers: Watcher[],
126127
private dateProvider: DateProvider,
@@ -404,8 +405,7 @@ export class EmpireSlasherClient implements ProposerSlashActionProvider, Slasher
404405
}
405406

406407
// Check if the slash payload is vetoed
407-
const slasherContract = await this.rollup.getSlasherContract();
408-
const isVetoed = await slasherContract.isPayloadVetoed(payload.payload);
408+
const isVetoed = await this.slasher.isPayloadVetoed(payload.payload);
409409

410410
if (isVetoed) {
411411
this.log.info(`Payload ${payload.payload} from round ${payload.round} is vetoed, skipping execution`);

0 commit comments

Comments
 (0)