diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs index cdb37bb0dd..de7eacbe2f 100644 --- a/pallets/subtensor/src/macros/events.rs +++ b/pallets/subtensor/src/macros/events.rs @@ -279,8 +279,9 @@ mod events { /// A weight set among a batch of weights failed. /// + /// - **netuid**: The netuid of the batch item that failed. /// - **error**: The dispatch error emitted by the failed item. - BatchWeightItemFailed(sp_runtime::DispatchError), + BatchWeightItemFailed(NetUid, sp_runtime::DispatchError), /// Stake has been transferred from one coldkey to another on the same subnet. /// Parameters: diff --git a/pallets/subtensor/src/subnets/weights.rs b/pallets/subtensor/src/subnets/weights.rs index 43e3c7e4ba..39bcfb80b5 100644 --- a/pallets/subtensor/src/subnets/weights.rs +++ b/pallets/subtensor/src/subnets/weights.rs @@ -184,24 +184,27 @@ impl Pallet { Error::::InputLengthsUnequal ); - let results: Vec = netuids + let results: Vec<(NetUid, dispatch::DispatchResult)> = netuids .iter() .zip(commit_hashes.iter()) .map(|(&netuid, &commit_hash)| { let origin_cloned = origin.clone(); - - Self::do_commit_weights(origin_cloned, netuid.into(), commit_hash) + let netuid: NetUid = netuid.into(); + ( + netuid, + Self::do_commit_weights(origin_cloned, netuid, commit_hash), + ) }) .collect(); let mut completed_with_errors: bool = false; - for result in results { + for (netuid, result) in results { if let Some(err) = result.err() { if !completed_with_errors { Self::deposit_event(Event::BatchCompletedWithErrors()); completed_with_errors = true; } - Self::deposit_event(Event::BatchWeightItemFailed(err)); + Self::deposit_event(Event::BatchWeightItemFailed(netuid, err)); } } @@ -1043,39 +1046,37 @@ impl Pallet { Error::::InputLengthsUnequal ); - let results: Vec = netuids + let results: Vec<(NetUid, dispatch::DispatchResult)> = netuids .iter() .zip(weights.iter()) .zip(version_keys.iter()) .map(|((&netuid, w), &version_key)| { let origin_cloned = origin.clone(); + let netuid: NetUid = netuid.into(); - if Self::get_commit_reveal_weights_enabled(netuid.into()) { - return Err(Error::::CommitRevealEnabled.into()); + if Self::get_commit_reveal_weights_enabled(netuid) { + return (netuid, Err(Error::::CommitRevealEnabled.into())); } let uids = w.iter().map(|(u, _)| (*u).into()).collect::>(); let values = w.iter().map(|(_, v)| (*v).into()).collect::>(); - Self::do_set_weights( - origin_cloned, - netuid.into(), - uids, - values, - version_key.into(), + ( + netuid, + Self::do_set_weights(origin_cloned, netuid, uids, values, version_key.into()), ) }) .collect(); let mut completed_with_errors: bool = false; - for result in results { + for (netuid, result) in results { if let Some(err) = result.err() { if !completed_with_errors { Self::deposit_event(Event::BatchCompletedWithErrors()); completed_with_errors = true; } - Self::deposit_event(Event::BatchWeightItemFailed(err)); + Self::deposit_event(Event::BatchWeightItemFailed(netuid, err)); } } diff --git a/pallets/subtensor/src/tests/weights.rs b/pallets/subtensor/src/tests/weights.rs index 36cf17bfd8..05da8520de 100644 --- a/pallets/subtensor/src/tests/weights.rs +++ b/pallets/subtensor/src/tests/weights.rs @@ -2,6 +2,7 @@ use ark_serialize::CanonicalDeserialize; use ark_serialize::CanonicalSerialize; +use codec::Compact; use frame_support::dispatch::DispatchInfo; use frame_support::{ assert_err, assert_ok, @@ -6965,3 +6966,93 @@ fn test_subnet_owner_can_validate_without_stake_or_manual_permit() { )); }); } + +// Regression: when a batch of weight commits has per-item failures, each +// emitted BatchWeightItemFailed event must carry the netuid of the failing +// item so downstream consumers (indexers, validator monitors) can correlate +// failure → subnet without re-deriving from iteration order. +// +// Both netuids in this test fail (commit-reveal disabled on both) — what we +// assert is the *positional propagation*: the per-item events carry the +// distinct netuids that produced them, in iteration order. +#[test] +fn test_batch_commit_weights_item_failure_event_includes_netuid() { + new_test_ext(1).execute_with(|| { + let netuid_a = NetUid::from(1); + let netuid_b = NetUid::from(2); + add_network(netuid_a, 1, 0); + add_network(netuid_b, 1, 0); + SubtensorModule::set_commit_reveal_weights_enabled(netuid_a, false); + SubtensorModule::set_commit_reveal_weights_enabled(netuid_b, false); + + let hotkey = U256::from(1); + let netuids: Vec> = vec![netuid_a.into(), netuid_b.into()]; + let hashes: Vec = vec![H256::repeat_byte(0xAA), H256::repeat_byte(0xBB)]; + + assert_ok!(SubtensorModule::do_batch_commit_weights( + RuntimeOrigin::signed(hotkey), + netuids, + hashes, + )); + + let failures: Vec = System::events() + .iter() + .filter_map(|e| match &e.event { + RuntimeEvent::SubtensorModule(Event::BatchWeightItemFailed(netuid, _err)) => { + Some(*netuid) + } + _ => None, + }) + .collect(); + + assert_eq!( + failures, + vec![netuid_a, netuid_b], + "BatchWeightItemFailed events should carry each failing netuid in batch order" + ); + }); +} + +// Regression: same shape as the commit-path test, but for the set-path +// (`do_batch_set_weights`). Each failing item must emit a +// BatchWeightItemFailed carrying its netuid. +#[test] +fn test_batch_set_weights_item_failure_event_includes_netuid() { + new_test_ext(1).execute_with(|| { + let netuid_a = NetUid::from(3); + let netuid_b = NetUid::from(4); + add_network(netuid_a, 1, 0); + add_network(netuid_b, 1, 0); + // do_set_weights fails iff commit-reveal is ENABLED on the netuid. + SubtensorModule::set_commit_reveal_weights_enabled(netuid_a, true); + SubtensorModule::set_commit_reveal_weights_enabled(netuid_b, true); + + let hotkey = U256::from(11); + let netuids: Vec> = vec![netuid_a.into(), netuid_b.into()]; + let weights: Vec, Compact)>> = vec![vec![], vec![]]; + let version_keys: Vec> = vec![0u64.into(), 0u64.into()]; + + assert_ok!(SubtensorModule::do_batch_set_weights( + RuntimeOrigin::signed(hotkey), + netuids, + weights, + version_keys, + )); + + let failures: Vec = System::events() + .iter() + .filter_map(|e| match &e.event { + RuntimeEvent::SubtensorModule(Event::BatchWeightItemFailed(netuid, _err)) => { + Some(*netuid) + } + _ => None, + }) + .collect(); + + assert_eq!( + failures, + vec![netuid_a, netuid_b], + "BatchWeightItemFailed events should carry each failing netuid in batch order" + ); + }); +} diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 00d3839fa7..85a35d21c8 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -272,7 +272,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 406, + spec_version: 407, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1,