From ff2e38290f263df419ba9465ccdb7cc62e3033e1 Mon Sep 17 00:00:00 2001 From: dandanlen <3168260+dandanlen@users.noreply.github.com> Date: Thu, 14 Sep 2023 15:01:27 +0200 Subject: [PATCH] feat: qualify nodes by minimum cfe version (#4003) --- state-chain/pallets/cf-funding/src/lib.rs | 2 +- state-chain/pallets/cf-validator/src/lib.rs | 28 +++++++ state-chain/pallets/cf-validator/src/tests.rs | 75 ++++++++++++++++++- state-chain/runtime/src/lib.rs | 17 ++++- state-chain/traits/src/lib.rs | 15 +--- 5 files changed, 119 insertions(+), 18 deletions(-) diff --git a/state-chain/pallets/cf-funding/src/lib.rs b/state-chain/pallets/cf-funding/src/lib.rs index 047d588bfd..d841be4899 100644 --- a/state-chain/pallets/cf-funding/src/lib.rs +++ b/state-chain/pallets/cf-funding/src/lib.rs @@ -686,7 +686,7 @@ pub mod pallet { impl Default for GenesisConfig { fn default() -> Self { Self { - genesis_accounts: vec![], + genesis_accounts: Default::default(), redemption_tax: Default::default(), minimum_funding: Default::default(), redemption_ttl: Default::default(), diff --git a/state-chain/pallets/cf-validator/src/lib.rs b/state-chain/pallets/cf-validator/src/lib.rs index 530cbb7aad..50dcbb1b18 100644 --- a/state-chain/pallets/cf-validator/src/lib.rs +++ b/state-chain/pallets/cf-validator/src/lib.rs @@ -59,6 +59,7 @@ pub enum PalletConfigUpdate { EpochDuration { blocks: u32 }, AuthoritySetMinSize { min_size: AuthorityCount }, AuctionParameters { parameters: SetSizeParameters }, + MinimumReportedCfeVersion { version: SemVer }, } type RuntimeRotationState = @@ -275,6 +276,12 @@ pub mod pallet { #[pallet::getter(fn auction_bid_cutoff_percentage)] pub(super) type AuctionBidCutoffPercentage = StorageValue<_, Percent, ValueQuery>; + /// Determines the minimum version that each CFE must report to be considered qualified + /// for Keygen. + #[pallet::storage] + #[pallet::getter(fn minimum_reported_cfe_version)] + pub(super) type MinimumReportedCfeVersion = StorageValue<_, SemVer, ValueQuery>; + #[pallet::event] #[pallet::generate_deposit(pub (super) fn deposit_event)] pub enum Event { @@ -500,6 +507,9 @@ pub mod pallet { PalletConfigUpdate::AuctionParameters { parameters } => { Self::try_update_auction_parameters(parameters)?; }, + PalletConfigUpdate::MinimumReportedCfeVersion { version } => { + MinimumReportedCfeVersion::::put(version); + }, } Self::deposit_event(Event::PalletConfigUpdated { update }); @@ -1356,3 +1366,21 @@ impl AuthoritiesCfeVersions for Pallet { Percent::from_rational(num_authorities_at_target_version, authorities_count) } } + +pub struct QualifyByCfeVersion(PhantomData); + +impl QualifyNode<::ValidatorId> for QualifyByCfeVersion { + fn is_qualified(validator_id: &::ValidatorId) -> bool { + NodeCFEVersion::::get(validator_id) >= MinimumReportedCfeVersion::::get() + } + + fn filter_unqualified( + validators: BTreeSet<::ValidatorId>, + ) -> BTreeSet<::ValidatorId> { + let min_version = MinimumReportedCfeVersion::::get(); + validators + .into_iter() + .filter(|id| NodeCFEVersion::::get(id) >= min_version) + .collect() + } +} diff --git a/state-chain/pallets/cf-validator/src/tests.rs b/state-chain/pallets/cf-validator/src/tests.rs index 22bbdc6e6f..47a478708c 100644 --- a/state-chain/pallets/cf-validator/src/tests.rs +++ b/state-chain/pallets/cf-validator/src/tests.rs @@ -12,7 +12,7 @@ use cf_traits::{ AccountRoleRegistry, SafeMode, SetSafeMode, }; use cf_utilities::success_threshold_from_share_count; -use frame_support::{assert_noop, assert_ok}; +use frame_support::{assert_noop, assert_ok, traits::OriginTrait}; use frame_system::RawOrigin; const ALICE: u64 = 100; @@ -1042,3 +1042,76 @@ fn can_calculate_percentage_cfe_at_target_version() { ); }); } + +#[test] +fn qualification_by_cfe_version() { + new_test_ext().execute_with(|| { + const VALIDATOR: u64 = GENESIS_AUTHORITIES[0]; + // No value reported, no value set: + assert!(!NodeCFEVersion::::contains_key(VALIDATOR)); + assert!(!MinimumReportedCfeVersion::::exists()); + assert!(QualifyByCfeVersion::::is_qualified(&VALIDATOR)); + + assert_ok!(ValidatorPallet::update_pallet_config( + OriginTrait::root(), + PalletConfigUpdate::MinimumReportedCfeVersion { + version: SemVer { major: 0, minor: 1, patch: 0 } + } + )); + assert!(!QualifyByCfeVersion::::is_qualified(&VALIDATOR)); + + // Report a version below the minimum: + assert_ok!(ValidatorPallet::cfe_version( + RuntimeOrigin::signed(VALIDATOR), + SemVer { major: 0, minor: 0, patch: 1 } + )); + assert!(!QualifyByCfeVersion::::is_qualified(&VALIDATOR)); + + // Report a version equal to the minimum: + assert_ok!(ValidatorPallet::cfe_version( + RuntimeOrigin::signed(VALIDATOR), + SemVer { major: 0, minor: 1, patch: 0 } + )); + assert!(QualifyByCfeVersion::::is_qualified(&VALIDATOR)); + + // Report a version greater than the minimum: + assert_ok!(ValidatorPallet::cfe_version( + RuntimeOrigin::signed(VALIDATOR), + SemVer { major: 0, minor: 1, patch: 1 } + )); + assert!(QualifyByCfeVersion::::is_qualified(&VALIDATOR)); + + // Report a version bumping the minor version: + assert_ok!(ValidatorPallet::cfe_version( + RuntimeOrigin::signed(VALIDATOR), + SemVer { major: 0, minor: 2, patch: 0 } + )); + assert!(QualifyByCfeVersion::::is_qualified(&VALIDATOR)); + + // Report a version bumping the major version: + assert_ok!(ValidatorPallet::cfe_version( + RuntimeOrigin::signed(VALIDATOR), + SemVer { major: 1, minor: 0, patch: 0 } + )); + assert!(QualifyByCfeVersion::::is_qualified(&VALIDATOR)); + + // Raise the minimum: + + assert_ok!(ValidatorPallet::update_pallet_config( + OriginTrait::root(), + PalletConfigUpdate::MinimumReportedCfeVersion { + version: SemVer { major: 1, minor: 0, patch: 0 } + } + )); + assert!(QualifyByCfeVersion::::is_qualified(&VALIDATOR)); + + // Raise the minimum again: + assert_ok!(ValidatorPallet::update_pallet_config( + OriginTrait::root(), + PalletConfigUpdate::MinimumReportedCfeVersion { + version: SemVer { major: 1, minor: 0, patch: 1 } + } + )); + assert!(!QualifyByCfeVersion::::is_qualified(&VALIDATOR)); + }); +} diff --git a/state-chain/runtime/src/lib.rs b/state-chain/runtime/src/lib.rs index 793086becf..6d37143254 100644 --- a/state-chain/runtime/src/lib.rs +++ b/state-chain/runtime/src/lib.rs @@ -168,10 +168,19 @@ impl pallet_cf_validator::Config for Runtime { type BidderProvider = pallet_cf_funding::Pallet; type KeygenQualification = ( Reputation, - ExclusionList, - pallet_cf_validator::PeerMapping, - SessionKeysRegistered>, - chainflip::ValidatorRoleQualification, + ( + ExclusionList, + ( + pallet_cf_validator::PeerMapping, + ( + SessionKeysRegistered>, + ( + chainflip::ValidatorRoleQualification, + pallet_cf_validator::QualifyByCfeVersion, + ), + ), + ), + ), ); type OffenceReporter = Reputation; type Bonder = Bonder; diff --git a/state-chain/traits/src/lib.rs b/state-chain/traits/src/lib.rs index 37280bbabc..6c8bc7e87b 100644 --- a/state-chain/traits/src/lib.rs +++ b/state-chain/traits/src/lib.rs @@ -540,26 +540,17 @@ impl QualifyNode for (A, B, C, D, E) +impl QualifyNode for (A, B) where A: QualifyNode, B: QualifyNode, - C: QualifyNode, - D: QualifyNode, - E: QualifyNode, { fn is_qualified(validator_id: &Id) -> bool { - A::is_qualified(validator_id) && - B::is_qualified(validator_id) && - C::is_qualified(validator_id) && - D::is_qualified(validator_id) && - E::is_qualified(validator_id) + A::is_qualified(validator_id) && B::is_qualified(validator_id) } fn filter_unqualified(validators: BTreeSet) -> BTreeSet { - E::filter_unqualified(D::filter_unqualified(C::filter_unqualified(B::filter_unqualified( - A::filter_unqualified(validators), - )))) + B::filter_unqualified(A::filter_unqualified(validators)) } }