Skip to content

Commit 1c64119

Browse files
authored
Merge pull request #2250 from opentensor/mevshield-fix-spam-attack-vector
MevShield Charge & Refund for `announce_next_key`
2 parents c1d3071 + 45f6371 commit 1c64119

File tree

2 files changed

+82
-8
lines changed

2 files changed

+82
-8
lines changed

pallets/shield/src/lib.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -249,12 +249,13 @@ pub mod pallet {
249249
.saturating_add(T::DbWeight::get().reads(1_u64))
250250
.saturating_add(T::DbWeight::get().writes(1_u64)),
251251
DispatchClass::Operational,
252-
Pays::No
252+
Pays::Yes
253253
))]
254+
#[allow(clippy::useless_conversion)]
254255
pub fn announce_next_key(
255256
origin: OriginFor<T>,
256257
public_key: BoundedVec<u8, ConstU32<2048>>,
257-
) -> DispatchResult {
258+
) -> DispatchResultWithPostInfo {
258259
// Only a current Aura validator may call this (signed account ∈ Aura authorities)
259260
T::AuthorityOrigin::ensure_validator(origin)?;
260261

@@ -264,9 +265,13 @@ pub mod pallet {
264265
Error::<T>::BadPublicKeyLen
265266
);
266267

267-
NextKey::<T>::put(public_key.clone());
268+
NextKey::<T>::put(public_key);
268269

269-
Ok(())
270+
// Refund the fee on success by setting pays_fee = Pays::No
271+
Ok(PostDispatchInfo {
272+
actual_weight: None,
273+
pays_fee: Pays::No,
274+
})
270275
}
271276

272277
/// Users submit an encrypted wrapper.
@@ -340,7 +345,7 @@ pub mod pallet {
340345
Weight::from_parts(77_280_000, 0)
341346
.saturating_add(T::DbWeight::get().reads(4_u64))
342347
.saturating_add(T::DbWeight::get().writes(1_u64)),
343-
DispatchClass::Operational,
348+
DispatchClass::Normal,
344349
Pays::No
345350
))]
346351
#[allow(clippy::useless_conversion)]
@@ -425,7 +430,7 @@ pub mod pallet {
425430
Weight::from_parts(13_260_000, 0)
426431
.saturating_add(T::DbWeight::get().reads(1_u64))
427432
.saturating_add(T::DbWeight::get().writes(1_u64)),
428-
DispatchClass::Operational,
433+
DispatchClass::Normal,
429434
Pays::No
430435
))]
431436
pub fn mark_decryption_failed(
@@ -481,7 +486,7 @@ pub mod pallet {
481486
// Only allow locally-submitted / already-in-block txs.
482487
TransactionSource::Local | TransactionSource::InBlock => {
483488
ValidTransaction::with_tag_prefix("mev-shield-exec")
484-
.priority(u64::MAX)
489+
.priority(1u64)
485490
.longevity(64) // long because propagate(false)
486491
.and_provides(id) // dedupe by wrapper id
487492
.propagate(false) // CRITICAL: no gossip, stays on author node
@@ -494,7 +499,7 @@ pub mod pallet {
494499
match source {
495500
TransactionSource::Local | TransactionSource::InBlock => {
496501
ValidTransaction::with_tag_prefix("mev-shield-failed")
497-
.priority(u64::MAX)
502+
.priority(1u64)
498503
.longevity(64) // long because propagate(false)
499504
.and_provides(id) // dedupe by wrapper id
500505
.propagate(false) // CRITICAL: no gossip, stays on author node

pallets/shield/src/tests.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,3 +660,72 @@ fn mark_decryption_failed_removes_submission_and_emits_event() {
660660
assert_noop!(res, pallet_mev_shield::Error::<Test>::MissingSubmission);
661661
});
662662
}
663+
664+
#[test]
665+
fn announce_next_key_charges_then_refunds_fee() {
666+
new_test_ext().execute_with(|| {
667+
const KYBER_PK_LEN: usize = 1184;
668+
669+
// ---------------------------------------------------------------------
670+
// 1. Seed Aura authorities with a single validator and derive account.
671+
// ---------------------------------------------------------------------
672+
let validator_pair = test_sr25519_pair();
673+
let validator_account: AccountId32 = validator_pair.public().into();
674+
let validator_aura_id: <Test as pallet_aura::Config>::AuthorityId =
675+
validator_pair.public().into();
676+
677+
let authorities: BoundedVec<
678+
<Test as pallet_aura::Config>::AuthorityId,
679+
<Test as pallet_aura::Config>::MaxAuthorities,
680+
> = BoundedVec::truncate_from(vec![validator_aura_id]);
681+
pallet_aura::Authorities::<Test>::put(authorities);
682+
683+
// ---------------------------------------------------------------------
684+
// 2. Build a valid Kyber public key and the corresponding RuntimeCall.
685+
// ---------------------------------------------------------------------
686+
let pk_bytes = vec![42u8; KYBER_PK_LEN];
687+
let bounded_pk: BoundedVec<u8, FrameConstU32<2048>> =
688+
BoundedVec::truncate_from(pk_bytes.clone());
689+
690+
let runtime_call = RuntimeCall::MevShield(MevShieldCall::<Test>::announce_next_key {
691+
public_key: bounded_pk.clone(),
692+
});
693+
694+
// ---------------------------------------------------------------------
695+
// 3. Pre-dispatch: DispatchInfo must say Pays::Yes.
696+
// ---------------------------------------------------------------------
697+
let pre_info = <RuntimeCall as frame_support::dispatch::GetDispatchInfo>::get_dispatch_info(
698+
&runtime_call,
699+
);
700+
701+
assert_eq!(
702+
pre_info.pays_fee,
703+
frame_support::dispatch::Pays::Yes,
704+
"announce_next_key must be declared as fee-paying at pre-dispatch"
705+
);
706+
707+
// ---------------------------------------------------------------------
708+
// 4. Dispatch via the pallet function.
709+
// ---------------------------------------------------------------------
710+
let post = MevShield::announce_next_key(
711+
RuntimeOrigin::signed(validator_account.clone()),
712+
bounded_pk.clone(),
713+
)
714+
.expect("announce_next_key should succeed for an Aura validator");
715+
716+
// Post-dispatch info should switch pays_fee from Yes -> No (refund).
717+
assert_eq!(
718+
post.pays_fee,
719+
frame_support::dispatch::Pays::No,
720+
"announce_next_key must refund the previously chargeable fee"
721+
);
722+
723+
// And we don't override the actual weight (None => use pre-dispatch weight).
724+
assert!(
725+
post.actual_weight.is_none(),
726+
"announce_next_key should not override actual_weight in PostDispatchInfo"
727+
);
728+
let next = NextKey::<Test>::get().expect("NextKey should be set by announce_next_key");
729+
assert_eq!(next, pk_bytes);
730+
});
731+
}

0 commit comments

Comments
 (0)