2121/// should be thrown out and which ones should be kept.
2222
2323use codec:: { Decode , Encode } ;
24+ use lru:: LruCache ;
2425use cumulus_client_consensus_common:: ParachainBlockImportMarker ;
2526
2627use sc_consensus:: {
@@ -36,12 +37,41 @@ use sp_consensus_aura::{AuraApi, Slot, SlotDuration};
3637use sp_core:: crypto:: Pair ;
3738use sp_inherents:: { CreateInherentDataProviders , InherentDataProvider } ;
3839use sp_runtime:: traits:: { Block as BlockT , Header as HeaderT } ;
39- use std:: { fmt:: Debug , sync:: Arc } ;
40+ use std:: { fmt:: Debug , num:: NonZeroUsize , sync:: Arc } ;
41+
42+ const LRU_WINDOW : usize = 256 ;
43+ const EQUIVOCATION_LIMIT : usize = 16 ;
44+
45+ struct NaiveEquivocationDefender {
46+ cache : LruCache < u64 , usize > ,
47+ }
48+
49+ impl Default for NaiveEquivocationDefender {
50+ fn default ( ) -> Self {
51+ NaiveEquivocationDefender {
52+ cache : LruCache :: new ( NonZeroUsize :: new ( LRU_WINDOW ) . expect ( "window > 0; qed" ) ) ,
53+ }
54+ }
55+ }
56+
57+ impl NaiveEquivocationDefender {
58+ // return `true` if equivocation is beyond the limit.
59+ fn insert_and_check ( & mut self , slot : Slot ) -> bool {
60+ let val = self . cache . get_or_insert_mut ( * slot, || 0 ) ;
61+ if * val == EQUIVOCATION_LIMIT {
62+ true
63+ } else {
64+ * val += 1 ;
65+ false
66+ }
67+ }
68+ }
4069
4170struct Verifier < P , Client , Block , CIDP > {
4271 client : Arc < Client > ,
4372 create_inherent_data_providers : CIDP ,
4473 slot_duration : SlotDuration ,
74+ defender : NaiveEquivocationDefender ,
4575 telemetry : Option < TelemetryHandle > ,
4676 _marker : std:: marker:: PhantomData < ( Block , P ) > ,
4777}
88118 ) ;
89119
90120 match res {
91- Ok ( ( pre_header, _slot , seal_digest) ) => {
121+ Ok ( ( pre_header, slot , seal_digest) ) => {
92122 telemetry ! (
93123 self . telemetry;
94124 CONSENSUS_TRACE ;
@@ -100,6 +130,14 @@ where
100130 block_params. post_digests . push ( seal_digest) ;
101131 block_params. fork_choice = Some ( ForkChoiceStrategy :: LongestChain ) ;
102132 block_params. post_hash = Some ( post_hash) ;
133+
134+ // Check for and reject egregious amounts of equivocations.
135+ if self . defender . insert_and_check ( slot) {
136+ return Err ( format ! (
137+ "Rejecting block {:?} due to excessive equivocations at slot" ,
138+ post_hash,
139+ ) ) ;
140+ }
103141 } ,
104142 Err ( aura_internal:: SealVerificationError :: Deferred ( hdr, slot) ) => {
105143 telemetry ! (
@@ -207,6 +245,7 @@ where
207245 let verifier = Verifier :: < P , _ , _ , _ > {
208246 client,
209247 create_inherent_data_providers,
248+ defender : NaiveEquivocationDefender :: default ( ) ,
210249 slot_duration,
211250 telemetry,
212251 _marker : std:: marker:: PhantomData ,
0 commit comments