Add support for stake::split() via create_account_with_seed() (#7879)

* Add split with seed

* move to new system_program APIs

* de-replicode
This commit is contained in:
Rob Walker 2020-01-20 12:33:27 -08:00 committed by GitHub
parent 82b75796f9
commit cc299053cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 130 additions and 11 deletions

View File

@ -128,7 +128,7 @@ pub enum StakeInstruction {
Deactivate,
}
pub fn initialize(stake_pubkey: &Pubkey, authorized: &Authorized, lockup: &Lockup) -> Instruction {
fn initialize(stake_pubkey: &Pubkey, authorized: &Authorized, lockup: &Lockup) -> Instruction {
Instruction::new(
id(),
&StakeInstruction::Initialize(*authorized, *lockup),
@ -181,6 +181,21 @@ pub fn create_account(
]
}
fn _split(
stake_pubkey: &Pubkey,
authorized_pubkey: &Pubkey,
lamports: u64,
split_stake_pubkey: &Pubkey,
) -> Instruction {
let account_metas = vec![
AccountMeta::new(*stake_pubkey, false),
AccountMeta::new(*split_stake_pubkey, false),
]
.with_signer(authorized_pubkey);
Instruction::new(id(), &StakeInstruction::Split(lamports), account_metas)
}
pub fn split(
stake_pubkey: &Pubkey,
authorized_pubkey: &Pubkey,
@ -188,21 +203,39 @@ pub fn split(
split_stake_pubkey: &Pubkey,
) -> Vec<Instruction> {
vec![
system_instruction::create_account(
system_instruction::allocate(split_stake_pubkey, std::mem::size_of::<StakeState>() as u64),
system_instruction::assign(split_stake_pubkey, &id()),
_split(
stake_pubkey,
authorized_pubkey,
lamports,
split_stake_pubkey,
0, // creates an ephemeral, uninitialized Stake
),
]
}
pub fn split_with_seed(
stake_pubkey: &Pubkey,
authorized_pubkey: &Pubkey,
lamports: u64,
split_stake_pubkey: &Pubkey, // derived using create_address_with_seed()
base: &Pubkey, // base
seed: &str, // seed
) -> Vec<Instruction> {
vec![
system_instruction::allocate_with_seed(
split_stake_pubkey,
base,
seed,
std::mem::size_of::<StakeState>() as u64,
&id(),
),
{
let account_metas = vec![
AccountMeta::new(*stake_pubkey, false),
AccountMeta::new(*split_stake_pubkey, false),
]
.with_signer(authorized_pubkey);
Instruction::new(id(), &StakeInstruction::Split(lamports), account_metas)
},
_split(
stake_pubkey,
authorized_pubkey,
lamports,
split_stake_pubkey,
),
]
}
@ -478,6 +511,19 @@ mod tests {
&Pubkey::default(),
100,
&Pubkey::default()
)[2]
),
Err(InstructionError::InvalidAccountData),
);
assert_eq!(
process_instruction(
&split_with_seed(
&Pubkey::default(),
&Pubkey::default(),
100,
&Pubkey::default(),
&Pubkey::default(),
"seed"
)[1]
),
Err(InstructionError::InvalidAccountData),

View File

@ -2779,6 +2779,18 @@ mod tests {
);
}
#[test]
#[ignore]
#[should_panic]
fn test_dbg_stake_minimum_balance() {
let minimum_balance = Rent::default().minimum_balance(std::mem::size_of::<StakeState>());
panic!(
"stake minimum_balance: {} lamports, {} SOL",
minimum_balance,
minimum_balance as f64 / solana_sdk::native_token::LAMPORTS_PER_SOL as f64
);
}
#[test]
fn test_authorize_delegated_stake() {
let stake_pubkey = Pubkey::new_rand();

View File

@ -97,6 +97,67 @@ fn get_staked(bank: &Bank, stake_pubkey: &Pubkey) -> u64 {
)
}
#[test]
fn test_stake_create_and_split_single_signature() {
solana_logger::setup();
let GenesisConfigInfo {
mut genesis_config,
mint_keypair: staker_keypair,
..
} = create_genesis_config_with_leader(100_000_000_000, &Pubkey::new_rand(), 1_000_000);
genesis_config
.native_instruction_processors
.push(solana_stake_program::solana_stake_program!());
let staker_pubkey = staker_keypair.pubkey();
let bank_client = BankClient::new_shared(&Arc::new(Bank::new(&genesis_config)));
let stake_address =
create_address_with_seed(&staker_pubkey, "stake", &solana_stake_program::id()).unwrap();
let authorized = stake_state::Authorized::auto(&staker_pubkey);
let lamports = 1_000_000;
// Create stake account with seed
let message = Message::new(stake_instruction::create_account_with_seed(
&staker_pubkey, // from
&stake_address, // to
&staker_pubkey, // base
"stake", // seed
&authorized,
&stake_state::Lockup::default(),
lamports,
));
// only one signature required
bank_client
.send_message(&[&staker_keypair], message)
.expect("failed to create and delegate stake account");
// split the stake
let split_stake_address =
create_address_with_seed(&staker_pubkey, "split_stake", &solana_stake_program::id())
.unwrap();
// Test split
let message = Message::new(stake_instruction::split_with_seed(
&stake_address, // original
&staker_pubkey, // authorized
lamports / 2,
&split_stake_address, // new address
&staker_pubkey, // base
"split_stake", // seed
));
assert!(bank_client
.send_message(&[&staker_keypair], message)
.is_ok());
// w00t!
}
#[test]
fn test_stake_account_lifetime() {
let stake_keypair = Keypair::new();