mod.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. // Copyright 2019 Joystream Contributors
  2. // This file is part of Joystream node.
  3. // Joystream node is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU General Public License as published by
  5. // the Free Software Foundation, either version 3 of the License, or
  6. // (at your option) any later version.
  7. // Joystream node is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU General Public License for more details.
  11. // You should have received a copy of the GNU General Public License
  12. // along with Joystream node. If not, see <http://www.gnu.org/licenses/>.
  13. // Clippy linter warning.
  14. // Disable it because we use such syntax for a code readability.
  15. // Example: voting_period: 1 * DAY
  16. #![allow(clippy::identity_op)]
  17. use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
  18. use serde_json as json;
  19. use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
  20. use sp_consensus_babe::AuthorityId as BabeId;
  21. use sp_core::{sr25519, Pair, Public};
  22. use sp_finality_grandpa::AuthorityId as GrandpaId;
  23. use sp_runtime::traits::{IdentifyAccount, Verify};
  24. use sp_runtime::Perbill;
  25. use node_runtime::{
  26. membership, wasm_binary_unwrap, AuthorityDiscoveryConfig, BabeConfig, Balance, BalancesConfig,
  27. ContentDirectoryConfig, CouncilConfig, CouncilElectionConfig, DataObjectStorageRegistryConfig,
  28. DataObjectTypeRegistryConfig, ElectionParameters, ForumConfig, GrandpaConfig, ImOnlineConfig,
  29. MembersConfig, Moment, SessionConfig, SessionKeys, Signature, StakerStatus, StakingConfig,
  30. SudoConfig, SystemConfig, DAYS,
  31. };
  32. // Exported to be used by chain-spec-builder
  33. pub use node_runtime::{AccountId, GenesisConfig};
  34. pub mod forum_config;
  35. pub mod initial_balances;
  36. pub mod initial_members;
  37. type AccountPublic = <Signature as Verify>::Signer;
  38. /// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.
  39. pub type ChainSpec = sc_service::GenericChainSpec<GenesisConfig>;
  40. use sc_chain_spec::ChainType;
  41. /// The chain specification option. This is expected to come in from the CLI and
  42. /// is little more than one of a number of alternatives which can easily be converted
  43. /// from a string (`--chain=...`) into a `ChainSpec`.
  44. #[derive(Clone, Debug)]
  45. pub enum Alternative {
  46. /// Whatever the current runtime is, with just Alice as an auth.
  47. Development,
  48. /// Whatever the current runtime is, with simple Alice/Bob auths.
  49. LocalTestnet,
  50. }
  51. /// Helper function to generate a crypto pair from seed
  52. pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
  53. TPublic::Pair::from_string(&format!("//{}", seed), None)
  54. .expect("static values are valid; qed")
  55. .public()
  56. }
  57. /// Helper function to generate an account ID from seed
  58. pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
  59. where
  60. AccountPublic: From<<TPublic::Pair as Pair>::Public>,
  61. {
  62. AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
  63. }
  64. /// Helper function to generate stash, controller and session key from seed
  65. pub fn get_authority_keys_from_seed(
  66. seed: &str,
  67. ) -> (
  68. AccountId,
  69. AccountId,
  70. GrandpaId,
  71. BabeId,
  72. ImOnlineId,
  73. AuthorityDiscoveryId,
  74. ) {
  75. (
  76. get_account_id_from_seed::<sr25519::Public>(&format!("{}//stash", seed)),
  77. get_account_id_from_seed::<sr25519::Public>(seed),
  78. get_from_seed::<GrandpaId>(seed),
  79. get_from_seed::<BabeId>(seed),
  80. get_from_seed::<ImOnlineId>(seed),
  81. get_from_seed::<AuthorityDiscoveryId>(seed),
  82. )
  83. }
  84. fn session_keys(
  85. grandpa: GrandpaId,
  86. babe: BabeId,
  87. im_online: ImOnlineId,
  88. authority_discovery: AuthorityDiscoveryId,
  89. ) -> SessionKeys {
  90. SessionKeys {
  91. grandpa,
  92. babe,
  93. im_online,
  94. authority_discovery,
  95. }
  96. }
  97. impl Alternative {
  98. /// Get an actual chain config from one of the alternatives.
  99. pub(crate) fn load(self) -> Result<ChainSpec, String> {
  100. Ok(match self {
  101. Alternative::Development => ChainSpec::from_genesis(
  102. "Development",
  103. "dev",
  104. ChainType::Development,
  105. || {
  106. testnet_genesis(
  107. vec![get_authority_keys_from_seed("Alice")],
  108. get_account_id_from_seed::<sr25519::Public>("Alice"),
  109. vec![
  110. get_account_id_from_seed::<sr25519::Public>("Alice"),
  111. get_account_id_from_seed::<sr25519::Public>("Bob"),
  112. get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
  113. get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
  114. ],
  115. initial_members::none(),
  116. forum_config::empty(get_account_id_from_seed::<sr25519::Public>("Alice")),
  117. vec![],
  118. )
  119. },
  120. Vec::new(),
  121. None,
  122. None,
  123. Some(chain_spec_properties()),
  124. None,
  125. ),
  126. Alternative::LocalTestnet => ChainSpec::from_genesis(
  127. "Local Testnet",
  128. "local_testnet",
  129. ChainType::Local,
  130. || {
  131. testnet_genesis(
  132. vec![
  133. get_authority_keys_from_seed("Alice"),
  134. get_authority_keys_from_seed("Bob"),
  135. ],
  136. get_account_id_from_seed::<sr25519::Public>("Alice"),
  137. vec![
  138. get_account_id_from_seed::<sr25519::Public>("Alice"),
  139. get_account_id_from_seed::<sr25519::Public>("Bob"),
  140. get_account_id_from_seed::<sr25519::Public>("Charlie"),
  141. get_account_id_from_seed::<sr25519::Public>("Dave"),
  142. get_account_id_from_seed::<sr25519::Public>("Eve"),
  143. get_account_id_from_seed::<sr25519::Public>("Ferdie"),
  144. get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
  145. get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
  146. get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),
  147. get_account_id_from_seed::<sr25519::Public>("Dave//stash"),
  148. get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
  149. get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
  150. ],
  151. initial_members::none(),
  152. forum_config::empty(get_account_id_from_seed::<sr25519::Public>("Alice")),
  153. vec![],
  154. )
  155. },
  156. Vec::new(),
  157. None,
  158. None,
  159. Some(chain_spec_properties()),
  160. None,
  161. ),
  162. })
  163. }
  164. }
  165. pub fn chain_spec_properties() -> json::map::Map<String, json::Value> {
  166. let mut properties: json::map::Map<String, json::Value> = json::map::Map::new();
  167. properties.insert(
  168. String::from("tokenDecimals"),
  169. json::Value::Number(json::Number::from(0)),
  170. );
  171. properties.insert(
  172. String::from("tokenSymbol"),
  173. json::Value::String(String::from("JOY")),
  174. );
  175. properties
  176. }
  177. // This method should be refactored after Alexandria to reduce number of arguments
  178. // as more args will likely be needed
  179. #[allow(clippy::too_many_arguments)]
  180. pub fn testnet_genesis(
  181. initial_authorities: Vec<(
  182. AccountId,
  183. AccountId,
  184. GrandpaId,
  185. BabeId,
  186. ImOnlineId,
  187. AuthorityDiscoveryId,
  188. )>,
  189. root_key: AccountId,
  190. endowed_accounts: Vec<AccountId>,
  191. members: Vec<membership::genesis::Member<u64, AccountId, Moment>>,
  192. forum_config: ForumConfig,
  193. initial_balances: Vec<(AccountId, Balance)>,
  194. ) -> GenesisConfig {
  195. const STASH: Balance = 5_000;
  196. const ENDOWMENT: Balance = 100_000_000;
  197. GenesisConfig {
  198. frame_system: Some(SystemConfig {
  199. code: wasm_binary_unwrap().to_vec(),
  200. changes_trie_config: Default::default(),
  201. }),
  202. pallet_balances: Some(BalancesConfig {
  203. balances: endowed_accounts
  204. .iter()
  205. .cloned()
  206. .map(|k| (k, ENDOWMENT))
  207. .chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH)))
  208. .chain(
  209. initial_balances
  210. .iter()
  211. .map(|(account, balance)| (account.clone(), *balance)),
  212. )
  213. .collect(),
  214. }),
  215. pallet_staking: Some(StakingConfig {
  216. validator_count: 20,
  217. minimum_validator_count: initial_authorities.len() as u32,
  218. stakers: initial_authorities
  219. .iter()
  220. .map(|x| (x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator))
  221. .collect(),
  222. invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
  223. slash_reward_fraction: Perbill::from_percent(10),
  224. history_depth: 336,
  225. ..Default::default()
  226. }),
  227. pallet_sudo: Some(SudoConfig { key: root_key }),
  228. pallet_babe: Some(BabeConfig {
  229. authorities: vec![],
  230. }),
  231. pallet_im_online: Some(ImOnlineConfig { keys: vec![] }),
  232. pallet_authority_discovery: Some(AuthorityDiscoveryConfig { keys: vec![] }),
  233. pallet_grandpa: Some(GrandpaConfig {
  234. authorities: vec![],
  235. }),
  236. pallet_session: Some(SessionConfig {
  237. keys: initial_authorities
  238. .iter()
  239. .map(|x| {
  240. (
  241. x.0.clone(),
  242. x.0.clone(),
  243. session_keys(x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone()),
  244. )
  245. })
  246. .collect::<Vec<_>>(),
  247. }),
  248. council: Some(CouncilConfig {
  249. active_council: vec![],
  250. term_ends_at: 1,
  251. }),
  252. election: Some(CouncilElectionConfig {
  253. auto_start: true,
  254. election_parameters: ElectionParameters {
  255. announcing_period: 2 * DAYS,
  256. voting_period: 1 * DAYS,
  257. revealing_period: 1 * DAYS,
  258. council_size: 6,
  259. candidacy_limit: 25,
  260. min_council_stake: 1_000,
  261. new_term_duration: 10 * DAYS,
  262. min_voting_stake: 100,
  263. },
  264. }),
  265. membership: Some(MembersConfig { members }),
  266. forum: Some(forum_config),
  267. data_object_type_registry: Some(DataObjectTypeRegistryConfig {
  268. first_data_object_type_id: 1,
  269. }),
  270. data_object_storage_registry: Some(DataObjectStorageRegistryConfig {
  271. first_relationship_id: 1,
  272. }),
  273. content_directory: Some({
  274. ContentDirectoryConfig {
  275. class_by_id: vec![],
  276. entity_by_id: vec![],
  277. curator_group_by_id: vec![],
  278. next_class_id: 1,
  279. next_entity_id: 1,
  280. next_curator_group_id: 1,
  281. }
  282. }),
  283. }
  284. }
  285. #[cfg(test)]
  286. pub(crate) mod tests {
  287. use super::*;
  288. use crate::service::{new_full_base, new_light_base, NewFullBase};
  289. use sc_service_test;
  290. fn local_testnet_genesis_instant_single() -> GenesisConfig {
  291. testnet_genesis(
  292. vec![get_authority_keys_from_seed("Alice")],
  293. get_account_id_from_seed::<sr25519::Public>("Alice"),
  294. vec![get_authority_keys_from_seed("Alice").0],
  295. initial_members::none(),
  296. forum_config::empty(get_account_id_from_seed::<sr25519::Public>("Alice")),
  297. vec![],
  298. )
  299. }
  300. /// Local testnet config (single validator - Alice)
  301. pub fn integration_test_config_with_single_authority() -> ChainSpec {
  302. ChainSpec::from_genesis(
  303. "Integration Test",
  304. "test",
  305. ChainType::Development,
  306. local_testnet_genesis_instant_single,
  307. vec![],
  308. None,
  309. None,
  310. None,
  311. Default::default(),
  312. )
  313. }
  314. fn local_testnet_genesis() -> GenesisConfig {
  315. testnet_genesis(
  316. vec![
  317. get_authority_keys_from_seed("Alice"),
  318. get_authority_keys_from_seed("Bob"),
  319. ],
  320. get_account_id_from_seed::<sr25519::Public>("Alice"),
  321. vec![
  322. get_authority_keys_from_seed("Alice").0,
  323. get_authority_keys_from_seed("Bob").0,
  324. ],
  325. initial_members::none(),
  326. forum_config::empty(get_account_id_from_seed::<sr25519::Public>("Alice")),
  327. vec![],
  328. )
  329. }
  330. /// Local testnet config (multivalidator Alice + Bob)
  331. pub fn integration_test_config_with_two_authorities() -> ChainSpec {
  332. ChainSpec::from_genesis(
  333. "Integration Test",
  334. "test",
  335. ChainType::Development,
  336. local_testnet_genesis,
  337. vec![],
  338. None,
  339. None,
  340. None,
  341. Default::default(),
  342. )
  343. }
  344. #[test]
  345. #[ignore]
  346. fn test_connectivity() {
  347. sc_service_test::connectivity(
  348. integration_test_config_with_two_authorities(),
  349. |config| {
  350. let NewFullBase {
  351. task_manager,
  352. client,
  353. network,
  354. transaction_pool,
  355. ..
  356. } = new_full_base(config, |_, _| ())?;
  357. Ok(sc_service_test::TestNetComponents::new(
  358. task_manager,
  359. client,
  360. network,
  361. transaction_pool,
  362. ))
  363. },
  364. |config| {
  365. let (keep_alive, _, client, network, transaction_pool) = new_light_base(config)?;
  366. Ok(sc_service_test::TestNetComponents::new(
  367. keep_alive,
  368. client,
  369. network,
  370. transaction_pool,
  371. ))
  372. },
  373. );
  374. }
  375. }