From 132c664e18fe9e3239596f54db840a948cac2389 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Fri, 15 Feb 2019 13:20:34 -0700 Subject: [PATCH] No longer modify external userdata --- programs/native/rewards/src/lib.rs | 22 ++++++++----------- programs/native/rewards/tests/rewards.rs | 6 ++++- .../rewards_api/src/rewards_transaction.rs | 15 ++++++++----- programs/native/vote/src/lib.rs | 1 + sdk/src/vote_program.rs | 15 +++++++++++++ 5 files changed, 39 insertions(+), 20 deletions(-) diff --git a/programs/native/rewards/src/lib.rs b/programs/native/rewards/src/lib.rs index 4611ac4ca4..c0ae474872 100644 --- a/programs/native/rewards/src/lib.rs +++ b/programs/native/rewards/src/lib.rs @@ -40,7 +40,11 @@ fn redeem_vote_credits(keyed_accounts: &mut [KeyedAccount]) -> Result<(), Progra Err(ProgramError::InvalidArgument)?; } - let mut vote_state = VoteState::deserialize(&keyed_accounts[0].account.userdata)?; + // TODO: Verify the next instruction in the transaction being processed is + // VoteInstruction::ClearCredits and that it points to the same vote account + // as keyed_accounts[0]. + + let vote_state = VoteState::deserialize(&keyed_accounts[0].account.userdata)?; //// TODO: This assumes the staker_id is static. If not, it should use the staker_id //// at the time of voting, not at credit redemption. @@ -63,11 +67,6 @@ fn redeem_vote_credits(keyed_accounts: &mut [KeyedAccount]) -> Result<(), Progra keyed_accounts[1].account.tokens -= lamports; keyed_accounts[2].account.tokens += lamports; - // TODO: The runtime should reject this, because this program - // is not the owner of the VoteState account. - vote_state.clear_credits(); - vote_state.serialize(&mut keyed_accounts[0].account.userdata)?; - Ok(()) } @@ -101,22 +100,20 @@ mod tests { Account::new(tokens, space, rewards_program::id()) } - fn redeem_vote_credits_and_deserialize( + fn redeem_vote_credits_( rewards_id: &Pubkey, rewards_account: &mut Account, vote_id: &Pubkey, vote_account: &mut Account, to_id: &Pubkey, to_account: &mut Account, - ) -> Result { + ) -> Result<(), ProgramError> { let mut keyed_accounts = [ KeyedAccount::new(vote_id, true, vote_account), KeyedAccount::new(rewards_id, false, rewards_account), KeyedAccount::new(to_id, false, to_account), ]; - redeem_vote_credits(&mut keyed_accounts)?; - let vote_state = VoteState::deserialize(&vote_account.userdata).unwrap(); - Ok(vote_state) + redeem_vote_credits(&mut keyed_accounts) } #[test] @@ -156,7 +153,7 @@ mod tests { let mut to_account = from_account; let to_tokens = to_account.tokens; - let vote_state = redeem_vote_credits_and_deserialize( + redeem_vote_credits_( &rewards_id, &mut rewards_account, &vote_id, @@ -165,7 +162,6 @@ mod tests { &mut to_account, ) .unwrap(); - assert_eq!(vote_state.credits(), 0); assert!(to_account.tokens > to_tokens); } } diff --git a/programs/native/rewards/tests/rewards.rs b/programs/native/rewards/tests/rewards.rs index 9836f348af..fcbdaacfde 100644 --- a/programs/native/rewards/tests/rewards.rs +++ b/programs/native/rewards/tests/rewards.rs @@ -82,7 +82,11 @@ fn redeem_credits( ) -> Result { let last_id = Hash::default(); let rewards_program_account = create_program_account("solana_rewards_program"); - let loaders = &mut [vec![(rewards_program::id(), rewards_program_account)]]; + let vote_program_account = create_program_account("solana_vote_program"); + let loaders = &mut [ + vec![(rewards_program::id(), rewards_program_account)], + vec![(vote_program::id(), vote_program_account)], + ]; let accounts = &mut [ vote_account.clone(), diff --git a/programs/native/rewards_api/src/rewards_transaction.rs b/programs/native/rewards_api/src/rewards_transaction.rs index 01656b82e4..05739a2bb3 100644 --- a/programs/native/rewards_api/src/rewards_transaction.rs +++ b/programs/native/rewards_api/src/rewards_transaction.rs @@ -7,7 +7,8 @@ use solana_sdk::hash::Hash; use solana_sdk::pubkey::Pubkey; use solana_sdk::signature::Keypair; use solana_sdk::system_transaction::SystemTransaction; -use solana_sdk::transaction::Transaction; +use solana_sdk::transaction::{Instruction, Transaction}; +use solana_sdk::vote_program::{self, VoteInstruction}; pub struct RewardsTransaction {} @@ -37,14 +38,16 @@ impl RewardsTransaction { last_id: Hash, fee: u64, ) -> Transaction { - let instruction = RewardsInstruction::RedeemVoteCredits; - Transaction::new( - vote_keypair, + Transaction::new_with_instructions( + &[vote_keypair], &[rewards_id, to_id], - rewards_program::id(), - &instruction, last_id, fee, + vec![rewards_program::id(), vote_program::id()], + vec![ + Instruction::new(0, &RewardsInstruction::RedeemVoteCredits, vec![0, 1, 2]), + Instruction::new(1, &VoteInstruction::ClearCredits, vec![0]), + ], ) } } diff --git a/programs/native/vote/src/lib.rs b/programs/native/vote/src/lib.rs index feea144fde..1cfe7d3e82 100644 --- a/programs/native/vote/src/lib.rs +++ b/programs/native/vote/src/lib.rs @@ -38,5 +38,6 @@ fn entrypoint( ); vote_program::process_vote(keyed_accounts, vote) } + VoteInstruction::ClearCredits => vote_program::clear_credits(keyed_accounts), } } diff --git a/sdk/src/vote_program.rs b/sdk/src/vote_program.rs index aeae900812..6169477d75 100644 --- a/sdk/src/vote_program.rs +++ b/sdk/src/vote_program.rs @@ -46,6 +46,9 @@ pub enum VoteInstruction { /// identified by keys[0] for voting RegisterAccount, Vote(Vote), + /// Clear the credits in the vote account + /// * Transaction::keys[0] - the "vote account" + ClearCredits, } #[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq)] @@ -148,6 +151,18 @@ pub fn process_vote(keyed_accounts: &mut [KeyedAccount], vote: Vote) -> Result<( Ok(()) } +pub fn clear_credits(keyed_accounts: &mut [KeyedAccount]) -> Result<(), ProgramError> { + if !check_id(&keyed_accounts[0].account.owner) { + error!("account[0] is not assigned to the VOTE_PROGRAM"); + Err(ProgramError::InvalidArgument)?; + } + + let mut vote_state = VoteState::deserialize(&keyed_accounts[0].account.userdata)?; + vote_state.clear_credits(); + vote_state.serialize(&mut keyed_accounts[0].account.userdata)?; + Ok(()) +} + pub fn create_vote_account(tokens: u64) -> Account { let space = get_max_size(); Account::new(tokens, space, id())