1
// This file is part of Substrate.
2

            
3
// Copyright (C) Parity Technologies (UK) Ltd.
4
// SPDX-License-Identifier: Apache-2.0
5

            
6
// Licensed under the Apache License, Version 2.0 (the "License");
7
// you may not use this file except in compliance with the License.
8
// You may obtain a copy of the License at
9
//
10
// 	http://www.apache.org/licenses/LICENSE-2.0
11
//
12
// Unless required by applicable law or agreed to in writing, software
13
// distributed under the License is distributed on an "AS IS" BASIS,
14
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
// See the License for the specific language governing permissions and
16
// limitations under the License.
17

            
18
//! The vote datatype.
19

            
20
use crate::{Conviction, Delegations};
21
use codec::{Decode, Encode, EncodeLike, Input, MaxEncodedLen, Output};
22
use frame_support::{pallet_prelude::Get, BoundedVec};
23
use scale_info::TypeInfo;
24
use sp_runtime::{
25
	traits::{Saturating, Zero},
26
	RuntimeDebug,
27
};
28

            
29
/// A number of lock periods, plus a vote, one way or the other.
30
#[derive(Copy, Clone, Eq, PartialEq, Default, RuntimeDebug, MaxEncodedLen)]
31
pub struct Vote {
32
	pub aye: bool,
33
	pub conviction: Conviction,
34
}
35

            
36
impl Encode for Vote {
37
1233
	fn encode_to<T: Output + ?Sized>(&self, output: &mut T) {
38
1233
		output.push_byte(u8::from(self.conviction) | if self.aye { 0b1000_0000 } else { 0 });
39
1233
	}
40
}
41

            
42
impl EncodeLike for Vote {}
43

            
44
impl Decode for Vote {
45
741
	fn decode<I: Input>(input: &mut I) -> Result<Self, codec::Error> {
46
741
		let b = input.read_byte()?;
47
		Ok(Vote {
48
738
			aye: (b & 0b1000_0000) == 0b1000_0000,
49
738
			conviction: Conviction::try_from(b & 0b0111_1111)
50
738
				.map_err(|_| codec::Error::from("Invalid conviction"))?,
51
		})
52
741
	}
53
}
54

            
55
impl TypeInfo for Vote {
56
	type Identity = Self;
57

            
58
	fn type_info() -> scale_info::Type {
59
		scale_info::Type::builder()
60
			.path(scale_info::Path::new("Vote", module_path!()))
61
			.composite(
62
				scale_info::build::Fields::unnamed()
63
					.field(|f| f.ty::<u8>().docs(&["Raw vote byte, encodes aye + conviction"])),
64
			)
65
	}
66
}
67

            
68
/// A vote for a referendum of a particular account.
69
18
#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
70
pub enum AccountVote<Balance> {
71
741
	/// A standard vote, one-way (approve or reject) with a given amount of conviction.
72
741
	Standard { vote: Vote, balance: Balance },
73
75
	/// A split vote with balances given for both ways, and with no conviction, useful for
74
	/// parachains when voting.
75
75
	Split { aye: Balance, nay: Balance },
76
495
	/// A split vote with balances given for both ways as well as abstentions, and with no
77
	/// conviction, useful for parachains when voting, other off-chain aggregate accounts and
78
	/// individuals who wish to abstain.
79
495
	SplitAbstain { aye: Balance, nay: Balance, abstain: Balance },
80
}
81

            
82
impl<Balance: Saturating> AccountVote<Balance> {
83
	/// Returns `Some` of the lock periods that the account is locked for, assuming that the
84
	/// referendum passed iff `approved` is `true`.
85
	pub fn locked_if(self, approved: bool) -> Option<(u32, Balance)> {
86
		// winning side: can only be removed after the lock period ends.
87
		match self {
88
			AccountVote::Standard { vote: Vote { conviction: Conviction::None, .. }, .. } => None,
89
			AccountVote::Standard { vote, balance } if vote.aye == approved =>
90
				Some((vote.conviction.lock_periods(), balance)),
91
			_ => None,
92
		}
93
	}
94

            
95
	/// The total balance involved in this vote.
96
549
	pub fn balance(self) -> Balance {
97
549
		match self {
98
276
			AccountVote::Standard { balance, .. } => balance,
99
15
			AccountVote::Split { aye, nay } => aye.saturating_add(nay),
100
258
			AccountVote::SplitAbstain { aye, nay, abstain } =>
101
258
				aye.saturating_add(nay).saturating_add(abstain),
102
		}
103
549
	}
104

            
105
	/// Returns `Some` with whether the vote is an aye vote if it is standard, otherwise `None` if
106
	/// it is split.
107
72
	pub fn as_standard(self) -> Option<bool> {
108
72
		match self {
109
72
			AccountVote::Standard { vote, .. } => Some(vote.aye),
110
			_ => None,
111
		}
112
72
	}
113
}
114

            
115
/// A "prior" lock, i.e. a lock for some now-forgotten reason.
116
#[derive(
117
	Encode,
118
	Decode,
119
	Default,
120
	Copy,
121
	Clone,
122
	Eq,
123
	PartialEq,
124
	Ord,
125
	PartialOrd,
126
	RuntimeDebug,
127
	TypeInfo,
128
	MaxEncodedLen,
129
)]
130
pub struct PriorLock<BlockNumber, Balance>(BlockNumber, Balance);
131

            
132
impl<BlockNumber: Ord + Copy + Zero, Balance: Ord + Copy + Zero> PriorLock<BlockNumber, Balance> {
133
	/// Accumulates an additional lock.
134
	pub fn accumulate(&mut self, until: BlockNumber, amount: Balance) {
135
		self.0 = self.0.max(until);
136
		self.1 = self.1.max(amount);
137
	}
138

            
139
315
	pub fn locked(&self) -> Balance {
140
315
		self.1
141
315
	}
142

            
143
315
	pub fn rejig(&mut self, now: BlockNumber) {
144
315
		if now >= self.0 {
145
315
			self.0 = Zero::zero();
146
315
			self.1 = Zero::zero();
147
315
		}
148
315
	}
149
}
150

            
151
/// Information concerning the delegation of some voting power.
152
#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
153
pub struct Delegating<Balance, AccountId, BlockNumber> {
154
	/// The amount of balance delegated.
155
	pub balance: Balance,
156
	/// The account to which the voting power is delegated.
157
	pub target: AccountId,
158
	/// The conviction with which the voting power is delegated. When this gets undelegated, the
159
	/// relevant lock begins.
160
	pub conviction: Conviction,
161
	/// The total amount of delegations that this account has received, post-conviction-weighting.
162
	pub delegations: Delegations<Balance>,
163
	/// Any pre-existing locks from past voting/delegating activity.
164
	pub prior: PriorLock<BlockNumber, Balance>,
165
}
166

            
167
/// Information concerning the direct vote-casting of some voting power.
168
#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
169
#[scale_info(skip_type_params(MaxVotes))]
170
#[codec(mel_bound(Balance: MaxEncodedLen, BlockNumber: MaxEncodedLen, PollIndex: MaxEncodedLen))]
171
pub struct Casting<Balance, BlockNumber, PollIndex, MaxVotes>
172
where
173
	MaxVotes: Get<u32>,
174
{
175
	/// The current votes of the account.
176
	pub votes: BoundedVec<(PollIndex, AccountVote<Balance>), MaxVotes>,
177
	/// The total amount of delegations that this account has received, post-conviction-weighting.
178
	pub delegations: Delegations<Balance>,
179
	/// Any pre-existing locks from past voting/delegating activity.
180
	pub prior: PriorLock<BlockNumber, Balance>,
181
}
182

            
183
/// An indicator for what an account is doing; it can either be delegating or voting.
184
#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
185
#[scale_info(skip_type_params(MaxVotes))]
186
#[codec(mel_bound(
187
	Balance: MaxEncodedLen, AccountId: MaxEncodedLen, BlockNumber: MaxEncodedLen,
188
	PollIndex: MaxEncodedLen,
189
))]
190
pub enum Voting<Balance, AccountId, BlockNumber, PollIndex, MaxVotes>
191
where
192
	MaxVotes: Get<u32>,
193
{
194
135
	/// The account is voting directly.
195
135
	Casting(Casting<Balance, BlockNumber, PollIndex, MaxVotes>),
196
63
	/// The account is delegating `balance` of its balance to a `target` account with `conviction`.
197
63
	Delegating(Delegating<Balance, AccountId, BlockNumber>),
198
}
199

            
200
impl<Balance: Default, AccountId, BlockNumber: Zero, PollIndex, MaxVotes> Default
201
	for Voting<Balance, AccountId, BlockNumber, PollIndex, MaxVotes>
202
where
203
	MaxVotes: Get<u32>,
204
{
205
711
	fn default() -> Self {
206
711
		Voting::Casting(Casting {
207
711
			votes: Default::default(),
208
711
			delegations: Default::default(),
209
711
			prior: PriorLock(Zero::zero(), Default::default()),
210
711
		})
211
711
	}
212
}
213

            
214
impl<Balance, AccountId, BlockNumber, PollIndex, MaxVotes> AsMut<PriorLock<BlockNumber, Balance>>
215
	for Voting<Balance, AccountId, BlockNumber, PollIndex, MaxVotes>
216
where
217
	MaxVotes: Get<u32>,
218
{
219
315
	fn as_mut(&mut self) -> &mut PriorLock<BlockNumber, Balance> {
220
315
		match self {
221
315
			Voting::Casting(Casting { prior, .. }) => prior,
222
			Voting::Delegating(Delegating { prior, .. }) => prior,
223
		}
224
315
	}
225
}
226

            
227
impl<
228
		Balance: Saturating + Ord + Zero + Copy,
229
		BlockNumber: Ord + Copy + Zero,
230
		AccountId,
231
		PollIndex,
232
		MaxVotes,
233
	> Voting<Balance, AccountId, BlockNumber, PollIndex, MaxVotes>
234
where
235
	MaxVotes: Get<u32>,
236
{
237
315
	pub fn rejig(&mut self, now: BlockNumber) {
238
315
		AsMut::<PriorLock<BlockNumber, Balance>>::as_mut(self).rejig(now);
239
315
	}
240

            
241
	/// The amount of this account's balance that must currently be locked due to voting.
242
315
	pub fn locked_balance(&self) -> Balance {
243
315
		match self {
244
315
			Voting::Casting(Casting { votes, prior, .. }) =>
245
315
				votes.iter().map(|i| i.1.balance()).fold(prior.locked(), |a, i| a.max(i)),
246
			Voting::Delegating(Delegating { balance, prior, .. }) => *balance.max(&prior.locked()),
247
		}
248
315
	}
249

            
250
102
	pub fn set_common(
251
102
		&mut self,
252
102
		delegations: Delegations<Balance>,
253
102
		prior: PriorLock<BlockNumber, Balance>,
254
102
	) {
255
102
		let (d, p) = match self {
256
			Voting::Casting(Casting { ref mut delegations, ref mut prior, .. }) =>
257
				(delegations, prior),
258
102
			Voting::Delegating(Delegating { ref mut delegations, ref mut prior, .. }) =>
259
102
				(delegations, prior),
260
		};
261
102
		*d = delegations;
262
102
		*p = prior;
263
102
	}
264
}