1414// You should have received a copy of the GNU General Public License
1515// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
1616
17- use crate :: { weights:: WeightInfo , BridgedBlockNumber , BridgedHeader , Config , Error , Pallet } ;
17+ use crate :: {
18+ weights:: WeightInfo , BridgedBlockNumber , BridgedHeader , Config , CurrentAuthoritySet , Error ,
19+ Pallet ,
20+ } ;
1821use bp_header_chain:: {
1922 justification:: GrandpaJustification , max_expected_submit_finality_proof_arguments_size,
2023 ChainWithGrandpa , GrandpaConsensusLogReader ,
2124} ;
2225use bp_runtime:: { BlockNumberOf , OwnedBridgeModule } ;
2326use codec:: Encode ;
2427use frame_support:: { dispatch:: CallableCallFor , traits:: IsSubType , weights:: Weight } ;
28+ use sp_consensus_grandpa:: SetId ;
2529use sp_runtime:: {
2630 traits:: { Header , Zero } ,
2731 transaction_validity:: { InvalidTransaction , TransactionValidity , ValidTransaction } ,
@@ -33,6 +37,9 @@ use sp_runtime::{
3337pub struct SubmitFinalityProofInfo < N > {
3438 /// Number of the finality target.
3539 pub block_number : N ,
40+ /// An identifier of the validators set that has signed the submitted justification.
41+ /// It might be `None` if deprecated version of the `submit_finality_proof` is used.
42+ pub current_set_id : Option < SetId > ,
3643 /// Extra weight that we assume is included in the call.
3744 ///
3845 /// We have some assumptions about headers and justifications of the bridged chain.
@@ -61,9 +68,11 @@ pub struct SubmitFinalityProofHelper<T: Config<I>, I: 'static> {
6168
6269impl < T : Config < I > , I : ' static > SubmitFinalityProofHelper < T , I > {
6370 /// Check that the GRANDPA head provided by the `SubmitFinalityProof` is better than the best
64- /// one we know.
71+ /// one we know. Additionally, checks if `current_set_id` matches the current authority set
72+ /// id, if specified.
6573 pub fn check_obsolete (
6674 finality_target : BlockNumberOf < T :: BridgedChain > ,
75+ current_set_id : Option < SetId > ,
6776 ) -> Result < ( ) , Error < T , I > > {
6877 let best_finalized = crate :: BestFinalized :: < T , I > :: get ( ) . ok_or_else ( || {
6978 log:: trace!(
@@ -85,6 +94,20 @@ impl<T: Config<I>, I: 'static> SubmitFinalityProofHelper<T, I> {
8594 return Err ( Error :: < T , I > :: OldHeader )
8695 }
8796
97+ if let Some ( current_set_id) = current_set_id {
98+ let actual_set_id = <CurrentAuthoritySet < T , I > >:: get ( ) . set_id ;
99+ if current_set_id != actual_set_id {
100+ log:: trace!(
101+ target: crate :: LOG_TARGET ,
102+ "Cannot finalize header signed by unknown authority set: bundled {:?}, best {:?}" ,
103+ current_set_id,
104+ actual_set_id,
105+ ) ;
106+
107+ return Err ( Error :: < T , I > :: InvalidAuthoritySetId )
108+ }
109+ }
110+
88111 Ok ( ( ) )
89112 }
90113
@@ -111,6 +134,18 @@ pub trait CallSubType<T: Config<I, RuntimeCall = Self>, I: 'static>:
111134 return Some ( submit_finality_proof_info_from_args :: < T , I > (
112135 finality_target,
113136 justification,
137+ None ,
138+ ) )
139+ } else if let Some ( crate :: Call :: < T , I > :: submit_finality_proof_ex {
140+ finality_target,
141+ justification,
142+ current_set_id,
143+ } ) = self . is_sub_type ( )
144+ {
145+ return Some ( submit_finality_proof_info_from_args :: < T , I > (
146+ finality_target,
147+ justification,
148+ Some ( * current_set_id) ,
114149 ) )
115150 }
116151
@@ -133,7 +168,10 @@ pub trait CallSubType<T: Config<I, RuntimeCall = Self>, I: 'static>:
133168 return InvalidTransaction :: Call . into ( )
134169 }
135170
136- match SubmitFinalityProofHelper :: < T , I > :: check_obsolete ( finality_target. block_number ) {
171+ match SubmitFinalityProofHelper :: < T , I > :: check_obsolete (
172+ finality_target. block_number ,
173+ finality_target. current_set_id ,
174+ ) {
137175 Ok ( _) => Ok ( ValidTransaction :: default ( ) ) ,
138176 Err ( Error :: < T , I > :: OldHeader ) => InvalidTransaction :: Stale . into ( ) ,
139177 Err ( _) => InvalidTransaction :: Call . into ( ) ,
@@ -150,6 +188,7 @@ impl<T: Config<I>, I: 'static> CallSubType<T, I> for T::RuntimeCall where
150188pub ( crate ) fn submit_finality_proof_info_from_args < T : Config < I > , I : ' static > (
151189 finality_target : & BridgedHeader < T , I > ,
152190 justification : & GrandpaJustification < BridgedHeader < T , I > > ,
191+ current_set_id : Option < SetId > ,
153192) -> SubmitFinalityProofInfo < BridgedBlockNumber < T , I > > {
154193 let block_number = * finality_target. number ( ) ;
155194
@@ -191,28 +230,32 @@ pub(crate) fn submit_finality_proof_info_from_args<T: Config<I>, I: 'static>(
191230 ) ;
192231 let extra_size = actual_call_size. saturating_sub ( max_expected_call_size) ;
193232
194- SubmitFinalityProofInfo { block_number, extra_weight, extra_size }
233+ SubmitFinalityProofInfo { block_number, current_set_id , extra_weight, extra_size }
195234}
196235
197236#[ cfg( test) ]
198237mod tests {
199238 use crate :: {
200239 call_ext:: CallSubType ,
201240 mock:: { run_test, test_header, RuntimeCall , TestBridgedChain , TestNumber , TestRuntime } ,
202- BestFinalized , Config , PalletOperatingMode , WeightInfo ,
241+ BestFinalized , Config , CurrentAuthoritySet , PalletOperatingMode , StoredAuthoritySet ,
242+ SubmitFinalityProofInfo , WeightInfo ,
203243 } ;
204244 use bp_header_chain:: ChainWithGrandpa ;
205245 use bp_runtime:: { BasicOperatingMode , HeaderId } ;
206246 use bp_test_utils:: {
207247 make_default_justification, make_justification_for_header, JustificationGeneratorParams ,
248+ TEST_GRANDPA_SET_ID ,
208249 } ;
209250 use frame_support:: weights:: Weight ;
210251 use sp_runtime:: { testing:: DigestItem , traits:: Header as _, SaturatedConversion } ;
211252
212253 fn validate_block_submit ( num : TestNumber ) -> bool {
213- let bridge_grandpa_call = crate :: Call :: < TestRuntime , ( ) > :: submit_finality_proof {
254+ let bridge_grandpa_call = crate :: Call :: < TestRuntime , ( ) > :: submit_finality_proof_ex {
214255 finality_target : Box :: new ( test_header ( num) ) ,
215256 justification : make_default_justification ( & test_header ( num) ) ,
257+ // not initialized => zero
258+ current_set_id : 0 ,
216259 } ;
217260 RuntimeCall :: check_obsolete_submit_finality_proof ( & RuntimeCall :: Grandpa (
218261 bridge_grandpa_call,
@@ -256,6 +299,18 @@ mod tests {
256299 } ) ;
257300 }
258301
302+ #[ test]
303+ fn extension_rejects_new_header_if_set_id_is_invalid ( ) {
304+ run_test ( || {
305+ // when set id is different from the passed one => tx is rejected
306+ sync_to_header_10 ( ) ;
307+ let next_set = StoredAuthoritySet :: < TestRuntime , ( ) > :: try_new ( vec ! [ ] , 0x42 ) . unwrap ( ) ;
308+ CurrentAuthoritySet :: < TestRuntime , ( ) > :: put ( next_set) ;
309+
310+ assert ! ( !validate_block_submit( 15 ) ) ;
311+ } ) ;
312+ }
313+
259314 #[ test]
260315 fn extension_accepts_new_header ( ) {
261316 run_test ( || {
@@ -266,6 +321,42 @@ mod tests {
266321 } ) ;
267322 }
268323
324+ #[ test]
325+ fn submit_finality_proof_info_is_parsed ( ) {
326+ // when `submit_finality_proof` is used, `current_set_id` is set to `None`
327+ let deprecated_call =
328+ RuntimeCall :: Grandpa ( crate :: Call :: < TestRuntime , ( ) > :: submit_finality_proof {
329+ finality_target : Box :: new ( test_header ( 42 ) ) ,
330+ justification : make_default_justification ( & test_header ( 42 ) ) ,
331+ } ) ;
332+ assert_eq ! (
333+ deprecated_call. submit_finality_proof_info( ) ,
334+ Some ( SubmitFinalityProofInfo {
335+ block_number: 42 ,
336+ current_set_id: None ,
337+ extra_weight: Weight :: zero( ) ,
338+ extra_size: 0 ,
339+ } )
340+ ) ;
341+
342+ // when `submit_finality_proof_ex` is used, `current_set_id` is set to `Some`
343+ let deprecated_call =
344+ RuntimeCall :: Grandpa ( crate :: Call :: < TestRuntime , ( ) > :: submit_finality_proof_ex {
345+ finality_target : Box :: new ( test_header ( 42 ) ) ,
346+ justification : make_default_justification ( & test_header ( 42 ) ) ,
347+ current_set_id : 777 ,
348+ } ) ;
349+ assert_eq ! (
350+ deprecated_call. submit_finality_proof_info( ) ,
351+ Some ( SubmitFinalityProofInfo {
352+ block_number: 42 ,
353+ current_set_id: Some ( 777 ) ,
354+ extra_weight: Weight :: zero( ) ,
355+ extra_size: 0 ,
356+ } )
357+ ) ;
358+ }
359+
269360 #[ test]
270361 fn extension_returns_correct_extra_size_if_call_arguments_are_too_large ( ) {
271362 // when call arguments are below our limit => no refund
@@ -275,9 +366,10 @@ mod tests {
275366 ..Default :: default ( )
276367 } ;
277368 let small_justification = make_justification_for_header ( justification_params) ;
278- let small_call = RuntimeCall :: Grandpa ( crate :: Call :: submit_finality_proof {
369+ let small_call = RuntimeCall :: Grandpa ( crate :: Call :: submit_finality_proof_ex {
279370 finality_target : Box :: new ( small_finality_target) ,
280371 justification : small_justification,
372+ current_set_id : TEST_GRANDPA_SET_ID ,
281373 } ) ;
282374 assert_eq ! ( small_call. submit_finality_proof_info( ) . unwrap( ) . extra_size, 0 ) ;
283375
@@ -291,9 +383,10 @@ mod tests {
291383 ..Default :: default ( )
292384 } ;
293385 let large_justification = make_justification_for_header ( justification_params) ;
294- let large_call = RuntimeCall :: Grandpa ( crate :: Call :: submit_finality_proof {
386+ let large_call = RuntimeCall :: Grandpa ( crate :: Call :: submit_finality_proof_ex {
295387 finality_target : Box :: new ( large_finality_target) ,
296388 justification : large_justification,
389+ current_set_id : TEST_GRANDPA_SET_ID ,
297390 } ) ;
298391 assert_ne ! ( large_call. submit_finality_proof_info( ) . unwrap( ) . extra_size, 0 ) ;
299392 }
@@ -309,9 +402,10 @@ mod tests {
309402
310403 // when there are `REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY` headers => no refund
311404 let justification = make_justification_for_header ( justification_params. clone ( ) ) ;
312- let call = RuntimeCall :: Grandpa ( crate :: Call :: submit_finality_proof {
405+ let call = RuntimeCall :: Grandpa ( crate :: Call :: submit_finality_proof_ex {
313406 finality_target : Box :: new ( finality_target. clone ( ) ) ,
314407 justification,
408+ current_set_id : TEST_GRANDPA_SET_ID ,
315409 } ) ;
316410 assert_eq ! ( call. submit_finality_proof_info( ) . unwrap( ) . extra_weight, Weight :: zero( ) ) ;
317411
@@ -322,9 +416,10 @@ mod tests {
322416 justification. commit . precommits . len ( ) . saturated_into ( ) ,
323417 justification. votes_ancestries . len ( ) . saturated_into ( ) ,
324418 ) ;
325- let call = RuntimeCall :: Grandpa ( crate :: Call :: submit_finality_proof {
419+ let call = RuntimeCall :: Grandpa ( crate :: Call :: submit_finality_proof_ex {
326420 finality_target : Box :: new ( finality_target) ,
327421 justification,
422+ current_set_id : TEST_GRANDPA_SET_ID ,
328423 } ) ;
329424 assert_eq ! ( call. submit_finality_proof_info( ) . unwrap( ) . extra_weight, call_weight) ;
330425 }
0 commit comments