-
Notifications
You must be signed in to change notification settings - Fork 353
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
Reject proposals early #668
Conversation
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll be back to review actual implementation, commented only obvious stuff so far.
if status == Status::Open && self.expires.is_expired(block) { | ||
status = Status::Rejected; | ||
} | ||
if status == Status::Open && self.is_rejected(block) { | ||
status = Status::Rejected; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if status == Status::Open && self.expires.is_expired(block) { | |
status = Status::Rejected; | |
} | |
if status == Status::Open && self.is_rejected(block) { | |
status = Status::Rejected; | |
} | |
if status == Status::Open && (self.expires.is_expired(block) || self.is_rejected(block)) { | |
status = Status::Rejected; | |
} |
/// returns true iff this proposal is sure to pass (even before expiration if no future | ||
/// sequence of possible votes can cause it to fail) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// returns true iff this proposal is sure to pass (even before expiration if no future | |
/// sequence of possible votes can cause it to fail) | |
/// returns true if this proposal is sure to pass (even before expiration, if no future | |
/// sequence of possible votes could cause it to fail) |
/// As above for the rejected check, used to check if a proposal is | ||
/// already rejected. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO doc comments shouldn't state "as above`, since "above" part won't be shown by IDE, rust compiled docs etc.
/// This function returns true if and only if vote_count is greater than the threshold which | ||
/// is calculated. | ||
/// In the case where we use yes votes, this function will return true if and only if the | ||
/// proposal will pass. | ||
/// In the case where we use no votes, this function will return true if and only if the | ||
/// proposal will be rejected regardless of other votes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// This function returns true if and only if vote_count is greater than the threshold which | |
/// is calculated. | |
/// In the case where we use yes votes, this function will return true if and only if the | |
/// proposal will pass. | |
/// In the case where we use no votes, this function will return true if and only if the | |
/// proposal will be rejected regardless of other votes. | |
/// This function returns true if vote_count is greater than the threshold. | |
/// In the case where we use `yes` votes, this function will return true if the proposal will pass. | |
/// In the case where we use `no` votes, this function will return true if the proposal will be | |
/// rejected, regardless of other votes. |
Those "if and only if" are redundant, as well as some other stuff..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks for the contribution.
Co-authored-by: Mauro Lacy <maurolacy@users.noreply.github.com>
Co-authored-by: Mauro Lacy <maurolacy@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is rejected doesn't work if the threshold deviates from 50%.
Added suggestions how to fix code and tests
match self.threshold { | ||
Threshold::AbsoluteCount { | ||
weight: weight_needed, | ||
} => self.votes.yes >= weight_needed, | ||
} => vote_count >= weight_needed, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check doesn't work properly of no votes. I would implement it sepately rather than combining.
Assume a threshold of 67%.
If we have 40% yes and 40% no, it would return false for both.
However, this could be safely marked as rejected.
Your logic works fine when the threshold is 50% (same for both).
I would propose not renaming the function and using it for both cases (as done here), but rather copying is_passed to is_rejected and make the various logic changes there needed (often 1-threshold or such). This is different for each branch and hard to generalise. Better to have two separate functions than combine them
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're completely right, will try and address this today
let info = mock_info(VOTER4, &[]); | ||
let res = execute(deps.as_mut(), mock_env(), info, no_vote).unwrap(); | ||
|
||
// Verify it is now rejected due to reaching threshold |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually a test showing the code is broken.
setup_test_case
adds 6 voters with a total weight of 16.
This test cases constructs an example with the odd configuration of 3 votes to reach threshold.
4 no votes should not mark it as rejected. You should require 14 no votes to ensure it is rejected.
I would propose a separate test function to cover this.
#[test] | ||
fn proposal_rejected_quorum() { | ||
let quorum = Threshold::ThresholdQuorum { | ||
threshold: Decimal::percent(50), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use threshold = Decimal::percent(60) so we can test the real case. Then fix the logic to match
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice fix.
Just request two minor changes, which don't affect correctness
.add_attribute("status", "Open") | ||
); | ||
|
||
// Voter 2 votes no, weight 2, total weight for no so far 15, need 14. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Threshold::AbsoluteCount { | ||
weight: weight_needed, | ||
} => { | ||
let weight = self.total_weight - weight_needed; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is good
self.votes.no | ||
> votes_needed( | ||
self.total_weight - self.votes.abstain, | ||
Decimal::one() - percentage_needed, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is proper place. Nice eye
) | ||
} | ||
Threshold::ThresholdQuorum { threshold, quorum } => { | ||
// we always require the quorum |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need this check. This is just needed for is_passed
If threshold is 67% and quorum is 40%, then 35% no votes should guarantee rejected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great work. merging
true | ||
)); | ||
|
||
// Check edgecase where quorum is not met but we can reject |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💯
Good catch! |
Addresses Issue #665
Implemented what I implemented for DAO DAO here for the multisigs. If I have missed any functionality or coverage do say.
Feedback appreciated.