@@ -2,13 +2,11 @@ use chacha20poly1305::{
22 KeyInit , XChaCha20Poly1305 , XNonce ,
33 aead:: { Aead , Payload } ,
44} ;
5- use frame_system_rpc_runtime_api:: AccountNonceApi ;
65use ml_kem:: { EncodedSizeUser , KemCore , MlKem768 } ;
76use node_subtensor_runtime as runtime;
87use rand:: rngs:: OsRng ;
9- use sp_api:: ProvideRuntimeApi ;
108use sp_core:: blake2_256;
11- use sp_runtime:: { AccountId32 , KeyTypeId } ;
9+ use sp_runtime:: KeyTypeId ;
1210use std:: sync:: { Arc , Mutex } ;
1311use subtensor_macros:: freeze_struct;
1412use tokio:: time:: sleep;
@@ -131,7 +129,7 @@ const AURA_KEY_TYPE: KeyTypeId = KeyTypeId(*b"aura");
131129
132130/// Start background tasks:
133131/// - per-slot ML‑KEM key rotation
134- /// - at ~announce_at_ms announce the next key bytes on chain,
132+ /// - at ~announce_at_ms announce the next key bytes on chain (as an UNSIGNED tx) ,
135133pub fn spawn_author_tasks < B , C , Pool > (
136134 task_spawner : & sc_service:: SpawnTaskHandle ,
137135 client : Arc < C > ,
@@ -141,13 +139,7 @@ pub fn spawn_author_tasks<B, C, Pool>(
141139) -> ShieldContext
142140where
143141 B : sp_runtime:: traits:: Block ,
144- C : sc_client_api:: HeaderBackend < B >
145- + sc_client_api:: BlockchainEvents < B >
146- + ProvideRuntimeApi < B >
147- + Send
148- + Sync
149- + ' static ,
150- C :: Api : AccountNonceApi < B , AccountId32 , u32 > ,
142+ C : sc_client_api:: HeaderBackend < B > + sc_client_api:: BlockchainEvents < B > + Send + Sync + ' static ,
151143 Pool : sc_transaction_pool_api:: TransactionPool < Block = B > + Send + Sync + ' static ,
152144 B :: Extrinsic : From < sp_runtime:: OpaqueExtrinsic > ,
153145{
@@ -156,25 +148,20 @@ where
156148 timing : timing. clone ( ) ,
157149 } ;
158150
151+ // Only run these tasks on nodes that actually have an Aura key in their keystore.
159152 let aura_keys: Vec < sp_core:: sr25519:: Public > = keystore. sr25519_public_keys ( AURA_KEY_TYPE ) ;
153+ if aura_keys. is_empty ( ) {
154+ log:: warn!(
155+ target: "mev-shield" ,
156+ "spawn_author_tasks: no local Aura sr25519 key in keystore; \
157+ this node will NOT announce MEV-Shield keys"
158+ ) ;
159+ return ctx;
160+ }
160161
161- let local_aura_pub = match aura_keys. first ( ) . copied ( ) {
162- Some ( k) => k,
163- None => {
164- log:: warn!(
165- target: "mev-shield" ,
166- "spawn_author_tasks: no local Aura sr25519 key in keystore; \
167- this node will NOT announce MEV-Shield keys"
168- ) ;
169- return ctx;
170- }
171- } ;
172-
173- let aura_account: AccountId32 = local_aura_pub. into ( ) ;
174162 let ctx_clone = ctx. clone ( ) ;
175163 let client_clone = client. clone ( ) ;
176164 let pool_clone = pool. clone ( ) ;
177- let keystore_clone = keystore. clone ( ) ;
178165
179166 // Slot tick / key-announce loop.
180167 task_spawner. spawn (
@@ -243,37 +230,17 @@ where
243230 }
244231 } ;
245232
246- // 🔑 Fetch the current on-chain nonce for the Aura account using the best block hash.
247- let best_hash = client_clone. info ( ) . best_hash ;
248-
249- let nonce: u32 = match client_clone
250- . runtime_api ( )
251- . account_nonce ( best_hash, aura_account. clone ( ) )
252- {
253- Ok ( n) => n,
254- Err ( e) => {
255- log:: debug!(
256- target: "mev-shield" ,
257- "spawn_author_tasks: failed to fetch account nonce for MEV-Shield author: {e:?}" ,
258- ) ;
259- continue ;
260- }
261- } ;
262-
263- // Submit announce_next_key signed with the Aura key using the correct nonce.
233+ // Submit announce_next_key as an UNSIGNED extrinsic (Origin::None).
264234 if let Err ( e) = submit_announce_extrinsic :: < B , C , Pool > (
265235 client_clone. clone ( ) ,
266236 pool_clone. clone ( ) ,
267- keystore_clone. clone ( ) ,
268- local_aura_pub,
269237 next_pk. clone ( ) ,
270- nonce,
271238 )
272239 . await
273240 {
274241 log:: debug!(
275242 target: "mev-shield" ,
276- "announce_next_key submit error (nonce={nonce:?}) : {e:?}"
243+ "announce_next_key unsigned submit error: {e:?}"
277244 ) ;
278245 }
279246
@@ -305,140 +272,47 @@ where
305272 ctx
306273}
307274
308- /// Build & submit the signed `announce_next_key` extrinsic OFF-CHAIN
275+ /// Build & submit the **unsigned** `announce_next_key` extrinsic OFF-CHAIN
309276pub async fn submit_announce_extrinsic < B , C , Pool > (
310277 client : Arc < C > ,
311278 pool : Arc < Pool > ,
312- keystore : sp_keystore:: KeystorePtr ,
313- aura_pub : sp_core:: sr25519:: Public ,
314279 next_public_key : Vec < u8 > ,
315- nonce : u32 ,
316280) -> anyhow:: Result < ( ) >
317281where
318282 B : sp_runtime:: traits:: Block ,
319283 C : sc_client_api:: HeaderBackend < B > + Send + Sync + ' static ,
320284 Pool : sc_transaction_pool_api:: TransactionPool < Block = B > + Send + Sync + ' static ,
321285 B :: Extrinsic : From < sp_runtime:: OpaqueExtrinsic > ,
322- B :: Hash : AsRef < [ u8 ] > ,
323286{
324- use node_subtensor_runtime as runtime;
325- use runtime:: { RuntimeCall , SignedPayload , UncheckedExtrinsic } ;
326-
287+ use runtime:: { RuntimeCall , UncheckedExtrinsic } ;
327288 use sc_transaction_pool_api:: TransactionSource ;
328- use sp_core:: H256 ;
329289 use sp_runtime:: codec:: Encode ;
330- use sp_runtime:: {
331- BoundedVec , MultiSignature ,
332- generic:: Era ,
333- traits:: { ConstU32 , TransactionExtension } ,
334- } ;
335-
336- fn to_h256 < H : AsRef < [ u8 ] > > ( h : H ) -> H256 {
337- let bytes = h. as_ref ( ) ;
338- let mut out = [ 0u8 ; 32 ] ;
339-
340- if bytes. is_empty ( ) {
341- return H256 ( out) ;
342- }
343-
344- let n = bytes. len ( ) . min ( 32 ) ;
345- let src_start = bytes. len ( ) . saturating_sub ( n) ;
346- let dst_start = 32usize . saturating_sub ( n) ;
347-
348- let src_slice = bytes. get ( src_start..) . and_then ( |s| s. get ( ..n) ) ;
349-
350- if let ( Some ( dst) , Some ( src) ) = ( out. get_mut ( dst_start..32 ) , src_slice) {
351- dst. copy_from_slice ( src) ;
352- H256 ( out)
353- } else {
354- // Extremely defensive fallback.
355- H256 ( [ 0u8 ; 32 ] )
356- }
357- }
290+ use sp_runtime:: { BoundedVec , traits:: ConstU32 } ;
358291
359292 type MaxPk = ConstU32 < 2048 > ;
360293 let public_key: BoundedVec < u8 , MaxPk > = BoundedVec :: try_from ( next_public_key)
361294 . map_err ( |_| anyhow:: anyhow!( "public key too long (>2048 bytes)" ) ) ?;
362295
363- // 1) Runtime call carrying the public key bytes.
296+ // Runtime call carrying the public key bytes.
364297 let call = RuntimeCall :: MevShield ( pallet_shield:: Call :: announce_next_key { public_key } ) ;
365298
366- // 2) Build the transaction extensions exactly like the runtime.
367- type Extra = runtime:: TransactionExtensions ;
368- let extra: Extra =
369- (
370- frame_system:: CheckNonZeroSender :: < runtime:: Runtime > :: new ( ) ,
371- frame_system:: CheckSpecVersion :: < runtime:: Runtime > :: new ( ) ,
372- frame_system:: CheckTxVersion :: < runtime:: Runtime > :: new ( ) ,
373- frame_system:: CheckGenesis :: < runtime:: Runtime > :: new ( ) ,
374- frame_system:: CheckEra :: < runtime:: Runtime > :: from ( Era :: Immortal ) ,
375- node_subtensor_runtime:: check_nonce:: CheckNonce :: < runtime:: Runtime > :: from ( nonce) . into ( ) ,
376- frame_system:: CheckWeight :: < runtime:: Runtime > :: new ( ) ,
377- node_subtensor_runtime:: transaction_payment_wrapper:: ChargeTransactionPaymentWrapper :: <
378- runtime:: Runtime ,
379- > :: new ( pallet_transaction_payment:: ChargeTransactionPayment :: <
380- runtime:: Runtime ,
381- > :: from ( 0u64 ) ) ,
382- pallet_subtensor:: transaction_extension:: SubtensorTransactionExtension :: <
383- runtime:: Runtime ,
384- > :: new ( ) ,
385- pallet_drand:: drand_priority:: DrandPriority :: < runtime:: Runtime > :: new ( ) ,
386- frame_metadata_hash_extension:: CheckMetadataHash :: < runtime:: Runtime > :: new ( false ) ,
387- ) ;
388-
389- // 3) Manually construct the `Implicit` tuple that the runtime will also derive.
390- type Implicit = <Extra as TransactionExtension < RuntimeCall > >:: Implicit ;
391-
392- let info = client. info ( ) ;
393- let genesis_h256: H256 = to_h256 ( info. genesis_hash ) ;
394-
395- let implicit: Implicit = (
396- ( ) , // CheckNonZeroSender
397- runtime:: VERSION . spec_version , // CheckSpecVersion::Implicit = u32
398- runtime:: VERSION . transaction_version , // CheckTxVersion::Implicit = u32
399- genesis_h256, // CheckGenesis::Implicit = Hash
400- genesis_h256, // CheckEra::Implicit (Immortal => genesis hash)
401- ( ) , // CheckNonce::Implicit = ()
402- ( ) , // CheckWeight::Implicit = ()
403- ( ) , // ChargeTransactionPaymentWrapper::Implicit = ()
404- ( ) , // SubtensorTransactionExtension::Implicit = ()
405- ( ) , // DrandPriority::Implicit = ()
406- None , // CheckMetadataHash::Implicit = Option<[u8; 32]>
407- ) ;
408-
409- // 4) Build the exact signable payload from call + extra + implicit.
410- let payload: SignedPayload = SignedPayload :: from_raw ( call. clone ( ) , extra. clone ( ) , implicit) ;
411-
412- // 5) Sign with the local Aura key using the same SCALE bytes the runtime expects.
413- let sig_opt = payload
414- . using_encoded ( |bytes| keystore. sr25519_sign ( AURA_KEY_TYPE , & aura_pub, bytes) )
415- . map_err ( |e| anyhow:: anyhow!( "keystore sr25519_sign error: {e:?}" ) ) ?;
416-
417- let sig = sig_opt
418- . ok_or_else ( || anyhow:: anyhow!( "keystore sr25519_sign returned None for Aura key" ) ) ?;
419-
420- let signature: MultiSignature = sig. into ( ) ;
421-
422- // 6) Sender address = AccountId32 derived from the Aura sr25519 public key.
423- let who: AccountId32 = aura_pub. into ( ) ;
424- let address = sp_runtime:: MultiAddress :: Id ( who) ;
425-
426- // 7) Assemble the signed extrinsic and submit it to the pool.
427- let uxt: UncheckedExtrinsic = UncheckedExtrinsic :: new_signed ( call, address, signature, extra) ;
299+ // Build UNSIGNED extrinsic (origin = None) using Frontier's `new_bare`.
300+ let uxt: UncheckedExtrinsic = UncheckedExtrinsic :: new_bare ( call) ;
428301
429302 let xt_bytes = uxt. encode ( ) ;
430- let xt_hash = sp_core :: hashing :: blake2_256 ( & xt_bytes) ;
303+ let xt_hash = blake2_256 ( & xt_bytes) ;
431304 let xt_hash_hex = hex:: encode ( xt_hash) ;
432305
433306 let opaque: sp_runtime:: OpaqueExtrinsic = uxt. into ( ) ;
434307 let xt: <B as sp_runtime:: traits:: Block >:: Extrinsic = opaque. into ( ) ;
435308
436- pool. submit_one ( info. best_hash , TransactionSource :: Local , xt)
309+ let best_hash = client. info ( ) . best_hash ;
310+ pool. submit_one ( best_hash, TransactionSource :: Local , xt)
437311 . await ?;
438312
439313 log:: debug!(
440314 target: "mev-shield" ,
441- "announce_next_key submitted: xt=0x{xt_hash_hex}, nonce={nonce:? }" ,
315+ "announce_next_key (unsigned) submitted: xt=0x{xt_hash_hex}" ,
442316 ) ;
443317
444318 Ok ( ( ) )
0 commit comments