Skip to content
This repository has been archived by the owner on Jan 10, 2025. It is now read-only.

Governance: vote options #2544

Merged
merged 57 commits into from
Nov 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
5bff3e9
feat: use VoteChoice instead of VoteWeight
SebastianBor Oct 25, 2021
13b53cf
chore: make clippy happy
SebastianBor Oct 25, 2021
508f925
feat: use options for ye/no vote
SebastianBor Oct 25, 2021
867c760
feat: use choices for CastVote instruction
SebastianBor Oct 25, 2021
a618faa
chore: move Vote enum to tests
SebastianBor Oct 25, 2021
417670c
fix: iterate overall choices for withdrawal
SebastianBor Oct 25, 2021
0a887c6
chore: split ProposalOption and ProposalOptionVote
SebastianBor Oct 25, 2021
aabe4e3
fix: calculate multi option proposal size
SebastianBor Oct 25, 2021
4ce9cc0
chore: split weighted and fractional vote choices
SebastianBor Oct 25, 2021
fc4c0dc
feat: add proposal type
SebastianBor Oct 25, 2021
8207e16
feat: add reject option flag
SebastianBor Oct 26, 2021
40c18cf
feat: calculate final state for proposal using options results
SebastianBor Oct 26, 2021
ae9e1d2
chore: make clippy happy
SebastianBor Oct 26, 2021
9966dee
fix: generalise max vote weight calculation for multiple options
SebastianBor Oct 26, 2021
0316db8
feat: gate vote tipping for yes/no proposals only
SebastianBor Oct 26, 2021
ef3c6b7
chore: make clippy happy
SebastianBor Oct 26, 2021
170ba0e
feat: add option_index to instruction
SebastianBor Oct 27, 2021
b5bd430
feat: move instructions to options
SebastianBor Oct 27, 2021
38f34cd
chore: advance clock
SebastianBor Oct 27, 2021
9ed8f14
chore: add await
SebastianBor Oct 27, 2021
53153ab
chore: add multi option proposal tests
SebastianBor Oct 27, 2021
772c005
chore: move governing_mint to account list
SebastianBor Oct 27, 2021
529d152
feat: assert valid proposal options
SebastianBor Oct 27, 2021
b258554
feat: assert proposal is executable when instruction is added
SebastianBor Oct 27, 2021
484a8c8
chore: make clippy happy
SebastianBor Oct 27, 2021
537ab3f
chore: add tests to insert instructions into multi option proposal
SebastianBor Oct 27, 2021
c507cc7
chore: make clippy happy
SebastianBor Oct 27, 2021
6421761
feat: use explicit reject_option_vote_weight
SebastianBor Oct 27, 2021
e64d156
feat: use Vote struct for vote results
SebastianBor Oct 27, 2021
1d19e0d
feat: validate vote
SebastianBor Oct 27, 2021
c23cd24
feat: reject empty proposal options
SebastianBor Oct 27, 2021
512a97d
chore: update comments
SebastianBor Oct 27, 2021
6e20486
fix: allow execute only successful options
SebastianBor Oct 27, 2021
5f45f7f
chore: add assertions for option statuses
SebastianBor Oct 28, 2021
e77bc18
chore: add partial success test
SebastianBor Oct 28, 2021
6a16453
chore: add full success execution test
SebastianBor Oct 28, 2021
530e0af
chore: add test for instructions execution for fully denied proposal
SebastianBor Oct 28, 2021
f407e16
feat: finalise none executable proposals into completed state
SebastianBor Oct 28, 2021
81d9115
chore: fix chat
SebastianBor Oct 28, 2021
03df0d9
feat: add vote_record v1 v2 roundtrip serialization
SebastianBor Oct 28, 2021
c864a16
eat: add proposal_instruction v1 v2 roundtrip serialisation
SebastianBor Oct 28, 2021
aac5806
chore: use VoteRecordV1
SebastianBor Oct 28, 2021
6285f0a
chore: use legacy structs instead of legacy crate version
SebastianBor Oct 28, 2021
c7b1170
chore: rename proposal to V2
SebastianBor Oct 28, 2021
e1f1420
feat: translate Proposal v1 v2 versions
SebastianBor Oct 28, 2021
1b5d74e
chore: make clippy happy
SebastianBor Oct 28, 2021
0a71dd9
chore: make clippy happy
SebastianBor Oct 28, 2021
2967adf
chore: remove unnecessary clone for match
SebastianBor Oct 30, 2021
677794a
chore: rename get_final_vote_state to resolve_final_vote_state
SebastianBor Oct 30, 2021
126464b
fix proposal account name
SebastianBor Oct 30, 2021
e6c4f77
chore: fix compilation
SebastianBor Oct 30, 2021
8fa1ba3
chore: use borsh::maybestd::io::Write
SebastianBor Oct 30, 2021
c6efecd
chore: consume self in serialise instructions to avoid cloning
SebastianBor Oct 30, 2021
00a446b
chore: update comments
SebastianBor Oct 30, 2021
ce61b13
feat: add N limit placeholder to multi choice vote type
SebastianBor Oct 30, 2021
a534d61
feat: increase options size to u16
SebastianBor Oct 30, 2021
172ead5
fix: use checked math
SebastianBor Oct 30, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 3 additions & 22 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion governance/chat/program/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ serde = "1.0.127"
serde_derive = "1.0.103"
solana-program = "1.8.1"
spl-token = { version = "3.2", path = "../../../token/program", features = [ "no-entrypoint" ] }
spl-governance= { version = "2.1.2", path ="../../program", features = [ "no-entrypoint" ]}
spl-governance= { version = "2.1.3", path ="../../program", features = [ "no-entrypoint" ]}
spl-governance-tools= { version = "0.1.0", path ="../../tools"}
thiserror = "1.0"

