Skip to content

feat: punish confirmed light-client attacks at double-sign severity - #71

Open
giunatale wants to merge 1 commit into
giunatale/feat/offline-detectionfrom
giunatale/feat/lightclient-attack-punishment
Open

feat: punish confirmed light-client attacks at double-sign severity#71
giunatale wants to merge 1 commit into
giunatale/feat/offline-detectionfrom
giunatale/feat/lightclient-attack-punishment

Conversation

@giunatale

@giunatale giunatale commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

A confirmed light-client attack on a consumer was previously detection-only:
the byzantine validators were extracted, logged, and returned — no slashing,
jailing, or tombstoning. That left the cheapest way to attack a consumer chain
unpunished, while the equivalent offence via double-voting was tombstoned.

What

HandleConsumerMisbehaviour now punishes:

  • The misbehaviour is verified as before (chain id and client id match the
    consumer, headers at the same height within the trusting period, genuinely
    conflicting, each valid against its trusted consensus state).
  • Every validator that signed both conflicting headers is punished through the
    same primitive as consumer double-voting — slash, jail, and tombstone at the
    double-sign infraction parameters. The punishment code is now factored and
    shared (punishEquivocation); the two evidence types differ only in
    verification. Already-tombstoned validators are a no-op, so repeated
    submissions stay idempotent.
  • When no byzantine validator can be punished, the provider stops the consumer
    and schedules it for removal rather than no-opping on a proven-compromised
    chain. This covers an amnesia attack, which has no attributable signer by
    construction, and also the case where every extracted signer turns out to be
    unpunishable (all unbonded). This is terminal: nothing moves a consumer out
    of STOPPED, so there is no veto or cancel path — deliberate, since the chain
    has been proven byzantine. Escalation only applies to a LAUNCHED consumer; one
    already stopping is left alone.

Testing

Unit: identifiable byzantine signers are slashed, jailed, and tombstoned at the
double-sign fraction; repeated submission is idempotent; an unidentifiable
attack stops the consumer and schedules removal; a non-launched consumer is not
escalated. Build, lint, and the module suite are green.

HandleConsumerMisbehaviour was detection-only: it verified a light-client
attack and logged the byzantine set but applied no punishment. It now slashes,
jails, and tombstones the validators that signed both conflicting headers at
the DoubleSign infraction severity, identical to vote-level double signing.

The slash/jail/tombstone path is factored into a shared punishEquivocation
primitive that HandleConsumerDoubleVoting also uses, so the two equivocation
paths differ only in how the evidence is verified, not in how the equivocation
is punished.

When an attack is confirmed but no validator can be punished (an amnesia attack
has no identifiable signers; other conflicts may leave only unbonded signers),
the consumer is stopped and scheduled for removal via
StopAndPrepareForConsumerRemoval instead of a silent no-op. The escalation only
fires from the launched phase, so re-submitting the same evidence does not
schedule removal twice.
@giunatale

Copy link
Copy Markdown
Contributor Author

Branched from giunatale/feat/offline-detection (#63).
Opened against that branch so only this PR's commit shows; will retarget to main after #63 lands and this rebases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant