1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
use crate::cli::{CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult}; use clap::{App, Arg, ArgMatches, SubCommand}; use solana_clap_utils::{ input_parsers::{pubkeys_of, value_of}, input_validators::is_valid_pubkey, keypair::*, }; use solana_cli_output::{ CliEpochRewardshMetadata, CliInflation, CliKeyedEpochReward, CliKeyedEpochRewards, }; use solana_client::rpc_client::RpcClient; use solana_remote_wallet::remote_wallet::RemoteWalletManager; use solana_sdk::{clock::Epoch, pubkey::Pubkey}; use std::sync::Arc; #[derive(Debug, PartialEq)] pub enum InflationCliCommand { Show, Rewards(Vec<Pubkey>, Option<Epoch>), } pub trait InflationSubCommands { fn inflation_subcommands(self) -> Self; } impl InflationSubCommands for App<'_, '_> { fn inflation_subcommands(self) -> Self { self.subcommand( SubCommand::with_name("inflation") .about("Show inflation information") .subcommand( SubCommand::with_name("rewards") .about("Show inflation rewards for a set of addresses") .arg(pubkey!( Arg::with_name("addresses") .value_name("ADDRESS") .index(1) .multiple(true) .required(true), "Address of account to query for rewards. " )) .arg( Arg::with_name("rewards_epoch") .long("rewards-epoch") .takes_value(true) .value_name("EPOCH") .help("Display rewards for specific epoch [default: latest epoch]"), ), ), ) } } pub fn parse_inflation_subcommand( matches: &ArgMatches<'_>, _default_signer: &DefaultSigner, _wallet_manager: &mut Option<Arc<RemoteWalletManager>>, ) -> Result<CliCommandInfo, CliError> { let command = match matches.subcommand() { ("rewards", Some(matches)) => { let addresses = pubkeys_of(matches, "addresses").unwrap(); let rewards_epoch = value_of(matches, "rewards_epoch"); InflationCliCommand::Rewards(addresses, rewards_epoch) } _ => InflationCliCommand::Show, }; Ok(CliCommandInfo { command: CliCommand::Inflation(command), signers: vec![], }) } pub fn process_inflation_subcommand( rpc_client: &RpcClient, config: &CliConfig, inflation_subcommand: &InflationCliCommand, ) -> ProcessResult { match inflation_subcommand { InflationCliCommand::Show => process_show(rpc_client, config), InflationCliCommand::Rewards(ref addresses, rewards_epoch) => { process_rewards(rpc_client, config, addresses, *rewards_epoch) } } } fn process_show(rpc_client: &RpcClient, config: &CliConfig) -> ProcessResult { let governor = rpc_client.get_inflation_governor()?; let current_rate = rpc_client.get_inflation_rate()?; let inflation = CliInflation { governor, current_rate, }; Ok(config.output_format.formatted_string(&inflation)) } fn process_rewards( rpc_client: &RpcClient, config: &CliConfig, addresses: &[Pubkey], rewards_epoch: Option<Epoch>, ) -> ProcessResult { let rewards = rpc_client .get_inflation_reward(&addresses, rewards_epoch) .map_err(|err| { if let Some(epoch) = rewards_epoch { format!("Rewards not available for epoch {}", epoch) } else { format!("Rewards not available {}", err) } })?; let epoch_schedule = rpc_client.get_epoch_schedule()?; let mut epoch_rewards: Vec<CliKeyedEpochReward> = vec![]; let epoch_metadata = if let Some(Some(first_reward)) = rewards.iter().find(|&v| v.is_some()) { let (epoch_start_time, epoch_end_time) = crate::stake::get_epoch_boundary_timestamps(rpc_client, first_reward, &epoch_schedule)?; for (reward, address) in rewards.iter().zip(addresses) { let cli_reward = reward.as_ref().and_then(|reward| { crate::stake::make_cli_reward(reward, epoch_start_time, epoch_end_time) }); epoch_rewards.push(CliKeyedEpochReward { address: address.to_string(), reward: cli_reward, }); } let block_time = rpc_client.get_block_time(first_reward.effective_slot)?; Some(CliEpochRewardshMetadata { epoch: first_reward.epoch, effective_slot: first_reward.effective_slot, block_time, }) } else { None }; let cli_rewards = CliKeyedEpochRewards { epoch_metadata, rewards: epoch_rewards, }; Ok(config.output_format.formatted_string(&cli_rewards)) }