diff --git a/cli/src/chain_spec.rs b/cli/src/chain_spec.rs index cda54b9e249af..40a659aff2d86 100644 --- a/cli/src/chain_spec.rs +++ b/cli/src/chain_spec.rs @@ -1,6 +1,7 @@ // Copyright 2019-2020 ChainX Project Authors. Licensed under GPL-3.0. use std::collections::BTreeMap; +use std::convert::TryInto; use hex_literal::hex; use serde::{Deserialize, Serialize}; @@ -381,7 +382,11 @@ pub fn mainnet_config() -> Result { "chainx", ChainType::Live, constructor, - bootnodes![], // FIXME Add mainnet bootnodes + bootnodes![ + "/dns/p2p.1.chainx.org/tcp/20222/p2p/12D3KooWMMGD6eyLDgoTPnmGrawn9gkjtsZGLACJXqVCUbe6R6bD", + "/dns/p2p.2.chainx.org/tcp/20222/p2p/12D3KooWC1tFLBFVw47S2nfD7Nzhg5hBMUvsnz4nqpr82zfTYWaH", + "/dns/p2p.3.chainx.org/tcp/20222/p2p/12D3KooWPthFY8xDDyM5X9PWZwNfioqP5EShiTKyVv5899H22WBT", + ], Some( TelemetryEndpoints::new(vec![ (CHAINX_TELEMETRY_URL.to_string(), 0), @@ -568,7 +573,8 @@ fn build_genesis( }), xpallet_genesis_builder: Some(XGenesisBuilderConfig { params: crate::genesis::genesis_builder_params(), - total_endowed, + initial_authorities_endowed: total_endowed, + root_endowed: 0, }), } } @@ -584,26 +590,33 @@ fn mainnet_genesis( ) -> GenesisConfig { // 1000 PCX const STAKING_LOCKED: Balance = 100_000 * DOLLARS; + // 100 PCX + const ROOT_ENDOWED: Balance = 10_000 * DOLLARS; let (assets, assets_restrictions) = init_assets(assets); let initial_authorities_len = initial_authorities.len(); - let tech_comm_members = initial_authorities - .iter() - .map(|((validator, _), _, _, _, _)| validator) - .take((initial_authorities_len + 1) / 2) - .cloned() - .collect::>(); + let tech_comm_members: Vec = vec![ + // 5C7VzhPqJsLXcyJmX71ZEt7GdkAMTxHNPwh6BSb8thgBbQU1 + hex!["0221ce7c4a0b771faaf0bbae23c3a1965348cb5257611313a73c3d4a53599509"].into(), + // 5D7F1AJoDwuCvZZKEggeGk2brxYty9mkamUcFHyshYBnbWs3 + hex!["2e2b928d39b7a9c8688509927e17031001fab604557db093ead5069474e0584e"].into(), + // 5HG5CswZ6X39BYqt8Dc8e4Cn2HieGnnUiG39ddGn2oq5G36W + hex!["e5d8bb656b124beb40990ef9346c441f888981ec7e0d4c55c9c72c176aec5290"].into(), + ]; - let balances = initial_authorities + let mut balances = initial_authorities .iter() .map(|((validator, _), _, _, _, _)| validator) .cloned() .map(|validator| (validator, STAKING_LOCKED)) .collect::>(); - let total_endowed = initial_authorities_len as Balance * STAKING_LOCKED; + // 100 PCX to root account for paying the transaction fee. + balances.push((root_key.clone(), ROOT_ENDOWED)); + + let initial_authorities_endowed = initial_authorities_len as Balance * STAKING_LOCKED; let validators = initial_authorities .clone() @@ -695,7 +708,8 @@ fn mainnet_genesis( vesting_account, glob_dist_ratio: (12, 88), // (Treasury, X-type Asset and Staking) = (12, 88) mining_ratio: (10, 90), // (Asset Mining, Staking) = (10, 90) - minimum_penalty: 2 * DOLLARS, + minimum_penalty: 100 * DOLLARS, + candidate_requirement: (100 * DOLLARS, 1_000 * DOLLARS), // Minimum value (self_bonded, total_bonded) to be a validator candidate ..Default::default() }), xpallet_mining_asset: Some(XMiningAssetConfig { @@ -707,7 +721,8 @@ fn mainnet_genesis( }), xpallet_genesis_builder: Some(XGenesisBuilderConfig { params: crate::genesis::genesis_builder_params(), - total_endowed, + root_endowed: ROOT_ENDOWED, + initial_authorities_endowed, }), } } diff --git a/scripts/build_wasm.sh b/scripts/build_wasm.sh index 03ecf93bf6233..7fdaeb6f94422 100755 --- a/scripts/build_wasm.sh +++ b/scripts/build_wasm.sh @@ -1,2 +1,3 @@ #!/usr/bin/env bash -docker run --rm -it -e PACKAGE=chainx-runtime -v $PWD:/build -v /tmp/cargo:/cargo-home chainx/srtool:nightly-2020-09-30 + +docker run --rm -it -e PACKAGE=chainx-runtime -v $PWD:/build -v /tmp/cargo:/cargo-home chainxorg/srtool:nightly-2020-09-30 diff --git a/xpallets/assets/src/lib.rs b/xpallets/assets/src/lib.rs index 230ff7796644f..dec549743fcad 100644 --- a/xpallets/assets/src/lib.rs +++ b/xpallets/assets/src/lib.rs @@ -123,7 +123,7 @@ decl_event!( /// Some balances of an asset were destoryed. [asset_id, who, amount] Destroyed(AssetId, AccountId, Balance), /// Set asset balance of an account by root. [asset_id, who, asset_type, amount] - SetBalance(AssetId, AccountId, AssetType, Balance), + BalanceSet(AssetId, AccountId, AssetType, Balance), } ); diff --git a/xpallets/assets/src/trigger.rs b/xpallets/assets/src/trigger.rs index e8f8ca9bce13e..5be071d2420d2 100644 --- a/xpallets/assets/src/trigger.rs +++ b/xpallets/assets/src/trigger.rs @@ -74,7 +74,7 @@ impl AssetChangedTrigger { type_: AssetType, value: BalanceOf, ) -> DispatchResult { - Module::::deposit_event(Event::::SetBalance(*id, who.clone(), type_, value)); + Module::::deposit_event(Event::::BalanceSet(*id, who.clone(), type_, value)); T::OnAssetChanged::on_set_balance(id, who, type_, value)?; Ok(()) } diff --git a/xpallets/genesis-builder/src/lib.rs b/xpallets/genesis-builder/src/lib.rs index caad2322a1381..02512682bd6bb 100644 --- a/xpallets/genesis-builder/src/lib.rs +++ b/xpallets/genesis-builder/src/lib.rs @@ -29,13 +29,14 @@ decl_storage! { trait Store for Module as XGenesisBuilder {} add_extra_genesis { config(params): AllParams, StakingBalanceOf>; - config(total_endowed): T::Balance; + config(root_endowed): T::Balance; + config(initial_authorities_endowed): T::Balance; build(|config| { use crate::genesis::{xassets, balances, xstaking, xmining_asset}; let now = std::time::Instant::now(); - balances::initialize::(&config.params.balances, config.total_endowed); + balances::initialize::(&config.params.balances, config.root_endowed, config.initial_authorities_endowed); xassets::initialize::(&config.params.xassets); xstaking::initialize::(&config.params.xstaking); xmining_asset::initialize::(&config.params.xmining_asset); @@ -68,7 +69,8 @@ mod genesis { pub fn initialize( params: &BalancesParams, - total_endowed: T::Balance, + root_endowed: T::Balance, + initial_authorities_endowed: T::Balance, ) { let BalancesParams { free_balances, @@ -100,9 +102,10 @@ mod genesis { for FreeBalanceInfo { who, free } in free_balances { if *who == *legacy_council { - set_free_balance(&treasury_account, free); + let treasury_free = *free - root_endowed; + set_free_balance(&treasury_account, &treasury_free); } else if *who == *legacy_team { - let vesting_free = *free - total_endowed; + let vesting_free = *free - initial_authorities_endowed; set_free_balance(&vesting_account, &vesting_free); } else if let Some(validator) = validator_for::(who, legacy_pots.iter()) { let new_pot = xpallet_mining_staking::Module::::reward_pot_for(validator); @@ -144,7 +147,7 @@ mod genesis { let genesis_validators = validators.iter().map(|v| v.who.clone()).collect::>(); // Firstly register the genesis validators. - xpallet_mining_staking::Module::::initialize_validators(validators) + xpallet_mining_staking::Module::::initialize_legacy_validators(validators) .expect("Failed to initialize genesis staking validators"); // Then mock the validator bond themselves and set the vote weights. @@ -166,7 +169,7 @@ mod genesis { nominator, nominee, *weight, ); // Skip the validator self-bonding as it has already been processed - // in initialize_validators() + // in initialize_legacy_validators() if *nominee == *nominator { continue; } diff --git a/xpallets/mining/staking/src/benchmarking.rs b/xpallets/mining/staking/src/benchmarking.rs index 643bcf13136c8..dd89ccd1ee3b9 100644 --- a/xpallets/mining/staking/src/benchmarking.rs +++ b/xpallets/mining/staking/src/benchmarking.rs @@ -170,6 +170,20 @@ benchmarks! { verify { assert_eq!(ValidatorBondingDuration::::get(), c.into()); } + + set_minimum_penalty { + let c = 1000u32; + }: _(RawOrigin::Root, c.into()) + verify { + assert_eq!(MinimumPenalty::::get(), c.into()); + } + + set_sessions_per_era { + let c = 1000u32; + }: _(RawOrigin::Root, c) + verify { + assert_eq!(SessionsPerEra::get(), c); + } } #[cfg(test)] diff --git a/xpallets/mining/staking/src/election.rs b/xpallets/mining/staking/src/election.rs index 157c075728b17..abbbffb1f9d17 100644 --- a/xpallets/mining/staking/src/election.rs +++ b/xpallets/mining/staking/src/election.rs @@ -35,7 +35,7 @@ impl Module { /// /// Otherwise the candidate will be **forced to be chilled**. fn meet_candidate_threshold(who: &T::AccountId) -> bool { - let BondRequirement { self_bonded, total } = Self::validator_bond_requirement(); + let BondRequirement { self_bonded, total } = Self::validator_candidate_requirement(); let threshold_satisfied = Self::validator_self_bonded(who) >= self_bonded && Self::total_votes_of(who) >= total; @@ -82,6 +82,37 @@ impl Module { .map(|(_, v)| v) .collect::>(); + // Remove the immortals once Sudo is removed. + if let Some(immortals) = Self::immortals() { + // since the genesis validators have the same votes, it's ok to not sort them. + let unwanted_losers = immortals + .iter() + .filter(|i| !validators.contains(i)) + .collect::>(); + + // If we are here, the returned validators are not ensured to be sorted. + if !unwanted_losers.is_empty() { + let mut validators_without_immortals = validators + .into_iter() + .filter(|v| !immortals.contains(v)) + .collect::>(); + + for _ in unwanted_losers { + if !validators_without_immortals.is_empty() { + // Pop out the validator with fewest votes. + validators_without_immortals.pop(); + } + } + + let mut validators = + Vec::with_capacity(validators_without_immortals.len() + immortals.len()); + validators.extend_from_slice(&validators_without_immortals); + validators.extend_from_slice(&immortals); + + return Some(validators); + } + } + // Always return Some(new_validators). Some(validators) } diff --git a/xpallets/mining/staking/src/lib.rs b/xpallets/mining/staking/src/lib.rs index 42a3a2f539f56..4aa4d1b03762f 100644 --- a/xpallets/mining/staking/src/lib.rs +++ b/xpallets/mining/staking/src/lib.rs @@ -116,7 +116,7 @@ decl_storage! { u32 = DEFAULT_MAXIMUM_VALIDATOR_COUNT; /// Minimum value (self_bonded, total_bonded) to be a candidate of validator election. - pub ValidatorCandidateRequirement get(fn validator_bond_requirement): + pub ValidatorCandidateRequirement get(fn validator_candidate_requirement): BondRequirement>; /// The length of a staking era in sessions. @@ -199,14 +199,18 @@ decl_storage! { /// Minimum penalty for each slash. pub MinimumPenalty get(fn minimum_penalty) config(): BalanceOf; + + /// Immortal validators will always be elected if any. + /// + /// Immortals will be intialized from the genesis validators. + Immortals get(fn immortals): Option>; } add_extra_genesis { - // Staking validators are used for initializing the genesis easier in tests. - // For the mainnet genesis, use `Module::::initialize_validators()`. config(validators): Vec<(T::AccountId, ReferralId, BalanceOf)>; config(glob_dist_ratio): (u32, u32); config(mining_ratio): (u32, u32); + config(candidate_requirement): (BalanceOf, BalanceOf); build(|config: &GenesisConfig| { assert!(config.glob_dist_ratio.0 + config.glob_dist_ratio.1 > 0); assert!(config.mining_ratio.0 + config.mining_ratio.1 > 0); @@ -218,6 +222,17 @@ decl_storage! { asset: config.mining_ratio.0, staking: config.mining_ratio.1, }); + ValidatorCandidateRequirement::::put(BondRequirement { + self_bonded: config.candidate_requirement.0, + total: config.candidate_requirement.1, + }); + Immortals::::put( + config + .validators + .iter() + .map(|(validator, _, _)| validator.clone()) + .collect::>(), + ); for (validator, referral_id, balance) in &config.validators { assert!( @@ -491,18 +506,31 @@ decl_module! { ValidatorBondingDuration::::put(new); } - // FIXME: add to WeightInfo once it's stable. - #[weight = 10_000_000] + #[weight = T::WeightInfo::set_minimum_penalty()] fn set_minimum_penalty(origin, #[compact] new: BalanceOf) { ensure_root(origin)?; MinimumPenalty::::put(new); } - #[weight = 10_000_000] + #[weight = T::WeightInfo::set_sessions_per_era()] fn set_sessions_per_era(origin, #[compact] new: SessionIndex) { ensure_root(origin)?; SessionsPerEra::put(new); } + + #[weight = 10_000_000] + fn set_immortals(origin, new: Vec) { + ensure_root(origin)?; + ensure!( + new.iter().find(|&v| !Self::is_validator(v)).is_none(), + Error::::NotValidator + ); + if new.is_empty() { + Immortals::::kill() + } else { + Immortals::::put(new); + } + } } } @@ -551,8 +579,9 @@ impl xpallet_support::traits::Validator for Module { } impl Module { + /// Initializes the validators exported from ChainX 1.0. #[cfg(feature = "std")] - pub fn initialize_validators( + pub fn initialize_legacy_validators( validators: &[xp_genesis_builder::ValidatorInfo>], ) -> DispatchResult { for xp_genesis_builder::ValidatorInfo { diff --git a/xpallets/mining/staking/src/mock.rs b/xpallets/mining/staking/src/mock.rs index 50b37437dd68c..9d5133e9440f5 100644 --- a/xpallets/mining/staking/src/mock.rs +++ b/xpallets/mining/staking/src/mock.rs @@ -309,6 +309,8 @@ impl ExtBuilder { ext.execute_with(|| { System::set_block_number(1); Timestamp::set_timestamp(INIT_TIMESTAMP); + // Just ignore the immortals for tests. + XStaking::set_immortals(Origin::root(), vec![]).unwrap(); }); ext diff --git a/xpallets/mining/staking/src/weights.rs b/xpallets/mining/staking/src/weights.rs index 0b1af9d598f0f..87fafb5333cb4 100644 --- a/xpallets/mining/staking/src/weights.rs +++ b/xpallets/mining/staking/src/weights.rs @@ -2,7 +2,7 @@ //! Weights for xpallet_mining_staking //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0 -//! DATE: 2020-11-20, STEPS: [50, ], REPEAT: 20, LOW RANGE: [], HIGH RANGE: [] +//! DATE: 2020-11-22, STEPS: [50, ], REPEAT: 20, LOW RANGE: [], HIGH RANGE: [] //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("benchmarks"), DB CACHE: 128 // Executed Command: @@ -42,117 +42,131 @@ pub trait WeightInfo { fn set_minimum_validator_count() -> Weight; fn set_bonding_duration() -> Weight; fn set_validator_bonding_duration() -> Weight; + fn set_minimum_penalty() -> Weight; + fn set_sessions_per_era() -> Weight; } /// Weights for xpallet_mining_staking using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn register() -> Weight { - (1_612_615_000 as Weight) + (2_094_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(92 as Weight)) .saturating_add(T::DbWeight::get().writes(7 as Weight)) } fn bond() -> Weight { - (214_417_000 as Weight) + (227_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(9 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } fn unbond() -> Weight { - (163_351_000 as Weight) + (153_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(3 as Weight)) } fn unlock_unbonded_withdrawal() -> Weight { - (134_368_000 as Weight) + (120_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(4 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } fn rebond() -> Weight { - (220_979_000 as Weight) + (199_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(10 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } fn claim() -> Weight { - (172_413_000 as Weight) + (155_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } fn chill() -> Weight { - (1_284_578_000 as Weight) + (1_407_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(55 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn validate() -> Weight { - (38_326_000 as Weight) + (25_000_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn set_validator_count() -> Weight { - (4_253_000 as Weight).saturating_add(T::DbWeight::get().writes(1 as Weight)) + (4_000_000 as Weight).saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn set_minimum_validator_count() -> Weight { - (4_190_000 as Weight).saturating_add(T::DbWeight::get().writes(1 as Weight)) + (4_000_000 as Weight).saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn set_bonding_duration() -> Weight { - (3_922_000 as Weight).saturating_add(T::DbWeight::get().writes(1 as Weight)) + (4_000_000 as Weight).saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn set_validator_bonding_duration() -> Weight { - (3_852_000 as Weight).saturating_add(T::DbWeight::get().writes(1 as Weight)) + (4_000_000 as Weight).saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + fn set_minimum_penalty() -> Weight { + (4_000_000 as Weight).saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + fn set_sessions_per_era() -> Weight { + (4_000_000 as Weight).saturating_add(T::DbWeight::get().writes(1 as Weight)) } } // For backwards compatibility and tests impl WeightInfo for () { fn register() -> Weight { - (1_612_615_000 as Weight) + (2_094_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(92 as Weight)) .saturating_add(RocksDbWeight::get().writes(7 as Weight)) } fn bond() -> Weight { - (214_417_000 as Weight) + (227_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(9 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } fn unbond() -> Weight { - (163_351_000 as Weight) + (153_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } fn unlock_unbonded_withdrawal() -> Weight { - (134_368_000 as Weight) + (120_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(4 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } fn rebond() -> Weight { - (220_979_000 as Weight) + (199_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(10 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } fn claim() -> Weight { - (172_413_000 as Weight) + (155_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } fn chill() -> Weight { - (1_284_578_000 as Weight) + (1_407_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(55 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn validate() -> Weight { - (38_326_000 as Weight) + (25_000_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn set_validator_count() -> Weight { - (4_253_000 as Weight).saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (4_000_000 as Weight).saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn set_minimum_validator_count() -> Weight { - (4_190_000 as Weight).saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (4_000_000 as Weight).saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn set_bonding_duration() -> Weight { - (3_922_000 as Weight).saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (4_000_000 as Weight).saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn set_validator_bonding_duration() -> Weight { - (3_852_000 as Weight).saturating_add(RocksDbWeight::get().writes(1 as Weight)) + (4_000_000 as Weight).saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + fn set_minimum_penalty() -> Weight { + (4_000_000 as Weight).saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + fn set_sessions_per_era() -> Weight { + (4_000_000 as Weight).saturating_add(RocksDbWeight::get().writes(1 as Weight)) } }