Repository navigation
feat(slasher): warn and expose metrics when own validators are slash targets #24923
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,19 +1,59 @@ | ||
| import { | ||
| type Gauge, | ||
| Metrics, | ||
| type TelemetryClient, | ||
| type UpDownCounter, | ||
| createUpDownCounterWithDefault, | ||
| } from '@aztec/telemetry-client'; | ||
|
|
||
| import { formatEther } from 'viem/utils'; | ||
|
|
||
| export class SlasherMetrics { | ||
| private readonly roundExecuted: UpDownCounter; | ||
| private readonly ownValidatorTargeted: UpDownCounter; | ||
| private readonly ownValidatorSlashedCount: UpDownCounter; | ||
| private readonly ownValidatorSlashedAmount: UpDownCounter; | ||
| private readonly ownValidatorCurrentRoundVotesMax: Gauge; | ||
| private readonly quorumSize: Gauge; | ||
|
|
||
| constructor(client: TelemetryClient, name = 'Slasher') { | ||
| const meter = client.getMeter(name); | ||
| this.roundExecuted = createUpDownCounterWithDefault(meter, Metrics.SLASHER_ROUND_EXECUTED_COUNT); | ||
| this.ownValidatorTargeted = createUpDownCounterWithDefault(meter, Metrics.SLASHER_OWN_VALIDATOR_TARGETED_COUNT); | ||
| this.ownValidatorSlashedCount = createUpDownCounterWithDefault(meter, Metrics.SLASHER_OWN_VALIDATOR_SLASHED_COUNT); | ||
| this.ownValidatorSlashedAmount = createUpDownCounterWithDefault( | ||
| meter, | ||
| Metrics.SLASHER_OWN_VALIDATOR_SLASHED_AMOUNT, | ||
| ); | ||
| this.ownValidatorCurrentRoundVotesMax = meter.createGauge(Metrics.SLASHER_OWN_VALIDATOR_CURRENT_ROUND_VOTES_MAX); | ||
| this.quorumSize = meter.createGauge(Metrics.SLASHER_QUORUM_SIZE); | ||
| } | ||
|
|
||
| public recordRoundExecuted(): void { | ||
| this.roundExecuted.add(1); | ||
| } | ||
|
|
||
| /** Records the quorum a validator must reach in a round to be slashed, so dashboards can plot the threshold. */ | ||
| public recordQuorumSize(quorum: number): void { | ||
| this.quorumSize.record(quorum); | ||
| } | ||
|
|
||
| /** Records that an onchain slashing vote named one of the node's own validators as a target. */ | ||
| public recordOwnValidatorTargeted(): void { | ||
| this.ownValidatorTargeted.add(1); | ||
| } | ||
|
|
||
| /** | ||
| * Records how close the most-voted committee position held by the node's own validators is to quorum this round. | ||
| * Recorded as an absolute value rather than a delta so a vote seen across a round rollover cannot make it drift. | ||
| */ | ||
| public recordCurrentRoundVotesMax(votes: number): void { | ||
| this.ownValidatorCurrentRoundVotesMax.record(votes); | ||
| } | ||
|
Comment on lines
+41
to
+52
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we also scope this by round? Or decrement it when a round ends? Not sure how to best visualize that, but I imagine that an operator would want to see how many times they get targeted per round, to know how far they are from being actually slashed.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we scope by round then it will explode the number of timeseries prometheus has to track.
Yes, this would be better. We should be able to keep track of how which validators were target in a round and when the round changes, reset the coutner to 0.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added a per-round gauge rather than a round label. |
||
|
|
||
| /** Records an executed slash against one of the node's own validators. */ | ||
| public recordOwnValidatorSlashed(amount: bigint): void { | ||
| this.ownValidatorSlashedCount.add(1); | ||
| this.ownValidatorSlashedAmount.add(parseFloat(formatEther(amount))); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this collapse is correct. We should be emitting every
VoteCastevent, without collapsing anything. Adding thiscollapsehere is confusing to consumers of this method.