fix: add zero address check for rewards send adapter (#112)

Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com>
Co-authored-by: Ahmad Kaouk <ahmadkaouk.93@gmail.com>
This commit is contained in:
Gonza Montiel 2025-08-14 09:44:45 +02:00 committed by GitHub
parent 1f0cd6de27
commit 33185e3680
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 275 additions and 3 deletions

View file

@ -1091,6 +1091,18 @@ impl pallet_external_validators_rewards::types::SendMessage for RewardsSendAdapt
fn build(
rewards_utils: &pallet_external_validators_rewards::types::EraRewardsUtils,
) -> Option<Self::Message> {
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::<Runtime>::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"),
}
}
});
}
}

View file

@ -1095,6 +1095,18 @@ impl pallet_external_validators_rewards::types::SendMessage for RewardsSendAdapt
fn build(
rewards_utils: &pallet_external_validators_rewards::types::EraRewardsUtils,
) -> Option<Self::Message> {
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::<Runtime>::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::<Runtime>::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"),
}
}
});
}
}

View file

@ -1091,6 +1091,18 @@ impl pallet_external_validators_rewards::types::SendMessage for RewardsSendAdapt
fn build(
rewards_utils: &pallet_external_validators_rewards::types::EraRewardsUtils,
) -> Option<Self::Message> {
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::<Runtime>::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"),
}
}
});
}
}