CLI: collect and deduplicate signers (#8398)
* Rename (keypair util is not a thing) * Add method to generate_unique_signers * Cli: refactor signer handling and remote-wallet init * Fixup unit tests * Fixup intergation tests * Update keypair path print statement * Remove &None * Use deterministic key in test * Retain storage-account as index * Make signer index-handling less brittle * Cache pubkey on RemoteKeypair::new * Make signer_of consistent + return pubkey * Remove &matches double references * Nonce authorities need special handling
This commit is contained in:
@ -3,7 +3,7 @@ use solana_cli::cli::{process_command, CliCommand, CliConfig};
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_core::validator::new_validator_for_tests;
|
||||
use solana_faucet::faucet::run_local_faucet;
|
||||
use solana_sdk::{bpf_loader, pubkey::Pubkey};
|
||||
use solana_sdk::{bpf_loader, pubkey::Pubkey, signature::Keypair};
|
||||
use std::{
|
||||
fs::{remove_dir_all, File},
|
||||
io::Read,
|
||||
@ -38,6 +38,7 @@ fn test_cli_deploy_program() {
|
||||
.unwrap();
|
||||
|
||||
let mut config = CliConfig::default();
|
||||
let keypair = Keypair::new();
|
||||
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config.command = CliCommand::Airdrop {
|
||||
faucet_host: None,
|
||||
@ -45,6 +46,7 @@ fn test_cli_deploy_program() {
|
||||
pubkey: None,
|
||||
lamports: minimum_balance_for_rent_exemption + 1, // min balance for rent exemption + leftover for tx processing
|
||||
};
|
||||
config.signers = vec![&keypair];
|
||||
process_command(&config).unwrap();
|
||||
|
||||
config.command = CliCommand::Deploy(pathbuf.to_str().unwrap().to_string());
|
||||
|
@ -4,25 +4,14 @@ use solana_faucet::faucet::run_local_faucet;
|
||||
use solana_sdk::{
|
||||
hash::Hash,
|
||||
pubkey::Pubkey,
|
||||
signature::{keypair_from_seed, read_keypair_file, write_keypair, Keypair, Signer},
|
||||
signature::{keypair_from_seed, Keypair, Signer},
|
||||
system_instruction::create_address_with_seed,
|
||||
system_program,
|
||||
};
|
||||
use std::fs::remove_dir_all;
|
||||
use std::sync::mpsc::channel;
|
||||
use std::{fs::remove_dir_all, sync::mpsc::channel, thread::sleep, time::Duration};
|
||||
|
||||
#[cfg(test)]
|
||||
use solana_core::validator::new_validator_for_tests;
|
||||
use std::rc::Rc;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
fn make_tmp_file() -> (String, NamedTempFile) {
|
||||
let tmp_file = NamedTempFile::new().unwrap();
|
||||
(String::from(tmp_file.path().to_str().unwrap()), tmp_file)
|
||||
}
|
||||
|
||||
fn check_balance(expected_balance: u64, client: &RpcClient, pubkey: &Pubkey) {
|
||||
(0..5).for_each(|tries| {
|
||||
@ -45,28 +34,9 @@ fn test_nonce() {
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
|
||||
let mut config_payer = CliConfig::default();
|
||||
config_payer.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
|
||||
let keypair = keypair_from_seed(&[0u8; 32]).unwrap();
|
||||
let (keypair_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&keypair, tmp_file.as_file_mut()).unwrap();
|
||||
let mut config_nonce = CliConfig::default();
|
||||
config_nonce.keypair = keypair.into();
|
||||
config_nonce.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
|
||||
full_battery_tests(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&mut config_payer,
|
||||
&mut config_nonce,
|
||||
&keypair_file,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
full_battery_tests(&rpc_client, &faucet_addr, json_rpc_url, None, false);
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
@ -80,27 +50,14 @@ fn test_nonce_with_seed() {
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
|
||||
let mut config_payer = CliConfig::default();
|
||||
config_payer.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
|
||||
let keypair = keypair_from_seed(&[0u8; 32]).unwrap();
|
||||
let (keypair_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&keypair, tmp_file.as_file_mut()).unwrap();
|
||||
let mut config_nonce = CliConfig::default();
|
||||
config_nonce.keypair = keypair.into();
|
||||
config_nonce.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
let json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
|
||||
full_battery_tests(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&mut config_payer,
|
||||
&mut config_nonce,
|
||||
&keypair_file,
|
||||
json_rpc_url,
|
||||
Some(String::from("seed")),
|
||||
None,
|
||||
false,
|
||||
);
|
||||
|
||||
server.close().unwrap();
|
||||
@ -115,78 +72,73 @@ fn test_nonce_with_authority() {
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
|
||||
let mut config_payer = CliConfig::default();
|
||||
config_payer.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
|
||||
let nonce_keypair = keypair_from_seed(&[0u8; 32]).unwrap();
|
||||
let (nonce_keypair_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&nonce_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
let mut config_nonce = CliConfig::default();
|
||||
config_nonce.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
|
||||
let nonce_authority = Keypair::new();
|
||||
let (authority_keypair_file, mut tmp_file2) = make_tmp_file();
|
||||
write_keypair(&nonce_authority, tmp_file2.as_file_mut()).unwrap();
|
||||
|
||||
full_battery_tests(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&mut config_payer,
|
||||
&mut config_nonce,
|
||||
&nonce_keypair_file,
|
||||
None,
|
||||
Some(&authority_keypair_file),
|
||||
);
|
||||
full_battery_tests(&rpc_client, &faucet_addr, json_rpc_url, None, true);
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
}
|
||||
|
||||
fn read_keypair_from_option(keypair_file: &Option<&str>) -> Option<Box<dyn Signer>> {
|
||||
keypair_file.map(|akf| read_keypair_file(&akf).unwrap().into())
|
||||
}
|
||||
|
||||
fn full_battery_tests(
|
||||
rpc_client: &RpcClient,
|
||||
faucet_addr: &std::net::SocketAddr,
|
||||
config_payer: &mut CliConfig,
|
||||
config_nonce: &mut CliConfig,
|
||||
nonce_keypair_file: &str,
|
||||
json_rpc_url: String,
|
||||
seed: Option<String>,
|
||||
authority_keypair_file: Option<&str>,
|
||||
use_nonce_authority: bool,
|
||||
) {
|
||||
let mut config_payer = CliConfig::default();
|
||||
config_payer.json_rpc_url = json_rpc_url.clone();
|
||||
let payer = Keypair::new();
|
||||
config_payer.signers = vec![&payer];
|
||||
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_payer.keypair.pubkey(),
|
||||
&config_payer.signers[0].pubkey(),
|
||||
2000,
|
||||
)
|
||||
.unwrap();
|
||||
check_balance(2000, &rpc_client, &config_payer.keypair.pubkey());
|
||||
check_balance(2000, &rpc_client, &config_payer.signers[0].pubkey());
|
||||
|
||||
let mut config_nonce = CliConfig::default();
|
||||
config_nonce.json_rpc_url = json_rpc_url;
|
||||
let nonce_keypair = keypair_from_seed(&[0u8; 32]).unwrap();
|
||||
config_nonce.signers = vec![&nonce_keypair];
|
||||
|
||||
let nonce_account = if let Some(seed) = seed.as_ref() {
|
||||
create_address_with_seed(&config_nonce.keypair.pubkey(), seed, &system_program::id())
|
||||
.unwrap()
|
||||
create_address_with_seed(
|
||||
&config_nonce.signers[0].pubkey(),
|
||||
seed,
|
||||
&system_program::id(),
|
||||
)
|
||||
.unwrap()
|
||||
} else {
|
||||
read_keypair_file(&nonce_keypair_file).unwrap().pubkey()
|
||||
nonce_keypair.pubkey()
|
||||
};
|
||||
|
||||
let nonce_authority = Keypair::new();
|
||||
let optional_authority = if use_nonce_authority {
|
||||
Some(nonce_authority.pubkey())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Create nonce account
|
||||
config_payer.signers.push(&nonce_keypair);
|
||||
config_payer.command = CliCommand::CreateNonceAccount {
|
||||
nonce_account: Rc::new(read_keypair_file(&nonce_keypair_file).unwrap().into()),
|
||||
nonce_account: 1,
|
||||
seed,
|
||||
nonce_authority: read_keypair_from_option(&authority_keypair_file).map(|k| k.pubkey()),
|
||||
nonce_authority: optional_authority,
|
||||
lamports: 1000,
|
||||
};
|
||||
|
||||
process_command(&config_payer).unwrap();
|
||||
check_balance(1000, &rpc_client, &config_payer.keypair.pubkey());
|
||||
check_balance(1000, &rpc_client, &config_payer.signers[0].pubkey());
|
||||
check_balance(1000, &rpc_client, &nonce_account);
|
||||
|
||||
// Get nonce
|
||||
config_payer.signers.pop();
|
||||
config_payer.command = CliCommand::GetNonce(nonce_account);
|
||||
let first_nonce_string = process_command(&config_payer).unwrap();
|
||||
let first_nonce = first_nonce_string.parse::<Hash>().unwrap();
|
||||
@ -198,14 +150,24 @@ fn full_battery_tests(
|
||||
|
||||
assert_eq!(first_nonce, second_nonce);
|
||||
|
||||
let mut authorized_signers: Vec<&dyn Signer> = vec![&payer];
|
||||
let index = if use_nonce_authority {
|
||||
authorized_signers.push(&nonce_authority);
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
// New nonce
|
||||
config_payer.signers = authorized_signers.clone();
|
||||
config_payer.command = CliCommand::NewNonce {
|
||||
nonce_account,
|
||||
nonce_authority: read_keypair_from_option(&authority_keypair_file),
|
||||
nonce_authority: index,
|
||||
};
|
||||
process_command(&config_payer).unwrap();
|
||||
|
||||
// Get nonce
|
||||
config_payer.signers = vec![&payer];
|
||||
config_payer.command = CliCommand::GetNonce(nonce_account);
|
||||
let third_nonce_string = process_command(&config_payer).unwrap();
|
||||
let third_nonce = third_nonce_string.parse::<Hash>().unwrap();
|
||||
@ -214,14 +176,15 @@ fn full_battery_tests(
|
||||
|
||||
// Withdraw from nonce account
|
||||
let payee_pubkey = Pubkey::new_rand();
|
||||
config_payer.signers = authorized_signers;
|
||||
config_payer.command = CliCommand::WithdrawFromNonceAccount {
|
||||
nonce_account,
|
||||
nonce_authority: read_keypair_from_option(&authority_keypair_file),
|
||||
nonce_authority: index,
|
||||
destination_account_pubkey: payee_pubkey,
|
||||
lamports: 100,
|
||||
};
|
||||
process_command(&config_payer).unwrap();
|
||||
check_balance(1000, &rpc_client, &config_payer.keypair.pubkey());
|
||||
check_balance(1000, &rpc_client, &config_payer.signers[0].pubkey());
|
||||
check_balance(900, &rpc_client, &nonce_account);
|
||||
check_balance(100, &rpc_client, &payee_pubkey);
|
||||
|
||||
@ -234,48 +197,37 @@ fn full_battery_tests(
|
||||
|
||||
// Set new authority
|
||||
let new_authority = Keypair::new();
|
||||
let (new_authority_keypair_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&new_authority, tmp_file.as_file_mut()).unwrap();
|
||||
config_payer.command = CliCommand::AuthorizeNonceAccount {
|
||||
nonce_account,
|
||||
nonce_authority: read_keypair_from_option(&authority_keypair_file),
|
||||
new_authority: read_keypair_file(&new_authority_keypair_file)
|
||||
.unwrap()
|
||||
.pubkey(),
|
||||
nonce_authority: index,
|
||||
new_authority: new_authority.pubkey(),
|
||||
};
|
||||
process_command(&config_payer).unwrap();
|
||||
|
||||
// Old authority fails now
|
||||
config_payer.command = CliCommand::NewNonce {
|
||||
nonce_account,
|
||||
nonce_authority: read_keypair_from_option(&authority_keypair_file),
|
||||
nonce_authority: index,
|
||||
};
|
||||
process_command(&config_payer).unwrap_err();
|
||||
|
||||
// New authority can advance nonce
|
||||
config_payer.signers = vec![&payer, &new_authority];
|
||||
config_payer.command = CliCommand::NewNonce {
|
||||
nonce_account,
|
||||
nonce_authority: Some(
|
||||
read_keypair_file(&new_authority_keypair_file)
|
||||
.unwrap()
|
||||
.into(),
|
||||
),
|
||||
nonce_authority: 1,
|
||||
};
|
||||
process_command(&config_payer).unwrap();
|
||||
|
||||
// New authority can withdraw from nonce account
|
||||
config_payer.command = CliCommand::WithdrawFromNonceAccount {
|
||||
nonce_account,
|
||||
nonce_authority: Some(
|
||||
read_keypair_file(&new_authority_keypair_file)
|
||||
.unwrap()
|
||||
.into(),
|
||||
),
|
||||
nonce_authority: 1,
|
||||
destination_account_pubkey: payee_pubkey,
|
||||
lamports: 100,
|
||||
};
|
||||
process_command(&config_payer).unwrap();
|
||||
check_balance(1000, &rpc_client, &config_payer.keypair.pubkey());
|
||||
check_balance(1000, &rpc_client, &config_payer.signers[0].pubkey());
|
||||
check_balance(800, &rpc_client, &nonce_account);
|
||||
check_balance(200, &rpc_client, &payee_pubkey);
|
||||
}
|
||||
|
114
cli/tests/pay.rs
114
cli/tests/pay.rs
@ -12,22 +12,12 @@ use solana_sdk::{
|
||||
fee_calculator::FeeCalculator,
|
||||
nonce_state::NonceState,
|
||||
pubkey::Pubkey,
|
||||
signature::{read_keypair_file, write_keypair, Keypair, Signer},
|
||||
signature::{Keypair, Signer},
|
||||
};
|
||||
use std::fs::remove_dir_all;
|
||||
use std::sync::mpsc::channel;
|
||||
use std::{fs::remove_dir_all, sync::mpsc::channel, thread::sleep, time::Duration};
|
||||
|
||||
#[cfg(test)]
|
||||
use solana_core::validator::new_validator_for_tests;
|
||||
use std::rc::Rc;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
fn make_tmp_file() -> (String, NamedTempFile) {
|
||||
let tmp_file = NamedTempFile::new().unwrap();
|
||||
(String::from(tmp_file.path().to_str().unwrap()), tmp_file)
|
||||
}
|
||||
|
||||
fn check_balance(expected_balance: u64, client: &RpcClient, pubkey: &Pubkey) {
|
||||
(0..5).for_each(|tries| {
|
||||
@ -52,32 +42,36 @@ fn test_cli_timestamp_tx() {
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer0 = Keypair::new();
|
||||
let default_signer1 = Keypair::new();
|
||||
|
||||
let mut config_payer = CliConfig::default();
|
||||
config_payer.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config_payer.signers = vec![&default_signer0];
|
||||
|
||||
let mut config_witness = CliConfig::default();
|
||||
config_witness.json_rpc_url = config_payer.json_rpc_url.clone();
|
||||
config_witness.signers = vec![&default_signer1];
|
||||
|
||||
assert_ne!(
|
||||
config_payer.keypair.pubkey(),
|
||||
config_witness.keypair.pubkey()
|
||||
config_payer.signers[0].pubkey(),
|
||||
config_witness.signers[0].pubkey()
|
||||
);
|
||||
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_payer.keypair.pubkey(),
|
||||
&config_payer.signers[0].pubkey(),
|
||||
50,
|
||||
)
|
||||
.unwrap();
|
||||
check_balance(50, &rpc_client, &config_payer.keypair.pubkey());
|
||||
check_balance(50, &rpc_client, &config_payer.signers[0].pubkey());
|
||||
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_witness.keypair.pubkey(),
|
||||
&config_witness.signers[0].pubkey(),
|
||||
1,
|
||||
)
|
||||
.unwrap();
|
||||
@ -89,7 +83,7 @@ fn test_cli_timestamp_tx() {
|
||||
lamports: 10,
|
||||
to: bob_pubkey,
|
||||
timestamp: Some(dt),
|
||||
timestamp_pubkey: Some(config_witness.keypair.pubkey()),
|
||||
timestamp_pubkey: Some(config_witness.signers[0].pubkey()),
|
||||
..PayCommand::default()
|
||||
});
|
||||
let sig_response = process_command(&config_payer);
|
||||
@ -101,7 +95,7 @@ fn test_cli_timestamp_tx() {
|
||||
.expect("base58-encoded public key");
|
||||
let process_id = Pubkey::new(&process_id_vec);
|
||||
|
||||
check_balance(40, &rpc_client, &config_payer.keypair.pubkey()); // config_payer balance
|
||||
check_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
|
||||
check_balance(10, &rpc_client, &process_id); // contract balance
|
||||
check_balance(0, &rpc_client, &bob_pubkey); // recipient balance
|
||||
|
||||
@ -109,7 +103,7 @@ fn test_cli_timestamp_tx() {
|
||||
config_witness.command = CliCommand::TimeElapsed(bob_pubkey, process_id, dt);
|
||||
process_command(&config_witness).unwrap();
|
||||
|
||||
check_balance(40, &rpc_client, &config_payer.keypair.pubkey()); // config_payer balance
|
||||
check_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
|
||||
check_balance(0, &rpc_client, &process_id); // contract balance
|
||||
check_balance(10, &rpc_client, &bob_pubkey); // recipient balance
|
||||
|
||||
@ -127,30 +121,34 @@ fn test_cli_witness_tx() {
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer0 = Keypair::new();
|
||||
let default_signer1 = Keypair::new();
|
||||
|
||||
let mut config_payer = CliConfig::default();
|
||||
config_payer.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config_payer.signers = vec![&default_signer0];
|
||||
|
||||
let mut config_witness = CliConfig::default();
|
||||
config_witness.json_rpc_url = config_payer.json_rpc_url.clone();
|
||||
config_witness.signers = vec![&default_signer1];
|
||||
|
||||
assert_ne!(
|
||||
config_payer.keypair.pubkey(),
|
||||
config_witness.keypair.pubkey()
|
||||
config_payer.signers[0].pubkey(),
|
||||
config_witness.signers[0].pubkey()
|
||||
);
|
||||
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_payer.keypair.pubkey(),
|
||||
&config_payer.signers[0].pubkey(),
|
||||
50,
|
||||
)
|
||||
.unwrap();
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_witness.keypair.pubkey(),
|
||||
&config_witness.signers[0].pubkey(),
|
||||
1,
|
||||
)
|
||||
.unwrap();
|
||||
@ -159,7 +157,7 @@ fn test_cli_witness_tx() {
|
||||
config_payer.command = CliCommand::Pay(PayCommand {
|
||||
lamports: 10,
|
||||
to: bob_pubkey,
|
||||
witnesses: Some(vec![config_witness.keypair.pubkey()]),
|
||||
witnesses: Some(vec![config_witness.signers[0].pubkey()]),
|
||||
..PayCommand::default()
|
||||
});
|
||||
let sig_response = process_command(&config_payer);
|
||||
@ -171,7 +169,7 @@ fn test_cli_witness_tx() {
|
||||
.expect("base58-encoded public key");
|
||||
let process_id = Pubkey::new(&process_id_vec);
|
||||
|
||||
check_balance(40, &rpc_client, &config_payer.keypair.pubkey()); // config_payer balance
|
||||
check_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
|
||||
check_balance(10, &rpc_client, &process_id); // contract balance
|
||||
check_balance(0, &rpc_client, &bob_pubkey); // recipient balance
|
||||
|
||||
@ -179,7 +177,7 @@ fn test_cli_witness_tx() {
|
||||
config_witness.command = CliCommand::Witness(bob_pubkey, process_id);
|
||||
process_command(&config_witness).unwrap();
|
||||
|
||||
check_balance(40, &rpc_client, &config_payer.keypair.pubkey()); // config_payer balance
|
||||
check_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
|
||||
check_balance(0, &rpc_client, &process_id); // contract balance
|
||||
check_balance(10, &rpc_client, &bob_pubkey); // recipient balance
|
||||
|
||||
@ -197,23 +195,27 @@ fn test_cli_cancel_tx() {
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer0 = Keypair::new();
|
||||
let default_signer1 = Keypair::new();
|
||||
|
||||
let mut config_payer = CliConfig::default();
|
||||
config_payer.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config_payer.signers = vec![&default_signer0];
|
||||
|
||||
let mut config_witness = CliConfig::default();
|
||||
config_witness.json_rpc_url = config_payer.json_rpc_url.clone();
|
||||
config_witness.signers = vec![&default_signer1];
|
||||
|
||||
assert_ne!(
|
||||
config_payer.keypair.pubkey(),
|
||||
config_witness.keypair.pubkey()
|
||||
config_payer.signers[0].pubkey(),
|
||||
config_witness.signers[0].pubkey()
|
||||
);
|
||||
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_payer.keypair.pubkey(),
|
||||
&config_payer.signers[0].pubkey(),
|
||||
50,
|
||||
)
|
||||
.unwrap();
|
||||
@ -222,7 +224,7 @@ fn test_cli_cancel_tx() {
|
||||
config_payer.command = CliCommand::Pay(PayCommand {
|
||||
lamports: 10,
|
||||
to: bob_pubkey,
|
||||
witnesses: Some(vec![config_witness.keypair.pubkey()]),
|
||||
witnesses: Some(vec![config_witness.signers[0].pubkey()]),
|
||||
cancelable: true,
|
||||
..PayCommand::default()
|
||||
});
|
||||
@ -235,7 +237,7 @@ fn test_cli_cancel_tx() {
|
||||
.expect("base58-encoded public key");
|
||||
let process_id = Pubkey::new(&process_id_vec);
|
||||
|
||||
check_balance(40, &rpc_client, &config_payer.keypair.pubkey()); // config_payer balance
|
||||
check_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
|
||||
check_balance(10, &rpc_client, &process_id); // contract balance
|
||||
check_balance(0, &rpc_client, &bob_pubkey); // recipient balance
|
||||
|
||||
@ -243,7 +245,7 @@ fn test_cli_cancel_tx() {
|
||||
config_payer.command = CliCommand::Cancel(process_id);
|
||||
process_command(&config_payer).unwrap();
|
||||
|
||||
check_balance(50, &rpc_client, &config_payer.keypair.pubkey()); // config_payer balance
|
||||
check_balance(50, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
|
||||
check_balance(0, &rpc_client, &process_id); // contract balance
|
||||
check_balance(0, &rpc_client, &bob_pubkey); // recipient balance
|
||||
|
||||
@ -261,22 +263,26 @@ fn test_offline_pay_tx() {
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer = Keypair::new();
|
||||
let default_offline_signer = Keypair::new();
|
||||
|
||||
let mut config_offline = CliConfig::default();
|
||||
config_offline.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config_offline.signers = vec![&default_offline_signer];
|
||||
let mut config_online = CliConfig::default();
|
||||
config_online.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config_online.signers = vec![&default_signer];
|
||||
assert_ne!(
|
||||
config_offline.keypair.pubkey(),
|
||||
config_online.keypair.pubkey()
|
||||
config_offline.signers[0].pubkey(),
|
||||
config_online.signers[0].pubkey()
|
||||
);
|
||||
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_offline.keypair.pubkey(),
|
||||
&config_offline.signers[0].pubkey(),
|
||||
50,
|
||||
)
|
||||
.unwrap();
|
||||
@ -284,12 +290,12 @@ fn test_offline_pay_tx() {
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_online.keypair.pubkey(),
|
||||
&config_online.signers[0].pubkey(),
|
||||
50,
|
||||
)
|
||||
.unwrap();
|
||||
check_balance(50, &rpc_client, &config_offline.keypair.pubkey());
|
||||
check_balance(50, &rpc_client, &config_online.keypair.pubkey());
|
||||
check_balance(50, &rpc_client, &config_offline.signers[0].pubkey());
|
||||
check_balance(50, &rpc_client, &config_online.signers[0].pubkey());
|
||||
|
||||
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
|
||||
config_offline.command = CliCommand::Pay(PayCommand {
|
||||
@ -301,15 +307,15 @@ fn test_offline_pay_tx() {
|
||||
});
|
||||
let sig_response = process_command(&config_offline).unwrap();
|
||||
|
||||
check_balance(50, &rpc_client, &config_offline.keypair.pubkey());
|
||||
check_balance(50, &rpc_client, &config_online.keypair.pubkey());
|
||||
check_balance(50, &rpc_client, &config_offline.signers[0].pubkey());
|
||||
check_balance(50, &rpc_client, &config_online.signers[0].pubkey());
|
||||
check_balance(0, &rpc_client, &bob_pubkey);
|
||||
|
||||
let (blockhash, signers) = parse_sign_only_reply_string(&sig_response);
|
||||
let offline_presigner =
|
||||
presigner_from_pubkey_sigs(&config_offline.keypair.pubkey(), &signers).unwrap();
|
||||
let online_pubkey = config_online.keypair.pubkey();
|
||||
config_online.keypair = offline_presigner.into();
|
||||
presigner_from_pubkey_sigs(&config_offline.signers[0].pubkey(), &signers).unwrap();
|
||||
let online_pubkey = config_online.signers[0].pubkey();
|
||||
config_online.signers = vec![&offline_presigner];
|
||||
config_online.command = CliCommand::Pay(PayCommand {
|
||||
lamports: 10,
|
||||
to: bob_pubkey,
|
||||
@ -318,7 +324,7 @@ fn test_offline_pay_tx() {
|
||||
});
|
||||
process_command(&config_online).unwrap();
|
||||
|
||||
check_balance(40, &rpc_client, &config_offline.keypair.pubkey());
|
||||
check_balance(40, &rpc_client, &config_offline.signers[0].pubkey());
|
||||
check_balance(50, &rpc_client, &online_pubkey);
|
||||
check_balance(10, &rpc_client, &bob_pubkey);
|
||||
|
||||
@ -336,9 +342,11 @@ fn test_nonced_pay_tx() {
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer = Keypair::new();
|
||||
|
||||
let mut config = CliConfig::default();
|
||||
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config.signers = vec![&default_signer];
|
||||
|
||||
let minimum_nonce_balance = rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(NonceState::size())
|
||||
@ -347,29 +355,28 @@ fn test_nonced_pay_tx() {
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config.keypair.pubkey(),
|
||||
&config.signers[0].pubkey(),
|
||||
50 + minimum_nonce_balance,
|
||||
)
|
||||
.unwrap();
|
||||
check_balance(
|
||||
50 + minimum_nonce_balance,
|
||||
&rpc_client,
|
||||
&config.keypair.pubkey(),
|
||||
&config.signers[0].pubkey(),
|
||||
);
|
||||
|
||||
// Create nonce account
|
||||
let nonce_account = Keypair::new();
|
||||
let (nonce_keypair_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&nonce_account, tmp_file.as_file_mut()).unwrap();
|
||||
config.command = CliCommand::CreateNonceAccount {
|
||||
nonce_account: Rc::new(read_keypair_file(&nonce_keypair_file).unwrap().into()),
|
||||
nonce_account: 1,
|
||||
seed: None,
|
||||
nonce_authority: Some(config.keypair.pubkey()),
|
||||
nonce_authority: Some(config.signers[0].pubkey()),
|
||||
lamports: minimum_nonce_balance,
|
||||
};
|
||||
config.signers.push(&nonce_account);
|
||||
process_command(&config).unwrap();
|
||||
|
||||
check_balance(50, &rpc_client, &config.keypair.pubkey());
|
||||
check_balance(50, &rpc_client, &config.signers[0].pubkey());
|
||||
check_balance(minimum_nonce_balance, &rpc_client, &nonce_account.pubkey());
|
||||
|
||||
// Fetch nonce hash
|
||||
@ -381,6 +388,7 @@ fn test_nonced_pay_tx() {
|
||||
};
|
||||
|
||||
let bob_pubkey = Pubkey::new_rand();
|
||||
config.signers = vec![&default_signer];
|
||||
config.command = CliCommand::Pay(PayCommand {
|
||||
lamports: 10,
|
||||
to: bob_pubkey,
|
||||
@ -390,7 +398,7 @@ fn test_nonced_pay_tx() {
|
||||
});
|
||||
process_command(&config).expect("failed to process pay command");
|
||||
|
||||
check_balance(40, &rpc_client, &config.keypair.pubkey());
|
||||
check_balance(40, &rpc_client, &config.signers[0].pubkey());
|
||||
check_balance(10, &rpc_client, &bob_pubkey);
|
||||
|
||||
// Verify that nonce has been used
|
||||
|
@ -2,8 +2,8 @@ use solana_cli::cli::{process_command, CliCommand, CliConfig};
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_core::validator::new_validator_for_tests;
|
||||
use solana_faucet::faucet::run_local_faucet;
|
||||
use std::fs::remove_dir_all;
|
||||
use std::sync::mpsc::channel;
|
||||
use solana_sdk::signature::Keypair;
|
||||
use std::{fs::remove_dir_all, sync::mpsc::channel};
|
||||
|
||||
#[test]
|
||||
fn test_cli_request_airdrop() {
|
||||
@ -20,6 +20,8 @@ fn test_cli_request_airdrop() {
|
||||
pubkey: None,
|
||||
lamports: 50,
|
||||
};
|
||||
let keypair = Keypair::new();
|
||||
bob_config.signers = vec![&keypair];
|
||||
|
||||
let sig_response = process_command(&bob_config);
|
||||
sig_response.unwrap();
|
||||
@ -27,7 +29,7 @@ fn test_cli_request_airdrop() {
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
|
||||
let balance = rpc_client
|
||||
.retry_get_balance(&bob_config.keypair.pubkey(), 1)
|
||||
.retry_get_balance(&bob_config.signers[0].pubkey(), 1)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(balance, 50);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -10,22 +10,12 @@ use solana_sdk::{
|
||||
fee_calculator::FeeCalculator,
|
||||
nonce_state::NonceState,
|
||||
pubkey::Pubkey,
|
||||
signature::{keypair_from_seed, read_keypair_file, write_keypair, Signer},
|
||||
signature::{keypair_from_seed, Keypair, Signer},
|
||||
};
|
||||
use std::fs::remove_dir_all;
|
||||
use std::sync::mpsc::channel;
|
||||
use std::{fs::remove_dir_all, sync::mpsc::channel, thread::sleep, time::Duration};
|
||||
|
||||
#[cfg(test)]
|
||||
use solana_core::validator::new_validator_for_tests_ex;
|
||||
use std::rc::Rc;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
fn make_tmp_file() -> (String, NamedTempFile) {
|
||||
let tmp_file = NamedTempFile::new().unwrap();
|
||||
(String::from(tmp_file.path().to_str().unwrap()), tmp_file)
|
||||
}
|
||||
|
||||
fn check_balance(expected_balance: u64, client: &RpcClient, pubkey: &Pubkey) {
|
||||
(0..5).for_each(|tries| {
|
||||
@ -50,13 +40,15 @@ fn test_transfer() {
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
|
||||
let default_signer = Keypair::new();
|
||||
let default_offline_signer = Keypair::new();
|
||||
|
||||
let mut config = CliConfig::default();
|
||||
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config.signers = vec![&default_signer];
|
||||
|
||||
let sender_pubkey = config.keypair.pubkey();
|
||||
let sender_pubkey = config.signers[0].pubkey();
|
||||
let recipient_pubkey = Pubkey::new(&[1u8; 32]);
|
||||
println!("sender: {:?}", sender_pubkey);
|
||||
println!("recipient: {:?}", recipient_pubkey);
|
||||
|
||||
request_and_confirm_airdrop(&rpc_client, &faucet_addr, &sender_pubkey, 50_000).unwrap();
|
||||
check_balance(50_000, &rpc_client, &sender_pubkey);
|
||||
@ -66,12 +58,12 @@ fn test_transfer() {
|
||||
config.command = CliCommand::Transfer {
|
||||
lamports: 10,
|
||||
to: recipient_pubkey,
|
||||
from: None,
|
||||
from: 0,
|
||||
sign_only: false,
|
||||
blockhash_query: BlockhashQuery::All,
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
fee_payer: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
check_balance(49_989, &rpc_client, &sender_pubkey);
|
||||
@ -79,12 +71,12 @@ fn test_transfer() {
|
||||
|
||||
let mut offline = CliConfig::default();
|
||||
offline.json_rpc_url = String::default();
|
||||
offline.signers = vec![&default_offline_signer];
|
||||
// Verify we cannot contact the cluster
|
||||
offline.command = CliCommand::ClusterVersion;
|
||||
process_command(&offline).unwrap_err();
|
||||
|
||||
let offline_pubkey = offline.keypair.pubkey();
|
||||
println!("offline: {:?}", offline_pubkey);
|
||||
let offline_pubkey = offline.signers[0].pubkey();
|
||||
request_and_confirm_airdrop(&rpc_client, &faucet_addr, &offline_pubkey, 50).unwrap();
|
||||
check_balance(50, &rpc_client, &offline_pubkey);
|
||||
|
||||
@ -93,25 +85,26 @@ fn test_transfer() {
|
||||
offline.command = CliCommand::Transfer {
|
||||
lamports: 10,
|
||||
to: recipient_pubkey,
|
||||
from: None,
|
||||
from: 0,
|
||||
sign_only: true,
|
||||
blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
fee_payer: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
};
|
||||
let sign_only_reply = process_command(&offline).unwrap();
|
||||
let (blockhash, signers) = parse_sign_only_reply_string(&sign_only_reply);
|
||||
let offline_presigner = presigner_from_pubkey_sigs(&offline_pubkey, &signers).unwrap();
|
||||
config.signers = vec![&offline_presigner];
|
||||
config.command = CliCommand::Transfer {
|
||||
lamports: 10,
|
||||
to: recipient_pubkey,
|
||||
from: Some(offline_presigner.clone().into()),
|
||||
from: 0,
|
||||
sign_only: false,
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
fee_payer: Some(offline_presigner.clone().into()),
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
check_balance(39, &rpc_client, &offline_pubkey);
|
||||
@ -119,13 +112,12 @@ fn test_transfer() {
|
||||
|
||||
// Create nonce account
|
||||
let nonce_account = keypair_from_seed(&[3u8; 32]).unwrap();
|
||||
let (nonce_account_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&nonce_account, tmp_file.as_file_mut()).unwrap();
|
||||
let minimum_nonce_balance = rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(NonceState::size())
|
||||
.unwrap();
|
||||
config.signers = vec![&default_signer, &nonce_account];
|
||||
config.command = CliCommand::CreateNonceAccount {
|
||||
nonce_account: Rc::new(read_keypair_file(&nonce_account_file).unwrap().into()),
|
||||
nonce_account: 1,
|
||||
seed: None,
|
||||
nonce_authority: None,
|
||||
lamports: minimum_nonce_balance,
|
||||
@ -142,15 +134,16 @@ fn test_transfer() {
|
||||
};
|
||||
|
||||
// Nonced transfer
|
||||
config.signers = vec![&default_signer];
|
||||
config.command = CliCommand::Transfer {
|
||||
lamports: 10,
|
||||
to: recipient_pubkey,
|
||||
from: None,
|
||||
from: 0,
|
||||
sign_only: false,
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(nonce_hash),
|
||||
nonce_account: Some(nonce_account.pubkey()),
|
||||
nonce_authority: None,
|
||||
fee_payer: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
check_balance(49_976 - minimum_nonce_balance, &rpc_client, &sender_pubkey);
|
||||
@ -164,9 +157,10 @@ fn test_transfer() {
|
||||
assert_ne!(nonce_hash, new_nonce_hash);
|
||||
|
||||
// Assign nonce authority to offline
|
||||
config.signers = vec![&default_signer];
|
||||
config.command = CliCommand::AuthorizeNonceAccount {
|
||||
nonce_account: nonce_account.pubkey(),
|
||||
nonce_authority: None,
|
||||
nonce_authority: 0,
|
||||
new_authority: offline_pubkey,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
@ -181,28 +175,30 @@ fn test_transfer() {
|
||||
};
|
||||
|
||||
// Offline, nonced transfer
|
||||
offline.signers = vec![&default_offline_signer];
|
||||
offline.command = CliCommand::Transfer {
|
||||
lamports: 10,
|
||||
to: recipient_pubkey,
|
||||
from: None,
|
||||
from: 0,
|
||||
sign_only: true,
|
||||
blockhash_query: BlockhashQuery::None(nonce_hash, FeeCalculator::default()),
|
||||
nonce_account: Some(nonce_account.pubkey()),
|
||||
nonce_authority: None,
|
||||
fee_payer: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
};
|
||||
let sign_only_reply = process_command(&offline).unwrap();
|
||||
let (blockhash, signers) = parse_sign_only_reply_string(&sign_only_reply);
|
||||
let offline_presigner = presigner_from_pubkey_sigs(&offline_pubkey, &signers).unwrap();
|
||||
config.signers = vec![&offline_presigner];
|
||||
config.command = CliCommand::Transfer {
|
||||
lamports: 10,
|
||||
to: recipient_pubkey,
|
||||
from: Some(offline_presigner.clone().into()),
|
||||
from: 0,
|
||||
sign_only: false,
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: Some(nonce_account.pubkey()),
|
||||
nonce_authority: Some(offline_presigner.clone().into()),
|
||||
fee_payer: Some(offline_presigner.clone().into()),
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
check_balance(28, &rpc_client, &offline_pubkey);
|
||||
|
Reference in New Issue
Block a user