1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use sn_data_types::{Error, Money, Result, RewardCounter};
pub struct RewardCounterSet {
quorum: usize,
counters: Vec<RewardCounter>,
}
impl RewardCounterSet {
pub fn new(expected_counters: usize, counters: Vec<RewardCounter>) -> Result<Self> {
if expected_counters % 2 == 0 || 3 > expected_counters {
return Err(Error::InvalidOperation);
}
let quorum = (expected_counters / 3) * 2;
Ok(Self { quorum, counters })
}
pub fn len(&self) -> usize {
self.counters.len()
}
pub fn is_empty(&self) -> bool {
self.counters.is_empty()
}
pub fn add(&mut self, counter: RewardCounter) {
self.counters.push(counter)
}
pub fn agreed_value(&self) -> Option<RewardCounter> {
let count = self.counters.len();
if self.quorum > count {
return None;
}
let median_reward = self.median_reward();
let median_work = self.median_work();
Some(RewardCounter {
reward: median_reward,
work: median_work,
})
}
fn median_reward(&self) -> Money {
let mut rewards: Vec<Money> = self
.counters
.clone()
.into_iter()
.map(|c| c.reward)
.collect();
rewards.sort();
if rewards.len() % 2 == 0 {
let mid_0 = rewards.len() / 2;
let mid_1 = (rewards.len() / 2) + 1;
let mid_0 = rewards.clone().remove(mid_0).as_nano();
let mid_1 = rewards.remove(mid_1).as_nano();
Money::from_nano((mid_0 + mid_1) / 2)
} else {
let mid = rewards.len() / 2;
rewards.remove(mid)
}
}
fn median_work(&self) -> u64 {
let mut works: Vec<u64> = self.counters.clone().into_iter().map(|c| c.work).collect();
works.sort();
if works.len() % 2 == 0 {
let mid_0 = works.len() / 2;
let mid_1 = (works.len() / 2) + 1;
let mid_0 = works.clone().remove(mid_0);
let mid_1 = works.remove(mid_1);
(mid_0 + mid_1) / 2
} else {
let mid = works.len() / 2;
works.remove(mid)
}
}
}