Add deploy err if program-account balance is too high (#13091)
* Add deploy err if program-account balance is too high * Review comments * Add system-program check * Rename and unhide flag
This commit is contained in:
parent
368aeb2cee
commit
4669fa0f98
|
@ -49,6 +49,7 @@ use solana_sdk::{
|
|||
instruction::{Instruction, InstructionError},
|
||||
loader_instruction,
|
||||
message::Message,
|
||||
native_token::Sol,
|
||||
pubkey::{Pubkey, MAX_SEED_LEN},
|
||||
signature::{keypair_from_seed, Keypair, Signature, Signer, SignerError},
|
||||
signers::Signers,
|
||||
|
@ -178,6 +179,7 @@ pub enum CliCommand {
|
|||
program_location: String,
|
||||
address: Option<SignerIndex>,
|
||||
use_deprecated_loader: bool,
|
||||
allow_excessive_balance: bool,
|
||||
},
|
||||
// Stake Commands
|
||||
CreateStakeAccount {
|
||||
|
@ -609,13 +611,13 @@ pub fn parse_command(
|
|||
signers.push(signer);
|
||||
1
|
||||
});
|
||||
let use_deprecated_loader = matches.is_present("use_deprecated_loader");
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::Deploy {
|
||||
program_location: matches.value_of("program_location").unwrap().to_string(),
|
||||
address,
|
||||
use_deprecated_loader,
|
||||
use_deprecated_loader: matches.is_present("use_deprecated_loader"),
|
||||
allow_excessive_balance: matches.is_present("allow_excessive_balance"),
|
||||
},
|
||||
signers,
|
||||
})
|
||||
|
@ -1132,6 +1134,7 @@ fn process_deploy(
|
|||
program_location: &str,
|
||||
address: Option<SignerIndex>,
|
||||
use_deprecated_loader: bool,
|
||||
allow_excessive_balance: bool,
|
||||
) -> ProcessResult {
|
||||
const WORDS: usize = 12;
|
||||
// Create ephemeral keypair to use for program address, if not provided
|
||||
|
@ -1145,6 +1148,7 @@ fn process_deploy(
|
|||
program_location,
|
||||
address,
|
||||
use_deprecated_loader,
|
||||
allow_excessive_balance,
|
||||
new_keypair,
|
||||
);
|
||||
|
||||
|
@ -1160,7 +1164,7 @@ fn process_deploy(
|
|||
WORDS
|
||||
);
|
||||
eprintln!(
|
||||
"then pass it as the [ADDRESS_SIGNER] argument to `solana deploy ...`\n{}\n{}\n{}",
|
||||
"then pass it as the [PROGRAM_ADDRESS_SIGNER] argument to `solana deploy ...`\n{}\n{}\n{}",
|
||||
divider, phrase, divider
|
||||
);
|
||||
}
|
||||
|
@ -1173,6 +1177,7 @@ fn do_process_deploy(
|
|||
program_location: &str,
|
||||
address: Option<SignerIndex>,
|
||||
use_deprecated_loader: bool,
|
||||
allow_excessive_balance: bool,
|
||||
new_keypair: Keypair,
|
||||
) -> ProcessResult {
|
||||
let program_id = if let Some(i) = address {
|
||||
|
@ -1237,6 +1242,15 @@ fn do_process_deploy(
|
|||
balance,
|
||||
));
|
||||
balance_needed = balance;
|
||||
} else if account.lamports > minimum_balance
|
||||
&& system_program::check_id(&account.owner)
|
||||
&& !allow_excessive_balance
|
||||
{
|
||||
return Err(CliError::DynamicProgramError(format!(
|
||||
"Program account has a balance: {:?}; it may already be in use",
|
||||
Sol(account.lamports)
|
||||
))
|
||||
.into());
|
||||
}
|
||||
(instructions, balance_needed)
|
||||
} else {
|
||||
|
@ -1619,12 +1633,14 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
|||
program_location,
|
||||
address,
|
||||
use_deprecated_loader,
|
||||
allow_excessive_balance,
|
||||
} => process_deploy(
|
||||
&rpc_client,
|
||||
config,
|
||||
program_location,
|
||||
*address,
|
||||
*use_deprecated_loader,
|
||||
*allow_excessive_balance,
|
||||
),
|
||||
|
||||
// Stake Commands
|
||||
|
@ -2241,7 +2257,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||
.arg(
|
||||
Arg::with_name("address_signer")
|
||||
.index(2)
|
||||
.value_name("ADDRESS_SIGNER")
|
||||
.value_name("PROGRAM_ADDRESS_SIGNER")
|
||||
.takes_value(true)
|
||||
.validator(is_valid_signer)
|
||||
.help("The signer for the desired address of the program [default: new random address]")
|
||||
|
@ -2253,6 +2269,12 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||
.hidden(true) // Don't document this argument to discourage its use
|
||||
.help("Use the deprecated BPF loader")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("allow_excessive_balance")
|
||||
.long("allow-excessive-deploy-account-balance")
|
||||
.takes_value(false)
|
||||
.help("Use the designated program id, even if the account already holds a large balance of SOL")
|
||||
)
|
||||
.arg(commitment_arg_with_default("max")),
|
||||
)
|
||||
.subcommand(
|
||||
|
@ -2621,6 +2643,7 @@ mod tests {
|
|||
program_location: "/Users/test/program.o".to_string(),
|
||||
address: None,
|
||||
use_deprecated_loader: false,
|
||||
allow_excessive_balance: false,
|
||||
},
|
||||
signers: vec![read_keypair_file(&keypair_file).unwrap().into()],
|
||||
}
|
||||
|
@ -2642,6 +2665,7 @@ mod tests {
|
|||
program_location: "/Users/test/program.o".to_string(),
|
||||
address: Some(1),
|
||||
use_deprecated_loader: false,
|
||||
allow_excessive_balance: false,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&keypair_file).unwrap().into(),
|
||||
|
@ -2955,6 +2979,7 @@ mod tests {
|
|||
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||
address: None,
|
||||
use_deprecated_loader: false,
|
||||
allow_excessive_balance: false,
|
||||
};
|
||||
let result = process_command(&config);
|
||||
let json: Value = serde_json::from_str(&result.unwrap()).unwrap();
|
||||
|
@ -2973,6 +2998,7 @@ mod tests {
|
|||
program_location: "bad/file/location.so".to_string(),
|
||||
address: None,
|
||||
use_deprecated_loader: false,
|
||||
allow_excessive_balance: false,
|
||||
};
|
||||
assert!(process_command(&config).is_err());
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ fn test_cli_deploy_program() {
|
|||
faucet_host: None,
|
||||
faucet_port: faucet_addr.port(),
|
||||
pubkey: None,
|
||||
lamports: 3 * minimum_balance_for_rent_exemption, // min balance for rent exemption for two programs + leftover for tx processing
|
||||
lamports: 4 * minimum_balance_for_rent_exemption, // min balance for rent exemption for three programs + leftover for tx processing
|
||||
};
|
||||
config.signers = vec![&keypair];
|
||||
process_command(&config).unwrap();
|
||||
|
@ -64,6 +64,7 @@ fn test_cli_deploy_program() {
|
|||
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||
address: None,
|
||||
use_deprecated_loader: false,
|
||||
allow_excessive_balance: false,
|
||||
};
|
||||
|
||||
let response = process_command(&config);
|
||||
|
@ -98,6 +99,7 @@ fn test_cli_deploy_program() {
|
|||
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||
address: Some(1),
|
||||
use_deprecated_loader: false,
|
||||
allow_excessive_balance: false,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let account1 = rpc_client
|
||||
|
@ -113,6 +115,44 @@ fn test_cli_deploy_program() {
|
|||
// Attempt to redeploy to the same address
|
||||
process_command(&config).unwrap_err();
|
||||
|
||||
// Attempt to deploy to account with excess balance
|
||||
let custom_address_keypair = Keypair::new();
|
||||
config.command = CliCommand::Airdrop {
|
||||
faucet_host: None,
|
||||
faucet_port: faucet_addr.port(),
|
||||
pubkey: None,
|
||||
lamports: 2 * minimum_balance_for_rent_exemption, // Anything over minimum_balance_for_rent_exemption should trigger err
|
||||
};
|
||||
config.signers = vec![&custom_address_keypair];
|
||||
process_command(&config).unwrap();
|
||||
|
||||
config.signers = vec![&keypair, &custom_address_keypair];
|
||||
config.command = CliCommand::Deploy {
|
||||
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||
address: Some(1),
|
||||
use_deprecated_loader: false,
|
||||
allow_excessive_balance: false,
|
||||
};
|
||||
process_command(&config).unwrap_err();
|
||||
|
||||
// Use forcing parameter to deploy to account with excess balance
|
||||
config.command = CliCommand::Deploy {
|
||||
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||
address: Some(1),
|
||||
use_deprecated_loader: false,
|
||||
allow_excessive_balance: true,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let account2 = rpc_client
|
||||
.get_account_with_commitment(&custom_address_keypair.pubkey(), CommitmentConfig::recent())
|
||||
.unwrap()
|
||||
.value
|
||||
.unwrap();
|
||||
assert_eq!(account2.lamports, 2 * minimum_balance_for_rent_exemption);
|
||||
assert_eq!(account2.owner, bpf_loader::id());
|
||||
assert_eq!(account2.executable, true);
|
||||
assert_eq!(account0.data, account2.data);
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue