From 68c488635f3bcb5c5e78e9afb2f3a698ff9b6ce9 Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 19 Jun 2019 21:31:51 +0800 Subject: [PATCH 1/6] optimise pbft message body --- libraries/chain/include/eosio/chain/pbft.hpp | 135 ++-- .../include/eosio/chain/pbft_database.hpp | 346 ++++------ libraries/chain/pbft.cpp | 243 +++----- libraries/chain/pbft_database.cpp | 589 +++++++++--------- .../include/eosio/chain/plugin_interface.hpp | 10 +- plugins/chain_plugin/chain_plugin.cpp | 74 +-- plugins/net_plugin/net_plugin.cpp | 91 ++- .../include/eosio/pbft_plugin/pbft_plugin.hpp | 4 +- plugins/pbft_plugin/pbft_plugin.cpp | 2 +- unittests/pbft_tests.cpp | 14 +- 10 files changed, 671 insertions(+), 837 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index cba705a2c50..7fd22b8ab76 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 { - vector prepares_cache; - vector commits_cache; - vector view_changes_cache; - pbft_prepared_certificate prepared_certificate; - vector committed_certificate; - pbft_view_changed_certificate view_changed_certificate; + 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; }; class psm_state; @@ -37,77 +37,61 @@ namespace eosio { return current; } - void on_prepare(pbft_prepare &e); - void send_prepare(); + void on_prepare(pbft_metadata_ptr e); + void on_commit(pbft_metadata_ptr e); + void on_view_change(pbft_metadata_ptr e); + void on_new_view(const pbft_metadata_ptr &e); - void on_commit(pbft_commit &e); + void send_prepare(); void send_commit(); - - void on_view_change(pbft_view_change &e); void send_view_change(); - void on_new_view(pbft_new_view &e); - void transit_to_committed_state(psm_state_ptr s, bool to_new_view); - void transit_to_prepared_state(psm_state_ptr s); - - void do_send_view_change(); - void transit_to_view_change_state(psm_state_ptr s); + void transit_to_new_view(const pbft_metadata_ptr& e, const psm_state_ptr& s); - bool maybe_new_view(psm_state_ptr s); - - void transit_to_new_view(const pbft_new_view &new_view, psm_state_ptr s); - - const vector& get_prepares_cache() const; - - void set_prepares_cache(const vector &pcache); - - const vector& get_commits_cache() const; + void do_send_view_change(); + bool maybe_new_view(const psm_state_ptr& s); - void set_commits_cache(const vector &ccache); + const pbft_prepare& get_prepares_cache() const; + void set_prepares_cache(const pbft_prepare &pcache); - const vector& get_view_changes_cache() const; + const pbft_commit& get_commits_cache() const; + void set_commits_cache(const pbft_commit &ccache); - void set_view_changes_cache(const vector &vc_cache); + const pbft_view_change& get_view_changes_cache() const; + void set_view_changes_cache(const pbft_view_change &vc_cache); const uint32_t &get_current_view() const; - void set_current_view(const uint32_t &cv); const pbft_prepared_certificate& get_prepared_certificate() const; - void set_prepared_certificate(const pbft_prepared_certificate &pcert); const vector& get_committed_certificate() const; - void set_committed_certificate(const vector &ccert); const pbft_view_changed_certificate& get_view_changed_certificate() const; - void set_view_changed_certificate(const pbft_view_changed_certificate &vc_cert); const uint32_t& get_target_view_retries() const; - void set_target_view_retries(const uint32_t &tv_reties); const uint32_t& get_target_view() const; - void set_target_view(const uint32_t &tv); const uint32_t& get_view_change_timer() const; - void set_view_change_timer(const uint32_t &vc_timer); void manually_set_current_view(const uint32_t &cv); protected: - psm_cache cache; - uint32_t current_view; - uint32_t target_view_retries; - uint32_t target_view; - uint32_t view_change_timer; + psm_cache cache; + uint32_t current_view; + uint32_t target_view_retries; + uint32_t target_view; + uint32_t view_change_timer; private: psm_state_ptr current; @@ -122,22 +106,15 @@ namespace eosio { psm_state(); ~psm_state(); - virtual void on_prepare(psm_machine_ptr m, pbft_prepare &e, pbft_database &pbft_db) = 0; + virtual void on_prepare(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) = 0; + virtual void on_commit(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) = 0; + virtual void on_view_change(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) = 0; virtual void send_prepare(psm_machine_ptr m, pbft_database &pbft_db) = 0; - - virtual void on_commit(psm_machine_ptr m, pbft_commit &e, pbft_database &pbft_db) = 0; - virtual void send_commit(psm_machine_ptr m, pbft_database &pbft_db) = 0; - - virtual void on_view_change(psm_machine_ptr m, pbft_view_change &e, pbft_database &pbft_db) = 0; - virtual void send_view_change(psm_machine_ptr m, pbft_database &pbft_db) = 0; - virtual void on_new_view(psm_machine_ptr m, pbft_new_view &e, pbft_database &pbft_db) = 0; - virtual const char* get_name() = 0; - std::shared_ptr get_self() { return shared_from_this(); }; }; @@ -147,20 +124,14 @@ namespace eosio { psm_prepared_state(); ~psm_prepared_state(); - void on_prepare(psm_machine_ptr m, pbft_prepare &e, pbft_database &pbft_db) override; + void on_prepare(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) override; + void on_commit(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) override; + void on_view_change(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) override; void send_prepare(psm_machine_ptr m, pbft_database &pbft_db) override; - - void on_commit(psm_machine_ptr m, pbft_commit &e, pbft_database &pbft_db) override; - void send_commit(psm_machine_ptr m, pbft_database &pbft_db) override; - - void on_view_change(psm_machine_ptr m, pbft_view_change &e, pbft_database &pbft_db) override; - void send_view_change(psm_machine_ptr m, pbft_database &pbft_db) override; - void on_new_view(psm_machine_ptr m, pbft_new_view &e, pbft_database &pbft_db) override; - bool pending_commit_local; const char* get_name() override { return "{==== PREPARED ====}"; } @@ -171,39 +142,30 @@ namespace eosio { psm_committed_state(); ~psm_committed_state(); - void on_prepare(psm_machine_ptr m, pbft_prepare &e, pbft_database &pbft_db) override; + void on_prepare(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) override; + void on_commit(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) override; + void on_view_change(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) override; void send_prepare(psm_machine_ptr m, pbft_database &pbft_db) override; - - void on_commit(psm_machine_ptr m, pbft_commit &e, pbft_database &pbft_db) override; - void send_commit(psm_machine_ptr m, pbft_database &pbft_db) override; - - void on_view_change(psm_machine_ptr m, pbft_view_change &e, pbft_database &pbft_db) override; - void send_view_change(psm_machine_ptr m, pbft_database &pbft_db) override; - void on_new_view(psm_machine_ptr m, pbft_new_view &e, pbft_database &pbft_db) override; - const char* get_name() override { return "{==== COMMITTED ====}"; } }; class psm_view_change_state final: public psm_state { public: - void on_prepare(psm_machine_ptr m, pbft_prepare &e, pbft_database &pbft_db) override; - - void send_prepare(psm_machine_ptr m, pbft_database &pbft_db) override; + psm_view_change_state(); + ~psm_view_change_state(); - void on_commit(psm_machine_ptr m, pbft_commit &e, pbft_database &pbft_db) override; + void on_prepare(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) override; + void on_commit(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) override; + void on_view_change(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) override; + void send_prepare(psm_machine_ptr m, pbft_database &pbft_db) override; void send_commit(psm_machine_ptr m, pbft_database &pbft_db) override; - - void on_view_change(psm_machine_ptr m, pbft_view_change &e, pbft_database &pbft_db) override; - void send_view_change(psm_machine_ptr m, pbft_database &pbft_db) override; - void on_new_view(psm_machine_ptr m, pbft_new_view &e, pbft_database &pbft_db) override; - const char* get_name() override { return "{==== VIEW CHANGE ====}"; } }; @@ -211,21 +173,22 @@ namespace eosio { public: explicit pbft_controller(controller& ctrl); ~pbft_controller(); - const uint16_t view_change_timeout = 6; - pbft_database pbft_db; - std::shared_ptr state_machine; + const uint16_t view_change_timeout = 6; + + pbft_database pbft_db; + std::shared_ptr state_machine; void maybe_pbft_prepare(); void maybe_pbft_commit(); void maybe_pbft_view_change(); void send_pbft_checkpoint(); - void on_pbft_prepare(pbft_prepare &p); - void on_pbft_commit(pbft_commit &c); - void on_pbft_view_change(pbft_view_change &vc); - void on_pbft_new_view(pbft_new_view &nv); - void on_pbft_checkpoint(pbft_checkpoint &cp); + void on_pbft_prepare(pbft_metadata_ptr p); + void on_pbft_commit(pbft_metadata_ptr c); + void on_pbft_view_change(pbft_metadata_ptr vc); + void on_pbft_new_view(const pbft_metadata_ptr &nv); + void on_pbft_checkpoint(const pbft_metadata_ptr &cp); private: fc::path datadir; diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 7dcf2f5b51d..9521990f02e 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -9,9 +9,6 @@ #include #include #include -#include -#include -#include #include namespace eosio { @@ -19,11 +16,13 @@ namespace eosio { using boost::multi_index_container; using namespace boost::multi_index; using namespace std; - using boost::uuids::uuid; using pbft_view_type = uint32_t; - enum class pbft_message_type : uint16_t { + constexpr uint16_t pbft_checkpoint_granularity = 100; + constexpr uint16_t oldest_stable_checkpoint = 10000; + + enum class pbft_message_type : uint8_t { prepare, commit, checkpoint, @@ -45,32 +44,38 @@ namespace eosio { bool operator!=(const block_info_type &rhs) const { return !(*this == rhs); } + + bool empty() const { + return block_id == block_id_type(); + } }; struct pbft_message_common { - pbft_message_type type; explicit pbft_message_common(pbft_message_type t): type{t} {}; - string uuid; - public_key_type sender; - chain_id_type chain_id = chain_id_type(""); + pbft_message_type type; time_point timestamp = time_point::now(); - bool operator==(const pbft_message_common &rhs) const { - return type == rhs.type - && chain_id == rhs.chain_id - && sender == rhs.sender; - } + ~pbft_message_common() = default; + }; - bool empty() const { - return uuid.empty() - && sender == public_key_type() - && chain_id == chain_id_type(""); + template + struct pbft_message_metadata { + explicit pbft_message_metadata(pbft_message_body m, chain_id_type chain_id): msg{m} { + try { + sender_key = crypto::public_key(msg.sender_signature, msg.digest(chain_id), true); + } catch (fc::exception & /*e*/) { + wlog("bad pbft message signature: ${m}", ("m", msg)); + } } - ~pbft_message_common() = default; + pbft_message_body msg; + public_key_type sender_key; }; + template + using pbft_metadata_ptr = std::shared_ptr>; + struct pbft_prepare { explicit pbft_prepare() = default; @@ -79,12 +84,6 @@ namespace eosio { block_info_type block_info; signature_type sender_signature; - bool operator==(const pbft_prepare &rhs) const { - return common == rhs.common - && view == rhs.view - && block_info == rhs.block_info; - } - bool operator<(const pbft_prepare &rhs) const { if (block_info.block_num() < rhs.block_info.block_num()) { return true; @@ -95,22 +94,20 @@ namespace eosio { } } - digest_type digest() const { + bool empty() const { + return !view + && block_info.empty() + && sender_signature == signature_type(); + } + + digest_type digest(chain_id_type chain_id) const { digest_type::encoder enc; + fc::raw::pack(enc, chain_id); fc::raw::pack(enc, common); fc::raw::pack(enc, view); fc::raw::pack(enc, block_info); return enc.result(); } - - bool is_signature_valid() const { - try { - auto pk = crypto::public_key(sender_signature, digest(), true); - return common.sender == pk; - } catch (fc::exception & /*e*/) { - return false; - } - } }; struct pbft_commit { @@ -121,12 +118,6 @@ namespace eosio { block_info_type block_info; signature_type sender_signature; - bool operator==(const pbft_commit &rhs) const { - return common == rhs.common - && view == rhs.view - && block_info == rhs.block_info; - } - bool operator<(const pbft_commit &rhs) const { if (block_info.block_num() < rhs.block_info.block_num()) { return true; @@ -137,24 +128,24 @@ namespace eosio { } } - digest_type digest() const { + bool empty() const { + return !view + && block_info.empty() + && sender_signature == signature_type(); + } + + digest_type digest(chain_id_type chain_id) const { digest_type::encoder enc; + fc::raw::pack(enc, chain_id); fc::raw::pack(enc, common); fc::raw::pack(enc, view); fc::raw::pack(enc, block_info); return enc.result(); } - - bool is_signature_valid() const { - try { - auto pk = crypto::public_key(sender_signature, digest(), true); - return common.sender == pk; - } catch (fc::exception & /*e*/) { - return false; - } - } }; + using pbft_commit_ptr = std::shared_ptr; + struct pbft_checkpoint { explicit pbft_checkpoint() = default; @@ -162,34 +153,17 @@ namespace eosio { block_info_type block_info; signature_type sender_signature; - bool operator==(const pbft_checkpoint &rhs) const { - return common == rhs.common - && block_info == rhs.block_info; - } - - bool operator!=(const pbft_checkpoint &rhs) const { - return !(*this == rhs); - } - bool operator<(const pbft_checkpoint &rhs) const { return block_info.block_num() < rhs.block_info.block_num(); } - digest_type digest() const { + digest_type digest(chain_id_type chain_id) const { digest_type::encoder enc; + fc::raw::pack(enc, chain_id); fc::raw::pack(enc, common); fc::raw::pack(enc, block_info); return enc.result(); } - - bool is_signature_valid() const { - try { - auto pk = crypto::public_key(sender_signature, digest(), true); - return common.sender == pk; - } catch (fc::exception & /*e*/) { - return false; - } - } }; struct pbft_stable_checkpoint { @@ -248,7 +222,7 @@ namespace eosio { pbft_view_type current_view = 0; pbft_view_type target_view = 1; pbft_prepared_certificate prepared_cert; - vector committed_cert; + vector committed_certs; pbft_stable_checkpoint stable_checkpoint; signature_type sender_signature; @@ -256,32 +230,23 @@ namespace eosio { return target_view < rhs.target_view; } - digest_type digest() const { + digest_type digest(chain_id_type chain_id) const { digest_type::encoder enc; + fc::raw::pack(enc, chain_id); fc::raw::pack(enc, common); fc::raw::pack(enc, current_view); fc::raw::pack(enc, target_view); fc::raw::pack(enc, prepared_cert); - fc::raw::pack(enc, committed_cert); + fc::raw::pack(enc, committed_certs); fc::raw::pack(enc, stable_checkpoint); return enc.result(); } - bool is_signature_valid() const { - try { - auto pk = crypto::public_key(sender_signature, digest(), true); - return common.sender == pk; - } catch (fc::exception & /*e*/) { - return false; - } - } - bool empty() const { - return common.empty() - && current_view == 0 - && target_view == 0 + return !current_view + && target_view == 1 && prepared_cert.empty() - && committed_cert.empty() + && committed_certs.empty() && stable_checkpoint.empty() && sender_signature == signature_type(); } @@ -294,7 +259,7 @@ namespace eosio { vector view_changes; bool empty() const { - return target_view == 0 + return !target_view && view_changes.empty(); } }; @@ -305,7 +270,7 @@ namespace eosio { pbft_message_common common = pbft_message_common(pbft_message_type::new_view); pbft_view_type new_view = 0; pbft_prepared_certificate prepared_cert; - vector committed_cert; + vector committed_certs; pbft_stable_checkpoint stable_checkpoint; pbft_view_changed_certificate view_changed_cert; signature_type sender_signature; @@ -314,31 +279,22 @@ namespace eosio { return new_view < rhs.new_view; } - digest_type digest() const { + digest_type digest(chain_id_type chain_id) const { digest_type::encoder enc; + fc::raw::pack(enc, chain_id); fc::raw::pack(enc, common); fc::raw::pack(enc, new_view); fc::raw::pack(enc, prepared_cert); - fc::raw::pack(enc, committed_cert); + fc::raw::pack(enc, committed_certs); fc::raw::pack(enc, stable_checkpoint); fc::raw::pack(enc, view_changed_cert); return enc.result(); } - bool is_signature_valid() const { - try { - auto pk = crypto::public_key(sender_signature, digest(), true); - return common.sender == pk; - } catch (fc::exception & /*e*/) { - return false; - } - } - bool empty() const { - return common.empty() - && new_view == 0 + return new_view == 0 && prepared_cert.empty() - && committed_cert.empty() + && committed_certs.empty() && stable_checkpoint.empty() && view_changed_cert.empty() && sender_signature == signature_type(); @@ -346,25 +302,25 @@ namespace eosio { }; struct pbft_state { - block_id_type block_id; - block_num_type block_num = 0; - vector prepares; - bool is_prepared = false; - vector commits; - bool is_committed = false; + block_id_type block_id; + block_num_type block_num = 0; + flat_map, pbft_prepare> prepares; + bool is_prepared = false; + flat_map, pbft_commit> commits; + bool is_committed = false; }; struct pbft_view_change_state { - pbft_view_type view; - vector view_changes; - bool is_view_changed = false; + pbft_view_type view; + flat_map view_changes; + bool is_view_changed = false; }; struct pbft_checkpoint_state { - block_id_type block_id; - block_num_type block_num = 0; - vector checkpoints; - bool is_stable = false; + block_id_type block_id; + block_num_type block_num = 0; + flat_map checkpoints; + bool is_stable = false; }; using pbft_state_ptr = std::shared_ptr; @@ -457,108 +413,73 @@ namespace eosio { void close(); - bool should_prepared(); - - bool should_committed(); - - pbft_view_type should_view_change(); - - bool should_new_view(pbft_view_type target_view); - - bool is_new_primary(pbft_view_type target_view); - - pbft_view_type get_proposed_new_view_num(); - - void add_pbft_prepare(pbft_prepare &p); - - void mark_as_prepared(const block_id_type &bid); + void add_pbft_prepare(pbft_prepare &p, const public_key_type &pk); + void add_pbft_commit(pbft_commit &c, const public_key_type &pk); + void add_pbft_view_change(pbft_view_change &vc, const public_key_type &pk); + void add_pbft_checkpoint(pbft_checkpoint &cp, const public_key_type &pk); - void add_pbft_commit(pbft_commit &c); - - void mark_as_committed(const block_id_type &bid); - - void add_pbft_view_change(pbft_view_change &vc); - - void add_pbft_checkpoint(pbft_checkpoint &cp); - - vector send_and_add_pbft_prepare( - const vector &pv = vector{}, - pbft_view_type current_view = 0); - - vector send_and_add_pbft_commit( - const vector &cv = vector{}, - pbft_view_type current_view = 0); - - vector send_and_add_pbft_view_change( - const vector &vcv = vector{}, - const pbft_prepared_certificate &ppc = pbft_prepared_certificate{}, + 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, - pbft_view_type new_view = 1); - + pbft_view_type target_view = 1); pbft_new_view send_pbft_new_view( - const pbft_view_changed_certificate &vcc = pbft_view_changed_certificate{}, + const pbft_view_changed_certificate &vcc = pbft_view_changed_certificate(), pbft_view_type current_view = 1); - vector generate_and_add_pbft_checkpoint(); + void send_pbft_checkpoint(); - bool is_valid_prepare(const pbft_prepare &p); - - bool is_valid_commit(const pbft_commit &c); + bool should_prepared(); + bool should_committed(); + pbft_view_type should_view_change(); + bool should_new_view(pbft_view_type target_view); + + //new view + 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 commit_local(); + void checkpoint_local(); - bool pending_pbft_lib(); - - void prune_pbft_index(); - - pbft_view_type get_committed_view(); - + //view change 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); - pbft_stable_checkpoint get_stable_checkpoint_by_id(const block_id_type &block_id); - - pbft_stable_checkpoint fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr &b); - - block_info_type cal_pending_stable_checkpoint() const; - + //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 should_send_pbft_msg(); - bool should_recv_pbft_msg(const public_key_type &pub_key); - public_key_type get_new_view_primary_key(pbft_view_type target_view); - - void send_pbft_checkpoint(); - - void checkpoint_local(); - - bool is_valid_checkpoint(const pbft_checkpoint &cp); - - bool is_valid_stable_checkpoint(const pbft_stable_checkpoint &scp); - - bool is_valid_view_change(const pbft_view_change &vc); - - bool is_valid_new_view(const pbft_new_view &nv); + 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); + pbft_stable_checkpoint fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr &b); + block_info_type cal_pending_stable_checkpoint() const; - bool should_stop_view_change(const pbft_view_change &vc); + void cleanup_on_new_view(); + void update_fork_schedules(); + //api related pbft_state_ptr get_pbft_state_by_id(const block_id_type &id) const; - vector get_checkpoints_by_num(const block_num_type &num) const; - pbft_view_change_state_ptr get_view_changes_by_target_view(const pbft_view_type &tv) const; - vector get_pbft_watermarks() const; - flat_map get_pbft_fork_schedules() const; - block_num_type get_current_pbft_watermark(); - - void update_fork_schedules(); signal pbft_outgoing_prepare; signal pbft_incoming_prepare; @@ -580,47 +501,33 @@ namespace eosio { 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; - chain_id_type chain_id = ctrl.get_chain_id(); fc::path pbft_db_dir; fc::path checkpoints_dir; - boost::uuids::random_generator uuid_generator; vector prepare_watermarks; flat_map fork_schedules; + chain_id_type chain_id = ctrl.get_chain_id(); - bool is_valid_pbft_message(const pbft_message_common &common); bool is_less_than_high_watermark(const block_num_type &bnum); - - bool is_valid_prepared_certificate(const pbft_prepared_certificate &certificate); - - bool is_valid_committed_certificate(const pbft_committed_certificate &certificate); - - vector> fetch_fork_from(vector &block_infos); - - vector fetch_first_fork_from(vector &bi); - - bool is_valid_longest_fork( - const block_info_type &bi, - vector block_infos, - unsigned long threshold, - unsigned long non_fork_bp_count); + bool is_valid_prepared_certificate(const pbft_prepared_certificate &certificate, bool add_to_pbft_db = false); + bool is_valid_committed_certificate(const pbft_committed_certificate &certificate, bool add_to_pbft_db = false); + bool is_valid_longest_fork(const block_info_type &bi, vector block_infos, unsigned long threshold, unsigned long non_fork_bp_count); producer_schedule_type lscb_active_producers() const; - vector& get_updated_watermarks(); - flat_map& get_updated_fork_schedules(); + block_num_type get_current_pbft_watermark(); + + vector> fetch_fork_from(vector &block_infos); + vector fetch_first_fork_from(vector &bi); template void emit(const Signal &s, Arg &&a); void set(const pbft_state_ptr& s); - void set(const pbft_checkpoint_state_ptr& s); - void prune(const pbft_state_ptr &h); - - void prune_checkpoints(const pbft_checkpoint_state_ptr &h); + void prune(const pbft_checkpoint_state_ptr &h); }; } } /// namespace eosio::chain @@ -628,12 +535,15 @@ namespace eosio { FC_REFLECT(eosio::chain::block_info_type, (block_id)) FC_REFLECT_ENUM(eosio::chain::pbft_message_type, (prepare)(commit)(checkpoint)(view_change)(new_view)) -FC_REFLECT(eosio::chain::pbft_message_common, (type)(uuid)(sender)(chain_id)(timestamp)) +FC_REFLECT(eosio::chain::pbft_message_common, (type)(timestamp)) + +FC_REFLECT_TEMPLATE((typename pbft_message_body), eosio::chain::pbft_message_metadata, (msg)(sender_key)) + FC_REFLECT(eosio::chain::pbft_prepare, (common)(view)(block_info)(sender_signature)) FC_REFLECT(eosio::chain::pbft_commit, (common)(view)(block_info)(sender_signature)) FC_REFLECT(eosio::chain::pbft_checkpoint,(common)(block_info)(sender_signature)) -FC_REFLECT(eosio::chain::pbft_view_change, (common)(current_view)(target_view)(prepared_cert)(committed_cert)(stable_checkpoint)(sender_signature)) -FC_REFLECT(eosio::chain::pbft_new_view, (common)(new_view)(prepared_cert)(committed_cert)(stable_checkpoint)(view_changed_cert)(sender_signature)) +FC_REFLECT(eosio::chain::pbft_view_change, (common)(current_view)(target_view)(prepared_cert)(committed_certs)(stable_checkpoint)(sender_signature)) +FC_REFLECT(eosio::chain::pbft_new_view, (common)(new_view)(prepared_cert)(committed_certs)(stable_checkpoint)(view_changed_cert)(sender_signature)) FC_REFLECT(eosio::chain::pbft_prepared_certificate, (block_info)(pre_prepares)(prepares)) diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index dc8e87f8198..e68f755fc13 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -61,19 +63,19 @@ namespace eosio { } } - void pbft_controller::on_pbft_prepare(pbft_prepare &p) { - state_machine->on_prepare(p); + void pbft_controller::on_pbft_prepare(pbft_metadata_ptr p) { + state_machine->on_prepare(std::move(p)); } - void pbft_controller::on_pbft_commit(pbft_commit &c) { - state_machine->on_commit(c); + void pbft_controller::on_pbft_commit(pbft_metadata_ptr c) { + state_machine->on_commit(std::move(c)); } - void pbft_controller::on_pbft_view_change(pbft_view_change &vc) { - state_machine->on_view_change(vc); + void pbft_controller::on_pbft_view_change(pbft_metadata_ptr vc) { + state_machine->on_view_change(std::move(vc)); } - void pbft_controller::on_pbft_new_view(pbft_new_view &nv) { + void pbft_controller::on_pbft_new_view(const pbft_metadata_ptr &nv) { state_machine->on_new_view(nv); } @@ -83,8 +85,9 @@ namespace eosio { pbft_db.checkpoint_local(); } - void pbft_controller::on_pbft_checkpoint(pbft_checkpoint &cp) { - pbft_db.add_pbft_checkpoint(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(); } @@ -96,9 +99,9 @@ namespace eosio { psm_machine::psm_machine(pbft_database &pbft_db) : pbft_db(pbft_db) { set_current(std::make_shared()); - set_prepares_cache(vector{}); - set_commits_cache(vector{}); - set_view_changes_cache(vector{}); + 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{}); @@ -112,51 +115,61 @@ namespace eosio { psm_machine::~psm_machine() = default; - void psm_machine::on_prepare(pbft_prepare &e) { - current->on_prepare(shared_from_this(), e, pbft_db); + void psm_machine::on_prepare(pbft_metadata_ptr e) { + current->on_prepare(shared_from_this(), std::move(e), pbft_db); } void psm_machine::send_prepare() { current->send_prepare(shared_from_this(), pbft_db); } - void psm_machine::on_commit(pbft_commit &e) { - current->on_commit(shared_from_this(), e, pbft_db); + void psm_machine::on_commit(pbft_metadata_ptr e) { + current->on_commit(shared_from_this(), std::move(e), pbft_db); } void psm_machine::send_commit() { current->send_commit(shared_from_this(), pbft_db); } - void psm_machine::on_view_change(pbft_view_change &e) { - current->on_view_change(shared_from_this(), e, pbft_db); + void psm_machine::on_view_change(pbft_metadata_ptr e) { + current->on_view_change(shared_from_this(), std::move(e), pbft_db); } void psm_machine::send_view_change() { current->send_view_change(shared_from_this(), pbft_db); } - void psm_machine::on_new_view(pbft_new_view &e) { - current->on_new_view(shared_from_this(), e, pbft_db); + void psm_machine::on_new_view(const pbft_metadata_ptr &e) { + if (e->msg.new_view <= get_current_view()) return; + + try { + pbft_db.validate_new_view(e->msg, e->sender_key); + } catch (const fc::exception& ex) { + elog("bad new view, ${s} ", ("s",ex.to_string())); + return; + } + + try { + transit_to_new_view(e, current); + } 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) { set_current_view(cv); set_target_view(cv + 1); - transit_to_view_change_state(get_current()); + transit_to_view_change_state(current); } /** * psm_prepared_state */ - psm_prepared_state::psm_prepared_state() { - pending_commit_local = false; - } - + psm_prepared_state::psm_prepared_state() {pending_commit_local = false;} psm_prepared_state::~psm_prepared_state() = default; - void psm_prepared_state::on_prepare(psm_machine_ptr m, pbft_prepare &e, pbft_database &pbft_db) { + void psm_prepared_state::on_prepare(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) { //ignore } @@ -167,11 +180,12 @@ namespace eosio { pbft_db.send_and_add_pbft_prepare(m->get_prepares_cache(), m->get_current_view()); } - void psm_prepared_state::on_commit(psm_machine_ptr m, pbft_commit &e, pbft_database &pbft_db) { + void psm_prepared_state::on_commit(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) { - if (e.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); + pbft_db.add_pbft_commit(e->msg, e->sender_key); //`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; @@ -207,11 +221,12 @@ namespace eosio { } } - void psm_prepared_state::on_view_change(psm_machine_ptr m, pbft_view_change &e, pbft_database &pbft_db) { + void psm_prepared_state::on_view_change(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) { - if (e.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); + 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(); @@ -225,30 +240,20 @@ namespace eosio { m->transit_to_view_change_state(shared_from_this()); } - void psm_prepared_state::on_new_view(psm_machine_ptr m, pbft_new_view &e, pbft_database &pbft_db) { - - if (e.new_view <= m->get_current_view()) return; - - try { - m->transit_to_new_view(e, shared_from_this()); - } catch(const fc::exception& ex) { - wlog("bad new view, ${s} ", ("s",ex.to_string())); - } - } psm_committed_state::psm_committed_state() = default; - psm_committed_state::~psm_committed_state() = default; /** * psm_committed_state */ - void psm_committed_state::on_prepare(psm_machine_ptr m, pbft_prepare &e, pbft_database &pbft_db) { + void psm_committed_state::on_prepare(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) { //validate - if (e.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); + 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()); @@ -266,11 +271,12 @@ namespace eosio { if (pbft_db.should_prepared()) m->transit_to_prepared_state(shared_from_this()); } - void psm_committed_state::on_commit(psm_machine_ptr m, pbft_commit &e, pbft_database &pbft_db) { + void psm_committed_state::on_commit(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) { - if (e.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); + pbft_db.add_pbft_commit(e->msg, e->sender_key); } void psm_committed_state::send_commit(psm_machine_ptr m, pbft_database &pbft_db) { @@ -280,11 +286,12 @@ namespace eosio { } - void psm_committed_state::on_view_change(psm_machine_ptr m, pbft_view_change &e, pbft_database &pbft_db) { + void psm_committed_state::on_view_change(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) { - if (e.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); + 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(); @@ -298,21 +305,12 @@ namespace eosio { m->transit_to_view_change_state(shared_from_this()); } - void psm_committed_state::on_new_view(psm_machine_ptr m, pbft_new_view &e, pbft_database &pbft_db) { - - if (e.new_view <= m->get_current_view()) return; - - try { - m->transit_to_new_view(e, shared_from_this()); - } catch(const fc::exception& ex) { - wlog("bad new view, ${s} ", ("s",ex.to_string())); - } - } - + psm_view_change_state::psm_view_change_state() = default; + psm_view_change_state::~psm_view_change_state() = default; /** * psm_view_change_state */ - void psm_view_change_state::on_prepare(psm_machine_ptr m, pbft_prepare &e, pbft_database &pbft_db) { + void psm_view_change_state::on_prepare(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) { //ignore; } @@ -320,7 +318,7 @@ namespace eosio { //ignore; } - void psm_view_change_state::on_commit(psm_machine_ptr m, pbft_commit &e, pbft_database &pbft_db) { + void psm_view_change_state::on_commit(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) { //ignore; } @@ -328,18 +326,19 @@ namespace eosio { //ignore; } - void psm_view_change_state::on_view_change(psm_machine_ptr m, pbft_view_change &e, pbft_database &pbft_db) { + void psm_view_change_state::on_view_change(psm_machine_ptr m, pbft_metadata_ptr e, 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.front())) { + if (!vc.empty() && pbft_db.should_stop_view_change(vc)) { m->transit_to_committed_state(shared_from_this(), false); return; } - if (e.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); + pbft_db.add_pbft_view_change(e->msg, e->sender_key); m->maybe_new_view(shared_from_this()); } @@ -348,7 +347,7 @@ namespace eosio { //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.front())) { + if (!vc.empty() && pbft_db.should_stop_view_change(vc)) { m->transit_to_committed_state(shared_from_this(), false); return; } @@ -358,18 +357,6 @@ namespace eosio { m->maybe_new_view(shared_from_this()); } - - void psm_view_change_state::on_new_view(psm_machine_ptr m, pbft_new_view &e, pbft_database &pbft_db) { - - if (e.new_view <= m->get_current_view()) return; - - try { - m->transit_to_new_view(e, shared_from_this()); - } catch(const fc::exception& ex) { - wlog("bad new view, ${s} ", ("s",ex.to_string())); - } - } - void psm_machine::transit_to_committed_state(psm_state_ptr s, bool to_new_view) { if (!to_new_view) { @@ -378,10 +365,10 @@ namespace eosio { set_target_view(get_current_view() + 1); } - auto prepares = pbft_db.send_and_add_pbft_prepare(vector{}, get_current_view()); + auto prepares = pbft_db.send_and_add_pbft_prepare(pbft_prepare(), get_current_view()); set_prepares_cache(prepares); - set_view_changes_cache(vector{}); + set_view_changes_cache(pbft_view_change()); set_view_change_timer(0); set_current(std::make_shared()); @@ -390,10 +377,10 @@ namespace eosio { void psm_machine::transit_to_prepared_state(psm_state_ptr s) { - auto commits = pbft_db.send_and_add_pbft_commit(vector{}, get_current_view()); + auto commits = pbft_db.send_and_add_pbft_commit(pbft_commit(), get_current_view()); set_commits_cache(commits); - set_view_changes_cache(vector{}); + set_view_changes_cache(pbft_view_change()); set_current(std::make_shared()); s.reset(); @@ -401,8 +388,8 @@ namespace eosio { void psm_machine::transit_to_view_change_state(psm_state_ptr s) { - set_commits_cache(vector{}); - set_prepares_cache(vector{}); + set_commits_cache(pbft_commit()); + set_prepares_cache(pbft_prepare()); set_view_change_timer(0); set_target_view_retries(0); @@ -416,10 +403,11 @@ namespace eosio { s.reset(); } - bool psm_machine::maybe_new_view(psm_state_ptr s) { + 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 auto nv = get_target_view(); - if (pbft_db.should_new_view(nv) && pbft_db.is_new_primary(nv)) { + auto pk = pbft_db.get_new_view_primary_key(nv); + if (pbft_db.should_new_view(nv) && pbft_db.has_new_primary(pk)) { set_view_changed_certificate(pbft_db.generate_view_changed_certificate(nv)); @@ -433,69 +421,44 @@ namespace eosio { if (nv_msg.empty()) return false; try { - transit_to_new_view(nv_msg, s); + pbft_db.validate_new_view(nv_msg, pk); + } catch (const fc::exception& ex) { + elog("bad new view, ${s} ", ("s", ex.to_string())); + return false; + } + + try { + transit_to_new_view(std::make_shared>(nv_msg, pbft_db.get_chain_id()), s); return true; } catch(const fc::exception& ex) { - wlog("bad new view, ${s} ", ("s",ex.to_string())); + elog("apply new view failed, waiting for next round.. ${nv} ", ("nv", nv_msg)); } } return false; } - void psm_machine::transit_to_new_view(const pbft_new_view &new_view, psm_state_ptr s) { - - bool valid_nv; - try { - valid_nv = pbft_db.is_valid_new_view(new_view); - } catch (const fc::exception& ex) { - throw; - } - EOS_ASSERT(valid_nv, pbft_exception, "new view is not valid, waiting for next round.."); + void psm_machine::transit_to_new_view(const pbft_metadata_ptr& e, const psm_state_ptr& s) { - set_current_view(new_view.new_view); - set_target_view(new_view.new_view + 1); + set_current_view(e->msg.new_view); + set_target_view(e->msg.new_view + 1); - set_prepares_cache(vector{}); + set_prepares_cache(pbft_prepare()); set_view_change_timer(0); set_target_view_retries(0); - pbft_db.prune_pbft_index(); + pbft_db.cleanup_on_new_view(); - if (!(new_view.stable_checkpoint.empty())) { - for (auto cp :new_view.stable_checkpoint.checkpoints) { - try { - pbft_db.add_pbft_checkpoint(cp); - } catch (...) { - wlog( "checkpoint insertion failure: ${cp}", ("cp", cp)); - } - } - } - - if (!new_view.committed_cert.empty()) { - auto committed_certs = new_view.committed_cert; + 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 (auto c: cc.commits) { - try { - pbft_db.add_pbft_commit(c); - } catch (...) { - wlog( "commit insertion failure: ${c}", ("c", c)); - } - } pbft_db.mark_as_committed(cc.block_info.block_id); } } - if (!new_view.prepared_cert.prepares.empty()) { - for (auto p: new_view.prepared_cert.prepares) { - try { - pbft_db.add_pbft_prepare(p); - } catch (...) { - wlog("prepare insertion failure: ${p}", ("p", p)); - } - } - pbft_db.mark_as_prepared(new_view.prepared_cert.block_info.block_id); + 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); return; @@ -508,7 +471,7 @@ namespace eosio { void psm_machine::do_send_view_change() { auto reset_view_change_state = [&]() { - set_view_changes_cache(vector{}); + set_view_changes_cache(pbft_view_change()); set_prepared_certificate(pbft_db.generate_prepared_certificate()); set_committed_certificate(pbft_db.generate_committed_certificate()); }; @@ -537,27 +500,27 @@ namespace eosio { } } - const vector& psm_machine::get_prepares_cache() const { + const pbft_prepare& psm_machine::get_prepares_cache() const { return cache.prepares_cache; } - void psm_machine::set_prepares_cache(const vector &pcache) { + void psm_machine::set_prepares_cache(const pbft_prepare &pcache) { cache.prepares_cache = pcache; } - const vector& psm_machine::get_commits_cache() const { + const pbft_commit& psm_machine::get_commits_cache() const { return cache.commits_cache; } - void psm_machine::set_commits_cache(const vector &ccache) { + void psm_machine::set_commits_cache(const pbft_commit &ccache) { cache.commits_cache = ccache; } - const vector& psm_machine::get_view_changes_cache() const { + const pbft_view_change& psm_machine::get_view_changes_cache() const { return cache.view_changes_cache; } - void psm_machine::set_view_changes_cache(const vector &vc_cache) { + void psm_machine::set_view_changes_cache(const pbft_view_change &vc_cache) { cache.view_changes_cache = vc_cache; } diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index a7b3ffddfca..ef8503aa9e2 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -8,8 +8,8 @@ namespace eosio { 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{}; + checkpoint_index = pbft_checkpoint_state_multi_index_type(); + view_state_index = pbft_view_state_multi_index_type(); prepare_watermarks = vector{}; pbft_db_dir = ctrl.state_dir(); checkpoints_dir = ctrl.blocks_dir(); @@ -35,7 +35,7 @@ namespace eosio { set(std::make_shared(move(s))); } } else { - pbft_state_index = pbft_state_multi_index_type{}; + pbft_state_index = pbft_state_multi_index_type(); } if (!fc::is_directory(checkpoints_dir)) fc::create_directories(checkpoints_dir); @@ -56,7 +56,7 @@ namespace eosio { } ilog("checkpoint index size: ${cs}", ("cs", checkpoint_index.size())); } else { - checkpoint_index = pbft_checkpoint_state_multi_index_type{}; + checkpoint_index = pbft_checkpoint_state_multi_index_type(); } fc::remove(checkpoints_db); @@ -93,9 +93,7 @@ namespace eosio { close(); } - void pbft_database::add_pbft_prepare(pbft_prepare &p) { - - if (!is_valid_prepare(p)) return; + void pbft_database::add_pbft_prepare(pbft_prepare &p, const public_key_type &pk) { auto &by_block_id_index = pbft_state_index.get(); @@ -106,23 +104,19 @@ namespace eosio { if (curr_itr == by_block_id_index.end()) { try { - auto curr_ps = pbft_state{current->id, current->block_num, {p}}; - auto curr_psp = make_shared(curr_ps); + flat_map, pbft_prepare> prepares; + prepares[std::make_pair(p.view, pk)] = p; + auto curr_ps = pbft_state{current->id, current->block_num, prepares}; + auto curr_psp = std::make_shared(move(curr_ps)); pbft_state_index.insert(curr_psp); } catch (...) { elog( "prepare insert failure: ${p}", ("p", p)); } } else { auto prepares = (*curr_itr)->prepares; - auto p_itr = find_if(prepares.begin(), prepares.end(), - [&](const pbft_prepare &prep) { - return prep.common.sender == p.common.sender - && prep.view == p.view; - }); - if (p_itr == prepares.end()) { + if (prepares.find(std::make_pair(p.view, pk)) == prepares.end()) { by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr &psp) { - psp->prepares.emplace_back(p); - std::sort(psp->prepares.begin(), psp->prepares.end(), less<>()); + psp->prepares[std::make_pair(p.view, pk)] = p; }); } } @@ -136,12 +130,12 @@ namespace eosio { if (prepares.size() >= threshold && !cpsp->is_prepared && is_less_than_high_watermark(cpsp->block_num)) { flat_map prepare_count; for (auto const &pre: prepares) { - if (prepare_count.find(pre.view) == prepare_count.end()) prepare_count[pre.view] = 0; + if (prepare_count.find(pre.second.view) == prepare_count.end()) prepare_count[pre.second.view] = 0; } for (auto const &sp: as) { for (auto const &pp: prepares) { - if (sp.block_signing_key == pp.common.sender) prepare_count[pp.view] += 1; + if (sp.block_signing_key == pp.first.second) prepare_count[pp.first.first] += 1; } } for (auto const &e: prepare_count) { @@ -160,18 +154,19 @@ namespace eosio { auto bnum = block_info_type{bid}.block_num(); if (itr == by_block_id_index.end()) { - auto ps = pbft_state{bid, bnum, .is_prepared = true}; - auto psp = make_shared(ps); + auto ps = pbft_state{bid, bnum, .is_prepared=true}; + auto psp = std::make_shared(move(ps)); pbft_state_index.insert(psp); return; } by_block_id_index.modify(itr, [&](const pbft_state_ptr &p) { p->is_prepared = true; }); } - vector pbft_database::send_and_add_pbft_prepare(const vector &pv, pbft_view_type current_view) { + 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(); auto head_block_num = ctrl.head_block_num(); - if (head_block_num <= 1) return vector{}; + if (head_block_num <= 1) return prepare_to_be_cached; auto my_prepare = ctrl.get_pbft_my_prepare(); auto reserve_prepare = [&](const block_id_type &in) { @@ -182,28 +177,25 @@ namespace eosio { return !forks.first.empty() && forks.second.empty(); }; - vector new_pv; - new_pv.reserve(ctrl.my_signature_providers().size()); - if (!pv.empty()) { - for (auto p : pv) { - //change uuid, sign again, update cache, then emit - auto uuid = boost::uuids::to_string(uuid_generator()); - p.common.uuid = uuid; - p.common.timestamp = time_point::now(); - p.sender_signature = ctrl.my_signature_providers()[p.common.sender](p.digest()); - emit(pbft_outgoing_prepare, p); - } - return vector{}; + + if (!cached_prepare.empty()) { + for (auto const &sp : ctrl.my_signature_providers()) { + //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, retry_p); + } + return prepare_to_be_cached; } else if (reserve_prepare(my_prepare)) { for (auto const &sp : ctrl.my_signature_providers()) { - auto uuid = boost::uuids::to_string(uuid_generator()); - pbft_prepare p; - p.common.uuid=uuid; p.view=current_view; p.block_info={my_prepare}; p.common.sender=sp.first; p.common.chain_id=chain_id; - p.sender_signature = sp.second(p.digest()); - emit(pbft_outgoing_prepare, p); - new_pv.emplace_back(p); - } - return new_pv; + pbft_prepare reserve_p; + 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, reserve_p); + if (prepare_to_be_cached.empty()) prepare_to_be_cached = reserve_p; + } + return prepare_to_be_cached; } else { auto current_watermark = get_current_pbft_watermark(); @@ -215,22 +207,24 @@ namespace eosio { high_watermark_block_num = std::min(head_block_num, current_watermark); } - if (high_watermark_block_num <= lib) return vector{}; + if (high_watermark_block_num <= lib) return prepare_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()) { - auto uuid = boost::uuids::to_string(uuid_generator()); - pbft_prepare p; - p.common.uuid=uuid; p.view=current_view; p.block_info={hwbs->id}; p.common.sender=sp.first; p.common.chain_id=chain_id; - p.sender_signature = sp.second(p.digest()); - add_pbft_prepare(p); - emit(pbft_outgoing_prepare, p); - new_pv.emplace_back(p); + pbft_prepare new_p; + 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, new_p); + add_pbft_prepare(new_p, sp.first); + sent = true; + if (prepare_to_be_cached.empty()) prepare_to_be_cached = new_p; + } } - ctrl.set_pbft_my_prepare(hwbs->id); + if (sent) ctrl.set_pbft_my_prepare(hwbs->id); } - return new_pv; + return prepare_to_be_cached; } } @@ -249,17 +243,16 @@ namespace eosio { return false; } - bool pbft_database::is_valid_prepare(const pbft_prepare &p) { - if (!is_valid_pbft_message(p.common)) return false; + 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; - if (!p.is_signature_valid()) return false; - return should_recv_pbft_msg(p.common.sender); + return should_recv_pbft_msg(pk); } - void pbft_database::add_pbft_commit(pbft_commit &c) { + void pbft_database::add_pbft_commit(pbft_commit &c, const public_key_type &pk) { + + if (!is_valid_commit(c, pk)) return; - if (!is_valid_commit(c)) return; auto &by_block_id_index = pbft_state_index.get(); auto current = ctrl.fetch_block_state_by_id(c.block_info.block_id); @@ -270,22 +263,19 @@ namespace eosio { if (curr_itr == by_block_id_index.end()) { try { - auto curr_ps = pbft_state{current->id, current->block_num, .commits={c}}; - auto curr_psp = make_shared(curr_ps); + flat_map, pbft_commit> commits; + commits[std::make_pair(c.view, pk)] = c; + auto curr_ps = pbft_state{current->id, current->block_num, .commits=commits}; + auto curr_psp = std::make_shared(move(curr_ps)); pbft_state_index.insert(curr_psp); } catch (...) { elog("commit insertion failure: ${c}", ("c", c)); } } else { auto commits = (*curr_itr)->commits; - auto p_itr = find_if(commits.begin(), commits.end(), - [&](const pbft_commit &comm) { - return comm.common.sender == c.common.sender - && comm.view == c.view; - }); - if (p_itr == commits.end()) { + if (commits.find(std::make_pair(c.view, pk)) == commits.end()) { by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr &psp) { - psp->commits.emplace_back(c); + psp->commits[std::make_pair(c.view, pk)] = c; std::sort(psp->commits.begin(), psp->commits.end(), less<>()); }); } @@ -302,13 +292,12 @@ namespace eosio { if (commits.size() >= threshold && !cpsp->is_committed && is_less_than_high_watermark(cpsp->block_num)) { flat_map commit_count; for (auto const &com: commits) { - if (commit_count.find(com.view) == commit_count.end()) commit_count[com.view] = 0; + if (commit_count.find(com.second.view) == commit_count.end()) commit_count[com.second.view] = 0; } - for (auto const &sp: as) { for (auto const &pc: commits) { - if (sp.block_signing_key == pc.common.sender) commit_count[pc.view] += 1; + if (sp.block_signing_key == pc.first.second) commit_count[pc.first.first] += 1; } } @@ -322,41 +311,43 @@ namespace eosio { } } - vector pbft_database::send_and_add_pbft_commit(const vector &cv, pbft_view_type current_view) { - if (!cv.empty()) { - for (auto c : cv) { - //change uuid, sign again, update cache, then emit - auto uuid = boost::uuids::to_string(uuid_generator()); - c.common.uuid = uuid; - c.common.timestamp = time_point::now(); - c.sender_signature = ctrl.my_signature_providers()[c.common.sender](c.digest()); - emit(pbft_outgoing_commit, c); - } - return vector{}; + 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(); + + if (!cached_commit.empty()) { + for (auto const &sp : ctrl.my_signature_providers()) { + //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, retry_c); + } + return commit_to_be_cached; } else { auto const &by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); - if (itr == by_prepare_and_num_index.end()) return vector{}; + if (itr == by_prepare_and_num_index.end()) return commit_to_be_cached; pbft_state_ptr psp = *itr; auto bs = ctrl.fork_db().get_block(psp->block_id); - if (!bs) return vector{}; + if (!bs) return commit_to_be_cached; - vector new_cv; - new_cv.reserve(ctrl.my_signature_providers().size()); if (psp->is_prepared && (psp->block_num > ctrl.last_irreversible_block_num())) { for (auto const &sp : ctrl.my_signature_providers()) { - auto uuid = boost::uuids::to_string(uuid_generator()); - pbft_commit c; - c.common.uuid=uuid; c.view=current_view; c.block_info={psp->block_id}; c.common.sender=sp.first; c.common.chain_id=chain_id; - c.sender_signature = sp.second(c.digest()); - add_pbft_commit(c); - emit(pbft_outgoing_commit, c); - new_cv.emplace_back(c); + pbft_commit new_c; + 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, new_c); + add_pbft_commit(new_c, sp.first); + if (commit_to_be_cached.empty()) commit_to_be_cached = new_c; + } } } - return new_cv; + return commit_to_be_cached; } } @@ -390,28 +381,30 @@ namespace eosio { auto commits = (*itr)->commits; + auto threshold = as.size() * 2 / 3 + 1; + flat_map commit_count; for (auto const &com: commits) { - if (commit_count.find(com.view) == commit_count.end()) { - commit_count[com.view] = 1; - } else { - commit_count[com.view] += 1; + if (commit_count.find(com.second.view) == commit_count.end()) commit_count[com.second.view] = 0; + } + + for (auto const &sp: as) { + for (auto const &pc: commits) { + if (sp.block_signing_key == pc.first.second) commit_count[pc.first.first] += 1; } } for (auto const &e: commit_count) { - if (e.second >= as.size() * 2 / 3 + 1 && e.first > new_view) { + if (e.second >= threshold && e.first > new_view) { new_view = e.first; } } return new_view; } - bool pbft_database::is_valid_commit(const pbft_commit &c) { - if (!is_valid_pbft_message(c.common)) return false; + 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; - if (!c.is_signature_valid()) return false; - return should_recv_pbft_msg(c.common.sender); + return should_recv_pbft_msg(pk); } void pbft_database::commit_local() { @@ -428,26 +421,25 @@ namespace eosio { return ctrl.pending_pbft_lib(); } - void pbft_database::add_pbft_view_change(pbft_view_change &vc) { - if (!is_valid_view_change(vc)) return; - auto active_bps = lscb_active_producers().producers; + void pbft_database::add_pbft_view_change(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 itr = by_view_index.find(vc.target_view); if (itr == by_view_index.end()) { - auto vs = pbft_view_change_state{vc.target_view, .view_changes={vc}}; - auto vsp = make_shared(vs); - view_state_index.insert(vsp); + flat_map view_changes; + view_changes[pk] = vc; + auto vcs = pbft_view_change_state{vc.target_view, view_changes}; + auto vcsp = std::make_shared(move(vcs)); + view_state_index.insert(vcsp); } else { auto pvs = (*itr); auto view_changes = pvs->view_changes; - auto p_itr = find_if(view_changes.begin(), view_changes.end(), - [&](const pbft_view_change &existed) { - return existed.common.sender == vc.common.sender; - }); - if (p_itr == view_changes.end()) { + + if (view_changes.find(pk) == view_changes.end()) { by_view_index.modify(itr, [&](const pbft_view_change_state_ptr &pvsp) { - pvsp->view_changes.emplace_back(vc); + pvsp->view_changes[pk] = vc; }); } } @@ -456,13 +448,13 @@ namespace eosio { if (itr == by_view_index.end()) return; auto vsp = *itr; - auto threshold = active_bps.size() * 2 / 3 + 1; + auto threshold = lscb_bps.size() * 2 / 3 + 1; if (vsp->view_changes.size() >= threshold && !vsp->is_view_changed) { auto vc_count = 0; - for (auto const &sp: active_bps) { - for (auto const &v: (*itr)->view_changes) { - if (sp.block_signing_key == v.common.sender) vc_count += 1; + for (auto const &sp: lscb_bps) { + for (auto const &v: vsp->view_changes) { + if (sp.block_signing_key == v.first) vc_count += 1; } } if (vc_count >= threshold) { @@ -483,8 +475,8 @@ namespace eosio { auto pvs = (*itr); for (auto const &bp: active_bps) { - for (auto const &pp: pvs->view_changes) { - if (bp.block_signing_key == pp.common.sender) vc_count += 1; + for (auto const &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 @@ -497,37 +489,42 @@ namespace eosio { return nv; } - vector pbft_database::send_and_add_pbft_view_change( - const vector &vcv, + 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, - pbft_view_type new_view) { - if (!vcv.empty()) { - for (auto vc : vcv) { - //change uuid, sign again, update cache, then emit - auto uuid = boost::uuids::to_string(uuid_generator()); - vc.common.uuid = uuid; - vc.common.timestamp = time_point::now(); - vc.sender_signature = ctrl.my_signature_providers()[vc.common.sender](vc.digest()); - emit(pbft_outgoing_view_change, vc); - } - return vector{}; + pbft_view_type target_view) { + + auto view_change_to_be_cached = pbft_view_change(); + if (!cached_view_change.empty()) { + for (auto const &sp : ctrl.my_signature_providers()) { + //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, retry_vc); + } + return view_change_to_be_cached; } else { - vector new_vcv; - new_vcv.reserve(ctrl.my_signature_providers().size()); for (auto const &my_sp : ctrl.my_signature_providers()) { auto my_lsc = get_stable_checkpoint_by_id(ctrl.last_stable_checkpoint_block_id()); - auto uuid = boost::uuids::to_string(uuid_generator()); - pbft_view_change vc; - vc.common.uuid=uuid; vc.current_view=current_view; vc.target_view=new_view; vc.prepared_cert=ppc; vc.committed_cert=pcc; vc.stable_checkpoint=my_lsc; vc.common.sender=my_sp.first; vc.common.chain_id=chain_id; - vc.sender_signature = my_sp.second(vc.digest()); - emit(pbft_outgoing_view_change, vc); - add_pbft_view_change(vc); - new_vcv.emplace_back(vc); + + 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, 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; + } } - return new_vcv; + return view_change_to_be_cached; } } @@ -545,16 +542,15 @@ namespace eosio { return (*itr)->view; } - bool pbft_database::is_new_primary(const pbft_view_type target_view) { + bool pbft_database::has_new_primary(const public_key_type &pk) { - auto primary_key = get_new_view_primary_key(target_view); - if (primary_key == public_key_type()) return false; + if (pk == public_key_type()) return false; auto sps = ctrl.my_signature_providers(); - auto sp_itr = sps.find(primary_key); + auto sp_itr = sps.find(pk); return sp_itr != sps.end(); } - void pbft_database::prune_pbft_index() { + void pbft_database::cleanup_on_new_view() { view_state_index.clear(); ctrl.reset_pbft_my_prepare(); } @@ -564,9 +560,9 @@ namespace eosio { pbft_view_type current_view) { auto primary_key = get_new_view_primary_key(current_view); - if (!is_new_primary(current_view) || vcc.empty()) return pbft_new_view(); + if (!has_new_primary(primary_key) || vcc.empty()) return pbft_new_view(); - //`sp_itr` is not possible to be the end iterator, since it's already been checked in `is_new_primary`. + //`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(); auto sp_itr = my_sps.find(primary_key); @@ -575,31 +571,25 @@ namespace eosio { auto highest_sc = pbft_stable_checkpoint(); for (auto const &vc: vcc.view_changes) { - if (vc.prepared_cert.block_info.block_num() > highest_ppc.block_info.block_num() - && is_valid_prepared_certificate(vc.prepared_cert)) { + 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_cert) { - if (is_valid_committed_certificate(cc)) { - auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), - [&](const pbft_committed_certificate &ext) { return ext.block_info.block_id == cc.block_info.block_id; }); - if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); - } + for (auto const &cc: vc.committed_certs) { + auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), + [&](const pbft_committed_certificate &ext) { return ext.block_info.block_id == cc.block_info.block_id; }); + if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); } - if (vc.stable_checkpoint.block_info.block_num() > highest_sc.block_info.block_num() && - is_valid_stable_checkpoint(vc.stable_checkpoint)) { + if (vc.stable_checkpoint.block_info.block_num() > highest_sc.block_info.block_num()) { highest_sc = vc.stable_checkpoint; } } - auto uuid = boost::uuids::to_string(uuid_generator()); - pbft_new_view nv; - nv.common.uuid=uuid; nv.new_view=current_view; nv.prepared_cert=highest_ppc; nv.committed_cert=highest_pcc; nv.stable_checkpoint=highest_sc, nv.view_changed_cert=vcc, nv.common.sender=sp_itr->first; nv.common.chain_id=chain_id; + nv.new_view=current_view; nv.prepared_cert=highest_ppc; nv.committed_certs=highest_pcc; nv.stable_checkpoint=highest_sc; nv.view_changed_cert=vcc; - nv.sender_signature = sp_itr->second(nv.digest()); + nv.sender_signature = sp_itr->second(nv.digest(chain_id)); emit(pbft_outgoing_new_view, nv); return nv; } @@ -623,13 +613,13 @@ namespace eosio { flat_map> prepare_msg; for (auto const &pre: prepares) { - if (prepare_count.find(pre.view) == prepare_count.end()) prepare_count[pre.view] = 0; - prepare_msg[pre.view].emplace_back(pre); + 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 &sp: as) { for (auto const &pp: prepares) { - if (sp.block_signing_key == pp.common.sender) prepare_count[pp.view] += 1; + if (sp.block_signing_key == pp.first.second) prepare_count[pp.first.first] += 1; } } @@ -657,13 +647,15 @@ namespace eosio { vector pbft_database::generate_committed_certificate() { + auto pcc = vector{}; + auto const &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 vector{}; + if (itr == by_commit_and_num_index.end()) return pcc; pbft_state_ptr psp = *itr; - if (!psp->is_committed) return vector{}; + if (!psp->is_committed) return pcc; auto highest_committed_block_num = psp->block_num; @@ -685,15 +677,15 @@ namespace eosio { auto const &by_id_index = pbft_state_index.get(); - auto pcc = vector{}; + std::sort(ccb.begin(), ccb.end()); pcc.reserve(ccb.size()); for (auto const &committed_block_num: ccb) { auto cbs = ctrl.fetch_block_state_by_number(committed_block_num); - if (!cbs) return vector{}; + if (!cbs) return pcc; auto it = by_id_index.find(cbs->id); if (it == by_id_index.end() || !(*it)->is_committed) { - return vector{}; + return pcc; } auto as = cbs->active_schedule.producers; @@ -705,13 +697,13 @@ namespace eosio { flat_map> commit_msg; for (auto const &com: commits) { - if (commit_count.find(com.view) == commit_count.end()) commit_count[com.view] = 0; - commit_msg[com.view].emplace_back(com); + 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 &sp: as) { for (auto const &cc: commits) { - if (sp.block_signing_key == cc.common.sender) commit_count[cc.view] += 1; + if (sp.block_signing_key == cc.first.second) commit_count[cc.first.first] += 1; } } @@ -722,7 +714,7 @@ namespace eosio { } } - if (valid_commits.empty()) return vector{}; + if (valid_commits.empty()) return pcc; pbft_committed_certificate cc; cc.block_info={cbs->id}; cc.commits=valid_commits; @@ -733,31 +725,44 @@ namespace eosio { pbft_view_changed_certificate pbft_database::generate_view_changed_certificate(pbft_view_type target_view) { + auto pvcc = pbft_view_changed_certificate(); + auto &by_view_index = view_state_index.get(); auto itr = by_view_index.find(target_view); - if (itr == by_view_index.end()) return pbft_view_changed_certificate(); + if (itr == by_view_index.end()) return pvcc; auto pvs = *itr; if (pvs->is_view_changed) { - auto pvcc = pbft_view_changed_certificate(); - pvcc.target_view=pvs->view; pvcc.view_changes=pvs->view_changes; + + pvcc.target_view=pvs->view; + pvcc.view_changes.reserve(pvs->view_changes.size()); + for( auto it = pvs->view_changes.begin(); it != pvs->view_changes.end(); ++it ) { + pvcc.view_changes.emplace_back( it->second ); + } return pvcc; - } else return pbft_view_changed_certificate(); + } else return pvcc; } - bool pbft_database::is_valid_prepared_certificate(const pbft_prepared_certificate &certificate) { + 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. if (certificate.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) return true; + auto prepares = certificate.prepares; + auto prepares_metadata = vector>{}; + prepares_metadata.reserve(prepares.size()); auto valid = true; - for (auto const &p : certificate.prepares) { - valid = valid && is_valid_prepare(p); + for (auto &p : prepares) { + + auto pmm = pbft_message_metadata(p, chain_id); + prepares_metadata.emplace_back(pmm); + valid = valid && is_valid_prepare(p, pmm.sender_key); if (!valid) return false; + if (add_to_pbft_db) add_pbft_prepare(p, pmm.sender_key); } auto cert_id = certificate.block_info.block_id; @@ -768,16 +773,15 @@ namespace eosio { } auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; - auto prepares = certificate.prepares; flat_map prepare_count; - for (auto const &pre: prepares) { - if (prepare_count.find(pre.view) == prepare_count.end()) prepare_count[pre.view] = 0; + for (auto const &pm: prepares_metadata) { + if (prepare_count.find(pm.msg.view) == prepare_count.end()) prepare_count[pm.msg.view] = 0; } for (auto const &sp: producer_schedule.producers) { - for (auto const &pp: prepares) { - if (sp.block_signing_key == pp.common.sender) prepare_count[pp.view] += 1; + for (auto const &pm: prepares_metadata) { + if (sp.block_signing_key == pm.sender_key) prepare_count[pm.msg.view] += 1; } } @@ -807,16 +811,22 @@ 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 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. if (certificate.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) return true; + auto commits = certificate.commits; + auto commits_metadata = vector>{}; + commits_metadata.reserve(commits.size()); auto valid = true; - for (auto const &c : certificate.commits) { - valid = valid && is_valid_commit(c); + for (auto &c : commits) { + auto pmm = pbft_message_metadata(c, chain_id); + commits_metadata.emplace_back(pmm); + valid = valid && is_valid_commit(c, pmm.sender_key); if (!valid) return false; + if (add_to_pbft_db) add_pbft_commit(c, pmm.sender_key); } auto cert_id = certificate.block_info.block_id; @@ -827,16 +837,15 @@ namespace eosio { } auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; - auto commits = certificate.commits; flat_map commit_count; - for (auto const &pre: commits) { - if (commit_count.find(pre.view) == commit_count.end()) commit_count[pre.view] = 0; + for (auto const &cm: commits_metadata) { + if (commit_count.find(cm.msg.view) == commit_count.end()) commit_count[cm.msg.view] = 0; } for (auto const &sp: producer_schedule.producers) { - for (auto const &pp: commits) { - if (sp.block_signing_key == pp.common.sender) commit_count[pp.view] += 1; + for (auto const &cm: commits_metadata) { + if (sp.block_signing_key == cm.sender_key) commit_count[cm.msg.view] += 1; } } @@ -866,65 +875,65 @@ 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) { - if (vc.common.chain_id != chain_id) return false; + bool pbft_database::is_valid_view_change(const pbft_view_change &vc, const public_key_type &pk) { - return vc.is_signature_valid() - && should_recv_pbft_msg(vc.common.sender); + return should_recv_pbft_msg(pk); // No need to check prepared cert and stable checkpoint, until generate or validate a new view msg } - bool pbft_database::is_valid_new_view(const pbft_new_view &nv) { - //all signatures should be valid - - EOS_ASSERT(nv.common.chain_id == chain_id, pbft_exception, "wrong chain."); + void pbft_database::validate_new_view(const pbft_new_view &nv, const public_key_type &pk) { - EOS_ASSERT(nv.is_signature_valid(), pbft_exception, "bad new view signature"); + EOS_ASSERT(pk == get_new_view_primary_key(nv.new_view), pbft_exception, + "new view is not signed with expected key"); - EOS_ASSERT(nv.common.sender == get_new_view_primary_key(nv.new_view), pbft_exception, "new view is not signed with expected key"); + EOS_ASSERT(is_valid_prepared_certificate(nv.prepared_cert, true), pbft_exception, + "bad prepared certificate: ${pc}", ("pc", nv.prepared_cert)); - EOS_ASSERT(is_valid_prepared_certificate(nv.prepared_cert), pbft_exception, - "bad prepared certificate: ${pc}", ("pc", nv.prepared_cert)); - - EOS_ASSERT(is_valid_stable_checkpoint(nv.stable_checkpoint), pbft_exception, + EOS_ASSERT(is_valid_stable_checkpoint(nv.stable_checkpoint, true), pbft_exception, "bad stable checkpoint: ${scp}", ("scp", nv.stable_checkpoint)); - for (auto const &c: nv.committed_cert) { - EOS_ASSERT(is_valid_committed_certificate(c), pbft_exception, "bad committed certificate: ${cc}", ("cc", c)); + for (auto const &c: nv.committed_certs) { + EOS_ASSERT(is_valid_committed_certificate(c, true), pbft_exception, + "bad committed certificate: ${cc}", ("cc", c)); } - EOS_ASSERT(nv.is_signature_valid(), pbft_exception, "bad new view signature"); - EOS_ASSERT(nv.view_changed_cert.target_view == nv.new_view, pbft_exception, "target view not match"); vector lscb_producers; lscb_producers.reserve(lscb_active_producers().producers.size()); - for (auto const& pk: lscb_active_producers().producers) { - lscb_producers.emplace_back(pk.block_signing_key); + for (auto const &bp: lscb_active_producers().producers) { + lscb_producers.emplace_back(bp.block_signing_key); } auto schedule_threshold = lscb_producers.size() * 2 / 3 + 1; + auto view_changes = nv.view_changed_cert.view_changes; + auto view_changes_metadata = vector>{}; + view_changes_metadata.reserve(view_changes.size()); + vector view_change_producers; - view_change_producers.reserve(nv.view_changed_cert.view_changes.size()); - for (auto vc: nv.view_changed_cert.view_changes) { - if (is_valid_view_change(vc)) { - add_pbft_view_change(vc); - view_change_producers.emplace_back(vc.common.sender); + view_change_producers.reserve(view_changes.size()); + 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)) { + add_pbft_view_change(vc, pmm.sender_key); + view_change_producers.emplace_back(pmm.sender_key); } } vector intersection; - std::sort(lscb_producers.begin(),lscb_producers.end()); - std::sort(view_change_producers.begin(),view_change_producers.end()); - std::set_intersection(lscb_producers.begin(),lscb_producers.end(), - view_change_producers.begin(),view_change_producers.end(), + std::sort(lscb_producers.begin(), lscb_producers.end()); + std::sort(view_change_producers.begin(), view_change_producers.end()); + std::set_intersection(lscb_producers.begin(), lscb_producers.end(), + view_change_producers.begin(), view_change_producers.end(), back_inserter(intersection)); EOS_ASSERT(intersection.size() >= schedule_threshold, pbft_exception, "view changes count not enough"); - EOS_ASSERT(should_new_view(nv.new_view), pbft_exception, "should not enter new view: ${nv}", ("nv", nv.new_view)); + EOS_ASSERT(should_new_view(nv.new_view), pbft_exception, "should not enter new view: ${nv}", + ("nv", nv.new_view)); auto highest_ppc = pbft_prepared_certificate(); auto highest_pcc = vector{}; @@ -936,39 +945,40 @@ namespace eosio { highest_ppc = vc.prepared_cert; } - for (auto const &cc: vc.committed_cert) { + for (auto const &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) { 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); } } if (vc.stable_checkpoint.block_info.block_num() > highest_scp.block_info.block_num() - && is_valid_stable_checkpoint(vc.stable_checkpoint)) { + && is_valid_stable_checkpoint(vc.stable_checkpoint, true)) { highest_scp = vc.stable_checkpoint; } } EOS_ASSERT(highest_ppc.block_info == nv.prepared_cert.block_info, pbft_exception, - "prepared certificate does not match, should be ${hppc} but ${pc} given", - ("hppc",highest_ppc)("pc", nv.prepared_cert)); + "prepared certificate does not match, should be ${hppc} but ${pc} given", + ("hppc", highest_ppc)("pc", nv.prepared_cert)); std::sort(highest_pcc.begin(), highest_pcc.end()); - auto committed_certs = nv.committed_cert; + auto committed_certs = nv.committed_certs; std::sort(committed_certs.begin(), committed_certs.end()); - EOS_ASSERT(highest_pcc.size() == committed_certs.size(), pbft_exception, "wrong committed certificates size"); + EOS_ASSERT(highest_pcc.size() == committed_certs.size(), pbft_exception, + "wrong committed certificates size"); for (auto i = 0; i < committed_certs.size(); ++i) { EOS_ASSERT(highest_pcc[i].block_info == committed_certs[i].block_info, pbft_exception, - "committed certificate does not match, should be ${hpcc} but ${cc} given", - ("hpcc",highest_pcc[i])("cc", committed_certs[i])); + "committed certificate does not match, should be ${hpcc} but ${cc} given", + ("hpcc", highest_pcc[i])("cc", committed_certs[i])); } EOS_ASSERT(highest_scp.block_info == nv.stable_checkpoint.block_info, pbft_exception, "stable checkpoint does not match, should be ${hscp} but ${scp} given", - ("hpcc",highest_scp)("pc", nv.stable_checkpoint)); - - return true; + ("hpcc", highest_scp)("pc", nv.stable_checkpoint)); } bool pbft_database::should_stop_view_change(const pbft_view_change &vc) { @@ -1099,9 +1109,12 @@ namespace eosio { auto cpp = *itr; if (cpp->is_stable) { - if (ctrl.my_signature_providers().empty()) return pbft_stable_checkpoint(); pbft_stable_checkpoint psc; - psc.block_info={cpp->block_id}; psc.checkpoints=cpp->checkpoints; + psc.block_info={cpp->block_id}; + psc.checkpoints.reserve(cpp->checkpoints.size()); + for (auto it = cpp->checkpoints.begin(); it != cpp->checkpoints.end(); ++it) { + psc.checkpoints.emplace_back(it->second) ; + } return psc; } else return pbft_stable_checkpoint(); } @@ -1161,12 +1174,12 @@ namespace eosio { if (in <= ucb) return false; auto watermarks = get_updated_watermarks(); return in == ucb + 1 // checkpoint on first pbft block; - || in % 100 == 1 // checkpoint on every 100 block; + || in % pbft_checkpoint_granularity == 1 // checkpoint on every 100 block; || std::find(watermarks.begin(), watermarks.end(), in) != watermarks.end(); // checkpoint on bp schedule change; }; auto new_pc = vector{}; - new_pc.reserve(ctrl.my_signature_providers().size()); + auto const &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; @@ -1186,9 +1199,7 @@ namespace eosio { } else { auto checkpoints = (*c_itr)->checkpoints; for (auto const &my_sp : ctrl.my_signature_providers()) { - auto p_itr = find_if(checkpoints.begin(), checkpoints.end(), - [&](const pbft_checkpoint &ext) { return ext.common.sender == my_sp.first; }); - if (p_itr != checkpoints.end() && !(*c_itr)->is_stable) pending_checkpoint_block_num[i] = true; //retry sending at this time. + 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; @@ -1204,12 +1215,11 @@ namespace eosio { 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()) { - auto uuid = boost::uuids::to_string(uuid_generator()); pbft_checkpoint cp; - cp.common.uuid=uuid; cp.block_info={bs->id}; cp.common.sender=my_sp.first; cp.common.chain_id=chain_id; - cp.sender_signature = my_sp.second(cp.digest()); - if (!bnum_and_retry.second) { //first time sending this checkpoint - add_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); } new_pc.emplace_back(cp); } @@ -1217,55 +1227,48 @@ namespace eosio { } } else if (lscb_num > 0) { //retry sending my lscb for (auto const &my_sp : ctrl.my_signature_providers()) { - auto uuid = boost::uuids::to_string(uuid_generator()); pbft_checkpoint cp; - cp.common.uuid=uuid; cp.block_info={ctrl.last_stable_checkpoint_block_id()}; cp.common.sender=my_sp.first; cp.common.chain_id=chain_id; - cp.sender_signature = my_sp.second(cp.digest()); + cp.block_info={ctrl.last_stable_checkpoint_block_id()}; + cp.sender_signature = my_sp.second(cp.digest(chain_id)); new_pc.emplace_back(cp); } } return new_pc; } - void pbft_database::add_pbft_checkpoint(pbft_checkpoint &cp) { - - if (!is_valid_checkpoint(cp)) return; + void pbft_database::add_pbft_checkpoint(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 active_bps = cp_block_state->active_schedule.producers; - auto checkpoint_count = count_if(active_bps.begin(), active_bps.end(), [&](const producer_key &p) { - return p.block_signing_key == cp.common.sender; - }); - if (checkpoint_count == 0) return; auto &by_block = checkpoint_index.get(); auto itr = by_block.find(cp.block_info.block_id); if (itr == by_block.end()) { - auto cs = pbft_checkpoint_state{cp.block_info.block_id, cp.block_info.block_num(), .checkpoints={cp}}; - auto csp = make_shared(cs); + flat_map checkpoints; + checkpoints[pk] = cp; + auto cs = pbft_checkpoint_state{cp.block_info.block_id, cp.block_info.block_num(), checkpoints}; + auto csp = std::make_shared(move(cs)); checkpoint_index.insert(csp); itr = by_block.find(cp.block_info.block_id); } else { auto csp = (*itr); auto checkpoints = csp->checkpoints; - auto p_itr = find_if(checkpoints.begin(), checkpoints.end(), - [&](const pbft_checkpoint &existed) { return existed.common.sender == cp.common.sender; }); - if (p_itr == checkpoints.end()) { + if (checkpoints.find(pk) == checkpoints.end()) { by_block.modify(itr, [&](const pbft_checkpoint_state_ptr &pcp) { - csp->checkpoints.emplace_back(cp); + csp->checkpoints[pk] = cp; }); } } auto csp = (*itr); + auto active_bps = cp_block_state->active_schedule.producers; auto threshold = active_bps.size() * 2 / 3 + 1; if (csp->checkpoints.size() >= threshold && !csp->is_stable) { auto cp_count = 0; for (auto const &sp: active_bps) { - for (auto const &pp: csp->checkpoints) { - if (sp.block_signing_key == pp.common.sender) cp_count += 1; + for (auto const &c: csp->checkpoints) { + if (sp.block_signing_key == c.first) cp_count += 1; } } if (cp_count >= threshold) { @@ -1314,41 +1317,43 @@ namespace eosio { } auto &bni = checkpoint_index.get(); auto oldest = bni.begin(); - if (oldest != bni.end() && lscb_num - (*oldest)->block_num > 10000) { - auto it = bni.lower_bound(lscb_num - 10000); + if (oldest != bni.end() && lscb_num - (*oldest)->block_num > oldest_stable_checkpoint) { + auto it = bni.lower_bound(lscb_num - oldest_stable_checkpoint); if (it != bni.end() && (*it)->is_stable) { - prune_checkpoints(*it); + prune(*it); } } } - bool pbft_database::is_valid_checkpoint(const pbft_checkpoint &cp) { - if (!(is_valid_pbft_message(cp.common) && cp.is_signature_valid())) return false; + 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() - || !cp.is_signature_valid()) - return false; + if (cp.block_info.block_num() > ctrl.head_block_num() || cp.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) return false; auto bs = ctrl.fetch_block_state_by_id(cp.block_info.block_id); if (bs) { auto active_bps = bs->active_schedule.producers; for (auto const &bp: active_bps) { - if (bp.block_signing_key == cp.common.sender) return true; + if (bp.block_signing_key == pk) return true; } } return false; } - bool pbft_database::is_valid_stable_checkpoint(const pbft_stable_checkpoint &scp) { + 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. return true; + auto checkpoints = scp.checkpoints; + auto checkpoints_metadata = vector>{}; + checkpoints_metadata.reserve(checkpoints.size()); auto valid = true; - for (auto const &c: scp.checkpoints) { - valid = valid && is_valid_checkpoint(c) && c.block_info == scp.block_info; + for (auto &cp : checkpoints) { + auto pmm = pbft_message_metadata(cp, chain_id); + checkpoints_metadata.emplace_back(pmm); + valid = valid && cp.block_info == scp.block_info && is_valid_checkpoint(cp, pmm.sender_key); if (!valid) return false; + if (add_to_pbft_db) add_pbft_checkpoint(cp, pmm.sender_key); } auto bs = ctrl.fetch_block_state_by_number(scp.block_info.block_num()); @@ -1356,8 +1361,8 @@ namespace eosio { auto as = bs->active_schedule; auto cp_count = 0; for (auto const &sp: as.producers) { - for (auto const &v: scp.checkpoints) { - if (sp.block_signing_key == v.common.sender) cp_count += 1; + for (auto const &cpm: checkpoints_metadata) { + if (sp.block_signing_key == cpm.sender_key) cp_count += 1; } } valid = valid && cp_count >= as.producers.size() * 2 / 3 + 1; @@ -1367,10 +1372,6 @@ namespace eosio { return valid; } - bool pbft_database::is_valid_pbft_message(const pbft_message_common &common) { - return common.chain_id == chain_id; - } - bool pbft_database::should_send_pbft_msg() { auto my_sp = ctrl.my_signature_providers(); @@ -1461,9 +1462,9 @@ namespace eosio { } } if (!removed.empty()) { - auto pruned_num = *max_element(removed.begin(), removed.end()); + auto removed_num = *max_element(removed.begin(), removed.end()); for (auto itr = fork_schedules.begin(); itr != fork_schedules.end();) { - if ((*itr).second <= pruned_num) { + if ((*itr).second <= removed_num) { itr = fork_schedules.erase(itr); } else { ++itr; @@ -1566,13 +1567,13 @@ namespace eosio { } } - void pbft_database::prune_checkpoints(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 bni = by_bn.begin(); while (bni != by_bn.end() && (*bni)->block_num < num) { - prune_checkpoints(*bni); + prune(*bni); bni = by_bn.begin(); } diff --git a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp index 766a73df56f..a168ea54928 100644 --- a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp +++ b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp @@ -64,11 +64,11 @@ namespace eosio { namespace chain { namespace plugin_interface { namespace pbft { namespace incoming { - using prepare_channel = channel_decl; - using commit_channel = channel_decl; - using view_change_channel = channel_decl; - using new_view_channel = channel_decl; - using checkpoint_channel = channel_decl; + using prepare_channel = channel_decl>; + using commit_channel = channel_decl>; + using view_change_channel = channel_decl>; + using new_view_channel = channel_decl>; + using checkpoint_channel = channel_decl>; } diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 1caabd56acd..ce0eab28de5 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -178,11 +178,11 @@ class chain_plugin_impl { fc::microseconds abi_serializer_max_time_ms; fc::optional snapshot_path; - void on_pbft_incoming_prepare(pbft_prepare p); - void on_pbft_incoming_commit(pbft_commit c); - void on_pbft_incoming_view_change(pbft_view_change vc); - void on_pbft_incoming_new_view(pbft_new_view nv); - void on_pbft_incoming_checkpoint(pbft_checkpoint cp); + void on_pbft_incoming_prepare(pbft_metadata_ptr p); + void on_pbft_incoming_commit(pbft_metadata_ptr c); + void on_pbft_incoming_view_change(pbft_metadata_ptr vc); + void on_pbft_incoming_new_view(pbft_metadata_ptr nv); + void on_pbft_incoming_checkpoint(pbft_metadata_ptr cp); // retained references to channels for easy publication channels::pre_accepted_block::channel_type& pre_accepted_block_channel; @@ -214,30 +214,30 @@ class chain_plugin_impl { fc::optional accepted_confirmation_connection; //pbft - fc::optional pbft_outgoing_prepare_connection; - pbft::incoming::prepare_channel::channel_type::handle pbft_incoming_prepare_subscription; - pbft::outgoing::prepare_channel::channel_type& pbft_outgoing_prepare_channel; - pbft::incoming::prepare_channel::channel_type& pbft_incoming_prepare_channel; + fc::optional pbft_outgoing_prepare_connection; + pbft::incoming::prepare_channel::channel_type::handle pbft_incoming_prepare_subscription; + pbft::outgoing::prepare_channel::channel_type& pbft_outgoing_prepare_channel; + pbft::incoming::prepare_channel::channel_type& pbft_incoming_prepare_channel; - fc::optional pbft_outgoing_commit_connection; + fc::optional pbft_outgoing_commit_connection; pbft::incoming::commit_channel::channel_type::handle pbft_incoming_commit_subscription; - pbft::outgoing::commit_channel::channel_type& pbft_outgoing_commit_channel; - pbft::incoming::commit_channel::channel_type& pbft_incoming_commit_channel; - - fc::optional pbft_outgoing_view_change_connection; - pbft::incoming::view_change_channel::channel_type::handle pbft_incoming_view_change_subscription; - pbft::outgoing::view_change_channel::channel_type& pbft_outgoing_view_change_channel; - pbft::incoming::view_change_channel::channel_type& pbft_incoming_view_change_channel; - - fc::optional pbft_outgoing_new_view_connection; - pbft::incoming::new_view_channel::channel_type::handle pbft_incoming_new_view_subscription; - pbft::outgoing::new_view_channel::channel_type& pbft_outgoing_new_view_channel; - pbft::incoming::new_view_channel::channel_type& pbft_incoming_new_view_channel; - - fc::optional pbft_outgoing_checkpoint_connection; - pbft::incoming::checkpoint_channel::channel_type::handle pbft_incoming_checkpoint_subscription; - pbft::outgoing::checkpoint_channel::channel_type& pbft_outgoing_checkpoint_channel; - pbft::incoming::checkpoint_channel::channel_type& pbft_incoming_checkpoint_channel; + pbft::outgoing::commit_channel::channel_type& pbft_outgoing_commit_channel; + pbft::incoming::commit_channel::channel_type& pbft_incoming_commit_channel; + + fc::optional pbft_outgoing_view_change_connection; + pbft::incoming::view_change_channel::channel_type::handle pbft_incoming_view_change_subscription; + pbft::outgoing::view_change_channel::channel_type& pbft_outgoing_view_change_channel; + pbft::incoming::view_change_channel::channel_type& pbft_incoming_view_change_channel; + + fc::optional pbft_outgoing_new_view_connection; + pbft::incoming::new_view_channel::channel_type::handle pbft_incoming_new_view_subscription; + pbft::outgoing::new_view_channel::channel_type& pbft_outgoing_new_view_channel; + pbft::incoming::new_view_channel::channel_type& pbft_incoming_new_view_channel; + + fc::optional pbft_outgoing_checkpoint_connection; + pbft::incoming::checkpoint_channel::channel_type::handle pbft_incoming_checkpoint_subscription; + pbft::outgoing::checkpoint_channel::channel_type& pbft_outgoing_checkpoint_channel; + pbft::incoming::checkpoint_channel::channel_type& pbft_incoming_checkpoint_channel; }; chain_plugin::chain_plugin() @@ -805,23 +805,23 @@ void chain_plugin::plugin_initialize(const variables_map& options) { //pbft - my->pbft_incoming_prepare_subscription = my->pbft_incoming_prepare_channel.subscribe( [this]( pbft_prepare p ){ + my->pbft_incoming_prepare_subscription = my->pbft_incoming_prepare_channel.subscribe( [this]( pbft_metadata_ptr p ){ my->on_pbft_incoming_prepare(p); }); - my->pbft_incoming_commit_subscription = my->pbft_incoming_commit_channel.subscribe( [this]( pbft_commit c ){ + my->pbft_incoming_commit_subscription = my->pbft_incoming_commit_channel.subscribe( [this]( pbft_metadata_ptr c ){ my->on_pbft_incoming_commit(c); }); - my->pbft_incoming_view_change_subscription = my->pbft_incoming_view_change_channel.subscribe( [this]( pbft_view_change vc ){ + my->pbft_incoming_view_change_subscription = my->pbft_incoming_view_change_channel.subscribe( [this]( pbft_metadata_ptr vc ){ my->on_pbft_incoming_view_change(vc); }); - my->pbft_incoming_new_view_subscription = my->pbft_incoming_new_view_channel.subscribe( [this]( pbft_new_view nv ){ + my->pbft_incoming_new_view_subscription = my->pbft_incoming_new_view_channel.subscribe( [this]( pbft_metadata_ptr nv ){ my->on_pbft_incoming_new_view(nv); }); - my->pbft_incoming_checkpoint_subscription = my->pbft_incoming_checkpoint_channel.subscribe( [this]( pbft_checkpoint cp ){ + my->pbft_incoming_checkpoint_subscription = my->pbft_incoming_checkpoint_channel.subscribe( [this]( pbft_metadata_ptr cp ){ my->on_pbft_incoming_checkpoint(cp); }); @@ -856,23 +856,23 @@ void chain_plugin::plugin_initialize(const variables_map& options) { } -void chain_plugin_impl::on_pbft_incoming_prepare(pbft_prepare p){ +void chain_plugin_impl::on_pbft_incoming_prepare(pbft_metadata_ptr p){ pbft_ctrl->on_pbft_prepare(p); } -void chain_plugin_impl::on_pbft_incoming_commit(pbft_commit c){ +void chain_plugin_impl::on_pbft_incoming_commit(pbft_metadata_ptr c){ pbft_ctrl->on_pbft_commit(c); } -void chain_plugin_impl::on_pbft_incoming_view_change(pbft_view_change vc){ +void chain_plugin_impl::on_pbft_incoming_view_change(pbft_metadata_ptr vc){ pbft_ctrl->on_pbft_view_change(vc); } -void chain_plugin_impl::on_pbft_incoming_new_view(pbft_new_view nv){ +void chain_plugin_impl::on_pbft_incoming_new_view(pbft_metadata_ptr nv){ pbft_ctrl->on_pbft_new_view(nv); } -void chain_plugin_impl::on_pbft_incoming_checkpoint(pbft_checkpoint cp){ +void chain_plugin_impl::on_pbft_incoming_checkpoint(pbft_metadata_ptr cp){ pbft_ctrl->on_pbft_checkpoint(cp); } diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 568d1f371c3..d3b184360f2 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -396,8 +396,6 @@ namespace eosio { constexpr uint16_t net_version = proto_explicit_sync; - constexpr uint16_t pbft_checkpoint_granularity = 100; - struct transaction_state { transaction_id_type id; uint32_t block_num = 0; ///< the block number the transaction was included in @@ -2997,8 +2995,7 @@ namespace eosio { template bool net_plugin_impl::is_pbft_msg_valid(M const & msg) { // Do some basic validations of an incoming pbft msg, bad msgs should be quickly discarded without affecting state. - return chain_id == msg.common.chain_id - && !is_pbft_msg_outdated(msg) + return !is_pbft_msg_outdated(msg) && !sync_master->is_syncing(); } @@ -3025,58 +3022,53 @@ namespace eosio { } void net_plugin_impl::pbft_outgoing_prepare(const pbft_prepare &msg) { - auto added = maybe_add_to_pbft_cache(msg.common.uuid); + auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_prepare(msg)) return; bcast_pbft_msg(msg, pbft_message_TTL); - fc_dlog( logger, "sent prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num())("v", msg.view)("k", msg.common.sender)); + 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 &msg) { - auto added = maybe_add_to_pbft_cache(msg.common.uuid); + auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_commit(msg)) return; bcast_pbft_msg(msg, pbft_message_TTL); - fc_dlog( logger, "sent commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num())("v", msg.view)("k", msg.common.sender)); + 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 &msg) { - auto added = maybe_add_to_pbft_cache(msg.common.uuid); + auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_view_change(msg)) return; bcast_pbft_msg(msg, pbft_message_TTL); - fc_dlog( logger, "sent view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", msg.current_view)("tv", msg.target_view)("v", msg.common.sender)); + 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 &msg) { - auto added = maybe_add_to_pbft_cache(msg.common.uuid); + auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_new_view(msg)) return; bcast_pbft_msg(msg, INT_MAX); - fc_dlog( logger, "sent new view at view: ${v}, from ${k}, ", ("v", msg.new_view)("k", msg.common.sender)); + fc_dlog( logger, "sent new view at view: ${v} ", ("v", msg.new_view)); } void net_plugin_impl::pbft_outgoing_checkpoint(const pbft_checkpoint &msg) { - auto added = maybe_add_to_pbft_cache(msg.common.uuid); + auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_checkpoint(msg)) return; bcast_pbft_msg(msg, pbft_message_TTL); - fc_dlog( logger, "sent checkpoint at height: ${n}, from ${k}, ", ("n", msg.block_info.block_num())("k", msg.common.sender)); + 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 &uuid){ @@ -3105,44 +3097,51 @@ namespace eosio { if (!is_pbft_msg_valid(msg)) return; - auto added = maybe_add_to_pbft_cache(msg.common.uuid); + auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); if (!added) return; + auto pmm = pbft_message_metadata(msg, chain_id); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_prepare(msg)) return; + if (!pcc.pbft_db.is_valid_prepare(msg, pmm.sender_key)) return; forward_pbft_msg(c, msg, pbft_message_TTL); - fc_dlog( logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num())("v", msg.view)("k", msg.common.sender)); + fc_dlog( logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num())("v", msg.view)("k", pmm.sender_key)); - pbft_incoming_prepare_channel.publish(msg); + pbft_incoming_prepare_channel.publish(std::make_shared>(pmm)); } void net_plugin_impl::handle_message( connection_ptr c, const pbft_commit &msg) { if (!is_pbft_msg_valid(msg)) return; - auto added = maybe_add_to_pbft_cache(msg.common.uuid); + auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); if (!added) return; + auto pmm = pbft_message_metadata(msg, chain_id); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_commit(msg)) return; + if (!pcc.pbft_db.is_valid_commit(msg, pmm.sender_key)) return; forward_pbft_msg(c, msg, pbft_message_TTL); - fc_dlog( logger, "received commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num())("v", msg.view)("k", msg.common.sender)); + fc_dlog( logger, "received commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num())("v", msg.view)("k", pmm.sender_key)); - pbft_incoming_commit_channel.publish(msg); + pbft_incoming_commit_channel.publish(std::make_shared>(pmm)); } void net_plugin_impl::handle_message( connection_ptr c, const pbft_view_change &msg) { if (!is_pbft_msg_valid(msg)) return; - auto added = maybe_add_to_pbft_cache(msg.common.uuid); + auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); if (!added) return; + auto pmm = pbft_message_metadata(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(msg)) return; + if (!pcc.pbft_db.is_valid_view_change(msg, pmm.sender_key)) return; + auto missing_blocks = set{}; for (auto const &b: msg.prepared_cert.pre_prepares) { if (!ctrl.fetch_block_by_id(b)) missing_blocks.emplace(b); @@ -3160,25 +3159,25 @@ namespace eosio { } forward_pbft_msg(c, msg, pbft_message_TTL); - fc_dlog( logger, "received view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", msg.current_view)("tv", msg.target_view)("v", msg.common.sender)); + fc_dlog( logger, "received view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", msg.current_view)("tv", msg.target_view)("v", pmm.sender_key)); - pbft_incoming_view_change_channel.publish(msg); + pbft_incoming_view_change_channel.publish(std::make_shared>(pmm)); } void net_plugin_impl::handle_message( connection_ptr c, const pbft_new_view &msg) { - if (chain_id != msg.common.chain_id) return; - - auto added = maybe_add_to_pbft_cache(msg.common.uuid); + auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); if (!added) return; + auto pmm = pbft_message_metadata(msg, chain_id); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!(msg.common.sender == pcc.pbft_db.get_new_view_primary_key(msg.new_view) && msg.is_signature_valid())) return; + if (pmm.sender_key != pcc.pbft_db.get_new_view_primary_key(msg.new_view)) return; forward_pbft_msg(c, msg, INT_MAX); - fc_dlog( logger, "received new view: ${n}, from ${v}", ("n", msg)("v", msg.common.sender)); + fc_dlog( logger, "received new view: ${n}, from ${v}", ("n", msg)("v", pmm.sender_key)); - pbft_incoming_new_view_channel.publish(msg); + pbft_incoming_new_view_channel.publish(std::make_shared>(pmm)); } void net_plugin_impl::handle_message( connection_ptr c, const compressed_pbft_message &msg) { @@ -3201,28 +3200,26 @@ namespace eosio { if (!is_pbft_msg_valid(msg)) return; - auto added = maybe_add_to_pbft_cache(msg.common.uuid); + auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); if (!added) return; + auto pmm = pbft_message_metadata(msg, chain_id); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_checkpoint(msg)) return; + if (!pcc.pbft_db.is_valid_checkpoint(msg, pmm.sender_key)) return; forward_pbft_msg(c, msg, pbft_message_TTL); - fc_dlog( logger, "received checkpoint at ${n}, from ${v}", ("n", msg.block_info.block_num())("v", msg.common.sender)); + fc_dlog( logger, "received checkpoint at ${n}, from ${v}", ("n", msg.block_info.block_num())("v", pmm.sender_key)); - pbft_incoming_checkpoint_channel.publish(msg); + pbft_incoming_checkpoint_channel.publish(std::make_shared>(pmm)); } void net_plugin_impl::handle_message( connection_ptr c, const pbft_stable_checkpoint &msg) { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (pcc.pbft_db.is_valid_stable_checkpoint(msg)) { - fc_ilog(logger, "received stable checkpoint at ${n}, from ${v}", ("n", msg.block_info.block_num())("v", c->peer_name())); - for (auto cp: msg.checkpoints) { - pbft_incoming_checkpoint_channel.publish(cp); - } - } + 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())); } void net_plugin_impl::start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection) { 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 7208d198366..69f67ea6cf8 100644 --- a/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp +++ b/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp @@ -22,7 +22,7 @@ class pbft_plugin : public appbase::plugin { void plugin_initialize(const variables_map& options); void plugin_startup(); - static void plugin_shutdown(); + void plugin_shutdown(); pbft_state get_pbft_record( const block_id_type& bid )const; @@ -34,7 +34,7 @@ class pbft_plugin : public appbase::plugin { block_id_type get_pbft_prepared_id()const; block_id_type get_pbft_my_prepare_id()const; - static void set_pbft_current_view(pbft_view_type view); + void set_pbft_current_view(const pbft_view_type &view); private: diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index 10f2a1af06c..f73e7191f8f 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -105,7 +105,7 @@ namespace eosio { return ctrl.get_pbft_my_prepare(); } - void pbft_plugin::set_pbft_current_view(const pbft_view_type view) { + void pbft_plugin::set_pbft_current_view(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); diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index 85e54320327..266a043bf5a 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -217,11 +217,11 @@ BOOST_AUTO_TEST_CASE(view_change_validation) { 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); - nv_msg.common.sender = tester::get_public_key( N(carol), "active"); - auto nv_flag = false; + bool nv_flag; try { - nv_flag = pbft_ctrl.pbft_db.is_valid_new_view(nv_msg); - } catch (fc::exception) { + pbft_ctrl.pbft_db.validate_new_view(nv_msg, tester::get_public_key(N(carol), "active")); + nv_flag = true; + } catch (fc::exception &e) { nv_flag = false; } BOOST_CHECK_EQUAL(nv_flag, false); @@ -302,7 +302,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.last_irreversible_block_num(), 101); //generate new view with short fork prepare certificate - pbft_new_view_generator.state_machine->set_prepares_cache({}); + pbft_new_view_generator.state_machine->set_prepares_cache(pbft_prepare()); BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_send_pbft_msg(), true); pbft_new_view_generator.maybe_pbft_prepare(); BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_prepared(), true); @@ -310,7 +310,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o for(int i = 0; ido_send_view_change(); + pbft_new_view_generator.state_machine->do_send_view_change(); auto new_view = pbft_new_view_generator.pbft_db.get_proposed_new_view_num(); auto vcc = pbft_new_view_generator.pbft_db.generate_view_changed_certificate(new_view); auto nv_msg = pbft_new_view_generator.pbft_db.send_pbft_new_view( @@ -330,7 +330,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.head_block_num(), 137); //can switch fork after apply prepare certificate in new view - pbft_short_prepared_fork.state_machine->on_new_view(nv_msg); + pbft_short_prepared_fork.state_machine->on_new_view(std::make_shared>(nv_msg, ctrl_new_view_generator.get_chain_id())); BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.head_block_num(), 136); BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.last_irreversible_block_num(), 101); From f6528195ffc54ddd51f91b29cfdfa1bdadfbcc1d Mon Sep 17 00:00:00 2001 From: oldcold Date: Fri, 21 Jun 2019 17:42:08 +0800 Subject: [PATCH 2/6] optimise stable checkpoints sync --- libraries/chain/include/eosio/chain/pbft.hpp | 2 +- libraries/chain/pbft.cpp | 18 +++---- libraries/chain/pbft_database.cpp | 53 ++++++++++--------- .../include/eosio/net_plugin/net_plugin.hpp | 2 + plugins/net_plugin/net_plugin.cpp | 41 +++++++------- plugins/pbft_plugin/pbft_plugin.cpp | 22 +++++--- 6 files changed, 76 insertions(+), 62 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index 7fd22b8ab76..ba78d3ab1ea 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -182,7 +182,7 @@ namespace eosio { void maybe_pbft_prepare(); void maybe_pbft_commit(); void maybe_pbft_view_change(); - void send_pbft_checkpoint(); + void maybe_pbft_checkpoint(); void on_pbft_prepare(pbft_metadata_ptr p); void on_pbft_commit(pbft_metadata_ptr c); diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index e68f755fc13..4e9828cd853 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -63,6 +63,12 @@ namespace eosio { } } + void pbft_controller::maybe_pbft_checkpoint() { + if (!pbft_db.should_send_pbft_msg()) return; + pbft_db.send_pbft_checkpoint(); + pbft_db.checkpoint_local(); + } + void pbft_controller::on_pbft_prepare(pbft_metadata_ptr p) { state_machine->on_prepare(std::move(p)); } @@ -79,12 +85,6 @@ namespace eosio { state_machine->on_new_view(nv); } - void pbft_controller::send_pbft_checkpoint() { - if (!pbft_db.should_send_pbft_msg()) return; - pbft_db.send_pbft_checkpoint(); - pbft_db.checkpoint_local(); - } - 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); @@ -92,10 +92,8 @@ namespace eosio { } psm_state::psm_state() = default; - psm_state::~psm_state() = default; - psm_machine::psm_machine(pbft_database &pbft_db) : pbft_db(pbft_db) { set_current(std::make_shared()); @@ -198,11 +196,11 @@ 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); } } - void psm_prepared_state::send_commit(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()); @@ -217,6 +215,7 @@ 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); } } @@ -307,6 +306,7 @@ namespace eosio { psm_view_change_state::psm_view_change_state() = default; psm_view_change_state::~psm_view_change_state() = default; + /** * psm_view_change_state */ diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index ef8503aa9e2..fe287e8ceea 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -251,8 +251,6 @@ namespace eosio { void pbft_database::add_pbft_commit(pbft_commit &c, const public_key_type &pk) { - if (!is_valid_commit(c, pk)) return; - auto &by_block_id_index = pbft_state_index.get(); auto current = ctrl.fetch_block_state_by_id(c.block_info.block_id); @@ -663,7 +661,7 @@ namespace eosio { //adding my highest committed cert. auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - if ( highest_committed_block_num > lscb_num ) { + if ( highest_committed_block_num <= ctrl.last_irreversible_block_num() && highest_committed_block_num > lscb_num ) { ccb.emplace_back(highest_committed_block_num); } @@ -737,8 +735,8 @@ namespace eosio { pvcc.target_view=pvs->view; pvcc.view_changes.reserve(pvs->view_changes.size()); - for( auto it = pvs->view_changes.begin(); it != pvs->view_changes.end(); ++it ) { - pvcc.view_changes.emplace_back( it->second ); + for(auto & view_change : pvs->view_changes) { + pvcc.view_changes.emplace_back( view_change.second ); } return pvcc; } else return pvcc; @@ -829,6 +827,8 @@ namespace eosio { if (add_to_pbft_db) add_pbft_commit(c, pmm.sender_key); } + if (add_to_pbft_db && should_committed()) commit_local(); + auto cert_id = certificate.block_info.block_id; auto cert_bs = ctrl.fetch_block_state_by_id(cert_id); auto producer_schedule = lscb_active_producers(); @@ -893,7 +893,9 @@ namespace eosio { EOS_ASSERT(is_valid_stable_checkpoint(nv.stable_checkpoint, true), pbft_exception, "bad stable checkpoint: ${scp}", ("scp", nv.stable_checkpoint)); - for (auto const &c: nv.committed_certs) { + auto committed_certs = nv.committed_certs; + std::sort(committed_certs.begin(), committed_certs.end()); + for (auto const &c: committed_certs) { EOS_ASSERT(is_valid_committed_certificate(c, true), pbft_exception, "bad committed certificate: ${cc}", ("cc", c)); } @@ -966,8 +968,6 @@ namespace eosio { ("hppc", highest_ppc)("pc", nv.prepared_cert)); std::sort(highest_pcc.begin(), highest_pcc.end()); - auto committed_certs = nv.committed_certs; - std::sort(committed_certs.begin(), committed_certs.end()); EOS_ASSERT(highest_pcc.size() == committed_certs.size(), pbft_exception, "wrong committed certificates size"); for (auto i = 0; i < committed_certs.size(); ++i) { @@ -1112,8 +1112,8 @@ namespace eosio { pbft_stable_checkpoint psc; psc.block_info={cpp->block_id}; psc.checkpoints.reserve(cpp->checkpoints.size()); - for (auto it = cpp->checkpoints.begin(); it != cpp->checkpoints.end(); ++it) { - psc.checkpoints.emplace_back(it->second) ; + for (auto & checkpoint : cpp->checkpoints) { + psc.checkpoints.emplace_back(checkpoint.second) ; } return psc; } else return pbft_stable_checkpoint(); @@ -1121,32 +1121,30 @@ namespace eosio { block_info_type pbft_database::cal_pending_stable_checkpoint() const { - auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - auto lscb_id = ctrl.last_stable_checkpoint_block_id(); - auto lscb_info = block_info_type{lscb_id}; + 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(); - auto itr = by_blk_num.lower_bound(lscb_num); - if (itr == by_blk_num.end()) return lscb_info; + auto itr = by_blk_num.lower_bound(pending_scb_num); + if (itr == by_blk_num.end()) return pending_scb_info; while (itr != by_blk_num.end()) { if ((*itr)->is_stable && ctrl.fetch_block_state_by_id((*itr)->block_id)) { - auto lscb = ctrl.fetch_block_state_by_number(ctrl.last_stable_checkpoint_block_num()); + auto lscb = ctrl.fetch_block_state_by_number(pending_scb_num); - auto head_checkpoint_schedule = ctrl.fetch_block_state_by_id( - (*itr)->block_id)->active_schedule; + auto head_checkpoint_schedule = ctrl.fetch_block_state_by_id((*itr)->block_id)->active_schedule; producer_schedule_type current_schedule; producer_schedule_type new_schedule; - if (lscb_num == 0) { + if (pending_scb_num == 0) { auto const& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; if (ucb == 0) { current_schedule = ctrl.initial_schedule(); new_schedule = ctrl.initial_schedule(); } else { auto bs = ctrl.fetch_block_state_by_number(ucb); - if (!bs) return lscb_info; + if (!bs) return pending_scb_info; current_schedule = bs->active_schedule; new_schedule = bs->pending_schedule; } @@ -1154,17 +1152,18 @@ namespace eosio { current_schedule = lscb->active_schedule; new_schedule = lscb->pending_schedule; } else { - return lscb_info; + return pending_scb_info; } if ((*itr)->is_stable && (head_checkpoint_schedule == current_schedule || head_checkpoint_schedule == new_schedule)) { - lscb_info = block_info_type{(*itr)->block_id}; + pending_scb_info = block_info_type{(*itr)->block_id}; + pending_scb_num = pending_scb_info.block_num(); } } ++itr; } - return lscb_info; + return pending_scb_info; } vector pbft_database::generate_and_add_pbft_checkpoint() { @@ -1302,10 +1301,10 @@ namespace eosio { } void pbft_database::checkpoint_local() { - auto lscb_info = cal_pending_stable_checkpoint(); + auto pending_scb_info = cal_pending_stable_checkpoint(); auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - auto pending_num = lscb_info.block_num(); - auto pending_id = lscb_info.block_id; + auto pending_num = pending_scb_info.block_num(); + auto pending_id = pending_scb_info.block_id; 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); @@ -1356,6 +1355,8 @@ namespace eosio { if (add_to_pbft_db) add_pbft_checkpoint(cp, pmm.sender_key); } + if (add_to_pbft_db) checkpoint_local(); + auto bs = ctrl.fetch_block_state_by_number(scp.block_info.block_num()); if (bs) { auto as = bs->active_schedule; diff --git a/plugins/net_plugin/include/eosio/net_plugin/net_plugin.hpp b/plugins/net_plugin/include/eosio/net_plugin/net_plugin.hpp index 7fb193a979b..3de8b9a8d34 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/net_plugin.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/net_plugin.hpp @@ -39,6 +39,8 @@ namespace eosio { vector connections()const; bool is_syncing()const; + void maybe_sync_stable_checkpoints(); + size_t num_peers() const; private: std::unique_ptr my; diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index d3b184360f2..c96ab13a087 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -246,7 +246,7 @@ namespace eosio { void handle_message( connection_ptr c, const response_p2p_message &msg); //pbft messages - bool maybe_add_to_pbft_cache(const string &uuid); + bool maybe_add_to_pbft_cache(const string &key); void clean_expired_pbft_messages(); template bool is_pbft_msg_outdated(M const & msg); @@ -1635,7 +1635,6 @@ namespace eosio { void sync_manager::recv_handshake(const connection_ptr& c, const handshake_message& msg) { controller& cc = chain_plug->chain(); uint32_t lib_num = cc.last_irreversible_block_num(); - uint32_t lscb_num = cc.last_stable_checkpoint_block_num(); uint32_t peer_lib = msg.last_irreversible_block_num; reset_lib_num(c); c->syncing = false; @@ -1654,16 +1653,6 @@ namespace eosio { uint32_t head = cc.fork_db_head_block_num(); block_id_type head_id = cc.fork_db_head_block_id(); - auto upgraded = cc.is_pbft_enabled(); - if (upgraded - && peer_lib > lscb_num - && (head - lscb_num) / pbft_checkpoint_granularity > 1) - { - //there might be a better way to sync checkpoints, yet we do not want to modify the existing handshake msg. - fc_dlog(logger, "request sync checkpoints"); - sync_stable_checkpoints(c, peer_lib); - } - if (head_id == msg.head_id) { fc_dlog(logger, "sync check state 0"); // notify peer of our pending transactions @@ -2845,7 +2834,7 @@ namespace eosio { if ( msg.end_block == 0 || msg.end_block < msg.start_block) return; - fc_dlog(logger, "received checkpoint request message"); + fc_dlog(logger, "received checkpoint request message ${m}", ("m", msg)); vector scp_stack; controller &cc = my_impl->chain_plug->chain(); pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); @@ -3071,11 +3060,11 @@ namespace eosio { 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 &uuid){ - auto itr = pbft_message_cache.find(uuid); + bool net_plugin_impl::maybe_add_to_pbft_cache(const string &key){ + auto itr = pbft_message_cache.find(key); if (itr == pbft_message_cache.end()) { //add to cache - pbft_message_cache[uuid] = time_point_sec(time_point::now()) + pbft_message_cache_TTL; + pbft_message_cache[key] = time_point_sec(time_point::now()) + pbft_message_cache_TTL; return true; } return false; @@ -3854,10 +3843,26 @@ namespace eosio { return result; } - bool net_plugin::is_syncing()const { - return my->sync_master->is_syncing(); + bool net_plugin::is_syncing()const { + return my->sync_master->is_syncing(); + } + + void net_plugin::maybe_sync_stable_checkpoints() { + controller& cc = my->chain_plug->chain(); + if (!cc.is_pbft_enabled()) return; + //there might be a better way to sync checkpoints, yet we do not want to modify the existing handshake msg. + uint32_t head = cc.fork_db_head_block_num(); + + //TODO: shuffle connections to avoid being stuck on some bad peers. + for (auto const &c: my->connections) { + if (c->current()) { + my->sync_master->sync_stable_checkpoints(c, head); + } + } + } + net_plugin_impl::net_plugin_impl(): pbft_incoming_prepare_channel(app().get_channel()), pbft_incoming_commit_channel(app().get_channel()), diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index f73e7191f8f..0dcc60a5d11 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -118,8 +118,8 @@ namespace eosio { prepare_timer_tick(); if (ec) { wlog ("pbft plugin prepare timer tick error: ${m}", ("m", ec.message())); - } else { - if (pbft_ready()) pbft_ctrl.maybe_pbft_prepare(); + } else if (pbft_ready()) { + pbft_ctrl.maybe_pbft_prepare(); } }); } @@ -131,8 +131,8 @@ namespace eosio { commit_timer_tick(); if (ec) { wlog ("pbft plugin commit timer tick error: ${m}", ("m", ec.message())); - } else { - if (pbft_ready()) pbft_ctrl.maybe_pbft_commit(); + } else if (pbft_ready()) { + pbft_ctrl.maybe_pbft_commit(); } }); } @@ -149,8 +149,8 @@ namespace eosio { view_change_timer_tick(); if (ec) { wlog ("pbft plugin view change timer tick error: ${m}", ("m", ec.message())); - } else { - if (pbft_ready()) pbft_ctrl.maybe_pbft_view_change(); + } else if (pbft_ready()) { + pbft_ctrl.maybe_pbft_view_change(); } }); } @@ -162,8 +162,14 @@ namespace eosio { checkpoint_timer_tick(); if (ec) { wlog ("pbft plugin checkpoint timer tick error: ${m}", ("m", ec.message())); - } else { - if (pbft_ready()) pbft_ctrl.send_pbft_checkpoint(); + } else if (pbft_ready()) { + 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(); + } } }); } From fe0a4ae1b43070ed315c3b0943e96289ee9090d2 Mon Sep 17 00:00:00 2001 From: oldcold Date: Fri, 21 Jun 2019 18:21:13 +0800 Subject: [PATCH 3/6] optimise stable checkpoints sync, based on bos-v0.11.0 --- libraries/chain/include/eosio/chain/pbft.hpp | 2 +- .../include/eosio/chain/pbft_database.hpp | 5 +- libraries/chain/pbft.cpp | 19 ++--- libraries/chain/pbft_database.cpp | 81 ++++++++++--------- .../include/eosio/net_plugin/net_plugin.hpp | 2 + plugins/net_plugin/net_plugin.cpp | 69 +++++++++------- plugins/pbft_plugin/pbft_plugin.cpp | 22 +++-- 7 files changed, 111 insertions(+), 89 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index cba705a2c50..d912ab279bf 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -219,7 +219,7 @@ namespace eosio { void maybe_pbft_prepare(); void maybe_pbft_commit(); void maybe_pbft_view_change(); - void send_pbft_checkpoint(); + void maybe_pbft_checkpoint(); void on_pbft_prepare(pbft_prepare &p); void on_pbft_commit(pbft_commit &c); diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 7dcf2f5b51d..b7701c8802d 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -21,6 +21,9 @@ namespace eosio { using namespace std; using boost::uuids::uuid; + constexpr uint16_t pbft_checkpoint_granularity = 100; + constexpr uint16_t oldest_stable_checkpoint = 10000; + using pbft_view_type = uint32_t; enum class pbft_message_type : uint16_t { @@ -520,7 +523,7 @@ namespace eosio { pbft_view_changed_certificate generate_view_changed_certificate(pbft_view_type target_view); - pbft_stable_checkpoint get_stable_checkpoint_by_id(const block_id_type &block_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); diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index dc8e87f8198..82ccfa187c6 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -61,6 +61,12 @@ namespace eosio { } } + void pbft_controller::maybe_pbft_checkpoint() { + if (!pbft_db.should_send_pbft_msg()) return; + pbft_db.send_pbft_checkpoint(); + pbft_db.checkpoint_local(); + } + void pbft_controller::on_pbft_prepare(pbft_prepare &p) { state_machine->on_prepare(p); } @@ -77,22 +83,14 @@ namespace eosio { state_machine->on_new_view(nv); } - void pbft_controller::send_pbft_checkpoint() { - if (!pbft_db.should_send_pbft_msg()) return; - pbft_db.send_pbft_checkpoint(); - pbft_db.checkpoint_local(); - } - void pbft_controller::on_pbft_checkpoint(pbft_checkpoint &cp) { pbft_db.add_pbft_checkpoint(cp); pbft_db.checkpoint_local(); } psm_state::psm_state() = default; - psm_state::~psm_state() = default; - psm_machine::psm_machine(pbft_database &pbft_db) : pbft_db(pbft_db) { set_current(std::make_shared()); @@ -184,11 +182,11 @@ 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); } } - void psm_prepared_state::send_commit(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()); @@ -203,6 +201,7 @@ 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); } } @@ -237,7 +236,6 @@ namespace eosio { } psm_committed_state::psm_committed_state() = default; - psm_committed_state::~psm_committed_state() = default; /** @@ -308,7 +306,6 @@ namespace eosio { wlog("bad new view, ${s} ", ("s",ex.to_string())); } } - /** * psm_view_change_state */ diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index a7b3ffddfca..fc47699bcf6 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -671,7 +671,7 @@ namespace eosio { //adding my highest committed cert. auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - if ( highest_committed_block_num > lscb_num ) { + if ( highest_committed_block_num <= ctrl.last_irreversible_block_num() && highest_committed_block_num > lscb_num ) { ccb.emplace_back(highest_committed_block_num); } @@ -1088,12 +1088,15 @@ namespace eosio { return pbft_stable_checkpoint(); } - pbft_stable_checkpoint pbft_database::get_stable_checkpoint_by_id(const block_id_type &block_id) { + 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(); auto itr = by_block.find(block_id); if (itr == by_block.end()) { - auto blk = ctrl.fetch_block_by_id(block_id); - return fetch_stable_checkpoint_from_blk_extn(blk); + if (incl_blk_extn) { + auto blk = ctrl.fetch_block_by_id(block_id); + return fetch_stable_checkpoint_from_blk_extn(blk); + } + return pbft_stable_checkpoint(); } auto cpp = *itr; @@ -1108,50 +1111,52 @@ namespace eosio { block_info_type pbft_database::cal_pending_stable_checkpoint() const { - auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - auto lscb_id = ctrl.last_stable_checkpoint_block_id(); - auto lscb_info = block_info_type{lscb_id}; + 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(); - auto itr = by_blk_num.lower_bound(lscb_num); - if (itr == by_blk_num.end()) return lscb_info; + auto itr = by_blk_num.lower_bound(pending_scb_num); + if (itr == by_blk_num.end()) return pending_scb_info; while (itr != by_blk_num.end()) { - if ((*itr)->is_stable && ctrl.fetch_block_state_by_id((*itr)->block_id)) { - auto lscb = ctrl.fetch_block_state_by_number(ctrl.last_stable_checkpoint_block_num()); + if (auto bs = ctrl.fetch_block_state_by_id((*itr)->block_id)) { + auto scb = ctrl.fetch_block_state_by_number(pending_scb_num); - auto head_checkpoint_schedule = ctrl.fetch_block_state_by_id( - (*itr)->block_id)->active_schedule; + auto head_checkpoint_schedule = bs->active_schedule; producer_schedule_type current_schedule; producer_schedule_type new_schedule; - if (lscb_num == 0) { - auto const& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; + if (pending_scb_num == 0) { + auto const &ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; if (ucb == 0) { current_schedule = ctrl.initial_schedule(); new_schedule = ctrl.initial_schedule(); } else { - auto bs = ctrl.fetch_block_state_by_number(ucb); - if (!bs) return lscb_info; - current_schedule = bs->active_schedule; - new_schedule = bs->pending_schedule; + auto ucb_state = ctrl.fetch_block_state_by_number(ucb); + if (!ucb_state) return pending_scb_info; + current_schedule = ucb_state->active_schedule; + new_schedule = ucb_state->pending_schedule; } - } else if (lscb) { - current_schedule = lscb->active_schedule; - new_schedule = lscb->pending_schedule; + } else if (scb) { + current_schedule = scb->active_schedule; + new_schedule = scb->pending_schedule; } else { - return lscb_info; + return pending_scb_info; } - if ((*itr)->is_stable - && (head_checkpoint_schedule == current_schedule || head_checkpoint_schedule == new_schedule)) { - lscb_info = block_info_type{(*itr)->block_id}; + if ((*itr)->is_stable) { + if (head_checkpoint_schedule == current_schedule || head_checkpoint_schedule == new_schedule) { + pending_scb_info = block_info_type{(*itr)->block_id}; + pending_scb_num = pending_scb_info.block_num(); + } else { + return pending_scb_info; + } } } ++itr; } - return lscb_info; + return pending_scb_info; } vector pbft_database::generate_and_add_pbft_checkpoint() { @@ -1299,14 +1304,14 @@ namespace eosio { } void pbft_database::checkpoint_local() { - auto lscb_info = cal_pending_stable_checkpoint(); + auto pending_scb_info = cal_pending_stable_checkpoint(); auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - auto pending_num = lscb_info.block_num(); - auto pending_id = lscb_info.block_id; + auto pending_num = pending_scb_info.block_num(); + auto pending_id = pending_scb_info.block_id; 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 const &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); @@ -1314,11 +1319,10 @@ namespace eosio { } auto &bni = checkpoint_index.get(); auto oldest = bni.begin(); - if (oldest != bni.end() && lscb_num - (*oldest)->block_num > 10000) { - auto it = bni.lower_bound(lscb_num - 10000); - if (it != bni.end() && (*it)->is_stable) { - prune_checkpoints(*it); - } + if ( oldest != bni.end() + && (*oldest)->is_stable + && (*oldest)->block_num < lscb_num - oldest_stable_checkpoint ) { + prune_checkpoints(*oldest); } } @@ -1512,9 +1516,8 @@ namespace eosio { auto &by_num_index = checkpoint_index.get(); auto pitr = by_num_index.lower_bound( num ); - auto epitr = by_num_index.upper_bound( num ); - while( pitr != epitr ) { - if (pitr != by_num_index.end() && (*pitr)) results.emplace_back(*(*pitr)); + while(pitr != by_num_index.end() && (*pitr)->block_num == num ) { + results.emplace_back(*(*pitr)); ++pitr; } diff --git a/plugins/net_plugin/include/eosio/net_plugin/net_plugin.hpp b/plugins/net_plugin/include/eosio/net_plugin/net_plugin.hpp index 7fb193a979b..3de8b9a8d34 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/net_plugin.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/net_plugin.hpp @@ -39,6 +39,8 @@ namespace eosio { vector connections()const; bool is_syncing()const; + void maybe_sync_stable_checkpoints(); + size_t num_peers() const; private: std::unique_ptr my; diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 568d1f371c3..feb122f718b 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -246,7 +246,7 @@ namespace eosio { void handle_message( connection_ptr c, const response_p2p_message &msg); //pbft messages - bool maybe_add_to_pbft_cache(const string &uuid); + bool maybe_add_to_pbft_cache(const string &key); void clean_expired_pbft_messages(); template bool is_pbft_msg_outdated(M const & msg); @@ -396,8 +396,6 @@ namespace eosio { constexpr uint16_t net_version = proto_explicit_sync; - constexpr uint16_t pbft_checkpoint_granularity = 100; - struct transaction_state { transaction_id_type id; uint32_t block_num = 0; ///< the block number the transaction was included in @@ -1637,7 +1635,6 @@ namespace eosio { void sync_manager::recv_handshake(const connection_ptr& c, const handshake_message& msg) { controller& cc = chain_plug->chain(); uint32_t lib_num = cc.last_irreversible_block_num(); - uint32_t lscb_num = cc.last_stable_checkpoint_block_num(); uint32_t peer_lib = msg.last_irreversible_block_num; reset_lib_num(c); c->syncing = false; @@ -1656,16 +1653,6 @@ namespace eosio { uint32_t head = cc.fork_db_head_block_num(); block_id_type head_id = cc.fork_db_head_block_id(); - auto upgraded = cc.is_pbft_enabled(); - if (upgraded - && peer_lib > lscb_num - && (head - lscb_num) / pbft_checkpoint_granularity > 1) - { - //there might be a better way to sync checkpoints, yet we do not want to modify the existing handshake msg. - fc_dlog(logger, "request sync checkpoints"); - sync_stable_checkpoints(c, peer_lib); - } - if (head_id == msg.head_id) { fc_dlog(logger, "sync check state 0"); // notify peer of our pending transactions @@ -2847,7 +2834,7 @@ namespace eosio { if ( msg.end_block == 0 || msg.end_block < msg.start_block) return; - fc_dlog(logger, "received checkpoint request message"); + fc_dlog(logger, "received checkpoint request message ${m}", ("m", msg)); vector scp_stack; controller &cc = my_impl->chain_plug->chain(); pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); @@ -2918,9 +2905,23 @@ namespace eosio { fc_dlog(logger, "canceling wait on ${p}", ("p",c->peer_name())); c->cancel_wait(); + auto accept_pbft_stable_checkpoint = [&]() { + auto &pcc = chain_plug->pbft_ctrl(); + auto scp = pcc.pbft_db.fetch_stable_checkpoint_from_blk_extn(msg); + + if (!scp.empty() && scp.block_info.block_num() > cc.last_stable_checkpoint_block_num()) { + if (pcc.pbft_db.get_stable_checkpoint_by_id(msg->id(), false).empty()) { + handle_message(c, scp); + } else { + pcc.pbft_db.checkpoint_local(); + } + } + }; + try { if( cc.fetch_block_by_id(blk_id)) { sync_master->recv_block(c, blk_id, blk_num); + accept_pbft_stable_checkpoint(); return; } } catch( ...) { @@ -2936,14 +2937,8 @@ namespace eosio { go_away_reason reason = fatal_other; try { chain_plug->accept_block(msg); //, sync_master->is_active(c)); + accept_pbft_stable_checkpoint(); reason = no_reason; - auto blk = msg; - auto &pcc = chain_plug->pbft_ctrl(); - auto scp = pcc.pbft_db.fetch_stable_checkpoint_from_blk_extn(blk); - - if (!scp.empty()) { - handle_message(c, scp); - } } catch( const unlinkable_block_exception &ex) { peer_elog(c, "bad signed_block : ${m}", ("m",ex.what())); reason = unlinkable; @@ -3079,11 +3074,11 @@ namespace eosio { fc_dlog( logger, "sent checkpoint at height: ${n}, from ${k}, ", ("n", msg.block_info.block_num())("k", msg.common.sender)); } - bool net_plugin_impl::maybe_add_to_pbft_cache(const string &uuid){ - auto itr = pbft_message_cache.find(uuid); + bool net_plugin_impl::maybe_add_to_pbft_cache(const string &key){ + auto itr = pbft_message_cache.find(key); if (itr == pbft_message_cache.end()) { //add to cache - pbft_message_cache[uuid] = time_point_sec(time_point::now()) + pbft_message_cache_TTL; + pbft_message_cache[key] = time_point_sec(time_point::now()) + pbft_message_cache_TTL; return true; } return false; @@ -3218,10 +3213,11 @@ namespace eosio { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (pcc.pbft_db.is_valid_stable_checkpoint(msg)) { - fc_ilog(logger, "received stable checkpoint at ${n}, from ${v}", ("n", msg.block_info.block_num())("v", c->peer_name())); for (auto cp: msg.checkpoints) { - pbft_incoming_checkpoint_channel.publish(cp); + pcc.pbft_db.add_pbft_checkpoint(cp); } + pcc.pbft_db.checkpoint_local(); + fc_ilog(logger, "received stable checkpoint at ${n}, from ${v}", ("n", msg.block_info.block_num())("v", c->peer_name())); } } @@ -3857,10 +3853,25 @@ namespace eosio { return result; } - bool net_plugin::is_syncing()const { - return my->sync_master->is_syncing(); + bool net_plugin::is_syncing()const { + return my->sync_master->is_syncing(); } + void net_plugin::maybe_sync_stable_checkpoints() { + controller& cc = my->chain_plug->chain(); + if (!cc.is_pbft_enabled()) return; + //there might be a better way to sync checkpoints, yet we do not want to modify the existing handshake msg. + uint32_t head = cc.fork_db_head_block_num(); + + for (auto const &c: my->connections) { + if (c->current()) { + my->sync_master->sync_stable_checkpoints(c, head); + } + } + + } + + net_plugin_impl::net_plugin_impl(): pbft_incoming_prepare_channel(app().get_channel()), pbft_incoming_commit_channel(app().get_channel()), diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index 10f2a1af06c..e66c9b48621 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -118,8 +118,8 @@ namespace eosio { prepare_timer_tick(); if (ec) { wlog ("pbft plugin prepare timer tick error: ${m}", ("m", ec.message())); - } else { - if (pbft_ready()) pbft_ctrl.maybe_pbft_prepare(); + } else if (pbft_ready()) { + pbft_ctrl.maybe_pbft_prepare(); } }); } @@ -131,8 +131,8 @@ namespace eosio { commit_timer_tick(); if (ec) { wlog ("pbft plugin commit timer tick error: ${m}", ("m", ec.message())); - } else { - if (pbft_ready()) pbft_ctrl.maybe_pbft_commit(); + } else if (pbft_ready()) { + pbft_ctrl.maybe_pbft_commit(); } }); } @@ -149,8 +149,8 @@ namespace eosio { view_change_timer_tick(); if (ec) { wlog ("pbft plugin view change timer tick error: ${m}", ("m", ec.message())); - } else { - if (pbft_ready()) pbft_ctrl.maybe_pbft_view_change(); + } else if (pbft_ready()) { + pbft_ctrl.maybe_pbft_view_change(); } }); } @@ -162,8 +162,14 @@ namespace eosio { checkpoint_timer_tick(); if (ec) { wlog ("pbft plugin checkpoint timer tick error: ${m}", ("m", ec.message())); - } else { - if (pbft_ready()) pbft_ctrl.send_pbft_checkpoint(); + } else if (pbft_ready()) { + 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(); + } } }); } From 0e2cbc131576b3a5d91d95b9817bc55571d97b56 Mon Sep 17 00:00:00 2001 From: oldcold Date: Tue, 25 Jun 2019 19:03:51 +0800 Subject: [PATCH 4/6] prune all blocks which are below current lscb in fork_db --- libraries/chain/fork_database.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index 425c212a8cd..2163a5a5960 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -220,14 +220,14 @@ namespace eosio { namespace chain { auto oldest = *my->index.get().begin(); - auto should_prune_oldest = oldest->block_num < lib; - - if (pbft_enabled) { - should_prune_oldest = should_prune_oldest && oldest->block_num < checkpoint; - } - - if ( should_prune_oldest ) { + if (!pbft_enabled && oldest->block_num < lib) { prune( oldest ); + } else { + // prune all blocks below lscb + while (oldest->block_num < lib && oldest->block_num < checkpoint ) { + prune( oldest ); + oldest = *my->index.get().begin(); + } } return n; From 6334a0c60b8bedf5dd56b22747a24db5cd1128b3 Mon Sep 17 00:00:00 2001 From: oldcold Date: Thu, 27 Jun 2019 11:38:20 +0800 Subject: [PATCH 5/6] add socket opening check during `start_read_message` --- libraries/chain/pbft_database.cpp | 129 +++++++++++++++--------------- plugins/net_plugin/net_plugin.cpp | 5 +- 2 files changed, 68 insertions(+), 66 deletions(-) diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 6d9ea9eb9ce..05eab7dcd1b 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -133,9 +133,9 @@ namespace eosio { if (prepare_count.find(pre.second.view) == prepare_count.end()) prepare_count[pre.second.view] = 0; } - for (auto const &sp: as) { + for (auto const &bp: as) { for (auto const &pp: prepares) { - if (sp.block_signing_key == pp.first.second) prepare_count[pp.first.first] += 1; + if (bp.block_signing_key == pp.first.second) prepare_count[pp.first.first] += 1; } } for (auto const &e: prepare_count) { @@ -293,9 +293,9 @@ namespace eosio { if (commit_count.find(com.second.view) == commit_count.end()) commit_count[com.second.view] = 0; } - for (auto const &sp: as) { + for (auto const &bp: as) { for (auto const &pc: commits) { - if (sp.block_signing_key == pc.first.second) commit_count[pc.first.first] += 1; + if (bp.block_signing_key == pc.first.second) commit_count[pc.first.first] += 1; } } @@ -386,9 +386,9 @@ namespace eosio { if (commit_count.find(com.second.view) == commit_count.end()) commit_count[com.second.view] = 0; } - for (auto const &sp: as) { + for (auto const &bp: as) { for (auto const &pc: commits) { - if (sp.block_signing_key == pc.first.second) commit_count[pc.first.first] += 1; + if (bp.block_signing_key == pc.first.second) commit_count[pc.first.first] += 1; } } @@ -450,9 +450,9 @@ namespace eosio { if (vsp->view_changes.size() >= threshold && !vsp->is_view_changed) { auto vc_count = 0; - for (auto const &sp: lscb_bps) { + for (auto const &bp: lscb_bps) { for (auto const &v: vsp->view_changes) { - if (sp.block_signing_key == v.first) vc_count += 1; + if (bp.block_signing_key == v.first) vc_count += 1; } } if (vc_count >= threshold) { @@ -585,8 +585,11 @@ 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=current_view; + nv.prepared_cert=highest_ppc; + nv.committed_certs=highest_pcc; + nv.stable_checkpoint=highest_sc; + nv.view_changed_cert=vcc; nv.sender_signature = sp_itr->second(nv.digest(chain_id)); emit(pbft_outgoing_new_view, nv); return nv; @@ -615,9 +618,9 @@ namespace eosio { prepare_msg[pre.first.first].emplace_back(pre.second); } - for (auto const &sp: as) { + for (auto const &bp: as) { for (auto const &pp: prepares) { - if (sp.block_signing_key == pp.first.second) prepare_count[pp.first.first] += 1; + if (bp.block_signing_key == pp.first.second) prepare_count[pp.first.first] += 1; } } @@ -659,16 +662,18 @@ namespace eosio { vector ccb; + auto lib_num = ctrl.last_irreversible_block_num(); + //adding my highest committed cert. auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - if ( highest_committed_block_num <= ctrl.last_irreversible_block_num() && highest_committed_block_num > lscb_num ) { + if ( highest_committed_block_num <= lib_num && highest_committed_block_num > lscb_num ) { ccb.emplace_back(highest_committed_block_num); } auto watermarks = get_updated_watermarks(); for (auto& watermark : watermarks) { //adding committed cert on every water mark. - if (watermark < highest_committed_block_num && watermark > lscb_num) { + if (watermark < lib_num && watermark > lscb_num) { ccb.emplace_back(watermark); } } @@ -699,9 +704,9 @@ namespace eosio { commit_msg[com.first.first].emplace_back(com.second); } - for (auto const &sp: as) { + for (auto const &bp: as) { for (auto const &cc: commits) { - if (sp.block_signing_key == cc.first.second) commit_count[cc.first.first] += 1; + if (bp.block_signing_key == cc.first.second) commit_count[cc.first.first] += 1; } } @@ -753,13 +758,11 @@ namespace eosio { auto prepares = certificate.prepares; auto prepares_metadata = vector>{}; prepares_metadata.reserve(prepares.size()); - auto valid = true; - for (auto &p : prepares) { + for (auto &p : prepares) { auto pmm = pbft_message_metadata(p, chain_id); prepares_metadata.emplace_back(pmm); - valid = valid && is_valid_prepare(p, pmm.sender_key); - if (!valid) return false; + if (!is_valid_prepare(p, pmm.sender_key)) return false; if (add_to_pbft_db) add_pbft_prepare(p, pmm.sender_key); } @@ -777,9 +780,9 @@ namespace eosio { if (prepare_count.find(pm.msg.view) == prepare_count.end()) prepare_count[pm.msg.view] = 0; } - for (auto const &sp: producer_schedule.producers) { + for (auto const &bp: producer_schedule.producers) { for (auto const &pm: prepares_metadata) { - if (sp.block_signing_key == pm.sender_key) prepare_count[pm.msg.view] += 1; + if (bp.block_signing_key == pm.sender_key) prepare_count[pm.msg.view] += 1; } } @@ -794,13 +797,13 @@ namespace eosio { if (!should_prepared) return false; //validate prepare - auto lscb = ctrl.last_stable_checkpoint_block_num(); + auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto non_fork_bp_count = 0; vector prepare_infos; prepare_infos.reserve(certificate.prepares.size()); for (auto const &p : certificate.prepares) { //only search in fork db - if (p.block_info.block_num() <= lscb) { + if (p.block_info.block_num() <= lscb_num) { ++non_fork_bp_count; } else { prepare_infos.emplace_back(p.block_info); @@ -818,12 +821,11 @@ namespace eosio { auto commits = certificate.commits; auto commits_metadata = vector>{}; commits_metadata.reserve(commits.size()); - auto valid = true; + for (auto &c : commits) { auto pmm = pbft_message_metadata(c, chain_id); commits_metadata.emplace_back(pmm); - valid = valid && is_valid_commit(c, pmm.sender_key); - if (!valid) return false; + if (!is_valid_commit(c, pmm.sender_key)) return false; if (add_to_pbft_db) add_pbft_commit(c, pmm.sender_key); } @@ -843,9 +845,9 @@ namespace eosio { if (commit_count.find(cm.msg.view) == commit_count.end()) commit_count[cm.msg.view] = 0; } - for (auto const &sp: producer_schedule.producers) { + for (auto const &bp: producer_schedule.producers) { for (auto const &cm: commits_metadata) { - if (sp.block_signing_key == cm.sender_key) commit_count[cm.msg.view] += 1; + if (bp.block_signing_key == cm.sender_key) commit_count[cm.msg.view] += 1; } } @@ -860,13 +862,13 @@ namespace eosio { if (!should_committed) return false; //validate commit - auto lscb = ctrl.last_stable_checkpoint_block_num(); + auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto non_fork_bp_count = 0; vector commit_infos; commit_infos.reserve(certificate.commits.size()); for (auto const &c : certificate.commits) { //only search in fork db - if (c.block_info.block_num() <= lscb) { + if (c.block_info.block_num() <= lscb_num) { ++non_fork_bp_count; } else { commit_infos.emplace_back(c.block_info); @@ -1072,20 +1074,20 @@ namespace eosio { pbft_stable_checkpoint pbft_database::fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr &b) { try { if (b) { - auto &ext = b->block_extensions; + auto &extn = b->block_extensions; - for (auto it = ext.begin(); it != ext.end();) { + for (auto it = extn.begin(); it != extn.end();) { if (it->first == static_cast(block_extension_type::pbft_stable_checkpoint)) { - auto scp_v = it->second; - fc::datastream ds_decode(scp_v.data(), scp_v.size()); + auto scp_ds = it->second; + fc::datastream ds(scp_ds.data(), scp_ds.size()); - pbft_stable_checkpoint scp_decode; - fc::raw::unpack(ds_decode, scp_decode); + pbft_stable_checkpoint scp; + fc::raw::unpack(ds, scp); - if (is_valid_stable_checkpoint(scp_decode)) { - return scp_decode; + if (is_valid_stable_checkpoint(scp)) { + return scp; } else { - it = ext.erase(it); + it = extn.erase(it); } } else { it++; @@ -1204,7 +1206,9 @@ namespace eosio { } 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 (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; @@ -1271,9 +1275,9 @@ namespace eosio { if (csp->checkpoints.size() >= threshold && !csp->is_stable) { auto cp_count = 0; - for (auto const &sp: active_bps) { + for (auto const &bp: active_bps) { for (auto const &c: csp->checkpoints) { - if (sp.block_signing_key == c.first) cp_count += 1; + if (bp.block_signing_key == c.first) cp_count += 1; } } if (cp_count >= threshold) { @@ -1332,8 +1336,8 @@ namespace eosio { 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; - auto bs = ctrl.fetch_block_state_by_id(cp.block_info.block_id); - if (bs) { + + 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) { if (bp.block_signing_key == pk) return true; @@ -1351,40 +1355,37 @@ namespace eosio { auto checkpoints = scp.checkpoints; auto checkpoints_metadata = vector>{}; checkpoints_metadata.reserve(checkpoints.size()); - auto valid = true; + for (auto &cp : checkpoints) { auto pmm = pbft_message_metadata(cp, chain_id); checkpoints_metadata.emplace_back(pmm); - valid = valid && cp.block_info == scp.block_info && is_valid_checkpoint(cp, pmm.sender_key); - if (!valid) return false; + if (cp.block_info != scp.block_info || !is_valid_checkpoint(cp, pmm.sender_key)) return false; if (add_to_pbft_db) add_pbft_checkpoint(cp, pmm.sender_key); } if (add_to_pbft_db) checkpoint_local(); - auto bs = ctrl.fetch_block_state_by_number(scp.block_info.block_num()); - if (bs) { + + 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 &sp: as.producers) { + for (auto const &bp: as.producers) { for (auto const &cpm: checkpoints_metadata) { - if (sp.block_signing_key == cpm.sender_key) cp_count += 1; + if (bp.block_signing_key == cpm.sender_key) cp_count += 1; } } - valid = valid && cp_count >= as.producers.size() * 2 / 3 + 1; - } else { - return false; + return cp_count >= as.producers.size() * 2 / 3 + 1; } - return valid; + return false; + } bool pbft_database::should_send_pbft_msg() { - auto my_sp = ctrl.my_signature_providers(); auto schedules = get_updated_fork_schedules(); for (auto const &bp: schedules) { - for (auto const &my: my_sp) { - if (bp.first == my.first) return true; + for (auto const &sp: ctrl.my_signature_providers()) { + if (bp.first == sp.first) return true; } } return false; @@ -1416,11 +1417,11 @@ namespace eosio { num = ucb; } - auto bs = ctrl.fetch_block_state_by_number(num); - if (!bs) return ctrl.initial_schedule(); - - if (bs->pending_schedule.producers.empty()) return bs->active_schedule; - return bs->pending_schedule; + if (auto bs = ctrl.fetch_block_state_by_number(num)) { + if (bs->pending_schedule.producers.empty()) return bs->active_schedule; + return bs->pending_schedule; + } + return ctrl.initial_schedule(); } block_num_type pbft_database::get_current_pbft_watermark() { diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 3814714689c..3b1a38f133b 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -2318,7 +2318,7 @@ namespace eosio { void net_plugin_impl::start_read_message(const connection_ptr& conn) { try { - if(!conn->socket) { + if(!conn->socket || !conn->socket->is_open()) { return; } connection_wptr weak_conn = conn; @@ -2848,7 +2848,8 @@ namespace eosio { scp_stack.push_back(scp); } } - fc_dlog(logger, "sent ${n} stable checkpoints on my node",("n",scp_stack.size())); + + if (!scp_stack.empty()) fc_dlog(logger, "sending ${n} stable checkpoints on my node",("n",scp_stack.size())); while (scp_stack.size()) { c->enqueue(scp_stack.back()); From 73ca6744814580db4468cba832b4df0d9aada15e Mon Sep 17 00:00:00 2001 From: oldcold Date: Fri, 28 Jun 2019 05:26:09 +0800 Subject: [PATCH 6/6] fix for compatibility. --- libraries/chain/pbft_database.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 05eab7dcd1b..7bcaf19fa45 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -106,7 +106,10 @@ namespace eosio { try { flat_map, pbft_prepare> prepares; prepares[std::make_pair(p.view, pk)] = p; - auto curr_ps = pbft_state{current->id, current->block_num, prepares}; + pbft_state curr_ps; + curr_ps.block_id = current->id; + curr_ps.block_num = current->block_num; + curr_ps.prepares = prepares; auto curr_psp = std::make_shared(move(curr_ps)); pbft_state_index.insert(curr_psp); } catch (...) { @@ -154,7 +157,10 @@ namespace eosio { auto bnum = block_info_type{bid}.block_num(); if (itr == by_block_id_index.end()) { - auto ps = pbft_state{bid, bnum, .is_prepared=true}; + pbft_state ps; + ps.block_id = bid; + ps.block_num = bnum; + ps.is_prepared = true; auto psp = std::make_shared(move(ps)); pbft_state_index.insert(psp); return; @@ -263,7 +269,10 @@ namespace eosio { try { flat_map, pbft_commit> commits; commits[std::make_pair(c.view, pk)] = c; - auto curr_ps = pbft_state{current->id, current->block_num, .commits=commits}; + pbft_state curr_ps; + curr_ps.block_id = current->id; + curr_ps.block_num = current->block_num; + curr_ps.commits = commits; auto curr_psp = std::make_shared(move(curr_ps)); pbft_state_index.insert(curr_psp); } catch (...) { @@ -428,7 +437,9 @@ namespace eosio { if (itr == by_view_index.end()) { flat_map view_changes; view_changes[pk] = vc; - auto vcs = pbft_view_change_state{vc.target_view, view_changes}; + pbft_view_change_state vcs; + vcs.view = vc.target_view; + vcs.view_changes = view_changes; auto vcsp = std::make_shared(move(vcs)); view_state_index.insert(vcsp); } else { @@ -1255,7 +1266,10 @@ namespace eosio { if (itr == by_block.end()) { flat_map checkpoints; checkpoints[pk] = cp; - auto cs = pbft_checkpoint_state{cp.block_info.block_id, cp.block_info.block_num(), checkpoints}; + pbft_checkpoint_state cs; + cs.block_id = cp.block_info.block_id; + cs.block_num = cp.block_info.block_num(); + cs.checkpoints = checkpoints; auto csp = std::make_shared(move(cs)); checkpoint_index.insert(csp); itr = by_block.find(cp.block_info.block_id);