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

Commit 46d27c7

Browse files
authored
Governance: Add max_executable_options to VoteType (#2831)
* feat: add max_executable_options to MultiChoice vote * chore: update Governance comments * chore: update comments
1 parent 6070eb5 commit 46d27c7

File tree

3 files changed

+99
-23
lines changed

3 files changed

+99
-23
lines changed

governance/program/src/state/governance.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,15 @@ pub struct Governance {
5757
/// Governance Realm
5858
pub realm: Pubkey,
5959

60-
/// Account governed by this Governance. It can be for example Program account, Mint account or Token Account
60+
/// Account governed by this Governance and/or PDA identity seed
61+
/// It can be Program account, Mint account, Token account or any other account
62+
///
63+
/// Note: The account doesn't have to exist. In that case the field is only a PDA seed
64+
///
65+
/// Note: Setting governed_account doesn't give any authority over the governed account
66+
/// The relevant authorities for specific account types must still be transferred to the Governance PDA
67+
/// Ex: mint_authority/freeze_authority for a Mint account
68+
/// or upgrade_authority for a Program account should be transferred to the Governance PDA
6169
pub governed_account: Pubkey,
6270

6371
/// Running count of proposals

governance/program/src/state/proposal.rs

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,23 @@ pub enum VoteType {
8181
/// Note: Yes/No vote is a single choice (Yes) vote with the deny option (No)
8282
SingleChoice,
8383

84-
/// Multiple options can be selected with up to N choices per voter
85-
/// By default N equals to the number of available options
86-
/// Note: In the current version the N limit is not supported and not enforced yet
87-
MultiChoice(u16),
84+
/// Multiple options can be selected with up to max_voter_options per voter
85+
/// and with up to max_executable_options of wining options eligible for execution
86+
/// Ex. voters are given 5 options, can choose up to 3 (max_voter_options)
87+
/// and only 1 (max_executable_options) wining option can be executed
88+
MultiChoice {
89+
/// The max number of options a voter can choose
90+
/// By default it equals to the number of available options
91+
/// Note: In the current version the limit is not supported and not enforced yet
92+
#[allow(dead_code)]
93+
max_voter_options: u16,
94+
95+
/// The max number of wining options which can be executed
96+
/// By default it equals to the number of available options
97+
/// Note: In the current version the limit is not supported and not enforced yet
98+
#[allow(dead_code)]
99+
max_executable_options: u16,
100+
},
88101
}
89102

90103
/// Governance Proposal
@@ -171,7 +184,7 @@ pub struct ProposalV2 {
171184
impl AccountMaxSize for ProposalV2 {
172185
fn get_max_size(&self) -> Option<usize> {
173186
let options_size: usize = self.options.iter().map(|o| o.label.len() + 19).sum();
174-
Some(self.name.len() + self.description_link.len() + options_size + 199)
187+
Some(self.name.len() + self.description_link.len() + options_size + 201)
175188
}
176189
}
177190

@@ -357,7 +370,10 @@ impl ProposalV2 {
357370

358371
proposal_state
359372
}
360-
VoteType::MultiChoice(_n) => {
373+
VoteType::MultiChoice {
374+
max_voter_options: _n,
375+
max_executable_options: _m,
376+
} => {
361377
// If any option succeeded for multi choice then the proposal as a whole succeeded as well
362378
ProposalState::Succeeded
363379
}
@@ -670,7 +686,10 @@ impl ProposalV2 {
670686
return Err(GovernanceError::InvalidVote.into());
671687
}
672688
}
673-
VoteType::MultiChoice(_n) => {
689+
VoteType::MultiChoice {
690+
max_voter_options: _n,
691+
max_executable_options: _m,
692+
} => {
674693
if choice_count == 0 {
675694
return Err(GovernanceError::InvalidVote.into());
676695
}
@@ -884,8 +903,15 @@ pub fn assert_valid_proposal_options(
884903
return Err(GovernanceError::InvalidProposalOptions.into());
885904
}
886905

887-
if let VoteType::MultiChoice(n) = *vote_type {
888-
if options.len() == 1 || n as usize != options.len() {
906+
if let VoteType::MultiChoice {
907+
max_voter_options,
908+
max_executable_options,
909+
} = *vote_type
910+
{
911+
if options.len() == 1
912+
|| max_voter_options as usize != options.len()
913+
|| max_executable_options as usize != options.len()
914+
{
889915
return Err(GovernanceError::InvalidProposalOptions.into());
890916
}
891917
}
@@ -1018,7 +1044,10 @@ mod test {
10181044
#[test]
10191045
fn test_max_size() {
10201046
let mut proposal = create_test_proposal();
1021-
proposal.vote_type = VoteType::MultiChoice(1);
1047+
proposal.vote_type = VoteType::MultiChoice {
1048+
max_voter_options: 1,
1049+
max_executable_options: 1,
1050+
};
10221051

10231052
let size = proposal.try_to_vec().unwrap().len();
10241053

@@ -1028,7 +1057,10 @@ mod test {
10281057
#[test]
10291058
fn test_multi_option_proposal_max_size() {
10301059
let mut proposal = create_test_multi_option_proposal();
1031-
proposal.vote_type = VoteType::MultiChoice(3);
1060+
proposal.vote_type = VoteType::MultiChoice {
1061+
max_voter_options: 3,
1062+
max_executable_options: 3,
1063+
};
10321064

10331065
let size = proposal.try_to_vec().unwrap().len();
10341066

@@ -1971,7 +2003,10 @@ mod test {
19712003
pub fn test_assert_valid_vote_with_no_choices_for_multi_choice_error() {
19722004
// Arrange
19732005
let mut proposal = create_test_multi_option_proposal();
1974-
proposal.vote_type = VoteType::MultiChoice(3);
2006+
proposal.vote_type = VoteType::MultiChoice {
2007+
max_voter_options: 3,
2008+
max_executable_options: 3,
2009+
};
19752010

19762011
let choices = vec![
19772012
VoteChoice {
@@ -2004,7 +2039,10 @@ mod test {
20042039
pub fn test_assert_valid_proposal_options_with_invalid_choice_number_for_multi_choice_vote_error(
20052040
) {
20062041
// Arrange
2007-
let vote_type = VoteType::MultiChoice(3);
2042+
let vote_type = VoteType::MultiChoice {
2043+
max_voter_options: 3,
2044+
max_executable_options: 3,
2045+
};
20082046

20092047
let options = vec!["option 1".to_string(), "option 2".to_string()];
20102048

@@ -2018,7 +2056,10 @@ mod test {
20182056
#[test]
20192057
pub fn test_assert_valid_proposal_options_with_no_options_for_multi_choice_vote_error() {
20202058
// Arrange
2021-
let vote_type = VoteType::MultiChoice(3);
2059+
let vote_type = VoteType::MultiChoice {
2060+
max_voter_options: 3,
2061+
max_executable_options: 3,
2062+
};
20222063

20232064
let options = vec![];
20242065

@@ -2046,7 +2087,10 @@ mod test {
20462087
#[test]
20472088
pub fn test_assert_valid_proposal_options_for_multi_choice_vote() {
20482089
// Arrange
2049-
let vote_type = VoteType::MultiChoice(3);
2090+
let vote_type = VoteType::MultiChoice {
2091+
max_voter_options: 3,
2092+
max_executable_options: 3,
2093+
};
20502094

20512095
let options = vec![
20522096
"option 1".to_string(),
@@ -2064,7 +2108,10 @@ mod test {
20642108
#[test]
20652109
pub fn test_assert_valid_proposal_options_for_multi_choice_vote_with_empty_option_error() {
20662110
// Arrange
2067-
let vote_type = VoteType::MultiChoice(3);
2111+
let vote_type = VoteType::MultiChoice {
2112+
max_voter_options: 3,
2113+
max_executable_options: 3,
2114+
};
20682115

20692116
let options = vec![
20702117
"".to_string(),

governance/program/tests/use_proposals_with_multiple_options.rs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,10 @@ async fn test_create_proposal_with_multiple_choice_options_and_without_deny_opti
9191
&mut account_governance_cookie,
9292
options,
9393
false,
94-
VoteType::MultiChoice(2),
94+
VoteType::MultiChoice {
95+
max_executable_options: 2,
96+
max_voter_options: 2,
97+
},
9598
)
9699
.await
97100
.unwrap();
@@ -100,7 +103,13 @@ async fn test_create_proposal_with_multiple_choice_options_and_without_deny_opti
100103
.get_proposal_account(&proposal_cookie.address)
101104
.await;
102105

103-
assert_eq!(proposal_account.vote_type, VoteType::MultiChoice(2));
106+
assert_eq!(
107+
proposal_account.vote_type,
108+
VoteType::MultiChoice {
109+
max_executable_options: 2,
110+
max_voter_options: 2,
111+
}
112+
);
104113
assert!(!proposal_account.deny_vote_weight.is_some());
105114

106115
assert_eq!(proposal_cookie.account, proposal_account);
@@ -350,7 +359,10 @@ async fn test_vote_on_none_executable_multi_choice_proposal_with_multiple_option
350359
"option 3".to_string(),
351360
],
352361
false,
353-
VoteType::MultiChoice(3),
362+
VoteType::MultiChoice {
363+
max_executable_options: 3,
364+
max_voter_options: 3,
365+
},
354366
)
355367
.await
356368
.unwrap();
@@ -475,7 +487,10 @@ async fn test_vote_on_executable_proposal_with_multiple_options_and_partial_succ
475487
"option 3".to_string(),
476488
],
477489
true,
478-
VoteType::MultiChoice(3),
490+
VoteType::MultiChoice {
491+
max_executable_options: 3,
492+
max_voter_options: 3,
493+
},
479494
)
480495
.await
481496
.unwrap();
@@ -633,7 +648,10 @@ async fn test_execute_proposal_with_multiple_options_and_partial_success() {
633648
"option 3".to_string(),
634649
],
635650
true,
636-
VoteType::MultiChoice(3),
651+
VoteType::MultiChoice {
652+
max_executable_options: 3,
653+
max_voter_options: 3,
654+
},
637655
)
638656
.await
639657
.unwrap();
@@ -836,7 +854,10 @@ async fn test_try_execute_proposal_with_multiple_options_and_full_deny() {
836854
"option 3".to_string(),
837855
],
838856
true,
839-
VoteType::MultiChoice(3),
857+
VoteType::MultiChoice {
858+
max_executable_options: 3,
859+
max_voter_options: 3,
860+
},
840861
)
841862
.await
842863
.unwrap();

0 commit comments

Comments
 (0)