diff --git a/node/src/chainspec/mainnet.rs b/node/src/chainspec/mainnet.rs index 73f3ce06a..c4e414e78 100644 --- a/node/src/chainspec/mainnet.rs +++ b/node/src/chainspec/mainnet.rs @@ -28,19 +28,54 @@ use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use sc_consensus_grandpa::AuthorityId as GrandpaId; use sc_service::ChainType; use sp_consensus_babe::AuthorityId as BabeId; -use sp_runtime::{traits::AccountIdConversion, BoundedVec}; -use tangle_primitives::BlockNumber; +use sp_core::{sr25519, Pair, Public}; +use sp_runtime::{ + traits::{AccountIdConversion, IdentifyAccount, Verify}, + BoundedVec, +}; +use tangle_primitives::{BlockNumber, Signature}; use tangle_runtime::{ - AccountId, Balance, BalancesConfig, ClaimsConfig, EVMChainIdConfig, Eth2ClientConfig, - ImOnlineConfig, MaxVestingSchedules, Perbill, RuntimeGenesisConfig, SessionConfig, - StakerStatus, StakingConfig, SudoConfig, SystemConfig, TreasuryPalletId, VestingConfig, - WASM_BINARY, + AccountId, BabeConfig, Balance, BalancesConfig, ClaimsConfig, EVMChainIdConfig, + Eth2ClientConfig, ImOnlineConfig, MaxVestingSchedules, Perbill, RuntimeGenesisConfig, + SessionConfig, StakerStatus, StakingConfig, SudoConfig, SystemConfig, TreasuryPalletId, + VestingConfig, UNIT, WASM_BINARY, }; use webb_consensus_types::network_config::{Network, NetworkConfig}; /// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type. pub type ChainSpec = sc_service::GenericChainSpec; +/// 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() +} + +type AccountPublic = ::Signer; + +/// 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() +} + +/// Generate an babe authority key. +pub fn authority_keys_from_seed( + controller: &str, + stash: &str, +) -> (AccountId, AccountId, BabeId, GrandpaId, ImOnlineId) { + ( + get_account_id_from_seed::(controller), + get_account_id_from_seed::(stash), + get_from_seed::(controller), + get_from_seed::(controller), + get_from_seed::(stash), + ) +} + /// Generate the session keys from individual elements. /// /// The input must be a tuple of individual keys (a single arg for now since we @@ -53,9 +88,69 @@ fn generate_session_keys( tangle_runtime::opaque::SessionKeys { grandpa, babe, im_online } } +pub fn local_mainnet_config(chain_id: u64) -> Result { + let wasm_binary = WASM_BINARY.ok_or_else(|| "tangle wasm not available".to_string())?; + let mut properties = sc_chain_spec::Properties::new(); + properties.insert("tokenSymbol".into(), "TNT".into()); + properties.insert("tokenDecimals".into(), 18u32.into()); + properties.insert("ss58Format".into(), 4006.into()); + + Ok(ChainSpec::from_genesis( + "Local Tangle Mainnet", + "local-tangle-mainnet", + ChainType::Local, + move || { + mainnet_genesis( + // Wasm binary + wasm_binary, + // Initial validators + vec![ + authority_keys_from_seed("Alice", "Alice//stash"), + authority_keys_from_seed("Bob", "Bob//stash"), + ], + // Endowed accounts + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + ], + // Sudo account + get_account_id_from_seed::("Alice"), + // EVM chain ID + chain_id, + // Genesis airdrop distribution (pallet-claims) + get_unique_distribution_results(vec![ + mainnet::get_edgeware_genesis_balance_distribution(), + mainnet::get_leaderboard_balance_distribution(), + mainnet::get_substrate_balance_distribution(), + mainnet::get_local_balance_distribution(), + ]), + // Genesis investor / team distribution (pallet-balances + pallet-vesting) + combine_distributions(vec![ + mainnet::get_team_balance_distribution(), + mainnet::get_investor_balance_distribution(), + ]), + ) + }, + // Bootnodes + vec![], + // Telemetry + None, + // Protocol ID + None, + // Fork id + None, + // Properties + Some(properties), + // Extensions + None, + )) +} + pub fn tangle_mainnet_config(chain_id: u64) -> Result { let wasm_binary = WASM_BINARY.ok_or_else(|| "tangle wasm not available".to_string())?; let mut properties = sc_chain_spec::Properties::new(); + properties.insert("tokenSymbol".into(), "TNT".into()); properties.insert("tokenDecimals".into(), 18u32.into()); properties.insert("ss58Format".into(), 4006.into()); @@ -69,6 +164,8 @@ pub fn tangle_mainnet_config(chain_id: u64) -> Result { wasm_binary, // Initial validators get_initial_authorities(), + // Endowed accounts + vec![], // Sudo account get_root_key(), // EVM chain ID @@ -106,11 +203,13 @@ pub fn tangle_mainnet_config(chain_id: u64) -> Result { fn mainnet_genesis( wasm_binary: &[u8], initial_authorities: Vec<(AccountId, AccountId, BabeId, GrandpaId, ImOnlineId)>, + endowed_accounts: Vec, root_key: AccountId, chain_id: u64, genesis_airdrop: DistributionResult, genesis_non_airdrop: Vec<(MultiAddress, u128, u64, u64, u128)>, ) -> RuntimeGenesisConfig { + const ENDOWMENT: Balance = 10_000_000 * UNIT; // stakers: all validators and nominators. let stakers = initial_authorities .iter() @@ -142,6 +241,7 @@ fn mainnet_genesis( balances: genesis_non_airdrop .iter() .map(|(x, y, _, _, _)| (x.clone().to_account_id_32(), *y)) + .chain(endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT))) .collect(), }, vesting: VestingConfig { @@ -175,7 +275,10 @@ fn mainnet_genesis( council: Default::default(), elections: Default::default(), treasury: Default::default(), - babe: Default::default(), + babe: BabeConfig { + epoch_config: Some(tangle_runtime::BABE_GENESIS_EPOCH_CONFIG), + ..Default::default() + }, grandpa: Default::default(), im_online: ImOnlineConfig { keys: vec![] }, nomination_pools: Default::default(), diff --git a/node/src/chainspec/testnet.rs b/node/src/chainspec/testnet.rs index de2b3f3b7..07e60d7ce 100644 --- a/node/src/chainspec/testnet.rs +++ b/node/src/chainspec/testnet.rs @@ -274,6 +274,7 @@ fn testnet_genesis( (MultiAddress::Native(x.clone()), bounded_vec) }) .collect(); + RuntimeGenesisConfig { system: SystemConfig { // Add Wasm runtime to storage. diff --git a/node/src/command.rs b/node/src/command.rs index 7879d9cde..23b9220f7 100644 --- a/node/src/command.rs +++ b/node/src/command.rs @@ -80,6 +80,7 @@ impl SubstrateCli for Cli { &include_bytes!("../../chainspecs/testnet/tangle-standalone.json")[..], )?), // generates the spec for mainnet + "mainnet-local" => Box::new(chainspec::mainnet::local_mainnet_config(4006)?), "mainnet" => Box::new(chainspec::mainnet::tangle_mainnet_config(4006)?), path => Box::new(chainspec::testnet::ChainSpec::from_json_file( std::path::PathBuf::from(path), diff --git a/node/src/distributions/develop.rs b/node/src/distributions/develop.rs index f6d53b7b9..4bf3b5fa2 100644 --- a/node/src/distributions/develop.rs +++ b/node/src/distributions/develop.rs @@ -139,5 +139,19 @@ pub fn get_evm_balance_distribution() -> Vec<(H160, GenesisAccount)> { code: Default::default(), }, ), + // Test account with a simple menmonic + // Mnemonic: "test test test test test test test test test test test junk" + // Path: m/44'/60'/0'/0/0 + // Private Key: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 + ( + H160::from_str("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266") + .expect("internal H160 is valid; qed"), + GenesisAccount { + nonce: U256::from(1), + balance: U256::from(1_000_000_000_000_000_000_000_000u128), + storage: Default::default(), + code: Default::default(), + }, + ), ] } diff --git a/node/src/distributions/mainnet.rs b/node/src/distributions/mainnet.rs index a75a42384..f9b61c611 100644 --- a/node/src/distributions/mainnet.rs +++ b/node/src/distributions/mainnet.rs @@ -163,6 +163,45 @@ pub fn get_leaderboard_balance_distribution() -> DistributionResult { ) } +/// Used for testing purposes +/// +/// DO NOT USE IN MAINNET +pub fn get_local_balance_distribution() -> DistributionResult { + let list = vec![ + // Test account with a simple menmonic + // Mnemonic: "test test test test test test test test test test test junk" + // Path: m/44'/60'/0'/0/0 + // Private Key: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 + H160::from_str("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266") + .expect("internal H160 is valid; qed"), + // Test account with a simple menmonic + // Mnemonic: "test test test test test test test test test test test junk" + // Path: m/44'/60'/0'/0/1 + // Private Key: 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d + H160::from_str("70997970C51812dc3A010C7d01b50e0d17dc79C8") + .expect("internal H160 is valid; qed"), + // H160 address of Alice dev account + // Derived from SS58 (42 prefix) address + // SS58: 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY + // hex: 0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d + // Using the full hex key, truncating to the first 20 bytes (the first 40 hex + // chars) + H160::from_str("d43593c715fdd31c61141abd04a99fd6822c8558") + .expect("internal H160 is valid; qed"), + ]; + let endowment = ONE_PERCENT_TOTAL_SUPPLY / list.len() as u128; + let local_list: Vec<(MultiAddress, u128)> = list + .into_iter() + .map(|address| (MultiAddress::EVM(EthereumAddress(address.0)), endowment)) + .collect(); + get_distribution_for( + local_list, + Some(StatementKind::Regular), + ONE_MONTH_BLOCKS, + TWO_YEARS_BLOCKS, + ) +} + pub fn get_substrate_balance_distribution() -> DistributionResult { let arr = get_edgeware_snapshot_list() .into_iter() diff --git a/node/src/distributions/mod.rs b/node/src/distributions/mod.rs index fa457ce70..5dddf6209 100644 --- a/node/src/distributions/mod.rs +++ b/node/src/distributions/mod.rs @@ -18,8 +18,7 @@ use self::mainnet::DistributionResult; use pallet_airdrop_claims::{MultiAddress, StatementKind}; -use tangle_primitives::{Balance, BlockNumber}; - +use tangle_primitives::{currency::EXISTENTIAL_DEPOSIT, Balance, BlockNumber}; pub mod develop; pub mod mainnet; pub mod testnet; @@ -59,7 +58,14 @@ pub fn get_unique_distribution_results( } let unique_claims: Vec<(MultiAddress, Balance, Option)> = unique_claims .into_iter() - .map(|(address, (balance, statement))| (address, balance, statement)) + .filter_map(|(address, (balance, statement))| { + // Skip any claims that are below the existential deposit. + if balance < EXISTENTIAL_DEPOSIT { + None + } else { + Some((address, balance, statement)) + } + }) .collect(); let mut unique_vesting = std::collections::HashMap::new(); diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 71e3695fc..6f88abd38 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -86,12 +86,7 @@ pub mod currency { pub const CENT: Balance = DOLLAR / 100; pub const MILLICENT: Balance = CENT / 1000; /// The existential deposit. - #[allow(clippy::identity_op)] - #[cfg(feature = "integration-tests")] - pub const EXISTENTIAL_DEPOSIT: Balance = 1000; - - #[cfg(not(feature = "integration-tests"))] - pub const EXISTENTIAL_DEPOSIT: Balance = MICROUNIT / 1000; + pub const EXISTENTIAL_DEPOSIT: Balance = UNIT; pub const WEI: Balance = 1; pub const KILOWEI: Balance = 1_000;