From fd2a936f14ae0d019466b56ade553fbb6e75f164 Mon Sep 17 00:00:00 2001 From: Mokhtar Naamani Date: Fri, 4 Sep 2020 09:32:09 +0300 Subject: [PATCH 1/5] chain spec: initial balances --- node/src/chain_spec/initial_balances.rs | 47 +++++++++++++++++++++++++ node/src/chain_spec/mod.rs | 9 +++++ utils/chain-spec-builder/src/main.rs | 36 +++++++++++++++++-- 3 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 node/src/chain_spec/initial_balances.rs diff --git a/node/src/chain_spec/initial_balances.rs b/node/src/chain_spec/initial_balances.rs new file mode 100644 index 0000000000..5377659212 --- /dev/null +++ b/node/src/chain_spec/initial_balances.rs @@ -0,0 +1,47 @@ +use codec::Decode; +use node_runtime::{AccountId, Balance}; +use serde::Deserialize; +use std::{fs, path::Path}; + +#[derive(Decode)] +struct InitialBalances { + balances: Vec<(AccountId, Balance)>, +} + +#[derive(Deserialize)] +struct EncodedInitialBalances { + balances: Vec<(String, String)>, +} + +impl EncodedInitialBalances { + fn decode(&self) -> InitialBalances { + InitialBalances { + balances: self + .balances + .iter() + .map(|(account, balance)| { + let encoded_account = hex::decode(&account[2..].as_bytes()) + .expect("failed to parse account id hex string"); + let encoded_balance = hex::decode(&balance[2..].as_bytes()) + .expect("failed to parse balance hex string"); + ( + Decode::decode(&mut encoded_account.as_slice()).unwrap(), + Decode::decode(&mut encoded_balance.as_slice()).unwrap(), + ) + }) + .collect(), + } + } +} + +fn parse_forum_json(data_file: &Path) -> EncodedInitialBalances { + let data = fs::read_to_string(data_file).expect("Failed reading file"); + serde_json::from_str(&data).expect("failed parsing balances data") +} + +/// Deserializes and Decodes initial balances from json file +pub fn from_json(data_file: &Path) -> Vec<(AccountId, Balance)> { + let encoded = parse_forum_json(data_file); + let decoded = encoded.decode(); + decoded.balances +} diff --git a/node/src/chain_spec/mod.rs b/node/src/chain_spec/mod.rs index 5ba451c403..f09158a987 100644 --- a/node/src/chain_spec/mod.rs +++ b/node/src/chain_spec/mod.rs @@ -42,6 +42,7 @@ pub use node_runtime::{AccountId, GenesisConfig}; pub mod content_config; pub mod forum_config; +pub mod initial_balances; pub mod initial_members; pub mod proposals_config; @@ -138,6 +139,7 @@ impl Alternative { content_config::empty_versioned_store_permissions_config(), content_config::empty_data_directory_config(), content_config::empty_content_working_group_config(), + vec![], ) }, Vec::new(), @@ -178,6 +180,7 @@ impl Alternative { content_config::empty_versioned_store_permissions_config(), content_config::empty_data_directory_config(), content_config::empty_content_working_group_config(), + vec![], ) }, Vec::new(), @@ -222,6 +225,7 @@ pub fn testnet_genesis( versioned_store_permissions_config: VersionedStorePermissionsConfig, data_directory_config: DataDirectoryConfig, content_working_group_config: ContentWorkingGroupConfig, + initial_balances: Vec<(AccountId, Balance)>, ) -> GenesisConfig { const CENTS: Balance = 1; const DOLLARS: Balance = 100 * CENTS; @@ -241,6 +245,11 @@ pub fn testnet_genesis( .cloned() .map(|k| (k, ENDOWMENT)) .chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH))) + .chain( + initial_balances + .iter() + .map(|(account, balance)| (account.clone(), *balance)), + ) .collect(), }), pallet_staking: Some(StakingConfig { diff --git a/utils/chain-spec-builder/src/main.rs b/utils/chain-spec-builder/src/main.rs index 40a11c4749..99a4aeb73c 100644 --- a/utils/chain-spec-builder/src/main.rs +++ b/utils/chain-spec-builder/src/main.rs @@ -24,8 +24,8 @@ use rand::{distributions::Alphanumeric, rngs::OsRng, Rng}; use structopt::StructOpt; use joystream_node::chain_spec::{ - self, chain_spec_properties, content_config, forum_config, initial_members, proposals_config, - AccountId, + self, chain_spec_properties, content_config, forum_config, initial_balances, initial_members, + proposals_config, AccountId, }; use sc_chain_spec::ChainType; @@ -68,6 +68,9 @@ enum ChainSpecBuilder { /// The path to an initial content directory data file #[structopt(long, short)] initial_content_path: Option, + /// The path to an initial balances file + #[structopt(long, short)] + initial_balances_path: Option, }, /// Create a new chain spec with the given number of authorities and endowed /// accounts. Random keys will be generated as required. @@ -97,6 +100,9 @@ enum ChainSpecBuilder { /// The path to an initial content directory data file #[structopt(long, short)] initial_content_path: Option, + /// The path to an initial balances file + #[structopt(long, short)] + initial_balances_path: Option, }, } @@ -152,6 +158,20 @@ impl ChainSpecBuilder { } => initial_content_path, } } + + /// Returns the path to load initial platform content from + fn initial_balances_path(&self) -> &Option { + match self { + ChainSpecBuilder::New { + initial_balances_path, + .. + } => initial_balances_path, + ChainSpecBuilder::Generate { + initial_balances_path, + .. + } => initial_balances_path, + } + } } fn genesis_constructor( @@ -161,6 +181,7 @@ fn genesis_constructor( initial_members_path: &Option, initial_forum_path: &Option, initial_content_path: &Option, + initial_balances_path: &Option, ) -> chain_spec::GenesisConfig { let authorities = authority_seeds .iter() @@ -203,6 +224,12 @@ fn genesis_constructor( ) }; + let initial_account_balances = if let Some(path) = initial_balances_path { + initial_balances::from_json(path.as_path()) + } else { + vec![] + }; + chain_spec::testnet_genesis( authorities, sudo_account.clone(), @@ -214,6 +241,7 @@ fn genesis_constructor( versioned_store_permissions_cfg, data_directory_config, content_working_group_config, + initial_account_balances, ) } @@ -224,6 +252,7 @@ fn generate_chain_spec( initial_members_path: Option, initial_forum_path: Option, initial_content_path: Option, + initial_balances_path: Option, ) -> Result { let parse_account = |address: &String| { AccountId::from_string(address) @@ -256,6 +285,7 @@ fn generate_chain_spec( &initial_members_path, &initial_forum_path, &initial_content_path, + &initial_balances_path, ) }, vec![], @@ -330,6 +360,7 @@ fn main() -> Result<(), String> { let initial_members_path = builder.initial_members_path().clone(); let initial_forum_path = builder.initial_forum_path().clone(); let initial_content_path = builder.initial_content_path().clone(); + let initial_balances_path = builder.initial_balances_path().clone(); let (authority_seeds, endowed_accounts, sudo_account) = match builder { ChainSpecBuilder::Generate { @@ -379,6 +410,7 @@ fn main() -> Result<(), String> { initial_members_path, initial_forum_path, initial_content_path, + initial_balances_path, )?; fs::write(chain_spec_path, json).map_err(|err| err.to_string()) From 956fe3512f972e702abf1ad27726244ca6dd630e Mon Sep 17 00:00:00 2001 From: Mokhtar Naamani Date: Fri, 4 Sep 2020 09:54:10 +0300 Subject: [PATCH 2/5] fix too many args in chain-spec-builder method --- utils/chain-spec-builder/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/chain-spec-builder/src/main.rs b/utils/chain-spec-builder/src/main.rs index d54a55585b..34192ee612 100644 --- a/utils/chain-spec-builder/src/main.rs +++ b/utils/chain-spec-builder/src/main.rs @@ -212,6 +212,7 @@ impl ChainSpecBuilder { } } +#[allow(clippy::too_many_arguments)] fn genesis_constructor( deployment: &ChainDeployment, authority_seeds: &[String], @@ -290,6 +291,7 @@ fn genesis_constructor( ) } +#[allow(clippy::too_many_arguments)] fn generate_chain_spec( deployment: ChainDeployment, authority_seeds: Vec, From 39ee2e21ddad30711444dc006fff019a8b1b66c8 Mon Sep 17 00:00:00 2001 From: Mokhtar Naamani Date: Fri, 4 Sep 2020 10:20:14 +0300 Subject: [PATCH 3/5] initial_member use serialized json instead of codec encoding for simplicity --- node/src/chain_spec/initial_balances.rs | 39 ++++--------------------- 1 file changed, 5 insertions(+), 34 deletions(-) diff --git a/node/src/chain_spec/initial_balances.rs b/node/src/chain_spec/initial_balances.rs index 5377659212..e0f4a898fb 100644 --- a/node/src/chain_spec/initial_balances.rs +++ b/node/src/chain_spec/initial_balances.rs @@ -1,47 +1,18 @@ -use codec::Decode; use node_runtime::{AccountId, Balance}; use serde::Deserialize; use std::{fs, path::Path}; -#[derive(Decode)] -struct InitialBalances { - balances: Vec<(AccountId, Balance)>, -} - #[derive(Deserialize)] -struct EncodedInitialBalances { - balances: Vec<(String, String)>, -} - -impl EncodedInitialBalances { - fn decode(&self) -> InitialBalances { - InitialBalances { - balances: self - .balances - .iter() - .map(|(account, balance)| { - let encoded_account = hex::decode(&account[2..].as_bytes()) - .expect("failed to parse account id hex string"); - let encoded_balance = hex::decode(&balance[2..].as_bytes()) - .expect("failed to parse balance hex string"); - ( - Decode::decode(&mut encoded_account.as_slice()).unwrap(), - Decode::decode(&mut encoded_balance.as_slice()).unwrap(), - ) - }) - .collect(), - } - } +struct SerializedInitialBalances { + balances: Vec<(AccountId, Balance)>, } -fn parse_forum_json(data_file: &Path) -> EncodedInitialBalances { +fn parse_json(data_file: &Path) -> SerializedInitialBalances { let data = fs::read_to_string(data_file).expect("Failed reading file"); serde_json::from_str(&data).expect("failed parsing balances data") } -/// Deserializes and Decodes initial balances from json file +/// Deserializes initial balances from json file pub fn from_json(data_file: &Path) -> Vec<(AccountId, Balance)> { - let encoded = parse_forum_json(data_file); - let decoded = encoded.decode(); - decoded.balances + parse_json(data_file).balances } From 441f4bde6b8b07d9742565798b9821761d5c66f4 Mon Sep 17 00:00:00 2001 From: Mokhtar Naamani Date: Fri, 4 Sep 2020 12:31:55 +0300 Subject: [PATCH 4/5] minor code refactor and comments about refactoring needed for method with too many args --- node/src/chain_spec/mod.rs | 3 ++- utils/chain-spec-builder/src/main.rs | 12 +++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/node/src/chain_spec/mod.rs b/node/src/chain_spec/mod.rs index 2a353ba602..a520e547d7 100644 --- a/node/src/chain_spec/mod.rs +++ b/node/src/chain_spec/mod.rs @@ -205,7 +205,8 @@ pub fn chain_spec_properties() -> json::map::Map { ); properties } - +// This method should be refactored after Alexandria to reduce number of arguments +// as more args will likely be needed #[allow(clippy::too_many_arguments)] pub fn testnet_genesis( initial_authorities: Vec<( diff --git a/utils/chain-spec-builder/src/main.rs b/utils/chain-spec-builder/src/main.rs index 34192ee612..4b4eddebdc 100644 --- a/utils/chain-spec-builder/src/main.rs +++ b/utils/chain-spec-builder/src/main.rs @@ -212,6 +212,8 @@ impl ChainSpecBuilder { } } +// TODO: This method should be refactored after Alexandria to reduce number of arguments +// as more args will likely be needed #[allow(clippy::too_many_arguments)] fn genesis_constructor( deployment: &ChainDeployment, @@ -264,11 +266,9 @@ fn genesis_constructor( ) }; - let initial_account_balances = if let Some(path) = initial_balances_path { - initial_balances::from_json(path.as_path()) - } else { - vec![] - }; + let initial_account_balances = initial_balances_path + .map(|path| initial_balances::from_json(path.as_path())) + .unwrap_or_else(vec![]); let proposals_cfg = match deployment { ChainDeployment::live => proposals_config::production(), @@ -291,6 +291,8 @@ fn genesis_constructor( ) } +// TODO: This method should be refactored after Alexandria to reduce number of arguments +// as more args will likely be needed #[allow(clippy::too_many_arguments)] fn generate_chain_spec( deployment: ChainDeployment, From 7b9c2f5be16ca4cddd1df5a7392d33f5d1c10179 Mon Sep 17 00:00:00 2001 From: Mokhtar Naamani Date: Fri, 4 Sep 2020 12:45:47 +0300 Subject: [PATCH 5/5] chainspec-builder: code refactor to functional style for clarity --- utils/chain-spec-builder/src/main.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/utils/chain-spec-builder/src/main.rs b/utils/chain-spec-builder/src/main.rs index 4b4eddebdc..8bd17fb625 100644 --- a/utils/chain-spec-builder/src/main.rs +++ b/utils/chain-spec-builder/src/main.rs @@ -231,17 +231,15 @@ fn genesis_constructor( .map(chain_spec::get_authority_keys_from_seed) .collect::>(); - let members = if let Some(path) = initial_members_path { - initial_members::from_json(path.as_path()) - } else { - initial_members::none() - }; + let members = initial_members_path + .as_ref() + .map(|path| initial_members::from_json(path.as_path())) + .unwrap_or_else(initial_members::none); - let forum_cfg = if let Some(path) = initial_forum_path { - forum_config::from_json(sudo_account.clone(), path.as_path()) - } else { - forum_config::empty(sudo_account.clone()) - }; + let forum_cfg = initial_forum_path + .as_ref() + .map(|path| forum_config::from_json(sudo_account.clone(), path.as_path())) + .unwrap_or_else(|| forum_config::empty(sudo_account.clone())); let ( versioned_store_cfg, @@ -267,8 +265,9 @@ fn genesis_constructor( }; let initial_account_balances = initial_balances_path + .as_ref() .map(|path| initial_balances::from_json(path.as_path())) - .unwrap_or_else(vec![]); + .unwrap_or_else(Vec::new); let proposals_cfg = match deployment { ChainDeployment::live => proposals_config::production(),