Expand Down
2 changes: 1 addition & 1 deletion governance/chat/program/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pub struct ChatMessage {

impl AccountMaxSize for ChatMessage {
fn get_max_size(&self) -> Option<usize> {
let body_size = match self.body.clone() {
let body_size = match &self.body {
MessageBody::Text(body) => body.len(),
MessageBody::Reaction(body) => body.len(),
};
Expand Down
7 changes: 6 additions & 1 deletion governance/chat/program/tests/program_test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use spl_governance::{
state::{
enums::{MintMaxVoteWeightSource, VoteThresholdPercentage},
governance::{get_account_governance_address, GovernanceConfig},
proposal::get_proposal_address,
proposal::{get_proposal_address, VoteType},
realm::get_realm_address,
token_owner_record::get_token_owner_record_address,
},
Expand Down Expand Up @@ -178,7 +178,9 @@ impl GovernanceChatProgramTest {

let proposal_name = "Proposal #1".to_string();
let description_link = "Proposal Description".to_string();
let options = vec!["Yes".to_string()];
let proposal_index: u32 = 0;
let use_deny_option = true;

let create_proposal_ix = create_proposal(
&self.governance_program_id,
Expand All @@ -191,6 +193,9 @@ impl GovernanceChatProgramTest {
proposal_name,
description_link.clone(),
&governing_token_mint_keypair.pubkey(),
VoteType::SingleChoice,
options,
use_deny_option,
proposal_index,
);

Expand Down
4 changes: 2 additions & 2 deletions governance/program/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "spl-governance"
version = "2.1.3"
version = "2.1.4"
description = "Solana Program Library Governance Program"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana-program-library"
Expand Down Expand Up @@ -32,7 +32,7 @@ proptest = "1.0"
solana-program-test = "1.8.1"
solana-sdk = "1.8.1"
spl-governance-test-sdk = { version = "0.1.0", path ="../test-sdk"}
spl-governance-v1 = {package="spl-governance", version = "1.1.1", features = [ "no-entrypoint" ] }


[lib]
crate-type = ["cdylib", "lib"]
24 changes: 24 additions & 0 deletions governance/program/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,30 @@ pub enum GovernanceError {
/// Governing token deposits not allowed
#[error("Governing token deposits not allowed")]
GoverningTokenDepositsNotAllowed,

/// Invalid vote choice weight percentage
#[error("Invalid vote choice weight percentage")]
InvalidVoteChoiceWeightPercentage,

/// Vote type not supported
#[error("Vote type not supported")]
VoteTypeNotSupported,

/// InvalidProposalOptions
#[error("Invalid proposal options")]
InvalidProposalOptions,

/// Proposal is not not executable
#[error("Proposal is not not executable")]
ProposalIsNotExecutable,

/// Invalid vote
#[error("Invalid vote")]
InvalidVote,

/// Cannot execute defeated option
#[error("Cannot execute defeated option")]
CannotExecuteDefeatedOption,
}

impl PrintProgramError for GovernanceError {
Expand Down
68 changes: 42 additions & 26 deletions governance/program/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ use crate::{
get_account_governance_address, get_mint_governance_address,
get_program_governance_address, get_token_governance_address, GovernanceConfig,
},
proposal::get_proposal_address,
proposal::{get_proposal_address, VoteType},
proposal_instruction::{get_proposal_instruction_address, InstructionData},
realm::{get_governing_token_holding_address, get_realm_address, RealmConfigArgs},
realm_config::get_realm_config_address,
signatory_record::get_signatory_record_address,
token_owner_record::get_token_owner_record_address,
vote_record::get_vote_record_address,
vote_record::{get_vote_record_address, Vote},
},
tools::bpf_loader_upgradeable::get_program_data_address,
};
Expand All @@ -25,16 +25,6 @@ use solana_program::{
system_program, sysvar,
};

/// Yes/No Vote
#[repr(C)]
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
pub enum Vote {
/// Yes vote
Yes,
/// No vote
No,
}

/// Instructions supported by the Governance program
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
#[repr(C)]
Expand Down Expand Up @@ -164,25 +154,36 @@ pub enum GovernanceInstruction {
/// 1. `[writable]` Proposal account. PDA seeds ['governance',governance, governing_token_mint, proposal_index]
/// 2. `[writable]` Governance account
/// 3. `[writable]` TokenOwnerRecord account of the Proposal owner
/// 4. `[signer]` Governance Authority (Token Owner or Governance Delegate)
/// 5. `[signer]` Payer
/// 6. `[]` System program
/// 7. `[]` Rent sysvar
/// 8. `[]` Clock sysvar
/// 9. `[]` Optional Realm Config
/// 10. `[]` Optional Voter Weight Record
/// 4. `[]` Governing Token Mint the Proposal is created for
/// 5. `[signer]` Governance Authority (Token Owner or Governance Delegate)
/// 6. `[signer]` Payer
/// 7. `[]` System program
/// 8. `[]` Rent sysvar
/// 9. `[]` Clock sysvar
/// 10. `[]` Optional Realm Config
/// 11. `[]` Optional Voter Weight Record
CreateProposal {
#[allow(dead_code)]
/// UTF-8 encoded name of the proposal
name: String,

#[allow(dead_code)]
/// Link to gist explaining proposal
/// Link to a gist explaining the proposal
description_link: String,

#[allow(dead_code)]
/// Governing Token Mint the Proposal is created for
governing_token_mint: Pubkey,
/// Proposal vote type
vote_type: VoteType,

#[allow(dead_code)]
/// Proposal options
options: Vec<String>,

#[allow(dead_code)]
/// Indicates whether the proposal has the deny option
/// A proposal without the rejecting option is a non binding survey
SebastianBor marked this conversation as resolved.
Show resolved Hide resolved
/// Only proposals with the rejecting option can have executable instructions
use_deny_option: bool,
},

/// Adds a signatory to the Proposal which means this Proposal can't leave Draft state until yet another Signatory signs
Expand Down Expand Up @@ -226,6 +227,9 @@ pub enum GovernanceInstruction {
/// 6. `[]` System program
/// 7. `[]` Rent sysvar
InsertInstruction {
#[allow(dead_code)]
/// The index of the option the instruction is for
option_index: u16,
#[allow(dead_code)]
/// Instruction index to be inserted at.
index: u16,
Expand Down Expand Up @@ -285,7 +289,7 @@ pub enum GovernanceInstruction {
/// 12. `[]` Optional Voter Weight Record
CastVote {
#[allow(dead_code)]
/// Yes/No vote
/// User's vote
vote: Vote,
},

Expand Down Expand Up @@ -823,6 +827,9 @@ pub fn create_proposal(
name: String,
description_link: String,
governing_token_mint: &Pubkey,
vote_type: VoteType,
options: Vec<String>,
use_deny_option: bool,
proposal_index: u32,
) -> Instruction {
let proposal_address = get_proposal_address(
Expand All @@ -837,6 +844,7 @@ pub fn create_proposal(
AccountMeta::new(proposal_address, false),
AccountMeta::new(*governance, false),
AccountMeta::new(*proposal_owner_record, false),
AccountMeta::new_readonly(*governing_token_mint, false),
AccountMeta::new_readonly(*governance_authority, true),
AccountMeta::new(*payer, true),
AccountMeta::new_readonly(system_program::id(), false),
Expand All @@ -849,7 +857,9 @@ pub fn create_proposal(
let instruction = GovernanceInstruction::CreateProposal {
name,
description_link,
governing_token_mint: *governing_token_mint,
vote_type,
options,
use_deny_option,
};

Instruction {
Expand Down Expand Up @@ -1095,12 +1105,17 @@ pub fn insert_instruction(
governance_authority: &Pubkey,
payer: &Pubkey,
// Args
option_index: u16,
index: u16,
hold_up_time: u32,
instruction: InstructionData,
) -> Instruction {
let proposal_instruction_address =
get_proposal_instruction_address(program_id, proposal, &index.to_le_bytes());
let proposal_instruction_address = get_proposal_instruction_address(
program_id,
proposal,
&option_index.to_le_bytes(),
&index.to_le_bytes(),
);

let accounts = vec![
AccountMeta::new_readonly(*governance, false),
Expand All @@ -1114,6 +1129,7 @@ pub fn insert_instruction(
];

let instruction = GovernanceInstruction::InsertInstruction {
option_index,
index,
hold_up_time,
instruction,
Expand Down
22 changes: 18 additions & 4 deletions governance/program/src/processor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,16 @@ pub fn process_instruction(
try_from_slice_unchecked(input).map_err(|_| ProgramError::InvalidInstructionData)?;

if let GovernanceInstruction::InsertInstruction {
option_index,
index,
hold_up_time,
instruction: _,
} = instruction
{
// Do not dump instruction data into logs
msg!(
"GOVERNANCE-INSTRUCTION: InsertInstruction {{ index: {:?}, hold_up_time: {:?} }}",
"GOVERNANCE-INSTRUCTION: InsertInstruction {{option_index: {:?}, index: {:?}, hold_up_time: {:?} }}",
option_index,
index,
hold_up_time
);
Expand Down Expand Up @@ -127,13 +129,17 @@ pub fn process_instruction(
GovernanceInstruction::CreateProposal {
name,
description_link,
governing_token_mint,
vote_type: proposal_type,
options,
use_deny_option,
} => process_create_proposal(
program_id,
accounts,
name,
description_link,
governing_token_mint,
proposal_type,
options,
use_deny_option,
),
GovernanceInstruction::AddSignatory { signatory } => {
process_add_signatory(program_id, accounts, signatory)
Expand All @@ -153,10 +159,18 @@ pub fn process_instruction(
GovernanceInstruction::CancelProposal {} => process_cancel_proposal(program_id, accounts),

GovernanceInstruction::InsertInstruction {
option_index,
index,
hold_up_time,
instruction,
} => process_insert_instruction(program_id, accounts, index, hold_up_time, instruction),
} => process_insert_instruction(
program_id,
accounts,
option_index,
index,
hold_up_time,
instruction,
),

GovernanceInstruction::RemoveInstruction {} => {
process_remove_instruction(program_id, accounts)
Expand Down
1 change: 0 additions & 1 deletion governance/program/src/processor/process_add_signatory.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! Program state processor

use borsh::BorshSerialize;
use solana_program::{
account_info::{next_account_info, AccountInfo},
entrypoint::ProgramResult,
Expand Down
Loading