agave_validator/commands/set_identity/
mod.rs1use {
2 crate::{
3 admin_rpc_service,
4 commands::{FromClapArgMatches, Result},
5 },
6 clap::{App, Arg, ArgMatches, SubCommand, value_t},
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)]
16pub struct SetIdentityArgs {
17 pub identity: Option<String>,
18 pub require_tower: bool,
19 pub require_vote_history: bool,
20}
21
22impl Default for SetIdentityArgs {
23 fn default() -> Self {
24 Self {
25 identity: None,
26 require_tower: false,
27 require_vote_history: true,
28 }
29 }
30}
31
32impl FromClapArgMatches for SetIdentityArgs {
33 fn from_clap_arg_match(matches: &ArgMatches) -> Result<Self> {
34 Ok(SetIdentityArgs {
35 identity: value_t!(matches, "identity", String).ok(),
36 require_tower: matches.is_present("require_tower"),
37 require_vote_history: !matches.is_present("do_not_require_vote_history"),
38 })
39 }
40}
41pub fn command<'a>() -> App<'a, 'a> {
42 SubCommand::with_name(COMMAND)
43 .about("Set the validator identity")
44 .arg(
45 Arg::with_name("identity")
46 .index(1)
47 .value_name("KEYPAIR")
48 .required(false)
49 .takes_value(true)
50 .validator(is_keypair)
51 .help("Path to validator identity keypair [default: read JSON keypair from stdin]"),
52 )
53 .arg(
54 clap::Arg::with_name("require_tower")
55 .long("require-tower")
56 .takes_value(false)
57 .help("Refuse to set the validator identity if saved tower state is not found"),
58 )
59 .arg(
60 clap::Arg::with_name("do_not_require_vote_history")
61 .long("do-not-require-vote-history")
62 .takes_value(false)
63 .help("Do not require saved vote history state for identity change"),
64 )
65 .after_help(
66 "Note: the new identity only applies to the currently running validator instance",
67 )
68}
69
70pub fn execute(matches: &ArgMatches, ledger_path: &Path) -> Result<()> {
71 let SetIdentityArgs {
72 identity,
73 require_tower,
74 require_vote_history,
75 } = SetIdentityArgs::from_clap_arg_match(matches)?;
76
77 if let Some(identity_keypair) = identity {
78 let identity_keypair = fs::canonicalize(&identity_keypair)?;
79
80 println!(
81 "New validator identity path: {}",
82 identity_keypair.display()
83 );
84
85 let admin_client = admin_rpc_service::connect(ledger_path);
86 admin_rpc_service::runtime().block_on(async move {
87 admin_client
88 .await?
89 .set_identity(
90 identity_keypair.display().to_string(),
91 require_tower,
92 require_vote_history,
93 )
94 .await
95 })?;
96 } else {
97 let mut stdin = std::io::stdin();
98 let identity_keypair = read_keypair(&mut stdin)?;
99
100 println!("New validator identity: {}", identity_keypair.pubkey());
101
102 let admin_client = admin_rpc_service::connect(ledger_path);
103 admin_rpc_service::runtime().block_on(async move {
104 admin_client
105 .await?
106 .set_identity_from_bytes(
107 Vec::from(identity_keypair.to_bytes()),
108 require_tower,
109 require_vote_history,
110 )
111 .await
112 })?;
113 }
114
115 Ok(())
116}
117
118#[cfg(test)]
119mod tests {
120 use {
121 super::*, crate::commands::tests::verify_args_struct_by_command, solana_keypair::Keypair,
122 };
123
124 #[test]
125 fn verify_args_struct_by_command_set_identity_default() {
126 verify_args_struct_by_command(command(), vec![COMMAND], SetIdentityArgs::default());
127 }
128
129 #[test]
130 fn verify_args_struct_by_command_set_identity_with_identity_file() {
131 let tmp_dir = tempfile::tempdir().unwrap();
133 let file = tmp_dir.path().join("id.json");
134 let keypair = Keypair::new();
135 solana_keypair::write_keypair_file(&keypair, &file).unwrap();
136
137 verify_args_struct_by_command(
138 command(),
139 vec![COMMAND, file.to_str().unwrap()],
140 SetIdentityArgs {
141 identity: Some(file.to_str().unwrap().to_string()),
142 ..SetIdentityArgs::default()
143 },
144 );
145 }
146
147 #[test]
148 fn verify_args_struct_by_command_set_identity_with_require_tower() {
149 verify_args_struct_by_command(
150 command(),
151 vec![COMMAND, "--require-tower"],
152 SetIdentityArgs {
153 require_tower: true,
154 ..SetIdentityArgs::default()
155 },
156 );
157 }
158
159 #[test]
160 fn verify_args_struct_by_command_set_identity_do_not_require_vote_history() {
161 verify_args_struct_by_command(
162 command(),
163 vec![COMMAND, "--do-not-require-vote-history"],
164 SetIdentityArgs {
165 require_vote_history: false,
166 ..SetIdentityArgs::default()
167 },
168 );
169 }
170}