@@ -3,7 +3,7 @@ use derivative::Derivative;
33use slot_clock:: SlotClock ;
44use std:: time:: Duration ;
55use strum:: AsRefStr ;
6- use types:: LightClientFinalityUpdate ;
6+ use types:: { Hash256 , LightClientFinalityUpdate , Slot } ;
77
88/// Returned when a light client finality update was not successfully verified. It might not have been verified for
99/// two reasons:
@@ -21,12 +21,37 @@ pub enum Error {
2121 ///
2222 /// Assuming the local clock is correct, the peer has sent an invalid message.
2323 TooEarly ,
24- /// Light client finality update message does not match the locally constructed one.
25- InvalidLightClientFinalityUpdate ,
24+ /// Light client finalized update message does not match the locally constructed one, it has a
25+ /// different signature slot.
26+ MismatchedSignatureSlot { local : Slot , observed : Slot } ,
27+ /// Light client finalized update message does not match the locally constructed one, it has a
28+ /// different finalized block header for the same signature slot.
29+ MismatchedFinalizedHeader {
30+ local_finalized_header_root : Hash256 ,
31+ observed_finalized_header_root : Hash256 ,
32+ signature_slot : Slot ,
33+ } ,
34+ /// Light client finalized update message does not match the locally constructed one, it has a
35+ /// different attested block header for the same signature slot and finalized header.
36+ MismatchedAttestedHeader {
37+ local_attested_header_root : Hash256 ,
38+ observed_attested_header_root : Hash256 ,
39+ finalized_header_root : Hash256 ,
40+ signature_slot : Slot ,
41+ } ,
42+ /// Light client finalized update message does not match the locally constructed one, it has a
43+ /// different proof or sync aggregate for the same slot, attested header and finalized header.
44+ MismatchedProofOrSyncAggregate {
45+ attested_header_root : Hash256 ,
46+ finalized_header_root : Hash256 ,
47+ signature_slot : Slot ,
48+ } ,
2649 /// Signature slot start time is none.
2750 SigSlotStartIsNone ,
2851 /// Failed to construct a LightClientFinalityUpdate from state.
2952 FailedConstructingUpdate ,
53+ /// Silently ignore this light client finality update
54+ Ignore ,
3055}
3156
3257/// Wraps a `LightClientFinalityUpdate` that has been verified for propagation on the gossip network.
@@ -48,7 +73,7 @@ impl<T: BeaconChainTypes> VerifiedLightClientFinalityUpdate<T> {
4873 // verify that enough time has passed for the block to have been propagated
4974 let start_time = chain
5075 . slot_clock
51- . start_of ( * rcv_finality_update. signature_slot ( ) )
76+ . start_of ( rcv_finality_update. signature_slot ( ) )
5277 . ok_or ( Error :: SigSlotStartIsNone ) ?;
5378 let one_third_slot_duration = Duration :: new ( chain. spec . seconds_per_slot / 3 , 0 ) ;
5479 if seen_timestamp + chain. spec . maximum_gossip_clock_disparity ( )
@@ -57,16 +82,76 @@ impl<T: BeaconChainTypes> VerifiedLightClientFinalityUpdate<T> {
5782 return Err ( Error :: TooEarly ) ;
5883 }
5984
85+ if let Some ( latest_broadcasted_finality_update) = chain
86+ . light_client_server_cache
87+ . get_latest_broadcasted_finality_update ( )
88+ {
89+ // Ignore the incoming finality update if we've already broadcasted it
90+ if latest_broadcasted_finality_update == rcv_finality_update {
91+ return Err ( Error :: Ignore ) ;
92+ }
93+
94+ // Ignore the incoming finality update if the latest broadcasted attested header slot
95+ // is greater than the incoming attested header slot.
96+ if latest_broadcasted_finality_update. get_attested_header_slot ( )
97+ > rcv_finality_update. get_attested_header_slot ( )
98+ {
99+ return Err ( Error :: Ignore ) ;
100+ }
101+ }
102+
60103 let latest_finality_update = chain
61104 . light_client_server_cache
62105 . get_latest_finality_update ( )
63106 . ok_or ( Error :: FailedConstructingUpdate ) ?;
64107
65- // verify that the gossiped finality update is the same as the locally constructed one.
108+ // Ignore the incoming finality update if the latest constructed attested header slot
109+ // is greater than the incoming attested header slot.
110+ if latest_finality_update. get_attested_header_slot ( )
111+ > rcv_finality_update. get_attested_header_slot ( )
112+ {
113+ return Err ( Error :: Ignore ) ;
114+ }
115+
116+ // Verify that the gossiped finality update is the same as the locally constructed one.
66117 if latest_finality_update != rcv_finality_update {
67- return Err ( Error :: InvalidLightClientFinalityUpdate ) ;
118+ let signature_slot = latest_finality_update. signature_slot ( ) ;
119+ if signature_slot != rcv_finality_update. signature_slot ( ) {
120+ return Err ( Error :: MismatchedSignatureSlot {
121+ local : signature_slot,
122+ observed : rcv_finality_update. signature_slot ( ) ,
123+ } ) ;
124+ }
125+ let local_finalized_header_root = latest_finality_update. get_finalized_header_root ( ) ;
126+ let observed_finalized_header_root = rcv_finality_update. get_finalized_header_root ( ) ;
127+ if local_finalized_header_root != observed_finalized_header_root {
128+ return Err ( Error :: MismatchedFinalizedHeader {
129+ local_finalized_header_root,
130+ observed_finalized_header_root,
131+ signature_slot,
132+ } ) ;
133+ }
134+ let local_attested_header_root = latest_finality_update. get_attested_header_root ( ) ;
135+ let observed_attested_header_root = rcv_finality_update. get_attested_header_root ( ) ;
136+ if local_attested_header_root != observed_attested_header_root {
137+ return Err ( Error :: MismatchedAttestedHeader {
138+ local_attested_header_root,
139+ observed_attested_header_root,
140+ finalized_header_root : local_finalized_header_root,
141+ signature_slot,
142+ } ) ;
143+ }
144+ return Err ( Error :: MismatchedProofOrSyncAggregate {
145+ attested_header_root : local_attested_header_root,
146+ finalized_header_root : local_finalized_header_root,
147+ signature_slot,
148+ } ) ;
68149 }
69150
151+ chain
152+ . light_client_server_cache
153+ . set_latest_broadcasted_finality_update ( rcv_finality_update. clone ( ) ) ;
154+
70155 Ok ( Self {
71156 light_client_finality_update : rcv_finality_update,
72157 seen_timestamp,
0 commit comments