Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Governance: voting_cool_off_time #3830

Merged
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
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
3 changes: 2 additions & 1 deletion governance/chat/program/tests/program_test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,8 @@ impl GovernanceChatProgramTest {
council_veto_vote_threshold: VoteThreshold::YesVotePercentage(50),
council_vote_tipping: spl_governance::state::enums::VoteTipping::Strict,
community_veto_vote_threshold: VoteThreshold::YesVotePercentage(55),
reserved: [0; 5],
reserved: 0,
SebastianBor marked this conversation as resolved.
Show resolved Hide resolved
voting_cool_off_time: 1,
};

let token_owner_record_address = get_token_owner_record_address(
Expand Down
14 changes: 11 additions & 3 deletions governance/program/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,13 +431,21 @@ pub enum GovernanceError {
#[error("Invalid GoverningToken source")]
InvalidGoverningTokenSource, // 603

/// Cannot change community TokenType to Memebership
#[error("Cannot change community TokenType to Memebership")]
CannotChangeCommunityTokenTypeToMemebership, // 604
/// Cannot change community TokenType to Membership
#[error("Cannot change community TokenType to Membership")]
CannotChangeCommunityTokenTypeToMembership, // 604

/// Voter weight threshold disabled
#[error("Voter weight threshold disabled")]
VoterWeightThresholdDisabled, // 605

/// Vote not allowed in cool off time
#[error("Vote not allowed in cool off time")]
VoteNotAllowedInCoolOffTime, // 606

/// Invalid voting cool off time
#[error("Invalid voting cool off time")]
InvalidVotingCoolOffTime, // 607
}

impl PrintProgramError for GovernanceError {
Expand Down
2 changes: 1 addition & 1 deletion governance/program/src/processor/process_cast_vote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ pub fn process_cast_vote(
governance_info.key,
&proposal_governing_token_mint,
)?;
proposal_data.assert_can_cast_vote(&governance_data.config, clock.unix_timestamp)?;
proposal_data.assert_can_cast_vote(&governance_data.config, &vote, clock.unix_timestamp)?;

let mut voter_token_owner_record_data =
get_token_owner_record_data_for_realm_and_governing_mint(
Expand Down
176 changes: 103 additions & 73 deletions governance/program/src/state/governance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,11 @@ pub struct GovernanceConfig {
/// The threshold for Community Veto votes
pub community_veto_vote_threshold: VoteThreshold,

/// Voting cool of time
pub voting_cool_off_time: u32,

/// Reserved space for future versions
pub reserved: [u8; 5],
pub reserved: u8,
}

/// Governance Account
Expand Down Expand Up @@ -178,7 +181,7 @@ impl GovernanceV2 {
} else if is_governance_v1_account_type(&self.account_type) {
// V1 account can't be resized and we have to translate it back to the original format

// If reserved_v2 is used it must be individually assesed for v1 backward compatibility impact
// If reserved_v2 is used it must be individually assessed for v1 backward compatibility impact
if self.reserved_v2 != [0; 128] {
panic!("Extended data not supported by GovernanceV1")
}
Expand Down Expand Up @@ -288,13 +291,14 @@ pub fn get_governance_data(

// In previous versions of spl-gov (< 3) we had config.proposal_cool_off_time:u32 which was unused and always 0
// In version 3.0.0 proposal_cool_off_time was replaced with council_vote_threshold:VoteThreshold and council_veto_vote_threshold:VoteThreshold
//
// If we read a legacy account then council_vote_threshold == VoteThreshold::YesVotePercentage(0)
// and we coerce it to be equal to community_vote_threshold which was used for both council and community thresholds before
//
// Note: assert_is_valid_governance_config() prevents setting council_vote_threshold to VoteThreshold::YesVotePercentage(0)
// which gives as guarantee that it is a legacy account layout set with proposal_cool_off_time = 0
//
// Note: All the settings below are one time config migration from V1 & V2 account data to V3
if governance_data.config.council_vote_threshold == VoteThreshold::YesVotePercentage(0) {
// Set council_vote_threshold to community_vote_threshold which was used for both council and community thresholds before
governance_data.config.council_vote_threshold =
governance_data.config.community_vote_threshold.clone();

Expand All @@ -309,8 +313,17 @@ pub fn get_governance_data(
// For legacy accounts set the community Veto threshold to Disabled
governance_data.config.community_veto_vote_threshold = VoteThreshold::Disabled;

// Reset reserved space previously used for voting_proposal_count
governance_data.config.reserved = [0; 5];
// Reset voting_cool_off_time and reserved space previously used for voting_proposal_count

// Default voting_cool_off_time to 1h for max_voting_time >= 10h
governance_data.config.voting_cool_off_time =
if governance_data.config.max_voting_time >= 36000 {
3600
} else {
0
};
SebastianBor marked this conversation as resolved.
Show resolved Hide resolved

governance_data.config.reserved = 0;
}

Ok(governance_data)
Expand Down Expand Up @@ -478,6 +491,14 @@ pub fn assert_is_valid_governance_config(
return Err(GovernanceError::AtLeastOneVoteThresholdRequired.into());
}

if governance_config.voting_cool_off_time >= governance_config.max_voting_time {
return Err(GovernanceError::InvalidVotingCoolOffTime.into());
}

if governance_config.reserved != 0 {
return Err(GovernanceError::ReservedBufferMustBeEmpty.into());
}

Ok(())
}

Expand Down Expand Up @@ -516,7 +537,8 @@ mod test {
council_veto_vote_threshold: VoteThreshold::YesVotePercentage(50),
council_vote_tipping: VoteTipping::Strict,
community_veto_vote_threshold: VoteThreshold::YesVotePercentage(40),
reserved: [0; 5],
reserved: 0,
voting_cool_off_time: 2,
}
}

Expand Down Expand Up @@ -621,25 +643,15 @@ mod test {
governance.config.community_vote_tipping
);

assert_eq!(governance.config.reserved, [0; 5]);
assert_eq!(governance.config.reserved, 0);
assert_eq!(governance.config.voting_cool_off_time, 0);
}

#[test]
fn test_assert_config_invalid_with_council_zero_yes_vote_threshold() {
// Arrange
let governance_config = GovernanceConfig {
community_vote_threshold: VoteThreshold::YesVotePercentage(1),
min_community_weight_to_create_proposal: 1,
min_transaction_hold_up_time: 1,
max_voting_time: 1,
community_vote_tipping: VoteTipping::Strict,
council_vote_threshold: VoteThreshold::YesVotePercentage(0),
council_veto_vote_threshold: VoteThreshold::YesVotePercentage(1),
min_council_weight_to_create_proposal: 1,
council_vote_tipping: VoteTipping::Strict,
community_veto_vote_threshold: VoteThreshold::YesVotePercentage(1),
reserved: [0; 5],
};
let mut governance_config = create_test_governance_config();
governance_config.council_vote_threshold = VoteThreshold::YesVotePercentage(0);

// Act
let err = assert_is_valid_governance_config(&governance_config)
Expand All @@ -650,22 +662,72 @@ mod test {
assert_eq!(err, GovernanceError::InvalidVoteThresholdPercentage.into());
}

#[test]
fn test_migrate_governance_config_from_legacy_data_to_v3() {
// Arrange
let mut governance_legacy_data = create_test_governance();

governance_legacy_data.config.council_vote_threshold = VoteThreshold::YesVotePercentage(0);
governance_legacy_data.config.council_veto_vote_threshold =
VoteThreshold::YesVotePercentage(0);
governance_legacy_data.config.council_vote_tipping = VoteTipping::Disabled;
governance_legacy_data.config.community_veto_vote_threshold =
VoteThreshold::YesVotePercentage(0);
governance_legacy_data.config.voting_cool_off_time = 1;
governance_legacy_data.config.max_voting_time = 36000;

let mut legacy_data = vec![];
governance_legacy_data.serialize(&mut legacy_data).unwrap();

let program_id = Pubkey::new_unique();

let info_key = Pubkey::new_unique();
let mut lamports = 10u64;

let legacy_account_info = AccountInfo::new(
&info_key,
false,
false,
&mut lamports,
&mut legacy_data[..],
&program_id,
false,
Epoch::default(),
);
// Act
let governance_v3 = get_governance_data(&program_id, &legacy_account_info).unwrap();

// Assert
assert_eq!(
governance_v3.config.council_vote_threshold,
VoteThreshold::YesVotePercentage(60)
);

assert_eq!(
governance_v3.config.council_veto_vote_threshold,
VoteThreshold::YesVotePercentage(60)
);

assert_eq!(
governance_v3.config.community_veto_vote_threshold,
VoteThreshold::Disabled
);

assert_eq!(
governance_v3.config.council_vote_tipping,
VoteTipping::Strict
);

assert_eq!(governance_v3.config.voting_cool_off_time, 3600);

assert_eq!(governance_v3.config.reserved, 0);
}

#[test]
fn test_assert_config_invalid_with_community_zero_yes_vote_threshold() {
// Arrange
let governance_config = GovernanceConfig {
community_vote_threshold: VoteThreshold::YesVotePercentage(0),
min_community_weight_to_create_proposal: 1,
min_transaction_hold_up_time: 1,
max_voting_time: 1,
community_vote_tipping: VoteTipping::Strict,
council_vote_threshold: VoteThreshold::YesVotePercentage(1),
council_veto_vote_threshold: VoteThreshold::YesVotePercentage(1),
min_council_weight_to_create_proposal: 1,
council_vote_tipping: VoteTipping::Strict,
community_veto_vote_threshold: VoteThreshold::YesVotePercentage(1),
reserved: [0; 5],
};
let mut governance_config = create_test_governance_config();
governance_config.community_vote_threshold = VoteThreshold::YesVotePercentage(0);

// Act
let err = assert_is_valid_governance_config(&governance_config)
Expand All @@ -679,19 +741,9 @@ mod test {
#[test]
fn test_assert_config_invalid_with_all_vote_thresholds_disabled() {
// Arrange
let governance_config = GovernanceConfig {
community_vote_threshold: VoteThreshold::Disabled,
min_community_weight_to_create_proposal: 1,
min_transaction_hold_up_time: 1,
max_voting_time: 1,
community_vote_tipping: VoteTipping::Strict,
council_vote_threshold: VoteThreshold::Disabled,
council_veto_vote_threshold: VoteThreshold::YesVotePercentage(1),
min_council_weight_to_create_proposal: 1,
council_vote_tipping: VoteTipping::Strict,
community_veto_vote_threshold: VoteThreshold::YesVotePercentage(1),
reserved: [0; 5],
};
let mut governance_config = create_test_governance_config();
governance_config.community_vote_threshold = VoteThreshold::Disabled;
governance_config.council_vote_threshold = VoteThreshold::Disabled;

// Act
let err = assert_is_valid_governance_config(&governance_config)
Expand All @@ -705,19 +757,8 @@ mod test {
#[test]
fn test_assert_config_invalid_with_council_zero_yes_veto_vote_threshold() {
// Arrange
let governance_config = GovernanceConfig {
community_vote_threshold: VoteThreshold::YesVotePercentage(1),
min_community_weight_to_create_proposal: 1,
min_transaction_hold_up_time: 1,
max_voting_time: 1,
community_vote_tipping: VoteTipping::Strict,
council_vote_threshold: VoteThreshold::YesVotePercentage(1),
council_veto_vote_threshold: VoteThreshold::YesVotePercentage(0),
min_council_weight_to_create_proposal: 1,
council_vote_tipping: VoteTipping::Strict,
community_veto_vote_threshold: VoteThreshold::YesVotePercentage(1),
reserved: [0; 5],
};
let mut governance_config = create_test_governance_config();
governance_config.council_veto_vote_threshold = VoteThreshold::YesVotePercentage(0);

// Act
let err = assert_is_valid_governance_config(&governance_config)
Expand All @@ -731,19 +772,8 @@ mod test {
#[test]
fn test_assert_config_invalid_with_community_zero_yes_veto_vote_threshold() {
// Arrange
let governance_config = GovernanceConfig {
community_vote_threshold: VoteThreshold::YesVotePercentage(1),
min_community_weight_to_create_proposal: 1,
min_transaction_hold_up_time: 1,
max_voting_time: 1,
council_vote_tipping: VoteTipping::Strict,
council_vote_threshold: VoteThreshold::YesVotePercentage(1),
council_veto_vote_threshold: VoteThreshold::YesVotePercentage(1),
min_council_weight_to_create_proposal: 1,
community_veto_vote_threshold: VoteThreshold::YesVotePercentage(0),
community_vote_tipping: VoteTipping::Strict,
reserved: [0; 5],
};
let mut governance_config = create_test_governance_config();
governance_config.community_veto_vote_threshold = VoteThreshold::YesVotePercentage(0);

// Act
let err = assert_is_valid_governance_config(&governance_config)
Expand Down
Loading