agave_validator/commands/set_identity/
mod.rs

1use {
2    crate::{
3        admin_rpc_service,
4        commands::{FromClapArgMatches, Result},
5    },
6    clap::{value_t, App, Arg, ArgMatches, SubCommand},
7    solana_clap_utils::input_validators::is_keypair,
8    solana_keypair::read_keypair,
9    solana_signer::Signer,
10    std::{fs, path::Path},
11};
12
13const COMMAND: &str = "set-identity";
14
15#[derive(Debug, PartialEq)]
16#[cfg_attr(test, derive(Default))]
17pub struct SetIdentityArgs {
18    pub identity: Option<String>,
19    pub require_tower: bool,
20}
21
22impl FromClapArgMatches for SetIdentityArgs {
23    fn from_clap_arg_match(matches: &ArgMatches) -> Result<Self> {
24        Ok(SetIdentityArgs {
25            identity: value_t!(matches, "identity", String).ok(),
26            require_tower: matches.is_present("require_tower"),
27        })
28    }
29}
30pub fn command<'a>() -> App<'a, 'a> {
31    SubCommand::with_name(COMMAND)
32        .about("Set the validator identity")
33        .arg(
34            Arg::with_name("identity")
35                .index(1)
36                .value_name("KEYPAIR")
37                .required(false)
38                .takes_value(true)
39                .validator(is_keypair)
40                .help("Path to validator identity keypair [default: read JSON keypair from stdin]"),
41        )
42        .arg(
43            clap::Arg::with_name("require_tower")
44                .long("require-tower")
45                .takes_value(false)
46                .help("Refuse to set the validator identity if saved tower state is not found"),
47        )
48        .after_help(
49            "Note: the new identity only applies to the currently running validator instance",
50        )
51}
52
53pub fn execute(matches: &ArgMatches, ledger_path: &Path) -> Result<()> {
54    let SetIdentityArgs {
55        identity,
56        require_tower,
57    } = SetIdentityArgs::from_clap_arg_match(matches)?;
58
59    if let Some(identity_keypair) = identity {
60        let identity_keypair = fs::canonicalize(&identity_keypair)?;
61
62        println!(
63            "New validator identity path: {}",
64            identity_keypair.display()
65        );
66
67        let admin_client = admin_rpc_service::connect(ledger_path);
68        admin_rpc_service::runtime().block_on(async move {
69            admin_client
70                .await?
71                .set_identity(identity_keypair.display().to_string(), require_tower)
72                .await
73        })?;
74    } else {
75        let mut stdin = std::io::stdin();
76        let identity_keypair = read_keypair(&mut stdin)?;
77
78        println!("New validator identity: {}", identity_keypair.pubkey());
79
80        let admin_client = admin_rpc_service::connect(ledger_path);
81        admin_rpc_service::runtime().block_on(async move {
82            admin_client
83                .await?
84                .set_identity_from_bytes(Vec::from(identity_keypair.to_bytes()), require_tower)
85                .await
86        })?;
87    }
88
89    Ok(())
90}
91
92#[cfg(test)]
93mod tests {
94    use {
95        super::*, crate::commands::tests::verify_args_struct_by_command, solana_keypair::Keypair,
96    };
97
98    #[test]
99    fn verify_args_struct_by_command_set_identity_default() {
100        verify_args_struct_by_command(command(), vec![COMMAND], SetIdentityArgs::default());
101    }
102
103    #[test]
104    fn verify_args_struct_by_command_set_identity_with_identity_file() {
105        // generate a keypair
106        let tmp_dir = tempfile::tempdir().unwrap();
107        let file = tmp_dir.path().join("id.json");
108        let keypair = Keypair::new();
109        solana_keypair::write_keypair_file(&keypair, &file).unwrap();
110
111        verify_args_struct_by_command(
112            command(),
113            vec![COMMAND, file.to_str().unwrap()],
114            SetIdentityArgs {
115                identity: Some(file.to_str().unwrap().to_string()),
116                ..SetIdentityArgs::default()
117            },
118        );
119    }
120
121    #[test]
122    fn verify_args_struct_by_command_set_identity_with_require_tower() {
123        verify_args_struct_by_command(
124            command(),
125            vec![COMMAND, "--require-tower"],
126            SetIdentityArgs {
127                require_tower: true,
128                ..SetIdentityArgs::default()
129            },
130        );
131    }
132}