diff --git a/Cargo.lock b/Cargo.lock index a0dc1ea374..0671395073 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5110,9 +5110,9 @@ checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" [[package]] name = "libp2p" -version = "0.52.1" +version = "0.52.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38039ba2df4f3255842050845daef4a004cc1f26da03dbc645535088b51910ef" +checksum = "ca4894076bfa3051e4f1725747308861af1e6641213640aeeb784f583e40e7d9" dependencies = [ "bytes", "futures", @@ -5178,7 +5178,7 @@ dependencies = [ "libp2p-identity", "log", "multiaddr", - "multihash 0.19.0", + "multihash 0.19.1", "multistream-select", "once_cell", "parking_lot 0.12.1", @@ -5238,7 +5238,7 @@ dependencies = [ "bs58 0.5.0", "ed25519-dalek", "log", - "multihash 0.19.0", + "multihash 0.19.1", "quick-protobuf", "rand 0.8.5", "sha2 0.10.7", @@ -5248,9 +5248,9 @@ dependencies = [ [[package]] name = "libp2p-kad" -version = "0.44.3" +version = "0.44.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2584b0c27f879a1cca4b753fd96874109e5a2f46bd6e30924096456c2ba9b2" +checksum = "fc125f83d8f75322c79e4ade74677d299b34aa5c9d9b5251c03ec28c683cb765" dependencies = [ "arrayvec 0.7.4", "asynchronous-codec", @@ -5297,9 +5297,9 @@ dependencies = [ [[package]] name = "libp2p-metrics" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3787ea81798dcc5bf1d8b40a8e8245cf894b168d04dd70aa48cb3ff2fff141d2" +checksum = "239ba7d28f8d0b5d77760dc6619c05c7e88e74ec8fbbe97f856f20a56745e620" dependencies = [ "instant", "libp2p-core", @@ -5325,7 +5325,7 @@ dependencies = [ "libp2p-identity", "log", "multiaddr", - "multihash 0.19.0", + "multihash 0.19.1", "once_cell", "quick-protobuf", "rand 0.8.5", @@ -5357,9 +5357,9 @@ dependencies = [ [[package]] name = "libp2p-request-response" -version = "0.25.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20bd837798cdcce4283d2675f08bcd3756a650d56eab4d4367e1b3f27eed6887" +checksum = "49e2cb9befb57e55f53d9463a6ea9b1b8a09a48174ad7be149c9cbebaa5e8e9b" dependencies = [ "async-trait", "futures", @@ -5375,9 +5375,9 @@ dependencies = [ [[package]] name = "libp2p-swarm" -version = "0.43.2" +version = "0.43.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43106820057e0f65c77b01a3873593f66e676da4e40c70c3a809b239109f1d30" +checksum = "28016944851bd73526d3c146aabf0fa9bbe27c558f080f9e5447da3a1772c01a" dependencies = [ "either", "fnv", @@ -5462,9 +5462,9 @@ dependencies = [ [[package]] name = "libp2p-yamux" -version = "0.44.0" +version = "0.44.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0a9b42ab6de15c6f076d8fb11dc5f48d899a10b55a2e16b12be9012a05287b0" +checksum = "8eedcb62824c4300efb9cfd4e2a6edaf3ca097b9e68b36dabe45a44469fd6a85" dependencies = [ "futures", "libp2p-core", @@ -5949,7 +5949,7 @@ dependencies = [ "data-encoding", "libp2p-identity", "multibase", - "multihash 0.19.0", + "multihash 0.19.1", "percent-encoding", "serde", "static_assertions", @@ -5987,9 +5987,9 @@ dependencies = [ [[package]] name = "multihash" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd59dcc2bbe70baabeac52cd22ae52c55eefe6c38ff11a9439f16a350a939f2" +checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" dependencies = [ "core2", "unsigned-varint", @@ -13036,14 +13036,15 @@ dependencies = [ [[package]] name = "yamux" -version = "0.10.2" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d9ba232399af1783a58d8eb26f6b5006fbefe2dc9ef36bd283324792d03ea5" +checksum = "0329ef377816896f014435162bb3711ea7a07729c23d0960e6f8048b21b8fe91" dependencies = [ "futures", "log", "nohash-hasher", "parking_lot 0.12.1", + "pin-project", "rand 0.8.5", "static_assertions", ] 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 51052dc429..029197b394 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 }); @@ -1364,3 +1374,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 e0033c48b5..0f69ea3468 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)) } }