cli: Use program length for deployments instead of 2x length (#34730)
* cli: Deploy the appropriate length program * Extend the extend-program test for new default * Add CHANGELOG entry * Update docs, and include `extend` * Update CHANGELOG.md Co-authored-by: Tyera <teulberg@gmail.com> --------- Co-authored-by: Tyera <teulberg@gmail.com>
This commit is contained in:
parent
fb97e93fe3
commit
5cb30cf9cc
|
@ -29,6 +29,9 @@ Release channels have their own copy of this changelog:
|
|||
* Bigtable upload now includes entry summary data for each slot, stored in a
|
||||
new `entries` table
|
||||
* Forbid multiple values for the `--signer` CLI flag, forcing users to specify multiple occurrences of `--signer`, one for each signature
|
||||
* New program deployments default to the exact size of a program, instead of
|
||||
double the size. Program accounts must be extended with `solana program extend`
|
||||
before an upgrade if they need to accommodate larger programs.
|
||||
* Upgrade Notes
|
||||
* `solana-program` and `solana-sdk` default to support for Borsh v1, with
|
||||
limited backward compatibility for v0.10 and v0.9. Please upgrade to Borsh v1.
|
||||
|
|
|
@ -219,7 +219,7 @@ impl ProgramSubCommands for App<'_, '_> {
|
|||
.required(false)
|
||||
.help(
|
||||
"Maximum length of the upgradeable program \
|
||||
[default: twice the length of the original deployed program]",
|
||||
[default: the length of the original deployed program]",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
|
@ -300,7 +300,7 @@ impl ProgramSubCommands for App<'_, '_> {
|
|||
.required(false)
|
||||
.help(
|
||||
"Maximum length of the upgradeable program \
|
||||
[default: twice the length of the original deployed program]",
|
||||
[default: the length of the original deployed program]",
|
||||
),
|
||||
),
|
||||
)
|
||||
|
@ -1171,10 +1171,8 @@ fn process_program_deploy(
|
|||
);
|
||||
}
|
||||
len
|
||||
} else if is_final {
|
||||
program_len
|
||||
} else {
|
||||
program_len * 2
|
||||
program_len
|
||||
};
|
||||
|
||||
let min_rent_exempt_program_data_balance = rpc_client.get_minimum_balance_for_rent_exemption(
|
||||
|
|
|
@ -780,6 +780,12 @@ fn test_cli_program_extend_program() {
|
|||
noop_path.push("noop");
|
||||
noop_path.set_extension("so");
|
||||
|
||||
let mut noop_large_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
noop_large_path.push("tests");
|
||||
noop_large_path.push("fixtures");
|
||||
noop_large_path.push("noop_large");
|
||||
noop_large_path.set_extension("so");
|
||||
|
||||
let mint_keypair = Keypair::new();
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||
|
@ -826,7 +832,7 @@ fn test_cli_program_extend_program() {
|
|||
allow_excessive_balance: false,
|
||||
upgrade_authority_signer_index: 1,
|
||||
is_final: false,
|
||||
max_len: Some(max_len),
|
||||
max_len: None, // Use None to check that it defaults to the max length
|
||||
skip_fee_check: false,
|
||||
});
|
||||
config.output_format = OutputFormat::JsonCompact;
|
||||
|
@ -837,22 +843,78 @@ fn test_cli_program_extend_program() {
|
|||
&bpf_loader_upgradeable::id(),
|
||||
);
|
||||
|
||||
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
|
||||
let expected_len = UpgradeableLoaderState::size_of_programdata(max_len);
|
||||
assert_eq!(expected_len, programdata_account.data.len());
|
||||
|
||||
// Wait one slot to avoid "Program was deployed in this block already" error
|
||||
wait_n_slots(&rpc_client, 1);
|
||||
|
||||
// Extend program
|
||||
let additional_bytes = 100;
|
||||
// Extend program for larger program, minus 1 required byte
|
||||
let mut file = File::open(noop_large_path.to_str().unwrap()).unwrap();
|
||||
let mut new_program_data = Vec::new();
|
||||
file.read_to_end(&mut new_program_data).unwrap();
|
||||
let new_max_len = new_program_data.len();
|
||||
let additional_bytes = (new_max_len - max_len) as u32;
|
||||
config.signers = vec![&keypair];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::ExtendProgram {
|
||||
program_pubkey: program_keypair.pubkey(),
|
||||
additional_bytes,
|
||||
additional_bytes: additional_bytes - 1,
|
||||
});
|
||||
process_command(&config).unwrap();
|
||||
|
||||
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
|
||||
let expected_len =
|
||||
UpgradeableLoaderState::size_of_programdata(max_len + additional_bytes as usize);
|
||||
let expected_len = UpgradeableLoaderState::size_of_programdata(new_max_len - 1);
|
||||
assert_eq!(expected_len, programdata_account.data.len());
|
||||
|
||||
// Larger program deploy fails because missing 1 byte
|
||||
config.signers = vec![&keypair, &upgrade_authority];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
|
||||
program_location: Some(noop_large_path.to_str().unwrap().to_string()),
|
||||
fee_payer_signer_index: 0,
|
||||
program_signer_index: None,
|
||||
program_pubkey: Some(program_keypair.pubkey()),
|
||||
buffer_signer_index: None,
|
||||
buffer_pubkey: None,
|
||||
allow_excessive_balance: false,
|
||||
upgrade_authority_signer_index: 1,
|
||||
is_final: false,
|
||||
max_len: None,
|
||||
skip_fee_check: false,
|
||||
});
|
||||
process_command(&config).unwrap_err();
|
||||
|
||||
// Wait one slot to avoid "Program was deployed in this block already" error
|
||||
wait_n_slots(&rpc_client, 1);
|
||||
|
||||
// Extend 1 last byte
|
||||
config.signers = vec![&keypair];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::ExtendProgram {
|
||||
program_pubkey: program_keypair.pubkey(),
|
||||
additional_bytes: 1,
|
||||
});
|
||||
process_command(&config).unwrap();
|
||||
|
||||
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
|
||||
let expected_len = UpgradeableLoaderState::size_of_programdata(new_max_len);
|
||||
assert_eq!(expected_len, programdata_account.data.len());
|
||||
|
||||
// Larger program deploy finally succeeds
|
||||
config.signers = vec![&keypair, &upgrade_authority];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
|
||||
program_location: Some(noop_large_path.to_str().unwrap().to_string()),
|
||||
fee_payer_signer_index: 0,
|
||||
program_signer_index: None,
|
||||
program_pubkey: Some(program_keypair.pubkey()),
|
||||
buffer_signer_index: None,
|
||||
buffer_pubkey: None,
|
||||
allow_excessive_balance: false,
|
||||
upgrade_authority_signer_index: 1,
|
||||
is_final: false,
|
||||
max_len: None,
|
||||
skip_fee_check: false,
|
||||
});
|
||||
process_command(&config).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -102,17 +102,25 @@ The command looks the same as the deployment command:
|
|||
solana program deploy <PROGRAM_FILEPATH>
|
||||
```
|
||||
|
||||
By default, programs are deployed to accounts that are twice the size of the
|
||||
original deployment. Doing so leaves room for program growth in future
|
||||
redeployments. But, if the initially deployed program is very small and then
|
||||
later grows substantially, the redeployment may fail. To avoid this, specify a
|
||||
`max_len` that is at least the size (in bytes) that the program is expected to
|
||||
become (plus some wiggle room).
|
||||
By default, programs are deployed to accounts that match the size of the
|
||||
original program file. But, if the redeployed program is larger, the
|
||||
redeployment will fail. To avoid this, specify a `max_len` that is at least the
|
||||
size (in bytes) that the program is expected to become (plus some wiggle room).
|
||||
|
||||
```bash
|
||||
solana program deploy --max-len 200000 <PROGRAM_FILEPATH>
|
||||
```
|
||||
|
||||
### Extend a program
|
||||
|
||||
If a program has already been deployed, and a redeployment goes beyond the
|
||||
`max_len` of the account, it's possible to extend the program to fit the larger
|
||||
redeployment:
|
||||
|
||||
```bash
|
||||
solana program extend <PROGRAM_ID> <ADDITIONAL_BYTES>
|
||||
```
|
||||
|
||||
### Resuming a failed deploy
|
||||
|
||||
If program deployment fails, there will be a hanging intermediate buffer account
|
||||
|
|
Loading…
Reference in New Issue