Skip to content

Commit

Permalink
staking: added process_votes() to on_vote() function
Browse files Browse the repository at this point in the history
  • Loading branch information
martinfridrich committed Jul 24, 2023
1 parent 13d9f04 commit 71814fa
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 41 deletions.
105 changes: 66 additions & 39 deletions pallets/staking/src/integrations/democracy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ use crate::traits::DemocracyReferendum;
use crate::types::{Balance, Conviction, Vote};
use crate::{Config, Error, Pallet};
use frame_support::dispatch::DispatchResult;
use frame_system::Origin;
use frame_support::traits::DefensiveOption;
use orml_traits::MultiCurrencyExtended;
use pallet_democracy::traits::DemocracyHooks;
use pallet_democracy::{AccountVote, ReferendumIndex, ReferendumInfo};
use sp_core::Get;

pub struct StakingDemocracy<T>(sp_std::marker::PhantomData<T>);

Expand All @@ -21,48 +20,51 @@ where
} else {
return Ok(());
};
let position = if let Some(position) = Positions::<T>::get(position_id) {
position
} else {
return Ok(());
};

let amount = vote.balance();
let conviction = if let AccountVote::Standard { vote, .. } = vote {
match vote.conviction {
pallet_democracy::Conviction::None => Conviction::None,
pallet_democracy::Conviction::Locked1x => Conviction::Locked1x,
pallet_democracy::Conviction::Locked2x => Conviction::Locked2x,
pallet_democracy::Conviction::Locked3x => Conviction::Locked3x,
pallet_democracy::Conviction::Locked4x => Conviction::Locked4x,
pallet_democracy::Conviction::Locked5x => Conviction::Locked5x,
pallet_democracy::Conviction::Locked6x => Conviction::Locked6x,
}
} else {
Conviction::default()
};
Positions::<T>::try_mutate(position_id, |maybe_position| {
let position = maybe_position
.as_mut()
.defensive_ok_or(crate::Error::<T>::InconsistentState(
crate::InconsistentStateError::PositionNotFound,
))?;

let staking_vote = Vote {
amount: amount.min(position.stake), // use only max staked amount
conviction,
};
Pallet::<T>::process_votes(position_id, position)?;

PositionVotes::<T>::try_mutate(position_id, |voting| -> DispatchResult {
match voting.votes.binary_search_by_key(&ref_index, |value| value.0) {
Ok(idx) => {
let _ = sp_std::mem::replace(&mut voting.votes[idx], (ref_index, staking_vote));
}
Err(idx) => {
voting
.votes
.try_insert(idx, (ref_index, staking_vote))
.map_err(|_| Error::<T>::MaxVotesReached)?;
let amount = vote.balance();
let conviction = if let AccountVote::Standard { vote, .. } = vote {
match vote.conviction {
pallet_democracy::Conviction::None => Conviction::None,
pallet_democracy::Conviction::Locked1x => Conviction::Locked1x,
pallet_democracy::Conviction::Locked2x => Conviction::Locked2x,
pallet_democracy::Conviction::Locked3x => Conviction::Locked3x,
pallet_democracy::Conviction::Locked4x => Conviction::Locked4x,
pallet_democracy::Conviction::Locked5x => Conviction::Locked5x,
pallet_democracy::Conviction::Locked6x => Conviction::Locked6x,
}
}
Ok(())
})?;
} else {
Conviction::default()
};

Ok(())
let staking_vote = Vote {
amount: amount.min(position.stake), // use only max staked amount
conviction,
};

PositionVotes::<T>::try_mutate(position_id, |voting| -> DispatchResult {
match voting.votes.binary_search_by_key(&ref_index, |value| value.0) {
Ok(idx) => {
let _ = sp_std::mem::replace(&mut voting.votes[idx], (ref_index, staking_vote));
}
Err(idx) => {
voting
.votes
.try_insert(idx, (ref_index, staking_vote))
.map_err(|_| Error::<T>::MaxVotesReached)?;
}
}
Ok(())
})
})
}

