Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit a22edf0

Browse files
andresilvabkchr
authored andcommitted
babe, grandpa: waive fees on valid equivocation report (#6981)
* babe: waive fees on report_equivocation * grandpa: waive fees on report_equivocation * babe: add test for fee waiving on valid equivocation report * grandpa: add test for fee waiving on valid equivocation report * grandpa: remove stray comment
1 parent 79cc67d commit a22edf0

File tree

4 files changed

+147
-19
lines changed

4 files changed

+147
-19
lines changed

frame/babe/src/lib.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@
2424
use codec::{Decode, Encode};
2525
use frame_support::{
2626
decl_error, decl_module, decl_storage,
27+
dispatch::DispatchResultWithPostInfo,
2728
traits::{FindAuthor, Get, KeyOwnerProofSystem, Randomness as RandomnessT},
28-
weights::Weight,
29+
weights::{Pays, Weight},
2930
Parameter,
3031
};
3132
use frame_system::{ensure_none, ensure_signed};
@@ -260,14 +261,14 @@ decl_module! {
260261
origin,
261262
equivocation_proof: EquivocationProof<T::Header>,
262263
key_owner_proof: T::KeyOwnerProof,
263-
) {
264+
) -> DispatchResultWithPostInfo {
264265
let reporter = ensure_signed(origin)?;
265266

266267
Self::do_report_equivocation(
267268
Some(reporter),
268269
equivocation_proof,
269270
key_owner_proof,
270-
)?;
271+
)
271272
}
272273

