Skip to content

Commit bcd84ac

Browse files
committed
Implement PriorityCollector
1 parent 7fb8a73 commit bcd84ac

File tree

5 files changed

+187
-2
lines changed

5 files changed

+187
-2
lines changed

core/src/consensus/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub use self::cuckoo::Cuckoo;
3131
pub use self::null_engine::NullEngine;
3232
pub use self::simple_poa::SimplePoA;
3333
pub use self::solo::Solo;
34+
pub use self::sortition::vrf_sortition::{Priority, PriorityInfo, VRFSortition};
3435
pub use self::tendermint::{
3536
ConsensusMessage, Height, Step, Tendermint, TendermintParams, TimeGapParams, View, VoteOn, VoteStep,
3637
};

core/src/consensus/sortition/vrf_sortition.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub struct VRFSortition {
3636
pub vrf_inst: Arc<RwLock<ECVRF>>,
3737
}
3838

39-
#[derive(Eq, PartialEq, Debug, RlpEncodable, RlpDecodable)]
39+
#[derive(Eq, PartialEq, Clone, Debug, RlpEncodable, RlpDecodable)]
4040
pub struct PriorityInfo {
4141
priority: Priority,
4242
sub_user_idx: u64,

core/src/consensus/tendermint/message.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ pub use super::super::sortition::PriorityMessage;
2727
use super::super::BitSet;
2828
use super::{Height, Step, View};
2929

30+
/// Step for the sortition round.
31+
/// FIXME: It has a large overlap with the previous VoteStep.
32+
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, RlpDecodable, RlpEncodable)]
33+
pub struct SortitionRound {
34+
pub height: Height,
35+
pub view: View,
36+
}
37+
3038
/// Complete step of the consensus process.
3139
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, RlpDecodable, RlpEncodable)]
3240
pub struct VoteStep {
@@ -73,6 +81,18 @@ impl Ord for VoteStep {
7381
}
7482
}
7583

84+
impl PartialOrd for SortitionRound {
85+
fn partial_cmp(&self, other: &SortitionRound) -> Option<cmp::Ordering> {
86+
Some(self.cmp(other))
87+
}
88+
}
89+
90+
impl Ord for SortitionRound {
91+
fn cmp(&self, other: &SortitionRound) -> cmp::Ordering {
92+
(self.height, self.view).cmp(&(other.height, other.view))
93+
}
94+
}
95+
7696
const MESSAGE_ID_CONSENSUS_MESSAGE: u8 = 0x01;
7797
const MESSAGE_ID_PROPOSAL_BLOCK: u8 = 0x02;
7898
const MESSAGE_ID_STEP_STATE: u8 = 0x03;

core/src/consensus/tendermint/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ mod engine;
2020
mod message;
2121
mod network;
2222
mod params;
23+
pub mod sortition_info_collector;
2324
pub mod types;
2425
pub mod vote_collector;
2526
mod vote_regression_checker;
@@ -35,7 +36,7 @@ use ctimer::TimerToken;
3536
use parking_lot::RwLock;
3637

3738
use self::chain_notify::TendermintChainNotify;
38-
pub use self::message::{ConsensusMessage, VoteOn, VoteStep};
39+
pub use self::message::{ConsensusMessage, PriorityMessage, SortitionRound, VoteOn, VoteStep};
3940
pub use self::params::{TendermintParams, TimeGapParams, TimeoutParams};
4041
pub use self::types::{Height, Step, View};
4142
use super::{stake, ValidatorSet};
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
// Copyright 2019 Kodebox, Inc.
2+
// This file is part of CodeChain.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as
6+
// published by the Free Software Foundation, either verion 3 of the
7+
// License, or (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
17+
use std::cmp::Ordering;
18+
use std::collections::{BTreeMap, BinaryHeap};
19+
20+
use rug::{integer::Order, Integer};
21+
22+
use super::{PriorityMessage, SortitionRound};
23+
use crate::consensus::PriorityInfo;
24+
25+
/// Storing Priorities
26+
#[derive(Default)]
27+
pub struct SortitionInfoCollector {
28+
priorities: BTreeMap<SortitionRound, BinaryHeap<SortitionInfo>>,
29+
}
30+
31+
#[cfg_attr(test, derive(Debug))]
32+
#[derive(Eq, PartialEq)]
33+
pub struct SortitionInfo {
34+
priority_info: PriorityInfo,
35+
signer_idx: usize,
36+
}
37+
38+
impl Ord for SortitionInfo {
39+
fn cmp(&self, other: &Self) -> Ordering {
40+
let self_as_int = Integer::from_digits(&self.priority_info.priority(), Order::MsfBe);
41+
let other_as_int = Integer::from_digits(&other.priority_info.priority(), Order::MsfBe);
42+
43+
self_as_int.cmp(&other_as_int)
44+
}
45+
}
46+
47+
impl PartialOrd for SortitionInfo {
48+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
49+
Some(self.cmp(other))
50+
}
51+
}
52+
53+
impl SortitionInfo {
54+
pub fn from_message_and_idx(message: &PriorityMessage, signer_idx: usize) -> Self {
55+
Self {
56+
priority_info: message.info.clone(),
57+
signer_idx,
58+
}
59+
}
60+
}
61+
62+
impl SortitionInfoCollector {
63+
pub fn insert(&mut self, message: &PriorityMessage, signer_idx: usize, round: SortitionRound) {
64+
let info_summary = SortitionInfo::from_message_and_idx(message, signer_idx);
65+
self.priorities.entry(round).or_insert_with(Default::default).push(info_summary);
66+
}
67+
68+
pub fn get_highest_priority(&mut self, round: SortitionRound) -> Option<SortitionInfo> {
69+
self.priorities.entry(round).or_default().pop()
70+
}
71+
72+
/// Throw away priorities older than the given round.
73+
pub fn throw_away_old(&mut self, round: &SortitionRound) {
74+
let new_collector = self.priorities.split_off(round);
75+
assert!(!new_collector.is_empty());
76+
self.priorities = new_collector;
77+
}
78+
}
79+
80+
#[cfg(test)]
81+
mod sortition_info_collector_tests {
82+
use super::*;
83+
use crate::consensus::Priority;
84+
85+
fn generate_priority_info_with_priority(priority: Priority) -> PriorityInfo {
86+
PriorityInfo::create_from_members(priority, 0, vec![], vec![])
87+
}
88+
89+
#[test]
90+
fn compare_sortition_info() {
91+
let greater_priority_info_summary = SortitionInfo {
92+
priority_info: generate_priority_info_with_priority(0xffu64.into()),
93+
signer_idx: 0,
94+
};
95+
let less_priority_info_summary = SortitionInfo {
96+
priority_info: generate_priority_info_with_priority(0x7fu64.into()),
97+
signer_idx: 1,
98+
};
99+
assert!(greater_priority_info_summary > less_priority_info_summary);
100+
}
101+
102+
#[test]
103+
fn compare_sortition_info2() {
104+
let greater_priority_info_summary = SortitionInfo {
105+
priority_info: generate_priority_info_with_priority(0x55555544u64.into()),
106+
signer_idx: 0,
107+
};
108+
let less_priority_info_summary = SortitionInfo {
109+
priority_info: generate_priority_info_with_priority(0x55555523u64.into()),
110+
signer_idx: 22,
111+
};
112+
assert!(greater_priority_info_summary > less_priority_info_summary);
113+
}
114+
115+
fn add_fixed_priorities(collector: &mut SortitionInfoCollector, round: SortitionRound) {
116+
let priority_messages = [0x55u64, 0xffu64, 0x44u64, 0xeeu64].into_iter().map(|priority| {
117+
let info = generate_priority_info_with_priority((*priority).into());
118+
PriorityMessage {
119+
seed: 0xffffu64.into(),
120+
info,
121+
}
122+
});
123+
priority_messages
124+
.zip([1, 2, 3, 4].iter())
125+
.for_each(|(message, signer_idx)| collector.insert(&message, *signer_idx, round));
126+
}
127+
128+
#[test]
129+
fn insert_and_get_highest() {
130+
let mut collector: SortitionInfoCollector = Default::default();
131+
let round = SortitionRound {
132+
height: 1,
133+
view: 0,
134+
};
135+
add_fixed_priorities(&mut collector, round);
136+
assert_eq!(collector.get_highest_priority(round).unwrap(), SortitionInfo {
137+
priority_info: generate_priority_info_with_priority(0xffu64.into()),
138+
signer_idx: 2,
139+
});
140+
}
141+
142+
#[test]
143+
fn throw_away_old() {
144+
let mut collector: SortitionInfoCollector = Default::default();
145+
let rounds = [(1, 0), (3, 1), (5, 2), (100, 7), (0, 8)].into_iter().map(|(height, view)| SortitionRound {
146+
height: *height,
147+
view: *view,
148+
});
149+
rounds.clone().for_each(|round| add_fixed_priorities(&mut collector, round));
150+
let target_round = SortitionRound {
151+
height: 5,
152+
view: 2,
153+
};
154+
collector.throw_away_old(&target_round);
155+
rounds
156+
.clone()
157+
.filter(|round| round >= &target_round)
158+
.for_each(|round_gte| assert!(collector.get_highest_priority(round_gte).is_some()));
159+
rounds
160+
.filter(|round| round < &target_round)
161+
.for_each(|round_lt| assert!(collector.get_highest_priority(round_lt).is_none()))
162+
}
163+
}

0 commit comments

Comments
 (0)