// Copyright 2019 Joystream Contributors
// This file is part of Joystream node.
// Joystream node is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Joystream node is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Joystream node. If not, see .
// Clippy linter warning.
// Disable it because we use such syntax for a code readability.
// Example: voting_period: 1 * DAY
#![allow(clippy::identity_op)]
use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
use serde_json as json;
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
use sp_consensus_babe::AuthorityId as BabeId;
use sp_core::{sr25519, Pair, Public};
use sp_finality_grandpa::AuthorityId as GrandpaId;
use sp_runtime::traits::{IdentifyAccount, Verify};
use sp_runtime::Perbill;
use node_runtime::{
membership, AuthorityDiscoveryConfig, BabeConfig, Balance, BalancesConfig,
ContentWorkingGroupConfig, CouncilConfig, CouncilElectionConfig, DataDirectoryConfig,
DataObjectStorageRegistryConfig, DataObjectTypeRegistryConfig, ElectionParameters, ForumConfig,
GrandpaConfig, ImOnlineConfig, MembersConfig, Moment, ProposalsCodexConfig, SessionConfig,
SessionKeys, Signature, StakerStatus, StakingConfig, StorageWorkingGroupConfig, SudoConfig,
SystemConfig, VersionedStoreConfig, VersionedStorePermissionsConfig, DAYS, WASM_BINARY,
};
// Exported to be used by chain-spec-builder
pub use node_runtime::{AccountId, GenesisConfig};
pub mod content_config;
pub mod forum_config;
pub mod initial_members;
pub mod proposals_config;
type AccountPublic = ::Signer;
/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.
pub type ChainSpec = sc_service::GenericChainSpec;
use sc_chain_spec::ChainType;
/// The chain specification option. This is expected to come in from the CLI and
/// is little more than one of a number of alternatives which can easily be converted
/// from a string (`--chain=...`) into a `ChainSpec`.
#[derive(Clone, Debug)]
pub enum Alternative {
/// Whatever the current runtime is, with just Alice as an auth.
Development,
/// Whatever the current runtime is, with simple Alice/Bob auths.
LocalTestnet,
}
/// Helper function to generate a crypto pair from seed
pub fn get_from_seed(seed: &str) -> ::Public {
TPublic::Pair::from_string(&format!("//{}", seed), None)
.expect("static values are valid; qed")
.public()
}
/// Helper function to generate an account ID from seed
pub fn get_account_id_from_seed(seed: &str) -> AccountId
where
AccountPublic: From<::Public>,
{
AccountPublic::from(get_from_seed::(seed)).into_account()
}
/// Helper function to generate stash, controller and session key from seed
pub fn get_authority_keys_from_seed(
seed: &str,
) -> (
AccountId,
AccountId,
GrandpaId,
BabeId,
ImOnlineId,
AuthorityDiscoveryId,
) {
(
get_account_id_from_seed::(&format!("{}//stash", seed)),
get_account_id_from_seed::(seed),
get_from_seed::(seed),
get_from_seed::(seed),
get_from_seed::(seed),
get_from_seed::(seed),
)
}
fn session_keys(
grandpa: GrandpaId,
babe: BabeId,
im_online: ImOnlineId,
authority_discovery: AuthorityDiscoveryId,
) -> SessionKeys {
SessionKeys {
grandpa,
babe,
im_online,
authority_discovery,
}
}
impl Alternative {
/// Get an actual chain config from one of the alternatives.
pub(crate) fn load(self) -> Result {
Ok(match self {
Alternative::Development => ChainSpec::from_genesis(
"Development",
"dev",
ChainType::Development,
|| {
testnet_genesis(
vec![get_authority_keys_from_seed("Alice")],
get_account_id_from_seed::("Alice"),
vec![
get_account_id_from_seed::("Alice"),
get_account_id_from_seed::("Bob"),
get_account_id_from_seed::("Alice//stash"),
get_account_id_from_seed::("Bob//stash"),
],
proposals_config::development(),
initial_members::none(),
forum_config::empty(get_account_id_from_seed::("Alice")),
content_config::empty_versioned_store_config(),
content_config::empty_versioned_store_permissions_config(),
content_config::empty_data_directory_config(),
content_config::empty_content_working_group_config(),
)
},
Vec::new(),
None,
None,
Some(chain_spec_properties()),
None,
),
Alternative::LocalTestnet => ChainSpec::from_genesis(
"Local Testnet",
"local_testnet",
ChainType::Local,
|| {
testnet_genesis(
vec![
get_authority_keys_from_seed("Alice"),
get_authority_keys_from_seed("Bob"),
],
get_account_id_from_seed::("Alice"),
vec![
get_account_id_from_seed::("Alice"),
get_account_id_from_seed::("Bob"),
get_account_id_from_seed::("Charlie"),
get_account_id_from_seed::("Dave"),
get_account_id_from_seed::("Eve"),
get_account_id_from_seed::("Ferdie"),
get_account_id_from_seed::("Alice//stash"),
get_account_id_from_seed::("Bob//stash"),
get_account_id_from_seed::("Charlie//stash"),
get_account_id_from_seed::("Dave//stash"),
get_account_id_from_seed::("Eve//stash"),
get_account_id_from_seed::("Ferdie//stash"),
],
proposals_config::development(),
initial_members::none(),
forum_config::empty(get_account_id_from_seed::("Alice")),
content_config::empty_versioned_store_config(),
content_config::empty_versioned_store_permissions_config(),
content_config::empty_data_directory_config(),
content_config::empty_content_working_group_config(),
)
},
Vec::new(),
None,
None,
Some(chain_spec_properties()),
None,
),
})
}
}
pub fn chain_spec_properties() -> json::map::Map {
let mut properties: json::map::Map = json::map::Map::new();
properties.insert(
String::from("tokenDecimals"),
json::Value::Number(json::Number::from(0)),
);
properties.insert(
String::from("tokenSymbol"),
json::Value::String(String::from("JOY")),
);
properties
}
#[allow(clippy::too_many_arguments)]
pub fn testnet_genesis(
initial_authorities: Vec<(
AccountId,
AccountId,
GrandpaId,
BabeId,
ImOnlineId,
AuthorityDiscoveryId,
)>,
root_key: AccountId,
endowed_accounts: Vec,
cpcp: node_runtime::ProposalsConfigParameters,
members: Vec>,
forum_config: ForumConfig,
versioned_store_config: VersionedStoreConfig,
versioned_store_permissions_config: VersionedStorePermissionsConfig,
data_directory_config: DataDirectoryConfig,
content_working_group_config: ContentWorkingGroupConfig,
) -> GenesisConfig {
const CENTS: Balance = 1;
const DOLLARS: Balance = 100 * CENTS;
const STASH: Balance = 20 * DOLLARS;
const ENDOWMENT: Balance = 100_000 * DOLLARS;
let default_text_constraint = node_runtime::working_group::default_text_constraint();
GenesisConfig {
system: Some(SystemConfig {
code: WASM_BINARY.to_vec(),
changes_trie_config: Default::default(),
}),
pallet_balances: Some(BalancesConfig {
balances: endowed_accounts
.iter()
.cloned()
.map(|k| (k, ENDOWMENT))
.chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH)))
.collect(),
}),
pallet_staking: Some(StakingConfig {
validator_count: 20,
minimum_validator_count: 1,
stakers: initial_authorities
.iter()
.map(|x| (x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator))
.collect(),
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
slash_reward_fraction: Perbill::from_percent(10),
..Default::default()
}),
pallet_sudo: Some(SudoConfig { key: root_key }),
pallet_babe: Some(BabeConfig {
authorities: vec![],
}),
pallet_im_online: Some(ImOnlineConfig { keys: vec![] }),
pallet_authority_discovery: Some(AuthorityDiscoveryConfig { keys: vec![] }),
pallet_grandpa: Some(GrandpaConfig {
authorities: vec![],
}),
pallet_session: Some(SessionConfig {
keys: initial_authorities
.iter()
.map(|x| {
(
x.0.clone(),
x.0.clone(),
session_keys(x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone()),
)
})
.collect::>(),
}),
council: Some(CouncilConfig {
active_council: vec![],
term_ends_at: 1,
}),
election: Some(CouncilElectionConfig {
auto_start: true,
election_parameters: ElectionParameters {
announcing_period: 3 * DAYS,
voting_period: 1 * DAYS,
revealing_period: 1 * DAYS,
council_size: 12,
candidacy_limit: 25,
min_council_stake: 10 * DOLLARS,
new_term_duration: 14 * DAYS,
min_voting_stake: 1 * DOLLARS,
},
}),
membership: Some(MembersConfig {
default_paid_membership_fee: 100u128,
members,
}),
forum: Some(forum_config),
data_directory: Some(data_directory_config),
data_object_type_registry: Some(DataObjectTypeRegistryConfig {
first_data_object_type_id: 1,
}),
data_object_storage_registry: Some(DataObjectStorageRegistryConfig {
first_relationship_id: 1,
}),
working_group_Instance2: Some(StorageWorkingGroupConfig {
phantom: Default::default(),
storage_working_group_mint_capacity: 0,
opening_human_readable_text_constraint: default_text_constraint,
worker_application_human_readable_text_constraint: default_text_constraint,
worker_exit_rationale_text_constraint: default_text_constraint,
}),
versioned_store: Some(versioned_store_config),
versioned_store_permissions: Some(versioned_store_permissions_config),
content_wg: Some(content_working_group_config),
proposals_codex: Some(ProposalsCodexConfig {
set_validator_count_proposal_voting_period: cpcp
.set_validator_count_proposal_voting_period,
set_validator_count_proposal_grace_period: cpcp
.set_validator_count_proposal_grace_period,
runtime_upgrade_proposal_voting_period: cpcp.runtime_upgrade_proposal_voting_period,
runtime_upgrade_proposal_grace_period: cpcp.runtime_upgrade_proposal_grace_period,
text_proposal_voting_period: cpcp.text_proposal_voting_period,
text_proposal_grace_period: cpcp.text_proposal_grace_period,
set_election_parameters_proposal_voting_period: cpcp
.set_election_parameters_proposal_voting_period,
set_election_parameters_proposal_grace_period: cpcp
.set_election_parameters_proposal_grace_period,
set_content_working_group_mint_capacity_proposal_voting_period: cpcp
.set_content_working_group_mint_capacity_proposal_voting_period,
set_content_working_group_mint_capacity_proposal_grace_period: cpcp
.set_content_working_group_mint_capacity_proposal_grace_period,
set_lead_proposal_voting_period: cpcp.set_lead_proposal_voting_period,
set_lead_proposal_grace_period: cpcp.set_lead_proposal_grace_period,
spending_proposal_voting_period: cpcp.spending_proposal_voting_period,
spending_proposal_grace_period: cpcp.spending_proposal_grace_period,
add_working_group_opening_proposal_voting_period: cpcp
.add_working_group_opening_proposal_voting_period,
add_working_group_opening_proposal_grace_period: cpcp
.add_working_group_opening_proposal_grace_period,
begin_review_working_group_leader_applications_proposal_voting_period: cpcp
.begin_review_working_group_leader_applications_proposal_voting_period,
begin_review_working_group_leader_applications_proposal_grace_period: cpcp
.begin_review_working_group_leader_applications_proposal_grace_period,
fill_working_group_leader_opening_proposal_voting_period: cpcp
.fill_working_group_leader_opening_proposal_voting_period,
fill_working_group_leader_opening_proposal_grace_period: cpcp
.fill_working_group_leader_opening_proposal_grace_period,
set_working_group_mint_capacity_proposal_voting_period: cpcp
.set_content_working_group_mint_capacity_proposal_voting_period,
set_working_group_mint_capacity_proposal_grace_period: cpcp
.set_content_working_group_mint_capacity_proposal_grace_period,
decrease_working_group_leader_stake_proposal_voting_period: cpcp
.decrease_working_group_leader_stake_proposal_voting_period,
decrease_working_group_leader_stake_proposal_grace_period: cpcp
.decrease_working_group_leader_stake_proposal_grace_period,
slash_working_group_leader_stake_proposal_voting_period: cpcp
.slash_working_group_leader_stake_proposal_voting_period,
slash_working_group_leader_stake_proposal_grace_period: cpcp
.slash_working_group_leader_stake_proposal_grace_period,
set_working_group_leader_reward_proposal_voting_period: cpcp
.set_working_group_leader_reward_proposal_voting_period,
set_working_group_leader_reward_proposal_grace_period: cpcp
.set_working_group_leader_reward_proposal_grace_period,
terminate_working_group_leader_role_proposal_voting_period: cpcp
.terminate_working_group_leader_role_proposal_voting_period,
terminate_working_group_leader_role_proposal_grace_period: cpcp
.terminate_working_group_leader_role_proposal_grace_period,
}),
}
}
// Tests are commented out until we find a solution to why
// building dependencies for the tests are taking so long on Travis CI
// #[cfg(test)]
// pub(crate) mod tests {
// use super::*;
// use crate::service::{new_full, new_light};
// use sc_service_test;
// fn local_testnet_genesis_instant_single() -> GenesisConfig {
// testnet_genesis(
// vec![get_authority_keys_from_seed("Alice")],
// get_account_id_from_seed::("Alice"),
// vec![get_authority_keys_from_seed("Alice").0],
// crate::proposals_config::development(),
// )
// }
// /// Local testnet config (single validator - Alice)
// pub fn integration_test_config_with_single_authority() -> ChainSpec {
// ChainSpec::from_genesis(
// "Integration Test",
// "test",
// ChainType::Development,
// local_testnet_genesis_instant_single,
// vec![],
// None,
// None,
// None,
// Default::default(),
// )
// }
// fn local_testnet_genesis() -> GenesisConfig {
// testnet_genesis(
// vec![
// get_authority_keys_from_seed("Alice"),
// get_authority_keys_from_seed("Bob"),
// ],
// get_account_id_from_seed::("Alice"),
// vec![
// get_authority_keys_from_seed("Alice").0,
// get_authority_keys_from_seed("Bob").0,
// ],
// crate::proposals_config::development(),
// )
// }
// /// Local testnet config (multivalidator Alice + Bob)
// pub fn integration_test_config_with_two_authorities() -> ChainSpec {
// ChainSpec::from_genesis(
// "Integration Test",
// "test",
// ChainType::Development,
// local_testnet_genesis,
// vec![],
// None,
// None,
// None,
// Default::default(),
// )
// }
// #[test]
// #[ignore]
// fn test_connectivity() {
// sc_service_test::connectivity(
// integration_test_config_with_two_authorities(),
// |config| new_full(config),
// |config| new_light(config),
// );
// }
// }