@@ -2,19 +2,23 @@ use crate as pallet_mev_shield;
22use crate :: mock:: * ;
33
44use codec:: Encode ;
5- use frame_support:: pallet_prelude:: ValidateUnsigned ;
6- use frame_support:: traits:: ConstU32 as FrameConstU32 ;
7- use frame_support:: traits:: Hooks ;
8- use frame_support:: { BoundedVec , assert_noop, assert_ok} ;
5+ use frame_support:: {
6+ BoundedVec , assert_noop, assert_ok,
7+ pallet_prelude:: ValidateUnsigned ,
8+ traits:: { ConstU32 as FrameConstU32 , Hooks } ,
9+ } ;
910use frame_system:: pallet_prelude:: BlockNumberFor ;
1011use pallet_mev_shield:: {
1112 Call as MevShieldCall , CurrentKey , Event as MevShieldEvent , KeyHashByBlock , NextKey ,
1213 Submissions ,
1314} ;
14- use sp_core:: Pair ;
15- use sp_core:: sr25519;
16- use sp_runtime:: traits:: { Hash , SaturatedConversion } ;
17- use sp_runtime:: { AccountId32 , MultiSignature , transaction_validity:: TransactionSource } ;
15+ use sp_core:: { Pair , sr25519} ;
16+ use sp_runtime:: {
17+ AccountId32 , MultiSignature , Vec ,
18+ traits:: { Hash , SaturatedConversion } ,
19+ transaction_validity:: TransactionSource ,
20+ } ;
21+ use sp_std:: boxed:: Box ;
1822
1923// Type aliases for convenience in tests.
2024type TestHash = <Test as frame_system:: Config >:: Hash ;
@@ -588,3 +592,140 @@ fn validate_unsigned_accepts_inblock_source_for_execute_revealed() {
588592 assert_ok ! ( validity) ;
589593 } ) ;
590594}
595+
596+ #[ test]
597+ fn mark_decryption_failed_removes_submission_and_emits_event ( ) {
598+ new_test_ext ( ) . execute_with ( || {
599+ System :: set_block_number ( 42 ) ;
600+ let pair = test_sr25519_pair ( ) ;
601+ let who: AccountId32 = pair. public ( ) . into ( ) ;
602+
603+ let commitment: TestHash =
604+ <Test as frame_system:: Config >:: Hashing :: hash ( b"failed-decryption-commitment" ) ;
605+ let ciphertext_bytes = vec ! [ 5u8 ; 8 ] ;
606+ let ciphertext: BoundedVec < u8 , FrameConstU32 < 8192 > > =
607+ BoundedVec :: truncate_from ( ciphertext_bytes. clone ( ) ) ;
608+
609+ assert_ok ! ( MevShield :: submit_encrypted(
610+ RuntimeOrigin :: signed( who. clone( ) ) ,
611+ commitment,
612+ ciphertext. clone( ) ,
613+ ) ) ;
614+
615+ let id: TestHash = <Test as frame_system:: Config >:: Hashing :: hash_of ( & (
616+ who. clone ( ) ,
617+ commitment,
618+ & ciphertext,
619+ ) ) ;
620+
621+ // Sanity: submission exists.
622+ assert ! ( Submissions :: <Test >:: get( id) . is_some( ) ) ;
623+
624+ // Reason we will pass into mark_decryption_failed.
625+ let reason_bytes = b"AEAD decrypt failed" . to_vec ( ) ;
626+ let reason: BoundedVec < u8 , FrameConstU32 < 256 > > =
627+ BoundedVec :: truncate_from ( reason_bytes. clone ( ) ) ;
628+
629+ // Call mark_decryption_failed as unsigned (RuntimeOrigin::none()).
630+ assert_ok ! ( MevShield :: mark_decryption_failed(
631+ RuntimeOrigin :: none( ) ,
632+ id,
633+ reason. clone( ) ,
634+ ) ) ;
635+
636+ // Submission should be removed.
637+ assert ! ( Submissions :: <Test >:: get( id) . is_none( ) ) ;
638+
639+ // Last event should be DecryptionFailed with the correct id and reason.
640+ let events = System :: events ( ) ;
641+ let last = events
642+ . last ( )
643+ . expect ( "an event should be emitted" )
644+ . event
645+ . clone ( ) ;
646+
647+ assert ! (
648+ matches!(
649+ last,
650+ RuntimeEvent :: MevShield (
651+ MevShieldEvent :: <Test >:: DecryptionFailed { id: ev_id, reason: ev_reason }
652+ )
653+ if ev_id == id && ev_reason. to_vec( ) == reason_bytes
654+ ) ,
655+ "expected DecryptionFailed event with correct id & reason"
656+ ) ;
657+
658+ // A second call with the same id should now fail with MissingSubmission.
659+ let res = MevShield :: mark_decryption_failed ( RuntimeOrigin :: none ( ) , id, reason) ;
660+ assert_noop ! ( res, pallet_mev_shield:: Error :: <Test >:: MissingSubmission ) ;
661+ } ) ;
662+ }
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