diff --git a/core/src/commitment_service.rs b/core/src/commitment_service.rs index bbccbfd82d..c3a7a6a14d 100644 --- a/core/src/commitment_service.rs +++ b/core/src/commitment_service.rs @@ -246,10 +246,7 @@ mod tests { bank_forks::BankForks, genesis_utils::{create_genesis_config_with_vote_accounts, ValidatorVoteKeypairs}, }; - use solana_sdk::{ - pubkey::Pubkey, - signature::{Keypair, Signer}, - }; + use solana_sdk::{pubkey::Pubkey, signature::Signer}; use solana_stake_program::stake_state; use solana_vote_program::{ vote_state::{self, VoteStateVersions}, @@ -488,14 +485,8 @@ mod tests { let block_commitment_cache = RwLock::new(BlockCommitmentCache::new_for_tests()); - let node_keypair = Arc::new(Keypair::new()); - let vote_keypair = Arc::new(Keypair::new()); - let stake_keypair = Arc::new(Keypair::new()); - let validator_keypairs = vec![ValidatorVoteKeypairs { - node_keypair: node_keypair.clone(), - vote_keypair: vote_keypair.clone(), - stake_keypair, - }]; + let validator_vote_keypairs = ValidatorVoteKeypairs::new_rand(); + let validator_keypairs = vec![&validator_vote_keypairs]; let GenesisConfigInfo { genesis_config, mint_keypair: _, @@ -518,9 +509,9 @@ mod tests { vec![x], previous_bank.hash(), previous_bank.last_blockhash(), - &node_keypair, - &vote_keypair, - &vote_keypair, + &validator_vote_keypairs.node_keypair, + &validator_vote_keypairs.vote_keypair, + &validator_vote_keypairs.vote_keypair, None, ); bank.process_transaction(&vote).unwrap(); @@ -528,7 +519,10 @@ mod tests { } let working_bank = bank_forks.working_bank(); - let root = get_vote_account_root_slot(vote_keypair.pubkey(), &working_bank); + let root = get_vote_account_root_slot( + validator_vote_keypairs.vote_keypair.pubkey(), + &working_bank, + ); for x in 0..root { bank_forks.set_root(x, &None, None); } @@ -540,16 +534,19 @@ mod tests { vec![33], bank33.hash(), bank33.last_blockhash(), - &node_keypair, - &vote_keypair, - &vote_keypair, + &validator_vote_keypairs.node_keypair, + &validator_vote_keypairs.vote_keypair, + &validator_vote_keypairs.vote_keypair, None, ); bank34.process_transaction(&vote33).unwrap(); bank_forks.insert(bank34); let working_bank = bank_forks.working_bank(); - let root = get_vote_account_root_slot(vote_keypair.pubkey(), &working_bank); + let root = get_vote_account_root_slot( + validator_vote_keypairs.vote_keypair.pubkey(), + &working_bank, + ); let ancestors = working_bank.status_cache_ancestors(); let _ = AggregateCommitmentService::update_commitment_cache( &block_commitment_cache, @@ -601,9 +598,9 @@ mod tests { vec![x], previous_bank.hash(), previous_bank.last_blockhash(), - &node_keypair, - &vote_keypair, - &vote_keypair, + &validator_vote_keypairs.node_keypair, + &validator_vote_keypairs.vote_keypair, + &validator_vote_keypairs.vote_keypair, None, ); bank.process_transaction(&vote).unwrap(); @@ -611,7 +608,10 @@ mod tests { } let working_bank = bank_forks.working_bank(); - let root = get_vote_account_root_slot(vote_keypair.pubkey(), &working_bank); + let root = get_vote_account_root_slot( + validator_vote_keypairs.vote_keypair.pubkey(), + &working_bank, + ); let ancestors = working_bank.status_cache_ancestors(); let _ = AggregateCommitmentService::update_commitment_cache( &block_commitment_cache, diff --git a/core/src/repair_weight.rs b/core/src/repair_weight.rs index 3c71ede347..8b9094821b 100644 --- a/core/src/repair_weight.rs +++ b/core/src/repair_weight.rs @@ -511,6 +511,7 @@ mod test { use super::*; use solana_ledger::{blockstore::Blockstore, get_tmp_ledger_path}; use solana_runtime::{bank::Bank, bank_utils}; + use solana_sdk::hash::Hash; use trees::tr; #[test] @@ -658,7 +659,7 @@ mod test { assert_eq!(repair_weight.trees.get(&8).unwrap().ancestors(10), vec![8]); // Connect orphan back to main fork - blockstore.add_tree(tr(6) / (tr(8)), true, true); + blockstore.add_tree(tr(6) / (tr(8)), true, true, 2, Hash::default()); assert_eq!( AncestorIterator::new(8, &blockstore).collect::>(), vec![6, 5, 3, 1, 0] @@ -742,8 +743,8 @@ mod test { assert!(repair_weight.trees.contains_key(&20)); // Resolve orphans in blockstore - blockstore.add_tree(tr(6) / (tr(8)), true, true); - blockstore.add_tree(tr(11) / (tr(20)), true, true); + blockstore.add_tree(tr(6) / (tr(8)), true, true, 2, Hash::default()); + blockstore.add_tree(tr(11) / (tr(20)), true, true, 2, Hash::default()); // Call `update_orphan_ancestors` to resolve orphan repair_weight.update_orphan_ancestors( &blockstore, @@ -853,8 +854,8 @@ mod test { // Resolve the orphans, should now return no // orphans repairs = vec![]; - blockstore.add_tree(tr(6) / (tr(8)), true, true); - blockstore.add_tree(tr(11) / (tr(20)), true, true); + blockstore.add_tree(tr(6) / (tr(8)), true, true, 2, Hash::default()); + blockstore.add_tree(tr(11) / (tr(20)), true, true, 2, Hash::default()); repair_weight.get_best_orphans( &blockstore, &mut repairs, @@ -889,7 +890,7 @@ mod test { // orphan in the `trees` map, we should search for // exactly one more of the remaining two let mut repairs = vec![]; - blockstore.add_tree(tr(100) / (tr(101)), true, true); + blockstore.add_tree(tr(100) / (tr(101)), true, true, 2, Hash::default()); repair_weight.get_best_orphans( &blockstore, &mut repairs, @@ -991,7 +992,7 @@ mod test { // Chain orphan 8 back to the main fork, but don't // touch orphan 20 - blockstore.add_tree(tr(4) / (tr(8)), true, true); + blockstore.add_tree(tr(4) / (tr(8)), true, true, 2, Hash::default()); // Call `update_orphan_ancestors` to resolve orphan repair_weight.update_orphan_ancestors( @@ -1061,10 +1062,10 @@ mod test { } // Chain orphan 8 back to slot `old_parent` - blockstore.add_tree(tr(*old_parent) / (tr(8)), true, true); + blockstore.add_tree(tr(*old_parent) / (tr(8)), true, true, 2, Hash::default()); // Chain orphan 20 back to orphan 8 - blockstore.add_tree(tr(8) / (tr(20)), true, true); + blockstore.add_tree(tr(8) / (tr(20)), true, true, 2, Hash::default()); // Call `update_orphan_ancestors` to resolve orphan repair_weight.update_orphan_ancestors( @@ -1089,7 +1090,13 @@ mod test { // Add a vote that chains back to `old_parent`, should be purged let new_vote_slot = 100; - blockstore.add_tree(tr(*old_parent) / tr(new_vote_slot), true, true); + blockstore.add_tree( + tr(*old_parent) / tr(new_vote_slot), + true, + true, + 2, + Hash::default(), + ); repair_weight.add_votes( &blockstore, vec![(new_vote_slot, vec![Pubkey::default()])].into_iter(), @@ -1137,7 +1144,7 @@ mod test { ); // Ancestors of slot 31 are [30], with no existing subtree - blockstore.add_tree(tr(30) / (tr(31)), true, true); + blockstore.add_tree(tr(30) / (tr(31)), true, true, 2, Hash::default()); assert_eq!( repair_weight.find_ancestor_subtree_of_slot(&blockstore, 31), (vec![30].into_iter().collect::>(), None) @@ -1155,7 +1162,7 @@ mod test { // Chain orphan 8 back to slot 4 on a different fork, ancestor search // should not return ancestors earlier than the root - blockstore.add_tree(tr(4) / (tr(8)), true, true); + blockstore.add_tree(tr(4) / (tr(8)), true, true, 2, Hash::default()); assert_eq!( repair_weight.find_ancestor_subtree_of_slot(&blockstore, 8), (vec![4].into_iter().collect::>(), None) @@ -1242,8 +1249,8 @@ mod test { */ let blockstore = setup_forks(); - blockstore.add_tree(tr(8) / (tr(10) / (tr(11))), true, true); - blockstore.add_tree(tr(20) / (tr(22) / (tr(23))), true, true); + blockstore.add_tree(tr(8) / (tr(10) / (tr(11))), true, true, 2, Hash::default()); + blockstore.add_tree(tr(20) / (tr(22) / (tr(23))), true, true, 2, Hash::default()); assert!(blockstore.orphan(8).unwrap().is_some()); blockstore } @@ -1265,7 +1272,7 @@ mod test { let forks = tr(0) / (tr(1) / (tr(2) / (tr(4))) / (tr(3) / (tr(5) / (tr(6))))); let ledger_path = get_tmp_ledger_path!(); let blockstore = Blockstore::open(&ledger_path).unwrap(); - blockstore.add_tree(forks, false, true); + blockstore.add_tree(forks, false, true, 2, Hash::default()); blockstore } } diff --git a/core/src/repair_weighted_traversal.rs b/core/src/repair_weighted_traversal.rs index 6672301008..a6354e3b8d 100644 --- a/core/src/repair_weighted_traversal.rs +++ b/core/src/repair_weighted_traversal.rs @@ -150,6 +150,7 @@ pub mod test { use super::*; use solana_ledger::{get_tmp_ledger_path, shred::Shred}; use solana_runtime::bank_utils; + use solana_sdk::hash::Hash; use trees::tr; #[test] @@ -246,7 +247,13 @@ pub mod test { repairs = vec![]; let best_overall_slot = heaviest_subtree_fork_choice.best_overall_slot(); assert_eq!(heaviest_subtree_fork_choice.best_overall_slot(), 4); - blockstore.add_tree(tr(best_overall_slot) / (tr(6) / tr(7)), true, false); + blockstore.add_tree( + tr(best_overall_slot) / (tr(6) / tr(7)), + true, + false, + 2, + Hash::default(), + ); get_best_repair_shreds( &heaviest_subtree_fork_choice, &blockstore, @@ -300,7 +307,7 @@ pub mod test { // Adding incomplete children with higher weighted parents, even if // the parents are complete should still be repaired repairs = vec![]; - blockstore.add_tree(tr(2) / (tr(8)), true, false); + blockstore.add_tree(tr(2) / (tr(8)), true, false, 2, Hash::default()); get_best_repair_shreds( &heaviest_subtree_fork_choice, &blockstore, @@ -322,7 +329,7 @@ pub mod test { let (blockstore, heaviest_subtree_fork_choice) = setup_forks(); // Add a branch to slot 2, make sure it doesn't repair child // 4 again when the Unvisited(2) event happens - blockstore.add_tree(tr(2) / (tr(6) / tr(7)), true, false); + blockstore.add_tree(tr(2) / (tr(6) / tr(7)), true, false, 2, Hash::default()); let mut repairs = vec![]; get_best_repair_shreds( &heaviest_subtree_fork_choice, @@ -368,7 +375,7 @@ pub mod test { // Adding slot 2 to ignore should not remove its unexplored children from // the repair set repairs = vec![]; - blockstore.add_tree(tr(2) / (tr(6) / tr(7)), true, false); + blockstore.add_tree(tr(2) / (tr(6) / tr(7)), true, false, 2, Hash::default()); ignore_set.insert(2); get_best_repair_shreds( &heaviest_subtree_fork_choice, @@ -420,7 +427,7 @@ pub mod test { let forks = tr(0) / (tr(1) / (tr(2) / (tr(4))) / (tr(3) / (tr(5)))); let ledger_path = get_tmp_ledger_path!(); let blockstore = Blockstore::open(&ledger_path).unwrap(); - blockstore.add_tree(forks.clone(), false, false); + blockstore.add_tree(forks.clone(), false, false, 2, Hash::default()); (blockstore, HeaviestSubtreeForkChoice::new_from_tree(forks)) } diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 513de83414..aeb07bf22f 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -4035,7 +4035,7 @@ pub mod tests { ( Arc::new(RwLock::new(BankForks::new(bank))), mint_keypair, - voting_keypair, + Arc::new(voting_keypair), ) } diff --git a/core/src/validator.rs b/core/src/validator.rs index a889d960aa..db126f8cb3 100644 --- a/core/src/validator.rs +++ b/core/src/validator.rs @@ -863,8 +863,8 @@ impl TestValidator { } = create_genesis_config_with_leader_ex( mint_lamports, &contact_info.id, - Arc::new(Keypair::new()), - Arc::new(Keypair::new()), + &Keypair::new(), + &Pubkey::new_rand(), 42, bootstrap_validator_lamports, ); @@ -882,12 +882,13 @@ impl TestValidator { )), ..ValidatorConfig::default() }; + let vote_pubkey = voting_keypair.pubkey(); let node = Validator::new( node, &node_keypair, &ledger_path, &voting_keypair.pubkey(), - vec![voting_keypair.clone()], + vec![Arc::new(voting_keypair)], None, true, &config, @@ -899,7 +900,7 @@ impl TestValidator { alice: mint_keypair, ledger_path, genesis_hash: blockhash, - vote_pubkey: voting_keypair.pubkey(), + vote_pubkey, } } } @@ -1117,7 +1118,7 @@ mod tests { .genesis_config; let (validator_ledger_path, _blockhash) = create_new_tmp_ledger!(&genesis_config); ledger_paths.push(validator_ledger_path.clone()); - let vote_account_keypair = Arc::new(Keypair::new()); + let vote_account_keypair = Keypair::new(); let config = ValidatorConfig { rpc_ports: Some(( validator_node.info.rpc.port(), @@ -1131,7 +1132,7 @@ mod tests { &Arc::new(validator_keypair), &validator_ledger_path, &vote_account_keypair.pubkey(), - vec![vote_account_keypair.clone()], + vec![Arc::new(vote_account_keypair)], Some(&leader_node.info), true, &config, diff --git a/core/tests/gossip.rs b/core/tests/gossip.rs index 13de97b281..637342ba3a 100644 --- a/core/tests/gossip.rs +++ b/core/tests/gossip.rs @@ -233,7 +233,9 @@ pub fn cluster_info_scale() { let nodes: Vec<_> = vote_keypairs .into_iter() - .map(|keypairs| test_node_with_bank(keypairs.node_keypair, &exit, bank_forks.clone())) + .map(|keypairs| { + test_node_with_bank(Arc::new(keypairs.node_keypair), &exit, bank_forks.clone()) + }) .collect(); let ci0 = nodes[0].0.my_contact_info(); for node in &nodes[1..] { diff --git a/ledger/src/blockstore.rs b/ledger/src/blockstore.rs index a9aa4abcfb..a2dc7165ef 100644 --- a/ledger/src/blockstore.rs +++ b/ledger/src/blockstore.rs @@ -350,18 +350,39 @@ impl Blockstore { Ok((blockstore, signal_receiver, completed_slots_receiver)) } - pub fn add_tree(&self, forks: Tree, is_orphan: bool, is_slot_complete: bool) { + pub fn add_tree( + &self, + forks: Tree, + is_orphan: bool, + is_slot_complete: bool, + num_ticks: u64, + starting_hash: Hash, + ) { let mut walk = TreeWalk::from(forks); + let mut blockhashes = HashMap::new(); while let Some(visit) = walk.get() { let slot = visit.node().data; if self.meta(slot).unwrap().is_some() && self.orphan(slot).unwrap().is_none() { - // If slot exists and is not an orphan, then skip it + // If slot exists in blockstore and is not an orphan, then skip it walk.forward(); continue; } let parent = walk.get_parent().map(|n| n.data); if parent.is_some() || !is_orphan { - let entries = create_ticks(2, 0, Hash::default()); + let parent_hash = parent + // parent won't exist for first node in a tree where + // `is_orphan == true` + .and_then(|parent| blockhashes.get(&parent)) + .unwrap_or(&starting_hash); + let mut entries = create_ticks( + num_ticks * (std::cmp::max(1, slot - parent.unwrap_or(slot))), + 0, + *parent_hash, + ); + blockhashes.insert(slot, entries.last().unwrap().hash); + if !is_slot_complete { + entries.pop().unwrap(); + } let shreds = entries_to_test_shreds( entries.clone(), slot, @@ -407,6 +428,16 @@ impl Blockstore { self.orphans_cf.get(slot) } + // Get max root or 0 if it doesn't exist + pub fn max_root(&self) -> Slot { + self.db + .iter::(IteratorMode::End) + .expect("Couldn't get rooted iterator for max_root()") + .next() + .map(|(slot, _)| slot) + .unwrap_or(0) + } + pub fn slot_meta_iterator<'a>( &'a self, slot: Slot, diff --git a/local-cluster/src/local_cluster.rs b/local-cluster/src/local_cluster.rs index 437e109db3..2b0f69dce8 100644 --- a/local-cluster/src/local_cluster.rs +++ b/local-cluster/src/local_cluster.rs @@ -135,9 +135,10 @@ impl LocalCluster { if *in_genesis { Some(( ValidatorVoteKeypairs { - node_keypair: node_keypair.clone(), - vote_keypair: Arc::new(Keypair::new()), - stake_keypair: Arc::new(Keypair::new()), + node_keypair: Keypair::from_bytes(&node_keypair.to_bytes()) + .unwrap(), + vote_keypair: Keypair::new(), + stake_keypair: Keypair::new(), }, stake, )) @@ -205,9 +206,12 @@ impl LocalCluster { leader_node.info.rpc_banks.port(), )); leader_config.account_paths = vec![leader_ledger_path.join("accounts")]; + let leader_keypair = Arc::new(Keypair::from_bytes(&leader_keypair.to_bytes()).unwrap()); + let leader_vote_keypair = + Arc::new(Keypair::from_bytes(&leader_vote_keypair.to_bytes()).unwrap()); let leader_server = Validator::new( leader_node, - leader_keypair, + &leader_keypair, &leader_ledger_path, &leader_vote_keypair.pubkey(), vec![leader_vote_keypair.clone()], @@ -218,8 +222,8 @@ impl LocalCluster { let mut validators = HashMap::new(); let leader_info = ValidatorInfo { - keypair: leader_keypair.clone(), - voting_keypair: leader_vote_keypair.clone(), + keypair: leader_keypair, + voting_keypair: leader_vote_keypair, ledger_path: leader_ledger_path, contact_info: leader_contact_info.clone(), }; @@ -241,7 +245,12 @@ impl LocalCluster { let node_pubkey_to_vote_key: HashMap> = keys_in_genesis .into_iter() - .map(|keypairs| (keypairs.node_keypair.pubkey(), keypairs.vote_keypair)) + .map(|keypairs| { + ( + keypairs.node_keypair.pubkey(), + Arc::new(Keypair::from_bytes(&keypairs.vote_keypair.to_bytes()).unwrap()), + ) + }) .collect(); for (stake, validator_config, (key, _)) in izip!( (&config.node_stakes[1..]).iter(), diff --git a/runtime/src/genesis_utils.rs b/runtime/src/genesis_utils.rs index be2645eaf6..badb51feae 100644 --- a/runtime/src/genesis_utils.rs +++ b/runtime/src/genesis_utils.rs @@ -9,23 +9,19 @@ use solana_sdk::{ }; use solana_stake_program::stake_state; use solana_vote_program::vote_state; -use std::{borrow::Borrow, sync::Arc}; +use std::borrow::Borrow; // The default stake placed with the bootstrap validator pub const BOOTSTRAP_VALIDATOR_LAMPORTS: u64 = 42; pub struct ValidatorVoteKeypairs { - pub node_keypair: Arc, - pub vote_keypair: Arc, - pub stake_keypair: Arc, + pub node_keypair: Keypair, + pub vote_keypair: Keypair, + pub stake_keypair: Keypair, } impl ValidatorVoteKeypairs { - pub fn new( - node_keypair: Arc, - vote_keypair: Arc, - stake_keypair: Arc, - ) -> Self { + pub fn new(node_keypair: Keypair, vote_keypair: Keypair, stake_keypair: Keypair) -> Self { Self { node_keypair, vote_keypair, @@ -35,9 +31,9 @@ impl ValidatorVoteKeypairs { pub fn new_rand() -> Self { Self { - node_keypair: Arc::new(Keypair::new()), - vote_keypair: Arc::new(Keypair::new()), - stake_keypair: Arc::new(Keypair::new()), + node_keypair: Keypair::new(), + vote_keypair: Keypair::new(), + stake_keypair: Keypair::new(), } } } @@ -45,7 +41,7 @@ impl ValidatorVoteKeypairs { pub struct GenesisConfigInfo { pub genesis_config: GenesisConfig, pub mint_keypair: Keypair, - pub voting_keypair: Arc, + pub voting_keypair: Keypair, } pub fn create_genesis_config(mint_lamports: u64) -> GenesisConfigInfo { @@ -57,31 +53,32 @@ pub fn create_genesis_config_with_vote_accounts( voting_keypairs: &[impl Borrow], stakes: Vec, ) -> GenesisConfigInfo { + assert!(!voting_keypairs.is_empty()); assert_eq!(voting_keypairs.len(), stakes.len()); let mut genesis_config_info = create_genesis_config_with_leader_ex( mint_lamports, &voting_keypairs[0].borrow().node_keypair.pubkey(), - voting_keypairs[0].borrow().vote_keypair.clone(), - voting_keypairs[0].borrow().stake_keypair.clone(), + &voting_keypairs[0].borrow().vote_keypair, + &voting_keypairs[0].borrow().stake_keypair.pubkey(), stakes[0], BOOTSTRAP_VALIDATOR_LAMPORTS, ); - for (validator_voting_keypairs, stake) in voting_keypairs.iter().zip(stakes) { + for (validator_voting_keypairs, stake) in voting_keypairs[1..].iter().zip(&stakes[1..]) { let node_pubkey = validator_voting_keypairs.borrow().node_keypair.pubkey(); let vote_pubkey = validator_voting_keypairs.borrow().vote_keypair.pubkey(); let stake_pubkey = validator_voting_keypairs.borrow().stake_keypair.pubkey(); // Create accounts let node_account = Account::new(BOOTSTRAP_VALIDATOR_LAMPORTS, 0, &system_program::id()); - let vote_account = vote_state::create_account(&vote_pubkey, &node_pubkey, 0, stake); + let vote_account = vote_state::create_account(&vote_pubkey, &node_pubkey, 0, *stake); let stake_account = stake_state::create_account( &stake_pubkey, &vote_pubkey, &vote_account, &genesis_config_info.genesis_config.rent, - stake, + *stake, ); // Put newly created accounts into genesis @@ -103,8 +100,8 @@ pub fn create_genesis_config_with_leader( create_genesis_config_with_leader_ex( mint_lamports, bootstrap_validator_pubkey, - Arc::new(Keypair::new()), - Arc::new(Keypair::new()), + &Keypair::new(), + &Pubkey::new_rand(), bootstrap_validator_stake_lamports, BOOTSTRAP_VALIDATOR_LAMPORTS, ) @@ -113,8 +110,8 @@ pub fn create_genesis_config_with_leader( pub fn create_genesis_config_with_leader_ex( mint_lamports: u64, bootstrap_validator_pubkey: &Pubkey, - bootstrap_validator_voting_keypair: Arc, - bootstrap_validator_staking_keypair: Arc, + bootstrap_validator_voting_keypair: &Keypair, + bootstrap_validator_staking_pubkey: &Pubkey, bootstrap_validator_stake_lamports: u64, bootstrap_validator_lamports: u64, ) -> GenesisConfigInfo { @@ -129,7 +126,7 @@ pub fn create_genesis_config_with_leader_ex( let rent = Rent::free(); let bootstrap_validator_stake_account = stake_state::create_account( - &bootstrap_validator_staking_keypair.pubkey(), + bootstrap_validator_staking_pubkey, &bootstrap_validator_voting_keypair.pubkey(), &bootstrap_validator_vote_account, &rent, @@ -150,7 +147,7 @@ pub fn create_genesis_config_with_leader_ex( bootstrap_validator_vote_account, ), ( - bootstrap_validator_staking_keypair.pubkey(), + *bootstrap_validator_staking_pubkey, bootstrap_validator_stake_account, ), ] @@ -171,6 +168,7 @@ pub fn create_genesis_config_with_leader_ex( GenesisConfigInfo { genesis_config, mint_keypair, - voting_keypair: bootstrap_validator_voting_keypair, + voting_keypair: Keypair::from_bytes(&bootstrap_validator_voting_keypair.to_bytes()) + .unwrap(), } }