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); }