From 70d3f36fba9ff6ac466f117f7fe241d3584029c3 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Wed, 9 Sep 2015 14:44:31 -0400 Subject: [PATCH] database: Handle gaps in block database when reindexing --- libraries/chain/block_database.cpp | 36 +++++++++++++++++++ libraries/chain/db_management.cpp | 32 +++++++++++++---- .../include/graphene/chain/block_database.hpp | 1 + 3 files changed, 63 insertions(+), 6 deletions(-) diff --git a/libraries/chain/block_database.cpp b/libraries/chain/block_database.cpp index c0005971..281dd387 100644 --- a/libraries/chain/block_database.cpp +++ b/libraries/chain/block_database.cpp @@ -237,4 +237,40 @@ optional block_database::last()const } return optional(); } + +optional block_database::last_id()const +{ + try + { + index_entry e; + _block_num_to_pos.seekg( 0, _block_num_to_pos.end ); + + if( _block_num_to_pos.tellp() < sizeof(index_entry) ) + return optional(); + + _block_num_to_pos.seekg( -sizeof(index_entry), _block_num_to_pos.end ); + _block_num_to_pos.read( (char*)&e, sizeof(e) ); + uint64_t pos = _block_num_to_pos.tellg(); + while( e.block_size == 0 && pos > 0 ) + { + pos -= sizeof(index_entry); + _block_num_to_pos.seekg( pos ); + _block_num_to_pos.read( (char*)&e, sizeof(e) ); + } + + if( e.block_size == 0 ) + return optional(); + + return e.block_id; + } + catch (const fc::exception&) + { + } + catch (const std::exception&) + { + } + return optional(); +} + + } } diff --git a/libraries/chain/db_management.cpp b/libraries/chain/db_management.cpp index baf4548b..c33b3ad1 100644 --- a/libraries/chain/db_management.cpp +++ b/libraries/chain/db_management.cpp @@ -58,12 +58,32 @@ void database::reindex(fc::path data_dir, const genesis_state_type& initial_allo for( uint32_t i = 1; i <= last_block_num; ++i ) { if( i % 2000 == 0 ) std::cerr << " " << double(i*100)/last_block_num << "% "< block = _block_id_to_block.fetch_by_number(i); + if( !block.valid() ) + { + wlog( "Reindexing terminated due to gap: Block ${i} does not exist!", ("i", i) ); + uint32_t dropped_count = 0; + while( true ) + { + fc::optional< block_id_type > last_id = _block_id_to_block.last_id(); + // this can trigger if we attempt to e.g. read a file that has block #2 but no block #1 + if( !last_id.valid() ) + break; + // we've caught up to the gap + if( block_header::num_from_id( *last_id ) <= i ) + break; + _block_id_to_block.remove( *last_id ); + dropped_count++; + } + wlog( "Dropped ${n} blocks from after the gap", ("n", dropped_count) ); + break; + } + apply_block(*block, skip_witness_signature | + skip_transaction_signatures | + skip_transaction_dupe_check | + skip_tapos_check | + skip_witness_schedule_check | + skip_authority_check); } _undo_db.enable(); auto end = fc::time_point::now(); diff --git a/libraries/chain/include/graphene/chain/block_database.hpp b/libraries/chain/include/graphene/chain/block_database.hpp index 1e8a97a6..816df798 100644 --- a/libraries/chain/include/graphene/chain/block_database.hpp +++ b/libraries/chain/include/graphene/chain/block_database.hpp @@ -36,6 +36,7 @@ namespace graphene { namespace chain { optional fetch_optional( const block_id_type& id )const; optional fetch_by_number( uint32_t block_num )const; optional last()const; + optional last_id()const; private: mutable std::fstream _blocks; mutable std::fstream _block_num_to_pos;