14
14
// You should have received a copy of the GNU Affero General Public License
15
15
// along with this program. If not, see <https://www.gnu.org/licenses/>.
16
16
17
- use ctypes:: BlockHash ;
18
17
use kvdb:: { DBTransaction , KeyValueDB } ;
18
+ use rlp:: { Decodable , DecoderError , Encodable , Rlp , RlpStream } ;
19
19
20
- use super :: message:: ConsensusMessage ;
20
+ use super :: message:: { ConsensusMessage , SortitionRound } ;
21
21
use super :: types:: { Height , Step , View } ;
22
+ use crate :: consensus:: PriorityInfo ;
22
23
use crate :: db;
23
24
use crate :: db_version;
24
25
25
26
const BACKUP_KEY : & [ u8 ] = b"tendermint-backup" ;
26
27
const BACKUP_VERSION : u32 = 1 ;
27
28
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
+
28
61
pub struct BackupView < ' a > {
29
62
pub height : & ' a Height ,
30
63
pub view : & ' a View ,
31
64
pub step : & ' a Step ,
32
65
pub votes : & ' a [ ConsensusMessage ] ,
66
+ pub priority_infos : & ' a [ PriorityInfoProjectionView < ' a > ] ,
33
67
pub finalized_view_of_previous_block : & ' a View ,
34
68
pub finalized_view_of_current_block : & ' a Option < View > ,
35
69
}
36
70
71
+ #[ derive( RlpDecodable ) ]
37
72
pub struct BackupDataV0 {
38
73
pub height : Height ,
39
74
pub view : View ,
40
75
pub step : Step ,
41
76
pub votes : Vec < ConsensusMessage > ,
42
- pub proposal : Option < BlockHash > ,
77
+ pub priority_infos : Vec < PriorityInfoProjection > ,
43
78
pub last_confirmed_view : View ,
44
79
}
45
80
81
+ #[ derive( RlpDecodable ) ]
46
82
pub struct BackupDataV1 {
47
83
pub height : Height ,
48
84
pub view : View ,
49
85
pub step : Step ,
50
86
pub votes : Vec < ConsensusMessage > ,
51
- pub proposal : Option < BlockHash > ,
87
+ pub priority_infos : Vec < PriorityInfoProjection > ,
52
88
pub finalized_view_of_previous_block : View ,
53
89
pub finalized_view_of_current_block : Option < View > ,
54
90
}
@@ -59,12 +95,14 @@ pub fn backup(db: &dyn KeyValueDB, backup_data: BackupView) {
59
95
view,
60
96
step,
61
97
votes,
98
+ priority_infos,
62
99
finalized_view_of_previous_block,
63
100
finalized_view_of_current_block,
64
101
} = backup_data;
65
102
let mut s = rlp:: RlpStream :: new ( ) ;
66
- s. begin_list ( 6 ) ;
103
+ s. begin_list ( 7 ) ;
67
104
s. append ( height) . append ( view) . append ( step) . append_list ( votes) ;
105
+ s. append_list ( priority_infos) ;
68
106
s. append ( finalized_view_of_previous_block) ;
69
107
s. append ( finalized_view_of_current_block) ;
70
108
@@ -83,19 +121,7 @@ pub fn restore(db: &dyn KeyValueDB) -> Option<BackupDataV1> {
83
121
if version < BACKUP_VERSION {
84
122
migrate ( db) ;
85
123
}
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)
99
125
}
100
126
101
127
fn migrate ( db : & dyn KeyValueDB ) {
@@ -114,7 +140,7 @@ fn migrate(db: &dyn KeyValueDB) {
114
140
}
115
141
116
142
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) {
118
144
v0
119
145
} else {
120
146
return
@@ -125,7 +151,7 @@ fn migrate_from_0_to_1(db: &dyn KeyValueDB) {
125
151
view : v0. view ,
126
152
step : v0. step ,
127
153
votes : v0. votes ,
128
- proposal : v0. proposal ,
154
+ priority_infos : v0. priority_infos ,
129
155
// This is not a correct behavior if step == Step::Commit.
130
156
// In Commit state, the Tendermint module overwrote the last_confirmed_view to finalized_view_of_current_block.
131
157
// So we can't restore finalized_view_of_previous block.
@@ -142,59 +168,15 @@ fn migrate_from_0_to_1(db: &dyn KeyValueDB) {
142
168
view : & v1. view ,
143
169
step : & v1. step ,
144
170
votes : & v1. votes ,
171
+ priority_infos : & v1. priority_infos . iter ( ) . map ( |projection| projection. get_view ( ) ) . collect :: < Vec < _ > > ( ) ,
145
172
finalized_view_of_previous_block : & v1. finalized_view_of_previous_block ,
146
173
finalized_view_of_current_block : & v1. finalized_view_of_current_block ,
147
174
} )
148
175
}
149
176
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 > {
186
178
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)
200
182
}
0 commit comments