273274
/// Report authority equivocation/misbehavior. This method will verify
@@ -283,14 +284,14 @@ decl_module! {
283284
origin,
284285
equivocation_proof: EquivocationProof<T::Header>,
285286
key_owner_proof: T::KeyOwnerProof,
286-
) {
287+
) -> DispatchResultWithPostInfo {
287288
ensure_none(origin)?;
288289

289290
Self::do_report_equivocation(
290291
T::HandleEquivocation::block_author(),
291292
equivocation_proof,
292293
key_owner_proof,
293-
)?;
294+
)
294295
}
295296
}
296297
}
@@ -637,13 +638,13 @@ impl<T: Trait> Module<T> {
637638
reporter: Option<T::AccountId>,
638639
equivocation_proof: EquivocationProof<T::Header>,
639640
key_owner_proof: T::KeyOwnerProof,
640-
) -> Result<(), Error<T>> {
641+
) -> DispatchResultWithPostInfo {
641642
let offender = equivocation_proof.offender.clone();
642643
let slot_number = equivocation_proof.slot_number;
643644

644645
// validate the equivocation proof
645646
if !sp_consensus_babe::check_equivocation_proof(equivocation_proof) {
646-
return Err(Error::InvalidEquivocationProof.into());
647+
return Err(Error::<T>::InvalidEquivocationProof.into());
647648
}
648649

649650
let validator_set_count = key_owner_proof.validator_count();
@@ -655,13 +656,13 @@ impl<T: Trait> Module<T> {
655656
// check that the slot number is consistent with the session index
656657
// in the key ownership proof (i.e. slot is for that epoch)
657658
if epoch_index != session_index {
658-
return Err(Error::InvalidKeyOwnershipProof.into());
659+
return Err(Error::<T>::InvalidKeyOwnershipProof.into());
659660
}
660661

661662
// check the membership proof and extract the offender's id
662663
let key = (sp_consensus_babe::KEY_TYPE, offender);
663664
let offender = T::KeyOwnerProofSystem::check_proof(key, key_owner_proof)
664-
.ok_or(Error::InvalidKeyOwnershipProof)?;
665+
.ok_or(Error::<T>::InvalidKeyOwnershipProof)?;
665666

666667
let offence = BabeEquivocationOffence {
667668
slot: slot_number,
@@ -676,9 +677,10 @@ impl<T: Trait> Module<T> {
676677
};
677678

678679
T::HandleEquivocation::report_offence(reporters, offence)
679-
.map_err(|_| Error::DuplicateOffenceReport)?;
680+
.map_err(|_| Error::<T>::DuplicateOffenceReport)?;
680681

681-
Ok(())
682+
// waive the fee since the report is valid and beneficial
683+
Ok(Pays::No.into())
682684
}
683685

684686
/// Submits an extrinsic to report an equivocation. This method will create

frame/babe/src/tests.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use super::{Call, *};
2121
use frame_support::{
2222
assert_err, assert_ok,
2323
traits::{Currency, OnFinalize},
24+
weights::{GetDispatchInfo, Pays},
2425
};
2526
use mock::*;
2627
use pallet_session::ShouldEndSession;
@@ -608,3 +609,61 @@ fn report_equivocation_has_valid_weight() {
608609
.all(|w| w[0] < w[1])
609610
);
610611
}
612+
613+
#[test]
614+
fn valid_equivocation_reports_dont_pay_fees() {
615+
let (pairs, mut ext) = new_test_ext_with_pairs(3);
616+
617+
ext.execute_with(|| {
618+
start_era(1);
619+
620+
let offending_authority_pair = &pairs[0];
621+
622+
// generate an equivocation proof.
623+
let equivocation_proof =
624+
generate_equivocation_proof(0, &offending_authority_pair, CurrentSlot::get());
625+
626+
// create the key ownership proof.
627+
let key_owner_proof = Historical::prove((
628+
sp_consensus_babe::KEY_TYPE,
629+
&offending_authority_pair.public(),
630+
))
631+
.unwrap();
632+
633+
// check the dispatch info for the call.
634+
let info = Call::<Test>::report_equivocation_unsigned(
635+
equivocation_proof.clone(),
636+
key_owner_proof.clone(),
637+
)
638+
.get_dispatch_info();
639+
640+
// it should have non-zero weight and the fee has to be paid.
641+
assert!(info.weight > 0);
642+
assert_eq!(info.pays_fee, Pays::Yes);
643+
644+
// report the equivocation.
645+
let post_info = Babe::report_equivocation_unsigned(
646+
Origin::none(),
647+
equivocation_proof.clone(),
648+
key_owner_proof.clone(),
649+
)
650+
.unwrap();
651+
652+
// the original weight should be kept, but given that the report
653+
// is valid the fee is waived.
654+
assert!(post_info.actual_weight.is_none());
655+
assert_eq!(post_info.pays_fee, Pays::No);
656+
657+
// report the equivocation again which is invalid now since it is
658+
// duplicate.
659+
let post_info =
660+
Babe::report_equivocation_unsigned(Origin::none(), equivocation_proof, key_owner_proof)
661+
.err()
662+
.unwrap()
663+
.post_info;
664+
665+
// the fee is not waived and the original weight is kept.
666+
assert!(post_info.actual_weight.is_none());
667+
assert_eq!(post_info.pays_fee, Pays::Yes);
668+
})
669+
}

frame/grandpa/src/lib.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ use fg_primitives::{
4040
GRANDPA_ENGINE_ID,
4141
};
4242
use frame_support::{
43-
decl_error, decl_event, decl_module, decl_storage, storage, traits::KeyOwnerProofSystem,
44-
Parameter,
43+
decl_error, decl_event, decl_module, decl_storage, dispatch::DispatchResultWithPostInfo,
44+
storage, traits::KeyOwnerProofSystem, weights::Pays, Parameter,
4545
};
4646
use frame_system::{ensure_none, ensure_root, ensure_signed};
4747
use pallet_finality_tracker::OnFinalizationStalled;
@@ -247,14 +247,14 @@ decl_module! {
247247
origin,
248248
equivocation_proof: EquivocationProof<T::Hash, T::BlockNumber>,
249249
key_owner_proof: T::KeyOwnerProof,
250-
) {
250+
) -> DispatchResultWithPostInfo {
251251
let reporter = ensure_signed(origin)?;
252252

253253
Self::do_report_equivocation(
254254
Some(reporter),
255255
equivocation_proof,
256256
key_owner_proof,
257-
)?;
257+
)
258258
}
259259

260260
/// Report voter equivocation/misbehavior. This method will verify the
@@ -271,14 +271,14 @@ decl_module! {
271271
origin,
272272
equivocation_proof: EquivocationProof<T::Hash, T::BlockNumber>,
273273
key_owner_proof: T::KeyOwnerProof,
274-
) {
274+
) -> DispatchResultWithPostInfo {
275275
ensure_none(origin)?;
276276

277277
Self::do_report_equivocation(
278278
T::HandleEquivocation::block_author(),
279279
equivocation_proof,
280280
key_owner_proof,
281-
)?;
281+
)
282282
}
283283

