Skip to content

Commit

Permalink
Make active stake consistent in split (#33295)
Browse files Browse the repository at this point in the history
* Add feature gate

* Add helper fn

* Require split destination to be rent-exempt if it is active

* Update cli to prefund split accounts

* cli: require rent param with sign-only

* Update tokens to prefund split accounts

* Update split tests with sysvar accounts

* Fix test_split_to_account_with_rent_exempt_reserve

* Fix test_staked_split_destination_minimum_balance

* Fix test_split_more_than_staked

* Fix test_split_minimum_stake_delegation and remove misleading StakeState::Initialized case

* Fix test_split_from_larger_sized_account

* Add test for pre-/post-activation behavior splitting some or all of stake account

* Assert active stake

* Fix runtime test

* Ignore stake-pool downstream

* Review comments

* Feature gate sysvar reads

(cherry picked from commit bca41ed)

# Conflicts:
#	cli/tests/stake.rs
#	programs/stake/src/stake_instruction.rs
#	programs/stake/src/stake_state.rs
#	runtime/tests/stake.rs
#	sdk/src/feature_set.rs
  • Loading branch information
CriesofCarrots authored and mergify[bot] committed Sep 20, 2023
1 parent d87681e commit a929f98
Show file tree
Hide file tree
Showing 14 changed files with 924 additions and 79 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/downstream-project-spl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ jobs:
- [governance/addin-mock/program, governance/program]
- [memo/program]
- [name-service/program]
- [stake-pool/program]
# - [stake-pool/program]
- [single-pool/program]

steps:
Expand Down
4 changes: 4 additions & 0 deletions cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ pub enum CliCommand {
lamports: u64,
fee_payer: SignerIndex,
compute_unit_price: Option<u64>,
rent_exempt_reserve: Option<u64>,
},
MergeStake {
stake_account_pubkey: Pubkey,
Expand Down Expand Up @@ -1215,6 +1216,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
lamports,
fee_payer,
compute_unit_price,
rent_exempt_reserve,
} => process_split_stake(
&rpc_client,
config,
Expand All @@ -1231,6 +1233,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
*lamports,
*fee_payer,
compute_unit_price.as_ref(),
rent_exempt_reserve.as_ref(),
),
CliCommand::MergeStake {
stake_account_pubkey,
Expand Down Expand Up @@ -2232,6 +2235,7 @@ mod tests {
lamports: 30,
fee_payer: 0,
compute_unit_price: None,
rent_exempt_reserve: None,
};
config.signers = vec![&keypair, &split_stake_account];
let result = process_command(&config);
Expand Down
78 changes: 57 additions & 21 deletions cli/src/stake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ use {
tools::{acceptable_reference_epoch_credits, eligible_for_deactivate_delinquent},
},
stake_history::{Epoch, StakeHistory},
system_instruction::SystemError,
system_instruction::{self, SystemError},
sysvar::{clock, stake_history},
transaction::Transaction,
},
Expand Down Expand Up @@ -119,6 +119,13 @@ pub struct StakeAuthorizationIndexed {
pub new_authority_signer: Option<SignerIndex>,
}

struct SignOnlySplitNeedsRent {}
impl ArgsConfig for SignOnlySplitNeedsRent {
fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> {
arg.requires("rent_exempt_reserve_sol")
}
}

pub trait StakeSubCommands {
fn stake_subcommands(self) -> Self;
}
Expand Down Expand Up @@ -491,11 +498,21 @@ impl StakeSubCommands for App<'_, '_> {
will be at a derived address of SPLIT_STAKE_ACCOUNT")
)
.arg(stake_authority_arg())
.offline_args()
.offline_args_config(&SignOnlySplitNeedsRent{})
.nonce_args(false)
.arg(fee_payer_arg())
.arg(memo_arg())
.arg(compute_unit_price_arg())
.arg(
Arg::with_name("rent_exempt_reserve_sol")
.long("rent-exempt-reserve-sol")
.value_name("AMOUNT")
.takes_value(true)
.validator(is_amount)
.requires("sign_only")
.help("Offline signing only: the rent-exempt amount to move into the new \
stake account, in SOL")
)
)
.subcommand(
SubCommand::with_name("merge-stake")
Expand Down Expand Up @@ -1025,6 +1042,7 @@ pub fn parse_split_stake(
let signer_info =
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
let compute_unit_price = value_of(matches, COMPUTE_UNIT_PRICE_ARG.name);
let rent_exempt_reserve = lamports_of_sol(matches, "rent_exempt_reserve_sol");

Ok(CliCommandInfo {
command: CliCommand::SplitStake {
Expand All @@ -1041,6 +1059,7 @@ pub fn parse_split_stake(
lamports,
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
compute_unit_price,
rent_exempt_reserve,
},
signers: signer_info.signers,
})
Expand Down Expand Up @@ -1850,6 +1869,7 @@ pub fn process_split_stake(
lamports: u64,
fee_payer: SignerIndex,
compute_unit_price: Option<&u64>,
rent_exempt_reserve: Option<&u64>,
) -> ProcessResult {
let split_stake_account = config.signers[split_stake_account];
let fee_payer = config.signers[fee_payer];
Expand Down Expand Up @@ -1883,7 +1903,7 @@ pub fn process_split_stake(
split_stake_account.pubkey()
};

if !sign_only {
let rent_exempt_reserve = if !sign_only {
if let Ok(stake_account) = rpc_client.get_account(&split_stake_account_address) {
let err_msg = if stake_account.owner == stake::program::id() {
format!("Stake account {split_stake_account_address} already exists")
Expand All @@ -1904,30 +1924,44 @@ pub fn process_split_stake(
))
.into());
}
}
minimum_balance
} else {
rent_exempt_reserve
.cloned()
.expect("rent_exempt_reserve_sol is required with sign_only")
};

let recent_blockhash = blockhash_query.get_blockhash(rpc_client, config.commitment)?;

let ixs = if let Some(seed) = split_stake_account_seed {
stake_instruction::split_with_seed(
stake_account_pubkey,
&stake_authority.pubkey(),
lamports,
&split_stake_account_address,
&split_stake_account.pubkey(),
seed,
let mut ixs = vec![system_instruction::transfer(
&fee_payer.pubkey(),
&split_stake_account_address,
rent_exempt_reserve,
)];
if let Some(seed) = split_stake_account_seed {
ixs.append(
&mut stake_instruction::split_with_seed(
stake_account_pubkey,
&stake_authority.pubkey(),
lamports,
&split_stake_account_address,
&split_stake_account.pubkey(),
seed,
)
.with_memo(memo)
.with_compute_unit_price(compute_unit_price),
)
.with_memo(memo)
.with_compute_unit_price(compute_unit_price)
} else {
stake_instruction::split(
stake_account_pubkey,
&stake_authority.pubkey(),
lamports,
&split_stake_account_address,
ixs.append(
&mut stake_instruction::split(
stake_account_pubkey,
&stake_authority.pubkey(),
lamports,
&split_stake_account_address,
)
.with_memo(memo)
.with_compute_unit_price(compute_unit_price),
)
.with_memo(memo)
.with_compute_unit_price(compute_unit_price)
};

let nonce_authority = config.signers[nonce_authority];
Expand Down Expand Up @@ -4845,6 +4879,7 @@ mod tests {
lamports: 50_000_000_000,
fee_payer: 0,
compute_unit_price: None,
rent_exempt_reserve: None,
},
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),
Expand Down Expand Up @@ -4912,6 +4947,7 @@ mod tests {
lamports: 50_000_000_000,
fee_payer: 1,
compute_unit_price: None,
rent_exempt_reserve: None,
},
signers: vec![
Presigner::new(&stake_auth_pubkey, &stake_sig).into(),
Expand Down
18 changes: 16 additions & 2 deletions cli/tests/stake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1467,6 +1467,10 @@ fn test_stake_split() {
config.json_rpc_url = test_validator.rpc_url();
config.signers = vec![&default_signer];

let minimum_balance = rpc_client
.get_minimum_balance_for_rent_exemption(StakeStateV2::size_of())
.unwrap();

let mut config_offline = CliConfig::recent_for_tests();
config_offline.json_rpc_url = String::default();
config_offline.signers = vec![&offline_signer];
Expand Down Expand Up @@ -1494,10 +1498,14 @@ fn test_stake_split() {
check_balance!(1_000_000_000_000, &rpc_client, &offline_pubkey);

// Create stake account, identity is authority
<<<<<<< HEAD
let stake_balance = rpc_client
.get_minimum_balance_for_rent_exemption(StakeState::size_of())
.unwrap()
+ 10_000_000_000;
=======
let stake_balance = minimum_balance + 10_000_000_000;
>>>>>>> bca41edf20 (Make active stake consistent in split (#33295))
let stake_keypair = keypair_from_seed(&[0u8; 32]).unwrap();
let stake_account_pubkey = stake_keypair.pubkey();
config.signers.push(&stake_keypair);
Expand Down Expand Up @@ -1567,6 +1575,7 @@ fn test_stake_split() {
lamports: 2 * stake_balance,
fee_payer: 0,
compute_unit_price: None,
rent_exempt_reserve: Some(minimum_balance),
};
config_offline.output_format = OutputFormat::JsonCompact;
let sig_response = process_command(&config_offline).unwrap();
Expand All @@ -1591,10 +1600,15 @@ fn test_stake_split() {
lamports: 2 * stake_balance,
fee_payer: 0,
compute_unit_price: None,
rent_exempt_reserve: None,
};
process_command(&config).unwrap();
check_balance!(8 * stake_balance, &rpc_client, &stake_account_pubkey,);
check_balance!(2 * stake_balance, &rpc_client, &split_account.pubkey(),);
check_balance!(8 * stake_balance, &rpc_client, &stake_account_pubkey);
check_balance!(
2 * stake_balance + minimum_balance,
&rpc_client,
&split_account.pubkey()
);
}

#[test]
Expand Down
Loading

0 comments on commit a929f98

Please sign in to comment.