diff --git a/Cargo.lock b/Cargo.lock index 2b562c5..eaf7082 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4128,7 +4128,7 @@ dependencies = [ "pallet-balances", "pallet-grandpa", "pallet-session", - "pallet-staking 3.0.0", + "pallet-staking 3.1.0", "pallet-timestamp", "pallet-transaction-payment", "pallet-treasury", @@ -4661,7 +4661,7 @@ dependencies = [ [[package]] name = "pallet-staking" -version = "3.0.0" +version = "3.1.0" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5221,7 +5221,7 @@ dependencies = [ "pallet-scheduler", "pallet-session", "pallet-session-benchmarking", - "pallet-staking 3.0.0", + "pallet-staking 3.1.0", "pallet-staking-reward-curve", "pallet-timestamp", "pallet-tips", @@ -5600,7 +5600,7 @@ dependencies = [ [[package]] name = "protonet-runtime" -version = "0.1.0" +version = "0.1.2" dependencies = [ "chainbridge", "claims", @@ -5634,7 +5634,7 @@ dependencies = [ "pallet-scheduler", "pallet-session", "pallet-session-benchmarking", - "pallet-staking 3.0.0", + "pallet-staking 3.1.0", "pallet-staking-reward-curve", "pallet-timestamp", "pallet-tips", @@ -10077,12 +10077,12 @@ dependencies = [ [[package]] name = "xxnetwork" -version = "0.1.0" +version = "0.1.1" dependencies = [ "frame-support", "frame-system", "pallet-proxy", - "pallet-staking 3.0.0", + "pallet-staking 3.1.0", "pallet-staking-reward-fn", "parity-scale-codec", "serde", @@ -10093,7 +10093,7 @@ dependencies = [ [[package]] name = "xxnetwork-cli" -version = "0.1.1" +version = "0.1.2" dependencies = [ "assert_cmd", "async-std", @@ -10113,7 +10113,7 @@ dependencies = [ "pallet-balances", "pallet-grandpa", "pallet-im-online", - "pallet-staking 3.0.0", + "pallet-staking 3.1.0", "pallet-timestamp", "pallet-transaction-payment", "parity-scale-codec", @@ -10209,7 +10209,7 @@ dependencies = [ "pallet-scheduler", "pallet-session", "pallet-session-benchmarking", - "pallet-staking 3.0.0", + "pallet-staking 3.1.0", "pallet-staking-reward-curve", "pallet-timestamp", "pallet-tips", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 2281da4..ed73d43 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xxnetwork-cli" -version = "0.1.1" +version = "0.1.2" authors = ["xxlabs "] description = "Substrate based, xxnetwork blockchain node implementation in Rust." build = "build.rs" @@ -80,12 +80,12 @@ pallet-transaction-payment = { git = "https://github.com/xx-labs/substrate", bra frame-support = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false } pallet-im-online = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false } pallet-authority-discovery = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet" } -pallet-staking = { version = "3.0.0", path = "../staking" } +pallet-staking = { version = "3.1.0", path = "../staking" } pallet-grandpa = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet" } # node-specific dependencies xxnetwork-runtime = { version = "0.1.0", path = "../runtime/xxnetwork" } -protonet-runtime = { version = "0.1.0", path = "../runtime/protonet" } +protonet-runtime = { version = "0.1.2", path = "../runtime/protonet" } phoenixx-runtime = { version = "0.1.0", path = "../runtime/phoenixx" } node-rpc = { version = "0.1.0", path = "../rpc" } node-primitives = { version = "0.1.0", path = "../primitives" } diff --git a/executor/Cargo.toml b/executor/Cargo.toml index 6fb963d..4baaed9 100644 --- a/executor/Cargo.toml +++ b/executor/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "2.0.0" } node-primitives = { version = "0.1.0", path = "../primitives" } xxnetwork-runtime = { version = "0.1.0", path = "../runtime/xxnetwork" } -protonet-runtime = { version = "0.1.0", path = "../runtime/protonet" } +protonet-runtime = { version = "0.1.2", path = "../runtime/protonet" } phoenixx-runtime = { version = "0.1.0", path = "../runtime/phoenixx" } sc-executor = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet" } sp-core = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet" } diff --git a/runtime/phoenixx/Cargo.toml b/runtime/phoenixx/Cargo.toml index c54c2b1..14e2b88 100644 --- a/runtime/phoenixx/Cargo.toml +++ b/runtime/phoenixx/Cargo.toml @@ -67,7 +67,7 @@ pallet-proxy = { git = "https://github.com/xx-labs/substrate", branch = "xx-prot pallet-randomness-collective-flip = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false } pallet-session = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", features = ["historical"], default-features = false } pallet-session-benchmarking = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false, optional = true } -pallet-staking = { version = "3.0.0", default-features = false, path = "../../staking" } +pallet-staking = { version = "3.1.0", default-features = false, path = "../../staking" } pallet-staking-reward-curve = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false } pallet-scheduler = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false } pallet-timestamp = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false } diff --git a/runtime/protonet/Cargo.toml b/runtime/protonet/Cargo.toml index 61b9511..3896c33 100644 --- a/runtime/protonet/Cargo.toml +++ b/runtime/protonet/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "protonet-runtime" -version = "0.1.0" +version = "0.1.2" authors = ["xxlabs "] edition = "2018" build = "build.rs" @@ -67,7 +67,7 @@ pallet-proxy = { git = "https://github.com/xx-labs/substrate", branch = "xx-prot pallet-randomness-collective-flip = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false } pallet-session = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", features = ["historical"], default-features = false } pallet-session-benchmarking = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false, optional = true } -pallet-staking = { version = "3.0.0", default-features = false, path = "../../staking" } +pallet-staking = { version = "3.1.0", default-features = false, path = "../../staking" } pallet-staking-reward-curve = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false } pallet-scheduler = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false } pallet-timestamp = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false } diff --git a/runtime/protonet/src/lib.rs b/runtime/protonet/src/lib.rs index 0e598df..37fabac 100644 --- a/runtime/protonet/src/lib.rs +++ b/runtime/protonet/src/lib.rs @@ -108,7 +108,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to 0. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 100, + spec_version: 102, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -461,7 +461,7 @@ parameter_types! { pub const RewardsPoolId: PalletId = PalletId(*b"xx/rwrds"); pub const EraDuration: BlockNumber = ERA_DURATION_IN_SESSIONS * EPOCH_DURATION_IN_BLOCKS; pub const PayoutFrequency: BlockNumber = 3 * DAYS; - pub const CustodyDuration: BlockNumber = 45 * DAYS; + pub const CustodyDuration: BlockNumber = 3 * YEARS; pub const GovernanceCustodyDuration: BlockNumber = 45 * DAYS; pub const GovernanceProxy: ProxyType = ProxyType::Governance; } diff --git a/runtime/xxnetwork/Cargo.toml b/runtime/xxnetwork/Cargo.toml index 32ab8e4..effad69 100644 --- a/runtime/xxnetwork/Cargo.toml +++ b/runtime/xxnetwork/Cargo.toml @@ -67,7 +67,7 @@ pallet-proxy = { git = "https://github.com/xx-labs/substrate", branch = "xx-prot pallet-randomness-collective-flip = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false } pallet-session = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", features = ["historical"], default-features = false } pallet-session-benchmarking = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false, optional = true } -pallet-staking = { version = "3.0.0", default-features = false, path = "../../staking" } +pallet-staking = { version = "3.1.0", default-features = false, path = "../../staking" } pallet-staking-reward-curve = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false } pallet-scheduler = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false } pallet-timestamp = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false } diff --git a/staking/Cargo.toml b/staking/Cargo.toml index afcf8de..cc62ed3 100644 --- a/staking/Cargo.toml +++ b/staking/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-staking" -version = "3.0.0" +version = "3.1.0" authors = ["xxlabs "] edition = "2018" homepage = "https://xx.network" diff --git a/staking/src/lib.rs b/staking/src/lib.rs index 3d25d7a..30d0d3f 100644 --- a/staking/src/lib.rs +++ b/staking/src/lib.rs @@ -1148,6 +1148,8 @@ decl_error! { ValidatorInsufficientBond, /// CMIX ID already exists ValidatorCmixIdNotUnique, + /// The validator has enough bond and thus cannot be chilled forcefully by an external user. + CannotChillOther, } } @@ -1484,9 +1486,13 @@ decl_module! { ensure!(ledger.active >= >::get(), Error::::ValidatorInsufficientBond); // Ensure validator cmix id is unique + // unless validator exists and cmix id remains the same + let existing_prefs = >::get(stash); let cmix_root = prefs.cmix_root.clone(); - if >::contains_key(&cmix_root) { - Err(Error::::ValidatorCmixIdNotUnique)? + if existing_prefs.cmix_root != cmix_root { + if >::contains_key(&cmix_root) { + Err(Error::::ValidatorCmixIdNotUnique)? + } } >::remove(stash); // Remove existing prefs to ensure cmix ID is cleared @@ -1928,6 +1934,42 @@ decl_module! { Ok(()) } + + /// Declare a `controller` to stop participating as a validator. + /// + /// Effects will be felt at the beginning of the next era. + /// + /// The dispatch origin for this call must be _Signed_, but can be called by anyone. + /// + /// If the caller is the same as the controller being targeted, then no further checks are + /// enforced, and this function behaves just like `chill`. + /// + /// If the caller is different than the controller being targeted, the stash must be a + /// validator, and the active bond must be lower than the minimum validator bond. + /// + /// This can be helpful if the minimum validator bond is increased, and we need to remove + /// validators who don't satisfy the new bond. + #[weight = T::WeightInfo::chill_other()] + pub fn chill_other(origin, controller: T::AccountId) -> DispatchResult { + // Anyone can call this function. + let caller = ensure_signed(origin)?; + let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; + let stash = ledger.stash; + + // In order for one user to chill another user, the stash must be a + // validator, and the active bond must be lower than the minimum validator bond. + // + // Otherwise, if caller is the same as the controller, this is just like `chill`. + if caller != controller { + if !Validators::::contains_key(&stash) { + Err(Error::::CannotChillOther)? + } + ensure!(ledger.active < >::get(), Error::::CannotChillOther); + } + + Self::chill_stash(&stash); + Ok(()) + } } } diff --git a/staking/src/weights.rs b/staking/src/weights.rs index d3274ca..2e506d4 100644 --- a/staking/src/weights.rs +++ b/staking/src/weights.rs @@ -70,6 +70,7 @@ pub trait WeightInfo { fn new_era(v: u32, n: u32, ) -> Weight; fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight; fn get_npos_targets(v: u32, ) -> Weight; + fn chill_other() -> Weight; } /// Weights for pallet_staking using the Substrate node and recommended hardware. @@ -251,6 +252,11 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) } + fn chill_other() -> Weight { + (58_222_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } } // For backwards compatibility and tests @@ -431,4 +437,9 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) } + fn chill_other() -> Weight { + (58_222_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } } diff --git a/testing/Cargo.toml b/testing/Cargo.toml index 7ff9046..cc64d64 100644 --- a/testing/Cargo.toml +++ b/testing/Cargo.toml @@ -26,7 +26,7 @@ sp-io = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet" } frame-support = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet" } pallet-session = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet" } sp-runtime = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet" } -pallet-staking = { version = "3.0.0", path = "../staking" } +pallet-staking = { version = "3.1.0", path = "../staking" } sc-executor = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", features = ["wasmtime"] } sp-consensus = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet" } frame-system = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet" } diff --git a/xxnetwork/Cargo.toml b/xxnetwork/Cargo.toml index 2296de7..9bd625c 100644 --- a/xxnetwork/Cargo.toml +++ b/xxnetwork/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xxnetwork" -version = "0.1.0" +version = "0.1.1" authors = ["Bernardo Cardoso "] edition = "2018" @@ -18,7 +18,7 @@ sp-arithmetic = { git = "https://github.com/xx-labs/substrate", branch = "xx-pro frame-support = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false } frame-system = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false } -pallet-staking = { version = "3.0.0", default-features = false, path = "../staking" } +pallet-staking = { version = "3.1.0", default-features = false, path = "../staking" } pallet-staking-reward-fn = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false } pallet-proxy = { git = "https://github.com/xx-labs/substrate", branch = "xx-protonet", default-features = false } diff --git a/xxnetwork/src/custody.rs b/xxnetwork/src/custody.rs index e8294dc..7d309ce 100644 --- a/xxnetwork/src/custody.rs +++ b/xxnetwork/src/custody.rs @@ -43,18 +43,13 @@ impl CustodyInfo where { /// Return true if self is fully vested fn is_vested(&self) -> bool { - self.allocation == self.vested + self.allocation <= self.vested } /// Increase vested amount in self fn increase_vested(&mut self, amount: Balance) { self.vested += amount; } - - /// Get the remaining payout - fn remaining_payout(&self) -> Balance { - self.allocation - self.vested - } } /// Implement Custody sub module functions @@ -234,7 +229,7 @@ impl Module { // 3.2. Remove any proxies on the custody account Self::refund_team_custody_proxy(who.clone(), info.clone())?; // 3.3. Payout remaining amount - Self::do_payout(who.clone(), info.remaining_payout(), info, false)?; + Self::do_payout(who.clone(), Zero::zero(), info, false)?; // 3.4. Emmit custody done event Self::deposit_event(RawEvent::CustodyDone(who)); return Ok(()) @@ -299,7 +294,7 @@ impl Module { // limit transfers down to existential deposit until end of the custody period let reserve = info.reserve.clone(); let reserve_transferable_balance = - T::Inspect::reducible_balance(&reserve, keep_alive); + T::Inspect::reducible_balance(&reserve, keep_alive.clone()); // T::Currency and T::Inspect are both implemented by Balances pallet, so the // balance type is the same. However, explicit conversion is needed here. let reserve_balance = >::try_from( @@ -307,9 +302,15 @@ impl Module { ).ok().unwrap_or(Zero::zero()); // 3. Calculate amounts to withdraw from custody and reserve - let withdraw_custody = amount.min(custody_balance); - let withdraw_reserve = amount - withdraw_custody; - let withdraw_reserve = withdraw_reserve.min(reserve_balance); + // If custody period is done, transfer full amount from both accounts + // in order to not leave any inaccessible funds around + let (withdraw_custody, withdraw_reserve) = if keep_alive { + let from_custody = amount.min(custody_balance); + let from_reserve = amount - from_custody; + (from_custody, from_reserve.min(reserve_balance)) + } else { + (custody_balance, reserve_balance) + }; let withdraw = withdraw_custody + withdraw_reserve; // 4. Make transfer from custody, if possible @@ -324,7 +325,7 @@ impl Module { // Emmit TeamPayoutCustody event Self::deposit_event(RawEvent::PayoutFromCustody(who.clone(), withdraw_custody)); // Update total amount under custody - >::mutate(|n| *n -= withdraw_custody); + >::mutate(|n| *n = n.clone().saturating_sub(withdraw_custody)); } // 5. Make transfer from reserve, if possible