Skip to content

Commit

Permalink
Merge pull request EOSIO#3301 from EOSIO/3283-fix-unconfirmed-blocks
Browse files Browse the repository at this point in the history
nodeos option to recover reversible blocks from unclean shutdown
  • Loading branch information
bytemaster authored May 23, 2018
2 parents 7c2e6e7 + 227859c commit 25ebcd1
Show file tree
Hide file tree
Showing 15 changed files with 183 additions and 381 deletions.
13 changes: 7 additions & 6 deletions libraries/chain/block_log.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,21 +262,20 @@ namespace eosio { namespace chain {
}
} // construct_index

void block_log::repair_log( const fc::path& data_dir ) {
fc::path block_log::repair_log( const fc::path& data_dir ) {
ilog("Recovering Block Log...");
FC_ASSERT( fc::is_directory(data_dir) && fc::is_regular_file(data_dir / "blocks.log"),
"Block log not found in '${blocks_dir}'", ("blocks_dir", data_dir) );

auto now = fc::time_point::now();

auto blocks_dir = fc::canonical( data_dir );
if( blocks_dir.filename().generic_string() == "." ) {
blocks_dir = blocks_dir.parent_path();
}
auto backup_dir = blocks_dir.parent_path();
auto blocks_dir_name = blocks_dir.filename();
if( blocks_dir_name.generic_string() == "." ) {
blocks_dir_name = backup_dir.filename();
backup_dir = backup_dir.parent_path();
FC_ASSERT( blocks_dir_name.generic_string() != ".", "Invalid path to blocks directory" );
}
FC_ASSERT( blocks_dir_name.generic_string() != ".", "Invalid path to blocks directory" );
backup_dir = backup_dir / blocks_dir_name.generic_string().append("-").append( now );

FC_ASSERT( !fc::exists(backup_dir),
Expand Down Expand Up @@ -369,6 +368,8 @@ namespace eosio { namespace chain {
} else {
ilog( "Existing block log was undamaged. Recovered all irreversible blocks up to block number ${num}.", ("num", block_num) );
}

return backup_dir;
}

} } /// eosio::chain
37 changes: 19 additions & 18 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <eosio/chain/contract_table_objects.hpp>
#include <eosio/chain/generated_transaction_object.hpp>
#include <eosio/chain/transaction_object.hpp>
#include <eosio/chain/unconfirmed_block_object.hpp>
#include <eosio/chain/reversible_block_object.hpp>

#include <eosio/chain/authorization_manager.hpp>
#include <eosio/chain/resource_limits.hpp>
Expand Down Expand Up @@ -47,7 +47,7 @@ struct pending_state {
struct controller_impl {
controller& self;
chainbase::database db;
chainbase::database unconfirmed_blocks; ///< a special database to persist blocks that have successfully been applied but are still reversible
chainbase::database reversible_blocks; ///< a special database to persist blocks that have successfully been applied but are still reversible
block_log blog;
optional<pending_state> pending;
block_state_ptr head;
Expand All @@ -73,9 +73,9 @@ struct controller_impl {
auto prev = fork_db.get_block( head->header.previous );
FC_ASSERT( prev, "attempt to pop beyond last irreversible block" );

if( const auto* b = unconfirmed_blocks.find<unconfirmed_block_object,by_num>(head->block_num) )
if( const auto* b = reversible_blocks.find<reversible_block_object,by_num>(head->block_num) )
{
unconfirmed_blocks.remove( *b );
reversible_blocks.remove( *b );
}

for( const auto& t : head->trxs )
Expand All @@ -95,9 +95,9 @@ struct controller_impl {
db( cfg.shared_memory_dir,
cfg.read_only ? database::read_only : database::read_write,
cfg.shared_memory_size ),
unconfirmed_blocks( cfg.block_log_dir/"unconfirmed",
reversible_blocks( cfg.block_log_dir/"reversible",
cfg.read_only ? database::read_only : database::read_write,
cfg.unconfirmed_cache_size ),
cfg.reversible_cache_size ),
blog( cfg.block_log_dir ),
fork_db( cfg.shared_memory_dir ),
wasmif( cfg.wasm_runtime ),
Expand Down Expand Up @@ -174,10 +174,10 @@ struct controller_impl {
emit( self.irreversible_block, s );
db.commit( s->block_num );

const auto& ubi = unconfirmed_blocks.get_index<unconfirmed_block_index,by_num>();
const auto& ubi = reversible_blocks.get_index<reversible_block_index,by_num>();
auto objitr = ubi.begin();
while( objitr != ubi.end() && objitr->blocknum <= s->block_num ) {
unconfirmed_blocks.remove( *objitr );
reversible_blocks.remove( *objitr );
objitr = ubi.begin();
}
}
Expand Down Expand Up @@ -209,16 +209,17 @@ struct controller_impl {
replaying_irreversible = false;

int unconf = 0;
while( auto obj = unconfirmed_blocks.find<unconfirmed_block_object,by_num>(head->block_num+1) ) {
while( auto obj = reversible_blocks.find<reversible_block_object,by_num>(head->block_num+1) ) {
++unconf;
self.push_block( obj->get_block(), true );
}

std::cerr<< "\n";
ilog( "${n} unconfirmed blocks replayed", ("n",unconf) );
ilog( "${n} reversible blocks replayed", ("n",unconf) );
auto end = fc::time_point::now();
ilog( "replayed blocks in ${n} seconds, ${spb} spb",
("n", head->block_num)("spb", ((end-start).count()/1000000.0)/head->block_num) );
ilog( "replayed ${n} blocks in seconds, ${mspb} ms/block",
("n", head->block_num)("duration", (end-start).count()/1000000)
("mspb", ((end-start).count()/1000.0)/head->block_num) );
std::cerr<< "\n";
replaying = false;

Expand All @@ -227,16 +228,16 @@ struct controller_impl {
}
}

const auto& ubi = unconfirmed_blocks.get_index<unconfirmed_block_index,by_num>();
const auto& ubi = reversible_blocks.get_index<reversible_block_index,by_num>();
auto objitr = ubi.rbegin();
if( objitr != ubi.rend() ) {
FC_ASSERT( objitr->blocknum == head->block_num,
"unconfirmed block database is inconsistent with fork database, replay blockchain",
"reversible block database is inconsistent with fork database, replay blockchain",
("head",head->block_num)("unconfimed", objitr->blocknum) );
} else {
auto end = blog.read_head();
FC_ASSERT( end && end->block_num() == head->block_num,
"fork database exists but unconfirmed block database does not, replay blockchain",
"fork database exists but reversible block database does not, replay blockchain",
("blog_head",end->block_num())("head",head->block_num) );
}

Expand All @@ -261,11 +262,11 @@ struct controller_impl {
edump((db.revision())(head->block_num)(blog.read_head()->block_num()));

db.flush();
unconfirmed_blocks.flush();
reversible_blocks.flush();
}

void add_indices() {
unconfirmed_blocks.add_index<unconfirmed_block_index>();
reversible_blocks.add_index<reversible_block_index>();

db.add_index<account_index>();
db.add_index<account_sequence_index>();
Expand Down Expand Up @@ -410,7 +411,7 @@ struct controller_impl {
emit( self.accepted_block, pending->_pending_block_state );

if( !replaying ) {
unconfirmed_blocks.create<unconfirmed_block_object>( [&]( auto& ubo ) {
reversible_blocks.create<reversible_block_object>( [&]( auto& ubo ) {
ubo.blocknum = pending->_pending_block_state->block_num;
ubo.set_block( pending->_pending_block_state->block );
});
Expand Down
2 changes: 2 additions & 0 deletions libraries/chain/fork_database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ namespace eosio { namespace chain {
fc::raw::unpack( ds, head_id );

my->head = get_block( head_id );

fc::remove( fork_db_dat );
}
}

Expand Down
2 changes: 1 addition & 1 deletion libraries/chain/include/eosio/chain/block_log.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ namespace eosio { namespace chain {

static const uint64_t npos = std::numeric_limits<uint64_t>::max();

static void repair_log( const fc::path& data_dir );
static fc::path repair_log( const fc::path& data_dir );

private:
void open(const fc::path& data_dir);
Expand Down
2 changes: 1 addition & 1 deletion libraries/chain/include/eosio/chain/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ typedef __uint128_t uint128_t;
const static auto default_block_log_dir = "block_log";
const static auto default_shared_memory_dir = "shared_mem";
const static auto default_shared_memory_size = 1*1024*1024*1024ll;
const static auto default_unconfirmed_cache_size = 320*1024*1024ll;/// 1MB * 340 blocks based on 21 producer BFT delay
const static auto default_reversible_cache_size = 320*1024*1024ll;/// 1MB * 340 blocks based on 21 producer BFT delay

const static uint64_t system_account_name = N(eosio);
const static uint64_t null_account_name = N(eosio.null);
Expand Down
4 changes: 2 additions & 2 deletions libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ namespace eosio { namespace chain {
public:
struct config {
path block_log_dir = chain::config::default_block_log_dir;
uint64_t unconfirmed_cache_size = chain::config::default_unconfirmed_cache_size;;
uint64_t reversible_cache_size = chain::config::default_reversible_cache_size;;
path shared_memory_dir = chain::config::default_shared_memory_dir;
uint64_t shared_memory_size = chain::config::default_shared_memory_size;
bool read_only = false;
Expand Down Expand Up @@ -203,7 +203,7 @@ namespace eosio { namespace chain {

FC_REFLECT( eosio::chain::controller::config,
(block_log_dir)
(unconfirmed_cache_size)
(reversible_cache_size)
(shared_memory_dir)(shared_memory_size)(read_only)
(force_all_checks)
(genesis)
Expand Down
3 changes: 2 additions & 1 deletion libraries/chain/include/eosio/chain/exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@ namespace eosio { namespace chain {
3100002, "unknown block" )
FC_DECLARE_DERIVED_EXCEPTION( unknown_transaction_exception, misc_exception,
3100003, "unknown transaction" )

FC_DECLARE_DERIVED_EXCEPTION( fixed_reversible_db_exception, misc_exception,
3100004, "corrupted reversible block database was fixed" )

FC_DECLARE_DERIVED_EXCEPTION( missing_plugin_exception, chain_exception,
3110000, "missing plugin exception" )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@

namespace eosio { namespace chain {

class unconfirmed_block_object : public chainbase::object<unconfirmed_block_object_type, unconfirmed_block_object> {
OBJECT_CTOR(unconfirmed_block_object,(packedblock) )
class reversible_block_object : public chainbase::object<reversible_block_object_type, reversible_block_object> {
OBJECT_CTOR(reversible_block_object,(packedblock) )

id_type id;
uint32_t blocknum = 0;
Expand All @@ -35,15 +35,14 @@ namespace eosio { namespace chain {
};

struct by_num;
using unconfirmed_block_index = chainbase::shared_multi_index_container<
unconfirmed_block_object,
using reversible_block_index = chainbase::shared_multi_index_container<
reversible_block_object,
indexed_by<
ordered_unique<tag<by_id>, member<unconfirmed_block_object, unconfirmed_block_object::id_type, &unconfirmed_block_object::id>>,
ordered_unique<tag<by_num>, member<unconfirmed_block_object, uint32_t, &unconfirmed_block_object::blocknum>>
ordered_unique<tag<by_id>, member<reversible_block_object, reversible_block_object::id_type, &reversible_block_object::id>>,
ordered_unique<tag<by_num>, member<reversible_block_object, uint32_t, &reversible_block_object::blocknum>>
>
>;

} } // eosio::chain

CHAINBASE_SET_INDEX_TYPE(eosio::chain::unconfirmed_block_object, eosio::chain::unconfirmed_block_index)

CHAINBASE_SET_INDEX_TYPE(eosio::chain::reversible_block_object, eosio::chain::reversible_block_index)
4 changes: 2 additions & 2 deletions libraries/chain/include/eosio/chain/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ namespace eosio { namespace chain {
resource_limits_config_object_type,
account_history_object_type,
action_history_object_type,
unconfirmed_block_object_type,
reversible_block_object_type,
OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types
};

Expand Down Expand Up @@ -220,7 +220,7 @@ FC_REFLECT_ENUM(eosio::chain::object_type,
(resource_limits_config_object_type)
(account_history_object_type)
(action_history_object_type)
(unconfirmed_block_object_type)
(reversible_block_object_type)
(OBJECT_TYPE_COUNT)
)
FC_REFLECT( eosio::chain::void_t, )
Loading

0 comments on commit 25ebcd1

Please sign in to comment.