Skip to content

Commit

Permalink
Surface staking activity in markdown
Browse files Browse the repository at this point in the history
  • Loading branch information
mvines committed Jun 2, 2021
1 parent 6b7f97a commit 555d435
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 71 deletions.
3 changes: 3 additions & 0 deletions bot/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ pub struct ValidatorClassification {
pub stake_state: ValidatorStakeState,
pub stake_state_reason: String,

// Summary of the action was taken this epoch to advance the validator's stake
pub stake_action: Option<String>,

// History of stake states, newest first, including (`stake_state`, `stake_state_reason`) at index 0
pub stake_states: Option<Vec<(ValidatorStakeState, String)>>,

Expand Down
7 changes: 5 additions & 2 deletions bot/src/generic_stake_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use {
serde::{Deserialize, Serialize},
solana_client::rpc_client::RpcClient,
solana_sdk::pubkey::Pubkey,
std::error,
std::{collections::HashMap, error},
};

#[derive(Debug, PartialEq, Clone, Copy, Deserialize, Serialize)]
Expand All @@ -25,11 +25,14 @@ pub struct ValidatorStake {
pub stake_state: ValidatorStakeState,
}

pub type ValidatorStakeActions = HashMap<Pubkey, String>;
pub type EpochStakeNotes = Vec<String>;

pub trait GenericStakePool {
fn apply(
&mut self,
rpc_client: &RpcClient,
dry_run: bool,
desired_validator_stake: &[ValidatorStake],
) -> Result<Vec<String>, Box<dyn error::Error>>;
) -> Result<(EpochStakeNotes, ValidatorStakeActions), Box<dyn error::Error>>;
}
26 changes: 20 additions & 6 deletions bot/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1389,6 +1389,7 @@ fn classify(
vote_address,
stake_state,
stake_states: Some(stake_states),
stake_action: None,
stake_state_reason: reason,
notes: validator_notes,
data_center_residency: Some(data_center_residency),
Expand Down Expand Up @@ -1505,7 +1506,8 @@ fn main() -> BoxResult<()> {

let mut notifications = epoch_classification.notes.clone();

if let Some(ref validator_classifications) = epoch_classification.validator_classifications {
if let Some(ref mut validator_classifications) = epoch_classification.validator_classifications
{
let previous_validator_classifications = previous_epoch_classification
.validator_classifications
.unwrap_or_default();
Expand Down Expand Up @@ -1544,11 +1546,17 @@ fn main() -> BoxResult<()> {
})
.collect();

let stake_pool_notes =
let (stake_pool_notes, validator_stake_actions) =
stake_pool.apply(&rpc_client, config.dry_run, &desired_validator_stake)?;
notifications.extend(stake_pool_notes.clone());
epoch_classification.notes.extend(stake_pool_notes);

for (identity, stake_action) in validator_stake_actions {
validator_classifications
.entry(identity)
.and_modify(|e| e.stake_action = Some(stake_action));
}

validator_notes.sort();
notifications.extend(validator_notes);

Expand Down Expand Up @@ -1593,7 +1601,7 @@ fn generate_markdown(epoch: Epoch, config: &Config) -> BoxResult<()> {
list.push((epoch, epoch_classification.into_current()));
}

let mut validators_markdown: HashMap<_, Vec<_>> = HashMap::new();
let mut validators_markdown: HashMap<_, Vec<_>> = HashMap::default();

let mut cluster_markdown = vec![];

Expand All @@ -1614,8 +1622,6 @@ fn generate_markdown(epoch: Epoch, config: &Config) -> BoxResult<()> {
"### [[{1} Epoch {0}|{1}#Epoch-{0}]]",
epoch, cluster_md
));
validator_markdown.push(classification.stake_state_reason.clone());

let stake_state_streak = classification.stake_state_streak();
validator_markdown.push(format!(
"* Stake level: **{:?}**{}",
Expand All @@ -1626,6 +1632,14 @@ fn generate_markdown(epoch: Epoch, config: &Config) -> BoxResult<()> {
"".to_string()
}
));
validator_markdown.push(format!(
"* Stake reason: {}",
classification.stake_state_reason
));
if let Some(stake_action) = classification.stake_action {
validator_markdown.push(format!("* Staking activity: {}", stake_action));
}

validator_markdown.push(format!(
"* Vote account address: {}",
classification.vote_address
Expand Down Expand Up @@ -1695,7 +1709,7 @@ mod test {
.iter()
.cloned()
.collect();
let mut leader_schedule = HashMap::new();
let mut leader_schedule = HashMap::default();
let l1 = Pubkey::new_unique();
let l2 = Pubkey::new_unique();
let l3 = Pubkey::new_unique();
Expand Down
72 changes: 44 additions & 28 deletions bot/src/stake_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ use {
stake_program::split_only,
state::{StakePool, StakeStatus, ValidatorList},
},
std::{collections::HashSet, error, mem},
std::{
collections::{HashMap, HashSet},
error, mem,
},
};

/// Minimum amount of lamports in a validator stake account, on top of the
Expand Down Expand Up @@ -153,12 +156,13 @@ impl GenericStakePool for StakePoolOMatic {
rpc_client: &RpcClient,
dry_run: bool,
desired_validator_stake: &[ValidatorStake],
) -> Result<Vec<String>, Box<dyn error::Error>> {
) -> Result<(EpochStakeNotes, ValidatorStakeActions), Box<dyn error::Error>> {
let mut validator_stake_actions = HashMap::default();
let mut bonus_stake_node_count = 0;
let mut baseline_stake_node_count = 0;

// used to find any validators that should be removed from the stake pool
let mut inuse_vote_addresses = HashSet::new();
let mut inuse_vote_addresses = HashSet::default();

for ValidatorStake {
stake_state,
Expand Down Expand Up @@ -208,13 +212,12 @@ impl GenericStakePool for StakePoolOMatic {
)?;
self.update(rpc_client)?;

let mut busy_validators = HashSet::new();
info!("Add unmerged transient stake accounts to the busy set");
add_unmerged_transient_stake_accounts(
rpc_client,
desired_validator_stake,
&self.stake_pool_address,
&mut busy_validators,
&mut validator_stake_actions,
)?;

info!("Create validator stake accounts if needed");
Expand All @@ -223,7 +226,7 @@ impl GenericStakePool for StakePoolOMatic {
&self.authorized_staker,
desired_validator_stake,
&self.stake_pool_address,
&mut busy_validators,
&mut validator_stake_actions,
)?;

let total_stake_amount = self.stake_pool.total_stake_lamports;
Expand Down Expand Up @@ -286,6 +289,11 @@ impl GenericStakePool for StakePoolOMatic {
format!("Baseline stake amount: {}", Sol(self.baseline_stake_amount)),
format!("Bonus stake amount: {}", Sol(bonus_stake_amount)),
];

let busy_validators = validator_stake_actions
.keys()
.cloned()
.collect::<HashSet<_>>();
distribute_validator_stake(
rpc_client,
dry_run,
Expand All @@ -300,8 +308,9 @@ impl GenericStakePool for StakePoolOMatic {
reserve_stake_balance,
self.baseline_stake_amount,
bonus_stake_amount,
&mut validator_stake_actions,
)?;
Ok(notes)
Ok((notes, validator_stake_actions))
}
}

Expand Down Expand Up @@ -336,7 +345,7 @@ fn add_unmerged_transient_stake_accounts(
rpc_client: &RpcClient,
desired_validator_stake: &[ValidatorStake],
stake_pool_address: &Pubkey,
busy_validators: &mut HashSet<Pubkey>,
validator_stake_actions: &mut ValidatorStakeActions,
) -> Result<(), Box<dyn error::Error>> {
for ValidatorStake {
identity,
Expand All @@ -356,7 +365,11 @@ fn add_unmerged_transient_stake_accounts(
.value;

if transient_stake_account.is_some() {
busy_validators.insert(*identity);
let action = format!(
"busy due to transient stake account {}",
transient_stake_address
);
validator_stake_actions.insert(*identity, action);
}
}
Ok(())
Expand Down Expand Up @@ -648,7 +661,7 @@ fn create_validator_stake_accounts(
authorized_staker: &Keypair,
desired_validator_stake: &[ValidatorStake],
stake_pool_address: &Pubkey,
busy_validators: &mut HashSet<Pubkey>,
validator_stake_actions: &mut ValidatorStakeActions,
) -> Result<(), Box<dyn error::Error>> {
let mut staker_balance = rpc_client.get_balance(&authorized_staker.pubkey()).unwrap();
info!("Staker available balance: {}", Sol(staker_balance));
Expand Down Expand Up @@ -682,18 +695,23 @@ fn create_validator_stake_accounts(

match stake_activation.state {
StakeActivationState::Activating | StakeActivationState::Deactivating => {
warn!(
"Validator {} busy due to stake activation or deactivation of {}: {:?}",
identity, stake_address, stake_activation
let action = format!(
"stake account busy due to stake activation or deactivation of {}",
stake_address
);
busy_validators.insert(*identity);
warn!("Busy validator {}: {}", *identity, action);
validator_stake_actions.insert(*identity, action);
}
StakeActivationState::Active => {}
StakeActivationState::Inactive => {
warn!(
"Validator {} busy due to inactive stake {}: {:?}",
identity, stake_address, stake_activation
);
let action =
format!("stake account busy due to inactive stake {}", stake_address);
warn!("Busy validator {}: {}", *identity, action);

transactions.push(Transaction::new_with_payer(
&[stake_instruction::delegate_stake(
&stake_address,
Expand All @@ -706,7 +724,7 @@ fn create_validator_stake_accounts(
"Activating stake account for validator {} ({})",
identity, stake_address
);
busy_validators.insert(*identity);
validator_stake_actions.insert(*identity, action);
}
}
} else {
Expand Down Expand Up @@ -737,8 +755,12 @@ fn create_validator_stake_accounts(
identity, stake_address
);
}
warn!("Validator {} busy due to no stake account", identity);
busy_validators.insert(*identity);
let action = format!(
"stake account busy due to no stake account: {}",
stake_address
);
warn!("Busy validator {}: {}", *identity, action);
validator_stake_actions.insert(*identity, action);
}
}

Expand All @@ -764,6 +786,7 @@ fn distribute_validator_stake<V>(
mut reserve_stake_balance: u64,
baseline_stake_amount: u64,
bonus_stake_amount: u64,
validator_stake_actions: &mut ValidatorStakeActions,
) -> Result<bool, Box<dyn error::Error>>
where
V: IntoIterator<Item = ValidatorStake>,
Expand Down Expand Up @@ -815,13 +838,6 @@ where
ValidatorStakeState::Baseline => baseline_stake_amount,
ValidatorStakeState::Bonus => bonus_stake_amount,
};
info!(
"desired stake for {} ({:?}) is {}, current balance is {}",
identity,
stake_state,
Sol(desired_balance),
Sol(balance)
);

#[allow(clippy::comparison_chain)]
let op_msg = if balance > desired_balance {
Expand Down Expand Up @@ -881,14 +897,14 @@ where
"no change".to_string()
};

debug!(
"{} ({:?}) target: {}, current: {}, {}",
identity,
stake_state,
let action = format!(
"target stake amount: {}, current stake amount: {} - {}",
Sol(desired_balance),
Sol(balance),
op_msg,
);
info!("{} ({:?}): {}", identity, stake_state, action);
validator_stake_actions.insert(identity, action);
}
info!(
"Reserve stake available balance after updates: {}",
Expand Down
Loading

0 comments on commit 555d435

Please sign in to comment.