Skip to content

Commit 21586fd

Browse files
committed
Modify Backup and Restore
1 parent de11f35 commit 21586fd

File tree

3 files changed

+83
-70
lines changed

3 files changed

+83
-70
lines changed

core/src/consensus/tendermint/backup.rs

+51-69
Original file line numberDiff line numberDiff line change
@@ -14,41 +14,77 @@
1414
// You should have received a copy of the GNU Affero General Public License
1515
// along with this program. If not, see <https://www.gnu.org/licenses/>.
1616

17-
use ctypes::BlockHash;
1817
use kvdb::{DBTransaction, KeyValueDB};
18+
use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream};
1919

20-
use super::message::ConsensusMessage;
20+
use super::message::{ConsensusMessage, SortitionRound};
2121
use super::types::{Height, Step, View};
22+
use crate::consensus::PriorityInfo;
2223
use crate::db;
2324
use crate::db_version;
2425

2526
const BACKUP_KEY: &[u8] = b"tendermint-backup";
2627
const BACKUP_VERSION: u32 = 1;
2728

29+
pub struct PriorityInfoProjection(pub (SortitionRound, PriorityInfo));
30+
31+
impl PriorityInfoProjection {
32+
pub fn get_view(&self) -> PriorityInfoProjectionView {
33+
let (ref sortition_round, ref priority_info) = self.0;
34+
PriorityInfoProjectionView((sortition_round, priority_info))
35+
}
36+
}
37+
38+
impl Decodable for PriorityInfoProjection {
39+
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
40+
let item_count = rlp.item_count()?;
41+
if item_count != 2 {
42+
Err(DecoderError::RlpIncorrectListLen {
43+
got: item_count,
44+
expected: 2,
45+
})
46+
} else {
47+
Ok(Self((rlp.val_at(0)?, rlp.val_at(1)?)))
48+
}
49+
}
50+
}
51+
52+
pub struct PriorityInfoProjectionView<'a>(pub (&'a SortitionRound, &'a PriorityInfo));
53+
54+
impl Encodable for PriorityInfoProjectionView<'_> {
55+
fn rlp_append(&self, s: &mut RlpStream) {
56+
let (sortition_round, priority_info) = self.0;
57+
s.begin_list(2).append(sortition_round).append(priority_info);
58+
}
59+
}
60+
2861
pub struct BackupView<'a> {
2962
pub height: &'a Height,
3063
pub view: &'a View,
3164
pub step: &'a Step,
3265
pub votes: &'a [ConsensusMessage],
66+
pub priority_infos: &'a [PriorityInfoProjectionView<'a>],
3367
pub finalized_view_of_previous_block: &'a View,
3468
pub finalized_view_of_current_block: &'a Option<View>,
3569
}
3670

71+
#[derive(RlpDecodable)]
3772
pub struct BackupDataV0 {
3873
pub height: Height,
3974
pub view: View,
4075
pub step: Step,
4176
pub votes: Vec<ConsensusMessage>,
42-
pub proposal: Option<BlockHash>,
77+
pub priority_infos: Vec<PriorityInfoProjection>,
4378
pub last_confirmed_view: View,
4479
}
4580

81+
#[derive(RlpDecodable)]
4682
pub struct BackupDataV1 {
4783
pub height: Height,
4884
pub view: View,
4985
pub step: Step,
5086
pub votes: Vec<ConsensusMessage>,
51-
pub proposal: Option<BlockHash>,
87+
pub priority_infos: Vec<PriorityInfoProjection>,
5288
pub finalized_view_of_previous_block: View,
5389
pub finalized_view_of_current_block: Option<View>,
5490
}
@@ -59,12 +95,14 @@ pub fn backup(db: &dyn KeyValueDB, backup_data: BackupView) {
5995
view,
6096
step,
6197
votes,
98+
priority_infos,
6299
finalized_view_of_previous_block,
63100
finalized_view_of_current_block,
64101
} = backup_data;
65102
let mut s = rlp::RlpStream::new();
66-
s.begin_list(6);
103+
s.begin_list(7);
67104
s.append(height).append(view).append(step).append_list(votes);
105+
s.append_list(priority_infos);
68106
s.append(finalized_view_of_previous_block);
69107
s.append(finalized_view_of_current_block);
70108

