Skip to content

Commit

Permalink
Merge branch 'develop' into feature/GRPH-99
Browse files Browse the repository at this point in the history
  • Loading branch information
bobinson authored Sep 18, 2019
2 parents 0a00ced + 96161db commit ce1321c
Show file tree
Hide file tree
Showing 18 changed files with 361 additions and 220 deletions.
65 changes: 8 additions & 57 deletions libraries/app/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,6 @@ namespace detail {

~application_impl()
{
fc::remove_all(_data_dir / "blockchain/dblock");
}

void set_dbg_init_key( genesis_state_type& genesis, const std::string& init_key )
Expand All @@ -314,8 +313,7 @@ namespace detail {

void startup()
{ try {
bool clean = !fc::exists(_data_dir / "blockchain/dblock");
fc::create_directories(_data_dir / "blockchain/dblock");
fc::create_directories(_data_dir / "blockchain");

auto initial_state = [&] {
ilog("Initializing database...");
Expand Down Expand Up @@ -381,64 +379,17 @@ namespace detail {
bool replay = false;
std::string replay_reason = "reason not provided";

// never replay if data dir is empty
if( fc::exists( _data_dir ) && fc::directory_iterator( _data_dir ) != fc::directory_iterator() )
{
if( _options->count("replay-blockchain") )
{
replay = true;
replay_reason = "replay-blockchain argument specified";
}
else if( !clean )
{
replay = true;
replay_reason = "unclean shutdown detected";
}
else if( !fc::exists( _data_dir / "db_version" ) )
{
replay = true;
replay_reason = "db_version file not found";
}
else
{
std::string version_string;
fc::read_file_contents( _data_dir / "db_version", version_string );
if( _options->count("replay-blockchain") )
_chain_db->wipe( _data_dir / "blockchain", false );

if( version_string != GRAPHENE_CURRENT_DB_VERSION )
{
replay = true;
replay_reason = "db_version file content mismatch";
}
}
}

if( !replay )
try
{
try
{
_chain_db->open( _data_dir / "blockchain", initial_state );
}
catch( const fc::exception& e )
{
ilog( "Caught exception ${e} in open()", ("e", e.to_detail_string()) );

replay = true;
replay_reason = "exception in open()";
}
_chain_db->open( _data_dir / "blockchain", initial_state, GRAPHENE_CURRENT_DB_VERSION );
}

if( replay )
catch( const fc::exception& e )
{
ilog( "Replaying blockchain due to: ${reason}", ("reason", replay_reason) );

fc::remove_all( _data_dir / "db_version" );
_chain_db->reindex( _data_dir / "blockchain", initial_state() );

const auto mode = std::ios::out | std::ios::binary | std::ios::trunc;
std::ofstream db_version( (_data_dir / "db_version").generic_string().c_str(), mode );
std::string version_string = GRAPHENE_CURRENT_DB_VERSION;
db_version.write( version_string.c_str(), version_string.size() );
db_version.close();
elog( "Caught exception ${e} in open(), you might want to force a replay", ("e", e.to_detail_string()) );
throw;
}

if( _options->count("force-validate") )
Expand Down
95 changes: 44 additions & 51 deletions libraries/chain/block_database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,15 @@ void block_database::open( const fc::path& dbdir )
_block_num_to_pos.exceptions(std::ios_base::failbit | std::ios_base::badbit);
_blocks.exceptions(std::ios_base::failbit | std::ios_base::badbit);

if( !fc::exists( dbdir/"index" ) )
_index_filename = dbdir / "index";
if( !fc::exists( _index_filename ) )
{
_block_num_to_pos.open( (dbdir/"index").generic_string().c_str(), std::fstream::binary | std::fstream::in | std::fstream::out | std::fstream::trunc);
_block_num_to_pos.open( _index_filename.generic_string().c_str(), std::fstream::binary | std::fstream::in | std::fstream::out | std::fstream::trunc);
_blocks.open( (dbdir/"blocks").generic_string().c_str(), std::fstream::binary | std::fstream::in | std::fstream::out | std::fstream::trunc);
}
else
{
_block_num_to_pos.open( (dbdir/"index").generic_string().c_str(), std::fstream::binary | std::fstream::in | std::fstream::out );
_block_num_to_pos.open( _index_filename.generic_string().c_str(), std::fstream::binary | std::fstream::in | std::fstream::out );
_blocks.open( (dbdir/"blocks").generic_string().c_str(), std::fstream::binary | std::fstream::in | std::fstream::out );
}
} FC_CAPTURE_AND_RETHROW( (dbdir) ) }
Expand Down Expand Up @@ -121,7 +122,7 @@ bool block_database::contains( const block_id_type& id )const
index_entry e;
auto index_pos = sizeof(e)*block_header::num_from_id(id);
_block_num_to_pos.seekg( 0, _block_num_to_pos.end );
if ( _block_num_to_pos.tellg() <= index_pos )
if ( _block_num_to_pos.tellg() < index_pos + sizeof(e) )
return false;
_block_num_to_pos.seekg( index_pos );
_block_num_to_pos.read( (char*)&e, sizeof(e) );
Expand Down Expand Up @@ -206,77 +207,69 @@ optional<signed_block> block_database::fetch_by_number( uint32_t block_num )cons
return optional<signed_block>();
}

optional<signed_block> block_database::last()const
{
optional<index_entry> block_database::last_index_entry()const {
try
{
index_entry e;

_block_num_to_pos.seekg( 0, _block_num_to_pos.end );
std::streampos pos = _block_num_to_pos.tellg();
if( pos < sizeof(index_entry) )
return optional<index_entry>();

if( _block_num_to_pos.tellp() < sizeof(index_entry) )
return optional<signed_block>();
pos -= pos % sizeof(index_entry);

_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 )
_blocks.seekg( 0, _block_num_to_pos.end );
const std::streampos blocks_size = _blocks.tellg();
while( pos > 0 )
{
pos -= sizeof(index_entry);
_block_num_to_pos.seekg( pos );
_block_num_to_pos.read( (char*)&e, sizeof(e) );
if( _block_num_to_pos.gcount() == sizeof(e) && e.block_size > 0
&& e.block_pos + e.block_size <= blocks_size )
try
{
vector<char> data( e.block_size );
_blocks.seekg( e.block_pos );
_blocks.read( data.data(), e.block_size );
if( _blocks.gcount() == e.block_size )
{
const signed_block block = fc::raw::unpack<signed_block>(data);
if( block.id() == e.block_id )
return e;
}
}
catch (const fc::exception&)
{
}
catch (const std::exception&)
{
}
fc::resize_file( _index_filename, pos );
}

if( e.block_size == 0 )
return optional<signed_block>();

vector<char> data( e.block_size );
_blocks.seekg( e.block_pos );
_blocks.read( data.data(), e.block_size );
auto result = fc::raw::unpack<signed_block>(data);
return result;
}
catch (const fc::exception&)
{
}
catch (const std::exception&)
{
}
return optional<index_entry>();
}

optional<signed_block> block_database::last()const
{
optional<index_entry> entry = last_index_entry();
if( entry.valid() ) return fetch_by_number( block_header::num_from_id(entry->block_id) );
return optional<signed_block>();
}

optional<block_id_type> 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_id_type>();

_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<block_id_type>();

return e.block_id;
}
catch (const fc::exception&)
{
}
catch (const std::exception&)
{
}
optional<index_entry> entry = last_index_entry();
if( entry.valid() ) return entry->block_id;
return optional<block_id_type>();
}


} }
20 changes: 14 additions & 6 deletions libraries/chain/db_block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,15 @@ bool database::_push_block(const signed_block& new_block)

