finality_grandpa/round/
context.rs1use crate::{
19 bitfield::{Bit1, Bitfield},
20 std::ops::AddAssign,
21 voter_set::{VoterInfo, VoterSet},
22 weights::VoteWeight,
23};
24
25use super::Phase;
26
27#[cfg_attr(any(feature = "std", test), derive(Debug))]
29#[cfg_attr(test, derive(Clone))]
30pub struct Context<T: Ord + Eq> {
31 voters: VoterSet<T>,
32 equivocations: Bitfield,
33}
34
35impl<T: Ord + Eq> Context<T> {
36 pub fn new(voters: VoterSet<T>) -> Self {
38 Context { voters, equivocations: Bitfield::new() }
39 }
40
41 pub fn voters(&self) -> &VoterSet<T> {
43 &self.voters
44 }
45
46 pub fn equivocation_weight(&self, p: Phase) -> VoteWeight {
48 match p {
49 Phase::Prevote => weight(self.equivocations.iter1s_even(), &self.voters),
50 Phase::Precommit => weight(self.equivocations.iter1s_odd(), &self.voters),
51 }
52 }
53
54 pub fn equivocated(&mut self, v: &VoterInfo, p: Phase) {
56 self.equivocations.set_bit(Vote::new(v, p).bit.position);
57 }
58
59 pub fn weight(&self, n: &VoteNode, p: Phase) -> VoteWeight {
62 if self.equivocations.is_blank() {
63 match p {
64 Phase::Prevote => weight(n.bits.iter1s_even(), &self.voters),
65 Phase::Precommit => weight(n.bits.iter1s_odd(), &self.voters),
66 }
67 } else {
68 match p {
69 Phase::Prevote => {
70 let bits = n.bits.iter1s_merged_even(&self.equivocations);
71 weight(bits, &self.voters)
72 },
73 Phase::Precommit => {
74 let bits = n.bits.iter1s_merged_odd(&self.equivocations);
75 weight(bits, &self.voters)
76 },
77 }
78 }
79 }
80}
81
82pub struct Vote {
84 bit: Bit1,
85}
86
87impl Vote {
88 pub fn new(v: &VoterInfo, p: Phase) -> Vote {
90 Vote {
91 bit: Bit1 {
92 position: match p {
93 Phase::Prevote => v.position() * 2,
94 Phase::Precommit => v.position() * 2 + 1,
95 },
96 },
97 }
98 }
99
100 fn voter<'a, Id>(&'a self, vs: &'a VoterSet<Id>) -> Option<(&'a Id, &'a VoterInfo)>
103 where
104 Id: Eq + Ord,
105 {
106 vs.nth(self.bit.position / 2)
107 }
108}
109
110#[derive(Clone, Debug)]
115pub struct VoteNode {
116 bits: Bitfield,
117}
118
119impl Default for VoteNode {
120 fn default() -> Self {
121 Self { bits: Bitfield::new() }
122 }
123}
124
125impl AddAssign<&VoteNode> for VoteNode {
126 fn add_assign(&mut self, rhs: &VoteNode) {
127 self.bits.merge(&rhs.bits);
128 }
129}
130
131impl AddAssign<&Vote> for VoteNode {
132 fn add_assign(&mut self, rhs: &Vote) {
133 self.bits.set_bit(rhs.bit.position);
134 }
135}
136
137fn weight<V, I>(bits: I, voters: &VoterSet<V>) -> VoteWeight
140where
141 V: Eq + Ord,
142 I: Iterator<Item = Bit1>,
143{
144 let mut total = VoteWeight(0);
145
146 for bit in bits {
147 let vote = Vote { bit };
148 if let Some((_id, v)) = vote.voter(voters) {
149 total = total + v.weight()
150 }
151 }
152
153 total
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159 use crate::std::vec::Vec;
160 use quickcheck::*;
161
162 impl Arbitrary for Phase {
163 fn arbitrary(g: &mut Gen) -> Self {
164 *g.choose(&[Phase::Prevote, Phase::Precommit]).unwrap()
165 }
166 }
167
168 impl Arbitrary for Context<usize> {
169 fn arbitrary(g: &mut Gen) -> Self {
170 let mut ctx = Context::new(VoterSet::arbitrary(g));
171
172 let n = usize::arbitrary(g) % ctx.voters.len().get();
173 let equivocators = (0..=n)
174 .map(|_| ctx.voters.nth_mod(usize::arbitrary(g)).1.clone())
175 .collect::<Vec<_>>();
176
177 for v in equivocators {
178 ctx.equivocated(&v, Phase::arbitrary(g))
179 }
180
181 ctx
182 }
183 }
184
185 #[test]
186 fn vote_voter() {
187 fn prop(vs: VoterSet<usize>, phase: Phase) {
188 for (id, v) in vs.iter() {
189 assert_eq!(Vote::new(v, phase).voter(&vs), Some((id, v)))
190 }
191 }
192
193 quickcheck(prop as fn(_, _))
194 }
195
196 #[test]
197 fn weights() {
198 fn prop(ctx: Context<usize>, phase: Phase, voters: Vec<usize>) {
199 let e = ctx.equivocation_weight(phase);
200 let t = ctx.voters.total_weight();
201
202 assert!(e <= t);
205
206 let mut n = VoteNode::default();
209 let mut expected = e;
210 for v in voters {
211 let (_id, v) = ctx.voters.nth_mod(v);
212 let vote = Vote::new(v, phase);
213
214 if !ctx.equivocations.test_bit(vote.bit.position) &&
217 !n.bits.test_bit(vote.bit.position)
218 {
219 expected = expected + v.weight();
220 }
221
222 n += &vote;
223 }
224
225 let w = ctx.weight(&n, phase);
227
228 assert!(w <= t);
230
231 assert_eq!(w, expected);
232 }
233
234 quickcheck(prop as fn(_, _, _))
235 }
236}