fn on_remove_vote(who: &T::AccountId, ref_index: ReferendumIndex) -> DispatchResult {
Expand All @@ -83,6 +85,9 @@ where

#[cfg(feature = "runtime-benchmarks")]
fn on_vote_worst_case(who: &T::AccountId) {
use frame_system::Origin;
use sp_core::Get;

T::Currency::update_balance(
T::HdxAssetId::get(),
&Pallet::<T>::pot_account_id(),
Expand All @@ -92,10 +97,32 @@ where
Pallet::<T>::initialize_staking(Origin::<T>::Root.into()).unwrap();
T::Currency::update_balance(T::HdxAssetId::get(), who, 1_000_000_000_000_000i128).unwrap();
Pallet::<T>::stake(Origin::<T>::Signed(who.clone()).into(), 1_000_000_000_000_000u128).unwrap();

let position_id = Pallet::<T>::get_user_position_id(&who.clone()).unwrap().unwrap();

let mut votes = sp_std::vec::Vec::<(u32, Vote)>::new();
for i in 0..<T as crate::pallet::Config>::MaxVotes::get() {
votes.push((
i,
Vote {
amount: 20_000_000_000_000_000,
conviction: Conviction::Locked1x,
},
));
}

let voting = crate::types::Voting::<T::MaxVotes> {
votes: votes.try_into().unwrap(),
};

crate::PositionVotes::<T>::insert(position_id, voting);
}

#[cfg(feature = "runtime-benchmarks")]
fn on_remove_vote_worst_case(who: &T::AccountId) {
use frame_system::Origin;
use sp_core::Get;

T::Currency::update_balance(
T::HdxAssetId::get(),
&Pallet::<T>::pot_account_id(),
Expand Down
5 changes: 4 additions & 1 deletion pallets/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -869,7 +869,10 @@ impl<T: Config> Pallet<T> {
}
}

fn process_votes(position_id: T::PositionItemId, position: &mut Position<T::BlockNumber>) -> DispatchResult {
pub(crate) fn process_votes(
position_id: T::PositionItemId,
position: &mut Position<T::BlockNumber>,
) -> DispatchResult {
PositionVotes::<T>::mutate(position_id, |voting| {
voting.votes.retain(|(ref_idx, vote)| {
if T::ReferendumInfo::is_referendum_finished(*ref_idx) {
Expand Down
100 changes: 99 additions & 1 deletion pallets/staking/src/tests/process_votes.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use crate::types::{Conviction, Vote};
use crate::{
integrations::democracy::StakingDemocracy,
types::{Conviction, Vote},
};

use super::*;

use mock::Staking;
use pallet_democracy::{traits::DemocracyHooks, AccountVote};
use pretty_assertions::assert_eq;

//NOTE: Referendums with even indexes are finished.
Expand Down Expand Up @@ -261,3 +265,97 @@ fn process_votes_should_do_nothing_when_referendum_doesnt_exists() {
assert_eq!(position_before, position);
});
}

#[test]
fn process_votes_should_work_when_on_vote_is_called() {
ExtBuilder::default()
.with_endowed_accounts(vec![
(ALICE, HDX, 150_000 * ONE),
(BOB, HDX, 250_000 * ONE),
(CHARLIE, HDX, 10_000 * ONE),
(DAVE, HDX, 100_000 * ONE),
])
.start_at_block(1_452_987)
.with_initialized_staking()
.with_stakes(vec![
(ALICE, 100_000 * ONE, 1_452_987, 200_000 * ONE),
(BOB, 120_000 * ONE, 1_452_987, 0),
(CHARLIE, 10_000 * ONE, 1_455_000, 10_000 * ONE),
(DAVE, 10 * ONE, 1_465_000, 1),
])
.with_votings(vec![(
1,
vec![
(
1_u32,
Vote {
amount: 10_000 * ONE,
conviction: Conviction::Locked4x,
},
),
(
2_u32,
Vote {
amount: 10_000 * ONE,
conviction: Conviction::Locked2x,
},
),
(
3_u32,
Vote {
amount: 10_000 * ONE,
conviction: Conviction::None,
},
),
(
4_u32,
Vote {
amount: 230_000 * ONE,
conviction: Conviction::Locked1x,
},
),
(
8_u32,
Vote {
amount: 230_000 * ONE,
conviction: Conviction::Locked1x,
},
),
(
6_u32,
Vote {
amount: 2 * ONE,
conviction: Conviction::Locked3x,
},
),
],
)])
.build()
.execute_with(|| {
let position_id = 1;
let position_before = Staking::positions(position_id).unwrap();

//Act
assert_ok!(StakingDemocracy::<Test>::on_vote(
&BOB,
7,
AccountVote::Standard {
balance: 1_000 * ONE,
vote: pallet_democracy::Vote {
aye: true,
conviction: pallet_democracy::Conviction::None
}
}
));

//Assert
assert_eq!(
Position {
action_points: 950_008_u128,
..position_before
},
Staking::positions(position_id).unwrap()
);
assert_eq!(PositionVotes::<Test>::get(position_id).votes.len(), 3);
});
}

0 comments on commit 71814fa

Please sign in to comment.