From f47911cd9cdaca8043f2e224ba6f2d5380f49383 Mon Sep 17 00:00:00 2001 From: oldcold Date: Mon, 22 Jul 2019 11:46:48 +0800 Subject: [PATCH 01/14] optimise for return value. --- libraries/chain/block_header_state.cpp | 4 +- libraries/chain/controller.cpp | 10 +- libraries/chain/fork_database.cpp | 4 +- .../include/eosio/chain/fork_database.hpp | 4 +- libraries/chain/include/eosio/chain/pbft.hpp | 91 +++++---- .../include/eosio/chain/pbft_database.hpp | 102 +++++----- libraries/chain/pbft.cpp | 82 +------- libraries/chain/pbft_database.cpp | 189 +++++++++--------- plugins/net_plugin/net_plugin.cpp | 163 ++++----------- .../include/eosio/pbft_plugin/pbft_plugin.hpp | 6 +- plugins/pbft_plugin/pbft_plugin.cpp | 9 +- 11 files changed, 245 insertions(+), 419 deletions(-) diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index 690b10a947e..83e7c3292ad 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -158,7 +158,7 @@ namespace eosio { namespace chain { pending_schedule = *header.new_producers; pending_schedule_lib_num = block_num; } - + /** * Transitions the current header state into the next header state given the supplied signed block header. @@ -176,7 +176,7 @@ namespace eosio { namespace chain { EOS_ASSERT( h.previous == id, unlinkable_block_exception, "block must link to current state" ); auto result = generate_next( h.timestamp, pbft_enabled); EOS_ASSERT( result.header.producer == h.producer, wrong_producer, "wrong producer specified" ); - EOS_ASSERT( result.header.schedule_version == h.schedule_version, producer_schedule_exception, "schedule_version in signed block is corrupted" ); + EOS_ASSERT( result.header.schedule_version == h.schedule_version, producer_schedule_exception, "schedule_version in s igned block is corrupted" ); auto itr = producer_to_last_produced.find(h.producer); if( itr != producer_to_last_produced.end() ) { diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 2aa4644afb4..da23d6e193f 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -2526,13 +2526,15 @@ void controller::set_pbft_my_prepare(const block_id_type& id) { } block_id_type controller::get_pbft_prepared() const { - if (my->pbft_prepared) return my->pbft_prepared->id; - return block_id_type{}; + block_id_type pp; + if (my->pbft_prepared) pp = my->pbft_prepared->id; + return pp; } block_id_type controller::get_pbft_my_prepare() const { - if (my->my_prepare) return my->my_prepare->id; - return block_id_type{}; + block_id_type mp; + if (my->my_prepare) mp = my->my_prepare->id; + return mp; } void controller::reset_pbft_my_prepare() { diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index 2163a5a5960..be36a908895 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -525,7 +525,7 @@ namespace eosio { namespace chain { * * This will require a search over all forks */ - void fork_database::set_bft_irreversible( block_id_type id ) { + void fork_database::set_bft_irreversible( const block_id_type& id ) { auto b = get_block( id ); EOS_ASSERT( b, fork_db_block_not_found, "unable to find block id ${id}", ("id",id)); @@ -569,7 +569,7 @@ namespace eosio { namespace chain { my->head = *my->index.get().begin(); } - void fork_database::set_latest_checkpoint( block_id_type id) { + void fork_database::set_latest_checkpoint( const block_id_type& id) { auto b = get_block( id ); EOS_ASSERT( b, fork_db_block_not_found, "unable to find block id ${id}", ("id",id)); diff --git a/libraries/chain/include/eosio/chain/fork_database.hpp b/libraries/chain/include/eosio/chain/fork_database.hpp index 823c65c5b92..9dfb3f0cc9c 100644 --- a/libraries/chain/include/eosio/chain/fork_database.hpp +++ b/libraries/chain/include/eosio/chain/fork_database.hpp @@ -70,9 +70,9 @@ namespace eosio { namespace chain { */ signal irreversible; - void set_bft_irreversible( block_id_type id ); + void set_bft_irreversible( const block_id_type& id ); - void set_latest_checkpoint( block_id_type id); + void set_latest_checkpoint( const block_id_type& id); void mark_pbft_prepared_fork(const block_state_ptr& h); diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index 2bebe05cc79..e9e1d856dad 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -54,38 +54,37 @@ namespace eosio { void do_send_view_change(); bool maybe_new_view(const psm_state_ptr& s); - const pbft_prepare& get_prepares_cache() const; - void set_prepares_cache(const pbft_prepare &pcache); + const pbft_prepare& get_prepares_cache() const { return cache.prepares_cache; } + void set_prepares_cache(const pbft_prepare& pcache) { cache.prepares_cache = pcache; } - const pbft_commit& get_commits_cache() const; - void set_commits_cache(const pbft_commit &ccache); + const pbft_commit& get_commits_cache() const { return cache.commits_cache; } + void set_commits_cache(const pbft_commit& ccache) { cache.commits_cache = ccache; } - const pbft_view_change& get_view_changes_cache() const; - void set_view_changes_cache(const pbft_view_change &vc_cache); + const pbft_view_change& get_view_changes_cache() const { return cache.view_changes_cache; } + void set_view_changes_cache(const pbft_view_change& vc_cache) { cache.view_changes_cache = vc_cache; } - const uint32_t &get_current_view() const; - void set_current_view(const uint32_t &cv); + uint32_t get_current_view() const { return current_view; } + void set_current_view(uint32_t cv) { current_view = cv; } - const pbft_prepared_certificate& get_prepared_certificate() const; - void set_prepared_certificate(const pbft_prepared_certificate &pcert); + const pbft_prepared_certificate& get_prepared_certificate() const { return cache.prepared_certificate; } + void set_prepared_certificate(const pbft_prepared_certificate& pcert) { cache.prepared_certificate = pcert; } - const vector& get_committed_certificate() const; - void set_committed_certificate(const vector &ccert); + const vector& get_committed_certificate() const { return cache.committed_certificate; } + void set_committed_certificate(const vector& ccert) { cache.committed_certificate = ccert; } - const pbft_view_changed_certificate& get_view_changed_certificate() const; - void set_view_changed_certificate(const pbft_view_changed_certificate &vc_cert); + const pbft_view_changed_certificate& get_view_changed_certificate() const { return cache.view_changed_certificate; } + void set_view_changed_certificate(const pbft_view_changed_certificate& vc_cert) { cache.view_changed_certificate = vc_cert; } - const uint32_t& get_target_view_retries() const; - void set_target_view_retries(const uint32_t &tv_reties); + uint32_t get_target_view_retries() const { return target_view_retries; } + void set_target_view_retries(uint32_t tv_reties) { target_view_retries = tv_reties; } - const uint32_t& get_target_view() const; - void set_target_view(const uint32_t &tv); + uint32_t get_target_view() const { return target_view; } + void set_target_view(uint32_t tv) { target_view = tv; } - const uint32_t& get_view_change_timer() const; - void set_view_change_timer(const uint32_t &vc_timer); - - void manually_set_current_view(const uint32_t &cv); + uint32_t get_view_change_timer() const { return view_change_timer; } + void set_view_change_timer(uint32_t vc_timer) { view_change_timer = vc_timer; } + void manually_set_current_view(uint32_t cv); protected: psm_cache cache; uint32_t current_view; @@ -106,13 +105,13 @@ namespace eosio { psm_state(); ~psm_state(); - virtual void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) = 0; - virtual void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) = 0; - virtual void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) = 0; + virtual void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) = 0; + virtual void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) = 0; + virtual void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) = 0; - virtual void send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) = 0; - virtual void send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) = 0; - virtual void send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) = 0; + virtual void send_prepare(const psm_machine_ptr& m, pbft_database& pbft_db) = 0; + virtual void send_commit(const psm_machine_ptr& m, pbft_database& pbft_db) = 0; + virtual void send_view_change(const psm_machine_ptr& m, pbft_database& pbft_db) = 0; virtual const char* get_name() = 0; std::shared_ptr get_self() { return shared_from_this(); }; @@ -124,13 +123,13 @@ namespace eosio { psm_prepared_state(); ~psm_prepared_state(); - void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; + void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; + void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; + void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; - void send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) override; + void send_prepare(const psm_machine_ptr& m, pbft_database& pbft_db) override; + void send_commit(const psm_machine_ptr& m, pbft_database& pbft_db) override; + void send_view_change(const psm_machine_ptr& m, pbft_database& pbft_db) override; bool pending_commit_local; @@ -142,13 +141,13 @@ namespace eosio { psm_committed_state(); ~psm_committed_state(); - void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; + void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; + void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; + void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; - void send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) override; + void send_prepare(const psm_machine_ptr& m, pbft_database& pbft_db) override; + void send_commit(const psm_machine_ptr& m, pbft_database& pbft_db) override; + void send_view_change(const psm_machine_ptr& m, pbft_database& pbft_db) override; const char* get_name() override { return "{==== COMMITTED ====}"; } }; @@ -158,13 +157,13 @@ namespace eosio { psm_view_change_state(); ~psm_view_change_state(); - void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; + void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; + void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; + void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; - void send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) override; + void send_prepare(const psm_machine_ptr& m, pbft_database& pbft_db) override; + void send_commit(const psm_machine_ptr& m, pbft_database& pbft_db) override; + void send_view_change(const psm_machine_ptr& m, pbft_database& pbft_db) override; const char* get_name() override { return "{==== VIEW CHANGE ====}"; } }; diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index b72f9645b66..b571c96f420 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -37,11 +37,11 @@ namespace eosio { return fc::endian_reverse_u32(block_id._hash[0]); } - bool operator==(const block_info_type &rhs) const { + bool operator==(const block_info_type& rhs) const { return block_id == rhs.block_id; } - bool operator!=(const block_info_type &rhs) const { + bool operator!=(const block_info_type& rhs) const { return !(*this == rhs); } @@ -84,7 +84,7 @@ namespace eosio { block_info_type block_info; signature_type sender_signature; - bool operator<(const pbft_prepare &rhs) const { + bool operator<(const pbft_prepare& rhs) const { if (block_info.block_num() < rhs.block_info.block_num()) { return true; } else if (block_info.block_num() == rhs.block_info.block_num()) { @@ -120,7 +120,7 @@ namespace eosio { block_info_type block_info; signature_type sender_signature; - bool operator<(const pbft_commit &rhs) const { + bool operator<(const pbft_commit& rhs) const { if (block_info.block_num() < rhs.block_info.block_num()) { return true; } else if (block_info.block_num() == rhs.block_info.block_num()) { @@ -155,7 +155,7 @@ namespace eosio { block_info_type block_info; signature_type sender_signature; - bool operator<(const pbft_checkpoint &rhs) const { + bool operator<(const pbft_checkpoint& rhs) const { return block_info.block_num() < rhs.block_info.block_num(); } @@ -176,7 +176,7 @@ namespace eosio { block_info_type block_info; vector checkpoints; - bool operator<(const pbft_stable_checkpoint &rhs) const { + bool operator<(const pbft_stable_checkpoint& rhs) const { return block_info.block_num() < rhs.block_info.block_num(); } @@ -193,7 +193,7 @@ namespace eosio { set pre_prepares; vector prepares; - bool operator<(const pbft_prepared_certificate &rhs) const { + bool operator<(const pbft_prepared_certificate& rhs) const { return block_info.block_num() < rhs.block_info.block_num(); } @@ -209,7 +209,7 @@ namespace eosio { block_info_type block_info; vector commits; - bool operator<(const pbft_committed_certificate &rhs) const { + bool operator<(const pbft_committed_certificate& rhs) const { return block_info.block_num() < rhs.block_info.block_num(); } @@ -230,7 +230,7 @@ namespace eosio { pbft_stable_checkpoint stable_checkpoint; signature_type sender_signature; - bool operator<(const pbft_view_change &rhs) const { + bool operator<(const pbft_view_change& rhs) const { return target_view < rhs.target_view; } @@ -281,7 +281,7 @@ namespace eosio { pbft_view_changed_certificate view_changed_cert; signature_type sender_signature; - bool operator<(const pbft_new_view &rhs) const { + bool operator<(const pbft_new_view& rhs) const { return new_view < rhs.new_view; } @@ -415,27 +415,27 @@ namespace eosio { class pbft_database { public: - explicit pbft_database(controller &ctrl); + explicit pbft_database(controller& ctrl); ~pbft_database(); void close(); - void add_pbft_prepare(pbft_prepare &p, const public_key_type &pk); - void add_pbft_commit(pbft_commit &c, const public_key_type &pk); - void add_pbft_view_change(pbft_view_change &vc, const public_key_type &pk); - void add_pbft_checkpoint(pbft_checkpoint &cp, const public_key_type &pk); + void add_pbft_prepare(const pbft_prepare& p, const public_key_type& pk); + void add_pbft_commit(const pbft_commit& c, const public_key_type& pk); + void add_pbft_view_change(const pbft_view_change& vc, const public_key_type& pk); + void add_pbft_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk); - pbft_prepare send_and_add_pbft_prepare(const pbft_prepare &cached_prepare = pbft_prepare(), pbft_view_type current_view = 0); - pbft_commit send_and_add_pbft_commit(const pbft_commit &cached_commit = pbft_commit(), pbft_view_type current_view = 0); + pbft_prepare send_and_add_pbft_prepare(const pbft_prepare& cached_prepare = pbft_prepare(), pbft_view_type current_view = 0); + pbft_commit send_and_add_pbft_commit(const pbft_commit& cached_commit = pbft_commit(), pbft_view_type current_view = 0); pbft_view_change send_and_add_pbft_view_change( - const pbft_view_change &cached_view_change = pbft_view_change(), - const pbft_prepared_certificate &ppc = pbft_prepared_certificate(), - const vector &pcc = vector{}, + const pbft_view_change& cached_view_change = pbft_view_change(), + const pbft_prepared_certificate& ppc = pbft_prepared_certificate(), + const vector& pcc = vector{}, pbft_view_type current_view = 0, pbft_view_type target_view = 1); pbft_new_view send_pbft_new_view( - const pbft_view_changed_certificate &vcc = pbft_view_changed_certificate(), + const pbft_view_changed_certificate& vcc = pbft_view_changed_certificate(), pbft_view_type current_view = 1); vector generate_and_add_pbft_checkpoint(); void send_pbft_checkpoint(); @@ -446,13 +446,13 @@ namespace eosio { bool should_new_view(pbft_view_type target_view); //new view - bool has_new_primary(const public_key_type &pk); + bool has_new_primary(const public_key_type& pk); pbft_view_type get_proposed_new_view_num(); pbft_view_type get_committed_view(); public_key_type get_new_view_primary_key(pbft_view_type target_view); - void mark_as_prepared(const block_id_type &bid); - void mark_as_committed(const block_id_type &bid); + void mark_as_prepared(const block_id_type& bid); + void mark_as_committed(const block_id_type& bid); void commit_local(); void checkpoint_local(); @@ -460,43 +460,43 @@ namespace eosio { pbft_prepared_certificate generate_prepared_certificate(); vector generate_committed_certificate(); pbft_view_changed_certificate generate_view_changed_certificate(pbft_view_type target_view); - bool should_stop_view_change(const pbft_view_change &vc); + bool should_stop_view_change(const pbft_view_change& vc); //validations - bool is_valid_prepare(const pbft_prepare &p, const public_key_type &pk); - bool is_valid_commit(const pbft_commit &c, const public_key_type &pk); - bool is_valid_checkpoint(const pbft_checkpoint &cp, const public_key_type &pk); - bool is_valid_view_change(const pbft_view_change &vc, const public_key_type &pk); - void validate_new_view(const pbft_new_view &nv, const public_key_type &pk); - bool is_valid_stable_checkpoint(const pbft_stable_checkpoint &scp, bool add_to_pbft_db = false); + bool is_valid_prepare(const pbft_prepare& p, const public_key_type& pk); + bool is_valid_commit(const pbft_commit& c, const public_key_type& pk); + bool is_valid_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk); + bool is_valid_view_change(const pbft_view_change& vc, const public_key_type& pk); + void validate_new_view(const pbft_new_view& nv, const public_key_type& pk); + bool is_valid_stable_checkpoint(const pbft_stable_checkpoint& scp, bool add_to_pbft_db = false); bool should_send_pbft_msg(); - bool should_recv_pbft_msg(const public_key_type &pub_key); + bool should_recv_pbft_msg(const public_key_type& pub_key); bool pending_pbft_lib(); chain_id_type& get_chain_id() {return chain_id;} - pbft_stable_checkpoint get_stable_checkpoint_by_id(const block_id_type &block_id, bool incl_blk_extn = true); - pbft_stable_checkpoint fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr &b); + pbft_stable_checkpoint get_stable_checkpoint_by_id(const block_id_type& block_id, bool incl_blk_extn = true); + pbft_stable_checkpoint fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr& b); block_info_type cal_pending_stable_checkpoint() const; void cleanup_on_new_view(); void update_fork_schedules(); //api related - pbft_state_ptr get_pbft_state_by_id(const block_id_type &id) const; - vector get_checkpoints_by_num(const block_num_type &num) const; - pbft_view_change_state_ptr get_view_changes_by_target_view(const pbft_view_type &tv) const; + pbft_state_ptr get_pbft_state_by_id(const block_id_type& id) const; + vector get_checkpoints_by_num(block_num_type num) const; + pbft_view_change_state_ptr get_view_changes_by_target_view(pbft_view_type tv) const; vector get_pbft_watermarks() const; flat_map get_pbft_fork_schedules() const; - signal pbft_outgoing_prepare; - signal pbft_outgoing_commit; - signal pbft_outgoing_view_change; - signal pbft_outgoing_new_view; - signal pbft_outgoing_checkpoint; + signal pbft_outgoing_prepare; + signal pbft_outgoing_commit; + signal pbft_outgoing_view_change; + signal pbft_outgoing_new_view; + signal pbft_outgoing_checkpoint; private: - controller &ctrl; + controller& ctrl; pbft_state_multi_index_type pbft_state_index; pbft_view_state_multi_index_type view_state_index; pbft_checkpoint_state_multi_index_type checkpoint_index; @@ -507,26 +507,26 @@ namespace eosio { chain_id_type chain_id = ctrl.get_chain_id(); - bool is_less_than_high_watermark(const block_num_type &bnum); - bool is_valid_prepared_certificate(const pbft_prepared_certificate &certificate, bool add_to_pbft_db = false); - bool is_valid_committed_certificate(const pbft_committed_certificate &certificate, bool add_to_pbft_db = false); - bool is_valid_longest_fork(const block_info_type &bi, vector block_infos, unsigned long threshold, unsigned long non_fork_bp_count); + bool is_less_than_high_watermark(block_num_type bnum); + bool is_valid_prepared_certificate(const pbft_prepared_certificate& certificate, bool add_to_pbft_db = false); + bool is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db = false); + bool is_valid_longest_fork(const block_info_type& bi, vector block_infos, unsigned long threshold, unsigned long non_fork_bp_count); producer_schedule_type lscb_active_producers() const; vector& get_updated_watermarks(); flat_map& get_updated_fork_schedules(); block_num_type get_current_pbft_watermark(); - vector> fetch_fork_from(vector &block_infos); - vector fetch_first_fork_from(vector &bi); + vector> fetch_fork_from(vector& block_infos); + vector fetch_first_fork_from(vector& bi); template void emit(const Signal &s, Arg &&a); void set(const pbft_state_ptr& s); void set(const pbft_checkpoint_state_ptr& s); - void prune(const pbft_state_ptr &h); - void prune(const pbft_checkpoint_state_ptr &h); + void prune(const pbft_state_ptr& h); + void prune(const pbft_checkpoint_state_ptr& h); }; } } /// namespace eosio::chain diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index ccc5598dc63..2c510ef6512 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -154,7 +154,7 @@ namespace eosio { } } - void psm_machine::manually_set_current_view(const uint32_t &cv) { + void psm_machine::manually_set_current_view(uint32_t cv) { set_current_view(cv); set_target_view(cv + 1); transit_to_view_change_state(current); @@ -493,85 +493,5 @@ namespace eosio { set_view_changes_cache(view_changes); } } - - const pbft_prepare& psm_machine::get_prepares_cache() const { - return cache.prepares_cache; - } - - void psm_machine::set_prepares_cache(const pbft_prepare &pcache) { - cache.prepares_cache = pcache; - } - - const pbft_commit& psm_machine::get_commits_cache() const { - return cache.commits_cache; - } - - void psm_machine::set_commits_cache(const pbft_commit &ccache) { - cache.commits_cache = ccache; - } - - const pbft_view_change& psm_machine::get_view_changes_cache() const { - return cache.view_changes_cache; - } - - void psm_machine::set_view_changes_cache(const pbft_view_change &vc_cache) { - cache.view_changes_cache = vc_cache; - } - - const uint32_t& psm_machine::get_current_view() const { - return current_view; - } - - void psm_machine::set_current_view(const uint32_t &cv) { - current_view = cv; - } - - const pbft_prepared_certificate& psm_machine::get_prepared_certificate() const { - return cache.prepared_certificate; - } - - void psm_machine::set_prepared_certificate(const pbft_prepared_certificate &pcert) { - cache.prepared_certificate = pcert; - } - - const vector& psm_machine::get_committed_certificate() const { - return cache.committed_certificate; - } - - void psm_machine::set_committed_certificate(const vector &ccert) { - cache.committed_certificate = ccert; - } - - const pbft_view_changed_certificate& psm_machine::get_view_changed_certificate() const { - return cache.view_changed_certificate; - } - - void psm_machine::set_view_changed_certificate(const pbft_view_changed_certificate &vc_cert) { - cache.view_changed_certificate = vc_cert; - } - - const uint32_t& psm_machine::get_target_view_retries() const { - return target_view_retries; - } - - void psm_machine::set_target_view_retries(const uint32_t &tv_reties) { - target_view_retries = tv_reties; - } - - const uint32_t& psm_machine::get_target_view() const { - return target_view; - } - - void psm_machine::set_target_view(const uint32_t &tv) { - target_view = tv; - } - - const uint32_t& psm_machine::get_view_change_timer() const { - return view_change_timer; - } - - void psm_machine::set_view_change_timer(const uint32_t &vc_timer) { - view_change_timer = vc_timer; - } } } \ No newline at end of file diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 3e2a71fd86f..f915e100383 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -6,8 +6,7 @@ namespace eosio { namespace chain { - pbft_database::pbft_database(controller &ctrl) : - ctrl(ctrl) { + pbft_database::pbft_database(controller& ctrl) :ctrl(ctrl) { checkpoint_index = pbft_checkpoint_state_multi_index_type(); view_state_index = pbft_view_state_multi_index_type(); prepare_watermarks = vector{}; @@ -93,7 +92,7 @@ namespace eosio { close(); } - void pbft_database::add_pbft_prepare(pbft_prepare &p, const public_key_type &pk) { + void pbft_database::add_pbft_prepare(const pbft_prepare& p, const public_key_type& pk) { auto &by_block_id_index = pbft_state_index.get(); @@ -118,7 +117,7 @@ namespace eosio { } else { auto prepares = (*curr_itr)->prepares; if (prepares.find(std::make_pair(p.view, pk)) == prepares.end()) { - by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr &psp) { + by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr& psp) { psp->prepares[std::make_pair(p.view, pk)] = p; }); } @@ -151,7 +150,7 @@ namespace eosio { } } - void pbft_database::mark_as_prepared(const block_id_type &bid) { + void pbft_database::mark_as_prepared(const block_id_type& bid) { auto &by_block_id_index = pbft_state_index.get(); auto itr = by_block_id_index.find(bid); auto bnum = block_info_type{bid}.block_num(); @@ -165,17 +164,17 @@ namespace eosio { pbft_state_index.insert(psp); return; } - by_block_id_index.modify(itr, [&](const pbft_state_ptr &p) { p->is_prepared = true; }); + by_block_id_index.modify(itr, [&](const pbft_state_ptr& p) { p->is_prepared = true; }); } - pbft_prepare pbft_database::send_and_add_pbft_prepare(const pbft_prepare &cached_prepare, pbft_view_type current_view) { - auto prepare_to_be_cached = pbft_prepare(); + pbft_prepare pbft_database::send_and_add_pbft_prepare(const pbft_prepare& cached_prepare, pbft_view_type current_view) { + pbft_prepare prepare_to_be_cached; auto head_block_num = ctrl.head_block_num(); if (head_block_num <= 1) return prepare_to_be_cached; auto my_prepare = ctrl.get_pbft_my_prepare(); - auto reserve_prepare = [&](const block_id_type &in) { + auto reserve_prepare = [&](const block_id_type& in) { if (in == block_id_type() || !ctrl.fetch_block_state_by_id(in)) return false; auto lib = ctrl.last_irreversible_block_id(); if (lib == block_id_type()) return true; @@ -195,7 +194,6 @@ namespace eosio { retry_p.sender_signature = sp.second(retry_p.digest(chain_id)); emit(pbft_outgoing_prepare, std::make_shared(retry_p)); } - return prepare_to_be_cached; } else if (reserve_prepare(my_prepare)) { for (auto const &sp : ctrl.my_signature_providers()) { pbft_prepare reserve_p; @@ -204,7 +202,6 @@ namespace eosio { emit(pbft_outgoing_prepare, std::make_shared(reserve_p)); if (prepare_to_be_cached.empty()) prepare_to_be_cached = reserve_p; } - return prepare_to_be_cached; } else { auto current_watermark = get_current_pbft_watermark(); @@ -233,8 +230,8 @@ namespace eosio { } if (sent) ctrl.set_pbft_my_prepare(hwbs->id); } - return prepare_to_be_cached; } + return prepare_to_be_cached; } bool pbft_database::should_prepared() { @@ -252,13 +249,13 @@ namespace eosio { return false; } - bool pbft_database::is_valid_prepare(const pbft_prepare &p, const public_key_type &pk) { + bool pbft_database::is_valid_prepare(const pbft_prepare& p, const public_key_type& pk) { // a prepare msg under lscb (which is no longer in fork_db), can be treated as null, thus true. if (p.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) return true; return should_recv_pbft_msg(pk); } - void pbft_database::add_pbft_commit(pbft_commit &c, const public_key_type &pk) { + void pbft_database::add_pbft_commit(const pbft_commit& c, const public_key_type& pk) { auto &by_block_id_index = pbft_state_index.get(); @@ -284,7 +281,7 @@ namespace eosio { } else { auto commits = (*curr_itr)->commits; if (commits.find(std::make_pair(c.view, pk)) == commits.end()) { - by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr &psp) { + by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr& psp) { psp->commits[std::make_pair(c.view, pk)] = c; std::sort(psp->commits.begin(), psp->commits.end(), less<>()); }); @@ -321,8 +318,8 @@ namespace eosio { } } - pbft_commit pbft_database::send_and_add_pbft_commit(const pbft_commit &cached_commit, pbft_view_type current_view) { - auto commit_to_be_cached = pbft_commit(); + pbft_commit pbft_database::send_and_add_pbft_commit(const pbft_commit& cached_commit, pbft_view_type current_view) { + pbft_commit commit_to_be_cached; if (!cached_commit.empty()) { for (auto const &sp : ctrl.my_signature_providers()) { @@ -332,7 +329,6 @@ namespace eosio { retry_c.sender_signature = sp.second(retry_c.digest(chain_id)); emit(pbft_outgoing_commit, std::make_shared(retry_c)); } - return commit_to_be_cached; } else { auto const &by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); @@ -357,15 +353,15 @@ namespace eosio { } } } - return commit_to_be_cached; } + return commit_to_be_cached; } - void pbft_database::mark_as_committed(const block_id_type &bid) { + void pbft_database::mark_as_committed(const block_id_type& bid) { auto &by_block_id_index = pbft_state_index.get(); auto itr = by_block_id_index.find(bid); if (itr == by_block_id_index.end()) return; - by_block_id_index.modify(itr, [&](const pbft_state_ptr &p) { p->is_committed = true; }); + by_block_id_index.modify(itr, [&](const pbft_state_ptr& p) { p->is_committed = true; }); } bool pbft_database::should_committed() { @@ -412,7 +408,7 @@ namespace eosio { return new_view; } - bool pbft_database::is_valid_commit(const pbft_commit &c, const public_key_type &pk) { + bool pbft_database::is_valid_commit(const pbft_commit& c, const public_key_type& pk) { if (c.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) return true; return should_recv_pbft_msg(pk); } @@ -431,7 +427,7 @@ namespace eosio { return ctrl.pending_pbft_lib(); } - void pbft_database::add_pbft_view_change(pbft_view_change &vc, const public_key_type &pk) { + void pbft_database::add_pbft_view_change(const pbft_view_change& vc, const public_key_type& pk) { auto lscb_bps = lscb_active_producers().producers; @@ -450,7 +446,7 @@ namespace eosio { auto view_changes = pvs->view_changes; if (view_changes.find(pk) == view_changes.end()) { - by_view_index.modify(itr, [&](const pbft_view_change_state_ptr &pvsp) { + by_view_index.modify(itr, [&](const pbft_view_change_state_ptr& pvsp) { pvsp->view_changes[pk] = vc; }); } @@ -470,7 +466,7 @@ namespace eosio { } } if (vc_count >= threshold) { - by_view_index.modify(itr, [&](const pbft_view_change_state_ptr &pvsp) { pvsp->is_view_changed = true; }); + by_view_index.modify(itr, [&](const pbft_view_change_state_ptr& pvsp) { pvsp->is_view_changed = true; }); } } } @@ -502,13 +498,13 @@ namespace eosio { } pbft_view_change pbft_database::send_and_add_pbft_view_change( - const pbft_view_change &cached_view_change, - const pbft_prepared_certificate &ppc, - const vector &pcc, + const pbft_view_change& cached_view_change, + const pbft_prepared_certificate& ppc, + const vector& pcc, pbft_view_type current_view, pbft_view_type target_view) { - auto view_change_to_be_cached = pbft_view_change(); + pbft_view_change view_change_to_be_cached; if (!cached_view_change.empty()) { for (auto const &sp : ctrl.my_signature_providers()) { //sign again, update cache, then emit @@ -517,7 +513,6 @@ namespace eosio { retry_vc.sender_signature = sp.second(retry_vc.digest(chain_id)); emit(pbft_outgoing_view_change, std::make_shared(retry_vc)); } - return view_change_to_be_cached; } else { for (auto const &my_sp : ctrl.my_signature_providers()) { @@ -536,11 +531,11 @@ namespace eosio { if (view_change_to_be_cached.empty()) view_change_to_be_cached = new_vc; } } - return view_change_to_be_cached; } + return view_change_to_be_cached; } - bool pbft_database::should_new_view(const pbft_view_type target_view) { + bool pbft_database::should_new_view(pbft_view_type target_view) { auto &by_view_index = view_state_index.get(); auto itr = by_view_index.find(target_view); if (itr == by_view_index.end()) return false; @@ -554,7 +549,7 @@ namespace eosio { return (*itr)->view; } - bool pbft_database::has_new_primary(const public_key_type &pk) { + bool pbft_database::has_new_primary(const public_key_type& pk) { if (pk == public_key_type()) return false; auto sps = ctrl.my_signature_providers(); @@ -568,11 +563,13 @@ namespace eosio { } pbft_new_view pbft_database::send_pbft_new_view( - const pbft_view_changed_certificate &vcc, + const pbft_view_changed_certificate& vcc, pbft_view_type current_view) { + pbft_new_view nv; + auto primary_key = get_new_view_primary_key(current_view); - if (!has_new_primary(primary_key) || vcc.empty()) return pbft_new_view(); + if (!has_new_primary(primary_key) || vcc.empty()) return nv; //`sp_itr` is not possible to be the end iterator, since it's already been checked in `has_new_primary`. auto my_sps = ctrl.my_signature_providers(); @@ -589,7 +586,7 @@ namespace eosio { for (auto const &cc: vc.committed_certs) { auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), - [&](const pbft_committed_certificate &ext) { return ext.block_info.block_id == cc.block_info.block_id; }); + [&](const pbft_committed_certificate& ext) { return ext.block_info.block_id == cc.block_info.block_id; }); if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); } @@ -598,7 +595,6 @@ namespace eosio { } } - pbft_new_view nv; nv.new_view=current_view; nv.prepared_cert=highest_ppc; nv.committed_certs=highest_pcc; @@ -608,22 +604,24 @@ namespace eosio { try { validate_new_view(nv, sp_itr->first); emit(pbft_outgoing_new_view, std::make_shared(nv)); - return nv; } catch (const fc::exception& ex) { elog("bad new view, ${s} ", ("s", ex.to_string())); - return pbft_new_view(); + nv = pbft_new_view(); } + return nv; } pbft_prepared_certificate pbft_database::generate_prepared_certificate() { + pbft_prepared_certificate ppc; + auto const &by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); - if (itr == by_prepare_and_num_index.end()) return pbft_prepared_certificate(); + if (itr == by_prepare_and_num_index.end()) return ppc; pbft_state_ptr psp = *itr; auto prepared_block_state = ctrl.fetch_block_state_by_id(psp->block_id); - if (!prepared_block_state) return pbft_prepared_certificate(); + if (!prepared_block_state) return ppc; auto as = prepared_block_state->active_schedule.producers; if (psp->is_prepared && psp->block_num > ctrl.last_irreversible_block_num()) { @@ -651,24 +649,23 @@ namespace eosio { } } - if (valid_prepares.empty()) return pbft_prepared_certificate(); + if (valid_prepares.empty()) return ppc; - pbft_prepared_certificate pc; - pc.block_info={psp->block_id}; pc.prepares=valid_prepares; pc.pre_prepares.emplace(psp->block_id); + ppc.block_info={psp->block_id}; ppc.prepares=valid_prepares; ppc.pre_prepares.emplace(psp->block_id); for (auto const &p: valid_prepares) { auto bid = p.block_info.block_id; while (bid != psp->block_id) { - pc.pre_prepares.emplace(bid); + ppc.pre_prepares.emplace(bid); bid = ctrl.fetch_block_state_by_id(bid)->prev(); } } - return pc; - } else return pbft_prepared_certificate(); + } + return ppc; } vector pbft_database::generate_committed_certificate() { - auto pcc = vector{}; + vector pcc{}; auto const &by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); @@ -748,7 +745,7 @@ namespace eosio { pbft_view_changed_certificate pbft_database::generate_view_changed_certificate(pbft_view_type target_view) { - auto pvcc = pbft_view_changed_certificate(); + pbft_view_changed_certificate pvcc; auto &by_view_index = view_state_index.get(); auto itr = by_view_index.find(target_view); @@ -757,19 +754,18 @@ namespace eosio { auto pvs = *itr; if (pvs->is_view_changed) { - pvcc.target_view=pvs->view; pvcc.view_changes.reserve(pvs->view_changes.size()); for(auto & view_change : pvs->view_changes) { pvcc.view_changes.emplace_back( view_change.second ); } - return pvcc; - } else return pvcc; + } + return pvcc; } - bool pbft_database::is_valid_prepared_certificate(const pbft_prepared_certificate &certificate, bool add_to_pbft_db) { + bool pbft_database::is_valid_prepared_certificate(const pbft_prepared_certificate& certificate, bool add_to_pbft_db) { // an empty certificate is valid since it acts as a null digest in pbft. if (certificate.empty()) return true; // a certificate under lscb (no longer in fork_db) is also treated as null. @@ -832,7 +828,7 @@ namespace eosio { return is_valid_longest_fork(certificate.block_info, prepare_infos, bp_threshold, non_fork_bp_count); } - bool pbft_database::is_valid_committed_certificate(const pbft_committed_certificate &certificate, bool add_to_pbft_db) { + bool pbft_database::is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db) { // an empty certificate is valid since it acts as a null digest in pbft. if (certificate.empty()) return true; // a certificate under lscb (no longer in fork_db) is also treated as null. @@ -895,14 +891,14 @@ namespace eosio { return is_valid_longest_fork(certificate.block_info, commit_infos, bp_threshold, non_fork_bp_count); } - bool pbft_database::is_valid_view_change(const pbft_view_change &vc, const public_key_type &pk) { + bool pbft_database::is_valid_view_change(const pbft_view_change& vc, const public_key_type& pk) { return should_recv_pbft_msg(pk); // No need to check prepared cert and stable checkpoint, until generate or validate a new view msg } - void pbft_database::validate_new_view(const pbft_new_view &nv, const public_key_type &pk) { + void pbft_database::validate_new_view(const pbft_new_view& nv, const public_key_type& pk) { EOS_ASSERT(pk == get_new_view_primary_key(nv.new_view), pbft_exception, "new view is not signed with expected key"); @@ -1001,13 +997,13 @@ namespace eosio { ("hpcc", highest_scp)("pc", nv.stable_checkpoint)); } - bool pbft_database::should_stop_view_change(const pbft_view_change &vc) { + bool pbft_database::should_stop_view_change(const pbft_view_change& vc) { auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto vc_lscb = vc.stable_checkpoint.block_info.block_num(); return vc_lscb > 0 && lscb_num > vc_lscb; } - vector> pbft_database::fetch_fork_from(vector &block_infos) { + vector> pbft_database::fetch_fork_from(vector& block_infos) { vector> result; if (block_infos.empty()) { @@ -1019,7 +1015,7 @@ namespace eosio { } sort(block_infos.begin(), block_infos.end(), - [](const block_info_type &a, const block_info_type &b) -> bool { return a.block_num() > b.block_num(); }); + [](const block_info_type& a, const block_info_type& b) -> bool { return a.block_num() > b.block_num(); }); while (!block_infos.empty()) { auto fork = fetch_first_fork_from(block_infos); @@ -1030,7 +1026,7 @@ namespace eosio { return result; } - vector pbft_database::fetch_first_fork_from(vector &bi) { + vector pbft_database::fetch_first_fork_from(vector& bi) { vector result; if (bi.empty()) { return result; @@ -1071,7 +1067,7 @@ namespace eosio { return result; } - bool pbft_database::is_valid_longest_fork(const block_info_type &bi, vector block_infos, unsigned long threshold, unsigned long non_fork_bp_count) { + bool pbft_database::is_valid_longest_fork(const block_info_type& bi, vector block_infos, unsigned long threshold, unsigned long non_fork_bp_count) { auto forks = fetch_fork_from(block_infos); vector longest_fork; @@ -1089,7 +1085,9 @@ namespace eosio { return bi.block_id == calculated_block_info.block_id; } - pbft_stable_checkpoint pbft_database::fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr &b) { + pbft_stable_checkpoint pbft_database::fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr& b) { + + pbft_stable_checkpoint psc; try { if (b) { auto &extn = b->block_extensions; @@ -1098,12 +1096,10 @@ namespace eosio { if (it->first == static_cast(block_extension_type::pbft_stable_checkpoint)) { auto scp_ds = it->second; fc::datastream ds(scp_ds.data(), scp_ds.size()); + fc::raw::unpack(ds, psc); - pbft_stable_checkpoint scp; - fc::raw::unpack(ds, scp); - - if (is_valid_stable_checkpoint(scp)) { - return scp; + if (is_valid_stable_checkpoint(psc)) { + return psc; } else { it = extn.erase(it); } @@ -1114,32 +1110,34 @@ namespace eosio { } } catch(...) { elog("no stable checkpoints found in the block extension"); + psc = pbft_stable_checkpoint(); } - return pbft_stable_checkpoint(); + return psc; } - pbft_stable_checkpoint pbft_database::get_stable_checkpoint_by_id(const block_id_type &block_id, bool incl_blk_extn ) { + pbft_stable_checkpoint pbft_database::get_stable_checkpoint_by_id(const block_id_type& block_id, bool incl_blk_extn ) { + pbft_stable_checkpoint psc; auto const &by_block = checkpoint_index.get(); auto itr = by_block.find(block_id); if (itr == by_block.end()) { if (incl_blk_extn) { auto blk = ctrl.fetch_block_by_id(block_id); - return fetch_stable_checkpoint_from_blk_extn(blk); + psc = fetch_stable_checkpoint_from_blk_extn(blk); } - return pbft_stable_checkpoint(); + return psc; } auto cpp = *itr; if (cpp->is_stable) { - pbft_stable_checkpoint psc; psc.block_info={cpp->block_id}; psc.checkpoints.reserve(cpp->checkpoints.size()); for (auto & checkpoint : cpp->checkpoints) { psc.checkpoints.emplace_back(checkpoint.second) ; } - return psc; - } else return pbft_stable_checkpoint(); + + } + return psc; } block_info_type pbft_database::cal_pending_stable_checkpoint() const { @@ -1193,7 +1191,7 @@ namespace eosio { } vector pbft_database::generate_and_add_pbft_checkpoint() { - auto checkpoint = [&](const block_num_type &in) { + auto checkpoint = [&](const block_num_type& in) { auto const& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; if (!ctrl.is_pbft_enabled()) return false; if (in <= ucb) return false; @@ -1203,7 +1201,7 @@ namespace eosio { || std::find(watermarks.begin(), watermarks.end(), in) != watermarks.end(); // checkpoint on bp schedule change; }; - auto new_pc = vector{}; + vector new_pc{}; auto const &by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); @@ -1263,7 +1261,7 @@ namespace eosio { return new_pc; } - void pbft_database::add_pbft_checkpoint(pbft_checkpoint &cp, const public_key_type &pk) { + void pbft_database::add_pbft_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk) { auto cp_block_state = ctrl.fetch_block_state_by_id(cp.block_info.block_id); if (!cp_block_state) return; @@ -1284,7 +1282,7 @@ namespace eosio { auto csp = (*itr); auto checkpoints = csp->checkpoints; if (checkpoints.find(pk) == checkpoints.end()) { - by_block.modify(itr, [&](const pbft_checkpoint_state_ptr &pcp) { + by_block.modify(itr, [&](const pbft_checkpoint_state_ptr& pcp) { csp->checkpoints[pk] = cp; }); } @@ -1302,7 +1300,7 @@ namespace eosio { } } if (cp_count >= threshold) { - by_block.modify(itr, [&](const pbft_checkpoint_state_ptr &pcp) { csp->is_stable = true; }); + by_block.modify(itr, [&](const pbft_checkpoint_state_ptr& pcp) { csp->is_stable = true; }); auto id = csp->block_id; auto blk = ctrl.fetch_block_by_id(id); @@ -1354,7 +1352,7 @@ namespace eosio { } } - bool pbft_database::is_valid_checkpoint(const pbft_checkpoint &cp, const public_key_type &pk) { + bool pbft_database::is_valid_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk) { if (cp.block_info.block_num() > ctrl.head_block_num() || cp.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) return false; @@ -1367,7 +1365,7 @@ namespace eosio { return false; } - bool pbft_database::is_valid_stable_checkpoint(const pbft_stable_checkpoint &scp, bool add_to_pbft_db) { + bool pbft_database::is_valid_stable_checkpoint(const pbft_stable_checkpoint& scp, bool add_to_pbft_db) { if (scp.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) // the stable checkpoint is way behind lib, no way getting the block state, // it will not be applied nor saved, thus considered safe. @@ -1412,7 +1410,7 @@ namespace eosio { return false; } - bool pbft_database::should_recv_pbft_msg(const public_key_type &pub_key) { + bool pbft_database::should_recv_pbft_msg(const public_key_type& pub_key) { auto schedules = get_updated_fork_schedules(); for (auto const &bp: schedules) { @@ -1421,7 +1419,7 @@ namespace eosio { return false; } - public_key_type pbft_database::get_new_view_primary_key(const pbft_view_type target_view) { + public_key_type pbft_database::get_new_view_primary_key(pbft_view_type target_view) { auto active_bps = lscb_active_producers().producers; if (active_bps.empty()) return public_key_type(); @@ -1430,19 +1428,24 @@ namespace eosio { } producer_schedule_type pbft_database::lscb_active_producers() const { + + auto ps = ctrl.initial_schedule(); auto num = ctrl.last_stable_checkpoint_block_num(); if (num == 0) { auto const &ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; - if (ucb == 0) return ctrl.initial_schedule(); + if (ucb == 0) return ps; num = ucb; } if (auto bs = ctrl.fetch_block_state_by_number(num)) { - if (bs->pending_schedule.producers.empty()) return bs->active_schedule; - return bs->pending_schedule; + if (bs->pending_schedule.producers.empty()) { + ps = bs->active_schedule; + } else { + ps = bs->pending_schedule; + } } - return ctrl.initial_schedule(); + return ps; } block_num_type pbft_database::get_current_pbft_watermark() { @@ -1460,7 +1463,7 @@ namespace eosio { void pbft_database::update_fork_schedules() { - auto vector_minus = [&](vector &v1, vector &v2) + auto vector_minus = [&](vector& v1, vector& v2) { vector diff; std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), @@ -1521,7 +1524,7 @@ namespace eosio { return fork_schedules; } - bool pbft_database::is_less_than_high_watermark(const block_num_type &bnum) { + bool pbft_database::is_less_than_high_watermark(block_num_type bnum) { auto current_watermark = get_current_pbft_watermark(); return current_watermark == 0 || bnum <= current_watermark; } @@ -1536,7 +1539,7 @@ namespace eosio { return pbft_state_ptr(); } - vector pbft_database::get_checkpoints_by_num(const block_num_type& num) const { + vector pbft_database::get_checkpoints_by_num(block_num_type num) const { auto results = vector{}; auto &by_num_index = checkpoint_index.get(); @@ -1549,7 +1552,7 @@ namespace eosio { return results; } - pbft_view_change_state_ptr pbft_database::get_view_changes_by_target_view(const pbft_view_type& tv) const { + pbft_view_change_state_ptr pbft_database::get_view_changes_by_target_view(pbft_view_type tv) const { auto &by_view_index = view_state_index.get(); auto itr = by_view_index.find(tv); @@ -1578,7 +1581,7 @@ namespace eosio { EOS_ASSERT(result.second, pbft_exception, "unable to insert pbft checkpoint index, duplicate state detected"); } - void pbft_database::prune(const pbft_state_ptr &h) { + void pbft_database::prune(const pbft_state_ptr& h) { auto num = h->block_num; auto &by_bn = pbft_state_index.get(); @@ -1594,7 +1597,7 @@ namespace eosio { } } - void pbft_database::prune(const pbft_checkpoint_state_ptr &h) { + void pbft_database::prune(const pbft_checkpoint_state_ptr& h) { auto num = h->block_num; auto &by_bn = checkpoint_index.get(); diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 529bd3ed900..d10d9be5048 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -153,13 +153,11 @@ namespace eosio { unique_ptr transaction_check; unique_ptr keepalive_timer; unique_ptr pbft_message_cache_timer; - unique_ptr connection_monitor_timer; boost::asio::steady_timer::duration connector_period; boost::asio::steady_timer::duration txn_exp_period; boost::asio::steady_timer::duration resp_expected_period; boost::asio::steady_timer::duration keepalive_interval{std::chrono::seconds{32}}; boost::asio::steady_timer::duration pbft_message_cache_tick_interval{std::chrono::seconds{10}}; - boost::asio::steady_timer::duration connection_monitor_tick_interval{std::chrono::seconds{2}}; int max_cleanup_time_ms = 0; const std::chrono::system_clock::duration peer_authentication_interval{std::chrono::seconds{1}}; ///< Peer clock may be no more than 1 second skewed from our clock, including network latency. @@ -246,16 +244,16 @@ namespace eosio { void handle_message( connection_ptr c, const response_p2p_message &msg); //pbft messages - bool maybe_add_to_pbft_cache(const string &key); + bool maybe_add_to_pbft_cache(const string& key); void clean_expired_pbft_messages(); template - bool is_pbft_msg_outdated(M const & msg); + bool is_pbft_msg_outdated(const M& msg); template - bool is_pbft_msg_valid(M const & msg); + bool is_pbft_msg_valid(const M& msg); - void bcast_pbft_msg(const net_message &msg, int ttl); + void bcast_pbft_msg(const net_message& msg, int ttl); - void forward_pbft_msg(const connection_ptr& c, const net_message &msg, int ttl); + void forward_pbft_msg(const connection_ptr& c, const net_message& msg, int ttl); void pbft_outgoing_prepare(const pbft_prepare_ptr& prepare); void pbft_outgoing_commit(const pbft_commit_ptr& commit); @@ -263,14 +261,14 @@ namespace eosio { void pbft_outgoing_new_view(const pbft_new_view_ptr& new_view); void pbft_outgoing_checkpoint(const pbft_checkpoint_ptr& checkpoint); - void handle_message( const connection_ptr& c, const pbft_prepare &msg); - void handle_message( const connection_ptr& c, const pbft_commit &msg); - void handle_message( const connection_ptr& c, const pbft_view_change &msg); - void handle_message( const connection_ptr& c, const pbft_new_view &msg); - void handle_message( const connection_ptr& c, const pbft_checkpoint &msg); - void handle_message( const connection_ptr& c, const pbft_stable_checkpoint &msg); - void handle_message( const connection_ptr& c, const checkpoint_request_message &msg); - void handle_message( const connection_ptr& c, const compressed_pbft_message &msg); + void handle_message( const connection_ptr& c, const pbft_prepare& msg); + void handle_message( const connection_ptr& c, const pbft_commit& msg); + void handle_message( const connection_ptr& c, const pbft_view_change& msg); + void handle_message( const connection_ptr& c, const pbft_new_view& msg); + void handle_message( const connection_ptr& c, const pbft_checkpoint& msg); + void handle_message( const connection_ptr& c, const pbft_stable_checkpoint& msg); + void handle_message( const connection_ptr& c, const checkpoint_request_message& msg); + void handle_message( const connection_ptr& c, const compressed_pbft_message& msg); void start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection); void start_txn_timer(); @@ -281,7 +279,6 @@ namespace eosio { void connection_monitor(std::weak_ptr from_connection); void pbft_message_cache_ticker(); - void connection_monitor_ticker(); /** \name Peer Timestamps * Time message handling * @{ @@ -590,7 +587,6 @@ namespace eosio { std::shared_ptr> message; fc::time_point_sec deadline; }; - const int OUT_QUEUE_SIZE_LIMIT_FROM_WRITE_QUEUE = 100; const int OUT_QUEUE_SIZE_LIMIT = 200; deque pbft_queue; @@ -703,7 +699,7 @@ namespace eosio { std::function callback, bool to_sync_queue = false); void do_queue_write(); - void fill_out_buffer_with_pbft_queue(std::vector &bufs); + void fill_out_buffer_with_pbft_queue(std::vector& bufs); void send_p2p_request(bool discoverable); void send_p2p_response(bool discoverable,string p2p_peer_list); @@ -814,7 +810,6 @@ namespace eosio { void recv_handshake(const connection_ptr& c, const handshake_message& msg); void recv_notice(const connection_ptr& c, const notice_message& msg); bool is_syncing(); - void set_in_sync(); void sync_stable_checkpoints(const connection_ptr& c, uint32_t target); }; @@ -1152,16 +1147,15 @@ namespace eosio { }); } - void connection::fill_out_buffer_with_pbft_queue(std::vector &bufs){ + void connection::fill_out_buffer_with_pbft_queue(std::vector& bufs){ //delete timeout pbft message auto now = time_point::now(); - int drop_pbft_count = 0; - while (pbft_queue.size()>0) { - if (pbft_queue.front().deadline <= now) { - pbft_queue.pop_front(); - ++drop_pbft_count; + auto itr = pbft_queue.begin(); + while (itr != pbft_queue.end()) { + if (itr->deadline <= now) { + itr = pbft_queue.erase(itr); } else { - break; + ++itr; } } @@ -1399,7 +1393,7 @@ namespace eosio { return false; } return true; - } + } bool connection::add_peer_block(const peer_block_state& entry) { auto bptr = blk_state.get().find(entry.id); @@ -1486,10 +1480,6 @@ namespace eosio { return state != in_sync; } - void sync_manager::set_in_sync() { - set_state(in_sync); - } - void sync_manager::request_next_chunk( const connection_ptr& conn ) { uint32_t head_block = chain_plug->chain().fork_db_head_block_num(); @@ -3034,8 +3024,6 @@ namespace eosio { auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); if (!added) return; - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - bcast_pbft_msg(*msg, pbft_message_TTL); fc_dlog( logger, "sent prepare at height: ${n}, view: ${v} ", ("n", msg->block_info.block_num())("v", msg->view)); } @@ -3044,8 +3032,6 @@ namespace eosio { auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); if (!added) return; - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - bcast_pbft_msg(*msg, pbft_message_TTL); fc_dlog( logger, "sent commit at height: ${n}, view: ${v} ", ("n", msg->block_info.block_num())("v", msg->view)); } @@ -3054,8 +3040,6 @@ namespace eosio { auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); if (!added) return; - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - bcast_pbft_msg(*msg, pbft_message_TTL); fc_dlog( logger, "sent view change {cv: ${cv}, tv: ${tv}}", ("cv", msg->current_view)("tv", msg->target_view)); } @@ -3064,7 +3048,7 @@ namespace eosio { auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); if (!added) return; - bcast_pbft_msg(*msg, INT_MAX); + bcast_pbft_msg(*msg, 60 * pbft_message_TTL); fc_dlog( logger, "sent new view at view: ${v} ", ("v", msg->new_view)); } @@ -3072,8 +3056,6 @@ namespace eosio { auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); if (!added) return; - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - bcast_pbft_msg(*msg, pbft_message_TTL); fc_dlog( logger, "sent checkpoint at height: ${n} ", ("n", msg->block_info.block_num())); } @@ -3103,7 +3085,6 @@ namespace eosio { } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_prepare &msg) { - if (!is_pbft_msg_valid(msg)) return; auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); @@ -3122,8 +3103,6 @@ namespace eosio { } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_commit &msg) { - - if (!is_pbft_msg_valid(msg)) return; auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); @@ -3141,7 +3120,6 @@ namespace eosio { } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_view_change &msg) { - if (!is_pbft_msg_valid(msg)) return; auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); @@ -3180,7 +3158,7 @@ namespace eosio { auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); if (!added) return; - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (time_point_sec(time_point::now()) > time_point_sec(msg.common.timestamp) + 60 * pbft_message_TTL || msg.new_view <= pcc.state_machine->get_current_view()) { @@ -3192,7 +3170,7 @@ namespace eosio { if (pmm.sender_key != pcc.pbft_db.get_new_view_primary_key(pmm.msg.new_view)) return; - forward_pbft_msg(c, pmm.msg, INT_MAX); + forward_pbft_msg(c, pmm.msg, 60 * pbft_message_TTL); fc_dlog( logger, "received new view: ${n}, from ${v}", ("n", pmm.msg)("v", pmm.sender_key)); pbft_incoming_new_view_channel.publish(std::make_shared>(std::move(pmm))); @@ -3215,7 +3193,6 @@ namespace eosio { } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_checkpoint &msg) { - if (!is_pbft_msg_valid(msg)) return; auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); @@ -3266,87 +3243,17 @@ namespace eosio { }); } - void net_plugin_impl::pbft_message_cache_ticker() { - pbft_message_cache_timer->expires_from_now (pbft_message_cache_tick_interval); - pbft_message_cache_timer->async_wait ([this](boost::system::error_code ec) { - - if ( !ec ) { - clean_expired_pbft_messages(); - } else { - wlog ("pbft message cache ticker error: ${m}", ("m", ec.message())); - pbft_message_cache_ticker(); - } + void net_plugin_impl::pbft_message_cache_ticker() { + pbft_message_cache_timer->expires_from_now (pbft_message_cache_tick_interval); + pbft_message_cache_timer->async_wait ([this](boost::system::error_code ec) { - }); - } - - void net_plugin_impl::connection_monitor_ticker() { - connection_monitor_timer->expires_from_now (connection_monitor_tick_interval); - connection_monitor_timer->async_wait ([this](boost::system::error_code ec) { - connection_monitor_ticker (); - if (ec) { - wlog ("connection monitor ticker error: ${m}", ("m", ec.message())); - } - int total=0; - int current=0; - for(auto &conn: connections){ - if(conn->current()){ - ++current; - } - ++total; - auto is_open = conn->socket && conn->socket->is_open(); -// auto paddr = conn->peer_addr; -// paddr.insert(0, 20 - paddr.length(), ' '); - std::ostringstream ss; - - auto so = is_open?"1":"0"; - auto con = conn->connecting ?"1":"0"; - auto syn = conn->syncing ?"1":"0"; - auto cur = conn->current() ?"1":"0"; - ss << so << con << syn << cur ; - auto status = ss.str(); - - ss.str(""); - ss.clear(); - - ss << std::setfill(' ') << std::setw(22) << conn->peer_addr; - auto paddr = ss.str(); - - ss.str(""); - ss.clear(); - - ss << std::setfill(' ') << std::setw(6) << conn->buffer_queue.write_queue_size(); - auto write_queue = ss.str(); - - ss.str(""); - ss.clear(); - - ss << std::setfill(' ') << std::setw(6) << conn->buffer_queue.out_queue_size(); - auto out_queue = ss.str(); - - ss.str(""); - ss.clear(); - - ss << std::setfill(' ') << std::setw(6) << conn->pbft_queue.size(); - auto pbft_queue = ss.str(); - - auto conn_str = conn->peer_addr; - if(conn_str.empty()) { - try { - conn_str = boost::lexical_cast(conn->socket->remote_endpoint()); - } catch (...) { - - } - } - - dlog("connection: ${conn} \tstatus(socket|connecting|syncing|current): ${status}\t|\twrite_queue: ${write}\t|\tout_queue: ${out}\t|\tpbft_queue: ${pbft}", ("status",status)("conn",conn_str)("write",write_queue)("out",out_queue)("pbft",pbft_queue)); - } - dlog("connections stats: current : ${current}\t total : ${total} ",("current",current)("total",total)); - dlog("================================================================================================"); - auto local_trx_pool_size = local_txns.size(); - fc_dlog(logger, "local trx pool size: ${local_trx_pool_size}",("local_trx_pool_size",local_trx_pool_size)); - fc_dlog(logger, "================================================================================================"); - }); + if ( !ec ) { + clean_expired_pbft_messages(); + } else { + wlog ("pbft message cache ticker error: ${m}", ("m", ec.message())); + pbft_message_cache_ticker(); + } + }); } void net_plugin_impl::ticker() { @@ -3745,9 +3652,7 @@ namespace eosio { my->keepalive_timer.reset( new boost::asio::steady_timer( app().get_io_service())); my->ticker(); my->pbft_message_cache_timer.reset( new boost::asio::steady_timer( app().get_io_service())); - my->connection_monitor_timer.reset( new boost::asio::steady_timer( app().get_io_service())); my->pbft_message_cache_ticker(); -// my->connection_monitor_ticker(); } FC_LOG_AND_RETHROW() } diff --git a/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp b/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp index 69f67ea6cf8..726e4d43591 100644 --- a/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp +++ b/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp @@ -26,15 +26,15 @@ class pbft_plugin : public appbase::plugin { pbft_state get_pbft_record( const block_id_type& bid )const; - vector get_pbft_checkpoints_record(const block_num_type &bnum)const; - pbft_view_change_state get_view_change_record(const pbft_view_type& view)const; + vector get_pbft_checkpoints_record(block_num_type bnum)const; + pbft_view_change_state get_view_change_record(pbft_view_type view)const; vector get_watermarks()const; flat_map get_fork_schedules()const; const char* get_pbft_status()const; block_id_type get_pbft_prepared_id()const; block_id_type get_pbft_my_prepare_id()const; - void set_pbft_current_view(const pbft_view_type &view); + void set_pbft_current_view(pbft_view_type view); private: diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index 0dcc60a5d11..ebff9c785f1 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -22,11 +22,8 @@ namespace eosio { boost::asio::steady_timer::duration checkpoint_timeout{std::chrono::seconds{50}}; void prepare_timer_tick(); - void commit_timer_tick(); - void view_change_timer_tick(); - void checkpoint_timer_tick(); private: @@ -67,13 +64,13 @@ namespace eosio { return pbft_state(); } - vector pbft_plugin::get_pbft_checkpoints_record(const block_num_type &bnum) const { + vector pbft_plugin::get_pbft_checkpoints_record(block_num_type bnum) const { pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); auto records = pbft_ctrl.pbft_db.get_checkpoints_by_num(bnum); if (!records.empty()) return records; return vector(); } - pbft_view_change_state pbft_plugin::get_view_change_record(const pbft_view_type& view) const { + pbft_view_change_state pbft_plugin::get_view_change_record(pbft_view_type view) const { pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); auto record = pbft_ctrl.pbft_db.get_view_changes_by_target_view(view); if (record) return *record; @@ -105,7 +102,7 @@ namespace eosio { return ctrl.get_pbft_my_prepare(); } - void pbft_plugin::set_pbft_current_view(const pbft_view_type& view) { + void pbft_plugin::set_pbft_current_view(pbft_view_type view) { //this is used to boost the recovery from a disaster, do not set this unless you have to do so. pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.state_machine->manually_set_current_view(view); From d47f2502708f97b14886b02d925420d3dfb2b87a Mon Sep 17 00:00:00 2001 From: oldcold Date: Thu, 25 Jul 2019 21:16:01 +0800 Subject: [PATCH 02/14] reset timer upon state transition; refactor code; --- libraries/chain/include/eosio/chain/pbft.hpp | 119 ++++--- .../include/eosio/chain/pbft_database.hpp | 42 +-- libraries/chain/pbft.cpp | 320 ++++++++++-------- libraries/chain/pbft_database.cpp | 320 +++++++++--------- .../include/eosio/chain/plugin_interface.hpp | 3 + plugins/chain_plugin/chain_plugin.cpp | 16 +- plugins/net_plugin/net_plugin.cpp | 202 +++++------ plugins/pbft_plugin/pbft_plugin.cpp | 198 ++++++----- unittests/pbft_tests.cpp | 66 ++-- 9 files changed, 668 insertions(+), 618 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index e9e1d856dad..a563147265c 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -12,9 +12,9 @@ namespace eosio { using namespace fc; struct psm_cache { - pbft_prepare prepares_cache; - pbft_commit commits_cache; - pbft_view_change view_changes_cache; + pbft_prepare prepare_cache; + pbft_commit commit_cache; + pbft_view_change view_change_cache; pbft_prepared_certificate prepared_certificate; vector committed_certificate; pbft_view_changed_certificate view_changed_certificate; @@ -29,13 +29,9 @@ namespace eosio { explicit psm_machine(pbft_database& pbft_db); ~psm_machine(); - void set_current(psm_state_ptr s) { - current = std::move(s); - } + void set_current(psm_state_ptr s) { current = std::move(s); } - psm_state_ptr get_current() { - return current; - } + const psm_state_ptr& get_current() { return current; } void on_prepare(const pbft_metadata_ptr& e); void on_commit(const pbft_metadata_ptr& e); @@ -45,23 +41,26 @@ namespace eosio { void send_prepare(); void send_commit(); void send_view_change(); + void send_checkpoint(); + bool maybe_new_view(); - void transit_to_committed_state(const psm_state_ptr& s, bool to_new_view); - void transit_to_prepared_state(const psm_state_ptr& s); - void transit_to_view_change_state(const psm_state_ptr& s); - void transit_to_new_view(const pbft_metadata_ptr& e, const psm_state_ptr& s); + void transit_to_committed_state(bool to_new_view); + void transit_to_prepared_state(); + void transit_to_view_change_state(); + void transit_to_new_view(const pbft_metadata_ptr& e); + void do_send_prepare(); + void do_send_commit(); void do_send_view_change(); - bool maybe_new_view(const psm_state_ptr& s); - const pbft_prepare& get_prepares_cache() const { return cache.prepares_cache; } - void set_prepares_cache(const pbft_prepare& pcache) { cache.prepares_cache = pcache; } + const pbft_prepare& get_prepare_cache() const { return cache.prepare_cache; } + void set_prepare_cache(const pbft_prepare &pcache) { cache.prepare_cache = pcache; } - const pbft_commit& get_commits_cache() const { return cache.commits_cache; } - void set_commits_cache(const pbft_commit& ccache) { cache.commits_cache = ccache; } + const pbft_commit& get_commit_cache() const { return cache.commit_cache; } + void set_commit_cache(const pbft_commit &ccache) { cache.commit_cache = ccache; } - const pbft_view_change& get_view_changes_cache() const { return cache.view_changes_cache; } - void set_view_changes_cache(const pbft_view_change& vc_cache) { cache.view_changes_cache = vc_cache; } + const pbft_view_change& get_view_change_cache() const { return cache.view_change_cache; } + void set_view_change_cache(const pbft_view_change &vc_cache) { cache.view_change_cache = vc_cache; } uint32_t get_current_view() const { return current_view; } void set_current_view(uint32_t cv) { current_view = cv; } @@ -85,6 +84,18 @@ namespace eosio { void set_view_change_timer(uint32_t vc_timer) { view_change_timer = vc_timer; } void manually_set_current_view(uint32_t cv); + + signal pbft_outgoing_prepare; + signal pbft_outgoing_commit; + signal pbft_outgoing_view_change; + signal pbft_outgoing_new_view; + signal pbft_outgoing_checkpoint; + signal pbft_transit_to_committed; + signal pbft_transit_to_prepared; + + template + void emit(const Signal &s, Arg &&a); + protected: psm_cache cache; uint32_t current_view; @@ -93,8 +104,8 @@ namespace eosio { uint32_t view_change_timer; private: - psm_state_ptr current; - pbft_database &pbft_db; + psm_state_ptr current = nullptr; + pbft_database& pbft_db; }; using psm_machine_ptr = std::shared_ptr; @@ -102,34 +113,40 @@ namespace eosio { class psm_state : public std::enable_shared_from_this { public: - psm_state(); + psm_state(psm_machine& m, pbft_database& pbft_db); ~psm_state(); - virtual void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) = 0; - virtual void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) = 0; - virtual void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) = 0; + virtual void on_prepare(const pbft_metadata_ptr& e) = 0; + virtual void on_commit(const pbft_metadata_ptr& e) = 0; + virtual void on_view_change(const pbft_metadata_ptr& e) = 0; - virtual void send_prepare(const psm_machine_ptr& m, pbft_database& pbft_db) = 0; - virtual void send_commit(const psm_machine_ptr& m, pbft_database& pbft_db) = 0; - virtual void send_view_change(const psm_machine_ptr& m, pbft_database& pbft_db) = 0; + virtual void send_prepare() = 0; + virtual void send_commit() = 0; + virtual void send_view_change() = 0; virtual const char* get_name() = 0; std::shared_ptr get_self() { return shared_from_this(); }; + + protected: + psm_machine& m; + pbft_database& pbft_db; }; class psm_prepared_state final: public psm_state { public: - psm_prepared_state(); + psm_prepared_state(psm_machine& m, pbft_database& pbft_db); ~psm_prepared_state(); - void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; - void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; - void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; + void on_prepare(const pbft_metadata_ptr& e) override; + void on_commit(const pbft_metadata_ptr& e) override; + void on_view_change(const pbft_metadata_ptr& e) override; + + void send_prepare() override; + void send_commit() override; + void send_view_change() override; - void send_prepare(const psm_machine_ptr& m, pbft_database& pbft_db) override; - void send_commit(const psm_machine_ptr& m, pbft_database& pbft_db) override; - void send_view_change(const psm_machine_ptr& m, pbft_database& pbft_db) override; + void maybe_transit_to_committed(); bool pending_commit_local; @@ -138,32 +155,32 @@ namespace eosio { class psm_committed_state final: public psm_state { public: - psm_committed_state(); + psm_committed_state(psm_machine& m, pbft_database& pbft_db); ~psm_committed_state(); - void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; - void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; - void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; + void on_prepare(const pbft_metadata_ptr& e) override; + void on_commit(const pbft_metadata_ptr& e) override; + void on_view_change(const pbft_metadata_ptr& e) override; - void send_prepare(const psm_machine_ptr& m, pbft_database& pbft_db) override; - void send_commit(const psm_machine_ptr& m, pbft_database& pbft_db) override; - void send_view_change(const psm_machine_ptr& m, pbft_database& pbft_db) override; + void send_prepare() override; + void send_commit() override; + void send_view_change() override; const char* get_name() override { return "{==== COMMITTED ====}"; } }; class psm_view_change_state final: public psm_state { public: - psm_view_change_state(); + psm_view_change_state(psm_machine& m, pbft_database& pbft_db); ~psm_view_change_state(); - void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; - void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; - void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; + void on_prepare(const pbft_metadata_ptr& e) override; + void on_commit(const pbft_metadata_ptr& e) override; + void on_view_change(const pbft_metadata_ptr& e) override; - void send_prepare(const psm_machine_ptr& m, pbft_database& pbft_db) override; - void send_commit(const psm_machine_ptr& m, pbft_database& pbft_db) override; - void send_view_change(const psm_machine_ptr& m, pbft_database& pbft_db) override; + void send_prepare() override; + void send_commit() override; + void send_view_change() override; const char* get_name() override { return "{==== VIEW CHANGE ====}"; } }; @@ -176,7 +193,7 @@ namespace eosio { const uint16_t view_change_timeout = 6; pbft_database pbft_db; - std::shared_ptr state_machine; + psm_machine state_machine; void maybe_pbft_prepare(); void maybe_pbft_commit(); diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index b571c96f420..8a935829d9a 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -50,6 +50,8 @@ namespace eosio { } }; + using fork_info_type = vector; + struct pbft_message_common { explicit pbft_message_common(pbft_message_type t): type{t} {}; @@ -426,19 +428,22 @@ namespace eosio { void add_pbft_view_change(const pbft_view_change& vc, const public_key_type& pk); void add_pbft_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk); - pbft_prepare send_and_add_pbft_prepare(const pbft_prepare& cached_prepare = pbft_prepare(), pbft_view_type current_view = 0); - pbft_commit send_and_add_pbft_commit(const pbft_commit& cached_commit = pbft_commit(), pbft_view_type current_view = 0); - pbft_view_change send_and_add_pbft_view_change( - const pbft_view_change& cached_view_change = pbft_view_change(), - const pbft_prepared_certificate& ppc = pbft_prepared_certificate(), - const vector& pcc = vector{}, + vector generate_and_add_pbft_prepare( + const pbft_prepare &cached_prepare = pbft_prepare(), + pbft_view_type current_view = 0); + vector generate_and_add_pbft_commit( + const pbft_commit &cached_commit = pbft_commit(), + pbft_view_type current_view = 0); + vector generate_and_add_pbft_view_change( + const pbft_view_change &cached_view_change = pbft_view_change(), + const pbft_prepared_certificate &ppc = pbft_prepared_certificate(), + const vector &pcc = vector{}, pbft_view_type current_view = 0, pbft_view_type target_view = 1); - pbft_new_view send_pbft_new_view( - const pbft_view_changed_certificate& vcc = pbft_view_changed_certificate(), + pbft_new_view generate_pbft_new_view( + const pbft_view_changed_certificate &vcc = pbft_view_changed_certificate(), pbft_view_type current_view = 1); vector generate_and_add_pbft_checkpoint(); - void send_pbft_checkpoint(); bool should_prepared(); bool should_committed(); @@ -476,7 +481,6 @@ namespace eosio { chain_id_type& get_chain_id() {return chain_id;} pbft_stable_checkpoint get_stable_checkpoint_by_id(const block_id_type& block_id, bool incl_blk_extn = true); pbft_stable_checkpoint fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr& b); - block_info_type cal_pending_stable_checkpoint() const; void cleanup_on_new_view(); void update_fork_schedules(); @@ -488,13 +492,6 @@ namespace eosio { vector get_pbft_watermarks() const; flat_map get_pbft_fork_schedules() const; - - signal pbft_outgoing_prepare; - signal pbft_outgoing_commit; - signal pbft_outgoing_view_change; - signal pbft_outgoing_new_view; - signal pbft_outgoing_checkpoint; - private: controller& ctrl; pbft_state_multi_index_type pbft_state_index; @@ -506,22 +503,19 @@ namespace eosio { flat_map fork_schedules; chain_id_type chain_id = ctrl.get_chain_id(); - + block_info_type cal_pending_stable_checkpoint() const; bool is_less_than_high_watermark(block_num_type bnum); bool is_valid_prepared_certificate(const pbft_prepared_certificate& certificate, bool add_to_pbft_db = false); bool is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db = false); - bool is_valid_longest_fork(const block_info_type& bi, vector block_infos, unsigned long threshold, unsigned long non_fork_bp_count); + bool is_valid_longest_fork(const block_info_type& bi, fork_info_type block_infos, unsigned long threshold, unsigned long non_fork_bp_count); producer_schedule_type lscb_active_producers() const; vector& get_updated_watermarks(); flat_map& get_updated_fork_schedules(); block_num_type get_current_pbft_watermark(); - vector> fetch_fork_from(vector& block_infos); - vector fetch_first_fork_from(vector& bi); - - template - void emit(const Signal &s, Arg &&a); + vector fetch_fork_from(fork_info_type& block_infos); + fork_info_type fetch_first_fork_from(fork_info_type& bi); void set(const pbft_state_ptr& s); void set(const pbft_checkpoint_state_ptr& s); diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 2c510ef6512..4739bded9ad 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -1,5 +1,3 @@ -#include - #include #include #include @@ -8,8 +6,9 @@ namespace eosio { namespace chain { pbft_controller::pbft_controller(controller &ctrl) : - pbft_db(ctrl), - state_machine(new psm_machine(pbft_db)) { + pbft_db(ctrl), + state_machine(pbft_db) { + state_machine.set_current(std::make_shared(state_machine, pbft_db)); datadir = ctrl.state_dir(); if (!fc::is_directory(datadir)) @@ -23,8 +22,8 @@ namespace eosio { fc::datastream ds(content.data(), content.size()); uint32_t current_view; fc::raw::unpack(ds, current_view); - state_machine->set_current_view(current_view); - state_machine->set_target_view(state_machine->get_current_view() + 1); + state_machine.set_current_view(current_view); + state_machine.set_target_view(state_machine.get_current_view() + 1); ilog("current view: ${cv}", ("cv", current_view)); } @@ -36,53 +35,53 @@ namespace eosio { std::ofstream out(pbft_db_dat.generic_string().c_str(), std::ios::out | std::ios::binary | std::ofstream::trunc); - uint32_t current_view = state_machine->get_current_view(); + uint32_t current_view = state_machine.get_current_view(); fc::raw::pack(out, current_view); } void pbft_controller::maybe_pbft_prepare() { if (!pbft_db.should_send_pbft_msg()) return; - state_machine->send_prepare(); + state_machine.send_prepare(); } void pbft_controller::maybe_pbft_commit() { if (!pbft_db.should_send_pbft_msg()) return; - state_machine->send_commit(); + state_machine.send_commit(); } void pbft_controller::maybe_pbft_view_change() { if (!pbft_db.should_send_pbft_msg()) return; - if (state_machine->get_view_change_timer() <= view_change_timeout) { - if (!state_machine->get_view_changes_cache().empty()) { - pbft_db.send_and_add_pbft_view_change(state_machine->get_view_changes_cache()); + if (state_machine.get_view_change_timer() <= view_change_timeout) { + if (!state_machine.get_view_change_cache().empty()) { + pbft_db.generate_and_add_pbft_view_change(state_machine.get_view_change_cache()); } - state_machine->set_view_change_timer(state_machine->get_view_change_timer() + 1); + state_machine.set_view_change_timer(state_machine.get_view_change_timer() + 1); } else { - state_machine->set_view_change_timer(0); - state_machine->send_view_change(); + state_machine.set_view_change_timer(0); + state_machine.send_view_change(); } } void pbft_controller::maybe_pbft_checkpoint() { if (!pbft_db.should_send_pbft_msg()) return; - pbft_db.send_pbft_checkpoint(); + state_machine.send_checkpoint(); pbft_db.checkpoint_local(); } void pbft_controller::on_pbft_prepare(const pbft_metadata_ptr& p) { - state_machine->on_prepare(p); + state_machine.on_prepare(p); } void pbft_controller::on_pbft_commit(const pbft_metadata_ptr& c) { - state_machine->on_commit(c); + state_machine.on_commit(c); } void pbft_controller::on_pbft_view_change(const pbft_metadata_ptr& vc) { - state_machine->on_view_change(vc); + state_machine.on_view_change(vc); } void pbft_controller::on_pbft_new_view(const pbft_metadata_ptr& nv) { - state_machine->on_new_view(nv); + state_machine.on_new_view(nv); } void pbft_controller::on_pbft_checkpoint(const pbft_metadata_ptr &cp) { @@ -91,15 +90,13 @@ namespace eosio { pbft_db.checkpoint_local(); } - psm_state::psm_state() = default; + psm_state::psm_state(psm_machine& m, pbft_database& pbft_db) : m(m), pbft_db(pbft_db){} psm_state::~psm_state() = default; - psm_machine::psm_machine(pbft_database &pbft_db) : pbft_db(pbft_db) { - set_current(std::make_shared()); - - set_prepares_cache(pbft_prepare()); - set_commits_cache(pbft_commit()); - set_view_changes_cache(pbft_view_change()); + psm_machine::psm_machine(pbft_database& pbft_db) : pbft_db(pbft_db) { + set_prepare_cache(pbft_prepare()); + set_commit_cache(pbft_commit()); + set_view_change_cache(pbft_view_change()); set_prepared_certificate(pbft_prepared_certificate{}); set_committed_certificate(vector{}); @@ -114,27 +111,27 @@ namespace eosio { psm_machine::~psm_machine() = default; void psm_machine::on_prepare(const pbft_metadata_ptr& e) { - current->on_prepare(shared_from_this(), e, pbft_db); + current->on_prepare(e); } void psm_machine::send_prepare() { - current->send_prepare(shared_from_this(), pbft_db); + current->send_prepare(); } void psm_machine::on_commit(const pbft_metadata_ptr& e) { - current->on_commit(shared_from_this(), e, pbft_db); + current->on_commit(e); } void psm_machine::send_commit() { - current->send_commit(shared_from_this(), pbft_db); + current->send_commit(); } void psm_machine::on_view_change(const pbft_metadata_ptr& e) { - current->on_view_change(shared_from_this(), e, pbft_db); + current->on_view_change(e); } void psm_machine::send_view_change() { - current->send_view_change(shared_from_this(), pbft_db); + current->send_view_change(); } void psm_machine::on_new_view(const pbft_metadata_ptr& e) { @@ -148,7 +145,7 @@ namespace eosio { } try { - transit_to_new_view(e, current); + transit_to_new_view(e); } catch(...) { elog("apply new view failed, waiting for next round.. ${nv} ", ("nv", e->msg)); } @@ -157,33 +154,17 @@ namespace eosio { void psm_machine::manually_set_current_view(uint32_t cv) { set_current_view(cv); set_target_view(cv + 1); - transit_to_view_change_state(current); + transit_to_view_change_state(); } /** * psm_prepared_state */ - psm_prepared_state::psm_prepared_state() {pending_commit_local = false;} + psm_prepared_state::psm_prepared_state(psm_machine& m, pbft_database& pbft_db) : psm_state(m, pbft_db) {pending_commit_local = false;} psm_prepared_state::~psm_prepared_state() = default; - void psm_prepared_state::on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { - //ignore - } - - void psm_prepared_state::send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) { - //retry - if (m->get_prepares_cache().empty()) return; - - pbft_db.send_and_add_pbft_prepare(m->get_prepares_cache(), m->get_current_view()); - } - - void psm_prepared_state::on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { - - if (e->msg.view < m->get_current_view()) return; - if (!pbft_db.is_valid_commit(e->msg, e->sender_key)) return; - - pbft_db.add_pbft_commit(e->msg, e->sender_key); + void psm_prepared_state::maybe_transit_to_committed() { //`pending_commit_local` is used to mark committed local status in psm machine; //`pbft_db.pending_pbft_lib()` is used to mark commit local status in controller; @@ -195,168 +176,174 @@ namespace eosio { } if (pending_commit_local && !pbft_db.pending_pbft_lib()) { - pbft_db.send_pbft_checkpoint(); + m.send_checkpoint(); pbft_db.checkpoint_local(); - m->transit_to_committed_state(shared_from_this(), false); + m.transit_to_committed_state(false); } } - void psm_prepared_state::send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) { - auto commits = pbft_db.send_and_add_pbft_commit(m->get_commits_cache(), m->get_current_view()); + void psm_prepared_state::on_prepare(const pbft_metadata_ptr& e) { + //ignore + } - if (!commits.empty()) { - m->set_commits_cache(commits); - } + void psm_prepared_state::send_prepare() { + //retry + if (m.get_prepare_cache().empty()) return; - if (pbft_db.should_committed() && !pending_commit_local) { - pbft_db.commit_local(); - pending_commit_local = true; - } + m.do_send_prepare(); + } - if (pending_commit_local && !pbft_db.pending_pbft_lib()) { - pbft_db.send_pbft_checkpoint(); - pbft_db.checkpoint_local(); - m->transit_to_committed_state(shared_from_this(), false); - } + void psm_prepared_state::on_commit(const pbft_metadata_ptr& e) { + + if (e->msg.view < m.get_current_view()) return; + if (!pbft_db.is_valid_commit(e->msg, e->sender_key)) return; + + pbft_db.add_pbft_commit(e->msg, e->sender_key); + + maybe_transit_to_committed(); + } + + void psm_prepared_state::send_commit() { + + m.do_send_commit(); + + maybe_transit_to_committed(); } - void psm_prepared_state::on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_prepared_state::on_view_change(const pbft_metadata_ptr& e) { - if (e->msg.target_view <= m->get_current_view()) return; + if (e->msg.target_view <= m.get_current_view()) return; if (!pbft_db.is_valid_view_change(e->msg, e->sender_key)) return; pbft_db.add_pbft_view_change(e->msg, e->sender_key); //if received >= f+1 view_change on some view, transit to view_change and send view change auto target_view = pbft_db.should_view_change(); - if (target_view > 0 && target_view > m->get_current_view()) { - m->set_target_view(target_view); - m->transit_to_view_change_state(shared_from_this()); + if (target_view > 0 && target_view > m.get_current_view()) { + m.set_target_view(target_view); + m.transit_to_view_change_state(); } } - void psm_prepared_state::send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) { - m->transit_to_view_change_state(shared_from_this()); + void psm_prepared_state::send_view_change() { + m.transit_to_view_change_state(); } - psm_committed_state::psm_committed_state() = default; + psm_committed_state::psm_committed_state(psm_machine& m, pbft_database& pbft_db) : psm_state(m, pbft_db) {} psm_committed_state::~psm_committed_state() = default; /** * psm_committed_state */ - void psm_committed_state::on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_committed_state::on_prepare(const pbft_metadata_ptr& e) { //validate - if (e->msg.view < m->get_current_view()) return; + if (e->msg.view < m.get_current_view()) return; if (!pbft_db.is_valid_prepare(e->msg, e->sender_key)) return; //do action add prepare pbft_db.add_pbft_prepare(e->msg, e->sender_key); //if prepare >= 2f+1, transit to prepared - if (pbft_db.should_prepared()) m->transit_to_prepared_state(shared_from_this()); + if (pbft_db.should_prepared()) m.transit_to_prepared_state(); } - void psm_committed_state::send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) { + void psm_committed_state::send_prepare() { - auto prepares = pbft_db.send_and_add_pbft_prepare(m->get_prepares_cache(), m->get_current_view()); - - if (!prepares.empty()) { - m->set_prepares_cache(prepares); - } + m.do_send_prepare(); //if prepare >= 2f+1, transit to prepared - if (pbft_db.should_prepared()) m->transit_to_prepared_state(shared_from_this()); + if (pbft_db.should_prepared()) m.transit_to_prepared_state(); } - void psm_committed_state::on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_committed_state::on_commit(const pbft_metadata_ptr& e) { - if (e->msg.view < m->get_current_view()) return; + if (e->msg.view < m.get_current_view()) return; if (!pbft_db.is_valid_commit(e->msg, e->sender_key)) return; pbft_db.add_pbft_commit(e->msg, e->sender_key); } - void psm_committed_state::send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) { + void psm_committed_state::send_commit() { + + if (m.get_commit_cache().empty()) return; - if (m->get_commits_cache().empty()) return; - pbft_db.send_and_add_pbft_commit(m->get_commits_cache(), m->get_current_view()); + m.do_send_commit(); } - void psm_committed_state::on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_committed_state::on_view_change(const pbft_metadata_ptr& e) { - if (e->msg.target_view <= m->get_current_view()) return; + if (e->msg.target_view <= m.get_current_view()) return; if (!pbft_db.is_valid_view_change(e->msg, e->sender_key)) return; pbft_db.add_pbft_view_change(e->msg, e->sender_key); //if received >= f+1 view_change on some view, transit to view_change and send view change auto new_view = pbft_db.should_view_change(); - if (new_view > 0 && new_view > m->get_current_view()) { - m->set_target_view(new_view); - m->transit_to_view_change_state(shared_from_this()); + if (new_view > 0 && new_view > m.get_current_view()) { + m.set_target_view(new_view); + m.transit_to_view_change_state(); } } - void psm_committed_state::send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) { - m->transit_to_view_change_state(shared_from_this()); + void psm_committed_state::send_view_change() { + m.transit_to_view_change_state(); } - psm_view_change_state::psm_view_change_state() = default; + psm_view_change_state::psm_view_change_state(psm_machine& m, pbft_database& pbft_db) : psm_state(m, pbft_db) {} psm_view_change_state::~psm_view_change_state() = default; /** * psm_view_change_state */ - void psm_view_change_state::on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_view_change_state::on_prepare(const pbft_metadata_ptr& e) { //ignore; } - void psm_view_change_state::send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) { + void psm_view_change_state::send_prepare() { //ignore; } - void psm_view_change_state::on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_view_change_state::on_commit(const pbft_metadata_ptr& e) { //ignore; } - void psm_view_change_state::send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) { + void psm_view_change_state::send_commit() { //ignore; } - void psm_view_change_state::on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_view_change_state::on_view_change(const pbft_metadata_ptr& e) { //skip from view change state if my lib is higher than my view change state height. - auto vc = m->get_view_changes_cache(); + auto vc = m.get_view_change_cache(); if (!vc.empty() && pbft_db.should_stop_view_change(vc)) { - m->transit_to_committed_state(shared_from_this(), false); + m.transit_to_committed_state(false); return; } - if (e->msg.target_view <= m->get_current_view()) return; + if (e->msg.target_view <= m.get_current_view()) return; if (!pbft_db.is_valid_view_change(e->msg, e->sender_key)) return; pbft_db.add_pbft_view_change(e->msg, e->sender_key); - m->maybe_new_view(shared_from_this()); + m.maybe_new_view(); } - void psm_view_change_state::send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) { + void psm_view_change_state::send_view_change() { //skip from view change state if my lib is higher than my view change state height. - auto vc = m->get_view_changes_cache(); + auto vc = m.get_view_change_cache(); if (!vc.empty() && pbft_db.should_stop_view_change(vc)) { - m->transit_to_committed_state(shared_from_this(), false); + m.transit_to_committed_state(false); return; } - m->do_send_view_change(); + m.do_send_view_change(); - m->maybe_new_view(shared_from_this()); + m.maybe_new_view(); } - void psm_machine::transit_to_committed_state(const psm_state_ptr& s, bool to_new_view) { + void psm_machine::transit_to_committed_state(bool to_new_view) { if (!to_new_view) { auto nv = pbft_db.get_committed_view(); @@ -364,44 +351,44 @@ namespace eosio { set_target_view(get_current_view() + 1); } - auto prepares = pbft_db.send_and_add_pbft_prepare(pbft_prepare(), get_current_view()); - set_prepares_cache(prepares); - //TODO: reset prepare timer; + set_prepare_cache(pbft_prepare()); + do_send_prepare(); - set_view_changes_cache(pbft_view_change()); + set_view_change_cache(pbft_view_change()); set_view_change_timer(0); - set_current(std::make_shared()); + set_current(std::make_shared(*this, pbft_db)); + emit(pbft_transit_to_committed, true); } - void psm_machine::transit_to_prepared_state(const psm_state_ptr& s) { + void psm_machine::transit_to_prepared_state() { - auto commits = pbft_db.send_and_add_pbft_commit(pbft_commit(), get_current_view()); - set_commits_cache(commits); - //TODO: reset commit timer; + set_commit_cache(pbft_commit()); + do_send_commit(); - set_view_changes_cache(pbft_view_change()); + set_view_change_cache(pbft_view_change()); - set_current(std::make_shared()); + set_current(std::make_shared(*this, pbft_db)); + emit(pbft_transit_to_prepared, true); } - void psm_machine::transit_to_view_change_state(const psm_state_ptr& s) { + void psm_machine::transit_to_view_change_state() { - set_commits_cache(pbft_commit()); - set_prepares_cache(pbft_prepare()); + set_commit_cache(pbft_commit()); + set_prepare_cache(pbft_prepare()); set_view_change_timer(0); set_target_view_retries(0); - set_current(std::make_shared()); + set_current(std::make_shared(*this, pbft_db)); if (pbft_db.should_send_pbft_msg()) { do_send_view_change(); - auto nv = maybe_new_view(s); + auto nv = maybe_new_view(); if (nv) return; } } - bool psm_machine::maybe_new_view(const psm_state_ptr &s) { + bool psm_machine::maybe_new_view() { //if view_change >= 2f+1, calculate next primary, send new view if is primary auto nv = get_target_view(); auto pk = pbft_db.get_new_view_primary_key(nv); @@ -412,14 +399,15 @@ namespace eosio { auto new_view = pbft_db.get_proposed_new_view_num(); if (new_view != nv) return false; - auto nv_msg = pbft_db.send_pbft_new_view( + auto nv_msg = pbft_db.generate_pbft_new_view( get_view_changed_certificate(), new_view); if (nv_msg.empty()) return false; + emit(pbft_outgoing_new_view, std::make_shared(nv_msg)); try { - transit_to_new_view(std::make_shared>(nv_msg, pbft_db.get_chain_id()), s); + transit_to_new_view(std::make_shared>(nv_msg, pbft_db.get_chain_id())); return true; } catch(const fc::exception& ex) { elog("apply new view failed, waiting for next round.. ${nv} ", ("nv", nv_msg)); @@ -428,12 +416,12 @@ namespace eosio { return false; } - void psm_machine::transit_to_new_view(const pbft_metadata_ptr& e, const psm_state_ptr& s) { + void psm_machine::transit_to_new_view(const pbft_metadata_ptr& e) { set_current_view(e->msg.new_view); set_target_view(e->msg.new_view + 1); - set_prepares_cache(pbft_prepare()); + set_prepare_cache(pbft_prepare()); set_view_change_timer(0); set_target_view_retries(0); @@ -451,7 +439,7 @@ namespace eosio { if (!e->msg.prepared_cert.prepares.empty()) { pbft_db.mark_as_prepared(e->msg.prepared_cert.block_info.block_id); if (pbft_db.should_prepared()) { - transit_to_prepared_state(s); + transit_to_prepared_state(); return; } } @@ -459,13 +447,34 @@ namespace eosio { if (pbft_db.should_committed()) { pbft_db.commit_local(); } - transit_to_committed_state(s, true); + transit_to_committed_state(true); + } + + void psm_machine::do_send_prepare() { + auto prepares = pbft_db.generate_and_add_pbft_prepare(get_prepare_cache(), get_current_view()); + if (!prepares.empty()) { + for (const auto& p: prepares) { + emit(pbft_outgoing_prepare, std::make_shared(p)); + } + set_prepare_cache(prepares.front()); + } + } + + void psm_machine::do_send_commit() { + auto commits = pbft_db.generate_and_add_pbft_commit(get_commit_cache(), get_current_view()); + + if (!commits.empty()) { + for (const auto& c: commits) { + emit(pbft_outgoing_commit, std::make_shared(c)); + } + set_commit_cache(commits.front()); + } } void psm_machine::do_send_view_change() { auto reset_view_change_state = [&]() { - set_view_changes_cache(pbft_view_change()); + set_view_change_cache(pbft_view_change()); set_prepared_certificate(pbft_db.generate_prepared_certificate()); set_committed_certificate(pbft_db.generate_committed_certificate()); }; @@ -482,15 +491,42 @@ namespace eosio { EOS_ASSERT((get_target_view() > get_current_view()), pbft_exception, "target view should be always greater than current view"); - auto view_changes = pbft_db.send_and_add_pbft_view_change( - get_view_changes_cache(), + auto view_changes = pbft_db.generate_and_add_pbft_view_change( + get_view_change_cache(), get_prepared_certificate(), get_committed_certificate(), get_current_view(), get_target_view()); if (!view_changes.empty()) { - set_view_changes_cache(view_changes); + for (const auto& vc : view_changes) { + emit(pbft_outgoing_view_change, std::make_shared(vc)); + } + set_view_change_cache(view_changes.front()); + } + } + + void psm_machine::send_checkpoint() { + auto checkpoints = pbft_db.generate_and_add_pbft_checkpoint(); + for (const auto& cp: checkpoints) { + emit(pbft_outgoing_checkpoint, std::make_shared(cp)); + } + } + + template + void psm_machine::emit(const Signal &s, Arg &&a) { + try { + s(std::forward(a)); + } 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 (...) { + wlog("signal handler threw exception"); } } } diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index f915e100383..22c2ab188ac 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -70,7 +70,7 @@ namespace eosio { uint32_t num_records_in_checkpoint_db = checkpoint_index.size(); fc::raw::pack(c_out, unsigned_int{num_records_in_checkpoint_db}); - for (auto const &s: checkpoint_index) { + for (const auto& s: checkpoint_index) { fc::raw::pack(c_out, *s); } @@ -80,7 +80,7 @@ namespace eosio { uint32_t num_records_in_db = pbft_state_index.size(); fc::raw::pack(out, unsigned_int{num_records_in_db}); - for (auto const &s : pbft_state_index) { + for (const auto& s : pbft_state_index) { fc::raw::pack(out, *s); } @@ -131,16 +131,16 @@ namespace eosio { auto threshold = as.size()* 2 / 3 + 1; if (prepares.size() >= threshold && !cpsp->is_prepared && is_less_than_high_watermark(cpsp->block_num)) { flat_map prepare_count; - for (auto const &pre: prepares) { + for (const auto& pre: prepares) { if (prepare_count.find(pre.second.view) == prepare_count.end()) prepare_count[pre.second.view] = 0; } - for (auto const &bp: as) { - for (auto const &pp: prepares) { + for (const auto& bp: as) { + for (const auto& pp: prepares) { if (bp.block_signing_key == pp.first.second) prepare_count[pp.first.first] += 1; } } - for (auto const &e: prepare_count) { + for (const auto& e: prepare_count) { if (e.second >= threshold) { mark_as_prepared(cpsp->block_id); } @@ -167,11 +167,13 @@ namespace eosio { by_block_id_index.modify(itr, [&](const pbft_state_ptr& p) { p->is_prepared = true; }); } - pbft_prepare pbft_database::send_and_add_pbft_prepare(const pbft_prepare& cached_prepare, pbft_view_type current_view) { - pbft_prepare prepare_to_be_cached; - + vector pbft_database::generate_and_add_pbft_prepare(const pbft_prepare &cached_prepare, + pbft_view_type current_view) { + vector prepares_to_be_cached; + const auto& my_sps = ctrl.my_signature_providers(); + prepares_to_be_cached.reserve(my_sps.size()); auto head_block_num = ctrl.head_block_num(); - if (head_block_num <= 1) return prepare_to_be_cached; + if (head_block_num <= 1) return prepares_to_be_cached; auto my_prepare = ctrl.get_pbft_my_prepare(); auto reserve_prepare = [&](const block_id_type& in) { @@ -187,23 +189,22 @@ namespace eosio { if (!cached_prepare.empty()) { - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { //sign again, update cache, then emit auto retry_p = cached_prepare; retry_p.common.timestamp = time_point::now(); retry_p.sender_signature = sp.second(retry_p.digest(chain_id)); - emit(pbft_outgoing_prepare, std::make_shared(retry_p)); + prepares_to_be_cached.emplace_back(retry_p); } } else if (reserve_prepare(my_prepare)) { - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { pbft_prepare reserve_p; - reserve_p.view=current_view; reserve_p.block_info={my_prepare}; + reserve_p.view = current_view; + reserve_p.block_info = {my_prepare}; reserve_p.sender_signature = sp.second(reserve_p.digest(chain_id)); - emit(pbft_outgoing_prepare, std::make_shared(reserve_p)); - if (prepare_to_be_cached.empty()) prepare_to_be_cached = reserve_p; + prepares_to_be_cached.emplace_back(reserve_p); } } else { - auto current_watermark = get_current_pbft_watermark(); auto lib = ctrl.last_irreversible_block_num(); @@ -213,30 +214,30 @@ namespace eosio { high_watermark_block_num = std::min(head_block_num, current_watermark); } - if (high_watermark_block_num <= lib) return prepare_to_be_cached; + if (high_watermark_block_num <= lib) return prepares_to_be_cached; if (auto hwbs = ctrl.fork_db().get_block_in_current_chain_by_num(high_watermark_block_num)) { auto sent = false; - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { pbft_prepare new_p; - new_p.view=current_view; new_p.block_info={hwbs->id}; + new_p.view = current_view; + new_p.block_info = {hwbs->id}; new_p.sender_signature = sp.second(new_p.digest(chain_id)); if (is_valid_prepare(new_p, sp.first)) { - emit(pbft_outgoing_prepare, std::make_shared(new_p)); add_pbft_prepare(new_p, sp.first); sent = true; - if (prepare_to_be_cached.empty()) prepare_to_be_cached = new_p; + prepares_to_be_cached.emplace_back(new_p); } } if (sent) ctrl.set_pbft_my_prepare(hwbs->id); } } - return prepare_to_be_cached; + return prepares_to_be_cached; } bool pbft_database::should_prepared() { - auto const &by_prepare_and_num_index = pbft_state_index.get(); + const auto& by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); if (itr == by_prepare_and_num_index.end()) return false; @@ -298,17 +299,17 @@ namespace eosio { auto commits = cpsp->commits; if (commits.size() >= threshold && !cpsp->is_committed && is_less_than_high_watermark(cpsp->block_num)) { flat_map commit_count; - for (auto const &com: commits) { + for (const auto& com: commits) { if (commit_count.find(com.second.view) == commit_count.end()) commit_count[com.second.view] = 0; } - for (auto const &bp: as) { - for (auto const &pc: commits) { + for (const auto& bp: as) { + for (const auto& pc: commits) { if (bp.block_signing_key == pc.first.second) commit_count[pc.first.first] += 1; } } - for (auto const &e: commit_count) { + for (const auto& e: commit_count) { if (e.second >= threshold) { mark_as_committed(cpsp->block_id); } @@ -318,43 +319,45 @@ namespace eosio { } } - pbft_commit pbft_database::send_and_add_pbft_commit(const pbft_commit& cached_commit, pbft_view_type current_view) { - pbft_commit commit_to_be_cached; + vector pbft_database::generate_and_add_pbft_commit(const pbft_commit &cached_commit, + pbft_view_type current_view) { + vector commits_to_be_cached; + const auto& my_sps = ctrl.my_signature_providers(); + commits_to_be_cached.reserve(my_sps.size()); if (!cached_commit.empty()) { - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { //sign again, update cache, then emit auto retry_c = cached_commit; retry_c.common.timestamp = time_point::now(); retry_c.sender_signature = sp.second(retry_c.digest(chain_id)); - emit(pbft_outgoing_commit, std::make_shared(retry_c)); + commits_to_be_cached.emplace_back(retry_c); } } else { - auto const &by_prepare_and_num_index = pbft_state_index.get(); + const auto& by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); - if (itr == by_prepare_and_num_index.end()) return commit_to_be_cached; + if (itr == by_prepare_and_num_index.end()) return commits_to_be_cached; pbft_state_ptr psp = *itr; auto bs = ctrl.fork_db().get_block(psp->block_id); - if (!bs) return commit_to_be_cached; + if (!bs) return commits_to_be_cached; if (psp->is_prepared && (psp->block_num > ctrl.last_irreversible_block_num())) { - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { pbft_commit new_c; - new_c.view=current_view; - new_c.block_info={psp->block_id}; + new_c.view = current_view; + new_c.block_info = {psp->block_id}; new_c.sender_signature = sp.second(new_c.digest(chain_id)); if (is_valid_commit(new_c, sp.first)) { - emit(pbft_outgoing_commit, std::make_shared(new_c)); add_pbft_commit(new_c, sp.first); - if (commit_to_be_cached.empty()) commit_to_be_cached = new_c; + commits_to_be_cached.emplace_back(new_c); } } } } - return commit_to_be_cached; + return commits_to_be_cached; } void pbft_database::mark_as_committed(const block_id_type& bid) { @@ -365,7 +368,7 @@ namespace eosio { } bool pbft_database::should_committed() { - auto const &by_commit_and_num_index = pbft_state_index.get(); + const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end()) return false; pbft_state_ptr psp = *itr; @@ -377,7 +380,7 @@ namespace eosio { pbft_view_type new_view = 0; if (!should_committed()) return new_view; - auto const &by_commit_and_num_index = pbft_state_index.get(); + const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); pbft_state_ptr psp = *itr; @@ -390,17 +393,17 @@ namespace eosio { auto threshold = as.size() * 2 / 3 + 1; flat_map commit_count; - for (auto const &com: commits) { + for (const auto& com: commits) { if (commit_count.find(com.second.view) == commit_count.end()) commit_count[com.second.view] = 0; } - for (auto const &bp: as) { - for (auto const &pc: commits) { + for (const auto& bp: as) { + for (const auto& pc: commits) { if (bp.block_signing_key == pc.first.second) commit_count[pc.first.first] += 1; } } - for (auto const &e: commit_count) { + for (const auto& e: commit_count) { if (e.second >= threshold && e.first > new_view) { new_view = e.first; } @@ -414,7 +417,7 @@ namespace eosio { } void pbft_database::commit_local() { - auto const &by_commit_and_num_index = pbft_state_index.get(); + const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end()) return; @@ -460,8 +463,8 @@ namespace eosio { if (vsp->view_changes.size() >= threshold && !vsp->is_view_changed) { auto vc_count = 0; - for (auto const &bp: lscb_bps) { - for (auto const &v: vsp->view_changes) { + for (const auto& bp: lscb_bps) { + for (const auto& v: vsp->view_changes) { if (bp.block_signing_key == v.first) vc_count += 1; } } @@ -482,8 +485,8 @@ namespace eosio { auto vc_count = 0; auto pvs = (*itr); - for (auto const &bp: active_bps) { - for (auto const &v: pvs->view_changes) { + for (const auto& bp: active_bps) { + for (const auto& v: pvs->view_changes) { if (bp.block_signing_key == v.first) vc_count += 1; } } @@ -497,42 +500,43 @@ namespace eosio { return nv; } - pbft_view_change pbft_database::send_and_add_pbft_view_change( - const pbft_view_change& cached_view_change, - const pbft_prepared_certificate& ppc, - const vector& pcc, + vector pbft_database::generate_and_add_pbft_view_change( + const pbft_view_change &cached_view_change, + const pbft_prepared_certificate &ppc, + const vector &pcc, pbft_view_type current_view, pbft_view_type target_view) { - pbft_view_change view_change_to_be_cached; + vector view_changes_to_be_cached; + const auto& my_sps = ctrl.my_signature_providers(); + view_changes_to_be_cached.reserve(my_sps.size()); + if (!cached_view_change.empty()) { - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { //sign again, update cache, then emit auto retry_vc = cached_view_change; retry_vc.common.timestamp = time_point::now(); retry_vc.sender_signature = sp.second(retry_vc.digest(chain_id)); - emit(pbft_outgoing_view_change, std::make_shared(retry_vc)); + view_changes_to_be_cached.emplace_back(retry_vc); } } else { - for (auto const &my_sp : ctrl.my_signature_providers()) { - + for (const auto& sp : my_sps) { auto my_lsc = get_stable_checkpoint_by_id(ctrl.last_stable_checkpoint_block_id()); pbft_view_change new_vc; - new_vc.current_view=current_view; - new_vc.target_view=target_view; - new_vc.prepared_cert=ppc; - new_vc.committed_certs=pcc; - new_vc.stable_checkpoint=my_lsc; - new_vc.sender_signature = my_sp.second(new_vc.digest(chain_id)); - if (is_valid_view_change(new_vc, my_sp.first)) { - emit(pbft_outgoing_view_change, std::make_shared(new_vc)); - add_pbft_view_change(new_vc, my_sp.first); - if (view_change_to_be_cached.empty()) view_change_to_be_cached = new_vc; + new_vc.current_view = current_view; + new_vc.target_view = target_view; + new_vc.prepared_cert = ppc; + new_vc.committed_certs = pcc; + new_vc.stable_checkpoint = my_lsc; + new_vc.sender_signature = sp.second(new_vc.digest(chain_id)); + if (is_valid_view_change(new_vc, sp.first)) { + add_pbft_view_change(new_vc, sp.first); + view_changes_to_be_cached.emplace_back(new_vc); } } } - return view_change_to_be_cached; + return view_changes_to_be_cached; } bool pbft_database::should_new_view(pbft_view_type target_view) { @@ -562,8 +566,8 @@ namespace eosio { ctrl.reset_pbft_my_prepare(); } - pbft_new_view pbft_database::send_pbft_new_view( - const pbft_view_changed_certificate& vcc, + pbft_new_view pbft_database::generate_pbft_new_view( + const pbft_view_changed_certificate &vcc, pbft_view_type current_view) { pbft_new_view nv; @@ -579,12 +583,12 @@ namespace eosio { auto highest_pcc = vector{}; auto highest_sc = pbft_stable_checkpoint(); - for (auto const &vc: vcc.view_changes) { + for (const auto& vc: vcc.view_changes) { if (vc.prepared_cert.block_info.block_num() > highest_ppc.block_info.block_num()) { highest_ppc = vc.prepared_cert; } - for (auto const &cc: vc.committed_certs) { + for (const auto& cc: vc.committed_certs) { auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), [&](const pbft_committed_certificate& ext) { return ext.block_info.block_id == cc.block_info.block_id; }); if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); @@ -595,15 +599,14 @@ namespace eosio { } } - nv.new_view=current_view; - nv.prepared_cert=highest_ppc; - nv.committed_certs=highest_pcc; - nv.stable_checkpoint=highest_sc; - nv.view_changed_cert=vcc; + nv.new_view = current_view; + nv.prepared_cert = highest_ppc; + nv.committed_certs = highest_pcc; + nv.stable_checkpoint = highest_sc; + nv.view_changed_cert = vcc; nv.sender_signature = sp_itr->second(nv.digest(chain_id)); try { validate_new_view(nv, sp_itr->first); - emit(pbft_outgoing_new_view, std::make_shared(nv)); } catch (const fc::exception& ex) { elog("bad new view, ${s} ", ("s", ex.to_string())); nv = pbft_new_view(); @@ -615,7 +618,7 @@ namespace eosio { pbft_prepared_certificate ppc; - auto const &by_prepare_and_num_index = pbft_state_index.get(); + const auto& by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); if (itr == by_prepare_and_num_index.end()) return ppc; pbft_state_ptr psp = *itr; @@ -631,19 +634,19 @@ namespace eosio { flat_map prepare_count; flat_map> prepare_msg; - for (auto const &pre: prepares) { + for (const auto& pre: prepares) { if (prepare_count.find(pre.first.first) == prepare_count.end()) prepare_count[pre.first.first] = 0; prepare_msg[pre.first.first].emplace_back(pre.second); } - for (auto const &bp: as) { - for (auto const &pp: prepares) { + for (const auto& bp: as) { + for (const auto& pp: prepares) { if (bp.block_signing_key == pp.first.second) prepare_count[pp.first.first] += 1; } } auto bp_threshold = as.size() * 2 / 3 + 1; - for (auto const &e: prepare_count) { + for (const auto& e: prepare_count) { if (e.second >= bp_threshold) { valid_prepares = prepare_msg[e.first]; } @@ -651,8 +654,10 @@ namespace eosio { if (valid_prepares.empty()) return ppc; - ppc.block_info={psp->block_id}; ppc.prepares=valid_prepares; ppc.pre_prepares.emplace(psp->block_id); - for (auto const &p: valid_prepares) { + ppc.block_info = {psp->block_id}; + ppc.prepares=valid_prepares; + ppc.pre_prepares.emplace(psp->block_id); + for (const auto& p: valid_prepares) { auto bid = p.block_info.block_id; while (bid != psp->block_id) { ppc.pre_prepares.emplace(bid); @@ -667,7 +672,7 @@ namespace eosio { vector pcc{}; - auto const &by_commit_and_num_index = pbft_state_index.get(); + const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end()) return pcc; @@ -695,11 +700,11 @@ namespace eosio { } } - auto const &by_id_index = pbft_state_index.get(); + const auto& by_id_index = pbft_state_index.get(); std::sort(ccb.begin(), ccb.end()); pcc.reserve(ccb.size()); - for (auto const &committed_block_num: ccb) { + for (const auto& committed_block_num: ccb) { auto cbs = ctrl.fetch_block_state_by_number(committed_block_num); if (!cbs) return pcc; @@ -716,19 +721,19 @@ namespace eosio { flat_map commit_count; flat_map> commit_msg; - for (auto const &com: commits) { + for (const auto& com: commits) { if (commit_count.find(com.first.first) == commit_count.end()) commit_count[com.first.first] = 0; commit_msg[com.first.first].emplace_back(com.second); } - for (auto const &bp: as) { - for (auto const &cc: commits) { + for (const auto& bp: as) { + for (const auto& cc: commits) { if (bp.block_signing_key == cc.first.second) commit_count[cc.first.first] += 1; } } auto bp_threshold = as.size() * 2 / 3 + 1; - for (auto const &e: commit_count) { + for (const auto& e: commit_count) { if (e.second >= bp_threshold) { valid_commits = commit_msg[e.first]; } @@ -737,7 +742,8 @@ namespace eosio { if (valid_commits.empty()) return pcc; pbft_committed_certificate cc; - cc.block_info={cbs->id}; cc.commits=valid_commits; + cc.block_info = {cbs->id}; + cc.commits = valid_commits; pcc.emplace_back(cc); } return pcc; @@ -792,19 +798,19 @@ namespace eosio { flat_map prepare_count; - for (auto const &pm: prepares_metadata) { + for (const auto& pm: prepares_metadata) { if (prepare_count.find(pm.msg.view) == prepare_count.end()) prepare_count[pm.msg.view] = 0; } - for (auto const &bp: producer_schedule.producers) { - for (auto const &pm: prepares_metadata) { + for (const auto& bp: producer_schedule.producers) { + for (const auto& pm: prepares_metadata) { if (bp.block_signing_key == pm.sender_key) prepare_count[pm.msg.view] += 1; } } auto should_prepared = false; - for (auto const &e: prepare_count) { + for (const auto& e: prepare_count) { if (e.second >= bp_threshold) { should_prepared = true; } @@ -815,9 +821,9 @@ namespace eosio { //validate prepare auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto non_fork_bp_count = 0; - vector prepare_infos; + fork_info_type prepare_infos; prepare_infos.reserve(certificate.prepares.size()); - for (auto const &p : certificate.prepares) { + for (const auto& p : certificate.prepares) { //only search in fork db if (p.block_info.block_num() <= lscb_num) { ++non_fork_bp_count; @@ -855,19 +861,19 @@ namespace eosio { flat_map commit_count; - for (auto const &cm: commits_metadata) { + for (const auto& cm: commits_metadata) { if (commit_count.find(cm.msg.view) == commit_count.end()) commit_count[cm.msg.view] = 0; } - for (auto const &bp: producer_schedule.producers) { - for (auto const &cm: commits_metadata) { + for (const auto& bp: producer_schedule.producers) { + for (const auto& cm: commits_metadata) { if (bp.block_signing_key == cm.sender_key) commit_count[cm.msg.view] += 1; } } auto should_committed = false; - for (auto const &e: commit_count) { + for (const auto& e: commit_count) { if (e.second >= bp_threshold) { should_committed = true; } @@ -878,9 +884,9 @@ namespace eosio { //validate commit auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto non_fork_bp_count = 0; - vector commit_infos; + fork_info_type commit_infos; commit_infos.reserve(certificate.commits.size()); - for (auto const &c : certificate.commits) { + for (const auto& c : certificate.commits) { //only search in fork db if (c.block_info.block_num() <= lscb_num) { ++non_fork_bp_count; @@ -897,7 +903,6 @@ namespace eosio { // No need to check prepared cert and stable checkpoint, until generate or validate a new view msg } - void pbft_database::validate_new_view(const pbft_new_view& nv, const public_key_type& pk) { EOS_ASSERT(pk == get_new_view_primary_key(nv.new_view), pbft_exception, @@ -911,7 +916,7 @@ namespace eosio { auto committed_certs = nv.committed_certs; std::sort(committed_certs.begin(), committed_certs.end()); - for (auto const &c: committed_certs) { + for (const auto& c: committed_certs) { EOS_ASSERT(is_valid_committed_certificate(c, true), pbft_exception, "bad committed certificate: ${cc}", ("cc", c)); } @@ -920,7 +925,7 @@ namespace eosio { vector lscb_producers; lscb_producers.reserve(lscb_active_producers().producers.size()); - for (auto const &bp: lscb_active_producers().producers) { + for (const auto& bp: lscb_active_producers().producers) { lscb_producers.emplace_back(bp.block_signing_key); } auto schedule_threshold = lscb_producers.size() * 2 / 3 + 1; @@ -957,13 +962,13 @@ namespace eosio { auto highest_pcc = vector{}; auto highest_scp = pbft_stable_checkpoint(); - for (auto const &vc: nv.view_changed_cert.view_changes) { + for (const auto& vc: nv.view_changed_cert.view_changes) { if (vc.prepared_cert.block_info.block_num() > highest_ppc.block_info.block_num() && is_valid_prepared_certificate(vc.prepared_cert)) { highest_ppc = vc.prepared_cert; } - for (auto const &cc: vc.committed_certs) { + for (const auto& cc: vc.committed_certs) { if (is_valid_committed_certificate(cc)) { auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), [&](const pbft_committed_certificate &ext) { @@ -1003,9 +1008,9 @@ namespace eosio { return vc_lscb > 0 && lscb_num > vc_lscb; } - vector> pbft_database::fetch_fork_from(vector& block_infos) { + vector pbft_database::fetch_fork_from(fork_info_type& block_infos) { - vector> result; + vector result; if (block_infos.empty()) { return result; } @@ -1026,8 +1031,8 @@ namespace eosio { return result; } - vector pbft_database::fetch_first_fork_from(vector& bi) { - vector result; + fork_info_type pbft_database::fetch_first_fork_from(fork_info_type& bi) { + fork_info_type result; if (bi.empty()) { return result; } @@ -1067,22 +1072,22 @@ namespace eosio { return result; } - bool pbft_database::is_valid_longest_fork(const block_info_type& bi, vector block_infos, unsigned long threshold, unsigned long non_fork_bp_count) { + bool pbft_database::is_valid_longest_fork( + const block_info_type& bi, + fork_info_type block_infos, + unsigned long threshold, + unsigned long non_fork_bp_count) { auto forks = fetch_fork_from(block_infos); - vector longest_fork; - for (auto const &f : forks) { + fork_info_type longest_fork; + for (const auto& f : forks) { if (f.size() > longest_fork.size()) { longest_fork = f; } } - if (longest_fork.size() + non_fork_bp_count < threshold) return false; - - if (longest_fork.empty()) return true; - - auto calculated_block_info = longest_fork.back(); - return bi.block_id == calculated_block_info.block_id; + return longest_fork.empty() + || (longest_fork.size() + non_fork_bp_count >= threshold && bi.block_id == longest_fork.back().block_id); } pbft_stable_checkpoint pbft_database::fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr& b) { @@ -1099,7 +1104,7 @@ namespace eosio { fc::raw::unpack(ds, psc); if (is_valid_stable_checkpoint(psc)) { - return psc; + break; } else { it = extn.erase(it); } @@ -1117,7 +1122,7 @@ namespace eosio { pbft_stable_checkpoint pbft_database::get_stable_checkpoint_by_id(const block_id_type& block_id, bool incl_blk_extn ) { pbft_stable_checkpoint psc; - auto const &by_block = checkpoint_index.get(); + const auto& by_block = checkpoint_index.get(); auto itr = by_block.find(block_id); if (itr == by_block.end()) { if (incl_blk_extn) { @@ -1145,7 +1150,7 @@ namespace eosio { auto pending_scb_num = ctrl.last_stable_checkpoint_block_num(); auto pending_scb_info = block_info_type{ctrl.last_stable_checkpoint_block_id()}; - auto const &by_blk_num = checkpoint_index.get(); + const auto& by_blk_num = checkpoint_index.get(); auto itr = by_blk_num.lower_bound(pending_scb_num); if (itr == by_blk_num.end()) return pending_scb_info; @@ -1159,7 +1164,7 @@ namespace eosio { producer_schedule_type new_schedule; if (pending_scb_num == 0) { - auto const &ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; + const auto& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; if (ucb == 0) { current_schedule = ctrl.initial_schedule(); new_schedule = ctrl.initial_schedule(); @@ -1203,7 +1208,7 @@ namespace eosio { vector new_pc{}; - auto const &by_commit_and_num_index = pbft_state_index.get(); + const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end() || !(*itr)->is_committed) return new_pc; @@ -1221,7 +1226,7 @@ namespace eosio { pending_checkpoint_block_num[i] = false; } else { auto checkpoints = (*c_itr)->checkpoints; - for (auto const &my_sp : ctrl.my_signature_providers()) { + for (const auto& my_sp : ctrl.my_signature_providers()) { if (checkpoints.find(my_sp.first) != checkpoints.end() && !(*c_itr)->is_stable) { pending_checkpoint_block_num[i] = true; //retry sending at this time. } @@ -1239,9 +1244,9 @@ namespace eosio { std::sort(pending_checkpoint_block_num.begin(), pending_checkpoint_block_num.end()); for (auto& bnum_and_retry: pending_checkpoint_block_num) { if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(bnum_and_retry.first)) { - for (auto const &my_sp : ctrl.my_signature_providers()) { + for (const auto& my_sp : ctrl.my_signature_providers()) { pbft_checkpoint cp; - cp.block_info={bs->id}; + cp.block_info = {bs->id}; cp.sender_signature = my_sp.second(cp.digest(chain_id)); if (!bnum_and_retry.second && is_valid_checkpoint(cp, my_sp.first)) { //first time sending this checkpoint add_pbft_checkpoint(cp, my_sp.first); @@ -1251,7 +1256,7 @@ namespace eosio { } } } else if (lscb_num > 0) { //retry sending my lscb - for (auto const &my_sp : ctrl.my_signature_providers()) { + for (const auto& my_sp : ctrl.my_signature_providers()) { pbft_checkpoint cp; cp.block_info={ctrl.last_stable_checkpoint_block_id()}; cp.sender_signature = my_sp.second(cp.digest(chain_id)); @@ -1294,8 +1299,8 @@ namespace eosio { if (csp->checkpoints.size() >= threshold && !csp->is_stable) { auto cp_count = 0; - for (auto const &bp: active_bps) { - for (auto const &c: csp->checkpoints) { + for (const auto& bp: active_bps) { + for (const auto& c: csp->checkpoints) { if (bp.block_signing_key == c.first) cp_count += 1; } } @@ -1322,18 +1327,12 @@ namespace eosio { } } - void pbft_database::send_pbft_checkpoint() { - auto cps_to_send = generate_and_add_pbft_checkpoint(); - for (auto const &cp: cps_to_send) { - emit(pbft_outgoing_checkpoint, std::make_shared(cp)); - } - } - void pbft_database::checkpoint_local() { auto pending_scb_info = cal_pending_stable_checkpoint(); auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto pending_num = pending_scb_info.block_num(); auto pending_id = pending_scb_info.block_id; + //TODO: optimise prune logic if (pending_num > lscb_num) { ctrl.set_pbft_latest_checkpoint(pending_id); if (ctrl.last_irreversible_block_num() < pending_num) ctrl.pbft_commit_local(pending_id); @@ -1358,7 +1357,7 @@ namespace eosio { if (auto bs = ctrl.fetch_block_state_by_id(cp.block_info.block_id)) { auto active_bps = bs->active_schedule.producers; - for (auto const &bp: active_bps) { + for (const auto& bp: active_bps) { if (bp.block_signing_key == pk) return true; } } @@ -1388,8 +1387,8 @@ namespace eosio { if (auto bs = ctrl.fetch_block_state_by_number(scp.block_info.block_num())) { auto as = bs->active_schedule; auto cp_count = 0; - for (auto const &bp: as.producers) { - for (auto const &cpm: checkpoints_metadata) { + for (const auto& bp: as.producers) { + for (const auto& cpm: checkpoints_metadata) { if (bp.block_signing_key == cpm.sender_key) cp_count += 1; } } @@ -1402,8 +1401,8 @@ namespace eosio { bool pbft_database::should_send_pbft_msg() { auto schedules = get_updated_fork_schedules(); - for (auto const &bp: schedules) { - for (auto const &sp: ctrl.my_signature_providers()) { + for (const auto& bp: schedules) { + for (const auto& sp: ctrl.my_signature_providers()) { if (bp.first == sp.first) return true; } } @@ -1413,7 +1412,7 @@ namespace eosio { bool pbft_database::should_recv_pbft_msg(const public_key_type& pub_key) { auto schedules = get_updated_fork_schedules(); - for (auto const &bp: schedules) { + for (const auto& bp: schedules) { if (bp.first == pub_key) return true; } return false; @@ -1433,7 +1432,7 @@ namespace eosio { auto num = ctrl.last_stable_checkpoint_block_num(); if (num == 0) { - auto const &ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; + const auto& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; if (ucb == 0) return ps; num = ucb; } @@ -1612,22 +1611,5 @@ namespace eosio { checkpoint_index.erase(itr); } } - - template - void pbft_database::emit(const Signal &s, Arg &&a) { - try { - s(std::forward(a)); - } 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 (...) { - wlog("signal handler threw exception"); - } - } } } \ No newline at end of file diff --git a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp index 81935707abe..9a3212a56fd 100644 --- a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp +++ b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp @@ -80,6 +80,9 @@ namespace eosio { namespace chain { namespace plugin_interface { using checkpoint_channel = channel_decl; } + + using committed_transition_channel = channel_decl; + using prepared_transition_channel = channel_decl; } } } } diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 581bcb80443..c720b348e10 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -740,7 +740,7 @@ void chain_plugin::plugin_initialize(const variables_map& options) { ilog("include pbft controller..."); my->pbft_ctrl.emplace(*my->chain); - // set up method providers + // set up method providers my->get_block_by_number_provider = app().get_method().register_provider( [this]( uint32_t block_num ) -> signed_block_ptr { return my->chain->fetch_block_by_number( block_num ); @@ -825,27 +825,27 @@ void chain_plugin::plugin_initialize(const variables_map& options) { my->on_pbft_incoming_checkpoint(cp); }); - my->pbft_outgoing_prepare_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_prepare.connect( + my->pbft_outgoing_prepare_connection = my->pbft_ctrl->state_machine.pbft_outgoing_prepare.connect( [this]( const pbft_prepare_ptr& prepare ) { my->pbft_outgoing_prepare_channel.publish( prepare ); }); - my->pbft_outgoing_commit_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_commit.connect( + my->pbft_outgoing_commit_connection = my->pbft_ctrl->state_machine.pbft_outgoing_commit.connect( [this]( const pbft_commit_ptr& commit ) { my->pbft_outgoing_commit_channel.publish( commit ); }); - my->pbft_outgoing_view_change_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_view_change.connect( + my->pbft_outgoing_view_change_connection = my->pbft_ctrl->state_machine.pbft_outgoing_view_change.connect( [this]( const pbft_view_change_ptr& view_change ) { my->pbft_outgoing_view_change_channel.publish( view_change ); }); - my->pbft_outgoing_new_view_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_new_view.connect( + my->pbft_outgoing_new_view_connection = my->pbft_ctrl->state_machine.pbft_outgoing_new_view.connect( [this]( const pbft_new_view_ptr& new_view ) { my->pbft_outgoing_new_view_channel.publish( new_view ); }); - my->pbft_outgoing_checkpoint_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_checkpoint.connect( + my->pbft_outgoing_checkpoint_connection = my->pbft_ctrl->state_machine.pbft_outgoing_checkpoint.connect( [this]( const pbft_checkpoint_ptr& checkpoint ) { my->pbft_outgoing_checkpoint_channel.publish( checkpoint ); }); @@ -1209,8 +1209,8 @@ read_only::get_info_results read_only::get_info(const read_only::get_info_params db.fork_db_head_block_id(), db.fork_db_head_block_time(), db.fork_db_head_block_producer(), - pbft_ctrl.state_machine->get_current_view(), - pbft_ctrl.state_machine->get_target_view(), + pbft_ctrl.state_machine.get_current_view(), + pbft_ctrl.state_machine.get_target_view(), db.last_stable_checkpoint_block_num(), rm.get_virtual_block_cpu_limit(), rm.get_virtual_block_net_limit(), diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index d10d9be5048..f9e611ad229 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -251,9 +251,7 @@ namespace eosio { template bool is_pbft_msg_valid(const M& msg); - void bcast_pbft_msg(const net_message& msg, int ttl); - - void forward_pbft_msg(const connection_ptr& c, const net_message& msg, int ttl); + void bcast_pbft_msg(const net_message& msg, int ttl, const connection_ptr& c = nullptr); void pbft_outgoing_prepare(const pbft_prepare_ptr& prepare); void pbft_outgoing_commit(const pbft_commit_ptr& commit); @@ -2998,21 +2996,11 @@ namespace eosio { && !sync_master->is_syncing(); } - void net_plugin_impl::bcast_pbft_msg(const net_message &msg, int ttl) { - if (sync_master->is_syncing()) return; + void net_plugin_impl::bcast_pbft_msg(const net_message &msg, int ttl, const connection_ptr& c) { +// if (sync_master->is_syncing()) return; auto deadline = time_point_sec(time_point::now()) + ttl; - for (auto &conn: connections) { - if (conn->pbft_ready()) { - conn->enqueue_pbft(encode_pbft_message(msg), deadline); - } - } - } - - void net_plugin_impl::forward_pbft_msg(const connection_ptr& c, const net_message &msg, int ttl) { - auto deadline = time_point_sec(time_point::now()) + ttl; - for (auto &conn: connections) { if (conn != c && conn->pbft_ready()) { conn->enqueue_pbft(encode_pbft_message(msg), deadline); @@ -3021,43 +3009,42 @@ namespace eosio { } void net_plugin_impl::pbft_outgoing_prepare(const pbft_prepare_ptr& msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); - if (!added) return; - - bcast_pbft_msg(*msg, pbft_message_TTL); - fc_dlog( logger, "sent prepare at height: ${n}, view: ${v} ", ("n", msg->block_info.block_num())("v", msg->view)); + if (maybe_add_to_pbft_cache(std::string(msg->sender_signature))) { + bcast_pbft_msg(*msg, pbft_message_TTL); + fc_dlog(logger, "sent prepare at height: ${n}, view: ${v} ", + ("n", msg->block_info.block_num())("v", msg->view)); + } } void net_plugin_impl::pbft_outgoing_commit(const pbft_commit_ptr& msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); - if (!added) return; - - bcast_pbft_msg(*msg, pbft_message_TTL); - fc_dlog( logger, "sent commit at height: ${n}, view: ${v} ", ("n", msg->block_info.block_num())("v", msg->view)); + if (maybe_add_to_pbft_cache(std::string(msg->sender_signature))) { + bcast_pbft_msg(*msg, pbft_message_TTL); + fc_dlog(logger, "sent commit at height: ${n}, view: ${v} ", + ("n", msg->block_info.block_num())("v", msg->view)); + } } void net_plugin_impl::pbft_outgoing_view_change(const pbft_view_change_ptr& msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); - if (!added) return; - - bcast_pbft_msg(*msg, pbft_message_TTL); - fc_dlog( logger, "sent view change {cv: ${cv}, tv: ${tv}}", ("cv", msg->current_view)("tv", msg->target_view)); + if (maybe_add_to_pbft_cache(std::string(msg->sender_signature))) { + bcast_pbft_msg(*msg, pbft_message_TTL); + fc_dlog(logger, "sent view change {cv: ${cv}, tv: ${tv}}", + ("cv", msg->current_view)("tv", msg->target_view)); + } } void net_plugin_impl::pbft_outgoing_new_view(const pbft_new_view_ptr& msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); - if (!added) return; + if (maybe_add_to_pbft_cache(std::string(msg->sender_signature))) { + bcast_pbft_msg(*msg, 60 * pbft_message_TTL); + fc_dlog( logger, "sent new view at view: ${v} ", ("v", msg->new_view)); + } - bcast_pbft_msg(*msg, 60 * pbft_message_TTL); - fc_dlog( logger, "sent new view at view: ${v} ", ("v", msg->new_view)); } void net_plugin_impl::pbft_outgoing_checkpoint(const pbft_checkpoint_ptr& msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); - if (!added) return; - - bcast_pbft_msg(*msg, pbft_message_TTL); - fc_dlog( logger, "sent checkpoint at height: ${n} ", ("n", msg->block_info.block_num())); + if (maybe_add_to_pbft_cache(std::string(msg->sender_signature))) { + bcast_pbft_msg(*msg, pbft_message_TTL); + fc_dlog(logger, "sent checkpoint at height: ${n} ", ("n", msg->block_info.block_num())); + } } bool net_plugin_impl::maybe_add_to_pbft_cache(const string &key){ @@ -3085,95 +3072,89 @@ namespace eosio { } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_prepare &msg) { - if (!is_pbft_msg_valid(msg)) return; - - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; + if (is_pbft_msg_valid(msg) && maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { + auto pmm = pbft_message_metadata(msg, chain_id); - auto pmm = pbft_message_metadata(std::move(msg), chain_id); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + if (!pcc.pbft_db.is_valid_prepare(pmm.msg, pmm.sender_key)) return; + bcast_pbft_msg(pmm.msg, pbft_message_TTL, c); + fc_dlog(logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", + ("n", pmm.msg.block_info.block_num())("v", pmm.msg.view)("k", pmm.sender_key)); - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_prepare(pmm.msg, pmm.sender_key)) return; - - forward_pbft_msg(c, pmm.msg, pbft_message_TTL); - fc_dlog( logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", pmm.msg.block_info.block_num())("v", pmm.msg.view)("k", pmm.sender_key)); + pbft_incoming_prepare_channel.publish(std::make_shared>(std::move(pmm))); + } - pbft_incoming_prepare_channel.publish(std::make_shared>(std::move(pmm))); } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_commit &msg) { - if (!is_pbft_msg_valid(msg)) return; + if (is_pbft_msg_valid(msg) && maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { + auto pmm = pbft_message_metadata(msg, chain_id); - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + if (!pcc.pbft_db.is_valid_commit(pmm.msg, pmm.sender_key)) return; - auto pmm = pbft_message_metadata(std::move(msg), chain_id); + bcast_pbft_msg(pmm.msg, pbft_message_TTL, c); + fc_dlog(logger, "received commit at height: ${n}, view: ${v}, from ${k}, ", + ("n", pmm.msg.block_info.block_num())("v", pmm.msg.view)("k", pmm.sender_key)); - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_commit(pmm.msg, pmm.sender_key)) return; - - forward_pbft_msg(c, pmm.msg, pbft_message_TTL); - fc_dlog( logger, "received commit at height: ${n}, view: ${v}, from ${k}, ", ("n", pmm.msg.block_info.block_num())("v", pmm.msg.view)("k", pmm.sender_key)); - - pbft_incoming_commit_channel.publish(std::make_shared>(std::move(pmm))); + pbft_incoming_commit_channel.publish(std::make_shared>(std::move(pmm))); + } } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_view_change &msg) { - if (!is_pbft_msg_valid(msg)) return; - - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; + if (is_pbft_msg_valid(msg) && maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { + auto pmm = pbft_message_metadata(msg, chain_id); - auto pmm = pbft_message_metadata( std::move(msg), chain_id); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + controller &ctrl = my_impl->chain_plug->chain(); + if (!pcc.pbft_db.is_valid_view_change(pmm.msg, pmm.sender_key)) return; - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - controller &ctrl = my_impl->chain_plug->chain(); - if (!pcc.pbft_db.is_valid_view_change(pmm.msg, pmm.sender_key)) return; - - auto missing_blocks = set{}; - for (auto const &b: pmm.msg.prepared_cert.pre_prepares) { - if (!ctrl.fetch_block_by_id(b)) missing_blocks.emplace(b); - } + auto missing_blocks = set{}; + for (auto const &b: pmm.msg.prepared_cert.pre_prepares) { + if (!ctrl.fetch_block_by_id(b)) missing_blocks.emplace(b); + } - if (!missing_blocks.empty()) { - fc_dlog( logger, "requesting ${num} missing blocks from view change", ("num", missing_blocks.size())); - request_message req; - for (auto const &b: missing_blocks) { - req.req_blocks.ids.push_back(b); + if (!missing_blocks.empty()) { + fc_dlog(logger, "requesting ${num} missing blocks from view change", ("num", missing_blocks.size())); + request_message req; + for (auto const &b: missing_blocks) { + req.req_blocks.ids.push_back(b); + } + req.req_trx.mode = normal; + req.req_blocks.mode = normal; + c->enqueue(req); } - req.req_trx.mode = normal; - req.req_blocks.mode = normal; - c->enqueue(req); - } - forward_pbft_msg(c, pmm.msg, pbft_message_TTL); - fc_dlog( logger, "received view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", pmm.msg.current_view)("tv", pmm.msg.target_view)("v", pmm.sender_key)); + bcast_pbft_msg(pmm.msg, pbft_message_TTL, c); + fc_dlog(logger, "received view change {cv: ${cv}, tv: ${tv}} from ${v}", + ("cv", pmm.msg.current_view)("tv", pmm.msg.target_view)("v", pmm.sender_key)); - pbft_incoming_view_change_channel.publish(std::make_shared>(std::move(pmm))); + pbft_incoming_view_change_channel.publish(std::make_shared>(std::move(pmm))); + } } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_new_view &msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; + if (maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (time_point_sec(time_point::now()) > time_point_sec(msg.common.timestamp) + 60 * pbft_message_TTL - || msg.new_view <= pcc.state_machine->get_current_view()) { - //skip new view messages that are too old or whose target views are lower than mine. - return; - } + if (time_point_sec(time_point::now()) > time_point_sec(msg.common.timestamp) + 60 * pbft_message_TTL + || msg.new_view <= pcc.state_machine.get_current_view()) { + //skip new view messages that are too old or whose target views are lower than mine. + return; + } - auto pmm = pbft_message_metadata(std::move(msg), chain_id); + auto pmm = pbft_message_metadata(msg, chain_id); - if (pmm.sender_key != pcc.pbft_db.get_new_view_primary_key(pmm.msg.new_view)) return; + if (pmm.sender_key != pcc.pbft_db.get_new_view_primary_key(pmm.msg.new_view)) return; - forward_pbft_msg(c, pmm.msg, 60 * pbft_message_TTL); - fc_dlog( logger, "received new view: ${n}, from ${v}", ("n", pmm.msg)("v", pmm.sender_key)); + bcast_pbft_msg(pmm.msg, 60 * pbft_message_TTL, c); + fc_dlog(logger, "received new view: ${n}, from ${v}", ("n", pmm.msg)("v", pmm.sender_key)); - pbft_incoming_new_view_channel.publish(std::make_shared>(std::move(pmm))); + pbft_incoming_new_view_channel.publish(std::make_shared>(std::move(pmm))); + } } void net_plugin_impl::handle_message( const connection_ptr& c, const compressed_pbft_message &msg) { @@ -3193,20 +3174,18 @@ namespace eosio { } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_checkpoint &msg) { - if (!is_pbft_msg_valid(msg)) return; - - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; + if (is_pbft_msg_valid(msg) && maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { + auto pmm = pbft_message_metadata(std::move(msg), chain_id); - auto pmm = pbft_message_metadata(std::move(msg), chain_id); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + if (!pcc.pbft_db.is_valid_checkpoint(pmm.msg, pmm.sender_key)) return; - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_checkpoint(pmm.msg, pmm.sender_key)) return; + bcast_pbft_msg(pmm.msg, pbft_message_TTL, c); + fc_dlog(logger, "received checkpoint at ${n}, from ${v}", + ("n", pmm.msg.block_info.block_num())("v", pmm.sender_key)); - forward_pbft_msg(c, pmm.msg, pbft_message_TTL); - fc_dlog( logger, "received checkpoint at ${n}, from ${v}", ("n", pmm.msg.block_info.block_num())("v", pmm.sender_key)); - - pbft_incoming_checkpoint_channel.publish(std::make_shared>(std::move(pmm))); + pbft_incoming_checkpoint_channel.publish(std::make_shared>(std::move(pmm))); + } } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_stable_checkpoint &msg) { @@ -3214,7 +3193,8 @@ namespace eosio { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_stable_checkpoint(msg, true)) return; - fc_ilog(logger, "received stable checkpoint at ${n}, from ${v}", ("n", msg.block_info.block_num())("v", c->peer_name())); + fc_ilog(logger, "received stable checkpoint at ${n}, from ${v}", + ("n", msg.block_info.block_num())("v", c->peer_name())); } void net_plugin_impl::start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection) { diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index ebff9c785f1..674a4ead103 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -3,14 +3,23 @@ #include #include #include +#include namespace eosio { static appbase::abstract_plugin &_pbft_plugin = app().register_plugin(); using namespace std; using namespace eosio::chain; + using namespace eosio::chain::plugin_interface; + using boost::signals2::scoped_connection; + class pbft_plugin_impl { public: + pbft_plugin_impl() + :transit_to_committed_channel(app().get_channel()) + ,transit_to_prepared_channel(app().get_channel()) + {} + unique_ptr prepare_timer; unique_ptr commit_timer; unique_ptr view_change_timer; @@ -26,6 +35,15 @@ namespace eosio { void view_change_timer_tick(); void checkpoint_timer_tick(); + pbft::committed_transition_channel::channel_type::handle transit_to_committed_subscription; + pbft::committed_transition_channel::channel_type& transit_to_committed_channel; + + pbft::prepared_transition_channel::channel_type::handle transit_to_prepared_subscription; + pbft::prepared_transition_channel::channel_type& transit_to_prepared_channel; + + void on_committed_transition(); + void on_prepared_transition(); + private: bool upgraded = false; bool is_replaying(); @@ -33,109 +51,44 @@ namespace eosio { bool pbft_ready(); }; - pbft_plugin::pbft_plugin() : my(new pbft_plugin_impl()) {} - - pbft_plugin::~pbft_plugin() = default; - - void pbft_plugin::set_program_options(options_description &, options_description &cfg) { - } - - void pbft_plugin::plugin_initialize(const variables_map &options) { - ilog("Initialize pbft plugin"); - my->prepare_timer = std::make_unique(app().get_io_service()); - my->commit_timer = std::make_unique(app().get_io_service()); - my->view_change_timer = std::make_unique(app().get_io_service()); - my->checkpoint_timer = std::make_unique(app().get_io_service()); - } - - void pbft_plugin::plugin_startup() { - my->prepare_timer_tick(); - my->commit_timer_tick(); - my->view_change_timer_tick(); - my->checkpoint_timer_tick(); - } - - void pbft_plugin::plugin_shutdown() {} - - pbft_state pbft_plugin::get_pbft_record( const block_id_type& bid ) const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - auto record = pbft_ctrl.pbft_db.get_pbft_state_by_id(bid); - if (record) return *record; - return pbft_state(); - } - - vector pbft_plugin::get_pbft_checkpoints_record(block_num_type bnum) const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - auto records = pbft_ctrl.pbft_db.get_checkpoints_by_num(bnum); - if (!records.empty()) return records; - return vector(); - } - pbft_view_change_state pbft_plugin::get_view_change_record(pbft_view_type view) const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - auto record = pbft_ctrl.pbft_db.get_view_changes_by_target_view(view); - if (record) return *record; - return pbft_view_change_state(); - } - - vector pbft_plugin::get_watermarks() const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - return pbft_ctrl.pbft_db.get_pbft_watermarks(); - } - - flat_map pbft_plugin::get_fork_schedules() const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - return pbft_ctrl.pbft_db.get_pbft_fork_schedules(); - } - - const char* pbft_plugin::get_pbft_status() const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - return pbft_ctrl.state_machine->get_current()->get_name(); - } - - block_id_type pbft_plugin::get_pbft_prepared_id() const { - auto& ctrl = app().get_plugin().chain(); - return ctrl.get_pbft_prepared(); - } - - block_id_type pbft_plugin::get_pbft_my_prepare_id() const { - auto& ctrl = app().get_plugin().chain(); - return ctrl.get_pbft_my_prepare(); + void pbft_plugin_impl::on_committed_transition() { + prepare_timer->expires_from_now(prepare_timeout); } - void pbft_plugin::set_pbft_current_view(pbft_view_type view) { - //this is used to boost the recovery from a disaster, do not set this unless you have to do so. - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - pbft_ctrl.state_machine->manually_set_current_view(view); + void pbft_plugin_impl::on_prepared_transition() { + commit_timer->expires_from_now(commit_timeout); } void pbft_plugin_impl::prepare_timer_tick() { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + prepare_timer->expires_from_now(prepare_timeout); prepare_timer->async_wait([&](boost::system::error_code ec) { prepare_timer_tick(); if (ec) { wlog ("pbft plugin prepare timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { + chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_prepare(); } }); } void pbft_plugin_impl::commit_timer_tick() { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + commit_timer->expires_from_now(commit_timeout); commit_timer->async_wait([&](boost::system::error_code ec) { commit_timer_tick(); if (ec) { wlog ("pbft plugin commit timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { + chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_commit(); } }); } void pbft_plugin_impl::view_change_timer_tick() { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + try { view_change_timer->cancel(); } catch (boost::system::system_error &e) { @@ -147,26 +100,28 @@ namespace eosio { if (ec) { wlog ("pbft plugin view change timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { + chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_view_change(); } }); } void pbft_plugin_impl::checkpoint_timer_tick() { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + checkpoint_timer->expires_from_now(checkpoint_timeout); checkpoint_timer->async_wait([&](boost::system::error_code ec) { checkpoint_timer_tick(); if (ec) { wlog ("pbft plugin checkpoint timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { + chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_checkpoint(); - chain::controller &ctrl = app().get_plugin().chain(); - if ( ctrl.head_block_num() - ctrl.last_stable_checkpoint_block_num() / pbft_checkpoint_granularity > 1) { - //perhaps we need to sync stable checkpoints from other peers - app().get_plugin().maybe_sync_stable_checkpoints(); - } + chain::controller &ctrl = app().get_plugin().chain(); + if ( ctrl.head_block_num() - ctrl.last_stable_checkpoint_block_num() / pbft_checkpoint_granularity > 1) { + //perhaps we need to sync stable checkpoints from other peers + app().get_plugin().maybe_sync_stable_checkpoints(); + } } }); } @@ -201,4 +156,87 @@ namespace eosio { return enabled && !is_syncing() && !is_replaying(); } + + pbft_plugin::pbft_plugin() : my(new pbft_plugin_impl()) {} + + pbft_plugin::~pbft_plugin() = default; + + void pbft_plugin::set_program_options(options_description &, options_description &cfg) { + } + + void pbft_plugin::plugin_initialize(const variables_map &options) { + ilog("Initialize pbft plugin"); + my->prepare_timer = std::make_unique(app().get_io_service()); + my->commit_timer = std::make_unique(app().get_io_service()); + my->view_change_timer = std::make_unique(app().get_io_service()); + my->checkpoint_timer = std::make_unique(app().get_io_service()); + } + + void pbft_plugin::plugin_startup() { + my->prepare_timer_tick(); + my->commit_timer_tick(); + my->view_change_timer_tick(); + my->checkpoint_timer_tick(); + + my->transit_to_prepared_subscription = my->transit_to_prepared_channel.subscribe( [this]( bool prepared ) { + my->on_prepared_transition(); + }); + + my->transit_to_committed_subscription = my->transit_to_committed_channel.subscribe( [this]( bool committed ) { + my->on_committed_transition(); + }); + } + + void pbft_plugin::plugin_shutdown() {} + + pbft_state pbft_plugin::get_pbft_record( const block_id_type& bid ) const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto record = pbft_ctrl.pbft_db.get_pbft_state_by_id(bid); + if (record) return *record; + return pbft_state(); + } + + vector pbft_plugin::get_pbft_checkpoints_record(block_num_type bnum) const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto records = pbft_ctrl.pbft_db.get_checkpoints_by_num(bnum); + if (!records.empty()) return records; + return vector(); + } + pbft_view_change_state pbft_plugin::get_view_change_record(pbft_view_type view) const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto record = pbft_ctrl.pbft_db.get_view_changes_by_target_view(view); + if (record) return *record; + return pbft_view_change_state(); + } + + vector pbft_plugin::get_watermarks() const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + return pbft_ctrl.pbft_db.get_pbft_watermarks(); + } + + flat_map pbft_plugin::get_fork_schedules() const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + return pbft_ctrl.pbft_db.get_pbft_fork_schedules(); + } + + const char* pbft_plugin::get_pbft_status() const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + return pbft_ctrl.state_machine.get_current()->get_name(); + } + + block_id_type pbft_plugin::get_pbft_prepared_id() const { + auto& ctrl = app().get_plugin().chain(); + return ctrl.get_pbft_prepared(); + } + + block_id_type pbft_plugin::get_pbft_my_prepare_id() const { + auto& ctrl = app().get_plugin().chain(); + return ctrl.get_pbft_my_prepare(); + } + + void pbft_plugin::set_pbft_current_view(pbft_view_type view) { + //this is used to boost the recovery from a disaster, do not set this unless you have to do so. + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + pbft_ctrl.state_machine.manually_set_current_view(view); + } } diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index f2d75c5a6e8..7c49b020129 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -212,10 +212,10 @@ BOOST_AUTO_TEST_CASE(view_change_validation) { for(int i = 0; i< pbft_ctrl.view_change_timeout; i++){ pbft_ctrl.maybe_pbft_view_change(); } - pbft_ctrl.state_machine->do_send_view_change(); + pbft_ctrl.state_machine.do_send_view_change(); auto new_view = pbft_ctrl.pbft_db.get_proposed_new_view_num(); auto vcc = pbft_ctrl.pbft_db.generate_view_changed_certificate(new_view); - auto nv_msg = pbft_ctrl.pbft_db.send_pbft_new_view(vcc, new_view); + auto nv_msg = pbft_ctrl.pbft_db.generate_pbft_new_view(vcc, new_view); bool nv_flag; try { @@ -302,7 +302,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.last_irreversible_block_num(), 101); //generate new view with short fork prepare certificate - pbft_new_view_generator.state_machine->set_prepares_cache(pbft_prepare()); + pbft_new_view_generator.state_machine.set_prepare_cache(pbft_prepare()); BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_send_pbft_msg(), true); ctrl_new_view_generator.reset_pbft_my_prepare(); pbft_new_view_generator.maybe_pbft_prepare(); @@ -311,10 +311,10 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o for(int i = 0; ido_send_view_change(); + pbft_new_view_generator.state_machine.do_send_view_change(); auto new_view = pbft_new_view_generator.pbft_db.get_proposed_new_view_num(); auto vcc = pbft_new_view_generator.pbft_db.generate_view_changed_certificate(new_view); - auto nv_msg = pbft_new_view_generator.pbft_db.send_pbft_new_view( + auto nv_msg = pbft_new_view_generator.pbft_db.generate_pbft_new_view( vcc, new_view); @@ -393,7 +393,7 @@ BOOST_AUTO_TEST_CASE(new_view_with_committed_cert_call_two_times_maybe_switch_fo c1.produce_blocks(6); new_view_generator.produce_blocks(10); - c1_pbft_controller.state_machine->set_prepares_cache(pbft_prepare()); + c1_pbft_controller.state_machine.set_prepare_cache(pbft_prepare()); c1_ctrl.reset_pbft_my_prepare(); c1_pbft_controller.maybe_pbft_prepare(); c1.produce_block(); @@ -410,7 +410,7 @@ BOOST_AUTO_TEST_CASE(new_view_with_committed_cert_call_two_times_maybe_switch_fo //generate new view with long fork commit certificate - pbft_new_view_generator.state_machine->set_prepares_cache(pbft_prepare()); + pbft_new_view_generator.state_machine.set_prepare_cache(pbft_prepare()); BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_send_pbft_msg(), true); ctrl_new_view_generator.reset_pbft_my_prepare(); pbft_new_view_generator.maybe_pbft_prepare(); @@ -427,10 +427,10 @@ BOOST_AUTO_TEST_CASE(new_view_with_committed_cert_call_two_times_maybe_switch_fo for(int i = 0; ido_send_view_change(); + pbft_new_view_generator.state_machine.do_send_view_change(); auto new_view = pbft_new_view_generator.pbft_db.get_proposed_new_view_num(); auto vcc = pbft_new_view_generator.pbft_db.generate_view_changed_certificate(new_view); - auto nv_msg = pbft_new_view_generator.pbft_db.send_pbft_new_view(vcc, new_view); + auto nv_msg = pbft_new_view_generator.pbft_db.generate_pbft_new_view(vcc, new_view); //can switch fork after apply prepare certificate in new view auto pmm = pbft_message_metadata(nv_msg, c1_pbft_controller.pbft_db.get_chain_id()); @@ -542,13 +542,13 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { push_blocks(c2, c1); /// make c1 lib 98 c1_pbft_controller.maybe_pbft_prepare(); - pbft_prepare c2_prepare_ = c2_pbft_controller.state_machine->get_prepares_cache(); + pbft_prepare c2_prepare_ = c2_pbft_controller.state_machine.get_prepare_cache(); BOOST_CHECK_EQUAL(c2_prepare_.block_info.block_num(), 98); - c1_pbft_controller.state_machine->on_prepare(std::make_shared>(c2_prepare_, c2_pbft_controller.pbft_db.get_chain_id())); + c1_pbft_controller.state_machine.on_prepare(std::make_shared>(c2_prepare_, c2_pbft_controller.pbft_db.get_chain_id())); c1_pbft_controller.maybe_pbft_commit(); - pbft_commit c2_commit_ = c2_pbft_controller.state_machine->get_commits_cache(); - c1_pbft_controller.state_machine->on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); + pbft_commit c2_commit_ = c2_pbft_controller.state_machine.get_commit_cache(); + c1_pbft_controller.state_machine.on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); c1.produce_block(); c1_pbft_controller.maybe_pbft_commit(); BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 98); @@ -557,13 +557,13 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { /// make c3_final lib 98 c3_final_pbft_controller.maybe_pbft_prepare(); - pbft_prepare c1_prepare_ = c1_pbft_controller.state_machine->get_prepares_cache(); + pbft_prepare c1_prepare_ = c1_pbft_controller.state_machine.get_prepare_cache(); BOOST_CHECK_EQUAL(c1_prepare_.block_info.block_num(), 99); - c3_final_pbft_controller.state_machine->on_prepare(std::make_shared>(c1_prepare_, c1_pbft_controller.pbft_db.get_chain_id())); + c3_final_pbft_controller.state_machine.on_prepare(std::make_shared>(c1_prepare_, c1_pbft_controller.pbft_db.get_chain_id())); c3_final_pbft_controller.maybe_pbft_commit(); - pbft_commit c1_commit_ = c1_pbft_controller.state_machine->get_commits_cache(); - c3_final_pbft_controller.state_machine->on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); + pbft_commit c1_commit_ = c1_pbft_controller.state_machine.get_commit_cache(); + c3_final_pbft_controller.state_machine.on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); c3_final.produce_block(); c3_final_pbft_controller.maybe_pbft_commit(); BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 98); @@ -572,35 +572,35 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { push_blocks(c2, c2_prime); pbft_prepare c1_prepare; - c1_prepare_ = c1_pbft_controller.state_machine->get_prepares_cache(); + c1_prepare_ = c1_pbft_controller.state_machine.get_prepare_cache(); c1_prepare = c1_prepare_; /// for set pbft commit cache to 99 c2.produce_block(); c2_pbft_controller.maybe_pbft_prepare(); - c2_prepare_ = c2_pbft_controller.state_machine->get_prepares_cache(); + c2_prepare_ = c2_pbft_controller.state_machine.get_prepare_cache(); BOOST_CHECK_EQUAL(c2_prepare_.block_info.block_num(), 99); c2_pbft_controller.maybe_pbft_commit(); c2.produce_block(); c2_pbft_controller.maybe_pbft_commit(); - c2_commit_ = c2_pbft_controller.state_machine->get_commits_cache(); + c2_commit_ = c2_pbft_controller.state_machine.get_commit_cache(); BOOST_CHECK_EQUAL(c2_commit_.block_info.block_num(), 99); BOOST_CHECK_EQUAL(c2.control->last_irreversible_block_num(), 99); push_blocks(c2, c1); c1_pbft_controller.maybe_pbft_prepare(); - c2_prepare_ = c2_pbft_controller.state_machine->get_prepares_cache(); - c1_pbft_controller.state_machine->on_prepare(std::make_shared>(c2_prepare_, c2_pbft_controller.pbft_db.get_chain_id())); + c2_prepare_ = c2_pbft_controller.state_machine.get_prepare_cache(); + c1_pbft_controller.state_machine.on_prepare(std::make_shared>(c2_prepare_, c2_pbft_controller.pbft_db.get_chain_id())); c1_pbft_controller.maybe_pbft_commit(); - c2_commit_ = c2_pbft_controller.state_machine->get_commits_cache(); - c1_pbft_controller.state_machine->on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); + c2_commit_ = c2_pbft_controller.state_machine.get_commit_cache(); + c1_pbft_controller.state_machine.on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); c1.produce_block(); c1_pbft_controller.maybe_pbft_commit(); - c1_prepare_ = c1_pbft_controller.state_machine->get_prepares_cache(); - c1_commit_ = c1_pbft_controller.state_machine->get_commits_cache(); + c1_prepare_ = c1_pbft_controller.state_machine.get_prepare_cache(); + c1_commit_ = c1_pbft_controller.state_machine.get_commit_cache(); BOOST_CHECK_EQUAL(c1_commit_.block_info.block_num(), 99); BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 99); @@ -612,12 +612,12 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { BOOST_CHECK_EQUAL(c1_prepare.block_info.block_num(), 99); /// set c3 my preprare at 100 c3_final_ctrl.set_pbft_my_prepare(c3_final_ctrl.get_block_id_for_num(100)); - c3_final_pbft_controller.state_machine->on_prepare(std::make_shared>(c1_prepare, c1_pbft_controller.pbft_db.get_chain_id())); + c3_final_pbft_controller.state_machine.on_prepare(std::make_shared>(c1_prepare, c1_pbft_controller.pbft_db.get_chain_id())); - pbft_prepare c3_final_prepare = c3_final_pbft_controller.state_machine->get_prepares_cache(); + pbft_prepare c3_final_prepare = c3_final_pbft_controller.state_machine.get_prepare_cache(); // check c3 prepare at 99 BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 99); - curr_state = c3_final_pbft_controller.state_machine->get_current()->get_name(); + curr_state = c3_final_pbft_controller.state_machine.get_current()->get_name(); BOOST_CHECK_EQUAL(curr_state, "{==== PREPARED ====}"); @@ -644,18 +644,18 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c3_final_pbft_controller.maybe_pbft_commit(); c3_final.produce_block(); - pbft_commit c3_final_commit = c3_final_pbft_controller.state_machine->get_commits_cache(); + pbft_commit c3_final_commit = c3_final_pbft_controller.state_machine.get_commit_cache(); /// on commit will prepare next block immediately will trigger reserve prepare - c3_final_pbft_controller.state_machine->on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); + c3_final_pbft_controller.state_machine.on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); // for sync c3_final.produce_block(); c3_final_pbft_controller.maybe_pbft_commit(); - curr_state = c3_final_pbft_controller.state_machine->get_current()->get_name(); + curr_state = c3_final_pbft_controller.state_machine.get_current()->get_name(); BOOST_CHECK_EQUAL(curr_state, "{==== COMMITTED ====}"); BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 99); c3_final_pbft_controller.maybe_pbft_prepare(); - c3_final_prepare = c3_final_pbft_controller.state_machine->get_prepares_cache(); + c3_final_prepare = c3_final_pbft_controller.state_machine.get_prepare_cache(); BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 100); } From 99d2ed758b55537f39b75c6ddfb6f343a5175dce Mon Sep 17 00:00:00 2001 From: oldcold Date: Tue, 30 Jul 2019 18:59:11 +0800 Subject: [PATCH 03/14] add global object to control pbft behavior; optimise checkpoint logic --- libraries/chain/chain_config.cpp | 4 + libraries/chain/controller.cpp | 13 ++ .../include/eosio/chain/chain_config.hpp | 9 ++ .../chain/include/eosio/chain/controller.hpp | 4 +- .../eosio/chain/global_property_object.hpp | 23 +++- libraries/chain/include/eosio/chain/pbft.hpp | 40 +++--- .../include/eosio/chain/pbft_database.hpp | 15 +- libraries/chain/include/eosio/chain/types.hpp | 1 + libraries/chain/pbft.cpp | 82 ++++------- libraries/chain/pbft_database.cpp | 130 +++++++++--------- plugins/net_plugin/net_plugin.cpp | 2 +- plugins/pbft_plugin/pbft_plugin.cpp | 30 ++-- unittests/pbft_tests.cpp | 8 +- 13 files changed, 195 insertions(+), 166 deletions(-) diff --git a/libraries/chain/chain_config.cpp b/libraries/chain/chain_config.cpp index c39d89cee46..e801736fe66 100644 --- a/libraries/chain/chain_config.cpp +++ b/libraries/chain/chain_config.cpp @@ -49,4 +49,8 @@ void chain_config2::validate() const{ EOS_ASSERT(std::numeric_limits::max() > resource_greylist.size(), action_validate_exception, "Overflow in greylistwhen adding resource greylist!"); } +void chain_config3::validate() const{ + EOS_ASSERT( view_change_timeout >= 1, action_validate_exception, "view change timeout must be at least 1"); +} + } } // namespace eosio::chain diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index da23d6e193f..75a799b74fa 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -36,6 +36,7 @@ using controller_index_set = index_set< global_property2_multi_index, dynamic_global_property_multi_index, upgrade_property_multi_index, + global_property3_multi_index, block_summary_multi_index, transaction_multi_index, generated_transaction_multi_index, @@ -455,6 +456,13 @@ struct controller_impl { wlog("no upo found, generating..."); db.create([](auto&){}); } + + try { + db.get(); + } catch( const boost::exception& e) { + wlog("no gpo3 found, generating..."); + db.create([](auto&){}); + } } ~controller_impl() { @@ -746,6 +754,7 @@ struct controller_impl { // *bos end* + db.create([](auto&) {}); authorization.initialize_database(); resource_limits.initialize_database(); @@ -2703,6 +2712,10 @@ const upgrade_property_object& controller::get_upgrade_properties()const { return my->db.get(); } +const global_property3_object& controller::get_pbft_properties()const { + return my->db.get(); +} + bool controller::is_pbft_enabled() const { return my->pbft_enabled; } diff --git a/libraries/chain/include/eosio/chain/chain_config.hpp b/libraries/chain/include/eosio/chain/chain_config.hpp index da258010fbb..283db798746 100644 --- a/libraries/chain/include/eosio/chain/chain_config.hpp +++ b/libraries/chain/include/eosio/chain/chain_config.hpp @@ -117,6 +117,13 @@ struct chain_config2 { void validate()const; }; +struct chain_config3 { + + uint16_t view_change_timeout = 6; /// the actual wait time will be `num * 5` + + void validate()const; +}; + // *bos* struct guaranteed_minimum_resources { uint64_t ram_byte; @@ -140,3 +147,5 @@ FC_REFLECT(eosio::chain::chain_config, // *bos* FC_REFLECT( eosio::chain::chain_config2, (actor_blacklist)(contract_blacklist)(resource_greylist) ) FC_REFLECT( eosio::chain::guaranteed_minimum_resources, (ram_byte)(cpu_us)(net_byte) ) + +FC_REFLECT( eosio::chain::chain_config3, (view_change_timeout) ) diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 7a90125da6e..05c5c925e59 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -31,6 +31,7 @@ namespace eosio { namespace chain { class global_property_object; class global_property2_object; // *bos* class upgrade_property_object; + class global_property3_object; // *bos* class permission_object; class account_object; using resource_limits::resource_limits_manager; @@ -305,7 +306,8 @@ namespace eosio { namespace chain { signal accepted_confirmation; signal bad_alloc; - const upgrade_property_object& get_upgrade_properties()const; + const upgrade_property_object& get_upgrade_properties()const; + const global_property3_object& get_pbft_properties()const; bool is_pbft_enabled()const; bool under_maintenance()const; void set_upo(uint32_t target_block_num); diff --git a/libraries/chain/include/eosio/chain/global_property_object.hpp b/libraries/chain/include/eosio/chain/global_property_object.hpp index 98f86939ad6..32edc5bea62 100644 --- a/libraries/chain/include/eosio/chain/global_property_object.hpp +++ b/libraries/chain/include/eosio/chain/global_property_object.hpp @@ -54,6 +54,14 @@ namespace eosio { namespace chain { block_num_type upgrade_complete_block_num = 0; }; + class global_property3_object : public chainbase::object + { + OBJECT_CTOR(global_property3_object) + + id_type id; + chain_config3 configuration; + }; + /** * @class dynamic_global_property_object @@ -108,6 +116,15 @@ namespace eosio { namespace chain { > > >; + + using global_property3_multi_index = chainbase::shared_multi_index_container< + global_property3_object, + indexed_by< + ordered_unique, + BOOST_MULTI_INDEX_MEMBER(global_property3_object, global_property3_object::id_type, id) + > + > + >; }} CHAINBASE_SET_INDEX_TYPE(eosio::chain::global_property_object, eosio::chain::global_property_multi_index) @@ -116,6 +133,7 @@ CHAINBASE_SET_INDEX_TYPE(eosio::chain::dynamic_global_property_object, // *bos* CHAINBASE_SET_INDEX_TYPE(eosio::chain::global_property2_object, eosio::chain::global_property2_multi_index) CHAINBASE_SET_INDEX_TYPE(eosio::chain::upgrade_property_object, eosio::chain::upgrade_property_multi_index) +CHAINBASE_SET_INDEX_TYPE(eosio::chain::global_property3_object, eosio::chain::global_property3_multi_index) FC_REFLECT(eosio::chain::dynamic_global_property_object, (global_action_sequence) @@ -130,4 +148,7 @@ FC_REFLECT(eosio::chain::global_property2_object, ) FC_REFLECT(eosio::chain::upgrade_property_object, (upgrade_target_block_num)(upgrade_complete_block_num) - ) \ No newline at end of file + ) +FC_REFLECT(eosio::chain::global_property3_object, + (configuration) +) \ No newline at end of file diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index a563147265c..0bfb7e8942a 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -12,12 +12,12 @@ namespace eosio { using namespace fc; struct psm_cache { - pbft_prepare prepare_cache; - pbft_commit commit_cache; - pbft_view_change view_change_cache; - pbft_prepared_certificate prepared_certificate; - vector committed_certificate; - pbft_view_changed_certificate view_changed_certificate; + pbft_prepare prepare_cache = pbft_prepare(); + pbft_commit commit_cache = pbft_commit(); + pbft_view_change view_change_cache = pbft_view_change(); + pbft_prepared_certificate prepared_certificate = pbft_prepared_certificate(); + vector committed_certificate = vector{}; + pbft_view_changed_certificate view_changed_certificate = pbft_view_changed_certificate(); }; class psm_state; @@ -43,6 +43,8 @@ namespace eosio { void send_view_change(); void send_checkpoint(); bool maybe_new_view(); + void maybe_view_change(); + bool maybe_stop_view_change(); void transit_to_committed_state(bool to_new_view); void transit_to_prepared_state(); @@ -54,13 +56,13 @@ namespace eosio { void do_send_view_change(); const pbft_prepare& get_prepare_cache() const { return cache.prepare_cache; } - void set_prepare_cache(const pbft_prepare &pcache) { cache.prepare_cache = pcache; } + void set_prepare_cache(const pbft_prepare& pcache) { cache.prepare_cache = pcache; } const pbft_commit& get_commit_cache() const { return cache.commit_cache; } - void set_commit_cache(const pbft_commit &ccache) { cache.commit_cache = ccache; } + void set_commit_cache(const pbft_commit& ccache) { cache.commit_cache = ccache; } const pbft_view_change& get_view_change_cache() const { return cache.view_change_cache; } - void set_view_change_cache(const pbft_view_change &vc_cache) { cache.view_change_cache = vc_cache; } + void set_view_change_cache(const pbft_view_change& vc_cache) { cache.view_change_cache = vc_cache; } uint32_t get_current_view() const { return current_view; } void set_current_view(uint32_t cv) { current_view = cv; } @@ -94,14 +96,14 @@ namespace eosio { signal pbft_transit_to_prepared; template - void emit(const Signal &s, Arg &&a); + void emit(const Signal& s, Arg&& a); protected: psm_cache cache; - uint32_t current_view; - uint32_t target_view_retries; - uint32_t target_view; - uint32_t view_change_timer; + uint32_t current_view = 0; + uint32_t target_view_retries = 0; + uint32_t target_view = current_view + 1; + uint32_t view_change_timer = 0; private: psm_state_ptr current = nullptr; @@ -128,8 +130,8 @@ namespace eosio { std::shared_ptr get_self() { return shared_from_this(); }; protected: - psm_machine& m; - pbft_database& pbft_db; + psm_machine& m; + pbft_database& pbft_db; }; class psm_prepared_state final: public psm_state { @@ -190,10 +192,8 @@ namespace eosio { explicit pbft_controller(controller& ctrl); ~pbft_controller(); - const uint16_t view_change_timeout = 6; - - pbft_database pbft_db; - psm_machine state_machine; + pbft_database pbft_db; + psm_machine state_machine; void maybe_pbft_prepare(); void maybe_pbft_commit(); diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 8a935829d9a..0d8bf6d3aa8 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -429,19 +429,19 @@ namespace eosio { void add_pbft_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk); vector generate_and_add_pbft_prepare( - const pbft_prepare &cached_prepare = pbft_prepare(), + const pbft_prepare& cached_prepare = pbft_prepare(), pbft_view_type current_view = 0); vector generate_and_add_pbft_commit( - const pbft_commit &cached_commit = pbft_commit(), + const pbft_commit& cached_commit = pbft_commit(), pbft_view_type current_view = 0); vector generate_and_add_pbft_view_change( - const pbft_view_change &cached_view_change = pbft_view_change(), - const pbft_prepared_certificate &ppc = pbft_prepared_certificate(), - const vector &pcc = vector{}, + const pbft_view_change& cached_view_change = pbft_view_change(), + const pbft_prepared_certificate& ppc = pbft_prepared_certificate(), + const vector& pcc = vector{}, pbft_view_type current_view = 0, pbft_view_type target_view = 1); pbft_new_view generate_pbft_new_view( - const pbft_view_changed_certificate &vcc = pbft_view_changed_certificate(), + const pbft_view_changed_certificate& vcc = pbft_view_changed_certificate(), pbft_view_type current_view = 1); vector generate_and_add_pbft_checkpoint(); @@ -484,6 +484,7 @@ namespace eosio { void cleanup_on_new_view(); void update_fork_schedules(); + uint16_t get_view_change_timeout() const; //api related pbft_state_ptr get_pbft_state_by_id(const block_id_type& id) const; @@ -507,7 +508,7 @@ namespace eosio { bool is_less_than_high_watermark(block_num_type bnum); bool is_valid_prepared_certificate(const pbft_prepared_certificate& certificate, bool add_to_pbft_db = false); bool is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db = false); - bool is_valid_longest_fork(const block_info_type& bi, fork_info_type block_infos, unsigned long threshold, unsigned long non_fork_bp_count); + bool is_valid_longest_fork(const block_info_type& bi, fork_info_type& block_infos, unsigned long threshold, unsigned long non_fork_bp_count); producer_schedule_type lscb_active_producers() const; vector& get_updated_watermarks(); diff --git a/libraries/chain/include/eosio/chain/types.hpp b/libraries/chain/include/eosio/chain/types.hpp index f8360c0bc7d..4cf8b055cd2 100644 --- a/libraries/chain/include/eosio/chain/types.hpp +++ b/libraries/chain/include/eosio/chain/types.hpp @@ -190,6 +190,7 @@ namespace eosio { namespace chain { action_history_object_type, ///< Defined by history_plugin reversible_block_object_type, upgrade_property_object_type, + global_property3_object_type, OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types }; diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 4739bded9ad..0fdf3adf43a 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -51,7 +51,7 @@ namespace eosio { void pbft_controller::maybe_pbft_view_change() { if (!pbft_db.should_send_pbft_msg()) return; - if (state_machine.get_view_change_timer() <= view_change_timeout) { + if (state_machine.get_view_change_timer() <= pbft_db.get_view_change_timeout()) { if (!state_machine.get_view_change_cache().empty()) { pbft_db.generate_and_add_pbft_view_change(state_machine.get_view_change_cache()); } @@ -93,20 +93,7 @@ namespace eosio { psm_state::psm_state(psm_machine& m, pbft_database& pbft_db) : m(m), pbft_db(pbft_db){} psm_state::~psm_state() = default; - psm_machine::psm_machine(pbft_database& pbft_db) : pbft_db(pbft_db) { - set_prepare_cache(pbft_prepare()); - set_commit_cache(pbft_commit()); - set_view_change_cache(pbft_view_change()); - - set_prepared_certificate(pbft_prepared_certificate{}); - set_committed_certificate(vector{}); - set_view_changed_certificate(pbft_view_changed_certificate{}); - - view_change_timer = 0; - target_view_retries = 0; - current_view = 0; - target_view = current_view + 1; - } + psm_machine::psm_machine(pbft_database& pbft_db) : pbft_db(pbft_db) {} psm_machine::~psm_machine() = default; @@ -157,7 +144,8 @@ namespace eosio { transit_to_view_change_state(); } - /** + /**\ + * * psm_prepared_state */ @@ -176,8 +164,6 @@ namespace eosio { } if (pending_commit_local && !pbft_db.pending_pbft_lib()) { - m.send_checkpoint(); - pbft_db.checkpoint_local(); m.transit_to_committed_state(false); } } @@ -189,7 +175,6 @@ namespace eosio { void psm_prepared_state::send_prepare() { //retry if (m.get_prepare_cache().empty()) return; - m.do_send_prepare(); } @@ -199,14 +184,12 @@ namespace eosio { if (!pbft_db.is_valid_commit(e->msg, e->sender_key)) return; pbft_db.add_pbft_commit(e->msg, e->sender_key); - maybe_transit_to_committed(); } void psm_prepared_state::send_commit() { m.do_send_commit(); - maybe_transit_to_committed(); } @@ -216,13 +199,7 @@ namespace eosio { if (!pbft_db.is_valid_view_change(e->msg, e->sender_key)) return; pbft_db.add_pbft_view_change(e->msg, e->sender_key); - - //if received >= f+1 view_change on some view, transit to view_change and send view change - auto target_view = pbft_db.should_view_change(); - if (target_view > 0 && target_view > m.get_current_view()) { - m.set_target_view(target_view); - m.transit_to_view_change_state(); - } + m.maybe_view_change(); } void psm_prepared_state::send_view_change() { @@ -243,7 +220,6 @@ namespace eosio { //do action add prepare pbft_db.add_pbft_prepare(e->msg, e->sender_key); - //if prepare >= 2f+1, transit to prepared if (pbft_db.should_prepared()) m.transit_to_prepared_state(); } @@ -251,7 +227,6 @@ namespace eosio { void psm_committed_state::send_prepare() { m.do_send_prepare(); - //if prepare >= 2f+1, transit to prepared if (pbft_db.should_prepared()) m.transit_to_prepared_state(); } @@ -267,9 +242,7 @@ namespace eosio { void psm_committed_state::send_commit() { if (m.get_commit_cache().empty()) return; - m.do_send_commit(); - } void psm_committed_state::on_view_change(const pbft_metadata_ptr& e) { @@ -278,13 +251,7 @@ namespace eosio { if (!pbft_db.is_valid_view_change(e->msg, e->sender_key)) return; pbft_db.add_pbft_view_change(e->msg, e->sender_key); - - //if received >= f+1 view_change on some view, transit to view_change and send view change - auto new_view = pbft_db.should_view_change(); - if (new_view > 0 && new_view > m.get_current_view()) { - m.set_target_view(new_view); - m.transit_to_view_change_state(); - } + m.maybe_view_change(); } void psm_committed_state::send_view_change() { @@ -314,32 +281,20 @@ namespace eosio { void psm_view_change_state::on_view_change(const pbft_metadata_ptr& e) { - //skip from view change state if my lib is higher than my view change state height. - auto vc = m.get_view_change_cache(); - if (!vc.empty() && pbft_db.should_stop_view_change(vc)) { - m.transit_to_committed_state(false); - return; - } + if (m.maybe_stop_view_change()) return; if (e->msg.target_view <= m.get_current_view()) return; if (!pbft_db.is_valid_view_change(e->msg, e->sender_key)) return; pbft_db.add_pbft_view_change(e->msg, e->sender_key); - m.maybe_new_view(); } void psm_view_change_state::send_view_change() { - //skip from view change state if my lib is higher than my view change state height. - auto vc = m.get_view_change_cache(); - if (!vc.empty() && pbft_db.should_stop_view_change(vc)) { - m.transit_to_committed_state(false); - return; - } + if (m.maybe_stop_view_change()) return; m.do_send_view_change(); - m.maybe_new_view(); } @@ -388,6 +343,25 @@ namespace eosio { } } + void psm_machine::maybe_view_change() { + //if received >= f+1 view_change on some view, transit to view_change and send view change + auto new_view = pbft_db.should_view_change(); + if (new_view > 0 && new_view > get_current_view()) { + set_target_view(new_view); + transit_to_view_change_state(); + } + } + + bool psm_machine::maybe_stop_view_change() { + //skip from view change state if my lib is higher than my view change state height. + auto vc = get_view_change_cache(); + if (!vc.empty() && pbft_db.should_stop_view_change(vc)) { + transit_to_committed_state(false); + return true; + } + return false; + } + bool psm_machine::maybe_new_view() { //if view_change >= 2f+1, calculate next primary, send new view if is primary auto nv = get_target_view(); @@ -514,7 +488,7 @@ namespace eosio { } template - void psm_machine::emit(const Signal &s, Arg &&a) { + void psm_machine::emit(const Signal& s, Arg&& a) { try { s(std::forward(a)); } catch (boost::interprocess::bad_alloc &e) { diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 22c2ab188ac..d0b60d88f35 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -94,7 +94,7 @@ namespace eosio { void pbft_database::add_pbft_prepare(const pbft_prepare& p, const public_key_type& pk) { - auto &by_block_id_index = pbft_state_index.get(); + auto& by_block_id_index = pbft_state_index.get(); auto current = ctrl.fetch_block_state_by_id(p.block_info.block_id); @@ -120,6 +120,8 @@ namespace eosio { by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr& psp) { psp->prepares[std::make_pair(p.view, pk)] = p; }); + } else { + return; } } curr_itr = by_block_id_index.find(current->id); @@ -151,7 +153,7 @@ namespace eosio { } void pbft_database::mark_as_prepared(const block_id_type& bid) { - auto &by_block_id_index = pbft_state_index.get(); + auto& by_block_id_index = pbft_state_index.get(); auto itr = by_block_id_index.find(bid); auto bnum = block_info_type{bid}.block_num(); @@ -167,7 +169,7 @@ namespace eosio { by_block_id_index.modify(itr, [&](const pbft_state_ptr& p) { p->is_prepared = true; }); } - vector pbft_database::generate_and_add_pbft_prepare(const pbft_prepare &cached_prepare, + vector pbft_database::generate_and_add_pbft_prepare(const pbft_prepare& cached_prepare, pbft_view_type current_view) { vector prepares_to_be_cached; const auto& my_sps = ctrl.my_signature_providers(); @@ -258,7 +260,7 @@ namespace eosio { void pbft_database::add_pbft_commit(const pbft_commit& c, const public_key_type& pk) { - auto &by_block_id_index = pbft_state_index.get(); + auto& by_block_id_index = pbft_state_index.get(); auto current = ctrl.fetch_block_state_by_id(c.block_info.block_id); @@ -286,6 +288,8 @@ namespace eosio { psp->commits[std::make_pair(c.view, pk)] = c; std::sort(psp->commits.begin(), psp->commits.end(), less<>()); }); + } else { + return; } } @@ -319,7 +323,7 @@ namespace eosio { } } - vector pbft_database::generate_and_add_pbft_commit(const pbft_commit &cached_commit, + vector pbft_database::generate_and_add_pbft_commit(const pbft_commit& cached_commit, pbft_view_type current_view) { vector commits_to_be_cached; const auto& my_sps = ctrl.my_signature_providers(); @@ -361,7 +365,7 @@ namespace eosio { } void pbft_database::mark_as_committed(const block_id_type& bid) { - auto &by_block_id_index = pbft_state_index.get(); + auto& by_block_id_index = pbft_state_index.get(); auto itr = by_block_id_index.find(bid); if (itr == by_block_id_index.end()) return; by_block_id_index.modify(itr, [&](const pbft_state_ptr& p) { p->is_committed = true; }); @@ -434,7 +438,7 @@ namespace eosio { auto lscb_bps = lscb_active_producers().producers; - auto &by_view_index = view_state_index.get(); + auto& by_view_index = view_state_index.get(); auto itr = by_view_index.find(vc.target_view); if (itr == by_view_index.end()) { flat_map view_changes; @@ -452,6 +456,8 @@ namespace eosio { by_view_index.modify(itr, [&](const pbft_view_change_state_ptr& pvsp) { pvsp->view_changes[pk] = vc; }); + } else { + return; } } @@ -476,7 +482,7 @@ namespace eosio { pbft_view_type pbft_database::should_view_change() { pbft_view_type nv = 0; - auto &by_view_index = view_state_index.get(); + auto& by_view_index = view_state_index.get(); auto itr = by_view_index.begin(); if (itr == by_view_index.end()) return nv; @@ -501,9 +507,9 @@ namespace eosio { } vector pbft_database::generate_and_add_pbft_view_change( - const pbft_view_change &cached_view_change, - const pbft_prepared_certificate &ppc, - const vector &pcc, + const pbft_view_change& cached_view_change, + const pbft_prepared_certificate& ppc, + const vector& pcc, pbft_view_type current_view, pbft_view_type target_view) { @@ -540,14 +546,14 @@ namespace eosio { } bool pbft_database::should_new_view(pbft_view_type target_view) { - auto &by_view_index = view_state_index.get(); + auto& by_view_index = view_state_index.get(); auto itr = by_view_index.find(target_view); if (itr == by_view_index.end()) return false; return (*itr)->is_view_changed; } pbft_view_type pbft_database::get_proposed_new_view_num() { - auto &by_count_and_view_index = view_state_index.get(); + auto& by_count_and_view_index = view_state_index.get(); auto itr = by_count_and_view_index.begin(); if (itr == by_count_and_view_index.end() || !(*itr)->is_view_changed) return 0; return (*itr)->view; @@ -567,7 +573,7 @@ namespace eosio { } pbft_new_view pbft_database::generate_pbft_new_view( - const pbft_view_changed_certificate &vcc, + const pbft_view_changed_certificate& vcc, pbft_view_type current_view) { pbft_new_view nv; @@ -753,7 +759,7 @@ namespace eosio { pbft_view_changed_certificate pvcc; - auto &by_view_index = view_state_index.get(); + auto& by_view_index = view_state_index.get(); auto itr = by_view_index.find(target_view); if (itr == by_view_index.end()) return pvcc; @@ -762,7 +768,7 @@ namespace eosio { if (pvs->is_view_changed) { pvcc.target_view=pvs->view; pvcc.view_changes.reserve(pvs->view_changes.size()); - for(auto & view_change : pvs->view_changes) { + for(auto& view_change : pvs->view_changes) { pvcc.view_changes.emplace_back( view_change.second ); } } @@ -781,7 +787,7 @@ namespace eosio { auto prepares_metadata = vector>{}; prepares_metadata.reserve(prepares.size()); - for (auto &p : prepares) { + for (auto& p : prepares) { auto pmm = pbft_message_metadata(p, chain_id); prepares_metadata.emplace_back(pmm); if (!is_valid_prepare(p, pmm.sender_key)) return false; @@ -844,7 +850,7 @@ namespace eosio { auto commits_metadata = vector>{}; commits_metadata.reserve(commits.size()); - for (auto &c : commits) { + for (auto& c : commits) { auto pmm = pbft_message_metadata(c, chain_id); commits_metadata.emplace_back(pmm); if (!is_valid_commit(c, pmm.sender_key)) return false; @@ -936,7 +942,7 @@ namespace eosio { vector view_change_producers; view_change_producers.reserve(view_changes.size()); - for (auto &vc: view_changes) { + for (auto& vc : view_changes) { auto pmm = pbft_message_metadata(vc, chain_id); view_changes_metadata.emplace_back(pmm); if (is_valid_view_change(vc, pmm.sender_key)) { @@ -971,7 +977,7 @@ namespace eosio { for (const auto& cc: vc.committed_certs) { if (is_valid_committed_certificate(cc)) { auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), - [&](const pbft_committed_certificate &ext) { + [&](const pbft_committed_certificate& ext) { return ext.block_info.block_id == cc.block_info.block_id; }); if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); @@ -1074,7 +1080,7 @@ namespace eosio { bool pbft_database::is_valid_longest_fork( const block_info_type& bi, - fork_info_type block_infos, + fork_info_type& block_infos, unsigned long threshold, unsigned long non_fork_bp_count) { @@ -1095,7 +1101,7 @@ namespace eosio { pbft_stable_checkpoint psc; try { if (b) { - auto &extn = b->block_extensions; + auto& extn = b->block_extensions; for (auto it = extn.begin(); it != extn.end();) { if (it->first == static_cast(block_extension_type::pbft_stable_checkpoint)) { @@ -1137,7 +1143,7 @@ namespace eosio { if (cpp->is_stable) { psc.block_info={cpp->block_id}; psc.checkpoints.reserve(cpp->checkpoints.size()); - for (auto & checkpoint : cpp->checkpoints) { + for (auto& checkpoint : cpp->checkpoints) { psc.checkpoints.emplace_back(checkpoint.second) ; } @@ -1207,59 +1213,44 @@ namespace eosio { }; vector new_pc{}; + auto my_sps = ctrl.my_signature_providers(); const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end() || !(*itr)->is_committed) return new_pc; pbft_state_ptr psp = (*itr); - - flat_map pending_checkpoint_block_num; // block_height and retry_flag auto lscb_num = ctrl.last_stable_checkpoint_block_num(); + + vector pending_checkpoint_block_num; + pending_checkpoint_block_num.reserve(psp->block_num - lscb_num); for (auto i = psp->block_num; i > lscb_num && i > 1; --i) { if (checkpoint(i)) { - auto &by_block = checkpoint_index.get(); - - if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(i)) { - auto c_itr = by_block.find(bs->id); - if (c_itr == by_block.end()) { - pending_checkpoint_block_num[i] = false; - } else { - auto checkpoints = (*c_itr)->checkpoints; - for (const auto& my_sp : ctrl.my_signature_providers()) { - if (checkpoints.find(my_sp.first) != checkpoints.end() && !(*c_itr)->is_stable) { - pending_checkpoint_block_num[i] = true; //retry sending at this time. - } - } - if (pending_checkpoint_block_num.find(i) == pending_checkpoint_block_num.end()) { - pending_checkpoint_block_num[i] = false; - } - } - } + pending_checkpoint_block_num.emplace_back(i); } } - auto &by_block = checkpoint_index.get(); + auto& by_block = checkpoint_index.get(); if (!pending_checkpoint_block_num.empty()) { std::sort(pending_checkpoint_block_num.begin(), pending_checkpoint_block_num.end()); - for (auto& bnum_and_retry: pending_checkpoint_block_num) { - if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(bnum_and_retry.first)) { - for (const auto& my_sp : ctrl.my_signature_providers()) { + for (auto bnum: pending_checkpoint_block_num) { + if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(bnum)) { + for (const auto& sp : my_sps) { pbft_checkpoint cp; cp.block_info = {bs->id}; - cp.sender_signature = my_sp.second(cp.digest(chain_id)); - if (!bnum_and_retry.second && is_valid_checkpoint(cp, my_sp.first)) { //first time sending this checkpoint - add_pbft_checkpoint(cp, my_sp.first); + cp.sender_signature = sp.second(cp.digest(chain_id)); + if (is_valid_checkpoint(cp, sp.first)) { + add_pbft_checkpoint(cp, sp.first); } new_pc.emplace_back(cp); } } } } else if (lscb_num > 0) { //retry sending my lscb - for (const auto& my_sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { pbft_checkpoint cp; cp.block_info={ctrl.last_stable_checkpoint_block_id()}; - cp.sender_signature = my_sp.second(cp.digest(chain_id)); + cp.sender_signature = sp.second(cp.digest(chain_id)); new_pc.emplace_back(cp); } } @@ -1271,7 +1262,7 @@ namespace eosio { auto cp_block_state = ctrl.fetch_block_state_by_id(cp.block_info.block_id); if (!cp_block_state) return; - auto &by_block = checkpoint_index.get(); + auto& by_block = checkpoint_index.get(); auto itr = by_block.find(cp.block_info.block_id); if (itr == by_block.end()) { flat_map checkpoints; @@ -1290,6 +1281,8 @@ namespace eosio { by_block.modify(itr, [&](const pbft_checkpoint_state_ptr& pcp) { csp->checkpoints[pk] = cp; }); + } else { + return; } } @@ -1318,7 +1311,7 @@ namespace eosio { fc::raw::pack( ds, scp ); blk->block_extensions.emplace_back(); - auto &extension = blk->block_extensions.back(); + auto& extension = blk->block_extensions.back(); extension.first = static_cast(block_extension_type::pbft_stable_checkpoint ); extension.second.resize(scp_size); std::copy(buffer->begin(),buffer->end(), extension.second.data()); @@ -1332,22 +1325,22 @@ namespace eosio { auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto pending_num = pending_scb_info.block_num(); auto pending_id = pending_scb_info.block_id; - //TODO: optimise prune logic if (pending_num > lscb_num) { ctrl.set_pbft_latest_checkpoint(pending_id); if (ctrl.last_irreversible_block_num() < pending_num) ctrl.pbft_commit_local(pending_id); - auto &by_block_id_index = pbft_state_index.get(); + auto& by_block_id_index = pbft_state_index.get(); auto pitr = by_block_id_index.find(pending_id); if (pitr != by_block_id_index.end()) { prune(*pitr); } } - auto &bni = checkpoint_index.get(); + auto& bni = checkpoint_index.get(); auto oldest = bni.begin(); - if ( oldest != bni.end() + while ( oldest != bni.end() && (*oldest)->is_stable && (*oldest)->block_num < lscb_num - oldest_stable_checkpoint ) { prune(*oldest); + oldest = bni.begin(); } } @@ -1374,7 +1367,7 @@ namespace eosio { auto checkpoints_metadata = vector>{}; checkpoints_metadata.reserve(checkpoints.size()); - for (auto &cp : checkpoints) { + for (auto& cp : checkpoints) { auto pmm = pbft_message_metadata(cp, chain_id); checkpoints_metadata.emplace_back(pmm); if (cp.block_info != scp.block_info || !is_valid_checkpoint(cp, pmm.sender_key)) return false; @@ -1481,7 +1474,7 @@ namespace eosio { for (auto i: added) { if (auto bs = ctrl.fetch_block_state_by_number(i)) { auto as = bs->active_schedule.producers; - for (auto &bp: as) { + for (const auto& bp: as) { auto key = bp.block_signing_key; if (fork_schedules.find(key) == fork_schedules.end()) { fork_schedules[key] = i; @@ -1505,7 +1498,7 @@ namespace eosio { auto lscb_bps = lscb_active_producers().producers; auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - for (auto &bp: lscb_bps) { + for (const auto& bp: lscb_bps) { if (fork_schedules.find(bp.block_signing_key) == fork_schedules.end() || fork_schedules[bp.block_signing_key] < lscb_num) { fork_schedules[bp.block_signing_key] = lscb_num; @@ -1523,6 +1516,11 @@ namespace eosio { return fork_schedules; } + uint16_t pbft_database::get_view_change_timeout() const { + return ctrl.get_pbft_properties().configuration.view_change_timeout; + } + + bool pbft_database::is_less_than_high_watermark(block_num_type bnum) { auto current_watermark = get_current_pbft_watermark(); return current_watermark == 0 || bnum <= current_watermark; @@ -1530,7 +1528,7 @@ namespace eosio { pbft_state_ptr pbft_database::get_pbft_state_by_id(const block_id_type& id) const { - auto &by_block_id_index = pbft_state_index.get(); + auto& by_block_id_index = pbft_state_index.get(); auto itr = by_block_id_index.find(id); if (itr != by_block_id_index.end()) return (*itr); @@ -1540,7 +1538,7 @@ namespace eosio { vector pbft_database::get_checkpoints_by_num(block_num_type num) const { auto results = vector{}; - auto &by_num_index = checkpoint_index.get(); + auto& by_num_index = checkpoint_index.get(); auto pitr = by_num_index.lower_bound( num ); while(pitr != by_num_index.end() && (*pitr)->block_num == num ) { @@ -1552,7 +1550,7 @@ namespace eosio { } pbft_view_change_state_ptr pbft_database::get_view_changes_by_target_view(pbft_view_type tv) const { - auto &by_view_index = view_state_index.get(); + auto& by_view_index = view_state_index.get(); auto itr = by_view_index.find(tv); if (itr != by_view_index.end()) return (*itr); @@ -1583,7 +1581,7 @@ namespace eosio { void pbft_database::prune(const pbft_state_ptr& h) { auto num = h->block_num; - auto &by_bn = pbft_state_index.get(); + auto& by_bn = pbft_state_index.get(); auto bni = by_bn.begin(); while (bni != by_bn.end() && (*bni)->block_num < num) { prune(*bni); @@ -1599,7 +1597,7 @@ namespace eosio { void pbft_database::prune(const pbft_checkpoint_state_ptr& h) { auto num = h->block_num; - auto &by_bn = checkpoint_index.get(); + auto& by_bn = checkpoint_index.get(); auto bni = by_bn.begin(); while (bni != by_bn.end() && (*bni)->block_num < num) { prune(*bni); diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index f9e611ad229..43f7336074e 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -3175,7 +3175,7 @@ namespace eosio { void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_checkpoint &msg) { if (is_pbft_msg_valid(msg) && maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { - auto pmm = pbft_message_metadata(std::move(msg), chain_id); + auto pmm = pbft_message_metadata(msg, chain_id); pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_checkpoint(pmm.msg, pmm.sender_key)) return; diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index 674a4ead103..8acf2b49a19 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -28,16 +28,18 @@ namespace eosio { boost::asio::steady_timer::duration prepare_timeout{std::chrono::milliseconds{1000}}; boost::asio::steady_timer::duration commit_timeout{std::chrono::milliseconds{1000}}; boost::asio::steady_timer::duration view_change_check_interval{std::chrono::seconds{5}}; - boost::asio::steady_timer::duration checkpoint_timeout{std::chrono::seconds{50}}; + boost::asio::steady_timer::duration checkpoint_timeout{std::chrono::seconds{25}}; void prepare_timer_tick(); void commit_timer_tick(); void view_change_timer_tick(); void checkpoint_timer_tick(); + fc::optional pbft_transit_to_committed_connection; pbft::committed_transition_channel::channel_type::handle transit_to_committed_subscription; pbft::committed_transition_channel::channel_type& transit_to_committed_channel; + fc::optional pbft_transit_to_prepared_connection; pbft::prepared_transition_channel::channel_type::handle transit_to_prepared_subscription; pbft::prepared_transition_channel::channel_type& transit_to_prepared_channel; @@ -52,24 +54,26 @@ namespace eosio { }; void pbft_plugin_impl::on_committed_transition() { - prepare_timer->expires_from_now(prepare_timeout); + prepare_timer_tick(); } void pbft_plugin_impl::on_prepared_transition() { - commit_timer->expires_from_now(commit_timeout); + commit_timer_tick(); } void pbft_plugin_impl::prepare_timer_tick() { prepare_timer->expires_from_now(prepare_timeout); prepare_timer->async_wait([&](boost::system::error_code ec) { - prepare_timer_tick(); - if (ec) { + if ( ec == boost::asio::error::operation_aborted ) { + return; + } else if (ec) { wlog ("pbft plugin prepare timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_prepare(); } + prepare_timer_tick(); }); } @@ -77,13 +81,15 @@ namespace eosio { commit_timer->expires_from_now(commit_timeout); commit_timer->async_wait([&](boost::system::error_code ec) { - commit_timer_tick(); - if (ec) { + if ( ec == boost::asio::error::operation_aborted ) { + return; + } else if (ec) { wlog ("pbft plugin commit timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_commit(); } + commit_timer_tick(); }); } @@ -110,8 +116,9 @@ namespace eosio { checkpoint_timer->expires_from_now(checkpoint_timeout); checkpoint_timer->async_wait([&](boost::system::error_code ec) { - checkpoint_timer_tick(); - if (ec) { + if ( ec == boost::asio::error::operation_aborted ) { + return; + } if (ec) { wlog ("pbft plugin checkpoint timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); @@ -123,6 +130,7 @@ namespace eosio { app().get_plugin().maybe_sync_stable_checkpoints(); } } + checkpoint_timer_tick(); }); } @@ -178,11 +186,11 @@ namespace eosio { my->view_change_timer_tick(); my->checkpoint_timer_tick(); - my->transit_to_prepared_subscription = my->transit_to_prepared_channel.subscribe( [this]( bool prepared ) { + my->pbft_transit_to_prepared_connection = app().get_plugin().pbft_ctrl().state_machine.pbft_transit_to_prepared.connect( [this]( bool prepared ) { my->on_prepared_transition(); }); - my->transit_to_committed_subscription = my->transit_to_committed_channel.subscribe( [this]( bool committed ) { + my->pbft_transit_to_committed_connection = app().get_plugin().pbft_ctrl().state_machine.pbft_transit_to_committed.connect( [this]( bool committed ) { my->on_committed_transition(); }); } diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index 7c49b020129..40856b24268 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -209,7 +209,7 @@ BOOST_AUTO_TEST_CASE(view_change_validation) { BOOST_CHECK_EQUAL(ctrl.head_block_num(), 102); - for(int i = 0; i< pbft_ctrl.view_change_timeout; i++){ + for(int i = 0; i< pbft_ctrl.pbft_db.get_view_change_timeout(); i++){ pbft_ctrl.maybe_pbft_view_change(); } pbft_ctrl.state_machine.do_send_view_change(); @@ -308,7 +308,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o pbft_new_view_generator.maybe_pbft_prepare(); BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_prepared(), true); BOOST_CHECK_EQUAL(ctrl_new_view_generator.head_block_num(), 136); - for(int i = 0; i(nv_msg, c1_pbft_controller.pbft_db.get_chain_id()); - /// boscore issue https://github.com/boscore/bos/issues/114. - /// It will never throw exception block_validate_exception, "next block must be in the future" in the version 20e08dba c1_pbft_controller.on_pbft_new_view(std::make_shared>(pmm)); c1_pbft_controller.maybe_pbft_commit(); c1.produce_blocks(2); From 239f48451f47cddf093b9231a207560ac125f26e Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 31 Jul 2019 15:50:22 +0800 Subject: [PATCH 04/14] refactor pbft db persistence --- libraries/chain/chain_config.cpp | 1 + .../include/eosio/chain/chain_config.hpp | 1 + .../include/eosio/chain/pbft_database.hpp | 14 +++-- libraries/chain/pbft.cpp | 45 +++++----------- libraries/chain/pbft_database.cpp | 51 +++++++++++-------- libraries/chain/wasm_interface.cpp | 11 ++++ plugins/net_plugin/net_plugin.cpp | 13 +++-- unittests/pbft_tests.cpp | 2 +- 8 files changed, 72 insertions(+), 66 deletions(-) diff --git a/libraries/chain/chain_config.cpp b/libraries/chain/chain_config.cpp index e801736fe66..7b4b1fca60c 100644 --- a/libraries/chain/chain_config.cpp +++ b/libraries/chain/chain_config.cpp @@ -51,6 +51,7 @@ void chain_config2::validate() const{ void chain_config3::validate() const{ EOS_ASSERT( view_change_timeout >= 1, action_validate_exception, "view change timeout must be at least 1"); + EOS_ASSERT( pbft_checkpoint_granularity >= 100 && pbft_checkpoint_granularity % 100 == 0, action_validate_exception, "pbft checkpoint granularity must be multiple of 100 blocks"); } } } // namespace eosio::chain diff --git a/libraries/chain/include/eosio/chain/chain_config.hpp b/libraries/chain/include/eosio/chain/chain_config.hpp index 283db798746..d2e9d5c0184 100644 --- a/libraries/chain/include/eosio/chain/chain_config.hpp +++ b/libraries/chain/include/eosio/chain/chain_config.hpp @@ -120,6 +120,7 @@ struct chain_config2 { struct chain_config3 { uint16_t view_change_timeout = 6; /// the actual wait time will be `num * 5` + uint16_t pbft_checkpoint_granularity = 100; /// the interval of normal checkpoints must be a multiple of 100 * n; void validate()const; }; diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 0d8bf6d3aa8..0ba096427ef 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -428,21 +428,16 @@ namespace eosio { void add_pbft_view_change(const pbft_view_change& vc, const public_key_type& pk); void add_pbft_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk); - vector generate_and_add_pbft_prepare( - const pbft_prepare& cached_prepare = pbft_prepare(), - pbft_view_type current_view = 0); - vector generate_and_add_pbft_commit( - const pbft_commit& cached_commit = pbft_commit(), - pbft_view_type current_view = 0); + vector generate_and_add_pbft_prepare(const pbft_prepare& cached_prepare = pbft_prepare()); + vector generate_and_add_pbft_commit(const pbft_commit& cached_commit = pbft_commit()); vector generate_and_add_pbft_view_change( const pbft_view_change& cached_view_change = pbft_view_change(), const pbft_prepared_certificate& ppc = pbft_prepared_certificate(), const vector& pcc = vector{}, - pbft_view_type current_view = 0, pbft_view_type target_view = 1); pbft_new_view generate_pbft_new_view( const pbft_view_changed_certificate& vcc = pbft_view_changed_certificate(), - pbft_view_type current_view = 1); + pbft_view_type new_view = 1); vector generate_and_add_pbft_checkpoint(); bool should_prepared(); @@ -485,6 +480,8 @@ namespace eosio { void cleanup_on_new_view(); void update_fork_schedules(); uint16_t get_view_change_timeout() const; + const pbft_view_type get_current_view() { return _current_view; } + void set_current_view(pbft_view_type view) { _current_view = view; } //api related pbft_state_ptr get_pbft_state_by_id(const block_id_type& id) const; @@ -503,6 +500,7 @@ namespace eosio { vector prepare_watermarks; flat_map fork_schedules; chain_id_type chain_id = ctrl.get_chain_id(); + pbft_view_type _current_view; block_info_type cal_pending_stable_checkpoint() const; bool is_less_than_high_watermark(block_num_type bnum); diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 0fdf3adf43a..30f9ab80df9 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -9,35 +9,12 @@ namespace eosio { pbft_db(ctrl), state_machine(pbft_db) { state_machine.set_current(std::make_shared(state_machine, pbft_db)); - datadir = ctrl.state_dir(); - - if (!fc::is_directory(datadir)) - fc::create_directories(datadir); - - auto pbft_db_dat = datadir / config::pbftdb_filename; - if (fc::exists(pbft_db_dat)) { - string content; - fc::read_file_contents(pbft_db_dat, content); - - fc::datastream ds(content.data(), content.size()); - uint32_t current_view; - fc::raw::unpack(ds, current_view); - state_machine.set_current_view(current_view); - state_machine.set_target_view(state_machine.get_current_view() + 1); - ilog("current view: ${cv}", ("cv", current_view)); - } - - fc::remove(pbft_db_dat); + state_machine.set_current_view(pbft_db.get_current_view()); + state_machine.set_target_view(state_machine.get_current_view() + 1); + ilog("current view: ${cv}", ("cv", pbft_db.get_current_view())); } - pbft_controller::~pbft_controller() { - fc::path pbft_db_dat = datadir / config::pbftdb_filename; - std::ofstream out(pbft_db_dat.generic_string().c_str(), - std::ios::out | std::ios::binary | std::ofstream::trunc); - - uint32_t current_view = state_machine.get_current_view(); - fc::raw::pack(out, current_view); - } + pbft_controller::~pbft_controller() = default; void pbft_controller::maybe_pbft_prepare() { if (!pbft_db.should_send_pbft_msg()) return; @@ -84,7 +61,7 @@ namespace eosio { state_machine.on_new_view(nv); } - void pbft_controller::on_pbft_checkpoint(const pbft_metadata_ptr &cp) { + void pbft_controller::on_pbft_checkpoint(const pbft_metadata_ptr& cp) { if (!pbft_db.is_valid_checkpoint(cp->msg, cp->sender_key)) return; pbft_db.add_pbft_checkpoint(cp->msg, cp->sender_key); pbft_db.checkpoint_local(); @@ -140,6 +117,7 @@ namespace eosio { void psm_machine::manually_set_current_view(uint32_t cv) { set_current_view(cv); + pbft_db.set_current_view(cv); set_target_view(cv + 1); transit_to_view_change_state(); } @@ -302,7 +280,10 @@ namespace eosio { if (!to_new_view) { auto nv = pbft_db.get_committed_view(); - if (nv > get_current_view()) set_current_view(nv); + if (nv > get_current_view()) { + set_current_view(nv); + pbft_db.set_current_view(nv); + } set_target_view(get_current_view() + 1); } @@ -393,6 +374,7 @@ namespace eosio { void psm_machine::transit_to_new_view(const pbft_metadata_ptr& e) { set_current_view(e->msg.new_view); + pbft_db.set_current_view(e->msg.new_view); set_target_view(e->msg.new_view + 1); set_prepare_cache(pbft_prepare()); @@ -425,7 +407,7 @@ namespace eosio { } void psm_machine::do_send_prepare() { - auto prepares = pbft_db.generate_and_add_pbft_prepare(get_prepare_cache(), get_current_view()); + auto prepares = pbft_db.generate_and_add_pbft_prepare(get_prepare_cache()); if (!prepares.empty()) { for (const auto& p: prepares) { emit(pbft_outgoing_prepare, std::make_shared(p)); @@ -435,7 +417,7 @@ namespace eosio { } void psm_machine::do_send_commit() { - auto commits = pbft_db.generate_and_add_pbft_commit(get_commit_cache(), get_current_view()); + auto commits = pbft_db.generate_and_add_pbft_commit(get_commit_cache()); if (!commits.empty()) { for (const auto& c: commits) { @@ -469,7 +451,6 @@ namespace eosio { get_view_change_cache(), get_prepared_certificate(), get_committed_certificate(), - get_current_view(), get_target_view()); if (!view_changes.empty()) { diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index d0b60d88f35..8b58e30e0ea 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -23,8 +23,8 @@ namespace eosio { fc::datastream ds(content.data(), content.size()); - //skip current_view in pbftdb.dat. - ds.seekp(ds.tellp() + 4); + //set current_view in pbftdb.dat. + fc::raw::unpack(ds, _current_view); unsigned_int size; fc::raw::unpack(ds, size); @@ -76,7 +76,9 @@ namespace eosio { fc::path pbft_db_dat = pbft_db_dir / config::pbftdb_filename; std::ofstream out(pbft_db_dat.generic_string().c_str(), - std::ios::out | std::ios::binary | std::ofstream::app); + std::ios::out | std::ios::binary | std::ofstream::trunc); + fc::raw::pack(out, _current_view); + uint32_t num_records_in_db = pbft_state_index.size(); fc::raw::pack(out, unsigned_int{num_records_in_db}); @@ -169,8 +171,7 @@ namespace eosio { by_block_id_index.modify(itr, [&](const pbft_state_ptr& p) { p->is_prepared = true; }); } - vector pbft_database::generate_and_add_pbft_prepare(const pbft_prepare& cached_prepare, - pbft_view_type current_view) { + vector pbft_database::generate_and_add_pbft_prepare(const pbft_prepare& cached_prepare) { vector prepares_to_be_cached; const auto& my_sps = ctrl.my_signature_providers(); prepares_to_be_cached.reserve(my_sps.size()); @@ -196,15 +197,19 @@ namespace eosio { auto retry_p = cached_prepare; retry_p.common.timestamp = time_point::now(); retry_p.sender_signature = sp.second(retry_p.digest(chain_id)); - prepares_to_be_cached.emplace_back(retry_p); + if (is_valid_prepare(retry_p, sp.first)) { + prepares_to_be_cached.emplace_back(retry_p); + } } } else if (reserve_prepare(my_prepare)) { for (const auto& sp : my_sps) { pbft_prepare reserve_p; - reserve_p.view = current_view; + reserve_p.view = _current_view; reserve_p.block_info = {my_prepare}; reserve_p.sender_signature = sp.second(reserve_p.digest(chain_id)); - prepares_to_be_cached.emplace_back(reserve_p); + if (is_valid_prepare(reserve_p, sp.first)) { + prepares_to_be_cached.emplace_back(reserve_p); + } } } else { auto current_watermark = get_current_pbft_watermark(); @@ -222,7 +227,7 @@ namespace eosio { auto sent = false; for (const auto& sp : my_sps) { pbft_prepare new_p; - new_p.view = current_view; + new_p.view = _current_view; new_p.block_info = {hwbs->id}; new_p.sender_signature = sp.second(new_p.digest(chain_id)); if (is_valid_prepare(new_p, sp.first)) { @@ -323,8 +328,7 @@ namespace eosio { } } - vector pbft_database::generate_and_add_pbft_commit(const pbft_commit& cached_commit, - pbft_view_type current_view) { + vector pbft_database::generate_and_add_pbft_commit(const pbft_commit& cached_commit) { vector commits_to_be_cached; const auto& my_sps = ctrl.my_signature_providers(); commits_to_be_cached.reserve(my_sps.size()); @@ -335,7 +339,9 @@ namespace eosio { auto retry_c = cached_commit; retry_c.common.timestamp = time_point::now(); retry_c.sender_signature = sp.second(retry_c.digest(chain_id)); - commits_to_be_cached.emplace_back(retry_c); + if (is_valid_commit(retry_c, sp.first)) { + commits_to_be_cached.emplace_back(retry_c); + } } } else { const auto& by_prepare_and_num_index = pbft_state_index.get(); @@ -350,7 +356,7 @@ namespace eosio { for (const auto& sp : my_sps) { pbft_commit new_c; - new_c.view = current_view; + new_c.view = _current_view; new_c.block_info = {psp->block_id}; new_c.sender_signature = sp.second(new_c.digest(chain_id)); @@ -510,7 +516,6 @@ namespace eosio { const pbft_view_change& cached_view_change, const pbft_prepared_certificate& ppc, const vector& pcc, - pbft_view_type current_view, pbft_view_type target_view) { vector view_changes_to_be_cached; @@ -523,14 +528,16 @@ namespace eosio { auto retry_vc = cached_view_change; retry_vc.common.timestamp = time_point::now(); retry_vc.sender_signature = sp.second(retry_vc.digest(chain_id)); - view_changes_to_be_cached.emplace_back(retry_vc); + if (is_valid_view_change(retry_vc, sp.first)) { + view_changes_to_be_cached.emplace_back(retry_vc); + } } } else { for (const auto& sp : my_sps) { auto my_lsc = get_stable_checkpoint_by_id(ctrl.last_stable_checkpoint_block_id()); pbft_view_change new_vc; - new_vc.current_view = current_view; + new_vc.current_view = _current_view; new_vc.target_view = target_view; new_vc.prepared_cert = ppc; new_vc.committed_certs = pcc; @@ -574,11 +581,11 @@ namespace eosio { pbft_new_view pbft_database::generate_pbft_new_view( const pbft_view_changed_certificate& vcc, - pbft_view_type current_view) { + pbft_view_type new_view) { pbft_new_view nv; - auto primary_key = get_new_view_primary_key(current_view); + auto primary_key = get_new_view_primary_key(new_view); if (!has_new_primary(primary_key) || vcc.empty()) return nv; //`sp_itr` is not possible to be the end iterator, since it's already been checked in `has_new_primary`. @@ -605,7 +612,7 @@ namespace eosio { } } - nv.new_view = current_view; + nv.new_view = new_view; nv.prepared_cert = highest_ppc; nv.committed_certs = highest_pcc; nv.stable_checkpoint = highest_sc; @@ -1241,8 +1248,8 @@ namespace eosio { cp.sender_signature = sp.second(cp.digest(chain_id)); if (is_valid_checkpoint(cp, sp.first)) { add_pbft_checkpoint(cp, sp.first); + new_pc.emplace_back(cp); } - new_pc.emplace_back(cp); } } } @@ -1251,7 +1258,9 @@ namespace eosio { pbft_checkpoint cp; cp.block_info={ctrl.last_stable_checkpoint_block_id()}; cp.sender_signature = sp.second(cp.digest(chain_id)); - new_pc.emplace_back(cp); + if (is_valid_checkpoint(cp, sp.first)) { + new_pc.emplace_back(cp); + } } } return new_pc; diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index a7993d40a27..6131f00f701 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -210,6 +210,17 @@ class privileged_api : public context_aware_api { }); } + void set_pbft_parameters_packed( array_ptr packed_pbft_parameters, size_t datalen) { + datastream ds( packed_pbft_parameters, datalen ); + chain::chain_config3 cfg; + fc::raw::unpack(ds, cfg); + cfg.validate(); + context.db.modify( context.control.get_pbft_properties(), + [&]( auto& gpp ) { + gpp.configuration = cfg; + }); + } + // *bos begin* void set_name_list_packed(int64_t list, int64_t action, array_ptr packed_name_list, size_t datalen) { diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 43f7336074e..bd1b6041048 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -1597,16 +1597,21 @@ namespace eosio { void sync_manager::sync_stable_checkpoints(const connection_ptr& c, uint32_t target) { controller& cc = chain_plug->chain(); uint32_t lscb_num = cc.last_stable_checkpoint_block_num(); - if (last_req_scp_num < lscb_num || last_req_scp_num == 0 || last_req_scp_num >= target) last_req_scp_num = lscb_num; + auto head_num = cc.head_block_num(); + if (last_req_scp_num < lscb_num + || last_req_scp_num == 0 + || last_req_scp_num > target) last_req_scp_num = lscb_num; + auto end = target; auto max_target_scp_num = last_req_scp_num + pbft_checkpoint_granularity * 10; - if (target > max_target_scp_num) end = max_target_scp_num; + if (target > max_target_scp_num) end = std::min(max_target_scp_num, head_num); + if (end - last_req_scp_num < pbft_checkpoint_granularity) return; checkpoint_request_message crm = {last_req_scp_num+1,end}; c->enqueue( net_message(crm)); fc_dlog(logger, "request sync stable checkpoints from ${s} to ${e}", - ("s", last_req_scp_num+1)("e", max_target_scp_num)); - last_req_scp_num = max_target_scp_num; + ("s", last_req_scp_num+1)("e", end)); + last_req_scp_num = end; } void sync_manager::reassign_fetch(const connection_ptr& c, go_away_reason reason) { diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index 40856b24268..bd2b53df97b 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -439,7 +439,7 @@ BOOST_AUTO_TEST_CASE(new_view_with_committed_cert_call_two_times_maybe_switch_fo c1_pbft_controller.maybe_pbft_commit(); c1.produce_blocks(2); BOOST_CHECK_EQUAL(c1_ctrl.last_irreversible_block_num(), 137); - // make sure commited block same with new view generator lib block + // make sure committed block same with new view generator lib block BOOST_CHECK_EQUAL(c1_ctrl.fetch_block_by_number(137)->id(), ctrl_new_view_generator.fetch_block_by_number(137)->id()); } From dac6102fc5b611ea438b679d02fc969db444c5a9 Mon Sep 17 00:00:00 2001 From: oldcold Date: Thu, 1 Aug 2019 16:31:43 +0800 Subject: [PATCH 05/14] fix tests --- .../chain/include/eosio/chain/pbft_database.hpp | 13 +++++-------- libraries/chain/pbft.cpp | 4 ++-- libraries/chain/pbft_database.cpp | 11 +++++------ plugins/net_plugin/net_plugin.cpp | 9 +++++---- plugins/pbft_plugin/pbft_plugin.cpp | 12 ++++++------ 5 files changed, 23 insertions(+), 26 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 0ba096427ef..6b4bb2cd7a9 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -19,7 +19,6 @@ namespace eosio { using pbft_view_type = uint32_t; - constexpr uint16_t pbft_checkpoint_granularity = 100; constexpr uint16_t oldest_stable_checkpoint = 10000; enum class pbft_message_type : uint8_t { @@ -268,7 +267,7 @@ namespace eosio { bool empty() const { return !target_view - && view_changes.empty(); + && view_changes.empty(); } }; @@ -300,7 +299,7 @@ namespace eosio { } bool empty() const { - return new_view == 0 + return !new_view && prepared_cert.empty() && committed_certs.empty() && stable_checkpoint.empty() @@ -418,11 +417,8 @@ namespace eosio { class pbft_database { public: explicit pbft_database(controller& ctrl); - ~pbft_database(); - void close(); - void add_pbft_prepare(const pbft_prepare& p, const public_key_type& pk); void add_pbft_commit(const pbft_commit& c, const public_key_type& pk); void add_pbft_view_change(const pbft_view_change& vc, const public_key_type& pk); @@ -473,13 +469,14 @@ namespace eosio { bool should_recv_pbft_msg(const public_key_type& pub_key); bool pending_pbft_lib(); - chain_id_type& get_chain_id() {return chain_id;} + chain_id_type& get_chain_id() { return chain_id; } pbft_stable_checkpoint get_stable_checkpoint_by_id(const block_id_type& block_id, bool incl_blk_extn = true); pbft_stable_checkpoint fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr& b); void cleanup_on_new_view(); void update_fork_schedules(); uint16_t get_view_change_timeout() const; + uint16_t get_checkpoint_interval() const; const pbft_view_type get_current_view() { return _current_view; } void set_current_view(pbft_view_type view) { _current_view = view; } @@ -500,7 +497,7 @@ namespace eosio { vector prepare_watermarks; flat_map fork_schedules; chain_id_type chain_id = ctrl.get_chain_id(); - pbft_view_type _current_view; + pbft_view_type _current_view = 0; block_info_type cal_pending_stable_checkpoint() const; bool is_less_than_high_watermark(block_num_type bnum); diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 30f9ab80df9..118848ea650 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -5,7 +5,7 @@ namespace eosio { namespace chain { - pbft_controller::pbft_controller(controller &ctrl) : + pbft_controller::pbft_controller(controller& ctrl) : pbft_db(ctrl), state_machine(pbft_db) { state_machine.set_current(std::make_shared(state_machine, pbft_db)); @@ -387,7 +387,7 @@ namespace eosio { if (!e->msg.committed_certs.empty()) { auto committed_certs = e->msg.committed_certs; std::sort(committed_certs.begin(), committed_certs.end()); - for (auto const &cc :committed_certs) { + for (const auto& cc :committed_certs) { pbft_db.mark_as_committed(cc.block_info.block_id); } } diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 8b58e30e0ea..73e50056b95 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -61,7 +61,7 @@ namespace eosio { fc::remove(checkpoints_db); } - void pbft_database::close() { + pbft_database::~pbft_database() { fc::path checkpoints_db = checkpoints_dir / config::checkpoints_filename; std::ofstream c_out(checkpoints_db.generic_string().c_str(), @@ -90,10 +90,6 @@ namespace eosio { checkpoint_index.clear(); } - pbft_database::~pbft_database() { - close(); - } - void pbft_database::add_pbft_prepare(const pbft_prepare& p, const public_key_type& pk) { auto& by_block_id_index = pbft_state_index.get(); @@ -1215,7 +1211,7 @@ namespace eosio { if (in <= ucb) return false; auto watermarks = get_updated_watermarks(); return in == ucb + 1 // checkpoint on first pbft block; - || in % pbft_checkpoint_granularity == 1 // checkpoint on every 100 block; + || in % get_checkpoint_interval() == 1 // checkpoint on every 100 block; || std::find(watermarks.begin(), watermarks.end(), in) != watermarks.end(); // checkpoint on bp schedule change; }; @@ -1529,6 +1525,9 @@ namespace eosio { return ctrl.get_pbft_properties().configuration.view_change_timeout; } + uint16_t pbft_database::get_checkpoint_interval() const { + return ctrl.get_pbft_properties().configuration.pbft_checkpoint_granularity; + } bool pbft_database::is_less_than_high_watermark(block_num_type bnum) { auto current_watermark = get_current_pbft_watermark(); diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index bd1b6041048..31fdeec6dd1 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -1602,6 +1602,7 @@ namespace eosio { || last_req_scp_num == 0 || last_req_scp_num > target) last_req_scp_num = lscb_num; + auto pbft_checkpoint_granularity = chain_plug->pbft_ctrl().pbft_db.get_checkpoint_interval(); auto end = target; auto max_target_scp_num = last_req_scp_num + pbft_checkpoint_granularity * 10; if (target > max_target_scp_num) end = std::min(max_target_scp_num, head_num); @@ -2830,18 +2831,18 @@ namespace eosio { fc_dlog(logger, "received checkpoint request message ${m}, from ${p}", ("m", msg)("p", c->peer_name())); - if ( msg.end_block - msg.start_block > pbft_checkpoint_granularity * 100) { + if ( msg.end_block - msg.start_block > chain_plug->pbft_ctrl().pbft_db.get_checkpoint_interval() * 100) { fc_dlog(logger, "request range too large"); return; } vector scp_stack; - controller &cc = my_impl->chain_plug->chain(); - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + controller& cc = my_impl->chain_plug->chain(); + pbft_controller& pcc = my_impl->chain_plug->pbft_ctrl(); auto end_block = std::min(msg.end_block, cc.last_stable_checkpoint_block_num()); - for (auto i = end_block; i >= msg.start_block && i>0; --i) { + for (auto i = end_block; i >= msg.start_block && i > 0; --i) { try { auto bid = cc.get_block_id_for_num(i); auto scp = pcc.pbft_db.get_stable_checkpoint_by_id(bid); diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index 8acf2b49a19..81a1c298c07 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -70,7 +70,7 @@ namespace eosio { } else if (ec) { wlog ("pbft plugin prepare timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + chain::pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_prepare(); } prepare_timer_tick(); @@ -86,7 +86,7 @@ namespace eosio { } else if (ec) { wlog ("pbft plugin commit timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + chain::pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_commit(); } commit_timer_tick(); @@ -106,7 +106,7 @@ namespace eosio { if (ec) { wlog ("pbft plugin view change timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + chain::pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_view_change(); } }); @@ -121,11 +121,11 @@ namespace eosio { } if (ec) { wlog ("pbft plugin checkpoint timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + chain::pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_checkpoint(); - chain::controller &ctrl = app().get_plugin().chain(); - if ( ctrl.head_block_num() - ctrl.last_stable_checkpoint_block_num() / pbft_checkpoint_granularity > 1) { + chain::controller& ctrl = app().get_plugin().chain(); + if ( ctrl.head_block_num() - ctrl.last_stable_checkpoint_block_num() / pbft_ctrl.pbft_db.get_checkpoint_interval() > 1) { //perhaps we need to sync stable checkpoints from other peers app().get_plugin().maybe_sync_stable_checkpoints(); } From 82f00a8e167e206a74e12ee674885ee723f2a27d Mon Sep 17 00:00:00 2001 From: oldcold Date: Thu, 15 Aug 2019 11:33:54 +0800 Subject: [PATCH 06/14] reset view change timer when global timeout is changed. --- libraries/chain/include/eosio/chain/pbft.hpp | 1 + libraries/chain/pbft.cpp | 15 +++++++++++---- libraries/chain/pbft_database.cpp | 2 +- plugins/pbft_plugin/pbft_plugin.cpp | 4 ++-- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index 0bfb7e8942a..b84962d03dc 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -208,6 +208,7 @@ namespace eosio { private: fc::path datadir; + uint16_t view_change_timeout = 6; }; } } /// namespace eosio::chain diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 118848ea650..8ac97cb1c49 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -28,7 +28,14 @@ namespace eosio { void pbft_controller::maybe_pbft_view_change() { if (!pbft_db.should_send_pbft_msg()) return; - if (state_machine.get_view_change_timer() <= pbft_db.get_view_change_timeout()) { + + if (view_change_timeout != pbft_db.get_view_change_timeout()) { + ///if there is a change in global states, update timeout and reset timer. + view_change_timeout = pbft_db.get_view_change_timeout(); + state_machine.set_view_change_timer(0); + } + + if (state_machine.get_view_change_timer() <= view_change_timeout) { if (!state_machine.get_view_change_cache().empty()) { pbft_db.generate_and_add_pbft_view_change(state_machine.get_view_change_cache()); } @@ -198,14 +205,14 @@ namespace eosio { //do action add prepare pbft_db.add_pbft_prepare(e->msg, e->sender_key); - //if prepare >= 2f+1, transit to prepared + //if prepare >= n-f, transit to prepared if (pbft_db.should_prepared()) m.transit_to_prepared_state(); } void psm_committed_state::send_prepare() { m.do_send_prepare(); - //if prepare >= 2f+1, transit to prepared + //if prepare >= n-f, transit to prepared if (pbft_db.should_prepared()) m.transit_to_prepared_state(); } @@ -344,7 +351,7 @@ namespace eosio { } bool psm_machine::maybe_new_view() { - //if view_change >= 2f+1, calculate next primary, send new view if is primary + //if view_change >= n-f, calculate next primary, send new view if is primary auto nv = get_target_view(); auto pk = pbft_db.get_new_view_primary_key(nv); if (pbft_db.should_new_view(nv) && pbft_db.has_new_primary(pk)) { diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 73e50056b95..7e83a1795d5 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -499,7 +499,7 @@ namespace eosio { } } //if contains self or view_change >= f+1, transit to view_change and send view change - if (vc_count >= active_bps.size() / 3 + 1) { + if (vc_count > (active_bps.size() - 1) / 3) { nv = pvs->view; break; } diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index 81a1c298c07..7d27f1607bd 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -25,8 +25,8 @@ namespace eosio { unique_ptr view_change_timer; unique_ptr checkpoint_timer; - boost::asio::steady_timer::duration prepare_timeout{std::chrono::milliseconds{1000}}; - boost::asio::steady_timer::duration commit_timeout{std::chrono::milliseconds{1000}}; + boost::asio::steady_timer::duration prepare_timeout{std::chrono::milliseconds{750}}; + boost::asio::steady_timer::duration commit_timeout{std::chrono::milliseconds{750}}; boost::asio::steady_timer::duration view_change_check_interval{std::chrono::seconds{5}}; boost::asio::steady_timer::duration checkpoint_timeout{std::chrono::seconds{25}}; From 28403172460f32acf504e59e5e8129bf5da60a31 Mon Sep 17 00:00:00 2001 From: oldcold Date: Fri, 16 Aug 2019 18:27:47 +0800 Subject: [PATCH 07/14] reserve prepare only if my_prepare is on forks --- libraries/chain/pbft_database.cpp | 10 +++++++--- unittests/pbft_tests.cpp | 22 +++++++++++++--------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 7e83a1795d5..5bf4a743bd1 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -176,14 +176,18 @@ namespace eosio { auto my_prepare = ctrl.get_pbft_my_prepare(); auto reserve_prepare = [&](const block_id_type& in) { - if (in == block_id_type() || !ctrl.fetch_block_state_by_id(in)) return false; + if (in == block_id_type()) return false; + auto bs = ctrl.fetch_block_state_by_id(in); + if (!bs) return false; auto lib = ctrl.last_irreversible_block_id(); if (lib == block_id_type()) return true; auto forks = ctrl.fork_db().fetch_branch_from(in, lib); //`branch_type` will always contain at least themselves. //`in` block num should be higher than lib, yet fall on the same branch with lib. - return forks.first.size() > 1 && forks.second.size() == 1; + return forks.first.size() > 1 + && forks.second.size() == 1 + && !bs->in_current_chain; }; @@ -197,7 +201,7 @@ namespace eosio { prepares_to_be_cached.emplace_back(retry_p); } } - } else if (reserve_prepare(my_prepare)) { + } else if (reserve_prepare(my_prepare) ) { for (const auto& sp : my_sps) { pbft_prepare reserve_p; reserve_p.view = _current_view; diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index bd2b53df97b..e7db3bbe66a 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -547,6 +547,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { pbft_commit c2_commit_ = c2_pbft_controller.state_machine.get_commit_cache(); c1_pbft_controller.state_machine.on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); + auto c1_my_prepare_block = c1_ctrl.get_pbft_my_prepare(); c1.produce_block(); c1_pbft_controller.maybe_pbft_commit(); BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 98); @@ -556,7 +557,10 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { /// make c3_final lib 98 c3_final_pbft_controller.maybe_pbft_prepare(); pbft_prepare c1_prepare_ = c1_pbft_controller.state_machine.get_prepare_cache(); - BOOST_CHECK_EQUAL(c1_prepare_.block_info.block_num(), 99); + + auto forks = c1_ctrl.fork_db().fetch_branch_from(c1_prepare_.block_info.block_id, c1_my_prepare_block); + BOOST_CHECK_EQUAL(forks.first.size() >= 1 && forks.second.size() == 1, true); + c3_final.produce_block(); c3_final_pbft_controller.state_machine.on_prepare(std::make_shared>(c1_prepare_, c1_pbft_controller.pbft_db.get_chain_id())); c3_final_pbft_controller.maybe_pbft_commit(); @@ -599,7 +603,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c1_prepare_ = c1_pbft_controller.state_machine.get_prepare_cache(); c1_commit_ = c1_pbft_controller.state_machine.get_commit_cache(); - BOOST_CHECK_EQUAL(c1_commit_.block_info.block_num(), 99); + BOOST_CHECK_EQUAL(c1_commit_.block_info.block_num(), 100); BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 99); c3_final_pbft_controller.maybe_pbft_prepare(); @@ -607,14 +611,14 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c3_final.produce_block(); c3_final.produce_block(); - BOOST_CHECK_EQUAL(c1_prepare.block_info.block_num(), 99); - /// set c3 my preprare at 100 - c3_final_ctrl.set_pbft_my_prepare(c3_final_ctrl.get_block_id_for_num(100)); + BOOST_CHECK_EQUAL(c1_prepare.block_info.block_num(), 100); + /// set c3 my prepare at 101 + c3_final_ctrl.set_pbft_my_prepare(c3_final_ctrl.get_block_id_for_num(101)); c3_final_pbft_controller.state_machine.on_prepare(std::make_shared>(c1_prepare, c1_pbft_controller.pbft_db.get_chain_id())); pbft_prepare c3_final_prepare = c3_final_pbft_controller.state_machine.get_prepare_cache(); - // check c3 prepare at 99 - BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 99); + // check c3 prepare at 100 + BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 101); curr_state = c3_final_pbft_controller.state_machine.get_current()->get_name(); BOOST_CHECK_EQUAL(curr_state, "{==== PREPARED ====}"); @@ -650,11 +654,11 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c3_final_pbft_controller.maybe_pbft_commit(); curr_state = c3_final_pbft_controller.state_machine.get_current()->get_name(); BOOST_CHECK_EQUAL(curr_state, "{==== COMMITTED ====}"); - BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 99); + BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 100); c3_final_pbft_controller.maybe_pbft_prepare(); c3_final_prepare = c3_final_pbft_controller.state_machine.get_prepare_cache(); - BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 100); + BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 103); } From 6efb1a98588161e032af7e1e900aeb26686c46ea Mon Sep 17 00:00:00 2001 From: oldcold Date: Fri, 16 Aug 2019 18:27:47 +0800 Subject: [PATCH 08/14] reserve prepare only if my_prepare is on forks --- libraries/chain/block_header_state.cpp | 4 ++-- libraries/chain/pbft_database.cpp | 10 +++++++--- unittests/pbft_tests.cpp | 22 +++++++++++++--------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index 83e7c3292ad..690b10a947e 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -158,7 +158,7 @@ namespace eosio { namespace chain { pending_schedule = *header.new_producers; pending_schedule_lib_num = block_num; } - + /** * Transitions the current header state into the next header state given the supplied signed block header. @@ -176,7 +176,7 @@ namespace eosio { namespace chain { EOS_ASSERT( h.previous == id, unlinkable_block_exception, "block must link to current state" ); auto result = generate_next( h.timestamp, pbft_enabled); EOS_ASSERT( result.header.producer == h.producer, wrong_producer, "wrong producer specified" ); - EOS_ASSERT( result.header.schedule_version == h.schedule_version, producer_schedule_exception, "schedule_version in s igned block is corrupted" ); + EOS_ASSERT( result.header.schedule_version == h.schedule_version, producer_schedule_exception, "schedule_version in signed block is corrupted" ); auto itr = producer_to_last_produced.find(h.producer); if( itr != producer_to_last_produced.end() ) { diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 7e83a1795d5..5bf4a743bd1 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -176,14 +176,18 @@ namespace eosio { auto my_prepare = ctrl.get_pbft_my_prepare(); auto reserve_prepare = [&](const block_id_type& in) { - if (in == block_id_type() || !ctrl.fetch_block_state_by_id(in)) return false; + if (in == block_id_type()) return false; + auto bs = ctrl.fetch_block_state_by_id(in); + if (!bs) return false; auto lib = ctrl.last_irreversible_block_id(); if (lib == block_id_type()) return true; auto forks = ctrl.fork_db().fetch_branch_from(in, lib); //`branch_type` will always contain at least themselves. //`in` block num should be higher than lib, yet fall on the same branch with lib. - return forks.first.size() > 1 && forks.second.size() == 1; + return forks.first.size() > 1 + && forks.second.size() == 1 + && !bs->in_current_chain; }; @@ -197,7 +201,7 @@ namespace eosio { prepares_to_be_cached.emplace_back(retry_p); } } - } else if (reserve_prepare(my_prepare)) { + } else if (reserve_prepare(my_prepare) ) { for (const auto& sp : my_sps) { pbft_prepare reserve_p; reserve_p.view = _current_view; diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index bd2b53df97b..e7db3bbe66a 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -547,6 +547,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { pbft_commit c2_commit_ = c2_pbft_controller.state_machine.get_commit_cache(); c1_pbft_controller.state_machine.on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); + auto c1_my_prepare_block = c1_ctrl.get_pbft_my_prepare(); c1.produce_block(); c1_pbft_controller.maybe_pbft_commit(); BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 98); @@ -556,7 +557,10 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { /// make c3_final lib 98 c3_final_pbft_controller.maybe_pbft_prepare(); pbft_prepare c1_prepare_ = c1_pbft_controller.state_machine.get_prepare_cache(); - BOOST_CHECK_EQUAL(c1_prepare_.block_info.block_num(), 99); + + auto forks = c1_ctrl.fork_db().fetch_branch_from(c1_prepare_.block_info.block_id, c1_my_prepare_block); + BOOST_CHECK_EQUAL(forks.first.size() >= 1 && forks.second.size() == 1, true); + c3_final.produce_block(); c3_final_pbft_controller.state_machine.on_prepare(std::make_shared>(c1_prepare_, c1_pbft_controller.pbft_db.get_chain_id())); c3_final_pbft_controller.maybe_pbft_commit(); @@ -599,7 +603,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c1_prepare_ = c1_pbft_controller.state_machine.get_prepare_cache(); c1_commit_ = c1_pbft_controller.state_machine.get_commit_cache(); - BOOST_CHECK_EQUAL(c1_commit_.block_info.block_num(), 99); + BOOST_CHECK_EQUAL(c1_commit_.block_info.block_num(), 100); BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 99); c3_final_pbft_controller.maybe_pbft_prepare(); @@ -607,14 +611,14 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c3_final.produce_block(); c3_final.produce_block(); - BOOST_CHECK_EQUAL(c1_prepare.block_info.block_num(), 99); - /// set c3 my preprare at 100 - c3_final_ctrl.set_pbft_my_prepare(c3_final_ctrl.get_block_id_for_num(100)); + BOOST_CHECK_EQUAL(c1_prepare.block_info.block_num(), 100); + /// set c3 my prepare at 101 + c3_final_ctrl.set_pbft_my_prepare(c3_final_ctrl.get_block_id_for_num(101)); c3_final_pbft_controller.state_machine.on_prepare(std::make_shared>(c1_prepare, c1_pbft_controller.pbft_db.get_chain_id())); pbft_prepare c3_final_prepare = c3_final_pbft_controller.state_machine.get_prepare_cache(); - // check c3 prepare at 99 - BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 99); + // check c3 prepare at 100 + BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 101); curr_state = c3_final_pbft_controller.state_machine.get_current()->get_name(); BOOST_CHECK_EQUAL(curr_state, "{==== PREPARED ====}"); @@ -650,11 +654,11 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c3_final_pbft_controller.maybe_pbft_commit(); curr_state = c3_final_pbft_controller.state_machine.get_current()->get_name(); BOOST_CHECK_EQUAL(curr_state, "{==== COMMITTED ====}"); - BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 99); + BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 100); c3_final_pbft_controller.maybe_pbft_prepare(); c3_final_prepare = c3_final_pbft_controller.state_machine.get_prepare_cache(); - BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 100); + BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 103); } From 6717cf2f853e1fb146763d90520c5daeb7e0f958 Mon Sep 17 00:00:00 2001 From: Frank-AFN Date: Mon, 19 Aug 2019 16:32:30 +0800 Subject: [PATCH 09/14] Modify reserve prepare test case --- unittests/pbft_tests.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index e7db3bbe66a..857b412b750 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -551,6 +551,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c1.produce_block(); c1_pbft_controller.maybe_pbft_commit(); BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 98); +// c1_ctrl.set_pbft_my_prepare(c1_ctrl.get_block_id_for_num(99)); c2_pbft_controller.maybe_pbft_commit(); @@ -612,12 +613,12 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c3_final.produce_block(); BOOST_CHECK_EQUAL(c1_prepare.block_info.block_num(), 100); - /// set c3 my prepare at 101 + /// set c3 my preprare at 101 c3_final_ctrl.set_pbft_my_prepare(c3_final_ctrl.get_block_id_for_num(101)); c3_final_pbft_controller.state_machine.on_prepare(std::make_shared>(c1_prepare, c1_pbft_controller.pbft_db.get_chain_id())); pbft_prepare c3_final_prepare = c3_final_pbft_controller.state_machine.get_prepare_cache(); - // check c3 prepare at 100 + // check c3 prepare at 101 BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 101); curr_state = c3_final_pbft_controller.state_machine.get_current()->get_name(); BOOST_CHECK_EQUAL(curr_state, "{==== PREPARED ====}"); @@ -625,11 +626,12 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c3_final_pbft_controller.maybe_pbft_commit(); + c2_prime.produce_block(); c2_prime.create_accounts({N(tester1)}); - c2_prime.produce_blocks(5); + c2_prime.produce_blocks(6); //push fork to c3_final - for(int i = 100; i <= 104; i++) { + for(int i = 101; i <= 106; i++) { auto fb = c2_prime.control->fetch_block_by_number(i); c3_final.push_block(fb); } @@ -642,7 +644,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { BOOST_CHECK_EQUAL(tmp_c2_prime_prepared_fork->pbft_my_prepare, true); BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 98); - BOOST_CHECK_EQUAL(c3_final.control->head_block_num(), 104); + BOOST_CHECK_EQUAL(c3_final.control->head_block_num(), 106); c3_final_pbft_controller.maybe_pbft_commit(); c3_final.produce_block(); @@ -658,7 +660,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c3_final_pbft_controller.maybe_pbft_prepare(); c3_final_prepare = c3_final_pbft_controller.state_machine.get_prepare_cache(); - BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 103); + BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 101); } From a4e89a239dea7fb172d45f014cfebf135d126e11 Mon Sep 17 00:00:00 2001 From: oldcold Date: Tue, 20 Aug 2019 10:39:09 +0800 Subject: [PATCH 10/14] dpos pbft optimise (#121) * optimise for return value. * reset timer upon state transition; refactor code; * add global object to control pbft behavior; optimise checkpoint logic * refactor pbft db persistence * fix tests * reset view change timer when global timeout is changed. * reserve prepare only if my_prepare is on forks * reserve prepare only if my_prepare is on forks * Modify reserve prepare test case --- libraries/chain/chain_config.cpp | 5 + libraries/chain/controller.cpp | 23 +- libraries/chain/fork_database.cpp | 4 +- .../include/eosio/chain/chain_config.hpp | 10 + .../chain/include/eosio/chain/controller.hpp | 4 +- .../include/eosio/chain/fork_database.hpp | 4 +- .../eosio/chain/global_property_object.hpp | 23 +- libraries/chain/include/eosio/chain/pbft.hpp | 171 ++--- .../include/eosio/chain/pbft_database.hpp | 132 ++-- libraries/chain/include/eosio/chain/types.hpp | 1 + libraries/chain/pbft.cpp | 486 ++++++-------- libraries/chain/pbft_database.cpp | 631 +++++++++--------- libraries/chain/wasm_interface.cpp | 11 + .../include/eosio/chain/plugin_interface.hpp | 3 + plugins/chain_plugin/chain_plugin.cpp | 16 +- plugins/net_plugin/net_plugin.cpp | 377 ++++------- .../include/eosio/pbft_plugin/pbft_plugin.hpp | 6 +- plugins/pbft_plugin/pbft_plugin.cpp | 227 ++++--- unittests/pbft_tests.cpp | 106 +-- 19 files changed, 1083 insertions(+), 1157 deletions(-) diff --git a/libraries/chain/chain_config.cpp b/libraries/chain/chain_config.cpp index c39d89cee46..7b4b1fca60c 100644 --- a/libraries/chain/chain_config.cpp +++ b/libraries/chain/chain_config.cpp @@ -49,4 +49,9 @@ void chain_config2::validate() const{ EOS_ASSERT(std::numeric_limits::max() > resource_greylist.size(), action_validate_exception, "Overflow in greylistwhen adding resource greylist!"); } +void chain_config3::validate() const{ + EOS_ASSERT( view_change_timeout >= 1, action_validate_exception, "view change timeout must be at least 1"); + EOS_ASSERT( pbft_checkpoint_granularity >= 100 && pbft_checkpoint_granularity % 100 == 0, action_validate_exception, "pbft checkpoint granularity must be multiple of 100 blocks"); +} + } } // namespace eosio::chain diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 2aa4644afb4..75a799b74fa 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -36,6 +36,7 @@ using controller_index_set = index_set< global_property2_multi_index, dynamic_global_property_multi_index, upgrade_property_multi_index, + global_property3_multi_index, block_summary_multi_index, transaction_multi_index, generated_transaction_multi_index, @@ -455,6 +456,13 @@ struct controller_impl { wlog("no upo found, generating..."); db.create([](auto&){}); } + + try { + db.get(); + } catch( const boost::exception& e) { + wlog("no gpo3 found, generating..."); + db.create([](auto&){}); + } } ~controller_impl() { @@ -746,6 +754,7 @@ struct controller_impl { // *bos end* + db.create([](auto&) {}); authorization.initialize_database(); resource_limits.initialize_database(); @@ -2526,13 +2535,15 @@ void controller::set_pbft_my_prepare(const block_id_type& id) { } block_id_type controller::get_pbft_prepared() const { - if (my->pbft_prepared) return my->pbft_prepared->id; - return block_id_type{}; + block_id_type pp; + if (my->pbft_prepared) pp = my->pbft_prepared->id; + return pp; } block_id_type controller::get_pbft_my_prepare() const { - if (my->my_prepare) return my->my_prepare->id; - return block_id_type{}; + block_id_type mp; + if (my->my_prepare) mp = my->my_prepare->id; + return mp; } void controller::reset_pbft_my_prepare() { @@ -2701,6 +2712,10 @@ const upgrade_property_object& controller::get_upgrade_properties()const { return my->db.get(); } +const global_property3_object& controller::get_pbft_properties()const { + return my->db.get(); +} + bool controller::is_pbft_enabled() const { return my->pbft_enabled; } diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index 2163a5a5960..be36a908895 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -525,7 +525,7 @@ namespace eosio { namespace chain { * * This will require a search over all forks */ - void fork_database::set_bft_irreversible( block_id_type id ) { + void fork_database::set_bft_irreversible( const block_id_type& id ) { auto b = get_block( id ); EOS_ASSERT( b, fork_db_block_not_found, "unable to find block id ${id}", ("id",id)); @@ -569,7 +569,7 @@ namespace eosio { namespace chain { my->head = *my->index.get().begin(); } - void fork_database::set_latest_checkpoint( block_id_type id) { + void fork_database::set_latest_checkpoint( const block_id_type& id) { auto b = get_block( id ); EOS_ASSERT( b, fork_db_block_not_found, "unable to find block id ${id}", ("id",id)); diff --git a/libraries/chain/include/eosio/chain/chain_config.hpp b/libraries/chain/include/eosio/chain/chain_config.hpp index da258010fbb..d2e9d5c0184 100644 --- a/libraries/chain/include/eosio/chain/chain_config.hpp +++ b/libraries/chain/include/eosio/chain/chain_config.hpp @@ -117,6 +117,14 @@ struct chain_config2 { void validate()const; }; +struct chain_config3 { + + uint16_t view_change_timeout = 6; /// the actual wait time will be `num * 5` + uint16_t pbft_checkpoint_granularity = 100; /// the interval of normal checkpoints must be a multiple of 100 * n; + + void validate()const; +}; + // *bos* struct guaranteed_minimum_resources { uint64_t ram_byte; @@ -140,3 +148,5 @@ FC_REFLECT(eosio::chain::chain_config, // *bos* FC_REFLECT( eosio::chain::chain_config2, (actor_blacklist)(contract_blacklist)(resource_greylist) ) FC_REFLECT( eosio::chain::guaranteed_minimum_resources, (ram_byte)(cpu_us)(net_byte) ) + +FC_REFLECT( eosio::chain::chain_config3, (view_change_timeout) ) diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 7a90125da6e..05c5c925e59 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -31,6 +31,7 @@ namespace eosio { namespace chain { class global_property_object; class global_property2_object; // *bos* class upgrade_property_object; + class global_property3_object; // *bos* class permission_object; class account_object; using resource_limits::resource_limits_manager; @@ -305,7 +306,8 @@ namespace eosio { namespace chain { signal accepted_confirmation; signal bad_alloc; - const upgrade_property_object& get_upgrade_properties()const; + const upgrade_property_object& get_upgrade_properties()const; + const global_property3_object& get_pbft_properties()const; bool is_pbft_enabled()const; bool under_maintenance()const; void set_upo(uint32_t target_block_num); diff --git a/libraries/chain/include/eosio/chain/fork_database.hpp b/libraries/chain/include/eosio/chain/fork_database.hpp index 823c65c5b92..9dfb3f0cc9c 100644 --- a/libraries/chain/include/eosio/chain/fork_database.hpp +++ b/libraries/chain/include/eosio/chain/fork_database.hpp @@ -70,9 +70,9 @@ namespace eosio { namespace chain { */ signal irreversible; - void set_bft_irreversible( block_id_type id ); + void set_bft_irreversible( const block_id_type& id ); - void set_latest_checkpoint( block_id_type id); + void set_latest_checkpoint( const block_id_type& id); void mark_pbft_prepared_fork(const block_state_ptr& h); diff --git a/libraries/chain/include/eosio/chain/global_property_object.hpp b/libraries/chain/include/eosio/chain/global_property_object.hpp index 98f86939ad6..32edc5bea62 100644 --- a/libraries/chain/include/eosio/chain/global_property_object.hpp +++ b/libraries/chain/include/eosio/chain/global_property_object.hpp @@ -54,6 +54,14 @@ namespace eosio { namespace chain { block_num_type upgrade_complete_block_num = 0; }; + class global_property3_object : public chainbase::object + { + OBJECT_CTOR(global_property3_object) + + id_type id; + chain_config3 configuration; + }; + /** * @class dynamic_global_property_object @@ -108,6 +116,15 @@ namespace eosio { namespace chain { > > >; + + using global_property3_multi_index = chainbase::shared_multi_index_container< + global_property3_object, + indexed_by< + ordered_unique, + BOOST_MULTI_INDEX_MEMBER(global_property3_object, global_property3_object::id_type, id) + > + > + >; }} CHAINBASE_SET_INDEX_TYPE(eosio::chain::global_property_object, eosio::chain::global_property_multi_index) @@ -116,6 +133,7 @@ CHAINBASE_SET_INDEX_TYPE(eosio::chain::dynamic_global_property_object, // *bos* CHAINBASE_SET_INDEX_TYPE(eosio::chain::global_property2_object, eosio::chain::global_property2_multi_index) CHAINBASE_SET_INDEX_TYPE(eosio::chain::upgrade_property_object, eosio::chain::upgrade_property_multi_index) +CHAINBASE_SET_INDEX_TYPE(eosio::chain::global_property3_object, eosio::chain::global_property3_multi_index) FC_REFLECT(eosio::chain::dynamic_global_property_object, (global_action_sequence) @@ -130,4 +148,7 @@ FC_REFLECT(eosio::chain::global_property2_object, ) FC_REFLECT(eosio::chain::upgrade_property_object, (upgrade_target_block_num)(upgrade_complete_block_num) - ) \ No newline at end of file + ) +FC_REFLECT(eosio::chain::global_property3_object, + (configuration) +) \ No newline at end of file diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index 2bebe05cc79..b84962d03dc 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -12,12 +12,12 @@ namespace eosio { using namespace fc; struct psm_cache { - pbft_prepare prepares_cache; - pbft_commit commits_cache; - pbft_view_change view_changes_cache; - pbft_prepared_certificate prepared_certificate; - vector committed_certificate; - pbft_view_changed_certificate view_changed_certificate; + pbft_prepare prepare_cache = pbft_prepare(); + pbft_commit commit_cache = pbft_commit(); + pbft_view_change view_change_cache = pbft_view_change(); + pbft_prepared_certificate prepared_certificate = pbft_prepared_certificate(); + vector committed_certificate = vector{}; + pbft_view_changed_certificate view_changed_certificate = pbft_view_changed_certificate(); }; class psm_state; @@ -29,13 +29,9 @@ namespace eosio { explicit psm_machine(pbft_database& pbft_db); ~psm_machine(); - void set_current(psm_state_ptr s) { - current = std::move(s); - } + void set_current(psm_state_ptr s) { current = std::move(s); } - psm_state_ptr get_current() { - return current; - } + const psm_state_ptr& get_current() { return current; } void on_prepare(const pbft_metadata_ptr& e); void on_commit(const pbft_metadata_ptr& e); @@ -45,57 +41,73 @@ namespace eosio { void send_prepare(); void send_commit(); void send_view_change(); + void send_checkpoint(); + bool maybe_new_view(); + void maybe_view_change(); + bool maybe_stop_view_change(); + + void transit_to_committed_state(bool to_new_view); + void transit_to_prepared_state(); + void transit_to_view_change_state(); + void transit_to_new_view(const pbft_metadata_ptr& e); + + void do_send_prepare(); + void do_send_commit(); + void do_send_view_change(); - void transit_to_committed_state(const psm_state_ptr& s, bool to_new_view); - void transit_to_prepared_state(const psm_state_ptr& s); - void transit_to_view_change_state(const psm_state_ptr& s); - void transit_to_new_view(const pbft_metadata_ptr& e, const psm_state_ptr& s); + const pbft_prepare& get_prepare_cache() const { return cache.prepare_cache; } + void set_prepare_cache(const pbft_prepare& pcache) { cache.prepare_cache = pcache; } - void do_send_view_change(); - bool maybe_new_view(const psm_state_ptr& s); + const pbft_commit& get_commit_cache() const { return cache.commit_cache; } + void set_commit_cache(const pbft_commit& ccache) { cache.commit_cache = ccache; } - const pbft_prepare& get_prepares_cache() const; - void set_prepares_cache(const pbft_prepare &pcache); + const pbft_view_change& get_view_change_cache() const { return cache.view_change_cache; } + void set_view_change_cache(const pbft_view_change& vc_cache) { cache.view_change_cache = vc_cache; } - const pbft_commit& get_commits_cache() const; - void set_commits_cache(const pbft_commit &ccache); + uint32_t get_current_view() const { return current_view; } + void set_current_view(uint32_t cv) { current_view = cv; } - const pbft_view_change& get_view_changes_cache() const; - void set_view_changes_cache(const pbft_view_change &vc_cache); + const pbft_prepared_certificate& get_prepared_certificate() const { return cache.prepared_certificate; } + void set_prepared_certificate(const pbft_prepared_certificate& pcert) { cache.prepared_certificate = pcert; } - const uint32_t &get_current_view() const; - void set_current_view(const uint32_t &cv); + const vector& get_committed_certificate() const { return cache.committed_certificate; } + void set_committed_certificate(const vector& ccert) { cache.committed_certificate = ccert; } - const pbft_prepared_certificate& get_prepared_certificate() const; - void set_prepared_certificate(const pbft_prepared_certificate &pcert); + const pbft_view_changed_certificate& get_view_changed_certificate() const { return cache.view_changed_certificate; } + void set_view_changed_certificate(const pbft_view_changed_certificate& vc_cert) { cache.view_changed_certificate = vc_cert; } - const vector& get_committed_certificate() const; - void set_committed_certificate(const vector &ccert); + uint32_t get_target_view_retries() const { return target_view_retries; } + void set_target_view_retries(uint32_t tv_reties) { target_view_retries = tv_reties; } - const pbft_view_changed_certificate& get_view_changed_certificate() const; - void set_view_changed_certificate(const pbft_view_changed_certificate &vc_cert); + uint32_t get_target_view() const { return target_view; } + void set_target_view(uint32_t tv) { target_view = tv; } - const uint32_t& get_target_view_retries() const; - void set_target_view_retries(const uint32_t &tv_reties); + uint32_t get_view_change_timer() const { return view_change_timer; } + void set_view_change_timer(uint32_t vc_timer) { view_change_timer = vc_timer; } - const uint32_t& get_target_view() const; - void set_target_view(const uint32_t &tv); + void manually_set_current_view(uint32_t cv); - const uint32_t& get_view_change_timer() const; - void set_view_change_timer(const uint32_t &vc_timer); + signal pbft_outgoing_prepare; + signal pbft_outgoing_commit; + signal pbft_outgoing_view_change; + signal pbft_outgoing_new_view; + signal pbft_outgoing_checkpoint; + signal pbft_transit_to_committed; + signal pbft_transit_to_prepared; - void manually_set_current_view(const uint32_t &cv); + template + void emit(const Signal& s, Arg&& a); protected: psm_cache cache; - uint32_t current_view; - uint32_t target_view_retries; - uint32_t target_view; - uint32_t view_change_timer; + uint32_t current_view = 0; + uint32_t target_view_retries = 0; + uint32_t target_view = current_view + 1; + uint32_t view_change_timer = 0; private: - psm_state_ptr current; - pbft_database &pbft_db; + psm_state_ptr current = nullptr; + pbft_database& pbft_db; }; using psm_machine_ptr = std::shared_ptr; @@ -103,34 +115,40 @@ namespace eosio { class psm_state : public std::enable_shared_from_this { public: - psm_state(); + psm_state(psm_machine& m, pbft_database& pbft_db); ~psm_state(); - virtual void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) = 0; - virtual void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) = 0; - virtual void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) = 0; + virtual void on_prepare(const pbft_metadata_ptr& e) = 0; + virtual void on_commit(const pbft_metadata_ptr& e) = 0; + virtual void on_view_change(const pbft_metadata_ptr& e) = 0; - virtual void send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) = 0; - virtual void send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) = 0; - virtual void send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) = 0; + virtual void send_prepare() = 0; + virtual void send_commit() = 0; + virtual void send_view_change() = 0; virtual const char* get_name() = 0; std::shared_ptr get_self() { return shared_from_this(); }; + + protected: + psm_machine& m; + pbft_database& pbft_db; }; class psm_prepared_state final: public psm_state { public: - psm_prepared_state(); + psm_prepared_state(psm_machine& m, pbft_database& pbft_db); ~psm_prepared_state(); - void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; + void on_prepare(const pbft_metadata_ptr& e) override; + void on_commit(const pbft_metadata_ptr& e) override; + void on_view_change(const pbft_metadata_ptr& e) override; + + void send_prepare() override; + void send_commit() override; + void send_view_change() override; - void send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) override; + void maybe_transit_to_committed(); bool pending_commit_local; @@ -139,32 +157,32 @@ namespace eosio { class psm_committed_state final: public psm_state { public: - psm_committed_state(); + psm_committed_state(psm_machine& m, pbft_database& pbft_db); ~psm_committed_state(); - void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; + void on_prepare(const pbft_metadata_ptr& e) override; + void on_commit(const pbft_metadata_ptr& e) override; + void on_view_change(const pbft_metadata_ptr& e) override; - void send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) override; + void send_prepare() override; + void send_commit() override; + void send_view_change() override; const char* get_name() override { return "{==== COMMITTED ====}"; } }; class psm_view_change_state final: public psm_state { public: - psm_view_change_state(); + psm_view_change_state(psm_machine& m, pbft_database& pbft_db); ~psm_view_change_state(); - void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; + void on_prepare(const pbft_metadata_ptr& e) override; + void on_commit(const pbft_metadata_ptr& e) override; + void on_view_change(const pbft_metadata_ptr& e) override; - void send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) override; + void send_prepare() override; + void send_commit() override; + void send_view_change() override; const char* get_name() override { return "{==== VIEW CHANGE ====}"; } }; @@ -174,10 +192,8 @@ namespace eosio { explicit pbft_controller(controller& ctrl); ~pbft_controller(); - const uint16_t view_change_timeout = 6; - - pbft_database pbft_db; - std::shared_ptr state_machine; + pbft_database pbft_db; + psm_machine state_machine; void maybe_pbft_prepare(); void maybe_pbft_commit(); @@ -192,6 +208,7 @@ namespace eosio { private: fc::path datadir; + uint16_t view_change_timeout = 6; }; } } /// namespace eosio::chain diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index b72f9645b66..6b4bb2cd7a9 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -19,7 +19,6 @@ namespace eosio { using pbft_view_type = uint32_t; - constexpr uint16_t pbft_checkpoint_granularity = 100; constexpr uint16_t oldest_stable_checkpoint = 10000; enum class pbft_message_type : uint8_t { @@ -37,11 +36,11 @@ namespace eosio { return fc::endian_reverse_u32(block_id._hash[0]); } - bool operator==(const block_info_type &rhs) const { + bool operator==(const block_info_type& rhs) const { return block_id == rhs.block_id; } - bool operator!=(const block_info_type &rhs) const { + bool operator!=(const block_info_type& rhs) const { return !(*this == rhs); } @@ -50,6 +49,8 @@ namespace eosio { } }; + using fork_info_type = vector; + struct pbft_message_common { explicit pbft_message_common(pbft_message_type t): type{t} {}; @@ -84,7 +85,7 @@ namespace eosio { block_info_type block_info; signature_type sender_signature; - bool operator<(const pbft_prepare &rhs) const { + bool operator<(const pbft_prepare& rhs) const { if (block_info.block_num() < rhs.block_info.block_num()) { return true; } else if (block_info.block_num() == rhs.block_info.block_num()) { @@ -120,7 +121,7 @@ namespace eosio { block_info_type block_info; signature_type sender_signature; - bool operator<(const pbft_commit &rhs) const { + bool operator<(const pbft_commit& rhs) const { if (block_info.block_num() < rhs.block_info.block_num()) { return true; } else if (block_info.block_num() == rhs.block_info.block_num()) { @@ -155,7 +156,7 @@ namespace eosio { block_info_type block_info; signature_type sender_signature; - bool operator<(const pbft_checkpoint &rhs) const { + bool operator<(const pbft_checkpoint& rhs) const { return block_info.block_num() < rhs.block_info.block_num(); } @@ -176,7 +177,7 @@ namespace eosio { block_info_type block_info; vector checkpoints; - bool operator<(const pbft_stable_checkpoint &rhs) const { + bool operator<(const pbft_stable_checkpoint& rhs) const { return block_info.block_num() < rhs.block_info.block_num(); } @@ -193,7 +194,7 @@ namespace eosio { set pre_prepares; vector prepares; - bool operator<(const pbft_prepared_certificate &rhs) const { + bool operator<(const pbft_prepared_certificate& rhs) const { return block_info.block_num() < rhs.block_info.block_num(); } @@ -209,7 +210,7 @@ namespace eosio { block_info_type block_info; vector commits; - bool operator<(const pbft_committed_certificate &rhs) const { + bool operator<(const pbft_committed_certificate& rhs) const { return block_info.block_num() < rhs.block_info.block_num(); } @@ -230,7 +231,7 @@ namespace eosio { pbft_stable_checkpoint stable_checkpoint; signature_type sender_signature; - bool operator<(const pbft_view_change &rhs) const { + bool operator<(const pbft_view_change& rhs) const { return target_view < rhs.target_view; } @@ -266,7 +267,7 @@ namespace eosio { bool empty() const { return !target_view - && view_changes.empty(); + && view_changes.empty(); } }; @@ -281,7 +282,7 @@ namespace eosio { pbft_view_changed_certificate view_changed_cert; signature_type sender_signature; - bool operator<(const pbft_new_view &rhs) const { + bool operator<(const pbft_new_view& rhs) const { return new_view < rhs.new_view; } @@ -298,7 +299,7 @@ namespace eosio { } bool empty() const { - return new_view == 0 + return !new_view && prepared_cert.empty() && committed_certs.empty() && stable_checkpoint.empty() @@ -415,30 +416,25 @@ namespace eosio { class pbft_database { public: - explicit pbft_database(controller &ctrl); - + explicit pbft_database(controller& ctrl); ~pbft_database(); - void close(); - - void add_pbft_prepare(pbft_prepare &p, const public_key_type &pk); - void add_pbft_commit(pbft_commit &c, const public_key_type &pk); - void add_pbft_view_change(pbft_view_change &vc, const public_key_type &pk); - void add_pbft_checkpoint(pbft_checkpoint &cp, const public_key_type &pk); - - pbft_prepare send_and_add_pbft_prepare(const pbft_prepare &cached_prepare = pbft_prepare(), pbft_view_type current_view = 0); - pbft_commit send_and_add_pbft_commit(const pbft_commit &cached_commit = pbft_commit(), pbft_view_type current_view = 0); - pbft_view_change send_and_add_pbft_view_change( - const pbft_view_change &cached_view_change = pbft_view_change(), - const pbft_prepared_certificate &ppc = pbft_prepared_certificate(), - const vector &pcc = vector{}, - pbft_view_type current_view = 0, + void add_pbft_prepare(const pbft_prepare& p, const public_key_type& pk); + void add_pbft_commit(const pbft_commit& c, const public_key_type& pk); + void add_pbft_view_change(const pbft_view_change& vc, const public_key_type& pk); + void add_pbft_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk); + + vector generate_and_add_pbft_prepare(const pbft_prepare& cached_prepare = pbft_prepare()); + vector generate_and_add_pbft_commit(const pbft_commit& cached_commit = pbft_commit()); + vector generate_and_add_pbft_view_change( + const pbft_view_change& cached_view_change = pbft_view_change(), + const pbft_prepared_certificate& ppc = pbft_prepared_certificate(), + const vector& pcc = vector{}, pbft_view_type target_view = 1); - pbft_new_view send_pbft_new_view( - const pbft_view_changed_certificate &vcc = pbft_view_changed_certificate(), - pbft_view_type current_view = 1); + pbft_new_view generate_pbft_new_view( + const pbft_view_changed_certificate& vcc = pbft_view_changed_certificate(), + pbft_view_type new_view = 1); vector generate_and_add_pbft_checkpoint(); - void send_pbft_checkpoint(); bool should_prepared(); bool should_committed(); @@ -446,13 +442,13 @@ namespace eosio { bool should_new_view(pbft_view_type target_view); //new view - bool has_new_primary(const public_key_type &pk); + bool has_new_primary(const public_key_type& pk); pbft_view_type get_proposed_new_view_num(); pbft_view_type get_committed_view(); public_key_type get_new_view_primary_key(pbft_view_type target_view); - void mark_as_prepared(const block_id_type &bid); - void mark_as_committed(const block_id_type &bid); + void mark_as_prepared(const block_id_type& bid); + void mark_as_committed(const block_id_type& bid); void commit_local(); void checkpoint_local(); @@ -460,43 +456,39 @@ namespace eosio { pbft_prepared_certificate generate_prepared_certificate(); vector generate_committed_certificate(); pbft_view_changed_certificate generate_view_changed_certificate(pbft_view_type target_view); - bool should_stop_view_change(const pbft_view_change &vc); + bool should_stop_view_change(const pbft_view_change& vc); //validations - bool is_valid_prepare(const pbft_prepare &p, const public_key_type &pk); - bool is_valid_commit(const pbft_commit &c, const public_key_type &pk); - bool is_valid_checkpoint(const pbft_checkpoint &cp, const public_key_type &pk); - bool is_valid_view_change(const pbft_view_change &vc, const public_key_type &pk); - void validate_new_view(const pbft_new_view &nv, const public_key_type &pk); - bool is_valid_stable_checkpoint(const pbft_stable_checkpoint &scp, bool add_to_pbft_db = false); + bool is_valid_prepare(const pbft_prepare& p, const public_key_type& pk); + bool is_valid_commit(const pbft_commit& c, const public_key_type& pk); + bool is_valid_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk); + bool is_valid_view_change(const pbft_view_change& vc, const public_key_type& pk); + void validate_new_view(const pbft_new_view& nv, const public_key_type& pk); + bool is_valid_stable_checkpoint(const pbft_stable_checkpoint& scp, bool add_to_pbft_db = false); bool should_send_pbft_msg(); - bool should_recv_pbft_msg(const public_key_type &pub_key); + bool should_recv_pbft_msg(const public_key_type& pub_key); bool pending_pbft_lib(); - chain_id_type& get_chain_id() {return chain_id;} - pbft_stable_checkpoint get_stable_checkpoint_by_id(const block_id_type &block_id, bool incl_blk_extn = true); - pbft_stable_checkpoint fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr &b); - block_info_type cal_pending_stable_checkpoint() const; + chain_id_type& get_chain_id() { return chain_id; } + pbft_stable_checkpoint get_stable_checkpoint_by_id(const block_id_type& block_id, bool incl_blk_extn = true); + pbft_stable_checkpoint fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr& b); void cleanup_on_new_view(); void update_fork_schedules(); + uint16_t get_view_change_timeout() const; + uint16_t get_checkpoint_interval() const; + const pbft_view_type get_current_view() { return _current_view; } + void set_current_view(pbft_view_type view) { _current_view = view; } //api related - pbft_state_ptr get_pbft_state_by_id(const block_id_type &id) const; - vector get_checkpoints_by_num(const block_num_type &num) const; - pbft_view_change_state_ptr get_view_changes_by_target_view(const pbft_view_type &tv) const; + pbft_state_ptr get_pbft_state_by_id(const block_id_type& id) const; + vector get_checkpoints_by_num(block_num_type num) const; + pbft_view_change_state_ptr get_view_changes_by_target_view(pbft_view_type tv) const; vector get_pbft_watermarks() const; flat_map get_pbft_fork_schedules() const; - - signal pbft_outgoing_prepare; - signal pbft_outgoing_commit; - signal pbft_outgoing_view_change; - signal pbft_outgoing_new_view; - signal pbft_outgoing_checkpoint; - private: - controller &ctrl; + controller& ctrl; pbft_state_multi_index_type pbft_state_index; pbft_view_state_multi_index_type view_state_index; pbft_checkpoint_state_multi_index_type checkpoint_index; @@ -505,28 +497,26 @@ namespace eosio { vector prepare_watermarks; flat_map fork_schedules; chain_id_type chain_id = ctrl.get_chain_id(); + pbft_view_type _current_view = 0; - - bool is_less_than_high_watermark(const block_num_type &bnum); - bool is_valid_prepared_certificate(const pbft_prepared_certificate &certificate, bool add_to_pbft_db = false); - bool is_valid_committed_certificate(const pbft_committed_certificate &certificate, bool add_to_pbft_db = false); - bool is_valid_longest_fork(const block_info_type &bi, vector block_infos, unsigned long threshold, unsigned long non_fork_bp_count); + block_info_type cal_pending_stable_checkpoint() const; + bool is_less_than_high_watermark(block_num_type bnum); + bool is_valid_prepared_certificate(const pbft_prepared_certificate& certificate, bool add_to_pbft_db = false); + bool is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db = false); + bool is_valid_longest_fork(const block_info_type& bi, fork_info_type& block_infos, unsigned long threshold, unsigned long non_fork_bp_count); producer_schedule_type lscb_active_producers() const; vector& get_updated_watermarks(); flat_map& get_updated_fork_schedules(); block_num_type get_current_pbft_watermark(); - vector> fetch_fork_from(vector &block_infos); - vector fetch_first_fork_from(vector &bi); - - template - void emit(const Signal &s, Arg &&a); + vector fetch_fork_from(fork_info_type& block_infos); + fork_info_type fetch_first_fork_from(fork_info_type& bi); void set(const pbft_state_ptr& s); void set(const pbft_checkpoint_state_ptr& s); - void prune(const pbft_state_ptr &h); - void prune(const pbft_checkpoint_state_ptr &h); + void prune(const pbft_state_ptr& h); + void prune(const pbft_checkpoint_state_ptr& h); }; } } /// namespace eosio::chain diff --git a/libraries/chain/include/eosio/chain/types.hpp b/libraries/chain/include/eosio/chain/types.hpp index f8360c0bc7d..4cf8b055cd2 100644 --- a/libraries/chain/include/eosio/chain/types.hpp +++ b/libraries/chain/include/eosio/chain/types.hpp @@ -190,6 +190,7 @@ namespace eosio { namespace chain { action_history_object_type, ///< Defined by history_plugin reversible_block_object_type, upgrade_property_object_type, + global_property3_object_type, OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types }; diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index ccc5598dc63..8ac97cb1c49 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -1,5 +1,3 @@ -#include - #include #include #include @@ -7,134 +5,104 @@ namespace eosio { namespace chain { - pbft_controller::pbft_controller(controller &ctrl) : - pbft_db(ctrl), - state_machine(new psm_machine(pbft_db)) { - datadir = ctrl.state_dir(); - - if (!fc::is_directory(datadir)) - fc::create_directories(datadir); - - auto pbft_db_dat = datadir / config::pbftdb_filename; - if (fc::exists(pbft_db_dat)) { - string content; - fc::read_file_contents(pbft_db_dat, content); - - fc::datastream ds(content.data(), content.size()); - uint32_t current_view; - fc::raw::unpack(ds, current_view); - state_machine->set_current_view(current_view); - state_machine->set_target_view(state_machine->get_current_view() + 1); - ilog("current view: ${cv}", ("cv", current_view)); - } - - fc::remove(pbft_db_dat); + pbft_controller::pbft_controller(controller& ctrl) : + pbft_db(ctrl), + state_machine(pbft_db) { + state_machine.set_current(std::make_shared(state_machine, pbft_db)); + state_machine.set_current_view(pbft_db.get_current_view()); + state_machine.set_target_view(state_machine.get_current_view() + 1); + ilog("current view: ${cv}", ("cv", pbft_db.get_current_view())); } - pbft_controller::~pbft_controller() { - fc::path pbft_db_dat = datadir / config::pbftdb_filename; - std::ofstream out(pbft_db_dat.generic_string().c_str(), - std::ios::out | std::ios::binary | std::ofstream::trunc); - - uint32_t current_view = state_machine->get_current_view(); - fc::raw::pack(out, current_view); - } + pbft_controller::~pbft_controller() = default; void pbft_controller::maybe_pbft_prepare() { if (!pbft_db.should_send_pbft_msg()) return; - state_machine->send_prepare(); + state_machine.send_prepare(); } void pbft_controller::maybe_pbft_commit() { if (!pbft_db.should_send_pbft_msg()) return; - state_machine->send_commit(); + state_machine.send_commit(); } void pbft_controller::maybe_pbft_view_change() { if (!pbft_db.should_send_pbft_msg()) return; - if (state_machine->get_view_change_timer() <= view_change_timeout) { - if (!state_machine->get_view_changes_cache().empty()) { - pbft_db.send_and_add_pbft_view_change(state_machine->get_view_changes_cache()); + + if (view_change_timeout != pbft_db.get_view_change_timeout()) { + ///if there is a change in global states, update timeout and reset timer. + view_change_timeout = pbft_db.get_view_change_timeout(); + state_machine.set_view_change_timer(0); + } + + if (state_machine.get_view_change_timer() <= view_change_timeout) { + if (!state_machine.get_view_change_cache().empty()) { + pbft_db.generate_and_add_pbft_view_change(state_machine.get_view_change_cache()); } - state_machine->set_view_change_timer(state_machine->get_view_change_timer() + 1); + state_machine.set_view_change_timer(state_machine.get_view_change_timer() + 1); } else { - state_machine->set_view_change_timer(0); - state_machine->send_view_change(); + state_machine.set_view_change_timer(0); + state_machine.send_view_change(); } } void pbft_controller::maybe_pbft_checkpoint() { if (!pbft_db.should_send_pbft_msg()) return; - pbft_db.send_pbft_checkpoint(); + state_machine.send_checkpoint(); pbft_db.checkpoint_local(); } void pbft_controller::on_pbft_prepare(const pbft_metadata_ptr& p) { - state_machine->on_prepare(p); + state_machine.on_prepare(p); } void pbft_controller::on_pbft_commit(const pbft_metadata_ptr& c) { - state_machine->on_commit(c); + state_machine.on_commit(c); } void pbft_controller::on_pbft_view_change(const pbft_metadata_ptr& vc) { - state_machine->on_view_change(vc); + state_machine.on_view_change(vc); } void pbft_controller::on_pbft_new_view(const pbft_metadata_ptr& nv) { - state_machine->on_new_view(nv); + state_machine.on_new_view(nv); } - void pbft_controller::on_pbft_checkpoint(const pbft_metadata_ptr &cp) { + void pbft_controller::on_pbft_checkpoint(const pbft_metadata_ptr& cp) { if (!pbft_db.is_valid_checkpoint(cp->msg, cp->sender_key)) return; pbft_db.add_pbft_checkpoint(cp->msg, cp->sender_key); pbft_db.checkpoint_local(); } - psm_state::psm_state() = default; + psm_state::psm_state(psm_machine& m, pbft_database& pbft_db) : m(m), pbft_db(pbft_db){} psm_state::~psm_state() = default; - psm_machine::psm_machine(pbft_database &pbft_db) : pbft_db(pbft_db) { - set_current(std::make_shared()); - - set_prepares_cache(pbft_prepare()); - set_commits_cache(pbft_commit()); - set_view_changes_cache(pbft_view_change()); - - set_prepared_certificate(pbft_prepared_certificate{}); - set_committed_certificate(vector{}); - set_view_changed_certificate(pbft_view_changed_certificate{}); - - view_change_timer = 0; - target_view_retries = 0; - current_view = 0; - target_view = current_view + 1; - } + psm_machine::psm_machine(pbft_database& pbft_db) : pbft_db(pbft_db) {} psm_machine::~psm_machine() = default; void psm_machine::on_prepare(const pbft_metadata_ptr& e) { - current->on_prepare(shared_from_this(), e, pbft_db); + current->on_prepare(e); } void psm_machine::send_prepare() { - current->send_prepare(shared_from_this(), pbft_db); + current->send_prepare(); } void psm_machine::on_commit(const pbft_metadata_ptr& e) { - current->on_commit(shared_from_this(), e, pbft_db); + current->on_commit(e); } void psm_machine::send_commit() { - current->send_commit(shared_from_this(), pbft_db); + current->send_commit(); } void psm_machine::on_view_change(const pbft_metadata_ptr& e) { - current->on_view_change(shared_from_this(), e, pbft_db); + current->on_view_change(e); } void psm_machine::send_view_change() { - current->send_view_change(shared_from_this(), pbft_db); + current->send_view_change(); } void psm_machine::on_new_view(const pbft_metadata_ptr& e) { @@ -148,42 +116,28 @@ namespace eosio { } try { - transit_to_new_view(e, current); + transit_to_new_view(e); } catch(...) { elog("apply new view failed, waiting for next round.. ${nv} ", ("nv", e->msg)); } } - void psm_machine::manually_set_current_view(const uint32_t &cv) { + void psm_machine::manually_set_current_view(uint32_t cv) { set_current_view(cv); + pbft_db.set_current_view(cv); set_target_view(cv + 1); - transit_to_view_change_state(current); + transit_to_view_change_state(); } - /** + /**\ + * * psm_prepared_state */ - psm_prepared_state::psm_prepared_state() {pending_commit_local = false;} + psm_prepared_state::psm_prepared_state(psm_machine& m, pbft_database& pbft_db) : psm_state(m, pbft_db) {pending_commit_local = false;} psm_prepared_state::~psm_prepared_state() = default; - void psm_prepared_state::on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { - //ignore - } - - void psm_prepared_state::send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) { - //retry - if (m->get_prepares_cache().empty()) return; - - pbft_db.send_and_add_pbft_prepare(m->get_prepares_cache(), m->get_current_view()); - } - - void psm_prepared_state::on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { - - if (e->msg.view < m->get_current_view()) return; - if (!pbft_db.is_valid_commit(e->msg, e->sender_key)) return; - - pbft_db.add_pbft_commit(e->msg, e->sender_key); + void psm_prepared_state::maybe_transit_to_committed() { //`pending_commit_local` is used to mark committed local status in psm machine; //`pbft_db.pending_pbft_lib()` is used to mark commit local status in controller; @@ -195,214 +149,209 @@ namespace eosio { } if (pending_commit_local && !pbft_db.pending_pbft_lib()) { - pbft_db.send_pbft_checkpoint(); - pbft_db.checkpoint_local(); - m->transit_to_committed_state(shared_from_this(), false); + m.transit_to_committed_state(false); } } - void psm_prepared_state::send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) { - auto commits = pbft_db.send_and_add_pbft_commit(m->get_commits_cache(), m->get_current_view()); + void psm_prepared_state::on_prepare(const pbft_metadata_ptr& e) { + //ignore + } - if (!commits.empty()) { - m->set_commits_cache(commits); - } + void psm_prepared_state::send_prepare() { + //retry + if (m.get_prepare_cache().empty()) return; + m.do_send_prepare(); + } - if (pbft_db.should_committed() && !pending_commit_local) { - pbft_db.commit_local(); - pending_commit_local = true; - } + void psm_prepared_state::on_commit(const pbft_metadata_ptr& e) { - if (pending_commit_local && !pbft_db.pending_pbft_lib()) { - pbft_db.send_pbft_checkpoint(); - pbft_db.checkpoint_local(); - m->transit_to_committed_state(shared_from_this(), false); - } + if (e->msg.view < m.get_current_view()) return; + if (!pbft_db.is_valid_commit(e->msg, e->sender_key)) return; + + pbft_db.add_pbft_commit(e->msg, e->sender_key); + maybe_transit_to_committed(); + } + + void psm_prepared_state::send_commit() { + + m.do_send_commit(); + maybe_transit_to_committed(); } - void psm_prepared_state::on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_prepared_state::on_view_change(const pbft_metadata_ptr& e) { - if (e->msg.target_view <= m->get_current_view()) return; + if (e->msg.target_view <= m.get_current_view()) return; if (!pbft_db.is_valid_view_change(e->msg, e->sender_key)) return; pbft_db.add_pbft_view_change(e->msg, e->sender_key); - - //if received >= f+1 view_change on some view, transit to view_change and send view change - auto target_view = pbft_db.should_view_change(); - if (target_view > 0 && target_view > m->get_current_view()) { - m->set_target_view(target_view); - m->transit_to_view_change_state(shared_from_this()); - } + m.maybe_view_change(); } - void psm_prepared_state::send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) { - m->transit_to_view_change_state(shared_from_this()); + void psm_prepared_state::send_view_change() { + m.transit_to_view_change_state(); } - psm_committed_state::psm_committed_state() = default; + psm_committed_state::psm_committed_state(psm_machine& m, pbft_database& pbft_db) : psm_state(m, pbft_db) {} psm_committed_state::~psm_committed_state() = default; /** * psm_committed_state */ - void psm_committed_state::on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_committed_state::on_prepare(const pbft_metadata_ptr& e) { //validate - if (e->msg.view < m->get_current_view()) return; + if (e->msg.view < m.get_current_view()) return; if (!pbft_db.is_valid_prepare(e->msg, e->sender_key)) return; //do action add prepare pbft_db.add_pbft_prepare(e->msg, e->sender_key); - - //if prepare >= 2f+1, transit to prepared - if (pbft_db.should_prepared()) m->transit_to_prepared_state(shared_from_this()); + //if prepare >= n-f, transit to prepared + if (pbft_db.should_prepared()) m.transit_to_prepared_state(); } - void psm_committed_state::send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) { - - auto prepares = pbft_db.send_and_add_pbft_prepare(m->get_prepares_cache(), m->get_current_view()); - - if (!prepares.empty()) { - m->set_prepares_cache(prepares); - } + void psm_committed_state::send_prepare() { - //if prepare >= 2f+1, transit to prepared - if (pbft_db.should_prepared()) m->transit_to_prepared_state(shared_from_this()); + m.do_send_prepare(); + //if prepare >= n-f, transit to prepared + if (pbft_db.should_prepared()) m.transit_to_prepared_state(); } - void psm_committed_state::on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_committed_state::on_commit(const pbft_metadata_ptr& e) { - if (e->msg.view < m->get_current_view()) return; + if (e->msg.view < m.get_current_view()) return; if (!pbft_db.is_valid_commit(e->msg, e->sender_key)) return; pbft_db.add_pbft_commit(e->msg, e->sender_key); } - void psm_committed_state::send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) { - - if (m->get_commits_cache().empty()) return; - pbft_db.send_and_add_pbft_commit(m->get_commits_cache(), m->get_current_view()); + void psm_committed_state::send_commit() { + if (m.get_commit_cache().empty()) return; + m.do_send_commit(); } - void psm_committed_state::on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_committed_state::on_view_change(const pbft_metadata_ptr& e) { - if (e->msg.target_view <= m->get_current_view()) return; + if (e->msg.target_view <= m.get_current_view()) return; if (!pbft_db.is_valid_view_change(e->msg, e->sender_key)) return; pbft_db.add_pbft_view_change(e->msg, e->sender_key); - - //if received >= f+1 view_change on some view, transit to view_change and send view change - auto new_view = pbft_db.should_view_change(); - if (new_view > 0 && new_view > m->get_current_view()) { - m->set_target_view(new_view); - m->transit_to_view_change_state(shared_from_this()); - } + m.maybe_view_change(); } - void psm_committed_state::send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) { - m->transit_to_view_change_state(shared_from_this()); + void psm_committed_state::send_view_change() { + m.transit_to_view_change_state(); } - psm_view_change_state::psm_view_change_state() = default; + psm_view_change_state::psm_view_change_state(psm_machine& m, pbft_database& pbft_db) : psm_state(m, pbft_db) {} psm_view_change_state::~psm_view_change_state() = default; /** * psm_view_change_state */ - void psm_view_change_state::on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_view_change_state::on_prepare(const pbft_metadata_ptr& e) { //ignore; } - void psm_view_change_state::send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) { + void psm_view_change_state::send_prepare() { //ignore; } - void psm_view_change_state::on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_view_change_state::on_commit(const pbft_metadata_ptr& e) { //ignore; } - void psm_view_change_state::send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) { + void psm_view_change_state::send_commit() { //ignore; } - void psm_view_change_state::on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_view_change_state::on_view_change(const pbft_metadata_ptr& e) { - //skip from view change state if my lib is higher than my view change state height. - auto vc = m->get_view_changes_cache(); - if (!vc.empty() && pbft_db.should_stop_view_change(vc)) { - m->transit_to_committed_state(shared_from_this(), false); - return; - } + if (m.maybe_stop_view_change()) return; - if (e->msg.target_view <= m->get_current_view()) return; + if (e->msg.target_view <= m.get_current_view()) return; if (!pbft_db.is_valid_view_change(e->msg, e->sender_key)) return; pbft_db.add_pbft_view_change(e->msg, e->sender_key); - - m->maybe_new_view(shared_from_this()); + m.maybe_new_view(); } - void psm_view_change_state::send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) { - - //skip from view change state if my lib is higher than my view change state height. - auto vc = m->get_view_changes_cache(); - if (!vc.empty() && pbft_db.should_stop_view_change(vc)) { - m->transit_to_committed_state(shared_from_this(), false); - return; - } + void psm_view_change_state::send_view_change() { - m->do_send_view_change(); + if (m.maybe_stop_view_change()) return; - m->maybe_new_view(shared_from_this()); + m.do_send_view_change(); + m.maybe_new_view(); } - void psm_machine::transit_to_committed_state(const psm_state_ptr& s, bool to_new_view) { + void psm_machine::transit_to_committed_state(bool to_new_view) { if (!to_new_view) { auto nv = pbft_db.get_committed_view(); - if (nv > get_current_view()) set_current_view(nv); + if (nv > get_current_view()) { + set_current_view(nv); + pbft_db.set_current_view(nv); + } set_target_view(get_current_view() + 1); } - auto prepares = pbft_db.send_and_add_pbft_prepare(pbft_prepare(), get_current_view()); - set_prepares_cache(prepares); - //TODO: reset prepare timer; + set_prepare_cache(pbft_prepare()); + do_send_prepare(); - set_view_changes_cache(pbft_view_change()); + set_view_change_cache(pbft_view_change()); set_view_change_timer(0); - set_current(std::make_shared()); + set_current(std::make_shared(*this, pbft_db)); + emit(pbft_transit_to_committed, true); } - void psm_machine::transit_to_prepared_state(const psm_state_ptr& s) { + void psm_machine::transit_to_prepared_state() { - auto commits = pbft_db.send_and_add_pbft_commit(pbft_commit(), get_current_view()); - set_commits_cache(commits); - //TODO: reset commit timer; + set_commit_cache(pbft_commit()); + do_send_commit(); - set_view_changes_cache(pbft_view_change()); + set_view_change_cache(pbft_view_change()); - set_current(std::make_shared()); + set_current(std::make_shared(*this, pbft_db)); + emit(pbft_transit_to_prepared, true); } - void psm_machine::transit_to_view_change_state(const psm_state_ptr& s) { + void psm_machine::transit_to_view_change_state() { - set_commits_cache(pbft_commit()); - set_prepares_cache(pbft_prepare()); + set_commit_cache(pbft_commit()); + set_prepare_cache(pbft_prepare()); set_view_change_timer(0); set_target_view_retries(0); - set_current(std::make_shared()); + set_current(std::make_shared(*this, pbft_db)); if (pbft_db.should_send_pbft_msg()) { do_send_view_change(); - auto nv = maybe_new_view(s); + auto nv = maybe_new_view(); if (nv) return; } } - bool psm_machine::maybe_new_view(const psm_state_ptr &s) { - //if view_change >= 2f+1, calculate next primary, send new view if is primary + void psm_machine::maybe_view_change() { + //if received >= f+1 view_change on some view, transit to view_change and send view change + auto new_view = pbft_db.should_view_change(); + if (new_view > 0 && new_view > get_current_view()) { + set_target_view(new_view); + transit_to_view_change_state(); + } + } + + bool psm_machine::maybe_stop_view_change() { + //skip from view change state if my lib is higher than my view change state height. + auto vc = get_view_change_cache(); + if (!vc.empty() && pbft_db.should_stop_view_change(vc)) { + transit_to_committed_state(false); + return true; + } + return false; + } + + bool psm_machine::maybe_new_view() { + //if view_change >= n-f, calculate next primary, send new view if is primary auto nv = get_target_view(); auto pk = pbft_db.get_new_view_primary_key(nv); if (pbft_db.should_new_view(nv) && pbft_db.has_new_primary(pk)) { @@ -412,14 +361,15 @@ namespace eosio { auto new_view = pbft_db.get_proposed_new_view_num(); if (new_view != nv) return false; - auto nv_msg = pbft_db.send_pbft_new_view( + auto nv_msg = pbft_db.generate_pbft_new_view( get_view_changed_certificate(), new_view); if (nv_msg.empty()) return false; + emit(pbft_outgoing_new_view, std::make_shared(nv_msg)); try { - transit_to_new_view(std::make_shared>(nv_msg, pbft_db.get_chain_id()), s); + transit_to_new_view(std::make_shared>(nv_msg, pbft_db.get_chain_id())); return true; } catch(const fc::exception& ex) { elog("apply new view failed, waiting for next round.. ${nv} ", ("nv", nv_msg)); @@ -428,12 +378,13 @@ namespace eosio { return false; } - void psm_machine::transit_to_new_view(const pbft_metadata_ptr& e, const psm_state_ptr& s) { + void psm_machine::transit_to_new_view(const pbft_metadata_ptr& e) { set_current_view(e->msg.new_view); + pbft_db.set_current_view(e->msg.new_view); set_target_view(e->msg.new_view + 1); - set_prepares_cache(pbft_prepare()); + set_prepare_cache(pbft_prepare()); set_view_change_timer(0); set_target_view_retries(0); @@ -443,7 +394,7 @@ namespace eosio { if (!e->msg.committed_certs.empty()) { auto committed_certs = e->msg.committed_certs; std::sort(committed_certs.begin(), committed_certs.end()); - for (auto const &cc :committed_certs) { + for (const auto& cc :committed_certs) { pbft_db.mark_as_committed(cc.block_info.block_id); } } @@ -451,7 +402,7 @@ namespace eosio { if (!e->msg.prepared_cert.prepares.empty()) { pbft_db.mark_as_prepared(e->msg.prepared_cert.block_info.block_id); if (pbft_db.should_prepared()) { - transit_to_prepared_state(s); + transit_to_prepared_state(); return; } } @@ -459,13 +410,34 @@ namespace eosio { if (pbft_db.should_committed()) { pbft_db.commit_local(); } - transit_to_committed_state(s, true); + transit_to_committed_state(true); + } + + void psm_machine::do_send_prepare() { + auto prepares = pbft_db.generate_and_add_pbft_prepare(get_prepare_cache()); + if (!prepares.empty()) { + for (const auto& p: prepares) { + emit(pbft_outgoing_prepare, std::make_shared(p)); + } + set_prepare_cache(prepares.front()); + } + } + + void psm_machine::do_send_commit() { + auto commits = pbft_db.generate_and_add_pbft_commit(get_commit_cache()); + + if (!commits.empty()) { + for (const auto& c: commits) { + emit(pbft_outgoing_commit, std::make_shared(c)); + } + set_commit_cache(commits.front()); + } } void psm_machine::do_send_view_change() { auto reset_view_change_state = [&]() { - set_view_changes_cache(pbft_view_change()); + set_view_change_cache(pbft_view_change()); set_prepared_certificate(pbft_db.generate_prepared_certificate()); set_committed_certificate(pbft_db.generate_committed_certificate()); }; @@ -482,96 +454,42 @@ namespace eosio { EOS_ASSERT((get_target_view() > get_current_view()), pbft_exception, "target view should be always greater than current view"); - auto view_changes = pbft_db.send_and_add_pbft_view_change( - get_view_changes_cache(), + auto view_changes = pbft_db.generate_and_add_pbft_view_change( + get_view_change_cache(), get_prepared_certificate(), get_committed_certificate(), - get_current_view(), get_target_view()); if (!view_changes.empty()) { - set_view_changes_cache(view_changes); + for (const auto& vc : view_changes) { + emit(pbft_outgoing_view_change, std::make_shared(vc)); + } + set_view_change_cache(view_changes.front()); } } - const pbft_prepare& psm_machine::get_prepares_cache() const { - return cache.prepares_cache; - } - - void psm_machine::set_prepares_cache(const pbft_prepare &pcache) { - cache.prepares_cache = pcache; - } - - const pbft_commit& psm_machine::get_commits_cache() const { - return cache.commits_cache; - } - - void psm_machine::set_commits_cache(const pbft_commit &ccache) { - cache.commits_cache = ccache; - } - - const pbft_view_change& psm_machine::get_view_changes_cache() const { - return cache.view_changes_cache; - } - - void psm_machine::set_view_changes_cache(const pbft_view_change &vc_cache) { - cache.view_changes_cache = vc_cache; - } - - const uint32_t& psm_machine::get_current_view() const { - return current_view; - } - - void psm_machine::set_current_view(const uint32_t &cv) { - current_view = cv; - } - - const pbft_prepared_certificate& psm_machine::get_prepared_certificate() const { - return cache.prepared_certificate; - } - - void psm_machine::set_prepared_certificate(const pbft_prepared_certificate &pcert) { - cache.prepared_certificate = pcert; - } - - const vector& psm_machine::get_committed_certificate() const { - return cache.committed_certificate; - } - - void psm_machine::set_committed_certificate(const vector &ccert) { - cache.committed_certificate = ccert; - } - - const pbft_view_changed_certificate& psm_machine::get_view_changed_certificate() const { - return cache.view_changed_certificate; - } - - void psm_machine::set_view_changed_certificate(const pbft_view_changed_certificate &vc_cert) { - cache.view_changed_certificate = vc_cert; - } - - const uint32_t& psm_machine::get_target_view_retries() const { - return target_view_retries; - } - - void psm_machine::set_target_view_retries(const uint32_t &tv_reties) { - target_view_retries = tv_reties; - } - - const uint32_t& psm_machine::get_target_view() const { - return target_view; - } - - void psm_machine::set_target_view(const uint32_t &tv) { - target_view = tv; - } - - const uint32_t& psm_machine::get_view_change_timer() const { - return view_change_timer; + void psm_machine::send_checkpoint() { + auto checkpoints = pbft_db.generate_and_add_pbft_checkpoint(); + for (const auto& cp: checkpoints) { + emit(pbft_outgoing_checkpoint, std::make_shared(cp)); + } } - void psm_machine::set_view_change_timer(const uint32_t &vc_timer) { - view_change_timer = vc_timer; + template + void psm_machine::emit(const Signal& s, Arg&& a) { + try { + s(std::forward(a)); + } 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 (...) { + wlog("signal handler threw exception"); + } } } } \ No newline at end of file diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 3e2a71fd86f..5bf4a743bd1 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -6,8 +6,7 @@ namespace eosio { namespace chain { - pbft_database::pbft_database(controller &ctrl) : - ctrl(ctrl) { + pbft_database::pbft_database(controller& ctrl) :ctrl(ctrl) { checkpoint_index = pbft_checkpoint_state_multi_index_type(); view_state_index = pbft_view_state_multi_index_type(); prepare_watermarks = vector{}; @@ -24,8 +23,8 @@ namespace eosio { fc::datastream ds(content.data(), content.size()); - //skip current_view in pbftdb.dat. - ds.seekp(ds.tellp() + 4); + //set current_view in pbftdb.dat. + fc::raw::unpack(ds, _current_view); unsigned_int size; fc::raw::unpack(ds, size); @@ -62,7 +61,7 @@ namespace eosio { fc::remove(checkpoints_db); } - void pbft_database::close() { + pbft_database::~pbft_database() { fc::path checkpoints_db = checkpoints_dir / config::checkpoints_filename; std::ofstream c_out(checkpoints_db.generic_string().c_str(), @@ -71,17 +70,19 @@ namespace eosio { uint32_t num_records_in_checkpoint_db = checkpoint_index.size(); fc::raw::pack(c_out, unsigned_int{num_records_in_checkpoint_db}); - for (auto const &s: checkpoint_index) { + for (const auto& s: checkpoint_index) { fc::raw::pack(c_out, *s); } fc::path pbft_db_dat = pbft_db_dir / config::pbftdb_filename; std::ofstream out(pbft_db_dat.generic_string().c_str(), - std::ios::out | std::ios::binary | std::ofstream::app); + std::ios::out | std::ios::binary | std::ofstream::trunc); + fc::raw::pack(out, _current_view); + uint32_t num_records_in_db = pbft_state_index.size(); fc::raw::pack(out, unsigned_int{num_records_in_db}); - for (auto const &s : pbft_state_index) { + for (const auto& s : pbft_state_index) { fc::raw::pack(out, *s); } @@ -89,13 +90,9 @@ namespace eosio { checkpoint_index.clear(); } - pbft_database::~pbft_database() { - close(); - } - - void pbft_database::add_pbft_prepare(pbft_prepare &p, const public_key_type &pk) { + void pbft_database::add_pbft_prepare(const pbft_prepare& p, const public_key_type& pk) { - auto &by_block_id_index = pbft_state_index.get(); + auto& by_block_id_index = pbft_state_index.get(); auto current = ctrl.fetch_block_state_by_id(p.block_info.block_id); @@ -118,9 +115,11 @@ namespace eosio { } else { auto prepares = (*curr_itr)->prepares; if (prepares.find(std::make_pair(p.view, pk)) == prepares.end()) { - by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr &psp) { + by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr& psp) { psp->prepares[std::make_pair(p.view, pk)] = p; }); + } else { + return; } } curr_itr = by_block_id_index.find(current->id); @@ -132,16 +131,16 @@ namespace eosio { auto threshold = as.size()* 2 / 3 + 1; if (prepares.size() >= threshold && !cpsp->is_prepared && is_less_than_high_watermark(cpsp->block_num)) { flat_map prepare_count; - for (auto const &pre: prepares) { + for (const auto& pre: prepares) { if (prepare_count.find(pre.second.view) == prepare_count.end()) prepare_count[pre.second.view] = 0; } - for (auto const &bp: as) { - for (auto const &pp: prepares) { + for (const auto& bp: as) { + for (const auto& pp: prepares) { if (bp.block_signing_key == pp.first.second) prepare_count[pp.first.first] += 1; } } - for (auto const &e: prepare_count) { + for (const auto& e: prepare_count) { if (e.second >= threshold) { mark_as_prepared(cpsp->block_id); } @@ -151,8 +150,8 @@ namespace eosio { } } - void pbft_database::mark_as_prepared(const block_id_type &bid) { - auto &by_block_id_index = pbft_state_index.get(); + void pbft_database::mark_as_prepared(const block_id_type& bid) { + auto& by_block_id_index = pbft_state_index.get(); auto itr = by_block_id_index.find(bid); auto bnum = block_info_type{bid}.block_num(); @@ -165,48 +164,54 @@ namespace eosio { pbft_state_index.insert(psp); return; } - by_block_id_index.modify(itr, [&](const pbft_state_ptr &p) { p->is_prepared = true; }); + by_block_id_index.modify(itr, [&](const pbft_state_ptr& p) { p->is_prepared = true; }); } - pbft_prepare pbft_database::send_and_add_pbft_prepare(const pbft_prepare &cached_prepare, pbft_view_type current_view) { - auto prepare_to_be_cached = pbft_prepare(); - + vector pbft_database::generate_and_add_pbft_prepare(const pbft_prepare& cached_prepare) { + vector prepares_to_be_cached; + const auto& my_sps = ctrl.my_signature_providers(); + prepares_to_be_cached.reserve(my_sps.size()); auto head_block_num = ctrl.head_block_num(); - if (head_block_num <= 1) return prepare_to_be_cached; + if (head_block_num <= 1) return prepares_to_be_cached; auto my_prepare = ctrl.get_pbft_my_prepare(); - auto reserve_prepare = [&](const block_id_type &in) { - if (in == block_id_type() || !ctrl.fetch_block_state_by_id(in)) return false; + auto reserve_prepare = [&](const block_id_type& in) { + if (in == block_id_type()) return false; + auto bs = ctrl.fetch_block_state_by_id(in); + if (!bs) return false; auto lib = ctrl.last_irreversible_block_id(); if (lib == block_id_type()) return true; auto forks = ctrl.fork_db().fetch_branch_from(in, lib); //`branch_type` will always contain at least themselves. //`in` block num should be higher than lib, yet fall on the same branch with lib. - return forks.first.size() > 1 && forks.second.size() == 1; + return forks.first.size() > 1 + && forks.second.size() == 1 + && !bs->in_current_chain; }; if (!cached_prepare.empty()) { - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { //sign again, update cache, then emit auto retry_p = cached_prepare; retry_p.common.timestamp = time_point::now(); retry_p.sender_signature = sp.second(retry_p.digest(chain_id)); - emit(pbft_outgoing_prepare, std::make_shared(retry_p)); + if (is_valid_prepare(retry_p, sp.first)) { + prepares_to_be_cached.emplace_back(retry_p); + } } - return prepare_to_be_cached; - } else if (reserve_prepare(my_prepare)) { - for (auto const &sp : ctrl.my_signature_providers()) { + } else if (reserve_prepare(my_prepare) ) { + for (const auto& sp : my_sps) { pbft_prepare reserve_p; - reserve_p.view=current_view; reserve_p.block_info={my_prepare}; + reserve_p.view = _current_view; + reserve_p.block_info = {my_prepare}; reserve_p.sender_signature = sp.second(reserve_p.digest(chain_id)); - emit(pbft_outgoing_prepare, std::make_shared(reserve_p)); - if (prepare_to_be_cached.empty()) prepare_to_be_cached = reserve_p; + if (is_valid_prepare(reserve_p, sp.first)) { + prepares_to_be_cached.emplace_back(reserve_p); + } } - return prepare_to_be_cached; } else { - auto current_watermark = get_current_pbft_watermark(); auto lib = ctrl.last_irreversible_block_num(); @@ -216,30 +221,30 @@ namespace eosio { high_watermark_block_num = std::min(head_block_num, current_watermark); } - if (high_watermark_block_num <= lib) return prepare_to_be_cached; + if (high_watermark_block_num <= lib) return prepares_to_be_cached; if (auto hwbs = ctrl.fork_db().get_block_in_current_chain_by_num(high_watermark_block_num)) { auto sent = false; - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { pbft_prepare new_p; - new_p.view=current_view; new_p.block_info={hwbs->id}; + new_p.view = _current_view; + new_p.block_info = {hwbs->id}; new_p.sender_signature = sp.second(new_p.digest(chain_id)); if (is_valid_prepare(new_p, sp.first)) { - emit(pbft_outgoing_prepare, std::make_shared(new_p)); add_pbft_prepare(new_p, sp.first); sent = true; - if (prepare_to_be_cached.empty()) prepare_to_be_cached = new_p; + prepares_to_be_cached.emplace_back(new_p); } } if (sent) ctrl.set_pbft_my_prepare(hwbs->id); } - return prepare_to_be_cached; } + return prepares_to_be_cached; } bool pbft_database::should_prepared() { - auto const &by_prepare_and_num_index = pbft_state_index.get(); + const auto& by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); if (itr == by_prepare_and_num_index.end()) return false; @@ -252,15 +257,15 @@ namespace eosio { return false; } - bool pbft_database::is_valid_prepare(const pbft_prepare &p, const public_key_type &pk) { + bool pbft_database::is_valid_prepare(const pbft_prepare& p, const public_key_type& pk) { // a prepare msg under lscb (which is no longer in fork_db), can be treated as null, thus true. if (p.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) return true; return should_recv_pbft_msg(pk); } - void pbft_database::add_pbft_commit(pbft_commit &c, const public_key_type &pk) { + void pbft_database::add_pbft_commit(const pbft_commit& c, const public_key_type& pk) { - auto &by_block_id_index = pbft_state_index.get(); + auto& by_block_id_index = pbft_state_index.get(); auto current = ctrl.fetch_block_state_by_id(c.block_info.block_id); @@ -284,10 +289,12 @@ namespace eosio { } else { auto commits = (*curr_itr)->commits; if (commits.find(std::make_pair(c.view, pk)) == commits.end()) { - by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr &psp) { + by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr& psp) { psp->commits[std::make_pair(c.view, pk)] = c; std::sort(psp->commits.begin(), psp->commits.end(), less<>()); }); + } else { + return; } } @@ -301,17 +308,17 @@ namespace eosio { auto commits = cpsp->commits; if (commits.size() >= threshold && !cpsp->is_committed && is_less_than_high_watermark(cpsp->block_num)) { flat_map commit_count; - for (auto const &com: commits) { + for (const auto& com: commits) { if (commit_count.find(com.second.view) == commit_count.end()) commit_count[com.second.view] = 0; } - for (auto const &bp: as) { - for (auto const &pc: commits) { + for (const auto& bp: as) { + for (const auto& pc: commits) { if (bp.block_signing_key == pc.first.second) commit_count[pc.first.first] += 1; } } - for (auto const &e: commit_count) { + for (const auto& e: commit_count) { if (e.second >= threshold) { mark_as_committed(cpsp->block_id); } @@ -321,55 +328,57 @@ namespace eosio { } } - pbft_commit pbft_database::send_and_add_pbft_commit(const pbft_commit &cached_commit, pbft_view_type current_view) { - auto commit_to_be_cached = pbft_commit(); + vector pbft_database::generate_and_add_pbft_commit(const pbft_commit& cached_commit) { + vector commits_to_be_cached; + const auto& my_sps = ctrl.my_signature_providers(); + commits_to_be_cached.reserve(my_sps.size()); if (!cached_commit.empty()) { - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { //sign again, update cache, then emit auto retry_c = cached_commit; retry_c.common.timestamp = time_point::now(); retry_c.sender_signature = sp.second(retry_c.digest(chain_id)); - emit(pbft_outgoing_commit, std::make_shared(retry_c)); + if (is_valid_commit(retry_c, sp.first)) { + commits_to_be_cached.emplace_back(retry_c); + } } - return commit_to_be_cached; } else { - auto const &by_prepare_and_num_index = pbft_state_index.get(); + const auto& by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); - if (itr == by_prepare_and_num_index.end()) return commit_to_be_cached; + if (itr == by_prepare_and_num_index.end()) return commits_to_be_cached; pbft_state_ptr psp = *itr; auto bs = ctrl.fork_db().get_block(psp->block_id); - if (!bs) return commit_to_be_cached; + if (!bs) return commits_to_be_cached; if (psp->is_prepared && (psp->block_num > ctrl.last_irreversible_block_num())) { - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { pbft_commit new_c; - new_c.view=current_view; - new_c.block_info={psp->block_id}; + new_c.view = _current_view; + new_c.block_info = {psp->block_id}; new_c.sender_signature = sp.second(new_c.digest(chain_id)); if (is_valid_commit(new_c, sp.first)) { - emit(pbft_outgoing_commit, std::make_shared(new_c)); add_pbft_commit(new_c, sp.first); - if (commit_to_be_cached.empty()) commit_to_be_cached = new_c; + commits_to_be_cached.emplace_back(new_c); } } } - return commit_to_be_cached; } + return commits_to_be_cached; } - void pbft_database::mark_as_committed(const block_id_type &bid) { - auto &by_block_id_index = pbft_state_index.get(); + void pbft_database::mark_as_committed(const block_id_type& bid) { + auto& by_block_id_index = pbft_state_index.get(); auto itr = by_block_id_index.find(bid); if (itr == by_block_id_index.end()) return; - by_block_id_index.modify(itr, [&](const pbft_state_ptr &p) { p->is_committed = true; }); + by_block_id_index.modify(itr, [&](const pbft_state_ptr& p) { p->is_committed = true; }); } bool pbft_database::should_committed() { - auto const &by_commit_and_num_index = pbft_state_index.get(); + const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end()) return false; pbft_state_ptr psp = *itr; @@ -381,7 +390,7 @@ namespace eosio { pbft_view_type new_view = 0; if (!should_committed()) return new_view; - auto const &by_commit_and_num_index = pbft_state_index.get(); + const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); pbft_state_ptr psp = *itr; @@ -394,17 +403,17 @@ namespace eosio { auto threshold = as.size() * 2 / 3 + 1; flat_map commit_count; - for (auto const &com: commits) { + for (const auto& com: commits) { if (commit_count.find(com.second.view) == commit_count.end()) commit_count[com.second.view] = 0; } - for (auto const &bp: as) { - for (auto const &pc: commits) { + for (const auto& bp: as) { + for (const auto& pc: commits) { if (bp.block_signing_key == pc.first.second) commit_count[pc.first.first] += 1; } } - for (auto const &e: commit_count) { + for (const auto& e: commit_count) { if (e.second >= threshold && e.first > new_view) { new_view = e.first; } @@ -412,13 +421,13 @@ namespace eosio { return new_view; } - bool pbft_database::is_valid_commit(const pbft_commit &c, const public_key_type &pk) { + bool pbft_database::is_valid_commit(const pbft_commit& c, const public_key_type& pk) { if (c.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) return true; return should_recv_pbft_msg(pk); } void pbft_database::commit_local() { - auto const &by_commit_and_num_index = pbft_state_index.get(); + const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end()) return; @@ -431,11 +440,11 @@ namespace eosio { return ctrl.pending_pbft_lib(); } - void pbft_database::add_pbft_view_change(pbft_view_change &vc, const public_key_type &pk) { + void pbft_database::add_pbft_view_change(const pbft_view_change& vc, const public_key_type& pk) { auto lscb_bps = lscb_active_producers().producers; - auto &by_view_index = view_state_index.get(); + auto& by_view_index = view_state_index.get(); auto itr = by_view_index.find(vc.target_view); if (itr == by_view_index.end()) { flat_map view_changes; @@ -450,9 +459,11 @@ namespace eosio { auto view_changes = pvs->view_changes; if (view_changes.find(pk) == view_changes.end()) { - by_view_index.modify(itr, [&](const pbft_view_change_state_ptr &pvsp) { + by_view_index.modify(itr, [&](const pbft_view_change_state_ptr& pvsp) { pvsp->view_changes[pk] = vc; }); + } else { + return; } } @@ -464,20 +475,20 @@ namespace eosio { if (vsp->view_changes.size() >= threshold && !vsp->is_view_changed) { auto vc_count = 0; - for (auto const &bp: lscb_bps) { - for (auto const &v: vsp->view_changes) { + for (const auto& bp: lscb_bps) { + for (const auto& v: vsp->view_changes) { if (bp.block_signing_key == v.first) vc_count += 1; } } if (vc_count >= threshold) { - by_view_index.modify(itr, [&](const pbft_view_change_state_ptr &pvsp) { pvsp->is_view_changed = true; }); + by_view_index.modify(itr, [&](const pbft_view_change_state_ptr& pvsp) { pvsp->is_view_changed = true; }); } } } pbft_view_type pbft_database::should_view_change() { pbft_view_type nv = 0; - auto &by_view_index = view_state_index.get(); + auto& by_view_index = view_state_index.get(); auto itr = by_view_index.begin(); if (itr == by_view_index.end()) return nv; @@ -486,13 +497,13 @@ namespace eosio { auto vc_count = 0; auto pvs = (*itr); - for (auto const &bp: active_bps) { - for (auto const &v: pvs->view_changes) { + for (const auto& bp: active_bps) { + for (const auto& v: pvs->view_changes) { if (bp.block_signing_key == v.first) vc_count += 1; } } //if contains self or view_change >= f+1, transit to view_change and send view change - if (vc_count >= active_bps.size() / 3 + 1) { + if (vc_count > (active_bps.size() - 1) / 3) { nv = pvs->view; break; } @@ -501,60 +512,61 @@ namespace eosio { return nv; } - pbft_view_change pbft_database::send_and_add_pbft_view_change( - const pbft_view_change &cached_view_change, - const pbft_prepared_certificate &ppc, - const vector &pcc, - pbft_view_type current_view, + vector pbft_database::generate_and_add_pbft_view_change( + const pbft_view_change& cached_view_change, + const pbft_prepared_certificate& ppc, + const vector& pcc, pbft_view_type target_view) { - auto view_change_to_be_cached = pbft_view_change(); + vector view_changes_to_be_cached; + const auto& my_sps = ctrl.my_signature_providers(); + view_changes_to_be_cached.reserve(my_sps.size()); + if (!cached_view_change.empty()) { - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { //sign again, update cache, then emit auto retry_vc = cached_view_change; retry_vc.common.timestamp = time_point::now(); retry_vc.sender_signature = sp.second(retry_vc.digest(chain_id)); - emit(pbft_outgoing_view_change, std::make_shared(retry_vc)); + if (is_valid_view_change(retry_vc, sp.first)) { + view_changes_to_be_cached.emplace_back(retry_vc); + } } - return view_change_to_be_cached; } else { - for (auto const &my_sp : ctrl.my_signature_providers()) { - + for (const auto& sp : my_sps) { auto my_lsc = get_stable_checkpoint_by_id(ctrl.last_stable_checkpoint_block_id()); pbft_view_change new_vc; - new_vc.current_view=current_view; - new_vc.target_view=target_view; - new_vc.prepared_cert=ppc; - new_vc.committed_certs=pcc; - new_vc.stable_checkpoint=my_lsc; - new_vc.sender_signature = my_sp.second(new_vc.digest(chain_id)); - if (is_valid_view_change(new_vc, my_sp.first)) { - emit(pbft_outgoing_view_change, std::make_shared(new_vc)); - add_pbft_view_change(new_vc, my_sp.first); - if (view_change_to_be_cached.empty()) view_change_to_be_cached = new_vc; + new_vc.current_view = _current_view; + new_vc.target_view = target_view; + new_vc.prepared_cert = ppc; + new_vc.committed_certs = pcc; + new_vc.stable_checkpoint = my_lsc; + new_vc.sender_signature = sp.second(new_vc.digest(chain_id)); + if (is_valid_view_change(new_vc, sp.first)) { + add_pbft_view_change(new_vc, sp.first); + view_changes_to_be_cached.emplace_back(new_vc); } } - return view_change_to_be_cached; } + return view_changes_to_be_cached; } - bool pbft_database::should_new_view(const pbft_view_type target_view) { - auto &by_view_index = view_state_index.get(); + bool pbft_database::should_new_view(pbft_view_type target_view) { + auto& by_view_index = view_state_index.get(); auto itr = by_view_index.find(target_view); if (itr == by_view_index.end()) return false; return (*itr)->is_view_changed; } pbft_view_type pbft_database::get_proposed_new_view_num() { - auto &by_count_and_view_index = view_state_index.get(); + auto& by_count_and_view_index = view_state_index.get(); auto itr = by_count_and_view_index.begin(); if (itr == by_count_and_view_index.end() || !(*itr)->is_view_changed) return 0; return (*itr)->view; } - bool pbft_database::has_new_primary(const public_key_type &pk) { + bool pbft_database::has_new_primary(const public_key_type& pk) { if (pk == public_key_type()) return false; auto sps = ctrl.my_signature_providers(); @@ -567,12 +579,14 @@ namespace eosio { ctrl.reset_pbft_my_prepare(); } - pbft_new_view pbft_database::send_pbft_new_view( - const pbft_view_changed_certificate &vcc, - pbft_view_type current_view) { + pbft_new_view pbft_database::generate_pbft_new_view( + const pbft_view_changed_certificate& vcc, + pbft_view_type new_view) { + + pbft_new_view nv; - auto primary_key = get_new_view_primary_key(current_view); - if (!has_new_primary(primary_key) || vcc.empty()) return pbft_new_view(); + auto primary_key = get_new_view_primary_key(new_view); + if (!has_new_primary(primary_key) || vcc.empty()) return nv; //`sp_itr` is not possible to be the end iterator, since it's already been checked in `has_new_primary`. auto my_sps = ctrl.my_signature_providers(); @@ -582,14 +596,14 @@ namespace eosio { auto highest_pcc = vector{}; auto highest_sc = pbft_stable_checkpoint(); - for (auto const &vc: vcc.view_changes) { + for (const auto& vc: vcc.view_changes) { if (vc.prepared_cert.block_info.block_num() > highest_ppc.block_info.block_num()) { highest_ppc = vc.prepared_cert; } - for (auto const &cc: vc.committed_certs) { + for (const auto& cc: vc.committed_certs) { auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), - [&](const pbft_committed_certificate &ext) { return ext.block_info.block_id == cc.block_info.block_id; }); + [&](const pbft_committed_certificate& ext) { return ext.block_info.block_id == cc.block_info.block_id; }); if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); } @@ -598,32 +612,32 @@ namespace eosio { } } - pbft_new_view nv; - nv.new_view=current_view; - nv.prepared_cert=highest_ppc; - nv.committed_certs=highest_pcc; - nv.stable_checkpoint=highest_sc; - nv.view_changed_cert=vcc; + nv.new_view = new_view; + nv.prepared_cert = highest_ppc; + nv.committed_certs = highest_pcc; + nv.stable_checkpoint = highest_sc; + nv.view_changed_cert = vcc; nv.sender_signature = sp_itr->second(nv.digest(chain_id)); try { validate_new_view(nv, sp_itr->first); - emit(pbft_outgoing_new_view, std::make_shared(nv)); - return nv; } catch (const fc::exception& ex) { elog("bad new view, ${s} ", ("s", ex.to_string())); - return pbft_new_view(); + nv = pbft_new_view(); } + return nv; } pbft_prepared_certificate pbft_database::generate_prepared_certificate() { - auto const &by_prepare_and_num_index = pbft_state_index.get(); + pbft_prepared_certificate ppc; + + const auto& by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); - if (itr == by_prepare_and_num_index.end()) return pbft_prepared_certificate(); + if (itr == by_prepare_and_num_index.end()) return ppc; pbft_state_ptr psp = *itr; auto prepared_block_state = ctrl.fetch_block_state_by_id(psp->block_id); - if (!prepared_block_state) return pbft_prepared_certificate(); + if (!prepared_block_state) return ppc; auto as = prepared_block_state->active_schedule.producers; if (psp->is_prepared && psp->block_num > ctrl.last_irreversible_block_num()) { @@ -633,44 +647,45 @@ namespace eosio { flat_map prepare_count; flat_map> prepare_msg; - for (auto const &pre: prepares) { + for (const auto& pre: prepares) { if (prepare_count.find(pre.first.first) == prepare_count.end()) prepare_count[pre.first.first] = 0; prepare_msg[pre.first.first].emplace_back(pre.second); } - for (auto const &bp: as) { - for (auto const &pp: prepares) { + for (const auto& bp: as) { + for (const auto& pp: prepares) { if (bp.block_signing_key == pp.first.second) prepare_count[pp.first.first] += 1; } } auto bp_threshold = as.size() * 2 / 3 + 1; - for (auto const &e: prepare_count) { + for (const auto& e: prepare_count) { if (e.second >= bp_threshold) { valid_prepares = prepare_msg[e.first]; } } - if (valid_prepares.empty()) return pbft_prepared_certificate(); + if (valid_prepares.empty()) return ppc; - pbft_prepared_certificate pc; - pc.block_info={psp->block_id}; pc.prepares=valid_prepares; pc.pre_prepares.emplace(psp->block_id); - for (auto const &p: valid_prepares) { + ppc.block_info = {psp->block_id}; + ppc.prepares=valid_prepares; + ppc.pre_prepares.emplace(psp->block_id); + for (const auto& p: valid_prepares) { auto bid = p.block_info.block_id; while (bid != psp->block_id) { - pc.pre_prepares.emplace(bid); + ppc.pre_prepares.emplace(bid); bid = ctrl.fetch_block_state_by_id(bid)->prev(); } } - return pc; - } else return pbft_prepared_certificate(); + } + return ppc; } vector pbft_database::generate_committed_certificate() { - auto pcc = vector{}; + vector pcc{}; - auto const &by_commit_and_num_index = pbft_state_index.get(); + const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end()) return pcc; @@ -698,11 +713,11 @@ namespace eosio { } } - auto const &by_id_index = pbft_state_index.get(); + const auto& by_id_index = pbft_state_index.get(); std::sort(ccb.begin(), ccb.end()); pcc.reserve(ccb.size()); - for (auto const &committed_block_num: ccb) { + for (const auto& committed_block_num: ccb) { auto cbs = ctrl.fetch_block_state_by_number(committed_block_num); if (!cbs) return pcc; @@ -719,19 +734,19 @@ namespace eosio { flat_map commit_count; flat_map> commit_msg; - for (auto const &com: commits) { + for (const auto& com: commits) { if (commit_count.find(com.first.first) == commit_count.end()) commit_count[com.first.first] = 0; commit_msg[com.first.first].emplace_back(com.second); } - for (auto const &bp: as) { - for (auto const &cc: commits) { + for (const auto& bp: as) { + for (const auto& cc: commits) { if (bp.block_signing_key == cc.first.second) commit_count[cc.first.first] += 1; } } auto bp_threshold = as.size() * 2 / 3 + 1; - for (auto const &e: commit_count) { + for (const auto& e: commit_count) { if (e.second >= bp_threshold) { valid_commits = commit_msg[e.first]; } @@ -740,7 +755,8 @@ namespace eosio { if (valid_commits.empty()) return pcc; pbft_committed_certificate cc; - cc.block_info={cbs->id}; cc.commits=valid_commits; + cc.block_info = {cbs->id}; + cc.commits = valid_commits; pcc.emplace_back(cc); } return pcc; @@ -748,28 +764,27 @@ namespace eosio { pbft_view_changed_certificate pbft_database::generate_view_changed_certificate(pbft_view_type target_view) { - auto pvcc = pbft_view_changed_certificate(); + pbft_view_changed_certificate pvcc; - auto &by_view_index = view_state_index.get(); + auto& by_view_index = view_state_index.get(); auto itr = by_view_index.find(target_view); if (itr == by_view_index.end()) return pvcc; auto pvs = *itr; if (pvs->is_view_changed) { - pvcc.target_view=pvs->view; pvcc.view_changes.reserve(pvs->view_changes.size()); - for(auto & view_change : pvs->view_changes) { + for(auto& view_change : pvs->view_changes) { pvcc.view_changes.emplace_back( view_change.second ); } - return pvcc; - } else return pvcc; + } + return pvcc; } - bool pbft_database::is_valid_prepared_certificate(const pbft_prepared_certificate &certificate, bool add_to_pbft_db) { + bool pbft_database::is_valid_prepared_certificate(const pbft_prepared_certificate& certificate, bool add_to_pbft_db) { // an empty certificate is valid since it acts as a null digest in pbft. if (certificate.empty()) return true; // a certificate under lscb (no longer in fork_db) is also treated as null. @@ -779,7 +794,7 @@ namespace eosio { auto prepares_metadata = vector>{}; prepares_metadata.reserve(prepares.size()); - for (auto &p : prepares) { + for (auto& p : prepares) { auto pmm = pbft_message_metadata(p, chain_id); prepares_metadata.emplace_back(pmm); if (!is_valid_prepare(p, pmm.sender_key)) return false; @@ -796,19 +811,19 @@ namespace eosio { flat_map prepare_count; - for (auto const &pm: prepares_metadata) { + for (const auto& pm: prepares_metadata) { if (prepare_count.find(pm.msg.view) == prepare_count.end()) prepare_count[pm.msg.view] = 0; } - for (auto const &bp: producer_schedule.producers) { - for (auto const &pm: prepares_metadata) { + for (const auto& bp: producer_schedule.producers) { + for (const auto& pm: prepares_metadata) { if (bp.block_signing_key == pm.sender_key) prepare_count[pm.msg.view] += 1; } } auto should_prepared = false; - for (auto const &e: prepare_count) { + for (const auto& e: prepare_count) { if (e.second >= bp_threshold) { should_prepared = true; } @@ -819,9 +834,9 @@ namespace eosio { //validate prepare auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto non_fork_bp_count = 0; - vector prepare_infos; + fork_info_type prepare_infos; prepare_infos.reserve(certificate.prepares.size()); - for (auto const &p : certificate.prepares) { + for (const auto& p : certificate.prepares) { //only search in fork db if (p.block_info.block_num() <= lscb_num) { ++non_fork_bp_count; @@ -832,7 +847,7 @@ namespace eosio { return is_valid_longest_fork(certificate.block_info, prepare_infos, bp_threshold, non_fork_bp_count); } - bool pbft_database::is_valid_committed_certificate(const pbft_committed_certificate &certificate, bool add_to_pbft_db) { + bool pbft_database::is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db) { // an empty certificate is valid since it acts as a null digest in pbft. if (certificate.empty()) return true; // a certificate under lscb (no longer in fork_db) is also treated as null. @@ -842,7 +857,7 @@ namespace eosio { auto commits_metadata = vector>{}; commits_metadata.reserve(commits.size()); - for (auto &c : commits) { + for (auto& c : commits) { auto pmm = pbft_message_metadata(c, chain_id); commits_metadata.emplace_back(pmm); if (!is_valid_commit(c, pmm.sender_key)) return false; @@ -859,19 +874,19 @@ namespace eosio { flat_map commit_count; - for (auto const &cm: commits_metadata) { + for (const auto& cm: commits_metadata) { if (commit_count.find(cm.msg.view) == commit_count.end()) commit_count[cm.msg.view] = 0; } - for (auto const &bp: producer_schedule.producers) { - for (auto const &cm: commits_metadata) { + for (const auto& bp: producer_schedule.producers) { + for (const auto& cm: commits_metadata) { if (bp.block_signing_key == cm.sender_key) commit_count[cm.msg.view] += 1; } } auto should_committed = false; - for (auto const &e: commit_count) { + for (const auto& e: commit_count) { if (e.second >= bp_threshold) { should_committed = true; } @@ -882,9 +897,9 @@ namespace eosio { //validate commit auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto non_fork_bp_count = 0; - vector commit_infos; + fork_info_type commit_infos; commit_infos.reserve(certificate.commits.size()); - for (auto const &c : certificate.commits) { + for (const auto& c : certificate.commits) { //only search in fork db if (c.block_info.block_num() <= lscb_num) { ++non_fork_bp_count; @@ -895,14 +910,13 @@ namespace eosio { return is_valid_longest_fork(certificate.block_info, commit_infos, bp_threshold, non_fork_bp_count); } - bool pbft_database::is_valid_view_change(const pbft_view_change &vc, const public_key_type &pk) { + bool pbft_database::is_valid_view_change(const pbft_view_change& vc, const public_key_type& pk) { return should_recv_pbft_msg(pk); // No need to check prepared cert and stable checkpoint, until generate or validate a new view msg } - - void pbft_database::validate_new_view(const pbft_new_view &nv, const public_key_type &pk) { + void pbft_database::validate_new_view(const pbft_new_view& nv, const public_key_type& pk) { EOS_ASSERT(pk == get_new_view_primary_key(nv.new_view), pbft_exception, "new view is not signed with expected key"); @@ -915,7 +929,7 @@ namespace eosio { auto committed_certs = nv.committed_certs; std::sort(committed_certs.begin(), committed_certs.end()); - for (auto const &c: committed_certs) { + for (const auto& c: committed_certs) { EOS_ASSERT(is_valid_committed_certificate(c, true), pbft_exception, "bad committed certificate: ${cc}", ("cc", c)); } @@ -924,7 +938,7 @@ namespace eosio { vector lscb_producers; lscb_producers.reserve(lscb_active_producers().producers.size()); - for (auto const &bp: lscb_active_producers().producers) { + for (const auto& bp: lscb_active_producers().producers) { lscb_producers.emplace_back(bp.block_signing_key); } auto schedule_threshold = lscb_producers.size() * 2 / 3 + 1; @@ -935,7 +949,7 @@ namespace eosio { vector view_change_producers; view_change_producers.reserve(view_changes.size()); - for (auto &vc: view_changes) { + for (auto& vc : view_changes) { auto pmm = pbft_message_metadata(vc, chain_id); view_changes_metadata.emplace_back(pmm); if (is_valid_view_change(vc, pmm.sender_key)) { @@ -961,16 +975,16 @@ namespace eosio { auto highest_pcc = vector{}; auto highest_scp = pbft_stable_checkpoint(); - for (auto const &vc: nv.view_changed_cert.view_changes) { + for (const auto& vc: nv.view_changed_cert.view_changes) { if (vc.prepared_cert.block_info.block_num() > highest_ppc.block_info.block_num() && is_valid_prepared_certificate(vc.prepared_cert)) { highest_ppc = vc.prepared_cert; } - for (auto const &cc: vc.committed_certs) { + for (const auto& cc: vc.committed_certs) { if (is_valid_committed_certificate(cc)) { auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), - [&](const pbft_committed_certificate &ext) { + [&](const pbft_committed_certificate& ext) { return ext.block_info.block_id == cc.block_info.block_id; }); if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); @@ -1001,15 +1015,15 @@ namespace eosio { ("hpcc", highest_scp)("pc", nv.stable_checkpoint)); } - bool pbft_database::should_stop_view_change(const pbft_view_change &vc) { + bool pbft_database::should_stop_view_change(const pbft_view_change& vc) { auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto vc_lscb = vc.stable_checkpoint.block_info.block_num(); return vc_lscb > 0 && lscb_num > vc_lscb; } - vector> pbft_database::fetch_fork_from(vector &block_infos) { + vector pbft_database::fetch_fork_from(fork_info_type& block_infos) { - vector> result; + vector result; if (block_infos.empty()) { return result; } @@ -1019,7 +1033,7 @@ namespace eosio { } sort(block_infos.begin(), block_infos.end(), - [](const block_info_type &a, const block_info_type &b) -> bool { return a.block_num() > b.block_num(); }); + [](const block_info_type& a, const block_info_type& b) -> bool { return a.block_num() > b.block_num(); }); while (!block_infos.empty()) { auto fork = fetch_first_fork_from(block_infos); @@ -1030,8 +1044,8 @@ namespace eosio { return result; } - vector pbft_database::fetch_first_fork_from(vector &bi) { - vector result; + fork_info_type pbft_database::fetch_first_fork_from(fork_info_type& bi) { + fork_info_type result; if (bi.empty()) { return result; } @@ -1071,39 +1085,39 @@ namespace eosio { return result; } - bool pbft_database::is_valid_longest_fork(const block_info_type &bi, vector block_infos, unsigned long threshold, unsigned long non_fork_bp_count) { + bool pbft_database::is_valid_longest_fork( + const block_info_type& bi, + fork_info_type& block_infos, + unsigned long threshold, + unsigned long non_fork_bp_count) { auto forks = fetch_fork_from(block_infos); - vector longest_fork; - for (auto const &f : forks) { + fork_info_type longest_fork; + for (const auto& f : forks) { if (f.size() > longest_fork.size()) { longest_fork = f; } } - if (longest_fork.size() + non_fork_bp_count < threshold) return false; - - if (longest_fork.empty()) return true; - auto calculated_block_info = longest_fork.back(); - - return bi.block_id == calculated_block_info.block_id; + return longest_fork.empty() + || (longest_fork.size() + non_fork_bp_count >= threshold && bi.block_id == longest_fork.back().block_id); } - pbft_stable_checkpoint pbft_database::fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr &b) { + pbft_stable_checkpoint pbft_database::fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr& b) { + + pbft_stable_checkpoint psc; try { if (b) { - auto &extn = b->block_extensions; + auto& extn = b->block_extensions; for (auto it = extn.begin(); it != extn.end();) { if (it->first == static_cast(block_extension_type::pbft_stable_checkpoint)) { auto scp_ds = it->second; fc::datastream ds(scp_ds.data(), scp_ds.size()); + fc::raw::unpack(ds, psc); - pbft_stable_checkpoint scp; - fc::raw::unpack(ds, scp); - - if (is_valid_stable_checkpoint(scp)) { - return scp; + if (is_valid_stable_checkpoint(psc)) { + break; } else { it = extn.erase(it); } @@ -1114,32 +1128,34 @@ namespace eosio { } } catch(...) { elog("no stable checkpoints found in the block extension"); + psc = pbft_stable_checkpoint(); } - return pbft_stable_checkpoint(); + return psc; } - pbft_stable_checkpoint pbft_database::get_stable_checkpoint_by_id(const block_id_type &block_id, bool incl_blk_extn ) { - auto const &by_block = checkpoint_index.get(); + pbft_stable_checkpoint pbft_database::get_stable_checkpoint_by_id(const block_id_type& block_id, bool incl_blk_extn ) { + pbft_stable_checkpoint psc; + const auto& by_block = checkpoint_index.get(); auto itr = by_block.find(block_id); if (itr == by_block.end()) { if (incl_blk_extn) { auto blk = ctrl.fetch_block_by_id(block_id); - return fetch_stable_checkpoint_from_blk_extn(blk); + psc = fetch_stable_checkpoint_from_blk_extn(blk); } - return pbft_stable_checkpoint(); + return psc; } auto cpp = *itr; if (cpp->is_stable) { - pbft_stable_checkpoint psc; psc.block_info={cpp->block_id}; psc.checkpoints.reserve(cpp->checkpoints.size()); - for (auto & checkpoint : cpp->checkpoints) { + for (auto& checkpoint : cpp->checkpoints) { psc.checkpoints.emplace_back(checkpoint.second) ; } - return psc; - } else return pbft_stable_checkpoint(); + + } + return psc; } block_info_type pbft_database::cal_pending_stable_checkpoint() const { @@ -1147,7 +1163,7 @@ namespace eosio { auto pending_scb_num = ctrl.last_stable_checkpoint_block_num(); auto pending_scb_info = block_info_type{ctrl.last_stable_checkpoint_block_id()}; - auto const &by_blk_num = checkpoint_index.get(); + const auto& by_blk_num = checkpoint_index.get(); auto itr = by_blk_num.lower_bound(pending_scb_num); if (itr == by_blk_num.end()) return pending_scb_info; @@ -1161,7 +1177,7 @@ namespace eosio { producer_schedule_type new_schedule; if (pending_scb_num == 0) { - auto const &ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; + const auto& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; if (ucb == 0) { current_schedule = ctrl.initial_schedule(); new_schedule = ctrl.initial_schedule(); @@ -1193,82 +1209,69 @@ namespace eosio { } vector pbft_database::generate_and_add_pbft_checkpoint() { - auto checkpoint = [&](const block_num_type &in) { + auto checkpoint = [&](const block_num_type& in) { auto const& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; if (!ctrl.is_pbft_enabled()) return false; if (in <= ucb) return false; auto watermarks = get_updated_watermarks(); return in == ucb + 1 // checkpoint on first pbft block; - || in % pbft_checkpoint_granularity == 1 // checkpoint on every 100 block; + || in % get_checkpoint_interval() == 1 // checkpoint on every 100 block; || std::find(watermarks.begin(), watermarks.end(), in) != watermarks.end(); // checkpoint on bp schedule change; }; - auto new_pc = vector{}; + vector new_pc{}; + auto my_sps = ctrl.my_signature_providers(); - auto const &by_commit_and_num_index = pbft_state_index.get(); + const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end() || !(*itr)->is_committed) return new_pc; pbft_state_ptr psp = (*itr); - - flat_map pending_checkpoint_block_num; // block_height and retry_flag auto lscb_num = ctrl.last_stable_checkpoint_block_num(); + + vector pending_checkpoint_block_num; + pending_checkpoint_block_num.reserve(psp->block_num - lscb_num); for (auto i = psp->block_num; i > lscb_num && i > 1; --i) { if (checkpoint(i)) { - auto &by_block = checkpoint_index.get(); - - if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(i)) { - auto c_itr = by_block.find(bs->id); - if (c_itr == by_block.end()) { - pending_checkpoint_block_num[i] = false; - } else { - auto checkpoints = (*c_itr)->checkpoints; - for (auto const &my_sp : ctrl.my_signature_providers()) { - if (checkpoints.find(my_sp.first) != checkpoints.end() && !(*c_itr)->is_stable) { - pending_checkpoint_block_num[i] = true; //retry sending at this time. - } - } - if (pending_checkpoint_block_num.find(i) == pending_checkpoint_block_num.end()) { - pending_checkpoint_block_num[i] = false; - } - } - } + pending_checkpoint_block_num.emplace_back(i); } } - auto &by_block = checkpoint_index.get(); + auto& by_block = checkpoint_index.get(); if (!pending_checkpoint_block_num.empty()) { std::sort(pending_checkpoint_block_num.begin(), pending_checkpoint_block_num.end()); - for (auto& bnum_and_retry: pending_checkpoint_block_num) { - if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(bnum_and_retry.first)) { - for (auto const &my_sp : ctrl.my_signature_providers()) { + for (auto bnum: pending_checkpoint_block_num) { + if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(bnum)) { + for (const auto& sp : my_sps) { pbft_checkpoint cp; - cp.block_info={bs->id}; - cp.sender_signature = my_sp.second(cp.digest(chain_id)); - if (!bnum_and_retry.second && is_valid_checkpoint(cp, my_sp.first)) { //first time sending this checkpoint - add_pbft_checkpoint(cp, my_sp.first); + cp.block_info = {bs->id}; + cp.sender_signature = sp.second(cp.digest(chain_id)); + if (is_valid_checkpoint(cp, sp.first)) { + add_pbft_checkpoint(cp, sp.first); + new_pc.emplace_back(cp); } - new_pc.emplace_back(cp); } } } } else if (lscb_num > 0) { //retry sending my lscb - for (auto const &my_sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { pbft_checkpoint cp; cp.block_info={ctrl.last_stable_checkpoint_block_id()}; - cp.sender_signature = my_sp.second(cp.digest(chain_id)); - new_pc.emplace_back(cp); + cp.sender_signature = sp.second(cp.digest(chain_id)); + if (is_valid_checkpoint(cp, sp.first)) { + new_pc.emplace_back(cp); + } } } return new_pc; } - void pbft_database::add_pbft_checkpoint(pbft_checkpoint &cp, const public_key_type &pk) { + void pbft_database::add_pbft_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk) { auto cp_block_state = ctrl.fetch_block_state_by_id(cp.block_info.block_id); if (!cp_block_state) return; - auto &by_block = checkpoint_index.get(); + auto& by_block = checkpoint_index.get(); auto itr = by_block.find(cp.block_info.block_id); if (itr == by_block.end()) { flat_map checkpoints; @@ -1284,9 +1287,11 @@ namespace eosio { auto csp = (*itr); auto checkpoints = csp->checkpoints; if (checkpoints.find(pk) == checkpoints.end()) { - by_block.modify(itr, [&](const pbft_checkpoint_state_ptr &pcp) { + by_block.modify(itr, [&](const pbft_checkpoint_state_ptr& pcp) { csp->checkpoints[pk] = cp; }); + } else { + return; } } @@ -1296,13 +1301,13 @@ namespace eosio { if (csp->checkpoints.size() >= threshold && !csp->is_stable) { auto cp_count = 0; - for (auto const &bp: active_bps) { - for (auto const &c: csp->checkpoints) { + for (const auto& bp: active_bps) { + for (const auto& c: csp->checkpoints) { if (bp.block_signing_key == c.first) cp_count += 1; } } if (cp_count >= threshold) { - by_block.modify(itr, [&](const pbft_checkpoint_state_ptr &pcp) { csp->is_stable = true; }); + by_block.modify(itr, [&](const pbft_checkpoint_state_ptr& pcp) { csp->is_stable = true; }); auto id = csp->block_id; auto blk = ctrl.fetch_block_by_id(id); @@ -1315,7 +1320,7 @@ namespace eosio { fc::raw::pack( ds, scp ); blk->block_extensions.emplace_back(); - auto &extension = blk->block_extensions.back(); + auto& extension = blk->block_extensions.back(); extension.first = static_cast(block_extension_type::pbft_stable_checkpoint ); extension.second.resize(scp_size); std::copy(buffer->begin(),buffer->end(), extension.second.data()); @@ -1324,13 +1329,6 @@ namespace eosio { } } - void pbft_database::send_pbft_checkpoint() { - auto cps_to_send = generate_and_add_pbft_checkpoint(); - for (auto const &cp: cps_to_send) { - emit(pbft_outgoing_checkpoint, std::make_shared(cp)); - } - } - void pbft_database::checkpoint_local() { auto pending_scb_info = cal_pending_stable_checkpoint(); auto lscb_num = ctrl.last_stable_checkpoint_block_num(); @@ -1339,35 +1337,36 @@ namespace eosio { if (pending_num > lscb_num) { ctrl.set_pbft_latest_checkpoint(pending_id); if (ctrl.last_irreversible_block_num() < pending_num) ctrl.pbft_commit_local(pending_id); - auto &by_block_id_index = pbft_state_index.get(); + auto& by_block_id_index = pbft_state_index.get(); auto pitr = by_block_id_index.find(pending_id); if (pitr != by_block_id_index.end()) { prune(*pitr); } } - auto &bni = checkpoint_index.get(); + auto& bni = checkpoint_index.get(); auto oldest = bni.begin(); - if ( oldest != bni.end() + while ( oldest != bni.end() && (*oldest)->is_stable && (*oldest)->block_num < lscb_num - oldest_stable_checkpoint ) { prune(*oldest); + oldest = bni.begin(); } } - bool pbft_database::is_valid_checkpoint(const pbft_checkpoint &cp, const public_key_type &pk) { + bool pbft_database::is_valid_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk) { if (cp.block_info.block_num() > ctrl.head_block_num() || cp.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) return false; if (auto bs = ctrl.fetch_block_state_by_id(cp.block_info.block_id)) { auto active_bps = bs->active_schedule.producers; - for (auto const &bp: active_bps) { + for (const auto& bp: active_bps) { if (bp.block_signing_key == pk) return true; } } return false; } - bool pbft_database::is_valid_stable_checkpoint(const pbft_stable_checkpoint &scp, bool add_to_pbft_db) { + bool pbft_database::is_valid_stable_checkpoint(const pbft_stable_checkpoint& scp, bool add_to_pbft_db) { if (scp.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) // the stable checkpoint is way behind lib, no way getting the block state, // it will not be applied nor saved, thus considered safe. @@ -1377,7 +1376,7 @@ namespace eosio { auto checkpoints_metadata = vector>{}; checkpoints_metadata.reserve(checkpoints.size()); - for (auto &cp : checkpoints) { + for (auto& cp : checkpoints) { auto pmm = pbft_message_metadata(cp, chain_id); checkpoints_metadata.emplace_back(pmm); if (cp.block_info != scp.block_info || !is_valid_checkpoint(cp, pmm.sender_key)) return false; @@ -1390,8 +1389,8 @@ namespace eosio { if (auto bs = ctrl.fetch_block_state_by_number(scp.block_info.block_num())) { auto as = bs->active_schedule; auto cp_count = 0; - for (auto const &bp: as.producers) { - for (auto const &cpm: checkpoints_metadata) { + for (const auto& bp: as.producers) { + for (const auto& cpm: checkpoints_metadata) { if (bp.block_signing_key == cpm.sender_key) cp_count += 1; } } @@ -1404,24 +1403,24 @@ namespace eosio { bool pbft_database::should_send_pbft_msg() { auto schedules = get_updated_fork_schedules(); - for (auto const &bp: schedules) { - for (auto const &sp: ctrl.my_signature_providers()) { + for (const auto& bp: schedules) { + for (const auto& sp: ctrl.my_signature_providers()) { if (bp.first == sp.first) return true; } } return false; } - bool pbft_database::should_recv_pbft_msg(const public_key_type &pub_key) { + bool pbft_database::should_recv_pbft_msg(const public_key_type& pub_key) { auto schedules = get_updated_fork_schedules(); - for (auto const &bp: schedules) { + for (const auto& bp: schedules) { if (bp.first == pub_key) return true; } return false; } - public_key_type pbft_database::get_new_view_primary_key(const pbft_view_type target_view) { + public_key_type pbft_database::get_new_view_primary_key(pbft_view_type target_view) { auto active_bps = lscb_active_producers().producers; if (active_bps.empty()) return public_key_type(); @@ -1430,19 +1429,24 @@ namespace eosio { } producer_schedule_type pbft_database::lscb_active_producers() const { + + auto ps = ctrl.initial_schedule(); auto num = ctrl.last_stable_checkpoint_block_num(); if (num == 0) { - auto const &ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; - if (ucb == 0) return ctrl.initial_schedule(); + const auto& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; + if (ucb == 0) return ps; num = ucb; } if (auto bs = ctrl.fetch_block_state_by_number(num)) { - if (bs->pending_schedule.producers.empty()) return bs->active_schedule; - return bs->pending_schedule; + if (bs->pending_schedule.producers.empty()) { + ps = bs->active_schedule; + } else { + ps = bs->pending_schedule; + } } - return ctrl.initial_schedule(); + return ps; } block_num_type pbft_database::get_current_pbft_watermark() { @@ -1460,7 +1464,7 @@ namespace eosio { void pbft_database::update_fork_schedules() { - auto vector_minus = [&](vector &v1, vector &v2) + auto vector_minus = [&](vector& v1, vector& v2) { vector diff; std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), @@ -1479,7 +1483,7 @@ namespace eosio { for (auto i: added) { if (auto bs = ctrl.fetch_block_state_by_number(i)) { auto as = bs->active_schedule.producers; - for (auto &bp: as) { + for (const auto& bp: as) { auto key = bp.block_signing_key; if (fork_schedules.find(key) == fork_schedules.end()) { fork_schedules[key] = i; @@ -1503,7 +1507,7 @@ namespace eosio { auto lscb_bps = lscb_active_producers().producers; auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - for (auto &bp: lscb_bps) { + for (const auto& bp: lscb_bps) { if (fork_schedules.find(bp.block_signing_key) == fork_schedules.end() || fork_schedules[bp.block_signing_key] < lscb_num) { fork_schedules[bp.block_signing_key] = lscb_num; @@ -1521,14 +1525,22 @@ namespace eosio { return fork_schedules; } - bool pbft_database::is_less_than_high_watermark(const block_num_type &bnum) { + uint16_t pbft_database::get_view_change_timeout() const { + return ctrl.get_pbft_properties().configuration.view_change_timeout; + } + + uint16_t pbft_database::get_checkpoint_interval() const { + return ctrl.get_pbft_properties().configuration.pbft_checkpoint_granularity; + } + + bool pbft_database::is_less_than_high_watermark(block_num_type bnum) { auto current_watermark = get_current_pbft_watermark(); return current_watermark == 0 || bnum <= current_watermark; } pbft_state_ptr pbft_database::get_pbft_state_by_id(const block_id_type& id) const { - auto &by_block_id_index = pbft_state_index.get(); + auto& by_block_id_index = pbft_state_index.get(); auto itr = by_block_id_index.find(id); if (itr != by_block_id_index.end()) return (*itr); @@ -1536,9 +1548,9 @@ namespace eosio { return pbft_state_ptr(); } - vector pbft_database::get_checkpoints_by_num(const block_num_type& num) const { + vector pbft_database::get_checkpoints_by_num(block_num_type num) const { auto results = vector{}; - auto &by_num_index = checkpoint_index.get(); + auto& by_num_index = checkpoint_index.get(); auto pitr = by_num_index.lower_bound( num ); while(pitr != by_num_index.end() && (*pitr)->block_num == num ) { @@ -1549,8 +1561,8 @@ namespace eosio { return results; } - pbft_view_change_state_ptr pbft_database::get_view_changes_by_target_view(const pbft_view_type& tv) const { - auto &by_view_index = view_state_index.get(); + pbft_view_change_state_ptr pbft_database::get_view_changes_by_target_view(pbft_view_type tv) const { + auto& by_view_index = view_state_index.get(); auto itr = by_view_index.find(tv); if (itr != by_view_index.end()) return (*itr); @@ -1578,10 +1590,10 @@ namespace eosio { EOS_ASSERT(result.second, pbft_exception, "unable to insert pbft checkpoint index, duplicate state detected"); } - void pbft_database::prune(const pbft_state_ptr &h) { + void pbft_database::prune(const pbft_state_ptr& h) { auto num = h->block_num; - auto &by_bn = pbft_state_index.get(); + auto& by_bn = pbft_state_index.get(); auto bni = by_bn.begin(); while (bni != by_bn.end() && (*bni)->block_num < num) { prune(*bni); @@ -1594,10 +1606,10 @@ namespace eosio { } } - void pbft_database::prune(const pbft_checkpoint_state_ptr &h) { + void pbft_database::prune(const pbft_checkpoint_state_ptr& h) { auto num = h->block_num; - auto &by_bn = checkpoint_index.get(); + auto& by_bn = checkpoint_index.get(); auto bni = by_bn.begin(); while (bni != by_bn.end() && (*bni)->block_num < num) { prune(*bni); @@ -1609,22 +1621,5 @@ namespace eosio { checkpoint_index.erase(itr); } } - - template - void pbft_database::emit(const Signal &s, Arg &&a) { - try { - s(std::forward(a)); - } 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 (...) { - wlog("signal handler threw exception"); - } - } } } \ No newline at end of file diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index a7993d40a27..6131f00f701 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -210,6 +210,17 @@ class privileged_api : public context_aware_api { }); } + void set_pbft_parameters_packed( array_ptr packed_pbft_parameters, size_t datalen) { + datastream ds( packed_pbft_parameters, datalen ); + chain::chain_config3 cfg; + fc::raw::unpack(ds, cfg); + cfg.validate(); + context.db.modify( context.control.get_pbft_properties(), + [&]( auto& gpp ) { + gpp.configuration = cfg; + }); + } + // *bos begin* void set_name_list_packed(int64_t list, int64_t action, array_ptr packed_name_list, size_t datalen) { diff --git a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp index 81935707abe..9a3212a56fd 100644 --- a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp +++ b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp @@ -80,6 +80,9 @@ namespace eosio { namespace chain { namespace plugin_interface { using checkpoint_channel = channel_decl; } + + using committed_transition_channel = channel_decl; + using prepared_transition_channel = channel_decl; } } } } diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 581bcb80443..c720b348e10 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -740,7 +740,7 @@ void chain_plugin::plugin_initialize(const variables_map& options) { ilog("include pbft controller..."); my->pbft_ctrl.emplace(*my->chain); - // set up method providers + // set up method providers my->get_block_by_number_provider = app().get_method().register_provider( [this]( uint32_t block_num ) -> signed_block_ptr { return my->chain->fetch_block_by_number( block_num ); @@ -825,27 +825,27 @@ void chain_plugin::plugin_initialize(const variables_map& options) { my->on_pbft_incoming_checkpoint(cp); }); - my->pbft_outgoing_prepare_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_prepare.connect( + my->pbft_outgoing_prepare_connection = my->pbft_ctrl->state_machine.pbft_outgoing_prepare.connect( [this]( const pbft_prepare_ptr& prepare ) { my->pbft_outgoing_prepare_channel.publish( prepare ); }); - my->pbft_outgoing_commit_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_commit.connect( + my->pbft_outgoing_commit_connection = my->pbft_ctrl->state_machine.pbft_outgoing_commit.connect( [this]( const pbft_commit_ptr& commit ) { my->pbft_outgoing_commit_channel.publish( commit ); }); - my->pbft_outgoing_view_change_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_view_change.connect( + my->pbft_outgoing_view_change_connection = my->pbft_ctrl->state_machine.pbft_outgoing_view_change.connect( [this]( const pbft_view_change_ptr& view_change ) { my->pbft_outgoing_view_change_channel.publish( view_change ); }); - my->pbft_outgoing_new_view_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_new_view.connect( + my->pbft_outgoing_new_view_connection = my->pbft_ctrl->state_machine.pbft_outgoing_new_view.connect( [this]( const pbft_new_view_ptr& new_view ) { my->pbft_outgoing_new_view_channel.publish( new_view ); }); - my->pbft_outgoing_checkpoint_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_checkpoint.connect( + my->pbft_outgoing_checkpoint_connection = my->pbft_ctrl->state_machine.pbft_outgoing_checkpoint.connect( [this]( const pbft_checkpoint_ptr& checkpoint ) { my->pbft_outgoing_checkpoint_channel.publish( checkpoint ); }); @@ -1209,8 +1209,8 @@ read_only::get_info_results read_only::get_info(const read_only::get_info_params db.fork_db_head_block_id(), db.fork_db_head_block_time(), db.fork_db_head_block_producer(), - pbft_ctrl.state_machine->get_current_view(), - pbft_ctrl.state_machine->get_target_view(), + pbft_ctrl.state_machine.get_current_view(), + pbft_ctrl.state_machine.get_target_view(), db.last_stable_checkpoint_block_num(), rm.get_virtual_block_cpu_limit(), rm.get_virtual_block_net_limit(), diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 529bd3ed900..31fdeec6dd1 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -153,13 +153,11 @@ namespace eosio { unique_ptr transaction_check; unique_ptr keepalive_timer; unique_ptr pbft_message_cache_timer; - unique_ptr connection_monitor_timer; boost::asio::steady_timer::duration connector_period; boost::asio::steady_timer::duration txn_exp_period; boost::asio::steady_timer::duration resp_expected_period; boost::asio::steady_timer::duration keepalive_interval{std::chrono::seconds{32}}; boost::asio::steady_timer::duration pbft_message_cache_tick_interval{std::chrono::seconds{10}}; - boost::asio::steady_timer::duration connection_monitor_tick_interval{std::chrono::seconds{2}}; int max_cleanup_time_ms = 0; const std::chrono::system_clock::duration peer_authentication_interval{std::chrono::seconds{1}}; ///< Peer clock may be no more than 1 second skewed from our clock, including network latency. @@ -246,16 +244,14 @@ namespace eosio { void handle_message( connection_ptr c, const response_p2p_message &msg); //pbft messages - bool maybe_add_to_pbft_cache(const string &key); + bool maybe_add_to_pbft_cache(const string& key); void clean_expired_pbft_messages(); template - bool is_pbft_msg_outdated(M const & msg); + bool is_pbft_msg_outdated(const M& msg); template - bool is_pbft_msg_valid(M const & msg); + bool is_pbft_msg_valid(const M& msg); - void bcast_pbft_msg(const net_message &msg, int ttl); - - void forward_pbft_msg(const connection_ptr& c, const net_message &msg, int ttl); + void bcast_pbft_msg(const net_message& msg, int ttl, const connection_ptr& c = nullptr); void pbft_outgoing_prepare(const pbft_prepare_ptr& prepare); void pbft_outgoing_commit(const pbft_commit_ptr& commit); @@ -263,14 +259,14 @@ namespace eosio { void pbft_outgoing_new_view(const pbft_new_view_ptr& new_view); void pbft_outgoing_checkpoint(const pbft_checkpoint_ptr& checkpoint); - void handle_message( const connection_ptr& c, const pbft_prepare &msg); - void handle_message( const connection_ptr& c, const pbft_commit &msg); - void handle_message( const connection_ptr& c, const pbft_view_change &msg); - void handle_message( const connection_ptr& c, const pbft_new_view &msg); - void handle_message( const connection_ptr& c, const pbft_checkpoint &msg); - void handle_message( const connection_ptr& c, const pbft_stable_checkpoint &msg); - void handle_message( const connection_ptr& c, const checkpoint_request_message &msg); - void handle_message( const connection_ptr& c, const compressed_pbft_message &msg); + void handle_message( const connection_ptr& c, const pbft_prepare& msg); + void handle_message( const connection_ptr& c, const pbft_commit& msg); + void handle_message( const connection_ptr& c, const pbft_view_change& msg); + void handle_message( const connection_ptr& c, const pbft_new_view& msg); + void handle_message( const connection_ptr& c, const pbft_checkpoint& msg); + void handle_message( const connection_ptr& c, const pbft_stable_checkpoint& msg); + void handle_message( const connection_ptr& c, const checkpoint_request_message& msg); + void handle_message( const connection_ptr& c, const compressed_pbft_message& msg); void start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection); void start_txn_timer(); @@ -281,7 +277,6 @@ namespace eosio { void connection_monitor(std::weak_ptr from_connection); void pbft_message_cache_ticker(); - void connection_monitor_ticker(); /** \name Peer Timestamps * Time message handling * @{ @@ -590,7 +585,6 @@ namespace eosio { std::shared_ptr> message; fc::time_point_sec deadline; }; - const int OUT_QUEUE_SIZE_LIMIT_FROM_WRITE_QUEUE = 100; const int OUT_QUEUE_SIZE_LIMIT = 200; deque pbft_queue; @@ -703,7 +697,7 @@ namespace eosio { std::function callback, bool to_sync_queue = false); void do_queue_write(); - void fill_out_buffer_with_pbft_queue(std::vector &bufs); + void fill_out_buffer_with_pbft_queue(std::vector& bufs); void send_p2p_request(bool discoverable); void send_p2p_response(bool discoverable,string p2p_peer_list); @@ -814,7 +808,6 @@ namespace eosio { void recv_handshake(const connection_ptr& c, const handshake_message& msg); void recv_notice(const connection_ptr& c, const notice_message& msg); bool is_syncing(); - void set_in_sync(); void sync_stable_checkpoints(const connection_ptr& c, uint32_t target); }; @@ -1152,16 +1145,15 @@ namespace eosio { }); } - void connection::fill_out_buffer_with_pbft_queue(std::vector &bufs){ + void connection::fill_out_buffer_with_pbft_queue(std::vector& bufs){ //delete timeout pbft message auto now = time_point::now(); - int drop_pbft_count = 0; - while (pbft_queue.size()>0) { - if (pbft_queue.front().deadline <= now) { - pbft_queue.pop_front(); - ++drop_pbft_count; + auto itr = pbft_queue.begin(); + while (itr != pbft_queue.end()) { + if (itr->deadline <= now) { + itr = pbft_queue.erase(itr); } else { - break; + ++itr; } } @@ -1399,7 +1391,7 @@ namespace eosio { return false; } return true; - } + } bool connection::add_peer_block(const peer_block_state& entry) { auto bptr = blk_state.get().find(entry.id); @@ -1486,10 +1478,6 @@ namespace eosio { return state != in_sync; } - void sync_manager::set_in_sync() { - set_state(in_sync); - } - void sync_manager::request_next_chunk( const connection_ptr& conn ) { uint32_t head_block = chain_plug->chain().fork_db_head_block_num(); @@ -1609,16 +1597,22 @@ namespace eosio { void sync_manager::sync_stable_checkpoints(const connection_ptr& c, uint32_t target) { controller& cc = chain_plug->chain(); uint32_t lscb_num = cc.last_stable_checkpoint_block_num(); - if (last_req_scp_num < lscb_num || last_req_scp_num == 0 || last_req_scp_num >= target) last_req_scp_num = lscb_num; + auto head_num = cc.head_block_num(); + if (last_req_scp_num < lscb_num + || last_req_scp_num == 0 + || last_req_scp_num > target) last_req_scp_num = lscb_num; + + auto pbft_checkpoint_granularity = chain_plug->pbft_ctrl().pbft_db.get_checkpoint_interval(); auto end = target; auto max_target_scp_num = last_req_scp_num + pbft_checkpoint_granularity * 10; - if (target > max_target_scp_num) end = max_target_scp_num; + if (target > max_target_scp_num) end = std::min(max_target_scp_num, head_num); + if (end - last_req_scp_num < pbft_checkpoint_granularity) return; checkpoint_request_message crm = {last_req_scp_num+1,end}; c->enqueue( net_message(crm)); fc_dlog(logger, "request sync stable checkpoints from ${s} to ${e}", - ("s", last_req_scp_num+1)("e", max_target_scp_num)); - last_req_scp_num = max_target_scp_num; + ("s", last_req_scp_num+1)("e", end)); + last_req_scp_num = end; } void sync_manager::reassign_fetch(const connection_ptr& c, go_away_reason reason) { @@ -2837,18 +2831,18 @@ namespace eosio { fc_dlog(logger, "received checkpoint request message ${m}, from ${p}", ("m", msg)("p", c->peer_name())); - if ( msg.end_block - msg.start_block > pbft_checkpoint_granularity * 100) { + if ( msg.end_block - msg.start_block > chain_plug->pbft_ctrl().pbft_db.get_checkpoint_interval() * 100) { fc_dlog(logger, "request range too large"); return; } vector scp_stack; - controller &cc = my_impl->chain_plug->chain(); - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + controller& cc = my_impl->chain_plug->chain(); + pbft_controller& pcc = my_impl->chain_plug->pbft_ctrl(); auto end_block = std::min(msg.end_block, cc.last_stable_checkpoint_block_num()); - for (auto i = end_block; i >= msg.start_block && i>0; --i) { + for (auto i = end_block; i >= msg.start_block && i > 0; --i) { try { auto bid = cc.get_block_id_for_num(i); auto scp = pcc.pbft_db.get_stable_checkpoint_by_id(bid); @@ -3008,21 +3002,11 @@ namespace eosio { && !sync_master->is_syncing(); } - void net_plugin_impl::bcast_pbft_msg(const net_message &msg, int ttl) { - if (sync_master->is_syncing()) return; + void net_plugin_impl::bcast_pbft_msg(const net_message &msg, int ttl, const connection_ptr& c) { +// if (sync_master->is_syncing()) return; auto deadline = time_point_sec(time_point::now()) + ttl; - for (auto &conn: connections) { - if (conn->pbft_ready()) { - conn->enqueue_pbft(encode_pbft_message(msg), deadline); - } - } - } - - void net_plugin_impl::forward_pbft_msg(const connection_ptr& c, const net_message &msg, int ttl) { - auto deadline = time_point_sec(time_point::now()) + ttl; - for (auto &conn: connections) { if (conn != c && conn->pbft_ready()) { conn->enqueue_pbft(encode_pbft_message(msg), deadline); @@ -3031,51 +3015,42 @@ namespace eosio { } void net_plugin_impl::pbft_outgoing_prepare(const pbft_prepare_ptr& msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); - if (!added) return; - - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - - bcast_pbft_msg(*msg, pbft_message_TTL); - fc_dlog( logger, "sent prepare at height: ${n}, view: ${v} ", ("n", msg->block_info.block_num())("v", msg->view)); + if (maybe_add_to_pbft_cache(std::string(msg->sender_signature))) { + bcast_pbft_msg(*msg, pbft_message_TTL); + fc_dlog(logger, "sent prepare at height: ${n}, view: ${v} ", + ("n", msg->block_info.block_num())("v", msg->view)); + } } void net_plugin_impl::pbft_outgoing_commit(const pbft_commit_ptr& msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); - if (!added) return; - - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - - bcast_pbft_msg(*msg, pbft_message_TTL); - fc_dlog( logger, "sent commit at height: ${n}, view: ${v} ", ("n", msg->block_info.block_num())("v", msg->view)); + if (maybe_add_to_pbft_cache(std::string(msg->sender_signature))) { + bcast_pbft_msg(*msg, pbft_message_TTL); + fc_dlog(logger, "sent commit at height: ${n}, view: ${v} ", + ("n", msg->block_info.block_num())("v", msg->view)); + } } void net_plugin_impl::pbft_outgoing_view_change(const pbft_view_change_ptr& msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); - if (!added) return; - - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - - bcast_pbft_msg(*msg, pbft_message_TTL); - fc_dlog( logger, "sent view change {cv: ${cv}, tv: ${tv}}", ("cv", msg->current_view)("tv", msg->target_view)); + if (maybe_add_to_pbft_cache(std::string(msg->sender_signature))) { + bcast_pbft_msg(*msg, pbft_message_TTL); + fc_dlog(logger, "sent view change {cv: ${cv}, tv: ${tv}}", + ("cv", msg->current_view)("tv", msg->target_view)); + } } void net_plugin_impl::pbft_outgoing_new_view(const pbft_new_view_ptr& msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); - if (!added) return; + if (maybe_add_to_pbft_cache(std::string(msg->sender_signature))) { + bcast_pbft_msg(*msg, 60 * pbft_message_TTL); + fc_dlog( logger, "sent new view at view: ${v} ", ("v", msg->new_view)); + } - bcast_pbft_msg(*msg, INT_MAX); - fc_dlog( logger, "sent new view at view: ${v} ", ("v", msg->new_view)); } void net_plugin_impl::pbft_outgoing_checkpoint(const pbft_checkpoint_ptr& msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); - if (!added) return; - - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - - bcast_pbft_msg(*msg, pbft_message_TTL); - fc_dlog( logger, "sent checkpoint at height: ${n} ", ("n", msg->block_info.block_num())); + if (maybe_add_to_pbft_cache(std::string(msg->sender_signature))) { + bcast_pbft_msg(*msg, pbft_message_TTL); + fc_dlog(logger, "sent checkpoint at height: ${n} ", ("n", msg->block_info.block_num())); + } } bool net_plugin_impl::maybe_add_to_pbft_cache(const string &key){ @@ -3103,99 +3078,89 @@ namespace eosio { } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_prepare &msg) { + if (is_pbft_msg_valid(msg) && maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { + auto pmm = pbft_message_metadata(msg, chain_id); - if (!is_pbft_msg_valid(msg)) return; - - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; - - auto pmm = pbft_message_metadata(std::move(msg), chain_id); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + if (!pcc.pbft_db.is_valid_prepare(pmm.msg, pmm.sender_key)) return; + bcast_pbft_msg(pmm.msg, pbft_message_TTL, c); + fc_dlog(logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", + ("n", pmm.msg.block_info.block_num())("v", pmm.msg.view)("k", pmm.sender_key)); - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_prepare(pmm.msg, pmm.sender_key)) return; - - forward_pbft_msg(c, pmm.msg, pbft_message_TTL); - fc_dlog( logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", pmm.msg.block_info.block_num())("v", pmm.msg.view)("k", pmm.sender_key)); + pbft_incoming_prepare_channel.publish(std::make_shared>(std::move(pmm))); + } - pbft_incoming_prepare_channel.publish(std::make_shared>(std::move(pmm))); } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_commit &msg) { + if (is_pbft_msg_valid(msg) && maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { + auto pmm = pbft_message_metadata(msg, chain_id); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + if (!pcc.pbft_db.is_valid_commit(pmm.msg, pmm.sender_key)) return; - if (!is_pbft_msg_valid(msg)) return; - - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; - - auto pmm = pbft_message_metadata(std::move(msg), chain_id); - - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_commit(pmm.msg, pmm.sender_key)) return; - - forward_pbft_msg(c, pmm.msg, pbft_message_TTL); - fc_dlog( logger, "received commit at height: ${n}, view: ${v}, from ${k}, ", ("n", pmm.msg.block_info.block_num())("v", pmm.msg.view)("k", pmm.sender_key)); + bcast_pbft_msg(pmm.msg, pbft_message_TTL, c); + fc_dlog(logger, "received commit at height: ${n}, view: ${v}, from ${k}, ", + ("n", pmm.msg.block_info.block_num())("v", pmm.msg.view)("k", pmm.sender_key)); - pbft_incoming_commit_channel.publish(std::make_shared>(std::move(pmm))); + pbft_incoming_commit_channel.publish(std::make_shared>(std::move(pmm))); + } } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_view_change &msg) { + if (is_pbft_msg_valid(msg) && maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { + auto pmm = pbft_message_metadata(msg, chain_id); - if (!is_pbft_msg_valid(msg)) return; - - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + controller &ctrl = my_impl->chain_plug->chain(); + if (!pcc.pbft_db.is_valid_view_change(pmm.msg, pmm.sender_key)) return; - auto pmm = pbft_message_metadata( std::move(msg), chain_id); - - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - controller &ctrl = my_impl->chain_plug->chain(); - if (!pcc.pbft_db.is_valid_view_change(pmm.msg, pmm.sender_key)) return; - - auto missing_blocks = set{}; - for (auto const &b: pmm.msg.prepared_cert.pre_prepares) { - if (!ctrl.fetch_block_by_id(b)) missing_blocks.emplace(b); - } + auto missing_blocks = set{}; + for (auto const &b: pmm.msg.prepared_cert.pre_prepares) { + if (!ctrl.fetch_block_by_id(b)) missing_blocks.emplace(b); + } - if (!missing_blocks.empty()) { - fc_dlog( logger, "requesting ${num} missing blocks from view change", ("num", missing_blocks.size())); - request_message req; - for (auto const &b: missing_blocks) { - req.req_blocks.ids.push_back(b); + if (!missing_blocks.empty()) { + fc_dlog(logger, "requesting ${num} missing blocks from view change", ("num", missing_blocks.size())); + request_message req; + for (auto const &b: missing_blocks) { + req.req_blocks.ids.push_back(b); + } + req.req_trx.mode = normal; + req.req_blocks.mode = normal; + c->enqueue(req); } - req.req_trx.mode = normal; - req.req_blocks.mode = normal; - c->enqueue(req); - } - forward_pbft_msg(c, pmm.msg, pbft_message_TTL); - fc_dlog( logger, "received view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", pmm.msg.current_view)("tv", pmm.msg.target_view)("v", pmm.sender_key)); + bcast_pbft_msg(pmm.msg, pbft_message_TTL, c); + fc_dlog(logger, "received view change {cv: ${cv}, tv: ${tv}} from ${v}", + ("cv", pmm.msg.current_view)("tv", pmm.msg.target_view)("v", pmm.sender_key)); - pbft_incoming_view_change_channel.publish(std::make_shared>(std::move(pmm))); + pbft_incoming_view_change_channel.publish(std::make_shared>(std::move(pmm))); + } } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_new_view &msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; + if (maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (time_point_sec(time_point::now()) > time_point_sec(msg.common.timestamp) + 60 * pbft_message_TTL - || msg.new_view <= pcc.state_machine->get_current_view()) { - //skip new view messages that are too old or whose target views are lower than mine. - return; - } + if (time_point_sec(time_point::now()) > time_point_sec(msg.common.timestamp) + 60 * pbft_message_TTL + || msg.new_view <= pcc.state_machine.get_current_view()) { + //skip new view messages that are too old or whose target views are lower than mine. + return; + } - auto pmm = pbft_message_metadata(std::move(msg), chain_id); + auto pmm = pbft_message_metadata(msg, chain_id); - if (pmm.sender_key != pcc.pbft_db.get_new_view_primary_key(pmm.msg.new_view)) return; + if (pmm.sender_key != pcc.pbft_db.get_new_view_primary_key(pmm.msg.new_view)) return; - forward_pbft_msg(c, pmm.msg, INT_MAX); - fc_dlog( logger, "received new view: ${n}, from ${v}", ("n", pmm.msg)("v", pmm.sender_key)); + bcast_pbft_msg(pmm.msg, 60 * pbft_message_TTL, c); + fc_dlog(logger, "received new view: ${n}, from ${v}", ("n", pmm.msg)("v", pmm.sender_key)); - pbft_incoming_new_view_channel.publish(std::make_shared>(std::move(pmm))); + pbft_incoming_new_view_channel.publish(std::make_shared>(std::move(pmm))); + } } void net_plugin_impl::handle_message( const connection_ptr& c, const compressed_pbft_message &msg) { @@ -3215,21 +3180,18 @@ namespace eosio { } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_checkpoint &msg) { + if (is_pbft_msg_valid(msg) && maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { + auto pmm = pbft_message_metadata(msg, chain_id); - if (!is_pbft_msg_valid(msg)) return; + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + if (!pcc.pbft_db.is_valid_checkpoint(pmm.msg, pmm.sender_key)) return; - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; + bcast_pbft_msg(pmm.msg, pbft_message_TTL, c); + fc_dlog(logger, "received checkpoint at ${n}, from ${v}", + ("n", pmm.msg.block_info.block_num())("v", pmm.sender_key)); - auto pmm = pbft_message_metadata(std::move(msg), chain_id); - - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_checkpoint(pmm.msg, pmm.sender_key)) return; - - forward_pbft_msg(c, pmm.msg, pbft_message_TTL); - fc_dlog( logger, "received checkpoint at ${n}, from ${v}", ("n", pmm.msg.block_info.block_num())("v", pmm.sender_key)); - - pbft_incoming_checkpoint_channel.publish(std::make_shared>(std::move(pmm))); + pbft_incoming_checkpoint_channel.publish(std::make_shared>(std::move(pmm))); + } } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_stable_checkpoint &msg) { @@ -3237,7 +3199,8 @@ namespace eosio { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_stable_checkpoint(msg, true)) return; - fc_ilog(logger, "received stable checkpoint at ${n}, from ${v}", ("n", msg.block_info.block_num())("v", c->peer_name())); + fc_ilog(logger, "received stable checkpoint at ${n}, from ${v}", + ("n", msg.block_info.block_num())("v", c->peer_name())); } void net_plugin_impl::start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection) { @@ -3266,87 +3229,17 @@ namespace eosio { }); } - void net_plugin_impl::pbft_message_cache_ticker() { - pbft_message_cache_timer->expires_from_now (pbft_message_cache_tick_interval); - pbft_message_cache_timer->async_wait ([this](boost::system::error_code ec) { - - if ( !ec ) { - clean_expired_pbft_messages(); - } else { - wlog ("pbft message cache ticker error: ${m}", ("m", ec.message())); - pbft_message_cache_ticker(); - } - - }); - } + void net_plugin_impl::pbft_message_cache_ticker() { + pbft_message_cache_timer->expires_from_now (pbft_message_cache_tick_interval); + pbft_message_cache_timer->async_wait ([this](boost::system::error_code ec) { - void net_plugin_impl::connection_monitor_ticker() { - connection_monitor_timer->expires_from_now (connection_monitor_tick_interval); - connection_monitor_timer->async_wait ([this](boost::system::error_code ec) { - connection_monitor_ticker (); - if (ec) { - wlog ("connection monitor ticker error: ${m}", ("m", ec.message())); - } - int total=0; - int current=0; - for(auto &conn: connections){ - if(conn->current()){ - ++current; - } - ++total; - auto is_open = conn->socket && conn->socket->is_open(); -// auto paddr = conn->peer_addr; -// paddr.insert(0, 20 - paddr.length(), ' '); - std::ostringstream ss; - - auto so = is_open?"1":"0"; - auto con = conn->connecting ?"1":"0"; - auto syn = conn->syncing ?"1":"0"; - auto cur = conn->current() ?"1":"0"; - ss << so << con << syn << cur ; - auto status = ss.str(); - - ss.str(""); - ss.clear(); - - ss << std::setfill(' ') << std::setw(22) << conn->peer_addr; - auto paddr = ss.str(); - - ss.str(""); - ss.clear(); - - ss << std::setfill(' ') << std::setw(6) << conn->buffer_queue.write_queue_size(); - auto write_queue = ss.str(); - - ss.str(""); - ss.clear(); - - ss << std::setfill(' ') << std::setw(6) << conn->buffer_queue.out_queue_size(); - auto out_queue = ss.str(); - - ss.str(""); - ss.clear(); - - ss << std::setfill(' ') << std::setw(6) << conn->pbft_queue.size(); - auto pbft_queue = ss.str(); - - auto conn_str = conn->peer_addr; - if(conn_str.empty()) { - try { - conn_str = boost::lexical_cast(conn->socket->remote_endpoint()); - } catch (...) { - - } - } - - dlog("connection: ${conn} \tstatus(socket|connecting|syncing|current): ${status}\t|\twrite_queue: ${write}\t|\tout_queue: ${out}\t|\tpbft_queue: ${pbft}", ("status",status)("conn",conn_str)("write",write_queue)("out",out_queue)("pbft",pbft_queue)); - } - dlog("connections stats: current : ${current}\t total : ${total} ",("current",current)("total",total)); - dlog("================================================================================================"); - auto local_trx_pool_size = local_txns.size(); - fc_dlog(logger, "local trx pool size: ${local_trx_pool_size}",("local_trx_pool_size",local_trx_pool_size)); - fc_dlog(logger, "================================================================================================"); - }); + if ( !ec ) { + clean_expired_pbft_messages(); + } else { + wlog ("pbft message cache ticker error: ${m}", ("m", ec.message())); + pbft_message_cache_ticker(); + } + }); } void net_plugin_impl::ticker() { @@ -3745,9 +3638,7 @@ namespace eosio { my->keepalive_timer.reset( new boost::asio::steady_timer( app().get_io_service())); my->ticker(); my->pbft_message_cache_timer.reset( new boost::asio::steady_timer( app().get_io_service())); - my->connection_monitor_timer.reset( new boost::asio::steady_timer( app().get_io_service())); my->pbft_message_cache_ticker(); -// my->connection_monitor_ticker(); } FC_LOG_AND_RETHROW() } diff --git a/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp b/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp index 69f67ea6cf8..726e4d43591 100644 --- a/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp +++ b/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp @@ -26,15 +26,15 @@ class pbft_plugin : public appbase::plugin { pbft_state get_pbft_record( const block_id_type& bid )const; - vector get_pbft_checkpoints_record(const block_num_type &bnum)const; - pbft_view_change_state get_view_change_record(const pbft_view_type& view)const; + vector get_pbft_checkpoints_record(block_num_type bnum)const; + pbft_view_change_state get_view_change_record(pbft_view_type view)const; vector get_watermarks()const; flat_map get_fork_schedules()const; const char* get_pbft_status()const; block_id_type get_pbft_prepared_id()const; block_id_type get_pbft_my_prepare_id()const; - void set_pbft_current_view(const pbft_view_type &view); + void set_pbft_current_view(pbft_view_type view); private: diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index 0dcc60a5d11..7d27f1607bd 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -3,32 +3,49 @@ #include #include #include +#include namespace eosio { static appbase::abstract_plugin &_pbft_plugin = app().register_plugin(); using namespace std; using namespace eosio::chain; + using namespace eosio::chain::plugin_interface; + using boost::signals2::scoped_connection; + class pbft_plugin_impl { public: + pbft_plugin_impl() + :transit_to_committed_channel(app().get_channel()) + ,transit_to_prepared_channel(app().get_channel()) + {} + unique_ptr prepare_timer; unique_ptr commit_timer; unique_ptr view_change_timer; unique_ptr checkpoint_timer; - boost::asio::steady_timer::duration prepare_timeout{std::chrono::milliseconds{1000}}; - boost::asio::steady_timer::duration commit_timeout{std::chrono::milliseconds{1000}}; + boost::asio::steady_timer::duration prepare_timeout{std::chrono::milliseconds{750}}; + boost::asio::steady_timer::duration commit_timeout{std::chrono::milliseconds{750}}; boost::asio::steady_timer::duration view_change_check_interval{std::chrono::seconds{5}}; - boost::asio::steady_timer::duration checkpoint_timeout{std::chrono::seconds{50}}; + boost::asio::steady_timer::duration checkpoint_timeout{std::chrono::seconds{25}}; void prepare_timer_tick(); - void commit_timer_tick(); - void view_change_timer_tick(); - void checkpoint_timer_tick(); + fc::optional pbft_transit_to_committed_connection; + pbft::committed_transition_channel::channel_type::handle transit_to_committed_subscription; + pbft::committed_transition_channel::channel_type& transit_to_committed_channel; + + fc::optional pbft_transit_to_prepared_connection; + pbft::prepared_transition_channel::channel_type::handle transit_to_prepared_subscription; + pbft::prepared_transition_channel::channel_type& transit_to_prepared_channel; + + void on_committed_transition(); + void on_prepared_transition(); + private: bool upgraded = false; bool is_replaying(); @@ -36,109 +53,48 @@ namespace eosio { bool pbft_ready(); }; - pbft_plugin::pbft_plugin() : my(new pbft_plugin_impl()) {} - - pbft_plugin::~pbft_plugin() = default; - - void pbft_plugin::set_program_options(options_description &, options_description &cfg) { + void pbft_plugin_impl::on_committed_transition() { + prepare_timer_tick(); } - void pbft_plugin::plugin_initialize(const variables_map &options) { - ilog("Initialize pbft plugin"); - my->prepare_timer = std::make_unique(app().get_io_service()); - my->commit_timer = std::make_unique(app().get_io_service()); - my->view_change_timer = std::make_unique(app().get_io_service()); - my->checkpoint_timer = std::make_unique(app().get_io_service()); - } - - void pbft_plugin::plugin_startup() { - my->prepare_timer_tick(); - my->commit_timer_tick(); - my->view_change_timer_tick(); - my->checkpoint_timer_tick(); - } - - void pbft_plugin::plugin_shutdown() {} - - pbft_state pbft_plugin::get_pbft_record( const block_id_type& bid ) const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - auto record = pbft_ctrl.pbft_db.get_pbft_state_by_id(bid); - if (record) return *record; - return pbft_state(); - } - - vector pbft_plugin::get_pbft_checkpoints_record(const block_num_type &bnum) const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - auto records = pbft_ctrl.pbft_db.get_checkpoints_by_num(bnum); - if (!records.empty()) return records; - return vector(); - } - pbft_view_change_state pbft_plugin::get_view_change_record(const pbft_view_type& view) const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - auto record = pbft_ctrl.pbft_db.get_view_changes_by_target_view(view); - if (record) return *record; - return pbft_view_change_state(); - } - - vector pbft_plugin::get_watermarks() const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - return pbft_ctrl.pbft_db.get_pbft_watermarks(); - } - - flat_map pbft_plugin::get_fork_schedules() const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - return pbft_ctrl.pbft_db.get_pbft_fork_schedules(); - } - - const char* pbft_plugin::get_pbft_status() const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - return pbft_ctrl.state_machine->get_current()->get_name(); - } - - block_id_type pbft_plugin::get_pbft_prepared_id() const { - auto& ctrl = app().get_plugin().chain(); - return ctrl.get_pbft_prepared(); - } - - block_id_type pbft_plugin::get_pbft_my_prepare_id() const { - auto& ctrl = app().get_plugin().chain(); - return ctrl.get_pbft_my_prepare(); - } - - void pbft_plugin::set_pbft_current_view(const pbft_view_type& view) { - //this is used to boost the recovery from a disaster, do not set this unless you have to do so. - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - pbft_ctrl.state_machine->manually_set_current_view(view); + void pbft_plugin_impl::on_prepared_transition() { + commit_timer_tick(); } void pbft_plugin_impl::prepare_timer_tick() { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + prepare_timer->expires_from_now(prepare_timeout); prepare_timer->async_wait([&](boost::system::error_code ec) { - prepare_timer_tick(); - if (ec) { + if ( ec == boost::asio::error::operation_aborted ) { + return; + } else if (ec) { wlog ("pbft plugin prepare timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { + chain::pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_prepare(); } + prepare_timer_tick(); }); } void pbft_plugin_impl::commit_timer_tick() { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + commit_timer->expires_from_now(commit_timeout); commit_timer->async_wait([&](boost::system::error_code ec) { - commit_timer_tick(); - if (ec) { + if ( ec == boost::asio::error::operation_aborted ) { + return; + } else if (ec) { wlog ("pbft plugin commit timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { + chain::pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_commit(); } + commit_timer_tick(); }); } void pbft_plugin_impl::view_change_timer_tick() { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + try { view_change_timer->cancel(); } catch (boost::system::system_error &e) { @@ -150,27 +106,31 @@ namespace eosio { if (ec) { wlog ("pbft plugin view change timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { + chain::pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_view_change(); } }); } void pbft_plugin_impl::checkpoint_timer_tick() { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + checkpoint_timer->expires_from_now(checkpoint_timeout); checkpoint_timer->async_wait([&](boost::system::error_code ec) { - checkpoint_timer_tick(); - if (ec) { + if ( ec == boost::asio::error::operation_aborted ) { + return; + } if (ec) { wlog ("pbft plugin checkpoint timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { + chain::pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_checkpoint(); - chain::controller &ctrl = app().get_plugin().chain(); - if ( ctrl.head_block_num() - ctrl.last_stable_checkpoint_block_num() / pbft_checkpoint_granularity > 1) { - //perhaps we need to sync stable checkpoints from other peers - app().get_plugin().maybe_sync_stable_checkpoints(); - } + chain::controller& ctrl = app().get_plugin().chain(); + if ( ctrl.head_block_num() - ctrl.last_stable_checkpoint_block_num() / pbft_ctrl.pbft_db.get_checkpoint_interval() > 1) { + //perhaps we need to sync stable checkpoints from other peers + app().get_plugin().maybe_sync_stable_checkpoints(); + } } + checkpoint_timer_tick(); }); } @@ -204,4 +164,87 @@ namespace eosio { return enabled && !is_syncing() && !is_replaying(); } + + pbft_plugin::pbft_plugin() : my(new pbft_plugin_impl()) {} + + pbft_plugin::~pbft_plugin() = default; + + void pbft_plugin::set_program_options(options_description &, options_description &cfg) { + } + + void pbft_plugin::plugin_initialize(const variables_map &options) { + ilog("Initialize pbft plugin"); + my->prepare_timer = std::make_unique(app().get_io_service()); + my->commit_timer = std::make_unique(app().get_io_service()); + my->view_change_timer = std::make_unique(app().get_io_service()); + my->checkpoint_timer = std::make_unique(app().get_io_service()); + } + + void pbft_plugin::plugin_startup() { + my->prepare_timer_tick(); + my->commit_timer_tick(); + my->view_change_timer_tick(); + my->checkpoint_timer_tick(); + + my->pbft_transit_to_prepared_connection = app().get_plugin().pbft_ctrl().state_machine.pbft_transit_to_prepared.connect( [this]( bool prepared ) { + my->on_prepared_transition(); + }); + + my->pbft_transit_to_committed_connection = app().get_plugin().pbft_ctrl().state_machine.pbft_transit_to_committed.connect( [this]( bool committed ) { + my->on_committed_transition(); + }); + } + + void pbft_plugin::plugin_shutdown() {} + + pbft_state pbft_plugin::get_pbft_record( const block_id_type& bid ) const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto record = pbft_ctrl.pbft_db.get_pbft_state_by_id(bid); + if (record) return *record; + return pbft_state(); + } + + vector pbft_plugin::get_pbft_checkpoints_record(block_num_type bnum) const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto records = pbft_ctrl.pbft_db.get_checkpoints_by_num(bnum); + if (!records.empty()) return records; + return vector(); + } + pbft_view_change_state pbft_plugin::get_view_change_record(pbft_view_type view) const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto record = pbft_ctrl.pbft_db.get_view_changes_by_target_view(view); + if (record) return *record; + return pbft_view_change_state(); + } + + vector pbft_plugin::get_watermarks() const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + return pbft_ctrl.pbft_db.get_pbft_watermarks(); + } + + flat_map pbft_plugin::get_fork_schedules() const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + return pbft_ctrl.pbft_db.get_pbft_fork_schedules(); + } + + const char* pbft_plugin::get_pbft_status() const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + return pbft_ctrl.state_machine.get_current()->get_name(); + } + + block_id_type pbft_plugin::get_pbft_prepared_id() const { + auto& ctrl = app().get_plugin().chain(); + return ctrl.get_pbft_prepared(); + } + + block_id_type pbft_plugin::get_pbft_my_prepare_id() const { + auto& ctrl = app().get_plugin().chain(); + return ctrl.get_pbft_my_prepare(); + } + + void pbft_plugin::set_pbft_current_view(pbft_view_type view) { + //this is used to boost the recovery from a disaster, do not set this unless you have to do so. + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + pbft_ctrl.state_machine.manually_set_current_view(view); + } } diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index f2d75c5a6e8..ff47933e765 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -209,13 +209,13 @@ BOOST_AUTO_TEST_CASE(view_change_validation) { BOOST_CHECK_EQUAL(ctrl.head_block_num(), 102); - for(int i = 0; i< pbft_ctrl.view_change_timeout; i++){ + for(int i = 0; i< pbft_ctrl.pbft_db.get_view_change_timeout(); i++){ pbft_ctrl.maybe_pbft_view_change(); } - pbft_ctrl.state_machine->do_send_view_change(); + pbft_ctrl.state_machine.do_send_view_change(); auto new_view = pbft_ctrl.pbft_db.get_proposed_new_view_num(); auto vcc = pbft_ctrl.pbft_db.generate_view_changed_certificate(new_view); - auto nv_msg = pbft_ctrl.pbft_db.send_pbft_new_view(vcc, new_view); + auto nv_msg = pbft_ctrl.pbft_db.generate_pbft_new_view(vcc, new_view); bool nv_flag; try { @@ -302,19 +302,19 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.last_irreversible_block_num(), 101); //generate new view with short fork prepare certificate - pbft_new_view_generator.state_machine->set_prepares_cache(pbft_prepare()); + pbft_new_view_generator.state_machine.set_prepare_cache(pbft_prepare()); BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_send_pbft_msg(), true); ctrl_new_view_generator.reset_pbft_my_prepare(); pbft_new_view_generator.maybe_pbft_prepare(); BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_prepared(), true); BOOST_CHECK_EQUAL(ctrl_new_view_generator.head_block_num(), 136); - for(int i = 0; ido_send_view_change(); + pbft_new_view_generator.state_machine.do_send_view_change(); auto new_view = pbft_new_view_generator.pbft_db.get_proposed_new_view_num(); auto vcc = pbft_new_view_generator.pbft_db.generate_view_changed_certificate(new_view); - auto nv_msg = pbft_new_view_generator.pbft_db.send_pbft_new_view( + auto nv_msg = pbft_new_view_generator.pbft_db.generate_pbft_new_view( vcc, new_view); @@ -393,7 +393,7 @@ BOOST_AUTO_TEST_CASE(new_view_with_committed_cert_call_two_times_maybe_switch_fo c1.produce_blocks(6); new_view_generator.produce_blocks(10); - c1_pbft_controller.state_machine->set_prepares_cache(pbft_prepare()); + c1_pbft_controller.state_machine.set_prepare_cache(pbft_prepare()); c1_ctrl.reset_pbft_my_prepare(); c1_pbft_controller.maybe_pbft_prepare(); c1.produce_block(); @@ -410,7 +410,7 @@ BOOST_AUTO_TEST_CASE(new_view_with_committed_cert_call_two_times_maybe_switch_fo //generate new view with long fork commit certificate - pbft_new_view_generator.state_machine->set_prepares_cache(pbft_prepare()); + pbft_new_view_generator.state_machine.set_prepare_cache(pbft_prepare()); BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_send_pbft_msg(), true); ctrl_new_view_generator.reset_pbft_my_prepare(); pbft_new_view_generator.maybe_pbft_prepare(); @@ -424,24 +424,22 @@ BOOST_AUTO_TEST_CASE(new_view_with_committed_cert_call_two_times_maybe_switch_fo new_view_generator.produce_block(); BOOST_CHECK_EQUAL(ctrl_new_view_generator.last_irreversible_block_num(), 137); - for(int i = 0; ido_send_view_change(); + pbft_new_view_generator.state_machine.do_send_view_change(); auto new_view = pbft_new_view_generator.pbft_db.get_proposed_new_view_num(); auto vcc = pbft_new_view_generator.pbft_db.generate_view_changed_certificate(new_view); - auto nv_msg = pbft_new_view_generator.pbft_db.send_pbft_new_view(vcc, new_view); + auto nv_msg = pbft_new_view_generator.pbft_db.generate_pbft_new_view(vcc, new_view); //can switch fork after apply prepare certificate in new view auto pmm = pbft_message_metadata(nv_msg, c1_pbft_controller.pbft_db.get_chain_id()); - /// boscore issue https://github.com/boscore/bos/issues/114. - /// It will never throw exception block_validate_exception, "next block must be in the future" in the version 20e08dba c1_pbft_controller.on_pbft_new_view(std::make_shared>(pmm)); c1_pbft_controller.maybe_pbft_commit(); c1.produce_blocks(2); BOOST_CHECK_EQUAL(c1_ctrl.last_irreversible_block_num(), 137); - // make sure commited block same with new view generator lib block + // make sure committed block same with new view generator lib block BOOST_CHECK_EQUAL(c1_ctrl.fetch_block_by_number(137)->id(), ctrl_new_view_generator.fetch_block_by_number(137)->id()); } @@ -542,28 +540,33 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { push_blocks(c2, c1); /// make c1 lib 98 c1_pbft_controller.maybe_pbft_prepare(); - pbft_prepare c2_prepare_ = c2_pbft_controller.state_machine->get_prepares_cache(); + pbft_prepare c2_prepare_ = c2_pbft_controller.state_machine.get_prepare_cache(); BOOST_CHECK_EQUAL(c2_prepare_.block_info.block_num(), 98); - c1_pbft_controller.state_machine->on_prepare(std::make_shared>(c2_prepare_, c2_pbft_controller.pbft_db.get_chain_id())); + c1_pbft_controller.state_machine.on_prepare(std::make_shared>(c2_prepare_, c2_pbft_controller.pbft_db.get_chain_id())); c1_pbft_controller.maybe_pbft_commit(); - pbft_commit c2_commit_ = c2_pbft_controller.state_machine->get_commits_cache(); - c1_pbft_controller.state_machine->on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); + pbft_commit c2_commit_ = c2_pbft_controller.state_machine.get_commit_cache(); + c1_pbft_controller.state_machine.on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); + auto c1_my_prepare_block = c1_ctrl.get_pbft_my_prepare(); c1.produce_block(); c1_pbft_controller.maybe_pbft_commit(); BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 98); +// c1_ctrl.set_pbft_my_prepare(c1_ctrl.get_block_id_for_num(99)); c2_pbft_controller.maybe_pbft_commit(); /// make c3_final lib 98 c3_final_pbft_controller.maybe_pbft_prepare(); - pbft_prepare c1_prepare_ = c1_pbft_controller.state_machine->get_prepares_cache(); - BOOST_CHECK_EQUAL(c1_prepare_.block_info.block_num(), 99); - c3_final_pbft_controller.state_machine->on_prepare(std::make_shared>(c1_prepare_, c1_pbft_controller.pbft_db.get_chain_id())); + pbft_prepare c1_prepare_ = c1_pbft_controller.state_machine.get_prepare_cache(); + + auto forks = c1_ctrl.fork_db().fetch_branch_from(c1_prepare_.block_info.block_id, c1_my_prepare_block); + BOOST_CHECK_EQUAL(forks.first.size() >= 1 && forks.second.size() == 1, true); + c3_final.produce_block(); + c3_final_pbft_controller.state_machine.on_prepare(std::make_shared>(c1_prepare_, c1_pbft_controller.pbft_db.get_chain_id())); c3_final_pbft_controller.maybe_pbft_commit(); - pbft_commit c1_commit_ = c1_pbft_controller.state_machine->get_commits_cache(); - c3_final_pbft_controller.state_machine->on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); + pbft_commit c1_commit_ = c1_pbft_controller.state_machine.get_commit_cache(); + c3_final_pbft_controller.state_machine.on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); c3_final.produce_block(); c3_final_pbft_controller.maybe_pbft_commit(); BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 98); @@ -572,36 +575,36 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { push_blocks(c2, c2_prime); pbft_prepare c1_prepare; - c1_prepare_ = c1_pbft_controller.state_machine->get_prepares_cache(); + c1_prepare_ = c1_pbft_controller.state_machine.get_prepare_cache(); c1_prepare = c1_prepare_; /// for set pbft commit cache to 99 c2.produce_block(); c2_pbft_controller.maybe_pbft_prepare(); - c2_prepare_ = c2_pbft_controller.state_machine->get_prepares_cache(); + c2_prepare_ = c2_pbft_controller.state_machine.get_prepare_cache(); BOOST_CHECK_EQUAL(c2_prepare_.block_info.block_num(), 99); c2_pbft_controller.maybe_pbft_commit(); c2.produce_block(); c2_pbft_controller.maybe_pbft_commit(); - c2_commit_ = c2_pbft_controller.state_machine->get_commits_cache(); + c2_commit_ = c2_pbft_controller.state_machine.get_commit_cache(); BOOST_CHECK_EQUAL(c2_commit_.block_info.block_num(), 99); BOOST_CHECK_EQUAL(c2.control->last_irreversible_block_num(), 99); push_blocks(c2, c1); c1_pbft_controller.maybe_pbft_prepare(); - c2_prepare_ = c2_pbft_controller.state_machine->get_prepares_cache(); - c1_pbft_controller.state_machine->on_prepare(std::make_shared>(c2_prepare_, c2_pbft_controller.pbft_db.get_chain_id())); + c2_prepare_ = c2_pbft_controller.state_machine.get_prepare_cache(); + c1_pbft_controller.state_machine.on_prepare(std::make_shared>(c2_prepare_, c2_pbft_controller.pbft_db.get_chain_id())); c1_pbft_controller.maybe_pbft_commit(); - c2_commit_ = c2_pbft_controller.state_machine->get_commits_cache(); - c1_pbft_controller.state_machine->on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); + c2_commit_ = c2_pbft_controller.state_machine.get_commit_cache(); + c1_pbft_controller.state_machine.on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); c1.produce_block(); c1_pbft_controller.maybe_pbft_commit(); - c1_prepare_ = c1_pbft_controller.state_machine->get_prepares_cache(); - c1_commit_ = c1_pbft_controller.state_machine->get_commits_cache(); - BOOST_CHECK_EQUAL(c1_commit_.block_info.block_num(), 99); + c1_prepare_ = c1_pbft_controller.state_machine.get_prepare_cache(); + c1_commit_ = c1_pbft_controller.state_machine.get_commit_cache(); + BOOST_CHECK_EQUAL(c1_commit_.block_info.block_num(), 100); BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 99); c3_final_pbft_controller.maybe_pbft_prepare(); @@ -609,25 +612,26 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c3_final.produce_block(); c3_final.produce_block(); - BOOST_CHECK_EQUAL(c1_prepare.block_info.block_num(), 99); - /// set c3 my preprare at 100 - c3_final_ctrl.set_pbft_my_prepare(c3_final_ctrl.get_block_id_for_num(100)); - c3_final_pbft_controller.state_machine->on_prepare(std::make_shared>(c1_prepare, c1_pbft_controller.pbft_db.get_chain_id())); + BOOST_CHECK_EQUAL(c1_prepare.block_info.block_num(), 100); + /// set c3 my prepare at 101 + c3_final_ctrl.set_pbft_my_prepare(c3_final_ctrl.get_block_id_for_num(101)); + c3_final_pbft_controller.state_machine.on_prepare(std::make_shared>(c1_prepare, c1_pbft_controller.pbft_db.get_chain_id())); - pbft_prepare c3_final_prepare = c3_final_pbft_controller.state_machine->get_prepares_cache(); - // check c3 prepare at 99 - BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 99); - curr_state = c3_final_pbft_controller.state_machine->get_current()->get_name(); + pbft_prepare c3_final_prepare = c3_final_pbft_controller.state_machine.get_prepare_cache(); + // check c3 prepare at 101 + BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 101); + curr_state = c3_final_pbft_controller.state_machine.get_current()->get_name(); BOOST_CHECK_EQUAL(curr_state, "{==== PREPARED ====}"); c3_final_pbft_controller.maybe_pbft_commit(); + c2_prime.produce_block(); c2_prime.create_accounts({N(tester1)}); - c2_prime.produce_blocks(5); + c2_prime.produce_blocks(6); //push fork to c3_final - for(int i = 100; i <= 104; i++) { + for(int i = 101; i <= 106; i++) { auto fb = c2_prime.control->fetch_block_by_number(i); c3_final.push_block(fb); } @@ -640,23 +644,23 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { BOOST_CHECK_EQUAL(tmp_c2_prime_prepared_fork->pbft_my_prepare, true); BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 98); - BOOST_CHECK_EQUAL(c3_final.control->head_block_num(), 104); + BOOST_CHECK_EQUAL(c3_final.control->head_block_num(), 106); c3_final_pbft_controller.maybe_pbft_commit(); c3_final.produce_block(); - pbft_commit c3_final_commit = c3_final_pbft_controller.state_machine->get_commits_cache(); + pbft_commit c3_final_commit = c3_final_pbft_controller.state_machine.get_commit_cache(); /// on commit will prepare next block immediately will trigger reserve prepare - c3_final_pbft_controller.state_machine->on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); + c3_final_pbft_controller.state_machine.on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); // for sync c3_final.produce_block(); c3_final_pbft_controller.maybe_pbft_commit(); - curr_state = c3_final_pbft_controller.state_machine->get_current()->get_name(); + curr_state = c3_final_pbft_controller.state_machine.get_current()->get_name(); BOOST_CHECK_EQUAL(curr_state, "{==== COMMITTED ====}"); - BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 99); + BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 100); c3_final_pbft_controller.maybe_pbft_prepare(); - c3_final_prepare = c3_final_pbft_controller.state_machine->get_prepares_cache(); - BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 100); + c3_final_prepare = c3_final_pbft_controller.state_machine.get_prepare_cache(); + BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 101); } From 08ec703be2f4fe2960bf1d5d03bcd2f416202725 Mon Sep 17 00:00:00 2001 From: thaipandada Date: Wed, 21 Aug 2019 09:49:45 +0800 Subject: [PATCH 11/14] update version info --- CMakeLists.txt | 2 +- Docker/README.md | 4 ++-- README.md | 2 +- README_CN.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 696bd5361f0..2276554450b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,7 @@ set( CXX_STANDARD_REQUIRED ON) set(VERSION_MAJOR 3) set(VERSION_MINOR 0) -set(VERSION_PATCH 1) +set(VERSION_PATCH 2) if(VERSION_SUFFIX) set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}") diff --git a/Docker/README.md b/Docker/README.md index 57d456fe78e..c06694deffb 100644 --- a/Docker/README.md +++ b/Docker/README.md @@ -20,10 +20,10 @@ cd bos/Docker docker build . -t boscore/bos -s BOS ``` -The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v3.0.1 tag, you could do the following: +The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v3.0.2 tag, you could do the following: ```bash -docker build -t boscore/bos:v3.0.1 --build-arg branch=v3.0.1 . +docker build -t boscore/bos:v3.0.2 --build-arg branch=v3.0.2 . ``` diff --git a/README.md b/README.md index 711835c591f..334f7cad8e0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # BOSCore - Born for DApps. Born for Usability. -## BOSCore Version: v3.0.1 +## BOSCore Version: v3.0.2 ### Basic EOSIO Version: v1.6.6 (support REX) # Background diff --git a/README_CN.md b/README_CN.md index ade0d3715a1..f7b893a12f7 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,6 +1,6 @@ # BOSCore - 更可用的链,为DApp而生。 -## BOSCore Version: v3.0.1 +## BOSCore Version: v3.0.2 ### Basic EOSIO Version: v1.6.6 (support REX) # 背景 From 2680d27f882d13770a85a8ef5ede2197be04f5cc Mon Sep 17 00:00:00 2001 From: thaipandada Date: Wed, 21 Aug 2019 13:38:32 +0800 Subject: [PATCH 12/14] fix issues 111 --- Docker/Dockerfile | 11 ++++++----- eosio_build.sh | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Docker/Dockerfile b/Docker/Dockerfile index 81b09c4171a..416cb2af00f 100644 --- a/Docker/Dockerfile +++ b/Docker/Dockerfile @@ -3,15 +3,16 @@ ARG branch=master ARG symbol=SYS ENV OPENSSL_ROOT_DIR /usr/include/openssl +ENV INSTALL_PREFIX=/usr/local/eosio +RUN mkdir -p "${INSTALL_PREFIX}" RUN git clone -b $branch https://github.com/boscore/bos.git --recursive \ && cd bos && echo "$branch:$(git rev-parse HEAD)" > /etc/eosio-version \ - && cmake -H. -B"/tmp/build" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \ - -DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX=/tmp/build -DBUILD_MONGO_DB_PLUGIN=true -DCORE_SYMBOL_NAME=$symbol \ - -DOPENSSL_ROOT_DIR="${OPENSSL_ROOT_DIR}" \ - && cmake --build /tmp/build --target install - + && cmake -H. -B"${INSTALL_PREFIX}" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \ + -DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}" -DBUILD_MONGO_DB_PLUGIN=true -DCORE_SYMBOL_NAME=$symbol \ + -DOPENSSL_ROOT_DIR="${OPENSSL_ROOT_DIR}" -DCMAKE_CXX_STANDARD_LIBRARIES="-lpthread" \ + && cmake --build "${INSTALL_PREFIX}" --target install FROM ubuntu:18.04 diff --git a/eosio_build.sh b/eosio_build.sh index b600e0905ea..eba45661cdd 100755 --- a/eosio_build.sh +++ b/eosio_build.sh @@ -272,6 +272,7 @@ -DCMAKE_C_COMPILER="${C_COMPILER}" -DWASM_ROOT="${WASM_ROOT}" -DCORE_SYMBOL_NAME="${CORE_SYMBOL_NAME}" \ -DOPENSSL_ROOT_DIR="${OPENSSL_ROOT_DIR}" -DBUILD_MONGO_DB_PLUGIN=true \ -DENABLE_COVERAGE_TESTING="${ENABLE_COVERAGE_TESTING}" -DBUILD_DOXYGEN="${DOXYGEN}" \ + -DCMAKE_CXX_STANDARD_LIBRARIES="-lpthread" \ -DCMAKE_INSTALL_PREFIX="/usr/local/eosio" ${LOCAL_CMAKE_FLAGS} "${SOURCE_DIR}" then printf "\\n\\t>>>>>>>>>>>>>>>>>>>> CMAKE building BOSCore has exited with the above error.\\n\\n" From 22bbfa062496239ffcaa48a5fcca49b6e9b20d25 Mon Sep 17 00:00:00 2001 From: thaipandada Date: Fri, 23 Aug 2019 14:02:09 +0800 Subject: [PATCH 13/14] adjust the dockerfile --- Docker/Dockerfile | 15 +++++---------- Docker/nodeosd.sh | 6 ------ 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/Docker/Dockerfile b/Docker/Dockerfile index 416cb2af00f..3ccc4bd0e62 100644 --- a/Docker/Dockerfile +++ b/Docker/Dockerfile @@ -3,28 +3,23 @@ ARG branch=master ARG symbol=SYS ENV OPENSSL_ROOT_DIR /usr/include/openssl -ENV INSTALL_PREFIX=/usr/local/eosio - -RUN mkdir -p "${INSTALL_PREFIX}" RUN git clone -b $branch https://github.com/boscore/bos.git --recursive \ && cd bos && echo "$branch:$(git rev-parse HEAD)" > /etc/eosio-version \ - && cmake -H. -B"${INSTALL_PREFIX}" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \ - -DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}" -DBUILD_MONGO_DB_PLUGIN=true -DCORE_SYMBOL_NAME=$symbol \ - -DOPENSSL_ROOT_DIR="${OPENSSL_ROOT_DIR}" -DCMAKE_CXX_STANDARD_LIBRARIES="-lpthread" \ - && cmake --build "${INSTALL_PREFIX}" --target install - + && cmake -H. -B"/tmp/build" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \ + -DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX=/tmp/build -DBUILD_MONGO_DB_PLUGIN=true -DCORE_SYMBOL_NAME=$symbol \ + -DOPENSSL_ROOT_DIR="${OPENSSL_ROOT_DIR}" -DCMAKE_CXX_STANDARD_LIBRARIES="-lpthread" \ + && cmake --build /tmp/build --target install FROM ubuntu:18.04 RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install openssl ca-certificates && rm -rf /var/lib/apt/lists/* COPY --from=builder /usr/local/lib/* /usr/local/lib/ COPY --from=builder /tmp/build/bin /opt/eosio/bin -COPY --from=builder /tmp/build/contracts /contracts COPY --from=builder /bos/Docker/config.ini / COPY --from=builder /etc/eosio-version /etc COPY --from=builder /bos/Docker/nodeosd.sh /opt/eosio/bin/nodeosd.sh ENV EOSIO_ROOT=/opt/eosio RUN chmod +x /opt/eosio/bin/nodeosd.sh ENV LD_LIBRARY_PATH /usr/local/lib -ENV PATH /opt/eosio/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +ENV PATH /opt/eosio/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \ No newline at end of file diff --git a/Docker/nodeosd.sh b/Docker/nodeosd.sh index 870548d6b6b..86f676dd159 100755 --- a/Docker/nodeosd.sh +++ b/Docker/nodeosd.sh @@ -11,12 +11,6 @@ if [ -f '/opt/eosio/bin/data-dir/config.ini' ]; then cp /config.ini /opt/eosio/bin/data-dir fi -if [ -d '/opt/eosio/bin/data-dir/contracts' ]; then - echo - else - cp -r /contracts /opt/eosio/bin/data-dir -fi - while :; do case $1 in --config-dir=?*) From b097d3ea46d5f090540cb84c0eaf320433635bec Mon Sep 17 00:00:00 2001 From: oldcold Date: Tue, 27 Aug 2019 02:06:36 +0800 Subject: [PATCH 14/14] avoid sending last prepare. --- libraries/chain/pbft.cpp | 4 +++- libraries/chain/pbft_database.cpp | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 8ac97cb1c49..69be56b67d2 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -301,7 +301,9 @@ namespace eosio { set_view_change_timer(0); set_current(std::make_shared(*this, pbft_db)); - emit(pbft_transit_to_committed, true); + if (!get_prepare_cache().empty()) { + emit(pbft_transit_to_committed, true); + } } void psm_machine::transit_to_prepared_state() { diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 5bf4a743bd1..84c7a70bcca 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -223,7 +223,8 @@ namespace eosio { if (high_watermark_block_num <= lib) return prepares_to_be_cached; - if (auto hwbs = ctrl.fork_db().get_block_in_current_chain_by_num(high_watermark_block_num)) { + auto hwbs = ctrl.fork_db().get_block_in_current_chain_by_num(high_watermark_block_num); + if ( hwbs && hwbs->id != my_prepare) { auto sent = false; for (const auto& sp : my_sps) { pbft_prepare new_p;