From 02cbf7c6fbb4e752a6656c56baa21b311ced55a4 Mon Sep 17 00:00:00 2001 From: hammeWang Date: Wed, 4 Sep 2019 22:51:04 +0800 Subject: [PATCH] restyle with rustfmt and follow polkadot coding style --- build.rs | 6 +- node/cli/build.rs | 43 +- node/cli/src/chain_spec.rs | 223 +++-- node/cli/src/factory_impl.rs | 416 ++++---- node/cli/src/lib.rs | 331 ++++--- node/cli/src/panic_handle.rs | 44 +- node/cli/src/service.rs | 694 +++++++------- node/executor/src/lib.rs | 1728 +++++++++++++++++----------------- node/primitives/src/lib.rs | 5 +- node/rpc-client/src/main.rs | 54 +- node/runtime/src/lib.rs | 503 +++++----- node/src/main.rs | 61 +- rustfmt.toml | 5 + srml/aura/src/lib.rs | 362 ++++--- srml/aura/src/mock.rs | 65 +- srml/kton/src/imbalance.rs | 14 +- srml/kton/src/lib.rs | 226 ++--- srml/kton/src/mock.rs | 40 +- srml/kton/src/tests.rs | 28 +- srml/staking/src/lib.rs | 831 ++++++++-------- srml/staking/src/mock.rs | 153 +-- srml/staking/src/phragmen.rs | 643 ++++++------- srml/staking/src/tests.rs | 655 ++++++++----- srml/staking/src/utils.rs | 16 +- srml/support/src/lib.rs | 3 +- srml/support/src/traits.rs | 3 +- srml/try/src/lib.rs | 88 +- srml/try/src/tests.rs | 100 +- 28 files changed, 3845 insertions(+), 3495 deletions(-) create mode 100644 rustfmt.toml diff --git a/build.rs b/build.rs index afc39d3b6..ce3d5bc53 100644 --- a/build.rs +++ b/build.rs @@ -1,8 +1,8 @@ -use vergen::{ConstantsFlags, generate_cargo_keys}; +use vergen::{generate_cargo_keys, ConstantsFlags}; const ERROR_MSG: &str = "Failed to generate metadata files"; fn main() { - generate_cargo_keys(ConstantsFlags::all()).expect(ERROR_MSG); - println!("cargo:rerun-if-changed=.git/HEAD"); + generate_cargo_keys(ConstantsFlags::all()).expect(ERROR_MSG); + println!("cargo:rerun-if-changed=.git/HEAD"); } diff --git a/node/cli/build.rs b/node/cli/build.rs index e7a7b271f..671c3f473 100644 --- a/node/cli/build.rs +++ b/node/cli/build.rs @@ -14,37 +14,40 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use cli::{NoCustom, CoreParams}; +use cli::{CoreParams, NoCustom}; -use std::{fs, env, path::Path}; +use std::{env, fs, path::Path}; -use structopt::{StructOpt, clap::Shell}; +use structopt::{clap::Shell, StructOpt}; fn main() { - build_shell_completion(); + build_shell_completion(); } /// Build shell completion scripts for all known shells /// Full list in https://github.com/kbknapp/clap-rs/blob/e9d0562a1dc5dfe731ed7c767e6cee0af08f0cf9/src/app/parser.rs#L123 fn build_shell_completion() { - for shell in &[Shell::Bash, Shell::Fish, Shell::Zsh, Shell::Elvish, Shell::PowerShell] { - build_completion(shell); - } + for shell in &[Shell::Bash, Shell::Fish, Shell::Zsh, Shell::Elvish, Shell::PowerShell] { + build_completion(shell); + } } /// Build the shell auto-completion for a given Shell fn build_completion(shell: &Shell) { - let outdir = match env::var_os("OUT_DIR") { - None => return, - Some(dir) => dir, - }; - let path = Path::new(&outdir) - .parent().unwrap() - .parent().unwrap() - .parent().unwrap() - .join("completion-scripts"); - - fs::create_dir(&path).ok(); - - CoreParams::::clap().gen_completions("substrate-node", *shell, &path); + let outdir = match env::var_os("OUT_DIR") { + None => return, + Some(dir) => dir, + }; + let path = Path::new(&outdir) + .parent() + .unwrap() + .parent() + .unwrap() + .parent() + .unwrap() + .join("completion-scripts"); + + fs::create_dir(&path).ok(); + + CoreParams::::clap().gen_completions("substrate-node", *shell, &path); } diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index 74b5eb6ff..25ea83daf 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -19,20 +19,18 @@ use grandpa::AuthorityId as GrandpaId; use hex_literal::hex; use node_primitives::{AccountId, AuraId, Balance}; +pub use node_runtime::GenesisConfig; use node_runtime::{ - AuraConfig, BalancesConfig, ContractsConfig, DAYS, - COIN, GrandpaConfig, IndicesConfig, MILLI, - Perbill, SECS_PER_BLOCK, KtonConfig, - SessionConfig, SessionKeys, StakerStatus, - StakingConfig, SudoConfig, SystemConfig, TimestampConfig, + AuraConfig, BalancesConfig, ContractsConfig, GrandpaConfig, IndicesConfig, KtonConfig, Perbill, SessionConfig, + SessionKeys, StakerStatus, StakingConfig, SudoConfig, SystemConfig, TimestampConfig, COIN, DAYS, MILLI, + SECS_PER_BLOCK, }; -pub use node_runtime::GenesisConfig; -use primitives::{crypto::UncheckedInto, ed25519, Pair, sr25519}; +use primitives::{crypto::UncheckedInto, ed25519, sr25519, Pair}; +use serde_json::de::ParserNumber; +use serde_json::Number; use substrate_service; -use substrate_telemetry::TelemetryEndpoints; use substrate_service::Properties; -use serde_json::Number; -use serde_json::de::ParserNumber; +use substrate_telemetry::TelemetryEndpoints; const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; @@ -55,44 +53,48 @@ fn staging_testnet_config_genesis() -> GenesisConfig { // and // for i in 1 2 3 4 ; do for j in session; do subkey --ed25519 inspect "$secret"//fir//$j//$i; done; done - let initial_authorities: Vec<(AccountId, AccountId, AuraId, GrandpaId)> = - vec![( - // 5Fbsd6WXDGiLTxunqeK5BATNiocfCqu9bS1yArVjCgeBLkVy - hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].unchecked_into(), - // 5EnCiV7wSHeNhjW3FSUwiJNkcc2SBkPLn5Nj93FmbLtBjQUq - hex!["781ead1e2fa9ccb74b44c19d29cb2a7a4b5be3972927ae98cd3877523976a276"].unchecked_into(), - // 5Fb9ayurnxnaXj56CjmyQLBiadfRCqUbL2VWNbbe1nZU6wiC - hex!["9becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe9699332"].unchecked_into(), - // 5Fb9ayurnxnaXj56CjmyQLBiadfRCqUbL2VWNbbe1nZU6wiC - hex!["9becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe9699332"].unchecked_into(), - ), ( - // 5ERawXCzCWkjVq3xz1W5KGNtVx2VdefvZ62Bw1FEuZW4Vny2 - hex!["68655684472b743e456907b398d3a44c113f189e56d1bbfd55e889e295dfde78"].unchecked_into(), - // 5Gc4vr42hH1uDZc93Nayk5G7i687bAQdHHc9unLuyeawHipF - hex!["c8dc79e36b29395413399edaec3e20fcca7205fb19776ed8ddb25d6f427ec40e"].unchecked_into(), - // 5EockCXN6YkiNCDjpqqnbcqd4ad35nU4RmA1ikM4YeRN4WcE - hex!["7932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f"].unchecked_into(), - // 5EockCXN6YkiNCDjpqqnbcqd4ad35nU4RmA1ikM4YeRN4WcE - hex!["7932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f"].unchecked_into(), - ), ( - // 5DyVtKWPidondEu8iHZgi6Ffv9yrJJ1NDNLom3X9cTDi98qp - hex!["547ff0ab649283a7ae01dbc2eb73932eba2fb09075e9485ff369082a2ff38d65"].unchecked_into(), - // 5FeD54vGVNpFX3PndHPXJ2MDakc462vBCD5mgtWRnWYCpZU9 - hex!["9e42241d7cd91d001773b0b616d523dd80e13c6c2cab860b1234ef1b9ffc1526"].unchecked_into(), - // 5E1jLYfLdUQKrFrtqoKgFrRvxM3oQPMbf6DfcsrugZZ5Bn8d - hex!["5633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440"].unchecked_into(), - // 5E1jLYfLdUQKrFrtqoKgFrRvxM3oQPMbf6DfcsrugZZ5Bn8d - hex!["5633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440"].unchecked_into(), - ), ( - // 5HYZnKWe5FVZQ33ZRJK1rG3WaLMztxWrrNDb1JRwaHHVWyP9 - hex!["f26cdb14b5aec7b2789fd5ca80f979cef3761897ae1f37ffb3e154cbcc1c2663"].unchecked_into(), - // 5EPQdAQ39WQNLCRjWsCk5jErsCitHiY5ZmjfWzzbXDoAoYbn - hex!["66bc1e5d275da50b72b15de072a2468a5ad414919ca9054d2695767cf650012f"].unchecked_into(), - // 5DMa31Hd5u1dwoRKgC4uvqyrdK45RHv3CpwvpUC1EzuwDit4 - hex!["3919132b851ef0fd2dae42a7e734fe547af5a6b809006100f48944d7fae8e8ef"].unchecked_into(), - // 5DMa31Hd5u1dwoRKgC4uvqyrdK45RHv3CpwvpUC1EzuwDit4 - hex!["3919132b851ef0fd2dae42a7e734fe547af5a6b809006100f48944d7fae8e8ef"].unchecked_into(), - )]; + let initial_authorities: Vec<(AccountId, AccountId, AuraId, GrandpaId)> = vec![ + ( + // 5Fbsd6WXDGiLTxunqeK5BATNiocfCqu9bS1yArVjCgeBLkVy + hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].unchecked_into(), + // 5EnCiV7wSHeNhjW3FSUwiJNkcc2SBkPLn5Nj93FmbLtBjQUq + hex!["781ead1e2fa9ccb74b44c19d29cb2a7a4b5be3972927ae98cd3877523976a276"].unchecked_into(), + // 5Fb9ayurnxnaXj56CjmyQLBiadfRCqUbL2VWNbbe1nZU6wiC + hex!["9becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe9699332"].unchecked_into(), + // 5Fb9ayurnxnaXj56CjmyQLBiadfRCqUbL2VWNbbe1nZU6wiC + hex!["9becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe9699332"].unchecked_into(), + ), + ( + // 5ERawXCzCWkjVq3xz1W5KGNtVx2VdefvZ62Bw1FEuZW4Vny2 + hex!["68655684472b743e456907b398d3a44c113f189e56d1bbfd55e889e295dfde78"].unchecked_into(), + // 5Gc4vr42hH1uDZc93Nayk5G7i687bAQdHHc9unLuyeawHipF + hex!["c8dc79e36b29395413399edaec3e20fcca7205fb19776ed8ddb25d6f427ec40e"].unchecked_into(), + // 5EockCXN6YkiNCDjpqqnbcqd4ad35nU4RmA1ikM4YeRN4WcE + hex!["7932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f"].unchecked_into(), + // 5EockCXN6YkiNCDjpqqnbcqd4ad35nU4RmA1ikM4YeRN4WcE + hex!["7932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f"].unchecked_into(), + ), + ( + // 5DyVtKWPidondEu8iHZgi6Ffv9yrJJ1NDNLom3X9cTDi98qp + hex!["547ff0ab649283a7ae01dbc2eb73932eba2fb09075e9485ff369082a2ff38d65"].unchecked_into(), + // 5FeD54vGVNpFX3PndHPXJ2MDakc462vBCD5mgtWRnWYCpZU9 + hex!["9e42241d7cd91d001773b0b616d523dd80e13c6c2cab860b1234ef1b9ffc1526"].unchecked_into(), + // 5E1jLYfLdUQKrFrtqoKgFrRvxM3oQPMbf6DfcsrugZZ5Bn8d + hex!["5633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440"].unchecked_into(), + // 5E1jLYfLdUQKrFrtqoKgFrRvxM3oQPMbf6DfcsrugZZ5Bn8d + hex!["5633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440"].unchecked_into(), + ), + ( + // 5HYZnKWe5FVZQ33ZRJK1rG3WaLMztxWrrNDb1JRwaHHVWyP9 + hex!["f26cdb14b5aec7b2789fd5ca80f979cef3761897ae1f37ffb3e154cbcc1c2663"].unchecked_into(), + // 5EPQdAQ39WQNLCRjWsCk5jErsCitHiY5ZmjfWzzbXDoAoYbn + hex!["66bc1e5d275da50b72b15de072a2468a5ad414919ca9054d2695767cf650012f"].unchecked_into(), + // 5DMa31Hd5u1dwoRKgC4uvqyrdK45RHv3CpwvpUC1EzuwDit4 + hex!["3919132b851ef0fd2dae42a7e734fe547af5a6b809006100f48944d7fae8e8ef"].unchecked_into(), + // 5DMa31Hd5u1dwoRKgC4uvqyrdK45RHv3CpwvpUC1EzuwDit4 + hex!["3919132b851ef0fd2dae42a7e734fe547af5a6b809006100f48944d7fae8e8ef"].unchecked_into(), + ), + ]; // generated with secret: subkey inspect "$secret"/fir let endowed_accounts: Vec = vec![ @@ -105,31 +107,41 @@ fn staging_testnet_config_genesis() -> GenesisConfig { GenesisConfig { system: Some(SystemConfig { - code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm").to_vec(), // FIXME change once we have #1252 + code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm") + .to_vec(), // FIXME change once we have #1252 changes_trie_config: Default::default(), }), balances: Some(BalancesConfig { - balances: endowed_accounts.iter().cloned() + balances: endowed_accounts + .iter() + .cloned() .map(|k| (k, ENDOWMENT)) .chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH))) .collect(), vesting: vec![], }), kton: Some(KtonConfig { - balances: endowed_accounts.iter().cloned() + balances: endowed_accounts + .iter() + .cloned() .map(|k| (k, ENDOWMENT)) .chain(initial_authorities.iter().map(|x| (x.0.clone(), ENDOWMENT))) .collect(), vesting: vec![], }), indices: Some(IndicesConfig { - ids: endowed_accounts.iter().cloned() + ids: endowed_accounts + .iter() + .cloned() .chain(initial_authorities.iter().map(|x| x.0.clone())) .collect::>(), }), session: Some(SessionConfig { validators: initial_authorities.iter().map(|x| x.1.clone()).collect(), - keys: initial_authorities.iter().map(|x| (x.1.clone(), SessionKeys(x.2.clone(), x.2.clone()))).collect::>(), + keys: initial_authorities + .iter() + .map(|x| (x.1.clone(), SessionKeys(x.2.clone(), x.2.clone()))) + .collect::>(), }), staking: Some(StakingConfig { current_era: 0, @@ -139,7 +151,10 @@ fn staging_testnet_config_genesis() -> GenesisConfig { validator_count: 7, offline_slash_grace: 4, minimum_validator_count: 4, - stakers: initial_authorities.iter().map(|x| (x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator)).collect(), + stakers: initial_authorities + .iter() + .map(|x| (x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator)) + .collect(), invulnerables: initial_authorities.iter().map(|x| x.1.clone()).collect(), }), timestamp: Some(TimestampConfig { @@ -158,7 +173,6 @@ fn staging_testnet_config_genesis() -> GenesisConfig { grandpa: Some(GrandpaConfig { authorities: initial_authorities.iter().map(|x| (x.3.clone(), 1)).collect(), }), - } } @@ -204,7 +218,7 @@ pub fn get_authority_keys_from_seed(seed: &str) -> (AccountId, AccountId, AuraId get_account_id_from_seed(&format!("{}//stash", seed)), get_account_id_from_seed(seed), get_aura_id_from_seed(seed), - get_grandpa_id_from_seed(seed) + get_grandpa_id_from_seed(seed), ) } @@ -237,7 +251,8 @@ pub fn testnet_genesis( GenesisConfig { system: Some(SystemConfig { - code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm").to_vec(), + code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm") + .to_vec(), changes_trie_config: Default::default(), }), indices: Some(IndicesConfig { @@ -248,7 +263,9 @@ pub fn testnet_genesis( vesting: vec![], }), kton: Some(KtonConfig { - balances: endowed_accounts.iter().cloned() + balances: endowed_accounts + .iter() + .cloned() .map(|k| (k, ENDOWMENT)) .chain(initial_authorities.iter().map(|x| (x.0.clone(), ENDOWMENT))) .collect(), @@ -256,7 +273,10 @@ pub fn testnet_genesis( }), session: Some(SessionConfig { validators: initial_authorities.iter().map(|x| x.1.clone()).collect(), - keys: initial_authorities.iter().map(|x| (x.1.clone(), SessionKeys(x.2.clone(), x.2.clone()))).collect::>(), + keys: initial_authorities + .iter() + .map(|x| (x.1.clone(), SessionKeys(x.2.clone(), x.2.clone()))) + .collect::>(), }), staking: Some(StakingConfig { current_era: 0, @@ -267,11 +287,14 @@ pub fn testnet_genesis( offline_slash: Perbill::from_parts(1_000_000), session_reward: Perbill::from_percent(90), offline_slash_grace: 4, - stakers: initial_authorities.iter().map(|x| (x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator)).collect(), + stakers: initial_authorities + .iter() + .map(|x| (x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator)) + .collect(), invulnerables: initial_authorities.iter().map(|x| x.1.clone()).collect(), }), timestamp: Some(TimestampConfig { - minimum_period: 3, // 3*2=6 second block time. + minimum_period: 3, // 3*2=6 second block time. }), contracts: Some(ContractsConfig { current_schedule: contracts::Schedule { @@ -280,9 +303,7 @@ pub fn testnet_genesis( }, gas_price: 1 * MILLI, }), - sudo: Some(SudoConfig { - key: root_key, - }), + sudo: Some(SudoConfig { key: root_key }), aura: Some(AuraConfig { authorities: initial_authorities.iter().map(|x| x.2.clone()).collect(), }), @@ -294,9 +315,7 @@ pub fn testnet_genesis( fn development_config_genesis() -> GenesisConfig { testnet_genesis( - vec![ - get_authority_keys_from_seed("Alice"), - ], + vec![get_authority_keys_from_seed("Alice")], get_account_id_from_seed("Alice"), None, true, @@ -315,7 +334,6 @@ fn crayfish_config_genesis() -> GenesisConfig { ) } - /// Helper function to create GenesisConfig for testing pub fn crayfish_testnet_genesis( initial_authorities: Vec<(AccountId, AccountId, AuraId, GrandpaId)>, @@ -345,14 +363,17 @@ pub fn crayfish_testnet_genesis( GenesisConfig { system: Some(SystemConfig { - code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm").to_vec(), + code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm") + .to_vec(), changes_trie_config: Default::default(), }), indices: Some(IndicesConfig { ids: endowed_accounts.clone(), }), balances: Some(BalancesConfig { - balances: endowed_accounts.iter().cloned() + balances: endowed_accounts + .iter() + .cloned() .map(|k| (k, 1 * ENDOWMENT)) .chain(initial_authorities.iter().map(|x| (x.0.clone(), 4 * ENDOWMENT))) .collect(), @@ -364,7 +385,10 @@ pub fn crayfish_testnet_genesis( }), session: Some(SessionConfig { validators: initial_authorities.iter().map(|x| x.1.clone()).collect(), - keys: initial_authorities.iter().map(|x| (x.1.clone(), SessionKeys(x.2.clone(), x.2.clone()))).collect::>(), + keys: initial_authorities + .iter() + .map(|x| (x.1.clone(), SessionKeys(x.2.clone(), x.2.clone()))) + .collect::>(), }), staking: Some(StakingConfig { current_era: 0, @@ -374,11 +398,14 @@ pub fn crayfish_testnet_genesis( offline_slash: Perbill::from_parts(1_000_000), session_reward: Perbill::from_percent(90), offline_slash_grace: 4, - stakers: initial_authorities.iter().map(|x| (x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator)).collect(), + stakers: initial_authorities + .iter() + .map(|x| (x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator)) + .collect(), invulnerables: initial_authorities.iter().map(|x| x.1.clone()).collect(), }), timestamp: Some(TimestampConfig { - minimum_period: 3, // 3*2=6 second block time. + minimum_period: 3, // 3*2=6 second block time. }), contracts: Some(ContractsConfig { current_schedule: contracts::Schedule { @@ -387,9 +414,7 @@ pub fn crayfish_testnet_genesis( }, gas_price: 1 * MILLI, }), - sudo: Some(SudoConfig { - key: root_key, - }), + sudo: Some(SudoConfig { key: root_key }), aura: Some(AuraConfig { authorities: initial_authorities.iter().map(|x| x.2.clone()).collect(), }), @@ -399,10 +424,18 @@ pub fn crayfish_testnet_genesis( } } - /// Development config (single validator Alice) pub fn development_config() -> ChainSpec { - ChainSpec::from_genesis("Development", "dev", development_config_genesis, vec![], None, None, None, None) + ChainSpec::from_genesis( + "Development", + "dev", + development_config_genesis, + vec![], + None, + None, + None, + None, + ) } fn local_testnet_genesis() -> GenesisConfig { @@ -419,14 +452,26 @@ fn local_testnet_genesis() -> GenesisConfig { fn token_properties() -> Option { let mut properties = Properties::new(); - properties.insert("tokenDecimals".to_owned(), serde_json::Value::Number(Number::from(ParserNumber::U64(9)))); + properties.insert( + "tokenDecimals".to_owned(), + serde_json::Value::Number(Number::from(ParserNumber::U64(9))), + ); properties.insert("tokenSymbol".to_owned(), serde_json::Value::String("RING".to_owned())); Some(properties) } /// Local testnet config (multivalidator Alice + Bob) pub fn local_testnet_config() -> ChainSpec { - ChainSpec::from_genesis("Local Testnet", "local_testnet", local_testnet_genesis, vec![], None, None, None, token_properties()) + ChainSpec::from_genesis( + "Local Testnet", + "local_testnet", + local_testnet_genesis, + vec![], + None, + None, + None, + token_properties(), + ) } /// c￿rayfish testnet config (multivalidator Alice + Bob) @@ -439,7 +484,8 @@ pub fn crayfish_testnet_config() -> ChainSpec { Some(TelemetryEndpoints::new(vec![(STAGING_TELEMETRY_URL.to_string(), 0)])), Some("DAR"), None, - token_properties()) + token_properties(), + ) } #[cfg(test)] @@ -458,9 +504,7 @@ pub(crate) mod tests { fn local_testnet_genesis_instant_single() -> GenesisConfig { let mut genesis = testnet_genesis( - vec![ - get_authority_keys_from_seed("Alice"), - ], + vec![get_authority_keys_from_seed("Alice")], get_account_id_from_seed("Alice"), None, false, @@ -485,7 +529,16 @@ pub(crate) mod tests { /// Local testnet config (multivalidator Alice + Bob) pub fn integration_test_config_with_two_authorities() -> ChainSpec { - ChainSpec::from_genesis("Integration Test", "test", local_testnet_genesis_instant, vec![], None, None, None, None) + ChainSpec::from_genesis( + "Integration Test", + "test", + local_testnet_genesis_instant, + vec![], + None, + None, + None, + None, + ) } #[test] diff --git a/node/cli/src/factory_impl.rs b/node/cli/src/factory_impl.rs index 3cb16ee6f..bac3c8fb0 100644 --- a/node/cli/src/factory_impl.rs +++ b/node/cli/src/factory_impl.rs @@ -18,242 +18,240 @@ //! using the cli to manufacture transactions and distribute them //! to accounts. -use rand::{Rng, SeedableRng}; use rand::rngs::StdRng; +use rand::{Rng, SeedableRng}; -use parity_codec::Decode; +use crate::service; +use finality_tracker; +use inherents::InherentData; use keyring::sr25519::Keyring; use node_primitives::Hash; -use node_runtime::{Call, CheckedExtrinsic, UncheckedExtrinsic, BalancesCall}; -use primitives::sr25519; -use primitives::crypto::Pair; +use node_runtime::{BalancesCall, Call, CheckedExtrinsic, UncheckedExtrinsic}; +use parity_codec::Decode; use parity_codec::Encode; +use primitives::crypto::Pair; +use primitives::sr25519; use sr_primitives::generic::Era; use sr_primitives::traits::{Block as BlockT, Header as HeaderT}; use substrate_service::ServiceFactory; -use transaction_factory::RuntimeAdapter; -use transaction_factory::modes::Mode; -use crate::service; -use inherents::InherentData; use timestamp; -use finality_tracker; +use transaction_factory::modes::Mode; +use transaction_factory::RuntimeAdapter; // TODO get via api: >::minimum_period(). See #2587. const MINIMUM_PERIOD: u64 = 99; pub struct FactoryState { - block_no: N, - - mode: Mode, - start_number: u64, - rounds: u64, - round: u64, - block_in_round: u64, - num: u64, + block_no: N, + + mode: Mode, + start_number: u64, + rounds: u64, + round: u64, + block_in_round: u64, + num: u64, } type Number = <::Header as HeaderT>::Number; impl RuntimeAdapter for FactoryState { - type AccountId = node_primitives::AccountId; - type Balance = node_primitives::Balance; - type Block = node_primitives::Block; - type Phase = sr_primitives::generic::Phase; - type Secret = sr25519::Pair; - type Index = node_primitives::Nonce; - - type Number = Number; - - fn new( - mode: Mode, - num: u64, - rounds: u64, - ) -> FactoryState { - FactoryState { - mode, - num: num, - round: 0, - rounds, - block_in_round: 0, - block_no: 0, - start_number: 0, - } - } - - fn block_no(&self) -> Self::Number { - self.block_no - } - - fn block_in_round(&self) -> Self::Number { - self.block_in_round - } - - fn rounds(&self) -> Self::Number { - self.rounds - } - - fn num(&self) -> Self::Number { - self.num - } - - fn round(&self) -> Self::Number { - self.round - } - - fn start_number(&self) -> Self::Number { - self.start_number - } - - fn mode(&self) -> &Mode { - &self.mode - } - - fn set_block_no(&mut self, val: Self::Number) { - self.block_no = val; - } - - fn set_block_in_round(&mut self, val: Self::Number) { - self.block_in_round = val; - } - - fn set_round(&mut self, val: Self::Number) { - self.round = val; - } - - fn transfer_extrinsic( - &self, - sender: &Self::AccountId, - key: &Self::Secret, - destination: &Self::AccountId, - amount: &Self::Number, - prior_block_hash: &::Hash, - ) -> ::Extrinsic { - let index = self.extract_index(&sender, prior_block_hash); - let phase = self.extract_phase(*prior_block_hash); - - sign::(CheckedExtrinsic { - signed: Some((sender.clone(), index)), - function: Call::Balances( - BalancesCall::transfer( - indices::address::Address::Id( - destination.clone().into() - ), - (*amount).into() - ) - ) - }, key, &prior_block_hash, phase) - } - - fn inherent_extrinsics(&self) -> InherentData { - let timestamp = self.block_no * MINIMUM_PERIOD; - - let mut inherent = InherentData::new(); - inherent.put_data(timestamp::INHERENT_IDENTIFIER, ×tamp) - .expect("Failed putting timestamp inherent"); - inherent.put_data(finality_tracker::INHERENT_IDENTIFIER, &self.block_no) - .expect("Failed putting finalized number inherent"); - inherent - } - - fn minimum_balance() -> Self::Number { - // TODO get correct amount via api. See #2587. - 1337 - } - - fn master_account_id() -> Self::AccountId { - Keyring::Alice.pair().public() - } - - fn master_account_secret() -> Self::Secret { - Keyring::Alice.pair() - } - - /// Generates a random `AccountId` from `seed`. - fn gen_random_account_id(seed: &Self::Number) -> Self::AccountId { - let pair: sr25519::Pair = sr25519::Pair::from_seed(&gen_seed_bytes(*seed)); - pair.public().into() - } - - /// Generates a random `Secret` from `seed`. - fn gen_random_account_secret(seed: &Self::Number) -> Self::Secret { - let pair: sr25519::Pair = sr25519::Pair::from_seed(&gen_seed_bytes(*seed)); - pair - } - - fn extract_index( - &self, - _account_id: &Self::AccountId, - _block_hash: &::Hash, - ) -> Self::Index { - // TODO get correct index for account via api. See #2587. - // This currently prevents the factory from being used - // without a preceding purge of the database. - if self.mode == Mode::MasterToN || self.mode == Mode::MasterTo1 { - self.block_no() - } else { - match self.round() { - 0 => - // if round is 0 all transactions will be done with master as a sender - self.block_no(), - _ => - // if round is e.g. 1 every sender account will be new and not yet have - // any transactions done - 0 - } - } - } - - fn extract_phase( - &self, - _block_hash: ::Hash - ) -> Self::Phase { - // TODO get correct phase via api. See #2587. - // This currently prevents the factory from being used - // without a preceding purge of the database. - self.block_no - } + type AccountId = node_primitives::AccountId; + type Balance = node_primitives::Balance; + type Block = node_primitives::Block; + type Phase = sr_primitives::generic::Phase; + type Secret = sr25519::Pair; + type Index = node_primitives::Nonce; + + type Number = Number; + + fn new(mode: Mode, num: u64, rounds: u64) -> FactoryState { + FactoryState { + mode, + num: num, + round: 0, + rounds, + block_in_round: 0, + block_no: 0, + start_number: 0, + } + } + + fn block_no(&self) -> Self::Number { + self.block_no + } + + fn block_in_round(&self) -> Self::Number { + self.block_in_round + } + + fn rounds(&self) -> Self::Number { + self.rounds + } + + fn num(&self) -> Self::Number { + self.num + } + + fn round(&self) -> Self::Number { + self.round + } + + fn start_number(&self) -> Self::Number { + self.start_number + } + + fn mode(&self) -> &Mode { + &self.mode + } + + fn set_block_no(&mut self, val: Self::Number) { + self.block_no = val; + } + + fn set_block_in_round(&mut self, val: Self::Number) { + self.block_in_round = val; + } + + fn set_round(&mut self, val: Self::Number) { + self.round = val; + } + + fn transfer_extrinsic( + &self, + sender: &Self::AccountId, + key: &Self::Secret, + destination: &Self::AccountId, + amount: &Self::Number, + prior_block_hash: &::Hash, + ) -> ::Extrinsic { + let index = self.extract_index(&sender, prior_block_hash); + let phase = self.extract_phase(*prior_block_hash); + + sign::( + CheckedExtrinsic { + signed: Some((sender.clone(), index)), + function: Call::Balances(BalancesCall::transfer( + indices::address::Address::Id(destination.clone().into()), + (*amount).into(), + )), + }, + key, + &prior_block_hash, + phase, + ) + } + + fn inherent_extrinsics(&self) -> InherentData { + let timestamp = self.block_no * MINIMUM_PERIOD; + + let mut inherent = InherentData::new(); + inherent + .put_data(timestamp::INHERENT_IDENTIFIER, ×tamp) + .expect("Failed putting timestamp inherent"); + inherent + .put_data(finality_tracker::INHERENT_IDENTIFIER, &self.block_no) + .expect("Failed putting finalized number inherent"); + inherent + } + + fn minimum_balance() -> Self::Number { + // TODO get correct amount via api. See #2587. + 1337 + } + + fn master_account_id() -> Self::AccountId { + Keyring::Alice.pair().public() + } + + fn master_account_secret() -> Self::Secret { + Keyring::Alice.pair() + } + + /// Generates a random `AccountId` from `seed`. + fn gen_random_account_id(seed: &Self::Number) -> Self::AccountId { + let pair: sr25519::Pair = sr25519::Pair::from_seed(&gen_seed_bytes(*seed)); + pair.public().into() + } + + /// Generates a random `Secret` from `seed`. + fn gen_random_account_secret(seed: &Self::Number) -> Self::Secret { + let pair: sr25519::Pair = sr25519::Pair::from_seed(&gen_seed_bytes(*seed)); + pair + } + + fn extract_index(&self, _account_id: &Self::AccountId, _block_hash: &::Hash) -> Self::Index { + // TODO get correct index for account via api. See #2587. + // This currently prevents the factory from being used + // without a preceding purge of the database. + if self.mode == Mode::MasterToN || self.mode == Mode::MasterTo1 { + self.block_no() + } else { + match self.round() { + 0 => + // if round is 0 all transactions will be done with master as a sender + { + self.block_no() + } + _ => + // if round is e.g. 1 every sender account will be new and not yet have + // any transactions done + { + 0 + } + } + } + } + + fn extract_phase(&self, _block_hash: ::Hash) -> Self::Phase { + // TODO get correct phase via api. See #2587. + // This currently prevents the factory from being used + // without a preceding purge of the database. + self.block_no + } } fn gen_seed_bytes(seed: u64) -> [u8; 32] { - let mut rng: StdRng = SeedableRng::seed_from_u64(seed); + let mut rng: StdRng = SeedableRng::seed_from_u64(seed); - let mut seed_bytes = [0u8; 32]; - for i in 0..32 { - seed_bytes[i] = rng.gen::(); - } - seed_bytes + let mut seed_bytes = [0u8; 32]; + for i in 0..32 { + seed_bytes[i] = rng.gen::(); + } + seed_bytes } /// Creates an `UncheckedExtrinsic` containing the appropriate signature for /// a `CheckedExtrinsics`. fn sign( - xt: CheckedExtrinsic, - key: &sr25519::Pair, - prior_block_hash: &Hash, - phase: u64, + xt: CheckedExtrinsic, + key: &sr25519::Pair, + prior_block_hash: &Hash, + phase: u64, ) -> ::Extrinsic { - let s = match xt.signed { - Some((signed, index)) => { - let era = Era::mortal(256, phase); - let payload = (index.into(), xt.function, era, prior_block_hash); - let signature = payload.using_encoded(|b| { - if b.len() > 256 { - key.sign(&sr_io::blake2_256(b)) - } else { - key.sign(b) - } - }).into(); - UncheckedExtrinsic { - signature: Some((indices::address::Address::Id(signed), signature, payload.0, era)), - function: payload.1, - } - } - None => UncheckedExtrinsic { - signature: None, - function: xt.function, - }, - }; - - let e = Encode::encode(&s); - Decode::decode(&mut &e[..]).expect("Failed to decode signed unchecked extrinsic") + let s = match xt.signed { + Some((signed, index)) => { + let era = Era::mortal(256, phase); + let payload = (index.into(), xt.function, era, prior_block_hash); + let signature = payload + .using_encoded(|b| { + if b.len() > 256 { + key.sign(&sr_io::blake2_256(b)) + } else { + key.sign(b) + } + }) + .into(); + UncheckedExtrinsic { + signature: Some((indices::address::Address::Id(signed), signature, payload.0, era)), + function: payload.1, + } + } + None => UncheckedExtrinsic { + signature: None, + function: xt.function, + }, + }; + + let e = Encode::encode(&s); + Decode::decode(&mut &e[..]).expect("Failed to decode signed unchecked extrinsic") } diff --git a/node/cli/src/lib.rs b/node/cli/src/lib.rs index e112ceaf3..81e2097ac 100644 --- a/node/cli/src/lib.rs +++ b/node/cli/src/lib.rs @@ -23,218 +23,213 @@ extern crate serde; pub use cli::error; pub mod chain_spec; -mod service; mod factory_impl; mod panic_handle; +mod service; -use tokio::prelude::Future; -use tokio::runtime::{Builder as RuntimeBuilder, Runtime}; -pub use cli::{VersionInfo, IntoExit, NoCustom, SharedParams}; -use substrate_service::{ServiceFactory, Roles as ServiceRoles}; -use std::ops::Deref; -use log::info; -use structopt::{StructOpt, clap::App}; -use cli::{AugmentClap, GetLogFilter}; use crate::factory_impl::FactoryState; use crate::panic_handle::set as panic_set; +use cli::{AugmentClap, GetLogFilter}; +pub use cli::{IntoExit, NoCustom, SharedParams, VersionInfo}; +use log::info; +use std::ops::Deref; +use structopt::{clap::App, StructOpt}; +use substrate_service::{Roles as ServiceRoles, ServiceFactory}; +use tokio::prelude::Future; +use tokio::runtime::{Builder as RuntimeBuilder, Runtime}; use transaction_factory::RuntimeAdapter; /// The chain specification option. #[derive(Clone, Debug, PartialEq)] pub enum ChainSpec { - /// Whatever the current runtime is, with just Alice as an auth. - Development, - /// Whatever the current runtime is, with simple Alice/Bob auths. - LocalTestnet, - /// The Flaming Fir testnet. - FlamingFir, - /// Whatever the current runtime is with the "global testnet" defaults. - StagingTestnet, - /// Crayfish, darwinia network poc-2 - CrayfishTestnet, - CrayfishTestnetFir, + /// Whatever the current runtime is, with just Alice as an auth. + Development, + /// Whatever the current runtime is, with simple Alice/Bob auths. + LocalTestnet, + /// The Flaming Fir testnet. + FlamingFir, + /// Whatever the current runtime is with the "global testnet" defaults. + StagingTestnet, + /// Crayfish, darwinia network poc-2 + CrayfishTestnet, + CrayfishTestnetFir, } /// Custom subcommands. #[derive(Clone, Debug, StructOpt)] pub enum CustomSubcommands { - /// The custom factory subcommmand for manufacturing transactions. - #[structopt( - name = "factory", - about = "Manufactures num transactions from Alice to random accounts. \ - Only supported for development or local testnet." - )] - Factory(FactoryCmd), + /// The custom factory subcommmand for manufacturing transactions. + #[structopt( + name = "factory", + about = "Manufactures num transactions from Alice to random accounts. \ + Only supported for development or local testnet." + )] + Factory(FactoryCmd), } impl GetLogFilter for CustomSubcommands { - fn get_log_filter(&self) -> Option { - None - } + fn get_log_filter(&self) -> Option { + None + } } /// The `factory` command used to generate transactions. /// Please note: this command currently only works on an empty database! #[derive(Debug, StructOpt, Clone)] pub struct FactoryCmd { - /// How often to repeat. This option only has an effect in mode `MasterToNToM`. - #[structopt(long="rounds", default_value = "1")] - pub rounds: u64, - - /// MasterToN: Manufacture `num` transactions from the master account - /// to `num` randomly created accounts, one each. - /// - /// MasterTo1: Manufacture `num` transactions from the master account - /// to exactly one other randomly created account. - /// - /// MasterToNToM: Manufacture `num` transactions from the master account - /// to `num` randomly created accounts. - /// From each of these randomly created accounts manufacture - /// a transaction to another randomly created account. - /// Repeat this `rounds` times. If `rounds` = 1 the behavior - /// is the same as `MasterToN`.{n} - /// A -> B, A -> C, A -> D, ... x `num`{n} - /// B -> E, C -> F, D -> G, ...{n} - /// ... x `rounds` - /// - /// These three modes control manufacturing. - #[structopt(long="mode", default_value = "MasterToN")] - pub mode: transaction_factory::Mode, - - /// Number of transactions to generate. In mode `MasterNToNToM` this is - /// the number of transactions per round. - #[structopt(long="num", default_value = "8")] - pub num: u64, - - #[allow(missing_docs)] - #[structopt(flatten)] - pub shared_params: SharedParams, + /// How often to repeat. This option only has an effect in mode `MasterToNToM`. + #[structopt(long = "rounds", default_value = "1")] + pub rounds: u64, + + /// MasterToN: Manufacture `num` transactions from the master account + /// to `num` randomly created accounts, one each. + /// + /// MasterTo1: Manufacture `num` transactions from the master account + /// to exactly one other randomly created account. + /// + /// MasterToNToM: Manufacture `num` transactions from the master account + /// to `num` randomly created accounts. + /// From each of these randomly created accounts manufacture + /// a transaction to another randomly created account. + /// Repeat this `rounds` times. If `rounds` = 1 the behavior + /// is the same as `MasterToN`.{n} + /// A -> B, A -> C, A -> D, ... x `num`{n} + /// B -> E, C -> F, D -> G, ...{n} + /// ... x `rounds` + /// + /// These three modes control manufacturing. + #[structopt(long = "mode", default_value = "MasterToN")] + pub mode: transaction_factory::Mode, + + /// Number of transactions to generate. In mode `MasterNToNToM` this is + /// the number of transactions per round. + #[structopt(long = "num", default_value = "8")] + pub num: u64, + + #[allow(missing_docs)] + #[structopt(flatten)] + pub shared_params: SharedParams, } impl AugmentClap for FactoryCmd { - fn augment_clap<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { - FactoryCmd::augment_clap(app) - } + fn augment_clap<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + FactoryCmd::augment_clap(app) + } } /// Get a chain config from a spec setting. impl ChainSpec { - pub(crate) fn load(self) -> Result { - Ok(match self { - ChainSpec::FlamingFir => chain_spec::flaming_fir_config()?, - ChainSpec::Development => chain_spec::development_config(), - ChainSpec::LocalTestnet => chain_spec::local_testnet_config(), - ChainSpec::StagingTestnet => chain_spec::staging_testnet_config(), - ChainSpec::CrayfishTestnet => chain_spec::crayfish_testnet_config(), - ChainSpec::CrayfishTestnetFir => chain_spec::crayfish_fir_config()?, - }) - } - - pub(crate) fn from(s: &str) -> Option { - match s { - "dev" => Some(ChainSpec::Development), - "" => Some(ChainSpec::CrayfishTestnetFir), - "local" => Some(ChainSpec::LocalTestnet), - "crayfish" => Some(ChainSpec::CrayfishTestnet), - "flaming-fir" => Some(ChainSpec::FlamingFir), - "staging" => Some(ChainSpec::StagingTestnet), - _ => None, - } - } + pub(crate) fn load(self) -> Result { + Ok(match self { + ChainSpec::FlamingFir => chain_spec::flaming_fir_config()?, + ChainSpec::Development => chain_spec::development_config(), + ChainSpec::LocalTestnet => chain_spec::local_testnet_config(), + ChainSpec::StagingTestnet => chain_spec::staging_testnet_config(), + ChainSpec::CrayfishTestnet => chain_spec::crayfish_testnet_config(), + ChainSpec::CrayfishTestnetFir => chain_spec::crayfish_fir_config()?, + }) + } + + pub(crate) fn from(s: &str) -> Option { + match s { + "dev" => Some(ChainSpec::Development), + "" => Some(ChainSpec::CrayfishTestnetFir), + "local" => Some(ChainSpec::LocalTestnet), + "crayfish" => Some(ChainSpec::CrayfishTestnet), + "flaming-fir" => Some(ChainSpec::FlamingFir), + "staging" => Some(ChainSpec::StagingTestnet), + _ => None, + } + } } fn load_spec(id: &str) -> Result, String> { - Ok(match ChainSpec::from(id) { - Some(spec) => Some(spec.load()?), - None => None, - }) + Ok(match ChainSpec::from(id) { + Some(spec) => Some(spec.load()?), + None => None, + }) } /// Parse command line arguments into service configuration. -pub fn run(args: I, exit: E, version: cli::VersionInfo) -> error::Result<()> where - I: IntoIterator, - T: Into + Clone, - E: IntoExit, +pub fn run(args: I, exit: E, version: cli::VersionInfo) -> error::Result<()> +where + I: IntoIterator, + T: Into + Clone, + E: IntoExit, { - let ret = cli::parse_and_execute::( - load_spec, &version, "substrate-node", args, exit, - |exit, _cli_args, _custom_args, config| { - info!("{}", version.name); - info!(" version {}", config.full_version()); - info!(" by Darwinia Network, 2017-2019"); - info!("Chain specification: {}", config.chain_spec.name()); - info!("Node name: {}", config.name); - info!("Roles: {:?}", config.roles); - let runtime = RuntimeBuilder::new().name_prefix("main-tokio-").build() - .map_err(|e| format!("{:?}", e))?; - match config.roles { - ServiceRoles::LIGHT => run_until_exit( - runtime, - service::Factory::new_light(config).map_err(|e| format!("{:?}", e))?, - exit - ), - _ => run_until_exit( - runtime, - service::Factory::new_full(config).map_err(|e| format!("{:?}", e))?, - exit - ), - }.map_err(|e| format!("{:?}", e)) - } - ); - panic_set(version.support_url); - match &ret { - Ok(Some(CustomSubcommands::Factory(cli_args))) => { - let config = cli::create_config_with_db_path::( - load_spec, - &cli_args.shared_params, - &version, - )?; - - match ChainSpec::from(config.chain_spec.id()) { - Some(ref c) if c == &ChainSpec::Development || c == &ChainSpec::LocalTestnet => {}, - _ => panic!("Factory is only supported for development and local testnet."), - } - - let factory_state = FactoryState::new( - cli_args.mode.clone(), - cli_args.num, - cli_args.rounds, - ); - transaction_factory::factory::>( - factory_state, - config, - ).map_err(|e| format!("Error in transaction factory: {}", e))?; - - Ok(()) - }, - _ => ret.map_err(Into::into).map(|_| ()) - } + let ret = cli::parse_and_execute::( + load_spec, + &version, + "substrate-node", + args, + exit, + |exit, _cli_args, _custom_args, config| { + info!("{}", version.name); + info!(" version {}", config.full_version()); + info!(" by Darwinia Network, 2017-2019"); + info!("Chain specification: {}", config.chain_spec.name()); + info!("Node name: {}", config.name); + info!("Roles: {:?}", config.roles); + let runtime = RuntimeBuilder::new() + .name_prefix("main-tokio-") + .build() + .map_err(|e| format!("{:?}", e))?; + match config.roles { + ServiceRoles::LIGHT => run_until_exit( + runtime, + service::Factory::new_light(config).map_err(|e| format!("{:?}", e))?, + exit, + ), + _ => run_until_exit( + runtime, + service::Factory::new_full(config).map_err(|e| format!("{:?}", e))?, + exit, + ), + } + .map_err(|e| format!("{:?}", e)) + }, + ); + panic_set(version.support_url); + match &ret { + Ok(Some(CustomSubcommands::Factory(cli_args))) => { + let config = + cli::create_config_with_db_path::(load_spec, &cli_args.shared_params, &version)?; + + match ChainSpec::from(config.chain_spec.id()) { + Some(ref c) if c == &ChainSpec::Development || c == &ChainSpec::LocalTestnet => {} + _ => panic!("Factory is only supported for development and local testnet."), + } + + let factory_state = FactoryState::new(cli_args.mode.clone(), cli_args.num, cli_args.rounds); + transaction_factory::factory::>(factory_state, config) + .map_err(|e| format!("Error in transaction factory: {}", e))?; + + Ok(()) + } + _ => ret.map_err(Into::into).map(|_| ()), + } } -fn run_until_exit( - mut runtime: Runtime, - service: T, - e: E, -) -> error::Result<()> - where - T: Deref> + Future + Send + 'static, - C: substrate_service::Components, - E: IntoExit, +fn run_until_exit(mut runtime: Runtime, service: T, e: E) -> error::Result<()> +where + T: Deref> + Future + Send + 'static, + C: substrate_service::Components, + E: IntoExit, { - let (exit_send, exit) = exit_future::signal(); + let (exit_send, exit) = exit_future::signal(); - let informant = cli::informant::build(&service); - runtime.executor().spawn(exit.until(informant).map(|_| ())); + let informant = cli::informant::build(&service); + runtime.executor().spawn(exit.until(informant).map(|_| ())); - // we eagerly drop the service so that the internal exit future is fired, - // but we need to keep holding a reference to the global telemetry guard - let _telemetry = service.telemetry(); + // we eagerly drop the service so that the internal exit future is fired, + // but we need to keep holding a reference to the global telemetry guard + let _telemetry = service.telemetry(); - let _ = runtime.block_on(service.select(e.into_exit())); - exit_send.fire(); + let _ = runtime.block_on(service.select(e.into_exit())); + exit_send.fire(); - // TODO [andre]: timeout this future #1318 - let _ = runtime.shutdown_on_idle().wait(); + // TODO [andre]: timeout this future #1318 + let _ = runtime.shutdown_on_idle().wait(); - Ok(()) + Ok(()) } diff --git a/node/cli/src/panic_handle.rs b/node/cli/src/panic_handle.rs index 0e222b9d1..4de3f1163 100644 --- a/node/cli/src/panic_handle.rs +++ b/node/cli/src/panic_handle.rs @@ -23,15 +23,15 @@ //! By default, the panic handler aborts the process by calling [`std::process::exit`]. This can //! temporarily be disabled by using an [`AbortGuard`]. use backtrace::Backtrace; +use std::cell::Cell; +use std::env; use std::io::{self, Write}; use std::marker::PhantomData; use std::panic::{self, PanicInfo}; -use std::cell::Cell; use std::thread; -use std::env; thread_local! { - static ABORT: Cell = Cell::new(true); + static ABORT: Cell = Cell::new(true); } /// Set the panic hook. @@ -45,11 +45,14 @@ pub fn set(bug_url: &'static str) { } macro_rules! ABOUT_PANIC { - () => (" + () => { + " This is a bug. Please report it at: {} -")} +" + }; +} /// Set aborting flag. Returns previous value of the flag. fn set_abort(enabled: bool) -> bool { @@ -111,7 +114,7 @@ fn panic_hook(info: &PanicInfo, report_url: &'static str) { None => match info.payload().downcast_ref::() { Some(s) => &s[..], None => "Box", - } + }, }; let thread = thread::current(); @@ -125,11 +128,7 @@ fn panic_hook(info: &PanicInfo, report_url: &'static str) { let _ = writeln!(stderr, ""); let _ = writeln!(stderr, "{:?}", backtrace); let _ = writeln!(stderr, ""); - let _ = writeln!( - stderr, - "Thread '{}' panicked at '{}', {}:{}", - name, msg, file, line - ); + let _ = writeln!(stderr, "Thread '{}' panicked at '{}', {}:{}", name, msg, file, line); let _ = writeln!(stderr, ABOUT_PANIC!(), report_url); push_alert_to_ding(format!("{:?}", backtrace)); ABORT.with(|flag| { @@ -147,7 +146,7 @@ pub struct PushMsg { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct PushText { - pub content: String + pub content: String, } pub fn push_alert_to_ding(trace_err: String) { @@ -155,19 +154,22 @@ pub fn push_alert_to_ding(trace_err: String) { let ding_talk_endpoint = "https://oapi.dingtalk.com/robot/send?access_token="; let ding_talk_token = env::var("DING_TALK_TOKEN").unwrap_or_default(); let r = client.post(&format!("{}{}", ding_talk_endpoint, ding_talk_token)); - let msg_body = PushMsg { msgtype: "text".to_string(), text: PushText { content: trace_err } }; + let msg_body = PushMsg { + msgtype: "text".to_string(), + text: PushText { content: trace_err }, + }; let res = r.json(&msg_body).send(); } #[cfg(test)] mod tests { - use super::*; + use super::*; - #[test] + #[test] #[ignore] - fn does_not_abort() { - set("test"); - let _guard = AbortGuard::force_unwind(); - ::std::panic::catch_unwind(|| panic!()).ok(); - } -} \ No newline at end of file + fn does_not_abort() { + set("test"); + let _guard = AbortGuard::force_unwind(); + ::std::panic::catch_unwind(|| panic!()).ok(); + } +} diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 73f8b8be1..8784e7bb5 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -23,378 +23,366 @@ use std::time::Duration; use client::{self, LongestChain}; use consensus::{import_queue, start_aura, AuraImportQueue, SlotDuration}; +use futures::prelude::*; use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider}; +use inherents::InherentDataProviders; +use log::info; +use network::construct_simple_protocol; use node_executor; -use primitives::{Pair as PairT, ed25519}; -use futures::prelude::*; use node_primitives::Block; use node_runtime::{GenesisConfig, RuntimeApi}; -use substrate_service::{ - FactoryFullConfiguration, LightComponents, FullComponents, FullBackend, - FullClient, LightClient, LightBackend, FullExecutor, LightExecutor, - error::{Error as ServiceError}, -}; -use transaction_pool::{self, txpool::{Pool as TransactionPool}}; -use inherents::InherentDataProviders; -use network::construct_simple_protocol; +use primitives::{ed25519, Pair as PairT}; use substrate_service::construct_service_factory; -use log::info; use substrate_service::TelemetryOnConnect; +use substrate_service::{ + error::Error as ServiceError, FactoryFullConfiguration, FullBackend, FullClient, FullComponents, FullExecutor, + LightBackend, LightClient, LightComponents, LightExecutor, +}; +use transaction_pool::{self, txpool::Pool as TransactionPool}; construct_simple_protocol! { - /// Demo protocol attachment for substrate. - pub struct NodeProtocol where Block = Block { } + /// Demo protocol attachment for substrate. + pub struct NodeProtocol where Block = Block { } } /// Node specific configuration pub struct NodeConfig { - /// grandpa connection to import block - // FIXME #1134 rather than putting this on the config, let's have an actual intermediate setup state - pub grandpa_import_setup: Option<(Arc>, grandpa::LinkHalfForService)>, - inherent_data_providers: InherentDataProviders, + /// grandpa connection to import block + // FIXME #1134 rather than putting this on the config, let's have an actual intermediate setup state + pub grandpa_import_setup: Option<(Arc>, grandpa::LinkHalfForService)>, + inherent_data_providers: InherentDataProviders, } -impl Default for NodeConfig where F: substrate_service::ServiceFactory { - fn default() -> NodeConfig { - NodeConfig { - grandpa_import_setup: None, - inherent_data_providers: InherentDataProviders::new(), - } - } +impl Default for NodeConfig +where + F: substrate_service::ServiceFactory, +{ + fn default() -> NodeConfig { + NodeConfig { + grandpa_import_setup: None, + inherent_data_providers: InherentDataProviders::new(), + } + } } construct_service_factory! { - struct Factory { - Block = Block, - RuntimeApi = RuntimeApi, - NetworkProtocol = NodeProtocol { |config| Ok(NodeProtocol::new()) }, - RuntimeDispatch = node_executor::Executor, - FullTransactionPoolApi = transaction_pool::ChainApi, FullExecutor, Block, RuntimeApi>, Block> - { |config, client| Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(client))) }, - LightTransactionPoolApi = transaction_pool::ChainApi, LightExecutor, Block, RuntimeApi>, Block> - { |config, client| Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(client))) }, - Genesis = GenesisConfig, - Configuration = NodeConfig, - FullService = FullComponents - { |config: FactoryFullConfiguration| - FullComponents::::new(config) }, - AuthoritySetup = { - |mut service: Self::FullService, local_key: Option>| { - let (block_import, link_half) = service.config.custom.grandpa_import_setup.take() - .expect("Link Half and Block Import are present for Full Services or setup failed before. qed"); - - if let Some(ref key) = local_key { - info!("Using authority key {}", key.public()); - let proposer = Arc::new(substrate_basic_authorship::ProposerFactory { - client: service.client(), - transaction_pool: service.transaction_pool(), - }); - - let client = service.client(); - let select_chain = service.select_chain() - .ok_or(ServiceError::SelectChainRequired)?; - let aura = start_aura( - SlotDuration::get_or_compute(&*client)?, - key.clone(), - client, - select_chain, - block_import.clone(), - proposer, - service.network(), - service.config.custom.inherent_data_providers.clone(), - service.config.force_authoring, - )?; - service.spawn_task(Box::new(aura.select(service.on_exit()).then(|_| Ok(())))); - - info!("Running Grandpa session as Authority {}", key.public()); - } - - let local_key = if service.config.disable_grandpa { - None - } else { - local_key - }; - - let config = grandpa::Config { - local_key, - // FIXME #1578 make this available through chainspec - gossip_duration: Duration::from_millis(333), - justification_period: 4096, - name: Some(service.config.name.clone()) - }; - - match config.local_key { - None => { - service.spawn_task(Box::new(grandpa::run_grandpa_observer( - config, - link_half, - service.network(), - service.on_exit(), - )?)); - }, - Some(_) => { - let telemetry_on_connect = TelemetryOnConnect { - telemetry_connection_sinks: service.telemetry_on_connect_stream(), - }; - let grandpa_config = grandpa::GrandpaParams { - config: config, - link: link_half, - network: service.network(), - inherent_data_providers: service.config.custom.inherent_data_providers.clone(), - on_exit: service.on_exit(), - telemetry_on_connect: Some(telemetry_on_connect), - }; - service.spawn_task(Box::new(grandpa::run_grandpa_voter(grandpa_config)?)); - }, - } - - Ok(service) - } - }, - LightService = LightComponents - { |config| >::new(config) }, - FullImportQueue = AuraImportQueue - { |config: &mut FactoryFullConfiguration , client: Arc>, select_chain: Self::SelectChain| { - let slot_duration = SlotDuration::get_or_compute(&*client)?; - let (block_import, link_half) = - grandpa::block_import::<_, _, _, RuntimeApi, FullClient, _>( - client.clone(), client.clone(), select_chain - )?; - let block_import = Arc::new(block_import); - let justification_import = block_import.clone(); - - config.custom.grandpa_import_setup = Some((block_import.clone(), link_half)); - - import_queue::<_, _, ed25519::Pair>( - slot_duration, - block_import, - Some(justification_import), - None, - None, - client, - config.custom.inherent_data_providers.clone(), - ).map_err(Into::into) - }}, - LightImportQueue = AuraImportQueue - { |config: &FactoryFullConfiguration, client: Arc>| { - #[allow(deprecated)] - let fetch_checker = client.backend().blockchain().fetcher() - .upgrade() - .map(|fetcher| fetcher.checker().clone()) - .ok_or_else(|| "Trying to start light import queue without active fetch checker")?; - let block_import = grandpa::light_block_import::<_, _, _, RuntimeApi, LightClient>( - client.clone(), Arc::new(fetch_checker), client.clone() - )?; - let block_import = Arc::new(block_import); - let finality_proof_import = block_import.clone(); - let finality_proof_request_builder = finality_proof_import.create_finality_proof_request_builder(); - - import_queue::<_, _, ed25519::Pair>( - SlotDuration::get_or_compute(&*client)?, - block_import, - None, - Some(finality_proof_import), - Some(finality_proof_request_builder), - client, - config.custom.inherent_data_providers.clone(), - ).map_err(Into::into) - }}, - SelectChain = LongestChain, Self::Block> - { |config: &FactoryFullConfiguration, client: Arc>| { - #[allow(deprecated)] - Ok(LongestChain::new(client.backend().clone())) - } - }, - FinalityProofProvider = { |client: Arc>| { - Ok(Some(Arc::new(GrandpaFinalityProofProvider::new(client.clone(), client)) as _)) - }}, - } + struct Factory { + Block = Block, + RuntimeApi = RuntimeApi, + NetworkProtocol = NodeProtocol { |config| Ok(NodeProtocol::new()) }, + RuntimeDispatch = node_executor::Executor, + FullTransactionPoolApi = transaction_pool::ChainApi, FullExecutor, Block, RuntimeApi>, Block> + { |config, client| Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(client))) }, + LightTransactionPoolApi = transaction_pool::ChainApi, LightExecutor, Block, RuntimeApi>, Block> + { |config, client| Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(client))) }, + Genesis = GenesisConfig, + Configuration = NodeConfig, + FullService = FullComponents + { |config: FactoryFullConfiguration| + FullComponents::::new(config) }, + AuthoritySetup = { + |mut service: Self::FullService, local_key: Option>| { + let (block_import, link_half) = service.config.custom.grandpa_import_setup.take() + .expect("Link Half and Block Import are present for Full Services or setup failed before. qed"); + + if let Some(ref key) = local_key { + info!("Using authority key {}", key.public()); + let proposer = Arc::new(substrate_basic_authorship::ProposerFactory { + client: service.client(), + transaction_pool: service.transaction_pool(), + }); + + let client = service.client(); + let select_chain = service.select_chain() + .ok_or(ServiceError::SelectChainRequired)?; + let aura = start_aura( + SlotDuration::get_or_compute(&*client)?, + key.clone(), + client, + select_chain, + block_import.clone(), + proposer, + service.network(), + service.config.custom.inherent_data_providers.clone(), + service.config.force_authoring, + )?; + service.spawn_task(Box::new(aura.select(service.on_exit()).then(|_| Ok(())))); + + info!("Running Grandpa session as Authority {}", key.public()); + } + + let local_key = if service.config.disable_grandpa { + None + } else { + local_key + }; + + let config = grandpa::Config { + local_key, + // FIXME #1578 make this available through chainspec + gossip_duration: Duration::from_millis(333), + justification_period: 4096, + name: Some(service.config.name.clone()) + }; + + match config.local_key { + None => { + service.spawn_task(Box::new(grandpa::run_grandpa_observer( + config, + link_half, + service.network(), + service.on_exit(), + )?)); + }, + Some(_) => { + let telemetry_on_connect = TelemetryOnConnect { + telemetry_connection_sinks: service.telemetry_on_connect_stream(), + }; + let grandpa_config = grandpa::GrandpaParams { + config: config, + link: link_half, + network: service.network(), + inherent_data_providers: service.config.custom.inherent_data_providers.clone(), + on_exit: service.on_exit(), + telemetry_on_connect: Some(telemetry_on_connect), + }; + service.spawn_task(Box::new(grandpa::run_grandpa_voter(grandpa_config)?)); + }, + } + + Ok(service) + } + }, + LightService = LightComponents + { |config| >::new(config) }, + FullImportQueue = AuraImportQueue + { |config: &mut FactoryFullConfiguration , client: Arc>, select_chain: Self::SelectChain| { + let slot_duration = SlotDuration::get_or_compute(&*client)?; + let (block_import, link_half) = + grandpa::block_import::<_, _, _, RuntimeApi, FullClient, _>( + client.clone(), client.clone(), select_chain + )?; + let block_import = Arc::new(block_import); + let justification_import = block_import.clone(); + + config.custom.grandpa_import_setup = Some((block_import.clone(), link_half)); + + import_queue::<_, _, ed25519::Pair>( + slot_duration, + block_import, + Some(justification_import), + None, + None, + client, + config.custom.inherent_data_providers.clone(), + ).map_err(Into::into) + }}, + LightImportQueue = AuraImportQueue + { |config: &FactoryFullConfiguration, client: Arc>| { + #[allow(deprecated)] + let fetch_checker = client.backend().blockchain().fetcher() + .upgrade() + .map(|fetcher| fetcher.checker().clone()) + .ok_or_else(|| "Trying to start light import queue without active fetch checker")?; + let block_import = grandpa::light_block_import::<_, _, _, RuntimeApi, LightClient>( + client.clone(), Arc::new(fetch_checker), client.clone() + )?; + let block_import = Arc::new(block_import); + let finality_proof_import = block_import.clone(); + let finality_proof_request_builder = finality_proof_import.create_finality_proof_request_builder(); + + import_queue::<_, _, ed25519::Pair>( + SlotDuration::get_or_compute(&*client)?, + block_import, + None, + Some(finality_proof_import), + Some(finality_proof_request_builder), + client, + config.custom.inherent_data_providers.clone(), + ).map_err(Into::into) + }}, + SelectChain = LongestChain, Self::Block> + { |config: &FactoryFullConfiguration, client: Arc>| { + #[allow(deprecated)] + Ok(LongestChain::new(client.backend().clone())) + } + }, + FinalityProofProvider = { |client: Arc>| { + Ok(Some(Arc::new(GrandpaFinalityProofProvider::new(client.clone(), client)) as _)) + }}, + } } - #[cfg(test)] mod tests { - use std::sync::Arc; - use consensus::CompatibleDigestItem; - use consensus_common::{Environment, Proposer, ImportBlock, BlockOrigin, ForkChoiceStrategy}; - use node_primitives::DigestItem; - use node_runtime::{BalancesCall, Call, COIN, UncheckedExtrinsic}; - use parity_codec::{Compact, Encode, Decode}; - use primitives::{ - crypto::Pair as CryptoPair, ed25519::Pair, blake2_256, - sr25519::Public as AddressPublic, H256, - }; - use sr_primitives::{generic::{BlockId, Era, Digest}, traits::Block, OpaqueExtrinsic}; - use timestamp; - use finality_tracker; - use keyring::{ed25519::Keyring as AuthorityKeyring, sr25519::Keyring as AccountKeyring}; - use substrate_service::ServiceFactory; - use service_test::SyncService; - use crate::service::Factory; - - #[cfg(feature = "rhd")] - fn test_sync() { - use {service_test, Factory}; - use client::{ImportBlock, BlockOrigin}; - - let alice: Arc = Arc::new(Keyring::Alice.into()); - let bob: Arc = Arc::new(Keyring::Bob.into()); - let validators = vec![alice.public().0.into(), bob.public().0.into()]; - let keys: Vec<&ed25519::Pair> = vec![&*alice, &*bob]; - let dummy_runtime = ::tokio::runtime::Runtime::new().unwrap(); - let block_factory = |service: &::FullService| { - let block_id = BlockId::number(service.client().info().chain.best_number); - let parent_header = service.client().header(&block_id).unwrap().unwrap(); - let consensus_net = ConsensusNetwork::new(service.network(), service.client().clone()); - let proposer_factory = consensus::ProposerFactory { - client: service.client().clone(), - transaction_pool: service.transaction_pool().clone(), - network: consensus_net, - force_delay: 0, - handle: dummy_runtime.executor(), - }; - let (proposer, _, _) = proposer_factory.init(&parent_header, &validators, alice.clone()).unwrap(); - let block = proposer.propose().expect("Error making test block"); - ImportBlock { - origin: BlockOrigin::File, - justification: Vec::new(), - internal_justification: Vec::new(), - finalized: true, - body: Some(block.extrinsics), - header: block.header, - auxiliary: Vec::new(), - } - }; - let extrinsic_factory = |service: &SyncService<::FullService>| { - let payload = ( - 0, - Call::Balances(BalancesCall::transfer(RawAddress::Id(bob.public().0.into()), 69.into())), - Era::immortal(), - service.client().genesis_hash() - ); - let signature = alice.sign(&payload.encode()).into(); - let id = alice.public().0.into(); - let xt = UncheckedExtrinsic { - signature: Some((RawAddress::Id(id), signature, payload.0, Era::immortal())), - function: payload.1, - }.encode(); - let v: Vec = Decode::decode(&mut xt.as_slice()).unwrap(); - OpaqueExtrinsic(v) - }; - service_test::sync::( - chain_spec::integration_test_config(), - block_factory, - extrinsic_factory, - ); - } - - #[test] - #[ignore] - fn test_sync() { - let chain_spec = crate::chain_spec::tests::integration_test_config_with_single_authority(); - - let alice = Arc::new(AuthorityKeyring::Alice.pair()); - let mut slot_num = 1u64; - let block_factory = |service: &SyncService<::FullService>| { - let service = service.get(); - let mut inherent_data = service - .config - .custom - .inherent_data_providers - .create_inherent_data() - .expect("Creates inherent data."); - inherent_data.replace_data(finality_tracker::INHERENT_IDENTIFIER, &1u64); - inherent_data.replace_data(timestamp::INHERENT_IDENTIFIER, &(slot_num * 10)); - - let parent_id = BlockId::number(service.client().info().chain.best_number); - let parent_header = service.client().header(&parent_id).unwrap().unwrap(); - let proposer_factory = Arc::new(substrate_basic_authorship::ProposerFactory { - client: service.client(), - transaction_pool: service.transaction_pool(), - }); - - let mut digest = Digest::::default(); - digest.push(>::aura_pre_digest(slot_num * 10 / 2)); - let proposer = proposer_factory.init(&parent_header).unwrap(); - let new_block = proposer.propose( - inherent_data, - digest, - std::time::Duration::from_secs(1), - ).expect("Error making test block"); - - let (new_header, new_body) = new_block.deconstruct(); - let pre_hash = new_header.hash(); - // sign the pre-sealed hash of the block and then - // add it to a digest item. - let to_sign = pre_hash.encode(); - let signature = alice.sign(&to_sign[..]); - let item = >::aura_seal( - signature, - ); - slot_num += 1; - - ImportBlock { - origin: BlockOrigin::File, - header: new_header, - justification: None, - post_digests: vec![item], - body: Some(new_body), - finalized: true, - auxiliary: Vec::new(), - fork_choice: ForkChoiceStrategy::LongestChain, - } - }; - - let bob = Arc::new(AccountKeyring::Bob.pair()); - let charlie = Arc::new(AccountKeyring::Charlie.pair()); - - let mut index = 0; - let extrinsic_factory = |service: &SyncService<::FullService>| { - let amount = 5 * COIN; - let to = AddressPublic::from_raw(bob.public().0); - let from = AddressPublic::from_raw(charlie.public().0); - let genesis_hash = service.get().client().block_hash(0).unwrap().unwrap(); - let signer = charlie.clone(); - - let function = Call::Balances(BalancesCall::transfer(to.into(), amount)); - let era = Era::immortal(); - let raw_payload = (Compact(index), function, era, genesis_hash); - let signature = raw_payload.using_encoded(|payload| if payload.len() > 256 { - signer.sign(&blake2_256(payload)[..]) - } else { - signer.sign(payload) - }); - let xt = UncheckedExtrinsic::new_signed( - index, - raw_payload.1, - from.into(), - signature.into(), - era, - ).encode(); - let v: Vec = Decode::decode(&mut xt.as_slice()).unwrap(); - - index += 1; - OpaqueExtrinsic(v) - }; - - service_test::sync::( - chain_spec, - block_factory, - extrinsic_factory, - ); - } - - #[test] - #[ignore] - fn test_consensus() { - use super::Factory; - - service_test::consensus::( - crate::chain_spec::tests::integration_test_config_with_two_authorities(), - vec![ - "//Alice".into(), - "//Bob".into(), - ], - ) - } + use crate::service::Factory; + use consensus::CompatibleDigestItem; + use consensus_common::{BlockOrigin, Environment, ForkChoiceStrategy, ImportBlock, Proposer}; + use finality_tracker; + use keyring::{ed25519::Keyring as AuthorityKeyring, sr25519::Keyring as AccountKeyring}; + use node_primitives::DigestItem; + use node_runtime::{BalancesCall, Call, UncheckedExtrinsic, COIN}; + use parity_codec::{Compact, Decode, Encode}; + use primitives::{blake2_256, crypto::Pair as CryptoPair, ed25519::Pair, sr25519::Public as AddressPublic, H256}; + use service_test::SyncService; + use sr_primitives::{ + generic::{BlockId, Digest, Era}, + traits::Block, + OpaqueExtrinsic, + }; + use std::sync::Arc; + use substrate_service::ServiceFactory; + use timestamp; + + #[cfg(feature = "rhd")] + fn test_sync() { + use client::{BlockOrigin, ImportBlock}; + use {service_test, Factory}; + + let alice: Arc = Arc::new(Keyring::Alice.into()); + let bob: Arc = Arc::new(Keyring::Bob.into()); + let validators = vec![alice.public().0.into(), bob.public().0.into()]; + let keys: Vec<&ed25519::Pair> = vec![&*alice, &*bob]; + let dummy_runtime = ::tokio::runtime::Runtime::new().unwrap(); + let block_factory = |service: &::FullService| { + let block_id = BlockId::number(service.client().info().chain.best_number); + let parent_header = service.client().header(&block_id).unwrap().unwrap(); + let consensus_net = ConsensusNetwork::new(service.network(), service.client().clone()); + let proposer_factory = consensus::ProposerFactory { + client: service.client().clone(), + transaction_pool: service.transaction_pool().clone(), + network: consensus_net, + force_delay: 0, + handle: dummy_runtime.executor(), + }; + let (proposer, _, _) = proposer_factory + .init(&parent_header, &validators, alice.clone()) + .unwrap(); + let block = proposer.propose().expect("Error making test block"); + ImportBlock { + origin: BlockOrigin::File, + justification: Vec::new(), + internal_justification: Vec::new(), + finalized: true, + body: Some(block.extrinsics), + header: block.header, + auxiliary: Vec::new(), + } + }; + let extrinsic_factory = |service: &SyncService<::FullService>| { + let payload = ( + 0, + Call::Balances(BalancesCall::transfer(RawAddress::Id(bob.public().0.into()), 69.into())), + Era::immortal(), + service.client().genesis_hash(), + ); + let signature = alice.sign(&payload.encode()).into(); + let id = alice.public().0.into(); + let xt = UncheckedExtrinsic { + signature: Some((RawAddress::Id(id), signature, payload.0, Era::immortal())), + function: payload.1, + } + .encode(); + let v: Vec = Decode::decode(&mut xt.as_slice()).unwrap(); + OpaqueExtrinsic(v) + }; + service_test::sync::(chain_spec::integration_test_config(), block_factory, extrinsic_factory); + } + + #[test] + #[ignore] + fn test_sync() { + let chain_spec = crate::chain_spec::tests::integration_test_config_with_single_authority(); + + let alice = Arc::new(AuthorityKeyring::Alice.pair()); + let mut slot_num = 1u64; + let block_factory = |service: &SyncService<::FullService>| { + let service = service.get(); + let mut inherent_data = service + .config + .custom + .inherent_data_providers + .create_inherent_data() + .expect("Creates inherent data."); + inherent_data.replace_data(finality_tracker::INHERENT_IDENTIFIER, &1u64); + inherent_data.replace_data(timestamp::INHERENT_IDENTIFIER, &(slot_num * 10)); + + let parent_id = BlockId::number(service.client().info().chain.best_number); + let parent_header = service.client().header(&parent_id).unwrap().unwrap(); + let proposer_factory = Arc::new(substrate_basic_authorship::ProposerFactory { + client: service.client(), + transaction_pool: service.transaction_pool(), + }); + + let mut digest = Digest::::default(); + digest.push(>::aura_pre_digest( + slot_num * 10 / 2, + )); + let proposer = proposer_factory.init(&parent_header).unwrap(); + let new_block = proposer + .propose(inherent_data, digest, std::time::Duration::from_secs(1)) + .expect("Error making test block"); + + let (new_header, new_body) = new_block.deconstruct(); + let pre_hash = new_header.hash(); + // sign the pre-sealed hash of the block and then + // add it to a digest item. + let to_sign = pre_hash.encode(); + let signature = alice.sign(&to_sign[..]); + let item = >::aura_seal(signature); + slot_num += 1; + + ImportBlock { + origin: BlockOrigin::File, + header: new_header, + justification: None, + post_digests: vec![item], + body: Some(new_body), + finalized: true, + auxiliary: Vec::new(), + fork_choice: ForkChoiceStrategy::LongestChain, + } + }; + + let bob = Arc::new(AccountKeyring::Bob.pair()); + let charlie = Arc::new(AccountKeyring::Charlie.pair()); + + let mut index = 0; + let extrinsic_factory = |service: &SyncService<::FullService>| { + let amount = 5 * COIN; + let to = AddressPublic::from_raw(bob.public().0); + let from = AddressPublic::from_raw(charlie.public().0); + let genesis_hash = service.get().client().block_hash(0).unwrap().unwrap(); + let signer = charlie.clone(); + + let function = Call::Balances(BalancesCall::transfer(to.into(), amount)); + let era = Era::immortal(); + let raw_payload = (Compact(index), function, era, genesis_hash); + let signature = raw_payload.using_encoded(|payload| { + if payload.len() > 256 { + signer.sign(&blake2_256(payload)[..]) + } else { + signer.sign(payload) + } + }); + let xt = UncheckedExtrinsic::new_signed(index, raw_payload.1, from.into(), signature.into(), era).encode(); + let v: Vec = Decode::decode(&mut xt.as_slice()).unwrap(); + + index += 1; + OpaqueExtrinsic(v) + }; + + service_test::sync::(chain_spec, block_factory, extrinsic_factory); + } + + #[test] + #[ignore] + fn test_consensus() { + use super::Factory; + + service_test::consensus::( + crate::chain_spec::tests::integration_test_config_with_two_authorities(), + vec!["//Alice".into(), "//Bob".into()], + ) + } } diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 10eb85296..1b85a1a18 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -19,11 +19,12 @@ #![cfg_attr(feature = "benchmarks", feature(test))] -#[cfg(feature = "benchmarks")] extern crate test; +#[cfg(feature = "benchmarks")] +extern crate test; -pub use substrate_executor::NativeExecutor; +pub use node_runtime::{BondingDuration, SessionsPerEra}; use substrate_executor::native_executor_instance; -pub use node_runtime::{SessionsPerEra, BondingDuration}; +pub use substrate_executor::NativeExecutor; // Declare an instance of the native executor named `Executor`. Include the wasm binary as the // equivalent wasm code. @@ -38,617 +39,654 @@ native_executor_instance!( #[cfg(test)] mod tests { - use runtime_io; - use super::Executor; - use substrate_executor::{WasmExecutor, NativeExecutionDispatch}; - use parity_codec::{Encode, Decode, Joiner}; - use keyring::{AuthorityKeyring, AccountKeyring}; - use runtime_support::{Hashable, StorageValue, StorageMap, traits::Currency}; - use state_machine::{CodeExecutor, Externalities, TestExternalities as CoreTestExternalities}; - use primitives::{twox_128, blake2_256, Blake2Hasher, ChangesTrieConfiguration, NeverNativeValue, - NativeOrEncoded}; - use node_primitives::{Hash, BlockNumber, AccountId}; - use runtime_primitives::traits::{Header as HeaderT, Hash as HashT}; - use runtime_primitives::{generic::Era, ApplyOutcome, ApplyError, ApplyResult, Perbill}; - use {balances, indices, system, staking, timestamp, treasury, contracts}; - use contracts::ContractAddressFor; - use system::{EventRecord, Phase}; - use node_runtime::{Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Call, Runtime, Balances, - BuildStorage, GenesisConfig, BalancesConfig, SessionConfig, StakingConfig, System, - SystemConfig, GrandpaConfig, IndicesConfig, KtonConfig, Event, SessionKeys, COIN}; - use wabt; - use primitives::map; - - /// The wasm runtime code. - /// - /// `compact` since it is after post-processing with wasm-gc which performs tree-shaking thus - /// making the binary slimmer. There is a convention to use compact version of the runtime - /// as canonical. This is why `native_executor_instance` also uses the compact version of the - /// runtime. - const COMPACT_CODE: &[u8] = - include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm"); - - /// The wasm runtime binary which hasn't undergone the compacting process. - /// - /// The idea here is to pass it as the current runtime code to the executor so the executor will - /// have to execute provided wasm code instead of the native equivalent. This trick is used to - /// test code paths that differ between native and wasm versions. - const BLOATY_CODE: &[u8] = - include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.wasm"); - - const GENESIS_HASH: [u8; 32] = [69u8; 32]; - - type TestExternalities = CoreTestExternalities; - - fn alice() -> AccountId { - AccountKeyring::Alice.into() - } - - fn bob() -> AccountId { - AccountKeyring::Bob.into() - } - - fn charlie() -> AccountId { - AccountKeyring::Charlie.into() - } - - fn dave() -> AccountId { - AccountKeyring::Dave.into() - } - - fn eve() -> AccountId { - AccountKeyring::Eve.into() - } - - fn ferdie() -> AccountId { - AccountKeyring::Ferdie.into() - } - - fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic { - match xt.signed { - Some((signed, index)) => { - let era = Era::mortal(256, 0); - let payload = (index.into(), xt.function, era, GENESIS_HASH); - let key = AccountKeyring::from_public(&signed).unwrap(); - let signature = payload.using_encoded(|b| { - if b.len() > 256 { - key.sign(&runtime_io::blake2_256(b)) - } else { - key.sign(b) - } - }).into(); - UncheckedExtrinsic { - signature: Some((indices::address::Address::Id(signed), signature, payload.0, era)), - function: payload.1, - } - } - None => UncheckedExtrinsic { - signature: None, - function: xt.function, - }, - } - } - - fn xt() -> UncheckedExtrinsic { - sign(CheckedExtrinsic { - signed: Some((alice(), 0)), - function: Call::Balances(balances::Call::transfer::(bob().into(), 69 * COIN)), - }) - } - - fn from_block_number(n: u64) -> Header { - Header::new(n, Default::default(), Default::default(), [69; 32].into(), Default::default()) - } - - fn executor() -> ::substrate_executor::NativeExecutor { - ::substrate_executor::NativeExecutor::new(None) - } - - #[test] - fn panic_execution_with_foreign_code_gives_error() { - let mut t = TestExternalities::::new_with_code(BLOATY_CODE, map![ - blake2_256(&>::key_for(alice())).to_vec() => { - vec![0u8; 16] - }, - twox_128(>::key()).to_vec() => { - vec![0u8; 16] - }, - twox_128(>::key()).to_vec() => { - vec![0u8; 16] - }, - blake2_256(&>::key_for(0)).to_vec() => { - vec![0u8; 32] - } - ]); - - let r = executor().call::<_, NeverNativeValue, fn() -> _>( - &mut t, - "Core_initialize_block", - &vec![].and(&from_block_number(1u64)), - true, - None, - ).0; - assert!(r.is_ok()); - let v = executor().call::<_, NeverNativeValue, fn() -> _>( - &mut t, - "BlockBuilder_apply_extrinsic", - &vec![].and(&xt()), - true, - None, - ).0.unwrap(); - let r = ApplyResult::decode(&mut &v.as_encoded()[..]).unwrap(); - assert_eq!(r, Err(ApplyError::CantPay)); - } - - #[test] - fn bad_extrinsic_with_native_equivalent_code_gives_error() { - let mut t = TestExternalities::::new_with_code(COMPACT_CODE, map![ - blake2_256(&>::key_for(alice())).to_vec() => { - vec![0u8; 16] - }, - twox_128(>::key()).to_vec() => { - vec![0u8; 16] - }, - twox_128(>::key()).to_vec() => { - vec![0u8; 16] - }, - blake2_256(&>::key_for(0)).to_vec() => { - vec![0u8; 32] - } - ]); - - let r = executor().call::<_, NeverNativeValue, fn() -> _>( - &mut t, - "Core_initialize_block", - &vec![].and(&from_block_number(1u64)), - true, - None, - ).0; - assert!(r.is_ok()); - let v = executor().call::<_, NeverNativeValue, fn() -> _>( - &mut t, - "BlockBuilder_apply_extrinsic", - &vec![].and(&xt()), - true, - None, - ).0.unwrap(); - let r = ApplyResult::decode(&mut &v.as_encoded()[..]).unwrap(); - assert_eq!(r, Err(ApplyError::CantPay)); - } - - #[test] - fn successful_execution_with_native_equivalent_code_gives_ok() { - let mut t = TestExternalities::::new_with_code(COMPACT_CODE, map![ - blake2_256(&>::key_for(alice())).to_vec() => { - (111 * COIN).encode() - }, - twox_128(>::key()).to_vec() => { - (111 * COIN).encode() - }, - twox_128(>::key()).to_vec() => vec![0u8; 16], - blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32] - ]); - - let r = executor().call::<_, NeverNativeValue, fn() -> _>( - &mut t, - "Core_initialize_block", - &vec![].and(&from_block_number(1u64)), - true, - None, - ).0; - assert!(r.is_ok()); - let r = executor().call::<_, NeverNativeValue, fn() -> _>( - &mut t, - "BlockBuilder_apply_extrinsic", - &vec![].and(&xt()), - true, - None, - ).0; - assert!(r.is_ok()); - - runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 41997856000); - assert_eq!(Balances::total_balance(&bob()), 69 * COIN); - }); - } - - #[test] - fn successful_execution_with_foreign_code_gives_ok() { - let mut t = TestExternalities::::new_with_code(BLOATY_CODE, map![ - blake2_256(&>::key_for(alice())).to_vec() => { - (111 * COIN).encode() - }, - twox_128(>::key()).to_vec() => { - (111 * COIN).encode() - }, - twox_128(>::key()).to_vec() => vec![0u8; 16], - blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32] - ]); - - let r = executor().call::<_, NeverNativeValue, fn() -> _>( - &mut t, - "Core_initialize_block", - &vec![].and(&from_block_number(1u64)), - true, - None, - ).0; - assert!(r.is_ok()); - let r = executor().call::<_, NeverNativeValue, fn() -> _>( - &mut t, - "BlockBuilder_apply_extrinsic", - &vec![].and(&xt()), - true, - None, - ).0; - assert!(r.is_ok()); - - runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 41997856000); - assert_eq!(Balances::total_balance(&bob()), 69 * COIN); - }); - } - - fn to_session_keys(ring: &AuthorityKeyring) -> SessionKeys { - SessionKeys(ring.to_owned().into(), ring.to_owned().into()) - } - - fn new_test_ext(code: &[u8], support_changes_trie: bool) -> TestExternalities { - let three = AccountId::from_raw([3u8; 32]); - let mut ext = TestExternalities::new_with_code(code, GenesisConfig { - aura: Some(Default::default()), - system: Some(SystemConfig { - changes_trie_config: if support_changes_trie { Some(ChangesTrieConfiguration { - digest_interval: 2, - digest_levels: 2, - }) } else { None }, - ..Default::default() - }), - indices: Some(IndicesConfig { - ids: vec![alice(), bob(), charlie(), dave(), eve(), ferdie()], - }), - balances: Some(BalancesConfig { - balances: vec![ - (alice(), 111 * COIN), - (bob(), 100 * COIN), - (charlie(), 100_000_000 * COIN), - (dave(), 111 * COIN), - (eve(), 101 * COIN), - (ferdie(), 100 * COIN), - ], - vesting: vec![], - }), - kton: Some(KtonConfig { - balances: vec![ - (alice(), 111), - (bob(), 100), - (charlie(), 100_000_000), - (dave(), 111), - (eve(), 101), - (ferdie(), 100), - ], - vesting: vec![], - }), - session: Some(SessionConfig { - validators: vec![AccountKeyring::One.into(), AccountKeyring::Two.into(), three], - keys: vec![ - (alice(), to_session_keys(&AuthorityKeyring::Alice)), - (bob(), to_session_keys(&AuthorityKeyring::Bob)), - (charlie(), to_session_keys(&AuthorityKeyring::Charlie)), - ] - }), - staking: Some(StakingConfig { - current_era: 0, - current_era_total_reward: 1, - stakers: vec![ - (dave(), alice(), 111, staking::StakerStatus::Validator), - (eve(), bob(), 100, staking::StakerStatus::Validator), - (ferdie(), charlie(), 100, staking::StakerStatus::Validator) - ], - validator_count: 3, - minimum_validator_count: 0, - offline_slash: Perbill::zero(), - session_reward: Perbill::zero(), - offline_slash_grace: 0, - invulnerables: vec![alice(), bob(), charlie()], - }), - timestamp: Some(Default::default()), - contracts: Some(Default::default()), - sudo: Some(Default::default()), - grandpa: Some(GrandpaConfig { - authorities: vec![], - }), - }.build_storage().unwrap().0); - ext.changes_trie_storage().insert(0, GENESIS_HASH.into(), Default::default()); - ext - } - - fn construct_block( - env: &mut TestExternalities, - number: BlockNumber, - parent_hash: Hash, - extrinsics: Vec, - ) -> (Vec, Hash) { - use trie::ordered_trie_root; - - // sign extrinsics. - let extrinsics = extrinsics.into_iter().map(sign).collect::>(); - - // calculate the header fields that we can. - let extrinsics_root = ordered_trie_root::( - extrinsics.iter().map(Encode::encode) - ).to_fixed_bytes() - .into(); - - let header = Header { - parent_hash, - number, - extrinsics_root, - state_root: Default::default(), - digest: Default::default(), - }; - - // execute the block to get the real header. - Executor::new(None).call::<_, NeverNativeValue, fn() -> _>( - env, - "Core_initialize_block", - &header.encode(), - true, - None, - ).0.unwrap(); - - for i in extrinsics.iter() { - Executor::new(None).call::<_, NeverNativeValue, fn() -> _>( - env, - "BlockBuilder_apply_extrinsic", - &i.encode(), - true, - None, - ).0.unwrap(); - } - - let header = match Executor::new(None).call::<_, NeverNativeValue, fn() -> _>( - env, - "BlockBuilder_finalize_block", - &[0u8;0], - true, - None, - ).0.unwrap() { - NativeOrEncoded::Native(_) => unreachable!(), - NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(), - }; - - let hash = header.blake2_256(); - (Block { header, extrinsics }.encode(), hash.into()) - } - - fn changes_trie_block() -> (Vec, Hash) { - construct_block( - &mut new_test_ext(COMPACT_CODE, true), - 1, - GENESIS_HASH.into(), - vec![ - CheckedExtrinsic { - signed: None, - function: Call::Timestamp(timestamp::Call::set(42)), - }, - CheckedExtrinsic { - signed: Some((alice(), 0)), - function: Call::Balances(balances::Call::transfer(bob().into(), 69 * COIN)), - }, - ] - ) - } - - // block 1 and 2 must be created together to ensure transactions are only signed once (since they - // are not guaranteed to be deterministic) and to ensure that the correct state is propagated - // from block1's execution to block2 to derive the correct storage_root. - fn blocks() -> ((Vec, Hash), (Vec, Hash)) { - let mut t = new_test_ext(COMPACT_CODE, false); - let block1 = construct_block( - &mut t, - 1, - GENESIS_HASH.into(), - vec![ - CheckedExtrinsic { - signed: None, - function: Call::Timestamp(timestamp::Call::set(42)), - }, - CheckedExtrinsic { - signed: Some((alice(), 0)), - function: Call::Balances(balances::Call::transfer(bob().into(), 69)), - }, - ] - ); - let block2 = construct_block( - &mut t, - 2, - block1.1.clone(), - vec![ - CheckedExtrinsic { - signed: None, - function: Call::Timestamp(timestamp::Call::set(52)), - }, - CheckedExtrinsic { - signed: Some((bob(), 0)), - function: Call::Balances(balances::Call::transfer(alice().into(), 5)), - }, - CheckedExtrinsic { - signed: Some((alice(), 1)), - function: Call::Balances(balances::Call::transfer(bob().into(), 15)), - } - ] - ); - - // session change => consensus authorities change => authorities change digest item appears - let digest = Header::decode(&mut &block2.0[..]).unwrap().digest; - assert_eq!(digest.logs().len(), 0); -// assert!(digest.logs()[0].as_consensus().is_some()); - - (block1, block2) - } - - fn big_block() -> (Vec, Hash) { - construct_block( - &mut new_test_ext(COMPACT_CODE, false), - 1, - GENESIS_HASH.into(), - vec![ - CheckedExtrinsic { - signed: None, - function: Call::Timestamp(timestamp::Call::set(42)), - }, - CheckedExtrinsic { - signed: Some((alice(), 0)), - function: Call::System(system::Call::remark(vec![0; 120000])), - } - ] - ) - } - - #[test] - fn full_native_block_import_works() { - let mut t = new_test_ext(COMPACT_CODE, false); - - let (block1, block2) = blocks(); - - executor().call::<_, NeverNativeValue, fn() -> _>( - &mut t, - "Core_execute_block", - &block1.0, - true, - None, - ).0.unwrap(); - - runtime_io::with_externalities(&mut t, || { - // block1 transfers from alice 69 to bob. - // -1 is the default fee - assert_eq!(Balances::total_balance(&alice()), 110997859931); - assert_eq!(Balances::total_balance(&bob()), 100000000069); -// assert_eq!(System::events(), vec![ -// EventRecord { -// phase: Phase::ApplyExtrinsic(0), -// event: Event::system(system::Event::ExtrinsicSuccess), -// topics: vec![], -// }, -// EventRecord { -// phase: Phase::ApplyExtrinsic(1), -// event: Event::indices(indices::RawEvent::NewAccountIndex( -// bob().into(), -// 6, -// )), -// topics: vec![], -// }, -// EventRecord { -// phase: Phase::ApplyExtrinsic(1), -// event: Event::balances(balances::RawEvent::NewAccount( -// bob().into(), -// 112 -// )), -// topics: vec![], -// }, -// EventRecord { -// phase: Phase::ApplyExtrinsic(1), -// event: Event::balances(balances::RawEvent::Transfer( -// alice().into(), -// bob().into(), -// 69, -// 1 -// )), -// topics: vec![], -// }, -// EventRecord { -// phase: Phase::ApplyExtrinsic(1), -// event: Event::system(system::Event::ExtrinsicSuccess), -// topics: vec![], -// }, -// ]); - }); - - executor().call::<_, NeverNativeValue, fn() -> _>( - &mut t, - "Core_execute_block", - &block2.0, - true, - None, - ).0.unwrap(); - - runtime_io::with_externalities(&mut t, || { - // bob sends 5, alice sends 15 | bob += 10, alice -= 10 - // 111 - 69 - 1 - 10 - 1 = 30 - assert_eq!(Balances::total_balance(&alice()), 110995720921); - // 100 + 69 + 10 - 1 = 178 - assert_eq!(Balances::total_balance(&bob()), 99997861079); -// assert_eq!(System::events(), vec![ -// EventRecord { -// phase: Phase::ApplyExtrinsic(0), -// event: Event::system(system::Event::ExtrinsicSuccess), -// topics: vec![], -// }, -// EventRecord { -// phase: Phase::ApplyExtrinsic(1), -// event: Event::balances( -// balances::RawEvent::Transfer( -// bob().into(), -// alice().into(), -// 5, -// 0 -// ) -// ), -// topics: vec![], -// }, -// EventRecord { -// phase: Phase::ApplyExtrinsic(1), -// event: Event::system(system::Event::ExtrinsicSuccess), -// topics: vec![], -// }, -// EventRecord { -// phase: Phase::ApplyExtrinsic(2), -// event: Event::balances( -// balances::RawEvent::Transfer( -// alice().into(), -// bob().into(), -// 15, -// 0 -// ) -// ), -// topics: vec![], -// }, -// EventRecord { -// phase: Phase::ApplyExtrinsic(2), -// event: Event::system(system::Event::ExtrinsicSuccess), -// topics: vec![], -// }, -// ]); - }); - } - - #[test] - fn full_wasm_block_import_works() { - let mut t = new_test_ext(COMPACT_CODE, false); - - let (block1, block2) = blocks(); - - WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1.0).unwrap(); - - runtime_io::with_externalities(&mut t, || { - // block1 transfers from alice 69 to bob. - // -1 is the default fee - assert_eq!(Balances::total_balance(&alice()), 110997859931); - assert_eq!(Balances::total_balance(&bob()), 100000000069); - }); - - WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block2.0).unwrap(); - - runtime_io::with_externalities(&mut t, || { - // bob sends 5, alice sends 15 | bob += 10, alice -= 10 - // 111 - 69 - 1 - 10 - 1 = 30 - assert_eq!(Balances::total_balance(&alice()), 110995720921); - // 100 + 69 + 10 - 1 = 178 - assert_eq!(Balances::total_balance(&bob()), 99997861079); - }); - } - - const CODE_TRANSFER: &str = r#" + use super::Executor; + use contracts::ContractAddressFor; + use keyring::{AccountKeyring, AuthorityKeyring}; + use node_primitives::{AccountId, BlockNumber, Hash}; + use node_runtime::{ + Balances, BalancesConfig, Block, BuildStorage, Call, CheckedExtrinsic, Event, GenesisConfig, GrandpaConfig, + Header, IndicesConfig, KtonConfig, Runtime, SessionConfig, SessionKeys, StakingConfig, System, SystemConfig, + UncheckedExtrinsic, COIN, + }; + use parity_codec::{Decode, Encode, Joiner}; + use primitives::map; + use primitives::{blake2_256, twox_128, Blake2Hasher, ChangesTrieConfiguration, NativeOrEncoded, NeverNativeValue}; + use runtime_io; + use runtime_primitives::traits::{Hash as HashT, Header as HeaderT}; + use runtime_primitives::{generic::Era, ApplyError, ApplyOutcome, ApplyResult, Perbill}; + use runtime_support::{traits::Currency, Hashable, StorageMap, StorageValue}; + use state_machine::{CodeExecutor, Externalities, TestExternalities as CoreTestExternalities}; + use substrate_executor::{NativeExecutionDispatch, WasmExecutor}; + use system::{EventRecord, Phase}; + use wabt; + use {balances, contracts, indices, staking, system, timestamp, treasury}; + + /// The wasm runtime code. + /// + /// `compact` since it is after post-processing with wasm-gc which performs tree-shaking thus + /// making the binary slimmer. There is a convention to use compact version of the runtime + /// as canonical. This is why `native_executor_instance` also uses the compact version of the + /// runtime. + const COMPACT_CODE: &[u8] = + include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm"); + + /// The wasm runtime binary which hasn't undergone the compacting process. + /// + /// The idea here is to pass it as the current runtime code to the executor so the executor will + /// have to execute provided wasm code instead of the native equivalent. This trick is used to + /// test code paths that differ between native and wasm versions. + const BLOATY_CODE: &[u8] = + include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.wasm"); + + const GENESIS_HASH: [u8; 32] = [69u8; 32]; + + type TestExternalities = CoreTestExternalities; + + fn alice() -> AccountId { + AccountKeyring::Alice.into() + } + + fn bob() -> AccountId { + AccountKeyring::Bob.into() + } + + fn charlie() -> AccountId { + AccountKeyring::Charlie.into() + } + + fn dave() -> AccountId { + AccountKeyring::Dave.into() + } + + fn eve() -> AccountId { + AccountKeyring::Eve.into() + } + + fn ferdie() -> AccountId { + AccountKeyring::Ferdie.into() + } + + fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic { + match xt.signed { + Some((signed, index)) => { + let era = Era::mortal(256, 0); + let payload = (index.into(), xt.function, era, GENESIS_HASH); + let key = AccountKeyring::from_public(&signed).unwrap(); + let signature = payload + .using_encoded(|b| { + if b.len() > 256 { + key.sign(&runtime_io::blake2_256(b)) + } else { + key.sign(b) + } + }) + .into(); + UncheckedExtrinsic { + signature: Some((indices::address::Address::Id(signed), signature, payload.0, era)), + function: payload.1, + } + } + None => UncheckedExtrinsic { + signature: None, + function: xt.function, + }, + } + } + + fn xt() -> UncheckedExtrinsic { + sign(CheckedExtrinsic { + signed: Some((alice(), 0)), + function: Call::Balances(balances::Call::transfer::(bob().into(), 69 * COIN)), + }) + } + + fn from_block_number(n: u64) -> Header { + Header::new( + n, + Default::default(), + Default::default(), + [69; 32].into(), + Default::default(), + ) + } + + fn executor() -> ::substrate_executor::NativeExecutor { + ::substrate_executor::NativeExecutor::new(None) + } + + #[test] + fn panic_execution_with_foreign_code_gives_error() { + let mut t = TestExternalities::::new_with_code( + BLOATY_CODE, + map![ + blake2_256(&>::key_for(alice())).to_vec() => { + vec![0u8; 16] + }, + twox_128(>::key()).to_vec() => { + vec![0u8; 16] + }, + twox_128(>::key()).to_vec() => { + vec![0u8; 16] + }, + blake2_256(&>::key_for(0)).to_vec() => { + vec![0u8; 32] + } + ], + ); + + let r = executor() + .call::<_, NeverNativeValue, fn() -> _>( + &mut t, + "Core_initialize_block", + &vec![].and(&from_block_number(1u64)), + true, + None, + ) + .0; + assert!(r.is_ok()); + let v = executor() + .call::<_, NeverNativeValue, fn() -> _>( + &mut t, + "BlockBuilder_apply_extrinsic", + &vec![].and(&xt()), + true, + None, + ) + .0 + .unwrap(); + let r = ApplyResult::decode(&mut &v.as_encoded()[..]).unwrap(); + assert_eq!(r, Err(ApplyError::CantPay)); + } + + #[test] + fn bad_extrinsic_with_native_equivalent_code_gives_error() { + let mut t = TestExternalities::::new_with_code( + COMPACT_CODE, + map![ + blake2_256(&>::key_for(alice())).to_vec() => { + vec![0u8; 16] + }, + twox_128(>::key()).to_vec() => { + vec![0u8; 16] + }, + twox_128(>::key()).to_vec() => { + vec![0u8; 16] + }, + blake2_256(&>::key_for(0)).to_vec() => { + vec![0u8; 32] + } + ], + ); + + let r = executor() + .call::<_, NeverNativeValue, fn() -> _>( + &mut t, + "Core_initialize_block", + &vec![].and(&from_block_number(1u64)), + true, + None, + ) + .0; + assert!(r.is_ok()); + let v = executor() + .call::<_, NeverNativeValue, fn() -> _>( + &mut t, + "BlockBuilder_apply_extrinsic", + &vec![].and(&xt()), + true, + None, + ) + .0 + .unwrap(); + let r = ApplyResult::decode(&mut &v.as_encoded()[..]).unwrap(); + assert_eq!(r, Err(ApplyError::CantPay)); + } + + #[test] + fn successful_execution_with_native_equivalent_code_gives_ok() { + let mut t = TestExternalities::::new_with_code( + COMPACT_CODE, + map![ + blake2_256(&>::key_for(alice())).to_vec() => { + (111 * COIN).encode() + }, + twox_128(>::key()).to_vec() => { + (111 * COIN).encode() + }, + twox_128(>::key()).to_vec() => vec![0u8; 16], + blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32] + ], + ); + + let r = executor() + .call::<_, NeverNativeValue, fn() -> _>( + &mut t, + "Core_initialize_block", + &vec![].and(&from_block_number(1u64)), + true, + None, + ) + .0; + assert!(r.is_ok()); + let r = executor() + .call::<_, NeverNativeValue, fn() -> _>( + &mut t, + "BlockBuilder_apply_extrinsic", + &vec![].and(&xt()), + true, + None, + ) + .0; + assert!(r.is_ok()); + + runtime_io::with_externalities(&mut t, || { + assert_eq!(Balances::total_balance(&alice()), 41997856000); + assert_eq!(Balances::total_balance(&bob()), 69 * COIN); + }); + } + + #[test] + fn successful_execution_with_foreign_code_gives_ok() { + let mut t = TestExternalities::::new_with_code( + BLOATY_CODE, + map![ + blake2_256(&>::key_for(alice())).to_vec() => { + (111 * COIN).encode() + }, + twox_128(>::key()).to_vec() => { + (111 * COIN).encode() + }, + twox_128(>::key()).to_vec() => vec![0u8; 16], + blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32] + ], + ); + + let r = executor() + .call::<_, NeverNativeValue, fn() -> _>( + &mut t, + "Core_initialize_block", + &vec![].and(&from_block_number(1u64)), + true, + None, + ) + .0; + assert!(r.is_ok()); + let r = executor() + .call::<_, NeverNativeValue, fn() -> _>( + &mut t, + "BlockBuilder_apply_extrinsic", + &vec![].and(&xt()), + true, + None, + ) + .0; + assert!(r.is_ok()); + + runtime_io::with_externalities(&mut t, || { + assert_eq!(Balances::total_balance(&alice()), 41997856000); + assert_eq!(Balances::total_balance(&bob()), 69 * COIN); + }); + } + + fn to_session_keys(ring: &AuthorityKeyring) -> SessionKeys { + SessionKeys(ring.to_owned().into(), ring.to_owned().into()) + } + + fn new_test_ext(code: &[u8], support_changes_trie: bool) -> TestExternalities { + let three = AccountId::from_raw([3u8; 32]); + let mut ext = TestExternalities::new_with_code( + code, + GenesisConfig { + aura: Some(Default::default()), + system: Some(SystemConfig { + changes_trie_config: if support_changes_trie { + Some(ChangesTrieConfiguration { + digest_interval: 2, + digest_levels: 2, + }) + } else { + None + }, + ..Default::default() + }), + indices: Some(IndicesConfig { + ids: vec![alice(), bob(), charlie(), dave(), eve(), ferdie()], + }), + balances: Some(BalancesConfig { + balances: vec![ + (alice(), 111 * COIN), + (bob(), 100 * COIN), + (charlie(), 100_000_000 * COIN), + (dave(), 111 * COIN), + (eve(), 101 * COIN), + (ferdie(), 100 * COIN), + ], + vesting: vec![], + }), + kton: Some(KtonConfig { + balances: vec![ + (alice(), 111), + (bob(), 100), + (charlie(), 100_000_000), + (dave(), 111), + (eve(), 101), + (ferdie(), 100), + ], + vesting: vec![], + }), + session: Some(SessionConfig { + validators: vec![AccountKeyring::One.into(), AccountKeyring::Two.into(), three], + keys: vec![ + (alice(), to_session_keys(&AuthorityKeyring::Alice)), + (bob(), to_session_keys(&AuthorityKeyring::Bob)), + (charlie(), to_session_keys(&AuthorityKeyring::Charlie)), + ], + }), + staking: Some(StakingConfig { + current_era: 0, + current_era_total_reward: 1, + stakers: vec![ + (dave(), alice(), 111, staking::StakerStatus::Validator), + (eve(), bob(), 100, staking::StakerStatus::Validator), + (ferdie(), charlie(), 100, staking::StakerStatus::Validator), + ], + validator_count: 3, + minimum_validator_count: 0, + offline_slash: Perbill::zero(), + session_reward: Perbill::zero(), + offline_slash_grace: 0, + invulnerables: vec![alice(), bob(), charlie()], + }), + timestamp: Some(Default::default()), + contracts: Some(Default::default()), + sudo: Some(Default::default()), + grandpa: Some(GrandpaConfig { authorities: vec![] }), + } + .build_storage() + .unwrap() + .0, + ); + ext.changes_trie_storage() + .insert(0, GENESIS_HASH.into(), Default::default()); + ext + } + + fn construct_block( + env: &mut TestExternalities, + number: BlockNumber, + parent_hash: Hash, + extrinsics: Vec, + ) -> (Vec, Hash) { + use trie::ordered_trie_root; + + // sign extrinsics. + let extrinsics = extrinsics.into_iter().map(sign).collect::>(); + + // calculate the header fields that we can. + let extrinsics_root = ordered_trie_root::(extrinsics.iter().map(Encode::encode)) + .to_fixed_bytes() + .into(); + + let header = Header { + parent_hash, + number, + extrinsics_root, + state_root: Default::default(), + digest: Default::default(), + }; + + // execute the block to get the real header. + Executor::new(None) + .call::<_, NeverNativeValue, fn() -> _>(env, "Core_initialize_block", &header.encode(), true, None) + .0 + .unwrap(); + + for i in extrinsics.iter() { + Executor::new(None) + .call::<_, NeverNativeValue, fn() -> _>(env, "BlockBuilder_apply_extrinsic", &i.encode(), true, None) + .0 + .unwrap(); + } + + let header = match Executor::new(None) + .call::<_, NeverNativeValue, fn() -> _>(env, "BlockBuilder_finalize_block", &[0u8; 0], true, None) + .0 + .unwrap() + { + NativeOrEncoded::Native(_) => unreachable!(), + NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(), + }; + + let hash = header.blake2_256(); + (Block { header, extrinsics }.encode(), hash.into()) + } + + fn changes_trie_block() -> (Vec, Hash) { + construct_block( + &mut new_test_ext(COMPACT_CODE, true), + 1, + GENESIS_HASH.into(), + vec![ + CheckedExtrinsic { + signed: None, + function: Call::Timestamp(timestamp::Call::set(42)), + }, + CheckedExtrinsic { + signed: Some((alice(), 0)), + function: Call::Balances(balances::Call::transfer(bob().into(), 69 * COIN)), + }, + ], + ) + } + + // block 1 and 2 must be created together to ensure transactions are only signed once (since they + // are not guaranteed to be deterministic) and to ensure that the correct state is propagated + // from block1's execution to block2 to derive the correct storage_root. + fn blocks() -> ((Vec, Hash), (Vec, Hash)) { + let mut t = new_test_ext(COMPACT_CODE, false); + let block1 = construct_block( + &mut t, + 1, + GENESIS_HASH.into(), + vec![ + CheckedExtrinsic { + signed: None, + function: Call::Timestamp(timestamp::Call::set(42)), + }, + CheckedExtrinsic { + signed: Some((alice(), 0)), + function: Call::Balances(balances::Call::transfer(bob().into(), 69)), + }, + ], + ); + let block2 = construct_block( + &mut t, + 2, + block1.1.clone(), + vec![ + CheckedExtrinsic { + signed: None, + function: Call::Timestamp(timestamp::Call::set(52)), + }, + CheckedExtrinsic { + signed: Some((bob(), 0)), + function: Call::Balances(balances::Call::transfer(alice().into(), 5)), + }, + CheckedExtrinsic { + signed: Some((alice(), 1)), + function: Call::Balances(balances::Call::transfer(bob().into(), 15)), + }, + ], + ); + + // session change => consensus authorities change => authorities change digest item appears + let digest = Header::decode(&mut &block2.0[..]).unwrap().digest; + assert_eq!(digest.logs().len(), 0); + // assert!(digest.logs()[0].as_consensus().is_some()); + + (block1, block2) + } + + fn big_block() -> (Vec, Hash) { + construct_block( + &mut new_test_ext(COMPACT_CODE, false), + 1, + GENESIS_HASH.into(), + vec![ + CheckedExtrinsic { + signed: None, + function: Call::Timestamp(timestamp::Call::set(42)), + }, + CheckedExtrinsic { + signed: Some((alice(), 0)), + function: Call::System(system::Call::remark(vec![0; 120000])), + }, + ], + ) + } + + #[test] + fn full_native_block_import_works() { + let mut t = new_test_ext(COMPACT_CODE, false); + + let (block1, block2) = blocks(); + + executor() + .call::<_, NeverNativeValue, fn() -> _>(&mut t, "Core_execute_block", &block1.0, true, None) + .0 + .unwrap(); + + runtime_io::with_externalities(&mut t, || { + // block1 transfers from alice 69 to bob. + // -1 is the default fee + assert_eq!(Balances::total_balance(&alice()), 110997859931); + assert_eq!(Balances::total_balance(&bob()), 100000000069); + // assert_eq!(System::events(), vec![ + // EventRecord { + // phase: Phase::ApplyExtrinsic(0), + // event: Event::system(system::Event::ExtrinsicSuccess), + // topics: vec![], + // }, + // EventRecord { + // phase: Phase::ApplyExtrinsic(1), + // event: Event::indices(indices::RawEvent::NewAccountIndex( + // bob().into(), + // 6, + // )), + // topics: vec![], + // }, + // EventRecord { + // phase: Phase::ApplyExtrinsic(1), + // event: Event::balances(balances::RawEvent::NewAccount( + // bob().into(), + // 112 + // )), + // topics: vec![], + // }, + // EventRecord { + // phase: Phase::ApplyExtrinsic(1), + // event: Event::balances(balances::RawEvent::Transfer( + // alice().into(), + // bob().into(), + // 69, + // 1 + // )), + // topics: vec![], + // }, + // EventRecord { + // phase: Phase::ApplyExtrinsic(1), + // event: Event::system(system::Event::ExtrinsicSuccess), + // topics: vec![], + // }, + // ]); + }); + + executor() + .call::<_, NeverNativeValue, fn() -> _>(&mut t, "Core_execute_block", &block2.0, true, None) + .0 + .unwrap(); + + runtime_io::with_externalities(&mut t, || { + // bob sends 5, alice sends 15 | bob += 10, alice -= 10 + // 111 - 69 - 1 - 10 - 1 = 30 + assert_eq!(Balances::total_balance(&alice()), 110995720921); + // 100 + 69 + 10 - 1 = 178 + assert_eq!(Balances::total_balance(&bob()), 99997861079); + // assert_eq!(System::events(), vec![ + // EventRecord { + // phase: Phase::ApplyExtrinsic(0), + // event: Event::system(system::Event::ExtrinsicSuccess), + // topics: vec![], + // }, + // EventRecord { + // phase: Phase::ApplyExtrinsic(1), + // event: Event::balances( + // balances::RawEvent::Transfer( + // bob().into(), + // alice().into(), + // 5, + // 0 + // ) + // ), + // topics: vec![], + // }, + // EventRecord { + // phase: Phase::ApplyExtrinsic(1), + // event: Event::system(system::Event::ExtrinsicSuccess), + // topics: vec![], + // }, + // EventRecord { + // phase: Phase::ApplyExtrinsic(2), + // event: Event::balances( + // balances::RawEvent::Transfer( + // alice().into(), + // bob().into(), + // 15, + // 0 + // ) + // ), + // topics: vec![], + // }, + // EventRecord { + // phase: Phase::ApplyExtrinsic(2), + // event: Event::system(system::Event::ExtrinsicSuccess), + // topics: vec![], + // }, + // ]); + }); + } + + #[test] + fn full_wasm_block_import_works() { + let mut t = new_test_ext(COMPACT_CODE, false); + + let (block1, block2) = blocks(); + + WasmExecutor::new() + .call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1.0) + .unwrap(); + + runtime_io::with_externalities(&mut t, || { + // block1 transfers from alice 69 to bob. + // -1 is the default fee + assert_eq!(Balances::total_balance(&alice()), 110997859931); + assert_eq!(Balances::total_balance(&bob()), 100000000069); + }); + + WasmExecutor::new() + .call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block2.0) + .unwrap(); + + runtime_io::with_externalities(&mut t, || { + // bob sends 5, alice sends 15 | bob += 10, alice -= 10 + // 111 - 69 - 1 - 10 - 1 = 30 + assert_eq!(Balances::total_balance(&alice()), 110995720921); + // 100 + 69 + 10 - 1 = 178 + assert_eq!(Balances::total_balance(&bob()), 99997861079); + }); + } + + const CODE_TRANSFER: &str = r#" (module ;; ext_call( ;; callee_ptr: u32, @@ -740,228 +778,242 @@ mod tests { ) "#; - #[test] - fn deploying_wasm_contract_should_work() { - -// let mut t = new_test_ext(COMPACT_CODE, false); -// -// let (block1, block2) = blocks(); -// -// executor().call::<_, NeverNativeValue, fn() -> _>( -// &mut t, -// "Core_execute_block", -// &block1.0, -// true, -// None, -// ).0.unwrap(); -// -// runtime_io::with_externalities(&mut t, || { -// // block1 transfers from alice 69 to bob. -// // -1 is the default fee -// assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * TX_FEE); -// assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS); -// let events = vec![ -// EventRecord { -// phase: Phase::ApplyExtrinsic(0), -// event: Event::system(system::Event::ExtrinsicSuccess), -// topics: vec![], -// }, -// EventRecord { -// phase: Phase::ApplyExtrinsic(1), -// event: Event::balances(balances::RawEvent::Transfer( -// alice().into(), -// bob().into(), -// 69 * DOLLARS, -// 1 * CENTS -// )), -// topics: vec![], -// }, -// EventRecord { -// phase: Phase::ApplyExtrinsic(1), -// event: Event::system(system::Event::ExtrinsicSuccess), -// topics: vec![], -// }, -// ]; -// assert_eq!(System::events(), events); -// }); -// -// executor().call::<_, NeverNativeValue, fn() -> _>( -// &mut t, -// "Core_execute_block", -// &block2.0, -// true, -// None, -// ).0.unwrap(); -// -// runtime_io::with_externalities(&mut t, || { -// // bob sends 5, alice sends 15 | bob += 10, alice -= 10 -// // 111 - 69 - 10 = 32 -// assert_eq!(Balances::total_balance(&alice()), 32 * DOLLARS - 2 * TX_FEE); -// // 100 + 69 + 10 = 179 -// assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - 1 * TX_FEE); -// let events = vec![ -// EventRecord { -// phase: Phase::ApplyExtrinsic(0), -// event: Event::system(system::Event::ExtrinsicSuccess), -// topics: vec![], -// }, -// EventRecord { -// phase: Phase::ApplyExtrinsic(1), -// event: Event::balances( -// balances::RawEvent::Transfer( -// bob().into(), -// alice().into(), -// 5 * DOLLARS, -// 1 * CENTS, -// ) -// ), -// topics: vec![], -// }, -// EventRecord { -// phase: Phase::ApplyExtrinsic(1), -// event: Event::system(system::Event::ExtrinsicSuccess), -// topics: vec![], -// }, -// EventRecord { -// phase: Phase::ApplyExtrinsic(2), -// event: Event::balances( -// balances::RawEvent::Transfer( -// alice().into(), -// bob().into(), -// 15 * DOLLARS, -// 1 * CENTS, -// ) -// ), -// topics: vec![], -// }, -// EventRecord { -// phase: Phase::ApplyExtrinsic(2), -// event: Event::system(system::Event::ExtrinsicSuccess), -// topics: vec![], -// }, -// ]; -// assert_eq!(System::events(), events); -// }); - } - - #[test] - fn wasm_big_block_import_fails() { - let mut t = new_test_ext(COMPACT_CODE, false); - - assert!( - WasmExecutor::new().call( - &mut t, - 4, - COMPACT_CODE, - "Core_execute_block", - &big_block().0 - ).is_err() - ); - } - - #[test] - fn native_big_block_import_succeeds() { - let mut t = new_test_ext(COMPACT_CODE, false); - - Executor::new(None).call::<_, NeverNativeValue, fn() -> _>( - &mut t, - "Core_execute_block", - &big_block().0, - true, - None, - ).0.unwrap(); - } - - #[test] - fn native_big_block_import_fails_on_fallback() { - let mut t = new_test_ext(COMPACT_CODE, false); - - assert!( - Executor::new(None).call::<_, NeverNativeValue, fn() -> _>( - &mut t, - "Core_execute_block", - &big_block().0, - false, - None, - ).0.is_err() - ); - } - - #[test] - fn panic_execution_gives_error() { - let mut t = TestExternalities::::new_with_code(BLOATY_CODE, map![ - blake2_256(&>::key_for(alice())).to_vec() => { - vec![0u8; 16] - }, - twox_128(>::key()).to_vec() => { - vec![0u8; 16] - }, - twox_128(>::key()).to_vec() => vec![0u8; 16], - blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32] - ]); - - let r = WasmExecutor::new() - .call(&mut t, 8, COMPACT_CODE, "Core_initialize_block", &vec![].and(&from_block_number(1u64))); - assert!(r.is_ok()); - let r = WasmExecutor::new() - .call(&mut t, 8, COMPACT_CODE, "BlockBuilder_apply_extrinsic", &vec![].and(&xt())).unwrap(); - let r = ApplyResult::decode(&mut &r[..]).unwrap(); - assert_eq!(r, Err(ApplyError::CantPay)); - } - - #[test] - fn successful_execution_gives_ok() { - let mut t = TestExternalities::::new_with_code(COMPACT_CODE, map![ - blake2_256(&>::key_for(alice())).to_vec() => { - (111 * COIN).encode() - }, - twox_128(>::key()).to_vec() => { - (111 * COIN).encode() - }, - twox_128(>::key()).to_vec() => vec![0u8; 16], - blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32] - ]); - - let r = WasmExecutor::new() - .call(&mut t, 8, COMPACT_CODE, "Core_initialize_block", &vec![].and(&from_block_number(1u64))); - assert!(r.is_ok()); - let r = WasmExecutor::new() - .call(&mut t, 8, COMPACT_CODE, "BlockBuilder_apply_extrinsic", &vec![].and(&xt())).unwrap(); - let r = ApplyResult::decode(&mut &r[..]).unwrap(); - assert_eq!(r, Ok(ApplyOutcome::Success)); - - runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 41997856000); - assert_eq!(Balances::total_balance(&bob()), 69 * COIN); - }); - } - - #[test] - fn full_native_block_import_works_with_changes_trie() { - let block1 = changes_trie_block(); - let block_data = block1.0; - let block = Block::decode(&mut &block_data[..]).unwrap(); - - let mut t = new_test_ext(COMPACT_CODE, true); - Executor::new(None).call::<_, NeverNativeValue, fn() -> _>( - &mut t, - "Core_execute_block", - &block.encode(), - true, - None, - ).0.unwrap(); - - assert!(t.storage_changes_root(GENESIS_HASH.into()).unwrap().is_some()); - } - - #[test] - fn full_wasm_block_import_works_with_changes_trie() { - let block1 = changes_trie_block(); - - let mut t = new_test_ext(COMPACT_CODE, true); - WasmExecutor::new() - .call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1.0).unwrap(); - - assert!(t.storage_changes_root(GENESIS_HASH.into()).unwrap().is_some()); - } + #[test] + fn deploying_wasm_contract_should_work() { + + // let mut t = new_test_ext(COMPACT_CODE, false); + // + // let (block1, block2) = blocks(); + // + // executor().call::<_, NeverNativeValue, fn() -> _>( + // &mut t, + // "Core_execute_block", + // &block1.0, + // true, + // None, + // ).0.unwrap(); + // + // runtime_io::with_externalities(&mut t, || { + // // block1 transfers from alice 69 to bob. + // // -1 is the default fee + // assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * TX_FEE); + // assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS); + // let events = vec![ + // EventRecord { + // phase: Phase::ApplyExtrinsic(0), + // event: Event::system(system::Event::ExtrinsicSuccess), + // topics: vec![], + // }, + // EventRecord { + // phase: Phase::ApplyExtrinsic(1), + // event: Event::balances(balances::RawEvent::Transfer( + // alice().into(), + // bob().into(), + // 69 * DOLLARS, + // 1 * CENTS + // )), + // topics: vec![], + // }, + // EventRecord { + // phase: Phase::ApplyExtrinsic(1), + // event: Event::system(system::Event::ExtrinsicSuccess), + // topics: vec![], + // }, + // ]; + // assert_eq!(System::events(), events); + // }); + // + // executor().call::<_, NeverNativeValue, fn() -> _>( + // &mut t, + // "Core_execute_block", + // &block2.0, + // true, + // None, + // ).0.unwrap(); + // + // runtime_io::with_externalities(&mut t, || { + // // bob sends 5, alice sends 15 | bob += 10, alice -= 10 + // // 111 - 69 - 10 = 32 + // assert_eq!(Balances::total_balance(&alice()), 32 * DOLLARS - 2 * TX_FEE); + // // 100 + 69 + 10 = 179 + // assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - 1 * TX_FEE); + // let events = vec![ + // EventRecord { + // phase: Phase::ApplyExtrinsic(0), + // event: Event::system(system::Event::ExtrinsicSuccess), + // topics: vec![], + // }, + // EventRecord { + // phase: Phase::ApplyExtrinsic(1), + // event: Event::balances( + // balances::RawEvent::Transfer( + // bob().into(), + // alice().into(), + // 5 * DOLLARS, + // 1 * CENTS, + // ) + // ), + // topics: vec![], + // }, + // EventRecord { + // phase: Phase::ApplyExtrinsic(1), + // event: Event::system(system::Event::ExtrinsicSuccess), + // topics: vec![], + // }, + // EventRecord { + // phase: Phase::ApplyExtrinsic(2), + // event: Event::balances( + // balances::RawEvent::Transfer( + // alice().into(), + // bob().into(), + // 15 * DOLLARS, + // 1 * CENTS, + // ) + // ), + // topics: vec![], + // }, + // EventRecord { + // phase: Phase::ApplyExtrinsic(2), + // event: Event::system(system::Event::ExtrinsicSuccess), + // topics: vec![], + // }, + // ]; + // assert_eq!(System::events(), events); + // }); + } + + #[test] + fn wasm_big_block_import_fails() { + let mut t = new_test_ext(COMPACT_CODE, false); + + assert!(WasmExecutor::new() + .call(&mut t, 4, COMPACT_CODE, "Core_execute_block", &big_block().0) + .is_err()); + } + + #[test] + fn native_big_block_import_succeeds() { + let mut t = new_test_ext(COMPACT_CODE, false); + + Executor::new(None) + .call::<_, NeverNativeValue, fn() -> _>(&mut t, "Core_execute_block", &big_block().0, true, None) + .0 + .unwrap(); + } + + #[test] + fn native_big_block_import_fails_on_fallback() { + let mut t = new_test_ext(COMPACT_CODE, false); + + assert!(Executor::new(None) + .call::<_, NeverNativeValue, fn() -> _>(&mut t, "Core_execute_block", &big_block().0, false, None,) + .0 + .is_err()); + } + + #[test] + fn panic_execution_gives_error() { + let mut t = TestExternalities::::new_with_code( + BLOATY_CODE, + map![ + blake2_256(&>::key_for(alice())).to_vec() => { + vec![0u8; 16] + }, + twox_128(>::key()).to_vec() => { + vec![0u8; 16] + }, + twox_128(>::key()).to_vec() => vec![0u8; 16], + blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32] + ], + ); + + let r = WasmExecutor::new().call( + &mut t, + 8, + COMPACT_CODE, + "Core_initialize_block", + &vec![].and(&from_block_number(1u64)), + ); + assert!(r.is_ok()); + let r = WasmExecutor::new() + .call( + &mut t, + 8, + COMPACT_CODE, + "BlockBuilder_apply_extrinsic", + &vec![].and(&xt()), + ) + .unwrap(); + let r = ApplyResult::decode(&mut &r[..]).unwrap(); + assert_eq!(r, Err(ApplyError::CantPay)); + } + + #[test] + fn successful_execution_gives_ok() { + let mut t = TestExternalities::::new_with_code( + COMPACT_CODE, + map![ + blake2_256(&>::key_for(alice())).to_vec() => { + (111 * COIN).encode() + }, + twox_128(>::key()).to_vec() => { + (111 * COIN).encode() + }, + twox_128(>::key()).to_vec() => vec![0u8; 16], + blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32] + ], + ); + + let r = WasmExecutor::new().call( + &mut t, + 8, + COMPACT_CODE, + "Core_initialize_block", + &vec![].and(&from_block_number(1u64)), + ); + assert!(r.is_ok()); + let r = WasmExecutor::new() + .call( + &mut t, + 8, + COMPACT_CODE, + "BlockBuilder_apply_extrinsic", + &vec![].and(&xt()), + ) + .unwrap(); + let r = ApplyResult::decode(&mut &r[..]).unwrap(); + assert_eq!(r, Ok(ApplyOutcome::Success)); + + runtime_io::with_externalities(&mut t, || { + assert_eq!(Balances::total_balance(&alice()), 41997856000); + assert_eq!(Balances::total_balance(&bob()), 69 * COIN); + }); + } + + #[test] + fn full_native_block_import_works_with_changes_trie() { + let block1 = changes_trie_block(); + let block_data = block1.0; + let block = Block::decode(&mut &block_data[..]).unwrap(); + + let mut t = new_test_ext(COMPACT_CODE, true); + Executor::new(None) + .call::<_, NeverNativeValue, fn() -> _>(&mut t, "Core_execute_block", &block.encode(), true, None) + .0 + .unwrap(); + + assert!(t.storage_changes_root(GENESIS_HASH.into()).unwrap().is_some()); + } + + #[test] + fn full_wasm_block_import_works_with_changes_trie() { + let block1 = changes_trie_block(); + + let mut t = new_test_ext(COMPACT_CODE, true); + WasmExecutor::new() + .call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1.0) + .unwrap(); + + assert!(t.storage_changes_root(GENESIS_HASH.into()).unwrap().is_some()); + } } diff --git a/node/primitives/src/lib.rs b/node/primitives/src/lib.rs index 1d6c18d6c..b5f779838 100644 --- a/node/primitives/src/lib.rs +++ b/node/primitives/src/lib.rs @@ -17,11 +17,12 @@ //! Low-level types used throughout the Substrate code. #![warn(missing_docs)] - #![cfg_attr(not(feature = "std"), no_std)] use runtime_primitives::{ - generic, traits::{Verify, BlakeTwo256}, OpaqueExtrinsic, AnySignature + generic, + traits::{BlakeTwo256, Verify}, + AnySignature, OpaqueExtrinsic, }; /// An index to a block. diff --git a/node/rpc-client/src/main.rs b/node/rpc-client/src/main.rs index fe057bcbe..6926bab35 100644 --- a/node/rpc-client/src/main.rs +++ b/node/rpc-client/src/main.rs @@ -23,30 +23,22 @@ use futures::Future; use hyper::rt; +use jsonrpc_core_client::{transports::http, RpcError}; use node_primitives::Hash; -use substrate_rpc::author::{ - AuthorClient, - hash::ExtrinsicOrHash, -}; -use jsonrpc_core_client::{ - transports::http, - RpcError, -}; +use substrate_rpc::author::{hash::ExtrinsicOrHash, AuthorClient}; fn main() { - env_logger::init(); + env_logger::init(); - rt::run(rt::lazy(|| { - let uri = "http://localhost:9933"; + rt::run(rt::lazy(|| { + let uri = "http://localhost:9933"; - http::connect(uri) - .and_then(|client: AuthorClient| { - remove_all_extrinsics(client) - }) - .map_err(|e| { - println!("Error: {:?}", e); - }) - })) + http::connect(uri) + .and_then(|client: AuthorClient| remove_all_extrinsics(client)) + .map_err(|e| { + println!("Error: {:?}", e); + }) + })) } /// Remove all pending extrinsics from the node. @@ -57,14 +49,18 @@ fn main() { /// /// As the resul of running the code the entire content of the transaction pool is going /// to be removed and the extrinsics are going to be temporarily banned. -fn remove_all_extrinsics(client: AuthorClient) -> impl Future { - client.pending_extrinsics() - .and_then(move |pending| { - client.remove_extrinsic( - pending.into_iter().map(|tx| ExtrinsicOrHash::Extrinsic(tx.into())).collect() - ) - }) - .map(|removed| { - println!("Removed extrinsics: {:?}", removed); - }) +fn remove_all_extrinsics(client: AuthorClient) -> impl Future { + client + .pending_extrinsics() + .and_then(move |pending| { + client.remove_extrinsic( + pending + .into_iter() + .map(|tx| ExtrinsicOrHash::Extrinsic(tx.into())) + .collect(), + ) + }) + .map(|removed| { + println!("Removed extrinsics: {:?}", removed); + }) } diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index a5668350a..59ebebb56 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -18,65 +18,58 @@ #![cfg_attr(not(feature = "std"), no_std)] // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. -#![recursion_limit="256"] +#![recursion_limit = "256"] -use rstd::prelude::*; -use support::{ - construct_runtime, parameter_types, traits::{SplitTwoWays, Currency, OnUnbalanced} -}; -use substrate_primitives::u32_trait::{_1, _2, _3, _4}; -pub use node_primitives::{ - AccountId, AccountIndex, AuraId, Balance, BlockNumber, Hash, Nonce, - Moment, Signature, -}; -use grandpa::fg_primitives::{self, ScheduledChange}; use client::{ - block_builder::api::{self as block_builder_api, InherentData, CheckInherentsResult}, - runtime_api as client_api, impl_runtime_apis + block_builder::api::{self as block_builder_api, CheckInherentsResult, InherentData}, + impl_runtime_apis, runtime_api as client_api, }; -use runtime_primitives::{ApplyResult, generic, create_runtime_str}; +use grandpa::fg_primitives::{self, ScheduledChange}; +pub use node_primitives::{AccountId, AccountIndex, AuraId, Balance, BlockNumber, Hash, Moment, Nonce, Signature}; +use rstd::prelude::*; +use runtime_primitives::traits::{BlakeTwo256, Block as BlockT, Convert, DigestFor, NumberFor, StaticLookup}; use runtime_primitives::transaction_validity::TransactionValidity; -use runtime_primitives::traits::{ - BlakeTwo256, Block as BlockT, DigestFor, NumberFor, StaticLookup, Convert, +use runtime_primitives::{create_runtime_str, generic, ApplyResult}; +use substrate_primitives::u32_trait::{_1, _2, _3, _4}; +use support::{ + construct_runtime, parameter_types, + traits::{Currency, OnUnbalanced, SplitTwoWays}, }; use version::RuntimeVersion; +use finality_tracker::{DEFAULT_REPORT_LATENCY, DEFAULT_WINDOW_SIZE}; +use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight}; +use substrate_primitives::OpaqueMetadata; #[cfg(any(feature = "std", test))] use version::NativeVersion; -use substrate_primitives::OpaqueMetadata; -use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight}; -use finality_tracker::{DEFAULT_REPORT_LATENCY, DEFAULT_WINDOW_SIZE}; -#[cfg(any(feature = "std", test))] -pub use runtime_primitives::BuildStorage; -pub use timestamp::Call as TimestampCall; pub use balances::Call as BalancesCall; pub use contracts::Gas; -pub use runtime_primitives::{Permill, Perbill, impl_opaque_keys}; -pub use support::StorageValue; -pub use staking::StakerStatus; +#[cfg(any(feature = "std", test))] +pub use runtime_primitives::BuildStorage; +pub use runtime_primitives::{impl_opaque_keys, Perbill, Permill}; pub use staking::EraIndex; - +pub use staking::StakerStatus; +pub use support::StorageValue; +pub use timestamp::Call as TimestampCall; /// Runtime version. pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("node"), - impl_name: create_runtime_str!("darwinia-node"), - authoring_version: 2, - spec_version: 78, - impl_version: 78, - apis: RUNTIME_API_VERSIONS, + spec_name: create_runtime_str!("node"), + impl_name: create_runtime_str!("darwinia-node"), + authoring_version: 2, + spec_version: 78, + impl_version: 78, + apis: RUNTIME_API_VERSIONS, }; - - /// Native version. #[cfg(any(feature = "std", test))] pub fn native_version() -> NativeVersion { - NativeVersion { - runtime_version: VERSION, - can_author_with: Default::default(), - } + NativeVersion { + runtime_version: VERSION, + can_author_with: Default::default(), + } } pub const NANO: Balance = 1; @@ -89,24 +82,25 @@ type NegativeImbalance = >::NegativeImbalance; pub struct Author; impl OnUnbalanced for Author { - fn on_unbalanced(amount: NegativeImbalance) { - Balances::resolve_creating(&Authorship::author(), amount); - } + fn on_unbalanced(amount: NegativeImbalance) { + Balances::resolve_creating(&Authorship::author(), amount); + } } pub struct MockTreasury; impl OnUnbalanced for MockTreasury { - fn on_unbalanced(amount: NegativeImbalance) { - Balances::resolve_creating(&Sudo::key(), amount); - } + fn on_unbalanced(amount: NegativeImbalance) { + Balances::resolve_creating(&Sudo::key(), amount); + } } - pub type DealWithFees = SplitTwoWays< - Balance, - NegativeImbalance, - _4, MockTreasury, // 4 parts (80%) goes to the treasury. - _1, Author, // 1 part (20%) goes to the block author. + Balance, + NegativeImbalance, + _4, + MockTreasury, // 4 parts (80%) goes to the treasury. + _1, + Author, // 1 part (20%) goes to the block author. >; pub const SECS_PER_BLOCK: Moment = 6; @@ -117,93 +111,96 @@ pub const DAYS: Moment = HOURS * 24; pub struct CurrencyToVoteHandler; impl CurrencyToVoteHandler { - fn factor() -> u128 { (Balances::total_issuance() / u64::max_value() as u128).max(1) } + fn factor() -> u128 { + (Balances::total_issuance() / u64::max_value() as u128).max(1) + } } impl Convert for CurrencyToVoteHandler { - fn convert(x: u128) -> u64 { (x / Self::factor()) as u64 } + fn convert(x: u128) -> u64 { + (x / Self::factor()) as u64 + } } impl Convert for CurrencyToVoteHandler { - fn convert(x: u128) -> u128 { x * Self::factor() } + fn convert(x: u128) -> u128 { + x * Self::factor() + } } impl system::Trait for Runtime { - type Origin = Origin; - type Index = Nonce; - type BlockNumber = BlockNumber; - type Hash = Hash; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = Indices; - type Header = generic::Header; - type Event = Event; + type Origin = Origin; + type Index = Nonce; + type BlockNumber = BlockNumber; + type Hash = Hash; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = Indices; + type Header = generic::Header; + type Event = Event; } impl aura::Trait for Runtime { - type HandleReport = aura::StakingSlasher; - type AuthorityId = AuraId; + type HandleReport = aura::StakingSlasher; + type AuthorityId = AuraId; } impl indices::Trait for Runtime { - type AccountIndex = AccountIndex; - type IsDeadAccount = Balances; - type ResolveHint = indices::SimpleResolveHint; - type Event = Event; + type AccountIndex = AccountIndex; + type IsDeadAccount = Balances; + type ResolveHint = indices::SimpleResolveHint; + type Event = Event; } impl balances::Trait for Runtime { - type Balance = Balance; - type OnFreeBalanceZero = ((Staking, Contracts), Session); - type OnNewAccount = Indices; - type Event = Event; - type TransactionPayment = DealWithFees; - type DustRemoval = (); - type TransferPayment = (); - type ExistentialDeposit = ExistentialDeposit; - type TransferFee = TransferFee; - type CreationFee = CreationFee; - type TransactionBaseFee = TransactionBaseFee; - type TransactionByteFee = TransactionByteFee; + type Balance = Balance; + type OnFreeBalanceZero = ((Staking, Contracts), Session); + type OnNewAccount = Indices; + type Event = Event; + type TransactionPayment = DealWithFees; + type DustRemoval = (); + type TransferPayment = (); + type ExistentialDeposit = ExistentialDeposit; + type TransferFee = TransferFee; + type CreationFee = CreationFee; + type TransactionBaseFee = TransactionBaseFee; + type TransactionByteFee = TransactionByteFee; } - impl kton::Trait for Runtime { - type Balance = Balance; - type Event = Event; - type OnMinted = (); - type OnRemoval = (); + type Balance = Balance; + type Event = Event; + type OnMinted = (); + type OnRemoval = (); } - impl timestamp::Trait for Runtime { - type Moment = u64; - type OnTimestampSet = Aura; + type Moment = u64; + type OnTimestampSet = Aura; } parameter_types! { - pub const ExistentialDeposit: Balance = 1 * MICRO; - pub const TransferFee: Balance = 1 * MILLI; - pub const CreationFee: Balance = 1 * MILLI; - pub const TransactionBaseFee: Balance = 1 * MILLI; - pub const TransactionByteFee: Balance = 1 * MICRO; + pub const ExistentialDeposit: Balance = 1 * MICRO; + pub const TransferFee: Balance = 1 * MILLI; + pub const CreationFee: Balance = 1 * MILLI; + pub const TransactionBaseFee: Balance = 1 * MILLI; + pub const TransactionByteFee: Balance = 1 * MICRO; } type SessionHandlers = (Grandpa, Aura); parameter_types! { - pub const UncleGenerations: u64 = 0; + pub const UncleGenerations: u64 = 0; } - impl_opaque_keys! { - pub struct SessionKeys(grandpa::AuthorityId, AuraId); + pub struct SessionKeys(grandpa::AuthorityId, AuraId); } impl authorship::Trait for Runtime { - type FindAuthor = (); - type UncleGenerations = UncleGenerations; - type FilterUncle = (); - type EventHandler = (); + type FindAuthor = (); + type UncleGenerations = UncleGenerations; + type FilterUncle = (); + type EventHandler = (); } // NOTE: `SessionHandler` and `SessionKeys` are co-dependent: One key will be used for each handler. @@ -212,113 +209,109 @@ impl authorship::Trait for Runtime { // TODO: Introduce some structure to tie these together to make it a bit less of a footgun. This // should be easy, since OneSessionHandler trait provides the `Key` as an associated type. #2858 - parameter_types! { - pub const Period: BlockNumber = 1 * MINUTES; - pub const Offset: BlockNumber = 0; + pub const Period: BlockNumber = 1 * MINUTES; + pub const Offset: BlockNumber = 0; } impl session::Trait for Runtime { - type OnSessionEnding = Staking; - type SessionHandler = SessionHandlers; - type ShouldEndSession = session::PeriodicSessions; - type Event = Event; - type Keys = SessionKeys; + type OnSessionEnding = Staking; + type SessionHandler = SessionHandlers; + type ShouldEndSession = session::PeriodicSessions; + type Event = Event; + type Keys = SessionKeys; } parameter_types! { - pub const SessionsPerEra: session::SessionIndex = 5; - // about 14 days - pub const BondingDuration: staking::EraIndex = 4032; - // 365 days * 24 hours * 60 minutes / 5 minutes - pub const ErasPerEpoch: EraIndex = 105120; + pub const SessionsPerEra: session::SessionIndex = 5; + // about 14 days + pub const BondingDuration: staking::EraIndex = 4032; + // 365 days * 24 hours * 60 minutes / 5 minutes + pub const ErasPerEpoch: EraIndex = 105120; } // customed parameter_types! { - // decimal 9 - pub const CAP: Balance = 10_000_000_000 * COIN; + // decimal 9 + pub const CAP: Balance = 10_000_000_000 * COIN; } - - impl staking::Trait for Runtime { - type Ring = Balances; - type Kton = Kton; - type CurrencyToVote = CurrencyToVoteHandler; - type Event = Event; - type RingReward = (); - type RingSlash = (); - type KtonReward = (); - type KtonSlash = (); - type SessionsPerEra = SessionsPerEra; - type BondingDuration = BondingDuration; - // customed - type Cap = CAP; - type ErasPerEpoch = ErasPerEpoch; + type Ring = Balances; + type Kton = Kton; + type CurrencyToVote = CurrencyToVoteHandler; + type Event = Event; + type RingReward = (); + type RingSlash = (); + type KtonReward = (); + type KtonSlash = (); + type SessionsPerEra = SessionsPerEra; + type BondingDuration = BondingDuration; + // customed + type Cap = CAP; + type ErasPerEpoch = ErasPerEpoch; } - parameter_types! { - pub const SignedClaimHandicap: BlockNumber = 2; - pub const TombstoneDeposit: Balance = 16; - pub const StorageSizeOffset: u32 = 8; - pub const RentByteFee: Balance = 4; - pub const RentDepositOffset: Balance = 1000; - pub const SurchargeReward: Balance = 150; - pub const ContractTransferFee: Balance = 1 * MILLI; - pub const ContractCreationFee: Balance = 1 * MILLI; - pub const ContractTransactionBaseFee: Balance = 1 * MILLI; - pub const ContractTransactionByteFee: Balance = 10 * NANO; - pub const ContractFee: Balance = 1 * MILLI; - pub const CallBaseFee: Gas = 1000; - pub const CreateBaseFee: Gas = 1000; - pub const MaxDepth: u32 = 1024; - pub const BlockGasLimit: Gas = 10_000_000; + pub const SignedClaimHandicap: BlockNumber = 2; + pub const TombstoneDeposit: Balance = 16; + pub const StorageSizeOffset: u32 = 8; + pub const RentByteFee: Balance = 4; + pub const RentDepositOffset: Balance = 1000; + pub const SurchargeReward: Balance = 150; + pub const ContractTransferFee: Balance = 1 * MILLI; + pub const ContractCreationFee: Balance = 1 * MILLI; + pub const ContractTransactionBaseFee: Balance = 1 * MILLI; + pub const ContractTransactionByteFee: Balance = 10 * NANO; + pub const ContractFee: Balance = 1 * MILLI; + pub const CallBaseFee: Gas = 1000; + pub const CreateBaseFee: Gas = 1000; + pub const MaxDepth: u32 = 1024; + pub const BlockGasLimit: Gas = 10_000_000; } impl contracts::Trait for Runtime { - type Currency = Balances; - type Call = Call; - type Event = Event; - type DetermineContractAddress = contracts::SimpleAddressDeterminator; - type ComputeDispatchFee = contracts::DefaultDispatchFeeComputor; - type TrieIdGenerator = contracts::TrieIdFromParentCounter; - type GasPayment = (); - type SignedClaimHandicap = SignedClaimHandicap; - type TombstoneDeposit = TombstoneDeposit; - type StorageSizeOffset = StorageSizeOffset; - type RentByteFee = RentByteFee; - type RentDepositOffset = RentDepositOffset; - type SurchargeReward = SurchargeReward; - type TransferFee = ContractTransferFee; - type CreationFee = ContractCreationFee; - type TransactionBaseFee = ContractTransactionBaseFee; - type TransactionByteFee = ContractTransactionByteFee; - type ContractFee = ContractFee; - type CallBaseFee = CallBaseFee; - type CreateBaseFee = CreateBaseFee; - type MaxDepth = MaxDepth; - type BlockGasLimit = BlockGasLimit; + type Currency = Balances; + type Call = Call; + type Event = Event; + type DetermineContractAddress = contracts::SimpleAddressDeterminator; + type ComputeDispatchFee = contracts::DefaultDispatchFeeComputor; + type TrieIdGenerator = contracts::TrieIdFromParentCounter; + type GasPayment = (); + type SignedClaimHandicap = SignedClaimHandicap; + type TombstoneDeposit = TombstoneDeposit; + type StorageSizeOffset = StorageSizeOffset; + type RentByteFee = RentByteFee; + type RentDepositOffset = RentDepositOffset; + type SurchargeReward = SurchargeReward; + type TransferFee = ContractTransferFee; + type CreationFee = ContractCreationFee; + type TransactionBaseFee = ContractTransactionBaseFee; + type TransactionByteFee = ContractTransactionByteFee; + type ContractFee = ContractFee; + type CallBaseFee = CallBaseFee; + type CreateBaseFee = CreateBaseFee; + type MaxDepth = MaxDepth; + type BlockGasLimit = BlockGasLimit; } impl sudo::Trait for Runtime { - type Event = Event; - type Proposal = Call; + type Event = Event; + type Proposal = Call; } impl grandpa::Trait for Runtime { - type Event = Event; + type Event = Event; } parameter_types! { - pub const WindowSize: BlockNumber = DEFAULT_WINDOW_SIZE.into(); - pub const ReportLatency: BlockNumber = DEFAULT_REPORT_LATENCY.into(); + pub const WindowSize: BlockNumber = DEFAULT_WINDOW_SIZE.into(); + pub const ReportLatency: BlockNumber = DEFAULT_REPORT_LATENCY.into(); } impl finality_tracker::Trait for Runtime { - type OnFinalizationStalled = Grandpa; - type WindowSize = WindowSize; - type ReportLatency = ReportLatency; + type OnFinalizationStalled = Grandpa; + type WindowSize = WindowSize; + type ReportLatency = ReportLatency; } construct_runtime!( @@ -361,84 +354,84 @@ pub type CheckedExtrinsic = generic::CheckedExtrinsic; pub type Executive = executive::Executive, Balances, Runtime, AllModules>; impl_runtime_apis! { - impl client_api::Core for Runtime { - fn version() -> RuntimeVersion { - VERSION - } - - fn execute_block(block: Block) { - Executive::execute_block(block) - } - - fn initialize_block(header: &::Header) { - Executive::initialize_block(header) - } - } - - impl client_api::Metadata for Runtime { - fn metadata() -> OpaqueMetadata { - Runtime::metadata().into() - } - } - - impl block_builder_api::BlockBuilder for Runtime { - fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyResult { - Executive::apply_extrinsic(extrinsic) - } - - fn finalize_block() -> ::Header { - Executive::finalize_block() - } - - fn inherent_extrinsics(data: InherentData) -> Vec<::Extrinsic> { - data.create_extrinsics() - } - - fn check_inherents(block: Block, data: InherentData) -> CheckInherentsResult { - data.check_extrinsics(&block) - } - - fn random_seed() -> ::Hash { - System::random_seed() - } - } - - impl client_api::TaggedTransactionQueue for Runtime { - fn validate_transaction(tx: ::Extrinsic) -> TransactionValidity { - Executive::validate_transaction(tx) - } - } - - impl offchain_primitives::OffchainWorkerApi for Runtime { - fn offchain_worker(number: NumberFor) { - Executive::offchain_worker(number) - } - } - - impl fg_primitives::GrandpaApi for Runtime { - fn grandpa_pending_change(digest: &DigestFor) - -> Option>> - { - Grandpa::pending_change(digest) - } - - fn grandpa_forced_change(digest: &DigestFor) - -> Option<(NumberFor, ScheduledChange>)> - { - Grandpa::forced_change(digest) - } - - fn grandpa_authorities() -> Vec<(GrandpaId, GrandpaWeight)> { - Grandpa::grandpa_authorities() - } - } - - impl consensus_aura::AuraApi for Runtime { - fn slot_duration() -> u64 { - Aura::slot_duration() - } - fn authorities() -> Vec { - Aura::authorities() - } - } + impl client_api::Core for Runtime { + fn version() -> RuntimeVersion { + VERSION + } + + fn execute_block(block: Block) { + Executive::execute_block(block) + } + + fn initialize_block(header: &::Header) { + Executive::initialize_block(header) + } + } + + impl client_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + Runtime::metadata().into() + } + } + + impl block_builder_api::BlockBuilder for Runtime { + fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyResult { + Executive::apply_extrinsic(extrinsic) + } + + fn finalize_block() -> ::Header { + Executive::finalize_block() + } + + fn inherent_extrinsics(data: InherentData) -> Vec<::Extrinsic> { + data.create_extrinsics() + } + + fn check_inherents(block: Block, data: InherentData) -> CheckInherentsResult { + data.check_extrinsics(&block) + } + + fn random_seed() -> ::Hash { + System::random_seed() + } + } + + impl client_api::TaggedTransactionQueue for Runtime { + fn validate_transaction(tx: ::Extrinsic) -> TransactionValidity { + Executive::validate_transaction(tx) + } + } + + impl offchain_primitives::OffchainWorkerApi for Runtime { + fn offchain_worker(number: NumberFor) { + Executive::offchain_worker(number) + } + } + + impl fg_primitives::GrandpaApi for Runtime { + fn grandpa_pending_change(digest: &DigestFor) + -> Option>> + { + Grandpa::pending_change(digest) + } + + fn grandpa_forced_change(digest: &DigestFor) + -> Option<(NumberFor, ScheduledChange>)> + { + Grandpa::forced_change(digest) + } + + fn grandpa_authorities() -> Vec<(GrandpaId, GrandpaWeight)> { + Grandpa::grandpa_authorities() + } + } + + impl consensus_aura::AuraApi for Runtime { + fn slot_duration() -> u64 { + Aura::slot_duration() + } + fn authorities() -> Vec { + Aura::authorities() + } + } } diff --git a/node/src/main.rs b/node/src/main.rs index 2d69f0244..1461c18cb 100644 --- a/node/src/main.rs +++ b/node/src/main.rs @@ -27,35 +27,40 @@ use std::cell::RefCell; // handles ctrl-c struct Exit; impl cli::IntoExit for Exit { - type Exit = future::MapErr, fn(oneshot::Canceled) -> ()>; - fn into_exit(self) -> Self::Exit { - // can't use signal directly here because CtrlC takes only `Fn`. - let (exit_send, exit) = oneshot::channel(); - - let exit_send_cell = RefCell::new(Some(exit_send)); - ctrlc::set_handler(move || { - if let Some(exit_send) = exit_send_cell.try_borrow_mut().expect("signal handler not reentrant; qed").take() { - exit_send.send(()).expect("Error sending exit notification"); - } - }).expect("Error setting Ctrl-C handler"); - - exit.map_err(drop) - } + type Exit = future::MapErr, fn(oneshot::Canceled) -> ()>; + fn into_exit(self) -> Self::Exit { + // can't use signal directly here because CtrlC takes only `Fn`. + let (exit_send, exit) = oneshot::channel(); + + let exit_send_cell = RefCell::new(Some(exit_send)); + ctrlc::set_handler(move || { + if let Some(exit_send) = exit_send_cell + .try_borrow_mut() + .expect("signal handler not reentrant; qed") + .take() + { + exit_send.send(()).expect("Error sending exit notification"); + } + }) + .expect("Error setting Ctrl-C handler"); + + exit.map_err(drop) + } } fn main() { - let version = VersionInfo { - name: "Darwinia Crayfish Node", - commit: env!("VERGEN_SHA_SHORT"), - version: env!("CARGO_PKG_VERSION"), - executable_name: "darwinia", - author: "Darwinia Network ", - description: "Darwinia poc-1 node", - support_url: "https://github.com/darwinia-network/darwinia/issues/new", - }; - - if let Err(e) = cli::run(::std::env::args(), Exit, version) { - eprintln!("Error starting the node: {}\n\n{:?}", e, e); - std::process::exit(1) - } + let version = VersionInfo { + name: "Darwinia Crayfish Node", + commit: env!("VERGEN_SHA_SHORT"), + version: env!("CARGO_PKG_VERSION"), + executable_name: "darwinia", + author: "Darwinia Network ", + description: "Darwinia poc-1 node", + support_url: "https://github.com/darwinia-network/darwinia/issues/new", + }; + + if let Err(e) = cli::run(::std::env::args(), Exit, version) { + eprintln!("Error starting the node: {}\n\n{:?}", e, e); + std::process::exit(1) + } } diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 000000000..0527f6291 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,5 @@ +max_width = 120 +tab_spaces = 4 +reorder_imports = true +reorder_modules = true +use_try_shorthand = true \ No newline at end of file diff --git a/srml/aura/src/lib.rs b/srml/aura/src/lib.rs index 11a4b3229..14ff8d449 100644 --- a/srml/aura/src/lib.rs +++ b/srml/aura/src/lib.rs @@ -50,19 +50,22 @@ pub use timestamp; -use rstd::{result, prelude::*}; -use parity_codec::Encode; -use srml_support::{decl_storage, decl_module, Parameter, storage::StorageValue}; -use primitives::{traits::{SaturatedConversion, Saturating, Zero, One, Member}, generic::DigestItem}; -use timestamp::OnTimestampSet; -#[cfg(feature = "std")] -use timestamp::TimestampInherentData; -use inherents::{RuntimeString, InherentIdentifier, InherentData, ProvideInherent, MakeFatalError}; +use inherents::{InherentData, InherentIdentifier, MakeFatalError, ProvideInherent, RuntimeString}; #[cfg(feature = "std")] use inherents::{InherentDataProviders, ProvideInherentData}; -use substrate_consensus_aura_primitives::{AURA_ENGINE_ID, ConsensusLog}; #[cfg(feature = "std")] use parity_codec::Decode; +use parity_codec::Encode; +use primitives::{ + generic::DigestItem, + traits::{Member, One, SaturatedConversion, Saturating, Zero}, +}; +use rstd::{prelude::*, result}; +use srml_support::{decl_module, decl_storage, storage::StorageValue, Parameter}; +use substrate_consensus_aura_primitives::{ConsensusLog, AURA_ENGINE_ID}; +use timestamp::OnTimestampSet; +#[cfg(feature = "std")] +use timestamp::TimestampInherentData; mod mock; //mod tests; @@ -75,243 +78,234 @@ pub type InherentType = u64; /// Auxiliary trait to extract Aura inherent data. pub trait AuraInherentData { - /// Get aura inherent data. - fn aura_inherent_data(&self) -> result::Result; - /// Replace aura inherent data. - fn aura_replace_inherent_data(&mut self, new: InherentType); + /// Get aura inherent data. + fn aura_inherent_data(&self) -> result::Result; + /// Replace aura inherent data. + fn aura_replace_inherent_data(&mut self, new: InherentType); } impl AuraInherentData for InherentData { - fn aura_inherent_data(&self) -> result::Result { - self.get_data(&INHERENT_IDENTIFIER) - .and_then(|r| r.ok_or_else(|| "Aura inherent data not found".into())) - } - - fn aura_replace_inherent_data(&mut self, new: InherentType) { - self.replace_data(INHERENT_IDENTIFIER, &new); - } + fn aura_inherent_data(&self) -> result::Result { + self.get_data(&INHERENT_IDENTIFIER) + .and_then(|r| r.ok_or_else(|| "Aura inherent data not found".into())) + } + + fn aura_replace_inherent_data(&mut self, new: InherentType) { + self.replace_data(INHERENT_IDENTIFIER, &new); + } } /// Provides the slot duration inherent data for `Aura`. #[cfg(feature = "std")] pub struct InherentDataProvider { - slot_duration: u64, + slot_duration: u64, } #[cfg(feature = "std")] impl InherentDataProvider { - pub fn new(slot_duration: u64) -> Self { - Self { - slot_duration - } - } + pub fn new(slot_duration: u64) -> Self { + Self { slot_duration } + } } #[cfg(feature = "std")] impl ProvideInherentData for InherentDataProvider { - fn on_register( - &self, - providers: &InherentDataProviders, - ) -> result::Result<(), RuntimeString> { - if !providers.has_provider(×tamp::INHERENT_IDENTIFIER) { - // Add the timestamp inherent data provider, as we require it. - providers.register_provider(timestamp::InherentDataProvider) - } else { - Ok(()) - } - } - - fn inherent_identifier(&self) -> &'static inherents::InherentIdentifier { - &INHERENT_IDENTIFIER - } - - fn provide_inherent_data( - &self, - inherent_data: &mut InherentData, - ) -> result::Result<(), RuntimeString> { - let timestamp = inherent_data.timestamp_inherent_data()?; - let slot_num = timestamp / self.slot_duration; - inherent_data.put_data(INHERENT_IDENTIFIER, &slot_num) - } - - fn error_to_string(&self, error: &[u8]) -> Option { - RuntimeString::decode(&mut &error[..]).map(Into::into) - } + fn on_register(&self, providers: &InherentDataProviders) -> result::Result<(), RuntimeString> { + if !providers.has_provider(×tamp::INHERENT_IDENTIFIER) { + // Add the timestamp inherent data provider, as we require it. + providers.register_provider(timestamp::InherentDataProvider) + } else { + Ok(()) + } + } + + fn inherent_identifier(&self) -> &'static inherents::InherentIdentifier { + &INHERENT_IDENTIFIER + } + + fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> result::Result<(), RuntimeString> { + let timestamp = inherent_data.timestamp_inherent_data()?; + let slot_num = timestamp / self.slot_duration; + inherent_data.put_data(INHERENT_IDENTIFIER, &slot_num) + } + + fn error_to_string(&self, error: &[u8]) -> Option { + RuntimeString::decode(&mut &error[..]).map(Into::into) + } } /// Something that can handle Aura consensus reports. pub trait HandleReport { - fn handle_report(report: AuraReport); + fn handle_report(report: AuraReport); } impl HandleReport for () { - fn handle_report(_report: AuraReport) { } + fn handle_report(_report: AuraReport) {} } pub trait Trait: timestamp::Trait { - /// The logic for handling reports. - type HandleReport: HandleReport; + /// The logic for handling reports. + type HandleReport: HandleReport; - /// The identifier type for an authority. - type AuthorityId: Member + Parameter + Default; + /// The identifier type for an authority. + type AuthorityId: Member + Parameter + Default; } decl_storage! { - trait Store for Module as Aura { - /// The last timestamp. - LastTimestamp get(last) build(|_| 0.into()): T::Moment; + trait Store for Module as Aura { + /// The last timestamp. + LastTimestamp get(last) build(|_| 0.into()): T::Moment; - /// The current authorities - pub Authorities get(authorities) config(): Vec; - } + /// The current authorities + pub Authorities get(authorities) config(): Vec; + } } decl_module! { - pub struct Module for enum Call where origin: T::Origin { } + pub struct Module for enum Call where origin: T::Origin { } } impl Module { - fn change_authorities(new: Vec) { - >::put(&new); - - let log: DigestItem = DigestItem::Consensus( - AURA_ENGINE_ID, - ConsensusLog::AuthoritiesChange(new).encode() - ); - >::deposit_log(log.into()); - } + fn change_authorities(new: Vec) { + >::put(&new); + + let log: DigestItem = + DigestItem::Consensus(AURA_ENGINE_ID, ConsensusLog::AuthoritiesChange(new).encode()); + >::deposit_log(log.into()); + } } impl session::OneSessionHandler for Module { - type Key = T::AuthorityId; - fn on_new_session<'a, I: 'a>(changed: bool, validators: I) - where I: Iterator - { - // instant changes - if changed { - let next_authorities = validators.map(|(_, k)| k).collect::>(); - let last_authorities = >::authorities(); - if next_authorities != last_authorities { - Self::change_authorities(next_authorities); - } - } - } - fn on_disabled(_i: usize) { - // ignore? - } + type Key = T::AuthorityId; + fn on_new_session<'a, I: 'a>(changed: bool, validators: I) + where + I: Iterator, + { + // instant changes + if changed { + let next_authorities = validators.map(|(_, k)| k).collect::>(); + let last_authorities = >::authorities(); + if next_authorities != last_authorities { + Self::change_authorities(next_authorities); + } + } + } + fn on_disabled(_i: usize) { + // ignore? + } } /// A report of skipped authorities in Aura. #[derive(Clone, PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Debug))] pub struct AuraReport { - // The first skipped slot. - start_slot: usize, - // The number of times authorities were skipped. - skipped: usize, + // The first skipped slot. + start_slot: usize, + // The number of times authorities were skipped. + skipped: usize, } impl AuraReport { - /// Call the closure with (`validator_indices`, `punishment_count`) for each - /// validator to punish. - pub fn punish(&self, validator_count: usize, mut punish_with: F) - where F: FnMut(usize, usize) - { - // If all validators have been skipped, then it implies some sort of - // systematic problem common to all rather than a minority of validators - // not fulfilling their specific duties. In this case, it doesn't make - // sense to punish anyone, so we guard against it. - if self.skipped < validator_count { - for index in 0..self.skipped { - punish_with((self.start_slot + index) % validator_count, 1); - } - } else { - runtime_io::print("ALL validators SKIP"); - } - } + /// Call the closure with (`validator_indices`, `punishment_count`) for each + /// validator to punish. + pub fn punish(&self, validator_count: usize, mut punish_with: F) + where + F: FnMut(usize, usize), + { + // If all validators have been skipped, then it implies some sort of + // systematic problem common to all rather than a minority of validators + // not fulfilling their specific duties. In this case, it doesn't make + // sense to punish anyone, so we guard against it. + if self.skipped < validator_count { + for index in 0..self.skipped { + punish_with((self.start_slot + index) % validator_count, 1); + } + } else { + runtime_io::print("ALL validators SKIP"); + } + } } impl Module { - /// Determine the Aura slot-duration based on the Timestamp module configuration. - pub fn slot_duration() -> T::Moment { - // we double the minimum block-period so each author can always propose within - // the majority of its slot. - >::minimum_period().saturating_mul(2.into()) - } - - fn on_timestamp_set(now: T::Moment, slot_duration: T::Moment) { - let last = Self::last(); - ::LastTimestamp::put(now.clone()); - - if last.is_zero() { - return; - } - - assert!(!slot_duration.is_zero(), "Aura slot duration cannot be zero."); - - let last_slot = last / slot_duration.clone(); - let first_skipped = last_slot.clone() + One::one(); - let cur_slot = now / slot_duration; - - assert!(last_slot < cur_slot, "Only one block may be authored per slot."); - if cur_slot == first_skipped { return } - - let skipped_slots = cur_slot - last_slot - One::one(); - - H::handle_report(AuraReport { - start_slot: first_skipped.saturated_into::(), - skipped: skipped_slots.saturated_into::(), - }) - } + /// Determine the Aura slot-duration based on the Timestamp module configuration. + pub fn slot_duration() -> T::Moment { + // we double the minimum block-period so each author can always propose within + // the majority of its slot. + >::minimum_period().saturating_mul(2.into()) + } + + fn on_timestamp_set(now: T::Moment, slot_duration: T::Moment) { + let last = Self::last(); + ::LastTimestamp::put(now.clone()); + + if last.is_zero() { + return; + } + + assert!(!slot_duration.is_zero(), "Aura slot duration cannot be zero."); + + let last_slot = last / slot_duration.clone(); + let first_skipped = last_slot.clone() + One::one(); + let cur_slot = now / slot_duration; + + assert!(last_slot < cur_slot, "Only one block may be authored per slot."); + if cur_slot == first_skipped { + return; + } + + let skipped_slots = cur_slot - last_slot - One::one(); + + H::handle_report(AuraReport { + start_slot: first_skipped.saturated_into::(), + skipped: skipped_slots.saturated_into::(), + }) + } } impl OnTimestampSet for Module { - fn on_timestamp_set(moment: T::Moment) { - Self::on_timestamp_set::(moment, Self::slot_duration()) - } + fn on_timestamp_set(moment: T::Moment) { + Self::on_timestamp_set::(moment, Self::slot_duration()) + } } /// A type for performing slashing based on Aura reports. pub struct StakingSlasher(::rstd::marker::PhantomData); impl HandleReport for StakingSlasher { - fn handle_report(report: AuraReport) { - let validators = session::Module::::validators(); - runtime_io::print("OFFLINE REPORT"); - report.punish( - validators.len(), - |idx, slash_count| { - let v = validators[idx].clone(); - staking::Module::::on_offline_validator(v, slash_count); - } - ); - } + fn handle_report(report: AuraReport) { + let validators = session::Module::::validators(); + runtime_io::print("OFFLINE REPORT"); + report.punish(validators.len(), |idx, slash_count| { + let v = validators[idx].clone(); + staking::Module::::on_offline_validator(v, slash_count); + }); + } } impl ProvideInherent for Module { - type Call = timestamp::Call; - type Error = MakeFatalError; - const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; - - fn create_inherent(_: &InherentData) -> Option { - None - } - - /// Verify the validity of the inherent using the timestamp. - fn check_inherent(call: &Self::Call, data: &InherentData) -> result::Result<(), Self::Error> { - let timestamp = match call { - timestamp::Call::set(ref timestamp) => timestamp.clone(), - _ => return Ok(()), - }; - - let timestamp_based_slot = timestamp / Self::slot_duration(); - - let seal_slot = data.aura_inherent_data()?.saturated_into(); - - if timestamp_based_slot == seal_slot { - Ok(()) - } else { - Err(RuntimeString::from("timestamp set in block doesn't match slot in seal").into()) - } - } + type Call = timestamp::Call; + type Error = MakeFatalError; + const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; + + fn create_inherent(_: &InherentData) -> Option { + None + } + + /// Verify the validity of the inherent using the timestamp. + fn check_inherent(call: &Self::Call, data: &InherentData) -> result::Result<(), Self::Error> { + let timestamp = match call { + timestamp::Call::set(ref timestamp) => timestamp.clone(), + _ => return Ok(()), + }; + + let timestamp_based_slot = timestamp / Self::slot_duration(); + + let seal_slot = data.aura_inherent_data()?.saturated_into(); + + if timestamp_based_slot == seal_slot { + Ok(()) + } else { + Err(RuntimeString::from("timestamp set in block doesn't match slot in seal").into()) + } + } } diff --git a/srml/aura/src/mock.rs b/srml/aura/src/mock.rs index 900ef21b3..d9f7bfd11 100644 --- a/srml/aura/src/mock.rs +++ b/srml/aura/src/mock.rs @@ -18,14 +18,17 @@ #![cfg(test)] -use primitives::{traits::IdentityLookup, testing::{Header, UintAuthorityId}}; -use srml_support::impl_outer_origin; +use crate::{GenesisConfig, Module, Trait}; +use primitives::{ + testing::{Header, UintAuthorityId}, + traits::IdentityLookup, +}; use runtime_io; -use substrate_primitives::{H256, Blake2Hasher}; -use crate::{Trait, Module, GenesisConfig}; +use srml_support::impl_outer_origin; +use substrate_primitives::{Blake2Hasher, H256}; -impl_outer_origin!{ - pub enum Origin for Test {} +impl_outer_origin! { + pub enum Origin for Test {} } // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. @@ -33,36 +36,44 @@ impl_outer_origin!{ pub struct Test; impl system::Trait for Test { - type Origin = Origin; - type Index = u64; - type BlockNumber = u64; - type Hash = H256; - type Hashing = ::primitives::traits::BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type Header = Header; - type Event = (); + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = ::primitives::traits::BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = (); } impl timestamp::Trait for Test { - type Moment = u64; - type OnTimestampSet = Aura; + type Moment = u64; + type OnTimestampSet = Aura; } impl Trait for Test { - type HandleReport = (); - type AuthorityId = UintAuthorityId; + type HandleReport = (); + type AuthorityId = UintAuthorityId; } pub fn new_test_ext(authorities: Vec) -> runtime_io::TestExternalities { - let mut t = system::GenesisConfig::default().build_storage::().unwrap().0; - t.extend(timestamp::GenesisConfig::{ - minimum_period: 1, - }.build_storage().unwrap().0); - t.extend(GenesisConfig::{ - authorities: authorities.into_iter().map(|a| UintAuthorityId(a)).collect(), - }.build_storage().unwrap().0); - t.into() + let mut t = system::GenesisConfig::default().build_storage::().unwrap().0; + t.extend( + timestamp::GenesisConfig:: { minimum_period: 1 } + .build_storage() + .unwrap() + .0, + ); + t.extend( + GenesisConfig:: { + authorities: authorities.into_iter().map(|a| UintAuthorityId(a)).collect(), + } + .build_storage() + .unwrap() + .0, + ); + t.into() } pub type System = system::Module; diff --git a/srml/kton/src/imbalance.rs b/srml/kton/src/imbalance.rs index 2f4a9d7c6..b9bd11662 100644 --- a/srml/kton/src/imbalance.rs +++ b/srml/kton/src/imbalance.rs @@ -1,9 +1,7 @@ - //TODO: move this into lib.rs to be a inner mod -use super::{result, Imbalance, Trait, Zero, Saturating, StorageValue}; +use super::{result, Imbalance, Saturating, StorageValue, Trait, Zero}; use rstd::mem; - pub struct PositiveImbalance(T::Balance); impl PositiveImbalance { @@ -113,17 +111,13 @@ impl Imbalance for NegativeImbalance { impl Drop for PositiveImbalance { /// Basic drop handler will just square up the total issuance. fn drop(&mut self) { - >::mutate( - |v| *v = v.saturating_add(self.0) - ); + >::mutate(|v| *v = v.saturating_add(self.0)); } } impl Drop for NegativeImbalance { /// Basic drop handler will just square up the total issuance. fn drop(&mut self) { - >::mutate( - |v| *v = v.saturating_sub(self.0) - ); + >::mutate(|v| *v = v.saturating_sub(self.0)); } -} \ No newline at end of file +} diff --git a/srml/kton/src/lib.rs b/srml/kton/src/lib.rs index 21249be5c..d221c8f5a 100644 --- a/srml/kton/src/lib.rs +++ b/srml/kton/src/lib.rs @@ -2,19 +2,17 @@ use parity_codec::{Codec, Decode, Encode}; use primitives::traits::{ - Bounded, CheckedAdd, CheckedSub, MaybeSerializeDebug, Member, Saturating, - SimpleArithmetic, StaticLookup, Zero, + Bounded, CheckedAdd, CheckedSub, MaybeSerializeDebug, Member, Saturating, SimpleArithmetic, StaticLookup, Zero, }; -use rstd::{cmp, result}; use rstd::prelude::*; +use rstd::{cmp, result}; -use srml_support::{decl_event, decl_module, decl_storage, Parameter, StorageMap, StorageValue}; use srml_support::dispatch::Result; use srml_support::traits::{ - Currency, ExistenceRequirement, Imbalance, LockableCurrency, LockIdentifier, - OnUnbalanced, SignedImbalance, UpdateBalanceOutcome, - WithdrawReason, WithdrawReasons, + Currency, ExistenceRequirement, Imbalance, LockIdentifier, LockableCurrency, OnUnbalanced, SignedImbalance, + UpdateBalanceOutcome, WithdrawReason, WithdrawReasons, }; +use srml_support::{decl_event, decl_module, decl_storage, Parameter, StorageMap, StorageValue}; use system::ensure_signed; // customed @@ -41,7 +39,8 @@ pub struct VestingSchedule { impl VestingSchedule { /// Amount locked at block `n`. pub fn locked_at(&self, n: BlockNumber) -> Balance - where Balance: From + where + Balance: From, { if let Some(x) = Balance::from(n).checked_mul(&self.per_block) { self.offset.max(x) - x @@ -61,8 +60,14 @@ pub struct BalanceLock { } pub trait Trait: timestamp::Trait { - type Balance: Parameter + Member + SimpleArithmetic + Codec + Default + Copy + - MaybeSerializeDebug + From; + type Balance: Parameter + + Member + + SimpleArithmetic + + Codec + + Default + + Copy + + MaybeSerializeDebug + + From; type Event: From> + Into<::Event>; @@ -81,48 +86,47 @@ decl_event!( } ); - decl_storage! { - trait Store for Module as Kton { + trait Store for Module as Kton { /// For Currency and LockableCurrency Trait - /// The total `units issued in the system. - // like `existential_deposit`, but always set to 0 - pub MinimumBalance get(minimum_balance): T::Balance = 0.into(); + /// The total `units issued in the system. + // like `existential_deposit`, but always set to 0 + pub MinimumBalance get(minimum_balance): T::Balance = 0.into(); - pub TotalIssuance get(total_issuance) build(|config: &GenesisConfig| { - config.balances.iter().fold(Zero::zero(), |acc: T::Balance, &(_, n)| acc + n) - }): T::Balance; + pub TotalIssuance get(total_issuance) build(|config: &GenesisConfig| { + config.balances.iter().fold(Zero::zero(), |acc: T::Balance, &(_, n)| acc + n) + }): T::Balance; - pub FreeBalance get(free_balance) build(|config: &GenesisConfig| config.balances.clone()): - map T::AccountId => T::Balance; + pub FreeBalance get(free_balance) build(|config: &GenesisConfig| config.balances.clone()): + map T::AccountId => T::Balance; - pub ReservedBalance get(reserved_balance): map T::AccountId => T::Balance; + pub ReservedBalance get(reserved_balance): map T::AccountId => T::Balance; - pub Locks get(locks): map T::AccountId => Vec>; + pub Locks get(locks): map T::AccountId => Vec>; - pub TotalLock get(total_lock): T::Balance; + pub TotalLock get(total_lock): T::Balance; - pub Vesting get(vesting) build(|config: &GenesisConfig| { - config.vesting.iter().filter_map(|&(ref who, begin, length)| { - let begin = >::from(begin); - let length = >::from(length); + pub Vesting get(vesting) build(|config: &GenesisConfig| { + config.vesting.iter().filter_map(|&(ref who, begin, length)| { + let begin = >::from(begin); + let length = >::from(length); - config.balances.iter() - .find(|&&(ref w, _)| w == who) - .map(|&(_, balance)| { - // <= begin it should be >= balance - // >= begin+length it should be <= 0 + config.balances.iter() + .find(|&&(ref w, _)| w == who) + .map(|&(_, balance)| { + // <= begin it should be >= balance + // >= begin+length it should be <= 0 - let per_block = balance / length.max(primitives::traits::One::one()); - let offset = begin * per_block + balance; + let per_block = balance / length.max(primitives::traits::One::one()); + let offset = begin * per_block + balance; - (who.clone(), VestingSchedule { offset, per_block }) - }) - }).collect::>() - }): map T::AccountId => Option>; - } - add_extra_genesis { + (who.clone(), VestingSchedule { offset, per_block }) + }) + }).collect::>() + }): map T::AccountId => Option>; + } + add_extra_genesis { config(balances): Vec<(T::AccountId, T::Balance)>; config(vesting): Vec<(T::AccountId, T::BlockNumber, T::BlockNumber)>; // begin, length } @@ -134,10 +138,10 @@ decl_module! { pub fn transfer(origin, dest: ::Source, - #[compact] value: T::Balance - ) { - let transactor = ensure_signed(origin)?; - let dest = T::Lookup::lookup(dest)?; + #[compact] value: T::Balance + ) { + let transactor = ensure_signed(origin)?; + let dest = T::Lookup::lookup(dest)?; >::transfer(&transactor, &dest, value)?; } @@ -147,14 +151,12 @@ decl_module! { impl Module { pub fn vesting_balance(who: &T::AccountId) -> T::Balance { if let Some(v) = Self::vesting(who) { - Self::free_balance(who) - .min(v.locked_at::(>::block_number())) + Self::free_balance(who).min(v.locked_at::(>::block_number())) } else { Zero::zero() } } - // PRIVATE MUTABLE // NOTE: different from balances module fn set_free_balance(who: &T::AccountId, balance: T::Balance) -> UpdateBalanceOutcome { @@ -169,7 +171,6 @@ impl Module { } } - impl Currency for Module { type Balance = T::Balance; type PositiveImbalance = PositiveImbalance; @@ -202,8 +203,9 @@ impl Currency for Module { new_balance: T::Balance, ) -> Result { match reason { - WithdrawReason::Reserve | WithdrawReason::Transfer if Self::vesting_balance(who) > new_balance => - return Err("vesting balance too high to send value"), + WithdrawReason::Reserve | WithdrawReason::Transfer if Self::vesting_balance(who) > new_balance => { + return Err("vesting balance too high to send value") + } _ => {} } let locks = Self::locks(who); @@ -212,12 +214,9 @@ impl Currency for Module { } let now = >::block_number(); - if locks.into_iter() - .all(|l| - now >= l.until - || new_balance >= l.amount - || !l.reasons.contains(reason) - ) + if locks + .into_iter() + .all(|l| now >= l.until || new_balance >= l.amount || !l.reasons.contains(reason)) { Ok(()) } else { @@ -225,7 +224,6 @@ impl Currency for Module { } } - // TODO: add fee fn transfer(transactor: &T::AccountId, dest: &T::AccountId, value: Self::Balance) -> Result { let from_balance = Self::free_balance(transactor); @@ -254,7 +252,6 @@ impl Currency for Module { Ok(()) } - fn withdraw( who: &T::AccountId, value: Self::Balance, @@ -275,11 +272,7 @@ impl Currency for Module { } } - - fn slash( - who: &T::AccountId, - value: Self::Balance, - ) -> (Self::NegativeImbalance, Self::Balance) { + fn slash(who: &T::AccountId, value: Self::Balance) -> (Self::NegativeImbalance, Self::Balance) { let free_balance = Self::free_balance(who); let free_slash = cmp::min(free_balance, value); @@ -292,7 +285,10 @@ impl Currency for Module { let reserved_balance = Self::reserved_balance(who); let reserved_slash = cmp::min(reserved_balance, remaining_slash); Self::set_reserved_balance(who, reserved_balance - reserved_slash); - (NegativeImbalance::new(free_slash + reserved_slash), remaining_slash - reserved_slash) + ( + NegativeImbalance::new(free_slash + reserved_slash), + remaining_slash - reserved_slash, + ) } else { (NegativeImbalance::new(value), Zero::zero()) } @@ -305,7 +301,7 @@ impl Currency for Module { if Self::total_balance(who).is_zero() { return Err("beneficiary account must pre-exist"); } - //add here + //add here let old_balance = Self::free_balance(who); let new_balance = old_balance + value; @@ -313,11 +309,7 @@ impl Currency for Module { Ok(PositiveImbalance::new(value)) } - fn deposit_creating( - who: &T::AccountId, - value: Self::Balance, - ) -> Self::PositiveImbalance { - + fn deposit_creating(who: &T::AccountId, value: Self::Balance) -> Self::PositiveImbalance { let old_balance = Self::free_balance(who); let new_balance = old_balance + value; @@ -331,9 +323,12 @@ impl Currency for Module { } } - fn make_free_balance_be(who: &T::AccountId, balance: Self::Balance) -> ( + fn make_free_balance_be( + who: &T::AccountId, + balance: Self::Balance, + ) -> ( SignedImbalance, - UpdateBalanceOutcome + UpdateBalanceOutcome, ) { let original = Self::free_balance(who); @@ -353,31 +348,30 @@ impl Currency for Module { // TODO: ready for hacking fn burn(mut amount: Self::Balance) -> Self::PositiveImbalance { - >::mutate(|issued| + >::mutate(|issued| { issued.checked_sub(&amount).unwrap_or_else(|| { amount = *issued; Zero::zero() }) - ); + }); PositiveImbalance::new(amount) } // TODO: ready for hacking fn issue(mut amount: Self::Balance) -> Self::NegativeImbalance { - >::mutate(|issued| + >::mutate(|issued| { *issued = issued.checked_add(&amount).unwrap_or_else(|| { amount = Self::Balance::max_value() - *issued; Self::Balance::max_value() }) - ); + }); NegativeImbalance::new(amount) } } - impl LockableCurrency for Module - where - T::Balance: MaybeSerializeDebug +where + T::Balance: MaybeSerializeDebug, { type Moment = T::BlockNumber; @@ -389,15 +383,24 @@ impl LockableCurrency for Module reasons: WithdrawReasons, ) { let now = >::block_number(); - let mut new_lock = Some(BalanceLock { id, amount, until, reasons }); - let mut locks = Self::locks(who).into_iter().filter_map(|l| - if l.id == id { - new_lock.take() - } else if l.until > now { - Some(l) - } else { - None - }).collect::>(); + let mut new_lock = Some(BalanceLock { + id, + amount, + until, + reasons, + }); + let mut locks = Self::locks(who) + .into_iter() + .filter_map(|l| { + if l.id == id { + new_lock.take() + } else if l.until > now { + Some(l) + } else { + None + } + }) + .collect::>(); if let Some(lock) = new_lock { locks.push(lock) } @@ -412,40 +415,41 @@ impl LockableCurrency for Module reasons: WithdrawReasons, ) { let now = >::block_number(); - let mut new_lock = Some(BalanceLock { id, amount, until, reasons }); - let mut locks = Self::locks(who).into_iter().filter_map(|l| - if l.id == id { - new_lock.take().map(|nl| { - BalanceLock { + let mut new_lock = Some(BalanceLock { + id, + amount, + until, + reasons, + }); + let mut locks = Self::locks(who) + .into_iter() + .filter_map(|l| { + if l.id == id { + new_lock.take().map(|nl| BalanceLock { id: l.id, amount: l.amount.max(nl.amount), until: l.until.max(nl.until), reasons: l.reasons | nl.reasons, - } - }) - } else if l.until > now { - Some(l) - } else { - None - }).collect::>(); + }) + } else if l.until > now { + Some(l) + } else { + None + } + }) + .collect::>(); if let Some(lock) = new_lock { locks.push(lock) } >::insert(who, locks); } - fn remove_lock( - id: LockIdentifier, - who: &T::AccountId, - ) { + fn remove_lock(id: LockIdentifier, who: &T::AccountId) { let now = >::block_number(); - let locks = Self::locks(who).into_iter().filter_map(|l| - if l.until > now && l.id != id { - Some(l) - } else { - None - }).collect::>(); + let locks = Self::locks(who) + .into_iter() + .filter_map(|l| if l.until > now && l.id != id { Some(l) } else { None }) + .collect::>(); >::insert(who, locks); } } - diff --git a/srml/kton/src/mock.rs b/srml/kton/src/mock.rs index 1806b2001..bad7ccd10 100644 --- a/srml/kton/src/mock.rs +++ b/srml/kton/src/mock.rs @@ -1,19 +1,16 @@ - - -use std::{collections::HashSet, cell::RefCell}; -use primitives::Perbill; -use primitives::traits::{IdentityLookup, Convert, OpaqueKeys, OnInitialize}; +use super::*; +use crate::{GenesisConfig, Module}; use primitives::testing::{Header, UintAuthorityId}; -use substrate_primitives::{H256, Blake2Hasher}; +use primitives::traits::{Convert, IdentityLookup, OnInitialize, OpaqueKeys}; +use primitives::Perbill; use runtime_io; -use srml_support::{assert_ok, impl_outer_origin, parameter_types, EnumerableStorageMap}; use srml_support::traits::{Currency, Get}; -use crate::{Module, GenesisConfig }; -use super::*; +use srml_support::{assert_ok, impl_outer_origin, parameter_types, EnumerableStorageMap}; +use std::{cell::RefCell, collections::HashSet}; +use substrate_primitives::{Blake2Hasher, H256}; const COIN: u64 = 1000000000; - /// The AccountId alias in this test module. pub type AccountId = u64; pub type BlockNumber = u64; @@ -22,7 +19,9 @@ pub type Balance = u64; /// Simple structure that exposes how u64 currency can be represented as... u64. pub struct CurrencyToVoteHandler; impl Convert for CurrencyToVoteHandler { - fn convert(x: u64) -> u64 { x } + fn convert(x: u64) -> u64 { + x + } } impl Convert for CurrencyToVoteHandler { fn convert(x: u128) -> u64 { @@ -31,8 +30,8 @@ impl Convert for CurrencyToVoteHandler { } thread_local! { - static SESSION: RefCell<(Vec, HashSet)> = RefCell::new(Default::default()); - static EXISTENTIAL_DEPOSIT: RefCell = RefCell::new(0); + static SESSION: RefCell<(Vec, HashSet)> = RefCell::new(Default::default()); + static EXISTENTIAL_DEPOSIT: RefCell = RefCell::new(0); } pub struct ExistentialDeposit; @@ -42,8 +41,8 @@ impl Get for ExistentialDeposit { } } -impl_outer_origin!{ - pub enum Origin for Test {} +impl_outer_origin! { + pub enum Origin for Test {} } // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. @@ -62,13 +61,11 @@ impl system::Trait for Test { type Event = (); } - impl timestamp::Trait for Test { type Moment = u64; type OnTimestampSet = (); } - impl Trait for Test { type Balance = Balance; type Event = (); @@ -82,9 +79,7 @@ pub struct ExtBuilder { impl Default for ExtBuilder { fn default() -> Self { - Self { - existential_deposit: 0 - } + Self { existential_deposit: 0 } } } @@ -106,7 +101,7 @@ impl ExtBuilder { } else { 1 * COIN }; - let _ = GenesisConfig::{ + let _ = GenesisConfig:: { balances: vec![ (1, 10 * balance_factor), (2, 20 * balance_factor), @@ -124,7 +119,8 @@ impl ExtBuilder { (101, 2000 * balance_factor), ], vesting: vec![], - }.assimilate_storage(&mut t, &mut c); + } + .assimilate_storage(&mut t, &mut c); t.into() } } diff --git a/srml/kton/src/tests.rs b/srml/kton/src/tests.rs index 3f6631e67..640bcdc36 100644 --- a/srml/kton/src/tests.rs +++ b/srml/kton/src/tests.rs @@ -1,31 +1,33 @@ - +use super::*; +use mock::{ExtBuilder, Kton, Origin, System, Test, Timestamp}; use runtime_io::with_externalities; +use srml_support::traits::{ + Currency, ExistenceRequirement, Imbalance, LockIdentifier, WithdrawReason, WithdrawReasons, +}; use srml_support::{assert_err, assert_noop, assert_ok}; -use srml_support::traits::{Currency, ExistenceRequirement, Imbalance, WithdrawReason, WithdrawReasons, LockIdentifier}; -use mock::{ExtBuilder, Kton, Origin, System, Test, Timestamp}; -use super::*; #[test] fn transfer_should_work() { - with_externalities(&mut ExtBuilder::default() - .existential_deposit(0).build(), || { + with_externalities(&mut ExtBuilder::default().existential_deposit(0).build(), || { // Kton::deposit_creating(&1001, 100); - assert_err!(Kton::transfer(Origin::signed(1001), 1000, 500), "balance too low to send value"); + assert_err!( + Kton::transfer(Origin::signed(1001), 1000, 500), + "balance too low to send value" + ); assert_eq!(Kton::free_balance(&1000), 0); - }); } #[test] fn lock_should_work() { - with_externalities(&mut ExtBuilder::default() - .existential_deposit(0).build(), || { - + with_externalities(&mut ExtBuilder::default().existential_deposit(0).build(), || { let lock_id: LockIdentifier = *b"locklock"; Kton::deposit_creating(&1001, 100); Kton::set_lock(lock_id, &1001, 90, u64::max_value(), WithdrawReasons::all()); - assert_err!(Kton::transfer(Origin::signed(1001), 1000, 20), "account liquidity restrictions prevent withdrawal"); + assert_err!( + Kton::transfer(Origin::signed(1001), 1000, 20), + "account liquidity restrictions prevent withdrawal" + ); }); } - diff --git a/srml/staking/src/lib.rs b/srml/staking/src/lib.rs index 3081cf9b1..00dd2e6d7 100644 --- a/srml/staking/src/lib.rs +++ b/srml/staking/src/lib.rs @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . - #![recursion_limit = "128"] #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(all(feature = "bench", test), feature(test))] @@ -22,30 +21,29 @@ #[cfg(all(feature = "bench", test))] extern crate test; - +use parity_codec::{CompactAs, Decode, Encode, HasCompact}; +use primitives::traits::{ + Bounded, CheckedShl, CheckedSub, Convert, One, SaturatedConversion, Saturating, StaticLookup, Zero, +}; +use primitives::Perbill; +#[cfg(feature = "std")] +use primitives::{Deserialize, Serialize}; +use rstd::{collections::btree_map::BTreeMap, prelude::*, result}; #[cfg(feature = "std")] use runtime_io::with_storage; -use rstd::{prelude::*, result, collections::btree_map::BTreeMap}; -use parity_codec::{HasCompact, Encode, Decode, CompactAs}; +use session::{OnSessionEnding, SessionIndex}; use srml_support::{ - StorageValue, StorageMap, EnumerableStorageMap, decl_module, decl_event, - decl_storage, ensure, traits::{ - Currency, OnFreeBalanceZero, LockIdentifier, LockableCurrency, - WithdrawReasons, WithdrawReason, OnUnbalanced, Imbalance, Get, + decl_event, decl_module, decl_storage, ensure, + traits::{ + Currency, Get, Imbalance, LockIdentifier, LockableCurrency, OnFreeBalanceZero, OnUnbalanced, WithdrawReason, + WithdrawReasons, }, + EnumerableStorageMap, StorageMap, StorageValue, }; -use session::{OnSessionEnding, SessionIndex}; -use primitives::Perbill; -use primitives::traits::{Convert, - Zero, One, StaticLookup, CheckedShl, CheckedSub, Saturating, Bounded, SaturatedConversion, -}; -#[cfg(feature = "std")] -use primitives::{Serialize, Deserialize}; use system::ensure_signed; +use phragmen::{elect, equalize, ExtendedBalance, ACCURACY}; use rstd::convert::TryInto; -use phragmen::{ACCURACY, elect, equalize, ExtendedBalance}; - mod utils; @@ -113,10 +111,9 @@ pub enum StakingBalance { Kton(KtonBalance), } -impl< - RingBalance: HasCompact + Copy + Clone, - KtonBalance: HasCompact + Copy + Clone, -> Distinguish for StakingBalance { +impl + Distinguish for StakingBalance +{ fn is_ring(&self) -> (bool, Option) { let res = match self { StakingBalance::Ring(r) => (true, Some(*r)), @@ -125,7 +122,6 @@ impl< res } - fn is_kton(&self) -> (bool, Option) { let res = match self { StakingBalance::Ring(_) => (true, None), @@ -135,9 +131,7 @@ impl< } } -impl< - RingBalance: Default, - KtonBalance: Default> Default for StakingBalance { +impl Default for StakingBalance { fn default() -> Self { StakingBalance::Ring(Default::default()) } @@ -149,7 +143,7 @@ impl< pub enum RewardDestination { /// Pay into the stash account, increasing the amount at stake accordingly. /// for now, we dont use this. -// DeprecatedStaked, + // DeprecatedStaked, /// Pay into the stash account, not increasing the amount at stake. Stash, /// Pay into the controller account. @@ -162,7 +156,6 @@ impl Default for RewardDestination { } } - #[derive(PartialEq, Eq, Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug))] pub struct UnlockChunk { @@ -213,46 +206,61 @@ pub struct StakingLedgers, - Moment -> StakingLedgers { + AccountId, + RingBalance: HasCompact + Copy + Saturating, + KtonBalance: HasCompact + Copy + Saturating, + StakingBalance: Distinguish, + Moment, + > StakingLedgers +{ // fn consolidate_unlocked(self, current_era: EraIndex) -> (Self, u32) { - let mut total_ring = self.total_ring; let mut total_kton = self.total_kton; let mut total_deposit_ring = self.total_deposit_ring; let mut unlock_ring = 0u32; let mut unlock_kton = 0u32; - let unlocking = self.unlocking.into_iter().filter(|chunk| if chunk.era > current_era { - true - } else { - // for ring - let (is_ring, ring_value) = chunk.value.is_ring(); - let(is_kton, kton_value) = chunk.value.is_kton(); - if is_ring { - total_ring = total_ring.saturating_sub(ring_value.unwrap()); - if chunk.is_time_deposit { - total_deposit_ring = total_deposit_ring.saturating_sub(ring_value.unwrap()); + let unlocking = self + .unlocking + .into_iter() + .filter(|chunk| { + if chunk.era > current_era { + true + } else { + // for ring + let (is_ring, ring_value) = chunk.value.is_ring(); + let (is_kton, kton_value) = chunk.value.is_kton(); + if is_ring { + total_ring = total_ring.saturating_sub(ring_value.unwrap()); + if chunk.is_time_deposit { + total_deposit_ring = total_deposit_ring.saturating_sub(ring_value.unwrap()); + } + unlock_ring = 1; + false + } else if is_kton { + total_kton = total_kton.saturating_sub(kton_value.unwrap()); + unlock_kton = 2; + false + } else { + // no ring or kton + // discard it + false + } } - unlock_ring = 1; - false - } else if is_kton { - total_kton = total_kton.saturating_sub(kton_value.unwrap()); - unlock_kton = 2; - false - } else { - // no ring or kton - // discard it - false - } - }).collect(); - - (Self {total_ring, total_kton, unlocking, total_deposit_ring, ..self }, unlock_ring + unlock_kton) + }) + .collect(); + + ( + Self { + total_ring, + total_kton, + unlocking, + total_deposit_ring, + ..self + }, + unlock_ring + unlock_kton, + ) } } @@ -278,33 +286,25 @@ pub struct Exposures { pub others: Vec>, } - type RingBalanceOf = <::Ring as Currency<::AccountId>>::Balance; type KtonBalanceOf = <::Kton as Currency<::AccountId>>::Balance; // for ring -type RingPositiveImbalanceOf = -<::Ring as Currency<::AccountId>>::PositiveImbalance; -type RingNegativeImbalanceOf = -<::Ring as Currency<::AccountId>>::NegativeImbalance; +type RingPositiveImbalanceOf = <::Ring as Currency<::AccountId>>::PositiveImbalance; +type RingNegativeImbalanceOf = <::Ring as Currency<::AccountId>>::NegativeImbalance; // for kton -type KtonPositiveImbalanceOf = -<::Kton as Currency<::AccountId>>::PositiveImbalance; -type KtonNegativeImbalanceOf = -<::Kton as Currency<::AccountId>>::NegativeImbalance; +type KtonPositiveImbalanceOf = <::Kton as Currency<::AccountId>>::PositiveImbalance; +type KtonNegativeImbalanceOf = <::Kton as Currency<::AccountId>>::NegativeImbalance; type RawAssignment = (::AccountId, ExtendedBalance); type Assignment = (::AccountId, ExtendedBalance, ExtendedBalance); -type ExpoMap = BTreeMap< - ::AccountId, - Exposures<::AccountId, ExtendedBalance> ->; - +type ExpoMap = + BTreeMap<::AccountId, Exposures<::AccountId, ExtendedBalance>>; pub trait Trait: timestamp::Trait + session::Trait { - type Ring: LockableCurrency; - type Kton: LockableCurrency; + type Ring: LockableCurrency; + type Kton: LockableCurrency; type CurrencyToVote: Convert, u64> + Convert>; @@ -334,18 +334,18 @@ pub trait Trait: timestamp::Trait + session::Trait { decl_storage! { trait Store for Module as Staking { - pub ValidatorCount get(validator_count) config(): u32; + pub ValidatorCount get(validator_count) config(): u32; - pub MinimumValidatorCount get(minimum_validator_count) config(): - u32 = DEFAULT_MINIMUM_VALIDATOR_COUNT; + pub MinimumValidatorCount get(minimum_validator_count) config(): + u32 = DEFAULT_MINIMUM_VALIDATOR_COUNT; - pub SessionReward get(session_reward) config(): Perbill = Perbill::from_percent(60); + pub SessionReward get(session_reward) config(): Perbill = Perbill::from_percent(60); - pub OfflineSlash get(offline_slash) config(): Perbill = Perbill::from_parts(1000); + pub OfflineSlash get(offline_slash) config(): Perbill = Perbill::from_parts(1000); - pub OfflineSlashGrace get(offline_slash_grace) config(): u32; + pub OfflineSlashGrace get(offline_slash_grace) config(): u32; - pub Invulnerables get(invulnerables) config(): Vec; + pub Invulnerables get(invulnerables) config(): Vec; pub Bonded get(bonded): map T::AccountId => Option; @@ -353,80 +353,80 @@ decl_storage! { T::AccountId, RingBalanceOf, KtonBalanceOf, StakingBalance, KtonBalanceOf>, T::Moment>>; - pub Payee get(payee): map T::AccountId => RewardDestination; + pub Payee get(payee): map T::AccountId => RewardDestination; - pub Validators get(validators): linked_map T::AccountId => ValidatorPrefs; + pub Validators get(validators): linked_map T::AccountId => ValidatorPrefs; - pub Nominators get(nominators): linked_map T::AccountId => Vec; + pub Nominators get(nominators): linked_map T::AccountId => Vec; - pub Stakers get(stakers): map T::AccountId => Exposures; + pub Stakers get(stakers): map T::AccountId => Exposures; - pub CurrentElected get(current_elected): Vec; + pub CurrentElected get(current_elected): Vec; - pub CurrentEra get(current_era) config(): EraIndex; + pub CurrentEra get(current_era) config(): EraIndex; - pub SlotStake get(slot_stake): ExtendedBalance; + pub SlotStake get(slot_stake): ExtendedBalance; - pub SlashCount get(slash_count): map T::AccountId => u32; + pub SlashCount get(slash_count): map T::AccountId => u32; - pub RecentlyOffline get(recently_offline): Vec<(T::AccountId, T::BlockNumber, u32)>; + pub RecentlyOffline get(recently_offline): Vec<(T::AccountId, T::BlockNumber, u32)>; - pub ForceNewEra get(forcing_new_era): bool; + pub ForceNewEra get(forcing_new_era): bool; - pub EpochIndex get(epoch_index): u32 = 0; + pub EpochIndex get(epoch_index): u32 = 0; - /// The accumulated reward for the current era. Reset to zero at the beginning of the era - /// and increased for every successfully finished session. - pub CurrentEraTotalReward get(current_era_total_reward) config(): RingBalanceOf; + /// The accumulated reward for the current era. Reset to zero at the beginning of the era + /// and increased for every successfully finished session. + pub CurrentEraTotalReward get(current_era_total_reward) config(): RingBalanceOf; - pub NodeName get(node_name): map T::AccountId => Vec; + pub NodeName get(node_name): map T::AccountId => Vec; - pub RingPool get(ring_pool): RingBalanceOf; + pub RingPool get(ring_pool): RingBalanceOf; - pub KtonPool get(kton_pool): KtonBalanceOf; + pub KtonPool get(kton_pool): KtonBalanceOf; } add_extra_genesis { - config(stakers): - Vec<(T::AccountId, T::AccountId, RingBalanceOf, StakerStatus)>; - build(| - storage: &mut primitives::StorageOverlay, - _: &mut primitives::ChildrenStorageOverlay, - config: &GenesisConfig - | { - with_storage(storage, || { - for &(ref stash, ref controller, balance, ref status) in &config.stakers { - assert!(T::Ring::free_balance(&stash) >= balance); - let _ = >::bond( - T::Origin::from(Some(stash.clone()).into()), - T::Lookup::unlookup(controller.clone()), - StakingBalance::Ring(balance), - RewardDestination::Stash, - 12 - ); - let _ = match status { - StakerStatus::Validator => { - >::validate( - T::Origin::from(Some(controller.clone()).into()), - [0;8].to_vec(), - 0, - 3 - ) - }, - StakerStatus::Nominator(votes) => { - >::nominate( - T::Origin::from(Some(controller.clone()).into()), - votes.iter().map(|l| {T::Lookup::unlookup(l.clone())}).collect() - ) - }, _ => Ok(()) - }; - } - - if let (_, Some(validators)) = >::select_validators() { - >::put(&validators); - } - }); - }); - } + config(stakers): + Vec<(T::AccountId, T::AccountId, RingBalanceOf, StakerStatus)>; + build(| + storage: &mut primitives::StorageOverlay, + _: &mut primitives::ChildrenStorageOverlay, + config: &GenesisConfig + | { + with_storage(storage, || { + for &(ref stash, ref controller, balance, ref status) in &config.stakers { + assert!(T::Ring::free_balance(&stash) >= balance); + let _ = >::bond( + T::Origin::from(Some(stash.clone()).into()), + T::Lookup::unlookup(controller.clone()), + StakingBalance::Ring(balance), + RewardDestination::Stash, + 12 + ); + let _ = match status { + StakerStatus::Validator => { + >::validate( + T::Origin::from(Some(controller.clone()).into()), + [0;8].to_vec(), + 0, + 3 + ) + }, + StakerStatus::Nominator(votes) => { + >::nominate( + T::Origin::from(Some(controller.clone()).into()), + votes.iter().map(|l| {T::Lookup::unlookup(l.clone())}).collect() + ) + }, _ => Ok(()) + }; + } + + if let (_, Some(validators)) = >::select_validators() { + >::put(&validators); + } + }); + }); + } } decl_event!( @@ -448,10 +448,10 @@ decl_module! { /// Number of sessions per era. const SessionsPerEra: SessionIndex = T::SessionsPerEra::get(); - /// Number of eras that staked funds must remain bonded for. - const BondingDuration: EraIndex = T::BondingDuration::get(); + /// Number of eras that staked funds must remain bonded for. + const BondingDuration: EraIndex = T::BondingDuration::get(); - fn deposit_event() = default; + fn deposit_event() = default; fn bond(origin, controller: ::Source, @@ -462,36 +462,36 @@ decl_module! { let stash = ensure_signed(origin)?; ensure!( promise_month <= 36, "months at most is 36."); - if >::exists(&stash) { - return Err("stash already bonded") - } + if >::exists(&stash) { + return Err("stash already bonded") + } - let controller = T::Lookup::lookup(controller)?; + let controller = T::Lookup::lookup(controller)?; - if >::exists(&controller) { - return Err("controller already paired") - } + if >::exists(&controller) { + return Err("controller already paired") + } - >::insert(&stash, controller.clone()); - >::insert(&stash, payee); + >::insert(&stash, controller.clone()); + >::insert(&stash, payee); let ledger = StakingLedgers {stash: stash.clone(), ..Default::default()}; - match value { - StakingBalance::Ring(r) => { - let stash_balance = T::Ring::free_balance(&stash); - let value = r.min(stash_balance); - // increase ring pool - >::mutate(|r| *r += value); - Self::bond_helper_in_ring(stash.clone(), controller.clone(), value, promise_month, ledger); - }, - StakingBalance::Kton(k) => { - let stash_balance = T::Kton::free_balance(&stash); - let value: KtonBalanceOf = k.min(stash_balance); - // increase kton pool - >::mutate(|k| *k += value); - Self::bond_helper_in_kton(controller.clone(), value, ledger); - }, - } + match value { + StakingBalance::Ring(r) => { + let stash_balance = T::Ring::free_balance(&stash); + let value = r.min(stash_balance); + // increase ring pool + >::mutate(|r| *r += value); + Self::bond_helper_in_ring(stash.clone(), controller.clone(), value, promise_month, ledger); + }, + StakingBalance::Kton(k) => { + let stash_balance = T::Kton::free_balance(&stash); + let value: KtonBalanceOf = k.min(stash_balance); + // increase kton pool + >::mutate(|k| *k += value); + Self::bond_helper_in_kton(controller.clone(), value, ledger); + }, + } } fn bond_extra(origin, @@ -500,8 +500,8 @@ decl_module! { ) { let stash = ensure_signed(origin)?; ensure!( promise_month <= 36, "months at most is 36."); - let controller = Self::bonded(&stash).ok_or("not a stash")?; - let ledger = Self::ledger(&controller).ok_or("not a controller")?; + let controller = Self::bonded(&stash).ok_or("not a stash")?; + let ledger = Self::ledger(&controller).ok_or("not a controller")?; match value { StakingBalance::Ring(r) => { let stash_balance = T::Ring::free_balance(&stash); @@ -530,27 +530,27 @@ decl_module! { let controller = ensure_signed(origin)?; let mut ledger = Self::ledger(&controller).ok_or("not a controller")?; - ensure!( - ledger.unlocking.len() < MAX_UNLOCKING_CHUNKS, - "can not schedule more unlock chunks" - ); + ensure!( + ledger.unlocking.len() < MAX_UNLOCKING_CHUNKS, + "can not schedule more unlock chunks" + ); - let era = Self::current_era() + T::BondingDuration::get(); + let era = Self::current_era() + T::BondingDuration::get(); - match value { - StakingBalance::Ring(r) => { - // total_unbond_value = normal_unbond + time_deposit_unbond + match value { + StakingBalance::Ring(r) => { + // total_unbond_value = normal_unbond + time_deposit_unbond let total_value = r.min(ledger.active_ring); - let active_normal_ring = ledger.active_ring - ledger.active_deposit_ring; + let active_normal_ring = ledger.active_ring - ledger.active_deposit_ring; // unbond normal ring first - let active_normal_value = total_value.min(active_normal_ring); - >::mutate(|r| *r -= active_normal_value); - let mut unlock_value_left = total_value - active_normal_value; - if !active_normal_value.is_zero() { - ledger.active_ring -= active_normal_value; + let active_normal_value = total_value.min(active_normal_ring); + >::mutate(|r| *r -= active_normal_value); + let mut unlock_value_left = total_value - active_normal_value; + if !active_normal_value.is_zero() { + ledger.active_ring -= active_normal_value; ledger.unlocking.push(UnlockChunk { value: StakingBalance::Ring(total_value), era, is_time_deposit: false }); - } + } // no active_normal_ring let is_time_deposit = if active_normal_value.is_zero() { @@ -561,8 +561,8 @@ decl_module! { let mut total_deposit_changed: RingBalanceOf = Zero::zero(); - if is_time_deposit { - let now = >::now(); + if is_time_deposit { + let now = >::now(); /// for time_deposit_ring, transform into normal one let deposit_items = ledger.deposit_items.clone(); @@ -596,22 +596,22 @@ decl_module! { ledger.deposit_items = new_deposit_items; // update unlocking list - ledger.unlocking.push(UnlockChunk { value: StakingBalance::Ring(total_deposit_changed), era, is_time_deposit: true }); - >::mutate(|r| *r -= total_deposit_changed); - } else { - // do nothing - } - }, - - StakingBalance::Kton(k) => { + ledger.unlocking.push(UnlockChunk { value: StakingBalance::Ring(total_deposit_changed), era, is_time_deposit: true }); + >::mutate(|r| *r -= total_deposit_changed); + } else { + // do nothing + } + }, + + StakingBalance::Kton(k) => { let value = k.min(ledger.active_kton); >::mutate(|r| *r -= value); ledger.active_kton -= value; - ledger.unlocking.push(UnlockChunk { value: StakingBalance::Kton(value), era, is_time_deposit: false }); - }, - } - >::insert(&controller, ledger); + ledger.unlocking.push(UnlockChunk { value: StakingBalance::Kton(value), era, is_time_deposit: false }); + }, + } + >::insert(&controller, ledger); } @@ -650,7 +650,7 @@ decl_module! { T::KtonSlash::on_unbalanced(imbalance); // update unlocks let era = Self::current_era() + T::BondingDuration::get(); - ledger.unlocking.push(UnlockChunk { value: StakingBalance::Ring(value), era, is_time_deposit: true }); + ledger.unlocking.push(UnlockChunk { value: StakingBalance::Ring(value), era, is_time_deposit: true }); let inner_res = if item.value.is_zero() { None @@ -675,13 +675,13 @@ decl_module! { let controller = ensure_signed(origin)?; ensure!( promise_month <= 36, "months at most is 36."); let mut ledger = Self::ledger(&controller).ok_or("not a controller")?; - let stash = &ledger.stash.clone(); + let stash = &ledger.stash.clone(); - // remove expired deposit_items - let now = >::now(); - let deposit_items = ledger.deposit_items.clone(); + // remove expired deposit_items + let now = >::now(); + let deposit_items = ledger.deposit_items.clone(); - let new_deposit_items = deposit_items.into_iter().filter(|item| + let new_deposit_items = deposit_items.into_iter().filter(|item| if item.expire_time < now.clone() { // reduce deposit_ring, // total/active ring @@ -694,7 +694,7 @@ decl_module! { ledger.deposit_items = new_deposit_items; - let value = value.min(ledger.active_ring - ledger.active_deposit_ring); // active_normal_ring + let value = value.min(ledger.active_ring - ledger.active_deposit_ring); // active_normal_ring let deposit_item = if promise_month >= 3 { let kton_return = utils::compute_kton_return::(value, promise_month); @@ -737,93 +737,92 @@ decl_module! { } fn validate(origin, name: Vec, ratio: u32, unstake_threshold: u32) { - let controller = ensure_signed(origin)?; - let ledger = Self::ledger(&controller).ok_or("not a controller")?; - let stash = &ledger.stash; - ensure!( - unstake_threshold <= MAX_UNSTAKE_THRESHOLD, - "unstake threshold too large" - ); + let controller = ensure_signed(origin)?; + let ledger = Self::ledger(&controller).ok_or("not a controller")?; + let stash = &ledger.stash; + ensure!( + unstake_threshold <= MAX_UNSTAKE_THRESHOLD, + "unstake threshold too large" + ); // at most 100% let ratio = Perbill::from_percent(ratio.min(100)); let prefs = ValidatorPrefs {unstake_threshold: unstake_threshold, validator_payment_ratio: ratio }; - >::remove(stash); - >::insert(stash, prefs); - if !>::exists(&controller) { - >::insert(controller, name); - Self::deposit_event(RawEvent::NodeNameUpdated); - } - } - - fn nominate(origin, targets: Vec<::Source>) { - let controller = ensure_signed(origin)?; - let ledger = Self::ledger(&controller).ok_or("not a controller")?; - let stash = &ledger.stash; - ensure!(!targets.is_empty(), "targets cannot be empty"); - let targets = targets.into_iter() - .take(MAX_NOMINATIONS) - .map(T::Lookup::lookup) - .collect::, &'static str>>()?; - - >::remove(stash); - >::insert(stash, targets); - } - - fn chill(origin) { - let controller = ensure_signed(origin)?; - let ledger = Self::ledger(&controller).ok_or("not a controller")?; - let stash = &ledger.stash; - >::remove(stash); - >::remove(stash); - } - - fn set_payee(origin, payee: RewardDestination) { - let controller = ensure_signed(origin)?; - let ledger = Self::ledger(&controller).ok_or("not a controller")?; - let stash = &ledger.stash; - >::insert(stash, payee); - } - - fn set_controller(origin, controller: ::Source) { - let stash = ensure_signed(origin)?; - let old_controller = Self::bonded(&stash).ok_or("not a stash")?; - let controller = T::Lookup::lookup(controller)?; - if >::exists(&controller) { - return Err("controller already paired") - } - if controller != old_controller { - >::insert(&stash, &controller); - if let Some(l) = >::take(&old_controller) { - >::insert(&controller, l); - } - } - } - - /// The ideal number of validators. - fn set_validator_count(#[compact] new: u32) { - ValidatorCount::put(new); - } - - // ----- Root calls. - - fn force_new_era() { - Self::apply_force_new_era() - } - - /// Set the offline slash grace period. - fn set_offline_slash_grace(#[compact] new: u32) { - OfflineSlashGrace::put(new); - } - - /// Set the validators who cannot be slashed (if any). - fn set_invulnerables(validators: Vec) { - >::put(validators); - } + >::remove(stash); + >::insert(stash, prefs); + if !>::exists(&controller) { + >::insert(controller, name); + Self::deposit_event(RawEvent::NodeNameUpdated); + } + } + + fn nominate(origin, targets: Vec<::Source>) { + let controller = ensure_signed(origin)?; + let ledger = Self::ledger(&controller).ok_or("not a controller")?; + let stash = &ledger.stash; + ensure!(!targets.is_empty(), "targets cannot be empty"); + let targets = targets.into_iter() + .take(MAX_NOMINATIONS) + .map(T::Lookup::lookup) + .collect::, &'static str>>()?; + + >::remove(stash); + >::insert(stash, targets); + } + + fn chill(origin) { + let controller = ensure_signed(origin)?; + let ledger = Self::ledger(&controller).ok_or("not a controller")?; + let stash = &ledger.stash; + >::remove(stash); + >::remove(stash); + } + + fn set_payee(origin, payee: RewardDestination) { + let controller = ensure_signed(origin)?; + let ledger = Self::ledger(&controller).ok_or("not a controller")?; + let stash = &ledger.stash; + >::insert(stash, payee); + } + + fn set_controller(origin, controller: ::Source) { + let stash = ensure_signed(origin)?; + let old_controller = Self::bonded(&stash).ok_or("not a stash")?; + let controller = T::Lookup::lookup(controller)?; + if >::exists(&controller) { + return Err("controller already paired") + } + if controller != old_controller { + >::insert(&stash, &controller); + if let Some(l) = >::take(&old_controller) { + >::insert(&controller, l); + } + } + } + + /// The ideal number of validators. + fn set_validator_count(#[compact] new: u32) { + ValidatorCount::put(new); + } + + // ----- Root calls. + + fn force_new_era() { + Self::apply_force_new_era() + } + + /// Set the offline slash grace period. + fn set_offline_slash_grace(#[compact] new: u32) { + OfflineSlashGrace::put(new); + } + + /// Set the validators who cannot be slashed (if any). + fn set_invulnerables(validators: Vec) { + >::put(validators); + } } } - impl Module { /// The total that can be slashed from a validator controller account as of /// right now. @@ -837,9 +836,13 @@ impl Module { value: RingBalanceOf, promise_month: u32, mut ledger: StakingLedgers< - T::AccountId, RingBalanceOf, KtonBalanceOf, StakingBalance, KtonBalanceOf>, T::Moment>, + T::AccountId, + RingBalanceOf, + KtonBalanceOf, + StakingBalance, KtonBalanceOf>, + T::Moment, + >, ) { - // if stash promise to a extra-lock // there will be extra reward, kton, which // can also be use to stake. @@ -853,7 +856,11 @@ impl Module { T::KtonReward::on_unbalanced(kton_positive_imbalance); let now = >::now(); let expire_time = now.clone() + (MONTH_IN_SECONDS * promise_month).into(); - Some(TimeDepositItem { value, start_time: now, expire_time }) + Some(TimeDepositItem { + value, + start_time: now, + expire_time, + }) } else { None }; @@ -871,8 +878,12 @@ impl Module { controller: T::AccountId, value: KtonBalanceOf, mut ledger: StakingLedgers< - T::AccountId, RingBalanceOf, KtonBalanceOf, StakingBalance, KtonBalanceOf>, - T::Moment>, + T::AccountId, + RingBalanceOf, + KtonBalanceOf, + StakingBalance, KtonBalanceOf>, + T::Moment, + >, ) { ledger.total_kton += value; ledger.active_kton += value; @@ -882,8 +893,13 @@ impl Module { fn update_ledger( controller: &T::AccountId, - ledger: &StakingLedgers, KtonBalanceOf, - StakingBalance, KtonBalanceOf>, T::Moment>, + ledger: &StakingLedgers< + T::AccountId, + RingBalanceOf, + KtonBalanceOf, + StakingBalance, KtonBalanceOf>, + T::Moment, + >, staking_balance: StakingBalance, KtonBalanceOf>, ) { match staking_balance { @@ -925,8 +941,9 @@ impl Module { T::KtonSlash::on_unbalanced(kton_imbalance); } - - fn slash_individual(stash: &T::AccountId, slash_ratio: Perbill, + fn slash_individual( + stash: &T::AccountId, + slash_ratio: Perbill, ) -> (RingNegativeImbalanceOf, KtonNegativeImbalanceOf) { let controller = Self::bonded(stash).unwrap(); let mut ledger = Self::ledger(&controller).unwrap(); @@ -953,9 +970,15 @@ impl Module { fn slash_helper( controller: &T::AccountId, - ledger: &mut StakingLedgers, KtonBalanceOf, - StakingBalance, KtonBalanceOf>, T::Moment>, - value: StakingBalance, KtonBalanceOf>) -> (RingBalanceOf, KtonBalanceOf){ + ledger: &mut StakingLedgers< + T::AccountId, + RingBalanceOf, + KtonBalanceOf, + StakingBalance, KtonBalanceOf>, + T::Moment, + >, + value: StakingBalance, KtonBalanceOf>, + ) -> (RingBalanceOf, KtonBalanceOf) { match value { StakingBalance::Ring(r) => { // if slashing ring, first slashing normal ring @@ -975,10 +998,11 @@ impl Module { // from the nearest expire time if !value_left.is_zero() { // sorted by expire_time from far to near - deposit_items.sort_unstable_by_key(|item| + deposit_items.sort_unstable_by_key(|item| { u64::max_value() - item.expire_time.clone().saturated_into::() - ); - let new_deposit_items = deposit_items.into_iter() + }); + let new_deposit_items = deposit_items + .into_iter() .filter_map(|mut item| { if value_left.is_zero() { Some(item) @@ -997,44 +1021,46 @@ impl Module { None } } - }).collect::>(); + }) + .collect::>(); ledger.deposit_items = new_deposit_items; } // active_ring all slashed // then slashing unlocking ring if !value_left.is_zero() { - let unlockings = ledger.unlocking.clone() + let unlockings = ledger + .unlocking + .clone() .into_iter() - .filter_map(|mut chunk| { - match chunk.value { - StakingBalance::Ring(r) => { - if value_left.is_zero() { - Some(chunk) + .filter_map(|mut chunk| match chunk.value { + StakingBalance::Ring(r) => { + if value_left.is_zero() { + Some(chunk) + } else { + let value = value_left.min(r); + let new_value = r - value; + chunk.value = StakingBalance::Ring(new_value); + value_left -= value; + if chunk.is_time_deposit { + ledger.total_deposit_ring -= value; + } + ledger.total_ring -= value; + if new_value.is_zero() { + None } else { - let value = value_left.min(r); - let new_value = r - value; - chunk.value = StakingBalance::Ring(new_value); - value_left -= value; - if chunk.is_time_deposit { - ledger.total_deposit_ring -= value; - } - ledger.total_ring -= value; - if new_value.is_zero() { - None - } else { - Some(chunk) - } + Some(chunk) } - }, - StakingBalance::Kton(_) => Some(chunk), + } } - }).collect::>(); + StakingBalance::Kton(_) => Some(chunk), + }) + .collect::>(); ledger.unlocking = unlockings; } Self::update_ledger(controller, ledger, StakingBalance::Ring(0.into())); (total_value, 0.into()) - }, + } StakingBalance::Kton(k) => { let total_value = k.min(ledger.total_kton); @@ -1047,29 +1073,30 @@ impl Module { let mut value_left = total_value - active_value; // slash unlocking kton if !value_left.is_zero() { - let unlockings = ledger.unlocking.clone() + let unlockings = ledger + .unlocking + .clone() .into_iter() - .filter_map(|mut chunk| { - match chunk.value { - StakingBalance::Kton(k) => { - if value_left.is_zero() { - Some(chunk) + .filter_map(|mut chunk| match chunk.value { + StakingBalance::Kton(k) => { + if value_left.is_zero() { + Some(chunk) + } else { + let value = value_left.min(k); + let new_value = k - value; + chunk.value = StakingBalance::Kton(k - value); + value_left -= value; + ledger.total_kton -= value; + if new_value.is_zero() { + None } else { - let value = value_left.min(k); - let new_value = k - value; - chunk.value = StakingBalance::Kton(k - value); - value_left -= value; - ledger.total_kton -= value; - if new_value.is_zero() { - None - } else { - Some(chunk) - } + Some(chunk) } - }, - StakingBalance::Ring(_) => Some(chunk), + } } - }).collect::>(); + StakingBalance::Ring(_) => Some(chunk), + }) + .collect::>(); ledger.unlocking = unlockings; } Self::update_ledger(controller, ledger, StakingBalance::Kton(0.into())); @@ -1078,9 +1105,7 @@ impl Module { } } - fn new_session(session_index: SessionIndex) -> Option> { - if ForceNewEra::take() || session_index % T::SessionsPerEra::get() == 0 { Self::new_era() } else { @@ -1088,11 +1113,10 @@ impl Module { } } - /// The era has changed - enact new staking set. - /// - /// NOTE: This always happens immediately before a session change to ensure that new validators - /// get a chance to set their session keys. + /// + /// NOTE: This always happens immediately before a session change to ensure that new validators + /// get a chance to set their session keys. fn new_era() -> Option> { let reward = Self::session_reward() * Self::current_era_total_reward(); if !reward.is_zero() { @@ -1128,10 +1152,8 @@ impl Module { if !next_era_reward.is_zero() { >::put(next_era_reward); } - } - fn reward_validator(stash: &T::AccountId, reward: RingBalanceOf) { let off_the_table = Self::validators(stash).validator_payment_ratio * reward; let reward = reward - off_the_table; @@ -1154,28 +1176,28 @@ impl Module { T::RingReward::on_unbalanced(imbalance); } - /// Actually make a payment to a staker. This uses the currency's reward function /// to pay the right payee for the given staker account. fn make_payout(stash: &T::AccountId, amount: RingBalanceOf) -> Option> { let dest = Self::payee(stash); match dest { - RewardDestination::Controller => Self::bonded(stash) - .and_then(|controller| - T::Ring::deposit_into_existing(&controller, amount).ok() - ), - RewardDestination::Stash => - T::Ring::deposit_into_existing(stash, amount).ok(), + RewardDestination::Controller => { + Self::bonded(stash).and_then(|controller| T::Ring::deposit_into_existing(&controller, amount).ok()) + } + RewardDestination::Stash => T::Ring::deposit_into_existing(stash, amount).ok(), } } // TODO: ready for hacking // power is a mixture of ring and kton fn slashable_balance_of(stash: &T::AccountId) -> ExtendedBalance { - Self::bonded(stash).and_then(Self::ledger).map(|l| { - l.active_ring.saturated_into::() + - l.active_kton.saturated_into::() * Self::kton_vote_weight() / ACCURACY - }).unwrap_or_default() + Self::bonded(stash) + .and_then(Self::ledger) + .map(|l| { + l.active_ring.saturated_into::() + + l.active_kton.saturated_into::() * Self::kton_vote_weight() / ACCURACY + }) + .unwrap_or_default() } /// Select a new validator set from the assembled stakers and their role preferences. @@ -1202,16 +1224,18 @@ impl Module { let ratio_of = |b, p| (p as ExtendedBalance).saturating_mul(b) / ACCURACY; // Compute the actual stake from nominator's ratio. - let assignments_with_stakes = assignments.iter().map(|(n, a)| ( - n.clone(), - Self::slashable_balance_of(n), - a.iter().map(|(acc, r)| ( - acc.clone(), - *r, - ratio_of(Self::slashable_balance_of(n), *r), - )) - .collect::>>() - )).collect::>)>>(); + let assignments_with_stakes = assignments + .iter() + .map(|(n, a)| { + ( + n.clone(), + Self::slashable_balance_of(n), + a.iter() + .map(|(acc, r)| (acc.clone(), *r, ratio_of(Self::slashable_balance_of(n), *r))) + .collect::>>(), + ) + }) + .collect::>)>>(); // update elected candidate exposures. let mut exposures = >::new(); @@ -1219,7 +1243,11 @@ impl Module { .iter() .map(|e| (e, Self::slashable_balance_of(e))) .for_each(|(e, s)| { - let item = Exposures { own: s, total: s, ..Default::default() }; + let item = Exposures { + own: s, + total: s, + ..Default::default() + }; exposures.insert(e.clone(), item); }); @@ -1231,7 +1259,10 @@ impl Module { // Nuked. Sadly there is not much that we can do about this. // See this test: phragmen_should_not_overflow_xxx() expo.total = expo.total.saturating_add(*s); - expo.others.push(IndividualExpo { who: n.clone(), value: *s }); + expo.others.push(IndividualExpo { + who: n.clone(), + value: *s, + }); } } } @@ -1239,17 +1270,23 @@ impl Module { if cfg!(feature = "equalize") { let tolerance = 0_u128; let iterations = 2_usize; - let mut assignments_with_votes = assignments_with_stakes.iter() - .map(|a| ( - a.0.clone(), a.1, - a.2.iter() - .map(|e| (e.0.clone(), e.1, e.2)) - .collect::>() - )) + let mut assignments_with_votes = assignments_with_stakes + .iter() + .map(|a| { + ( + a.0.clone(), + a.1, + a.2.iter().map(|e| (e.0.clone(), e.1, e.2)).collect::>(), + ) + }) .collect:: + Vec<(T::AccountId, ExtendedBalance, ExtendedBalance)>, )>>(); equalize::(&mut assignments_with_votes, &mut exposures, tolerance, iterations); } @@ -1277,7 +1314,8 @@ impl Module { // Set the new validator set in sessions. >::put(&elected_stashes); - let validators = elected_stashes.into_iter() + let validators = elected_stashes + .into_iter() .map(|s| Self::bonded(s).unwrap_or_default()) .collect::>(); (slot_stake, Some(validators)) @@ -1292,7 +1330,6 @@ impl Module { } } - fn apply_force_new_era() { ForceNewEra::put(true); } @@ -1317,15 +1354,18 @@ impl Module { if RECENT_OFFLINE_COUNT > 0 { let item = (stash.clone(), >::block_number(), count as u32); - >::mutate(|v| if v.len() >= RECENT_OFFLINE_COUNT { - let index = v.iter() - .enumerate() - .min_by_key(|(_, (_, block, _))| block) - .expect("v is non-empty; qed") - .0; - v[index] = item; - } else { - v.push(item); + >::mutate(|v| { + if v.len() >= RECENT_OFFLINE_COUNT { + let index = v + .iter() + .enumerate() + .min_by_key(|(_, (_, block, _))| block) + .expect("v is non-empty; qed") + .0; + v[index] = item; + } else { + v.push(item); + } }); } @@ -1368,18 +1408,15 @@ impl Module { // total_ring and total_kton are within the scope of u64 // so it is safe to multiply ACCURACY when extended to u128 total_ring * ACCURACY / total_kton - } } - impl OnSessionEnding for Module { fn on_session_ending(i: SessionIndex) -> Option> { Self::new_session(i + 1) } } - impl OnFreeBalanceZero for Module { fn on_free_balance_zero(stash: &T::AccountId) { if let Some(controller) = >::take(stash) { @@ -1391,5 +1428,3 @@ impl OnFreeBalanceZero for Module { >::remove(stash); } } - - diff --git a/srml/staking/src/mock.rs b/srml/staking/src/mock.rs index c104bfaaa..6087722ab 100644 --- a/srml/staking/src/mock.rs +++ b/srml/staking/src/mock.rs @@ -1,18 +1,14 @@ - - -use std::{collections::HashSet, cell::RefCell}; -use primitives::Perbill; -use primitives::traits::{IdentityLookup, Convert, OpaqueKeys, OnInitialize}; +use crate::{ + EraIndex, GenesisConfig, Module, Nominators, RewardDestination, StakerStatus, StakingBalance, Trait, ValidatorPrefs, +}; use primitives::testing::{Header, UintAuthorityId}; -use substrate_primitives::{H256, Blake2Hasher}; +use primitives::traits::{Convert, IdentityLookup, OnInitialize, OpaqueKeys}; +use primitives::Perbill; use runtime_io; -use srml_support::{assert_ok, impl_outer_origin, parameter_types, EnumerableStorageMap}; use srml_support::traits::{Currency, Get}; -use crate::{EraIndex, GenesisConfig, Module, Trait, StakerStatus, - ValidatorPrefs, RewardDestination, Nominators, StakingBalance -}; - - +use srml_support::{assert_ok, impl_outer_origin, parameter_types, EnumerableStorageMap}; +use std::{cell::RefCell, collections::HashSet}; +use substrate_primitives::{Blake2Hasher, H256}; /// The AccountId alias in this test module. pub type AccountId = u64; @@ -22,7 +18,9 @@ pub type Balance = u64; /// Simple structure that exposes how u64 currency can be represented as... u64. pub struct CurrencyToVoteHandler; impl Convert for CurrencyToVoteHandler { - fn convert(x: u64) -> u64 { x } + fn convert(x: u64) -> u64 { + x + } } impl Convert for CurrencyToVoteHandler { fn convert(x: u128) -> u64 { @@ -31,16 +29,14 @@ impl Convert for CurrencyToVoteHandler { } thread_local! { - static SESSION: RefCell<(Vec, HashSet)> = RefCell::new(Default::default()); - static EXISTENTIAL_DEPOSIT: RefCell = RefCell::new(0); + static SESSION: RefCell<(Vec, HashSet)> = RefCell::new(Default::default()); + static EXISTENTIAL_DEPOSIT: RefCell = RefCell::new(0); } pub struct TestSessionHandler; impl session::SessionHandler for TestSessionHandler { fn on_new_session(_changed: bool, validators: &[(AccountId, Ks)]) { - SESSION.with(|x| - *x.borrow_mut() = (validators.iter().map(|x| x.0.clone()).collect(), HashSet::new()) - ); + SESSION.with(|x| *x.borrow_mut() = (validators.iter().map(|x| x.0.clone()).collect(), HashSet::new())); } fn on_disabled(validator_index: usize) { @@ -64,8 +60,8 @@ impl Get for ExistentialDeposit { } } -impl_outer_origin!{ - pub enum Origin for Test {} +impl_outer_origin! { + pub enum Origin for Test {} } // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. @@ -84,10 +80,10 @@ impl system::Trait for Test { type Event = (); } parameter_types! { - pub const TransferFee: u64 = 0; - pub const CreationFee: u64 = 0; - pub const TransactionBaseFee: u64 = 0; - pub const TransactionByteFee: u64 = 0; + pub const TransferFee: u64 = 0; + pub const CreationFee: u64 = 0; + pub const TransactionBaseFee: u64 = 0; + pub const TransactionByteFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; @@ -104,8 +100,8 @@ impl balances::Trait for Test { type TransactionByteFee = TransactionByteFee; } parameter_types! { - pub const Period: BlockNumber = 1; - pub const Offset: BlockNumber = 0; + pub const Period: BlockNumber = 1; + pub const Offset: BlockNumber = 0; } impl session::Trait for Test { type OnSessionEnding = Staking; @@ -120,7 +116,6 @@ impl timestamp::Trait for Test { type OnTimestampSet = (); } - impl kton::Trait for Test { type Balance = Balance; type Event = (); @@ -128,20 +123,18 @@ impl kton::Trait for Test { type OnRemoval = (); } - parameter_types! { - pub const SessionsPerEra: session::SessionIndex = 3; - pub const BondingDuration: EraIndex = 3; - pub const ErasPerEpoch: EraIndex = 10; + pub const SessionsPerEra: session::SessionIndex = 3; + pub const BondingDuration: EraIndex = 3; + pub const ErasPerEpoch: EraIndex = 10; } pub const COIN: u64 = 1_000_000_000; parameter_types! { - // decimal 9 - pub const CAP: Balance = 10_000_000_000 * COIN; + // decimal 9 + pub const CAP: Balance = 10_000_000_000 * COIN; } - impl Trait for Test { type Ring = Ring; type Kton = Kton; @@ -179,7 +172,7 @@ impl Default for ExtBuilder { nominate: true, validator_count: 3, minimum_validator_count: 0, - fair: true + fair: true, } } } @@ -224,13 +217,18 @@ impl ExtBuilder { } else { 1 * COIN }; - let validators = if self.validator_pool { vec![10, 20, 30, 40] } else { vec![10, 20] }; - let _ = session::GenesisConfig::{ + let validators = if self.validator_pool { + vec![10, 20, 30, 40] + } else { + vec![10, 20] + }; + let _ = session::GenesisConfig:: { // NOTE: if config.nominate == false then 100 is also selected in the initial round. validators, keys: vec![], - }.assimilate_storage(&mut t, &mut c); - let _ = balances::GenesisConfig::{ + } + .assimilate_storage(&mut t, &mut c); + let _ = balances::GenesisConfig:: { balances: vec![ (1, 10 * balance_factor), (2, 20 * balance_factor), @@ -248,11 +246,13 @@ impl ExtBuilder { (101, 2000 * balance_factor), ], vesting: vec![], - }.assimilate_storage(&mut t, &mut c); + } + .assimilate_storage(&mut t, &mut c); let _ = kton::GenesisConfig:: { - balances : vec![], + balances: vec![], vesting: vec![], - }.assimilate_storage(&mut t, &mut c); + } + .assimilate_storage(&mut t, &mut c); let stake_21 = if self.fair { 1000 } else { 2000 }; let stake_31 = if self.validator_pool { balance_factor * 1000 } else { 1 }; @@ -262,17 +262,22 @@ impl ExtBuilder { StakerStatus::::Idle }; let nominated = if self.nominate { vec![11, 21] } else { vec![] }; - let _ = GenesisConfig::{ + let _ = GenesisConfig:: { current_era: self.current_era, current_era_total_reward: 80_000_000 * COIN / ErasPerEpoch::get() as u64, stakers: vec![ -// (2, 1, 1 * COIN, StakerStatus::::Validator), + // (2, 1, 1 * COIN, StakerStatus::::Validator), (11, 10, 100 * COIN, StakerStatus::::Validator), (21, 20, stake_21, StakerStatus::::Validator), (31, 30, stake_31, StakerStatus::::Validator), (41, 40, balance_factor * 1000, status_41), // nominator - (101, 100, balance_factor * 500, StakerStatus::::Nominator(nominated)) + ( + 101, + 100, + balance_factor * 500, + StakerStatus::::Nominator(nominated), + ), ], validator_count: self.validator_count, minimum_validator_count: self.minimum_validator_count, @@ -280,16 +285,13 @@ impl ExtBuilder { offline_slash: Perbill::from_percent(5), offline_slash_grace: 0, invulnerables: vec![], - }.assimilate_storage(&mut t, &mut c); - let _ = timestamp::GenesisConfig::{ - minimum_period: 5, - }.assimilate_storage(&mut t, &mut c); + } + .assimilate_storage(&mut t, &mut c); + let _ = timestamp::GenesisConfig:: { minimum_period: 5 }.assimilate_storage(&mut t, &mut c); let mut ext = t.into(); runtime_io::with_externalities(&mut ext, || { let validators = Session::validators(); - SESSION.with(|x| - *x.borrow_mut() = (validators.clone(), HashSet::new()) - ); + SESSION.with(|x| *x.borrow_mut() = (validators.clone(), HashSet::new())); }); ext } @@ -302,7 +304,9 @@ pub type Timestamp = timestamp::Module; pub type Staking = Module; pub fn check_exposure_all() { - Staking::current_elected().into_iter().for_each(|acc| check_exposure(acc)); + Staking::current_elected() + .into_iter() + .for_each(|acc| check_exposure(acc)); } pub fn check_nominator_all() { @@ -314,8 +318,11 @@ pub fn check_exposure(stash: u64) { assert_is_stash(stash); let expo = Staking::stakers(&stash); assert_eq!( - expo.total as u128, expo.own as u128 + expo.others.iter().map(|e| e.value as u128).sum::(), - "wrong total exposure for {:?}: {:?}", stash, expo, + expo.total as u128, + expo.own as u128 + expo.others.iter().map(|e| e.value as u128).sum::(), + "wrong total exposure for {:?}: {:?}", + stash, + expo, ); } @@ -327,14 +334,15 @@ pub fn check_nominator_exposure(stash: u64) { Staking::current_elected() .iter() .map(|v| Staking::stakers(v)) - .for_each(|e| e.others.iter() - .filter(|i| i.who == stash) - .for_each(|i| sum += i.value)); + .for_each(|e| e.others.iter().filter(|i| i.who == stash).for_each(|i| sum += i.value)); let nominator_stake = Staking::slashable_balance_of(&stash); // a nominator cannot over-spend. assert!( nominator_stake >= sum, - "failed: Nominator({}) stake({}) >= sum divided({})", stash, nominator_stake, sum, + "failed: Nominator({}) stake({}) >= sum divided({})", + stash, + nominator_stake, + sum, ); } @@ -350,16 +358,33 @@ pub fn assert_is_stash(acc: u64) { pub fn bond_validator(acc: u64, val: u64) { // a = controller // a + 1 = stash - let _ = Ring::make_free_balance_be(&(acc+1), val); - assert_ok!(Staking::bond(Origin::signed(acc+1), acc, StakingBalance::Ring(val), RewardDestination::Controller, 0)); - assert_ok!(Staking::validate(Origin::signed(acc), "test".as_bytes().to_owned(), 0, 0)); + let _ = Ring::make_free_balance_be(&(acc + 1), val); + assert_ok!(Staking::bond( + Origin::signed(acc + 1), + acc, + StakingBalance::Ring(val), + RewardDestination::Controller, + 0 + )); + assert_ok!(Staking::validate( + Origin::signed(acc), + "test".as_bytes().to_owned(), + 0, + 0 + )); } pub fn bond_nominator(acc: u64, val: u64, target: Vec) { // a = controller // a + 1 = stash - let _ = Ring::make_free_balance_be(&(acc+1), val); - assert_ok!(Staking::bond(Origin::signed(acc+1), acc, StakingBalance::Ring(val), RewardDestination::Controller, 0)); + let _ = Ring::make_free_balance_be(&(acc + 1), val); + assert_ok!(Staking::bond( + Origin::signed(acc + 1), + acc, + StakingBalance::Ring(val), + RewardDestination::Controller, + 0 + )); assert_ok!(Staking::nominate(Origin::signed(acc), target)); } diff --git a/srml/staking/src/phragmen.rs b/srml/staking/src/phragmen.rs index 2ab6b2ba8..fd9a9bde9 100644 --- a/srml/staking/src/phragmen.rs +++ b/srml/staking/src/phragmen.rs @@ -16,10 +16,10 @@ //! Rust implementation of the Phragmén election algorithm. -use rstd::{prelude::*, collections::btree_map::BTreeMap}; -use primitives::{PerU128}; -use primitives::traits::{Zero, Convert, Saturating}; -use crate::{RingBalanceOf, RawAssignment, ExpoMap, Trait, ValidatorPrefs, IndividualExpo}; +use crate::{ExpoMap, IndividualExpo, RawAssignment, RingBalanceOf, Trait, ValidatorPrefs}; +use primitives::traits::{Convert, Saturating, Zero}; +use primitives::PerU128; +use rstd::{collections::btree_map::BTreeMap, prelude::*}; type Fraction = PerU128; /// Wrapper around the type used as the _safe_ wrapper around a `balance`. @@ -37,42 +37,42 @@ pub const ACCURACY: ExtendedBalance = u32::max_value() as ExtendedBalance + 1; #[derive(Clone, Default)] #[cfg_attr(feature = "std", derive(Debug))] pub struct Candidate { - /// The validator's account - pub who: AccountId, - /// Intermediary value used to sort candidates. - pub score: Fraction, - /// Accumulator of the stake of this candidate based on received votes. - approval_stake: ExtendedBalance, - /// Flag for being elected. - elected: bool, + /// The validator's account + pub who: AccountId, + /// Intermediary value used to sort candidates. + pub score: Fraction, + /// Accumulator of the stake of this candidate based on received votes. + approval_stake: ExtendedBalance, + /// Flag for being elected. + elected: bool, } /// Wrapper around the nomination info of a single nominator for a group of validators. #[derive(Clone, Default)] #[cfg_attr(feature = "std", derive(Debug))] pub struct Nominator { - /// The nominator's account. - who: AccountId, - /// List of validators proposed by this nominator. - edges: Vec>, - /// the stake amount proposed by the nominator as a part of the vote. - budget: ExtendedBalance, - /// Incremented each time a nominee that this nominator voted for has been elected. - load: Fraction, + /// The nominator's account. + who: AccountId, + /// List of validators proposed by this nominator. + edges: Vec>, + /// the stake amount proposed by the nominator as a part of the vote. + budget: ExtendedBalance, + /// Incremented each time a nominee that this nominator voted for has been elected. + load: Fraction, } /// Wrapper around a nominator vote and the load of that vote. #[derive(Clone, Default)] #[cfg_attr(feature = "std", derive(Debug))] pub struct Edge { - /// Account being voted for - who: AccountId, - /// Load of this vote. - load: Fraction, - /// Equal to `edge.load / nom.load`. Stored only to be used with post-processing. - ratio: ExtendedBalance, - /// Index of the candidate stored in the 'candidates' vector. - candidate_index: usize, + /// Account being voted for + who: AccountId, + /// Load of this vote. + load: Fraction, + /// Equal to `edge.load / nom.load`. Stored only to be used with post-processing. + ratio: ExtendedBalance, + /// Index of the candidate stored in the 'candidates' vector. + candidate_index: usize, } /// Perform election based on Phragmén algorithm. @@ -86,187 +86,190 @@ pub struct Edge { /// - The list of elected candidates. /// - The list of nominators and their associated vote weights. pub fn elect( - validator_count: usize, - minimum_validator_count: usize, - validator_iter: FV, - nominator_iter: FN, - stash_of: FS, -) -> Option<(Vec, Vec<(T::AccountId, Vec>)>)> where - FV: Iterator, - FN: Iterator)>, - for <'r> FS: Fn(&'r T::AccountId) -> ExtendedBalance, + validator_count: usize, + minimum_validator_count: usize, + validator_iter: FV, + nominator_iter: FN, + stash_of: FS, +) -> Option<(Vec, Vec<(T::AccountId, Vec>)>)> +where + FV: Iterator, + FN: Iterator)>, + for<'r> FS: Fn(&'r T::AccountId) -> ExtendedBalance, { - - // return structures - let mut elected_candidates: Vec; - let mut assigned: Vec<(T::AccountId, Vec>)>; - let mut c_idx_cache = BTreeMap::::new(); - - // 1- Pre-process candidates and place them in a container, optimisation and add phantom votes. - // Candidates who have 0 stake => have no votes or all null-votes. Kick them out not. - let mut nominators: Vec> = - Vec::with_capacity(validator_iter.size_hint().0 + nominator_iter.size_hint().0); - let mut candidates = validator_iter.map(|(who, _)| { - - let stash_balance = stash_of(&who); - (Candidate { who, ..Default::default() }, stash_balance) - }) - .filter_map(|(mut c, s)| { - c.approval_stake += s; - if c.approval_stake.is_zero() { - None - } else { - Some((c, s)) - } - }) - .enumerate() - .map(|(idx, (c, s))| { - nominators.push(Nominator { - who: c.who.clone(), - edges: vec![ Edge { who: c.who.clone(), candidate_index: idx, ..Default::default() }], - budget: s, - load: Fraction::zero(), - }); - c_idx_cache.insert(c.who.clone(), idx); - c - }) - .collect::>>(); - - // 2- Collect the nominators with the associated votes. - // Also collect approval stake along the way. - nominators.extend(nominator_iter.map(|(who, nominees)| { - let nominator_stake = stash_of(&who); - let mut edges: Vec> = Vec::with_capacity(nominees.len()); - for n in &nominees { - if let Some(idx) = c_idx_cache.get(n) { - // This candidate is valid + already cached. - candidates[*idx].approval_stake = candidates[*idx].approval_stake - .saturating_add(nominator_stake); - edges.push(Edge { who: n.clone(), candidate_index: *idx, ..Default::default() }); - } // else {} would be wrong votes. We don't really care about it. - } - Nominator { - who, - edges: edges, - budget: nominator_stake, - load: Fraction::zero(), - } - })); - - // 4- If we have more candidates then needed, run Phragmén. - if candidates.len() >= minimum_validator_count { - let validator_count = validator_count.min(candidates.len()); - - elected_candidates = Vec::with_capacity(validator_count); - assigned = Vec::with_capacity(validator_count); - // Main election loop - for _round in 0..validator_count { - // Loop 1: initialize score - for c in &mut candidates { - if !c.elected { - c.score = Fraction::from_xth(c.approval_stake); - } - } - // Loop 2: increment score. - for n in &nominators { - for e in &n.edges { - let c = &mut candidates[e.candidate_index]; - if !c.elected && !c.approval_stake.is_zero() { - // Basic fixed-point shifting by 32. - // `n.budget.saturating_mul(SCALE_FACTOR)` will never saturate - // since n.budget cannot exceed u64,despite being stored in u128. yet, - // `*n.load / SCALE_FACTOR` might collapse to zero. Hence, 32 or 16 bits are better scale factors. - // Note that left-associativity in operators precedence is crucially important here. - let temp = - n.budget.saturating_mul(SCALE_FACTOR) / c.approval_stake - * (*n.load / SCALE_FACTOR); - c.score = Fraction::from_parts((*c.score).saturating_add(temp)); - } - } - } - - // Find the best - if let Some(winner) = candidates - .iter_mut() - .filter(|c| !c.elected) - .min_by_key(|c| *c.score) - { - // loop 3: update nominator and edge load - winner.elected = true; - for n in &mut nominators { - for e in &mut n.edges { - if e.who == winner.who { - e.load = Fraction::from_parts(*winner.score - *n.load); - n.load = winner.score; - } - } - } - - elected_candidates.push(winner.who.clone()); - } else { - break - } - } // end of all rounds - - // 4.1- Update backing stake of candidates and nominators - for n in &mut nominators { - let mut assignment = (n.who.clone(), vec![]); - for e in &mut n.edges { - if let Some(c) = elected_candidates.iter().find(|c| **c == e.who) { - if *c != n.who { - let ratio = { - // Full support. No need to calculate. - if *n.load == *e.load { ACCURACY } - else { - // This should not saturate. Safest is to just check - if let Some(r) = ACCURACY.checked_mul(*e.load) { - r / n.load.max(1) - } else { - // Just a simple trick. - *e.load / (n.load.max(1) / ACCURACY) - } - } - }; - e.ratio = ratio; - assignment.1.push((e.who.clone(), ratio)); - } - } - } - - if assignment.1.len() > 0 { - // To ensure an assertion indicating: no stake from the nominator going to waste, - // we add a minimal post-processing to equally assign all of the leftover stake ratios. - let vote_count = assignment.1.len() as ExtendedBalance; - let l = assignment.1.len(); - let sum = assignment.1.iter().map(|a| a.1).sum::(); - let diff = ACCURACY.checked_sub(sum).unwrap_or(0); - let diff_per_vote= diff / vote_count; - - if diff_per_vote > 0 { - for i in 0..l { - assignment.1[i%l].1 = - assignment.1[i%l].1 - .saturating_add(diff_per_vote); - } - } - - // `remainder` is set to be less than maximum votes of a nominator (currently 16). - // safe to cast it to usize. - let remainder = diff - diff_per_vote * vote_count; - for i in 0..remainder as usize { - assignment.1[i%l].1 = - assignment.1[i%l].1 - .saturating_add(1); - } - assigned.push(assignment); - } - } - - } else { - // if we have less than minimum, use the previous validator set. - return None - } - Some((elected_candidates, assigned)) + // return structures + let mut elected_candidates: Vec; + let mut assigned: Vec<(T::AccountId, Vec>)>; + let mut c_idx_cache = BTreeMap::::new(); + + // 1- Pre-process candidates and place them in a container, optimisation and add phantom votes. + // Candidates who have 0 stake => have no votes or all null-votes. Kick them out not. + let mut nominators: Vec> = + Vec::with_capacity(validator_iter.size_hint().0 + nominator_iter.size_hint().0); + let mut candidates = validator_iter + .map(|(who, _)| { + let stash_balance = stash_of(&who); + ( + Candidate { + who, + ..Default::default() + }, + stash_balance, + ) + }) + .filter_map(|(mut c, s)| { + c.approval_stake += s; + if c.approval_stake.is_zero() { + None + } else { + Some((c, s)) + } + }) + .enumerate() + .map(|(idx, (c, s))| { + nominators.push(Nominator { + who: c.who.clone(), + edges: vec![Edge { + who: c.who.clone(), + candidate_index: idx, + ..Default::default() + }], + budget: s, + load: Fraction::zero(), + }); + c_idx_cache.insert(c.who.clone(), idx); + c + }) + .collect::>>(); + + // 2- Collect the nominators with the associated votes. + // Also collect approval stake along the way. + nominators.extend(nominator_iter.map(|(who, nominees)| { + let nominator_stake = stash_of(&who); + let mut edges: Vec> = Vec::with_capacity(nominees.len()); + for n in &nominees { + if let Some(idx) = c_idx_cache.get(n) { + // This candidate is valid + already cached. + candidates[*idx].approval_stake = candidates[*idx].approval_stake.saturating_add(nominator_stake); + edges.push(Edge { + who: n.clone(), + candidate_index: *idx, + ..Default::default() + }); + } // else {} would be wrong votes. We don't really care about it. + } + Nominator { + who, + edges: edges, + budget: nominator_stake, + load: Fraction::zero(), + } + })); + + // 4- If we have more candidates then needed, run Phragmén. + if candidates.len() >= minimum_validator_count { + let validator_count = validator_count.min(candidates.len()); + + elected_candidates = Vec::with_capacity(validator_count); + assigned = Vec::with_capacity(validator_count); + // Main election loop + for _round in 0..validator_count { + // Loop 1: initialize score + for c in &mut candidates { + if !c.elected { + c.score = Fraction::from_xth(c.approval_stake); + } + } + // Loop 2: increment score. + for n in &nominators { + for e in &n.edges { + let c = &mut candidates[e.candidate_index]; + if !c.elected && !c.approval_stake.is_zero() { + // Basic fixed-point shifting by 32. + // `n.budget.saturating_mul(SCALE_FACTOR)` will never saturate + // since n.budget cannot exceed u64,despite being stored in u128. yet, + // `*n.load / SCALE_FACTOR` might collapse to zero. Hence, 32 or 16 bits are better scale factors. + // Note that left-associativity in operators precedence is crucially important here. + let temp = n.budget.saturating_mul(SCALE_FACTOR) / c.approval_stake * (*n.load / SCALE_FACTOR); + c.score = Fraction::from_parts((*c.score).saturating_add(temp)); + } + } + } + + // Find the best + if let Some(winner) = candidates.iter_mut().filter(|c| !c.elected).min_by_key(|c| *c.score) { + // loop 3: update nominator and edge load + winner.elected = true; + for n in &mut nominators { + for e in &mut n.edges { + if e.who == winner.who { + e.load = Fraction::from_parts(*winner.score - *n.load); + n.load = winner.score; + } + } + } + + elected_candidates.push(winner.who.clone()); + } else { + break; + } + } // end of all rounds + + // 4.1- Update backing stake of candidates and nominators + for n in &mut nominators { + let mut assignment = (n.who.clone(), vec![]); + for e in &mut n.edges { + if let Some(c) = elected_candidates.iter().find(|c| **c == e.who) { + if *c != n.who { + let ratio = { + // Full support. No need to calculate. + if *n.load == *e.load { + ACCURACY + } else { + // This should not saturate. Safest is to just check + if let Some(r) = ACCURACY.checked_mul(*e.load) { + r / n.load.max(1) + } else { + // Just a simple trick. + *e.load / (n.load.max(1) / ACCURACY) + } + } + }; + e.ratio = ratio; + assignment.1.push((e.who.clone(), ratio)); + } + } + } + + if assignment.1.len() > 0 { + // To ensure an assertion indicating: no stake from the nominator going to waste, + // we add a minimal post-processing to equally assign all of the leftover stake ratios. + let vote_count = assignment.1.len() as ExtendedBalance; + let l = assignment.1.len(); + let sum = assignment.1.iter().map(|a| a.1).sum::(); + let diff = ACCURACY.checked_sub(sum).unwrap_or(0); + let diff_per_vote = diff / vote_count; + + if diff_per_vote > 0 { + for i in 0..l { + assignment.1[i % l].1 = assignment.1[i % l].1.saturating_add(diff_per_vote); + } + } + + // `remainder` is set to be less than maximum votes of a nominator (currently 16). + // safe to cast it to usize. + let remainder = diff - diff_per_vote * vote_count; + for i in 0..remainder as usize { + assignment.1[i % l].1 = assignment.1[i % l].1.saturating_add(1); + } + assigned.push(assignment); + } + } + } else { + // if we have less than minimum, use the previous validator set. + return None; + } + Some((elected_candidates, assigned)) } /// Performs equalize post-processing to the output of the election algorithm @@ -275,117 +278,125 @@ pub fn elect( /// /// No value is returned from the function and the `expo_map` parameter is updated. pub fn equalize( - assignments: &mut Vec<(T::AccountId, ExtendedBalance, Vec<(T::AccountId, ExtendedBalance, ExtendedBalance)>)>, - expo_map: &mut ExpoMap, - tolerance: ExtendedBalance, - iterations: usize, + assignments: &mut Vec<( + T::AccountId, + ExtendedBalance, + Vec<(T::AccountId, ExtendedBalance, ExtendedBalance)>, + )>, + expo_map: &mut ExpoMap, + tolerance: ExtendedBalance, + iterations: usize, ) { - for _i in 0..iterations { - let mut max_diff = 0; - assignments.iter_mut().for_each(|(n, budget, assignment)| { - let diff = do_equalize::(&n, *budget, assignment, expo_map, tolerance); - if diff > max_diff { - max_diff = diff; - } - }); - if max_diff < tolerance { - break; - } - } + for _i in 0..iterations { + let mut max_diff = 0; + assignments.iter_mut().for_each(|(n, budget, assignment)| { + let diff = do_equalize::(&n, *budget, assignment, expo_map, tolerance); + if diff > max_diff { + max_diff = diff; + } + }); + if max_diff < tolerance { + break; + } + } } - fn do_equalize( - nominator: &T::AccountId, - budget_balance: ExtendedBalance, - elected_edges: &mut Vec<(T::AccountId, ExtendedBalance, ExtendedBalance)>, - expo_map: &mut ExpoMap, - tolerance: ExtendedBalance + nominator: &T::AccountId, + budget_balance: ExtendedBalance, + elected_edges: &mut Vec<(T::AccountId, ExtendedBalance, ExtendedBalance)>, + expo_map: &mut ExpoMap, + tolerance: ExtendedBalance, ) -> ExtendedBalance { - - let budget = budget_balance; - - // Nothing to do. This nominator had nothing useful. - // Defensive only. Assignment list should always be populated. - if elected_edges.is_empty() { return 0; } - - let stake_used = elected_edges - .iter() - .fold(0 as ExtendedBalance, |s, e| s.saturating_add(e.2)); - - let backed_stakes_iter = elected_edges - .iter() - .filter_map(|e| expo_map.get(&e.0)) - .map(|e| e.total); - - let backing_backed_stake = elected_edges - .iter() - .filter(|e| e.2 > 0) - .filter_map(|e| expo_map.get(&e.0)) - .map(|e| e.total) - .collect::>(); - - let mut difference: u128; - if backing_backed_stake.len() > 0 { - let max_stake = backing_backed_stake - .iter() - .max() - .expect("vector with positive length will have a max; qed"); - let min_stake = backed_stakes_iter - .min() - .expect("iterator with positive length will have a min; qed"); - - difference = max_stake.saturating_sub(min_stake); - difference = difference.saturating_add(budget.saturating_sub(stake_used)); - if difference < tolerance { - return difference; - } - } else { - difference = budget; - } - - // Undo updates to exposure - elected_edges.iter_mut().for_each(|e| { - if let Some(expo) = expo_map.get_mut(&e.0) { - expo.total = expo.total.saturating_sub(e.2); - expo.others.retain(|i_expo| i_expo.who != *nominator); - } - e.2 = 0; - }); - - elected_edges.sort_unstable_by_key(|e| - if let Some(e) = expo_map.get(&e.0) { e.total } else { Zero::zero() } - ); - - let mut cumulative_stake: ExtendedBalance = 0; - let mut last_index = elected_edges.len() - 1; - elected_edges.iter_mut().enumerate().for_each(|(idx, e)| { - if let Some(expo) = expo_map.get_mut(&e.0) { - let stake: ExtendedBalance = expo.total; - let stake_mul = stake.saturating_mul(idx as ExtendedBalance); - let stake_sub = stake_mul.saturating_sub(cumulative_stake); - if stake_sub > budget { - last_index = idx.checked_sub(1).unwrap_or(0); - return - } - cumulative_stake = cumulative_stake.saturating_add(stake); - } - }); - - let last_stake = elected_edges[last_index].2; - let split_ways = last_index + 1; - let excess = budget - .saturating_add(cumulative_stake) - .saturating_sub(last_stake.saturating_mul(split_ways as ExtendedBalance)); - elected_edges.iter_mut().take(split_ways).for_each(|e| { - if let Some(expo) = expo_map.get_mut(&e.0) { - e.2 = (excess / split_ways as ExtendedBalance) - .saturating_add(last_stake) - .saturating_sub(expo.total); - expo.total = expo.total.saturating_add(e.2); - expo.others.push(IndividualExpo { who: nominator.clone(), value: e.2}); - } - }); - - difference + let budget = budget_balance; + + // Nothing to do. This nominator had nothing useful. + // Defensive only. Assignment list should always be populated. + if elected_edges.is_empty() { + return 0; + } + + let stake_used = elected_edges + .iter() + .fold(0 as ExtendedBalance, |s, e| s.saturating_add(e.2)); + + let backed_stakes_iter = elected_edges.iter().filter_map(|e| expo_map.get(&e.0)).map(|e| e.total); + + let backing_backed_stake = elected_edges + .iter() + .filter(|e| e.2 > 0) + .filter_map(|e| expo_map.get(&e.0)) + .map(|e| e.total) + .collect::>(); + + let mut difference: u128; + if backing_backed_stake.len() > 0 { + let max_stake = backing_backed_stake + .iter() + .max() + .expect("vector with positive length will have a max; qed"); + let min_stake = backed_stakes_iter + .min() + .expect("iterator with positive length will have a min; qed"); + + difference = max_stake.saturating_sub(min_stake); + difference = difference.saturating_add(budget.saturating_sub(stake_used)); + if difference < tolerance { + return difference; + } + } else { + difference = budget; + } + + // Undo updates to exposure + elected_edges.iter_mut().for_each(|e| { + if let Some(expo) = expo_map.get_mut(&e.0) { + expo.total = expo.total.saturating_sub(e.2); + expo.others.retain(|i_expo| i_expo.who != *nominator); + } + e.2 = 0; + }); + + elected_edges.sort_unstable_by_key(|e| { + if let Some(e) = expo_map.get(&e.0) { + e.total + } else { + Zero::zero() + } + }); + + let mut cumulative_stake: ExtendedBalance = 0; + let mut last_index = elected_edges.len() - 1; + elected_edges.iter_mut().enumerate().for_each(|(idx, e)| { + if let Some(expo) = expo_map.get_mut(&e.0) { + let stake: ExtendedBalance = expo.total; + let stake_mul = stake.saturating_mul(idx as ExtendedBalance); + let stake_sub = stake_mul.saturating_sub(cumulative_stake); + if stake_sub > budget { + last_index = idx.checked_sub(1).unwrap_or(0); + return; + } + cumulative_stake = cumulative_stake.saturating_add(stake); + } + }); + + let last_stake = elected_edges[last_index].2; + let split_ways = last_index + 1; + let excess = budget + .saturating_add(cumulative_stake) + .saturating_sub(last_stake.saturating_mul(split_ways as ExtendedBalance)); + elected_edges.iter_mut().take(split_ways).for_each(|e| { + if let Some(expo) = expo_map.get_mut(&e.0) { + e.2 = (excess / split_ways as ExtendedBalance) + .saturating_add(last_stake) + .saturating_sub(expo.total); + expo.total = expo.total.saturating_add(e.2); + expo.others.push(IndividualExpo { + who: nominator.clone(), + value: e.2, + }); + } + }); + + difference } diff --git a/srml/staking/src/tests.rs b/srml/staking/src/tests.rs index eaadd0602..b93a6198c 100644 --- a/srml/staking/src/tests.rs +++ b/srml/staking/src/tests.rs @@ -1,166 +1,268 @@ +use super::MONTH_IN_SECONDS; +use super::*; +use mock::*; use primitives::traits::OnInitialize; use runtime_io::with_externalities; -use srml_support::{assert_eq_uvec, assert_err, assert_noop, assert_ok, EnumerableStorageMap}; use srml_support::traits::{Currency, ReservableCurrency, WithdrawReason, WithdrawReasons}; -use mock::*; -use super::*; -use super::MONTH_IN_SECONDS; +use srml_support::{assert_eq_uvec, assert_err, assert_noop, assert_ok, EnumerableStorageMap}; #[test] fn test_env_build() { - with_externalities(&mut ExtBuilder::default() - .existential_deposit(0).build(), || { + with_externalities(&mut ExtBuilder::default().existential_deposit(0).build(), || { check_exposure_all(); assert_eq!(Staking::bonded(&11), Some(10)); - assert_eq!(Staking::ledger(&10), Some(StakingLedgers { - stash: 11, - total_ring: 100 * COIN, - total_deposit_ring: 100 * COIN, - active_deposit_ring: 100 * COIN, - active_ring: 100 * COIN, - total_kton: 0, - active_kton: 0, - deposit_items: vec![TimeDepositItem {value: 100 * COIN, start_time: 0, expire_time: 12 * MONTH_IN_SECONDS as u64}], - unlocking: vec![] - })); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedgers { + stash: 11, + total_ring: 100 * COIN, + total_deposit_ring: 100 * COIN, + active_deposit_ring: 100 * COIN, + active_ring: 100 * COIN, + total_kton: 0, + active_kton: 0, + deposit_items: vec![TimeDepositItem { + value: 100 * COIN, + start_time: 0, + expire_time: 12 * MONTH_IN_SECONDS as u64 + }], + unlocking: vec![] + }) + ); assert_eq!(Kton::free_balance(&11), COIN / 100); assert_eq!(Kton::total_issuance(), 16 * COIN / 100); let origin_ledger = Staking::ledger(&10).unwrap(); Ring::deposit_creating(&11, 100 * COIN); - assert_ok!(Staking::bond_extra(Origin::signed(11), StakingBalance::Ring(20 * COIN), 13)); - assert_eq!(Staking::ledger(&10), Some(StakingLedgers { - stash: 11, - total_ring: origin_ledger.total_ring + 20 * COIN, - total_deposit_ring: origin_ledger.total_deposit_ring + 20 * COIN, - active_deposit_ring: origin_ledger.active_deposit_ring + 20 * COIN, - active_ring: origin_ledger.active_ring + 20 * COIN, - total_kton: 0, - active_kton: 0, - deposit_items: vec![TimeDepositItem {value: 100 * COIN, start_time: 0, expire_time: 12 * MONTH_IN_SECONDS as u64}, - TimeDepositItem {value: 20 * COIN, start_time: 0, expire_time: 13 * MONTH_IN_SECONDS as u64}], - unlocking: vec![] - })); + assert_ok!(Staking::bond_extra( + Origin::signed(11), + StakingBalance::Ring(20 * COIN), + 13 + )); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedgers { + stash: 11, + total_ring: origin_ledger.total_ring + 20 * COIN, + total_deposit_ring: origin_ledger.total_deposit_ring + 20 * COIN, + active_deposit_ring: origin_ledger.active_deposit_ring + 20 * COIN, + active_ring: origin_ledger.active_ring + 20 * COIN, + total_kton: 0, + active_kton: 0, + deposit_items: vec![ + TimeDepositItem { + value: 100 * COIN, + start_time: 0, + expire_time: 12 * MONTH_IN_SECONDS as u64 + }, + TimeDepositItem { + value: 20 * COIN, + start_time: 0, + expire_time: 13 * MONTH_IN_SECONDS as u64 + } + ], + unlocking: vec![] + }) + ); }); } #[test] fn normal_kton_should_work() { - with_externalities(&mut ExtBuilder::default() - .existential_deposit(0).build(), || { - + with_externalities(&mut ExtBuilder::default().existential_deposit(0).build(), || { Kton::deposit_creating(&1001, 10 * COIN); - assert_ok!(Staking::bond(Origin::signed(1001), 1000, StakingBalance::Kton(10 * COIN), RewardDestination::Stash, 0)); - assert_eq!(Staking::ledger(&1000), Some(StakingLedgers { - stash: 1001, - total_ring: 0, - total_deposit_ring: 0, - active_deposit_ring: 0, - active_ring: 0, - total_kton: 10 * COIN, - active_kton: 10 * COIN, - deposit_items: vec![], - unlocking: vec![] - })); - - assert_eq!(Kton::locks(&1001), vec![kton::BalanceLock {id: STAKING_ID, amount: 10 * COIN, until: u64::max_value(), reasons: WithdrawReasons::all()}]); + assert_ok!(Staking::bond( + Origin::signed(1001), + 1000, + StakingBalance::Kton(10 * COIN), + RewardDestination::Stash, + 0 + )); + assert_eq!( + Staking::ledger(&1000), + Some(StakingLedgers { + stash: 1001, + total_ring: 0, + total_deposit_ring: 0, + active_deposit_ring: 0, + active_ring: 0, + total_kton: 10 * COIN, + active_kton: 10 * COIN, + deposit_items: vec![], + unlocking: vec![] + }) + ); + + assert_eq!( + Kton::locks(&1001), + vec![kton::BalanceLock { + id: STAKING_ID, + amount: 10 * COIN, + until: u64::max_value(), + reasons: WithdrawReasons::all() + }] + ); // promise_month should not work for kton Kton::deposit_creating(&2001, 10 * COIN); - assert_ok!(Staking::bond(Origin::signed(2001), 2000, StakingBalance::Kton(10 * COIN), RewardDestination::Stash, 12)); - assert_eq!(Staking::ledger(&2000),Some(StakingLedgers { - stash: 2001, - total_ring: 0, - total_deposit_ring: 0, - active_deposit_ring: 0, - active_ring: 0, - total_kton: 10 * COIN, - active_kton: 10 * COIN, - deposit_items: vec![], - unlocking: vec![] - })); - + assert_ok!(Staking::bond( + Origin::signed(2001), + 2000, + StakingBalance::Kton(10 * COIN), + RewardDestination::Stash, + 12 + )); + assert_eq!( + Staking::ledger(&2000), + Some(StakingLedgers { + stash: 2001, + total_ring: 0, + total_deposit_ring: 0, + active_deposit_ring: 0, + active_ring: 0, + total_kton: 10 * COIN, + active_kton: 10 * COIN, + deposit_items: vec![], + unlocking: vec![] + }) + ); }); } #[test] fn time_deposit_ring_unbond_and_withdraw_should_work() { - with_externalities(&mut ExtBuilder::default() - .existential_deposit(0).build(), || { - + with_externalities(&mut ExtBuilder::default().existential_deposit(0).build(), || { Timestamp::set_timestamp(13 * MONTH_IN_SECONDS as u64); Ring::deposit_creating(&11, 1000 * COIN); Staking::unbond(Origin::signed(10), StakingBalance::Ring(10 * COIN)); - assert_eq!(Staking::ledger(&10), Some(StakingLedgers { - stash: 11, - total_ring: 100 * COIN, - total_deposit_ring: 100 * COIN, - active_deposit_ring: 90 * COIN, - active_ring: 90 * COIN, - total_kton: 0, - active_kton: 0, - deposit_items: vec![TimeDepositItem {value: 90 * COIN, start_time: 0, expire_time: 12 * MONTH_IN_SECONDS as u64}], - unlocking: vec![UnlockChunk { value: StakingBalance::Ring(10000000000), era: 3, is_time_deposit: true }] - })); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedgers { + stash: 11, + total_ring: 100 * COIN, + total_deposit_ring: 100 * COIN, + active_deposit_ring: 90 * COIN, + active_ring: 90 * COIN, + total_kton: 0, + active_kton: 0, + deposit_items: vec![TimeDepositItem { + value: 90 * COIN, + start_time: 0, + expire_time: 12 * MONTH_IN_SECONDS as u64 + }], + unlocking: vec![UnlockChunk { + value: StakingBalance::Ring(10000000000), + era: 3, + is_time_deposit: true + }] + }) + ); Staking::unbond(Origin::signed(10), StakingBalance::Ring(20 * COIN)); - assert_eq!(Staking::ledger(&10), Some(StakingLedgers { - stash: 11, - total_ring: 100 * COIN, - total_deposit_ring: 100 * COIN, - active_deposit_ring: 70 * COIN, - active_ring: 70 * COIN, - total_kton: 0, - active_kton: 0, - deposit_items: vec![TimeDepositItem {value: 70 * COIN, start_time: 0, expire_time: 12 * MONTH_IN_SECONDS as u64 }], - unlocking: vec![UnlockChunk { value: StakingBalance::Ring(10000000000), era: 3, is_time_deposit: true}, - UnlockChunk { value: StakingBalance::Ring(20000000000), era: 3, is_time_deposit: true}] - })); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedgers { + stash: 11, + total_ring: 100 * COIN, + total_deposit_ring: 100 * COIN, + active_deposit_ring: 70 * COIN, + active_ring: 70 * COIN, + total_kton: 0, + active_kton: 0, + deposit_items: vec![TimeDepositItem { + value: 70 * COIN, + start_time: 0, + expire_time: 12 * MONTH_IN_SECONDS as u64 + }], + unlocking: vec![ + UnlockChunk { + value: StakingBalance::Ring(10000000000), + era: 3, + is_time_deposit: true + }, + UnlockChunk { + value: StakingBalance::Ring(20000000000), + era: 3, + is_time_deposit: true + } + ] + }) + ); // more than active ring Staking::unbond(Origin::signed(10), StakingBalance::Ring(120 * COIN)); - assert_eq!(Staking::ledger(&10), Some(StakingLedgers { - stash: 11, - total_ring: 100 * COIN, - total_deposit_ring: 100 * COIN, - active_deposit_ring: 0, - active_ring: 0, - total_kton: 0, - active_kton: 0, - deposit_items: vec![], // should be cleared - unlocking: vec![UnlockChunk { value: StakingBalance::Ring(10000000000), era: 3, is_time_deposit: true}, - UnlockChunk { value: StakingBalance::Ring(20000000000), era: 3, is_time_deposit: true}, - UnlockChunk { value: StakingBalance::Ring(70000000000), era: 3, is_time_deposit: true}, - ] - })); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedgers { + stash: 11, + total_ring: 100 * COIN, + total_deposit_ring: 100 * COIN, + active_deposit_ring: 0, + active_ring: 0, + total_kton: 0, + active_kton: 0, + deposit_items: vec![], // should be cleared + unlocking: vec![ + UnlockChunk { + value: StakingBalance::Ring(10000000000), + era: 3, + is_time_deposit: true + }, + UnlockChunk { + value: StakingBalance::Ring(20000000000), + era: 3, + is_time_deposit: true + }, + UnlockChunk { + value: StakingBalance::Ring(70000000000), + era: 3, + is_time_deposit: true + }, + ] + }) + ); start_era(3); assert_ok!(Staking::withdraw_unbonded(Origin::signed(10))); - assert_eq!(Staking::ledger(&10), Some(StakingLedgers { - stash: 11, - total_ring: 0, - total_deposit_ring: 0, - active_deposit_ring: 0, - active_ring: 0, - total_kton: 0, - active_kton: 0, - deposit_items: vec![], // should be cleared - unlocking: vec![] - })); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedgers { + stash: 11, + total_ring: 0, + total_deposit_ring: 0, + active_deposit_ring: 0, + active_ring: 0, + total_kton: 0, + active_kton: 0, + deposit_items: vec![], // should be cleared + unlocking: vec![] + }) + ); let free_balance = Ring::free_balance(&11); - assert_eq!(Ring::locks(&11), vec![balances::BalanceLock {id: STAKING_ID, amount: 0, until: u64::max_value(), reasons: WithdrawReasons::all()}]); - assert_ok!(Ring::ensure_can_withdraw(&11, free_balance, WithdrawReason::Transfer, 0)); + assert_eq!( + Ring::locks(&11), + vec![balances::BalanceLock { + id: STAKING_ID, + amount: 0, + until: u64::max_value(), + reasons: WithdrawReasons::all() + }] + ); + assert_ok!(Ring::ensure_can_withdraw( + &11, + free_balance, + WithdrawReason::Transfer, + 0 + )); }); } #[test] fn normal_unbond_should_work() { - with_externalities(&mut ExtBuilder::default() - .existential_deposit(0).build(), || { - + with_externalities(&mut ExtBuilder::default().existential_deposit(0).build(), || { // unbond normal ring Ring::deposit_creating(&11, 1000 * COIN); let kton_free_balance = Kton::free_balance(&11); @@ -168,155 +270,219 @@ fn normal_unbond_should_work() { Staking::bond_extra(Origin::signed(11), StakingBalance::Ring(200 * COIN), 12); assert_eq!(Kton::free_balance(&11), kton_free_balance + 200 * COIN / 10000); - origin_ledger.deposit_items.push(TimeDepositItem {value: 200 * COIN, start_time: 0, expire_time: 12 * MONTH_IN_SECONDS as u64}); - assert_eq!(Staking::ledger(&10), Some(StakingLedgers { - stash: 11, - total_ring: origin_ledger.total_ring + 200 * COIN, - total_deposit_ring: origin_ledger.total_deposit_ring + 200 * COIN, - active_deposit_ring: origin_ledger.active_deposit_ring + 200 * COIN, - active_ring: origin_ledger.active_ring + 200 * COIN, - total_kton: origin_ledger.total_kton, - active_kton: origin_ledger.active_kton, - deposit_items: origin_ledger.deposit_items, - unlocking: origin_ledger.unlocking - })); + origin_ledger.deposit_items.push(TimeDepositItem { + value: 200 * COIN, + start_time: 0, + expire_time: 12 * MONTH_IN_SECONDS as u64, + }); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedgers { + stash: 11, + total_ring: origin_ledger.total_ring + 200 * COIN, + total_deposit_ring: origin_ledger.total_deposit_ring + 200 * COIN, + active_deposit_ring: origin_ledger.active_deposit_ring + 200 * COIN, + active_ring: origin_ledger.active_ring + 200 * COIN, + total_kton: origin_ledger.total_kton, + active_kton: origin_ledger.active_kton, + deposit_items: origin_ledger.deposit_items, + unlocking: origin_ledger.unlocking + }) + ); assert_eq!(Kton::free_balance(&11), 300 * COIN / 10000); let mut origin_ledger = Staking::ledger(&10).unwrap(); // actually acc 11 only has 0.03 Kton // we try to bond 1 kton assert_ok!(Staking::bond_extra(Origin::signed(11), StakingBalance::Kton(COIN), 0)); - assert_eq!(Staking::ledger(&10), Some(StakingLedgers { - stash: 11, - total_ring: origin_ledger.total_ring, - total_deposit_ring: origin_ledger.total_deposit_ring, - active_deposit_ring: origin_ledger.active_deposit_ring, - active_ring: origin_ledger.active_ring, - total_kton: origin_ledger.total_kton + 300 * COIN / 10000, - active_kton: origin_ledger.active_kton + 300 * COIN / 10000, - deposit_items: origin_ledger.deposit_items, - unlocking: origin_ledger.unlocking - })); - - assert_ok!(Staking::unbond(Origin::signed(10), StakingBalance::Kton(300 * COIN / 10000))); - + assert_eq!( + Staking::ledger(&10), + Some(StakingLedgers { + stash: 11, + total_ring: origin_ledger.total_ring, + total_deposit_ring: origin_ledger.total_deposit_ring, + active_deposit_ring: origin_ledger.active_deposit_ring, + active_ring: origin_ledger.active_ring, + total_kton: origin_ledger.total_kton + 300 * COIN / 10000, + active_kton: origin_ledger.active_kton + 300 * COIN / 10000, + deposit_items: origin_ledger.deposit_items, + unlocking: origin_ledger.unlocking + }) + ); + + assert_ok!(Staking::unbond( + Origin::signed(10), + StakingBalance::Kton(300 * COIN / 10000) + )); }); } #[test] fn punished_unbond_should_work() { - with_externalities(&mut ExtBuilder::default() - .existential_deposit(0).build(), || { + with_externalities(&mut ExtBuilder::default().existential_deposit(0).build(), || { Ring::deposit_creating(&1001, 100 * COIN); Kton::deposit_creating(&1001, COIN / 100000); // timestamp now is 0. // free balance of kton is too low to work - assert_ok!(Staking::bond(Origin::signed(1001), 1000, StakingBalance::Ring(10 * COIN), RewardDestination::Stash, 36)); - assert_eq!(Staking::ledger(&1000), Some(StakingLedgers { - stash: 1001, - total_ring: 10 * COIN, - total_deposit_ring: 10 * COIN, - active_deposit_ring: 10 * COIN, - active_ring: 10 * COIN, - total_kton: 0, - active_kton: 0, - deposit_items: vec![TimeDepositItem { value: 10 * COIN, start_time: 0, expire_time: 36 * MONTH_IN_SECONDS as u64 }], // should be cleared - unlocking: vec![] - })); + assert_ok!(Staking::bond( + Origin::signed(1001), + 1000, + StakingBalance::Ring(10 * COIN), + RewardDestination::Stash, + 36 + )); + assert_eq!( + Staking::ledger(&1000), + Some(StakingLedgers { + stash: 1001, + total_ring: 10 * COIN, + total_deposit_ring: 10 * COIN, + active_deposit_ring: 10 * COIN, + active_ring: 10 * COIN, + total_kton: 0, + active_kton: 0, + deposit_items: vec![TimeDepositItem { + value: 10 * COIN, + start_time: 0, + expire_time: 36 * MONTH_IN_SECONDS as u64 + }], // should be cleared + unlocking: vec![] + }) + ); let origin_ledger = Staking::ledger(&1000).unwrap(); let kton_free_balance = Kton::free_balance(&1001); - assert_ok!(Staking::unbond_with_punish(Origin::signed(1000), 10 * COIN, MONTH_IN_SECONDS as u64 * 36)); + assert_ok!(Staking::unbond_with_punish( + Origin::signed(1000), + 10 * COIN, + MONTH_IN_SECONDS as u64 * 36 + )); assert_eq!(Staking::ledger(&1000), Some(origin_ledger.clone())); assert_eq!(Kton::free_balance(&1001), kton_free_balance); - // set more kton balance to make it work Kton::deposit_creating(&1001, 10 * COIN); let kton_free_balance = Kton::free_balance(&1001); - assert_ok!(Staking::unbond_with_punish(Origin::signed(1000), 5 * COIN, MONTH_IN_SECONDS as u64 * 36)); - assert_eq!(Staking::ledger(&1000), Some(StakingLedgers { - stash: 1001, - total_ring: origin_ledger.total_ring, - total_deposit_ring: origin_ledger.total_deposit_ring, - active_deposit_ring: origin_ledger.active_deposit_ring - 5 * COIN, - active_ring: origin_ledger.active_ring - 5 * COIN, - total_kton: origin_ledger.total_kton, - active_kton: origin_ledger.active_kton, - deposit_items: vec![TimeDepositItem { value: 5 * COIN, start_time: 0, expire_time: 36 * MONTH_IN_SECONDS as u64 }], - unlocking: vec![UnlockChunk { value: StakingBalance::Ring(5 * COIN), era: 3, is_time_deposit: true }] - })); + assert_ok!(Staking::unbond_with_punish( + Origin::signed(1000), + 5 * COIN, + MONTH_IN_SECONDS as u64 * 36 + )); + assert_eq!( + Staking::ledger(&1000), + Some(StakingLedgers { + stash: 1001, + total_ring: origin_ledger.total_ring, + total_deposit_ring: origin_ledger.total_deposit_ring, + active_deposit_ring: origin_ledger.active_deposit_ring - 5 * COIN, + active_ring: origin_ledger.active_ring - 5 * COIN, + total_kton: origin_ledger.total_kton, + active_kton: origin_ledger.active_kton, + deposit_items: vec![TimeDepositItem { + value: 5 * COIN, + start_time: 0, + expire_time: 36 * MONTH_IN_SECONDS as u64 + }], + unlocking: vec![UnlockChunk { + value: StakingBalance::Ring(5 * COIN), + era: 3, + is_time_deposit: true + }] + }) + ); let kton_punishment = utils::compute_kton_return::(5 * COIN, 36); assert_eq!(Kton::free_balance(&1001), kton_free_balance - 3 * kton_punishment); // if deposit_item.value == 0 // the whole item should be be dropped - assert_ok!(Staking::unbond_with_punish(Origin::signed(1000), 5 * COIN, MONTH_IN_SECONDS as u64 * 36)); + assert_ok!(Staking::unbond_with_punish( + Origin::signed(1000), + 5 * COIN, + MONTH_IN_SECONDS as u64 * 36 + )); assert_eq!(Staking::ledger(&1000).unwrap().deposit_items, vec![]); }); } - #[test] fn transform_to_promised_ring_should_work() { - with_externalities(&mut ExtBuilder::default() - .existential_deposit(0).build(), || { - + with_externalities(&mut ExtBuilder::default().existential_deposit(0).build(), || { Ring::deposit_creating(&1001, 100 * COIN); - assert_ok!(Staking::bond(Origin::signed(1001), 1000, StakingBalance::Ring(10 * COIN), RewardDestination::Stash, 0)); + assert_ok!(Staking::bond( + Origin::signed(1001), + 1000, + StakingBalance::Ring(10 * COIN), + RewardDestination::Stash, + 0 + )); let origin_ledger = Staking::ledger(&1000).unwrap(); let kton_free_balance = Kton::free_balance(&1001); assert_ok!(Staking::promise_extra(Origin::signed(1000), 5 * COIN, 12)); - assert_eq!(Staking::ledger(&1000), Some(StakingLedgers { - stash: 1001, - total_ring: origin_ledger.total_ring, - total_deposit_ring: origin_ledger.total_deposit_ring + 5 * COIN, - active_deposit_ring: origin_ledger.active_deposit_ring + 5 * COIN, - active_ring: origin_ledger.active_ring, - total_kton: origin_ledger.total_kton, - active_kton: origin_ledger.active_kton, - deposit_items: vec![ TimeDepositItem { value: 5 * COIN, start_time: 0, expire_time: 12 * MONTH_IN_SECONDS as u64 }], - unlocking: vec![] - })); + assert_eq!( + Staking::ledger(&1000), + Some(StakingLedgers { + stash: 1001, + total_ring: origin_ledger.total_ring, + total_deposit_ring: origin_ledger.total_deposit_ring + 5 * COIN, + active_deposit_ring: origin_ledger.active_deposit_ring + 5 * COIN, + active_ring: origin_ledger.active_ring, + total_kton: origin_ledger.total_kton, + active_kton: origin_ledger.active_kton, + deposit_items: vec![TimeDepositItem { + value: 5 * COIN, + start_time: 0, + expire_time: 12 * MONTH_IN_SECONDS as u64 + }], + unlocking: vec![] + }) + ); assert_eq!(Kton::free_balance(&1001), kton_free_balance + (5 * COIN / 10000)); - }); } #[test] fn expired_ring_should_capable_to_promise_again() { - with_externalities(&mut ExtBuilder::default() - .existential_deposit(0).build(), || { - + with_externalities(&mut ExtBuilder::default().existential_deposit(0).build(), || { Ring::deposit_creating(&1001, 100 * COIN); - assert_ok!(Staking::bond(Origin::signed(1001), 1000, StakingBalance::Ring(10 * COIN), RewardDestination::Stash, 12)); + assert_ok!(Staking::bond( + Origin::signed(1001), + 1000, + StakingBalance::Ring(10 * COIN), + RewardDestination::Stash, + 12 + )); let origin_ledger = Staking::ledger(&1000).unwrap(); Timestamp::set_timestamp(13 * MONTH_IN_SECONDS as u64); assert_ok!(Staking::promise_extra(Origin::signed(1000), 5 * COIN, 13)); - assert_eq!(Staking::ledger(&1000), Some(StakingLedgers { - stash: 1001, - total_ring: origin_ledger.total_ring, - total_deposit_ring: 5 * COIN, - active_deposit_ring: 5 * COIN, - active_ring: origin_ledger.active_ring, - total_kton: origin_ledger.total_kton, - active_kton: origin_ledger.active_kton, - // old deposit_item with 12 months promised removed - deposit_items: vec![ TimeDepositItem { value: 5 * COIN, start_time: 33696000, expire_time: 26 * MONTH_IN_SECONDS as u64 }], - unlocking: vec![] - })); + assert_eq!( + Staking::ledger(&1000), + Some(StakingLedgers { + stash: 1001, + total_ring: origin_ledger.total_ring, + total_deposit_ring: 5 * COIN, + active_deposit_ring: 5 * COIN, + active_ring: origin_ledger.active_ring, + total_kton: origin_ledger.total_kton, + active_kton: origin_ledger.active_kton, + // old deposit_item with 12 months promised removed + deposit_items: vec![TimeDepositItem { + value: 5 * COIN, + start_time: 33696000, + expire_time: 26 * MONTH_IN_SECONDS as u64 + }], + unlocking: vec![] + }) + ); }); } #[test] fn inflation_should_be_correct() { - with_externalities(&mut ExtBuilder::default() - .existential_deposit(0).build(), || { - + with_externalities(&mut ExtBuilder::default().existential_deposit(0).build(), || { let initial_issuance = 1_200_000_000 * COIN; let surplus_needed = initial_issuance - Ring::total_issuance(); Ring::deposit_into_existing(&11, surplus_needed); @@ -330,8 +496,7 @@ fn inflation_should_be_correct() { #[test] fn reward_should_work_correctly() { - with_externalities(&mut ExtBuilder::default() - .existential_deposit(0).build(), || { + with_externalities(&mut ExtBuilder::default().existential_deposit(0).build(), || { // create controller account Ring::deposit_creating(&2000, COIN); Ring::deposit_creating(&1000, COIN); @@ -340,7 +505,7 @@ fn reward_should_work_correctly() { Ring::deposit_creating(&2001, 2000 * COIN); Kton::deposit_creating(&2001, 10 * COIN); // new validator - Ring::deposit_creating(&1001, 300 * COIN); + Ring::deposit_creating(&1001, 300 * COIN); Kton::deposit_creating(&1001, 1 * COIN); // handle some dirty work Ring::deposit_creating(&201, 2000 * COIN); @@ -348,21 +513,39 @@ fn reward_should_work_correctly() { assert_eq!(Kton::free_balance(&201), 10 * COIN); // 2001-2000 - Staking::bond(Origin::signed(2001), 2000, StakingBalance::Ring(300 * COIN), RewardDestination::Controller, 12); + Staking::bond( + Origin::signed(2001), + 2000, + StakingBalance::Ring(300 * COIN), + RewardDestination::Controller, + 12, + ); Staking::bond_extra(Origin::signed(2001), StakingBalance::Kton(1 * COIN), 0); // 1001-1000 - Staking::bond(Origin::signed(1001), 1000, StakingBalance::Ring(300 * COIN), RewardDestination::Controller, 12); + Staking::bond( + Origin::signed(1001), + 1000, + StakingBalance::Ring(300 * COIN), + RewardDestination::Controller, + 12, + ); Staking::bond_extra(Origin::signed(1001), StakingBalance::Kton(1 * COIN), 0); let ring_pool = Staking::ring_pool(); let kton_pool = Staking::kton_pool(); // 201-200 - Staking::bond(Origin::signed(201), 200, StakingBalance::Ring(3000 * COIN - ring_pool), RewardDestination::Stash, 12); + Staking::bond( + Origin::signed(201), + 200, + StakingBalance::Ring(3000 * COIN - ring_pool), + RewardDestination::Stash, + 12, + ); Staking::bond_extra(Origin::signed(201), StakingBalance::Kton(10 * COIN - kton_pool), 0); // ring_pool and kton_pool assert_eq!(Staking::ring_pool(), 3000 * COIN); assert_eq!(Staking::kton_pool(), 10 * COIN); // 1/5 ring_ppol and 1/5 kton_pool - Staking::validate(Origin::signed(2000), [0;8].to_vec(), 0, 3); + Staking::validate(Origin::signed(2000), [0; 8].to_vec(), 0, 3); Staking::nominate(Origin::signed(1000), vec![2001]); assert_eq!(Staking::ledger(&2000).unwrap().active_kton, 1 * COIN); @@ -373,11 +556,17 @@ fn reward_should_work_correctly() { Staking::select_validators(); Staking::reward_validator(&2001, 1200 * COIN); - assert_eq!(Staking::stakers(2001), - Exposures { - total: 1200000000000, - own: 600000000000, - others: vec![IndividualExpo { who: 1001, value: 600000000000 }] }); + assert_eq!( + Staking::stakers(2001), + Exposures { + total: 1200000000000, + own: 600000000000, + others: vec![IndividualExpo { + who: 1001, + value: 600000000000 + }] + } + ); assert_eq!(Ring::free_balance(&2000), 601 * COIN); assert_eq!(Ring::free_balance(&1000), 601 * COIN); }); @@ -385,15 +574,19 @@ fn reward_should_work_correctly() { #[test] fn slash_should_work() { - with_externalities(&mut ExtBuilder::default() - .existential_deposit(0).build(), || { - + with_externalities(&mut ExtBuilder::default().existential_deposit(0).build(), || { Ring::deposit_creating(&1001, 100 * COIN); Kton::deposit_creating(&1001, 100 * COIN); - Staking::bond(Origin::signed(1001), 1000, StakingBalance::Ring(50 * COIN), RewardDestination::Controller, 0); + Staking::bond( + Origin::signed(1001), + 1000, + StakingBalance::Ring(50 * COIN), + RewardDestination::Controller, + 0, + ); Staking::bond_extra(Origin::signed(1000), StakingBalance::Kton(50 * COIN), 0); - Staking::validate(Origin::signed(1000), [0;8].to_vec(), 0, 3); + Staking::validate(Origin::signed(1000), [0; 8].to_vec(), 0, 3); // slash 1% Staking::slash_validator(&1001, 10_000_000); assert_eq!(Staking::ledger(&1000).unwrap().active_ring, 495 * COIN / 10); @@ -403,11 +596,19 @@ fn slash_should_work() { #[test] fn test_inflation() { - with_externalities(&mut ExtBuilder::default() - .existential_deposit(0).build(), || { + with_externalities(&mut ExtBuilder::default().existential_deposit(0).build(), || { assert_eq!(Staking::current_era_total_reward(), 80_000_000 * COIN / 10); start_era(20); assert_eq!(Staking::epoch_index(), 2); assert_eq!(Staking::current_era_total_reward(), 9_999_988_266 * COIN / 1000); }); -} \ No newline at end of file +} + +#[test] +fn set_controller_should_not_change_ledger() { + with_externalities(&mut ExtBuilder::default().existential_deposit(0).build(), || { + assert_eq!(Staking::ledger(&10).unwrap().total_ring, 100 * COIN); + assert_ok!(Staking::set_controller(Origin::signed(11), 12)); + assert_eq!(Staking::ledger(&12).unwrap().total_ring, 100 * COIN); + }); +} diff --git a/srml/staking/src/utils.rs b/srml/staking/src/utils.rs index 3a33ae23a..7d5d52345 100644 --- a/srml/staking/src/utils.rs +++ b/srml/staking/src/utils.rs @@ -1,10 +1,9 @@ - /// utility in staking -use crate::{Trait, EraIndex, Module, RingBalanceOf, KtonBalanceOf}; +use crate::{EraIndex, KtonBalanceOf, Module, RingBalanceOf, Trait}; +use primitives::traits::{CheckedSub, Convert, IntegerSquareRoot, SaturatedConversion}; +use rstd::convert::{TryFrom, TryInto}; use srml_support::traits::{Currency, Get}; -use primitives::traits::{ CheckedSub,SaturatedConversion, IntegerSquareRoot, Convert }; use substrate_primitives::U256; -use rstd::convert::{TryInto, TryFrom}; //change when new epoch // the total reward per era @@ -12,7 +11,8 @@ pub fn compute_current_era_reward() -> RingBalanceOf { let eras_per_epoch: RingBalanceOf = >::get().into(); let current_epoch: u32 = >::epoch_index(); let total_left: u128 = (T::Cap::get() - T::Ring::total_issuance()).saturated_into::(); - let surplus = total_left - total_left * 99_u128.pow(current_epoch.integer_sqrt()) / 100_u128.pow(current_epoch.integer_sqrt()); + let surplus = total_left + - total_left * 99_u128.pow(current_epoch.integer_sqrt()) / 100_u128.pow(current_epoch.integer_sqrt()); let surplus: RingBalanceOf = >::saturated_from::(surplus); (surplus / eras_per_epoch) } @@ -26,9 +26,7 @@ pub fn compute_kton_return(value: RingBalanceOf, months: let quotient = no / de; let remainder = no % de; - let res = U256::from(value) * (U256::from(1000) * (quotient - 1) + U256::from(1000) * remainder / de) / U256::from(1970000); + let res = U256::from(value) * (U256::from(1000) * (quotient - 1) + U256::from(1000) * remainder / de) + / U256::from(1970000); res.as_u128().try_into().unwrap_or_default() - - - } diff --git a/srml/support/src/lib.rs b/srml/support/src/lib.rs index 715546f25..57a707ac6 100644 --- a/srml/support/src/lib.rs +++ b/srml/support/src/lib.rs @@ -1,4 +1,3 @@ - #![cfg_attr(not(feature = "std"), no_std)] -pub mod traits; \ No newline at end of file +pub mod traits; diff --git a/srml/support/src/traits.rs b/srml/support/src/traits.rs index c598a8c06..6ad317cd7 100644 --- a/srml/support/src/traits.rs +++ b/srml/support/src/traits.rs @@ -12,10 +12,9 @@ //} pub trait OnMinted { - fn on_minted(value: Balance); + fn on_minted(value: Balance); } pub trait OnAccountBalanceChanged { fn on_changed(who: &AccountId, old: Balance, new: Balance); } - diff --git a/srml/try/src/lib.rs b/srml/try/src/lib.rs index d98d100f5..97f5ca49e 100644 --- a/srml/try/src/lib.rs +++ b/srml/try/src/lib.rs @@ -5,83 +5,81 @@ // DONE: test visibility of functions in `decl_module!` and `impl Module` block // DONE: check the priority between configs set in chain_spec or in module - // TODO: test difference between dispatch::Result & rstd::result::Result // TODO: try out add_extra_genesis // TODO: check tests in executor - //! Tests in `try` mod is to test origin-module in SRML #![cfg_attr(not(feature = "std"), no_std)] -use rstd::{cmp, result}; use rstd::prelude::*; -use support::{decl_event, decl_module, decl_storage, StorageMap, StorageValue}; +use rstd::{cmp, result}; use support::dispatch::Result; +use support::{decl_event, decl_module, decl_storage, StorageMap, StorageValue}; use system::ensure_signed; mod tests; - pub trait Trait: system::Trait { /// The overarching event type. type Event: From> + Into<::Event>; } decl_event!( - pub enum Event where AccountId = ::AccountId { - SomethingStored(u32, AccountId), - } + pub enum Event + where + AccountId = ::AccountId, + { + SomethingStored(u32, AccountId), + } ); decl_storage! { - trait Store for Module as TemplateModule { - SomeOption get(some_option) config(): Option = Some(1); - Something get(something): u32; - MapOption get(map_option): map u32 => Option; - Map get(map): map u32 => T::AccountId; - List get(list): map u32 => Vec; - } + trait Store for Module as TemplateModule { + SomeOption get(some_option) config(): Option = Some(1); + Something get(something): u32; + MapOption get(map_option): map u32 => Option; + Map get(map): map u32 => T::AccountId; + List get(list): map u32 => Vec; + } } decl_module! { - /// The module declaration. - pub struct Module for enum Call where origin: T::Origin { + /// The module declaration. + pub struct Module for enum Call where origin: T::Origin { - fn deposit_event() = default; + fn deposit_event() = default; - pub fn do_something(origin, something: u32) -> Result { - let who = ensure_signed(origin)?; + pub fn do_something(origin, something: u32) -> Result { + let who = ensure_signed(origin)?; - Something::put(something); - SomeOption::put(something); + Something::put(something); + SomeOption::put(something); - // here we are raising the Something event - Self::deposit_event(RawEvent::SomethingStored(something, who)); - Ok(()) - } + // here we are raising the Something event + Self::deposit_event(RawEvent::SomethingStored(something, who)); + Ok(()) + } - pub fn do_map(origin, uint: u32) -> Result { - let who = ensure_signed(origin)?; + pub fn do_map(origin, uint: u32) -> Result { + let who = ensure_signed(origin)?; - >::insert(uint, who.clone()); - >::insert(uint, who.clone()); + >::insert(uint, who.clone()); + >::insert(uint, who.clone()); Ok(()) - } - - fn update_list(value: u32, is_add: bool) { - let mut list = Self::list(1); - if is_add { - list.push(value); - List::insert(1, list); - } else { - list.remove(value as usize); - } - - } - } + } + + fn update_list(value: u32, is_add: bool) { + let mut list = Self::list(1); + if is_add { + list.push(value); + List::insert(1, list); + } else { + list.remove(value as usize); + } + + } + } } - - diff --git a/srml/try/src/tests.rs b/srml/try/src/tests.rs index ea93cdd96..3bb924cf0 100644 --- a/srml/try/src/tests.rs +++ b/srml/try/src/tests.rs @@ -19,94 +19,86 @@ #![cfg(test)] use super::*; -use sr_primitives::BuildStorage; -use sr_primitives::{traits::{IdentityLookup}, testing::Header}; -use primitives::{H256, Blake2Hasher}; -use sr_io::with_externalities; -use support::{ impl_outer_origin, assert_ok }; use crate::{GenesisConfig, Module, Trait}; +use primitives::{Blake2Hasher, H256}; +use sr_io::with_externalities; +use sr_primitives::BuildStorage; +use sr_primitives::{testing::Header, traits::IdentityLookup}; +use support::{assert_ok, impl_outer_origin}; -impl_outer_origin!{ - pub enum Origin for Test {} +impl_outer_origin! { + pub enum Origin for Test {} } // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, PartialEq, Eq, Debug)] pub struct Test; impl system::Trait for Test { - type Origin = Origin; - type Index = u64; - type BlockNumber = u64; - type Hash = H256; - type Hashing = ::sr_primitives::traits::BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type Header = Header; - type Event = (); + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = ::sr_primitives::traits::BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = (); } - - - impl Trait for Test { - type Event = (); + type Event = (); } - type System = system::Module; type Try = Module; fn new_test_ext() -> sr_io::TestExternalities { - let mut t = system::GenesisConfig::default().build_storage::().unwrap().0; - t.extend(GenesisConfig { - some_option: 42, - }.build_storage().unwrap().0); - t.into() - + let mut t = system::GenesisConfig::default().build_storage::().unwrap().0; + t.extend(GenesisConfig { some_option: 42 }.build_storage().unwrap().0); + t.into() } #[test] fn it_works_for_default_value() { - with_externalities(&mut new_test_ext(), || { - - assert_eq!(Try::something(), 0); - assert_eq!(Try::some_option(), Some(42)); - }); + with_externalities(&mut new_test_ext(), || { + assert_eq!(Try::something(), 0); + assert_eq!(Try::some_option(), Some(42)); + }); } #[test] fn it_works_with_map() { - with_externalities(&mut new_test_ext(), || { - assert_ok!(Try::do_map(Origin::signed(1), 42)); - assert_eq!(Try::map_option(42), Some(1)); - assert_eq!(Try::map(42), 1); - }) + with_externalities(&mut new_test_ext(), || { + assert_ok!(Try::do_map(Origin::signed(1), 42)); + assert_eq!(Try::map_option(42), Some(1)); + assert_eq!(Try::map(42), 1); + }) } #[test] fn check_default_value() { - with_externalities(&mut new_test_ext(), || { - assert_ok!(Try::do_map(Origin::signed(1), 42)); - assert_eq!(Try::map_option(40), None); - assert_eq!(Try::map(40), 0); - }); + with_externalities(&mut new_test_ext(), || { + assert_ok!(Try::do_map(Origin::signed(1), 42)); + assert_eq!(Try::map_option(40), None); + assert_eq!(Try::map(40), 0); + }); } #[test] fn check_delete() { - with_externalities(&mut new_test_ext(), || { - Try::update_list(1, true); - assert_eq!(Try::list(1), vec![1]); - Try::update_list(2, true); - assert_eq!(Try::list(1), vec![1, 2]); - }); + with_externalities(&mut new_test_ext(), || { + Try::update_list(1, true); + assert_eq!(Try::list(1), vec![1]); + Try::update_list(2, true); + assert_eq!(Try::list(1), vec![1, 2]); + }); } #[test] fn check_genesis_privilege() { - with_externalities(&mut new_test_ext(), || { - assert_eq!(Try::some_option(), Some(42)); - SomeOption::kill(); - assert_eq!(Try::some_option(), Some(1)); - }); -} \ No newline at end of file + with_externalities(&mut new_test_ext(), || { + assert_eq!(Try::some_option(), Some(42)); + SomeOption::kill(); + assert_eq!(Try::some_option(), Some(1)); + }); +}