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},
|
instruction::{Instruction, InstructionError},
|
||||||
loader_instruction,
|
loader_instruction,
|
||||||
message::Message,
|
message::Message,
|
||||||
|
native_token::Sol,
|
||||||
pubkey::{Pubkey, MAX_SEED_LEN},
|
pubkey::{Pubkey, MAX_SEED_LEN},
|
||||||
signature::{keypair_from_seed, Keypair, Signature, Signer, SignerError},
|
signature::{keypair_from_seed, Keypair, Signature, Signer, SignerError},
|
||||||
signers::Signers,
|
signers::Signers,
|
||||||
|
@ -178,6 +179,7 @@ pub enum CliCommand {
|
||||||
program_location: String,
|
program_location: String,
|
||||||
address: Option<SignerIndex>,
|
address: Option<SignerIndex>,
|
||||||
use_deprecated_loader: bool,
|
use_deprecated_loader: bool,
|
||||||
|
allow_excessive_balance: bool,
|
||||||
},
|
},
|
||||||
// Stake Commands
|
// Stake Commands
|
||||||
CreateStakeAccount {
|
CreateStakeAccount {
|
||||||
|
@ -609,13 +611,13 @@ pub fn parse_command(
|
||||||
signers.push(signer);
|
signers.push(signer);
|
||||||
1
|
1
|
||||||
});
|
});
|
||||||
let use_deprecated_loader = matches.is_present("use_deprecated_loader");
|
|
||||||
|
|
||||||
Ok(CliCommandInfo {
|
Ok(CliCommandInfo {
|
||||||
command: CliCommand::Deploy {
|
command: CliCommand::Deploy {
|
||||||
program_location: matches.value_of("program_location").unwrap().to_string(),
|
program_location: matches.value_of("program_location").unwrap().to_string(),
|
||||||
address,
|
address,
|
||||||
use_deprecated_loader,
|
use_deprecated_loader: matches.is_present("use_deprecated_loader"),
|
||||||
|
allow_excessive_balance: matches.is_present("allow_excessive_balance"),
|
||||||
},
|
},
|
||||||
signers,
|
signers,
|
||||||
})
|
})
|
||||||
|
@ -1132,6 +1134,7 @@ fn process_deploy(
|
||||||
program_location: &str,
|
program_location: &str,
|
||||||
address: Option<SignerIndex>,
|
address: Option<SignerIndex>,
|
||||||
use_deprecated_loader: bool,
|
use_deprecated_loader: bool,
|
||||||
|
allow_excessive_balance: bool,
|
||||||
) -> ProcessResult {
|
) -> ProcessResult {
|
||||||
const WORDS: usize = 12;
|
const WORDS: usize = 12;
|
||||||
// Create ephemeral keypair to use for program address, if not provided
|
// Create ephemeral keypair to use for program address, if not provided
|
||||||
|
@ -1145,6 +1148,7 @@ fn process_deploy(
|
||||||
program_location,
|
program_location,
|
||||||
address,
|
address,
|
||||||
use_deprecated_loader,
|
use_deprecated_loader,
|
||||||
|
allow_excessive_balance,
|
||||||
new_keypair,
|
new_keypair,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1160,7 +1164,7 @@ fn process_deploy(
|
||||||
WORDS
|
WORDS
|
||||||
);
|
);
|
||||||
eprintln!(
|
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
|
divider, phrase, divider
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1173,6 +1177,7 @@ fn do_process_deploy(
|
||||||
program_location: &str,
|
program_location: &str,
|
||||||
address: Option<SignerIndex>,
|
address: Option<SignerIndex>,
|
||||||
use_deprecated_loader: bool,
|
use_deprecated_loader: bool,
|
||||||
|
allow_excessive_balance: bool,
|
||||||
new_keypair: Keypair,
|
new_keypair: Keypair,
|
||||||
) -> ProcessResult {
|
) -> ProcessResult {
|
||||||
let program_id = if let Some(i) = address {
|
let program_id = if let Some(i) = address {
|
||||||
|
@ -1237,6 +1242,15 @@ fn do_process_deploy(
|
||||||
balance,
|
balance,
|
||||||
));
|
));
|
||||||
balance_needed = 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)
|
(instructions, balance_needed)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1619,12 +1633,14 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||||
program_location,
|
program_location,
|
||||||
address,
|
address,
|
||||||
use_deprecated_loader,
|
use_deprecated_loader,
|
||||||
|
allow_excessive_balance,
|
||||||
} => process_deploy(
|
} => process_deploy(
|
||||||
&rpc_client,
|
&rpc_client,
|
||||||
config,
|
config,
|
||||||
program_location,
|
program_location,
|
||||||
*address,
|
*address,
|
||||||
*use_deprecated_loader,
|
*use_deprecated_loader,
|
||||||
|
*allow_excessive_balance,
|
||||||
),
|
),
|
||||||
|
|
||||||
// Stake Commands
|
// Stake Commands
|
||||||
|
@ -2241,7 +2257,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("address_signer")
|
Arg::with_name("address_signer")
|
||||||
.index(2)
|
.index(2)
|
||||||
.value_name("ADDRESS_SIGNER")
|
.value_name("PROGRAM_ADDRESS_SIGNER")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.validator(is_valid_signer)
|
.validator(is_valid_signer)
|
||||||
.help("The signer for the desired address of the program [default: new random address]")
|
.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
|
.hidden(true) // Don't document this argument to discourage its use
|
||||||
.help("Use the deprecated BPF loader")
|
.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")),
|
.arg(commitment_arg_with_default("max")),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
|
@ -2621,6 +2643,7 @@ mod tests {
|
||||||
program_location: "/Users/test/program.o".to_string(),
|
program_location: "/Users/test/program.o".to_string(),
|
||||||
address: None,
|
address: None,
|
||||||
use_deprecated_loader: false,
|
use_deprecated_loader: false,
|
||||||
|
allow_excessive_balance: false,
|
||||||
},
|
},
|
||||||
signers: vec![read_keypair_file(&keypair_file).unwrap().into()],
|
signers: vec![read_keypair_file(&keypair_file).unwrap().into()],
|
||||||
}
|
}
|
||||||
|
@ -2642,6 +2665,7 @@ mod tests {
|
||||||
program_location: "/Users/test/program.o".to_string(),
|
program_location: "/Users/test/program.o".to_string(),
|
||||||
address: Some(1),
|
address: Some(1),
|
||||||
use_deprecated_loader: false,
|
use_deprecated_loader: false,
|
||||||
|
allow_excessive_balance: false,
|
||||||
},
|
},
|
||||||
signers: vec![
|
signers: vec![
|
||||||
read_keypair_file(&keypair_file).unwrap().into(),
|
read_keypair_file(&keypair_file).unwrap().into(),
|
||||||
|
@ -2955,6 +2979,7 @@ mod tests {
|
||||||
program_location: pathbuf.to_str().unwrap().to_string(),
|
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||||
address: None,
|
address: None,
|
||||||
use_deprecated_loader: false,
|
use_deprecated_loader: false,
|
||||||
|
allow_excessive_balance: false,
|
||||||
};
|
};
|
||||||
let result = process_command(&config);
|
let result = process_command(&config);
|
||||||
let json: Value = serde_json::from_str(&result.unwrap()).unwrap();
|
let json: Value = serde_json::from_str(&result.unwrap()).unwrap();
|
||||||
|
@ -2973,6 +2998,7 @@ mod tests {
|
||||||
program_location: "bad/file/location.so".to_string(),
|
program_location: "bad/file/location.so".to_string(),
|
||||||
address: None,
|
address: None,
|
||||||
use_deprecated_loader: false,
|
use_deprecated_loader: false,
|
||||||
|
allow_excessive_balance: false,
|
||||||
};
|
};
|
||||||
assert!(process_command(&config).is_err());
|
assert!(process_command(&config).is_err());
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ fn test_cli_deploy_program() {
|
||||||
faucet_host: None,
|
faucet_host: None,
|
||||||
faucet_port: faucet_addr.port(),
|
faucet_port: faucet_addr.port(),
|
||||||
pubkey: None,
|
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];
|
config.signers = vec![&keypair];
|
||||||
process_command(&config).unwrap();
|
process_command(&config).unwrap();
|
||||||
|
@ -64,6 +64,7 @@ fn test_cli_deploy_program() {
|
||||||
program_location: pathbuf.to_str().unwrap().to_string(),
|
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||||
address: None,
|
address: None,
|
||||||
use_deprecated_loader: false,
|
use_deprecated_loader: false,
|
||||||
|
allow_excessive_balance: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let response = process_command(&config);
|
let response = process_command(&config);
|
||||||
|
@ -98,6 +99,7 @@ fn test_cli_deploy_program() {
|
||||||
program_location: pathbuf.to_str().unwrap().to_string(),
|
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||||
address: Some(1),
|
address: Some(1),
|
||||||
use_deprecated_loader: false,
|
use_deprecated_loader: false,
|
||||||
|
allow_excessive_balance: false,
|
||||||
};
|
};
|
||||||
process_command(&config).unwrap();
|
process_command(&config).unwrap();
|
||||||
let account1 = rpc_client
|
let account1 = rpc_client
|
||||||
|
@ -113,6 +115,44 @@ fn test_cli_deploy_program() {
|
||||||
// Attempt to redeploy to the same address
|
// Attempt to redeploy to the same address
|
||||||
process_command(&config).unwrap_err();
|
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();
|
server.close().unwrap();
|
||||||
remove_dir_all(ledger_path).unwrap();
|
remove_dir_all(ledger_path).unwrap();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue