From 8c80315a8ff40cd5afdab44a9c5daed97dc0c867 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Thu, 29 Apr 2021 12:18:13 -0700 Subject: [PATCH] authorized_staker arg is now stake-pool implementation specific --- src/generic_stake_pool.rs | 7 +-- src/legacy_stake_pool.rs | 16 +++--- src/main.rs | 49 +++++++++++------ src/stake_pool.rs | 6 ++- src/stake_pool_v0.rs | 108 +++++++++++++++++--------------------- 5 files changed, 96 insertions(+), 90 deletions(-) diff --git a/src/generic_stake_pool.rs b/src/generic_stake_pool.rs index c474ba46..9359c5ce 100644 --- a/src/generic_stake_pool.rs +++ b/src/generic_stake_pool.rs @@ -1,8 +1,4 @@ -use { - solana_client::rpc_client::RpcClient, - solana_sdk::{pubkey::Pubkey, signature::Keypair}, - std::error, -}; +use {solana_client::rpc_client::RpcClient, solana_sdk::pubkey::Pubkey, std::error}; #[derive(Debug, PartialEq, Clone, Copy)] pub enum ValidatorStakeState { @@ -25,7 +21,6 @@ pub trait GenericStakePool { &mut self, rpc_client: &RpcClient, dry_run: bool, - authorized_staker: &Keypair, desired_validator_stake: &[ValidatorStake], ) -> Result, Box>; } diff --git a/src/legacy_stake_pool.rs b/src/legacy_stake_pool.rs index 60e2ca45..4730806a 100644 --- a/src/legacy_stake_pool.rs +++ b/src/legacy_stake_pool.rs @@ -13,8 +13,8 @@ use { std::{collections::HashSet, error}, }; -#[derive(Default)] pub struct LegacyStakePool { + authorized_staker: Keypair, baseline_stake_amount: u64, bonus_stake_amount: u64, source_stake_address: Pubkey, @@ -23,12 +23,14 @@ pub struct LegacyStakePool { pub fn new( _rpc_client: &RpcClient, + authorized_staker: Keypair, baseline_stake_amount: u64, bonus_stake_amount: u64, source_stake_address: Pubkey, validator_list: HashSet, ) -> Result> { Ok(LegacyStakePool { + authorized_staker, baseline_stake_amount, bonus_stake_amount, source_stake_address, @@ -45,17 +47,19 @@ impl GenericStakePool for LegacyStakePool { &mut self, rpc_client: &RpcClient, dry_run: bool, - authorized_staker: &Keypair, validator_stake: &[ValidatorStake], ) -> Result, Box> { - let (init_transactions, update_transactions) = - self.build_transactions(rpc_client, authorized_staker.pubkey(), &validator_stake)?; + let (init_transactions, update_transactions) = self.build_transactions( + rpc_client, + self.authorized_staker.pubkey(), + &validator_stake, + )?; if !send_and_confirm_transactions( rpc_client, dry_run, init_transactions, - authorized_staker, + &self.authorized_staker, &mut vec![], )? { return Err("Failed to initialize stake pool. Unable to continue".into()); @@ -69,7 +73,7 @@ impl GenericStakePool for LegacyStakePool { rpc_client, dry_run, update_transactions, - authorized_staker, + &self.authorized_staker, &mut notifications, )?; diff --git a/src/main.rs b/src/main.rs index f502184d..14dab7da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,7 +30,6 @@ use { commitment_config::CommitmentConfig, native_token::*, pubkey::Pubkey, - signature::Keypair, slot_history::{self, SlotHistory}, sysvar, }, @@ -157,7 +156,6 @@ fn release_version_of(matches: &ArgMatches<'_>, name: &str) -> Option BoxResult<(Config, RpcClient, Box)> { destaking those in the list and warning \ any others") ) - .arg( - Arg::with_name("authorized_staker") - .index(1) - .value_name("KEYPAIR") - .validator(is_keypair) - .required(true) - .takes_value(true) - .help("Keypair of the authorized staker") - ) .subcommand( SubCommand::with_name("legacy").about("Use the legacy staking solution") .arg( @@ -463,6 +451,15 @@ fn get_config() -> BoxResult<(Config, RpcClient, Box)> { .validator(is_pubkey_or_keypair) .help("The source stake account for splitting individual validator stake accounts from") ) + .arg( + Arg::with_name("authorized_staker") + .index(2) + .value_name("KEYPAIR") + .validator(is_keypair) + .required(true) + .takes_value(true) + .help("Keypair of the authorized staker") + ) .arg( Arg::with_name("baseline_stake_amount") .long("baseline-stake-amount") @@ -499,6 +496,15 @@ fn get_config() -> BoxResult<(Config, RpcClient, Box)> { .validator(is_pubkey_or_keypair) .help("The reserve stake account used to fund the stake pool") ) + .arg( + Arg::with_name("authorized_staker") + .index(2) + .value_name("KEYPAIR") + .validator(is_keypair) + .required(true) + .takes_value(true) + .help("Keypair of the authorized staker") + ) .arg( Arg::with_name("min_reserve_stake_balance") .long("min-reserve-stake-balance") @@ -536,6 +542,15 @@ fn get_config() -> BoxResult<(Config, RpcClient, Box)> { .validator(is_pubkey_or_keypair) .help("The stake pool address") ) + .arg( + Arg::with_name("authorized_staker") + .index(2) + .value_name("KEYPAIR") + .validator(is_keypair) + .required(true) + .takes_value(true) + .help("Keypair of the authorized staker") + ) .arg( Arg::with_name("baseline_stake_amount") .long("baseline-stake-amount") @@ -593,12 +608,9 @@ fn get_config() -> BoxResult<(Config, RpcClient, Box)> { ) .unwrap(); - let authorized_staker = keypair_of(&matches, "authorized_staker").unwrap(); - let config = Config { json_rpc_url, cluster, - authorized_staker, dry_run, quality_block_producer_percentage, max_commission, @@ -623,6 +635,7 @@ fn get_config() -> BoxResult<(Config, RpcClient, Box)> { let stake_pool: Box = match matches.subcommand() { ("legacy", Some(matches)) => { + let authorized_staker = keypair_of(&matches, "authorized_staker").unwrap(); let source_stake_address = pubkey_of(&matches, "source_stake_address").unwrap(); let baseline_stake_amount = sol_to_lamports(value_t_or_exit!(matches, "baseline_stake_amount", f64)); @@ -632,6 +645,7 @@ fn get_config() -> BoxResult<(Config, RpcClient, Box)> { Box::new(legacy_stake_pool::new( &rpc_client, + authorized_staker, baseline_stake_amount, bonus_stake_amount, source_stake_address, @@ -639,6 +653,7 @@ fn get_config() -> BoxResult<(Config, RpcClient, Box)> { )?) } ("stake-pool-v0", Some(matches)) => { + let authorized_staker = keypair_of(&matches, "authorized_staker").unwrap(); let reserve_stake_address = pubkey_of(&matches, "reserve_stake_address").unwrap(); let min_reserve_stake_balance = sol_to_lamports(value_t_or_exit!(matches, "min_reserve_stake_balance", f64)); @@ -647,6 +662,7 @@ fn get_config() -> BoxResult<(Config, RpcClient, Box)> { let validator_list = validator_list_of(matches, config.cluster.as_str()); Box::new(stake_pool_v0::new( &rpc_client, + authorized_staker, baseline_stake_amount, reserve_stake_address, min_reserve_stake_balance, @@ -654,11 +670,13 @@ fn get_config() -> BoxResult<(Config, RpcClient, Box)> { )?) } ("stake-pool", Some(matches)) => { + let authorized_staker = keypair_of(&matches, "authorized_staker").unwrap(); let pool_address = pubkey_of(&matches, "pool_address").unwrap(); let baseline_stake_amount = sol_to_lamports(value_t_or_exit!(matches, "baseline_stake_amount", f64)); Box::new(stake_pool::new( &rpc_client, + authorized_staker, pool_address, baseline_stake_amount, )?) @@ -1117,7 +1135,6 @@ fn main() -> BoxResult<()> { notifications.extend(stake_pool.apply( &rpc_client, config.dry_run, - &config.authorized_staker, &desired_validator_stake, )?); notifications.push(format!("{} validators processed", validators_processed)); diff --git a/src/stake_pool.rs b/src/stake_pool.rs index 6fe23d7e..200e6722 100644 --- a/src/stake_pool.rs +++ b/src/stake_pool.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] use { crate::generic_stake_pool::*, log::*, @@ -13,8 +14,8 @@ struct ValidatorInfo { baseline_stake_activation_state: StakeActivationState, } -#[derive(Debug)] pub struct SplStakePool { + authorized_staker: Keypair, baseline_stake_amount: u64, pool_address: Pubkey, validator_info: HashMap, @@ -22,10 +23,12 @@ pub struct SplStakePool { pub fn new( _rpc_client: &RpcClient, + authorized_staker: Keypair, pool_address: Pubkey, baseline_stake_amount: u64, ) -> Result> { Ok(SplStakePool { + authorized_staker, baseline_stake_amount, pool_address, validator_info: HashMap::new(), @@ -41,7 +44,6 @@ impl GenericStakePool for SplStakePool { &mut self, _rpc_client: &RpcClient, _dry_run: bool, - _authorized_staker: &Keypair, _desired_validator_stake: &[ValidatorStake], ) -> Result, Box> { todo!(); diff --git a/src/stake_pool_v0.rs b/src/stake_pool_v0.rs index f7a60709..b788d004 100644 --- a/src/stake_pool_v0.rs +++ b/src/stake_pool_v0.rs @@ -27,6 +27,7 @@ const MIN_STAKE_CHANGE_AMOUNT: u64 = MIN_STAKE_ACCOUNT_BALANCE; #[derive(Debug)] pub struct StakePool { + authorized_staker: Keypair, baseline_stake_amount: u64, reserve_stake_address: Pubkey, min_reserve_stake_balance: u64, @@ -35,6 +36,7 @@ pub struct StakePool { pub fn new( _rpc_client: &RpcClient, + authorized_staker: Keypair, baseline_stake_amount: u64, reserve_stake_address: Pubkey, min_reserve_stake_balance: u64, @@ -57,6 +59,7 @@ pub fn new( } Ok(StakePool { + authorized_staker, baseline_stake_amount, reserve_stake_address, min_reserve_stake_balance, @@ -99,7 +102,6 @@ impl GenericStakePool for StakePool { &mut self, rpc_client: &RpcClient, dry_run: bool, - authorized_staker: &Keypair, desired_validator_stake: &[ValidatorStake], ) -> Result, Box> { if dry_run { @@ -119,9 +121,10 @@ impl GenericStakePool for StakePool { .. } in desired_validator_stake { - let stake_address = validator_stake_address(authorized_staker.pubkey(), *vote_address); + let stake_address = + validator_stake_address(self.authorized_staker.pubkey(), *vote_address); let transient_stake_address = - validator_transient_stake_address(authorized_staker.pubkey(), *vote_address); + validator_transient_stake_address(self.authorized_staker.pubkey(), *vote_address); inuse_stake_addresses.insert(stake_address); inuse_stake_addresses.insert(transient_stake_address); @@ -134,12 +137,12 @@ impl GenericStakePool for StakePool { } let (all_stake_addresses, all_stake_total_amount) = - get_all_stake(rpc_client, authorized_staker.pubkey())?; + get_all_stake(rpc_client, self.authorized_staker.pubkey())?; info!("Merge orphaned stake into the reserve"); merge_orphaned_stake_accounts( rpc_client, - authorized_staker, + &self.authorized_staker, &all_stake_addresses - &inuse_stake_addresses, self.reserve_stake_address, )?; @@ -148,7 +151,7 @@ impl GenericStakePool for StakePool { let mut busy_validators = HashSet::new(); merge_transient_stake_accounts( rpc_client, - authorized_staker, + &self.authorized_staker, desired_validator_stake, self.reserve_stake_address, &mut busy_validators, @@ -157,7 +160,7 @@ impl GenericStakePool for StakePool { info!("Create validator stake accounts if needed"); create_validator_stake_accounts( rpc_client, - authorized_staker, + &self.authorized_staker, desired_validator_stake, self.reserve_stake_address, self.min_reserve_stake_balance, @@ -207,7 +210,7 @@ impl GenericStakePool for StakePool { ]; notifications.extend(distribute_validator_stake( rpc_client, - authorized_staker, + &self.authorized_staker, desired_validator_stake .iter() .filter(|vs| !busy_validators.contains(&vs.identity)) @@ -751,18 +754,16 @@ mod test { fn validator_stake_balance( rpc_client: &RpcClient, - authorized_staker: &Keypair, + authorized_staker: Pubkey, validator: &ValidatorAddressPair, ) -> u64 { - let stake_address = - validator_stake_address(authorized_staker.pubkey(), validator.vote_address); + let stake_address = validator_stake_address(authorized_staker, validator.vote_address); rpc_client.get_balance(&stake_address).unwrap() } fn uniform_stake_pool_apply( stake_pool: &mut StakePool, rpc_client: &RpcClient, - authorized_staker: &Keypair, validators: &[ValidatorAddressPair], stake_state: ValidatorStakeState, expected_validator_stake_balance: u64, @@ -779,30 +780,20 @@ mod test { .collect::>(); stake_pool - .apply( - rpc_client, - false, - authorized_staker, - &desired_validator_stake, - ) + .apply(rpc_client, false, &desired_validator_stake) .unwrap(); assert_eq!( - num_stake_accounts(rpc_client, authorized_staker), + num_stake_accounts(rpc_client, &stake_pool.authorized_staker), 1 + 2 * validators.len() ); let _epoch = wait_for_next_epoch(&rpc_client).unwrap(); stake_pool - .apply( - rpc_client, - false, - authorized_staker, - &desired_validator_stake, - ) + .apply(rpc_client, false, &desired_validator_stake) .unwrap(); assert_eq!( - num_stake_accounts(rpc_client, authorized_staker), + num_stake_accounts(rpc_client, &stake_pool.authorized_staker), 1 + validators.len() ); assert_eq!( @@ -813,7 +804,11 @@ mod test { ); for validator in validators { assert_eq!( - validator_stake_balance(rpc_client, authorized_staker, validator), + validator_stake_balance( + rpc_client, + stake_pool.authorized_staker.pubkey(), + validator + ), expected_validator_stake_balance ); } @@ -833,10 +828,12 @@ mod test { let (rpc_client, _recent_blockhash, _fee_calculator) = test_validator.rpc_client(); + let authorized_staker_address = authorized_staker.pubkey(); + let assert_validator_stake_activation = |vap: &ValidatorAddressPair, epoch: Epoch, state: StakeActivationState| { let stake_address = - validator_stake_address(authorized_staker.pubkey(), vap.vote_address); + validator_stake_address(authorized_staker_address, vap.vote_address); assert_eq!( rpc_client .get_stake_activation(stake_address, Some(epoch)) @@ -878,7 +875,7 @@ mod test { ); let (all_stake, all_stake_total_amount) = - get_all_stake(&rpc_client, authorized_staker.pubkey()).unwrap(); + get_all_stake(&rpc_client, authorized_staker_address).unwrap(); assert_eq!(all_stake_total_amount, total_stake_amount_plus_min); assert_eq!(all_stake.len(), 1); assert!(all_stake.contains(&reserve_stake_address)); @@ -888,6 +885,7 @@ mod test { let mut stake_pool = new( &rpc_client, + authorized_staker, baseline_stake_amount, reserve_stake_address, min_reserve_stake_balance, @@ -902,7 +900,6 @@ mod test { .apply( &rpc_client, false, - &authorized_staker, &validators .iter() .map(|vap| ValidatorStake { @@ -926,12 +923,16 @@ mod test { for validator in &validators { assert_validator_stake_activation(validator, epoch, StakeActivationState::Activating); assert_eq!( - validator_stake_balance(&rpc_client, &authorized_staker, validator), + validator_stake_balance( + &rpc_client, + stake_pool.authorized_staker.pubkey(), + validator + ), MIN_STAKE_ACCOUNT_BALANCE ); } assert_eq!( - num_stake_accounts(&rpc_client, &authorized_staker), + num_stake_accounts(&rpc_client, &stake_pool.authorized_staker), 1 + validators.len() ); let epoch = wait_for_next_epoch(&rpc_client).unwrap(); @@ -944,7 +945,6 @@ mod test { uniform_stake_pool_apply( &mut stake_pool, &rpc_client, - &authorized_staker, &validators, ValidatorStakeState::Baseline, baseline_stake_amount, @@ -956,7 +956,6 @@ mod test { uniform_stake_pool_apply( &mut stake_pool, &rpc_client, - &authorized_staker, &validators, ValidatorStakeState::Bonus, total_stake_amount / validators.len() as u64, @@ -987,21 +986,11 @@ mod test { ]; stake_pool - .apply( - &rpc_client, - false, - &authorized_staker, - &desired_validator_stake, - ) + .apply(&rpc_client, false, &desired_validator_stake) .unwrap(); let _epoch = wait_for_next_epoch(&rpc_client).unwrap(); stake_pool - .apply( - &rpc_client, - false, - &authorized_staker, - &desired_validator_stake, - ) + .apply(&rpc_client, false, &desired_validator_stake) .unwrap(); // after the first epoch, validators 0 and 1 are at their target levels but validator 2 @@ -1009,7 +998,11 @@ mod test { for (validator, expected_sol_balance) in validators.iter().zip(&[1., 10., 110.]) { assert_eq!( sol_to_lamports(*expected_sol_balance), - validator_stake_balance(&rpc_client, &authorized_staker, validator), + validator_stake_balance( + &rpc_client, + stake_pool.authorized_staker.pubkey(), + validator + ), "stake balance mismatch for validator {}, expected {}", validator.identity, expected_sol_balance @@ -1025,12 +1018,7 @@ mod test { let _epoch = wait_for_next_epoch(&rpc_client).unwrap(); stake_pool - .apply( - &rpc_client, - false, - &authorized_staker, - &desired_validator_stake, - ) + .apply(&rpc_client, false, &desired_validator_stake) .unwrap(); assert_eq!( @@ -1044,7 +1032,11 @@ mod test { for (validator, expected_sol_balance) in validators.iter().zip(&[1., 10., 319.]) { assert_eq!( sol_to_lamports(*expected_sol_balance), - validator_stake_balance(&rpc_client, &authorized_staker, validator), + validator_stake_balance( + &rpc_client, + stake_pool.authorized_staker.pubkey(), + validator + ), "stake balance mismatch for validator {}", validator.identity ); @@ -1054,14 +1046,10 @@ mod test { info!("remove all validators"); // deactivate all validator stake - stake_pool - .apply(&rpc_client, false, &authorized_staker, &[]) - .unwrap(); + stake_pool.apply(&rpc_client, false, &[]).unwrap(); let _epoch = wait_for_next_epoch(&rpc_client).unwrap(); // merge deactivated validator stake back into the reserve - stake_pool - .apply(&rpc_client, false, &authorized_staker, &[]) - .unwrap(); + stake_pool.apply(&rpc_client, false, &[]).unwrap(); // all stake has returned to the reserve account assert_reserve_account_only(); }