// pop blocks until we hit the forked block
while( head_block_id() != branches.second.back()->data.previous )
{
ilog( "popping block #${n} ${id}", ("n",head_block_num())("id",head_block_id()) );
pop_block();
}

// push all blocks on the new fork
for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr )
{
ilog( "pushing blocks from fork ${n} ${id}", ("n",(*ritr)->data.block_num())("id",(*ritr)->data.id()) );
ilog( "pushing block from fork #${n} ${id}", ("n",(*ritr)->data.block_num())("id",(*ritr)->id) );
optional<fc::exception> except;
try {
undo_database::session session = _undo_db.start_undo_session();
Expand All @@ -235,21 +238,27 @@ bool database::_push_block(const signed_block& new_block)
// remove the rest of branches.first from the fork_db, those blocks are invalid
while( ritr != branches.first.rend() )
{
_fork_db.remove( (*ritr)->data.id() );
ilog( "removing block from fork_db #${n} ${id}", ("n",(*ritr)->data.block_num())("id",(*ritr)->id) );
_fork_db.remove( (*ritr)->id );
++ritr;
}
_fork_db.set_head( branches.second.front() );

// pop all blocks from the bad fork
while( head_block_id() != branches.second.back()->data.previous )
{
ilog( "popping block #${n} ${id}", ("n",head_block_num())("id",head_block_id()) );
pop_block();
}

ilog( "Switching back to fork: ${id}", ("id",branches.second.front()->data.id()) );
// restore all blocks from the good fork
for( auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr )
for( auto ritr2 = branches.second.rbegin(); ritr2 != branches.second.rend(); ++ritr2 )
{
ilog( "pushing block #${n} ${id}", ("n",(*ritr2)->data.block_num())("id",(*ritr2)->id) );
auto session = _undo_db.start_undo_session();
apply_block( (*ritr)->data, skip );
_block_id_to_block.store( new_block.id(), (*ritr)->data );
apply_block( (*ritr2)->data, skip );
_block_id_to_block.store( (*ritr2)->id, (*ritr2)->data );
session.commit();
}
throw *except;
Expand Down Expand Up @@ -506,7 +515,6 @@ void database::pop_block()
GRAPHENE_ASSERT( head_block.valid(), pop_empty_chain, "there are no blocks to pop" );

_fork_db.pop_block();
_block_id_to_block.remove( head_id );
pop_undo();

_popped_tx.insert( _popped_tx.begin(), head_block->transactions.begin(), head_block->transactions.end() );
Expand Down
Loading

0 comments on commit ce1321c

Please sign in to comment.