In our runtime we have a custom implementation of offence reporting. I want to write an adapter for grandpa equivocation offences (implementing the ReportOffence
trait), and have been using the offences pallet as a guide for how to do this.
In the Offences pallet, offence details are stored in a map of (effectively) (Offence::ID, Slot, Offender) => OffenceDetails
(see here). This allows efficient lookup of reports that have already been submitted via HandleEquivocations::is_known_offence
.
The downside seems to be that we can never prune any reports, since otherwise the offence report could (presumably) be replayed by some malicious party, causing an offender to be slashed twice for the same offence. Indeed, checking the chain state of offence.reports()
on polkadot, my browser slows noticeably while downloading and parsing the huge number of accumulated reports. So it appears these are never (or rarely?) pruned.
In my implementation of [ReportOffence
], I would like to to avoid the abovementioned storage bloat if possible. Thus my plan would be to take advantage of the Ord
property of Offence::TimeSlot
. Instead of storing a map of (Offence::ID, Slot, Offender) => OffenceDetails
, I would store (Offence::ID, Offender) => Slot
and then reject any equivocation report for a slot older than slot of the last reported offence.
So, a couple of concrete questions:
- Is there any fundamental reason that offence reports are (or seem to be) stored indefinitely in polkadot, apart from checking for dupliate reports?
- Similarly: Is there any fundamental reason that frame's offences pallet does not implement double-slashing prevention through the
TimeSlot: Ord
trait rather than a hash?