diff --git a/libraries/appbase b/libraries/appbase index f3a63c1c04d..1d6e6e4a0b3 160000 --- a/libraries/appbase +++ b/libraries/appbase @@ -1 +1 @@ -Subproject commit f3a63c1c04df957c0675b51d298851c71d6ccbe7 +Subproject commit 1d6e6e4a0b334553658fe05cfa1e86081b6d0b4a diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 38d52c7890c..9893c451aac 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -307,22 +307,25 @@ struct controller_impl { } } - void replay() { + void replay(std::function shutdown) { auto blog_head = blog.read_head(); auto blog_head_time = blog_head->timestamp.to_time_point(); replaying = true; replay_head_time = blog_head_time; - ilog( "existing block log, attempting to replay ${n} blocks", ("n",blog_head->block_num()) ); + auto start_block_num = head->block_num + 1; + ilog( "existing block log, attempting to replay from ${s} to ${n} blocks", + ("s", start_block_num)("n", blog_head->block_num()) ); auto start = fc::time_point::now(); while( auto next = blog.read_block_by_num( head->block_num + 1 ) ) { self.push_block( next, controller::block_status::irreversible ); if( next->block_num() % 100 == 0 ) { std::cerr << std::setw(10) << next->block_num() << " of " << blog_head->block_num() <<"\r"; + if( shutdown() ) break; } } std::cerr<< "\n"; - ilog( "${n} blocks replayed", ("n", head->block_num) ); + ilog( "${n} blocks replayed", ("n", head->block_num - start_block_num) ); // if the irreverible log is played without undo sessions enabled, we need to sync the // revision ordinal to the appropriate expected value here. @@ -338,42 +341,48 @@ struct controller_impl { ilog( "${n} reversible blocks replayed", ("n",rev) ); auto end = fc::time_point::now(); ilog( "replayed ${n} blocks in ${duration} seconds, ${mspb} ms/block", - ("n", head->block_num)("duration", (end-start).count()/1000000) - ("mspb", ((end-start).count()/1000.0)/head->block_num) ); + ("n", head->block_num - start_block_num)("duration", (end-start).count()/1000000) + ("mspb", ((end-start).count()/1000.0)/(head->block_num-start_block_num)) ); replaying = false; replay_head_time.reset(); } - void init(const snapshot_reader_ptr& snapshot) { + void init(std::function shutdown, const snapshot_reader_ptr& snapshot) { thread_pool.emplace( conf.thread_pool_size ); + bool report_integrity_hash = !!snapshot; if (snapshot) { - EOS_ASSERT(!head, fork_database_exception, ""); + EOS_ASSERT( !head, fork_database_exception, "" ); snapshot->validate(); - read_from_snapshot(snapshot); + read_from_snapshot( snapshot ); auto end = blog.read_head(); if( !end ) { - blog.reset(conf.genesis, signed_block_ptr(), head->block_num + 1); - } else if ( end->block_num() > head->block_num) { - replay(); + blog.reset( conf.genesis, signed_block_ptr(), head->block_num + 1 ); + } else if( end->block_num() > head->block_num ) { + replay( shutdown ); } else { - EOS_ASSERT(end->block_num() == head->block_num, fork_database_exception, - "Block log is provided with snapshot but does not contain the head block from the snapshot"); + EOS_ASSERT( end->block_num() == head->block_num, fork_database_exception, + "Block log is provided with snapshot but does not contain the head block from the snapshot" ); + } + } else { + if( !head ) { + initialize_fork_db(); // set head to genesis state } - } else if( !head ) { - initialize_fork_db(); // set head to genesis state auto end = blog.read_head(); - if( end && end->block_num() > 1 ) { - replay(); - } else if( !end ) { + if( !end ) { blog.reset( conf.genesis, head->block ); + } else if( end->block_num() > head->block_num ) { + replay( shutdown ); + report_integrity_hash = true; } } + if( shutdown() ) return; + const auto& ubi = reversible_blocks.get_index(); auto objitr = ubi.rbegin(); if( objitr != ubi.rend() ) { @@ -399,7 +408,7 @@ struct controller_impl { db.undo(); } - if( snapshot ) { + if( report_integrity_hash ) { const auto hash = calculate_integrity_hash(); ilog( "database initialized with hash: ${hash}", ("hash", hash) ); } @@ -1612,12 +1621,12 @@ void controller::add_indices() { my->add_indices(); } -void controller::startup( const snapshot_reader_ptr& snapshot ) { +void controller::startup( std::function shutdown, const snapshot_reader_ptr& snapshot ) { my->head = my->fork_db.head(); if( !my->head ) { elog( "No head block in fork db, perhaps we need to replay" ); } - my->init(snapshot); + my->init(shutdown, snapshot); } const chainbase::database& controller::db()const { return my->db; } diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 6f85668940c..4f781671fb2 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -90,7 +90,7 @@ namespace eosio { namespace chain { ~controller(); void add_indices(); - void startup( const snapshot_reader_ptr& snapshot = nullptr ); + void startup( std::function shutdown, const snapshot_reader_ptr& snapshot = nullptr ); /** * Starts a new pending block session upon which new transactions can diff --git a/libraries/testing/include/eosio/testing/tester.hpp b/libraries/testing/include/eosio/testing/tester.hpp index 9a4f4094330..b8ac40b3929 100644 --- a/libraries/testing/include/eosio/testing/tester.hpp +++ b/libraries/testing/include/eosio/testing/tester.hpp @@ -351,7 +351,7 @@ namespace eosio { namespace testing { validating_node = std::make_unique(vcfg); validating_node->add_indices(); - validating_node->startup(); + validating_node->startup( []() { return false; } ); init(true); } @@ -366,7 +366,7 @@ namespace eosio { namespace testing { validating_node = std::make_unique(vcfg); validating_node->add_indices(); - validating_node->startup(); + validating_node->startup( []() { return false; } ); init(config); } @@ -411,7 +411,7 @@ namespace eosio { namespace testing { validating_node.reset(); validating_node = std::make_unique(vcfg); validating_node->add_indices(); - validating_node->startup(); + validating_node->startup( []() { return false; } ); return ok; } diff --git a/libraries/testing/tester.cpp b/libraries/testing/tester.cpp index b116d1a4969..03d669dd5e4 100644 --- a/libraries/testing/tester.cpp +++ b/libraries/testing/tester.cpp @@ -124,7 +124,7 @@ namespace eosio { namespace testing { void base_tester::open( const snapshot_reader_ptr& snapshot) { control.reset( new controller(cfg) ); control->add_indices(); - control->startup(snapshot); + control->startup( []() { return false; }, snapshot); chain_transactions.clear(); control->accepted_block.connect([this]( const block_state_ptr& block_state ){ FC_ASSERT( block_state->block ); diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 3dd3a7e020f..69082c1dd90 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -703,13 +703,14 @@ void chain_plugin::plugin_initialize(const variables_map& options) { void chain_plugin::plugin_startup() { try { try { + auto shutdown = [](){ return app().is_quiting(); }; if (my->snapshot_path) { auto infile = std::ifstream(my->snapshot_path->generic_string(), (std::ios::in | std::ios::binary)); auto reader = std::make_shared(infile); - my->chain->startup(reader); + my->chain->startup(shutdown, reader); infile.close(); } else { - my->chain->startup(); + my->chain->startup(shutdown); } } catch (const database_guard_exception& e) { log_guard_exception(e);