diff --git a/polkadot/runtime/parachains/src/reward_points.rs b/polkadot/runtime/parachains/src/reward_points.rs index 3fb8435e09..d4688cda5b 100644 --- a/polkadot/runtime/parachains/src/reward_points.rs +++ b/polkadot/runtime/parachains/src/reward_points.rs @@ -23,6 +23,7 @@ use primitives::v1::ValidatorIndex; use pallet_staking::SessionInterface; +use crate::shared; /// The amount of era points given by backing a candidate that is included. pub const BACKING_POINTS: u32 = 20; @@ -30,26 +31,99 @@ pub const BACKING_POINTS: u32 = 20; /// Rewards validators for participating in parachains with era points in pallet-staking. pub struct RewardValidatorsWithEraPoints(sp_std::marker::PhantomData); -fn reward_by_indices(points: u32, indices: I) where - C: pallet_staking::Config, +fn validators_to_reward(validators: &'_ [T], indirect_indices: I) -> impl IntoIterator where + C: shared::Config, I: IntoIterator { - // Fetch the validators from the _session_ because sessions are offset from eras - // and we are rewarding for behavior in current session. - let validators = C::SessionInterface::validators(); - let rewards = indices.into_iter() - .filter_map(|i| validators.get(i.0 as usize).map(|v| v.clone())) - .map(|v| (v, points)); + let validator_indirection = >::active_validator_indices(); - >::reward_by_ids(rewards); + indirect_indices.into_iter() + .filter_map(move |i| validator_indirection.get(i.0 as usize).map(|v| v.clone())) + .filter_map(move |i| validators.get(i.0 as usize)) } impl crate::inclusion::RewardValidators for RewardValidatorsWithEraPoints - where C: pallet_staking::Config + where C: pallet_staking::Config + shared::Config, { - fn reward_backing(validators: impl IntoIterator) { - reward_by_indices::(BACKING_POINTS, validators); + fn reward_backing(indirect_indices: impl IntoIterator) { + // Fetch the validators from the _session_ because sessions are offset from eras + // and we are rewarding for behavior in current session. + let validators = C::SessionInterface::validators(); + + let rewards = validators_to_reward::(&validators, indirect_indices) + .into_iter() + .map(|v| (v.clone(), BACKING_POINTS)); + + >::reward_by_ids(rewards); } fn reward_bitfields(_validators: impl IntoIterator) { } } + +#[cfg(test)] +mod tests { + use super::*; + use primitives::v1::ValidatorId; + use crate::configuration::HostConfiguration; + use crate::mock::{new_test_ext, MockGenesisConfig, Shared, Test}; + use keyring::Sr25519Keyring; + + #[test] + fn rewards_based_on_indirection() { + let validators = vec![ + Sr25519Keyring::Alice, + Sr25519Keyring::Bob, + Sr25519Keyring::Charlie, + Sr25519Keyring::Dave, + Sr25519Keyring::Ferdie, + ]; + + fn validator_pubkeys(val_ids: &[Sr25519Keyring]) -> Vec { + val_ids.iter().map(|v| v.public().into()).collect() + } + + new_test_ext(MockGenesisConfig::default()).execute_with(|| { + let mut config = HostConfiguration::default(); + config.max_validators = None; + + let pubkeys = validator_pubkeys(&validators); + + let shuffled_pubkeys = Shared::initializer_on_new_session( + 1, + [1; 32], + &config, + pubkeys, + ); + + assert_eq!( + shuffled_pubkeys, + validator_pubkeys(&[ + Sr25519Keyring::Ferdie, + Sr25519Keyring::Bob, + Sr25519Keyring::Charlie, + Sr25519Keyring::Dave, + Sr25519Keyring::Alice, + ]) + ); + + assert_eq!( + Shared::active_validator_indices(), + vec![ + ValidatorIndex(4), + ValidatorIndex(1), + ValidatorIndex(2), + ValidatorIndex(3), + ValidatorIndex(0), + ] + ); + + assert_eq!( + validators_to_reward::( + &validators, + vec![ValidatorIndex(0), ValidatorIndex(1), ValidatorIndex(2)], + ).into_iter().copied().collect::>(), + vec![Sr25519Keyring::Ferdie, Sr25519Keyring::Bob, Sr25519Keyring::Charlie], + ); + }) + } +}