@@ -13,6 +13,26 @@ use std::{
1313 sync:: { Arc , Mutex } ,
1414} ;
1515
16+ /// Truncate a UTF-8 string to at most `max_bytes` bytes without splitting codepoints.
17+ fn truncate_utf8_to_bytes ( s : & str , max_bytes : usize ) -> String {
18+ if s. len ( ) <= max_bytes {
19+ return s. to_string ( ) ;
20+ }
21+
22+ let mut end = max_bytes. min ( s. len ( ) ) ;
23+
24+ // Decrement until we find a valid UTF-8 boundary.
25+ while end > 0 {
26+ if let Some ( prefix) = s. get ( ..end) {
27+ return prefix. to_string ( ) ;
28+ }
29+ end = end. saturating_sub ( 1 ) ;
30+ }
31+
32+ // If max_bytes was 0 or we couldn't find a boundary (extremely defensive), return empty.
33+ String :: new ( )
34+ }
35+
1636/// Helper to build a `mark_decryption_failed` runtime call with a bounded reason string.
1737fn create_failed_call ( id : H256 , reason : & str ) -> node_subtensor_runtime:: RuntimeCall {
1838 use sp_runtime:: BoundedVec ;
@@ -587,8 +607,7 @@ pub fn spawn_revealer<B, C, Pool>(
587607 ss32. copy_from_slice ( ss_bytes) ;
588608
589609 let ss_hash = sp_core:: hashing:: blake2_256 ( & ss32) ;
590- let aead_key =
591- crate :: mev_shield:: author:: derive_aead_key ( & ss32) ;
610+ let aead_key = crate :: mev_shield:: author:: derive_aead_key ( & ss32) ;
592611 let key_hash_dbg = sp_core:: hashing:: blake2_256 ( & aead_key) ;
593612
594613 log:: debug!(
@@ -643,8 +662,6 @@ pub fn spawn_revealer<B, C, Pool>(
643662 plaintext. len( )
644663 ) ;
645664
646- // Safely parse plaintext layout without panics.
647-
648665 if plaintext. is_empty ( ) {
649666 let error_message = "plaintext too short" ;
650667 log:: debug!(
@@ -731,22 +748,40 @@ pub fn spawn_revealer<B, C, Pool>(
731748 ) ;
732749 }
733750 Err ( e) => {
751+ // Emit an on-chain failure event even when the *inner*
752+ // transaction fails pre-dispatch validation in the pool.
753+ let err_dbg = format ! ( "{e:?}" ) ;
754+ let reason = truncate_utf8_to_bytes (
755+ & format ! (
756+ "inner extrinsic rejected by tx-pool (pre-dispatch): {err_dbg}"
757+ ) ,
758+ 240 ,
759+ ) ;
734760 log:: debug!(
735761 target: "mev-shield" ,
736- " id=0x{}: submit_one(...) FAILED: {:?}" ,
762+ " id=0x{}: submit_one(...) FAILED (will mark_decryption_failed) : {:?}" ,
737763 hex:: encode( id. as_bytes( ) ) ,
738764 e
739765 ) ;
766+ failed_calls. push ( ( id, create_failed_call ( id, & reason) ) ) ;
740767 }
741768 }
742769 }
743770 Err ( e) => {
771+ let err_dbg = format ! ( "{e:?}" ) ;
772+ let reason = truncate_utf8_to_bytes (
773+ & format ! (
774+ "invalid decrypted extrinsic bytes (OpaqueExtrinsic::from_bytes): {err_dbg}"
775+ ) ,
776+ 240 ,
777+ ) ;
744778 log:: debug!(
745779 target: "mev-shield" ,
746- " id=0x{}: OpaqueExtrinsic::from_bytes failed: {:?}" ,
780+ " id=0x{}: OpaqueExtrinsic::from_bytes failed (will mark_decryption_failed) : {:?}" ,
747781 hex:: encode( id. as_bytes( ) ) ,
748782 e
749783 ) ;
784+ failed_calls. push ( ( id, create_failed_call ( id, & reason) ) ) ;
750785 }
751786 }
752787 }
0 commit comments