diff --git a/operator/runtime/mainnet/src/configs/mod.rs b/operator/runtime/mainnet/src/configs/mod.rs index 9adc5f74..c4892e9b 100644 --- a/operator/runtime/mainnet/src/configs/mod.rs +++ b/operator/runtime/mainnet/src/configs/mod.rs @@ -1091,6 +1091,18 @@ impl pallet_external_validators_rewards::types::SendMessage for RewardsSendAdapt fn build( rewards_utils: &pallet_external_validators_rewards::types::EraRewardsUtils, ) -> Option { + let rewards_registry_address = + runtime_params::dynamic_params::runtime_config::RewardsRegistryAddress::get(); + + // Skip sending message if RewardsRegistryAddress is zero (invalid) + if rewards_registry_address == H160::zero() { + log::warn!( + target: "rewards_send_adapter", + "Skipping rewards message: RewardsRegistryAddress is zero" + ); + return None; + } + let selector = runtime_params::dynamic_params::runtime_config::RewardsUpdateSelector::get(); let mut calldata = Vec::new(); @@ -1098,7 +1110,7 @@ impl pallet_external_validators_rewards::types::SendMessage for RewardsSendAdapt calldata.extend_from_slice(rewards_utils.rewards_merkle_root.as_bytes()); let command = Command::CallContract { - target: runtime_params::dynamic_params::runtime_config::RewardsRegistryAddress::get(), + target: rewards_registry_address, calldata, gas: 1_000_000, // TODO: Determine appropriate gas value after testing value: 0, @@ -1217,4 +1229,79 @@ mod tests { "Computed account must match hardcoded value" ); } + + #[test] + fn test_rewards_send_adapter_with_zero_address() { + use pallet_external_validators_rewards::types::{EraRewardsUtils, SendMessage}; + use sp_io::TestExternalities; + + TestExternalities::default().execute_with(|| { + // Create test rewards utils + let rewards_utils = EraRewardsUtils { + rewards_merkle_root: H256::random(), + leaves: vec![H256::random()], + leaf_index: Some(1), + total_points: 1000, + }; + + // By default, RewardsRegistryAddress is zero (H160::repeat_byte(0x0)) + // So the adapter should return None + let message = RewardsSendAdapter::build(&rewards_utils); + assert!( + message.is_none(), + "Should return None when RewardsRegistryAddress is zero" + ); + }); + } + + #[test] + fn test_rewards_send_adapter_with_valid_address() { + use frame_support::assert_ok; + use pallet_external_validators_rewards::types::{EraRewardsUtils, SendMessage}; + use sp_io::TestExternalities; + + TestExternalities::default().execute_with(|| { + // Set a valid (non-zero) rewards registry address + let valid_address = H160::from_low_u64_be(0x1234567890abcdef); + assert_ok!(pallet_parameters::Pallet::::set_parameter( + RuntimeOrigin::root(), + RuntimeParameters::RuntimeConfig( + runtime_params::dynamic_params::runtime_config::Parameters::RewardsRegistryAddress( + runtime_params::dynamic_params::runtime_config::RewardsRegistryAddress, + Some(valid_address), + ), + ), + )); + + // Create test rewards utils + let rewards_utils = EraRewardsUtils { + rewards_merkle_root: H256::random(), + leaves: vec![H256::random()], + leaf_index: Some(1), + total_points: 1000, + }; + + // Now the adapter should return a valid message + let message = RewardsSendAdapter::build(&rewards_utils); + assert!( + message.is_some(), + "Should return Some(message) when RewardsRegistryAddress is non-zero" + ); + + // Verify the message contains the correct target address + if let Some(msg) = message { + // Check that the first command has the correct target + let command = &msg.commands[0]; + match command { + Command::CallContract { target, .. } => { + assert_eq!( + *target, valid_address, + "Message should target the configured address" + ); + } + _ => panic!("Expected CallContract command"), + } + } + }); + } } diff --git a/operator/runtime/stagenet/src/configs/mod.rs b/operator/runtime/stagenet/src/configs/mod.rs index 5e28fc2e..a1eb8256 100644 --- a/operator/runtime/stagenet/src/configs/mod.rs +++ b/operator/runtime/stagenet/src/configs/mod.rs @@ -1095,6 +1095,18 @@ impl pallet_external_validators_rewards::types::SendMessage for RewardsSendAdapt fn build( rewards_utils: &pallet_external_validators_rewards::types::EraRewardsUtils, ) -> Option { + let rewards_registry_address = + runtime_params::dynamic_params::runtime_config::RewardsRegistryAddress::get(); + + // Skip sending message if RewardsRegistryAddress is zero (invalid) + if rewards_registry_address == H160::zero() { + log::warn!( + target: "rewards_send_adapter", + "Skipping rewards message: RewardsRegistryAddress is zero" + ); + return None; + } + let selector = runtime_params::dynamic_params::runtime_config::RewardsUpdateSelector::get(); let mut calldata = Vec::new(); @@ -1102,7 +1114,7 @@ impl pallet_external_validators_rewards::types::SendMessage for RewardsSendAdapt calldata.extend_from_slice(rewards_utils.rewards_merkle_root.as_bytes()); let command = Command::CallContract { - target: runtime_params::dynamic_params::runtime_config::RewardsRegistryAddress::get(), + target: rewards_registry_address, calldata, gas: 1_000_000, // TODO: Determine appropriate gas value after testing value: 0, @@ -1221,4 +1233,90 @@ mod tests { "Computed account must match hardcoded value" ); } + + #[test] + fn test_rewards_send_adapter_with_zero_address() { + use frame_support::assert_ok; + use pallet_external_validators_rewards::types::{EraRewardsUtils, SendMessage}; + use sp_io::TestExternalities; + + TestExternalities::default().execute_with(|| { + // First, set RewardsRegistryAddress to zero + assert_ok!(pallet_parameters::Pallet::::set_parameter( + RuntimeOrigin::root(), + RuntimeParameters::RuntimeConfig( + runtime_params::dynamic_params::runtime_config::Parameters::RewardsRegistryAddress( + runtime_params::dynamic_params::runtime_config::RewardsRegistryAddress, + Some(H160::zero()), + ), + ), + )); + + // Create test rewards utils + let rewards_utils = EraRewardsUtils { + rewards_merkle_root: H256::random(), + leaves: vec![H256::random()], + leaf_index: Some(1), + total_points: 1000, + }; + + // Now the adapter should return None + let message = RewardsSendAdapter::build(&rewards_utils); + assert!( + message.is_none(), + "Should return None when RewardsRegistryAddress is zero" + ); + }); + } + + #[test] + fn test_rewards_send_adapter_with_valid_address() { + use frame_support::assert_ok; + use pallet_external_validators_rewards::types::{EraRewardsUtils, SendMessage}; + use sp_io::TestExternalities; + + TestExternalities::default().execute_with(|| { + // Set a valid (non-zero) rewards registry address + let valid_address = H160::from_low_u64_be(0x1234567890abcdef); + assert_ok!(pallet_parameters::Pallet::::set_parameter( + RuntimeOrigin::root(), + RuntimeParameters::RuntimeConfig( + runtime_params::dynamic_params::runtime_config::Parameters::RewardsRegistryAddress( + runtime_params::dynamic_params::runtime_config::RewardsRegistryAddress, + Some(valid_address), + ), + ), + )); + + // Create test rewards utils + let rewards_utils = EraRewardsUtils { + rewards_merkle_root: H256::random(), + leaves: vec![H256::random()], + leaf_index: Some(1), + total_points: 1000, + }; + + // Now the adapter should return a valid message + let message = RewardsSendAdapter::build(&rewards_utils); + assert!( + message.is_some(), + "Should return Some(message) when RewardsRegistryAddress is non-zero" + ); + + // Verify the message contains the correct target address + if let Some(msg) = message { + // Check that the first command has the correct target + let command = &msg.commands[0]; + match command { + Command::CallContract { target, .. } => { + assert_eq!( + *target, valid_address, + "Message should target the configured address" + ); + } + _ => panic!("Expected CallContract command"), + } + } + }); + } } diff --git a/operator/runtime/testnet/src/configs/mod.rs b/operator/runtime/testnet/src/configs/mod.rs index 6e7d0024..7535ce64 100644 --- a/operator/runtime/testnet/src/configs/mod.rs +++ b/operator/runtime/testnet/src/configs/mod.rs @@ -1091,6 +1091,18 @@ impl pallet_external_validators_rewards::types::SendMessage for RewardsSendAdapt fn build( rewards_utils: &pallet_external_validators_rewards::types::EraRewardsUtils, ) -> Option { + let rewards_registry_address = + runtime_params::dynamic_params::runtime_config::RewardsRegistryAddress::get(); + + // Skip sending message if RewardsRegistryAddress is zero (invalid) + if rewards_registry_address == H160::zero() { + log::warn!( + target: "rewards_send_adapter", + "Skipping rewards message: RewardsRegistryAddress is zero" + ); + return None; + } + let selector = runtime_params::dynamic_params::runtime_config::RewardsUpdateSelector::get(); let mut calldata = Vec::new(); @@ -1098,7 +1110,7 @@ impl pallet_external_validators_rewards::types::SendMessage for RewardsSendAdapt calldata.extend_from_slice(rewards_utils.rewards_merkle_root.as_bytes()); let command = Command::CallContract { - target: runtime_params::dynamic_params::runtime_config::RewardsRegistryAddress::get(), + target: rewards_registry_address, calldata, gas: 1_000_000, // TODO: Determine appropriate gas value after testing value: 0, @@ -1235,4 +1247,79 @@ mod tests { "Different chain IDs must produce different sovereign accounts" ); } + + #[test] + fn test_rewards_send_adapter_with_zero_address() { + use pallet_external_validators_rewards::types::{EraRewardsUtils, SendMessage}; + use sp_io::TestExternalities; + + TestExternalities::default().execute_with(|| { + // Create test rewards utils + let rewards_utils = EraRewardsUtils { + rewards_merkle_root: H256::random(), + leaves: vec![H256::random()], + leaf_index: Some(1), + total_points: 1000, + }; + + // By default, RewardsRegistryAddress is zero (H160::repeat_byte(0x0)) + // So the adapter should return None + let message = RewardsSendAdapter::build(&rewards_utils); + assert!( + message.is_none(), + "Should return None when RewardsRegistryAddress is zero" + ); + }); + } + + #[test] + fn test_rewards_send_adapter_with_valid_address() { + use frame_support::assert_ok; + use pallet_external_validators_rewards::types::{EraRewardsUtils, SendMessage}; + use sp_io::TestExternalities; + + TestExternalities::default().execute_with(|| { + // Set a valid (non-zero) rewards registry address + let valid_address = H160::from_low_u64_be(0x1234567890abcdef); + assert_ok!(pallet_parameters::Pallet::::set_parameter( + RuntimeOrigin::root(), + RuntimeParameters::RuntimeConfig( + runtime_params::dynamic_params::runtime_config::Parameters::RewardsRegistryAddress( + runtime_params::dynamic_params::runtime_config::RewardsRegistryAddress, + Some(valid_address), + ), + ), + )); + + // Create test rewards utils + let rewards_utils = EraRewardsUtils { + rewards_merkle_root: H256::random(), + leaves: vec![H256::random()], + leaf_index: Some(1), + total_points: 1000, + }; + + // Now the adapter should return a valid message + let message = RewardsSendAdapter::build(&rewards_utils); + assert!( + message.is_some(), + "Should return Some(message) when RewardsRegistryAddress is non-zero" + ); + + // Verify the message contains the correct target address + if let Some(msg) = message { + // Check that the first command has the correct target + let command = &msg.commands[0]; + match command { + Command::CallContract { target, .. } => { + assert_eq!( + *target, valid_address, + "Message should target the configured address" + ); + } + _ => panic!("Expected CallContract command"), + } + } + }); + } }