add vote withdraw (#5284)
This commit is contained in:
		@@ -89,7 +89,7 @@ pub fn redeem_vote_credits(stake_pubkey: &Pubkey, vote_pubkey: &Pubkey) -> Instr
 | 
			
		||||
pub fn delegate_stake(stake_pubkey: &Pubkey, vote_pubkey: &Pubkey, stake: u64) -> Instruction {
 | 
			
		||||
    let account_metas = vec![
 | 
			
		||||
        AccountMeta::new(*stake_pubkey, true),
 | 
			
		||||
        AccountMeta::new(*vote_pubkey, false),
 | 
			
		||||
        AccountMeta::new_credit_only(*vote_pubkey, false),
 | 
			
		||||
        AccountMeta::new_credit_only(sysvar::clock::id(), false),
 | 
			
		||||
    ];
 | 
			
		||||
    Instruction::new(id(), &StakeInstruction::DelegateStake(stake), account_metas)
 | 
			
		||||
@@ -98,7 +98,7 @@ pub fn delegate_stake(stake_pubkey: &Pubkey, vote_pubkey: &Pubkey, stake: u64) -
 | 
			
		||||
pub fn withdraw(stake_pubkey: &Pubkey, to_pubkey: &Pubkey, lamports: u64) -> Instruction {
 | 
			
		||||
    let account_metas = vec![
 | 
			
		||||
        AccountMeta::new(*stake_pubkey, true),
 | 
			
		||||
        AccountMeta::new(*to_pubkey, false),
 | 
			
		||||
        AccountMeta::new_credit_only(*to_pubkey, false),
 | 
			
		||||
        AccountMeta::new_credit_only(sysvar::clock::id(), false),
 | 
			
		||||
    ];
 | 
			
		||||
    Instruction::new(id(), &StakeInstruction::Withdraw(lamports), account_metas)
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,9 @@ pub enum VoteInstruction {
 | 
			
		||||
 | 
			
		||||
    /// A Vote instruction with recent votes
 | 
			
		||||
    Vote(Vec<Vote>),
 | 
			
		||||
 | 
			
		||||
    /// Withdraw some amount of funds
 | 
			
		||||
    Withdraw(u64),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn initialize_account(vote_pubkey: &Pubkey, node_pubkey: &Pubkey, commission: u8) -> Instruction {
 | 
			
		||||
@@ -71,7 +74,7 @@ fn metas_for_authorized_signer(
 | 
			
		||||
 | 
			
		||||
    // append signer at the end
 | 
			
		||||
    if !is_own_signer {
 | 
			
		||||
        account_metas.push(AccountMeta::new(*authorized_voter_pubkey, true)) // signer
 | 
			
		||||
        account_metas.push(AccountMeta::new_credit_only(*authorized_voter_pubkey, true)) // signer
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    account_metas
 | 
			
		||||
@@ -110,6 +113,15 @@ pub fn vote(
 | 
			
		||||
    Instruction::new(id(), &VoteInstruction::Vote(recent_votes), account_metas)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn withdraw(vote_pubkey: &Pubkey, lamports: u64, to_pubkey: &Pubkey) -> Instruction {
 | 
			
		||||
    let account_metas = vec![
 | 
			
		||||
        AccountMeta::new(*vote_pubkey, true),
 | 
			
		||||
        AccountMeta::new_credit_only(*to_pubkey, false),
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    Instruction::new(id(), &VoteInstruction::Withdraw(lamports), account_metas)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn process_instruction(
 | 
			
		||||
    _program_id: &Pubkey,
 | 
			
		||||
    keyed_accounts: &mut [KeyedAccount],
 | 
			
		||||
@@ -151,6 +163,12 @@ pub fn process_instruction(
 | 
			
		||||
                &votes,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        VoteInstruction::Withdraw(lamports) => {
 | 
			
		||||
            if rest.is_empty() {
 | 
			
		||||
                Err(InstructionError::InvalidInstructionData)?;
 | 
			
		||||
            }
 | 
			
		||||
            vote_state::withdraw(me, lamports, &mut rest[0])
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -300,6 +300,23 @@ pub fn authorize_voter(
 | 
			
		||||
    vote_account.set_state(&vote_state)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Withdraw funds from the vote account
 | 
			
		||||
pub fn withdraw(
 | 
			
		||||
    vote_account: &mut KeyedAccount,
 | 
			
		||||
    lamports: u64,
 | 
			
		||||
    to_account: &mut KeyedAccount,
 | 
			
		||||
) -> Result<(), InstructionError> {
 | 
			
		||||
    if vote_account.signer_key().is_none() {
 | 
			
		||||
        return Err(InstructionError::MissingRequiredSignature);
 | 
			
		||||
    }
 | 
			
		||||
    if vote_account.account.lamports < lamports {
 | 
			
		||||
        return Err(InstructionError::InsufficientFunds);
 | 
			
		||||
    }
 | 
			
		||||
    vote_account.account.lamports -= lamports;
 | 
			
		||||
    to_account.account.lamports += lamports;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Initialize the vote_state for a vote account
 | 
			
		||||
/// Assumes that the account is being init as part of a account creation or balance transfer and
 | 
			
		||||
/// that the transaction must be signed by the staker's keys
 | 
			
		||||
@@ -811,6 +828,39 @@ mod tests {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_vote_state_withdraw() {
 | 
			
		||||
        let (vote_pubkey, mut vote_account) = create_test_account();
 | 
			
		||||
 | 
			
		||||
        // unsigned
 | 
			
		||||
        let res = withdraw(
 | 
			
		||||
            &mut KeyedAccount::new(&vote_pubkey, false, &mut vote_account),
 | 
			
		||||
            0,
 | 
			
		||||
            &mut KeyedAccount::new(&Pubkey::new_rand(), false, &mut Account::default()),
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(res, Err(InstructionError::MissingRequiredSignature));
 | 
			
		||||
 | 
			
		||||
        // insufficient funds
 | 
			
		||||
        let res = withdraw(
 | 
			
		||||
            &mut KeyedAccount::new(&vote_pubkey, true, &mut vote_account),
 | 
			
		||||
            101,
 | 
			
		||||
            &mut KeyedAccount::new(&Pubkey::new_rand(), false, &mut Account::default()),
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(res, Err(InstructionError::InsufficientFunds));
 | 
			
		||||
 | 
			
		||||
        // all good
 | 
			
		||||
        let mut to_account = Account::default();
 | 
			
		||||
        let lamports = vote_account.lamports;
 | 
			
		||||
        let res = withdraw(
 | 
			
		||||
            &mut KeyedAccount::new(&vote_pubkey, true, &mut vote_account),
 | 
			
		||||
            lamports,
 | 
			
		||||
            &mut KeyedAccount::new(&Pubkey::new_rand(), false, &mut to_account),
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(res, Ok(()));
 | 
			
		||||
        assert_eq!(vote_account.lamports, 0);
 | 
			
		||||
        assert_eq!(to_account.lamports, lamports);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_vote_state_epoch_credits() {
 | 
			
		||||
        let mut vote_state = VoteState::default();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user