@@ -83,19 +121,7 @@ pub fn restore(db: &dyn KeyValueDB) -> Option<BackupDataV1> {
83121
if version < BACKUP_VERSION {
84122
migrate(db);
85123
}
86-
load_v1(db)
87-
}
88-
89-
fn find_proposal(votes: &[ConsensusMessage], height: Height, view: View) -> Option<BlockHash> {
90-
votes
91-
.iter()
92-
.rev()
93-
.map(|vote| &vote.on)
94-
.find(|vote_on| {
95-
vote_on.step.step == Step::Propose && vote_on.step.view == view && vote_on.step.height == height
96-
})
97-
.map(|vote_on| vote_on.block_hash)
98-
.unwrap_or(None)
124+
load_with_version::<BackupDataV1>(db)
99125
}
100126

101127
fn migrate(db: &dyn KeyValueDB) {
@@ -114,7 +140,7 @@ fn migrate(db: &dyn KeyValueDB) {
114140
}
115141

116142
fn migrate_from_0_to_1(db: &dyn KeyValueDB) {
117-
let v0 = if let Some(v0) = load_v0(db) {
143+
let v0 = if let Some(v0) = load_with_version::<BackupDataV0>(db) {
118144
v0
119145
} else {
120146
return
@@ -125,7 +151,7 @@ fn migrate_from_0_to_1(db: &dyn KeyValueDB) {
125151
view: v0.view,
126152
step: v0.step,
127153
votes: v0.votes,
128-
proposal: v0.proposal,
154+
priority_infos: v0.priority_infos,
129155
// This is not a correct behavior if step == Step::Commit.
130156
// In Commit state, the Tendermint module overwrote the last_confirmed_view to finalized_view_of_current_block.
131157
// So we can't restore finalized_view_of_previous block.
@@ -142,59 +168,15 @@ fn migrate_from_0_to_1(db: &dyn KeyValueDB) {
142168
view: &v1.view,
143169
step: &v1.step,
144170
votes: &v1.votes,
171+
priority_infos: &v1.priority_infos.iter().map(|projection| projection.get_view()).collect::<Vec<_>>(),
145172
finalized_view_of_previous_block: &v1.finalized_view_of_previous_block,
146173
finalized_view_of_current_block: &v1.finalized_view_of_current_block,
147174
})
148175
}
149176

150-
fn load_v0(db: &dyn KeyValueDB) -> Option<BackupDataV0> {
151-
let value = db.get(db::COL_EXTRA, BACKUP_KEY).expect("Low level database error. Some issue with disk?");
152-
let (height, view, step, votes, last_confirmed_view) = value.map(|bytes| {
153-
let rlp = rlp::Rlp::new(&bytes);
154-
(
155-
rlp.val_at(0).unwrap(),
156-
rlp.val_at(1).unwrap(),
157-
rlp.val_at(2).unwrap(),
158-
rlp.at(3).unwrap().as_list().unwrap(),
159-
rlp.val_at(4).unwrap(),
160-
)
161-
})?;
162-
163-
let proposal = find_proposal(&votes, height, view);
164-
165-
Some(BackupDataV0 {
166-
height,
167-
view,
168-
step,
169-
votes,
170-
proposal,
171-
last_confirmed_view,
172-
})
173-
}
174-
175-
fn load_v1(db: &dyn KeyValueDB) -> Option<BackupDataV1> {
176-
#[derive(RlpDecodable)]
177-
struct Backup {
178-
height: Height,
179-
view: View,
180-
step: Step,
181-
votes: Vec<ConsensusMessage>,
182-
finalized_view_of_previous_block: View,
183-
finalized_view_of_current_block: Option<View>,
184-
}
185-
177+
fn load_with_version<T: Decodable>(db: &dyn KeyValueDB) -> Option<T> {
186178
let value = db.get(db::COL_EXTRA, BACKUP_KEY).expect("Low level database error. Some issue with disk?")?;
187-
let backup: Backup = rlp::decode(&value).unwrap();
188-
189-
let proposal = find_proposal(&backup.votes, backup.height, backup.view);
190-
191-
Some(BackupDataV1 {
192-
height: backup.height,
193-
view: backup.view,
194-
step: backup.step,
195-
votes: backup.votes,
196-
proposal,
197-
finalized_view_of_previous_block: backup.finalized_view_of_previous_block,
198-
finalized_view_of_current_block: backup.finalized_view_of_current_block,
199-
})
179+
let backup: T = rlp::decode(&value).unwrap();
180+
181+
Some(backup)
200182
}

core/src/consensus/tendermint/vote_collector.rs

+19
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ impl PriorityCollector {
138138
fn iter_from_highest(&self) -> Rev<Iter<'_, PriorityInfo>> {
139139
self.priorities.iter().rev()
140140
}
141+
142+
fn iter(&self) -> Iter<PriorityInfo> {
143+
self.priorities.iter()
144+
}
141145
}
142146

143147
impl MessageCollector {
@@ -377,4 +381,19 @@ impl VoteCollector {
377381
None => vec![],
378382
}
379383
}
384+
385+
pub fn get_all_priority_infos(&self) -> Vec<(SortitionRound, PriorityInfo)> {
386+
self.votes
387+
.iter()
388+
.filter(|(vote_step, _)| vote_step.step == Step::Propose)
389+
.flat_map(|(&vote_step, collector)| {
390+
let round: SortitionRound = vote_step.into();
391+
collector
392+
.priority_collector()
393+
.iter()
394+
.map(|priority_info| (round, priority_info.clone()))
395+
.collect::<Vec<_>>()
396+
})
397+
.collect()
398+
}
380399
}

core/src/consensus/tendermint/worker.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use rlp::{Encodable, Rlp};
3232
use vrf::openssl::{CipherSuite, ECVRF};
3333

3434
use super::super::BitSet;
35-
use super::backup::{backup, restore, BackupView};
35+
use super::backup::{backup, restore, BackupView, PriorityInfoProjection, PriorityInfoProjectionView};
3636
use super::message::*;
3737
use super::network;
3838
use super::params::TimeGapParams;
@@ -1013,11 +1013,18 @@ impl Worker {
10131013
}
10141014

10151015
fn backup(&self) {
1016+
let priority_infos = self.votes.get_all_priority_infos();
1017+
let priority_info_projection_views = priority_infos
1018+
.iter()
1019+
.map(|(round, priority_info)| PriorityInfoProjectionView((&round, &priority_info)))
1020+
.collect::<Vec<PriorityInfoProjectionView>>();
1021+
10161022
backup(self.client().get_kvdb().as_ref(), BackupView {
10171023
height: &self.height,
10181024
view: &self.view,
10191025
step: &self.step.to_step(),
10201026
votes: &self.votes.get_all(),
1027+
priority_infos: &priority_info_projection_views,
10211028
finalized_view_of_previous_block: &self.finalized_view_of_previous_block,
10221029
finalized_view_of_current_block: &self.finalized_view_of_current_block,
10231030
});
@@ -1039,6 +1046,11 @@ impl Worker {
10391046
self.step = backup_step;
10401047
self.height = backup.height;
10411048
self.view = backup.view;
1049+
backup.priority_infos.into_iter().for_each(|projection| match projection {
1050+
PriorityInfoProjection((round, priority_info)) => {
1051+
self.votes.collect_priority(round, priority_info);
1052+
}
1053+
});
10421054
self.finalized_view_of_previous_block = backup.finalized_view_of_previous_block;
10431055
self.finalized_view_of_current_block = backup.finalized_view_of_current_block;
10441056

0 commit comments

Comments
 (0)