Skip to content

Commit

Permalink
feat: qualify nodes by minimum cfe version (#4003)
Browse files Browse the repository at this point in the history
  • Loading branch information
dandanlen authored Sep 14, 2023
1 parent c00a008 commit 1d3ccfc
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 38 deletions.
41 changes: 21 additions & 20 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion state-chain/pallets/cf-funding/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ pub mod pallet {
impl<T: Config> Default for GenesisConfig<T> {
fn default() -> Self {
Self {
genesis_accounts: vec![],
genesis_accounts: Default::default(),
redemption_tax: Default::default(),
minimum_funding: Default::default(),
redemption_ttl: Default::default(),
Expand Down
28 changes: 28 additions & 0 deletions state-chain/pallets/cf-validator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ pub enum PalletConfigUpdate {
EpochDuration { blocks: u32 },
AuthoritySetMinSize { min_size: AuthorityCount },
AuctionParameters { parameters: SetSizeParameters },
MinimumReportedCfeVersion { version: SemVer },
}

type RuntimeRotationState<T> =
Expand Down Expand Up @@ -275,6 +276,12 @@ pub mod pallet {
#[pallet::getter(fn auction_bid_cutoff_percentage)]
pub(super) type AuctionBidCutoffPercentage<T: Config> = 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<T: Config> = StorageValue<_, SemVer, ValueQuery>;

#[pallet::event]
#[pallet::generate_deposit(pub (super) fn deposit_event)]
pub enum Event<T: Config> {
Expand Down Expand Up @@ -500,6 +507,9 @@ pub mod pallet {
PalletConfigUpdate::AuctionParameters { parameters } => {
Self::try_update_auction_parameters(parameters)?;
},
PalletConfigUpdate::MinimumReportedCfeVersion { version } => {
MinimumReportedCfeVersion::<T>::put(version);
},
}

Self::deposit_event(Event::PalletConfigUpdated { update });
Expand Down Expand Up @@ -1364,3 +1374,21 @@ impl<T: Config> AuthoritiesCfeVersions for Pallet<T> {
Percent::from_rational(num_authorities_at_target_version, authorities_count)
}
}

pub struct QualifyByCfeVersion<T>(PhantomData<T>);

impl<T: Config> QualifyNode<<T as Chainflip>::ValidatorId> for QualifyByCfeVersion<T> {
fn is_qualified(validator_id: &<T as Chainflip>::ValidatorId) -> bool {
NodeCFEVersion::<T>::get(validator_id) >= MinimumReportedCfeVersion::<T>::get()
}

fn filter_unqualified(
validators: BTreeSet<<T as Chainflip>::ValidatorId>,
) -> BTreeSet<<T as Chainflip>::ValidatorId> {
let min_version = MinimumReportedCfeVersion::<T>::get();
validators
.into_iter()
.filter(|id| NodeCFEVersion::<T>::get(id) >= min_version)
.collect()
}
}
75 changes: 74 additions & 1 deletion state-chain/pallets/cf-validator/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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::<Test>::contains_key(VALIDATOR));
assert!(!MinimumReportedCfeVersion::<Test>::exists());
assert!(QualifyByCfeVersion::<Test>::is_qualified(&VALIDATOR));

assert_ok!(ValidatorPallet::update_pallet_config(
OriginTrait::root(),
PalletConfigUpdate::MinimumReportedCfeVersion {
version: SemVer { major: 0, minor: 1, patch: 0 }
}
));
assert!(!QualifyByCfeVersion::<Test>::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::<Test>::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::<Test>::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::<Test>::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::<Test>::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::<Test>::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::<Test>::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::<Test>::is_qualified(&VALIDATOR));
});
}
17 changes: 13 additions & 4 deletions state-chain/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,19 @@ impl pallet_cf_validator::Config for Runtime {
type BidderProvider = pallet_cf_funding::Pallet<Self>;
type KeygenQualification = (
Reputation,
ExclusionList<Self, chainflip::KeygenExclusionOffences>,
pallet_cf_validator::PeerMapping<Self>,
SessionKeysRegistered<Self, pallet_session::Pallet<Self>>,
chainflip::ValidatorRoleQualification,
(
ExclusionList<Self, chainflip::KeygenExclusionOffences>,
(
pallet_cf_validator::PeerMapping<Self>,
(
SessionKeysRegistered<Self, pallet_session::Pallet<Self>>,
(
chainflip::ValidatorRoleQualification,
pallet_cf_validator::QualifyByCfeVersion<Self>,
),
),
),
),
);
type OffenceReporter = Reputation;
type Bonder = Bonder<Runtime>;
Expand Down
15 changes: 3 additions & 12 deletions state-chain/traits/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -540,26 +540,17 @@ impl<T: Chainflip, R: frame_support::traits::ValidatorRegistration<T::ValidatorI
}
}

impl<Id: Ord, A, B, C, D, E> QualifyNode<Id> for (A, B, C, D, E)
impl<Id: Ord, A, B> QualifyNode<Id> for (A, B)
where
A: QualifyNode<Id>,
B: QualifyNode<Id>,
C: QualifyNode<Id>,
D: QualifyNode<Id>,
E: QualifyNode<Id>,
{
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<Id>) -> BTreeSet<Id> {
E::filter_unqualified(D::filter_unqualified(C::filter_unqualified(B::filter_unqualified(
A::filter_unqualified(validators),
))))
B::filter_unqualified(A::filter_unqualified(validators))
}
}

Expand Down

0 comments on commit 1d3ccfc

Please sign in to comment.