Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

enforce checkpoints #4471

Merged
merged 2 commits into from
Jul 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 ( ... ) {
Expand Down Expand Up @@ -877,6 +880,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 );
Expand Down
1 change: 1 addition & 0 deletions libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ namespace eosio { namespace chain {

db_read_mode get_read_mode()const;

signal<void(const signed_block_ptr&)> pre_accepted_block;
signal<void(const block_state_ptr&)> accepted_block_header;
signal<void(const block_state_ptr&)> accepted_block;
signal<void(const block_state_ptr&)> irreversible_block;
Expand Down
17 changes: 11 additions & 6 deletions libraries/chain/include/eosio/chain/exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ namespace eosio { namespace chain { namespace plugin_interface {
using next_function = std::function<void(const fc::static_variant<fc::exception_ptr, T>&)>;

struct chain_plugin_interface;

namespace channels {
using pre_accepted_block = channel_decl<struct pre_accepted_block_tag, signed_block_ptr>;
using rejected_block = channel_decl<struct rejected_block_tag, signed_block_ptr>;
using accepted_block_header = channel_decl<struct accepted_block_header_tag, block_state_ptr>;
using accepted_block = channel_decl<struct accepted_block_tag, block_state_ptr>;
Expand Down
42 changes: 33 additions & 9 deletions plugins/chain_plugin/chain_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ using boost::signals2::scoped_connection;
class chain_plugin_impl {
public:
chain_plugin_impl()
:accepted_block_header_channel(app().get_channel<channels::accepted_block_header>())
:pre_accepted_block_channel(app().get_channel<channels::pre_accepted_block>())
,accepted_block_header_channel(app().get_channel<channels::accepted_block_header>())
,accepted_block_channel(app().get_channel<channels::accepted_block>())
,irreversible_block_channel(app().get_channel<channels::irreversible_block>())
,accepted_transaction_channel(app().get_channel<channels::accepted_transaction>())
Expand All @@ -129,6 +130,7 @@ class chain_plugin_impl {
fc::optional<vm_type> 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;
Expand All @@ -148,6 +150,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<scoped_connection> pre_accepted_block_connection;
fc::optional<scoped_connection> accepted_block_header_connection;
fc::optional<scoped_connection> accepted_block_connection;
fc::optional<scoped_connection> irreversible_block_connection;
Expand Down Expand Up @@ -301,15 +304,23 @@ void chain_plugin::plugin_initialize(const variables_map& options) {
my->blocks_dir = bld;
}

if( options.count( "checkpoint" )) {
auto cps = options.at( "checkpoint" ).as<vector<string>>();
my->loaded_checkpoints.reserve( cps.size());
for( auto cp : cps ) {
auto item = fc::json::from_string( cp ).as<std::pair<uint32_t, block_id_type>>();
my->loaded_checkpoints[item.first] = item.second;
if( options.count("checkpoint") ) {
auto cps = options.at("checkpoint").as<vector<string>>();
my->loaded_checkpoints.reserve(cps.size());
for( const auto& cp : cps ) {
auto item = fc::json::from_string(cp).as<std::pair<uint32_t,block_id_type>>();
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;
}
}
}

if(options.count("abi-serializer-max-time-ms"))
abi_serializer::set_max_serialization_time(fc::microseconds(options.at("abi-serializer-max-time-ms").as<uint32_t>() * 1000));

Expand Down Expand Up @@ -477,6 +488,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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future it would probably be convenient to allow for short-ids however, since we encode the block number in the ID we would need a canonical short ID that is reasonably collision resistant first.

"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 );
Expand Down Expand Up @@ -514,7 +538,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}",
Expand All @@ -524,6 +547,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();
Expand Down