284284
/// Note that the current authority set of the GRANDPA finality gadget has
@@ -520,7 +520,7 @@ impl<T: Trait> Module<T> {
520520
reporter: Option<T::AccountId>,
521521
equivocation_proof: EquivocationProof<T::Hash, T::BlockNumber>,
522522
key_owner_proof: T::KeyOwnerProof,
523-
) -> Result<(), Error<T>> {
523+
) -> DispatchResultWithPostInfo {
524524
// we check the equivocation within the context of its set id (and
525525
// associated session) and round. we also need to know the validator
526526
// set count when the offence since it is required to calculate the
@@ -585,7 +585,10 @@ impl<T: Trait> Module<T> {
585585
set_id,
586586
round,
587587
),
588-
).map_err(|_| Error::<T>::DuplicateOffenceReport)
588+
).map_err(|_| Error::<T>::DuplicateOffenceReport)?;
589+
590+
// waive the fee since the report is valid and beneficial
591+
Ok(Pays::No.into())
589592
}
590593

591594
/// Submits an extrinsic to report an equivocation. This method will create

frame/grandpa/src/tests.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use fg_primitives::ScheduledChange;
2626
use frame_support::{
2727
assert_err, assert_ok,
2828
traits::{Currency, OnFinalize},
29+
weights::{GetDispatchInfo, Pays},
2930
};
3031
use frame_system::{EventRecord, Phase};
3132
use pallet_session::OneSessionHandler;
@@ -865,3 +866,66 @@ fn report_equivocation_has_valid_weight() {
865866
.all(|w| w[0] < w[1])
866867
);
867868
}
869+
870+
#[test]
871+
fn valid_equivocation_reports_dont_pay_fees() {
872+
let authorities = test_authorities();
873+
874+
new_test_ext_raw_authorities(authorities).execute_with(|| {
875+
start_era(1);
876+
877+
let equivocation_key = &Grandpa::grandpa_authorities()[0].0;
878+
let equivocation_keyring = extract_keyring(equivocation_key);
879+
let set_id = Grandpa::current_set_id();
880+
881+
// generate an equivocation proof.
882+
let equivocation_proof = generate_equivocation_proof(
883+
set_id,
884+
(1, H256::random(), 10, &equivocation_keyring),
885+
(1, H256::random(), 10, &equivocation_keyring),
886+
);
887+
888+
// create the key ownership proof.
889+
let key_owner_proof =
890+
Historical::prove((sp_finality_grandpa::KEY_TYPE, &equivocation_key)).unwrap();
891+
892+
// check the dispatch info for the call.
893+
let info = Call::<Test>::report_equivocation_unsigned(
894+
equivocation_proof.clone(),
895+
key_owner_proof.clone(),
896+
)
897+
.get_dispatch_info();
898+
899+
// it should have non-zero weight and the fee has to be paid.
900+
assert!(info.weight > 0);
901+
assert_eq!(info.pays_fee, Pays::Yes);
902+
903+
// report the equivocation.
904+
let post_info = Grandpa::report_equivocation_unsigned(
905+
Origin::none(),
906+
equivocation_proof.clone(),
907+
key_owner_proof.clone(),
908+
)
909+
.unwrap();
910+
911+
// the original weight should be kept, but given that the report
912+
// is valid the fee is waived.
913+
assert!(post_info.actual_weight.is_none());
914+
assert_eq!(post_info.pays_fee, Pays::No);
915+
916+
// report the equivocation again which is invalid now since it is
917+
// duplicate.
918+
let post_info = Grandpa::report_equivocation_unsigned(
919+
Origin::none(),
920+
equivocation_proof,
921+
key_owner_proof,
922+
)
923+
.err()
924+
.unwrap()
925+
.post_info;
926+
927+
// the fee is not waived and the original weight is kept.
928+
assert!(post_info.actual_weight.is_none());
929+
assert_eq!(post_info.pays_fee, Pays::Yes);
930+
})
931+
}

0 commit comments

Comments
 (0)