use pallet_staking::Forcing; use sp_staking::StakerStatus; use casper_runtime_constants::currency::CSPR; use primitives::{AccountId, AccountPublic}; use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; use babe_primitives::AuthorityId as BabeId; use grandpa_primitives::AuthorityId as GrandpaId; use hex_literal::hex; use sp_core::crypto::UncheckedFrom; use sp_core::{sr25519, Pair, Public}; use sp_runtime::{traits::IdentifyAccount, Perbill}; #[cfg(not(feature = "std"))] use sp_std::alloc::format; use sp_std::prelude::*; use sp_std::vec::Vec; use crate::{Balance, NetworkId}; use ghost_weaver::sr25519::AuthorityId as WeaverId; use ghost_exodus::sr25519::AuthorityId as ExodusId; use ghost_helpers::networks::{ NetworkClaim, NetworkInitiation, NetworkInitiationBuilder, NetworkDataBuilder, NetworkType, NetworkCurve, }; #[derive(Clone)] pub struct AuthorityInitiation { stash: AccountId, account: AccountId, babe_id: BabeId, grandpa_id: GrandpaId, authority_discovery_id: AuthorityDiscoveryId, weaver_id: WeaverId, exodus_id: ExodusId, } impl AuthorityInitiation { pub fn casper_session_keys(self) -> crate::opaque::SessionKeys { crate::opaque::SessionKeys { babe: self.babe_id, grandpa: self.grandpa_id, authority_discovery: self.authority_discovery_id, weaver: self.weaver_id, exodus: self.exodus_id, } } } #[derive(Default)] struct AuthorityInitiationBuilder { stash: Option, account: Option, babe_id: Option, grandpa_id: Option, authority_discovery_id: Option, weaver_id: Option, exodus_id: Option, } impl AuthorityInitiationBuilder { pub fn with_stash(mut self, stash: AccountId) -> Self { self.stash = Some(stash); self } pub fn with_account(mut self, account: AccountId) -> Self { self.account = Some(account); self } pub fn with_babe_id(mut self, babe_id: BabeId) -> Self { self.babe_id = Some(babe_id); self } pub fn with_grandpa_id(mut self, grandpa_id: GrandpaId) -> Self { self.grandpa_id = Some(grandpa_id); self } pub fn with_authority_id(mut self, authority_id: AuthorityDiscoveryId,) -> Self { self.authority_discovery_id = Some(authority_id); self } pub fn with_weaver_id(mut self, weaver_id: WeaverId) -> Self { self.weaver_id = Some(weaver_id); self } pub fn with_exodus_id(mut self, exodus_id: ExodusId) -> Self { self.exodus_id = Some(exodus_id); self } pub fn build(self) -> AuthorityInitiation { AuthorityInitiation { stash: self.stash.expect("No stash key provided during authority initiation."), account: self.account.expect("No account key provided during authority initiation."), babe_id: self.babe_id.expect("No babe key provided during authority initiation."), grandpa_id: self.grandpa_id.expect("No gran key provided during authority initiation."), authority_discovery_id: self.authority_discovery_id.expect("No audi key provided during authority initiation."), weaver_id: self.weaver_id.expect("No weav key provided during authority initiation."), exodus_id: self.exodus_id.expect("No exds key provided during authority initiation."), } } } pub struct AccountInitiation { account: AccountId, balance: u128, } #[derive(Default)] struct AccountInitiationBuilder { account: Option, balance: u128, } impl AccountInitiationBuilder { pub fn with_account(mut self, account: AccountId) -> Self { self.account = Some(account); self } pub fn with_balance(mut self, balance: u128) -> Self { self.balance = balance; self } pub fn build(self) -> AccountInitiation { AccountInitiation { balance: self.balance, account: self.account .expect("No account key provided during account initiation."), } } } fn get_from_seed(seed: &str) -> ::Public { TPublic::Pair::from_string(&format!("//{}", seed), None) .expect("static values are valid; qed") .public() } fn get_account_id_from_seed(seed: &str) -> AccountId where AccountPublic: From<::Public>, { AccountPublic::from(get_from_seed::(seed)).into_account() } fn get_authority_keys_from_seed( seed: &str, ) -> AuthorityInitiation { let stash = get_account_id_from_seed::(&format!("{}//stash", seed)); let account = get_account_id_from_seed::(seed); let babe_id = get_from_seed::(seed); let weaver_id = get_from_seed::(seed); let exodus_id = get_from_seed::(seed); let grandpa_id = get_from_seed::(seed); let authority_id = get_from_seed::(seed); AuthorityInitiationBuilder::default() .with_stash(stash) .with_account(account) .with_babe_id(babe_id) .with_weaver_id(weaver_id) .with_exodus_id(exodus_id) .with_grandpa_id(grandpa_id) .with_authority_id(authority_id) .build() } fn casper_staging_initial_authorities() -> Vec { vec![ // sfFXZmnDVnkQ781J2gbqUpi7K5KgMWMdM4eeii74xxGgKYnNN AuthorityInitiationBuilder::default() .with_stash(AccountId::new(hex!("507045c82be367f95408466cd054ca39bfa52697a3ef22809af14cf9de304f02"))) .with_account(AccountId::new(hex!("507045c82be367f95408466cd054ca39bfa52697a3ef22809af14cf9de304f02"))) .with_babe_id(BabeId::unchecked_from(hex!("daaaaab6a6e574099e24ae9bb75b543610edef9d374fa85a378edb573b47615f"))) .with_grandpa_id(GrandpaId::unchecked_from(hex!("55446f9a7aa99ced06b317c80ce90d56b84e56526775683af2525969e8da0b64"))) .with_authority_id(AuthorityDiscoveryId::unchecked_from(hex!("12c14850562021eb99f58f90ab624fb6cfaf3ac9228a92f8b60115fe6a6af15a"))) .with_weaver_id(WeaverId::unchecked_from(hex!("0e9e698c7b2bf5ce3861cb4bc4ddf9e200237c282025b093ada850d764d12a35"))) .with_exodus_id(ExodusId::unchecked_from(hex!("0e9e698c7b2bf5ce3861cb4bc4ddf9e200237c282025b093ada850d764d12a35"))) .build(), // TODO: revisit ] } fn casper_testnet_networks() -> Vec> { vec![ NetworkInitiationBuilder::default() .with_network_id(11155111) .with_gatekeeper_amount(0) .with_network_data( NetworkDataBuilder::default() .with_gatekeeper(hex!("9cFfBdBdF29C67c5DbAB1B5E8Ae897AeAFcaf70C").to_vec()) .with_selector(hex!("d4be7935").to_vec()) .with_default_endpoints( vec![ b"https://sepolia.drpc.org".to_vec(), b"https://sepolia.gateway.tenderly.co".to_vec(), b"https://api.zan.top/eth-sepolia".to_vec(), b"https://rpc.sepolia.ethpandaops.io".to_vec(), b"https://ethereum-sepolia-rpc.publicnode.com".to_vec(), b"https://1rpc.io/sepolia".to_vec(), b"https://0xrpc.io/sep".to_vec(), b"https://eth-sepolia.api.onfinality.io/public".to_vec(), ] ) .with_network_type(NetworkType::Evm) .with_network_curve(NetworkCurve::Secp256k1) .with_finality_delay(69) .with_rate_limit_delay(5_000) .with_block_deviation(420) .with_incoming_fee(69_000_000u32) .with_outgoing_fee(69_000_000u32) .build() ) .build() ] } pub fn testnet_config_genesis( initial_authorities: Vec, initial_accounts: Vec, initial_networks: Vec>, initial_claims: Vec>, ) -> serde_json::Value { const ENDOWMENT: u128 = 31 * CSPR; const STASH: u128 = 69 * CSPR; let sudo = initial_authorities.first().map(|x| x.account.clone()).unwrap(); serde_json::json!({ "balances": { "balances": initial_accounts .iter() .map(|x| (x.account.clone(), x.balance)) .chain(initial_authorities.iter().map(|x| (x.account.clone(), ENDOWMENT))) .chain(initial_authorities.iter().map(|x| (x.stash.clone(), STASH))) .collect::>(), }, "session": { "keys": initial_authorities .iter() .map(|x| { (x.stash.clone(), x.stash.clone(), x.clone().casper_session_keys()) }) .collect::>(), }, "staking": { "validatorCount": initial_authorities.len() as u32, "minimumValidatorCount": 4, "invulnerables": initial_authorities .iter() .map(|x| x.stash.clone()) .collect::>(), "forceEra": Forcing::NotForcing, "slashRewardFraction": Perbill::from_percent(10), "stakers": initial_authorities .iter() .map(|x| ( x.stash.clone(), x.stash.clone(), STASH, StakerStatus::::Validator, )) .collect::>(), }, "babe": { "epochConfig": Some(crate::BABE_GENESIS_EPOCH_CONFIG) }, "ghostSudo": { "key": sudo }, "ghostNetworks": { "networks": initial_networks }, "ghostGovernance": { "networkClaims": initial_claims }, "ghostWeaver": { "authorities": [], "loomStates": [] }, "ghostExodus": { "authorities": [] } }) } pub fn casper_development_config_genesis() -> serde_json::Value { let initial_authorities = vec![get_authority_keys_from_seed("Alice")]; testnet_config_genesis( initial_authorities, Default::default(), Default::default(), Default::default(), ) } pub fn casper_local_config_genesis() -> serde_json::Value { let initial_authorities = vec![ get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob"), get_authority_keys_from_seed("Charlie"), get_authority_keys_from_seed("Dave"), ]; let initial_accounts = vec![ AccountInitiationBuilder::default() .with_account(get_account_id_from_seed::("Eve")) .with_balance(420 * CSPR) .build(), AccountInitiationBuilder::default() .with_account(get_account_id_from_seed::("Ferdie")) .with_balance(1337 * CSPR) .build(), ]; testnet_config_genesis( initial_authorities, initial_accounts, casper_testnet_networks(), Default::default(), ) } pub fn casper_staging_config_genesis() -> serde_json::Value { testnet_config_genesis( casper_staging_initial_authorities(), Default::default(), casper_testnet_networks(), Default::default(), ) } /// Provides the JSON representation of predefined genesis config for given `id`. pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option> { let patch = match id.try_into() { Ok("casper_development") => casper_development_config_genesis(), Ok("casper_local_testnest") => casper_local_config_genesis(), Ok("casper_staging_testnet") => casper_staging_config_genesis(), _ => return None, }; Some( serde_json::to_string(&patch) .expect("serialization to json is expected to work; qed") .into_bytes(), ) } /// Returns a list of identifiers for available builtin `RuntimeGenesisConfig` presets. pub fn preset_names() -> Vec { Vec::from([ sp_genesis_builder::PresetId::from("casper_staging_testnet"), sp_genesis_builder::PresetId::from("casper_local_testnet"), sp_genesis_builder::PresetId::from("casper_development"), ]) }