MrBoec/service/src/chain_spec.rs

490 lines
18 KiB
Rust
Raw Normal View History

//! Ghost chain configuration.
use codec::Encode;
use ghost_slow_clap::sr25519::AuthorityId as SlowClapId;
use primitives::{AccountId, AccountPublic};
use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId;
use grandpa_primitives::AuthorityId as GrandpaId;
use babe_primitives::AuthorityId as BabeId;
#[cfg(feature = "casper-native")]
use pallet_staking::Forcing;
#[cfg(feature = "casper-native")]
use casper_runtime as casper;
#[cfg(feature = "casper-native")]
use casper_runtime_constants::currency::CSPR;
use sc_chain_spec::ChainSpecExtension;
#[cfg(feature = "casper-native")]
use sc_chain_spec::ChainType;
use serde::{Deserialize, Serialize};
use sp_core::{sr25519, Pair, Public};
use sp_runtime::traits::IdentifyAccount;
#[cfg(feature = "casper-native")]
use sp_runtime::Perbill;
#[cfg(feature = "casper-native")]
use telemetry::TelemetryEndpoints;
#[cfg(feature = "casper-native")]
const CASPER_TELEMETRY_URL: &str = "wss://telemetry.ghostchain.io/submit/";
#[cfg(feature = "casper-native")]
const DEFAULT_PROTOCOL_ID: &str = "cspr";
/// Node `ChainSpec` extensions.
///
/// Additional parameters for some substrate core modules,
/// customizable from the chain spec.
#[derive(Default, Clone, Serialize, Deserialize, ChainSpecExtension)]
#[serde(rename_all = "camelCase")]
pub struct Extensions {
/// Block number with known hashes.
pub fork_blocks: sc_client_api::ForkBlocks<primitives::Block>,
/// Known bad block hashes.
pub bad_blocks: sc_client_api::BadBlocks<primitives::Block>,
/// The light sync state.
/// This value will be set by the `sync-state rpc` implementation.
pub light_sync_state: sc_sync_state_rpc::LightSyncStateExtension,
}
// Generic chain spec, in case when we don't have the native runtime.
pub type GenericChainSpec = sc_service::GenericChainSpec<(), Extensions>;
/// The `ChainSpec` parametrized for the ghost runtime.
#[cfg(feature = "casper-native")]
pub type CasperChainSpec = sc_service::GenericChainSpec<(), Extensions>;
#[cfg(not(feature = "casper-native"))]
pub type CasperChainSpec = GenericChainSpec;
pub fn casper_config() -> Result<CasperChainSpec, String> {
CasperChainSpec::from_json_bytes(&include_bytes!("../chain-specs/casper.json")[..])
}
#[cfg(feature = "casper-native")]
fn casper_session_keys(
babe: BabeId,
grandpa: GrandpaId,
authority_discovery: AuthorityDiscoveryId,
slow_clap: SlowClapId,
) -> casper::opaque::SessionKeys {
casper::opaque::SessionKeys {
babe,
grandpa,
authority_discovery,
slow_clap,
}
}
pub fn casper_chain_spec_properties() -> serde_json::map::Map<String, serde_json::Value> {
serde_json::json!({
"ss58Format": 1996,
"tokenDecimals": 18,
"tokenSymbol": "CSPR",
})
.as_object()
.expect("Map given; qed")
.clone()
}
/// Helper function to generate a crypto pair from seed.
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
TPublic::Pair::from_string(&format!("//{}", seed), None)
.expect("static values are valid; qed")
.public()
}
/// Helper function to generate account ID from seed.
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
where
AccountPublic: From<<TPublic::Pair as Pair>::Public>,
{
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
}
/// Helper function to generate stash, controller and session key from seed
pub fn generate_authority_keys_from_seed(
seed: &str,
) -> (
AccountId,
AccountId,
BabeId,
GrandpaId,
AuthorityDiscoveryId,
SlowClapId,
) {
let keys = get_authority_keys_from_seed(seed);
(keys.0, keys.1, keys.2, keys.3, keys.4, keys.5)
}
/// Helper function to generate stash, controller and session key from seed
pub fn get_authority_keys_from_seed(
seed: &str,
) -> (
AccountId,
AccountId,
BabeId,
GrandpaId,
AuthorityDiscoveryId,
SlowClapId,
) {
(
get_account_id_from_seed::<sr25519::Public>(&format!("{}//stash", seed)),
get_account_id_from_seed::<sr25519::Public>(seed),
get_from_seed::<BabeId>(seed),
get_from_seed::<GrandpaId>(seed),
get_from_seed::<AuthorityDiscoveryId>(seed),
get_from_seed::<SlowClapId>(seed),
)
}
#[cfg(feature = "casper-native")]
fn casper_testnet_accounts() -> Vec<AccountId> {
vec![
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_account_id_from_seed::<sr25519::Public>("Charlie"),
get_account_id_from_seed::<sr25519::Public>("Dave"),
get_account_id_from_seed::<sr25519::Public>("Eve"),
get_account_id_from_seed::<sr25519::Public>("Feride"),
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),
get_account_id_from_seed::<sr25519::Public>("Dave//stash"),
get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
get_account_id_from_seed::<sr25519::Public>("Feride//stash"),
]
}
#[cfg(feature = "casper-native")]
fn casper_testnet_evm_accounts() -> Vec<(AccountId, u128, u8)> {
vec![
// 01c928771aea942a1e7ac06adf2b73dfbc9a25d9eaa516e3673116af7f345198
(get_account_id_from_seed::<sr25519::Public>("1A69d2D5568D1878023EeB121a73d33B9116A760"), 1337 * CSPR, 1),
// b19a435901872f817185f7234a1484eae837613f9d10cf21927a23c2d8cb9139
(get_account_id_from_seed::<sr25519::Public>("2f86cfBED3fbc1eCf2989B9aE5fc019a837A9C12"), 1337 * CSPR, 2),
// d3baf57b74d65719b2dc33f5a464176022d0cc5edbca002234229f3e733875fc
(get_account_id_from_seed::<sr25519::Public>("e83f67361Ac74D42A48E2DAfb6706eb047D8218D"), 69 * CSPR, 3),
// c4683d566436af6b58b4a59c8f501319226e85b21869bf93d5eeb4596d4791d4
(get_account_id_from_seed::<sr25519::Public>("827ee4ad9b259b6fa1390ed60921508c78befd63"), 69 * CSPR, 4),
]
}
#[cfg(feature = "casper-native")]
fn casper_testnet_evm_networks() -> Vec<(u32, Vec<u8>)> {
vec![
(1, ghost_networks::NetworkData {
chain_name: "ethereum-mainnet".into(),
default_endpoint: "https://nd-422-757-666.p2pify.com/0a9d79d93fb2f4a4b1e04695da2b77a7/".into(),
finality_delay: Some(40u64),
release_delay: Some(80u64),
network_type: ghost_networks::NetworkType::Evm,
gatekeeper: "0x4d224452801aced8b2f0aebe155379bb5d594381".into(),
topic_name: "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef".into(),
incoming_fee: 0u32,
outgoing_fee: 0u32,
}.encode()),
(56, ghost_networks::NetworkData {
chain_name: "bnb-mainnet".into(),
default_endpoint: "https://bsc-mainnet.core.chainstack.com/35848e183f3e3303c8cfeacbea831cab/".into(),
finality_delay: Some(20u64),
release_delay: Some(40u64),
network_type: ghost_networks::NetworkType::Evm,
gatekeeper: "0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82".into(),
topic_name: "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef".into(),
incoming_fee: 0u32,
outgoing_fee: 0u32,
}.encode())
]
}
/// Helper function to create casper `GenesisConfig` for testing
#[cfg(feature = "casper-native")]
pub fn testnet_config_genesis(
initial_authorities: Vec<(
AccountId,
AccountId,
BabeId,
GrandpaId,
AuthorityDiscoveryId,
SlowClapId,
)>,
endowed_accounts: Option<Vec<AccountId>>,
ghost_accounts: Option<Vec<(AccountId, u128, u8)>>,
evm_networks: Option<Vec<(u32, Vec<u8>)>>,
) -> serde_json::Value {
let endowed_accounts: Vec<AccountId> = endowed_accounts
.unwrap_or_else(casper_testnet_accounts);
let ghost_accounts: Vec<(AccountId, u128, u8)> = ghost_accounts
.unwrap_or_default();
let evm_networks: Vec<(u32, Vec<u8>)> = evm_networks
.unwrap_or_default();
const ENDOWMENT: u128 = 1_000 * CSPR;
const STASH: u128 = 500 * CSPR;
serde_json::json!({
"balances": {
"balances": endowed_accounts
.iter()
.map(|k| (k.clone(), ENDOWMENT))
.chain(ghost_accounts
.iter()
.map(|k| (k.0.clone(), k.1.clone())))
.collect::<Vec<_>>(),
},
"session": {
"keys": initial_authorities
.iter()
.map(|x| {
(
x.0.clone(),
x.0.clone(),
casper_session_keys(
x.2.clone(),
x.3.clone(),
x.4.clone(),
x.5.clone(),
),
)
})
.collect::<Vec<_>>(),
},
"staking": {
"validatorCount": initial_authorities.len() as u32,
"minimumValidatorCount": 1,
"invulnerables": initial_authorities
.iter()
.map(|x| x.0.clone())
.collect::<Vec<_>>(),
"forceEra": Forcing::NotForcing,
"slashRewardFraction": Perbill::from_percent(10),
"stakers": initial_authorities
.iter()
.map(|x| (x.0.clone(), x.0.clone(), STASH, casper::StakerStatus::<AccountId>::Validator))
.collect::<Vec<_>>(),
},
"babe": {
"epochConfig": Some(casper::BABE_GENESIS_EPOCH_CONFIG),
},
"ghostNetworks": {
"networks": evm_networks,
},
"ghostClaims": {
"total": ghost_accounts.iter().fold(0, |acc, k| acc + k.1),
"membersAndRanks": ghost_accounts
.iter()
.map(|k| (k.0.clone(), k.2.clone()))
.collect::<Vec<_>>(),
},
})
}
#[cfg(feature = "casper-native")]
fn casper_staging_config_genesis() -> serde_json::Value {
use hex_literal::hex;
use sp_core::crypto::UncheckedInto;
// Following keys are used in genesis config for testing (casper) chains.
// DO NOT use them in production chains such as ghost.
let endowed_accounts = vec![
// sfErNwRgZ6ypB7wY8M2smXMZjxqUkc2TgUcNvC1JNQJFXS8bw
hex!["328d3b7c3046ef7700937d99fb2e98ce2591682c2b5dcf3f562e4da157650237"].into(),
// sfEwRjyvEQcpRQ1qbCZum27nEkTggKEt7DtqxwyYQULt9UuUN
hex!["3666e4e19f87bb8680495f31864ce1f1c69d4178002cc01911aef2cc7313f203"].into(),
// sfHcJxw5cgkvukZZyxcNUMCdbm9e7773orByLrGgAREka81TK
hex!["ac871e8bab00dd56ba3a1c0bd289357203dcaf10010b0b04ad7472870cd22a3c"].into(),
];
let initial_authorities: Vec<(
AccountId,
AccountId,
BabeId,
GrandpaId,
AuthorityDiscoveryId,
SlowClapId,
)> = vec![
(
// sfFXZmnDVnkQ781J2gbqUpi7K5KgMWMdM4eeii74xxGgKYnNN
hex!["507045c82be367f95408466cd054ca39bfa52697a3ef22809af14cf9de304f02"].into(),
// sfFXZmnDVnkQ781J2gbqUpi7K5KgMWMdM4eeii74xxGgKYnNN
hex!["507045c82be367f95408466cd054ca39bfa52697a3ef22809af14cf9de304f02"].into(),
// sfJeojACBa7WiH6tBwikBKAMU2oKmseEBD1GYUYATvfWuLcPa
hex!["daaaaab6a6e574099e24ae9bb75b543610edef9d374fa85a378edb573b47615f"].unchecked_into(),
// sfFdtzNxJdeEkgHxvk144rJKxf7wcYvgX5tqfgZRutW9YvAKE
hex!["55446f9a7aa99ced06b317c80ce90d56b84e56526775683af2525969e8da0b64"].unchecked_into(),
// sfE8gsMYAjAJHk5gyYZN7AW6pfmJ7V9H7xxWto24nmhzCUXaQ
hex!["12c14850562021eb99f58f90ab624fb6cfaf3ac9228a92f8b60115fe6a6af15a"].unchecked_into(),
// sfE3GKSrKZzrZpdapJ2VGRpPor45T4D4i8QBZNumSNGqGv7PX
hex!["0e9e698c7b2bf5ce3861cb4bc4ddf9e200237c282025b093ada850d764d12a35"].unchecked_into(),
),
(
// sfHLqWNC4hMKHhwvPWmWcxZsDPhCTQKgh1Ap7pm3qML5GBTBa
hex!["a0ba0196e6ee7e6b5b0553035c5cb5c04e9725001b5732839d0529cbc00c9600"].into(),
// sfHLqWNC4hMKHhwvPWmWcxZsDPhCTQKgh1Ap7pm3qML5GBTBa
hex!["a0ba0196e6ee7e6b5b0553035c5cb5c04e9725001b5732839d0529cbc00c9600"].into(),
// sfGA6tPPF8dAc8QpMCMjxitG3j8sXPhkdpm5bwz4UsXAApUiw
hex!["6c4dd88b43e2011cf9a6a73d53446336ac9e04cdd4ca23587df63187ac455e49"].unchecked_into(),
// sfGxQZXFUQH1AXv82rpjiJHFs7YsdEuVGdyvKiS2Tajpvw6Se
hex!["8f9ea20bf4a807a8e710f7559dece86e94672b5b361de157bdaa5c1f37849f8d"].unchecked_into(),
// sfGz2enFUR22cQ5ey61MdtPqbCeEWZA1wsCFFSLGaK7vKnv8C
hex!["90db5ed339a559ed157995a48d781f44c7df972dfba4bc855e4b59fa46438e17"].unchecked_into(),
// sfEtwe5BoroNjkdLsvnjnMemUKiw8MS1X4YW8bepbbGvhS4LZ
hex!["3481cdcbcf37a4669c29a78cf9ceb39383a10ef0a18b36b92d149fdd0c24ae00"].unchecked_into(),
),
(
// sfGq75CrCrkcfqNzyyidu3D4jW3AoJSzL5tKKuv1UbS16ezzy
hex!["8a0d0b66e827bf20e79f9a499317e73925ce4f422371067edfab690e43857f13"].into(),
// sfGq75CrCrkcfqNzyyidu3D4jW3AoJSzL5tKKuv1UbS16ezzy
hex!["8a0d0b66e827bf20e79f9a499317e73925ce4f422371067edfab690e43857f13"].into(),
// sfJo2ogBpssRAU9ZPTvuXFZEdmJw9pKsPydLjXe8DypRScjzT
hex!["e0f0a776ecc9fa5e1f22e2fa001fe3fba5aea52b9444bc894b45589d42132475"].unchecked_into(),
// sfHq3EVT1sqY7o5ki3zA6LEdRDfdFc29YaZN3w2Thhz6JD5ZF
hex!["b63c5a0cf342b9b04931bc8ed74d7d0165ab99ab5f8a4514797d4b299a4501fe"].unchecked_into(),
// sfEj3wrDy9EDLCAodyEdQEYxJpNnM8Etaj3RJ5bCBRzdaDced
hex!["2cf69452e9f2a8457119139408884941ed50f590c0fc0f2b044c4d82c69e4245"].unchecked_into(),
// sfE32RmBp1xX4KRTphVGLUJBxLGPN3Dzg9BwCJktxMf3iEwck
hex!["0e6fa6934f9e99fa84874f2ed9318825a0d5443a0ced984acfbd24ece72ba55e"].unchecked_into(),
),
];
let ghost_accounts: Vec<(AccountId, u128, u8)> = casper_testnet_evm_accounts();
let evm_networks = casper_testnet_evm_networks();
const ENDOWMENT: u128 = 5_000 * CSPR;
const STASH: u128 = 500 * CSPR;
serde_json::json!({
"balances": {
"balances": endowed_accounts
.iter()
.map(|k: &AccountId| (k.clone(), ENDOWMENT))
.chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH)))
.collect::<Vec<_>>(),
},
"session": {
"keys": initial_authorities
.iter()
.map(|x| {
(
x.0.clone(),
x.0.clone(),
casper_session_keys(
x.2.clone(),
x.3.clone(),
x.4.clone(),
x.5.clone(),
),
)
})
.collect::<Vec<_>>(),
},
"staking": {
"validatorCount": 50,
"minimumValidatorCount": 2,
"stakers": initial_authorities
.iter()
.map(|x| {
(
x.0.clone(),
x.0.clone(),
STASH,
casper::StakerStatus::<AccountId>::Validator,
)
})
.collect::<Vec<_>>(),
"invulnerables": initial_authorities.iter().map(|x| x.0.clone()).collect::<Vec<_>>(),
"forceEra": Forcing::ForceNone,
"slashRewardFraction": Perbill::from_percent(10)
},
"babe": {
"epochConfig": Some(casper::BABE_GENESIS_EPOCH_CONFIG),
},
"ghostNetworks": {
"networks": evm_networks,
},
"ghostClaims": {
"total": ghost_accounts
.iter()
.fold(0, |acc, k| acc + k.1),
"membersAndRanks": ghost_accounts
.iter()
.map(|k| (k.0.clone(), k.2.clone()))
.collect::<Vec<_>>(),
},
})
}
#[cfg(feature = "casper-native")]
fn casper_development_config_genesis() -> serde_json::Value {
testnet_config_genesis(
vec![get_authority_keys_from_seed("Alice")],
None, None, None,
)
}
#[cfg(feature = "casper-native")]
fn casper_local_config_genesis() -> serde_json::Value {
testnet_config_genesis(
vec![
get_authority_keys_from_seed("Alice"),
get_authority_keys_from_seed("Bob"),
],
Some(casper_testnet_accounts()),
Some(casper_testnet_evm_accounts()),
Some(casper_testnet_evm_networks()),
)
}
#[cfg(feature = "casper-native")]
pub fn casper_development_config() -> Result<CasperChainSpec, String> {
Ok(CasperChainSpec::builder(
casper::WASM_BINARY.ok_or("Casper development wasm not available")?,
Default::default(),
)
.with_name("Development")
.with_id("casper_dev")
.with_chain_type(ChainType::Development)
.with_genesis_config_patch(casper_development_config_genesis())
.with_protocol_id(DEFAULT_PROTOCOL_ID)
.with_properties(casper_chain_spec_properties())
.build())
}
#[cfg(feature = "casper-native")]
pub fn casper_local_testnet_config() -> Result<CasperChainSpec, String> {
Ok(CasperChainSpec::builder(
casper::WASM_BINARY.ok_or("Casper local testnet wasm not available")?,
Default::default(),
)
.with_name("Casper Local Testnet")
.with_id("casper_local_testnet")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(casper_local_config_genesis())
.with_protocol_id(DEFAULT_PROTOCOL_ID)
.with_properties(casper_chain_spec_properties())
.build())
}
#[cfg(feature = "casper-native")]
pub fn casper_staging_testnet_config() -> Result<CasperChainSpec, String> {
Ok(CasperChainSpec::builder(
casper::WASM_BINARY.ok_or("Casper staging testnet wasm not available")?,
Default::default(),
)
.with_name("Casper Staging Testnet")
.with_id("casper_staging_testnet")
.with_chain_type(ChainType::Live)
.with_genesis_config_patch(casper_staging_config_genesis())
.with_telemetry_endpoints(
TelemetryEndpoints::new(vec![(CASPER_TELEMETRY_URL.to_string(), 0)])
.expect("Casper Staging telemetry url is valid; qed"),
)
.with_protocol_id(DEFAULT_PROTOCOL_ID)
.with_properties(casper_chain_spec_properties())
.build())
}