12
12
13
13
namespace eosio { namespace chain {
14
14
15
- const uint32_t block_log::supported_version = 1 ;
15
+ const uint32_t block_log::min_supported_version = 1 ;
16
+
17
+ /* *
18
+ * History:
19
+ * Version 1: complete block log from genesis
20
+ * Version 2: adds optional partial block log, cannot be used for replay without snapshot
21
+ * this is in the form of an first_block_num that is written immediately after the version
22
+ */
23
+ const uint32_t block_log::max_supported_version = 2 ;
16
24
17
25
namespace detail {
18
26
class block_log_impl {
@@ -26,6 +34,8 @@ namespace eosio { namespace chain {
26
34
bool block_write;
27
35
bool index_write;
28
36
bool genesis_written_to_block_log = false ;
37
+ uint32_t version = 0 ;
38
+ uint32_t first_block_num = 0 ;
29
39
30
40
inline void check_block_read () {
31
41
if (block_write) {
@@ -124,14 +134,21 @@ namespace eosio { namespace chain {
124
134
ilog (" Log is nonempty" );
125
135
my->check_block_read ();
126
136
my->block_stream .seekg ( 0 );
127
- uint32_t version = 0 ;
128
- my->block_stream .read ( (char *)&version, sizeof (version) );
129
- EOS_ASSERT ( version > 0 , block_log_exception, " Block log was not setup properly with genesis information." );
130
- EOS_ASSERT ( version == block_log::supported_version, block_log_unsupported_version,
131
- " Unsupported version of block log. Block log version is ${version} while code supports version ${supported}" ,
132
- (" version" , version)(" supported" , block_log::supported_version) );
137
+ my->version = 0 ;
138
+ my->block_stream .read ( (char *)&my->version , sizeof (my->version ) );
139
+ EOS_ASSERT ( my->version > 0 , block_log_exception, " Block log was not setup properly" );
140
+ EOS_ASSERT ( my->version >= min_supported_version && my->version <= max_supported_version, block_log_unsupported_version,
141
+ " Unsupported version of block log. Block log version is ${version} while code supports version(s) [${min},${max}]" ,
142
+ (" version" , my->version )(" min" , block_log::min_supported_version)(" max" , block_log::max_supported_version) );
143
+
133
144
134
145
my->genesis_written_to_block_log = true ; // Assume it was constructed properly.
146
+ if (my->version > 1 ){
147
+ my->first_block_num = 0 ;
148
+ my->block_stream .read ( (char *)&my->first_block_num , sizeof (my->first_block_num ) );
149
+ EOS_ASSERT (my->first_block_num > 0 , block_log_exception, " Block log is malformed, first recorded block number is 0 but must be greater than or equal to 1" );
150
+ }
151
+
135
152
my->head = read_head ();
136
153
my->head_id = my->head ->id ();
137
154
@@ -176,11 +193,11 @@ namespace eosio { namespace chain {
176
193
my->check_index_write ();
177
194
178
195
uint64_t pos = my->block_stream .tellp ();
179
- EOS_ASSERT (my->index_stream .tellp () == sizeof (uint64_t ) * (b->block_num () - 1 ),
196
+ EOS_ASSERT (my->index_stream .tellp () == sizeof (uint64_t ) * (b->block_num () - my-> first_block_num ),
180
197
block_log_append_fail,
181
198
" Append to index file occuring at wrong position." ,
182
199
(" position" , (uint64_t ) my->index_stream .tellp ())
183
- (" expected" , (b->block_num () - 1 ) * sizeof (uint64_t )));
200
+ (" expected" , (b->block_num () - my-> first_block_num ) * sizeof (uint64_t )));
184
201
auto data = fc::raw::pack (*b);
185
202
my->block_stream .write (data.data (), data.size ());
186
203
my->block_stream .write ((char *)&pos, sizeof (pos));
@@ -200,44 +217,50 @@ namespace eosio { namespace chain {
200
217
my->index_stream .flush ();
201
218
}
202
219
203
- uint64_t block_log::reset_to_genesis ( const genesis_state& gs, const signed_block_ptr& genesis_block ) {
204
- if ( my->block_stream .is_open () )
220
+ void block_log::reset ( const genesis_state& gs, const signed_block_ptr& first_block, uint32_t first_block_num ) {
221
+ if ( my->block_stream .is_open ())
205
222
my->block_stream .close ();
206
- if ( my->index_stream .is_open () )
223
+ if ( my->index_stream .is_open ())
207
224
my->index_stream .close ();
208
225
209
- fc::remove_all ( my->block_file );
210
- fc::remove_all ( my->index_file );
226
+ fc::remove_all (my->block_file );
227
+ fc::remove_all (my->index_file );
211
228
212
229
my->block_stream .open (my->block_file .generic_string ().c_str (), LOG_WRITE);
213
230
my->index_stream .open (my->index_file .generic_string ().c_str (), LOG_WRITE);
214
231
my->block_write = true ;
215
232
my->index_write = true ;
216
233
217
- auto data = fc::raw::pack ( gs );
218
- uint32_t version = 0 ; // version of 0 is invalid; it indicates that the genesis was not properly written to the block log
219
- my->block_stream .write ( (char *)&version, sizeof (version) );
220
- my->block_stream .write ( data.data (), data.size () );
234
+ auto data = fc::raw::pack (gs);
235
+ my->version = 0 ; // version of 0 is invalid; it indicates that the genesis was not properly written to the block log
236
+ my->first_block_num = first_block_num;
237
+ my->block_stream .write ((char *)&my->version , sizeof (my->version ));
238
+ my->block_stream .write ((char *)&my->first_block_num , sizeof (my->first_block_num ));
239
+ my->block_stream .write (data.data (), data.size ());
221
240
my->genesis_written_to_block_log = true ;
222
241
223
- auto ret = append ( genesis_block );
242
+ // append a totem to indicate the division between blocks and header
243
+ auto totem = npos;
244
+ my->block_stream .write ((char *)&totem, sizeof (totem));
245
+
246
+ if (first_block) {
247
+ auto ret = append (first_block);
248
+ }
224
249
225
250
auto pos = my->block_stream .tellp ();
226
251
227
252
my->block_stream .close ();
228
253
my->block_stream .open (my->block_file .generic_string ().c_str (), std::ios::in | std::ios::out | std::ios::binary ); // Bypass append-only writing just once
229
254
230
- static_assert ( block_log::supported_version > 0 , " a version number of zero is not supported" );
231
- version = block_log::supported_version ;
255
+ static_assert ( block_log::max_supported_version > 0 , " a version number of zero is not supported" );
256
+ my-> version = block_log::max_supported_version ;
232
257
my->block_stream .seekp ( 0 );
233
- my->block_stream .write ( (char *)&version, sizeof (version) ); // Finally write actual version to disk.
258
+ my->block_stream .write ( (char *)&my-> version , sizeof (my-> version ) );
234
259
my->block_stream .seekp ( pos );
235
260
flush ();
236
261
237
262
my->block_write = false ;
238
263
my->check_block_write (); // Reset to append-only writing.
239
-
240
- return ret;
241
264
}
242
265
243
266
std::pair<signed_block_ptr, uint64_t > block_log::read_block (uint64_t pos)const {
@@ -266,10 +289,9 @@ namespace eosio { namespace chain {
266
289
267
290
uint64_t block_log::get_block_pos (uint32_t block_num) const {
268
291
my->check_index_read ();
269
-
270
- if (!(my->head && block_num <= block_header::num_from_id (my->head_id ) && block_num > 0 ))
292
+ if (!(my->head && block_num <= block_header::num_from_id (my->head_id ) && block_num >= my->first_block_num ))
271
293
return npos;
272
- my->index_stream .seekg (sizeof (uint64_t ) * (block_num - 1 ));
294
+ my->index_stream .seekg (sizeof (uint64_t ) * (block_num - my-> first_block_num ));
273
295
uint64_t pos;
274
296
my->index_stream .read ((char *)&pos, sizeof (pos));
275
297
return pos;
@@ -287,13 +309,21 @@ namespace eosio { namespace chain {
287
309
288
310
my->block_stream .seekg (-sizeof (pos), std::ios::end);
289
311
my->block_stream .read ((char *)&pos, sizeof (pos));
290
- return read_block (pos).first ;
312
+ if (pos != npos) {
313
+ return read_block (pos).first ;
314
+ } else {
315
+ return {};
316
+ }
291
317
}
292
318
293
319
const signed_block_ptr& block_log::head ()const {
294
320
return my->head ;
295
321
}
296
322
323
+ uint32_t block_log::first_block_num () const {
324
+ return my->first_block_num ;
325
+ }
326
+
297
327
void block_log::construct_index () {
298
328
ilog (" Reconstructing Block Log Index..." );
299
329
my->index_stream .close ();
@@ -308,7 +338,12 @@ namespace eosio { namespace chain {
308
338
my->block_stream .read ((char *)&end_pos, sizeof (end_pos));
309
339
signed_block tmp;
310
340
311
- uint64_t pos = 4 ; // Skip version which should have already been checked.
341
+ uint64_t pos = 0 ;
342
+ if (my->version == 1 ) {
343
+ pos = 4 ; // Skip version which should have already been checked.
344
+ } else {
345
+ pos = 8 ; // Skip version and first block offset which should have already been checked
346
+ }
312
347
my->block_stream .seekg (pos);
313
348
314
349
genesis_state gs;
@@ -361,16 +396,23 @@ namespace eosio { namespace chain {
361
396
362
397
uint32_t version = 0 ;
363
398
old_block_stream.read ( (char *)&version, sizeof (version) );
364
- EOS_ASSERT ( version > 0 , block_log_exception, " Block log was not setup properly with genesis information." );
365
- EOS_ASSERT ( version == block_log::supported_version, block_log_unsupported_version,
366
- " Unsupported version of block log. Block log version is ${version} while code supports version ${supported}" ,
367
- (" version" , version)(" supported" , block_log::supported_version) );
399
+ EOS_ASSERT ( version > 0 , block_log_exception, " Block log was not setup properly" );
400
+ EOS_ASSERT ( version >= min_supported_version && version <= max_supported_version, block_log_unsupported_version,
401
+ " Unsupported version of block log. Block log version is ${version} while code supports version(s) [${min},${max}]" ,
402
+ (" version" , version)(" min" , block_log::min_supported_version)(" max" , block_log::max_supported_version) );
403
+
404
+ new_block_stream.write ( (char *)&version, sizeof (version) );
405
+
406
+ uint32_t first_block_num = 1 ;
407
+ if (version != 1 ) {
408
+ old_block_stream.read ( (char *)&first_block_num, sizeof (first_block_num) );
409
+ new_block_stream.write ( (char *)&first_block_num, sizeof (first_block_num) );
410
+ }
368
411
369
412
genesis_state gs;
370
413
fc::raw::unpack (old_block_stream, gs);
371
414
372
415
auto data = fc::raw::pack ( gs );
373
- new_block_stream.write ( (char *)&version, sizeof (version) );
374
416
new_block_stream.write ( data.data (), data.size () );
375
417
376
418
std::exception_ptr except_ptr;
@@ -472,10 +514,15 @@ namespace eosio { namespace chain {
472
514
473
515
uint32_t version = 0 ;
474
516
block_stream.read ( (char *)&version, sizeof (version) );
475
- EOS_ASSERT ( version > 0 , block_log_exception, " Block log was not setup properly with genesis information." );
476
- EOS_ASSERT ( version == block_log::supported_version, block_log_unsupported_version,
477
- " Unsupported version of block log. Block log version is ${version} while code supports version ${supported}" ,
478
- (" version" , version)(" supported" , block_log::supported_version) );
517
+ EOS_ASSERT ( version > 0 , block_log_exception, " Block log was not setup properly." );
518
+ EOS_ASSERT ( version >= min_supported_version && version <= max_supported_version, block_log_unsupported_version,
519
+ " Unsupported version of block log. Block log version is ${version} while code supports version(s) [${min},${max}]" ,
520
+ (" version" , version)(" min" , block_log::min_supported_version)(" max" , block_log::max_supported_version) );
521
+
522
+ uint32_t first_block_num = 1 ;
523
+ if (version != 1 ) {
524
+ block_stream.read ( (char *)&first_block_num, sizeof (first_block_num) );
525
+ }
479
526
480
527
genesis_state gs;
481
528
fc::raw::unpack (block_stream, gs);
0 commit comments