From a08235da9a6e27fd2ea42710bcf2090278b77835 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sun, 10 May 2020 10:14:31 -0700 Subject: [PATCH] send_and_confirm_transaction() no longer needs a keypair (#9950) (#9962) automerge --- cli/src/cli.rs | 33 ++--- cli/src/nonce.rs | 9 +- cli/src/stake.rs | 14 +-- cli/src/storage.rs | 4 +- cli/src/validator_info.rs | 2 +- cli/src/vote.rs | 10 +- client/src/rpc_client.rs | 51 ++++---- install/src/command.rs | 7 +- ramp-tps/src/voters.rs | 244 +++++++++++++++++++++++++++++++++++++ stake-accounts/src/main.rs | 2 +- 10 files changed, 300 insertions(+), 76 deletions(-) create mode 100644 ramp-tps/src/voters.rs diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 9d53599910..3cd88fc434 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -1343,8 +1343,7 @@ fn process_deploy( )?; trace!("Creating program account"); - let result = - rpc_client.send_and_confirm_transaction_with_spinner(&mut create_account_tx, &signers); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&create_account_tx); log_instruction_custom_error::(result, &config).map_err(|_| { CliError::DynamicProgramError("Program account allocation failed".to_string()) })?; @@ -1354,7 +1353,7 @@ fn process_deploy( trace!("Finalizing program account"); rpc_client - .send_and_confirm_transaction_with_spinner(&mut finalize_tx, &signers) + .send_and_confirm_transaction_with_spinner(&finalize_tx) .map_err(|e| { CliError::DynamicProgramError(format!("Program finalize transaction failed: {}", e)) })?; @@ -1419,8 +1418,7 @@ fn process_pay( &fee_calculator, &tx.message, )?; - let result = - rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); log_instruction_custom_error::(result, &config) } } else if *witnesses == None { @@ -1455,10 +1453,7 @@ fn process_pay( &fee_calculator, &tx.message, )?; - let result = rpc_client.send_and_confirm_transaction_with_spinner( - &mut tx, - &[config.signers[0], &contract_state], - ); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); let signature = log_instruction_custom_error::(result, &config)?; Ok(json!({ "signature": signature, @@ -1494,10 +1489,7 @@ fn process_pay( return_signers(&tx, &config) } else { tx.try_sign(&[config.signers[0], &contract_state], blockhash)?; - let result = rpc_client.send_and_confirm_transaction_with_spinner( - &mut tx, - &[config.signers[0], &contract_state], - ); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); check_account_for_fee( rpc_client, &config.signers[0].pubkey(), @@ -1532,8 +1524,7 @@ fn process_cancel(rpc_client: &RpcClient, config: &CliConfig, pubkey: &Pubkey) - &fee_calculator, &tx.message, )?; - let result = - rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &[config.signers[0]]); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); log_instruction_custom_error::(result, &config) } @@ -1556,8 +1547,7 @@ fn process_time_elapsed( &fee_calculator, &tx.message, )?; - let result = - rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &[config.signers[0]]); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); log_instruction_custom_error::(result, &config) } @@ -1619,7 +1609,7 @@ fn process_transfer( let result = if no_wait { rpc_client.send_transaction(&tx) } else { - rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers) + rpc_client.send_and_confirm_transaction_with_spinner(&tx) }; log_instruction_custom_error::(result, &config) } @@ -1643,8 +1633,7 @@ fn process_witness( &fee_calculator, &tx.message, )?; - let result = - rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &[config.signers[0]]); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); log_instruction_custom_error::(result, &config) } @@ -2275,8 +2264,8 @@ pub fn request_and_confirm_airdrop( sleep(Duration::from_secs(1)); } }?; - let mut tx = keypair.airdrop_transaction(); - let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &[&keypair]); + let tx = keypair.airdrop_transaction(); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); log_instruction_custom_error::(result, &config) } diff --git a/cli/src/nonce.rs b/cli/src/nonce.rs index 099edc364b..e5b1d34053 100644 --- a/cli/src/nonce.rs +++ b/cli/src/nonce.rs @@ -462,7 +462,7 @@ pub fn process_authorize_nonce_account( &fee_calculator, &tx.message, )?; - let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); log_instruction_custom_error::(result, &config) } @@ -539,7 +539,7 @@ pub fn process_create_nonce_account( &fee_calculator, &tx.message, )?; - let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); log_instruction_custom_error::(result, &config) } @@ -580,8 +580,7 @@ pub fn process_new_nonce( &fee_calculator, &tx.message, )?; - let result = rpc_client - .send_and_confirm_transaction_with_spinner(&mut tx, &[config.signers[0], nonce_authority]); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); log_instruction_custom_error::(result, &config) } @@ -640,7 +639,7 @@ pub fn process_withdraw_from_nonce_account( &fee_calculator, &tx.message, )?; - let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); log_instruction_custom_error::(result, &config) } diff --git a/cli/src/stake.rs b/cli/src/stake.rs index a2bae32d0c..4d51d5e989 100644 --- a/cli/src/stake.rs +++ b/cli/src/stake.rs @@ -894,7 +894,7 @@ pub fn process_create_stake_account( &fee_calculator, &tx.message, )?; - let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); log_instruction_custom_error::(result, &config) } } @@ -959,7 +959,7 @@ pub fn process_stake_authorize( &fee_calculator, &tx.message, )?; - let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); log_instruction_custom_error::(result, &config) } } @@ -1013,7 +1013,7 @@ pub fn process_deactivate_stake_account( &fee_calculator, &tx.message, )?; - let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); log_instruction_custom_error::(result, &config) } } @@ -1076,7 +1076,7 @@ pub fn process_withdraw_stake( &fee_calculator, &tx.message, )?; - let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); log_instruction_custom_error::(result, &config) } } @@ -1210,7 +1210,7 @@ pub fn process_split_stake( &fee_calculator, &tx.message, )?; - let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); log_instruction_custom_error::(result, &config) } } @@ -1267,7 +1267,7 @@ pub fn process_stake_set_lockup( &fee_calculator, &tx.message, )?; - let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); log_instruction_custom_error::(result, &config) } } @@ -1475,7 +1475,7 @@ pub fn process_delegate_stake( &fee_calculator, &tx.message, )?; - let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); log_instruction_custom_error::(result, &config) } } diff --git a/cli/src/storage.rs b/cli/src/storage.rs index 0866705d0d..377456f0b1 100644 --- a/cli/src/storage.rs +++ b/cli/src/storage.rs @@ -242,7 +242,7 @@ pub fn process_create_storage_account( &fee_calculator, &tx.message, )?; - let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); log_instruction_custom_error::(result, &config) } @@ -266,7 +266,7 @@ pub fn process_claim_storage_reward( &fee_calculator, &tx.message, )?; - let signature = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &signers)?; + let signature = rpc_client.send_and_confirm_transaction_with_spinner(&tx)?; Ok(signature.to_string()) } diff --git a/cli/src/validator_info.rs b/cli/src/validator_info.rs index 0a7ce48813..4f2927e7d4 100644 --- a/cli/src/validator_info.rs +++ b/cli/src/validator_info.rs @@ -367,7 +367,7 @@ pub fn process_set_validator_info( &fee_calculator, &tx.message, )?; - let signature_str = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &signers)?; + let signature_str = rpc_client.send_and_confirm_transaction_with_spinner(&tx)?; println!("Success! Validator info published at: {:?}", info_pubkey); println!("{}", signature_str); diff --git a/cli/src/vote.rs b/cli/src/vote.rs index db79d53c84..6c686f2bc4 100644 --- a/cli/src/vote.rs +++ b/cli/src/vote.rs @@ -457,7 +457,7 @@ pub fn process_create_vote_account( &fee_calculator, &tx.message, )?; - let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); log_instruction_custom_error::(result, &config) } @@ -497,8 +497,7 @@ pub fn process_vote_authorize( &fee_calculator, &tx.message, )?; - let result = - rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &[config.signers[0]]); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); log_instruction_custom_error::(result, &config) } @@ -531,7 +530,7 @@ pub fn process_vote_update_validator( &fee_calculator, &tx.message, )?; - let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx); log_instruction_custom_error::(result, &config) } @@ -636,8 +635,7 @@ pub fn process_withdraw_from_vote_account( &fee_calculator, &transaction.message, )?; - let result = - rpc_client.send_and_confirm_transaction_with_spinner(&mut transaction, &config.signers); + let result = rpc_client.send_and_confirm_transaction_with_spinner(&transaction); log_instruction_custom_error::(result, &config) } diff --git a/client/src/rpc_client.rs b/client/src/rpc_client.rs index 8d1f721fdf..f095f1ed61 100644 --- a/client/src/rpc_client.rs +++ b/client/src/rpc_client.rs @@ -24,7 +24,7 @@ use solana_sdk::{ pubkey::Pubkey, signature::Signature, signers::Signers, - transaction::{self, Transaction, TransactionError}, + transaction::{self, Transaction}, }; use solana_transaction_status::{ ConfirmedBlock, ConfirmedTransaction, TransactionEncoding, TransactionStatus, @@ -449,10 +449,9 @@ impl RpcClient { .map_err(|err| ClientError::new_with_command(err.into(), "MinimumLedgerSlot")) } - pub fn send_and_confirm_transaction( + pub fn send_and_confirm_transaction( &self, - transaction: &mut Transaction, - signer_keys: &T, + transaction: &Transaction, ) -> ClientResult { let mut send_retries = 20; loop { @@ -476,11 +475,6 @@ impl RpcClient { send_retries = if let Some(result) = status.clone() { match result { Ok(_) => return Ok(signature), - Err(TransactionError::AccountInUse) => { - // Fetch a new blockhash and re-sign the transaction before sending it again - self.resign_transaction(transaction, signer_keys)?; - send_retries - 1 - } Err(_) => 0, } } else { @@ -491,7 +485,9 @@ impl RpcClient { return Err(err.unwrap_err().into()); } else { return Err( - RpcError::ForUser("unable to confirm transaction. This can happen in situations such as transaction expiration and insufficient fee-payer funds".to_string()).into(), + RpcError::ForUser("unable to confirm transaction. \ + This can happen in situations such as transaction expiration \ + and insufficient fee-payer funds".to_string()).into(), ); } } @@ -1066,10 +1062,9 @@ impl RpcClient { Ok(confirmations) } - pub fn send_and_confirm_transaction_with_spinner( + pub fn send_and_confirm_transaction_with_spinner( &self, - transaction: &mut Transaction, - signer_keys: &T, + transaction: &Transaction, ) -> ClientResult { let mut confirmations = 0; @@ -1106,11 +1101,6 @@ impl RpcClient { send_retries = if let Some(result) = status.clone() { match result { Ok(_) => 0, - Err(TransactionError::AccountInUse) => { - // Fetch a new blockhash and re-sign the transaction before sending it again - self.resign_transaction(transaction, signer_keys)?; - send_retries - 1 - } // If transaction errors, return right away; no point in counting confirmations Err(_) => 0, } @@ -1128,9 +1118,13 @@ impl RpcClient { } } } else { - return Err( - RpcError::ForUser("unable to confirm transaction. This can happen in situations such as transaction expiration and insufficient fee-payer funds".to_string()).into(), - ); + return Err(RpcError::ForUser( + "unable to confirm transaction. \ + This can happen in situations such as transaction \ + expiration and insufficient fee-payer funds" + .to_string(), + ) + .into()); } } }; @@ -1155,7 +1149,9 @@ impl RpcClient { .unwrap_or(confirmations); if now.elapsed().as_secs() >= MAX_HASH_AGE_IN_SECONDS as u64 { return Err( - RpcError::ForUser("transaction not finalized. This can happen when a transaction lands in an abandoned fork. Please retry.".to_string()).into(), + RpcError::ForUser("transaction not finalized. \ + This can happen when a transaction lands in an abandoned fork. \ + Please retry.".to_string()).into(), ); } } @@ -1358,17 +1354,16 @@ mod tests { let key = Keypair::new(); let to = Pubkey::new_rand(); let blockhash = Hash::default(); - let mut tx = system_transaction::transfer(&key, &to, 50, blockhash); - - let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&key]); + let tx = system_transaction::transfer(&key, &to, 50, blockhash); + let result = rpc_client.send_and_confirm_transaction(&tx); result.unwrap(); let rpc_client = RpcClient::new_mock("account_in_use".to_string()); - let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&key]); + let result = rpc_client.send_and_confirm_transaction(&tx); assert!(result.is_err()); let rpc_client = RpcClient::new_mock("instruction_error".to_string()); - let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&key]); + let result = rpc_client.send_and_confirm_transaction(&tx); assert_matches!( result.unwrap_err().kind(), ClientErrorKind::TransactionError(TransactionError::InstructionError( @@ -1378,7 +1373,7 @@ mod tests { ); let rpc_client = RpcClient::new_mock("sig_not_found".to_string()); - let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&key]); + let result = rpc_client.send_and_confirm_transaction(&tx); if let ClientErrorKind::Io(err) = result.unwrap_err().kind() { assert_eq!(err.kind(), io::ErrorKind::Other); } diff --git a/install/src/command.rs b/install/src/command.rs index b919ddb8e4..84e05ebe5c 100644 --- a/install/src/command.rs +++ b/install/src/command.rs @@ -221,8 +221,7 @@ fn new_update_manifest( let mut transaction = Transaction::new_unsigned_instructions(new_account); let signers = [from_keypair, update_manifest_keypair]; transaction.sign(&signers, recent_blockhash); - - rpc_client.send_and_confirm_transaction(&mut transaction, &[from_keypair])?; + rpc_client.send_and_confirm_transaction(&transaction)?; } Ok(()) } @@ -245,8 +244,8 @@ fn store_update_manifest( ); let message = Message::new_with_payer(&[instruction], Some(&from_keypair.pubkey())); - let mut transaction = Transaction::new(&signers, message, recent_blockhash); - rpc_client.send_and_confirm_transaction(&mut transaction, &[from_keypair])?; + let transaction = Transaction::new(&signers, message, recent_blockhash); + rpc_client.send_and_confirm_transaction(&transaction)?; Ok(()) } diff --git a/ramp-tps/src/voters.rs b/ramp-tps/src/voters.rs new file mode 100644 index 0000000000..2eae40a822 --- /dev/null +++ b/ramp-tps/src/voters.rs @@ -0,0 +1,244 @@ +use crate::notifier::Notifier; +use crate::utils; +use log::*; +use solana_client::{client_error::Result as ClientResult, rpc_client::RpcClient}; +use solana_sdk::{ + clock::Slot, + epoch_schedule::EpochSchedule, + native_token::sol_to_lamports, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, +}; +use solana_stake_program::{ + stake_instruction, + stake_state::{Authorized as StakeAuthorized, Lockup}, +}; +use std::{ + collections::{HashMap, HashSet}, + rc::Rc, + str::FromStr, + thread::sleep, + time::Duration, +}; + +// The percentage of leader slots that validators complete in order to receive the stake +// reward at the end of a TPS round. +const MIN_LEADER_SLOT_PCT: f64 = 80.0; + +#[derive(Default)] +pub struct LeaderRecord { + total_slots: u64, + missed_slots: u64, +} + +impl LeaderRecord { + pub fn completed_slot_pct(&self) -> f64 { + if self.total_slots == 0 { + 0f64 + } else { + let completed_slots = self.total_slots - self.missed_slots; + 100f64 * completed_slots as f64 / self.total_slots as f64 + } + } + + pub fn healthy(&self) -> bool { + self.completed_slot_pct() >= MIN_LEADER_SLOT_PCT + } +} + +/// Calculate the leader record for each active validator +pub fn calculate_leader_records( + rpc_client: &RpcClient, + epoch_schedule: &EpochSchedule, + start_slot: Slot, + end_slot: Slot, + notifier: &Notifier, +) -> ClientResult> { + let start_epoch = epoch_schedule.get_epoch(start_slot); + let end_epoch = epoch_schedule.get_epoch(end_slot); + let confirmed_blocks: HashSet<_> = rpc_client + .get_confirmed_blocks(start_slot, Some(end_slot))? + .into_iter() + .collect(); + + let mut leader_records = HashMap::::new(); + for epoch in start_epoch..=end_epoch { + let first_slot_in_epoch = epoch_schedule.get_first_slot_in_epoch(epoch); + let start_slot = std::cmp::max(start_slot, first_slot_in_epoch); + let last_slot_in_epoch = epoch_schedule.get_last_slot_in_epoch(epoch); + let end_slot = std::cmp::min(end_slot, last_slot_in_epoch); + + rpc_client + .get_leader_schedule(Some(start_slot))? + .unwrap_or_else(|| utils::bail(notifier, "Error: Leader schedule was not found")) + .into_iter() + .map(|(pk, s)| (Pubkey::from_str(&pk).unwrap(), s)) + .for_each(|(pubkey, leader_slots)| { + let mut record = leader_records.entry(pubkey).or_default(); + for slot_index in leader_slots.iter() { + let slot = (*slot_index as u64) + first_slot_in_epoch; + if slot >= start_slot && slot <= end_slot { + record.total_slots += 1; + if !confirmed_blocks.contains(&slot) { + record.missed_slots += 1; + } + } + } + }); + } + + Ok(leader_records) +} + +pub fn fetch_active_validators(rpc_client: &RpcClient) -> HashMap { + match rpc_client.get_vote_accounts() { + Err(err) => { + warn!("Failed to get_vote_accounts(): {}", err); + HashMap::new() + } + Ok(vote_accounts) => vote_accounts + .current + .into_iter() + .filter_map(|info| { + if let (Ok(node_pubkey), Ok(vote_pubkey)) = ( + Pubkey::from_str(&info.node_pubkey), + Pubkey::from_str(&info.vote_pubkey), + ) { + Some((node_pubkey, vote_pubkey)) + } else { + None + } + }) + .collect(), + } +} + +/// Endlessly retry stake delegation until success +fn delegate_stake( + rpc_client: &RpcClient, + faucet_keypair: &Keypair, + vote_account_pubkey: &Pubkey, + sol_gift: u64, +) { + let stake_account_keypair = Keypair::new(); + info!( + "delegate_stake: stake pubkey: {}", + stake_account_keypair.pubkey() + ); + let mut retry_count = 0; + loop { + let recent_blockhash = loop { + match rpc_client.get_recent_blockhash() { + Ok(response) => break response.0, + Err(err) => { + error!("Failed to get recent blockhash: {}", err); + sleep(Duration::from_secs(5)); + } + } + }; + + let transaction = Transaction::new_signed_instructions( + &[faucet_keypair, &stake_account_keypair], + &stake_instruction::create_account_and_delegate_stake( + &faucet_keypair.pubkey(), + &stake_account_keypair.pubkey(), + &vote_account_pubkey, + &StakeAuthorized::auto(&faucet_keypair.pubkey()), + &Lockup::default(), + sol_to_lamports(sol_gift as f64), + ), + recent_blockhash, + ); + + // Check if stake was delegated but just failed to confirm on an earlier attempt + if retry_count > 0 { + if let Ok(stake_account) = rpc_client.get_account(&stake_account_keypair.pubkey()) { + if stake_account.owner == solana_stake_program::id() { + break; + } + } + } + + if let Err(err) = rpc_client.send_and_confirm_transaction(&transaction) { + error!( + "Failed to delegate stake (retries: {}): {}", + retry_count, err + ); + retry_count += 1; + sleep(Duration::from_secs(5)); + } else { + break; + } + } +} + +/// Announce validator status leader slot performance +pub fn announce_results( + starting_validators: &HashMap, + remaining_validators: &HashMap, + pubkey_to_keybase: Rc String>, + leader_records: &HashMap, + notifier: &mut Notifier, +) { + let buffer_records = |keys: Vec<&Pubkey>, notifier: &mut Notifier| { + if keys.is_empty() { + notifier.buffer("* None".to_string()); + return; + } + + let mut validators = vec![]; + for pubkey in keys { + let name = pubkey_to_keybase(pubkey); + if let Some(record) = leader_records.get(pubkey) { + validators.push(format!( + "* {} ({:.1}% leader efficiency)", + name, + record.completed_slot_pct() + )); + } + } + validators.sort(); + notifier.buffer_vec(validators); + }; + + let healthy: Vec<_> = remaining_validators + .keys() + .filter(|k| leader_records.get(k).map(|r| r.healthy()).unwrap_or(false)) + .collect(); + + let unhealthy: Vec<_> = remaining_validators + .keys() + .filter(|k| leader_records.get(k).map(|r| !r.healthy()).unwrap_or(true)) + .collect(); + + let inactive: Vec<_> = starting_validators + .keys() + .filter(|k| !remaining_validators.contains_key(k)) + .collect(); + + notifier.buffer("Healthy Validators:".to_string()); + buffer_records(healthy, notifier); + notifier.buffer("Unhealthy Validators:".to_string()); + buffer_records(unhealthy, notifier); + notifier.buffer("Inactive Validators:".to_string()); + buffer_records(inactive, notifier); + + notifier.flush(); +} + +/// Award stake to the surviving validators by delegating stake to their vote account +pub fn award_stake( + rpc_client: &RpcClient, + faucet_keypair: &Keypair, + voters: Vec<(String, &Pubkey)>, + sol_gift: u64, + notifier: &mut Notifier, +) { + for (node_pubkey, vote_account_pubkey) in voters { + info!("Delegate {} SOL to {}", sol_gift, node_pubkey); + delegate_stake(rpc_client, faucet_keypair, vote_account_pubkey, sol_gift); + notifier.buffer(format!("Delegated {} SOL to {}", sol_gift, node_pubkey)); + } + notifier.flush(); +} diff --git a/stake-accounts/src/main.rs b/stake-accounts/src/main.rs index a0070e440a..f4a8e3e0a5 100644 --- a/stake-accounts/src/main.rs +++ b/stake-accounts/src/main.rs @@ -162,7 +162,7 @@ fn send_message( ) -> Result { let mut transaction = Transaction::new_unsigned(message); client.resign_transaction(&mut transaction, signers)?; - client.send_and_confirm_transaction_with_spinner(&mut transaction, signers) + client.send_and_confirm_transaction_with_spinner(&transaction) } fn main() -> Result<(), Box> {