-
Notifications
You must be signed in to change notification settings - Fork 856
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
pallet-conviction-voting: add voting hooks #5735
base: master
Are you sure you want to change the base?
pallet-conviction-voting: add voting hooks #5735
Conversation
@@ -0,0 +1,40 @@ | |||
use crate::AccountVote; |
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.
Missing license header.
pub trait VotingHooks<AccountId, Index, Balance> { | ||
// Called when vote is executed. | ||
fn on_vote(who: &AccountId, ref_index: Index, vote: AccountVote<Balance>) -> DispatchResult; | ||
|
||
// Called when removed vote is executed. | ||
// is_finished indicates the state of the referendum = None if referendum is cancelled, Some(true) if referendum is ongoing and Some(false) when finished. | ||
fn on_remove_vote(who: &AccountId, ref_index: Index, ongoing: Option<bool>); | ||
|
||
// Called when removed vote is executed and voter lost the direction to possibly lock some balance. | ||
// Can return an amount that should be locked for the conviction time. | ||
fn balance_locked_on_unsuccessful_vote(who: &AccountId, ref_index: Index) -> Option<Balance>; | ||
|
||
#[cfg(feature = "runtime-benchmarks")] | ||
fn on_vote_worst_case(who: &AccountId); | ||
|
||
#[cfg(feature = "runtime-benchmarks")] | ||
fn on_remove_vote_worst_case(who: &AccountId); | ||
} |
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.
Please improve the docs.
|
||
// Called when removed vote is executed. | ||
// is_finished indicates the state of the referendum = None if referendum is cancelled, Some(true) if referendum is ongoing and Some(false) when finished. | ||
fn on_remove_vote(who: &AccountId, ref_index: Index, ongoing: Option<bool>); |
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.
ongoing
should be an enum that expresses the state better.
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.
@bkchr, My plan is to replace the bool
by a generic, and use the trait Config
to bring in the enum ReferendumInfo
from pallet_referenda
:
In conviction_voting
runtime implementation, I see that the type Polls
is defined as Referenda
. is it possible through Polls
in the trait Config
to bring the enum ReferendumInfo
in conviction_voting
and use it here? or do we necessarily need to add the corresponding type in the runtime implementation & the trait config?
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 don't really understand your plan. Why not just make it an enum as I said above?
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 the enum items are the same I just thought it would be nice to re-use what we already have in pallet-referenda. And as we have a connection between conviction-voting and referenda in the runtime implementation....
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.
The pallets are not tightly coupled and I also don't see a reason why we should do this here now. Let's try some custom enum for now :)
@@ -487,10 +496,36 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { | |||
); | |||
prior.accumulate(unlock_at, balance) | |||
} | |||
} else if v.1.as_standard() == Some(!approved) { |
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.
locked_if
should be changed to take an enum
enum LockedIf {
Status(bool),
Always,
}
Always
would only be set when the balance_locked_on_unsuccessful_vote
returns so.
// Call on_vote hook | ||
T::VotingHooks::on_vote(who, poll_index, vote)?; |
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 would move this outside of try_access_poll
call
@jak-pan will someone from your side finish this or should I do this? |
Description
We, at Hydration, need to perform additional actions when a new vote is registered and existing vote is removed. Our use case is tied to staking, where we need to reward an account for voting.
Therefore, we need to know when a new vote is registered. We propose this PR to add voting hooks to the conviction-voting pallet.
This change does not change the original behavior ( except one special case described below if desired).
In the pallet config, there is a new config parameter:
Anything that integrates conviction-voting pallet, can decide to implement the voting hooks and perform desirable action on events such as
on_vote
andon_remove_vote
.The
VotingHooks
traits looks like:The
on_vote
andon_remove_vote
are pretty self-explanatory and are called when a vote is added/removed.There is a hook called
balance_locked_on_unsuccessful_vote
. This is a special hook that is called when a vote that is being removed was in opposition to the winning vote.The result of this function can return a balance and that amount will be locked for the conviction time. This is the only change that modifies original behavior of the pallet where there was no locking in such case.
It is a special case, where a chain can decide that it needs to lock some balance even in the case of not-winning vote. We, at Hydration, use these hooks with staking functionality where we require to lock too in such cases. Obviously, returning None by defaut, completely disables this feature and its behavior remains as it is.
Integration
To integrate
VotingHooks
and to perform certain actions as described above, it is required to implement corresponding trait.Otherwise, simple
can be used and conviction-voting pallet works as nothing happens.
Review Notes
The hooks are called in
try_vote
andtry_remove_vote
with parameters.on_vote hook needs an account that voted on referendum identified by
ref_index
and the vote itself.on_remove_vote needs an account that is removing the vote from referendum identified by
ref_index
. Also bool flag is added to provide information if the referendum is still ongoing.ongoing flag is an option because value None is used when referendum has been cancelled.
Tests
Unit tests are added to verify that each hooks is called with correct parameters.
Benchmarks
VotingHook trait contains:
These are called in benchmarks to set up worst cases for the hooks.
Question/Consideration: WE considered adding BenchmarkHelper instead of having the
runtime-benchmarks
functions in the trait. But I believe this is easier to understand when and why it needs to implement worst cases scenarios ( only if voting hook is used).