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
|
* Bigtable upload now includes entry summary data for each slot, stored in a
|
||||||
new `entries` table
|
new `entries` table
|
||||||
* Forbid multiple values for the `--signer` CLI flag, forcing users to specify multiple occurrences of `--signer`, one for each signature
|
* 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
|
* Upgrade Notes
|
||||||
* `solana-program` and `solana-sdk` default to support for Borsh v1, with
|
* `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.
|
limited backward compatibility for v0.10 and v0.9. Please upgrade to Borsh v1.
|
||||||
|
|
|
@ -219,7 +219,7 @@ impl ProgramSubCommands for App<'_, '_> {
|
||||||
.required(false)
|
.required(false)
|
||||||
.help(
|
.help(
|
||||||
"Maximum length of the upgradeable program \
|
"Maximum length of the upgradeable program \
|
||||||
[default: twice the length of the original deployed program]",
|
[default: the length of the original deployed program]",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
|
@ -300,7 +300,7 @@ impl ProgramSubCommands for App<'_, '_> {
|
||||||
.required(false)
|
.required(false)
|
||||||
.help(
|
.help(
|
||||||
"Maximum length of the upgradeable program \
|
"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
|
len
|
||||||
} else if is_final {
|
|
||||||
program_len
|
|
||||||
} else {
|
} else {
|
||||||
program_len * 2
|
program_len
|
||||||
};
|
};
|
||||||
|
|
||||||
let min_rent_exempt_program_data_balance = rpc_client.get_minimum_balance_for_rent_exemption(
|
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.push("noop");
|
||||||
noop_path.set_extension("so");
|
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_keypair = Keypair::new();
|
||||||
let mint_pubkey = mint_keypair.pubkey();
|
let mint_pubkey = mint_keypair.pubkey();
|
||||||
let faucet_addr = run_local_faucet(mint_keypair, None);
|
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||||
|
@ -826,7 +832,7 @@ fn test_cli_program_extend_program() {
|
||||||
allow_excessive_balance: false,
|
allow_excessive_balance: false,
|
||||||
upgrade_authority_signer_index: 1,
|
upgrade_authority_signer_index: 1,
|
||||||
is_final: false,
|
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,
|
skip_fee_check: false,
|
||||||
});
|
});
|
||||||
config.output_format = OutputFormat::JsonCompact;
|
config.output_format = OutputFormat::JsonCompact;
|
||||||
|
@ -837,22 +843,78 @@ fn test_cli_program_extend_program() {
|
||||||
&bpf_loader_upgradeable::id(),
|
&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 one slot to avoid "Program was deployed in this block already" error
|
||||||
wait_n_slots(&rpc_client, 1);
|
wait_n_slots(&rpc_client, 1);
|
||||||
|
|
||||||
// Extend program
|
// Extend program for larger program, minus 1 required byte
|
||||||
let additional_bytes = 100;
|
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.signers = vec![&keypair];
|
||||||
config.command = CliCommand::Program(ProgramCliCommand::ExtendProgram {
|
config.command = CliCommand::Program(ProgramCliCommand::ExtendProgram {
|
||||||
program_pubkey: program_keypair.pubkey(),
|
program_pubkey: program_keypair.pubkey(),
|
||||||
additional_bytes,
|
additional_bytes: additional_bytes - 1,
|
||||||
});
|
});
|
||||||
process_command(&config).unwrap();
|
process_command(&config).unwrap();
|
||||||
|
|
||||||
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
|
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
|
||||||
let expected_len =
|
let expected_len = UpgradeableLoaderState::size_of_programdata(new_max_len - 1);
|
||||||
UpgradeableLoaderState::size_of_programdata(max_len + additional_bytes as usize);
|
|
||||||
assert_eq!(expected_len, programdata_account.data.len());
|
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]
|
#[test]
|
||||||
|
|
|
@ -102,17 +102,25 @@ The command looks the same as the deployment command:
|
||||||
solana program deploy <PROGRAM_FILEPATH>
|
solana program deploy <PROGRAM_FILEPATH>
|
||||||
```
|
```
|
||||||
|
|
||||||
By default, programs are deployed to accounts that are twice the size of the
|
By default, programs are deployed to accounts that match the size of the
|
||||||
original deployment. Doing so leaves room for program growth in future
|
original program file. But, if the redeployed program is larger, the
|
||||||
redeployments. But, if the initially deployed program is very small and then
|
redeployment will fail. To avoid this, specify a `max_len` that is at least the
|
||||||
later grows substantially, the redeployment may fail. To avoid this, specify a
|
size (in bytes) that the program is expected to become (plus some wiggle room).
|
||||||
`max_len` that is at least the size (in bytes) that the program is expected to
|
|
||||||
become (plus some wiggle room).
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana program deploy --max-len 200000 <PROGRAM_FILEPATH>
|
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
|
### Resuming a failed deploy
|
||||||
|
|
||||||
If program deployment fails, there will be a hanging intermediate buffer account
|
If program deployment fails, there will be a hanging intermediate buffer account
|
||||||
|
|
Loading…
Reference in New Issue