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
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: Ordtrait rather than a hash?