Skip to content

Commit

Permalink
Add wait for max stake command (solana-labs#13532)
Browse files Browse the repository at this point in the history
  • Loading branch information
sakridge authored Nov 12, 2020
1 parent 30ef53c commit 598e5f5
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 11 deletions.
13 changes: 13 additions & 0 deletions cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ pub enum CliCommand {
limit: usize,
show_transactions: bool,
},
WaitForMaxStake {
max_stake_percent: f32,
},
// Nonce commands
AuthorizeNonceAccount {
nonce_account: Pubkey,
Expand Down Expand Up @@ -624,6 +627,13 @@ pub fn parse_command(
signers,
})
}
("wait-for-max-stake", Some(matches)) => {
let max_stake_percent = value_t_or_exit!(matches, "max_percent", f32);
Ok(CliCommandInfo {
command: CliCommand::WaitForMaxStake { max_stake_percent },
signers: vec![],
})
}
// Stake Commands
("create-stake-account", Some(matches)) => {
parse_stake_create_account(matches, default_signer, wallet_manager)
Expand Down Expand Up @@ -1565,6 +1575,9 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
*use_lamports_unit,
vote_account_pubkeys.as_deref(),
),
CliCommand::WaitForMaxStake { max_stake_percent } => {
process_wait_for_max_stake(&rpc_client, config, *max_stake_percent)
}
CliCommand::ShowValidators { use_lamports_unit } => {
process_show_validators(&rpc_client, config, *use_lamports_unit)
}
Expand Down
21 changes: 21 additions & 0 deletions cli/src/cluster_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,17 @@ impl ClusterQuerySubCommands for App<'_, '_> {
.help("Display the full transactions"),
)
)
.subcommand(
SubCommand::with_name("wait-for-max-stake")
.about("Wait for the max stake of any one node to drop below a percentage of total.")
.arg(
Arg::with_name("max_percent")
.long("max-percent")
.value_name("PERCENT")
.takes_value(true)
.index(1),
),
)
}
}

Expand Down Expand Up @@ -1400,6 +1411,16 @@ pub fn process_show_stakes(
.formatted_string(&CliStakeVec::new(stake_accounts)))
}

pub fn process_wait_for_max_stake(
rpc_client: &RpcClient,
config: &CliConfig,
max_stake_percent: f32,
) -> ProcessResult {
let now = std::time::Instant::now();
rpc_client.wait_for_max_stake(config.commitment, max_stake_percent)?;
Ok(format!("Done waiting, took: {}s", now.elapsed().as_secs()))
}

pub fn process_show_validators(
rpc_client: &RpcClient,
config: &CliConfig,
Expand Down
32 changes: 32 additions & 0 deletions client/src/rpc_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,38 @@ impl RpcClient {
self.send(RpcRequest::GetVoteAccounts, json!([commitment_config]))
}

pub fn wait_for_max_stake(
&self,
commitment: CommitmentConfig,
max_stake_percent: f32,
) -> ClientResult<()> {
let mut current_percent;
loop {
let vote_accounts = self.get_vote_accounts_with_commitment(commitment)?;

let mut max = 0;
let total_active_stake = vote_accounts
.current
.iter()
.chain(vote_accounts.delinquent.iter())
.map(|vote_account| {
max = std::cmp::max(max, vote_account.activated_stake);
vote_account.activated_stake
})
.sum::<u64>();
current_percent = 100f32 * max as f32 / total_active_stake as f32;
if current_percent < max_stake_percent {
break;
}
info!(
"Waiting for stake to drop below {} current: {:.1}",
max_stake_percent, current_percent
);
sleep(Duration::from_secs(10));
}
Ok(())
}

pub fn get_cluster_nodes(&self) -> ClientResult<Vec<RpcContactInfo>> {
self.send(RpcRequest::GetClusterNodes, Value::Null)
}
Expand Down
20 changes: 20 additions & 0 deletions local-cluster/tests/local_cluster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1340,6 +1340,26 @@ fn test_faulty_node(faulty_node_type: BroadcastStageType) {
cluster.check_for_new_roots(16, &"test_faulty_node");
}

#[test]
fn test_wait_for_max_stake() {
solana_logger::setup();
let mut validator_config = ValidatorConfig::default();
validator_config.rpc_config.enable_validator_exit = true;
let config = ClusterConfig {
cluster_lamports: 10_000,
node_stakes: vec![100; 4],
validator_configs: vec![validator_config; 4],
..ClusterConfig::default()
};
let cluster = LocalCluster::new(&config);
let client = RpcClient::new_socket(cluster.entry_point_info.rpc);

assert!(client
.wait_for_max_stake(CommitmentConfig::default(), 33.0f32)
.is_ok());
assert!(client.get_slot().unwrap() > 10);
}

#[test]
// Test that when a leader is leader for banks B_i..B_{i+n}, and B_i is not
// votable, then B_{i+1} still chains to B_i
Expand Down
12 changes: 1 addition & 11 deletions system-test/automation_utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,8 @@ function wait_for_bootstrap_validator_stake_drop {
source "${REPO_ROOT}"/net/common.sh
loadConfigFile

while true; do
# shellcheck disable=SC2154
bootstrap_validator_validator_info="$(ssh "${sshOptions[@]}" "${validatorIpList[0]}" '$HOME/.cargo/bin/solana --url http://127.0.0.1:8899 validators | grep "$($HOME/.cargo/bin/solana-keygen pubkey ~/solana/config/bootstrap-validator/identity.json)"')"
bootstrap_validator_stake_percentage="$(echo "$bootstrap_validator_validator_info" | awk '{gsub(/[\(,\),\%]/,""); print $9}')"

if [[ $(echo "$bootstrap_validator_stake_percentage < $max_stake" | bc) -ne 0 ]]; then
echo "Bootstrap validator stake has fallen below $max_stake to $bootstrap_validator_stake_percentage"
break
fi
echo "Max bootstrap validator stake: $max_stake. Current stake: $bootstrap_validator_stake_percentage. Sleeping 30s for stake to distribute."
sleep 30
done
ssh "${sshOptions[@]}" "${validatorIpList[0]}" '$HOME/.cargo/bin/solana wait-for-max-stake $max_stake --url http://127.0.0.1:8899'
}

function get_slot {
Expand Down

0 comments on commit 598e5f5

Please sign in to comment.