From b2166804959c7018215c6ab095590171db377199 Mon Sep 17 00:00:00 2001 From: arhag Date: Sat, 30 Jun 2018 13:13:06 -0400 Subject: [PATCH] enforce loaded checkpoints #3337 --- libraries/chain/controller.cpp | 4 +++ .../chain/include/eosio/chain/controller.hpp | 1 + .../chain/include/eosio/chain/exceptions.hpp | 17 +++++++---- .../include/eosio/chain/plugin_interface.hpp | 3 +- plugins/chain_plugin/chain_plugin.cpp | 30 +++++++++++++++++-- 5 files changed, 45 insertions(+), 10 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 10a269ea7a7..39bf485245c 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -151,6 +151,9 @@ struct controller_impl { } catch (boost::interprocess::bad_alloc& e) { wlog( "bad alloc" ); throw e; + } catch ( controller_emit_signal_exception& e ) { + wlog( "${details}", ("details", e.to_detail_string()) ); + throw e; } catch ( fc::exception& e ) { wlog( "${details}", ("details", e.to_detail_string()) ); } catch ( ... ) { @@ -871,6 +874,7 @@ struct controller_impl { try { FC_ASSERT( b ); FC_ASSERT( s != controller::block_status::incomplete, "invalid block status for a completed block" ); + emit( self.pre_accepted_block, b ); bool trust = !conf.force_all_checks && (s == controller::block_status::irreversible || s == controller::block_status::validated); auto new_header_state = fork_db.add( b, trust ); emit( self.accepted_block_header, new_header_state ); diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 0dfd81f9e06..d3c686d4212 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -190,6 +190,7 @@ namespace eosio { namespace chain { db_read_mode get_read_mode()const; + signal pre_accepted_block; signal accepted_block_header; signal accepted_block; signal irreversible_block; diff --git a/libraries/chain/include/eosio/chain/exceptions.hpp b/libraries/chain/include/eosio/chain/exceptions.hpp index 900f66709ee..e3d07aa0371 100644 --- a/libraries/chain/include/eosio/chain/exceptions.hpp +++ b/libraries/chain/include/eosio/chain/exceptions.hpp @@ -287,17 +287,22 @@ namespace eosio { namespace chain { FC_DECLARE_DERIVED_EXCEPTION( whitelist_blacklist_exception, chain_exception, 3130000, "actor or contract whitelist/blacklist exception" ) - FC_DECLARE_DERIVED_EXCEPTION( actor_whitelist_exception, chain_exception, + FC_DECLARE_DERIVED_EXCEPTION( actor_whitelist_exception, whitelist_blacklist_exception, 3130001, "Authorizing actor of transaction is not on the whitelist" ) - FC_DECLARE_DERIVED_EXCEPTION( actor_blacklist_exception, chain_exception, + FC_DECLARE_DERIVED_EXCEPTION( actor_blacklist_exception, whitelist_blacklist_exception, 3130002, "Authorizing actor of transaction is on the blacklist" ) - FC_DECLARE_DERIVED_EXCEPTION( contract_whitelist_exception, chain_exception, + FC_DECLARE_DERIVED_EXCEPTION( contract_whitelist_exception, whitelist_blacklist_exception, 3130003, "Contract to execute is not on the whitelist" ) - FC_DECLARE_DERIVED_EXCEPTION( contract_blacklist_exception, chain_exception, + FC_DECLARE_DERIVED_EXCEPTION( contract_blacklist_exception, whitelist_blacklist_exception, 3130004, "Contract to execute is on the blacklist" ) - FC_DECLARE_DERIVED_EXCEPTION( action_blacklist_exception, chain_exception, + FC_DECLARE_DERIVED_EXCEPTION( action_blacklist_exception, whitelist_blacklist_exception, 3130005, "Action to execute is on the blacklist" ) - FC_DECLARE_DERIVED_EXCEPTION( key_blacklist_exception, chain_exception, + FC_DECLARE_DERIVED_EXCEPTION( key_blacklist_exception, whitelist_blacklist_exception, 3130006, "Public key in authority is on the blacklist" ) + FC_DECLARE_DERIVED_EXCEPTION( controller_emit_signal_exception, chain_exception, + 3140000, "exceptions that are allowed to bubble out of emit calls in controller" ) + FC_DECLARE_DERIVED_EXCEPTION( checkpoint_exception, controller_emit_signal_exception, + 3140001, "Block does not match checkpoint" ) + } } // eosio::chain diff --git a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp index 15700bb4485..7303768cab4 100644 --- a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp +++ b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp @@ -20,8 +20,9 @@ namespace eosio { namespace chain { namespace plugin_interface { using next_function = std::function&)>; struct chain_plugin_interface; - + namespace channels { + using pre_accepted_block = channel_decl; using rejected_block = channel_decl; using accepted_block_header = channel_decl; using accepted_block = channel_decl; diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index ba4e4ab76bb..fe4d5f92bde 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -100,7 +100,8 @@ using boost::signals2::scoped_connection; class chain_plugin_impl { public: chain_plugin_impl() - :accepted_block_header_channel(app().get_channel()) + :pre_accepted_block_channel(app().get_channel()) + ,accepted_block_header_channel(app().get_channel()) ,accepted_block_channel(app().get_channel()) ,irreversible_block_channel(app().get_channel()) ,accepted_transaction_channel(app().get_channel()) @@ -124,6 +125,7 @@ class chain_plugin_impl { fc::optional wasm_runtime; // retained references to channels for easy publication + channels::pre_accepted_block::channel_type& pre_accepted_block_channel; channels::accepted_block_header::channel_type& accepted_block_header_channel; channels::accepted_block::channel_type& accepted_block_channel; channels::irreversible_block::channel_type& irreversible_block_channel; @@ -143,6 +145,7 @@ class chain_plugin_impl { methods::get_last_irreversible_block_number::method_type::handle get_last_irreversible_block_number_provider; // scoped connections for chain controller + fc::optional pre_accepted_block_connection; fc::optional accepted_block_header_connection; fc::optional accepted_block_connection; fc::optional irreversible_block_connection; @@ -300,7 +303,15 @@ void chain_plugin::plugin_initialize(const variables_map& options) { for(auto cp : cps) { auto item = fc::json::from_string(cp).as>(); - my->loaded_checkpoints[item.first] = item.second; + auto itr = my->loaded_checkpoints.find(item.first); + if( itr != my->loaded_checkpoints.end() ) { + FC_ASSERT( itr->second == item.second, + "redefining existing checkpoint at block number ${num}: original: ${orig} new: ${new}", + ("num", item.first)("orig", itr->second)("new", item.second) + ); + } else { + my->loaded_checkpoints[item.first] = item.second; + } } } @@ -461,6 +472,19 @@ void chain_plugin::plugin_initialize(const variables_map& options) { }); // relay signals to channels + my->pre_accepted_block_connection = my->chain->pre_accepted_block.connect([this](const signed_block_ptr& blk) { + auto itr = my->loaded_checkpoints.find( blk->block_num() ); + if( itr != my->loaded_checkpoints.end() ) { + auto id = blk->id(); + EOS_ASSERT( itr->second == id, checkpoint_exception, + "Checkpoint does not match for block number ${num}: expected: ${expected} actual: ${actual}", + ("num", blk->block_num())("expected", itr->second)("actual", id) + ); + } + + my->pre_accepted_block_channel.publish(blk); + }); + my->accepted_block_header_connection = my->chain->accepted_block_header.connect([this](const block_state_ptr& blk) { my->accepted_block_header_channel.publish(blk); }); @@ -493,7 +517,6 @@ void chain_plugin::plugin_startup() if(!my->readonly) { ilog("starting chain in read/write mode"); - /// TODO: my->chain->add_checkpoints(my->loaded_checkpoints); } ilog("Blockchain started; head block is #${num}, genesis timestamp is ${ts}", @@ -503,6 +526,7 @@ void chain_plugin::plugin_startup() } FC_CAPTURE_AND_RETHROW() } void chain_plugin::plugin_shutdown() { + my->pre_accepted_block_connection.reset(); my->accepted_block_header_connection.reset(); my->accepted_block_connection.reset(); my->irreversible_block_connection.reset();