CLI: Add hidden support for `SystemInstruction::TransferWithSeed`

This commit is contained in:
Trent Nelson 2021-02-18 00:08:12 -07:00 committed by mergify[bot]
parent 16e0a4b412
commit 700685c223
4 changed files with 185 additions and 2 deletions

View File

@ -355,6 +355,8 @@ pub enum CliCommand {
nonce_account: Option<Pubkey>,
nonce_authority: SignerIndex,
fee_payer: SignerIndex,
derived_address_seed: Option<String>,
derived_address_program_id: Option<Pubkey>,
},
}
@ -858,6 +860,12 @@ pub fn parse_command(
let signer_info =
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
let derived_address_seed = matches
.value_of("derived_address_seed")
.map(|s| s.to_string());
let derived_address_program_id =
resolve_derived_address_program_id(matches, "derived_address_program_id");
Ok(CliCommandInfo {
command: CliCommand::Transfer {
amount,
@ -869,6 +877,8 @@ pub fn parse_command(
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
from: signer_info.index_of(from_pubkey).unwrap(),
derived_address_seed,
derived_address_program_id,
},
signers: signer_info.signers,
})
@ -1106,8 +1116,11 @@ fn process_transfer(
nonce_account: Option<&Pubkey>,
nonce_authority: SignerIndex,
fee_payer: SignerIndex,
derived_address_seed: Option<String>,
derived_address_program_id: Option<&Pubkey>,
) -> ProcessResult {
let from = config.signers[from];
let mut from_pubkey = from.pubkey();
let (recent_blockhash, fee_calculator) =
blockhash_query.get_blockhash_and_fee_calculator(rpc_client, config.commitment)?;
@ -1115,8 +1128,28 @@ fn process_transfer(
let nonce_authority = config.signers[nonce_authority];
let fee_payer = config.signers[fee_payer];
let derived_parts = derived_address_seed.zip(derived_address_program_id);
let with_seed = if let Some((seed, program_id)) = derived_parts {
let base_pubkey = from_pubkey;
from_pubkey = Pubkey::create_with_seed(&base_pubkey, &seed, program_id)?;
Some((base_pubkey, seed, program_id, from_pubkey))
} else {
None
};
let build_message = |lamports| {
let ixs = vec![system_instruction::transfer(&from.pubkey(), to, lamports)];
let ixs = if let Some((base_pubkey, seed, program_id, from_pubkey)) = with_seed.as_ref() {
vec![system_instruction::transfer_with_seed(
from_pubkey,
base_pubkey,
seed.clone(),
program_id,
to,
lamports,
)]
} else {
vec![system_instruction::transfer(&from_pubkey, to, lamports)]
};
if let Some(nonce_account) = &nonce_account {
Message::new_with_nonce(
@ -1135,7 +1168,7 @@ fn process_transfer(
sign_only,
amount,
&fee_calculator,
&from.pubkey(),
&from_pubkey,
&fee_payer.pubkey(),
build_message,
config.commitment,
@ -1741,6 +1774,8 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
ref nonce_account,
nonce_authority,
fee_payer,
derived_address_seed,
ref derived_address_program_id,
} => process_transfer(
&rpc_client,
config,
@ -1753,6 +1788,8 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
nonce_account.as_ref(),
*nonce_authority,
*fee_payer,
derived_address_seed.clone(),
derived_address_program_id.as_ref(),
),
}
}
@ -2086,6 +2123,23 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
.takes_value(false)
.help("Return signature immediately after submitting the transaction, instead of waiting for confirmations"),
)
.arg(
Arg::with_name("derived_address_seed")
.long("derived-address-seed")
.takes_value(true)
.value_name("SEED_STRING")
.requires("derived_address_program_id")
.validator(is_derived_address_seed)
.hidden(true)
)
.arg(
Arg::with_name("derived_address_program_id")
.long("derived-address-program-id")
.takes_value(true)
.value_name("PROGRAM_ID")
.requires("derived_address_seed")
.hidden(true)
)
.offline_args()
.nonce_args(false)
.arg(fee_payer_arg()),
@ -2787,6 +2841,8 @@ mod tests {
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
},
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
}
@ -2809,6 +2865,8 @@ mod tests {
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
},
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
}
@ -2835,6 +2893,8 @@ mod tests {
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
},
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
}
@ -2865,6 +2925,8 @@ mod tests {
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
},
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
}
@ -2903,6 +2965,8 @@ mod tests {
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
},
signers: vec![Presigner::new(&from_pubkey, &from_sig).into()],
}
@ -2942,6 +3006,8 @@ mod tests {
nonce_account: Some(nonce_address),
nonce_authority: 1,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
},
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),
@ -2949,5 +3015,38 @@ mod tests {
],
}
);
//Test Transfer Subcommand, with seed
let derived_address_seed = "seed".to_string();
let derived_address_program_id = "STAKE";
let test_transfer = test_commands.clone().get_matches_from(vec![
"test",
"transfer",
&to_string,
"42",
"--derived-address-seed",
&derived_address_seed,
"--derived-address-program-id",
derived_address_program_id,
]);
assert_eq!(
parse_command(&test_transfer, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Transfer {
amount: SpendAmount::Some(42_000_000_000),
to: to_pubkey,
from: 0,
sign_only: false,
no_wait: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: Some(derived_address_seed),
derived_address_program_id: Some(solana_stake_program::id()),
},
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into(),],
}
);
}
}

