Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit 3e1dd7c

Browse files
authored
Validate proposal owner for tipped vote (#2793)
1 parent bc00009 commit 3e1dd7c

File tree

2 files changed

+104
-5
lines changed

2 files changed

+104
-5
lines changed

governance/program/src/processor/process_cast_vote.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,14 +135,17 @@ pub fn process_cast_vote(
135135
&realm_data,
136136
clock.unix_timestamp,
137137
)? {
138+
// Deserialize proposal owner and validate it's the actual owner of the proposal
139+
let mut proposal_owner_record_data = get_token_owner_record_data_for_proposal_owner(
140+
program_id,
141+
proposal_owner_record_info,
142+
&proposal_data.token_owner_record,
143+
)?;
144+
145+
// If the voter is also the proposal owner then update the voter record which is serialized for the voter later on
138146
if proposal_owner_record_info.key == voter_token_owner_record_info.key {
139147
voter_token_owner_record_data.decrease_outstanding_proposal_count();
140148
} else {
141-
let mut proposal_owner_record_data = get_token_owner_record_data_for_proposal_owner(
142-
program_id,
143-
proposal_owner_record_info,
144-
&proposal_data.token_owner_record,
145-
)?;
146149
proposal_owner_record_data.decrease_outstanding_proposal_count();
147150
proposal_owner_record_data
148151
.serialize(&mut *proposal_owner_record_info.data.borrow_mut())?;

governance/program/tests/process_cast_vote.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
mod program_test;
44

5+
use solana_program::pubkey::Pubkey;
56
use solana_program_test::tokio;
67

78
use program_test::*;
@@ -676,3 +677,98 @@ async fn test_cast_vote_with_cast_twice_error() {
676677
// Assert
677678
assert_eq!(err, GovernanceError::VoteAlreadyExists.into());
678679
}
680+
681+
#[tokio::test]
682+
async fn test_cast_vote_with_invalid_proposal_owner_error() {
683+
// Arrange
684+
let mut governance_test = GovernanceProgramTest::start_new().await;
685+
686+
let realm_cookie = governance_test.with_realm().await;
687+
let governed_account_cookie = governance_test.with_governed_account().await;
688+
689+
let token_owner_record_cookie = governance_test
690+
.with_community_token_deposit(&realm_cookie)
691+
.await
692+
.unwrap();
693+
694+
let mut account_governance_cookie = governance_test
695+
.with_account_governance(
696+
&realm_cookie,
697+
&governed_account_cookie,
698+
&token_owner_record_cookie,
699+
)
700+
.await
701+
.unwrap();
702+
703+
let mut proposal_cookie = governance_test
704+
.with_signed_off_proposal(&token_owner_record_cookie, &mut account_governance_cookie)
705+
.await
706+
.unwrap();
707+
708+
// Try to use an invalid account as the proposal owner
709+
proposal_cookie.account.token_owner_record = Pubkey::new_unique();
710+
711+
// Act
712+
let err = governance_test
713+
.with_cast_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes)
714+
.await
715+
.err()
716+
.unwrap();
717+
718+
assert_eq!(err, GovernanceError::InvalidProposalOwnerAccount.into());
719+
}
720+
721+
#[tokio::test]
722+
async fn test_cast_tipping_vote_with_invalid_proposal_owner_error() {
723+
// Arrange
724+
let mut governance_test = GovernanceProgramTest::start_new().await;
725+
726+
let realm_cookie = governance_test.with_realm().await;
727+
let governed_account_cookie = governance_test.with_governed_account().await;
728+
729+
let token_owner_record_cookie = governance_test
730+
.with_community_token_deposit(&realm_cookie)
731+
.await
732+
.unwrap();
733+
734+
let mut account_governance_cookie = governance_test
735+
.with_account_governance(
736+
&realm_cookie,
737+
&governed_account_cookie,
738+
&token_owner_record_cookie,
739+
)
740+
.await
741+
.unwrap();
742+
743+
let mut proposal_cookie = governance_test
744+
.with_signed_off_proposal(&token_owner_record_cookie, &mut account_governance_cookie)
745+
.await
746+
.unwrap();
747+
748+
// Create another voter and vote
749+
let token_owner_record_cookie2 = governance_test
750+
.with_community_token_deposit(&realm_cookie)
751+
.await
752+
.unwrap();
753+
754+
governance_test
755+
.with_cast_vote(
756+
&proposal_cookie,
757+
&token_owner_record_cookie2,
758+
YesNoVote::Yes,
759+
)
760+
.await
761+
.unwrap();
762+
763+
// Try to use the other voter as the proposal owner
764+
proposal_cookie.account.token_owner_record = token_owner_record_cookie2.address;
765+
766+
// Act
767+
let err = governance_test
768+
.with_cast_vote(&proposal_cookie, &token_owner_record_cookie, YesNoVote::Yes)
769+
.await
770+
.err()
771+
.unwrap();
772+
773+
assert_eq!(err, GovernanceError::InvalidProposalOwnerAccount.into());
774+
}

0 commit comments

Comments
 (0)