View File

@ -298,6 +298,8 @@ fn test_create_account_with_seed() {
nonce_account: Some(nonce_address),
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
authority_config.output_format = OutputFormat::JsonCompact;
let sign_only_reply = process_command(&authority_config).unwrap();
@ -322,6 +324,8 @@ fn test_create_account_with_seed() {
nonce_account: Some(nonce_address),
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
process_command(&submit_config).unwrap();
check_recent_balance(241, &rpc_client, &nonce_address);

View File

@ -56,6 +56,8 @@ fn test_transfer() {
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
process_command(&config).unwrap();
check_recent_balance(49_989, &rpc_client, &sender_pubkey);
@ -72,6 +74,8 @@ fn test_transfer() {
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
assert!(process_command(&config).is_err());
check_recent_balance(49_989, &rpc_client, &sender_pubkey);
@ -100,6 +104,8 @@ fn test_transfer() {
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
offline.output_format = OutputFormat::JsonCompact;
let sign_only_reply = process_command(&offline).unwrap();
@ -117,6 +123,8 @@ fn test_transfer() {
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
process_command(&config).unwrap();
check_recent_balance(39, &rpc_client, &offline_pubkey);
@ -162,6 +170,8 @@ fn test_transfer() {
nonce_account: Some(nonce_account.pubkey()),
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
process_command(&config).unwrap();
check_recent_balance(49_976 - minimum_nonce_balance, &rpc_client, &sender_pubkey);
@ -208,6 +218,8 @@ fn test_transfer() {
nonce_account: Some(nonce_account.pubkey()),
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
let sign_only_reply = process_command(&offline).unwrap();
let sign_only = parse_sign_only_reply_string(&sign_only_reply);
@ -227,6 +239,8 @@ fn test_transfer() {
nonce_account: Some(nonce_account.pubkey()),
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
process_command(&config).unwrap();
check_recent_balance(28, &rpc_client, &offline_pubkey);
@ -290,6 +304,8 @@ fn test_transfer_multisession_signing() {
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
fee_payer_config.output_format = OutputFormat::JsonCompact;
let sign_only_reply = process_command(&fee_payer_config).unwrap();
@ -316,6 +332,8 @@ fn test_transfer_multisession_signing() {
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
from_config.output_format = OutputFormat::JsonCompact;
let sign_only_reply = process_command(&from_config).unwrap();
@ -339,6 +357,8 @@ fn test_transfer_multisession_signing() {
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
process_command(&config).unwrap();
@ -384,8 +404,66 @@ fn test_transfer_all() {
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
process_command(&config).unwrap();
check_recent_balance(0, &rpc_client, &sender_pubkey);
check_recent_balance(49_999, &rpc_client, &recipient_pubkey);
}
#[test]
fn test_transfer_with_seed() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let test_validator = TestValidator::with_custom_fees(mint_keypair.pubkey(), 1);
let faucet_addr = run_local_faucet(mint_keypair, None);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
let default_signer = Keypair::new();
let mut config = CliConfig::recent_for_tests();
config.json_rpc_url = test_validator.rpc_url();
config.signers = vec![&default_signer];
let sender_pubkey = config.signers[0].pubkey();
let recipient_pubkey = Pubkey::new(&[1u8; 32]);
let derived_address_seed = "seed".to_string();
let derived_address_program_id = solana_stake_program::id();
let derived_address = Pubkey::create_with_seed(
&sender_pubkey,
&derived_address_seed,
&derived_address_program_id,
)
.unwrap();
request_and_confirm_airdrop(&rpc_client, &faucet_addr, &sender_pubkey, 1, &config).unwrap();
request_and_confirm_airdrop(&rpc_client, &faucet_addr, &derived_address, 50_000, &config)
.unwrap();
check_recent_balance(1, &rpc_client, &sender_pubkey);
check_recent_balance(50_000, &rpc_client, &derived_address);
check_recent_balance(0, &rpc_client, &recipient_pubkey);
check_ready(&rpc_client);
// Transfer with seed
config.command = CliCommand::Transfer {
amount: SpendAmount::Some(50_000),
to: recipient_pubkey,
from: 0,
sign_only: false,
no_wait: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: Some(derived_address_seed),
derived_address_program_id: Some(derived_address_program_id),
};
process_command(&config).unwrap();
check_recent_balance(0, &rpc_client, &sender_pubkey);
check_recent_balance(50_000, &rpc_client, &recipient_pubkey);
check_recent_balance(0, &rpc_client, &derived_address);
}

View File

@ -76,6 +76,8 @@ fn test_vote_authorize_and_withdraw() {
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
};
process_command(&config).unwrap();
let expected_balance = expected_balance + 1_000;