From 1f3eaebd3b75730c0951deb878bbd4d130dbdc2d Mon Sep 17 00:00:00 2001 From: maodaishan Date: Thu, 9 May 2019 15:47:11 +0800 Subject: [PATCH 01/37] update cleos to support eosio.msig new actions eosio.msig added new actions: oppose unoppose abstain unabstain update cleos to support above actions, and update "cleos multisig review" to show the oppose/abstain opposals. --- programs/cleos/main.cpp | 88 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index f0ac7a53937..9fe50efa771 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -3545,7 +3545,9 @@ int main( int argc, char** argv ) { enum class approval_status { unapproved, approved, - invalidated + invalidated, + opposed, + abstained }; std::map> all_approvals; @@ -3647,6 +3649,46 @@ int main( int argc, char** argv ) { } } } + + //get opposed and obstained + fc::variants rows5; + try { + const auto& result5 = call(get_table_func, fc::mutable_variant_object("json", true) + ("code", "eosio.msig") + ("scope", proposer) + ("table", "opposes") + ("table_key", "") + ("lower_bound", name(proposal_name).value) + ("upper_bound", name(proposal_name).value + 1) + // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions + // Change to name(proposal_name).value when cleos no longer needs to support nodeos versions older than 1.5.0 + ("limit", 1) + ); + rows5 = result5.get_object()["rows"].get_array(); + } catch( ... ) { + } + if( !rows5.empty() && rows5[0].get_object()["proposal_name"] == proposal_name ) { + const auto& oppo_object = rows5[0].get_object(); + + for( const auto& opa : oppo_object["opposed_approvals"].get_array() ) { + permission_level pl = opa.as(); + for( auto& a : all_approvals ) { + if( a.first == pl ) { + a.second.second = approval_status::opposed; + } + } + } + + for( const auto& aba : oppo_object["abstained_approvals"].get_array() ) { + auto pl = aba.as(); + for( auto& a : all_approvals ) { + if( a.first == pl ) { + a.second.second = approval_status::abstained; + } + } + } + } + } auto trx_hex = proposal_object["packed_transaction"].as_string(); @@ -3699,6 +3741,16 @@ int main( int argc, char** argv ) { approval_obj["invalidation_time"] = provided_approvers[approval.first.actor].first; } break; + case approval_status::opposed: + { + approval_obj["status"] = "opposed"; + } + break; + case approval_status::abstained: + { + approval_obj["status"] = "abstained"; + } + break; } approvals.push_back( std::move(approval_obj) ); @@ -3748,6 +3800,40 @@ int main( int argc, char** argv ) { unapprove->add_option("permissions", perm, localized("The JSON string of filename defining approving permissions"))->required(); unapprove->set_callback([&] { approve_or_unapprove("unapprove"); }); + // multisig oppose + auto oppose = msig->add_subcommand("oppose", localized("Oppose proposed transaction")); + add_standard_transaction_options(oppose, "proposer@active"); + oppose->add_option("proposer", proposer, localized("proposer name (string)"))->required(); + oppose->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); + oppose->add_option("permissions", perm, localized("The JSON string of filename defining opposing permissions"))->required(); + oppose->add_option("proposal_hash", proposal_hash, localized("Hash of proposed transaction (i.e. transaction ID) to optionally enforce as a condition of the approval")); + oppose->set_callback([&] { approve_or_unapprove("oppose"); }); + + // multisig unoppose + auto unoppose = msig->add_subcommand("unoppose", localized("Unoppose proposed transaction")); + add_standard_transaction_options(unoppose, "proposer@active"); + unoppose->add_option("proposer", proposer, localized("proposer name (string)"))->required(); + unoppose->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); + unoppose->add_option("permissions", perm, localized("The JSON string of filename defining unopposing permissions"))->required(); + unoppose->set_callback([&] { approve_or_unapprove("unoppose"); }); + + // multisig abstain + auto abstain = msig->add_subcommand("abstain", localized("Abstain proposed transaction")); + add_standard_transaction_options(abstain, "proposer@active"); + abstain->add_option("proposer", proposer, localized("proposer name (string)"))->required(); + abstain->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); + abstain->add_option("permissions", perm, localized("The JSON string of filename defining abstaining permissions"))->required(); + abstain->add_option("proposal_hash", proposal_hash, localized("Hash of proposed transaction (i.e. transaction ID) to optionally enforce as a condition of the approval")); + abstain->set_callback([&] { approve_or_unapprove("abstain"); }); + + // multisig unabstain + auto unabstain = msig->add_subcommand("unabstain", localized("Unabstain proposed transaction")); + add_standard_transaction_options(unabstain, "proposer@active"); + unabstain->add_option("proposer", proposer, localized("proposer name (string)"))->required(); + unabstain->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); + unabstain->add_option("permissions", perm, localized("The JSON string of filename defining unabstaining permissions"))->required(); + unabstain->set_callback([&] { approve_or_unapprove("unabstain"); }); + // multisig invalidate string invalidator; auto invalidate = msig->add_subcommand("invalidate", localized("Invalidate all multisig approvals of an account")); From 36006e9e62f79bb25311392c7717c88152211fb6 Mon Sep 17 00:00:00 2001 From: oldcold Date: Mon, 8 Jul 2019 11:42:42 +0800 Subject: [PATCH 02/37] valid new view before emit --- libraries/chain/include/eosio/chain/pbft.hpp | 4 ++-- libraries/chain/pbft.cpp | 24 ++++++++------------ libraries/chain/pbft_database.cpp | 10 ++++++-- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index ba78d3ab1ea..05e34596a7a 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -40,7 +40,7 @@ namespace eosio { 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_new_view(pbft_metadata_ptr e); void send_prepare(); void send_commit(); @@ -187,7 +187,7 @@ namespace eosio { 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_new_view(pbft_metadata_ptr nv); void on_pbft_checkpoint(const pbft_metadata_ptr &cp); private: diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 8789abce3cf..92b646c8af5 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -81,8 +81,8 @@ namespace eosio { state_machine->on_view_change(std::move(vc)); } - void pbft_controller::on_pbft_new_view(const pbft_metadata_ptr &nv) { - state_machine->on_new_view(nv); + void pbft_controller::on_pbft_new_view(pbft_metadata_ptr nv) { + state_machine->on_new_view(std::move(nv)); } void pbft_controller::on_pbft_checkpoint(const pbft_metadata_ptr &cp) { @@ -137,20 +137,21 @@ namespace eosio { current->send_view_change(shared_from_this(), pbft_db); } - void psm_machine::on_new_view(const pbft_metadata_ptr &e) { - if (e->msg.new_view <= get_current_view()) return; + void psm_machine::on_new_view(pbft_metadata_ptr e) { + auto nv = std::move(e); + if (nv->msg.new_view <= get_current_view()) return; try { - pbft_db.validate_new_view(e->msg, e->sender_key); + pbft_db.validate_new_view(nv->msg, nv->sender_key); } catch (const fc::exception& ex) { elog("bad new view, ${s} ", ("s",ex.to_string())); return; } try { - transit_to_new_view(e, current); + transit_to_new_view(nv, current); } catch(...) { - elog("apply new view failed, waiting for next round.. ${nv} ", ("nv", e->msg)); + elog("apply new view failed, waiting for next round.. ${nv} ", ("nv", nv->msg)); } } @@ -366,6 +367,7 @@ namespace eosio { auto prepares = pbft_db.send_and_add_pbft_prepare(pbft_prepare(), get_current_view()); set_prepares_cache(prepares); + //TODO: reset prepare timer; set_view_changes_cache(pbft_view_change()); set_view_change_timer(0); @@ -378,6 +380,7 @@ namespace eosio { auto commits = pbft_db.send_and_add_pbft_commit(pbft_commit(), get_current_view()); set_commits_cache(commits); + //TODO: reset commit timer; set_view_changes_cache(pbft_view_change()); @@ -419,13 +422,6 @@ namespace eosio { if (nv_msg.empty()) return false; - try { - 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; diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 7ef06c068cd..a6df008f755 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -605,8 +605,14 @@ namespace eosio { 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; + try { + validate_new_view(nv, sp_itr->first); + emit(pbft_outgoing_new_view, nv); + return nv; + } catch (const fc::exception& ex) { + elog("bad new view, ${s} ", ("s", ex.to_string())); + return pbft_new_view(); + } } pbft_prepared_certificate pbft_database::generate_prepared_certificate() { From 019f595ff14e8ec8cacdfb3309b238cb1257bca2 Mon Sep 17 00:00:00 2001 From: oldcold Date: Tue, 9 Jul 2019 18:17:41 +0800 Subject: [PATCH 03/37] add necessary validations before trying to relay new view msgs; optimise pbft signals. --- libraries/chain/include/eosio/chain/pbft.hpp | 72 +++---- .../include/eosio/chain/pbft_database.hpp | 31 ++- libraries/chain/pbft.cpp | 84 ++++---- libraries/chain/pbft_database.cpp | 20 +- .../include/eosio/chain/plugin_interface.hpp | 10 +- plugins/chain_plugin/chain_plugin.cpp | 40 ++-- plugins/net_plugin/net_plugin.cpp | 180 +++++++++--------- unittests/pbft_tests.cpp | 18 +- 8 files changed, 229 insertions(+), 226 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index 05e34596a7a..2bebe05cc79 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -37,18 +37,18 @@ namespace eosio { return current; } - 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(pbft_metadata_ptr e); + void on_prepare(const pbft_metadata_ptr& e); + void on_commit(const pbft_metadata_ptr& e); + void on_view_change(const pbft_metadata_ptr& e); + void on_new_view(const pbft_metadata_ptr& e); void send_prepare(); void send_commit(); void send_view_change(); - void transit_to_committed_state(psm_state_ptr s, bool to_new_view); - void transit_to_prepared_state(psm_state_ptr s); - void transit_to_view_change_state(psm_state_ptr s); + void transit_to_committed_state(const psm_state_ptr& s, bool to_new_view); + void transit_to_prepared_state(const psm_state_ptr& s); + void transit_to_view_change_state(const psm_state_ptr& s); void transit_to_new_view(const pbft_metadata_ptr& e, const psm_state_ptr& s); void do_send_view_change(); @@ -106,13 +106,13 @@ namespace eosio { psm_state(); ~psm_state(); - 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 on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) = 0; + virtual void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) = 0; + virtual void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) = 0; - virtual void send_prepare(psm_machine_ptr m, pbft_database &pbft_db) = 0; - virtual void send_commit(psm_machine_ptr m, pbft_database &pbft_db) = 0; - virtual void send_view_change(psm_machine_ptr m, pbft_database &pbft_db) = 0; + virtual void send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) = 0; + virtual void send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) = 0; + virtual void send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) = 0; virtual const char* get_name() = 0; std::shared_ptr get_self() { return shared_from_this(); }; @@ -124,13 +124,13 @@ namespace eosio { psm_prepared_state(); ~psm_prepared_state(); - 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 on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; + void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; + void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void send_prepare(psm_machine_ptr m, pbft_database &pbft_db) override; - void send_commit(psm_machine_ptr m, pbft_database &pbft_db) override; - void send_view_change(psm_machine_ptr m, pbft_database &pbft_db) override; + void send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) override; + void send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) override; + void send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) override; bool pending_commit_local; @@ -142,13 +142,13 @@ namespace eosio { psm_committed_state(); ~psm_committed_state(); - 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 on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; + void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; + void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void send_prepare(psm_machine_ptr m, pbft_database &pbft_db) override; - void send_commit(psm_machine_ptr m, pbft_database &pbft_db) override; - void send_view_change(psm_machine_ptr m, pbft_database &pbft_db) override; + void send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) override; + void send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) override; + void send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) override; const char* get_name() override { return "{==== COMMITTED ====}"; } }; @@ -158,13 +158,13 @@ namespace eosio { psm_view_change_state(); ~psm_view_change_state(); - 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 on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; + void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; + void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void send_prepare(psm_machine_ptr m, pbft_database &pbft_db) override; - void send_commit(psm_machine_ptr m, pbft_database &pbft_db) override; - void send_view_change(psm_machine_ptr m, pbft_database &pbft_db) override; + void send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) override; + void send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) override; + void send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) override; const char* get_name() override { return "{==== VIEW CHANGE ====}"; } }; @@ -184,11 +184,11 @@ namespace eosio { void maybe_pbft_view_change(); void maybe_pbft_checkpoint(); - 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(pbft_metadata_ptr nv); - void on_pbft_checkpoint(const pbft_metadata_ptr &cp); + void on_pbft_prepare(const pbft_metadata_ptr& p); + void on_pbft_commit(const pbft_metadata_ptr& c); + void on_pbft_view_change(const 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 7fd03ebb3e7..b72f9645b66 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -61,7 +61,7 @@ namespace eosio { template struct pbft_message_metadata { - explicit pbft_message_metadata(pbft_message_body m, chain_id_type chain_id): msg{m} { + 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*/) { @@ -110,6 +110,8 @@ namespace eosio { } }; + using pbft_prepare_ptr = std::shared_ptr; + struct pbft_commit { explicit pbft_commit() = default; @@ -166,6 +168,8 @@ namespace eosio { } }; + using pbft_checkpoint_ptr = std::shared_ptr; + struct pbft_stable_checkpoint { explicit pbft_stable_checkpoint() = default; @@ -252,6 +256,8 @@ namespace eosio { } }; + using pbft_view_change_ptr = std::shared_ptr; + struct pbft_view_changed_certificate { explicit pbft_view_changed_certificate() = default; @@ -301,6 +307,8 @@ namespace eosio { } }; + using pbft_new_view_ptr = std::shared_ptr; + struct pbft_state { block_id_type block_id; block_num_type block_num = 0; @@ -465,7 +473,7 @@ namespace eosio { bool should_recv_pbft_msg(const public_key_type &pub_key); bool pending_pbft_lib(); - chain_id_type get_chain_id() {return chain_id;} + chain_id_type& get_chain_id() {return chain_id;} pbft_stable_checkpoint get_stable_checkpoint_by_id(const block_id_type &block_id, bool incl_blk_extn = true); pbft_stable_checkpoint fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr &b); block_info_type cal_pending_stable_checkpoint() const; @@ -481,20 +489,11 @@ namespace eosio { flat_map get_pbft_fork_schedules() const; - signal pbft_outgoing_prepare; - signal pbft_incoming_prepare; - - signal pbft_outgoing_commit; - signal pbft_incoming_commit; - - signal pbft_outgoing_view_change; - signal pbft_incoming_view_change; - - signal pbft_outgoing_new_view; - signal pbft_incoming_new_view; - - signal pbft_outgoing_checkpoint; - signal pbft_incoming_checkpoint; + signal pbft_outgoing_prepare; + signal pbft_outgoing_commit; + signal pbft_outgoing_view_change; + signal pbft_outgoing_new_view; + signal pbft_outgoing_checkpoint; private: controller &ctrl; diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 92b646c8af5..5679b332733 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -69,20 +69,20 @@ namespace eosio { pbft_db.checkpoint_local(); } - void pbft_controller::on_pbft_prepare(pbft_metadata_ptr p) { - state_machine->on_prepare(std::move(p)); + void pbft_controller::on_pbft_prepare(const pbft_metadata_ptr& p) { + state_machine->on_prepare(p); } - void pbft_controller::on_pbft_commit(pbft_metadata_ptr c) { - state_machine->on_commit(std::move(c)); + void pbft_controller::on_pbft_commit(const pbft_metadata_ptr& c) { + state_machine->on_commit(c); } - void pbft_controller::on_pbft_view_change(pbft_metadata_ptr vc) { - state_machine->on_view_change(std::move(vc)); + void pbft_controller::on_pbft_view_change(const pbft_metadata_ptr& vc) { + state_machine->on_view_change(vc); } - void pbft_controller::on_pbft_new_view(pbft_metadata_ptr nv) { - state_machine->on_new_view(std::move(nv)); + void pbft_controller::on_pbft_new_view(const pbft_metadata_ptr& nv) { + state_machine->on_new_view(nv); } void pbft_controller::on_pbft_checkpoint(const pbft_metadata_ptr &cp) { @@ -113,45 +113,44 @@ namespace eosio { psm_machine::~psm_machine() = default; - void psm_machine::on_prepare(pbft_metadata_ptr e) { - current->on_prepare(shared_from_this(), std::move(e), pbft_db); + void psm_machine::on_prepare(const pbft_metadata_ptr& e) { + current->on_prepare(shared_from_this(), e, pbft_db); } void psm_machine::send_prepare() { current->send_prepare(shared_from_this(), 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::on_commit(const pbft_metadata_ptr& e) { + current->on_commit(shared_from_this(), e, pbft_db); } void psm_machine::send_commit() { current->send_commit(shared_from_this(), 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::on_view_change(const pbft_metadata_ptr& e) { + current->on_view_change(shared_from_this(), 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_metadata_ptr e) { - auto nv = std::move(e); - if (nv->msg.new_view <= get_current_view()) return; + 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(nv->msg, nv->sender_key); + 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(nv, current); + transit_to_new_view(e, current); } catch(...) { - elog("apply new view failed, waiting for next round.. ${nv} ", ("nv", nv->msg)); + elog("apply new view failed, waiting for next round.. ${nv} ", ("nv", e->msg)); } } @@ -168,18 +167,18 @@ namespace eosio { 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_metadata_ptr e, pbft_database &pbft_db) { + void psm_prepared_state::on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { //ignore } - void psm_prepared_state::send_prepare(psm_machine_ptr m, pbft_database &pbft_db) { + void psm_prepared_state::send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) { //retry if (m->get_prepares_cache().empty()) return; pbft_db.send_and_add_pbft_prepare(m->get_prepares_cache(), m->get_current_view()); } - void psm_prepared_state::on_commit(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) { + void psm_prepared_state::on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { if (e->msg.view < m->get_current_view()) return; if (!pbft_db.is_valid_commit(e->msg, e->sender_key)) return; @@ -202,7 +201,7 @@ namespace eosio { } } - void psm_prepared_state::send_commit(psm_machine_ptr m, pbft_database &pbft_db) { + void psm_prepared_state::send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) { auto commits = pbft_db.send_and_add_pbft_commit(m->get_commits_cache(), m->get_current_view()); if (!commits.empty()) { @@ -221,7 +220,7 @@ namespace eosio { } } - void psm_prepared_state::on_view_change(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) { + void psm_prepared_state::on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { if (e->msg.target_view <= m->get_current_view()) return; if (!pbft_db.is_valid_view_change(e->msg, e->sender_key)) return; @@ -236,7 +235,7 @@ namespace eosio { } } - void psm_prepared_state::send_view_change(psm_machine_ptr m, pbft_database &pbft_db) { + void psm_prepared_state::send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) { m->transit_to_view_change_state(shared_from_this()); } @@ -247,7 +246,7 @@ namespace eosio { /** * psm_committed_state */ - void psm_committed_state::on_prepare(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) { + void psm_committed_state::on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { //validate if (e->msg.view < m->get_current_view()) return; if (!pbft_db.is_valid_prepare(e->msg, e->sender_key)) return; @@ -259,7 +258,7 @@ namespace eosio { if (pbft_db.should_prepared()) m->transit_to_prepared_state(shared_from_this()); } - void psm_committed_state::send_prepare(psm_machine_ptr m, pbft_database &pbft_db) { + void psm_committed_state::send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) { auto prepares = pbft_db.send_and_add_pbft_prepare(m->get_prepares_cache(), m->get_current_view()); @@ -271,7 +270,7 @@ 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_metadata_ptr e, pbft_database &pbft_db) { + void psm_committed_state::on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { if (e->msg.view < m->get_current_view()) return; if (!pbft_db.is_valid_commit(e->msg, e->sender_key)) return; @@ -279,14 +278,14 @@ namespace eosio { pbft_db.add_pbft_commit(e->msg, e->sender_key); } - void psm_committed_state::send_commit(psm_machine_ptr m, pbft_database &pbft_db) { + void psm_committed_state::send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) { if (m->get_commits_cache().empty()) return; pbft_db.send_and_add_pbft_commit(m->get_commits_cache(), m->get_current_view()); } - void psm_committed_state::on_view_change(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) { + void psm_committed_state::on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { if (e->msg.target_view <= m->get_current_view()) return; if (!pbft_db.is_valid_view_change(e->msg, e->sender_key)) return; @@ -301,7 +300,7 @@ namespace eosio { } } - void psm_committed_state::send_view_change(psm_machine_ptr m, pbft_database &pbft_db) { + void psm_committed_state::send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) { m->transit_to_view_change_state(shared_from_this()); } @@ -310,23 +309,23 @@ namespace eosio { /** * psm_view_change_state */ - void psm_view_change_state::on_prepare(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) { + void psm_view_change_state::on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { //ignore; } - void psm_view_change_state::send_prepare(psm_machine_ptr m, pbft_database &pbft_db) { + void psm_view_change_state::send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) { //ignore; } - void psm_view_change_state::on_commit(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) { + void psm_view_change_state::on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { //ignore; } - void psm_view_change_state::send_commit(psm_machine_ptr m, pbft_database &pbft_db) { + void psm_view_change_state::send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) { //ignore; } - void psm_view_change_state::on_view_change(psm_machine_ptr m, pbft_metadata_ptr e, pbft_database &pbft_db) { + void psm_view_change_state::on_view_change(const psm_machine_ptr& m, const 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(); @@ -343,7 +342,7 @@ namespace eosio { m->maybe_new_view(shared_from_this()); } - void psm_view_change_state::send_view_change(psm_machine_ptr m, pbft_database &pbft_db) { + void psm_view_change_state::send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) { //skip from view change state if my lib is higher than my view change state height. auto vc = m->get_view_changes_cache(); @@ -357,7 +356,7 @@ namespace eosio { m->maybe_new_view(shared_from_this()); } - void psm_machine::transit_to_committed_state(psm_state_ptr s, bool to_new_view) { + void psm_machine::transit_to_committed_state(const psm_state_ptr& s, bool to_new_view) { if (!to_new_view) { auto nv = pbft_db.get_committed_view(); @@ -373,10 +372,9 @@ namespace eosio { set_view_change_timer(0); set_current(std::make_shared()); - s.reset(); } - void psm_machine::transit_to_prepared_state(psm_state_ptr s) { + void psm_machine::transit_to_prepared_state(const psm_state_ptr& s) { auto commits = pbft_db.send_and_add_pbft_commit(pbft_commit(), get_current_view()); set_commits_cache(commits); @@ -385,10 +383,9 @@ namespace eosio { set_view_changes_cache(pbft_view_change()); set_current(std::make_shared()); - s.reset(); } - void psm_machine::transit_to_view_change_state(psm_state_ptr s) { + void psm_machine::transit_to_view_change_state(const psm_state_ptr& s) { set_commits_cache(pbft_commit()); set_prepares_cache(pbft_prepare()); @@ -402,7 +399,6 @@ namespace eosio { auto nv = maybe_new_view(s); if (nv) return; } - s.reset(); } bool psm_machine::maybe_new_view(const psm_state_ptr &s) { diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index a6df008f755..10f05347f1c 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -181,7 +181,7 @@ namespace eosio { if (lib == block_id_type()) return true; auto forks = ctrl.fork_db().fetch_branch_from(in, lib); - //`branch_type` will always contain at least the common ancestor. + //`branch_type` will always contain at least themselves. //`in` block num should be higher than lib, yet fall on the same branch with lib. return forks.first.size() > 1 && forks.second.size() == 1; }; @@ -193,7 +193,7 @@ namespace eosio { auto retry_p = cached_prepare; retry_p.common.timestamp = time_point::now(); retry_p.sender_signature = sp.second(retry_p.digest(chain_id)); - emit(pbft_outgoing_prepare, retry_p); + emit(pbft_outgoing_prepare, std::make_shared(retry_p)); } return prepare_to_be_cached; } else if (reserve_prepare(my_prepare)) { @@ -201,7 +201,7 @@ namespace eosio { 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); + emit(pbft_outgoing_prepare, std::make_shared(reserve_p)); if (prepare_to_be_cached.empty()) prepare_to_be_cached = reserve_p; } return prepare_to_be_cached; @@ -225,7 +225,7 @@ namespace eosio { 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); + emit(pbft_outgoing_prepare, std::make_shared(new_p)); add_pbft_prepare(new_p, sp.first); sent = true; if (prepare_to_be_cached.empty()) prepare_to_be_cached = new_p; @@ -330,7 +330,7 @@ namespace eosio { auto retry_c = cached_commit; retry_c.common.timestamp = time_point::now(); retry_c.sender_signature = sp.second(retry_c.digest(chain_id)); - emit(pbft_outgoing_commit, retry_c); + emit(pbft_outgoing_commit, std::make_shared(retry_c)); } return commit_to_be_cached; } else { @@ -351,7 +351,7 @@ namespace eosio { 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); + emit(pbft_outgoing_commit, std::make_shared(new_c)); add_pbft_commit(new_c, sp.first); if (commit_to_be_cached.empty()) commit_to_be_cached = new_c; } @@ -515,7 +515,7 @@ namespace eosio { auto retry_vc = cached_view_change; retry_vc.common.timestamp = time_point::now(); retry_vc.sender_signature = sp.second(retry_vc.digest(chain_id)); - emit(pbft_outgoing_view_change, retry_vc); + emit(pbft_outgoing_view_change, std::make_shared(retry_vc)); } return view_change_to_be_cached; } else { @@ -531,7 +531,7 @@ namespace eosio { 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); + emit(pbft_outgoing_view_change, std::make_shared(new_vc)); add_pbft_view_change(new_vc, my_sp.first); if (view_change_to_be_cached.empty()) view_change_to_be_cached = new_vc; } @@ -607,7 +607,7 @@ namespace eosio { nv.sender_signature = sp_itr->second(nv.digest(chain_id)); try { validate_new_view(nv, sp_itr->first); - emit(pbft_outgoing_new_view, nv); + emit(pbft_outgoing_new_view, std::make_shared(nv)); return nv; } catch (const fc::exception& ex) { elog("bad new view, ${s} ", ("s", ex.to_string())); @@ -1329,7 +1329,7 @@ namespace eosio { void pbft_database::send_pbft_checkpoint() { auto cps_to_send = generate_and_add_pbft_checkpoint(); for (auto const &cp: cps_to_send) { - emit(pbft_outgoing_checkpoint, cp); + emit(pbft_outgoing_checkpoint, std::make_shared(cp)); } } diff --git a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp index a168ea54928..81935707abe 100644 --- a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp +++ b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp @@ -73,11 +73,11 @@ namespace eosio { namespace chain { namespace plugin_interface { } namespace outgoing { - 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 ce0eab28de5..581bcb80443 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_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); + void on_pbft_incoming_prepare(const pbft_metadata_ptr& p); + void on_pbft_incoming_commit(const pbft_metadata_ptr& c); + void on_pbft_incoming_view_change(const pbft_metadata_ptr& vc); + void on_pbft_incoming_new_view(const pbft_metadata_ptr& nv); + void on_pbft_incoming_checkpoint(const pbft_metadata_ptr& cp); // retained references to channels for easy publication channels::pre_accepted_block::channel_type& pre_accepted_block_channel; @@ -805,48 +805,48 @@ void chain_plugin::plugin_initialize(const variables_map& options) { //pbft - my->pbft_incoming_prepare_subscription = my->pbft_incoming_prepare_channel.subscribe( [this]( pbft_metadata_ptr p ){ + my->pbft_incoming_prepare_subscription = my->pbft_incoming_prepare_channel.subscribe( [this]( const pbft_metadata_ptr& p ){ my->on_pbft_incoming_prepare(p); }); - my->pbft_incoming_commit_subscription = my->pbft_incoming_commit_channel.subscribe( [this]( pbft_metadata_ptr c ){ + my->pbft_incoming_commit_subscription = my->pbft_incoming_commit_channel.subscribe( [this]( const 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_metadata_ptr vc ){ + my->pbft_incoming_view_change_subscription = my->pbft_incoming_view_change_channel.subscribe( [this]( const 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_metadata_ptr nv ){ + my->pbft_incoming_new_view_subscription = my->pbft_incoming_new_view_channel.subscribe( [this]( const pbft_metadata_ptr& nv ){ my->on_pbft_incoming_new_view(nv); }); - my->pbft_incoming_checkpoint_subscription = my->pbft_incoming_checkpoint_channel.subscribe( [this]( pbft_metadata_ptr cp ){ + my->pbft_incoming_checkpoint_subscription = my->pbft_incoming_checkpoint_channel.subscribe( [this]( const pbft_metadata_ptr& cp ){ my->on_pbft_incoming_checkpoint(cp); }); my->pbft_outgoing_prepare_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_prepare.connect( - [this]( const pbft_prepare& prepare ) { + [this]( const pbft_prepare_ptr& prepare ) { my->pbft_outgoing_prepare_channel.publish( prepare ); }); my->pbft_outgoing_commit_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_commit.connect( - [this]( const pbft_commit& commit ) { + [this]( const pbft_commit_ptr& commit ) { my->pbft_outgoing_commit_channel.publish( commit ); }); my->pbft_outgoing_view_change_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_view_change.connect( - [this]( const pbft_view_change& view_change ) { + [this]( const pbft_view_change_ptr& view_change ) { my->pbft_outgoing_view_change_channel.publish( view_change ); }); my->pbft_outgoing_new_view_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_new_view.connect( - [this]( const pbft_new_view& new_view ) { + [this]( const pbft_new_view_ptr& new_view ) { my->pbft_outgoing_new_view_channel.publish( new_view ); }); my->pbft_outgoing_checkpoint_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_checkpoint.connect( - [this]( const pbft_checkpoint& checkpoint ) { + [this]( const pbft_checkpoint_ptr& checkpoint ) { my->pbft_outgoing_checkpoint_channel.publish( checkpoint ); }); @@ -856,23 +856,23 @@ void chain_plugin::plugin_initialize(const variables_map& options) { } -void chain_plugin_impl::on_pbft_incoming_prepare(pbft_metadata_ptr p){ +void chain_plugin_impl::on_pbft_incoming_prepare(const pbft_metadata_ptr& p){ pbft_ctrl->on_pbft_prepare(p); } -void chain_plugin_impl::on_pbft_incoming_commit(pbft_metadata_ptr c){ +void chain_plugin_impl::on_pbft_incoming_commit(const pbft_metadata_ptr& c){ pbft_ctrl->on_pbft_commit(c); } -void chain_plugin_impl::on_pbft_incoming_view_change(pbft_metadata_ptr vc){ +void chain_plugin_impl::on_pbft_incoming_view_change(const pbft_metadata_ptr& vc){ pbft_ctrl->on_pbft_view_change(vc); } -void chain_plugin_impl::on_pbft_incoming_new_view(pbft_metadata_ptr nv){ +void chain_plugin_impl::on_pbft_incoming_new_view(const pbft_metadata_ptr& nv){ pbft_ctrl->on_pbft_new_view(nv); } -void chain_plugin_impl::on_pbft_incoming_checkpoint(pbft_metadata_ptr cp){ +void chain_plugin_impl::on_pbft_incoming_checkpoint(const 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 15bdb522743..78402c21dd7 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -255,22 +255,22 @@ namespace eosio { void bcast_pbft_msg(const net_message &msg, int ttl); - void forward_pbft_msg(connection_ptr c, const net_message &msg, int ttl); - - void pbft_outgoing_prepare(const pbft_prepare &prepare); - void pbft_outgoing_commit(const pbft_commit &commit); - void pbft_outgoing_view_change(const pbft_view_change &view_change); - void pbft_outgoing_new_view(const pbft_new_view &new_view); - void pbft_outgoing_checkpoint(const pbft_checkpoint &checkpoint); - - void handle_message( connection_ptr c, const pbft_prepare &msg); - void handle_message( connection_ptr c, const pbft_commit &msg); - void handle_message( connection_ptr c, const pbft_view_change &msg); - void handle_message( connection_ptr c, const pbft_new_view &msg); - void handle_message( connection_ptr c, const pbft_checkpoint &msg); - void handle_message( connection_ptr c, const pbft_stable_checkpoint &msg); - void handle_message( connection_ptr c, const checkpoint_request_message &msg); - void handle_message( connection_ptr c, const compressed_pbft_message &msg); + void forward_pbft_msg(const connection_ptr& c, const net_message &msg, int ttl); + + void pbft_outgoing_prepare(const pbft_prepare_ptr& prepare); + void pbft_outgoing_commit(const pbft_commit_ptr& commit); + void pbft_outgoing_view_change(const pbft_view_change_ptr& view_change); + void pbft_outgoing_new_view(const pbft_new_view_ptr& new_view); + void pbft_outgoing_checkpoint(const pbft_checkpoint_ptr& checkpoint); + + void handle_message( const connection_ptr& c, pbft_prepare &msg); + void handle_message( const connection_ptr& c, pbft_commit &msg); + void handle_message( const connection_ptr& c, pbft_view_change &msg); + void handle_message( const connection_ptr& c, pbft_new_view &msg); + void handle_message( const connection_ptr& c, pbft_checkpoint &msg); + void handle_message( const connection_ptr& c, pbft_stable_checkpoint &msg); + void handle_message( const connection_ptr& c, const checkpoint_request_message &msg); + void handle_message( const connection_ptr& c, compressed_pbft_message &msg); void start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection); void start_txn_timer(); @@ -2831,7 +2831,7 @@ namespace eosio { trx->get_signatures().size() * sizeof(signature_type); } - void net_plugin_impl::handle_message( connection_ptr c, const checkpoint_request_message &msg) { + void net_plugin_impl::handle_message( const connection_ptr& c, const checkpoint_request_message &msg) { if ( msg.end_block == 0 || msg.end_block < msg.start_block) return; @@ -3020,7 +3020,7 @@ namespace eosio { } } - void net_plugin_impl::forward_pbft_msg(connection_ptr c, const net_message &msg, int ttl) { + void net_plugin_impl::forward_pbft_msg(const connection_ptr& c, const net_message &msg, int ttl) { auto deadline = time_point_sec(time_point::now()) + ttl; for (auto &conn: connections) { @@ -3030,54 +3030,52 @@ namespace eosio { } } - void net_plugin_impl::pbft_outgoing_prepare(const pbft_prepare &msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); + void net_plugin_impl::pbft_outgoing_prepare(const pbft_prepare_ptr& msg) { + auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - bcast_pbft_msg(msg, pbft_message_TTL); - fc_dlog( logger, "sent prepare at height: ${n}, view: ${v} ", ("n", msg.block_info.block_num())("v", msg.view)); + bcast_pbft_msg(*msg, pbft_message_TTL); + fc_dlog( logger, "sent prepare at height: ${n}, view: ${v} ", ("n", msg->block_info.block_num())("v", msg->view)); } - void net_plugin_impl::pbft_outgoing_commit(const pbft_commit &msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); + void net_plugin_impl::pbft_outgoing_commit(const pbft_commit_ptr& msg) { + auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - bcast_pbft_msg(msg, pbft_message_TTL); - fc_dlog( logger, "sent commit at height: ${n}, view: ${v} ", ("n", msg.block_info.block_num())("v", msg.view)); + bcast_pbft_msg(*msg, pbft_message_TTL); + fc_dlog( logger, "sent commit at height: ${n}, view: ${v} ", ("n", msg->block_info.block_num())("v", msg->view)); } - void net_plugin_impl::pbft_outgoing_view_change(const pbft_view_change &msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); + void net_plugin_impl::pbft_outgoing_view_change(const pbft_view_change_ptr& msg) { + auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - bcast_pbft_msg(msg, pbft_message_TTL); - fc_dlog( logger, "sent view change {cv: ${cv}, tv: ${tv}}", ("cv", msg.current_view)("tv", msg.target_view)); + bcast_pbft_msg(*msg, pbft_message_TTL); + fc_dlog( logger, "sent view change {cv: ${cv}, tv: ${tv}}", ("cv", msg->current_view)("tv", msg->target_view)); } - void net_plugin_impl::pbft_outgoing_new_view(const pbft_new_view &msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); + void net_plugin_impl::pbft_outgoing_new_view(const pbft_new_view_ptr& msg) { + auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); if (!added) return; - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - - bcast_pbft_msg(msg, INT_MAX); - fc_dlog( logger, "sent new view at view: ${v} ", ("v", msg.new_view)); + bcast_pbft_msg(*msg, INT_MAX); + fc_dlog( logger, "sent new view at view: ${v} ", ("v", msg->new_view)); } - void net_plugin_impl::pbft_outgoing_checkpoint(const pbft_checkpoint &msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); + void net_plugin_impl::pbft_outgoing_checkpoint(const pbft_checkpoint_ptr& msg) { + auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - bcast_pbft_msg(msg, pbft_message_TTL); - fc_dlog( logger, "sent checkpoint at height: ${n} ", ("n", msg.block_info.block_num())); + bcast_pbft_msg(*msg, pbft_message_TTL); + fc_dlog( logger, "sent checkpoint at height: ${n} ", ("n", msg->block_info.block_num())); } bool net_plugin_impl::maybe_add_to_pbft_cache(const string &key){ @@ -3091,7 +3089,7 @@ namespace eosio { } void net_plugin_impl::clean_expired_pbft_messages(){ - pbft_message_cache_ticker (); + pbft_message_cache_ticker(); auto itr = pbft_message_cache.begin(); auto now = time_point::now(); @@ -3104,57 +3102,58 @@ namespace eosio { } } - void net_plugin_impl::handle_message( connection_ptr c, const pbft_prepare &msg) { + void net_plugin_impl::handle_message( const connection_ptr& c, pbft_prepare &msg) { - if (!is_pbft_msg_valid(msg)) return; + auto pmm = pbft_message_metadata(std::move(msg), chain_id); - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; + if (!is_pbft_msg_valid(pmm.msg)) return; - auto pmm = pbft_message_metadata(msg, chain_id); + auto added = maybe_add_to_pbft_cache(std::string(pmm.msg.sender_signature)); + if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_prepare(msg, pmm.sender_key)) return; + if (!pcc.pbft_db.is_valid_prepare(pmm.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", pmm.sender_key)); + forward_pbft_msg(c, pmm.msg, pbft_message_TTL); + fc_dlog( logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", pmm.msg.block_info.block_num())("v", pmm.msg.view)("k", pmm.sender_key)); - pbft_incoming_prepare_channel.publish(std::make_shared>(pmm)); + pbft_incoming_prepare_channel.publish(std::make_shared>(std::move(pmm))); } - void net_plugin_impl::handle_message( connection_ptr c, const pbft_commit &msg) { + void net_plugin_impl::handle_message( const connection_ptr& c, pbft_commit &msg) { - if (!is_pbft_msg_valid(msg)) return; + auto pmm = pbft_message_metadata(std::move(msg), chain_id); - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); + if (!is_pbft_msg_valid(pmm.msg)) return; + + auto added = maybe_add_to_pbft_cache(std::string(pmm.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, pmm.sender_key)) return; + if (!pcc.pbft_db.is_valid_commit(pmm.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", pmm.sender_key)); + forward_pbft_msg(c, pmm.msg, pbft_message_TTL); + fc_dlog( logger, "received commit at height: ${n}, view: ${v}, from ${k}, ", ("n", pmm.msg.block_info.block_num())("v", pmm.msg.view)("k", pmm.sender_key)); - pbft_incoming_commit_channel.publish(std::make_shared>(pmm)); + pbft_incoming_commit_channel.publish(std::make_shared>(std::move(pmm))); } - void net_plugin_impl::handle_message( connection_ptr c, const pbft_view_change &msg) { + void net_plugin_impl::handle_message( const connection_ptr& c, pbft_view_change &msg) { - if (!is_pbft_msg_valid(msg)) return; + auto pmm = pbft_message_metadata( std::move(msg), chain_id); - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; + if (!is_pbft_msg_valid(pmm.msg)) return; - auto pmm = pbft_message_metadata(msg, chain_id); + auto added = maybe_add_to_pbft_cache(std::string(pmm.msg.sender_signature)); + if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); controller &ctrl = my_impl->chain_plug->chain(); - if (!pcc.pbft_db.is_valid_view_change(msg, pmm.sender_key)) return; + if (!pcc.pbft_db.is_valid_view_change(pmm.msg, pmm.sender_key)) return; auto missing_blocks = set{}; - for (auto const &b: msg.prepared_cert.pre_prepares) { + for (auto const &b: pmm.msg.prepared_cert.pre_prepares) { if (!ctrl.fetch_block_by_id(b)) missing_blocks.emplace(b); } @@ -3169,29 +3168,36 @@ namespace eosio { c->enqueue(req); } - 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", pmm.sender_key)); + forward_pbft_msg(c, pmm.msg, pbft_message_TTL); + fc_dlog( logger, "received view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", pmm.msg.current_view)("tv", pmm.msg.target_view)("v", pmm.sender_key)); - pbft_incoming_view_change_channel.publish(std::make_shared>(pmm)); + pbft_incoming_view_change_channel.publish(std::make_shared>(std::move(pmm))); } - void net_plugin_impl::handle_message( connection_ptr c, const pbft_new_view &msg) { + void net_plugin_impl::handle_message( const connection_ptr& c, pbft_new_view &msg) { + + auto pmm = pbft_message_metadata(std::move(msg), chain_id); - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); + auto added = maybe_add_to_pbft_cache(std::string(pmm.msg.sender_signature)); if (!added) return; - auto pmm = pbft_message_metadata(msg, chain_id); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (pmm.sender_key != pcc.pbft_db.get_new_view_primary_key(msg.new_view)) return; + if (time_point_sec(time_point::now()) > time_point_sec(pmm.msg.common.timestamp) + 60 * pbft_message_TTL + || pmm.msg.new_view <= pcc.state_machine->get_current_view()) { + //skip new view messages that are too old or whose target views are lower than mine. + return; + } - forward_pbft_msg(c, msg, INT_MAX); - fc_dlog( logger, "received new view: ${n}, from ${v}", ("n", msg)("v", pmm.sender_key)); + if (pmm.sender_key != pcc.pbft_db.get_new_view_primary_key(pmm.msg.new_view)) return; - pbft_incoming_new_view_channel.publish(std::make_shared>(pmm)); + forward_pbft_msg(c, pmm.msg, INT_MAX); + fc_dlog( logger, "received new view: ${n}, from ${v}", ("n", pmm.msg)("v", pmm.sender_key)); + + pbft_incoming_new_view_channel.publish(std::make_shared>(std::move(pmm))); } - void net_plugin_impl::handle_message( connection_ptr c, const compressed_pbft_message &msg) { + void net_plugin_impl::handle_message( const connection_ptr& c, compressed_pbft_message &msg) { auto decompressed_msg = decompress_pbft(msg.content); @@ -3207,25 +3213,25 @@ namespace eosio { } } - void net_plugin_impl::handle_message( connection_ptr c, const pbft_checkpoint &msg) { + void net_plugin_impl::handle_message( const connection_ptr& c, pbft_checkpoint &msg) { - if (!is_pbft_msg_valid(msg)) return; + auto pmm = pbft_message_metadata(std::move(msg), chain_id); - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; + if (!is_pbft_msg_valid(pmm.msg)) return; - auto pmm = pbft_message_metadata(msg, chain_id); + auto added = maybe_add_to_pbft_cache(std::string(pmm.msg.sender_signature)); + if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_checkpoint(msg, pmm.sender_key)) return; + if (!pcc.pbft_db.is_valid_checkpoint(pmm.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", pmm.sender_key)); + forward_pbft_msg(c, pmm.msg, pbft_message_TTL); + fc_dlog( logger, "received checkpoint at ${n}, from ${v}", ("n", pmm.msg.block_info.block_num())("v", pmm.sender_key)); - pbft_incoming_checkpoint_channel.publish(std::make_shared>(pmm)); + pbft_incoming_checkpoint_channel.publish(std::make_shared>(std::move(pmm))); } - void net_plugin_impl::handle_message( connection_ptr c, const pbft_stable_checkpoint &msg) { + void net_plugin_impl::handle_message( const connection_ptr& c, pbft_stable_checkpoint &msg) { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index 266a043bf5a..a0c5e3b45be 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -60,7 +60,7 @@ std::map make_signature_ BOOST_AUTO_TEST_CASE(can_init) { tester tester; - controller &ctrl = *tester.control.get(); + controller &ctrl = *tester.control; pbft_controller pbft_ctrl{ctrl}; tester.produce_block(); @@ -70,7 +70,7 @@ BOOST_AUTO_TEST_CASE(can_init) { BOOST_AUTO_TEST_CASE(can_advance_lib_in_old_version) { tester tester; - controller &ctrl = *tester.control.get(); + controller &ctrl = *tester.control; pbft_controller pbft_ctrl{ctrl}; auto msp = make_signature_provider(); @@ -86,7 +86,7 @@ BOOST_AUTO_TEST_CASE(can_advance_lib_in_old_version) { BOOST_AUTO_TEST_CASE(can_advance_lib_after_upgrade) { tester tester; - controller &ctrl = *tester.control.get(); + controller &ctrl = *tester.control; pbft_controller pbft_ctrl{ctrl}; ctrl.set_upo(150); @@ -130,7 +130,7 @@ BOOST_AUTO_TEST_CASE(can_advance_lib_after_upgrade) { BOOST_AUTO_TEST_CASE(can_advance_lib_after_upgrade_with_four_producers) { tester tester; - controller &ctrl = *tester.control.get(); + controller &ctrl = *tester.control; pbft_controller pbft_ctrl{ctrl}; ctrl.set_upo(109); @@ -229,11 +229,11 @@ BOOST_AUTO_TEST_CASE(view_change_validation) { BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_on_short_fork) { tester short_prepared_fork, long_non_prepared_fork, new_view_generator; - controller &ctrl_short_prepared_fork = *short_prepared_fork.control.get(); + controller &ctrl_short_prepared_fork = *short_prepared_fork.control; pbft_controller pbft_short_prepared_fork{ctrl_short_prepared_fork}; - controller &ctrl_long_non_prepared_fork = *long_non_prepared_fork.control.get(); + controller &ctrl_long_non_prepared_fork = *long_non_prepared_fork.control; pbft_controller pbft_long_non_prepared_fork{ctrl_long_non_prepared_fork}; - controller &ctrl_new_view_generator = *new_view_generator.control.get(); + controller &ctrl_new_view_generator = *new_view_generator.control; pbft_controller pbft_new_view_generator{ctrl_new_view_generator}; auto msp = make_signature_provider(); @@ -304,6 +304,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o //generate new view with short fork prepare certificate 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); + ctrl_new_view_generator.reset_pbft_my_prepare(); pbft_new_view_generator.maybe_pbft_prepare(); BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_prepared(), true); BOOST_CHECK_EQUAL(ctrl_new_view_generator.head_block_num(), 136); @@ -330,7 +331,8 @@ 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(std::make_shared>(nv_msg, ctrl_new_view_generator.get_chain_id())); + auto pmm = pbft_message_metadata(nv_msg, pbft_short_prepared_fork.pbft_db.get_chain_id()); + pbft_short_prepared_fork.on_pbft_new_view(std::make_shared>(pmm)); BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.head_block_num(), 136); BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.last_irreversible_block_num(), 101); From 20e08dbacb7b59e1760798e5ade18f4a330b3eb2 Mon Sep 17 00:00:00 2001 From: oldcold Date: Thu, 11 Jul 2019 18:20:25 +0800 Subject: [PATCH 04/37] optimise transit_to_new_view; optimise handle pbft messages; --- libraries/chain/pbft.cpp | 3 ++ libraries/chain/pbft_database.cpp | 2 - plugins/net_plugin/net_plugin.cpp | 69 ++++++++++++++++--------------- 3 files changed, 38 insertions(+), 36 deletions(-) diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 5679b332733..ccc5598dc63 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -456,6 +456,9 @@ namespace eosio { } } + if (pbft_db.should_committed()) { + pbft_db.commit_local(); + } transit_to_committed_state(s, true); } diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 10f05347f1c..3e2a71fd86f 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -849,8 +849,6 @@ 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(); diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 78402c21dd7..49eb8e9b191 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -263,14 +263,14 @@ namespace eosio { void pbft_outgoing_new_view(const pbft_new_view_ptr& new_view); void pbft_outgoing_checkpoint(const pbft_checkpoint_ptr& checkpoint); - void handle_message( const connection_ptr& c, pbft_prepare &msg); - void handle_message( const connection_ptr& c, pbft_commit &msg); - void handle_message( const connection_ptr& c, pbft_view_change &msg); - void handle_message( const connection_ptr& c, pbft_new_view &msg); - void handle_message( const connection_ptr& c, pbft_checkpoint &msg); - void handle_message( const connection_ptr& c, pbft_stable_checkpoint &msg); + void handle_message( const connection_ptr& c, const pbft_prepare &msg); + void handle_message( const connection_ptr& c, const pbft_commit &msg); + void handle_message( const connection_ptr& c, const pbft_view_change &msg); + void handle_message( const connection_ptr& c, const pbft_new_view &msg); + void handle_message( const connection_ptr& c, const pbft_checkpoint &msg); + void handle_message( const connection_ptr& c, const pbft_stable_checkpoint &msg); void handle_message( const connection_ptr& c, const checkpoint_request_message &msg); - void handle_message( const connection_ptr& c, compressed_pbft_message &msg); + void handle_message( const connection_ptr& c, const compressed_pbft_message &msg); void start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection); void start_txn_timer(); @@ -3102,15 +3102,16 @@ namespace eosio { } } - void net_plugin_impl::handle_message( const connection_ptr& c, pbft_prepare &msg) { + void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_prepare &msg) { - auto pmm = pbft_message_metadata(std::move(msg), chain_id); - - if (!is_pbft_msg_valid(pmm.msg)) return; + if (!is_pbft_msg_valid(msg)) return; - auto added = maybe_add_to_pbft_cache(std::string(pmm.msg.sender_signature)); + auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); if (!added) return; + auto pmm = pbft_message_metadata(std::move(msg), chain_id); + + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_prepare(pmm.msg, pmm.sender_key)) return; @@ -3120,15 +3121,15 @@ namespace eosio { pbft_incoming_prepare_channel.publish(std::make_shared>(std::move(pmm))); } - void net_plugin_impl::handle_message( const connection_ptr& c, pbft_commit &msg) { + void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_commit &msg) { - auto pmm = pbft_message_metadata(std::move(msg), chain_id); - if (!is_pbft_msg_valid(pmm.msg)) return; + if (!is_pbft_msg_valid(msg)) return; - auto added = maybe_add_to_pbft_cache(std::string(pmm.msg.sender_signature)); + auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); if (!added) return; + auto pmm = pbft_message_metadata(std::move(msg), chain_id); pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_commit(pmm.msg, pmm.sender_key)) return; @@ -3139,15 +3140,15 @@ namespace eosio { pbft_incoming_commit_channel.publish(std::make_shared>(std::move(pmm))); } - void net_plugin_impl::handle_message( const connection_ptr& c, pbft_view_change &msg) { + void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_view_change &msg) { - auto pmm = pbft_message_metadata( std::move(msg), chain_id); + if (!is_pbft_msg_valid(msg)) return; - if (!is_pbft_msg_valid(pmm.msg)) return; - - auto added = maybe_add_to_pbft_cache(std::string(pmm.msg.sender_signature)); + auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); if (!added) return; + auto pmm = pbft_message_metadata( std::move(msg), chain_id); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); controller &ctrl = my_impl->chain_plug->chain(); if (!pcc.pbft_db.is_valid_view_change(pmm.msg, pmm.sender_key)) return; @@ -3174,21 +3175,21 @@ namespace eosio { pbft_incoming_view_change_channel.publish(std::make_shared>(std::move(pmm))); } - void net_plugin_impl::handle_message( const connection_ptr& c, pbft_new_view &msg) { - - auto pmm = pbft_message_metadata(std::move(msg), chain_id); + void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_new_view &msg) { - auto added = maybe_add_to_pbft_cache(std::string(pmm.msg.sender_signature)); + 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 (time_point_sec(time_point::now()) > time_point_sec(pmm.msg.common.timestamp) + 60 * pbft_message_TTL - || pmm.msg.new_view <= pcc.state_machine->get_current_view()) { + if (time_point_sec(time_point::now()) > time_point_sec(msg.common.timestamp) + 60 * pbft_message_TTL + || msg.new_view <= pcc.state_machine->get_current_view()) { //skip new view messages that are too old or whose target views are lower than mine. return; } + auto pmm = pbft_message_metadata(std::move(msg), chain_id); + if (pmm.sender_key != pcc.pbft_db.get_new_view_primary_key(pmm.msg.new_view)) return; forward_pbft_msg(c, pmm.msg, INT_MAX); @@ -3197,7 +3198,7 @@ namespace eosio { pbft_incoming_new_view_channel.publish(std::make_shared>(std::move(pmm))); } - void net_plugin_impl::handle_message( const connection_ptr& c, compressed_pbft_message &msg) { + void net_plugin_impl::handle_message( const connection_ptr& c, const compressed_pbft_message &msg) { auto decompressed_msg = decompress_pbft(msg.content); @@ -3213,15 +3214,15 @@ namespace eosio { } } - void net_plugin_impl::handle_message( const connection_ptr& c, pbft_checkpoint &msg) { + void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_checkpoint &msg) { - auto pmm = pbft_message_metadata(std::move(msg), chain_id); - - if (!is_pbft_msg_valid(pmm.msg)) return; + if (!is_pbft_msg_valid(msg)) return; - auto added = maybe_add_to_pbft_cache(std::string(pmm.msg.sender_signature)); + auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); if (!added) return; + auto pmm = pbft_message_metadata(std::move(msg), chain_id); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_checkpoint(pmm.msg, pmm.sender_key)) return; @@ -3231,7 +3232,7 @@ namespace eosio { pbft_incoming_checkpoint_channel.publish(std::make_shared>(std::move(pmm))); } - void net_plugin_impl::handle_message( const connection_ptr& c, pbft_stable_checkpoint &msg) { + void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_stable_checkpoint &msg) { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); From f4c83c22b59078a7eb5d40273c432789224e44b5 Mon Sep 17 00:00:00 2001 From: oldcold Date: Fri, 12 Jul 2019 18:24:20 +0800 Subject: [PATCH 05/37] net_plugin revert. --- plugins/net_plugin/net_plugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 49eb8e9b191..529bd3ed900 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 || !conn->socket->is_open()) { + if(!conn->socket) { return; } connection_wptr weak_conn = conn; From 8916700639ef6d9f11944c0b776afd792554d05f Mon Sep 17 00:00:00 2001 From: Frank-AFN Date: Mon, 15 Jul 2019 17:37:50 +0800 Subject: [PATCH 06/37] Add: switch fork reserve prepare and fetch branch from function test case --- unittests/pbft_tests.cpp | 397 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 397 insertions(+) diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index a0c5e3b45be..ea0420c24a2 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -350,5 +350,402 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o } +private_key_type get_private_key( name keyname, string role ) { + return private_key_type::regenerate(fc::sha256::hash(string(keyname)+role)); +} + +public_key_type get_public_key( name keyname, string role ){ + return get_private_key( keyname, role ).get_public_key(); +} + +BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { + const char* curr_state; + tester c1, c2, c2_prime, c3, c3_final; + controller &c1_fork = *c1.control.get(); + pbft_controller c1_pbft_controller{c1_fork}; + controller &c2_fork = *c2.control.get(); + pbft_controller c2_pbft_controller{c2_fork}; + controller &c2_fork_prime = c2_fork; + pbft_controller c2_prime_pbft_controller{c2_fork_prime}; + controller &c3_fork = *c3.control.get(); + pbft_controller c3_pbft_controller{c3_fork}; + controller &c3_final_fork = *c3_final.control.get(); + pbft_controller c3_final_pbft_controller{c3_final_fork}; + + + c1_fork.set_upo(48); + c2_fork.set_upo(48); + c2_fork_prime.set_upo(48); + c3_fork.set_upo(48); + c3_final_fork.set_upo(48); + + /// c1 + c1.produce_block(); + c1.create_accounts( {N(alice), N(bob)} ); + c1.produce_block(); + + // make and get signature provider for c1 + std::map msp_c1; + auto priv_alice = tester::get_private_key( N(alice), "active" ); + auto pub_alice = tester::get_public_key( N(alice), "active"); + auto sp_alice = [priv_alice]( const eosio::chain::digest_type& digest ) { + return priv_alice.sign(digest); + }; + msp_c1[pub_alice]=sp_alice; + c1_fork.set_my_signature_providers(msp_c1); + + c1.set_producers( {N(alice), N(bob)} ); + + vector c1_sch = { {N(alice),get_public_key(N(alice), "active")} }; + + + /// c2 + c2.produce_block(); + c2.create_accounts( {N(alice), N(bob)} ); + c2.produce_block(); + + // make and get signature provider for c2 + std::map msp_c2; + msp_c2[pub_alice]=sp_alice; + + auto priv_bob = tester::get_private_key( N(bob), "active" ); + auto pub_bob = tester::get_public_key( N(bob), "active"); + auto sp_bob = [priv_bob]( const eosio::chain::digest_type& digest ) { + return priv_bob.sign(digest); + }; + msp_c2[pub_bob]=sp_bob; + c2_fork.set_my_signature_providers(msp_c2); + + c2.set_producers( {N(alice), N(bob)} ); + + vector c2_sch = { {N(alice),get_public_key(N(alice), "active")}, + {N(bob),get_public_key(N(bob), "active")}}; + + + c2.produce_blocks(95); + c2_pbft_controller.maybe_pbft_prepare(); + c2_pbft_controller.maybe_pbft_commit(); + c2.produce_block(); + BOOST_CHECK_EQUAL(c2.control->last_irreversible_block_num(), 98); + + + /// c3 + c3.produce_block(); + c3.create_accounts( {N(alice), N(bob)} ); + c3.produce_block(); + + // make and get signature provider for c3 + std::map msp_c3; + msp_c3[pub_bob]=sp_bob; + + c3_fork.set_my_signature_providers(msp_c3); + + c3.set_producers( {N(alice), N(bob)} ); + + vector c3_sch = { {N(bob),get_public_key(N(bob), "active")} }; + + /// c3 final + c3_final.produce_block(); + c3_final.create_accounts( {N(alice), N(bob)} ); + c3_final.produce_block(); + + // make and get signature provider for c3 + std::map msp_c3_final; + msp_c3_final[pub_bob]=sp_bob; + + c3_final_fork.set_my_signature_providers(msp_c3_final); + + c3_final.set_producers( {N(alice), N(bob)} ); + + vector c3_final_sch = { {N(bob),get_public_key(N(bob), "active")} }; + + push_blocks(c2, c3_final); + + + push_blocks(c2, c1); + /// make c1 lib 98 c3 lib 99 + c1_pbft_controller.maybe_pbft_prepare(); + pbft_prepare c2_prepare_ = c2_pbft_controller.state_machine->get_prepares_cache(); + // check c3 prepare at 63 + BOOST_CHECK_EQUAL(c2_prepare_.block_info.block_num(), 98); + c1_pbft_controller.state_machine->on_prepare(std::make_shared>(c2_prepare_, c2_pbft_controller.pbft_db.get_chain_id())); + c1_pbft_controller.maybe_pbft_commit(); + + pbft_commit c2_commit_ = c2_pbft_controller.state_machine->get_commits_cache(); + c1_pbft_controller.state_machine->on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); + c1.produce_block(); + c1_pbft_controller.maybe_pbft_commit(); + BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 98); + + c2_pbft_controller.maybe_pbft_commit(); + + /// make c3_final lib 98 + c3_final_pbft_controller.maybe_pbft_prepare(); + pbft_prepare c1_prepare_ = c1_pbft_controller.state_machine->get_prepares_cache(); + BOOST_CHECK_EQUAL(c1_prepare_.block_info.block_num(), 99); + c3_final_pbft_controller.state_machine->on_prepare(std::make_shared>(c1_prepare_, c1_pbft_controller.pbft_db.get_chain_id())); + c3_final_pbft_controller.maybe_pbft_commit(); + + pbft_commit c1_commit_ = c1_pbft_controller.state_machine->get_commits_cache(); + c3_final_pbft_controller.state_machine->on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); + c3_final.produce_block(); + c3_final_pbft_controller.maybe_pbft_commit(); + BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 98); + + // copy c2 to c2_prime + push_blocks(c2, c2_prime); + + /// make c3 as prepared + push_blocks(c2, c3); + c3_pbft_controller.maybe_pbft_prepare(); + pbft_prepare c1_prepare; + c1_prepare_ = c1_pbft_controller.state_machine->get_prepares_cache(); + c1_prepare = c1_prepare_; +// check c1 prepare at 99 + BOOST_CHECK_EQUAL(c1_prepare_.block_info.block_num(), 99); + c3_pbft_controller.state_machine->on_prepare(std::make_shared>(c1_prepare_, c1_pbft_controller.pbft_db.get_chain_id())); + curr_state = c3_pbft_controller.state_machine->get_current()->get_name(); + BOOST_CHECK_EQUAL(curr_state, "{==== PREPARED ====}"); + + /// for set pbft commit cache to 99 + c2.produce_block(); + + c2_pbft_controller.maybe_pbft_prepare(); + c2_prepare_ = c2_pbft_controller.state_machine->get_prepares_cache(); + BOOST_CHECK_EQUAL(c2_prepare_.block_info.block_num(), 99); + c2_pbft_controller.maybe_pbft_commit(); + c2.produce_block(); + c2_pbft_controller.maybe_pbft_commit(); + + c2_commit_ = c2_pbft_controller.state_machine->get_commits_cache(); + BOOST_CHECK_EQUAL(c2_commit_.block_info.block_num(), 99); + BOOST_CHECK_EQUAL(c2.control->last_irreversible_block_num(), 99); + + push_blocks(c2, c1); + c1_pbft_controller.maybe_pbft_prepare(); + c2_prepare_ = c2_pbft_controller.state_machine->get_prepares_cache(); + c1_pbft_controller.state_machine->on_prepare(std::make_shared>(c2_prepare_, c2_pbft_controller.pbft_db.get_chain_id())); + c1_pbft_controller.maybe_pbft_commit(); + c2_commit_ = c2_pbft_controller.state_machine->get_commits_cache(); + c1_pbft_controller.state_machine->on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); + c1.produce_block(); + c1_pbft_controller.maybe_pbft_commit(); + + c1_prepare_ = c1_pbft_controller.state_machine->get_prepares_cache(); + c1_commit_ = c1_pbft_controller.state_machine->get_commits_cache(); + BOOST_CHECK_EQUAL(c1_commit_.block_info.block_num(), 99); + BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 99); + + /// make c3 as committed + c3_pbft_controller.maybe_pbft_commit(); + c1_commit_ = c1_pbft_controller.state_machine->get_commits_cache(); + c3_pbft_controller.state_machine->on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); + c3.produce_block(); + c3_pbft_controller.maybe_pbft_commit(); + curr_state = c3_pbft_controller.state_machine->get_current()->get_name(); + BOOST_CHECK_EQUAL(curr_state, "{==== COMMITTED ====}"); + + BOOST_CHECK_EQUAL(c3.control->last_irreversible_block_num(), 99); + + + BOOST_CHECK_EQUAL(c2.control->head_block_num(), 101); + BOOST_CHECK_EQUAL(c3.control->head_block_num(), 100); + + c3.produce_block(); + c3_pbft_controller.maybe_pbft_prepare(); + c3_final_pbft_controller.maybe_pbft_prepare(); + c3.produce_block(); + + c3_final.produce_block(); + c3_final.produce_block(); + + // get c3 prepare and push to c1 + pbft_prepare c3_prepare = c3_pbft_controller.state_machine->get_prepares_cache(); + // check c3 prepare at 99 + BOOST_CHECK_EQUAL(c3_prepare.block_info.block_num(), 100); + BOOST_CHECK_EQUAL(c1_prepare.block_info.block_num(), 99); + + c3_final_fork.set_pbft_my_prepare(c3_prepare.block_info.block_id); + c3_final_pbft_controller.state_machine->on_prepare(std::make_shared>(c1_prepare, c1_pbft_controller.pbft_db.get_chain_id())); + + BOOST_CHECK_EQUAL(c3_final_fork.get_pbft_my_prepare(), c3_prepare.block_info.block_id); + + pbft_prepare c3_final_prepare = c3_final_pbft_controller.state_machine->get_prepares_cache(); + // check c3 prepare at 99 + BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 99); + curr_state = c3_final_pbft_controller.state_machine->get_current()->get_name(); + BOOST_CHECK_EQUAL(curr_state, "{==== PREPARED ====}"); + + + c3_final_pbft_controller.maybe_pbft_commit(); + + c2_prime.create_accounts({N(tester1)}); + c2_prime.produce_blocks(5); + + //push fork to c3 + for(int i = 100; i <= 104; i++) { + auto fb = c2_prime.control->fetch_block_by_number(i); + c3_final.push_block(fb); + } + + auto tmp_c2_prime_prepared_fork = c3_final.control->fork_db().get_block(c2_prime.control->get_block_id_for_num(100)); + auto tmp_c3_final_prepared_fork = c3_final.control->fork_db().get_block(c3_final.control->get_block_id_for_num(100)); + BOOST_CHECK_EQUAL(tmp_c3_final_prepared_fork->pbft_prepared, true); + BOOST_CHECK_EQUAL(tmp_c3_final_prepared_fork->pbft_my_prepare, true); + BOOST_CHECK_EQUAL(tmp_c2_prime_prepared_fork->pbft_prepared, true); + BOOST_CHECK_EQUAL(tmp_c2_prime_prepared_fork->pbft_my_prepare, true); + BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 98); + + BOOST_CHECK_EQUAL(c3_final.control->head_block_num(), 104); + + pbft_commit c3_commit = c3_pbft_controller.state_machine->get_commits_cache(); + BOOST_CHECK_EQUAL(c3_commit.block_info.block_num(), 99); + c3_final_pbft_controller.maybe_pbft_commit(); + c3_final.produce_block(); +// c3_final_pbft_controller.maybe_pbft_commit(); + pbft_commit c3_final_commit = c3_final_pbft_controller.state_machine->get_commits_cache(); + c3_final_pbft_controller.state_machine->on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); + // for sync + c3_final.produce_block(); + c3_final_pbft_controller.maybe_pbft_commit(); + curr_state = c3_final_pbft_controller.state_machine->get_current()->get_name(); + BOOST_CHECK_EQUAL(curr_state, "{==== COMMITTED ====}"); + BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 99); + + c3_final_pbft_controller.maybe_pbft_prepare(); + c3_final_prepare = c3_final_pbft_controller.state_machine->get_prepares_cache(); + BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 100); + +} + + +BOOST_AUTO_TEST_CASE(fetch_branch_from_block_at_same_fork_return_at_least_common_ancestor) { + //create forks + tester c; + c.produce_block(); + c.produce_block(); + auto r = c.create_accounts( {N(dan),N(sam),N(pam)} ); + wdump((fc::json::to_pretty_string(r))); + c.produce_block(); + auto res = c.set_producers( {N(dan),N(sam),N(pam)} ); + vector sch = { {N(dan),get_public_key(N(dan), "active")}, + {N(sam),get_public_key(N(sam), "active")}, + {N(pam),get_public_key(N(pam), "active")}}; + wdump((fc::json::to_pretty_string(res))); + wlog("set producer schedule to [dan,sam,pam]"); + c.produce_blocks(98); + + BOOST_CHECK_EQUAL(c.control->head_block_num(), 102); + + // first is low block number + auto first = c.control->get_block_id_for_num(100); + auto second = c.control->get_block_id_for_num(102); + auto result = c.control->fork_db().fetch_branch_from(first, second); + + BOOST_CHECK_EQUAL(result.first.size(), 1); + BOOST_CHECK_EQUAL(result.second.size(), 3); + + + // first is high block number + first = c.control->get_block_id_for_num(102); + second = c.control->get_block_id_for_num(99); + result = c.control->fork_db().fetch_branch_from(first, second); + + BOOST_CHECK_EQUAL(result.first.size(), 4); + BOOST_CHECK_EQUAL(result.second.size(), 1); + + BOOST_CHECK_EQUAL(result.first[result.first.size() - 1]->id, result.second[result.second.size() - 1]->id); +} + + +BOOST_AUTO_TEST_CASE(fetch_branch_from_block_at_same_block_return_at_least_common_ancestor) { + //create forks + tester c; + c.produce_block(); + c.produce_block(); + auto r = c.create_accounts( {N(dan),N(sam),N(pam)} ); + wdump((fc::json::to_pretty_string(r))); + c.produce_block(); + auto res = c.set_producers( {N(dan),N(sam),N(pam)} ); + vector sch = { {N(dan),get_public_key(N(dan), "active")}, + {N(sam),get_public_key(N(sam), "active")}, + {N(pam),get_public_key(N(pam), "active")}}; + wdump((fc::json::to_pretty_string(res))); + wlog("set producer schedule to [dan,sam,pam]"); + c.produce_blocks(98); + + BOOST_CHECK_EQUAL(c.control->head_block_num(), 102); + + // same block + auto first = c.control->get_block_id_for_num(102); + auto second = c.control->get_block_id_for_num(102); + auto result = c.control->fork_db().fetch_branch_from(first, second); + + // result two branch will only include one common_ancestor + BOOST_CHECK_EQUAL(result.first.size(), 1); + BOOST_CHECK_EQUAL(result.second.size(), 1); + + BOOST_CHECK_EQUAL(result.first[result.first.size() - 1]->id == result.second[result.second.size() - 1]->id, true); +} + + +BOOST_AUTO_TEST_CASE(fetch_branch_from_block_at_diffent_fork_return_without_common_ancestor) { + //create forks + tester c; + c.produce_block(); + c.produce_block(); + auto r = c.create_accounts( {N(dan),N(sam),N(pam)} ); + wdump((fc::json::to_pretty_string(r))); + c.produce_block(); + auto res = c.set_producers( {N(dan),N(sam),N(pam)} ); + vector sch = { {N(dan),get_public_key(N(dan), "active")}, + {N(sam),get_public_key(N(sam), "active")}, + {N(pam),get_public_key(N(pam), "active")}}; + wdump((fc::json::to_pretty_string(res))); + wlog("set producer schedule to [dan,sam,pam]"); + c.produce_blocks(98); + + tester c2; + c2.produce_block(); + c2.produce_block(); + c2.create_accounts( {N(dan),N(sam),N(pam)} ); + c2.produce_block(); + c2.set_producers( {N(dan),N(sam),N(pam)} ); + wlog("set producer schedule to [dan,sam,pam]"); + c2.produce_blocks(98); + + //check c2 98 c98 equal + + c.create_accounts({N(tester1)}); + c.produce_blocks(10); + c2.create_accounts({N(tester2)}); + c2.produce_blocks(1); + + auto c2_previous_fork_head_id = c2.control->get_block_id_for_num(103); + auto c2_tmp_102 = c2.control->get_block_id_for_num(102); + BOOST_CHECK_EQUAL(c2.control->head_block_num(), 103); + + // push this fork to c2 + for (int i = 103; i <= 104; i++) { + auto fb = c.control->fetch_block_by_number(i); + c2.push_block(fb); + } + + BOOST_CHECK_EQUAL(c2.control->head_block_num(), 104); + + + auto first = c2.control->get_block_id_for_num(103); + BOOST_CHECK_EQUAL(first!= c2_previous_fork_head_id, true); + BOOST_CHECK_EQUAL(c2.control->get_block_id_for_num(102) == c2_tmp_102, true); + auto result = c2.control->fork_db().fetch_branch_from(first, c2_previous_fork_head_id); + + // if first and second in different fork, the result two branch do not include common ancestor + BOOST_CHECK_EQUAL(result.first.size(), 1); + BOOST_CHECK_EQUAL(result.second.size(), 1); + + BOOST_CHECK_EQUAL(result.first[result.first.size() - 1]->id != result.second[result.second.size() - 1]->id, true); + BOOST_CHECK_EQUAL(result.first[result.first.size() - 1]->block_num, 103); + BOOST_CHECK_EQUAL(result.second[result.second.size() - 1]->block_num, 103); +} BOOST_AUTO_TEST_SUITE_END() From 02093537df9dc2ceb3ce72573a7ed33d54a14f23 Mon Sep 17 00:00:00 2001 From: Frank-AFN Date: Tue, 16 Jul 2019 11:43:49 +0800 Subject: [PATCH 07/37] Refactor reserve prepare testcase and Add two times maybe switch forks testcase for issue 114 in boscore --- unittests/pbft_tests.cpp | 198 ++++++++++++++++++++++++--------------- 1 file changed, 120 insertions(+), 78 deletions(-) diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index ea0420c24a2..f2d75c5a6e8 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -349,6 +349,102 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.last_irreversible_block_num(), 136); } +BOOST_AUTO_TEST_CASE(new_view_with_committed_cert_call_two_times_maybe_switch_forks) { + tester c1, new_view_generator; + controller &c1_ctrl = *c1.control.get(); + pbft_controller c1_pbft_controller{c1_ctrl}; + controller &ctrl_new_view_generator = *new_view_generator.control.get(); + pbft_controller pbft_new_view_generator{ctrl_new_view_generator}; + + auto msp = make_signature_provider(); + c1_ctrl.set_my_signature_providers(msp); + ctrl_new_view_generator.set_my_signature_providers(msp); + + c1_ctrl.set_upo(48); + ctrl_new_view_generator.set_upo(48); + + c1.create_accounts( {N(alice),N(bob),N(carol),N(deny)} ); + c1.set_producers({N(alice),N(bob),N(carol),N(deny)}); + c1.produce_blocks(100); + + new_view_generator.create_accounts( {N(alice),N(bob),N(carol),N(deny)} ); + new_view_generator.set_producers({N(alice),N(bob),N(carol),N(deny)}); + new_view_generator.produce_blocks(100); + + c1_pbft_controller.maybe_pbft_prepare(); + c1_pbft_controller.maybe_pbft_commit(); + c1.produce_blocks(1); + c1_pbft_controller.maybe_pbft_commit(); + c1.produce_blocks(25); + + pbft_new_view_generator.maybe_pbft_prepare(); + pbft_new_view_generator.maybe_pbft_commit(); + new_view_generator.produce_blocks(1); + pbft_new_view_generator.maybe_pbft_commit(); + new_view_generator.produce_blocks(25); + + BOOST_CHECK_EQUAL(ctrl_new_view_generator.head_block_num(), 127); + BOOST_CHECK_EQUAL(c1_ctrl.head_block_num(), 127); + BOOST_CHECK_EQUAL(ctrl_new_view_generator.last_irreversible_block_num(), 101); + BOOST_CHECK_EQUAL(c1_ctrl.last_irreversible_block_num(), 101); + + c1.create_accounts({N(shortname)}); + new_view_generator.create_accounts({N(longname)}); + c1.produce_blocks(6); + new_view_generator.produce_blocks(10); + + c1_pbft_controller.state_machine->set_prepares_cache(pbft_prepare()); + c1_ctrl.reset_pbft_my_prepare(); + c1_pbft_controller.maybe_pbft_prepare(); + c1.produce_block(); + + //merge short fork and long fork, make sure current head is short fork + for(int i=1;i<=10;i++){ + auto tmp = ctrl_new_view_generator.fetch_block_by_number(127+i); + c1.push_block(tmp); + } + BOOST_CHECK_EQUAL(c1_ctrl.head_block_num(), 134); + auto c1_my_prepare = c1_ctrl.get_pbft_my_prepare(); + auto c1_my_prepare_num = c1_ctrl.fork_db().get_block(c1_my_prepare)->block_num; + BOOST_CHECK_EQUAL(c1_my_prepare_num, 133); + + + //generate new view with long fork commit certificate + 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); + ctrl_new_view_generator.reset_pbft_my_prepare(); + pbft_new_view_generator.maybe_pbft_prepare(); + + auto pbft_new_view_prepare = ctrl_new_view_generator.get_pbft_my_prepare(); + auto pbft_new_view_prepare_num = ctrl_new_view_generator.fork_db().get_block(pbft_new_view_prepare)->block_num; + BOOST_CHECK_EQUAL(pbft_new_view_prepare_num, 137); + + BOOST_CHECK_EQUAL(ctrl_new_view_generator.head_block_num(), 137); + pbft_new_view_generator.maybe_pbft_commit(); + new_view_generator.produce_block(); + BOOST_CHECK_EQUAL(ctrl_new_view_generator.last_irreversible_block_num(), 137); + + for(int i = 0; ido_send_view_change(); + auto new_view = pbft_new_view_generator.pbft_db.get_proposed_new_view_num(); + auto vcc = pbft_new_view_generator.pbft_db.generate_view_changed_certificate(new_view); + auto nv_msg = pbft_new_view_generator.pbft_db.send_pbft_new_view(vcc, new_view); + + //can switch fork after apply prepare certificate in new view + auto pmm = pbft_message_metadata(nv_msg, c1_pbft_controller.pbft_db.get_chain_id()); + + /// boscore issue https://github.com/boscore/bos/issues/114. + /// It will never throw exception block_validate_exception, "next block must be in the future" in the version 20e08dba + c1_pbft_controller.on_pbft_new_view(std::make_shared>(pmm)); + c1_pbft_controller.maybe_pbft_commit(); + c1.produce_blocks(2); + BOOST_CHECK_EQUAL(c1_ctrl.last_irreversible_block_num(), 137); + // make sure commited block same with new view generator lib block + BOOST_CHECK_EQUAL(c1_ctrl.fetch_block_by_number(137)->id(), ctrl_new_view_generator.fetch_block_by_number(137)->id()); +} + private_key_type get_private_key( name keyname, string role ) { return private_key_type::regenerate(fc::sha256::hash(string(keyname)+role)); @@ -360,24 +456,21 @@ public_key_type get_public_key( name keyname, string role ){ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { const char* curr_state; - tester c1, c2, c2_prime, c3, c3_final; - controller &c1_fork = *c1.control.get(); - pbft_controller c1_pbft_controller{c1_fork}; - controller &c2_fork = *c2.control.get(); - pbft_controller c2_pbft_controller{c2_fork}; - controller &c2_fork_prime = c2_fork; - pbft_controller c2_prime_pbft_controller{c2_fork_prime}; - controller &c3_fork = *c3.control.get(); - pbft_controller c3_pbft_controller{c3_fork}; - controller &c3_final_fork = *c3_final.control.get(); - pbft_controller c3_final_pbft_controller{c3_final_fork}; - - - c1_fork.set_upo(48); - c2_fork.set_upo(48); - c2_fork_prime.set_upo(48); - c3_fork.set_upo(48); - c3_final_fork.set_upo(48); + tester c1, c2, c2_prime, c3_final; + controller &c1_ctrl = *c1.control.get(); /// only have signature Alice + pbft_controller c1_pbft_controller{c1_ctrl}; + controller &c2_ctrl = *c2.control.get(); /// have signature Alice and bob + pbft_controller c2_pbft_controller{c2_ctrl}; + controller &c2_ctrl_prime = c2_ctrl; /// for make fork + pbft_controller c2_prime_pbft_controller{c2_ctrl_prime}; + controller &c3_final_ctrl = *c3_final.control.get(); /// only have signature bob + pbft_controller c3_final_pbft_controller{c3_final_ctrl}; + + + c1_ctrl.set_upo(48); + c2_ctrl.set_upo(48); + c2_ctrl_prime.set_upo(48); + c3_final_ctrl.set_upo(48); /// c1 c1.produce_block(); @@ -392,7 +485,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { return priv_alice.sign(digest); }; msp_c1[pub_alice]=sp_alice; - c1_fork.set_my_signature_providers(msp_c1); + c1_ctrl.set_my_signature_providers(msp_c1); c1.set_producers( {N(alice), N(bob)} ); @@ -414,7 +507,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { return priv_bob.sign(digest); }; msp_c2[pub_bob]=sp_bob; - c2_fork.set_my_signature_providers(msp_c2); + c2_ctrl.set_my_signature_providers(msp_c2); c2.set_producers( {N(alice), N(bob)} ); @@ -428,32 +521,16 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c2.produce_block(); BOOST_CHECK_EQUAL(c2.control->last_irreversible_block_num(), 98); - - /// c3 - c3.produce_block(); - c3.create_accounts( {N(alice), N(bob)} ); - c3.produce_block(); - - // make and get signature provider for c3 - std::map msp_c3; - msp_c3[pub_bob]=sp_bob; - - c3_fork.set_my_signature_providers(msp_c3); - - c3.set_producers( {N(alice), N(bob)} ); - - vector c3_sch = { {N(bob),get_public_key(N(bob), "active")} }; - /// c3 final c3_final.produce_block(); c3_final.create_accounts( {N(alice), N(bob)} ); c3_final.produce_block(); - // make and get signature provider for c3 + // make and get signature provider for c3 final std::map msp_c3_final; msp_c3_final[pub_bob]=sp_bob; - c3_final_fork.set_my_signature_providers(msp_c3_final); + c3_final_ctrl.set_my_signature_providers(msp_c3_final); c3_final.set_producers( {N(alice), N(bob)} ); @@ -463,10 +540,9 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { push_blocks(c2, c1); - /// make c1 lib 98 c3 lib 99 + /// make c1 lib 98 c1_pbft_controller.maybe_pbft_prepare(); pbft_prepare c2_prepare_ = c2_pbft_controller.state_machine->get_prepares_cache(); - // check c3 prepare at 63 BOOST_CHECK_EQUAL(c2_prepare_.block_info.block_num(), 98); c1_pbft_controller.state_machine->on_prepare(std::make_shared>(c2_prepare_, c2_pbft_controller.pbft_db.get_chain_id())); c1_pbft_controller.maybe_pbft_commit(); @@ -495,17 +571,9 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { // copy c2 to c2_prime push_blocks(c2, c2_prime); - /// make c3 as prepared - push_blocks(c2, c3); - c3_pbft_controller.maybe_pbft_prepare(); pbft_prepare c1_prepare; c1_prepare_ = c1_pbft_controller.state_machine->get_prepares_cache(); c1_prepare = c1_prepare_; -// check c1 prepare at 99 - BOOST_CHECK_EQUAL(c1_prepare_.block_info.block_num(), 99); - c3_pbft_controller.state_machine->on_prepare(std::make_shared>(c1_prepare_, c1_pbft_controller.pbft_db.get_chain_id())); - curr_state = c3_pbft_controller.state_machine->get_current()->get_name(); - BOOST_CHECK_EQUAL(curr_state, "{==== PREPARED ====}"); /// for set pbft commit cache to 99 c2.produce_block(); @@ -536,40 +604,16 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { BOOST_CHECK_EQUAL(c1_commit_.block_info.block_num(), 99); BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 99); - /// make c3 as committed - c3_pbft_controller.maybe_pbft_commit(); - c1_commit_ = c1_pbft_controller.state_machine->get_commits_cache(); - c3_pbft_controller.state_machine->on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); - c3.produce_block(); - c3_pbft_controller.maybe_pbft_commit(); - curr_state = c3_pbft_controller.state_machine->get_current()->get_name(); - BOOST_CHECK_EQUAL(curr_state, "{==== COMMITTED ====}"); - - BOOST_CHECK_EQUAL(c3.control->last_irreversible_block_num(), 99); - - - BOOST_CHECK_EQUAL(c2.control->head_block_num(), 101); - BOOST_CHECK_EQUAL(c3.control->head_block_num(), 100); - - c3.produce_block(); - c3_pbft_controller.maybe_pbft_prepare(); c3_final_pbft_controller.maybe_pbft_prepare(); - c3.produce_block(); c3_final.produce_block(); c3_final.produce_block(); - // get c3 prepare and push to c1 - pbft_prepare c3_prepare = c3_pbft_controller.state_machine->get_prepares_cache(); - // check c3 prepare at 99 - BOOST_CHECK_EQUAL(c3_prepare.block_info.block_num(), 100); BOOST_CHECK_EQUAL(c1_prepare.block_info.block_num(), 99); - - c3_final_fork.set_pbft_my_prepare(c3_prepare.block_info.block_id); + /// set c3 my preprare at 100 + c3_final_ctrl.set_pbft_my_prepare(c3_final_ctrl.get_block_id_for_num(100)); c3_final_pbft_controller.state_machine->on_prepare(std::make_shared>(c1_prepare, c1_pbft_controller.pbft_db.get_chain_id())); - BOOST_CHECK_EQUAL(c3_final_fork.get_pbft_my_prepare(), c3_prepare.block_info.block_id); - pbft_prepare c3_final_prepare = c3_final_pbft_controller.state_machine->get_prepares_cache(); // check c3 prepare at 99 BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 99); @@ -582,7 +626,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c2_prime.create_accounts({N(tester1)}); c2_prime.produce_blocks(5); - //push fork to c3 + //push fork to c3_final for(int i = 100; i <= 104; i++) { auto fb = c2_prime.control->fetch_block_by_number(i); c3_final.push_block(fb); @@ -598,12 +642,10 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { BOOST_CHECK_EQUAL(c3_final.control->head_block_num(), 104); - pbft_commit c3_commit = c3_pbft_controller.state_machine->get_commits_cache(); - BOOST_CHECK_EQUAL(c3_commit.block_info.block_num(), 99); c3_final_pbft_controller.maybe_pbft_commit(); c3_final.produce_block(); -// c3_final_pbft_controller.maybe_pbft_commit(); pbft_commit c3_final_commit = c3_final_pbft_controller.state_machine->get_commits_cache(); + /// on commit will prepare next block immediately will trigger reserve prepare c3_final_pbft_controller.state_machine->on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); // for sync c3_final.produce_block(); From f47911cd9cdaca8043f2e224ba6f2d5380f49383 Mon Sep 17 00:00:00 2001 From: oldcold Date: Mon, 22 Jul 2019 11:46:48 +0800 Subject: [PATCH 08/37] optimise for return value. --- libraries/chain/block_header_state.cpp | 4 +- libraries/chain/controller.cpp | 10 +- libraries/chain/fork_database.cpp | 4 +- .../include/eosio/chain/fork_database.hpp | 4 +- libraries/chain/include/eosio/chain/pbft.hpp | 91 +++++---- .../include/eosio/chain/pbft_database.hpp | 102 +++++----- libraries/chain/pbft.cpp | 82 +------- libraries/chain/pbft_database.cpp | 189 +++++++++--------- plugins/net_plugin/net_plugin.cpp | 163 ++++----------- .../include/eosio/pbft_plugin/pbft_plugin.hpp | 6 +- plugins/pbft_plugin/pbft_plugin.cpp | 9 +- 11 files changed, 245 insertions(+), 419 deletions(-) diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index 690b10a947e..83e7c3292ad 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -158,7 +158,7 @@ namespace eosio { namespace chain { pending_schedule = *header.new_producers; pending_schedule_lib_num = block_num; } - + /** * Transitions the current header state into the next header state given the supplied signed block header. @@ -176,7 +176,7 @@ namespace eosio { namespace chain { EOS_ASSERT( h.previous == id, unlinkable_block_exception, "block must link to current state" ); auto result = generate_next( h.timestamp, pbft_enabled); EOS_ASSERT( result.header.producer == h.producer, wrong_producer, "wrong producer specified" ); - EOS_ASSERT( result.header.schedule_version == h.schedule_version, producer_schedule_exception, "schedule_version in signed block is corrupted" ); + EOS_ASSERT( result.header.schedule_version == h.schedule_version, producer_schedule_exception, "schedule_version in s igned block is corrupted" ); auto itr = producer_to_last_produced.find(h.producer); if( itr != producer_to_last_produced.end() ) { diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 2aa4644afb4..da23d6e193f 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -2526,13 +2526,15 @@ void controller::set_pbft_my_prepare(const block_id_type& id) { } block_id_type controller::get_pbft_prepared() const { - if (my->pbft_prepared) return my->pbft_prepared->id; - return block_id_type{}; + block_id_type pp; + if (my->pbft_prepared) pp = my->pbft_prepared->id; + return pp; } block_id_type controller::get_pbft_my_prepare() const { - if (my->my_prepare) return my->my_prepare->id; - return block_id_type{}; + block_id_type mp; + if (my->my_prepare) mp = my->my_prepare->id; + return mp; } void controller::reset_pbft_my_prepare() { diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index 2163a5a5960..be36a908895 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -525,7 +525,7 @@ namespace eosio { namespace chain { * * This will require a search over all forks */ - void fork_database::set_bft_irreversible( block_id_type id ) { + void fork_database::set_bft_irreversible( const block_id_type& id ) { auto b = get_block( id ); EOS_ASSERT( b, fork_db_block_not_found, "unable to find block id ${id}", ("id",id)); @@ -569,7 +569,7 @@ namespace eosio { namespace chain { my->head = *my->index.get().begin(); } - void fork_database::set_latest_checkpoint( block_id_type id) { + void fork_database::set_latest_checkpoint( const block_id_type& id) { auto b = get_block( id ); EOS_ASSERT( b, fork_db_block_not_found, "unable to find block id ${id}", ("id",id)); diff --git a/libraries/chain/include/eosio/chain/fork_database.hpp b/libraries/chain/include/eosio/chain/fork_database.hpp index 823c65c5b92..9dfb3f0cc9c 100644 --- a/libraries/chain/include/eosio/chain/fork_database.hpp +++ b/libraries/chain/include/eosio/chain/fork_database.hpp @@ -70,9 +70,9 @@ namespace eosio { namespace chain { */ signal irreversible; - void set_bft_irreversible( block_id_type id ); + void set_bft_irreversible( const block_id_type& id ); - void set_latest_checkpoint( block_id_type id); + void set_latest_checkpoint( const block_id_type& id); void mark_pbft_prepared_fork(const block_state_ptr& h); diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index 2bebe05cc79..e9e1d856dad 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -54,38 +54,37 @@ namespace eosio { void do_send_view_change(); bool maybe_new_view(const psm_state_ptr& s); - const pbft_prepare& get_prepares_cache() const; - void set_prepares_cache(const pbft_prepare &pcache); + const pbft_prepare& get_prepares_cache() const { return cache.prepares_cache; } + void set_prepares_cache(const pbft_prepare& pcache) { cache.prepares_cache = pcache; } - const pbft_commit& get_commits_cache() const; - void set_commits_cache(const pbft_commit &ccache); + const pbft_commit& get_commits_cache() const { return cache.commits_cache; } + void set_commits_cache(const pbft_commit& ccache) { cache.commits_cache = ccache; } - const pbft_view_change& get_view_changes_cache() const; - void set_view_changes_cache(const pbft_view_change &vc_cache); + const pbft_view_change& get_view_changes_cache() const { return cache.view_changes_cache; } + void set_view_changes_cache(const pbft_view_change& vc_cache) { cache.view_changes_cache = vc_cache; } - const uint32_t &get_current_view() const; - void set_current_view(const uint32_t &cv); + uint32_t get_current_view() const { return current_view; } + void set_current_view(uint32_t cv) { current_view = cv; } - const pbft_prepared_certificate& get_prepared_certificate() const; - void set_prepared_certificate(const pbft_prepared_certificate &pcert); + const pbft_prepared_certificate& get_prepared_certificate() const { return cache.prepared_certificate; } + void set_prepared_certificate(const pbft_prepared_certificate& pcert) { cache.prepared_certificate = pcert; } - const vector& get_committed_certificate() const; - void set_committed_certificate(const vector &ccert); + const vector& get_committed_certificate() const { return cache.committed_certificate; } + void set_committed_certificate(const vector& ccert) { cache.committed_certificate = ccert; } - const pbft_view_changed_certificate& get_view_changed_certificate() const; - void set_view_changed_certificate(const pbft_view_changed_certificate &vc_cert); + const pbft_view_changed_certificate& get_view_changed_certificate() const { return cache.view_changed_certificate; } + void set_view_changed_certificate(const pbft_view_changed_certificate& vc_cert) { cache.view_changed_certificate = vc_cert; } - const uint32_t& get_target_view_retries() const; - void set_target_view_retries(const uint32_t &tv_reties); + uint32_t get_target_view_retries() const { return target_view_retries; } + void set_target_view_retries(uint32_t tv_reties) { target_view_retries = tv_reties; } - const uint32_t& get_target_view() const; - void set_target_view(const uint32_t &tv); + uint32_t get_target_view() const { return target_view; } + void set_target_view(uint32_t tv) { target_view = tv; } - const uint32_t& get_view_change_timer() const; - void set_view_change_timer(const uint32_t &vc_timer); - - void manually_set_current_view(const uint32_t &cv); + uint32_t get_view_change_timer() const { return view_change_timer; } + void set_view_change_timer(uint32_t vc_timer) { view_change_timer = vc_timer; } + void manually_set_current_view(uint32_t cv); protected: psm_cache cache; uint32_t current_view; @@ -106,13 +105,13 @@ namespace eosio { psm_state(); ~psm_state(); - virtual void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) = 0; - virtual void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) = 0; - virtual void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) = 0; + virtual void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) = 0; + virtual void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) = 0; + virtual void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) = 0; - virtual void send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) = 0; - virtual void send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) = 0; - virtual void send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) = 0; + virtual void send_prepare(const psm_machine_ptr& m, pbft_database& pbft_db) = 0; + virtual void send_commit(const psm_machine_ptr& m, pbft_database& pbft_db) = 0; + virtual void send_view_change(const psm_machine_ptr& m, pbft_database& pbft_db) = 0; virtual const char* get_name() = 0; std::shared_ptr get_self() { return shared_from_this(); }; @@ -124,13 +123,13 @@ namespace eosio { psm_prepared_state(); ~psm_prepared_state(); - void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; + void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; + void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; + void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; - void send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) override; + void send_prepare(const psm_machine_ptr& m, pbft_database& pbft_db) override; + void send_commit(const psm_machine_ptr& m, pbft_database& pbft_db) override; + void send_view_change(const psm_machine_ptr& m, pbft_database& pbft_db) override; bool pending_commit_local; @@ -142,13 +141,13 @@ namespace eosio { psm_committed_state(); ~psm_committed_state(); - void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; + void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; + void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; + void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; - void send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) override; + void send_prepare(const psm_machine_ptr& m, pbft_database& pbft_db) override; + void send_commit(const psm_machine_ptr& m, pbft_database& pbft_db) override; + void send_view_change(const psm_machine_ptr& m, pbft_database& pbft_db) override; const char* get_name() override { return "{==== COMMITTED ====}"; } }; @@ -158,13 +157,13 @@ namespace eosio { psm_view_change_state(); ~psm_view_change_state(); - void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; + void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; + void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; + void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; - void send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) override; + void send_prepare(const psm_machine_ptr& m, pbft_database& pbft_db) override; + void send_commit(const psm_machine_ptr& m, pbft_database& pbft_db) override; + void send_view_change(const psm_machine_ptr& m, pbft_database& pbft_db) override; const char* get_name() override { return "{==== VIEW CHANGE ====}"; } }; diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index b72f9645b66..b571c96f420 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -37,11 +37,11 @@ namespace eosio { return fc::endian_reverse_u32(block_id._hash[0]); } - bool operator==(const block_info_type &rhs) const { + bool operator==(const block_info_type& rhs) const { return block_id == rhs.block_id; } - bool operator!=(const block_info_type &rhs) const { + bool operator!=(const block_info_type& rhs) const { return !(*this == rhs); } @@ -84,7 +84,7 @@ namespace eosio { block_info_type block_info; signature_type sender_signature; - bool operator<(const pbft_prepare &rhs) const { + bool operator<(const pbft_prepare& rhs) const { if (block_info.block_num() < rhs.block_info.block_num()) { return true; } else if (block_info.block_num() == rhs.block_info.block_num()) { @@ -120,7 +120,7 @@ namespace eosio { block_info_type block_info; signature_type sender_signature; - bool operator<(const pbft_commit &rhs) const { + bool operator<(const pbft_commit& rhs) const { if (block_info.block_num() < rhs.block_info.block_num()) { return true; } else if (block_info.block_num() == rhs.block_info.block_num()) { @@ -155,7 +155,7 @@ namespace eosio { block_info_type block_info; signature_type sender_signature; - bool operator<(const pbft_checkpoint &rhs) const { + bool operator<(const pbft_checkpoint& rhs) const { return block_info.block_num() < rhs.block_info.block_num(); } @@ -176,7 +176,7 @@ namespace eosio { block_info_type block_info; vector checkpoints; - bool operator<(const pbft_stable_checkpoint &rhs) const { + bool operator<(const pbft_stable_checkpoint& rhs) const { return block_info.block_num() < rhs.block_info.block_num(); } @@ -193,7 +193,7 @@ namespace eosio { set pre_prepares; vector prepares; - bool operator<(const pbft_prepared_certificate &rhs) const { + bool operator<(const pbft_prepared_certificate& rhs) const { return block_info.block_num() < rhs.block_info.block_num(); } @@ -209,7 +209,7 @@ namespace eosio { block_info_type block_info; vector commits; - bool operator<(const pbft_committed_certificate &rhs) const { + bool operator<(const pbft_committed_certificate& rhs) const { return block_info.block_num() < rhs.block_info.block_num(); } @@ -230,7 +230,7 @@ namespace eosio { pbft_stable_checkpoint stable_checkpoint; signature_type sender_signature; - bool operator<(const pbft_view_change &rhs) const { + bool operator<(const pbft_view_change& rhs) const { return target_view < rhs.target_view; } @@ -281,7 +281,7 @@ namespace eosio { pbft_view_changed_certificate view_changed_cert; signature_type sender_signature; - bool operator<(const pbft_new_view &rhs) const { + bool operator<(const pbft_new_view& rhs) const { return new_view < rhs.new_view; } @@ -415,27 +415,27 @@ namespace eosio { class pbft_database { public: - explicit pbft_database(controller &ctrl); + explicit pbft_database(controller& ctrl); ~pbft_database(); void close(); - void add_pbft_prepare(pbft_prepare &p, const public_key_type &pk); - void add_pbft_commit(pbft_commit &c, const public_key_type &pk); - void add_pbft_view_change(pbft_view_change &vc, const public_key_type &pk); - void add_pbft_checkpoint(pbft_checkpoint &cp, const public_key_type &pk); + void add_pbft_prepare(const pbft_prepare& p, const public_key_type& pk); + void add_pbft_commit(const pbft_commit& c, const public_key_type& pk); + void add_pbft_view_change(const pbft_view_change& vc, const public_key_type& pk); + void add_pbft_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk); - pbft_prepare send_and_add_pbft_prepare(const pbft_prepare &cached_prepare = pbft_prepare(), pbft_view_type current_view = 0); - pbft_commit send_and_add_pbft_commit(const pbft_commit &cached_commit = pbft_commit(), pbft_view_type current_view = 0); + pbft_prepare send_and_add_pbft_prepare(const pbft_prepare& cached_prepare = pbft_prepare(), pbft_view_type current_view = 0); + pbft_commit send_and_add_pbft_commit(const pbft_commit& cached_commit = pbft_commit(), pbft_view_type current_view = 0); pbft_view_change send_and_add_pbft_view_change( - const pbft_view_change &cached_view_change = pbft_view_change(), - const pbft_prepared_certificate &ppc = pbft_prepared_certificate(), - const vector &pcc = vector{}, + const pbft_view_change& cached_view_change = pbft_view_change(), + const pbft_prepared_certificate& ppc = pbft_prepared_certificate(), + const vector& pcc = vector{}, pbft_view_type current_view = 0, pbft_view_type target_view = 1); pbft_new_view send_pbft_new_view( - const pbft_view_changed_certificate &vcc = pbft_view_changed_certificate(), + const pbft_view_changed_certificate& vcc = pbft_view_changed_certificate(), pbft_view_type current_view = 1); vector generate_and_add_pbft_checkpoint(); void send_pbft_checkpoint(); @@ -446,13 +446,13 @@ namespace eosio { bool should_new_view(pbft_view_type target_view); //new view - bool has_new_primary(const public_key_type &pk); + bool has_new_primary(const public_key_type& pk); pbft_view_type get_proposed_new_view_num(); pbft_view_type get_committed_view(); public_key_type get_new_view_primary_key(pbft_view_type target_view); - void mark_as_prepared(const block_id_type &bid); - void mark_as_committed(const block_id_type &bid); + void mark_as_prepared(const block_id_type& bid); + void mark_as_committed(const block_id_type& bid); void commit_local(); void checkpoint_local(); @@ -460,43 +460,43 @@ namespace eosio { pbft_prepared_certificate generate_prepared_certificate(); vector generate_committed_certificate(); pbft_view_changed_certificate generate_view_changed_certificate(pbft_view_type target_view); - bool should_stop_view_change(const pbft_view_change &vc); + bool should_stop_view_change(const pbft_view_change& vc); //validations - bool is_valid_prepare(const pbft_prepare &p, const public_key_type &pk); - bool is_valid_commit(const pbft_commit &c, const public_key_type &pk); - bool is_valid_checkpoint(const pbft_checkpoint &cp, const public_key_type &pk); - bool is_valid_view_change(const pbft_view_change &vc, const public_key_type &pk); - void validate_new_view(const pbft_new_view &nv, const public_key_type &pk); - bool is_valid_stable_checkpoint(const pbft_stable_checkpoint &scp, bool add_to_pbft_db = false); + bool is_valid_prepare(const pbft_prepare& p, const public_key_type& pk); + bool is_valid_commit(const pbft_commit& c, const public_key_type& pk); + bool is_valid_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk); + bool is_valid_view_change(const pbft_view_change& vc, const public_key_type& pk); + void validate_new_view(const pbft_new_view& nv, const public_key_type& pk); + bool is_valid_stable_checkpoint(const pbft_stable_checkpoint& scp, bool add_to_pbft_db = false); bool should_send_pbft_msg(); - bool should_recv_pbft_msg(const public_key_type &pub_key); + bool should_recv_pbft_msg(const public_key_type& pub_key); bool pending_pbft_lib(); chain_id_type& get_chain_id() {return chain_id;} - pbft_stable_checkpoint get_stable_checkpoint_by_id(const block_id_type &block_id, bool incl_blk_extn = true); - pbft_stable_checkpoint fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr &b); + pbft_stable_checkpoint get_stable_checkpoint_by_id(const block_id_type& block_id, bool incl_blk_extn = true); + pbft_stable_checkpoint fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr& b); block_info_type cal_pending_stable_checkpoint() const; void cleanup_on_new_view(); void update_fork_schedules(); //api related - pbft_state_ptr get_pbft_state_by_id(const block_id_type &id) const; - vector get_checkpoints_by_num(const block_num_type &num) const; - pbft_view_change_state_ptr get_view_changes_by_target_view(const pbft_view_type &tv) const; + pbft_state_ptr get_pbft_state_by_id(const block_id_type& id) const; + vector get_checkpoints_by_num(block_num_type num) const; + pbft_view_change_state_ptr get_view_changes_by_target_view(pbft_view_type tv) const; vector get_pbft_watermarks() const; flat_map get_pbft_fork_schedules() const; - signal pbft_outgoing_prepare; - signal pbft_outgoing_commit; - signal pbft_outgoing_view_change; - signal pbft_outgoing_new_view; - signal pbft_outgoing_checkpoint; + signal pbft_outgoing_prepare; + signal pbft_outgoing_commit; + signal pbft_outgoing_view_change; + signal pbft_outgoing_new_view; + signal pbft_outgoing_checkpoint; private: - controller &ctrl; + controller& ctrl; pbft_state_multi_index_type pbft_state_index; pbft_view_state_multi_index_type view_state_index; pbft_checkpoint_state_multi_index_type checkpoint_index; @@ -507,26 +507,26 @@ namespace eosio { chain_id_type chain_id = ctrl.get_chain_id(); - bool is_less_than_high_watermark(const block_num_type &bnum); - bool is_valid_prepared_certificate(const pbft_prepared_certificate &certificate, bool add_to_pbft_db = false); - bool is_valid_committed_certificate(const pbft_committed_certificate &certificate, bool add_to_pbft_db = false); - bool is_valid_longest_fork(const block_info_type &bi, vector block_infos, unsigned long threshold, unsigned long non_fork_bp_count); + bool is_less_than_high_watermark(block_num_type bnum); + bool is_valid_prepared_certificate(const pbft_prepared_certificate& certificate, bool add_to_pbft_db = false); + bool is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db = false); + bool is_valid_longest_fork(const block_info_type& bi, vector block_infos, unsigned long threshold, unsigned long non_fork_bp_count); producer_schedule_type lscb_active_producers() const; vector& get_updated_watermarks(); flat_map& get_updated_fork_schedules(); block_num_type get_current_pbft_watermark(); - vector> fetch_fork_from(vector &block_infos); - vector fetch_first_fork_from(vector &bi); + vector> fetch_fork_from(vector& block_infos); + vector fetch_first_fork_from(vector& bi); template void emit(const Signal &s, Arg &&a); void set(const pbft_state_ptr& s); void set(const pbft_checkpoint_state_ptr& s); - void prune(const pbft_state_ptr &h); - void prune(const pbft_checkpoint_state_ptr &h); + void prune(const pbft_state_ptr& h); + void prune(const pbft_checkpoint_state_ptr& h); }; } } /// namespace eosio::chain diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index ccc5598dc63..2c510ef6512 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -154,7 +154,7 @@ namespace eosio { } } - void psm_machine::manually_set_current_view(const uint32_t &cv) { + void psm_machine::manually_set_current_view(uint32_t cv) { set_current_view(cv); set_target_view(cv + 1); transit_to_view_change_state(current); @@ -493,85 +493,5 @@ namespace eosio { set_view_changes_cache(view_changes); } } - - const pbft_prepare& psm_machine::get_prepares_cache() const { - return cache.prepares_cache; - } - - void psm_machine::set_prepares_cache(const pbft_prepare &pcache) { - cache.prepares_cache = pcache; - } - - const pbft_commit& psm_machine::get_commits_cache() const { - return cache.commits_cache; - } - - void psm_machine::set_commits_cache(const pbft_commit &ccache) { - cache.commits_cache = ccache; - } - - const pbft_view_change& psm_machine::get_view_changes_cache() const { - return cache.view_changes_cache; - } - - void psm_machine::set_view_changes_cache(const pbft_view_change &vc_cache) { - cache.view_changes_cache = vc_cache; - } - - const uint32_t& psm_machine::get_current_view() const { - return current_view; - } - - void psm_machine::set_current_view(const uint32_t &cv) { - current_view = cv; - } - - const pbft_prepared_certificate& psm_machine::get_prepared_certificate() const { - return cache.prepared_certificate; - } - - void psm_machine::set_prepared_certificate(const pbft_prepared_certificate &pcert) { - cache.prepared_certificate = pcert; - } - - const vector& psm_machine::get_committed_certificate() const { - return cache.committed_certificate; - } - - void psm_machine::set_committed_certificate(const vector &ccert) { - cache.committed_certificate = ccert; - } - - const pbft_view_changed_certificate& psm_machine::get_view_changed_certificate() const { - return cache.view_changed_certificate; - } - - void psm_machine::set_view_changed_certificate(const pbft_view_changed_certificate &vc_cert) { - cache.view_changed_certificate = vc_cert; - } - - const uint32_t& psm_machine::get_target_view_retries() const { - return target_view_retries; - } - - void psm_machine::set_target_view_retries(const uint32_t &tv_reties) { - target_view_retries = tv_reties; - } - - const uint32_t& psm_machine::get_target_view() const { - return target_view; - } - - void psm_machine::set_target_view(const uint32_t &tv) { - target_view = tv; - } - - const uint32_t& psm_machine::get_view_change_timer() const { - return view_change_timer; - } - - void psm_machine::set_view_change_timer(const uint32_t &vc_timer) { - view_change_timer = vc_timer; - } } } \ No newline at end of file diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 3e2a71fd86f..f915e100383 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -6,8 +6,7 @@ namespace eosio { namespace chain { - pbft_database::pbft_database(controller &ctrl) : - ctrl(ctrl) { + pbft_database::pbft_database(controller& ctrl) :ctrl(ctrl) { checkpoint_index = pbft_checkpoint_state_multi_index_type(); view_state_index = pbft_view_state_multi_index_type(); prepare_watermarks = vector{}; @@ -93,7 +92,7 @@ namespace eosio { close(); } - void pbft_database::add_pbft_prepare(pbft_prepare &p, const public_key_type &pk) { + void pbft_database::add_pbft_prepare(const pbft_prepare& p, const public_key_type& pk) { auto &by_block_id_index = pbft_state_index.get(); @@ -118,7 +117,7 @@ namespace eosio { } else { auto prepares = (*curr_itr)->prepares; if (prepares.find(std::make_pair(p.view, pk)) == prepares.end()) { - by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr &psp) { + by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr& psp) { psp->prepares[std::make_pair(p.view, pk)] = p; }); } @@ -151,7 +150,7 @@ namespace eosio { } } - void pbft_database::mark_as_prepared(const block_id_type &bid) { + void pbft_database::mark_as_prepared(const block_id_type& bid) { auto &by_block_id_index = pbft_state_index.get(); auto itr = by_block_id_index.find(bid); auto bnum = block_info_type{bid}.block_num(); @@ -165,17 +164,17 @@ namespace eosio { pbft_state_index.insert(psp); return; } - by_block_id_index.modify(itr, [&](const pbft_state_ptr &p) { p->is_prepared = true; }); + by_block_id_index.modify(itr, [&](const pbft_state_ptr& p) { p->is_prepared = true; }); } - pbft_prepare pbft_database::send_and_add_pbft_prepare(const pbft_prepare &cached_prepare, pbft_view_type current_view) { - auto prepare_to_be_cached = pbft_prepare(); + pbft_prepare pbft_database::send_and_add_pbft_prepare(const pbft_prepare& cached_prepare, pbft_view_type current_view) { + pbft_prepare prepare_to_be_cached; auto head_block_num = ctrl.head_block_num(); if (head_block_num <= 1) return prepare_to_be_cached; auto my_prepare = ctrl.get_pbft_my_prepare(); - auto reserve_prepare = [&](const block_id_type &in) { + auto reserve_prepare = [&](const block_id_type& in) { if (in == block_id_type() || !ctrl.fetch_block_state_by_id(in)) return false; auto lib = ctrl.last_irreversible_block_id(); if (lib == block_id_type()) return true; @@ -195,7 +194,6 @@ namespace eosio { retry_p.sender_signature = sp.second(retry_p.digest(chain_id)); emit(pbft_outgoing_prepare, std::make_shared(retry_p)); } - return prepare_to_be_cached; } else if (reserve_prepare(my_prepare)) { for (auto const &sp : ctrl.my_signature_providers()) { pbft_prepare reserve_p; @@ -204,7 +202,6 @@ namespace eosio { emit(pbft_outgoing_prepare, std::make_shared(reserve_p)); if (prepare_to_be_cached.empty()) prepare_to_be_cached = reserve_p; } - return prepare_to_be_cached; } else { auto current_watermark = get_current_pbft_watermark(); @@ -233,8 +230,8 @@ namespace eosio { } if (sent) ctrl.set_pbft_my_prepare(hwbs->id); } - return prepare_to_be_cached; } + return prepare_to_be_cached; } bool pbft_database::should_prepared() { @@ -252,13 +249,13 @@ namespace eosio { return false; } - bool pbft_database::is_valid_prepare(const pbft_prepare &p, const public_key_type &pk) { + bool pbft_database::is_valid_prepare(const pbft_prepare& p, const public_key_type& pk) { // a prepare msg under lscb (which is no longer in fork_db), can be treated as null, thus true. if (p.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) return true; return should_recv_pbft_msg(pk); } - void pbft_database::add_pbft_commit(pbft_commit &c, const public_key_type &pk) { + void pbft_database::add_pbft_commit(const pbft_commit& c, const public_key_type& pk) { auto &by_block_id_index = pbft_state_index.get(); @@ -284,7 +281,7 @@ namespace eosio { } else { auto commits = (*curr_itr)->commits; if (commits.find(std::make_pair(c.view, pk)) == commits.end()) { - by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr &psp) { + by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr& psp) { psp->commits[std::make_pair(c.view, pk)] = c; std::sort(psp->commits.begin(), psp->commits.end(), less<>()); }); @@ -321,8 +318,8 @@ namespace eosio { } } - pbft_commit pbft_database::send_and_add_pbft_commit(const pbft_commit &cached_commit, pbft_view_type current_view) { - auto commit_to_be_cached = pbft_commit(); + pbft_commit pbft_database::send_and_add_pbft_commit(const pbft_commit& cached_commit, pbft_view_type current_view) { + pbft_commit commit_to_be_cached; if (!cached_commit.empty()) { for (auto const &sp : ctrl.my_signature_providers()) { @@ -332,7 +329,6 @@ namespace eosio { retry_c.sender_signature = sp.second(retry_c.digest(chain_id)); emit(pbft_outgoing_commit, std::make_shared(retry_c)); } - return commit_to_be_cached; } else { auto const &by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); @@ -357,15 +353,15 @@ namespace eosio { } } } - return commit_to_be_cached; } + return commit_to_be_cached; } - void pbft_database::mark_as_committed(const block_id_type &bid) { + void pbft_database::mark_as_committed(const block_id_type& bid) { auto &by_block_id_index = pbft_state_index.get(); auto itr = by_block_id_index.find(bid); if (itr == by_block_id_index.end()) return; - by_block_id_index.modify(itr, [&](const pbft_state_ptr &p) { p->is_committed = true; }); + by_block_id_index.modify(itr, [&](const pbft_state_ptr& p) { p->is_committed = true; }); } bool pbft_database::should_committed() { @@ -412,7 +408,7 @@ namespace eosio { return new_view; } - bool pbft_database::is_valid_commit(const pbft_commit &c, const public_key_type &pk) { + bool pbft_database::is_valid_commit(const pbft_commit& c, const public_key_type& pk) { if (c.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) return true; return should_recv_pbft_msg(pk); } @@ -431,7 +427,7 @@ namespace eosio { return ctrl.pending_pbft_lib(); } - void pbft_database::add_pbft_view_change(pbft_view_change &vc, const public_key_type &pk) { + void pbft_database::add_pbft_view_change(const pbft_view_change& vc, const public_key_type& pk) { auto lscb_bps = lscb_active_producers().producers; @@ -450,7 +446,7 @@ namespace eosio { auto view_changes = pvs->view_changes; if (view_changes.find(pk) == view_changes.end()) { - by_view_index.modify(itr, [&](const pbft_view_change_state_ptr &pvsp) { + by_view_index.modify(itr, [&](const pbft_view_change_state_ptr& pvsp) { pvsp->view_changes[pk] = vc; }); } @@ -470,7 +466,7 @@ namespace eosio { } } if (vc_count >= threshold) { - by_view_index.modify(itr, [&](const pbft_view_change_state_ptr &pvsp) { pvsp->is_view_changed = true; }); + by_view_index.modify(itr, [&](const pbft_view_change_state_ptr& pvsp) { pvsp->is_view_changed = true; }); } } } @@ -502,13 +498,13 @@ namespace eosio { } pbft_view_change pbft_database::send_and_add_pbft_view_change( - const pbft_view_change &cached_view_change, - const pbft_prepared_certificate &ppc, - const vector &pcc, + const pbft_view_change& cached_view_change, + const pbft_prepared_certificate& ppc, + const vector& pcc, pbft_view_type current_view, pbft_view_type target_view) { - auto view_change_to_be_cached = pbft_view_change(); + pbft_view_change view_change_to_be_cached; if (!cached_view_change.empty()) { for (auto const &sp : ctrl.my_signature_providers()) { //sign again, update cache, then emit @@ -517,7 +513,6 @@ namespace eosio { retry_vc.sender_signature = sp.second(retry_vc.digest(chain_id)); emit(pbft_outgoing_view_change, std::make_shared(retry_vc)); } - return view_change_to_be_cached; } else { for (auto const &my_sp : ctrl.my_signature_providers()) { @@ -536,11 +531,11 @@ namespace eosio { if (view_change_to_be_cached.empty()) view_change_to_be_cached = new_vc; } } - return view_change_to_be_cached; } + return view_change_to_be_cached; } - bool pbft_database::should_new_view(const pbft_view_type target_view) { + bool pbft_database::should_new_view(pbft_view_type target_view) { auto &by_view_index = view_state_index.get(); auto itr = by_view_index.find(target_view); if (itr == by_view_index.end()) return false; @@ -554,7 +549,7 @@ namespace eosio { return (*itr)->view; } - bool pbft_database::has_new_primary(const public_key_type &pk) { + bool pbft_database::has_new_primary(const public_key_type& pk) { if (pk == public_key_type()) return false; auto sps = ctrl.my_signature_providers(); @@ -568,11 +563,13 @@ namespace eosio { } pbft_new_view pbft_database::send_pbft_new_view( - const pbft_view_changed_certificate &vcc, + const pbft_view_changed_certificate& vcc, pbft_view_type current_view) { + pbft_new_view nv; + auto primary_key = get_new_view_primary_key(current_view); - if (!has_new_primary(primary_key) || vcc.empty()) return pbft_new_view(); + if (!has_new_primary(primary_key) || vcc.empty()) return nv; //`sp_itr` is not possible to be the end iterator, since it's already been checked in `has_new_primary`. auto my_sps = ctrl.my_signature_providers(); @@ -589,7 +586,7 @@ namespace eosio { for (auto const &cc: vc.committed_certs) { auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), - [&](const pbft_committed_certificate &ext) { return ext.block_info.block_id == cc.block_info.block_id; }); + [&](const pbft_committed_certificate& ext) { return ext.block_info.block_id == cc.block_info.block_id; }); if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); } @@ -598,7 +595,6 @@ namespace eosio { } } - pbft_new_view nv; nv.new_view=current_view; nv.prepared_cert=highest_ppc; nv.committed_certs=highest_pcc; @@ -608,22 +604,24 @@ namespace eosio { try { validate_new_view(nv, sp_itr->first); emit(pbft_outgoing_new_view, std::make_shared(nv)); - return nv; } catch (const fc::exception& ex) { elog("bad new view, ${s} ", ("s", ex.to_string())); - return pbft_new_view(); + nv = pbft_new_view(); } + return nv; } pbft_prepared_certificate pbft_database::generate_prepared_certificate() { + pbft_prepared_certificate ppc; + auto const &by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); - if (itr == by_prepare_and_num_index.end()) return pbft_prepared_certificate(); + if (itr == by_prepare_and_num_index.end()) return ppc; pbft_state_ptr psp = *itr; auto prepared_block_state = ctrl.fetch_block_state_by_id(psp->block_id); - if (!prepared_block_state) return pbft_prepared_certificate(); + if (!prepared_block_state) return ppc; auto as = prepared_block_state->active_schedule.producers; if (psp->is_prepared && psp->block_num > ctrl.last_irreversible_block_num()) { @@ -651,24 +649,23 @@ namespace eosio { } } - if (valid_prepares.empty()) return pbft_prepared_certificate(); + if (valid_prepares.empty()) return ppc; - pbft_prepared_certificate pc; - pc.block_info={psp->block_id}; pc.prepares=valid_prepares; pc.pre_prepares.emplace(psp->block_id); + ppc.block_info={psp->block_id}; ppc.prepares=valid_prepares; ppc.pre_prepares.emplace(psp->block_id); for (auto const &p: valid_prepares) { auto bid = p.block_info.block_id; while (bid != psp->block_id) { - pc.pre_prepares.emplace(bid); + ppc.pre_prepares.emplace(bid); bid = ctrl.fetch_block_state_by_id(bid)->prev(); } } - return pc; - } else return pbft_prepared_certificate(); + } + return ppc; } vector pbft_database::generate_committed_certificate() { - auto pcc = vector{}; + vector pcc{}; auto const &by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); @@ -748,7 +745,7 @@ namespace eosio { pbft_view_changed_certificate pbft_database::generate_view_changed_certificate(pbft_view_type target_view) { - auto pvcc = pbft_view_changed_certificate(); + pbft_view_changed_certificate pvcc; auto &by_view_index = view_state_index.get(); auto itr = by_view_index.find(target_view); @@ -757,19 +754,18 @@ namespace eosio { auto pvs = *itr; if (pvs->is_view_changed) { - pvcc.target_view=pvs->view; pvcc.view_changes.reserve(pvs->view_changes.size()); for(auto & view_change : pvs->view_changes) { pvcc.view_changes.emplace_back( view_change.second ); } - return pvcc; - } else return pvcc; + } + return pvcc; } - bool pbft_database::is_valid_prepared_certificate(const pbft_prepared_certificate &certificate, bool add_to_pbft_db) { + bool pbft_database::is_valid_prepared_certificate(const pbft_prepared_certificate& certificate, bool add_to_pbft_db) { // an empty certificate is valid since it acts as a null digest in pbft. if (certificate.empty()) return true; // a certificate under lscb (no longer in fork_db) is also treated as null. @@ -832,7 +828,7 @@ namespace eosio { return is_valid_longest_fork(certificate.block_info, prepare_infos, bp_threshold, non_fork_bp_count); } - bool pbft_database::is_valid_committed_certificate(const pbft_committed_certificate &certificate, bool add_to_pbft_db) { + bool pbft_database::is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db) { // an empty certificate is valid since it acts as a null digest in pbft. if (certificate.empty()) return true; // a certificate under lscb (no longer in fork_db) is also treated as null. @@ -895,14 +891,14 @@ namespace eosio { return is_valid_longest_fork(certificate.block_info, commit_infos, bp_threshold, non_fork_bp_count); } - bool pbft_database::is_valid_view_change(const pbft_view_change &vc, const public_key_type &pk) { + bool pbft_database::is_valid_view_change(const pbft_view_change& vc, const public_key_type& pk) { return should_recv_pbft_msg(pk); // No need to check prepared cert and stable checkpoint, until generate or validate a new view msg } - void pbft_database::validate_new_view(const pbft_new_view &nv, const public_key_type &pk) { + void pbft_database::validate_new_view(const pbft_new_view& nv, const public_key_type& pk) { EOS_ASSERT(pk == get_new_view_primary_key(nv.new_view), pbft_exception, "new view is not signed with expected key"); @@ -1001,13 +997,13 @@ namespace eosio { ("hpcc", highest_scp)("pc", nv.stable_checkpoint)); } - bool pbft_database::should_stop_view_change(const pbft_view_change &vc) { + bool pbft_database::should_stop_view_change(const pbft_view_change& vc) { auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto vc_lscb = vc.stable_checkpoint.block_info.block_num(); return vc_lscb > 0 && lscb_num > vc_lscb; } - vector> pbft_database::fetch_fork_from(vector &block_infos) { + vector> pbft_database::fetch_fork_from(vector& block_infos) { vector> result; if (block_infos.empty()) { @@ -1019,7 +1015,7 @@ namespace eosio { } sort(block_infos.begin(), block_infos.end(), - [](const block_info_type &a, const block_info_type &b) -> bool { return a.block_num() > b.block_num(); }); + [](const block_info_type& a, const block_info_type& b) -> bool { return a.block_num() > b.block_num(); }); while (!block_infos.empty()) { auto fork = fetch_first_fork_from(block_infos); @@ -1030,7 +1026,7 @@ namespace eosio { return result; } - vector pbft_database::fetch_first_fork_from(vector &bi) { + vector pbft_database::fetch_first_fork_from(vector& bi) { vector result; if (bi.empty()) { return result; @@ -1071,7 +1067,7 @@ namespace eosio { return result; } - bool pbft_database::is_valid_longest_fork(const block_info_type &bi, vector block_infos, unsigned long threshold, unsigned long non_fork_bp_count) { + bool pbft_database::is_valid_longest_fork(const block_info_type& bi, vector block_infos, unsigned long threshold, unsigned long non_fork_bp_count) { auto forks = fetch_fork_from(block_infos); vector longest_fork; @@ -1089,7 +1085,9 @@ namespace eosio { return bi.block_id == calculated_block_info.block_id; } - pbft_stable_checkpoint pbft_database::fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr &b) { + pbft_stable_checkpoint pbft_database::fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr& b) { + + pbft_stable_checkpoint psc; try { if (b) { auto &extn = b->block_extensions; @@ -1098,12 +1096,10 @@ namespace eosio { if (it->first == static_cast(block_extension_type::pbft_stable_checkpoint)) { auto scp_ds = it->second; fc::datastream ds(scp_ds.data(), scp_ds.size()); + fc::raw::unpack(ds, psc); - pbft_stable_checkpoint scp; - fc::raw::unpack(ds, scp); - - if (is_valid_stable_checkpoint(scp)) { - return scp; + if (is_valid_stable_checkpoint(psc)) { + return psc; } else { it = extn.erase(it); } @@ -1114,32 +1110,34 @@ namespace eosio { } } catch(...) { elog("no stable checkpoints found in the block extension"); + psc = pbft_stable_checkpoint(); } - return pbft_stable_checkpoint(); + return psc; } - pbft_stable_checkpoint pbft_database::get_stable_checkpoint_by_id(const block_id_type &block_id, bool incl_blk_extn ) { + pbft_stable_checkpoint pbft_database::get_stable_checkpoint_by_id(const block_id_type& block_id, bool incl_blk_extn ) { + pbft_stable_checkpoint psc; auto const &by_block = checkpoint_index.get(); auto itr = by_block.find(block_id); if (itr == by_block.end()) { if (incl_blk_extn) { auto blk = ctrl.fetch_block_by_id(block_id); - return fetch_stable_checkpoint_from_blk_extn(blk); + psc = fetch_stable_checkpoint_from_blk_extn(blk); } - return pbft_stable_checkpoint(); + return psc; } auto cpp = *itr; if (cpp->is_stable) { - pbft_stable_checkpoint psc; psc.block_info={cpp->block_id}; psc.checkpoints.reserve(cpp->checkpoints.size()); for (auto & checkpoint : cpp->checkpoints) { psc.checkpoints.emplace_back(checkpoint.second) ; } - return psc; - } else return pbft_stable_checkpoint(); + + } + return psc; } block_info_type pbft_database::cal_pending_stable_checkpoint() const { @@ -1193,7 +1191,7 @@ namespace eosio { } vector pbft_database::generate_and_add_pbft_checkpoint() { - auto checkpoint = [&](const block_num_type &in) { + auto checkpoint = [&](const block_num_type& in) { auto const& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; if (!ctrl.is_pbft_enabled()) return false; if (in <= ucb) return false; @@ -1203,7 +1201,7 @@ namespace eosio { || std::find(watermarks.begin(), watermarks.end(), in) != watermarks.end(); // checkpoint on bp schedule change; }; - auto new_pc = vector{}; + vector new_pc{}; auto const &by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); @@ -1263,7 +1261,7 @@ namespace eosio { return new_pc; } - void pbft_database::add_pbft_checkpoint(pbft_checkpoint &cp, const public_key_type &pk) { + void pbft_database::add_pbft_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk) { auto cp_block_state = ctrl.fetch_block_state_by_id(cp.block_info.block_id); if (!cp_block_state) return; @@ -1284,7 +1282,7 @@ namespace eosio { auto csp = (*itr); auto checkpoints = csp->checkpoints; if (checkpoints.find(pk) == checkpoints.end()) { - by_block.modify(itr, [&](const pbft_checkpoint_state_ptr &pcp) { + by_block.modify(itr, [&](const pbft_checkpoint_state_ptr& pcp) { csp->checkpoints[pk] = cp; }); } @@ -1302,7 +1300,7 @@ namespace eosio { } } if (cp_count >= threshold) { - by_block.modify(itr, [&](const pbft_checkpoint_state_ptr &pcp) { csp->is_stable = true; }); + by_block.modify(itr, [&](const pbft_checkpoint_state_ptr& pcp) { csp->is_stable = true; }); auto id = csp->block_id; auto blk = ctrl.fetch_block_by_id(id); @@ -1354,7 +1352,7 @@ namespace eosio { } } - bool pbft_database::is_valid_checkpoint(const pbft_checkpoint &cp, const public_key_type &pk) { + bool pbft_database::is_valid_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk) { if (cp.block_info.block_num() > ctrl.head_block_num() || cp.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) return false; @@ -1367,7 +1365,7 @@ namespace eosio { return false; } - bool pbft_database::is_valid_stable_checkpoint(const pbft_stable_checkpoint &scp, bool add_to_pbft_db) { + bool pbft_database::is_valid_stable_checkpoint(const pbft_stable_checkpoint& scp, bool add_to_pbft_db) { if (scp.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) // the stable checkpoint is way behind lib, no way getting the block state, // it will not be applied nor saved, thus considered safe. @@ -1412,7 +1410,7 @@ namespace eosio { return false; } - bool pbft_database::should_recv_pbft_msg(const public_key_type &pub_key) { + bool pbft_database::should_recv_pbft_msg(const public_key_type& pub_key) { auto schedules = get_updated_fork_schedules(); for (auto const &bp: schedules) { @@ -1421,7 +1419,7 @@ namespace eosio { return false; } - public_key_type pbft_database::get_new_view_primary_key(const pbft_view_type target_view) { + public_key_type pbft_database::get_new_view_primary_key(pbft_view_type target_view) { auto active_bps = lscb_active_producers().producers; if (active_bps.empty()) return public_key_type(); @@ -1430,19 +1428,24 @@ namespace eosio { } producer_schedule_type pbft_database::lscb_active_producers() const { + + auto ps = ctrl.initial_schedule(); auto num = ctrl.last_stable_checkpoint_block_num(); if (num == 0) { auto const &ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; - if (ucb == 0) return ctrl.initial_schedule(); + if (ucb == 0) return ps; num = ucb; } if (auto bs = ctrl.fetch_block_state_by_number(num)) { - if (bs->pending_schedule.producers.empty()) return bs->active_schedule; - return bs->pending_schedule; + if (bs->pending_schedule.producers.empty()) { + ps = bs->active_schedule; + } else { + ps = bs->pending_schedule; + } } - return ctrl.initial_schedule(); + return ps; } block_num_type pbft_database::get_current_pbft_watermark() { @@ -1460,7 +1463,7 @@ namespace eosio { void pbft_database::update_fork_schedules() { - auto vector_minus = [&](vector &v1, vector &v2) + auto vector_minus = [&](vector& v1, vector& v2) { vector diff; std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), @@ -1521,7 +1524,7 @@ namespace eosio { return fork_schedules; } - bool pbft_database::is_less_than_high_watermark(const block_num_type &bnum) { + bool pbft_database::is_less_than_high_watermark(block_num_type bnum) { auto current_watermark = get_current_pbft_watermark(); return current_watermark == 0 || bnum <= current_watermark; } @@ -1536,7 +1539,7 @@ namespace eosio { return pbft_state_ptr(); } - vector pbft_database::get_checkpoints_by_num(const block_num_type& num) const { + vector pbft_database::get_checkpoints_by_num(block_num_type num) const { auto results = vector{}; auto &by_num_index = checkpoint_index.get(); @@ -1549,7 +1552,7 @@ namespace eosio { return results; } - pbft_view_change_state_ptr pbft_database::get_view_changes_by_target_view(const pbft_view_type& tv) const { + pbft_view_change_state_ptr pbft_database::get_view_changes_by_target_view(pbft_view_type tv) const { auto &by_view_index = view_state_index.get(); auto itr = by_view_index.find(tv); @@ -1578,7 +1581,7 @@ namespace eosio { EOS_ASSERT(result.second, pbft_exception, "unable to insert pbft checkpoint index, duplicate state detected"); } - void pbft_database::prune(const pbft_state_ptr &h) { + void pbft_database::prune(const pbft_state_ptr& h) { auto num = h->block_num; auto &by_bn = pbft_state_index.get(); @@ -1594,7 +1597,7 @@ namespace eosio { } } - void pbft_database::prune(const pbft_checkpoint_state_ptr &h) { + void pbft_database::prune(const pbft_checkpoint_state_ptr& h) { auto num = h->block_num; auto &by_bn = checkpoint_index.get(); diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 529bd3ed900..d10d9be5048 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -153,13 +153,11 @@ namespace eosio { unique_ptr transaction_check; unique_ptr keepalive_timer; unique_ptr pbft_message_cache_timer; - unique_ptr connection_monitor_timer; boost::asio::steady_timer::duration connector_period; boost::asio::steady_timer::duration txn_exp_period; boost::asio::steady_timer::duration resp_expected_period; boost::asio::steady_timer::duration keepalive_interval{std::chrono::seconds{32}}; boost::asio::steady_timer::duration pbft_message_cache_tick_interval{std::chrono::seconds{10}}; - boost::asio::steady_timer::duration connection_monitor_tick_interval{std::chrono::seconds{2}}; int max_cleanup_time_ms = 0; const std::chrono::system_clock::duration peer_authentication_interval{std::chrono::seconds{1}}; ///< Peer clock may be no more than 1 second skewed from our clock, including network latency. @@ -246,16 +244,16 @@ namespace eosio { void handle_message( connection_ptr c, const response_p2p_message &msg); //pbft messages - bool maybe_add_to_pbft_cache(const string &key); + bool maybe_add_to_pbft_cache(const string& key); void clean_expired_pbft_messages(); template - bool is_pbft_msg_outdated(M const & msg); + bool is_pbft_msg_outdated(const M& msg); template - bool is_pbft_msg_valid(M const & msg); + bool is_pbft_msg_valid(const M& msg); - void bcast_pbft_msg(const net_message &msg, int ttl); + void bcast_pbft_msg(const net_message& msg, int ttl); - void forward_pbft_msg(const connection_ptr& c, const net_message &msg, int ttl); + void forward_pbft_msg(const connection_ptr& c, const net_message& msg, int ttl); void pbft_outgoing_prepare(const pbft_prepare_ptr& prepare); void pbft_outgoing_commit(const pbft_commit_ptr& commit); @@ -263,14 +261,14 @@ namespace eosio { void pbft_outgoing_new_view(const pbft_new_view_ptr& new_view); void pbft_outgoing_checkpoint(const pbft_checkpoint_ptr& checkpoint); - void handle_message( const connection_ptr& c, const pbft_prepare &msg); - void handle_message( const connection_ptr& c, const pbft_commit &msg); - void handle_message( const connection_ptr& c, const pbft_view_change &msg); - void handle_message( const connection_ptr& c, const pbft_new_view &msg); - void handle_message( const connection_ptr& c, const pbft_checkpoint &msg); - void handle_message( const connection_ptr& c, const pbft_stable_checkpoint &msg); - void handle_message( const connection_ptr& c, const checkpoint_request_message &msg); - void handle_message( const connection_ptr& c, const compressed_pbft_message &msg); + void handle_message( const connection_ptr& c, const pbft_prepare& msg); + void handle_message( const connection_ptr& c, const pbft_commit& msg); + void handle_message( const connection_ptr& c, const pbft_view_change& msg); + void handle_message( const connection_ptr& c, const pbft_new_view& msg); + void handle_message( const connection_ptr& c, const pbft_checkpoint& msg); + void handle_message( const connection_ptr& c, const pbft_stable_checkpoint& msg); + void handle_message( const connection_ptr& c, const checkpoint_request_message& msg); + void handle_message( const connection_ptr& c, const compressed_pbft_message& msg); void start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection); void start_txn_timer(); @@ -281,7 +279,6 @@ namespace eosio { void connection_monitor(std::weak_ptr from_connection); void pbft_message_cache_ticker(); - void connection_monitor_ticker(); /** \name Peer Timestamps * Time message handling * @{ @@ -590,7 +587,6 @@ namespace eosio { std::shared_ptr> message; fc::time_point_sec deadline; }; - const int OUT_QUEUE_SIZE_LIMIT_FROM_WRITE_QUEUE = 100; const int OUT_QUEUE_SIZE_LIMIT = 200; deque pbft_queue; @@ -703,7 +699,7 @@ namespace eosio { std::function callback, bool to_sync_queue = false); void do_queue_write(); - void fill_out_buffer_with_pbft_queue(std::vector &bufs); + void fill_out_buffer_with_pbft_queue(std::vector& bufs); void send_p2p_request(bool discoverable); void send_p2p_response(bool discoverable,string p2p_peer_list); @@ -814,7 +810,6 @@ namespace eosio { void recv_handshake(const connection_ptr& c, const handshake_message& msg); void recv_notice(const connection_ptr& c, const notice_message& msg); bool is_syncing(); - void set_in_sync(); void sync_stable_checkpoints(const connection_ptr& c, uint32_t target); }; @@ -1152,16 +1147,15 @@ namespace eosio { }); } - void connection::fill_out_buffer_with_pbft_queue(std::vector &bufs){ + void connection::fill_out_buffer_with_pbft_queue(std::vector& bufs){ //delete timeout pbft message auto now = time_point::now(); - int drop_pbft_count = 0; - while (pbft_queue.size()>0) { - if (pbft_queue.front().deadline <= now) { - pbft_queue.pop_front(); - ++drop_pbft_count; + auto itr = pbft_queue.begin(); + while (itr != pbft_queue.end()) { + if (itr->deadline <= now) { + itr = pbft_queue.erase(itr); } else { - break; + ++itr; } } @@ -1399,7 +1393,7 @@ namespace eosio { return false; } return true; - } + } bool connection::add_peer_block(const peer_block_state& entry) { auto bptr = blk_state.get().find(entry.id); @@ -1486,10 +1480,6 @@ namespace eosio { return state != in_sync; } - void sync_manager::set_in_sync() { - set_state(in_sync); - } - void sync_manager::request_next_chunk( const connection_ptr& conn ) { uint32_t head_block = chain_plug->chain().fork_db_head_block_num(); @@ -3034,8 +3024,6 @@ namespace eosio { auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); if (!added) return; - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - bcast_pbft_msg(*msg, pbft_message_TTL); fc_dlog( logger, "sent prepare at height: ${n}, view: ${v} ", ("n", msg->block_info.block_num())("v", msg->view)); } @@ -3044,8 +3032,6 @@ namespace eosio { auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); if (!added) return; - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - bcast_pbft_msg(*msg, pbft_message_TTL); fc_dlog( logger, "sent commit at height: ${n}, view: ${v} ", ("n", msg->block_info.block_num())("v", msg->view)); } @@ -3054,8 +3040,6 @@ namespace eosio { auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); if (!added) return; - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - bcast_pbft_msg(*msg, pbft_message_TTL); fc_dlog( logger, "sent view change {cv: ${cv}, tv: ${tv}}", ("cv", msg->current_view)("tv", msg->target_view)); } @@ -3064,7 +3048,7 @@ namespace eosio { auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); if (!added) return; - bcast_pbft_msg(*msg, INT_MAX); + bcast_pbft_msg(*msg, 60 * pbft_message_TTL); fc_dlog( logger, "sent new view at view: ${v} ", ("v", msg->new_view)); } @@ -3072,8 +3056,6 @@ namespace eosio { auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); if (!added) return; - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - bcast_pbft_msg(*msg, pbft_message_TTL); fc_dlog( logger, "sent checkpoint at height: ${n} ", ("n", msg->block_info.block_num())); } @@ -3103,7 +3085,6 @@ namespace eosio { } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_prepare &msg) { - if (!is_pbft_msg_valid(msg)) return; auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); @@ -3122,8 +3103,6 @@ namespace eosio { } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_commit &msg) { - - if (!is_pbft_msg_valid(msg)) return; auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); @@ -3141,7 +3120,6 @@ namespace eosio { } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_view_change &msg) { - if (!is_pbft_msg_valid(msg)) return; auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); @@ -3180,7 +3158,7 @@ namespace eosio { auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); if (!added) return; - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (time_point_sec(time_point::now()) > time_point_sec(msg.common.timestamp) + 60 * pbft_message_TTL || msg.new_view <= pcc.state_machine->get_current_view()) { @@ -3192,7 +3170,7 @@ namespace eosio { if (pmm.sender_key != pcc.pbft_db.get_new_view_primary_key(pmm.msg.new_view)) return; - forward_pbft_msg(c, pmm.msg, INT_MAX); + forward_pbft_msg(c, pmm.msg, 60 * pbft_message_TTL); fc_dlog( logger, "received new view: ${n}, from ${v}", ("n", pmm.msg)("v", pmm.sender_key)); pbft_incoming_new_view_channel.publish(std::make_shared>(std::move(pmm))); @@ -3215,7 +3193,6 @@ namespace eosio { } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_checkpoint &msg) { - if (!is_pbft_msg_valid(msg)) return; auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); @@ -3266,87 +3243,17 @@ namespace eosio { }); } - void net_plugin_impl::pbft_message_cache_ticker() { - pbft_message_cache_timer->expires_from_now (pbft_message_cache_tick_interval); - pbft_message_cache_timer->async_wait ([this](boost::system::error_code ec) { - - if ( !ec ) { - clean_expired_pbft_messages(); - } else { - wlog ("pbft message cache ticker error: ${m}", ("m", ec.message())); - pbft_message_cache_ticker(); - } + void net_plugin_impl::pbft_message_cache_ticker() { + pbft_message_cache_timer->expires_from_now (pbft_message_cache_tick_interval); + pbft_message_cache_timer->async_wait ([this](boost::system::error_code ec) { - }); - } - - void net_plugin_impl::connection_monitor_ticker() { - connection_monitor_timer->expires_from_now (connection_monitor_tick_interval); - connection_monitor_timer->async_wait ([this](boost::system::error_code ec) { - connection_monitor_ticker (); - if (ec) { - wlog ("connection monitor ticker error: ${m}", ("m", ec.message())); - } - int total=0; - int current=0; - for(auto &conn: connections){ - if(conn->current()){ - ++current; - } - ++total; - auto is_open = conn->socket && conn->socket->is_open(); -// auto paddr = conn->peer_addr; -// paddr.insert(0, 20 - paddr.length(), ' '); - std::ostringstream ss; - - auto so = is_open?"1":"0"; - auto con = conn->connecting ?"1":"0"; - auto syn = conn->syncing ?"1":"0"; - auto cur = conn->current() ?"1":"0"; - ss << so << con << syn << cur ; - auto status = ss.str(); - - ss.str(""); - ss.clear(); - - ss << std::setfill(' ') << std::setw(22) << conn->peer_addr; - auto paddr = ss.str(); - - ss.str(""); - ss.clear(); - - ss << std::setfill(' ') << std::setw(6) << conn->buffer_queue.write_queue_size(); - auto write_queue = ss.str(); - - ss.str(""); - ss.clear(); - - ss << std::setfill(' ') << std::setw(6) << conn->buffer_queue.out_queue_size(); - auto out_queue = ss.str(); - - ss.str(""); - ss.clear(); - - ss << std::setfill(' ') << std::setw(6) << conn->pbft_queue.size(); - auto pbft_queue = ss.str(); - - auto conn_str = conn->peer_addr; - if(conn_str.empty()) { - try { - conn_str = boost::lexical_cast(conn->socket->remote_endpoint()); - } catch (...) { - - } - } - - dlog("connection: ${conn} \tstatus(socket|connecting|syncing|current): ${status}\t|\twrite_queue: ${write}\t|\tout_queue: ${out}\t|\tpbft_queue: ${pbft}", ("status",status)("conn",conn_str)("write",write_queue)("out",out_queue)("pbft",pbft_queue)); - } - dlog("connections stats: current : ${current}\t total : ${total} ",("current",current)("total",total)); - dlog("================================================================================================"); - auto local_trx_pool_size = local_txns.size(); - fc_dlog(logger, "local trx pool size: ${local_trx_pool_size}",("local_trx_pool_size",local_trx_pool_size)); - fc_dlog(logger, "================================================================================================"); - }); + if ( !ec ) { + clean_expired_pbft_messages(); + } else { + wlog ("pbft message cache ticker error: ${m}", ("m", ec.message())); + pbft_message_cache_ticker(); + } + }); } void net_plugin_impl::ticker() { @@ -3745,9 +3652,7 @@ namespace eosio { my->keepalive_timer.reset( new boost::asio::steady_timer( app().get_io_service())); my->ticker(); my->pbft_message_cache_timer.reset( new boost::asio::steady_timer( app().get_io_service())); - my->connection_monitor_timer.reset( new boost::asio::steady_timer( app().get_io_service())); my->pbft_message_cache_ticker(); -// my->connection_monitor_ticker(); } FC_LOG_AND_RETHROW() } diff --git a/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp b/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp index 69f67ea6cf8..726e4d43591 100644 --- a/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp +++ b/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp @@ -26,15 +26,15 @@ class pbft_plugin : public appbase::plugin { pbft_state get_pbft_record( const block_id_type& bid )const; - vector get_pbft_checkpoints_record(const block_num_type &bnum)const; - pbft_view_change_state get_view_change_record(const pbft_view_type& view)const; + vector get_pbft_checkpoints_record(block_num_type bnum)const; + pbft_view_change_state get_view_change_record(pbft_view_type view)const; vector get_watermarks()const; flat_map get_fork_schedules()const; const char* get_pbft_status()const; block_id_type get_pbft_prepared_id()const; block_id_type get_pbft_my_prepare_id()const; - void set_pbft_current_view(const pbft_view_type &view); + void set_pbft_current_view(pbft_view_type view); private: diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index 0dcc60a5d11..ebff9c785f1 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -22,11 +22,8 @@ namespace eosio { boost::asio::steady_timer::duration checkpoint_timeout{std::chrono::seconds{50}}; void prepare_timer_tick(); - void commit_timer_tick(); - void view_change_timer_tick(); - void checkpoint_timer_tick(); private: @@ -67,13 +64,13 @@ namespace eosio { return pbft_state(); } - vector pbft_plugin::get_pbft_checkpoints_record(const block_num_type &bnum) const { + vector pbft_plugin::get_pbft_checkpoints_record(block_num_type bnum) const { pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); auto records = pbft_ctrl.pbft_db.get_checkpoints_by_num(bnum); if (!records.empty()) return records; return vector(); } - pbft_view_change_state pbft_plugin::get_view_change_record(const pbft_view_type& view) const { + pbft_view_change_state pbft_plugin::get_view_change_record(pbft_view_type view) const { pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); auto record = pbft_ctrl.pbft_db.get_view_changes_by_target_view(view); if (record) return *record; @@ -105,7 +102,7 @@ namespace eosio { return ctrl.get_pbft_my_prepare(); } - void pbft_plugin::set_pbft_current_view(const pbft_view_type& view) { + void pbft_plugin::set_pbft_current_view(pbft_view_type view) { //this is used to boost the recovery from a disaster, do not set this unless you have to do so. pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.state_machine->manually_set_current_view(view); From f975445db5d28c404a312c2f0aca54618e0e75d9 Mon Sep 17 00:00:00 2001 From: EOSBIXIN Date: Mon, 22 Jul 2019 15:25:20 +0800 Subject: [PATCH 09/37] add Tips section into Readme --- README.md | 6 ++++++ README_CN.md | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/README.md b/README.md index 9beed62b565..711835c591f 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,12 @@ As BOS continues to develop, developer rewards will be appropriately adjusted to 1. Build from code : `bash ./eosio_build.sh -s BOS` 2. Docker Style,check [Docker](./Docker/README.md) +## Tips: +- HTTP&P2P endpoints can be get from the [validator](https://validate.eosnation.io/bos/reports/endpoints.html) by EOS Nation +- BOS Mainnet [genesis.json](https://github.com/boscore/bosres/blob/master/genesis.json) +- BOS Mainnet [Genesis](https://github.com/boscore/bosres/blob/master/BOS_Genesis.md) +- EOS Mainnet [snapshot](https://github.com/boscore/bos-airdrop-snapshots/blob/master/README.md) + ## BOSCore Workflow BOSCore encourage community developer actively participate in contributing the code, members should follow the workflow below. ![BOSCore Workflow](./images/bos-workflow.png) diff --git a/README_CN.md b/README_CN.md index 92921ccf091..ade0d3715a1 100644 --- a/README_CN.md +++ b/README_CN.md @@ -29,6 +29,12 @@ BOS链的代码完全由社区贡献并维护,每个生态参与者都可以 1. 源码直接编译: `bash ./eosio_build.sh -s BOS` 2. Docker方式部署,参看 [Docker](./Docker/README.md) +## Tips: +- HTTP&P2P 列表可以从 EOS Nation 提供的[验证页面](https://validate.eosnation.io/bos/reports/endpoints.html)获取 +- BOS Mainnet [genesis.json](https://github.com/boscore/bosres/blob/master/genesis.json) +- BOS Mainnet [创世纪](https://github.com/boscore/bosres/blob/master/BOS_Genesis.md) +- EOS Mainnet [账户空投信息](https://github.com/boscore/bos-airdrop-snapshots/blob/master/README.md) + ## BOSCore 开发流程 BOSCore 鼓励社区开发者参与代码贡献,社区成员应当遵循以下工作流: ![BOSCore Workflow](./images/bos-workflow.png) From d47f2502708f97b14886b02d925420d3dfb2b87a Mon Sep 17 00:00:00 2001 From: oldcold Date: Thu, 25 Jul 2019 21:16:01 +0800 Subject: [PATCH 10/37] reset timer upon state transition; refactor code; --- libraries/chain/include/eosio/chain/pbft.hpp | 119 ++++--- .../include/eosio/chain/pbft_database.hpp | 42 +-- libraries/chain/pbft.cpp | 320 ++++++++++-------- libraries/chain/pbft_database.cpp | 320 +++++++++--------- .../include/eosio/chain/plugin_interface.hpp | 3 + plugins/chain_plugin/chain_plugin.cpp | 16 +- plugins/net_plugin/net_plugin.cpp | 202 +++++------ plugins/pbft_plugin/pbft_plugin.cpp | 198 ++++++----- unittests/pbft_tests.cpp | 66 ++-- 9 files changed, 668 insertions(+), 618 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index e9e1d856dad..a563147265c 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -12,9 +12,9 @@ namespace eosio { using namespace fc; struct psm_cache { - pbft_prepare prepares_cache; - pbft_commit commits_cache; - pbft_view_change view_changes_cache; + pbft_prepare prepare_cache; + pbft_commit commit_cache; + pbft_view_change view_change_cache; pbft_prepared_certificate prepared_certificate; vector committed_certificate; pbft_view_changed_certificate view_changed_certificate; @@ -29,13 +29,9 @@ namespace eosio { explicit psm_machine(pbft_database& pbft_db); ~psm_machine(); - void set_current(psm_state_ptr s) { - current = std::move(s); - } + void set_current(psm_state_ptr s) { current = std::move(s); } - psm_state_ptr get_current() { - return current; - } + const psm_state_ptr& get_current() { return current; } void on_prepare(const pbft_metadata_ptr& e); void on_commit(const pbft_metadata_ptr& e); @@ -45,23 +41,26 @@ namespace eosio { void send_prepare(); void send_commit(); void send_view_change(); + void send_checkpoint(); + bool maybe_new_view(); - void transit_to_committed_state(const psm_state_ptr& s, bool to_new_view); - void transit_to_prepared_state(const psm_state_ptr& s); - void transit_to_view_change_state(const psm_state_ptr& s); - void transit_to_new_view(const pbft_metadata_ptr& e, const psm_state_ptr& s); + void transit_to_committed_state(bool to_new_view); + void transit_to_prepared_state(); + void transit_to_view_change_state(); + void transit_to_new_view(const pbft_metadata_ptr& e); + void do_send_prepare(); + void do_send_commit(); void do_send_view_change(); - bool maybe_new_view(const psm_state_ptr& s); - const pbft_prepare& get_prepares_cache() const { return cache.prepares_cache; } - void set_prepares_cache(const pbft_prepare& pcache) { cache.prepares_cache = pcache; } + const pbft_prepare& get_prepare_cache() const { return cache.prepare_cache; } + void set_prepare_cache(const pbft_prepare &pcache) { cache.prepare_cache = pcache; } - const pbft_commit& get_commits_cache() const { return cache.commits_cache; } - void set_commits_cache(const pbft_commit& ccache) { cache.commits_cache = ccache; } + const pbft_commit& get_commit_cache() const { return cache.commit_cache; } + void set_commit_cache(const pbft_commit &ccache) { cache.commit_cache = ccache; } - const pbft_view_change& get_view_changes_cache() const { return cache.view_changes_cache; } - void set_view_changes_cache(const pbft_view_change& vc_cache) { cache.view_changes_cache = vc_cache; } + const pbft_view_change& get_view_change_cache() const { return cache.view_change_cache; } + void set_view_change_cache(const pbft_view_change &vc_cache) { cache.view_change_cache = vc_cache; } uint32_t get_current_view() const { return current_view; } void set_current_view(uint32_t cv) { current_view = cv; } @@ -85,6 +84,18 @@ namespace eosio { void set_view_change_timer(uint32_t vc_timer) { view_change_timer = vc_timer; } void manually_set_current_view(uint32_t cv); + + signal pbft_outgoing_prepare; + signal pbft_outgoing_commit; + signal pbft_outgoing_view_change; + signal pbft_outgoing_new_view; + signal pbft_outgoing_checkpoint; + signal pbft_transit_to_committed; + signal pbft_transit_to_prepared; + + template + void emit(const Signal &s, Arg &&a); + protected: psm_cache cache; uint32_t current_view; @@ -93,8 +104,8 @@ namespace eosio { uint32_t view_change_timer; private: - psm_state_ptr current; - pbft_database &pbft_db; + psm_state_ptr current = nullptr; + pbft_database& pbft_db; }; using psm_machine_ptr = std::shared_ptr; @@ -102,34 +113,40 @@ namespace eosio { class psm_state : public std::enable_shared_from_this { public: - psm_state(); + psm_state(psm_machine& m, pbft_database& pbft_db); ~psm_state(); - virtual void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) = 0; - virtual void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) = 0; - virtual void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) = 0; + virtual void on_prepare(const pbft_metadata_ptr& e) = 0; + virtual void on_commit(const pbft_metadata_ptr& e) = 0; + virtual void on_view_change(const pbft_metadata_ptr& e) = 0; - virtual void send_prepare(const psm_machine_ptr& m, pbft_database& pbft_db) = 0; - virtual void send_commit(const psm_machine_ptr& m, pbft_database& pbft_db) = 0; - virtual void send_view_change(const psm_machine_ptr& m, pbft_database& pbft_db) = 0; + virtual void send_prepare() = 0; + virtual void send_commit() = 0; + virtual void send_view_change() = 0; virtual const char* get_name() = 0; std::shared_ptr get_self() { return shared_from_this(); }; + + protected: + psm_machine& m; + pbft_database& pbft_db; }; class psm_prepared_state final: public psm_state { public: - psm_prepared_state(); + psm_prepared_state(psm_machine& m, pbft_database& pbft_db); ~psm_prepared_state(); - void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; - void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; - void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; + void on_prepare(const pbft_metadata_ptr& e) override; + void on_commit(const pbft_metadata_ptr& e) override; + void on_view_change(const pbft_metadata_ptr& e) override; + + void send_prepare() override; + void send_commit() override; + void send_view_change() override; - void send_prepare(const psm_machine_ptr& m, pbft_database& pbft_db) override; - void send_commit(const psm_machine_ptr& m, pbft_database& pbft_db) override; - void send_view_change(const psm_machine_ptr& m, pbft_database& pbft_db) override; + void maybe_transit_to_committed(); bool pending_commit_local; @@ -138,32 +155,32 @@ namespace eosio { class psm_committed_state final: public psm_state { public: - psm_committed_state(); + psm_committed_state(psm_machine& m, pbft_database& pbft_db); ~psm_committed_state(); - void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; - void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; - void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; + void on_prepare(const pbft_metadata_ptr& e) override; + void on_commit(const pbft_metadata_ptr& e) override; + void on_view_change(const pbft_metadata_ptr& e) override; - void send_prepare(const psm_machine_ptr& m, pbft_database& pbft_db) override; - void send_commit(const psm_machine_ptr& m, pbft_database& pbft_db) override; - void send_view_change(const psm_machine_ptr& m, pbft_database& pbft_db) override; + void send_prepare() override; + void send_commit() override; + void send_view_change() override; const char* get_name() override { return "{==== COMMITTED ====}"; } }; class psm_view_change_state final: public psm_state { public: - psm_view_change_state(); + psm_view_change_state(psm_machine& m, pbft_database& pbft_db); ~psm_view_change_state(); - void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; - void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; - void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database& pbft_db) override; + void on_prepare(const pbft_metadata_ptr& e) override; + void on_commit(const pbft_metadata_ptr& e) override; + void on_view_change(const pbft_metadata_ptr& e) override; - void send_prepare(const psm_machine_ptr& m, pbft_database& pbft_db) override; - void send_commit(const psm_machine_ptr& m, pbft_database& pbft_db) override; - void send_view_change(const psm_machine_ptr& m, pbft_database& pbft_db) override; + void send_prepare() override; + void send_commit() override; + void send_view_change() override; const char* get_name() override { return "{==== VIEW CHANGE ====}"; } }; @@ -176,7 +193,7 @@ namespace eosio { const uint16_t view_change_timeout = 6; pbft_database pbft_db; - std::shared_ptr state_machine; + psm_machine state_machine; void maybe_pbft_prepare(); void maybe_pbft_commit(); diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index b571c96f420..8a935829d9a 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -50,6 +50,8 @@ namespace eosio { } }; + using fork_info_type = vector; + struct pbft_message_common { explicit pbft_message_common(pbft_message_type t): type{t} {}; @@ -426,19 +428,22 @@ namespace eosio { void add_pbft_view_change(const pbft_view_change& vc, const public_key_type& pk); void add_pbft_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk); - pbft_prepare send_and_add_pbft_prepare(const pbft_prepare& cached_prepare = pbft_prepare(), pbft_view_type current_view = 0); - pbft_commit send_and_add_pbft_commit(const pbft_commit& cached_commit = pbft_commit(), pbft_view_type current_view = 0); - pbft_view_change send_and_add_pbft_view_change( - const pbft_view_change& cached_view_change = pbft_view_change(), - const pbft_prepared_certificate& ppc = pbft_prepared_certificate(), - const vector& pcc = vector{}, + vector generate_and_add_pbft_prepare( + const pbft_prepare &cached_prepare = pbft_prepare(), + pbft_view_type current_view = 0); + vector generate_and_add_pbft_commit( + const pbft_commit &cached_commit = pbft_commit(), + pbft_view_type current_view = 0); + vector generate_and_add_pbft_view_change( + const pbft_view_change &cached_view_change = pbft_view_change(), + const pbft_prepared_certificate &ppc = pbft_prepared_certificate(), + const vector &pcc = vector{}, pbft_view_type current_view = 0, pbft_view_type target_view = 1); - pbft_new_view send_pbft_new_view( - const pbft_view_changed_certificate& vcc = pbft_view_changed_certificate(), + pbft_new_view generate_pbft_new_view( + const pbft_view_changed_certificate &vcc = pbft_view_changed_certificate(), pbft_view_type current_view = 1); vector generate_and_add_pbft_checkpoint(); - void send_pbft_checkpoint(); bool should_prepared(); bool should_committed(); @@ -476,7 +481,6 @@ namespace eosio { chain_id_type& get_chain_id() {return chain_id;} pbft_stable_checkpoint get_stable_checkpoint_by_id(const block_id_type& block_id, bool incl_blk_extn = true); pbft_stable_checkpoint fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr& b); - block_info_type cal_pending_stable_checkpoint() const; void cleanup_on_new_view(); void update_fork_schedules(); @@ -488,13 +492,6 @@ namespace eosio { vector get_pbft_watermarks() const; flat_map get_pbft_fork_schedules() const; - - signal pbft_outgoing_prepare; - signal pbft_outgoing_commit; - signal pbft_outgoing_view_change; - signal pbft_outgoing_new_view; - signal pbft_outgoing_checkpoint; - private: controller& ctrl; pbft_state_multi_index_type pbft_state_index; @@ -506,22 +503,19 @@ namespace eosio { flat_map fork_schedules; chain_id_type chain_id = ctrl.get_chain_id(); - + block_info_type cal_pending_stable_checkpoint() const; bool is_less_than_high_watermark(block_num_type bnum); bool is_valid_prepared_certificate(const pbft_prepared_certificate& certificate, bool add_to_pbft_db = false); bool is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db = false); - bool is_valid_longest_fork(const block_info_type& bi, vector block_infos, unsigned long threshold, unsigned long non_fork_bp_count); + bool is_valid_longest_fork(const block_info_type& bi, fork_info_type block_infos, unsigned long threshold, unsigned long non_fork_bp_count); producer_schedule_type lscb_active_producers() const; vector& get_updated_watermarks(); flat_map& get_updated_fork_schedules(); block_num_type get_current_pbft_watermark(); - vector> fetch_fork_from(vector& block_infos); - vector fetch_first_fork_from(vector& bi); - - template - void emit(const Signal &s, Arg &&a); + vector fetch_fork_from(fork_info_type& block_infos); + fork_info_type fetch_first_fork_from(fork_info_type& bi); void set(const pbft_state_ptr& s); void set(const pbft_checkpoint_state_ptr& s); diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 2c510ef6512..4739bded9ad 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -1,5 +1,3 @@ -#include - #include #include #include @@ -8,8 +6,9 @@ namespace eosio { namespace chain { pbft_controller::pbft_controller(controller &ctrl) : - pbft_db(ctrl), - state_machine(new psm_machine(pbft_db)) { + pbft_db(ctrl), + state_machine(pbft_db) { + state_machine.set_current(std::make_shared(state_machine, pbft_db)); datadir = ctrl.state_dir(); if (!fc::is_directory(datadir)) @@ -23,8 +22,8 @@ namespace eosio { fc::datastream ds(content.data(), content.size()); uint32_t current_view; fc::raw::unpack(ds, current_view); - state_machine->set_current_view(current_view); - state_machine->set_target_view(state_machine->get_current_view() + 1); + state_machine.set_current_view(current_view); + state_machine.set_target_view(state_machine.get_current_view() + 1); ilog("current view: ${cv}", ("cv", current_view)); } @@ -36,53 +35,53 @@ namespace eosio { std::ofstream out(pbft_db_dat.generic_string().c_str(), std::ios::out | std::ios::binary | std::ofstream::trunc); - uint32_t current_view = state_machine->get_current_view(); + uint32_t current_view = state_machine.get_current_view(); fc::raw::pack(out, current_view); } void pbft_controller::maybe_pbft_prepare() { if (!pbft_db.should_send_pbft_msg()) return; - state_machine->send_prepare(); + state_machine.send_prepare(); } void pbft_controller::maybe_pbft_commit() { if (!pbft_db.should_send_pbft_msg()) return; - state_machine->send_commit(); + state_machine.send_commit(); } void pbft_controller::maybe_pbft_view_change() { if (!pbft_db.should_send_pbft_msg()) return; - if (state_machine->get_view_change_timer() <= view_change_timeout) { - if (!state_machine->get_view_changes_cache().empty()) { - pbft_db.send_and_add_pbft_view_change(state_machine->get_view_changes_cache()); + if (state_machine.get_view_change_timer() <= view_change_timeout) { + if (!state_machine.get_view_change_cache().empty()) { + pbft_db.generate_and_add_pbft_view_change(state_machine.get_view_change_cache()); } - state_machine->set_view_change_timer(state_machine->get_view_change_timer() + 1); + state_machine.set_view_change_timer(state_machine.get_view_change_timer() + 1); } else { - state_machine->set_view_change_timer(0); - state_machine->send_view_change(); + state_machine.set_view_change_timer(0); + state_machine.send_view_change(); } } void pbft_controller::maybe_pbft_checkpoint() { if (!pbft_db.should_send_pbft_msg()) return; - pbft_db.send_pbft_checkpoint(); + state_machine.send_checkpoint(); pbft_db.checkpoint_local(); } void pbft_controller::on_pbft_prepare(const pbft_metadata_ptr& p) { - state_machine->on_prepare(p); + state_machine.on_prepare(p); } void pbft_controller::on_pbft_commit(const pbft_metadata_ptr& c) { - state_machine->on_commit(c); + state_machine.on_commit(c); } void pbft_controller::on_pbft_view_change(const pbft_metadata_ptr& vc) { - state_machine->on_view_change(vc); + state_machine.on_view_change(vc); } void pbft_controller::on_pbft_new_view(const pbft_metadata_ptr& nv) { - state_machine->on_new_view(nv); + state_machine.on_new_view(nv); } void pbft_controller::on_pbft_checkpoint(const pbft_metadata_ptr &cp) { @@ -91,15 +90,13 @@ namespace eosio { pbft_db.checkpoint_local(); } - psm_state::psm_state() = default; + psm_state::psm_state(psm_machine& m, pbft_database& pbft_db) : m(m), pbft_db(pbft_db){} psm_state::~psm_state() = default; - psm_machine::psm_machine(pbft_database &pbft_db) : pbft_db(pbft_db) { - set_current(std::make_shared()); - - set_prepares_cache(pbft_prepare()); - set_commits_cache(pbft_commit()); - set_view_changes_cache(pbft_view_change()); + psm_machine::psm_machine(pbft_database& pbft_db) : pbft_db(pbft_db) { + set_prepare_cache(pbft_prepare()); + set_commit_cache(pbft_commit()); + set_view_change_cache(pbft_view_change()); set_prepared_certificate(pbft_prepared_certificate{}); set_committed_certificate(vector{}); @@ -114,27 +111,27 @@ namespace eosio { psm_machine::~psm_machine() = default; void psm_machine::on_prepare(const pbft_metadata_ptr& e) { - current->on_prepare(shared_from_this(), e, pbft_db); + current->on_prepare(e); } void psm_machine::send_prepare() { - current->send_prepare(shared_from_this(), pbft_db); + current->send_prepare(); } void psm_machine::on_commit(const pbft_metadata_ptr& e) { - current->on_commit(shared_from_this(), e, pbft_db); + current->on_commit(e); } void psm_machine::send_commit() { - current->send_commit(shared_from_this(), pbft_db); + current->send_commit(); } void psm_machine::on_view_change(const pbft_metadata_ptr& e) { - current->on_view_change(shared_from_this(), e, pbft_db); + current->on_view_change(e); } void psm_machine::send_view_change() { - current->send_view_change(shared_from_this(), pbft_db); + current->send_view_change(); } void psm_machine::on_new_view(const pbft_metadata_ptr& e) { @@ -148,7 +145,7 @@ namespace eosio { } try { - transit_to_new_view(e, current); + transit_to_new_view(e); } catch(...) { elog("apply new view failed, waiting for next round.. ${nv} ", ("nv", e->msg)); } @@ -157,33 +154,17 @@ namespace eosio { void psm_machine::manually_set_current_view(uint32_t cv) { set_current_view(cv); set_target_view(cv + 1); - transit_to_view_change_state(current); + transit_to_view_change_state(); } /** * psm_prepared_state */ - psm_prepared_state::psm_prepared_state() {pending_commit_local = false;} + psm_prepared_state::psm_prepared_state(psm_machine& m, pbft_database& pbft_db) : psm_state(m, pbft_db) {pending_commit_local = false;} psm_prepared_state::~psm_prepared_state() = default; - void psm_prepared_state::on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { - //ignore - } - - void psm_prepared_state::send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) { - //retry - if (m->get_prepares_cache().empty()) return; - - pbft_db.send_and_add_pbft_prepare(m->get_prepares_cache(), m->get_current_view()); - } - - void psm_prepared_state::on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { - - if (e->msg.view < m->get_current_view()) return; - if (!pbft_db.is_valid_commit(e->msg, e->sender_key)) return; - - pbft_db.add_pbft_commit(e->msg, e->sender_key); + void psm_prepared_state::maybe_transit_to_committed() { //`pending_commit_local` is used to mark committed local status in psm machine; //`pbft_db.pending_pbft_lib()` is used to mark commit local status in controller; @@ -195,168 +176,174 @@ namespace eosio { } if (pending_commit_local && !pbft_db.pending_pbft_lib()) { - pbft_db.send_pbft_checkpoint(); + m.send_checkpoint(); pbft_db.checkpoint_local(); - m->transit_to_committed_state(shared_from_this(), false); + m.transit_to_committed_state(false); } } - void psm_prepared_state::send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) { - auto commits = pbft_db.send_and_add_pbft_commit(m->get_commits_cache(), m->get_current_view()); + void psm_prepared_state::on_prepare(const pbft_metadata_ptr& e) { + //ignore + } - if (!commits.empty()) { - m->set_commits_cache(commits); - } + void psm_prepared_state::send_prepare() { + //retry + if (m.get_prepare_cache().empty()) return; - if (pbft_db.should_committed() && !pending_commit_local) { - pbft_db.commit_local(); - pending_commit_local = true; - } + m.do_send_prepare(); + } - if (pending_commit_local && !pbft_db.pending_pbft_lib()) { - pbft_db.send_pbft_checkpoint(); - pbft_db.checkpoint_local(); - m->transit_to_committed_state(shared_from_this(), false); - } + void psm_prepared_state::on_commit(const pbft_metadata_ptr& e) { + + if (e->msg.view < m.get_current_view()) return; + if (!pbft_db.is_valid_commit(e->msg, e->sender_key)) return; + + pbft_db.add_pbft_commit(e->msg, e->sender_key); + + maybe_transit_to_committed(); + } + + void psm_prepared_state::send_commit() { + + m.do_send_commit(); + + maybe_transit_to_committed(); } - void psm_prepared_state::on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_prepared_state::on_view_change(const pbft_metadata_ptr& e) { - if (e->msg.target_view <= m->get_current_view()) return; + if (e->msg.target_view <= m.get_current_view()) return; if (!pbft_db.is_valid_view_change(e->msg, e->sender_key)) return; pbft_db.add_pbft_view_change(e->msg, e->sender_key); //if received >= f+1 view_change on some view, transit to view_change and send view change auto target_view = pbft_db.should_view_change(); - if (target_view > 0 && target_view > m->get_current_view()) { - m->set_target_view(target_view); - m->transit_to_view_change_state(shared_from_this()); + if (target_view > 0 && target_view > m.get_current_view()) { + m.set_target_view(target_view); + m.transit_to_view_change_state(); } } - void psm_prepared_state::send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) { - m->transit_to_view_change_state(shared_from_this()); + void psm_prepared_state::send_view_change() { + m.transit_to_view_change_state(); } - psm_committed_state::psm_committed_state() = default; + psm_committed_state::psm_committed_state(psm_machine& m, pbft_database& pbft_db) : psm_state(m, pbft_db) {} psm_committed_state::~psm_committed_state() = default; /** * psm_committed_state */ - void psm_committed_state::on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_committed_state::on_prepare(const pbft_metadata_ptr& e) { //validate - if (e->msg.view < m->get_current_view()) return; + if (e->msg.view < m.get_current_view()) return; if (!pbft_db.is_valid_prepare(e->msg, e->sender_key)) return; //do action add prepare pbft_db.add_pbft_prepare(e->msg, e->sender_key); //if prepare >= 2f+1, transit to prepared - if (pbft_db.should_prepared()) m->transit_to_prepared_state(shared_from_this()); + if (pbft_db.should_prepared()) m.transit_to_prepared_state(); } - void psm_committed_state::send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) { + void psm_committed_state::send_prepare() { - auto prepares = pbft_db.send_and_add_pbft_prepare(m->get_prepares_cache(), m->get_current_view()); - - if (!prepares.empty()) { - m->set_prepares_cache(prepares); - } + m.do_send_prepare(); //if prepare >= 2f+1, transit to prepared - if (pbft_db.should_prepared()) m->transit_to_prepared_state(shared_from_this()); + if (pbft_db.should_prepared()) m.transit_to_prepared_state(); } - void psm_committed_state::on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_committed_state::on_commit(const pbft_metadata_ptr& e) { - if (e->msg.view < m->get_current_view()) return; + if (e->msg.view < m.get_current_view()) return; if (!pbft_db.is_valid_commit(e->msg, e->sender_key)) return; pbft_db.add_pbft_commit(e->msg, e->sender_key); } - void psm_committed_state::send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) { + void psm_committed_state::send_commit() { + + if (m.get_commit_cache().empty()) return; - if (m->get_commits_cache().empty()) return; - pbft_db.send_and_add_pbft_commit(m->get_commits_cache(), m->get_current_view()); + m.do_send_commit(); } - void psm_committed_state::on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_committed_state::on_view_change(const pbft_metadata_ptr& e) { - if (e->msg.target_view <= m->get_current_view()) return; + if (e->msg.target_view <= m.get_current_view()) return; if (!pbft_db.is_valid_view_change(e->msg, e->sender_key)) return; pbft_db.add_pbft_view_change(e->msg, e->sender_key); //if received >= f+1 view_change on some view, transit to view_change and send view change auto new_view = pbft_db.should_view_change(); - if (new_view > 0 && new_view > m->get_current_view()) { - m->set_target_view(new_view); - m->transit_to_view_change_state(shared_from_this()); + if (new_view > 0 && new_view > m.get_current_view()) { + m.set_target_view(new_view); + m.transit_to_view_change_state(); } } - void psm_committed_state::send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) { - m->transit_to_view_change_state(shared_from_this()); + void psm_committed_state::send_view_change() { + m.transit_to_view_change_state(); } - psm_view_change_state::psm_view_change_state() = default; + psm_view_change_state::psm_view_change_state(psm_machine& m, pbft_database& pbft_db) : psm_state(m, pbft_db) {} psm_view_change_state::~psm_view_change_state() = default; /** * psm_view_change_state */ - void psm_view_change_state::on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_view_change_state::on_prepare(const pbft_metadata_ptr& e) { //ignore; } - void psm_view_change_state::send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) { + void psm_view_change_state::send_prepare() { //ignore; } - void psm_view_change_state::on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_view_change_state::on_commit(const pbft_metadata_ptr& e) { //ignore; } - void psm_view_change_state::send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) { + void psm_view_change_state::send_commit() { //ignore; } - void psm_view_change_state::on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_view_change_state::on_view_change(const pbft_metadata_ptr& e) { //skip from view change state if my lib is higher than my view change state height. - auto vc = m->get_view_changes_cache(); + auto vc = m.get_view_change_cache(); if (!vc.empty() && pbft_db.should_stop_view_change(vc)) { - m->transit_to_committed_state(shared_from_this(), false); + m.transit_to_committed_state(false); return; } - if (e->msg.target_view <= m->get_current_view()) return; + if (e->msg.target_view <= m.get_current_view()) return; if (!pbft_db.is_valid_view_change(e->msg, e->sender_key)) return; pbft_db.add_pbft_view_change(e->msg, e->sender_key); - m->maybe_new_view(shared_from_this()); + m.maybe_new_view(); } - void psm_view_change_state::send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) { + void psm_view_change_state::send_view_change() { //skip from view change state if my lib is higher than my view change state height. - auto vc = m->get_view_changes_cache(); + auto vc = m.get_view_change_cache(); if (!vc.empty() && pbft_db.should_stop_view_change(vc)) { - m->transit_to_committed_state(shared_from_this(), false); + m.transit_to_committed_state(false); return; } - m->do_send_view_change(); + m.do_send_view_change(); - m->maybe_new_view(shared_from_this()); + m.maybe_new_view(); } - void psm_machine::transit_to_committed_state(const psm_state_ptr& s, bool to_new_view) { + void psm_machine::transit_to_committed_state(bool to_new_view) { if (!to_new_view) { auto nv = pbft_db.get_committed_view(); @@ -364,44 +351,44 @@ namespace eosio { set_target_view(get_current_view() + 1); } - auto prepares = pbft_db.send_and_add_pbft_prepare(pbft_prepare(), get_current_view()); - set_prepares_cache(prepares); - //TODO: reset prepare timer; + set_prepare_cache(pbft_prepare()); + do_send_prepare(); - set_view_changes_cache(pbft_view_change()); + set_view_change_cache(pbft_view_change()); set_view_change_timer(0); - set_current(std::make_shared()); + set_current(std::make_shared(*this, pbft_db)); + emit(pbft_transit_to_committed, true); } - void psm_machine::transit_to_prepared_state(const psm_state_ptr& s) { + void psm_machine::transit_to_prepared_state() { - auto commits = pbft_db.send_and_add_pbft_commit(pbft_commit(), get_current_view()); - set_commits_cache(commits); - //TODO: reset commit timer; + set_commit_cache(pbft_commit()); + do_send_commit(); - set_view_changes_cache(pbft_view_change()); + set_view_change_cache(pbft_view_change()); - set_current(std::make_shared()); + set_current(std::make_shared(*this, pbft_db)); + emit(pbft_transit_to_prepared, true); } - void psm_machine::transit_to_view_change_state(const psm_state_ptr& s) { + void psm_machine::transit_to_view_change_state() { - set_commits_cache(pbft_commit()); - set_prepares_cache(pbft_prepare()); + set_commit_cache(pbft_commit()); + set_prepare_cache(pbft_prepare()); set_view_change_timer(0); set_target_view_retries(0); - set_current(std::make_shared()); + set_current(std::make_shared(*this, pbft_db)); if (pbft_db.should_send_pbft_msg()) { do_send_view_change(); - auto nv = maybe_new_view(s); + auto nv = maybe_new_view(); if (nv) return; } } - bool psm_machine::maybe_new_view(const psm_state_ptr &s) { + bool psm_machine::maybe_new_view() { //if view_change >= 2f+1, calculate next primary, send new view if is primary auto nv = get_target_view(); auto pk = pbft_db.get_new_view_primary_key(nv); @@ -412,14 +399,15 @@ namespace eosio { auto new_view = pbft_db.get_proposed_new_view_num(); if (new_view != nv) return false; - auto nv_msg = pbft_db.send_pbft_new_view( + auto nv_msg = pbft_db.generate_pbft_new_view( get_view_changed_certificate(), new_view); if (nv_msg.empty()) return false; + emit(pbft_outgoing_new_view, std::make_shared(nv_msg)); try { - transit_to_new_view(std::make_shared>(nv_msg, pbft_db.get_chain_id()), s); + transit_to_new_view(std::make_shared>(nv_msg, pbft_db.get_chain_id())); return true; } catch(const fc::exception& ex) { elog("apply new view failed, waiting for next round.. ${nv} ", ("nv", nv_msg)); @@ -428,12 +416,12 @@ namespace eosio { return false; } - void psm_machine::transit_to_new_view(const pbft_metadata_ptr& e, const psm_state_ptr& s) { + void psm_machine::transit_to_new_view(const pbft_metadata_ptr& e) { set_current_view(e->msg.new_view); set_target_view(e->msg.new_view + 1); - set_prepares_cache(pbft_prepare()); + set_prepare_cache(pbft_prepare()); set_view_change_timer(0); set_target_view_retries(0); @@ -451,7 +439,7 @@ namespace eosio { if (!e->msg.prepared_cert.prepares.empty()) { pbft_db.mark_as_prepared(e->msg.prepared_cert.block_info.block_id); if (pbft_db.should_prepared()) { - transit_to_prepared_state(s); + transit_to_prepared_state(); return; } } @@ -459,13 +447,34 @@ namespace eosio { if (pbft_db.should_committed()) { pbft_db.commit_local(); } - transit_to_committed_state(s, true); + transit_to_committed_state(true); + } + + void psm_machine::do_send_prepare() { + auto prepares = pbft_db.generate_and_add_pbft_prepare(get_prepare_cache(), get_current_view()); + if (!prepares.empty()) { + for (const auto& p: prepares) { + emit(pbft_outgoing_prepare, std::make_shared(p)); + } + set_prepare_cache(prepares.front()); + } + } + + void psm_machine::do_send_commit() { + auto commits = pbft_db.generate_and_add_pbft_commit(get_commit_cache(), get_current_view()); + + if (!commits.empty()) { + for (const auto& c: commits) { + emit(pbft_outgoing_commit, std::make_shared(c)); + } + set_commit_cache(commits.front()); + } } void psm_machine::do_send_view_change() { auto reset_view_change_state = [&]() { - set_view_changes_cache(pbft_view_change()); + set_view_change_cache(pbft_view_change()); set_prepared_certificate(pbft_db.generate_prepared_certificate()); set_committed_certificate(pbft_db.generate_committed_certificate()); }; @@ -482,15 +491,42 @@ namespace eosio { EOS_ASSERT((get_target_view() > get_current_view()), pbft_exception, "target view should be always greater than current view"); - auto view_changes = pbft_db.send_and_add_pbft_view_change( - get_view_changes_cache(), + auto view_changes = pbft_db.generate_and_add_pbft_view_change( + get_view_change_cache(), get_prepared_certificate(), get_committed_certificate(), get_current_view(), get_target_view()); if (!view_changes.empty()) { - set_view_changes_cache(view_changes); + for (const auto& vc : view_changes) { + emit(pbft_outgoing_view_change, std::make_shared(vc)); + } + set_view_change_cache(view_changes.front()); + } + } + + void psm_machine::send_checkpoint() { + auto checkpoints = pbft_db.generate_and_add_pbft_checkpoint(); + for (const auto& cp: checkpoints) { + emit(pbft_outgoing_checkpoint, std::make_shared(cp)); + } + } + + template + void psm_machine::emit(const Signal &s, Arg &&a) { + try { + s(std::forward(a)); + } catch (boost::interprocess::bad_alloc &e) { + wlog("bad alloc"); + throw e; + } catch (controller_emit_signal_exception &e) { + wlog("${details}", ("details", e.to_detail_string())); + throw e; + } catch (fc::exception &e) { + wlog("${details}", ("details", e.to_detail_string())); + } catch (...) { + wlog("signal handler threw exception"); } } } diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index f915e100383..22c2ab188ac 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -70,7 +70,7 @@ namespace eosio { uint32_t num_records_in_checkpoint_db = checkpoint_index.size(); fc::raw::pack(c_out, unsigned_int{num_records_in_checkpoint_db}); - for (auto const &s: checkpoint_index) { + for (const auto& s: checkpoint_index) { fc::raw::pack(c_out, *s); } @@ -80,7 +80,7 @@ namespace eosio { uint32_t num_records_in_db = pbft_state_index.size(); fc::raw::pack(out, unsigned_int{num_records_in_db}); - for (auto const &s : pbft_state_index) { + for (const auto& s : pbft_state_index) { fc::raw::pack(out, *s); } @@ -131,16 +131,16 @@ namespace eosio { auto threshold = as.size()* 2 / 3 + 1; if (prepares.size() >= threshold && !cpsp->is_prepared && is_less_than_high_watermark(cpsp->block_num)) { flat_map prepare_count; - for (auto const &pre: prepares) { + for (const auto& pre: prepares) { if (prepare_count.find(pre.second.view) == prepare_count.end()) prepare_count[pre.second.view] = 0; } - for (auto const &bp: as) { - for (auto const &pp: prepares) { + for (const auto& bp: as) { + for (const auto& pp: prepares) { if (bp.block_signing_key == pp.first.second) prepare_count[pp.first.first] += 1; } } - for (auto const &e: prepare_count) { + for (const auto& e: prepare_count) { if (e.second >= threshold) { mark_as_prepared(cpsp->block_id); } @@ -167,11 +167,13 @@ namespace eosio { by_block_id_index.modify(itr, [&](const pbft_state_ptr& p) { p->is_prepared = true; }); } - pbft_prepare pbft_database::send_and_add_pbft_prepare(const pbft_prepare& cached_prepare, pbft_view_type current_view) { - pbft_prepare prepare_to_be_cached; - + vector pbft_database::generate_and_add_pbft_prepare(const pbft_prepare &cached_prepare, + pbft_view_type current_view) { + vector prepares_to_be_cached; + const auto& my_sps = ctrl.my_signature_providers(); + prepares_to_be_cached.reserve(my_sps.size()); auto head_block_num = ctrl.head_block_num(); - if (head_block_num <= 1) return prepare_to_be_cached; + if (head_block_num <= 1) return prepares_to_be_cached; auto my_prepare = ctrl.get_pbft_my_prepare(); auto reserve_prepare = [&](const block_id_type& in) { @@ -187,23 +189,22 @@ namespace eosio { if (!cached_prepare.empty()) { - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { //sign again, update cache, then emit auto retry_p = cached_prepare; retry_p.common.timestamp = time_point::now(); retry_p.sender_signature = sp.second(retry_p.digest(chain_id)); - emit(pbft_outgoing_prepare, std::make_shared(retry_p)); + prepares_to_be_cached.emplace_back(retry_p); } } else if (reserve_prepare(my_prepare)) { - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { pbft_prepare reserve_p; - reserve_p.view=current_view; reserve_p.block_info={my_prepare}; + reserve_p.view = current_view; + reserve_p.block_info = {my_prepare}; reserve_p.sender_signature = sp.second(reserve_p.digest(chain_id)); - emit(pbft_outgoing_prepare, std::make_shared(reserve_p)); - if (prepare_to_be_cached.empty()) prepare_to_be_cached = reserve_p; + prepares_to_be_cached.emplace_back(reserve_p); } } else { - auto current_watermark = get_current_pbft_watermark(); auto lib = ctrl.last_irreversible_block_num(); @@ -213,30 +214,30 @@ namespace eosio { high_watermark_block_num = std::min(head_block_num, current_watermark); } - if (high_watermark_block_num <= lib) return prepare_to_be_cached; + if (high_watermark_block_num <= lib) return prepares_to_be_cached; if (auto hwbs = ctrl.fork_db().get_block_in_current_chain_by_num(high_watermark_block_num)) { auto sent = false; - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { pbft_prepare new_p; - new_p.view=current_view; new_p.block_info={hwbs->id}; + new_p.view = current_view; + new_p.block_info = {hwbs->id}; new_p.sender_signature = sp.second(new_p.digest(chain_id)); if (is_valid_prepare(new_p, sp.first)) { - emit(pbft_outgoing_prepare, std::make_shared(new_p)); add_pbft_prepare(new_p, sp.first); sent = true; - if (prepare_to_be_cached.empty()) prepare_to_be_cached = new_p; + prepares_to_be_cached.emplace_back(new_p); } } if (sent) ctrl.set_pbft_my_prepare(hwbs->id); } } - return prepare_to_be_cached; + return prepares_to_be_cached; } bool pbft_database::should_prepared() { - auto const &by_prepare_and_num_index = pbft_state_index.get(); + const auto& by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); if (itr == by_prepare_and_num_index.end()) return false; @@ -298,17 +299,17 @@ namespace eosio { auto commits = cpsp->commits; if (commits.size() >= threshold && !cpsp->is_committed && is_less_than_high_watermark(cpsp->block_num)) { flat_map commit_count; - for (auto const &com: commits) { + for (const auto& com: commits) { if (commit_count.find(com.second.view) == commit_count.end()) commit_count[com.second.view] = 0; } - for (auto const &bp: as) { - for (auto const &pc: commits) { + for (const auto& bp: as) { + for (const auto& pc: commits) { if (bp.block_signing_key == pc.first.second) commit_count[pc.first.first] += 1; } } - for (auto const &e: commit_count) { + for (const auto& e: commit_count) { if (e.second >= threshold) { mark_as_committed(cpsp->block_id); } @@ -318,43 +319,45 @@ namespace eosio { } } - pbft_commit pbft_database::send_and_add_pbft_commit(const pbft_commit& cached_commit, pbft_view_type current_view) { - pbft_commit commit_to_be_cached; + vector pbft_database::generate_and_add_pbft_commit(const pbft_commit &cached_commit, + pbft_view_type current_view) { + vector commits_to_be_cached; + const auto& my_sps = ctrl.my_signature_providers(); + commits_to_be_cached.reserve(my_sps.size()); if (!cached_commit.empty()) { - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { //sign again, update cache, then emit auto retry_c = cached_commit; retry_c.common.timestamp = time_point::now(); retry_c.sender_signature = sp.second(retry_c.digest(chain_id)); - emit(pbft_outgoing_commit, std::make_shared(retry_c)); + commits_to_be_cached.emplace_back(retry_c); } } else { - auto const &by_prepare_and_num_index = pbft_state_index.get(); + const auto& by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); - if (itr == by_prepare_and_num_index.end()) return commit_to_be_cached; + if (itr == by_prepare_and_num_index.end()) return commits_to_be_cached; pbft_state_ptr psp = *itr; auto bs = ctrl.fork_db().get_block(psp->block_id); - if (!bs) return commit_to_be_cached; + if (!bs) return commits_to_be_cached; if (psp->is_prepared && (psp->block_num > ctrl.last_irreversible_block_num())) { - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { pbft_commit new_c; - new_c.view=current_view; - new_c.block_info={psp->block_id}; + new_c.view = current_view; + new_c.block_info = {psp->block_id}; new_c.sender_signature = sp.second(new_c.digest(chain_id)); if (is_valid_commit(new_c, sp.first)) { - emit(pbft_outgoing_commit, std::make_shared(new_c)); add_pbft_commit(new_c, sp.first); - if (commit_to_be_cached.empty()) commit_to_be_cached = new_c; + commits_to_be_cached.emplace_back(new_c); } } } } - return commit_to_be_cached; + return commits_to_be_cached; } void pbft_database::mark_as_committed(const block_id_type& bid) { @@ -365,7 +368,7 @@ namespace eosio { } bool pbft_database::should_committed() { - auto const &by_commit_and_num_index = pbft_state_index.get(); + const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end()) return false; pbft_state_ptr psp = *itr; @@ -377,7 +380,7 @@ namespace eosio { pbft_view_type new_view = 0; if (!should_committed()) return new_view; - auto const &by_commit_and_num_index = pbft_state_index.get(); + const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); pbft_state_ptr psp = *itr; @@ -390,17 +393,17 @@ namespace eosio { auto threshold = as.size() * 2 / 3 + 1; flat_map commit_count; - for (auto const &com: commits) { + for (const auto& com: commits) { if (commit_count.find(com.second.view) == commit_count.end()) commit_count[com.second.view] = 0; } - for (auto const &bp: as) { - for (auto const &pc: commits) { + for (const auto& bp: as) { + for (const auto& pc: commits) { if (bp.block_signing_key == pc.first.second) commit_count[pc.first.first] += 1; } } - for (auto const &e: commit_count) { + for (const auto& e: commit_count) { if (e.second >= threshold && e.first > new_view) { new_view = e.first; } @@ -414,7 +417,7 @@ namespace eosio { } void pbft_database::commit_local() { - auto const &by_commit_and_num_index = pbft_state_index.get(); + const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end()) return; @@ -460,8 +463,8 @@ namespace eosio { if (vsp->view_changes.size() >= threshold && !vsp->is_view_changed) { auto vc_count = 0; - for (auto const &bp: lscb_bps) { - for (auto const &v: vsp->view_changes) { + for (const auto& bp: lscb_bps) { + for (const auto& v: vsp->view_changes) { if (bp.block_signing_key == v.first) vc_count += 1; } } @@ -482,8 +485,8 @@ namespace eosio { auto vc_count = 0; auto pvs = (*itr); - for (auto const &bp: active_bps) { - for (auto const &v: pvs->view_changes) { + for (const auto& bp: active_bps) { + for (const auto& v: pvs->view_changes) { if (bp.block_signing_key == v.first) vc_count += 1; } } @@ -497,42 +500,43 @@ namespace eosio { return nv; } - pbft_view_change pbft_database::send_and_add_pbft_view_change( - const pbft_view_change& cached_view_change, - const pbft_prepared_certificate& ppc, - const vector& pcc, + vector pbft_database::generate_and_add_pbft_view_change( + const pbft_view_change &cached_view_change, + const pbft_prepared_certificate &ppc, + const vector &pcc, pbft_view_type current_view, pbft_view_type target_view) { - pbft_view_change view_change_to_be_cached; + vector view_changes_to_be_cached; + const auto& my_sps = ctrl.my_signature_providers(); + view_changes_to_be_cached.reserve(my_sps.size()); + if (!cached_view_change.empty()) { - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { //sign again, update cache, then emit auto retry_vc = cached_view_change; retry_vc.common.timestamp = time_point::now(); retry_vc.sender_signature = sp.second(retry_vc.digest(chain_id)); - emit(pbft_outgoing_view_change, std::make_shared(retry_vc)); + view_changes_to_be_cached.emplace_back(retry_vc); } } else { - for (auto const &my_sp : ctrl.my_signature_providers()) { - + for (const auto& sp : my_sps) { auto my_lsc = get_stable_checkpoint_by_id(ctrl.last_stable_checkpoint_block_id()); pbft_view_change new_vc; - new_vc.current_view=current_view; - new_vc.target_view=target_view; - new_vc.prepared_cert=ppc; - new_vc.committed_certs=pcc; - new_vc.stable_checkpoint=my_lsc; - new_vc.sender_signature = my_sp.second(new_vc.digest(chain_id)); - if (is_valid_view_change(new_vc, my_sp.first)) { - emit(pbft_outgoing_view_change, std::make_shared(new_vc)); - add_pbft_view_change(new_vc, my_sp.first); - if (view_change_to_be_cached.empty()) view_change_to_be_cached = new_vc; + new_vc.current_view = current_view; + new_vc.target_view = target_view; + new_vc.prepared_cert = ppc; + new_vc.committed_certs = pcc; + new_vc.stable_checkpoint = my_lsc; + new_vc.sender_signature = sp.second(new_vc.digest(chain_id)); + if (is_valid_view_change(new_vc, sp.first)) { + add_pbft_view_change(new_vc, sp.first); + view_changes_to_be_cached.emplace_back(new_vc); } } } - return view_change_to_be_cached; + return view_changes_to_be_cached; } bool pbft_database::should_new_view(pbft_view_type target_view) { @@ -562,8 +566,8 @@ namespace eosio { ctrl.reset_pbft_my_prepare(); } - pbft_new_view pbft_database::send_pbft_new_view( - const pbft_view_changed_certificate& vcc, + pbft_new_view pbft_database::generate_pbft_new_view( + const pbft_view_changed_certificate &vcc, pbft_view_type current_view) { pbft_new_view nv; @@ -579,12 +583,12 @@ namespace eosio { auto highest_pcc = vector{}; auto highest_sc = pbft_stable_checkpoint(); - for (auto const &vc: vcc.view_changes) { + for (const auto& vc: vcc.view_changes) { if (vc.prepared_cert.block_info.block_num() > highest_ppc.block_info.block_num()) { highest_ppc = vc.prepared_cert; } - for (auto const &cc: vc.committed_certs) { + for (const auto& cc: vc.committed_certs) { auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), [&](const pbft_committed_certificate& ext) { return ext.block_info.block_id == cc.block_info.block_id; }); if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); @@ -595,15 +599,14 @@ namespace eosio { } } - nv.new_view=current_view; - nv.prepared_cert=highest_ppc; - nv.committed_certs=highest_pcc; - nv.stable_checkpoint=highest_sc; - nv.view_changed_cert=vcc; + nv.new_view = current_view; + nv.prepared_cert = highest_ppc; + nv.committed_certs = highest_pcc; + nv.stable_checkpoint = highest_sc; + nv.view_changed_cert = vcc; nv.sender_signature = sp_itr->second(nv.digest(chain_id)); try { validate_new_view(nv, sp_itr->first); - emit(pbft_outgoing_new_view, std::make_shared(nv)); } catch (const fc::exception& ex) { elog("bad new view, ${s} ", ("s", ex.to_string())); nv = pbft_new_view(); @@ -615,7 +618,7 @@ namespace eosio { pbft_prepared_certificate ppc; - auto const &by_prepare_and_num_index = pbft_state_index.get(); + const auto& by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); if (itr == by_prepare_and_num_index.end()) return ppc; pbft_state_ptr psp = *itr; @@ -631,19 +634,19 @@ namespace eosio { flat_map prepare_count; flat_map> prepare_msg; - for (auto const &pre: prepares) { + for (const auto& pre: prepares) { if (prepare_count.find(pre.first.first) == prepare_count.end()) prepare_count[pre.first.first] = 0; prepare_msg[pre.first.first].emplace_back(pre.second); } - for (auto const &bp: as) { - for (auto const &pp: prepares) { + for (const auto& bp: as) { + for (const auto& pp: prepares) { if (bp.block_signing_key == pp.first.second) prepare_count[pp.first.first] += 1; } } auto bp_threshold = as.size() * 2 / 3 + 1; - for (auto const &e: prepare_count) { + for (const auto& e: prepare_count) { if (e.second >= bp_threshold) { valid_prepares = prepare_msg[e.first]; } @@ -651,8 +654,10 @@ namespace eosio { if (valid_prepares.empty()) return ppc; - ppc.block_info={psp->block_id}; ppc.prepares=valid_prepares; ppc.pre_prepares.emplace(psp->block_id); - for (auto const &p: valid_prepares) { + ppc.block_info = {psp->block_id}; + ppc.prepares=valid_prepares; + ppc.pre_prepares.emplace(psp->block_id); + for (const auto& p: valid_prepares) { auto bid = p.block_info.block_id; while (bid != psp->block_id) { ppc.pre_prepares.emplace(bid); @@ -667,7 +672,7 @@ namespace eosio { vector pcc{}; - auto const &by_commit_and_num_index = pbft_state_index.get(); + const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end()) return pcc; @@ -695,11 +700,11 @@ namespace eosio { } } - auto const &by_id_index = pbft_state_index.get(); + const auto& by_id_index = pbft_state_index.get(); std::sort(ccb.begin(), ccb.end()); pcc.reserve(ccb.size()); - for (auto const &committed_block_num: ccb) { + for (const auto& committed_block_num: ccb) { auto cbs = ctrl.fetch_block_state_by_number(committed_block_num); if (!cbs) return pcc; @@ -716,19 +721,19 @@ namespace eosio { flat_map commit_count; flat_map> commit_msg; - for (auto const &com: commits) { + for (const auto& com: commits) { if (commit_count.find(com.first.first) == commit_count.end()) commit_count[com.first.first] = 0; commit_msg[com.first.first].emplace_back(com.second); } - for (auto const &bp: as) { - for (auto const &cc: commits) { + for (const auto& bp: as) { + for (const auto& cc: commits) { if (bp.block_signing_key == cc.first.second) commit_count[cc.first.first] += 1; } } auto bp_threshold = as.size() * 2 / 3 + 1; - for (auto const &e: commit_count) { + for (const auto& e: commit_count) { if (e.second >= bp_threshold) { valid_commits = commit_msg[e.first]; } @@ -737,7 +742,8 @@ namespace eosio { if (valid_commits.empty()) return pcc; pbft_committed_certificate cc; - cc.block_info={cbs->id}; cc.commits=valid_commits; + cc.block_info = {cbs->id}; + cc.commits = valid_commits; pcc.emplace_back(cc); } return pcc; @@ -792,19 +798,19 @@ namespace eosio { flat_map prepare_count; - for (auto const &pm: prepares_metadata) { + for (const auto& pm: prepares_metadata) { if (prepare_count.find(pm.msg.view) == prepare_count.end()) prepare_count[pm.msg.view] = 0; } - for (auto const &bp: producer_schedule.producers) { - for (auto const &pm: prepares_metadata) { + for (const auto& bp: producer_schedule.producers) { + for (const auto& pm: prepares_metadata) { if (bp.block_signing_key == pm.sender_key) prepare_count[pm.msg.view] += 1; } } auto should_prepared = false; - for (auto const &e: prepare_count) { + for (const auto& e: prepare_count) { if (e.second >= bp_threshold) { should_prepared = true; } @@ -815,9 +821,9 @@ namespace eosio { //validate prepare auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto non_fork_bp_count = 0; - vector prepare_infos; + fork_info_type prepare_infos; prepare_infos.reserve(certificate.prepares.size()); - for (auto const &p : certificate.prepares) { + for (const auto& p : certificate.prepares) { //only search in fork db if (p.block_info.block_num() <= lscb_num) { ++non_fork_bp_count; @@ -855,19 +861,19 @@ namespace eosio { flat_map commit_count; - for (auto const &cm: commits_metadata) { + for (const auto& cm: commits_metadata) { if (commit_count.find(cm.msg.view) == commit_count.end()) commit_count[cm.msg.view] = 0; } - for (auto const &bp: producer_schedule.producers) { - for (auto const &cm: commits_metadata) { + for (const auto& bp: producer_schedule.producers) { + for (const auto& cm: commits_metadata) { if (bp.block_signing_key == cm.sender_key) commit_count[cm.msg.view] += 1; } } auto should_committed = false; - for (auto const &e: commit_count) { + for (const auto& e: commit_count) { if (e.second >= bp_threshold) { should_committed = true; } @@ -878,9 +884,9 @@ namespace eosio { //validate commit auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto non_fork_bp_count = 0; - vector commit_infos; + fork_info_type commit_infos; commit_infos.reserve(certificate.commits.size()); - for (auto const &c : certificate.commits) { + for (const auto& c : certificate.commits) { //only search in fork db if (c.block_info.block_num() <= lscb_num) { ++non_fork_bp_count; @@ -897,7 +903,6 @@ namespace eosio { // No need to check prepared cert and stable checkpoint, until generate or validate a new view msg } - void pbft_database::validate_new_view(const pbft_new_view& nv, const public_key_type& pk) { EOS_ASSERT(pk == get_new_view_primary_key(nv.new_view), pbft_exception, @@ -911,7 +916,7 @@ namespace eosio { auto committed_certs = nv.committed_certs; std::sort(committed_certs.begin(), committed_certs.end()); - for (auto const &c: committed_certs) { + for (const auto& c: committed_certs) { EOS_ASSERT(is_valid_committed_certificate(c, true), pbft_exception, "bad committed certificate: ${cc}", ("cc", c)); } @@ -920,7 +925,7 @@ namespace eosio { vector lscb_producers; lscb_producers.reserve(lscb_active_producers().producers.size()); - for (auto const &bp: lscb_active_producers().producers) { + for (const auto& bp: lscb_active_producers().producers) { lscb_producers.emplace_back(bp.block_signing_key); } auto schedule_threshold = lscb_producers.size() * 2 / 3 + 1; @@ -957,13 +962,13 @@ namespace eosio { auto highest_pcc = vector{}; auto highest_scp = pbft_stable_checkpoint(); - for (auto const &vc: nv.view_changed_cert.view_changes) { + for (const auto& vc: nv.view_changed_cert.view_changes) { if (vc.prepared_cert.block_info.block_num() > highest_ppc.block_info.block_num() && is_valid_prepared_certificate(vc.prepared_cert)) { highest_ppc = vc.prepared_cert; } - for (auto const &cc: vc.committed_certs) { + for (const auto& cc: vc.committed_certs) { if (is_valid_committed_certificate(cc)) { auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), [&](const pbft_committed_certificate &ext) { @@ -1003,9 +1008,9 @@ namespace eosio { return vc_lscb > 0 && lscb_num > vc_lscb; } - vector> pbft_database::fetch_fork_from(vector& block_infos) { + vector pbft_database::fetch_fork_from(fork_info_type& block_infos) { - vector> result; + vector result; if (block_infos.empty()) { return result; } @@ -1026,8 +1031,8 @@ namespace eosio { return result; } - vector pbft_database::fetch_first_fork_from(vector& bi) { - vector result; + fork_info_type pbft_database::fetch_first_fork_from(fork_info_type& bi) { + fork_info_type result; if (bi.empty()) { return result; } @@ -1067,22 +1072,22 @@ namespace eosio { return result; } - bool pbft_database::is_valid_longest_fork(const block_info_type& bi, vector block_infos, unsigned long threshold, unsigned long non_fork_bp_count) { + bool pbft_database::is_valid_longest_fork( + const block_info_type& bi, + fork_info_type block_infos, + unsigned long threshold, + unsigned long non_fork_bp_count) { auto forks = fetch_fork_from(block_infos); - vector longest_fork; - for (auto const &f : forks) { + fork_info_type longest_fork; + for (const auto& f : forks) { if (f.size() > longest_fork.size()) { longest_fork = f; } } - if (longest_fork.size() + non_fork_bp_count < threshold) return false; - - if (longest_fork.empty()) return true; - - auto calculated_block_info = longest_fork.back(); - return bi.block_id == calculated_block_info.block_id; + return longest_fork.empty() + || (longest_fork.size() + non_fork_bp_count >= threshold && bi.block_id == longest_fork.back().block_id); } pbft_stable_checkpoint pbft_database::fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr& b) { @@ -1099,7 +1104,7 @@ namespace eosio { fc::raw::unpack(ds, psc); if (is_valid_stable_checkpoint(psc)) { - return psc; + break; } else { it = extn.erase(it); } @@ -1117,7 +1122,7 @@ namespace eosio { pbft_stable_checkpoint pbft_database::get_stable_checkpoint_by_id(const block_id_type& block_id, bool incl_blk_extn ) { pbft_stable_checkpoint psc; - auto const &by_block = checkpoint_index.get(); + const auto& by_block = checkpoint_index.get(); auto itr = by_block.find(block_id); if (itr == by_block.end()) { if (incl_blk_extn) { @@ -1145,7 +1150,7 @@ namespace eosio { auto pending_scb_num = ctrl.last_stable_checkpoint_block_num(); auto pending_scb_info = block_info_type{ctrl.last_stable_checkpoint_block_id()}; - auto const &by_blk_num = checkpoint_index.get(); + const auto& by_blk_num = checkpoint_index.get(); auto itr = by_blk_num.lower_bound(pending_scb_num); if (itr == by_blk_num.end()) return pending_scb_info; @@ -1159,7 +1164,7 @@ namespace eosio { producer_schedule_type new_schedule; if (pending_scb_num == 0) { - auto const &ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; + const auto& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; if (ucb == 0) { current_schedule = ctrl.initial_schedule(); new_schedule = ctrl.initial_schedule(); @@ -1203,7 +1208,7 @@ namespace eosio { vector new_pc{}; - auto const &by_commit_and_num_index = pbft_state_index.get(); + const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end() || !(*itr)->is_committed) return new_pc; @@ -1221,7 +1226,7 @@ namespace eosio { pending_checkpoint_block_num[i] = false; } else { auto checkpoints = (*c_itr)->checkpoints; - for (auto const &my_sp : ctrl.my_signature_providers()) { + for (const auto& my_sp : ctrl.my_signature_providers()) { if (checkpoints.find(my_sp.first) != checkpoints.end() && !(*c_itr)->is_stable) { pending_checkpoint_block_num[i] = true; //retry sending at this time. } @@ -1239,9 +1244,9 @@ namespace eosio { std::sort(pending_checkpoint_block_num.begin(), pending_checkpoint_block_num.end()); for (auto& bnum_and_retry: pending_checkpoint_block_num) { if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(bnum_and_retry.first)) { - for (auto const &my_sp : ctrl.my_signature_providers()) { + for (const auto& my_sp : ctrl.my_signature_providers()) { pbft_checkpoint cp; - cp.block_info={bs->id}; + cp.block_info = {bs->id}; cp.sender_signature = my_sp.second(cp.digest(chain_id)); if (!bnum_and_retry.second && is_valid_checkpoint(cp, my_sp.first)) { //first time sending this checkpoint add_pbft_checkpoint(cp, my_sp.first); @@ -1251,7 +1256,7 @@ namespace eosio { } } } else if (lscb_num > 0) { //retry sending my lscb - for (auto const &my_sp : ctrl.my_signature_providers()) { + for (const auto& my_sp : ctrl.my_signature_providers()) { pbft_checkpoint cp; cp.block_info={ctrl.last_stable_checkpoint_block_id()}; cp.sender_signature = my_sp.second(cp.digest(chain_id)); @@ -1294,8 +1299,8 @@ namespace eosio { if (csp->checkpoints.size() >= threshold && !csp->is_stable) { auto cp_count = 0; - for (auto const &bp: active_bps) { - for (auto const &c: csp->checkpoints) { + for (const auto& bp: active_bps) { + for (const auto& c: csp->checkpoints) { if (bp.block_signing_key == c.first) cp_count += 1; } } @@ -1322,18 +1327,12 @@ namespace eosio { } } - void pbft_database::send_pbft_checkpoint() { - auto cps_to_send = generate_and_add_pbft_checkpoint(); - for (auto const &cp: cps_to_send) { - emit(pbft_outgoing_checkpoint, std::make_shared(cp)); - } - } - void pbft_database::checkpoint_local() { auto pending_scb_info = cal_pending_stable_checkpoint(); auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto pending_num = pending_scb_info.block_num(); auto pending_id = pending_scb_info.block_id; + //TODO: optimise prune logic if (pending_num > lscb_num) { ctrl.set_pbft_latest_checkpoint(pending_id); if (ctrl.last_irreversible_block_num() < pending_num) ctrl.pbft_commit_local(pending_id); @@ -1358,7 +1357,7 @@ namespace eosio { if (auto bs = ctrl.fetch_block_state_by_id(cp.block_info.block_id)) { auto active_bps = bs->active_schedule.producers; - for (auto const &bp: active_bps) { + for (const auto& bp: active_bps) { if (bp.block_signing_key == pk) return true; } } @@ -1388,8 +1387,8 @@ namespace eosio { if (auto bs = ctrl.fetch_block_state_by_number(scp.block_info.block_num())) { auto as = bs->active_schedule; auto cp_count = 0; - for (auto const &bp: as.producers) { - for (auto const &cpm: checkpoints_metadata) { + for (const auto& bp: as.producers) { + for (const auto& cpm: checkpoints_metadata) { if (bp.block_signing_key == cpm.sender_key) cp_count += 1; } } @@ -1402,8 +1401,8 @@ namespace eosio { bool pbft_database::should_send_pbft_msg() { auto schedules = get_updated_fork_schedules(); - for (auto const &bp: schedules) { - for (auto const &sp: ctrl.my_signature_providers()) { + for (const auto& bp: schedules) { + for (const auto& sp: ctrl.my_signature_providers()) { if (bp.first == sp.first) return true; } } @@ -1413,7 +1412,7 @@ namespace eosio { bool pbft_database::should_recv_pbft_msg(const public_key_type& pub_key) { auto schedules = get_updated_fork_schedules(); - for (auto const &bp: schedules) { + for (const auto& bp: schedules) { if (bp.first == pub_key) return true; } return false; @@ -1433,7 +1432,7 @@ namespace eosio { auto num = ctrl.last_stable_checkpoint_block_num(); if (num == 0) { - auto const &ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; + const auto& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; if (ucb == 0) return ps; num = ucb; } @@ -1612,22 +1611,5 @@ namespace eosio { checkpoint_index.erase(itr); } } - - template - void pbft_database::emit(const Signal &s, Arg &&a) { - try { - s(std::forward(a)); - } catch (boost::interprocess::bad_alloc &e) { - wlog("bad alloc"); - throw e; - } catch (controller_emit_signal_exception &e) { - wlog("${details}", ("details", e.to_detail_string())); - throw e; - } catch (fc::exception &e) { - wlog("${details}", ("details", e.to_detail_string())); - } catch (...) { - wlog("signal handler threw exception"); - } - } } } \ No newline at end of file diff --git a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp index 81935707abe..9a3212a56fd 100644 --- a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp +++ b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp @@ -80,6 +80,9 @@ namespace eosio { namespace chain { namespace plugin_interface { using checkpoint_channel = channel_decl; } + + using committed_transition_channel = channel_decl; + using prepared_transition_channel = channel_decl; } } } } diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 581bcb80443..c720b348e10 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -740,7 +740,7 @@ void chain_plugin::plugin_initialize(const variables_map& options) { ilog("include pbft controller..."); my->pbft_ctrl.emplace(*my->chain); - // set up method providers + // set up method providers my->get_block_by_number_provider = app().get_method().register_provider( [this]( uint32_t block_num ) -> signed_block_ptr { return my->chain->fetch_block_by_number( block_num ); @@ -825,27 +825,27 @@ void chain_plugin::plugin_initialize(const variables_map& options) { my->on_pbft_incoming_checkpoint(cp); }); - my->pbft_outgoing_prepare_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_prepare.connect( + my->pbft_outgoing_prepare_connection = my->pbft_ctrl->state_machine.pbft_outgoing_prepare.connect( [this]( const pbft_prepare_ptr& prepare ) { my->pbft_outgoing_prepare_channel.publish( prepare ); }); - my->pbft_outgoing_commit_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_commit.connect( + my->pbft_outgoing_commit_connection = my->pbft_ctrl->state_machine.pbft_outgoing_commit.connect( [this]( const pbft_commit_ptr& commit ) { my->pbft_outgoing_commit_channel.publish( commit ); }); - my->pbft_outgoing_view_change_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_view_change.connect( + my->pbft_outgoing_view_change_connection = my->pbft_ctrl->state_machine.pbft_outgoing_view_change.connect( [this]( const pbft_view_change_ptr& view_change ) { my->pbft_outgoing_view_change_channel.publish( view_change ); }); - my->pbft_outgoing_new_view_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_new_view.connect( + my->pbft_outgoing_new_view_connection = my->pbft_ctrl->state_machine.pbft_outgoing_new_view.connect( [this]( const pbft_new_view_ptr& new_view ) { my->pbft_outgoing_new_view_channel.publish( new_view ); }); - my->pbft_outgoing_checkpoint_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_checkpoint.connect( + my->pbft_outgoing_checkpoint_connection = my->pbft_ctrl->state_machine.pbft_outgoing_checkpoint.connect( [this]( const pbft_checkpoint_ptr& checkpoint ) { my->pbft_outgoing_checkpoint_channel.publish( checkpoint ); }); @@ -1209,8 +1209,8 @@ read_only::get_info_results read_only::get_info(const read_only::get_info_params db.fork_db_head_block_id(), db.fork_db_head_block_time(), db.fork_db_head_block_producer(), - pbft_ctrl.state_machine->get_current_view(), - pbft_ctrl.state_machine->get_target_view(), + pbft_ctrl.state_machine.get_current_view(), + pbft_ctrl.state_machine.get_target_view(), db.last_stable_checkpoint_block_num(), rm.get_virtual_block_cpu_limit(), rm.get_virtual_block_net_limit(), diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index d10d9be5048..f9e611ad229 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -251,9 +251,7 @@ namespace eosio { template bool is_pbft_msg_valid(const M& msg); - void bcast_pbft_msg(const net_message& msg, int ttl); - - void forward_pbft_msg(const connection_ptr& c, const net_message& msg, int ttl); + void bcast_pbft_msg(const net_message& msg, int ttl, const connection_ptr& c = nullptr); void pbft_outgoing_prepare(const pbft_prepare_ptr& prepare); void pbft_outgoing_commit(const pbft_commit_ptr& commit); @@ -2998,21 +2996,11 @@ namespace eosio { && !sync_master->is_syncing(); } - void net_plugin_impl::bcast_pbft_msg(const net_message &msg, int ttl) { - if (sync_master->is_syncing()) return; + void net_plugin_impl::bcast_pbft_msg(const net_message &msg, int ttl, const connection_ptr& c) { +// if (sync_master->is_syncing()) return; auto deadline = time_point_sec(time_point::now()) + ttl; - for (auto &conn: connections) { - if (conn->pbft_ready()) { - conn->enqueue_pbft(encode_pbft_message(msg), deadline); - } - } - } - - void net_plugin_impl::forward_pbft_msg(const connection_ptr& c, const net_message &msg, int ttl) { - auto deadline = time_point_sec(time_point::now()) + ttl; - for (auto &conn: connections) { if (conn != c && conn->pbft_ready()) { conn->enqueue_pbft(encode_pbft_message(msg), deadline); @@ -3021,43 +3009,42 @@ namespace eosio { } void net_plugin_impl::pbft_outgoing_prepare(const pbft_prepare_ptr& msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); - if (!added) return; - - bcast_pbft_msg(*msg, pbft_message_TTL); - fc_dlog( logger, "sent prepare at height: ${n}, view: ${v} ", ("n", msg->block_info.block_num())("v", msg->view)); + if (maybe_add_to_pbft_cache(std::string(msg->sender_signature))) { + bcast_pbft_msg(*msg, pbft_message_TTL); + fc_dlog(logger, "sent prepare at height: ${n}, view: ${v} ", + ("n", msg->block_info.block_num())("v", msg->view)); + } } void net_plugin_impl::pbft_outgoing_commit(const pbft_commit_ptr& msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); - if (!added) return; - - bcast_pbft_msg(*msg, pbft_message_TTL); - fc_dlog( logger, "sent commit at height: ${n}, view: ${v} ", ("n", msg->block_info.block_num())("v", msg->view)); + if (maybe_add_to_pbft_cache(std::string(msg->sender_signature))) { + bcast_pbft_msg(*msg, pbft_message_TTL); + fc_dlog(logger, "sent commit at height: ${n}, view: ${v} ", + ("n", msg->block_info.block_num())("v", msg->view)); + } } void net_plugin_impl::pbft_outgoing_view_change(const pbft_view_change_ptr& msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); - if (!added) return; - - bcast_pbft_msg(*msg, pbft_message_TTL); - fc_dlog( logger, "sent view change {cv: ${cv}, tv: ${tv}}", ("cv", msg->current_view)("tv", msg->target_view)); + if (maybe_add_to_pbft_cache(std::string(msg->sender_signature))) { + bcast_pbft_msg(*msg, pbft_message_TTL); + fc_dlog(logger, "sent view change {cv: ${cv}, tv: ${tv}}", + ("cv", msg->current_view)("tv", msg->target_view)); + } } void net_plugin_impl::pbft_outgoing_new_view(const pbft_new_view_ptr& msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); - if (!added) return; + if (maybe_add_to_pbft_cache(std::string(msg->sender_signature))) { + bcast_pbft_msg(*msg, 60 * pbft_message_TTL); + fc_dlog( logger, "sent new view at view: ${v} ", ("v", msg->new_view)); + } - bcast_pbft_msg(*msg, 60 * pbft_message_TTL); - fc_dlog( logger, "sent new view at view: ${v} ", ("v", msg->new_view)); } void net_plugin_impl::pbft_outgoing_checkpoint(const pbft_checkpoint_ptr& msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); - if (!added) return; - - bcast_pbft_msg(*msg, pbft_message_TTL); - fc_dlog( logger, "sent checkpoint at height: ${n} ", ("n", msg->block_info.block_num())); + if (maybe_add_to_pbft_cache(std::string(msg->sender_signature))) { + bcast_pbft_msg(*msg, pbft_message_TTL); + fc_dlog(logger, "sent checkpoint at height: ${n} ", ("n", msg->block_info.block_num())); + } } bool net_plugin_impl::maybe_add_to_pbft_cache(const string &key){ @@ -3085,95 +3072,89 @@ namespace eosio { } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_prepare &msg) { - if (!is_pbft_msg_valid(msg)) return; - - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; + if (is_pbft_msg_valid(msg) && maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { + auto pmm = pbft_message_metadata(msg, chain_id); - auto pmm = pbft_message_metadata(std::move(msg), chain_id); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + if (!pcc.pbft_db.is_valid_prepare(pmm.msg, pmm.sender_key)) return; + bcast_pbft_msg(pmm.msg, pbft_message_TTL, c); + fc_dlog(logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", + ("n", pmm.msg.block_info.block_num())("v", pmm.msg.view)("k", pmm.sender_key)); - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_prepare(pmm.msg, pmm.sender_key)) return; - - forward_pbft_msg(c, pmm.msg, pbft_message_TTL); - fc_dlog( logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", pmm.msg.block_info.block_num())("v", pmm.msg.view)("k", pmm.sender_key)); + pbft_incoming_prepare_channel.publish(std::make_shared>(std::move(pmm))); + } - pbft_incoming_prepare_channel.publish(std::make_shared>(std::move(pmm))); } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_commit &msg) { - if (!is_pbft_msg_valid(msg)) return; + if (is_pbft_msg_valid(msg) && maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { + auto pmm = pbft_message_metadata(msg, chain_id); - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + if (!pcc.pbft_db.is_valid_commit(pmm.msg, pmm.sender_key)) return; - auto pmm = pbft_message_metadata(std::move(msg), chain_id); + bcast_pbft_msg(pmm.msg, pbft_message_TTL, c); + fc_dlog(logger, "received commit at height: ${n}, view: ${v}, from ${k}, ", + ("n", pmm.msg.block_info.block_num())("v", pmm.msg.view)("k", pmm.sender_key)); - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_commit(pmm.msg, pmm.sender_key)) return; - - forward_pbft_msg(c, pmm.msg, pbft_message_TTL); - fc_dlog( logger, "received commit at height: ${n}, view: ${v}, from ${k}, ", ("n", pmm.msg.block_info.block_num())("v", pmm.msg.view)("k", pmm.sender_key)); - - pbft_incoming_commit_channel.publish(std::make_shared>(std::move(pmm))); + pbft_incoming_commit_channel.publish(std::make_shared>(std::move(pmm))); + } } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_view_change &msg) { - if (!is_pbft_msg_valid(msg)) return; - - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; + if (is_pbft_msg_valid(msg) && maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { + auto pmm = pbft_message_metadata(msg, chain_id); - auto pmm = pbft_message_metadata( std::move(msg), chain_id); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + controller &ctrl = my_impl->chain_plug->chain(); + if (!pcc.pbft_db.is_valid_view_change(pmm.msg, pmm.sender_key)) return; - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - controller &ctrl = my_impl->chain_plug->chain(); - if (!pcc.pbft_db.is_valid_view_change(pmm.msg, pmm.sender_key)) return; - - auto missing_blocks = set{}; - for (auto const &b: pmm.msg.prepared_cert.pre_prepares) { - if (!ctrl.fetch_block_by_id(b)) missing_blocks.emplace(b); - } + auto missing_blocks = set{}; + for (auto const &b: pmm.msg.prepared_cert.pre_prepares) { + if (!ctrl.fetch_block_by_id(b)) missing_blocks.emplace(b); + } - if (!missing_blocks.empty()) { - fc_dlog( logger, "requesting ${num} missing blocks from view change", ("num", missing_blocks.size())); - request_message req; - for (auto const &b: missing_blocks) { - req.req_blocks.ids.push_back(b); + if (!missing_blocks.empty()) { + fc_dlog(logger, "requesting ${num} missing blocks from view change", ("num", missing_blocks.size())); + request_message req; + for (auto const &b: missing_blocks) { + req.req_blocks.ids.push_back(b); + } + req.req_trx.mode = normal; + req.req_blocks.mode = normal; + c->enqueue(req); } - req.req_trx.mode = normal; - req.req_blocks.mode = normal; - c->enqueue(req); - } - forward_pbft_msg(c, pmm.msg, pbft_message_TTL); - fc_dlog( logger, "received view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", pmm.msg.current_view)("tv", pmm.msg.target_view)("v", pmm.sender_key)); + bcast_pbft_msg(pmm.msg, pbft_message_TTL, c); + fc_dlog(logger, "received view change {cv: ${cv}, tv: ${tv}} from ${v}", + ("cv", pmm.msg.current_view)("tv", pmm.msg.target_view)("v", pmm.sender_key)); - pbft_incoming_view_change_channel.publish(std::make_shared>(std::move(pmm))); + pbft_incoming_view_change_channel.publish(std::make_shared>(std::move(pmm))); + } } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_new_view &msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; + if (maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (time_point_sec(time_point::now()) > time_point_sec(msg.common.timestamp) + 60 * pbft_message_TTL - || msg.new_view <= pcc.state_machine->get_current_view()) { - //skip new view messages that are too old or whose target views are lower than mine. - return; - } + if (time_point_sec(time_point::now()) > time_point_sec(msg.common.timestamp) + 60 * pbft_message_TTL + || msg.new_view <= pcc.state_machine.get_current_view()) { + //skip new view messages that are too old or whose target views are lower than mine. + return; + } - auto pmm = pbft_message_metadata(std::move(msg), chain_id); + auto pmm = pbft_message_metadata(msg, chain_id); - if (pmm.sender_key != pcc.pbft_db.get_new_view_primary_key(pmm.msg.new_view)) return; + if (pmm.sender_key != pcc.pbft_db.get_new_view_primary_key(pmm.msg.new_view)) return; - forward_pbft_msg(c, pmm.msg, 60 * pbft_message_TTL); - fc_dlog( logger, "received new view: ${n}, from ${v}", ("n", pmm.msg)("v", pmm.sender_key)); + bcast_pbft_msg(pmm.msg, 60 * pbft_message_TTL, c); + fc_dlog(logger, "received new view: ${n}, from ${v}", ("n", pmm.msg)("v", pmm.sender_key)); - pbft_incoming_new_view_channel.publish(std::make_shared>(std::move(pmm))); + pbft_incoming_new_view_channel.publish(std::make_shared>(std::move(pmm))); + } } void net_plugin_impl::handle_message( const connection_ptr& c, const compressed_pbft_message &msg) { @@ -3193,20 +3174,18 @@ namespace eosio { } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_checkpoint &msg) { - if (!is_pbft_msg_valid(msg)) return; - - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; + if (is_pbft_msg_valid(msg) && maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { + auto pmm = pbft_message_metadata(std::move(msg), chain_id); - auto pmm = pbft_message_metadata(std::move(msg), chain_id); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + if (!pcc.pbft_db.is_valid_checkpoint(pmm.msg, pmm.sender_key)) return; - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_checkpoint(pmm.msg, pmm.sender_key)) return; + bcast_pbft_msg(pmm.msg, pbft_message_TTL, c); + fc_dlog(logger, "received checkpoint at ${n}, from ${v}", + ("n", pmm.msg.block_info.block_num())("v", pmm.sender_key)); - forward_pbft_msg(c, pmm.msg, pbft_message_TTL); - fc_dlog( logger, "received checkpoint at ${n}, from ${v}", ("n", pmm.msg.block_info.block_num())("v", pmm.sender_key)); - - pbft_incoming_checkpoint_channel.publish(std::make_shared>(std::move(pmm))); + pbft_incoming_checkpoint_channel.publish(std::make_shared>(std::move(pmm))); + } } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_stable_checkpoint &msg) { @@ -3214,7 +3193,8 @@ namespace eosio { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_stable_checkpoint(msg, true)) return; - fc_ilog(logger, "received stable checkpoint at ${n}, from ${v}", ("n", msg.block_info.block_num())("v", c->peer_name())); + fc_ilog(logger, "received stable checkpoint at ${n}, from ${v}", + ("n", msg.block_info.block_num())("v", c->peer_name())); } void net_plugin_impl::start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection) { diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index ebff9c785f1..674a4ead103 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -3,14 +3,23 @@ #include #include #include +#include namespace eosio { static appbase::abstract_plugin &_pbft_plugin = app().register_plugin(); using namespace std; using namespace eosio::chain; + using namespace eosio::chain::plugin_interface; + using boost::signals2::scoped_connection; + class pbft_plugin_impl { public: + pbft_plugin_impl() + :transit_to_committed_channel(app().get_channel()) + ,transit_to_prepared_channel(app().get_channel()) + {} + unique_ptr prepare_timer; unique_ptr commit_timer; unique_ptr view_change_timer; @@ -26,6 +35,15 @@ namespace eosio { void view_change_timer_tick(); void checkpoint_timer_tick(); + pbft::committed_transition_channel::channel_type::handle transit_to_committed_subscription; + pbft::committed_transition_channel::channel_type& transit_to_committed_channel; + + pbft::prepared_transition_channel::channel_type::handle transit_to_prepared_subscription; + pbft::prepared_transition_channel::channel_type& transit_to_prepared_channel; + + void on_committed_transition(); + void on_prepared_transition(); + private: bool upgraded = false; bool is_replaying(); @@ -33,109 +51,44 @@ namespace eosio { bool pbft_ready(); }; - pbft_plugin::pbft_plugin() : my(new pbft_plugin_impl()) {} - - pbft_plugin::~pbft_plugin() = default; - - void pbft_plugin::set_program_options(options_description &, options_description &cfg) { - } - - void pbft_plugin::plugin_initialize(const variables_map &options) { - ilog("Initialize pbft plugin"); - my->prepare_timer = std::make_unique(app().get_io_service()); - my->commit_timer = std::make_unique(app().get_io_service()); - my->view_change_timer = std::make_unique(app().get_io_service()); - my->checkpoint_timer = std::make_unique(app().get_io_service()); - } - - void pbft_plugin::plugin_startup() { - my->prepare_timer_tick(); - my->commit_timer_tick(); - my->view_change_timer_tick(); - my->checkpoint_timer_tick(); - } - - void pbft_plugin::plugin_shutdown() {} - - pbft_state pbft_plugin::get_pbft_record( const block_id_type& bid ) const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - auto record = pbft_ctrl.pbft_db.get_pbft_state_by_id(bid); - if (record) return *record; - return pbft_state(); - } - - vector pbft_plugin::get_pbft_checkpoints_record(block_num_type bnum) const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - auto records = pbft_ctrl.pbft_db.get_checkpoints_by_num(bnum); - if (!records.empty()) return records; - return vector(); - } - pbft_view_change_state pbft_plugin::get_view_change_record(pbft_view_type view) const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - auto record = pbft_ctrl.pbft_db.get_view_changes_by_target_view(view); - if (record) return *record; - return pbft_view_change_state(); - } - - vector pbft_plugin::get_watermarks() const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - return pbft_ctrl.pbft_db.get_pbft_watermarks(); - } - - flat_map pbft_plugin::get_fork_schedules() const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - return pbft_ctrl.pbft_db.get_pbft_fork_schedules(); - } - - const char* pbft_plugin::get_pbft_status() const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - return pbft_ctrl.state_machine->get_current()->get_name(); - } - - block_id_type pbft_plugin::get_pbft_prepared_id() const { - auto& ctrl = app().get_plugin().chain(); - return ctrl.get_pbft_prepared(); - } - - block_id_type pbft_plugin::get_pbft_my_prepare_id() const { - auto& ctrl = app().get_plugin().chain(); - return ctrl.get_pbft_my_prepare(); + void pbft_plugin_impl::on_committed_transition() { + prepare_timer->expires_from_now(prepare_timeout); } - void pbft_plugin::set_pbft_current_view(pbft_view_type view) { - //this is used to boost the recovery from a disaster, do not set this unless you have to do so. - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - pbft_ctrl.state_machine->manually_set_current_view(view); + void pbft_plugin_impl::on_prepared_transition() { + commit_timer->expires_from_now(commit_timeout); } void pbft_plugin_impl::prepare_timer_tick() { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + prepare_timer->expires_from_now(prepare_timeout); prepare_timer->async_wait([&](boost::system::error_code ec) { prepare_timer_tick(); if (ec) { wlog ("pbft plugin prepare timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { + chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_prepare(); } }); } void pbft_plugin_impl::commit_timer_tick() { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + commit_timer->expires_from_now(commit_timeout); commit_timer->async_wait([&](boost::system::error_code ec) { commit_timer_tick(); if (ec) { wlog ("pbft plugin commit timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { + chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_commit(); } }); } void pbft_plugin_impl::view_change_timer_tick() { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + try { view_change_timer->cancel(); } catch (boost::system::system_error &e) { @@ -147,26 +100,28 @@ namespace eosio { if (ec) { wlog ("pbft plugin view change timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { + chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_view_change(); } }); } void pbft_plugin_impl::checkpoint_timer_tick() { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + checkpoint_timer->expires_from_now(checkpoint_timeout); checkpoint_timer->async_wait([&](boost::system::error_code ec) { checkpoint_timer_tick(); if (ec) { wlog ("pbft plugin checkpoint timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { + chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_checkpoint(); - chain::controller &ctrl = app().get_plugin().chain(); - if ( ctrl.head_block_num() - ctrl.last_stable_checkpoint_block_num() / pbft_checkpoint_granularity > 1) { - //perhaps we need to sync stable checkpoints from other peers - app().get_plugin().maybe_sync_stable_checkpoints(); - } + chain::controller &ctrl = app().get_plugin().chain(); + if ( ctrl.head_block_num() - ctrl.last_stable_checkpoint_block_num() / pbft_checkpoint_granularity > 1) { + //perhaps we need to sync stable checkpoints from other peers + app().get_plugin().maybe_sync_stable_checkpoints(); + } } }); } @@ -201,4 +156,87 @@ namespace eosio { return enabled && !is_syncing() && !is_replaying(); } + + pbft_plugin::pbft_plugin() : my(new pbft_plugin_impl()) {} + + pbft_plugin::~pbft_plugin() = default; + + void pbft_plugin::set_program_options(options_description &, options_description &cfg) { + } + + void pbft_plugin::plugin_initialize(const variables_map &options) { + ilog("Initialize pbft plugin"); + my->prepare_timer = std::make_unique(app().get_io_service()); + my->commit_timer = std::make_unique(app().get_io_service()); + my->view_change_timer = std::make_unique(app().get_io_service()); + my->checkpoint_timer = std::make_unique(app().get_io_service()); + } + + void pbft_plugin::plugin_startup() { + my->prepare_timer_tick(); + my->commit_timer_tick(); + my->view_change_timer_tick(); + my->checkpoint_timer_tick(); + + my->transit_to_prepared_subscription = my->transit_to_prepared_channel.subscribe( [this]( bool prepared ) { + my->on_prepared_transition(); + }); + + my->transit_to_committed_subscription = my->transit_to_committed_channel.subscribe( [this]( bool committed ) { + my->on_committed_transition(); + }); + } + + void pbft_plugin::plugin_shutdown() {} + + pbft_state pbft_plugin::get_pbft_record( const block_id_type& bid ) const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto record = pbft_ctrl.pbft_db.get_pbft_state_by_id(bid); + if (record) return *record; + return pbft_state(); + } + + vector pbft_plugin::get_pbft_checkpoints_record(block_num_type bnum) const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto records = pbft_ctrl.pbft_db.get_checkpoints_by_num(bnum); + if (!records.empty()) return records; + return vector(); + } + pbft_view_change_state pbft_plugin::get_view_change_record(pbft_view_type view) const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto record = pbft_ctrl.pbft_db.get_view_changes_by_target_view(view); + if (record) return *record; + return pbft_view_change_state(); + } + + vector pbft_plugin::get_watermarks() const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + return pbft_ctrl.pbft_db.get_pbft_watermarks(); + } + + flat_map pbft_plugin::get_fork_schedules() const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + return pbft_ctrl.pbft_db.get_pbft_fork_schedules(); + } + + const char* pbft_plugin::get_pbft_status() const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + return pbft_ctrl.state_machine.get_current()->get_name(); + } + + block_id_type pbft_plugin::get_pbft_prepared_id() const { + auto& ctrl = app().get_plugin().chain(); + return ctrl.get_pbft_prepared(); + } + + block_id_type pbft_plugin::get_pbft_my_prepare_id() const { + auto& ctrl = app().get_plugin().chain(); + return ctrl.get_pbft_my_prepare(); + } + + void pbft_plugin::set_pbft_current_view(pbft_view_type view) { + //this is used to boost the recovery from a disaster, do not set this unless you have to do so. + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + pbft_ctrl.state_machine.manually_set_current_view(view); + } } diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index f2d75c5a6e8..7c49b020129 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -212,10 +212,10 @@ BOOST_AUTO_TEST_CASE(view_change_validation) { for(int i = 0; i< pbft_ctrl.view_change_timeout; i++){ pbft_ctrl.maybe_pbft_view_change(); } - pbft_ctrl.state_machine->do_send_view_change(); + pbft_ctrl.state_machine.do_send_view_change(); auto new_view = pbft_ctrl.pbft_db.get_proposed_new_view_num(); auto vcc = pbft_ctrl.pbft_db.generate_view_changed_certificate(new_view); - auto nv_msg = pbft_ctrl.pbft_db.send_pbft_new_view(vcc, new_view); + auto nv_msg = pbft_ctrl.pbft_db.generate_pbft_new_view(vcc, new_view); bool nv_flag; try { @@ -302,7 +302,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.last_irreversible_block_num(), 101); //generate new view with short fork prepare certificate - pbft_new_view_generator.state_machine->set_prepares_cache(pbft_prepare()); + pbft_new_view_generator.state_machine.set_prepare_cache(pbft_prepare()); BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_send_pbft_msg(), true); ctrl_new_view_generator.reset_pbft_my_prepare(); pbft_new_view_generator.maybe_pbft_prepare(); @@ -311,10 +311,10 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o for(int i = 0; ido_send_view_change(); + pbft_new_view_generator.state_machine.do_send_view_change(); auto new_view = pbft_new_view_generator.pbft_db.get_proposed_new_view_num(); auto vcc = pbft_new_view_generator.pbft_db.generate_view_changed_certificate(new_view); - auto nv_msg = pbft_new_view_generator.pbft_db.send_pbft_new_view( + auto nv_msg = pbft_new_view_generator.pbft_db.generate_pbft_new_view( vcc, new_view); @@ -393,7 +393,7 @@ BOOST_AUTO_TEST_CASE(new_view_with_committed_cert_call_two_times_maybe_switch_fo c1.produce_blocks(6); new_view_generator.produce_blocks(10); - c1_pbft_controller.state_machine->set_prepares_cache(pbft_prepare()); + c1_pbft_controller.state_machine.set_prepare_cache(pbft_prepare()); c1_ctrl.reset_pbft_my_prepare(); c1_pbft_controller.maybe_pbft_prepare(); c1.produce_block(); @@ -410,7 +410,7 @@ BOOST_AUTO_TEST_CASE(new_view_with_committed_cert_call_two_times_maybe_switch_fo //generate new view with long fork commit certificate - pbft_new_view_generator.state_machine->set_prepares_cache(pbft_prepare()); + pbft_new_view_generator.state_machine.set_prepare_cache(pbft_prepare()); BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_send_pbft_msg(), true); ctrl_new_view_generator.reset_pbft_my_prepare(); pbft_new_view_generator.maybe_pbft_prepare(); @@ -427,10 +427,10 @@ BOOST_AUTO_TEST_CASE(new_view_with_committed_cert_call_two_times_maybe_switch_fo for(int i = 0; ido_send_view_change(); + pbft_new_view_generator.state_machine.do_send_view_change(); auto new_view = pbft_new_view_generator.pbft_db.get_proposed_new_view_num(); auto vcc = pbft_new_view_generator.pbft_db.generate_view_changed_certificate(new_view); - auto nv_msg = pbft_new_view_generator.pbft_db.send_pbft_new_view(vcc, new_view); + auto nv_msg = pbft_new_view_generator.pbft_db.generate_pbft_new_view(vcc, new_view); //can switch fork after apply prepare certificate in new view auto pmm = pbft_message_metadata(nv_msg, c1_pbft_controller.pbft_db.get_chain_id()); @@ -542,13 +542,13 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { push_blocks(c2, c1); /// make c1 lib 98 c1_pbft_controller.maybe_pbft_prepare(); - pbft_prepare c2_prepare_ = c2_pbft_controller.state_machine->get_prepares_cache(); + pbft_prepare c2_prepare_ = c2_pbft_controller.state_machine.get_prepare_cache(); BOOST_CHECK_EQUAL(c2_prepare_.block_info.block_num(), 98); - c1_pbft_controller.state_machine->on_prepare(std::make_shared>(c2_prepare_, c2_pbft_controller.pbft_db.get_chain_id())); + c1_pbft_controller.state_machine.on_prepare(std::make_shared>(c2_prepare_, c2_pbft_controller.pbft_db.get_chain_id())); c1_pbft_controller.maybe_pbft_commit(); - pbft_commit c2_commit_ = c2_pbft_controller.state_machine->get_commits_cache(); - c1_pbft_controller.state_machine->on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); + pbft_commit c2_commit_ = c2_pbft_controller.state_machine.get_commit_cache(); + c1_pbft_controller.state_machine.on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); c1.produce_block(); c1_pbft_controller.maybe_pbft_commit(); BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 98); @@ -557,13 +557,13 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { /// make c3_final lib 98 c3_final_pbft_controller.maybe_pbft_prepare(); - pbft_prepare c1_prepare_ = c1_pbft_controller.state_machine->get_prepares_cache(); + pbft_prepare c1_prepare_ = c1_pbft_controller.state_machine.get_prepare_cache(); BOOST_CHECK_EQUAL(c1_prepare_.block_info.block_num(), 99); - c3_final_pbft_controller.state_machine->on_prepare(std::make_shared>(c1_prepare_, c1_pbft_controller.pbft_db.get_chain_id())); + c3_final_pbft_controller.state_machine.on_prepare(std::make_shared>(c1_prepare_, c1_pbft_controller.pbft_db.get_chain_id())); c3_final_pbft_controller.maybe_pbft_commit(); - pbft_commit c1_commit_ = c1_pbft_controller.state_machine->get_commits_cache(); - c3_final_pbft_controller.state_machine->on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); + pbft_commit c1_commit_ = c1_pbft_controller.state_machine.get_commit_cache(); + c3_final_pbft_controller.state_machine.on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); c3_final.produce_block(); c3_final_pbft_controller.maybe_pbft_commit(); BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 98); @@ -572,35 +572,35 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { push_blocks(c2, c2_prime); pbft_prepare c1_prepare; - c1_prepare_ = c1_pbft_controller.state_machine->get_prepares_cache(); + c1_prepare_ = c1_pbft_controller.state_machine.get_prepare_cache(); c1_prepare = c1_prepare_; /// for set pbft commit cache to 99 c2.produce_block(); c2_pbft_controller.maybe_pbft_prepare(); - c2_prepare_ = c2_pbft_controller.state_machine->get_prepares_cache(); + c2_prepare_ = c2_pbft_controller.state_machine.get_prepare_cache(); BOOST_CHECK_EQUAL(c2_prepare_.block_info.block_num(), 99); c2_pbft_controller.maybe_pbft_commit(); c2.produce_block(); c2_pbft_controller.maybe_pbft_commit(); - c2_commit_ = c2_pbft_controller.state_machine->get_commits_cache(); + c2_commit_ = c2_pbft_controller.state_machine.get_commit_cache(); BOOST_CHECK_EQUAL(c2_commit_.block_info.block_num(), 99); BOOST_CHECK_EQUAL(c2.control->last_irreversible_block_num(), 99); push_blocks(c2, c1); c1_pbft_controller.maybe_pbft_prepare(); - c2_prepare_ = c2_pbft_controller.state_machine->get_prepares_cache(); - c1_pbft_controller.state_machine->on_prepare(std::make_shared>(c2_prepare_, c2_pbft_controller.pbft_db.get_chain_id())); + c2_prepare_ = c2_pbft_controller.state_machine.get_prepare_cache(); + c1_pbft_controller.state_machine.on_prepare(std::make_shared>(c2_prepare_, c2_pbft_controller.pbft_db.get_chain_id())); c1_pbft_controller.maybe_pbft_commit(); - c2_commit_ = c2_pbft_controller.state_machine->get_commits_cache(); - c1_pbft_controller.state_machine->on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); + c2_commit_ = c2_pbft_controller.state_machine.get_commit_cache(); + c1_pbft_controller.state_machine.on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); c1.produce_block(); c1_pbft_controller.maybe_pbft_commit(); - c1_prepare_ = c1_pbft_controller.state_machine->get_prepares_cache(); - c1_commit_ = c1_pbft_controller.state_machine->get_commits_cache(); + c1_prepare_ = c1_pbft_controller.state_machine.get_prepare_cache(); + c1_commit_ = c1_pbft_controller.state_machine.get_commit_cache(); BOOST_CHECK_EQUAL(c1_commit_.block_info.block_num(), 99); BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 99); @@ -612,12 +612,12 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { BOOST_CHECK_EQUAL(c1_prepare.block_info.block_num(), 99); /// set c3 my preprare at 100 c3_final_ctrl.set_pbft_my_prepare(c3_final_ctrl.get_block_id_for_num(100)); - c3_final_pbft_controller.state_machine->on_prepare(std::make_shared>(c1_prepare, c1_pbft_controller.pbft_db.get_chain_id())); + c3_final_pbft_controller.state_machine.on_prepare(std::make_shared>(c1_prepare, c1_pbft_controller.pbft_db.get_chain_id())); - pbft_prepare c3_final_prepare = c3_final_pbft_controller.state_machine->get_prepares_cache(); + pbft_prepare c3_final_prepare = c3_final_pbft_controller.state_machine.get_prepare_cache(); // check c3 prepare at 99 BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 99); - curr_state = c3_final_pbft_controller.state_machine->get_current()->get_name(); + curr_state = c3_final_pbft_controller.state_machine.get_current()->get_name(); BOOST_CHECK_EQUAL(curr_state, "{==== PREPARED ====}"); @@ -644,18 +644,18 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c3_final_pbft_controller.maybe_pbft_commit(); c3_final.produce_block(); - pbft_commit c3_final_commit = c3_final_pbft_controller.state_machine->get_commits_cache(); + pbft_commit c3_final_commit = c3_final_pbft_controller.state_machine.get_commit_cache(); /// on commit will prepare next block immediately will trigger reserve prepare - c3_final_pbft_controller.state_machine->on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); + c3_final_pbft_controller.state_machine.on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); // for sync c3_final.produce_block(); c3_final_pbft_controller.maybe_pbft_commit(); - curr_state = c3_final_pbft_controller.state_machine->get_current()->get_name(); + curr_state = c3_final_pbft_controller.state_machine.get_current()->get_name(); BOOST_CHECK_EQUAL(curr_state, "{==== COMMITTED ====}"); BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 99); c3_final_pbft_controller.maybe_pbft_prepare(); - c3_final_prepare = c3_final_pbft_controller.state_machine->get_prepares_cache(); + c3_final_prepare = c3_final_pbft_controller.state_machine.get_prepare_cache(); BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 100); } From 99d2ed758b55537f39b75c6ddfb6f343a5175dce Mon Sep 17 00:00:00 2001 From: oldcold Date: Tue, 30 Jul 2019 18:59:11 +0800 Subject: [PATCH 11/37] add global object to control pbft behavior; optimise checkpoint logic --- libraries/chain/chain_config.cpp | 4 + libraries/chain/controller.cpp | 13 ++ .../include/eosio/chain/chain_config.hpp | 9 ++ .../chain/include/eosio/chain/controller.hpp | 4 +- .../eosio/chain/global_property_object.hpp | 23 +++- libraries/chain/include/eosio/chain/pbft.hpp | 40 +++--- .../include/eosio/chain/pbft_database.hpp | 15 +- libraries/chain/include/eosio/chain/types.hpp | 1 + libraries/chain/pbft.cpp | 82 ++++------- libraries/chain/pbft_database.cpp | 130 +++++++++--------- plugins/net_plugin/net_plugin.cpp | 2 +- plugins/pbft_plugin/pbft_plugin.cpp | 30 ++-- unittests/pbft_tests.cpp | 8 +- 13 files changed, 195 insertions(+), 166 deletions(-) diff --git a/libraries/chain/chain_config.cpp b/libraries/chain/chain_config.cpp index c39d89cee46..e801736fe66 100644 --- a/libraries/chain/chain_config.cpp +++ b/libraries/chain/chain_config.cpp @@ -49,4 +49,8 @@ void chain_config2::validate() const{ EOS_ASSERT(std::numeric_limits::max() > resource_greylist.size(), action_validate_exception, "Overflow in greylistwhen adding resource greylist!"); } +void chain_config3::validate() const{ + EOS_ASSERT( view_change_timeout >= 1, action_validate_exception, "view change timeout must be at least 1"); +} + } } // namespace eosio::chain diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index da23d6e193f..75a799b74fa 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -36,6 +36,7 @@ using controller_index_set = index_set< global_property2_multi_index, dynamic_global_property_multi_index, upgrade_property_multi_index, + global_property3_multi_index, block_summary_multi_index, transaction_multi_index, generated_transaction_multi_index, @@ -455,6 +456,13 @@ struct controller_impl { wlog("no upo found, generating..."); db.create([](auto&){}); } + + try { + db.get(); + } catch( const boost::exception& e) { + wlog("no gpo3 found, generating..."); + db.create([](auto&){}); + } } ~controller_impl() { @@ -746,6 +754,7 @@ struct controller_impl { // *bos end* + db.create([](auto&) {}); authorization.initialize_database(); resource_limits.initialize_database(); @@ -2703,6 +2712,10 @@ const upgrade_property_object& controller::get_upgrade_properties()const { return my->db.get(); } +const global_property3_object& controller::get_pbft_properties()const { + return my->db.get(); +} + bool controller::is_pbft_enabled() const { return my->pbft_enabled; } diff --git a/libraries/chain/include/eosio/chain/chain_config.hpp b/libraries/chain/include/eosio/chain/chain_config.hpp index da258010fbb..283db798746 100644 --- a/libraries/chain/include/eosio/chain/chain_config.hpp +++ b/libraries/chain/include/eosio/chain/chain_config.hpp @@ -117,6 +117,13 @@ struct chain_config2 { void validate()const; }; +struct chain_config3 { + + uint16_t view_change_timeout = 6; /// the actual wait time will be `num * 5` + + void validate()const; +}; + // *bos* struct guaranteed_minimum_resources { uint64_t ram_byte; @@ -140,3 +147,5 @@ FC_REFLECT(eosio::chain::chain_config, // *bos* FC_REFLECT( eosio::chain::chain_config2, (actor_blacklist)(contract_blacklist)(resource_greylist) ) FC_REFLECT( eosio::chain::guaranteed_minimum_resources, (ram_byte)(cpu_us)(net_byte) ) + +FC_REFLECT( eosio::chain::chain_config3, (view_change_timeout) ) diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 7a90125da6e..05c5c925e59 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -31,6 +31,7 @@ namespace eosio { namespace chain { class global_property_object; class global_property2_object; // *bos* class upgrade_property_object; + class global_property3_object; // *bos* class permission_object; class account_object; using resource_limits::resource_limits_manager; @@ -305,7 +306,8 @@ namespace eosio { namespace chain { signal accepted_confirmation; signal bad_alloc; - const upgrade_property_object& get_upgrade_properties()const; + const upgrade_property_object& get_upgrade_properties()const; + const global_property3_object& get_pbft_properties()const; bool is_pbft_enabled()const; bool under_maintenance()const; void set_upo(uint32_t target_block_num); diff --git a/libraries/chain/include/eosio/chain/global_property_object.hpp b/libraries/chain/include/eosio/chain/global_property_object.hpp index 98f86939ad6..32edc5bea62 100644 --- a/libraries/chain/include/eosio/chain/global_property_object.hpp +++ b/libraries/chain/include/eosio/chain/global_property_object.hpp @@ -54,6 +54,14 @@ namespace eosio { namespace chain { block_num_type upgrade_complete_block_num = 0; }; + class global_property3_object : public chainbase::object + { + OBJECT_CTOR(global_property3_object) + + id_type id; + chain_config3 configuration; + }; + /** * @class dynamic_global_property_object @@ -108,6 +116,15 @@ namespace eosio { namespace chain { > > >; + + using global_property3_multi_index = chainbase::shared_multi_index_container< + global_property3_object, + indexed_by< + ordered_unique, + BOOST_MULTI_INDEX_MEMBER(global_property3_object, global_property3_object::id_type, id) + > + > + >; }} CHAINBASE_SET_INDEX_TYPE(eosio::chain::global_property_object, eosio::chain::global_property_multi_index) @@ -116,6 +133,7 @@ CHAINBASE_SET_INDEX_TYPE(eosio::chain::dynamic_global_property_object, // *bos* CHAINBASE_SET_INDEX_TYPE(eosio::chain::global_property2_object, eosio::chain::global_property2_multi_index) CHAINBASE_SET_INDEX_TYPE(eosio::chain::upgrade_property_object, eosio::chain::upgrade_property_multi_index) +CHAINBASE_SET_INDEX_TYPE(eosio::chain::global_property3_object, eosio::chain::global_property3_multi_index) FC_REFLECT(eosio::chain::dynamic_global_property_object, (global_action_sequence) @@ -130,4 +148,7 @@ FC_REFLECT(eosio::chain::global_property2_object, ) FC_REFLECT(eosio::chain::upgrade_property_object, (upgrade_target_block_num)(upgrade_complete_block_num) - ) \ No newline at end of file + ) +FC_REFLECT(eosio::chain::global_property3_object, + (configuration) +) \ No newline at end of file diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index a563147265c..0bfb7e8942a 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -12,12 +12,12 @@ namespace eosio { using namespace fc; struct psm_cache { - pbft_prepare prepare_cache; - pbft_commit commit_cache; - pbft_view_change view_change_cache; - pbft_prepared_certificate prepared_certificate; - vector committed_certificate; - pbft_view_changed_certificate view_changed_certificate; + pbft_prepare prepare_cache = pbft_prepare(); + pbft_commit commit_cache = pbft_commit(); + pbft_view_change view_change_cache = pbft_view_change(); + pbft_prepared_certificate prepared_certificate = pbft_prepared_certificate(); + vector committed_certificate = vector{}; + pbft_view_changed_certificate view_changed_certificate = pbft_view_changed_certificate(); }; class psm_state; @@ -43,6 +43,8 @@ namespace eosio { void send_view_change(); void send_checkpoint(); bool maybe_new_view(); + void maybe_view_change(); + bool maybe_stop_view_change(); void transit_to_committed_state(bool to_new_view); void transit_to_prepared_state(); @@ -54,13 +56,13 @@ namespace eosio { void do_send_view_change(); const pbft_prepare& get_prepare_cache() const { return cache.prepare_cache; } - void set_prepare_cache(const pbft_prepare &pcache) { cache.prepare_cache = pcache; } + void set_prepare_cache(const pbft_prepare& pcache) { cache.prepare_cache = pcache; } const pbft_commit& get_commit_cache() const { return cache.commit_cache; } - void set_commit_cache(const pbft_commit &ccache) { cache.commit_cache = ccache; } + void set_commit_cache(const pbft_commit& ccache) { cache.commit_cache = ccache; } const pbft_view_change& get_view_change_cache() const { return cache.view_change_cache; } - void set_view_change_cache(const pbft_view_change &vc_cache) { cache.view_change_cache = vc_cache; } + void set_view_change_cache(const pbft_view_change& vc_cache) { cache.view_change_cache = vc_cache; } uint32_t get_current_view() const { return current_view; } void set_current_view(uint32_t cv) { current_view = cv; } @@ -94,14 +96,14 @@ namespace eosio { signal pbft_transit_to_prepared; template - void emit(const Signal &s, Arg &&a); + void emit(const Signal& s, Arg&& a); protected: psm_cache cache; - uint32_t current_view; - uint32_t target_view_retries; - uint32_t target_view; - uint32_t view_change_timer; + uint32_t current_view = 0; + uint32_t target_view_retries = 0; + uint32_t target_view = current_view + 1; + uint32_t view_change_timer = 0; private: psm_state_ptr current = nullptr; @@ -128,8 +130,8 @@ namespace eosio { std::shared_ptr get_self() { return shared_from_this(); }; protected: - psm_machine& m; - pbft_database& pbft_db; + psm_machine& m; + pbft_database& pbft_db; }; class psm_prepared_state final: public psm_state { @@ -190,10 +192,8 @@ namespace eosio { explicit pbft_controller(controller& ctrl); ~pbft_controller(); - const uint16_t view_change_timeout = 6; - - pbft_database pbft_db; - psm_machine state_machine; + pbft_database pbft_db; + psm_machine state_machine; void maybe_pbft_prepare(); void maybe_pbft_commit(); diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 8a935829d9a..0d8bf6d3aa8 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -429,19 +429,19 @@ namespace eosio { void add_pbft_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk); vector generate_and_add_pbft_prepare( - const pbft_prepare &cached_prepare = pbft_prepare(), + const pbft_prepare& cached_prepare = pbft_prepare(), pbft_view_type current_view = 0); vector generate_and_add_pbft_commit( - const pbft_commit &cached_commit = pbft_commit(), + const pbft_commit& cached_commit = pbft_commit(), pbft_view_type current_view = 0); vector generate_and_add_pbft_view_change( - const pbft_view_change &cached_view_change = pbft_view_change(), - const pbft_prepared_certificate &ppc = pbft_prepared_certificate(), - const vector &pcc = vector{}, + const pbft_view_change& cached_view_change = pbft_view_change(), + const pbft_prepared_certificate& ppc = pbft_prepared_certificate(), + const vector& pcc = vector{}, pbft_view_type current_view = 0, pbft_view_type target_view = 1); pbft_new_view generate_pbft_new_view( - const pbft_view_changed_certificate &vcc = pbft_view_changed_certificate(), + const pbft_view_changed_certificate& vcc = pbft_view_changed_certificate(), pbft_view_type current_view = 1); vector generate_and_add_pbft_checkpoint(); @@ -484,6 +484,7 @@ namespace eosio { void cleanup_on_new_view(); void update_fork_schedules(); + uint16_t get_view_change_timeout() const; //api related pbft_state_ptr get_pbft_state_by_id(const block_id_type& id) const; @@ -507,7 +508,7 @@ namespace eosio { bool is_less_than_high_watermark(block_num_type bnum); bool is_valid_prepared_certificate(const pbft_prepared_certificate& certificate, bool add_to_pbft_db = false); bool is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db = false); - bool is_valid_longest_fork(const block_info_type& bi, fork_info_type block_infos, unsigned long threshold, unsigned long non_fork_bp_count); + bool is_valid_longest_fork(const block_info_type& bi, fork_info_type& block_infos, unsigned long threshold, unsigned long non_fork_bp_count); producer_schedule_type lscb_active_producers() const; vector& get_updated_watermarks(); diff --git a/libraries/chain/include/eosio/chain/types.hpp b/libraries/chain/include/eosio/chain/types.hpp index f8360c0bc7d..4cf8b055cd2 100644 --- a/libraries/chain/include/eosio/chain/types.hpp +++ b/libraries/chain/include/eosio/chain/types.hpp @@ -190,6 +190,7 @@ namespace eosio { namespace chain { action_history_object_type, ///< Defined by history_plugin reversible_block_object_type, upgrade_property_object_type, + global_property3_object_type, OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types }; diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 4739bded9ad..0fdf3adf43a 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -51,7 +51,7 @@ namespace eosio { void pbft_controller::maybe_pbft_view_change() { if (!pbft_db.should_send_pbft_msg()) return; - if (state_machine.get_view_change_timer() <= view_change_timeout) { + if (state_machine.get_view_change_timer() <= pbft_db.get_view_change_timeout()) { if (!state_machine.get_view_change_cache().empty()) { pbft_db.generate_and_add_pbft_view_change(state_machine.get_view_change_cache()); } @@ -93,20 +93,7 @@ namespace eosio { psm_state::psm_state(psm_machine& m, pbft_database& pbft_db) : m(m), pbft_db(pbft_db){} psm_state::~psm_state() = default; - psm_machine::psm_machine(pbft_database& pbft_db) : pbft_db(pbft_db) { - set_prepare_cache(pbft_prepare()); - set_commit_cache(pbft_commit()); - set_view_change_cache(pbft_view_change()); - - set_prepared_certificate(pbft_prepared_certificate{}); - set_committed_certificate(vector{}); - set_view_changed_certificate(pbft_view_changed_certificate{}); - - view_change_timer = 0; - target_view_retries = 0; - current_view = 0; - target_view = current_view + 1; - } + psm_machine::psm_machine(pbft_database& pbft_db) : pbft_db(pbft_db) {} psm_machine::~psm_machine() = default; @@ -157,7 +144,8 @@ namespace eosio { transit_to_view_change_state(); } - /** + /**\ + * * psm_prepared_state */ @@ -176,8 +164,6 @@ namespace eosio { } if (pending_commit_local && !pbft_db.pending_pbft_lib()) { - m.send_checkpoint(); - pbft_db.checkpoint_local(); m.transit_to_committed_state(false); } } @@ -189,7 +175,6 @@ namespace eosio { void psm_prepared_state::send_prepare() { //retry if (m.get_prepare_cache().empty()) return; - m.do_send_prepare(); } @@ -199,14 +184,12 @@ namespace eosio { if (!pbft_db.is_valid_commit(e->msg, e->sender_key)) return; pbft_db.add_pbft_commit(e->msg, e->sender_key); - maybe_transit_to_committed(); } void psm_prepared_state::send_commit() { m.do_send_commit(); - maybe_transit_to_committed(); } @@ -216,13 +199,7 @@ namespace eosio { if (!pbft_db.is_valid_view_change(e->msg, e->sender_key)) return; pbft_db.add_pbft_view_change(e->msg, e->sender_key); - - //if received >= f+1 view_change on some view, transit to view_change and send view change - auto target_view = pbft_db.should_view_change(); - if (target_view > 0 && target_view > m.get_current_view()) { - m.set_target_view(target_view); - m.transit_to_view_change_state(); - } + m.maybe_view_change(); } void psm_prepared_state::send_view_change() { @@ -243,7 +220,6 @@ namespace eosio { //do action add prepare pbft_db.add_pbft_prepare(e->msg, e->sender_key); - //if prepare >= 2f+1, transit to prepared if (pbft_db.should_prepared()) m.transit_to_prepared_state(); } @@ -251,7 +227,6 @@ namespace eosio { void psm_committed_state::send_prepare() { m.do_send_prepare(); - //if prepare >= 2f+1, transit to prepared if (pbft_db.should_prepared()) m.transit_to_prepared_state(); } @@ -267,9 +242,7 @@ namespace eosio { void psm_committed_state::send_commit() { if (m.get_commit_cache().empty()) return; - m.do_send_commit(); - } void psm_committed_state::on_view_change(const pbft_metadata_ptr& e) { @@ -278,13 +251,7 @@ namespace eosio { if (!pbft_db.is_valid_view_change(e->msg, e->sender_key)) return; pbft_db.add_pbft_view_change(e->msg, e->sender_key); - - //if received >= f+1 view_change on some view, transit to view_change and send view change - auto new_view = pbft_db.should_view_change(); - if (new_view > 0 && new_view > m.get_current_view()) { - m.set_target_view(new_view); - m.transit_to_view_change_state(); - } + m.maybe_view_change(); } void psm_committed_state::send_view_change() { @@ -314,32 +281,20 @@ namespace eosio { void psm_view_change_state::on_view_change(const pbft_metadata_ptr& e) { - //skip from view change state if my lib is higher than my view change state height. - auto vc = m.get_view_change_cache(); - if (!vc.empty() && pbft_db.should_stop_view_change(vc)) { - m.transit_to_committed_state(false); - return; - } + if (m.maybe_stop_view_change()) return; if (e->msg.target_view <= m.get_current_view()) return; if (!pbft_db.is_valid_view_change(e->msg, e->sender_key)) return; pbft_db.add_pbft_view_change(e->msg, e->sender_key); - m.maybe_new_view(); } void psm_view_change_state::send_view_change() { - //skip from view change state if my lib is higher than my view change state height. - auto vc = m.get_view_change_cache(); - if (!vc.empty() && pbft_db.should_stop_view_change(vc)) { - m.transit_to_committed_state(false); - return; - } + if (m.maybe_stop_view_change()) return; m.do_send_view_change(); - m.maybe_new_view(); } @@ -388,6 +343,25 @@ namespace eosio { } } + void psm_machine::maybe_view_change() { + //if received >= f+1 view_change on some view, transit to view_change and send view change + auto new_view = pbft_db.should_view_change(); + if (new_view > 0 && new_view > get_current_view()) { + set_target_view(new_view); + transit_to_view_change_state(); + } + } + + bool psm_machine::maybe_stop_view_change() { + //skip from view change state if my lib is higher than my view change state height. + auto vc = get_view_change_cache(); + if (!vc.empty() && pbft_db.should_stop_view_change(vc)) { + transit_to_committed_state(false); + return true; + } + return false; + } + bool psm_machine::maybe_new_view() { //if view_change >= 2f+1, calculate next primary, send new view if is primary auto nv = get_target_view(); @@ -514,7 +488,7 @@ namespace eosio { } template - void psm_machine::emit(const Signal &s, Arg &&a) { + void psm_machine::emit(const Signal& s, Arg&& a) { try { s(std::forward(a)); } catch (boost::interprocess::bad_alloc &e) { diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 22c2ab188ac..d0b60d88f35 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -94,7 +94,7 @@ namespace eosio { void pbft_database::add_pbft_prepare(const pbft_prepare& p, const public_key_type& pk) { - auto &by_block_id_index = pbft_state_index.get(); + auto& by_block_id_index = pbft_state_index.get(); auto current = ctrl.fetch_block_state_by_id(p.block_info.block_id); @@ -120,6 +120,8 @@ namespace eosio { by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr& psp) { psp->prepares[std::make_pair(p.view, pk)] = p; }); + } else { + return; } } curr_itr = by_block_id_index.find(current->id); @@ -151,7 +153,7 @@ namespace eosio { } void pbft_database::mark_as_prepared(const block_id_type& bid) { - auto &by_block_id_index = pbft_state_index.get(); + auto& by_block_id_index = pbft_state_index.get(); auto itr = by_block_id_index.find(bid); auto bnum = block_info_type{bid}.block_num(); @@ -167,7 +169,7 @@ namespace eosio { by_block_id_index.modify(itr, [&](const pbft_state_ptr& p) { p->is_prepared = true; }); } - vector pbft_database::generate_and_add_pbft_prepare(const pbft_prepare &cached_prepare, + vector pbft_database::generate_and_add_pbft_prepare(const pbft_prepare& cached_prepare, pbft_view_type current_view) { vector prepares_to_be_cached; const auto& my_sps = ctrl.my_signature_providers(); @@ -258,7 +260,7 @@ namespace eosio { void pbft_database::add_pbft_commit(const pbft_commit& c, const public_key_type& pk) { - auto &by_block_id_index = pbft_state_index.get(); + auto& by_block_id_index = pbft_state_index.get(); auto current = ctrl.fetch_block_state_by_id(c.block_info.block_id); @@ -286,6 +288,8 @@ namespace eosio { psp->commits[std::make_pair(c.view, pk)] = c; std::sort(psp->commits.begin(), psp->commits.end(), less<>()); }); + } else { + return; } } @@ -319,7 +323,7 @@ namespace eosio { } } - vector pbft_database::generate_and_add_pbft_commit(const pbft_commit &cached_commit, + vector pbft_database::generate_and_add_pbft_commit(const pbft_commit& cached_commit, pbft_view_type current_view) { vector commits_to_be_cached; const auto& my_sps = ctrl.my_signature_providers(); @@ -361,7 +365,7 @@ namespace eosio { } void pbft_database::mark_as_committed(const block_id_type& bid) { - auto &by_block_id_index = pbft_state_index.get(); + auto& by_block_id_index = pbft_state_index.get(); auto itr = by_block_id_index.find(bid); if (itr == by_block_id_index.end()) return; by_block_id_index.modify(itr, [&](const pbft_state_ptr& p) { p->is_committed = true; }); @@ -434,7 +438,7 @@ namespace eosio { auto lscb_bps = lscb_active_producers().producers; - auto &by_view_index = view_state_index.get(); + auto& by_view_index = view_state_index.get(); auto itr = by_view_index.find(vc.target_view); if (itr == by_view_index.end()) { flat_map view_changes; @@ -452,6 +456,8 @@ namespace eosio { by_view_index.modify(itr, [&](const pbft_view_change_state_ptr& pvsp) { pvsp->view_changes[pk] = vc; }); + } else { + return; } } @@ -476,7 +482,7 @@ namespace eosio { pbft_view_type pbft_database::should_view_change() { pbft_view_type nv = 0; - auto &by_view_index = view_state_index.get(); + auto& by_view_index = view_state_index.get(); auto itr = by_view_index.begin(); if (itr == by_view_index.end()) return nv; @@ -501,9 +507,9 @@ namespace eosio { } vector pbft_database::generate_and_add_pbft_view_change( - const pbft_view_change &cached_view_change, - const pbft_prepared_certificate &ppc, - const vector &pcc, + const pbft_view_change& cached_view_change, + const pbft_prepared_certificate& ppc, + const vector& pcc, pbft_view_type current_view, pbft_view_type target_view) { @@ -540,14 +546,14 @@ namespace eosio { } bool pbft_database::should_new_view(pbft_view_type target_view) { - auto &by_view_index = view_state_index.get(); + auto& by_view_index = view_state_index.get(); auto itr = by_view_index.find(target_view); if (itr == by_view_index.end()) return false; return (*itr)->is_view_changed; } pbft_view_type pbft_database::get_proposed_new_view_num() { - auto &by_count_and_view_index = view_state_index.get(); + auto& by_count_and_view_index = view_state_index.get(); auto itr = by_count_and_view_index.begin(); if (itr == by_count_and_view_index.end() || !(*itr)->is_view_changed) return 0; return (*itr)->view; @@ -567,7 +573,7 @@ namespace eosio { } pbft_new_view pbft_database::generate_pbft_new_view( - const pbft_view_changed_certificate &vcc, + const pbft_view_changed_certificate& vcc, pbft_view_type current_view) { pbft_new_view nv; @@ -753,7 +759,7 @@ namespace eosio { pbft_view_changed_certificate pvcc; - auto &by_view_index = view_state_index.get(); + auto& by_view_index = view_state_index.get(); auto itr = by_view_index.find(target_view); if (itr == by_view_index.end()) return pvcc; @@ -762,7 +768,7 @@ namespace eosio { if (pvs->is_view_changed) { pvcc.target_view=pvs->view; pvcc.view_changes.reserve(pvs->view_changes.size()); - for(auto & view_change : pvs->view_changes) { + for(auto& view_change : pvs->view_changes) { pvcc.view_changes.emplace_back( view_change.second ); } } @@ -781,7 +787,7 @@ namespace eosio { auto prepares_metadata = vector>{}; prepares_metadata.reserve(prepares.size()); - for (auto &p : prepares) { + for (auto& p : prepares) { auto pmm = pbft_message_metadata(p, chain_id); prepares_metadata.emplace_back(pmm); if (!is_valid_prepare(p, pmm.sender_key)) return false; @@ -844,7 +850,7 @@ namespace eosio { auto commits_metadata = vector>{}; commits_metadata.reserve(commits.size()); - for (auto &c : commits) { + for (auto& c : commits) { auto pmm = pbft_message_metadata(c, chain_id); commits_metadata.emplace_back(pmm); if (!is_valid_commit(c, pmm.sender_key)) return false; @@ -936,7 +942,7 @@ namespace eosio { vector view_change_producers; view_change_producers.reserve(view_changes.size()); - for (auto &vc: view_changes) { + for (auto& vc : view_changes) { auto pmm = pbft_message_metadata(vc, chain_id); view_changes_metadata.emplace_back(pmm); if (is_valid_view_change(vc, pmm.sender_key)) { @@ -971,7 +977,7 @@ namespace eosio { for (const auto& cc: vc.committed_certs) { if (is_valid_committed_certificate(cc)) { auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), - [&](const pbft_committed_certificate &ext) { + [&](const pbft_committed_certificate& ext) { return ext.block_info.block_id == cc.block_info.block_id; }); if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); @@ -1074,7 +1080,7 @@ namespace eosio { bool pbft_database::is_valid_longest_fork( const block_info_type& bi, - fork_info_type block_infos, + fork_info_type& block_infos, unsigned long threshold, unsigned long non_fork_bp_count) { @@ -1095,7 +1101,7 @@ namespace eosio { pbft_stable_checkpoint psc; try { if (b) { - auto &extn = b->block_extensions; + auto& extn = b->block_extensions; for (auto it = extn.begin(); it != extn.end();) { if (it->first == static_cast(block_extension_type::pbft_stable_checkpoint)) { @@ -1137,7 +1143,7 @@ namespace eosio { if (cpp->is_stable) { psc.block_info={cpp->block_id}; psc.checkpoints.reserve(cpp->checkpoints.size()); - for (auto & checkpoint : cpp->checkpoints) { + for (auto& checkpoint : cpp->checkpoints) { psc.checkpoints.emplace_back(checkpoint.second) ; } @@ -1207,59 +1213,44 @@ namespace eosio { }; vector new_pc{}; + auto my_sps = ctrl.my_signature_providers(); const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end() || !(*itr)->is_committed) return new_pc; pbft_state_ptr psp = (*itr); - - flat_map pending_checkpoint_block_num; // block_height and retry_flag auto lscb_num = ctrl.last_stable_checkpoint_block_num(); + + vector pending_checkpoint_block_num; + pending_checkpoint_block_num.reserve(psp->block_num - lscb_num); for (auto i = psp->block_num; i > lscb_num && i > 1; --i) { if (checkpoint(i)) { - auto &by_block = checkpoint_index.get(); - - if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(i)) { - auto c_itr = by_block.find(bs->id); - if (c_itr == by_block.end()) { - pending_checkpoint_block_num[i] = false; - } else { - auto checkpoints = (*c_itr)->checkpoints; - for (const auto& my_sp : ctrl.my_signature_providers()) { - if (checkpoints.find(my_sp.first) != checkpoints.end() && !(*c_itr)->is_stable) { - pending_checkpoint_block_num[i] = true; //retry sending at this time. - } - } - if (pending_checkpoint_block_num.find(i) == pending_checkpoint_block_num.end()) { - pending_checkpoint_block_num[i] = false; - } - } - } + pending_checkpoint_block_num.emplace_back(i); } } - auto &by_block = checkpoint_index.get(); + auto& by_block = checkpoint_index.get(); if (!pending_checkpoint_block_num.empty()) { std::sort(pending_checkpoint_block_num.begin(), pending_checkpoint_block_num.end()); - for (auto& bnum_and_retry: pending_checkpoint_block_num) { - if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(bnum_and_retry.first)) { - for (const auto& my_sp : ctrl.my_signature_providers()) { + for (auto bnum: pending_checkpoint_block_num) { + if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(bnum)) { + for (const auto& sp : my_sps) { pbft_checkpoint cp; cp.block_info = {bs->id}; - cp.sender_signature = my_sp.second(cp.digest(chain_id)); - if (!bnum_and_retry.second && is_valid_checkpoint(cp, my_sp.first)) { //first time sending this checkpoint - add_pbft_checkpoint(cp, my_sp.first); + cp.sender_signature = sp.second(cp.digest(chain_id)); + if (is_valid_checkpoint(cp, sp.first)) { + add_pbft_checkpoint(cp, sp.first); } new_pc.emplace_back(cp); } } } } else if (lscb_num > 0) { //retry sending my lscb - for (const auto& my_sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { pbft_checkpoint cp; cp.block_info={ctrl.last_stable_checkpoint_block_id()}; - cp.sender_signature = my_sp.second(cp.digest(chain_id)); + cp.sender_signature = sp.second(cp.digest(chain_id)); new_pc.emplace_back(cp); } } @@ -1271,7 +1262,7 @@ namespace eosio { auto cp_block_state = ctrl.fetch_block_state_by_id(cp.block_info.block_id); if (!cp_block_state) return; - auto &by_block = checkpoint_index.get(); + auto& by_block = checkpoint_index.get(); auto itr = by_block.find(cp.block_info.block_id); if (itr == by_block.end()) { flat_map checkpoints; @@ -1290,6 +1281,8 @@ namespace eosio { by_block.modify(itr, [&](const pbft_checkpoint_state_ptr& pcp) { csp->checkpoints[pk] = cp; }); + } else { + return; } } @@ -1318,7 +1311,7 @@ namespace eosio { fc::raw::pack( ds, scp ); blk->block_extensions.emplace_back(); - auto &extension = blk->block_extensions.back(); + auto& extension = blk->block_extensions.back(); extension.first = static_cast(block_extension_type::pbft_stable_checkpoint ); extension.second.resize(scp_size); std::copy(buffer->begin(),buffer->end(), extension.second.data()); @@ -1332,22 +1325,22 @@ namespace eosio { auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto pending_num = pending_scb_info.block_num(); auto pending_id = pending_scb_info.block_id; - //TODO: optimise prune logic if (pending_num > lscb_num) { ctrl.set_pbft_latest_checkpoint(pending_id); if (ctrl.last_irreversible_block_num() < pending_num) ctrl.pbft_commit_local(pending_id); - auto &by_block_id_index = pbft_state_index.get(); + auto& by_block_id_index = pbft_state_index.get(); auto pitr = by_block_id_index.find(pending_id); if (pitr != by_block_id_index.end()) { prune(*pitr); } } - auto &bni = checkpoint_index.get(); + auto& bni = checkpoint_index.get(); auto oldest = bni.begin(); - if ( oldest != bni.end() + while ( oldest != bni.end() && (*oldest)->is_stable && (*oldest)->block_num < lscb_num - oldest_stable_checkpoint ) { prune(*oldest); + oldest = bni.begin(); } } @@ -1374,7 +1367,7 @@ namespace eosio { auto checkpoints_metadata = vector>{}; checkpoints_metadata.reserve(checkpoints.size()); - for (auto &cp : checkpoints) { + for (auto& cp : checkpoints) { auto pmm = pbft_message_metadata(cp, chain_id); checkpoints_metadata.emplace_back(pmm); if (cp.block_info != scp.block_info || !is_valid_checkpoint(cp, pmm.sender_key)) return false; @@ -1481,7 +1474,7 @@ namespace eosio { for (auto i: added) { if (auto bs = ctrl.fetch_block_state_by_number(i)) { auto as = bs->active_schedule.producers; - for (auto &bp: as) { + for (const auto& bp: as) { auto key = bp.block_signing_key; if (fork_schedules.find(key) == fork_schedules.end()) { fork_schedules[key] = i; @@ -1505,7 +1498,7 @@ namespace eosio { auto lscb_bps = lscb_active_producers().producers; auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - for (auto &bp: lscb_bps) { + for (const auto& bp: lscb_bps) { if (fork_schedules.find(bp.block_signing_key) == fork_schedules.end() || fork_schedules[bp.block_signing_key] < lscb_num) { fork_schedules[bp.block_signing_key] = lscb_num; @@ -1523,6 +1516,11 @@ namespace eosio { return fork_schedules; } + uint16_t pbft_database::get_view_change_timeout() const { + return ctrl.get_pbft_properties().configuration.view_change_timeout; + } + + bool pbft_database::is_less_than_high_watermark(block_num_type bnum) { auto current_watermark = get_current_pbft_watermark(); return current_watermark == 0 || bnum <= current_watermark; @@ -1530,7 +1528,7 @@ namespace eosio { pbft_state_ptr pbft_database::get_pbft_state_by_id(const block_id_type& id) const { - auto &by_block_id_index = pbft_state_index.get(); + auto& by_block_id_index = pbft_state_index.get(); auto itr = by_block_id_index.find(id); if (itr != by_block_id_index.end()) return (*itr); @@ -1540,7 +1538,7 @@ namespace eosio { vector pbft_database::get_checkpoints_by_num(block_num_type num) const { auto results = vector{}; - auto &by_num_index = checkpoint_index.get(); + auto& by_num_index = checkpoint_index.get(); auto pitr = by_num_index.lower_bound( num ); while(pitr != by_num_index.end() && (*pitr)->block_num == num ) { @@ -1552,7 +1550,7 @@ namespace eosio { } pbft_view_change_state_ptr pbft_database::get_view_changes_by_target_view(pbft_view_type tv) const { - auto &by_view_index = view_state_index.get(); + auto& by_view_index = view_state_index.get(); auto itr = by_view_index.find(tv); if (itr != by_view_index.end()) return (*itr); @@ -1583,7 +1581,7 @@ namespace eosio { void pbft_database::prune(const pbft_state_ptr& h) { auto num = h->block_num; - auto &by_bn = pbft_state_index.get(); + auto& by_bn = pbft_state_index.get(); auto bni = by_bn.begin(); while (bni != by_bn.end() && (*bni)->block_num < num) { prune(*bni); @@ -1599,7 +1597,7 @@ namespace eosio { void pbft_database::prune(const pbft_checkpoint_state_ptr& h) { auto num = h->block_num; - auto &by_bn = checkpoint_index.get(); + auto& by_bn = checkpoint_index.get(); auto bni = by_bn.begin(); while (bni != by_bn.end() && (*bni)->block_num < num) { prune(*bni); diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index f9e611ad229..43f7336074e 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -3175,7 +3175,7 @@ namespace eosio { void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_checkpoint &msg) { if (is_pbft_msg_valid(msg) && maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { - auto pmm = pbft_message_metadata(std::move(msg), chain_id); + auto pmm = pbft_message_metadata(msg, chain_id); pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_checkpoint(pmm.msg, pmm.sender_key)) return; diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index 674a4ead103..8acf2b49a19 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -28,16 +28,18 @@ namespace eosio { boost::asio::steady_timer::duration prepare_timeout{std::chrono::milliseconds{1000}}; boost::asio::steady_timer::duration commit_timeout{std::chrono::milliseconds{1000}}; boost::asio::steady_timer::duration view_change_check_interval{std::chrono::seconds{5}}; - boost::asio::steady_timer::duration checkpoint_timeout{std::chrono::seconds{50}}; + boost::asio::steady_timer::duration checkpoint_timeout{std::chrono::seconds{25}}; void prepare_timer_tick(); void commit_timer_tick(); void view_change_timer_tick(); void checkpoint_timer_tick(); + fc::optional pbft_transit_to_committed_connection; pbft::committed_transition_channel::channel_type::handle transit_to_committed_subscription; pbft::committed_transition_channel::channel_type& transit_to_committed_channel; + fc::optional pbft_transit_to_prepared_connection; pbft::prepared_transition_channel::channel_type::handle transit_to_prepared_subscription; pbft::prepared_transition_channel::channel_type& transit_to_prepared_channel; @@ -52,24 +54,26 @@ namespace eosio { }; void pbft_plugin_impl::on_committed_transition() { - prepare_timer->expires_from_now(prepare_timeout); + prepare_timer_tick(); } void pbft_plugin_impl::on_prepared_transition() { - commit_timer->expires_from_now(commit_timeout); + commit_timer_tick(); } void pbft_plugin_impl::prepare_timer_tick() { prepare_timer->expires_from_now(prepare_timeout); prepare_timer->async_wait([&](boost::system::error_code ec) { - prepare_timer_tick(); - if (ec) { + if ( ec == boost::asio::error::operation_aborted ) { + return; + } else if (ec) { wlog ("pbft plugin prepare timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_prepare(); } + prepare_timer_tick(); }); } @@ -77,13 +81,15 @@ namespace eosio { commit_timer->expires_from_now(commit_timeout); commit_timer->async_wait([&](boost::system::error_code ec) { - commit_timer_tick(); - if (ec) { + if ( ec == boost::asio::error::operation_aborted ) { + return; + } else if (ec) { wlog ("pbft plugin commit timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_commit(); } + commit_timer_tick(); }); } @@ -110,8 +116,9 @@ namespace eosio { checkpoint_timer->expires_from_now(checkpoint_timeout); checkpoint_timer->async_wait([&](boost::system::error_code ec) { - checkpoint_timer_tick(); - if (ec) { + if ( ec == boost::asio::error::operation_aborted ) { + return; + } if (ec) { wlog ("pbft plugin checkpoint timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); @@ -123,6 +130,7 @@ namespace eosio { app().get_plugin().maybe_sync_stable_checkpoints(); } } + checkpoint_timer_tick(); }); } @@ -178,11 +186,11 @@ namespace eosio { my->view_change_timer_tick(); my->checkpoint_timer_tick(); - my->transit_to_prepared_subscription = my->transit_to_prepared_channel.subscribe( [this]( bool prepared ) { + my->pbft_transit_to_prepared_connection = app().get_plugin().pbft_ctrl().state_machine.pbft_transit_to_prepared.connect( [this]( bool prepared ) { my->on_prepared_transition(); }); - my->transit_to_committed_subscription = my->transit_to_committed_channel.subscribe( [this]( bool committed ) { + my->pbft_transit_to_committed_connection = app().get_plugin().pbft_ctrl().state_machine.pbft_transit_to_committed.connect( [this]( bool committed ) { my->on_committed_transition(); }); } diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index 7c49b020129..40856b24268 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -209,7 +209,7 @@ BOOST_AUTO_TEST_CASE(view_change_validation) { BOOST_CHECK_EQUAL(ctrl.head_block_num(), 102); - for(int i = 0; i< pbft_ctrl.view_change_timeout; i++){ + for(int i = 0; i< pbft_ctrl.pbft_db.get_view_change_timeout(); i++){ pbft_ctrl.maybe_pbft_view_change(); } pbft_ctrl.state_machine.do_send_view_change(); @@ -308,7 +308,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o pbft_new_view_generator.maybe_pbft_prepare(); BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_prepared(), true); BOOST_CHECK_EQUAL(ctrl_new_view_generator.head_block_num(), 136); - for(int i = 0; i(nv_msg, c1_pbft_controller.pbft_db.get_chain_id()); - /// boscore issue https://github.com/boscore/bos/issues/114. - /// It will never throw exception block_validate_exception, "next block must be in the future" in the version 20e08dba c1_pbft_controller.on_pbft_new_view(std::make_shared>(pmm)); c1_pbft_controller.maybe_pbft_commit(); c1.produce_blocks(2); From 239f48451f47cddf093b9231a207560ac125f26e Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 31 Jul 2019 15:50:22 +0800 Subject: [PATCH 12/37] refactor pbft db persistence --- libraries/chain/chain_config.cpp | 1 + .../include/eosio/chain/chain_config.hpp | 1 + .../include/eosio/chain/pbft_database.hpp | 14 +++-- libraries/chain/pbft.cpp | 45 +++++----------- libraries/chain/pbft_database.cpp | 51 +++++++++++-------- libraries/chain/wasm_interface.cpp | 11 ++++ plugins/net_plugin/net_plugin.cpp | 13 +++-- unittests/pbft_tests.cpp | 2 +- 8 files changed, 72 insertions(+), 66 deletions(-) diff --git a/libraries/chain/chain_config.cpp b/libraries/chain/chain_config.cpp index e801736fe66..7b4b1fca60c 100644 --- a/libraries/chain/chain_config.cpp +++ b/libraries/chain/chain_config.cpp @@ -51,6 +51,7 @@ void chain_config2::validate() const{ void chain_config3::validate() const{ EOS_ASSERT( view_change_timeout >= 1, action_validate_exception, "view change timeout must be at least 1"); + EOS_ASSERT( pbft_checkpoint_granularity >= 100 && pbft_checkpoint_granularity % 100 == 0, action_validate_exception, "pbft checkpoint granularity must be multiple of 100 blocks"); } } } // namespace eosio::chain diff --git a/libraries/chain/include/eosio/chain/chain_config.hpp b/libraries/chain/include/eosio/chain/chain_config.hpp index 283db798746..d2e9d5c0184 100644 --- a/libraries/chain/include/eosio/chain/chain_config.hpp +++ b/libraries/chain/include/eosio/chain/chain_config.hpp @@ -120,6 +120,7 @@ struct chain_config2 { struct chain_config3 { uint16_t view_change_timeout = 6; /// the actual wait time will be `num * 5` + uint16_t pbft_checkpoint_granularity = 100; /// the interval of normal checkpoints must be a multiple of 100 * n; void validate()const; }; diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 0d8bf6d3aa8..0ba096427ef 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -428,21 +428,16 @@ namespace eosio { void add_pbft_view_change(const pbft_view_change& vc, const public_key_type& pk); void add_pbft_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk); - vector generate_and_add_pbft_prepare( - const pbft_prepare& cached_prepare = pbft_prepare(), - pbft_view_type current_view = 0); - vector generate_and_add_pbft_commit( - const pbft_commit& cached_commit = pbft_commit(), - pbft_view_type current_view = 0); + vector generate_and_add_pbft_prepare(const pbft_prepare& cached_prepare = pbft_prepare()); + vector generate_and_add_pbft_commit(const pbft_commit& cached_commit = pbft_commit()); vector generate_and_add_pbft_view_change( const pbft_view_change& cached_view_change = pbft_view_change(), const pbft_prepared_certificate& ppc = pbft_prepared_certificate(), const vector& pcc = vector{}, - pbft_view_type current_view = 0, pbft_view_type target_view = 1); pbft_new_view generate_pbft_new_view( const pbft_view_changed_certificate& vcc = pbft_view_changed_certificate(), - pbft_view_type current_view = 1); + pbft_view_type new_view = 1); vector generate_and_add_pbft_checkpoint(); bool should_prepared(); @@ -485,6 +480,8 @@ namespace eosio { void cleanup_on_new_view(); void update_fork_schedules(); uint16_t get_view_change_timeout() const; + const pbft_view_type get_current_view() { return _current_view; } + void set_current_view(pbft_view_type view) { _current_view = view; } //api related pbft_state_ptr get_pbft_state_by_id(const block_id_type& id) const; @@ -503,6 +500,7 @@ namespace eosio { vector prepare_watermarks; flat_map fork_schedules; chain_id_type chain_id = ctrl.get_chain_id(); + pbft_view_type _current_view; block_info_type cal_pending_stable_checkpoint() const; bool is_less_than_high_watermark(block_num_type bnum); diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 0fdf3adf43a..30f9ab80df9 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -9,35 +9,12 @@ namespace eosio { pbft_db(ctrl), state_machine(pbft_db) { state_machine.set_current(std::make_shared(state_machine, pbft_db)); - datadir = ctrl.state_dir(); - - if (!fc::is_directory(datadir)) - fc::create_directories(datadir); - - auto pbft_db_dat = datadir / config::pbftdb_filename; - if (fc::exists(pbft_db_dat)) { - string content; - fc::read_file_contents(pbft_db_dat, content); - - fc::datastream ds(content.data(), content.size()); - uint32_t current_view; - fc::raw::unpack(ds, current_view); - state_machine.set_current_view(current_view); - state_machine.set_target_view(state_machine.get_current_view() + 1); - ilog("current view: ${cv}", ("cv", current_view)); - } - - fc::remove(pbft_db_dat); + state_machine.set_current_view(pbft_db.get_current_view()); + state_machine.set_target_view(state_machine.get_current_view() + 1); + ilog("current view: ${cv}", ("cv", pbft_db.get_current_view())); } - pbft_controller::~pbft_controller() { - fc::path pbft_db_dat = datadir / config::pbftdb_filename; - std::ofstream out(pbft_db_dat.generic_string().c_str(), - std::ios::out | std::ios::binary | std::ofstream::trunc); - - uint32_t current_view = state_machine.get_current_view(); - fc::raw::pack(out, current_view); - } + pbft_controller::~pbft_controller() = default; void pbft_controller::maybe_pbft_prepare() { if (!pbft_db.should_send_pbft_msg()) return; @@ -84,7 +61,7 @@ namespace eosio { state_machine.on_new_view(nv); } - void pbft_controller::on_pbft_checkpoint(const pbft_metadata_ptr &cp) { + void pbft_controller::on_pbft_checkpoint(const pbft_metadata_ptr& cp) { if (!pbft_db.is_valid_checkpoint(cp->msg, cp->sender_key)) return; pbft_db.add_pbft_checkpoint(cp->msg, cp->sender_key); pbft_db.checkpoint_local(); @@ -140,6 +117,7 @@ namespace eosio { void psm_machine::manually_set_current_view(uint32_t cv) { set_current_view(cv); + pbft_db.set_current_view(cv); set_target_view(cv + 1); transit_to_view_change_state(); } @@ -302,7 +280,10 @@ namespace eosio { if (!to_new_view) { auto nv = pbft_db.get_committed_view(); - if (nv > get_current_view()) set_current_view(nv); + if (nv > get_current_view()) { + set_current_view(nv); + pbft_db.set_current_view(nv); + } set_target_view(get_current_view() + 1); } @@ -393,6 +374,7 @@ namespace eosio { void psm_machine::transit_to_new_view(const pbft_metadata_ptr& e) { set_current_view(e->msg.new_view); + pbft_db.set_current_view(e->msg.new_view); set_target_view(e->msg.new_view + 1); set_prepare_cache(pbft_prepare()); @@ -425,7 +407,7 @@ namespace eosio { } void psm_machine::do_send_prepare() { - auto prepares = pbft_db.generate_and_add_pbft_prepare(get_prepare_cache(), get_current_view()); + auto prepares = pbft_db.generate_and_add_pbft_prepare(get_prepare_cache()); if (!prepares.empty()) { for (const auto& p: prepares) { emit(pbft_outgoing_prepare, std::make_shared(p)); @@ -435,7 +417,7 @@ namespace eosio { } void psm_machine::do_send_commit() { - auto commits = pbft_db.generate_and_add_pbft_commit(get_commit_cache(), get_current_view()); + auto commits = pbft_db.generate_and_add_pbft_commit(get_commit_cache()); if (!commits.empty()) { for (const auto& c: commits) { @@ -469,7 +451,6 @@ namespace eosio { get_view_change_cache(), get_prepared_certificate(), get_committed_certificate(), - get_current_view(), get_target_view()); if (!view_changes.empty()) { diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index d0b60d88f35..8b58e30e0ea 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -23,8 +23,8 @@ namespace eosio { fc::datastream ds(content.data(), content.size()); - //skip current_view in pbftdb.dat. - ds.seekp(ds.tellp() + 4); + //set current_view in pbftdb.dat. + fc::raw::unpack(ds, _current_view); unsigned_int size; fc::raw::unpack(ds, size); @@ -76,7 +76,9 @@ namespace eosio { fc::path pbft_db_dat = pbft_db_dir / config::pbftdb_filename; std::ofstream out(pbft_db_dat.generic_string().c_str(), - std::ios::out | std::ios::binary | std::ofstream::app); + std::ios::out | std::ios::binary | std::ofstream::trunc); + fc::raw::pack(out, _current_view); + uint32_t num_records_in_db = pbft_state_index.size(); fc::raw::pack(out, unsigned_int{num_records_in_db}); @@ -169,8 +171,7 @@ namespace eosio { by_block_id_index.modify(itr, [&](const pbft_state_ptr& p) { p->is_prepared = true; }); } - vector pbft_database::generate_and_add_pbft_prepare(const pbft_prepare& cached_prepare, - pbft_view_type current_view) { + vector pbft_database::generate_and_add_pbft_prepare(const pbft_prepare& cached_prepare) { vector prepares_to_be_cached; const auto& my_sps = ctrl.my_signature_providers(); prepares_to_be_cached.reserve(my_sps.size()); @@ -196,15 +197,19 @@ namespace eosio { auto retry_p = cached_prepare; retry_p.common.timestamp = time_point::now(); retry_p.sender_signature = sp.second(retry_p.digest(chain_id)); - prepares_to_be_cached.emplace_back(retry_p); + if (is_valid_prepare(retry_p, sp.first)) { + prepares_to_be_cached.emplace_back(retry_p); + } } } else if (reserve_prepare(my_prepare)) { for (const auto& sp : my_sps) { pbft_prepare reserve_p; - reserve_p.view = current_view; + reserve_p.view = _current_view; reserve_p.block_info = {my_prepare}; reserve_p.sender_signature = sp.second(reserve_p.digest(chain_id)); - prepares_to_be_cached.emplace_back(reserve_p); + if (is_valid_prepare(reserve_p, sp.first)) { + prepares_to_be_cached.emplace_back(reserve_p); + } } } else { auto current_watermark = get_current_pbft_watermark(); @@ -222,7 +227,7 @@ namespace eosio { auto sent = false; for (const auto& sp : my_sps) { pbft_prepare new_p; - new_p.view = current_view; + new_p.view = _current_view; new_p.block_info = {hwbs->id}; new_p.sender_signature = sp.second(new_p.digest(chain_id)); if (is_valid_prepare(new_p, sp.first)) { @@ -323,8 +328,7 @@ namespace eosio { } } - vector pbft_database::generate_and_add_pbft_commit(const pbft_commit& cached_commit, - pbft_view_type current_view) { + vector pbft_database::generate_and_add_pbft_commit(const pbft_commit& cached_commit) { vector commits_to_be_cached; const auto& my_sps = ctrl.my_signature_providers(); commits_to_be_cached.reserve(my_sps.size()); @@ -335,7 +339,9 @@ namespace eosio { auto retry_c = cached_commit; retry_c.common.timestamp = time_point::now(); retry_c.sender_signature = sp.second(retry_c.digest(chain_id)); - commits_to_be_cached.emplace_back(retry_c); + if (is_valid_commit(retry_c, sp.first)) { + commits_to_be_cached.emplace_back(retry_c); + } } } else { const auto& by_prepare_and_num_index = pbft_state_index.get(); @@ -350,7 +356,7 @@ namespace eosio { for (const auto& sp : my_sps) { pbft_commit new_c; - new_c.view = current_view; + new_c.view = _current_view; new_c.block_info = {psp->block_id}; new_c.sender_signature = sp.second(new_c.digest(chain_id)); @@ -510,7 +516,6 @@ namespace eosio { const pbft_view_change& cached_view_change, const pbft_prepared_certificate& ppc, const vector& pcc, - pbft_view_type current_view, pbft_view_type target_view) { vector view_changes_to_be_cached; @@ -523,14 +528,16 @@ namespace eosio { auto retry_vc = cached_view_change; retry_vc.common.timestamp = time_point::now(); retry_vc.sender_signature = sp.second(retry_vc.digest(chain_id)); - view_changes_to_be_cached.emplace_back(retry_vc); + if (is_valid_view_change(retry_vc, sp.first)) { + view_changes_to_be_cached.emplace_back(retry_vc); + } } } else { for (const auto& sp : my_sps) { auto my_lsc = get_stable_checkpoint_by_id(ctrl.last_stable_checkpoint_block_id()); pbft_view_change new_vc; - new_vc.current_view = current_view; + new_vc.current_view = _current_view; new_vc.target_view = target_view; new_vc.prepared_cert = ppc; new_vc.committed_certs = pcc; @@ -574,11 +581,11 @@ namespace eosio { pbft_new_view pbft_database::generate_pbft_new_view( const pbft_view_changed_certificate& vcc, - pbft_view_type current_view) { + pbft_view_type new_view) { pbft_new_view nv; - auto primary_key = get_new_view_primary_key(current_view); + auto primary_key = get_new_view_primary_key(new_view); if (!has_new_primary(primary_key) || vcc.empty()) return nv; //`sp_itr` is not possible to be the end iterator, since it's already been checked in `has_new_primary`. @@ -605,7 +612,7 @@ namespace eosio { } } - nv.new_view = current_view; + nv.new_view = new_view; nv.prepared_cert = highest_ppc; nv.committed_certs = highest_pcc; nv.stable_checkpoint = highest_sc; @@ -1241,8 +1248,8 @@ namespace eosio { cp.sender_signature = sp.second(cp.digest(chain_id)); if (is_valid_checkpoint(cp, sp.first)) { add_pbft_checkpoint(cp, sp.first); + new_pc.emplace_back(cp); } - new_pc.emplace_back(cp); } } } @@ -1251,7 +1258,9 @@ namespace eosio { pbft_checkpoint cp; cp.block_info={ctrl.last_stable_checkpoint_block_id()}; cp.sender_signature = sp.second(cp.digest(chain_id)); - new_pc.emplace_back(cp); + if (is_valid_checkpoint(cp, sp.first)) { + new_pc.emplace_back(cp); + } } } return new_pc; diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index a7993d40a27..6131f00f701 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -210,6 +210,17 @@ class privileged_api : public context_aware_api { }); } + void set_pbft_parameters_packed( array_ptr packed_pbft_parameters, size_t datalen) { + datastream ds( packed_pbft_parameters, datalen ); + chain::chain_config3 cfg; + fc::raw::unpack(ds, cfg); + cfg.validate(); + context.db.modify( context.control.get_pbft_properties(), + [&]( auto& gpp ) { + gpp.configuration = cfg; + }); + } + // *bos begin* void set_name_list_packed(int64_t list, int64_t action, array_ptr packed_name_list, size_t datalen) { diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 43f7336074e..bd1b6041048 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -1597,16 +1597,21 @@ namespace eosio { void sync_manager::sync_stable_checkpoints(const connection_ptr& c, uint32_t target) { controller& cc = chain_plug->chain(); uint32_t lscb_num = cc.last_stable_checkpoint_block_num(); - if (last_req_scp_num < lscb_num || last_req_scp_num == 0 || last_req_scp_num >= target) last_req_scp_num = lscb_num; + auto head_num = cc.head_block_num(); + if (last_req_scp_num < lscb_num + || last_req_scp_num == 0 + || last_req_scp_num > target) last_req_scp_num = lscb_num; + auto end = target; auto max_target_scp_num = last_req_scp_num + pbft_checkpoint_granularity * 10; - if (target > max_target_scp_num) end = max_target_scp_num; + if (target > max_target_scp_num) end = std::min(max_target_scp_num, head_num); + if (end - last_req_scp_num < pbft_checkpoint_granularity) return; checkpoint_request_message crm = {last_req_scp_num+1,end}; c->enqueue( net_message(crm)); fc_dlog(logger, "request sync stable checkpoints from ${s} to ${e}", - ("s", last_req_scp_num+1)("e", max_target_scp_num)); - last_req_scp_num = max_target_scp_num; + ("s", last_req_scp_num+1)("e", end)); + last_req_scp_num = end; } void sync_manager::reassign_fetch(const connection_ptr& c, go_away_reason reason) { diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index 40856b24268..bd2b53df97b 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -439,7 +439,7 @@ BOOST_AUTO_TEST_CASE(new_view_with_committed_cert_call_two_times_maybe_switch_fo c1_pbft_controller.maybe_pbft_commit(); c1.produce_blocks(2); BOOST_CHECK_EQUAL(c1_ctrl.last_irreversible_block_num(), 137); - // make sure commited block same with new view generator lib block + // make sure committed block same with new view generator lib block BOOST_CHECK_EQUAL(c1_ctrl.fetch_block_by_number(137)->id(), ctrl_new_view_generator.fetch_block_by_number(137)->id()); } From dac6102fc5b611ea438b679d02fc969db444c5a9 Mon Sep 17 00:00:00 2001 From: oldcold Date: Thu, 1 Aug 2019 16:31:43 +0800 Subject: [PATCH 13/37] fix tests --- .../chain/include/eosio/chain/pbft_database.hpp | 13 +++++-------- libraries/chain/pbft.cpp | 4 ++-- libraries/chain/pbft_database.cpp | 11 +++++------ plugins/net_plugin/net_plugin.cpp | 9 +++++---- plugins/pbft_plugin/pbft_plugin.cpp | 12 ++++++------ 5 files changed, 23 insertions(+), 26 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 0ba096427ef..6b4bb2cd7a9 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -19,7 +19,6 @@ namespace eosio { using pbft_view_type = uint32_t; - constexpr uint16_t pbft_checkpoint_granularity = 100; constexpr uint16_t oldest_stable_checkpoint = 10000; enum class pbft_message_type : uint8_t { @@ -268,7 +267,7 @@ namespace eosio { bool empty() const { return !target_view - && view_changes.empty(); + && view_changes.empty(); } }; @@ -300,7 +299,7 @@ namespace eosio { } bool empty() const { - return new_view == 0 + return !new_view && prepared_cert.empty() && committed_certs.empty() && stable_checkpoint.empty() @@ -418,11 +417,8 @@ namespace eosio { class pbft_database { public: explicit pbft_database(controller& ctrl); - ~pbft_database(); - void close(); - void add_pbft_prepare(const pbft_prepare& p, const public_key_type& pk); void add_pbft_commit(const pbft_commit& c, const public_key_type& pk); void add_pbft_view_change(const pbft_view_change& vc, const public_key_type& pk); @@ -473,13 +469,14 @@ namespace eosio { bool should_recv_pbft_msg(const public_key_type& pub_key); bool pending_pbft_lib(); - chain_id_type& get_chain_id() {return chain_id;} + chain_id_type& get_chain_id() { return chain_id; } pbft_stable_checkpoint get_stable_checkpoint_by_id(const block_id_type& block_id, bool incl_blk_extn = true); pbft_stable_checkpoint fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr& b); void cleanup_on_new_view(); void update_fork_schedules(); uint16_t get_view_change_timeout() const; + uint16_t get_checkpoint_interval() const; const pbft_view_type get_current_view() { return _current_view; } void set_current_view(pbft_view_type view) { _current_view = view; } @@ -500,7 +497,7 @@ namespace eosio { vector prepare_watermarks; flat_map fork_schedules; chain_id_type chain_id = ctrl.get_chain_id(); - pbft_view_type _current_view; + pbft_view_type _current_view = 0; block_info_type cal_pending_stable_checkpoint() const; bool is_less_than_high_watermark(block_num_type bnum); diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 30f9ab80df9..118848ea650 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -5,7 +5,7 @@ namespace eosio { namespace chain { - pbft_controller::pbft_controller(controller &ctrl) : + pbft_controller::pbft_controller(controller& ctrl) : pbft_db(ctrl), state_machine(pbft_db) { state_machine.set_current(std::make_shared(state_machine, pbft_db)); @@ -387,7 +387,7 @@ namespace eosio { if (!e->msg.committed_certs.empty()) { auto committed_certs = e->msg.committed_certs; std::sort(committed_certs.begin(), committed_certs.end()); - for (auto const &cc :committed_certs) { + for (const auto& cc :committed_certs) { pbft_db.mark_as_committed(cc.block_info.block_id); } } diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 8b58e30e0ea..73e50056b95 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -61,7 +61,7 @@ namespace eosio { fc::remove(checkpoints_db); } - void pbft_database::close() { + pbft_database::~pbft_database() { fc::path checkpoints_db = checkpoints_dir / config::checkpoints_filename; std::ofstream c_out(checkpoints_db.generic_string().c_str(), @@ -90,10 +90,6 @@ namespace eosio { checkpoint_index.clear(); } - pbft_database::~pbft_database() { - close(); - } - void pbft_database::add_pbft_prepare(const pbft_prepare& p, const public_key_type& pk) { auto& by_block_id_index = pbft_state_index.get(); @@ -1215,7 +1211,7 @@ namespace eosio { if (in <= ucb) return false; auto watermarks = get_updated_watermarks(); return in == ucb + 1 // checkpoint on first pbft block; - || in % pbft_checkpoint_granularity == 1 // checkpoint on every 100 block; + || in % get_checkpoint_interval() == 1 // checkpoint on every 100 block; || std::find(watermarks.begin(), watermarks.end(), in) != watermarks.end(); // checkpoint on bp schedule change; }; @@ -1529,6 +1525,9 @@ namespace eosio { return ctrl.get_pbft_properties().configuration.view_change_timeout; } + uint16_t pbft_database::get_checkpoint_interval() const { + return ctrl.get_pbft_properties().configuration.pbft_checkpoint_granularity; + } bool pbft_database::is_less_than_high_watermark(block_num_type bnum) { auto current_watermark = get_current_pbft_watermark(); diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index bd1b6041048..31fdeec6dd1 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -1602,6 +1602,7 @@ namespace eosio { || last_req_scp_num == 0 || last_req_scp_num > target) last_req_scp_num = lscb_num; + auto pbft_checkpoint_granularity = chain_plug->pbft_ctrl().pbft_db.get_checkpoint_interval(); auto end = target; auto max_target_scp_num = last_req_scp_num + pbft_checkpoint_granularity * 10; if (target > max_target_scp_num) end = std::min(max_target_scp_num, head_num); @@ -2830,18 +2831,18 @@ namespace eosio { fc_dlog(logger, "received checkpoint request message ${m}, from ${p}", ("m", msg)("p", c->peer_name())); - if ( msg.end_block - msg.start_block > pbft_checkpoint_granularity * 100) { + if ( msg.end_block - msg.start_block > chain_plug->pbft_ctrl().pbft_db.get_checkpoint_interval() * 100) { fc_dlog(logger, "request range too large"); return; } vector scp_stack; - controller &cc = my_impl->chain_plug->chain(); - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + controller& cc = my_impl->chain_plug->chain(); + pbft_controller& pcc = my_impl->chain_plug->pbft_ctrl(); auto end_block = std::min(msg.end_block, cc.last_stable_checkpoint_block_num()); - for (auto i = end_block; i >= msg.start_block && i>0; --i) { + for (auto i = end_block; i >= msg.start_block && i > 0; --i) { try { auto bid = cc.get_block_id_for_num(i); auto scp = pcc.pbft_db.get_stable_checkpoint_by_id(bid); diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index 8acf2b49a19..81a1c298c07 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -70,7 +70,7 @@ namespace eosio { } else if (ec) { wlog ("pbft plugin prepare timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + chain::pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_prepare(); } prepare_timer_tick(); @@ -86,7 +86,7 @@ namespace eosio { } else if (ec) { wlog ("pbft plugin commit timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + chain::pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_commit(); } commit_timer_tick(); @@ -106,7 +106,7 @@ namespace eosio { if (ec) { wlog ("pbft plugin view change timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + chain::pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_view_change(); } }); @@ -121,11 +121,11 @@ namespace eosio { } if (ec) { wlog ("pbft plugin checkpoint timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + chain::pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_checkpoint(); - chain::controller &ctrl = app().get_plugin().chain(); - if ( ctrl.head_block_num() - ctrl.last_stable_checkpoint_block_num() / pbft_checkpoint_granularity > 1) { + chain::controller& ctrl = app().get_plugin().chain(); + if ( ctrl.head_block_num() - ctrl.last_stable_checkpoint_block_num() / pbft_ctrl.pbft_db.get_checkpoint_interval() > 1) { //perhaps we need to sync stable checkpoints from other peers app().get_plugin().maybe_sync_stable_checkpoints(); } From 82f00a8e167e206a74e12ee674885ee723f2a27d Mon Sep 17 00:00:00 2001 From: oldcold Date: Thu, 15 Aug 2019 11:33:54 +0800 Subject: [PATCH 14/37] reset view change timer when global timeout is changed. --- libraries/chain/include/eosio/chain/pbft.hpp | 1 + libraries/chain/pbft.cpp | 15 +++++++++++---- libraries/chain/pbft_database.cpp | 2 +- plugins/pbft_plugin/pbft_plugin.cpp | 4 ++-- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index 0bfb7e8942a..b84962d03dc 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -208,6 +208,7 @@ namespace eosio { private: fc::path datadir; + uint16_t view_change_timeout = 6; }; } } /// namespace eosio::chain diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 118848ea650..8ac97cb1c49 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -28,7 +28,14 @@ namespace eosio { void pbft_controller::maybe_pbft_view_change() { if (!pbft_db.should_send_pbft_msg()) return; - if (state_machine.get_view_change_timer() <= pbft_db.get_view_change_timeout()) { + + if (view_change_timeout != pbft_db.get_view_change_timeout()) { + ///if there is a change in global states, update timeout and reset timer. + view_change_timeout = pbft_db.get_view_change_timeout(); + state_machine.set_view_change_timer(0); + } + + if (state_machine.get_view_change_timer() <= view_change_timeout) { if (!state_machine.get_view_change_cache().empty()) { pbft_db.generate_and_add_pbft_view_change(state_machine.get_view_change_cache()); } @@ -198,14 +205,14 @@ namespace eosio { //do action add prepare pbft_db.add_pbft_prepare(e->msg, e->sender_key); - //if prepare >= 2f+1, transit to prepared + //if prepare >= n-f, transit to prepared if (pbft_db.should_prepared()) m.transit_to_prepared_state(); } void psm_committed_state::send_prepare() { m.do_send_prepare(); - //if prepare >= 2f+1, transit to prepared + //if prepare >= n-f, transit to prepared if (pbft_db.should_prepared()) m.transit_to_prepared_state(); } @@ -344,7 +351,7 @@ namespace eosio { } bool psm_machine::maybe_new_view() { - //if view_change >= 2f+1, calculate next primary, send new view if is primary + //if view_change >= n-f, calculate next primary, send new view if is primary auto nv = get_target_view(); auto pk = pbft_db.get_new_view_primary_key(nv); if (pbft_db.should_new_view(nv) && pbft_db.has_new_primary(pk)) { diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 73e50056b95..7e83a1795d5 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -499,7 +499,7 @@ namespace eosio { } } //if contains self or view_change >= f+1, transit to view_change and send view change - if (vc_count >= active_bps.size() / 3 + 1) { + if (vc_count > (active_bps.size() - 1) / 3) { nv = pvs->view; break; } diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index 81a1c298c07..7d27f1607bd 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -25,8 +25,8 @@ namespace eosio { unique_ptr view_change_timer; unique_ptr checkpoint_timer; - boost::asio::steady_timer::duration prepare_timeout{std::chrono::milliseconds{1000}}; - boost::asio::steady_timer::duration commit_timeout{std::chrono::milliseconds{1000}}; + boost::asio::steady_timer::duration prepare_timeout{std::chrono::milliseconds{750}}; + boost::asio::steady_timer::duration commit_timeout{std::chrono::milliseconds{750}}; boost::asio::steady_timer::duration view_change_check_interval{std::chrono::seconds{5}}; boost::asio::steady_timer::duration checkpoint_timeout{std::chrono::seconds{25}}; From 28403172460f32acf504e59e5e8129bf5da60a31 Mon Sep 17 00:00:00 2001 From: oldcold Date: Fri, 16 Aug 2019 18:27:47 +0800 Subject: [PATCH 15/37] reserve prepare only if my_prepare is on forks --- libraries/chain/pbft_database.cpp | 10 +++++++--- unittests/pbft_tests.cpp | 22 +++++++++++++--------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 7e83a1795d5..5bf4a743bd1 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -176,14 +176,18 @@ namespace eosio { auto my_prepare = ctrl.get_pbft_my_prepare(); auto reserve_prepare = [&](const block_id_type& in) { - if (in == block_id_type() || !ctrl.fetch_block_state_by_id(in)) return false; + if (in == block_id_type()) return false; + auto bs = ctrl.fetch_block_state_by_id(in); + if (!bs) return false; auto lib = ctrl.last_irreversible_block_id(); if (lib == block_id_type()) return true; auto forks = ctrl.fork_db().fetch_branch_from(in, lib); //`branch_type` will always contain at least themselves. //`in` block num should be higher than lib, yet fall on the same branch with lib. - return forks.first.size() > 1 && forks.second.size() == 1; + return forks.first.size() > 1 + && forks.second.size() == 1 + && !bs->in_current_chain; }; @@ -197,7 +201,7 @@ namespace eosio { prepares_to_be_cached.emplace_back(retry_p); } } - } else if (reserve_prepare(my_prepare)) { + } else if (reserve_prepare(my_prepare) ) { for (const auto& sp : my_sps) { pbft_prepare reserve_p; reserve_p.view = _current_view; diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index bd2b53df97b..e7db3bbe66a 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -547,6 +547,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { pbft_commit c2_commit_ = c2_pbft_controller.state_machine.get_commit_cache(); c1_pbft_controller.state_machine.on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); + auto c1_my_prepare_block = c1_ctrl.get_pbft_my_prepare(); c1.produce_block(); c1_pbft_controller.maybe_pbft_commit(); BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 98); @@ -556,7 +557,10 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { /// make c3_final lib 98 c3_final_pbft_controller.maybe_pbft_prepare(); pbft_prepare c1_prepare_ = c1_pbft_controller.state_machine.get_prepare_cache(); - BOOST_CHECK_EQUAL(c1_prepare_.block_info.block_num(), 99); + + auto forks = c1_ctrl.fork_db().fetch_branch_from(c1_prepare_.block_info.block_id, c1_my_prepare_block); + BOOST_CHECK_EQUAL(forks.first.size() >= 1 && forks.second.size() == 1, true); + c3_final.produce_block(); c3_final_pbft_controller.state_machine.on_prepare(std::make_shared>(c1_prepare_, c1_pbft_controller.pbft_db.get_chain_id())); c3_final_pbft_controller.maybe_pbft_commit(); @@ -599,7 +603,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c1_prepare_ = c1_pbft_controller.state_machine.get_prepare_cache(); c1_commit_ = c1_pbft_controller.state_machine.get_commit_cache(); - BOOST_CHECK_EQUAL(c1_commit_.block_info.block_num(), 99); + BOOST_CHECK_EQUAL(c1_commit_.block_info.block_num(), 100); BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 99); c3_final_pbft_controller.maybe_pbft_prepare(); @@ -607,14 +611,14 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c3_final.produce_block(); c3_final.produce_block(); - BOOST_CHECK_EQUAL(c1_prepare.block_info.block_num(), 99); - /// set c3 my preprare at 100 - c3_final_ctrl.set_pbft_my_prepare(c3_final_ctrl.get_block_id_for_num(100)); + BOOST_CHECK_EQUAL(c1_prepare.block_info.block_num(), 100); + /// set c3 my prepare at 101 + c3_final_ctrl.set_pbft_my_prepare(c3_final_ctrl.get_block_id_for_num(101)); c3_final_pbft_controller.state_machine.on_prepare(std::make_shared>(c1_prepare, c1_pbft_controller.pbft_db.get_chain_id())); pbft_prepare c3_final_prepare = c3_final_pbft_controller.state_machine.get_prepare_cache(); - // check c3 prepare at 99 - BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 99); + // check c3 prepare at 100 + BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 101); curr_state = c3_final_pbft_controller.state_machine.get_current()->get_name(); BOOST_CHECK_EQUAL(curr_state, "{==== PREPARED ====}"); @@ -650,11 +654,11 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c3_final_pbft_controller.maybe_pbft_commit(); curr_state = c3_final_pbft_controller.state_machine.get_current()->get_name(); BOOST_CHECK_EQUAL(curr_state, "{==== COMMITTED ====}"); - BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 99); + BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 100); c3_final_pbft_controller.maybe_pbft_prepare(); c3_final_prepare = c3_final_pbft_controller.state_machine.get_prepare_cache(); - BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 100); + BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 103); } From 6efb1a98588161e032af7e1e900aeb26686c46ea Mon Sep 17 00:00:00 2001 From: oldcold Date: Fri, 16 Aug 2019 18:27:47 +0800 Subject: [PATCH 16/37] reserve prepare only if my_prepare is on forks --- libraries/chain/block_header_state.cpp | 4 ++-- libraries/chain/pbft_database.cpp | 10 +++++++--- unittests/pbft_tests.cpp | 22 +++++++++++++--------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index 83e7c3292ad..690b10a947e 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -158,7 +158,7 @@ namespace eosio { namespace chain { pending_schedule = *header.new_producers; pending_schedule_lib_num = block_num; } - + /** * Transitions the current header state into the next header state given the supplied signed block header. @@ -176,7 +176,7 @@ namespace eosio { namespace chain { EOS_ASSERT( h.previous == id, unlinkable_block_exception, "block must link to current state" ); auto result = generate_next( h.timestamp, pbft_enabled); EOS_ASSERT( result.header.producer == h.producer, wrong_producer, "wrong producer specified" ); - EOS_ASSERT( result.header.schedule_version == h.schedule_version, producer_schedule_exception, "schedule_version in s igned block is corrupted" ); + EOS_ASSERT( result.header.schedule_version == h.schedule_version, producer_schedule_exception, "schedule_version in signed block is corrupted" ); auto itr = producer_to_last_produced.find(h.producer); if( itr != producer_to_last_produced.end() ) { diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 7e83a1795d5..5bf4a743bd1 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -176,14 +176,18 @@ namespace eosio { auto my_prepare = ctrl.get_pbft_my_prepare(); auto reserve_prepare = [&](const block_id_type& in) { - if (in == block_id_type() || !ctrl.fetch_block_state_by_id(in)) return false; + if (in == block_id_type()) return false; + auto bs = ctrl.fetch_block_state_by_id(in); + if (!bs) return false; auto lib = ctrl.last_irreversible_block_id(); if (lib == block_id_type()) return true; auto forks = ctrl.fork_db().fetch_branch_from(in, lib); //`branch_type` will always contain at least themselves. //`in` block num should be higher than lib, yet fall on the same branch with lib. - return forks.first.size() > 1 && forks.second.size() == 1; + return forks.first.size() > 1 + && forks.second.size() == 1 + && !bs->in_current_chain; }; @@ -197,7 +201,7 @@ namespace eosio { prepares_to_be_cached.emplace_back(retry_p); } } - } else if (reserve_prepare(my_prepare)) { + } else if (reserve_prepare(my_prepare) ) { for (const auto& sp : my_sps) { pbft_prepare reserve_p; reserve_p.view = _current_view; diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index bd2b53df97b..e7db3bbe66a 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -547,6 +547,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { pbft_commit c2_commit_ = c2_pbft_controller.state_machine.get_commit_cache(); c1_pbft_controller.state_machine.on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); + auto c1_my_prepare_block = c1_ctrl.get_pbft_my_prepare(); c1.produce_block(); c1_pbft_controller.maybe_pbft_commit(); BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 98); @@ -556,7 +557,10 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { /// make c3_final lib 98 c3_final_pbft_controller.maybe_pbft_prepare(); pbft_prepare c1_prepare_ = c1_pbft_controller.state_machine.get_prepare_cache(); - BOOST_CHECK_EQUAL(c1_prepare_.block_info.block_num(), 99); + + auto forks = c1_ctrl.fork_db().fetch_branch_from(c1_prepare_.block_info.block_id, c1_my_prepare_block); + BOOST_CHECK_EQUAL(forks.first.size() >= 1 && forks.second.size() == 1, true); + c3_final.produce_block(); c3_final_pbft_controller.state_machine.on_prepare(std::make_shared>(c1_prepare_, c1_pbft_controller.pbft_db.get_chain_id())); c3_final_pbft_controller.maybe_pbft_commit(); @@ -599,7 +603,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c1_prepare_ = c1_pbft_controller.state_machine.get_prepare_cache(); c1_commit_ = c1_pbft_controller.state_machine.get_commit_cache(); - BOOST_CHECK_EQUAL(c1_commit_.block_info.block_num(), 99); + BOOST_CHECK_EQUAL(c1_commit_.block_info.block_num(), 100); BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 99); c3_final_pbft_controller.maybe_pbft_prepare(); @@ -607,14 +611,14 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c3_final.produce_block(); c3_final.produce_block(); - BOOST_CHECK_EQUAL(c1_prepare.block_info.block_num(), 99); - /// set c3 my preprare at 100 - c3_final_ctrl.set_pbft_my_prepare(c3_final_ctrl.get_block_id_for_num(100)); + BOOST_CHECK_EQUAL(c1_prepare.block_info.block_num(), 100); + /// set c3 my prepare at 101 + c3_final_ctrl.set_pbft_my_prepare(c3_final_ctrl.get_block_id_for_num(101)); c3_final_pbft_controller.state_machine.on_prepare(std::make_shared>(c1_prepare, c1_pbft_controller.pbft_db.get_chain_id())); pbft_prepare c3_final_prepare = c3_final_pbft_controller.state_machine.get_prepare_cache(); - // check c3 prepare at 99 - BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 99); + // check c3 prepare at 100 + BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 101); curr_state = c3_final_pbft_controller.state_machine.get_current()->get_name(); BOOST_CHECK_EQUAL(curr_state, "{==== PREPARED ====}"); @@ -650,11 +654,11 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c3_final_pbft_controller.maybe_pbft_commit(); curr_state = c3_final_pbft_controller.state_machine.get_current()->get_name(); BOOST_CHECK_EQUAL(curr_state, "{==== COMMITTED ====}"); - BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 99); + BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 100); c3_final_pbft_controller.maybe_pbft_prepare(); c3_final_prepare = c3_final_pbft_controller.state_machine.get_prepare_cache(); - BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 100); + BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 103); } From 6717cf2f853e1fb146763d90520c5daeb7e0f958 Mon Sep 17 00:00:00 2001 From: Frank-AFN Date: Mon, 19 Aug 2019 16:32:30 +0800 Subject: [PATCH 17/37] Modify reserve prepare test case --- unittests/pbft_tests.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index e7db3bbe66a..857b412b750 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -551,6 +551,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c1.produce_block(); c1_pbft_controller.maybe_pbft_commit(); BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 98); +// c1_ctrl.set_pbft_my_prepare(c1_ctrl.get_block_id_for_num(99)); c2_pbft_controller.maybe_pbft_commit(); @@ -612,12 +613,12 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c3_final.produce_block(); BOOST_CHECK_EQUAL(c1_prepare.block_info.block_num(), 100); - /// set c3 my prepare at 101 + /// set c3 my preprare at 101 c3_final_ctrl.set_pbft_my_prepare(c3_final_ctrl.get_block_id_for_num(101)); c3_final_pbft_controller.state_machine.on_prepare(std::make_shared>(c1_prepare, c1_pbft_controller.pbft_db.get_chain_id())); pbft_prepare c3_final_prepare = c3_final_pbft_controller.state_machine.get_prepare_cache(); - // check c3 prepare at 100 + // check c3 prepare at 101 BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 101); curr_state = c3_final_pbft_controller.state_machine.get_current()->get_name(); BOOST_CHECK_EQUAL(curr_state, "{==== PREPARED ====}"); @@ -625,11 +626,12 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c3_final_pbft_controller.maybe_pbft_commit(); + c2_prime.produce_block(); c2_prime.create_accounts({N(tester1)}); - c2_prime.produce_blocks(5); + c2_prime.produce_blocks(6); //push fork to c3_final - for(int i = 100; i <= 104; i++) { + for(int i = 101; i <= 106; i++) { auto fb = c2_prime.control->fetch_block_by_number(i); c3_final.push_block(fb); } @@ -642,7 +644,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { BOOST_CHECK_EQUAL(tmp_c2_prime_prepared_fork->pbft_my_prepare, true); BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 98); - BOOST_CHECK_EQUAL(c3_final.control->head_block_num(), 104); + BOOST_CHECK_EQUAL(c3_final.control->head_block_num(), 106); c3_final_pbft_controller.maybe_pbft_commit(); c3_final.produce_block(); @@ -658,7 +660,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c3_final_pbft_controller.maybe_pbft_prepare(); c3_final_prepare = c3_final_pbft_controller.state_machine.get_prepare_cache(); - BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 103); + BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 101); } From a4e89a239dea7fb172d45f014cfebf135d126e11 Mon Sep 17 00:00:00 2001 From: oldcold Date: Tue, 20 Aug 2019 10:39:09 +0800 Subject: [PATCH 18/37] dpos pbft optimise (#121) * optimise for return value. * reset timer upon state transition; refactor code; * add global object to control pbft behavior; optimise checkpoint logic * refactor pbft db persistence * fix tests * reset view change timer when global timeout is changed. * reserve prepare only if my_prepare is on forks * reserve prepare only if my_prepare is on forks * Modify reserve prepare test case --- libraries/chain/chain_config.cpp | 5 + libraries/chain/controller.cpp | 23 +- libraries/chain/fork_database.cpp | 4 +- .../include/eosio/chain/chain_config.hpp | 10 + .../chain/include/eosio/chain/controller.hpp | 4 +- .../include/eosio/chain/fork_database.hpp | 4 +- .../eosio/chain/global_property_object.hpp | 23 +- libraries/chain/include/eosio/chain/pbft.hpp | 171 ++--- .../include/eosio/chain/pbft_database.hpp | 132 ++-- libraries/chain/include/eosio/chain/types.hpp | 1 + libraries/chain/pbft.cpp | 486 ++++++-------- libraries/chain/pbft_database.cpp | 631 +++++++++--------- libraries/chain/wasm_interface.cpp | 11 + .../include/eosio/chain/plugin_interface.hpp | 3 + plugins/chain_plugin/chain_plugin.cpp | 16 +- plugins/net_plugin/net_plugin.cpp | 377 ++++------- .../include/eosio/pbft_plugin/pbft_plugin.hpp | 6 +- plugins/pbft_plugin/pbft_plugin.cpp | 227 ++++--- unittests/pbft_tests.cpp | 106 +-- 19 files changed, 1083 insertions(+), 1157 deletions(-) diff --git a/libraries/chain/chain_config.cpp b/libraries/chain/chain_config.cpp index c39d89cee46..7b4b1fca60c 100644 --- a/libraries/chain/chain_config.cpp +++ b/libraries/chain/chain_config.cpp @@ -49,4 +49,9 @@ void chain_config2::validate() const{ EOS_ASSERT(std::numeric_limits::max() > resource_greylist.size(), action_validate_exception, "Overflow in greylistwhen adding resource greylist!"); } +void chain_config3::validate() const{ + EOS_ASSERT( view_change_timeout >= 1, action_validate_exception, "view change timeout must be at least 1"); + EOS_ASSERT( pbft_checkpoint_granularity >= 100 && pbft_checkpoint_granularity % 100 == 0, action_validate_exception, "pbft checkpoint granularity must be multiple of 100 blocks"); +} + } } // namespace eosio::chain diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 2aa4644afb4..75a799b74fa 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -36,6 +36,7 @@ using controller_index_set = index_set< global_property2_multi_index, dynamic_global_property_multi_index, upgrade_property_multi_index, + global_property3_multi_index, block_summary_multi_index, transaction_multi_index, generated_transaction_multi_index, @@ -455,6 +456,13 @@ struct controller_impl { wlog("no upo found, generating..."); db.create([](auto&){}); } + + try { + db.get(); + } catch( const boost::exception& e) { + wlog("no gpo3 found, generating..."); + db.create([](auto&){}); + } } ~controller_impl() { @@ -746,6 +754,7 @@ struct controller_impl { // *bos end* + db.create([](auto&) {}); authorization.initialize_database(); resource_limits.initialize_database(); @@ -2526,13 +2535,15 @@ void controller::set_pbft_my_prepare(const block_id_type& id) { } block_id_type controller::get_pbft_prepared() const { - if (my->pbft_prepared) return my->pbft_prepared->id; - return block_id_type{}; + block_id_type pp; + if (my->pbft_prepared) pp = my->pbft_prepared->id; + return pp; } block_id_type controller::get_pbft_my_prepare() const { - if (my->my_prepare) return my->my_prepare->id; - return block_id_type{}; + block_id_type mp; + if (my->my_prepare) mp = my->my_prepare->id; + return mp; } void controller::reset_pbft_my_prepare() { @@ -2701,6 +2712,10 @@ const upgrade_property_object& controller::get_upgrade_properties()const { return my->db.get(); } +const global_property3_object& controller::get_pbft_properties()const { + return my->db.get(); +} + bool controller::is_pbft_enabled() const { return my->pbft_enabled; } diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index 2163a5a5960..be36a908895 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -525,7 +525,7 @@ namespace eosio { namespace chain { * * This will require a search over all forks */ - void fork_database::set_bft_irreversible( block_id_type id ) { + void fork_database::set_bft_irreversible( const block_id_type& id ) { auto b = get_block( id ); EOS_ASSERT( b, fork_db_block_not_found, "unable to find block id ${id}", ("id",id)); @@ -569,7 +569,7 @@ namespace eosio { namespace chain { my->head = *my->index.get().begin(); } - void fork_database::set_latest_checkpoint( block_id_type id) { + void fork_database::set_latest_checkpoint( const block_id_type& id) { auto b = get_block( id ); EOS_ASSERT( b, fork_db_block_not_found, "unable to find block id ${id}", ("id",id)); diff --git a/libraries/chain/include/eosio/chain/chain_config.hpp b/libraries/chain/include/eosio/chain/chain_config.hpp index da258010fbb..d2e9d5c0184 100644 --- a/libraries/chain/include/eosio/chain/chain_config.hpp +++ b/libraries/chain/include/eosio/chain/chain_config.hpp @@ -117,6 +117,14 @@ struct chain_config2 { void validate()const; }; +struct chain_config3 { + + uint16_t view_change_timeout = 6; /// the actual wait time will be `num * 5` + uint16_t pbft_checkpoint_granularity = 100; /// the interval of normal checkpoints must be a multiple of 100 * n; + + void validate()const; +}; + // *bos* struct guaranteed_minimum_resources { uint64_t ram_byte; @@ -140,3 +148,5 @@ FC_REFLECT(eosio::chain::chain_config, // *bos* FC_REFLECT( eosio::chain::chain_config2, (actor_blacklist)(contract_blacklist)(resource_greylist) ) FC_REFLECT( eosio::chain::guaranteed_minimum_resources, (ram_byte)(cpu_us)(net_byte) ) + +FC_REFLECT( eosio::chain::chain_config3, (view_change_timeout) ) diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 7a90125da6e..05c5c925e59 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -31,6 +31,7 @@ namespace eosio { namespace chain { class global_property_object; class global_property2_object; // *bos* class upgrade_property_object; + class global_property3_object; // *bos* class permission_object; class account_object; using resource_limits::resource_limits_manager; @@ -305,7 +306,8 @@ namespace eosio { namespace chain { signal accepted_confirmation; signal bad_alloc; - const upgrade_property_object& get_upgrade_properties()const; + const upgrade_property_object& get_upgrade_properties()const; + const global_property3_object& get_pbft_properties()const; bool is_pbft_enabled()const; bool under_maintenance()const; void set_upo(uint32_t target_block_num); diff --git a/libraries/chain/include/eosio/chain/fork_database.hpp b/libraries/chain/include/eosio/chain/fork_database.hpp index 823c65c5b92..9dfb3f0cc9c 100644 --- a/libraries/chain/include/eosio/chain/fork_database.hpp +++ b/libraries/chain/include/eosio/chain/fork_database.hpp @@ -70,9 +70,9 @@ namespace eosio { namespace chain { */ signal irreversible; - void set_bft_irreversible( block_id_type id ); + void set_bft_irreversible( const block_id_type& id ); - void set_latest_checkpoint( block_id_type id); + void set_latest_checkpoint( const block_id_type& id); void mark_pbft_prepared_fork(const block_state_ptr& h); diff --git a/libraries/chain/include/eosio/chain/global_property_object.hpp b/libraries/chain/include/eosio/chain/global_property_object.hpp index 98f86939ad6..32edc5bea62 100644 --- a/libraries/chain/include/eosio/chain/global_property_object.hpp +++ b/libraries/chain/include/eosio/chain/global_property_object.hpp @@ -54,6 +54,14 @@ namespace eosio { namespace chain { block_num_type upgrade_complete_block_num = 0; }; + class global_property3_object : public chainbase::object + { + OBJECT_CTOR(global_property3_object) + + id_type id; + chain_config3 configuration; + }; + /** * @class dynamic_global_property_object @@ -108,6 +116,15 @@ namespace eosio { namespace chain { > > >; + + using global_property3_multi_index = chainbase::shared_multi_index_container< + global_property3_object, + indexed_by< + ordered_unique, + BOOST_MULTI_INDEX_MEMBER(global_property3_object, global_property3_object::id_type, id) + > + > + >; }} CHAINBASE_SET_INDEX_TYPE(eosio::chain::global_property_object, eosio::chain::global_property_multi_index) @@ -116,6 +133,7 @@ CHAINBASE_SET_INDEX_TYPE(eosio::chain::dynamic_global_property_object, // *bos* CHAINBASE_SET_INDEX_TYPE(eosio::chain::global_property2_object, eosio::chain::global_property2_multi_index) CHAINBASE_SET_INDEX_TYPE(eosio::chain::upgrade_property_object, eosio::chain::upgrade_property_multi_index) +CHAINBASE_SET_INDEX_TYPE(eosio::chain::global_property3_object, eosio::chain::global_property3_multi_index) FC_REFLECT(eosio::chain::dynamic_global_property_object, (global_action_sequence) @@ -130,4 +148,7 @@ FC_REFLECT(eosio::chain::global_property2_object, ) FC_REFLECT(eosio::chain::upgrade_property_object, (upgrade_target_block_num)(upgrade_complete_block_num) - ) \ No newline at end of file + ) +FC_REFLECT(eosio::chain::global_property3_object, + (configuration) +) \ No newline at end of file diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index 2bebe05cc79..b84962d03dc 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -12,12 +12,12 @@ namespace eosio { using namespace fc; struct psm_cache { - pbft_prepare prepares_cache; - pbft_commit commits_cache; - pbft_view_change view_changes_cache; - pbft_prepared_certificate prepared_certificate; - vector committed_certificate; - pbft_view_changed_certificate view_changed_certificate; + pbft_prepare prepare_cache = pbft_prepare(); + pbft_commit commit_cache = pbft_commit(); + pbft_view_change view_change_cache = pbft_view_change(); + pbft_prepared_certificate prepared_certificate = pbft_prepared_certificate(); + vector committed_certificate = vector{}; + pbft_view_changed_certificate view_changed_certificate = pbft_view_changed_certificate(); }; class psm_state; @@ -29,13 +29,9 @@ namespace eosio { explicit psm_machine(pbft_database& pbft_db); ~psm_machine(); - void set_current(psm_state_ptr s) { - current = std::move(s); - } + void set_current(psm_state_ptr s) { current = std::move(s); } - psm_state_ptr get_current() { - return current; - } + const psm_state_ptr& get_current() { return current; } void on_prepare(const pbft_metadata_ptr& e); void on_commit(const pbft_metadata_ptr& e); @@ -45,57 +41,73 @@ namespace eosio { void send_prepare(); void send_commit(); void send_view_change(); + void send_checkpoint(); + bool maybe_new_view(); + void maybe_view_change(); + bool maybe_stop_view_change(); + + void transit_to_committed_state(bool to_new_view); + void transit_to_prepared_state(); + void transit_to_view_change_state(); + void transit_to_new_view(const pbft_metadata_ptr& e); + + void do_send_prepare(); + void do_send_commit(); + void do_send_view_change(); - void transit_to_committed_state(const psm_state_ptr& s, bool to_new_view); - void transit_to_prepared_state(const psm_state_ptr& s); - void transit_to_view_change_state(const psm_state_ptr& s); - void transit_to_new_view(const pbft_metadata_ptr& e, const psm_state_ptr& s); + const pbft_prepare& get_prepare_cache() const { return cache.prepare_cache; } + void set_prepare_cache(const pbft_prepare& pcache) { cache.prepare_cache = pcache; } - void do_send_view_change(); - bool maybe_new_view(const psm_state_ptr& s); + const pbft_commit& get_commit_cache() const { return cache.commit_cache; } + void set_commit_cache(const pbft_commit& ccache) { cache.commit_cache = ccache; } - const pbft_prepare& get_prepares_cache() const; - void set_prepares_cache(const pbft_prepare &pcache); + const pbft_view_change& get_view_change_cache() const { return cache.view_change_cache; } + void set_view_change_cache(const pbft_view_change& vc_cache) { cache.view_change_cache = vc_cache; } - const pbft_commit& get_commits_cache() const; - void set_commits_cache(const pbft_commit &ccache); + uint32_t get_current_view() const { return current_view; } + void set_current_view(uint32_t cv) { current_view = cv; } - const pbft_view_change& get_view_changes_cache() const; - void set_view_changes_cache(const pbft_view_change &vc_cache); + const pbft_prepared_certificate& get_prepared_certificate() const { return cache.prepared_certificate; } + void set_prepared_certificate(const pbft_prepared_certificate& pcert) { cache.prepared_certificate = pcert; } - const uint32_t &get_current_view() const; - void set_current_view(const uint32_t &cv); + const vector& get_committed_certificate() const { return cache.committed_certificate; } + void set_committed_certificate(const vector& ccert) { cache.committed_certificate = ccert; } - const pbft_prepared_certificate& get_prepared_certificate() const; - void set_prepared_certificate(const pbft_prepared_certificate &pcert); + const pbft_view_changed_certificate& get_view_changed_certificate() const { return cache.view_changed_certificate; } + void set_view_changed_certificate(const pbft_view_changed_certificate& vc_cert) { cache.view_changed_certificate = vc_cert; } - const vector& get_committed_certificate() const; - void set_committed_certificate(const vector &ccert); + uint32_t get_target_view_retries() const { return target_view_retries; } + void set_target_view_retries(uint32_t tv_reties) { target_view_retries = tv_reties; } - const pbft_view_changed_certificate& get_view_changed_certificate() const; - void set_view_changed_certificate(const pbft_view_changed_certificate &vc_cert); + uint32_t get_target_view() const { return target_view; } + void set_target_view(uint32_t tv) { target_view = tv; } - const uint32_t& get_target_view_retries() const; - void set_target_view_retries(const uint32_t &tv_reties); + uint32_t get_view_change_timer() const { return view_change_timer; } + void set_view_change_timer(uint32_t vc_timer) { view_change_timer = vc_timer; } - const uint32_t& get_target_view() const; - void set_target_view(const uint32_t &tv); + void manually_set_current_view(uint32_t cv); - const uint32_t& get_view_change_timer() const; - void set_view_change_timer(const uint32_t &vc_timer); + signal pbft_outgoing_prepare; + signal pbft_outgoing_commit; + signal pbft_outgoing_view_change; + signal pbft_outgoing_new_view; + signal pbft_outgoing_checkpoint; + signal pbft_transit_to_committed; + signal pbft_transit_to_prepared; - void manually_set_current_view(const uint32_t &cv); + template + void emit(const Signal& s, Arg&& a); protected: psm_cache cache; - uint32_t current_view; - uint32_t target_view_retries; - uint32_t target_view; - uint32_t view_change_timer; + uint32_t current_view = 0; + uint32_t target_view_retries = 0; + uint32_t target_view = current_view + 1; + uint32_t view_change_timer = 0; private: - psm_state_ptr current; - pbft_database &pbft_db; + psm_state_ptr current = nullptr; + pbft_database& pbft_db; }; using psm_machine_ptr = std::shared_ptr; @@ -103,34 +115,40 @@ namespace eosio { class psm_state : public std::enable_shared_from_this { public: - psm_state(); + psm_state(psm_machine& m, pbft_database& pbft_db); ~psm_state(); - virtual void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) = 0; - virtual void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) = 0; - virtual void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) = 0; + virtual void on_prepare(const pbft_metadata_ptr& e) = 0; + virtual void on_commit(const pbft_metadata_ptr& e) = 0; + virtual void on_view_change(const pbft_metadata_ptr& e) = 0; - virtual void send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) = 0; - virtual void send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) = 0; - virtual void send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) = 0; + virtual void send_prepare() = 0; + virtual void send_commit() = 0; + virtual void send_view_change() = 0; virtual const char* get_name() = 0; std::shared_ptr get_self() { return shared_from_this(); }; + + protected: + psm_machine& m; + pbft_database& pbft_db; }; class psm_prepared_state final: public psm_state { public: - psm_prepared_state(); + psm_prepared_state(psm_machine& m, pbft_database& pbft_db); ~psm_prepared_state(); - void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; + void on_prepare(const pbft_metadata_ptr& e) override; + void on_commit(const pbft_metadata_ptr& e) override; + void on_view_change(const pbft_metadata_ptr& e) override; + + void send_prepare() override; + void send_commit() override; + void send_view_change() override; - void send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) override; + void maybe_transit_to_committed(); bool pending_commit_local; @@ -139,32 +157,32 @@ namespace eosio { class psm_committed_state final: public psm_state { public: - psm_committed_state(); + psm_committed_state(psm_machine& m, pbft_database& pbft_db); ~psm_committed_state(); - void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; + void on_prepare(const pbft_metadata_ptr& e) override; + void on_commit(const pbft_metadata_ptr& e) override; + void on_view_change(const pbft_metadata_ptr& e) override; - void send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) override; + void send_prepare() override; + void send_commit() override; + void send_view_change() override; const char* get_name() override { return "{==== COMMITTED ====}"; } }; class psm_view_change_state final: public psm_state { public: - psm_view_change_state(); + psm_view_change_state(psm_machine& m, pbft_database& pbft_db); ~psm_view_change_state(); - void on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; - void on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) override; + void on_prepare(const pbft_metadata_ptr& e) override; + void on_commit(const pbft_metadata_ptr& e) override; + void on_view_change(const pbft_metadata_ptr& e) override; - void send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) override; - void send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) override; + void send_prepare() override; + void send_commit() override; + void send_view_change() override; const char* get_name() override { return "{==== VIEW CHANGE ====}"; } }; @@ -174,10 +192,8 @@ namespace eosio { explicit pbft_controller(controller& ctrl); ~pbft_controller(); - const uint16_t view_change_timeout = 6; - - pbft_database pbft_db; - std::shared_ptr state_machine; + pbft_database pbft_db; + psm_machine state_machine; void maybe_pbft_prepare(); void maybe_pbft_commit(); @@ -192,6 +208,7 @@ namespace eosio { private: fc::path datadir; + uint16_t view_change_timeout = 6; }; } } /// namespace eosio::chain diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index b72f9645b66..6b4bb2cd7a9 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -19,7 +19,6 @@ namespace eosio { using pbft_view_type = uint32_t; - constexpr uint16_t pbft_checkpoint_granularity = 100; constexpr uint16_t oldest_stable_checkpoint = 10000; enum class pbft_message_type : uint8_t { @@ -37,11 +36,11 @@ namespace eosio { return fc::endian_reverse_u32(block_id._hash[0]); } - bool operator==(const block_info_type &rhs) const { + bool operator==(const block_info_type& rhs) const { return block_id == rhs.block_id; } - bool operator!=(const block_info_type &rhs) const { + bool operator!=(const block_info_type& rhs) const { return !(*this == rhs); } @@ -50,6 +49,8 @@ namespace eosio { } }; + using fork_info_type = vector; + struct pbft_message_common { explicit pbft_message_common(pbft_message_type t): type{t} {}; @@ -84,7 +85,7 @@ namespace eosio { block_info_type block_info; signature_type sender_signature; - bool operator<(const pbft_prepare &rhs) const { + bool operator<(const pbft_prepare& rhs) const { if (block_info.block_num() < rhs.block_info.block_num()) { return true; } else if (block_info.block_num() == rhs.block_info.block_num()) { @@ -120,7 +121,7 @@ namespace eosio { block_info_type block_info; signature_type sender_signature; - bool operator<(const pbft_commit &rhs) const { + bool operator<(const pbft_commit& rhs) const { if (block_info.block_num() < rhs.block_info.block_num()) { return true; } else if (block_info.block_num() == rhs.block_info.block_num()) { @@ -155,7 +156,7 @@ namespace eosio { block_info_type block_info; signature_type sender_signature; - bool operator<(const pbft_checkpoint &rhs) const { + bool operator<(const pbft_checkpoint& rhs) const { return block_info.block_num() < rhs.block_info.block_num(); } @@ -176,7 +177,7 @@ namespace eosio { block_info_type block_info; vector checkpoints; - bool operator<(const pbft_stable_checkpoint &rhs) const { + bool operator<(const pbft_stable_checkpoint& rhs) const { return block_info.block_num() < rhs.block_info.block_num(); } @@ -193,7 +194,7 @@ namespace eosio { set pre_prepares; vector prepares; - bool operator<(const pbft_prepared_certificate &rhs) const { + bool operator<(const pbft_prepared_certificate& rhs) const { return block_info.block_num() < rhs.block_info.block_num(); } @@ -209,7 +210,7 @@ namespace eosio { block_info_type block_info; vector commits; - bool operator<(const pbft_committed_certificate &rhs) const { + bool operator<(const pbft_committed_certificate& rhs) const { return block_info.block_num() < rhs.block_info.block_num(); } @@ -230,7 +231,7 @@ namespace eosio { pbft_stable_checkpoint stable_checkpoint; signature_type sender_signature; - bool operator<(const pbft_view_change &rhs) const { + bool operator<(const pbft_view_change& rhs) const { return target_view < rhs.target_view; } @@ -266,7 +267,7 @@ namespace eosio { bool empty() const { return !target_view - && view_changes.empty(); + && view_changes.empty(); } }; @@ -281,7 +282,7 @@ namespace eosio { pbft_view_changed_certificate view_changed_cert; signature_type sender_signature; - bool operator<(const pbft_new_view &rhs) const { + bool operator<(const pbft_new_view& rhs) const { return new_view < rhs.new_view; } @@ -298,7 +299,7 @@ namespace eosio { } bool empty() const { - return new_view == 0 + return !new_view && prepared_cert.empty() && committed_certs.empty() && stable_checkpoint.empty() @@ -415,30 +416,25 @@ namespace eosio { class pbft_database { public: - explicit pbft_database(controller &ctrl); - + explicit pbft_database(controller& ctrl); ~pbft_database(); - void close(); - - void add_pbft_prepare(pbft_prepare &p, const public_key_type &pk); - void add_pbft_commit(pbft_commit &c, const public_key_type &pk); - void add_pbft_view_change(pbft_view_change &vc, const public_key_type &pk); - void add_pbft_checkpoint(pbft_checkpoint &cp, const public_key_type &pk); - - pbft_prepare send_and_add_pbft_prepare(const pbft_prepare &cached_prepare = pbft_prepare(), pbft_view_type current_view = 0); - pbft_commit send_and_add_pbft_commit(const pbft_commit &cached_commit = pbft_commit(), pbft_view_type current_view = 0); - pbft_view_change send_and_add_pbft_view_change( - const pbft_view_change &cached_view_change = pbft_view_change(), - const pbft_prepared_certificate &ppc = pbft_prepared_certificate(), - const vector &pcc = vector{}, - pbft_view_type current_view = 0, + void add_pbft_prepare(const pbft_prepare& p, const public_key_type& pk); + void add_pbft_commit(const pbft_commit& c, const public_key_type& pk); + void add_pbft_view_change(const pbft_view_change& vc, const public_key_type& pk); + void add_pbft_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk); + + vector generate_and_add_pbft_prepare(const pbft_prepare& cached_prepare = pbft_prepare()); + vector generate_and_add_pbft_commit(const pbft_commit& cached_commit = pbft_commit()); + vector generate_and_add_pbft_view_change( + const pbft_view_change& cached_view_change = pbft_view_change(), + const pbft_prepared_certificate& ppc = pbft_prepared_certificate(), + const vector& pcc = vector{}, pbft_view_type target_view = 1); - pbft_new_view send_pbft_new_view( - const pbft_view_changed_certificate &vcc = pbft_view_changed_certificate(), - pbft_view_type current_view = 1); + pbft_new_view generate_pbft_new_view( + const pbft_view_changed_certificate& vcc = pbft_view_changed_certificate(), + pbft_view_type new_view = 1); vector generate_and_add_pbft_checkpoint(); - void send_pbft_checkpoint(); bool should_prepared(); bool should_committed(); @@ -446,13 +442,13 @@ namespace eosio { bool should_new_view(pbft_view_type target_view); //new view - bool has_new_primary(const public_key_type &pk); + bool has_new_primary(const public_key_type& pk); pbft_view_type get_proposed_new_view_num(); pbft_view_type get_committed_view(); public_key_type get_new_view_primary_key(pbft_view_type target_view); - void mark_as_prepared(const block_id_type &bid); - void mark_as_committed(const block_id_type &bid); + void mark_as_prepared(const block_id_type& bid); + void mark_as_committed(const block_id_type& bid); void commit_local(); void checkpoint_local(); @@ -460,43 +456,39 @@ namespace eosio { pbft_prepared_certificate generate_prepared_certificate(); vector generate_committed_certificate(); pbft_view_changed_certificate generate_view_changed_certificate(pbft_view_type target_view); - bool should_stop_view_change(const pbft_view_change &vc); + bool should_stop_view_change(const pbft_view_change& vc); //validations - bool is_valid_prepare(const pbft_prepare &p, const public_key_type &pk); - bool is_valid_commit(const pbft_commit &c, const public_key_type &pk); - bool is_valid_checkpoint(const pbft_checkpoint &cp, const public_key_type &pk); - bool is_valid_view_change(const pbft_view_change &vc, const public_key_type &pk); - void validate_new_view(const pbft_new_view &nv, const public_key_type &pk); - bool is_valid_stable_checkpoint(const pbft_stable_checkpoint &scp, bool add_to_pbft_db = false); + bool is_valid_prepare(const pbft_prepare& p, const public_key_type& pk); + bool is_valid_commit(const pbft_commit& c, const public_key_type& pk); + bool is_valid_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk); + bool is_valid_view_change(const pbft_view_change& vc, const public_key_type& pk); + void validate_new_view(const pbft_new_view& nv, const public_key_type& pk); + bool is_valid_stable_checkpoint(const pbft_stable_checkpoint& scp, bool add_to_pbft_db = false); bool should_send_pbft_msg(); - bool should_recv_pbft_msg(const public_key_type &pub_key); + bool should_recv_pbft_msg(const public_key_type& pub_key); bool pending_pbft_lib(); - chain_id_type& get_chain_id() {return chain_id;} - pbft_stable_checkpoint get_stable_checkpoint_by_id(const block_id_type &block_id, bool incl_blk_extn = true); - pbft_stable_checkpoint fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr &b); - block_info_type cal_pending_stable_checkpoint() const; + chain_id_type& get_chain_id() { return chain_id; } + pbft_stable_checkpoint get_stable_checkpoint_by_id(const block_id_type& block_id, bool incl_blk_extn = true); + pbft_stable_checkpoint fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr& b); void cleanup_on_new_view(); void update_fork_schedules(); + uint16_t get_view_change_timeout() const; + uint16_t get_checkpoint_interval() const; + const pbft_view_type get_current_view() { return _current_view; } + void set_current_view(pbft_view_type view) { _current_view = view; } //api related - pbft_state_ptr get_pbft_state_by_id(const block_id_type &id) const; - vector get_checkpoints_by_num(const block_num_type &num) const; - pbft_view_change_state_ptr get_view_changes_by_target_view(const pbft_view_type &tv) const; + pbft_state_ptr get_pbft_state_by_id(const block_id_type& id) const; + vector get_checkpoints_by_num(block_num_type num) const; + pbft_view_change_state_ptr get_view_changes_by_target_view(pbft_view_type tv) const; vector get_pbft_watermarks() const; flat_map get_pbft_fork_schedules() const; - - signal pbft_outgoing_prepare; - signal pbft_outgoing_commit; - signal pbft_outgoing_view_change; - signal pbft_outgoing_new_view; - signal pbft_outgoing_checkpoint; - private: - controller &ctrl; + controller& ctrl; pbft_state_multi_index_type pbft_state_index; pbft_view_state_multi_index_type view_state_index; pbft_checkpoint_state_multi_index_type checkpoint_index; @@ -505,28 +497,26 @@ namespace eosio { vector prepare_watermarks; flat_map fork_schedules; chain_id_type chain_id = ctrl.get_chain_id(); + pbft_view_type _current_view = 0; - - bool is_less_than_high_watermark(const block_num_type &bnum); - bool is_valid_prepared_certificate(const pbft_prepared_certificate &certificate, bool add_to_pbft_db = false); - bool is_valid_committed_certificate(const pbft_committed_certificate &certificate, bool add_to_pbft_db = false); - bool is_valid_longest_fork(const block_info_type &bi, vector block_infos, unsigned long threshold, unsigned long non_fork_bp_count); + block_info_type cal_pending_stable_checkpoint() const; + bool is_less_than_high_watermark(block_num_type bnum); + bool is_valid_prepared_certificate(const pbft_prepared_certificate& certificate, bool add_to_pbft_db = false); + bool is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db = false); + bool is_valid_longest_fork(const block_info_type& bi, fork_info_type& block_infos, unsigned long threshold, unsigned long non_fork_bp_count); producer_schedule_type lscb_active_producers() const; vector& get_updated_watermarks(); flat_map& get_updated_fork_schedules(); block_num_type get_current_pbft_watermark(); - vector> fetch_fork_from(vector &block_infos); - vector fetch_first_fork_from(vector &bi); - - template - void emit(const Signal &s, Arg &&a); + vector fetch_fork_from(fork_info_type& block_infos); + fork_info_type fetch_first_fork_from(fork_info_type& bi); void set(const pbft_state_ptr& s); void set(const pbft_checkpoint_state_ptr& s); - void prune(const pbft_state_ptr &h); - void prune(const pbft_checkpoint_state_ptr &h); + void prune(const pbft_state_ptr& h); + void prune(const pbft_checkpoint_state_ptr& h); }; } } /// namespace eosio::chain diff --git a/libraries/chain/include/eosio/chain/types.hpp b/libraries/chain/include/eosio/chain/types.hpp index f8360c0bc7d..4cf8b055cd2 100644 --- a/libraries/chain/include/eosio/chain/types.hpp +++ b/libraries/chain/include/eosio/chain/types.hpp @@ -190,6 +190,7 @@ namespace eosio { namespace chain { action_history_object_type, ///< Defined by history_plugin reversible_block_object_type, upgrade_property_object_type, + global_property3_object_type, OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types }; diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index ccc5598dc63..8ac97cb1c49 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -1,5 +1,3 @@ -#include - #include #include #include @@ -7,134 +5,104 @@ namespace eosio { namespace chain { - pbft_controller::pbft_controller(controller &ctrl) : - pbft_db(ctrl), - state_machine(new psm_machine(pbft_db)) { - datadir = ctrl.state_dir(); - - if (!fc::is_directory(datadir)) - fc::create_directories(datadir); - - auto pbft_db_dat = datadir / config::pbftdb_filename; - if (fc::exists(pbft_db_dat)) { - string content; - fc::read_file_contents(pbft_db_dat, content); - - fc::datastream ds(content.data(), content.size()); - uint32_t current_view; - fc::raw::unpack(ds, current_view); - state_machine->set_current_view(current_view); - state_machine->set_target_view(state_machine->get_current_view() + 1); - ilog("current view: ${cv}", ("cv", current_view)); - } - - fc::remove(pbft_db_dat); + pbft_controller::pbft_controller(controller& ctrl) : + pbft_db(ctrl), + state_machine(pbft_db) { + state_machine.set_current(std::make_shared(state_machine, pbft_db)); + state_machine.set_current_view(pbft_db.get_current_view()); + state_machine.set_target_view(state_machine.get_current_view() + 1); + ilog("current view: ${cv}", ("cv", pbft_db.get_current_view())); } - pbft_controller::~pbft_controller() { - fc::path pbft_db_dat = datadir / config::pbftdb_filename; - std::ofstream out(pbft_db_dat.generic_string().c_str(), - std::ios::out | std::ios::binary | std::ofstream::trunc); - - uint32_t current_view = state_machine->get_current_view(); - fc::raw::pack(out, current_view); - } + pbft_controller::~pbft_controller() = default; void pbft_controller::maybe_pbft_prepare() { if (!pbft_db.should_send_pbft_msg()) return; - state_machine->send_prepare(); + state_machine.send_prepare(); } void pbft_controller::maybe_pbft_commit() { if (!pbft_db.should_send_pbft_msg()) return; - state_machine->send_commit(); + state_machine.send_commit(); } void pbft_controller::maybe_pbft_view_change() { if (!pbft_db.should_send_pbft_msg()) return; - if (state_machine->get_view_change_timer() <= view_change_timeout) { - if (!state_machine->get_view_changes_cache().empty()) { - pbft_db.send_and_add_pbft_view_change(state_machine->get_view_changes_cache()); + + if (view_change_timeout != pbft_db.get_view_change_timeout()) { + ///if there is a change in global states, update timeout and reset timer. + view_change_timeout = pbft_db.get_view_change_timeout(); + state_machine.set_view_change_timer(0); + } + + if (state_machine.get_view_change_timer() <= view_change_timeout) { + if (!state_machine.get_view_change_cache().empty()) { + pbft_db.generate_and_add_pbft_view_change(state_machine.get_view_change_cache()); } - state_machine->set_view_change_timer(state_machine->get_view_change_timer() + 1); + state_machine.set_view_change_timer(state_machine.get_view_change_timer() + 1); } else { - state_machine->set_view_change_timer(0); - state_machine->send_view_change(); + state_machine.set_view_change_timer(0); + state_machine.send_view_change(); } } void pbft_controller::maybe_pbft_checkpoint() { if (!pbft_db.should_send_pbft_msg()) return; - pbft_db.send_pbft_checkpoint(); + state_machine.send_checkpoint(); pbft_db.checkpoint_local(); } void pbft_controller::on_pbft_prepare(const pbft_metadata_ptr& p) { - state_machine->on_prepare(p); + state_machine.on_prepare(p); } void pbft_controller::on_pbft_commit(const pbft_metadata_ptr& c) { - state_machine->on_commit(c); + state_machine.on_commit(c); } void pbft_controller::on_pbft_view_change(const pbft_metadata_ptr& vc) { - state_machine->on_view_change(vc); + state_machine.on_view_change(vc); } void pbft_controller::on_pbft_new_view(const pbft_metadata_ptr& nv) { - state_machine->on_new_view(nv); + state_machine.on_new_view(nv); } - void pbft_controller::on_pbft_checkpoint(const pbft_metadata_ptr &cp) { + void pbft_controller::on_pbft_checkpoint(const pbft_metadata_ptr& cp) { if (!pbft_db.is_valid_checkpoint(cp->msg, cp->sender_key)) return; pbft_db.add_pbft_checkpoint(cp->msg, cp->sender_key); pbft_db.checkpoint_local(); } - psm_state::psm_state() = default; + psm_state::psm_state(psm_machine& m, pbft_database& pbft_db) : m(m), pbft_db(pbft_db){} psm_state::~psm_state() = default; - psm_machine::psm_machine(pbft_database &pbft_db) : pbft_db(pbft_db) { - set_current(std::make_shared()); - - set_prepares_cache(pbft_prepare()); - set_commits_cache(pbft_commit()); - set_view_changes_cache(pbft_view_change()); - - set_prepared_certificate(pbft_prepared_certificate{}); - set_committed_certificate(vector{}); - set_view_changed_certificate(pbft_view_changed_certificate{}); - - view_change_timer = 0; - target_view_retries = 0; - current_view = 0; - target_view = current_view + 1; - } + psm_machine::psm_machine(pbft_database& pbft_db) : pbft_db(pbft_db) {} psm_machine::~psm_machine() = default; void psm_machine::on_prepare(const pbft_metadata_ptr& e) { - current->on_prepare(shared_from_this(), e, pbft_db); + current->on_prepare(e); } void psm_machine::send_prepare() { - current->send_prepare(shared_from_this(), pbft_db); + current->send_prepare(); } void psm_machine::on_commit(const pbft_metadata_ptr& e) { - current->on_commit(shared_from_this(), e, pbft_db); + current->on_commit(e); } void psm_machine::send_commit() { - current->send_commit(shared_from_this(), pbft_db); + current->send_commit(); } void psm_machine::on_view_change(const pbft_metadata_ptr& e) { - current->on_view_change(shared_from_this(), e, pbft_db); + current->on_view_change(e); } void psm_machine::send_view_change() { - current->send_view_change(shared_from_this(), pbft_db); + current->send_view_change(); } void psm_machine::on_new_view(const pbft_metadata_ptr& e) { @@ -148,42 +116,28 @@ namespace eosio { } try { - transit_to_new_view(e, current); + transit_to_new_view(e); } catch(...) { elog("apply new view failed, waiting for next round.. ${nv} ", ("nv", e->msg)); } } - void psm_machine::manually_set_current_view(const uint32_t &cv) { + void psm_machine::manually_set_current_view(uint32_t cv) { set_current_view(cv); + pbft_db.set_current_view(cv); set_target_view(cv + 1); - transit_to_view_change_state(current); + transit_to_view_change_state(); } - /** + /**\ + * * psm_prepared_state */ - psm_prepared_state::psm_prepared_state() {pending_commit_local = false;} + psm_prepared_state::psm_prepared_state(psm_machine& m, pbft_database& pbft_db) : psm_state(m, pbft_db) {pending_commit_local = false;} psm_prepared_state::~psm_prepared_state() = default; - void psm_prepared_state::on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { - //ignore - } - - void psm_prepared_state::send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) { - //retry - if (m->get_prepares_cache().empty()) return; - - pbft_db.send_and_add_pbft_prepare(m->get_prepares_cache(), m->get_current_view()); - } - - void psm_prepared_state::on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { - - if (e->msg.view < m->get_current_view()) return; - if (!pbft_db.is_valid_commit(e->msg, e->sender_key)) return; - - pbft_db.add_pbft_commit(e->msg, e->sender_key); + void psm_prepared_state::maybe_transit_to_committed() { //`pending_commit_local` is used to mark committed local status in psm machine; //`pbft_db.pending_pbft_lib()` is used to mark commit local status in controller; @@ -195,214 +149,209 @@ namespace eosio { } if (pending_commit_local && !pbft_db.pending_pbft_lib()) { - pbft_db.send_pbft_checkpoint(); - pbft_db.checkpoint_local(); - m->transit_to_committed_state(shared_from_this(), false); + m.transit_to_committed_state(false); } } - void psm_prepared_state::send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) { - auto commits = pbft_db.send_and_add_pbft_commit(m->get_commits_cache(), m->get_current_view()); + void psm_prepared_state::on_prepare(const pbft_metadata_ptr& e) { + //ignore + } - if (!commits.empty()) { - m->set_commits_cache(commits); - } + void psm_prepared_state::send_prepare() { + //retry + if (m.get_prepare_cache().empty()) return; + m.do_send_prepare(); + } - if (pbft_db.should_committed() && !pending_commit_local) { - pbft_db.commit_local(); - pending_commit_local = true; - } + void psm_prepared_state::on_commit(const pbft_metadata_ptr& e) { - if (pending_commit_local && !pbft_db.pending_pbft_lib()) { - pbft_db.send_pbft_checkpoint(); - pbft_db.checkpoint_local(); - m->transit_to_committed_state(shared_from_this(), false); - } + if (e->msg.view < m.get_current_view()) return; + if (!pbft_db.is_valid_commit(e->msg, e->sender_key)) return; + + pbft_db.add_pbft_commit(e->msg, e->sender_key); + maybe_transit_to_committed(); + } + + void psm_prepared_state::send_commit() { + + m.do_send_commit(); + maybe_transit_to_committed(); } - void psm_prepared_state::on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_prepared_state::on_view_change(const pbft_metadata_ptr& e) { - if (e->msg.target_view <= m->get_current_view()) return; + if (e->msg.target_view <= m.get_current_view()) return; if (!pbft_db.is_valid_view_change(e->msg, e->sender_key)) return; pbft_db.add_pbft_view_change(e->msg, e->sender_key); - - //if received >= f+1 view_change on some view, transit to view_change and send view change - auto target_view = pbft_db.should_view_change(); - if (target_view > 0 && target_view > m->get_current_view()) { - m->set_target_view(target_view); - m->transit_to_view_change_state(shared_from_this()); - } + m.maybe_view_change(); } - void psm_prepared_state::send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) { - m->transit_to_view_change_state(shared_from_this()); + void psm_prepared_state::send_view_change() { + m.transit_to_view_change_state(); } - psm_committed_state::psm_committed_state() = default; + psm_committed_state::psm_committed_state(psm_machine& m, pbft_database& pbft_db) : psm_state(m, pbft_db) {} psm_committed_state::~psm_committed_state() = default; /** * psm_committed_state */ - void psm_committed_state::on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_committed_state::on_prepare(const pbft_metadata_ptr& e) { //validate - if (e->msg.view < m->get_current_view()) return; + if (e->msg.view < m.get_current_view()) return; if (!pbft_db.is_valid_prepare(e->msg, e->sender_key)) return; //do action add prepare pbft_db.add_pbft_prepare(e->msg, e->sender_key); - - //if prepare >= 2f+1, transit to prepared - if (pbft_db.should_prepared()) m->transit_to_prepared_state(shared_from_this()); + //if prepare >= n-f, transit to prepared + if (pbft_db.should_prepared()) m.transit_to_prepared_state(); } - void psm_committed_state::send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) { - - auto prepares = pbft_db.send_and_add_pbft_prepare(m->get_prepares_cache(), m->get_current_view()); - - if (!prepares.empty()) { - m->set_prepares_cache(prepares); - } + void psm_committed_state::send_prepare() { - //if prepare >= 2f+1, transit to prepared - if (pbft_db.should_prepared()) m->transit_to_prepared_state(shared_from_this()); + m.do_send_prepare(); + //if prepare >= n-f, transit to prepared + if (pbft_db.should_prepared()) m.transit_to_prepared_state(); } - void psm_committed_state::on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_committed_state::on_commit(const pbft_metadata_ptr& e) { - if (e->msg.view < m->get_current_view()) return; + if (e->msg.view < m.get_current_view()) return; if (!pbft_db.is_valid_commit(e->msg, e->sender_key)) return; pbft_db.add_pbft_commit(e->msg, e->sender_key); } - void psm_committed_state::send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) { - - if (m->get_commits_cache().empty()) return; - pbft_db.send_and_add_pbft_commit(m->get_commits_cache(), m->get_current_view()); + void psm_committed_state::send_commit() { + if (m.get_commit_cache().empty()) return; + m.do_send_commit(); } - void psm_committed_state::on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_committed_state::on_view_change(const pbft_metadata_ptr& e) { - if (e->msg.target_view <= m->get_current_view()) return; + if (e->msg.target_view <= m.get_current_view()) return; if (!pbft_db.is_valid_view_change(e->msg, e->sender_key)) return; pbft_db.add_pbft_view_change(e->msg, e->sender_key); - - //if received >= f+1 view_change on some view, transit to view_change and send view change - auto new_view = pbft_db.should_view_change(); - if (new_view > 0 && new_view > m->get_current_view()) { - m->set_target_view(new_view); - m->transit_to_view_change_state(shared_from_this()); - } + m.maybe_view_change(); } - void psm_committed_state::send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) { - m->transit_to_view_change_state(shared_from_this()); + void psm_committed_state::send_view_change() { + m.transit_to_view_change_state(); } - psm_view_change_state::psm_view_change_state() = default; + psm_view_change_state::psm_view_change_state(psm_machine& m, pbft_database& pbft_db) : psm_state(m, pbft_db) {} psm_view_change_state::~psm_view_change_state() = default; /** * psm_view_change_state */ - void psm_view_change_state::on_prepare(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_view_change_state::on_prepare(const pbft_metadata_ptr& e) { //ignore; } - void psm_view_change_state::send_prepare(const psm_machine_ptr& m, pbft_database &pbft_db) { + void psm_view_change_state::send_prepare() { //ignore; } - void psm_view_change_state::on_commit(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_view_change_state::on_commit(const pbft_metadata_ptr& e) { //ignore; } - void psm_view_change_state::send_commit(const psm_machine_ptr& m, pbft_database &pbft_db) { + void psm_view_change_state::send_commit() { //ignore; } - void psm_view_change_state::on_view_change(const psm_machine_ptr& m, const pbft_metadata_ptr& e, pbft_database &pbft_db) { + void psm_view_change_state::on_view_change(const pbft_metadata_ptr& e) { - //skip from view change state if my lib is higher than my view change state height. - auto vc = m->get_view_changes_cache(); - if (!vc.empty() && pbft_db.should_stop_view_change(vc)) { - m->transit_to_committed_state(shared_from_this(), false); - return; - } + if (m.maybe_stop_view_change()) return; - if (e->msg.target_view <= m->get_current_view()) return; + if (e->msg.target_view <= m.get_current_view()) return; if (!pbft_db.is_valid_view_change(e->msg, e->sender_key)) return; pbft_db.add_pbft_view_change(e->msg, e->sender_key); - - m->maybe_new_view(shared_from_this()); + m.maybe_new_view(); } - void psm_view_change_state::send_view_change(const psm_machine_ptr& m, pbft_database &pbft_db) { - - //skip from view change state if my lib is higher than my view change state height. - auto vc = m->get_view_changes_cache(); - if (!vc.empty() && pbft_db.should_stop_view_change(vc)) { - m->transit_to_committed_state(shared_from_this(), false); - return; - } + void psm_view_change_state::send_view_change() { - m->do_send_view_change(); + if (m.maybe_stop_view_change()) return; - m->maybe_new_view(shared_from_this()); + m.do_send_view_change(); + m.maybe_new_view(); } - void psm_machine::transit_to_committed_state(const psm_state_ptr& s, bool to_new_view) { + void psm_machine::transit_to_committed_state(bool to_new_view) { if (!to_new_view) { auto nv = pbft_db.get_committed_view(); - if (nv > get_current_view()) set_current_view(nv); + if (nv > get_current_view()) { + set_current_view(nv); + pbft_db.set_current_view(nv); + } set_target_view(get_current_view() + 1); } - auto prepares = pbft_db.send_and_add_pbft_prepare(pbft_prepare(), get_current_view()); - set_prepares_cache(prepares); - //TODO: reset prepare timer; + set_prepare_cache(pbft_prepare()); + do_send_prepare(); - set_view_changes_cache(pbft_view_change()); + set_view_change_cache(pbft_view_change()); set_view_change_timer(0); - set_current(std::make_shared()); + set_current(std::make_shared(*this, pbft_db)); + emit(pbft_transit_to_committed, true); } - void psm_machine::transit_to_prepared_state(const psm_state_ptr& s) { + void psm_machine::transit_to_prepared_state() { - auto commits = pbft_db.send_and_add_pbft_commit(pbft_commit(), get_current_view()); - set_commits_cache(commits); - //TODO: reset commit timer; + set_commit_cache(pbft_commit()); + do_send_commit(); - set_view_changes_cache(pbft_view_change()); + set_view_change_cache(pbft_view_change()); - set_current(std::make_shared()); + set_current(std::make_shared(*this, pbft_db)); + emit(pbft_transit_to_prepared, true); } - void psm_machine::transit_to_view_change_state(const psm_state_ptr& s) { + void psm_machine::transit_to_view_change_state() { - set_commits_cache(pbft_commit()); - set_prepares_cache(pbft_prepare()); + set_commit_cache(pbft_commit()); + set_prepare_cache(pbft_prepare()); set_view_change_timer(0); set_target_view_retries(0); - set_current(std::make_shared()); + set_current(std::make_shared(*this, pbft_db)); if (pbft_db.should_send_pbft_msg()) { do_send_view_change(); - auto nv = maybe_new_view(s); + auto nv = maybe_new_view(); if (nv) return; } } - bool psm_machine::maybe_new_view(const psm_state_ptr &s) { - //if view_change >= 2f+1, calculate next primary, send new view if is primary + void psm_machine::maybe_view_change() { + //if received >= f+1 view_change on some view, transit to view_change and send view change + auto new_view = pbft_db.should_view_change(); + if (new_view > 0 && new_view > get_current_view()) { + set_target_view(new_view); + transit_to_view_change_state(); + } + } + + bool psm_machine::maybe_stop_view_change() { + //skip from view change state if my lib is higher than my view change state height. + auto vc = get_view_change_cache(); + if (!vc.empty() && pbft_db.should_stop_view_change(vc)) { + transit_to_committed_state(false); + return true; + } + return false; + } + + bool psm_machine::maybe_new_view() { + //if view_change >= n-f, calculate next primary, send new view if is primary auto nv = get_target_view(); auto pk = pbft_db.get_new_view_primary_key(nv); if (pbft_db.should_new_view(nv) && pbft_db.has_new_primary(pk)) { @@ -412,14 +361,15 @@ namespace eosio { auto new_view = pbft_db.get_proposed_new_view_num(); if (new_view != nv) return false; - auto nv_msg = pbft_db.send_pbft_new_view( + auto nv_msg = pbft_db.generate_pbft_new_view( get_view_changed_certificate(), new_view); if (nv_msg.empty()) return false; + emit(pbft_outgoing_new_view, std::make_shared(nv_msg)); try { - transit_to_new_view(std::make_shared>(nv_msg, pbft_db.get_chain_id()), s); + transit_to_new_view(std::make_shared>(nv_msg, pbft_db.get_chain_id())); return true; } catch(const fc::exception& ex) { elog("apply new view failed, waiting for next round.. ${nv} ", ("nv", nv_msg)); @@ -428,12 +378,13 @@ namespace eosio { return false; } - void psm_machine::transit_to_new_view(const pbft_metadata_ptr& e, const psm_state_ptr& s) { + void psm_machine::transit_to_new_view(const pbft_metadata_ptr& e) { set_current_view(e->msg.new_view); + pbft_db.set_current_view(e->msg.new_view); set_target_view(e->msg.new_view + 1); - set_prepares_cache(pbft_prepare()); + set_prepare_cache(pbft_prepare()); set_view_change_timer(0); set_target_view_retries(0); @@ -443,7 +394,7 @@ namespace eosio { if (!e->msg.committed_certs.empty()) { auto committed_certs = e->msg.committed_certs; std::sort(committed_certs.begin(), committed_certs.end()); - for (auto const &cc :committed_certs) { + for (const auto& cc :committed_certs) { pbft_db.mark_as_committed(cc.block_info.block_id); } } @@ -451,7 +402,7 @@ namespace eosio { if (!e->msg.prepared_cert.prepares.empty()) { pbft_db.mark_as_prepared(e->msg.prepared_cert.block_info.block_id); if (pbft_db.should_prepared()) { - transit_to_prepared_state(s); + transit_to_prepared_state(); return; } } @@ -459,13 +410,34 @@ namespace eosio { if (pbft_db.should_committed()) { pbft_db.commit_local(); } - transit_to_committed_state(s, true); + transit_to_committed_state(true); + } + + void psm_machine::do_send_prepare() { + auto prepares = pbft_db.generate_and_add_pbft_prepare(get_prepare_cache()); + if (!prepares.empty()) { + for (const auto& p: prepares) { + emit(pbft_outgoing_prepare, std::make_shared(p)); + } + set_prepare_cache(prepares.front()); + } + } + + void psm_machine::do_send_commit() { + auto commits = pbft_db.generate_and_add_pbft_commit(get_commit_cache()); + + if (!commits.empty()) { + for (const auto& c: commits) { + emit(pbft_outgoing_commit, std::make_shared(c)); + } + set_commit_cache(commits.front()); + } } void psm_machine::do_send_view_change() { auto reset_view_change_state = [&]() { - set_view_changes_cache(pbft_view_change()); + set_view_change_cache(pbft_view_change()); set_prepared_certificate(pbft_db.generate_prepared_certificate()); set_committed_certificate(pbft_db.generate_committed_certificate()); }; @@ -482,96 +454,42 @@ namespace eosio { EOS_ASSERT((get_target_view() > get_current_view()), pbft_exception, "target view should be always greater than current view"); - auto view_changes = pbft_db.send_and_add_pbft_view_change( - get_view_changes_cache(), + auto view_changes = pbft_db.generate_and_add_pbft_view_change( + get_view_change_cache(), get_prepared_certificate(), get_committed_certificate(), - get_current_view(), get_target_view()); if (!view_changes.empty()) { - set_view_changes_cache(view_changes); + for (const auto& vc : view_changes) { + emit(pbft_outgoing_view_change, std::make_shared(vc)); + } + set_view_change_cache(view_changes.front()); } } - const pbft_prepare& psm_machine::get_prepares_cache() const { - return cache.prepares_cache; - } - - void psm_machine::set_prepares_cache(const pbft_prepare &pcache) { - cache.prepares_cache = pcache; - } - - const pbft_commit& psm_machine::get_commits_cache() const { - return cache.commits_cache; - } - - void psm_machine::set_commits_cache(const pbft_commit &ccache) { - cache.commits_cache = ccache; - } - - const pbft_view_change& psm_machine::get_view_changes_cache() const { - return cache.view_changes_cache; - } - - void psm_machine::set_view_changes_cache(const pbft_view_change &vc_cache) { - cache.view_changes_cache = vc_cache; - } - - const uint32_t& psm_machine::get_current_view() const { - return current_view; - } - - void psm_machine::set_current_view(const uint32_t &cv) { - current_view = cv; - } - - const pbft_prepared_certificate& psm_machine::get_prepared_certificate() const { - return cache.prepared_certificate; - } - - void psm_machine::set_prepared_certificate(const pbft_prepared_certificate &pcert) { - cache.prepared_certificate = pcert; - } - - const vector& psm_machine::get_committed_certificate() const { - return cache.committed_certificate; - } - - void psm_machine::set_committed_certificate(const vector &ccert) { - cache.committed_certificate = ccert; - } - - const pbft_view_changed_certificate& psm_machine::get_view_changed_certificate() const { - return cache.view_changed_certificate; - } - - void psm_machine::set_view_changed_certificate(const pbft_view_changed_certificate &vc_cert) { - cache.view_changed_certificate = vc_cert; - } - - const uint32_t& psm_machine::get_target_view_retries() const { - return target_view_retries; - } - - void psm_machine::set_target_view_retries(const uint32_t &tv_reties) { - target_view_retries = tv_reties; - } - - const uint32_t& psm_machine::get_target_view() const { - return target_view; - } - - void psm_machine::set_target_view(const uint32_t &tv) { - target_view = tv; - } - - const uint32_t& psm_machine::get_view_change_timer() const { - return view_change_timer; + void psm_machine::send_checkpoint() { + auto checkpoints = pbft_db.generate_and_add_pbft_checkpoint(); + for (const auto& cp: checkpoints) { + emit(pbft_outgoing_checkpoint, std::make_shared(cp)); + } } - void psm_machine::set_view_change_timer(const uint32_t &vc_timer) { - view_change_timer = vc_timer; + template + void psm_machine::emit(const Signal& s, Arg&& a) { + try { + s(std::forward(a)); + } catch (boost::interprocess::bad_alloc &e) { + wlog("bad alloc"); + throw e; + } catch (controller_emit_signal_exception &e) { + wlog("${details}", ("details", e.to_detail_string())); + throw e; + } catch (fc::exception &e) { + wlog("${details}", ("details", e.to_detail_string())); + } catch (...) { + wlog("signal handler threw exception"); + } } } } \ No newline at end of file diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 3e2a71fd86f..5bf4a743bd1 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -6,8 +6,7 @@ namespace eosio { namespace chain { - pbft_database::pbft_database(controller &ctrl) : - ctrl(ctrl) { + pbft_database::pbft_database(controller& ctrl) :ctrl(ctrl) { checkpoint_index = pbft_checkpoint_state_multi_index_type(); view_state_index = pbft_view_state_multi_index_type(); prepare_watermarks = vector{}; @@ -24,8 +23,8 @@ namespace eosio { fc::datastream ds(content.data(), content.size()); - //skip current_view in pbftdb.dat. - ds.seekp(ds.tellp() + 4); + //set current_view in pbftdb.dat. + fc::raw::unpack(ds, _current_view); unsigned_int size; fc::raw::unpack(ds, size); @@ -62,7 +61,7 @@ namespace eosio { fc::remove(checkpoints_db); } - void pbft_database::close() { + pbft_database::~pbft_database() { fc::path checkpoints_db = checkpoints_dir / config::checkpoints_filename; std::ofstream c_out(checkpoints_db.generic_string().c_str(), @@ -71,17 +70,19 @@ namespace eosio { uint32_t num_records_in_checkpoint_db = checkpoint_index.size(); fc::raw::pack(c_out, unsigned_int{num_records_in_checkpoint_db}); - for (auto const &s: checkpoint_index) { + for (const auto& s: checkpoint_index) { fc::raw::pack(c_out, *s); } fc::path pbft_db_dat = pbft_db_dir / config::pbftdb_filename; std::ofstream out(pbft_db_dat.generic_string().c_str(), - std::ios::out | std::ios::binary | std::ofstream::app); + std::ios::out | std::ios::binary | std::ofstream::trunc); + fc::raw::pack(out, _current_view); + uint32_t num_records_in_db = pbft_state_index.size(); fc::raw::pack(out, unsigned_int{num_records_in_db}); - for (auto const &s : pbft_state_index) { + for (const auto& s : pbft_state_index) { fc::raw::pack(out, *s); } @@ -89,13 +90,9 @@ namespace eosio { checkpoint_index.clear(); } - pbft_database::~pbft_database() { - close(); - } - - void pbft_database::add_pbft_prepare(pbft_prepare &p, const public_key_type &pk) { + void pbft_database::add_pbft_prepare(const pbft_prepare& p, const public_key_type& pk) { - auto &by_block_id_index = pbft_state_index.get(); + auto& by_block_id_index = pbft_state_index.get(); auto current = ctrl.fetch_block_state_by_id(p.block_info.block_id); @@ -118,9 +115,11 @@ namespace eosio { } else { auto prepares = (*curr_itr)->prepares; if (prepares.find(std::make_pair(p.view, pk)) == prepares.end()) { - by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr &psp) { + by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr& psp) { psp->prepares[std::make_pair(p.view, pk)] = p; }); + } else { + return; } } curr_itr = by_block_id_index.find(current->id); @@ -132,16 +131,16 @@ namespace eosio { auto threshold = as.size()* 2 / 3 + 1; if (prepares.size() >= threshold && !cpsp->is_prepared && is_less_than_high_watermark(cpsp->block_num)) { flat_map prepare_count; - for (auto const &pre: prepares) { + for (const auto& pre: prepares) { if (prepare_count.find(pre.second.view) == prepare_count.end()) prepare_count[pre.second.view] = 0; } - for (auto const &bp: as) { - for (auto const &pp: prepares) { + for (const auto& bp: as) { + for (const auto& pp: prepares) { if (bp.block_signing_key == pp.first.second) prepare_count[pp.first.first] += 1; } } - for (auto const &e: prepare_count) { + for (const auto& e: prepare_count) { if (e.second >= threshold) { mark_as_prepared(cpsp->block_id); } @@ -151,8 +150,8 @@ namespace eosio { } } - void pbft_database::mark_as_prepared(const block_id_type &bid) { - auto &by_block_id_index = pbft_state_index.get(); + void pbft_database::mark_as_prepared(const block_id_type& bid) { + auto& by_block_id_index = pbft_state_index.get(); auto itr = by_block_id_index.find(bid); auto bnum = block_info_type{bid}.block_num(); @@ -165,48 +164,54 @@ namespace eosio { pbft_state_index.insert(psp); return; } - by_block_id_index.modify(itr, [&](const pbft_state_ptr &p) { p->is_prepared = true; }); + by_block_id_index.modify(itr, [&](const pbft_state_ptr& p) { p->is_prepared = true; }); } - pbft_prepare pbft_database::send_and_add_pbft_prepare(const pbft_prepare &cached_prepare, pbft_view_type current_view) { - auto prepare_to_be_cached = pbft_prepare(); - + vector pbft_database::generate_and_add_pbft_prepare(const pbft_prepare& cached_prepare) { + vector prepares_to_be_cached; + const auto& my_sps = ctrl.my_signature_providers(); + prepares_to_be_cached.reserve(my_sps.size()); auto head_block_num = ctrl.head_block_num(); - if (head_block_num <= 1) return prepare_to_be_cached; + if (head_block_num <= 1) return prepares_to_be_cached; auto my_prepare = ctrl.get_pbft_my_prepare(); - auto reserve_prepare = [&](const block_id_type &in) { - if (in == block_id_type() || !ctrl.fetch_block_state_by_id(in)) return false; + auto reserve_prepare = [&](const block_id_type& in) { + if (in == block_id_type()) return false; + auto bs = ctrl.fetch_block_state_by_id(in); + if (!bs) return false; auto lib = ctrl.last_irreversible_block_id(); if (lib == block_id_type()) return true; auto forks = ctrl.fork_db().fetch_branch_from(in, lib); //`branch_type` will always contain at least themselves. //`in` block num should be higher than lib, yet fall on the same branch with lib. - return forks.first.size() > 1 && forks.second.size() == 1; + return forks.first.size() > 1 + && forks.second.size() == 1 + && !bs->in_current_chain; }; if (!cached_prepare.empty()) { - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { //sign again, update cache, then emit auto retry_p = cached_prepare; retry_p.common.timestamp = time_point::now(); retry_p.sender_signature = sp.second(retry_p.digest(chain_id)); - emit(pbft_outgoing_prepare, std::make_shared(retry_p)); + if (is_valid_prepare(retry_p, sp.first)) { + prepares_to_be_cached.emplace_back(retry_p); + } } - return prepare_to_be_cached; - } else if (reserve_prepare(my_prepare)) { - for (auto const &sp : ctrl.my_signature_providers()) { + } else if (reserve_prepare(my_prepare) ) { + for (const auto& sp : my_sps) { pbft_prepare reserve_p; - reserve_p.view=current_view; reserve_p.block_info={my_prepare}; + reserve_p.view = _current_view; + reserve_p.block_info = {my_prepare}; reserve_p.sender_signature = sp.second(reserve_p.digest(chain_id)); - emit(pbft_outgoing_prepare, std::make_shared(reserve_p)); - if (prepare_to_be_cached.empty()) prepare_to_be_cached = reserve_p; + if (is_valid_prepare(reserve_p, sp.first)) { + prepares_to_be_cached.emplace_back(reserve_p); + } } - return prepare_to_be_cached; } else { - auto current_watermark = get_current_pbft_watermark(); auto lib = ctrl.last_irreversible_block_num(); @@ -216,30 +221,30 @@ namespace eosio { high_watermark_block_num = std::min(head_block_num, current_watermark); } - if (high_watermark_block_num <= lib) return prepare_to_be_cached; + if (high_watermark_block_num <= lib) return prepares_to_be_cached; if (auto hwbs = ctrl.fork_db().get_block_in_current_chain_by_num(high_watermark_block_num)) { auto sent = false; - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { pbft_prepare new_p; - new_p.view=current_view; new_p.block_info={hwbs->id}; + new_p.view = _current_view; + new_p.block_info = {hwbs->id}; new_p.sender_signature = sp.second(new_p.digest(chain_id)); if (is_valid_prepare(new_p, sp.first)) { - emit(pbft_outgoing_prepare, std::make_shared(new_p)); add_pbft_prepare(new_p, sp.first); sent = true; - if (prepare_to_be_cached.empty()) prepare_to_be_cached = new_p; + prepares_to_be_cached.emplace_back(new_p); } } if (sent) ctrl.set_pbft_my_prepare(hwbs->id); } - return prepare_to_be_cached; } + return prepares_to_be_cached; } bool pbft_database::should_prepared() { - auto const &by_prepare_and_num_index = pbft_state_index.get(); + const auto& by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); if (itr == by_prepare_and_num_index.end()) return false; @@ -252,15 +257,15 @@ namespace eosio { return false; } - bool pbft_database::is_valid_prepare(const pbft_prepare &p, const public_key_type &pk) { + bool pbft_database::is_valid_prepare(const pbft_prepare& p, const public_key_type& pk) { // a prepare msg under lscb (which is no longer in fork_db), can be treated as null, thus true. if (p.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) return true; return should_recv_pbft_msg(pk); } - void pbft_database::add_pbft_commit(pbft_commit &c, const public_key_type &pk) { + void pbft_database::add_pbft_commit(const pbft_commit& c, const public_key_type& pk) { - auto &by_block_id_index = pbft_state_index.get(); + auto& by_block_id_index = pbft_state_index.get(); auto current = ctrl.fetch_block_state_by_id(c.block_info.block_id); @@ -284,10 +289,12 @@ namespace eosio { } else { auto commits = (*curr_itr)->commits; if (commits.find(std::make_pair(c.view, pk)) == commits.end()) { - by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr &psp) { + by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr& psp) { psp->commits[std::make_pair(c.view, pk)] = c; std::sort(psp->commits.begin(), psp->commits.end(), less<>()); }); + } else { + return; } } @@ -301,17 +308,17 @@ namespace eosio { auto commits = cpsp->commits; if (commits.size() >= threshold && !cpsp->is_committed && is_less_than_high_watermark(cpsp->block_num)) { flat_map commit_count; - for (auto const &com: commits) { + for (const auto& com: commits) { if (commit_count.find(com.second.view) == commit_count.end()) commit_count[com.second.view] = 0; } - for (auto const &bp: as) { - for (auto const &pc: commits) { + for (const auto& bp: as) { + for (const auto& pc: commits) { if (bp.block_signing_key == pc.first.second) commit_count[pc.first.first] += 1; } } - for (auto const &e: commit_count) { + for (const auto& e: commit_count) { if (e.second >= threshold) { mark_as_committed(cpsp->block_id); } @@ -321,55 +328,57 @@ namespace eosio { } } - pbft_commit pbft_database::send_and_add_pbft_commit(const pbft_commit &cached_commit, pbft_view_type current_view) { - auto commit_to_be_cached = pbft_commit(); + vector pbft_database::generate_and_add_pbft_commit(const pbft_commit& cached_commit) { + vector commits_to_be_cached; + const auto& my_sps = ctrl.my_signature_providers(); + commits_to_be_cached.reserve(my_sps.size()); if (!cached_commit.empty()) { - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { //sign again, update cache, then emit auto retry_c = cached_commit; retry_c.common.timestamp = time_point::now(); retry_c.sender_signature = sp.second(retry_c.digest(chain_id)); - emit(pbft_outgoing_commit, std::make_shared(retry_c)); + if (is_valid_commit(retry_c, sp.first)) { + commits_to_be_cached.emplace_back(retry_c); + } } - return commit_to_be_cached; } else { - auto const &by_prepare_and_num_index = pbft_state_index.get(); + const auto& by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); - if (itr == by_prepare_and_num_index.end()) return commit_to_be_cached; + if (itr == by_prepare_and_num_index.end()) return commits_to_be_cached; pbft_state_ptr psp = *itr; auto bs = ctrl.fork_db().get_block(psp->block_id); - if (!bs) return commit_to_be_cached; + if (!bs) return commits_to_be_cached; if (psp->is_prepared && (psp->block_num > ctrl.last_irreversible_block_num())) { - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { pbft_commit new_c; - new_c.view=current_view; - new_c.block_info={psp->block_id}; + new_c.view = _current_view; + new_c.block_info = {psp->block_id}; new_c.sender_signature = sp.second(new_c.digest(chain_id)); if (is_valid_commit(new_c, sp.first)) { - emit(pbft_outgoing_commit, std::make_shared(new_c)); add_pbft_commit(new_c, sp.first); - if (commit_to_be_cached.empty()) commit_to_be_cached = new_c; + commits_to_be_cached.emplace_back(new_c); } } } - return commit_to_be_cached; } + return commits_to_be_cached; } - void pbft_database::mark_as_committed(const block_id_type &bid) { - auto &by_block_id_index = pbft_state_index.get(); + void pbft_database::mark_as_committed(const block_id_type& bid) { + auto& by_block_id_index = pbft_state_index.get(); auto itr = by_block_id_index.find(bid); if (itr == by_block_id_index.end()) return; - by_block_id_index.modify(itr, [&](const pbft_state_ptr &p) { p->is_committed = true; }); + by_block_id_index.modify(itr, [&](const pbft_state_ptr& p) { p->is_committed = true; }); } bool pbft_database::should_committed() { - auto const &by_commit_and_num_index = pbft_state_index.get(); + const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end()) return false; pbft_state_ptr psp = *itr; @@ -381,7 +390,7 @@ namespace eosio { pbft_view_type new_view = 0; if (!should_committed()) return new_view; - auto const &by_commit_and_num_index = pbft_state_index.get(); + const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); pbft_state_ptr psp = *itr; @@ -394,17 +403,17 @@ namespace eosio { auto threshold = as.size() * 2 / 3 + 1; flat_map commit_count; - for (auto const &com: commits) { + for (const auto& com: commits) { if (commit_count.find(com.second.view) == commit_count.end()) commit_count[com.second.view] = 0; } - for (auto const &bp: as) { - for (auto const &pc: commits) { + for (const auto& bp: as) { + for (const auto& pc: commits) { if (bp.block_signing_key == pc.first.second) commit_count[pc.first.first] += 1; } } - for (auto const &e: commit_count) { + for (const auto& e: commit_count) { if (e.second >= threshold && e.first > new_view) { new_view = e.first; } @@ -412,13 +421,13 @@ namespace eosio { return new_view; } - bool pbft_database::is_valid_commit(const pbft_commit &c, const public_key_type &pk) { + bool pbft_database::is_valid_commit(const pbft_commit& c, const public_key_type& pk) { if (c.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) return true; return should_recv_pbft_msg(pk); } void pbft_database::commit_local() { - auto const &by_commit_and_num_index = pbft_state_index.get(); + const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end()) return; @@ -431,11 +440,11 @@ namespace eosio { return ctrl.pending_pbft_lib(); } - void pbft_database::add_pbft_view_change(pbft_view_change &vc, const public_key_type &pk) { + void pbft_database::add_pbft_view_change(const pbft_view_change& vc, const public_key_type& pk) { auto lscb_bps = lscb_active_producers().producers; - auto &by_view_index = view_state_index.get(); + auto& by_view_index = view_state_index.get(); auto itr = by_view_index.find(vc.target_view); if (itr == by_view_index.end()) { flat_map view_changes; @@ -450,9 +459,11 @@ namespace eosio { auto view_changes = pvs->view_changes; if (view_changes.find(pk) == view_changes.end()) { - by_view_index.modify(itr, [&](const pbft_view_change_state_ptr &pvsp) { + by_view_index.modify(itr, [&](const pbft_view_change_state_ptr& pvsp) { pvsp->view_changes[pk] = vc; }); + } else { + return; } } @@ -464,20 +475,20 @@ namespace eosio { if (vsp->view_changes.size() >= threshold && !vsp->is_view_changed) { auto vc_count = 0; - for (auto const &bp: lscb_bps) { - for (auto const &v: vsp->view_changes) { + for (const auto& bp: lscb_bps) { + for (const auto& v: vsp->view_changes) { if (bp.block_signing_key == v.first) vc_count += 1; } } if (vc_count >= threshold) { - by_view_index.modify(itr, [&](const pbft_view_change_state_ptr &pvsp) { pvsp->is_view_changed = true; }); + by_view_index.modify(itr, [&](const pbft_view_change_state_ptr& pvsp) { pvsp->is_view_changed = true; }); } } } pbft_view_type pbft_database::should_view_change() { pbft_view_type nv = 0; - auto &by_view_index = view_state_index.get(); + auto& by_view_index = view_state_index.get(); auto itr = by_view_index.begin(); if (itr == by_view_index.end()) return nv; @@ -486,13 +497,13 @@ namespace eosio { auto vc_count = 0; auto pvs = (*itr); - for (auto const &bp: active_bps) { - for (auto const &v: pvs->view_changes) { + for (const auto& bp: active_bps) { + for (const auto& v: pvs->view_changes) { if (bp.block_signing_key == v.first) vc_count += 1; } } //if contains self or view_change >= f+1, transit to view_change and send view change - if (vc_count >= active_bps.size() / 3 + 1) { + if (vc_count > (active_bps.size() - 1) / 3) { nv = pvs->view; break; } @@ -501,60 +512,61 @@ namespace eosio { return nv; } - pbft_view_change pbft_database::send_and_add_pbft_view_change( - const pbft_view_change &cached_view_change, - const pbft_prepared_certificate &ppc, - const vector &pcc, - pbft_view_type current_view, + vector pbft_database::generate_and_add_pbft_view_change( + const pbft_view_change& cached_view_change, + const pbft_prepared_certificate& ppc, + const vector& pcc, pbft_view_type target_view) { - auto view_change_to_be_cached = pbft_view_change(); + vector view_changes_to_be_cached; + const auto& my_sps = ctrl.my_signature_providers(); + view_changes_to_be_cached.reserve(my_sps.size()); + if (!cached_view_change.empty()) { - for (auto const &sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { //sign again, update cache, then emit auto retry_vc = cached_view_change; retry_vc.common.timestamp = time_point::now(); retry_vc.sender_signature = sp.second(retry_vc.digest(chain_id)); - emit(pbft_outgoing_view_change, std::make_shared(retry_vc)); + if (is_valid_view_change(retry_vc, sp.first)) { + view_changes_to_be_cached.emplace_back(retry_vc); + } } - return view_change_to_be_cached; } else { - for (auto const &my_sp : ctrl.my_signature_providers()) { - + for (const auto& sp : my_sps) { auto my_lsc = get_stable_checkpoint_by_id(ctrl.last_stable_checkpoint_block_id()); pbft_view_change new_vc; - new_vc.current_view=current_view; - new_vc.target_view=target_view; - new_vc.prepared_cert=ppc; - new_vc.committed_certs=pcc; - new_vc.stable_checkpoint=my_lsc; - new_vc.sender_signature = my_sp.second(new_vc.digest(chain_id)); - if (is_valid_view_change(new_vc, my_sp.first)) { - emit(pbft_outgoing_view_change, std::make_shared(new_vc)); - add_pbft_view_change(new_vc, my_sp.first); - if (view_change_to_be_cached.empty()) view_change_to_be_cached = new_vc; + new_vc.current_view = _current_view; + new_vc.target_view = target_view; + new_vc.prepared_cert = ppc; + new_vc.committed_certs = pcc; + new_vc.stable_checkpoint = my_lsc; + new_vc.sender_signature = sp.second(new_vc.digest(chain_id)); + if (is_valid_view_change(new_vc, sp.first)) { + add_pbft_view_change(new_vc, sp.first); + view_changes_to_be_cached.emplace_back(new_vc); } } - return view_change_to_be_cached; } + return view_changes_to_be_cached; } - bool pbft_database::should_new_view(const pbft_view_type target_view) { - auto &by_view_index = view_state_index.get(); + bool pbft_database::should_new_view(pbft_view_type target_view) { + auto& by_view_index = view_state_index.get(); auto itr = by_view_index.find(target_view); if (itr == by_view_index.end()) return false; return (*itr)->is_view_changed; } pbft_view_type pbft_database::get_proposed_new_view_num() { - auto &by_count_and_view_index = view_state_index.get(); + auto& by_count_and_view_index = view_state_index.get(); auto itr = by_count_and_view_index.begin(); if (itr == by_count_and_view_index.end() || !(*itr)->is_view_changed) return 0; return (*itr)->view; } - bool pbft_database::has_new_primary(const public_key_type &pk) { + bool pbft_database::has_new_primary(const public_key_type& pk) { if (pk == public_key_type()) return false; auto sps = ctrl.my_signature_providers(); @@ -567,12 +579,14 @@ namespace eosio { ctrl.reset_pbft_my_prepare(); } - pbft_new_view pbft_database::send_pbft_new_view( - const pbft_view_changed_certificate &vcc, - pbft_view_type current_view) { + pbft_new_view pbft_database::generate_pbft_new_view( + const pbft_view_changed_certificate& vcc, + pbft_view_type new_view) { + + pbft_new_view nv; - auto primary_key = get_new_view_primary_key(current_view); - if (!has_new_primary(primary_key) || vcc.empty()) return pbft_new_view(); + auto primary_key = get_new_view_primary_key(new_view); + if (!has_new_primary(primary_key) || vcc.empty()) return nv; //`sp_itr` is not possible to be the end iterator, since it's already been checked in `has_new_primary`. auto my_sps = ctrl.my_signature_providers(); @@ -582,14 +596,14 @@ namespace eosio { auto highest_pcc = vector{}; auto highest_sc = pbft_stable_checkpoint(); - for (auto const &vc: vcc.view_changes) { + for (const auto& vc: vcc.view_changes) { if (vc.prepared_cert.block_info.block_num() > highest_ppc.block_info.block_num()) { highest_ppc = vc.prepared_cert; } - for (auto const &cc: vc.committed_certs) { + for (const auto& cc: vc.committed_certs) { auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), - [&](const pbft_committed_certificate &ext) { return ext.block_info.block_id == cc.block_info.block_id; }); + [&](const pbft_committed_certificate& ext) { return ext.block_info.block_id == cc.block_info.block_id; }); if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); } @@ -598,32 +612,32 @@ namespace eosio { } } - pbft_new_view nv; - nv.new_view=current_view; - nv.prepared_cert=highest_ppc; - nv.committed_certs=highest_pcc; - nv.stable_checkpoint=highest_sc; - nv.view_changed_cert=vcc; + nv.new_view = new_view; + nv.prepared_cert = highest_ppc; + nv.committed_certs = highest_pcc; + nv.stable_checkpoint = highest_sc; + nv.view_changed_cert = vcc; nv.sender_signature = sp_itr->second(nv.digest(chain_id)); try { validate_new_view(nv, sp_itr->first); - emit(pbft_outgoing_new_view, std::make_shared(nv)); - return nv; } catch (const fc::exception& ex) { elog("bad new view, ${s} ", ("s", ex.to_string())); - return pbft_new_view(); + nv = pbft_new_view(); } + return nv; } pbft_prepared_certificate pbft_database::generate_prepared_certificate() { - auto const &by_prepare_and_num_index = pbft_state_index.get(); + pbft_prepared_certificate ppc; + + const auto& by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); - if (itr == by_prepare_and_num_index.end()) return pbft_prepared_certificate(); + if (itr == by_prepare_and_num_index.end()) return ppc; pbft_state_ptr psp = *itr; auto prepared_block_state = ctrl.fetch_block_state_by_id(psp->block_id); - if (!prepared_block_state) return pbft_prepared_certificate(); + if (!prepared_block_state) return ppc; auto as = prepared_block_state->active_schedule.producers; if (psp->is_prepared && psp->block_num > ctrl.last_irreversible_block_num()) { @@ -633,44 +647,45 @@ namespace eosio { flat_map prepare_count; flat_map> prepare_msg; - for (auto const &pre: prepares) { + for (const auto& pre: prepares) { if (prepare_count.find(pre.first.first) == prepare_count.end()) prepare_count[pre.first.first] = 0; prepare_msg[pre.first.first].emplace_back(pre.second); } - for (auto const &bp: as) { - for (auto const &pp: prepares) { + for (const auto& bp: as) { + for (const auto& pp: prepares) { if (bp.block_signing_key == pp.first.second) prepare_count[pp.first.first] += 1; } } auto bp_threshold = as.size() * 2 / 3 + 1; - for (auto const &e: prepare_count) { + for (const auto& e: prepare_count) { if (e.second >= bp_threshold) { valid_prepares = prepare_msg[e.first]; } } - if (valid_prepares.empty()) return pbft_prepared_certificate(); + if (valid_prepares.empty()) return ppc; - pbft_prepared_certificate pc; - pc.block_info={psp->block_id}; pc.prepares=valid_prepares; pc.pre_prepares.emplace(psp->block_id); - for (auto const &p: valid_prepares) { + ppc.block_info = {psp->block_id}; + ppc.prepares=valid_prepares; + ppc.pre_prepares.emplace(psp->block_id); + for (const auto& p: valid_prepares) { auto bid = p.block_info.block_id; while (bid != psp->block_id) { - pc.pre_prepares.emplace(bid); + ppc.pre_prepares.emplace(bid); bid = ctrl.fetch_block_state_by_id(bid)->prev(); } } - return pc; - } else return pbft_prepared_certificate(); + } + return ppc; } vector pbft_database::generate_committed_certificate() { - auto pcc = vector{}; + vector pcc{}; - auto const &by_commit_and_num_index = pbft_state_index.get(); + const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end()) return pcc; @@ -698,11 +713,11 @@ namespace eosio { } } - auto const &by_id_index = pbft_state_index.get(); + const auto& by_id_index = pbft_state_index.get(); std::sort(ccb.begin(), ccb.end()); pcc.reserve(ccb.size()); - for (auto const &committed_block_num: ccb) { + for (const auto& committed_block_num: ccb) { auto cbs = ctrl.fetch_block_state_by_number(committed_block_num); if (!cbs) return pcc; @@ -719,19 +734,19 @@ namespace eosio { flat_map commit_count; flat_map> commit_msg; - for (auto const &com: commits) { + for (const auto& com: commits) { if (commit_count.find(com.first.first) == commit_count.end()) commit_count[com.first.first] = 0; commit_msg[com.first.first].emplace_back(com.second); } - for (auto const &bp: as) { - for (auto const &cc: commits) { + for (const auto& bp: as) { + for (const auto& cc: commits) { if (bp.block_signing_key == cc.first.second) commit_count[cc.first.first] += 1; } } auto bp_threshold = as.size() * 2 / 3 + 1; - for (auto const &e: commit_count) { + for (const auto& e: commit_count) { if (e.second >= bp_threshold) { valid_commits = commit_msg[e.first]; } @@ -740,7 +755,8 @@ namespace eosio { if (valid_commits.empty()) return pcc; pbft_committed_certificate cc; - cc.block_info={cbs->id}; cc.commits=valid_commits; + cc.block_info = {cbs->id}; + cc.commits = valid_commits; pcc.emplace_back(cc); } return pcc; @@ -748,28 +764,27 @@ namespace eosio { pbft_view_changed_certificate pbft_database::generate_view_changed_certificate(pbft_view_type target_view) { - auto pvcc = pbft_view_changed_certificate(); + pbft_view_changed_certificate pvcc; - auto &by_view_index = view_state_index.get(); + auto& by_view_index = view_state_index.get(); auto itr = by_view_index.find(target_view); if (itr == by_view_index.end()) return pvcc; auto pvs = *itr; if (pvs->is_view_changed) { - pvcc.target_view=pvs->view; pvcc.view_changes.reserve(pvs->view_changes.size()); - for(auto & view_change : pvs->view_changes) { + for(auto& view_change : pvs->view_changes) { pvcc.view_changes.emplace_back( view_change.second ); } - return pvcc; - } else return pvcc; + } + return pvcc; } - bool pbft_database::is_valid_prepared_certificate(const pbft_prepared_certificate &certificate, bool add_to_pbft_db) { + bool pbft_database::is_valid_prepared_certificate(const pbft_prepared_certificate& certificate, bool add_to_pbft_db) { // an empty certificate is valid since it acts as a null digest in pbft. if (certificate.empty()) return true; // a certificate under lscb (no longer in fork_db) is also treated as null. @@ -779,7 +794,7 @@ namespace eosio { auto prepares_metadata = vector>{}; prepares_metadata.reserve(prepares.size()); - for (auto &p : prepares) { + for (auto& p : prepares) { auto pmm = pbft_message_metadata(p, chain_id); prepares_metadata.emplace_back(pmm); if (!is_valid_prepare(p, pmm.sender_key)) return false; @@ -796,19 +811,19 @@ namespace eosio { flat_map prepare_count; - for (auto const &pm: prepares_metadata) { + for (const auto& pm: prepares_metadata) { if (prepare_count.find(pm.msg.view) == prepare_count.end()) prepare_count[pm.msg.view] = 0; } - for (auto const &bp: producer_schedule.producers) { - for (auto const &pm: prepares_metadata) { + for (const auto& bp: producer_schedule.producers) { + for (const auto& pm: prepares_metadata) { if (bp.block_signing_key == pm.sender_key) prepare_count[pm.msg.view] += 1; } } auto should_prepared = false; - for (auto const &e: prepare_count) { + for (const auto& e: prepare_count) { if (e.second >= bp_threshold) { should_prepared = true; } @@ -819,9 +834,9 @@ namespace eosio { //validate prepare auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto non_fork_bp_count = 0; - vector prepare_infos; + fork_info_type prepare_infos; prepare_infos.reserve(certificate.prepares.size()); - for (auto const &p : certificate.prepares) { + for (const auto& p : certificate.prepares) { //only search in fork db if (p.block_info.block_num() <= lscb_num) { ++non_fork_bp_count; @@ -832,7 +847,7 @@ namespace eosio { return is_valid_longest_fork(certificate.block_info, prepare_infos, bp_threshold, non_fork_bp_count); } - bool pbft_database::is_valid_committed_certificate(const pbft_committed_certificate &certificate, bool add_to_pbft_db) { + bool pbft_database::is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db) { // an empty certificate is valid since it acts as a null digest in pbft. if (certificate.empty()) return true; // a certificate under lscb (no longer in fork_db) is also treated as null. @@ -842,7 +857,7 @@ namespace eosio { auto commits_metadata = vector>{}; commits_metadata.reserve(commits.size()); - for (auto &c : commits) { + for (auto& c : commits) { auto pmm = pbft_message_metadata(c, chain_id); commits_metadata.emplace_back(pmm); if (!is_valid_commit(c, pmm.sender_key)) return false; @@ -859,19 +874,19 @@ namespace eosio { flat_map commit_count; - for (auto const &cm: commits_metadata) { + for (const auto& cm: commits_metadata) { if (commit_count.find(cm.msg.view) == commit_count.end()) commit_count[cm.msg.view] = 0; } - for (auto const &bp: producer_schedule.producers) { - for (auto const &cm: commits_metadata) { + for (const auto& bp: producer_schedule.producers) { + for (const auto& cm: commits_metadata) { if (bp.block_signing_key == cm.sender_key) commit_count[cm.msg.view] += 1; } } auto should_committed = false; - for (auto const &e: commit_count) { + for (const auto& e: commit_count) { if (e.second >= bp_threshold) { should_committed = true; } @@ -882,9 +897,9 @@ namespace eosio { //validate commit auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto non_fork_bp_count = 0; - vector commit_infos; + fork_info_type commit_infos; commit_infos.reserve(certificate.commits.size()); - for (auto const &c : certificate.commits) { + for (const auto& c : certificate.commits) { //only search in fork db if (c.block_info.block_num() <= lscb_num) { ++non_fork_bp_count; @@ -895,14 +910,13 @@ namespace eosio { return is_valid_longest_fork(certificate.block_info, commit_infos, bp_threshold, non_fork_bp_count); } - bool pbft_database::is_valid_view_change(const pbft_view_change &vc, const public_key_type &pk) { + bool pbft_database::is_valid_view_change(const pbft_view_change& vc, const public_key_type& pk) { return should_recv_pbft_msg(pk); // No need to check prepared cert and stable checkpoint, until generate or validate a new view msg } - - void pbft_database::validate_new_view(const pbft_new_view &nv, const public_key_type &pk) { + void pbft_database::validate_new_view(const pbft_new_view& nv, const public_key_type& pk) { EOS_ASSERT(pk == get_new_view_primary_key(nv.new_view), pbft_exception, "new view is not signed with expected key"); @@ -915,7 +929,7 @@ namespace eosio { auto committed_certs = nv.committed_certs; std::sort(committed_certs.begin(), committed_certs.end()); - for (auto const &c: committed_certs) { + for (const auto& c: committed_certs) { EOS_ASSERT(is_valid_committed_certificate(c, true), pbft_exception, "bad committed certificate: ${cc}", ("cc", c)); } @@ -924,7 +938,7 @@ namespace eosio { vector lscb_producers; lscb_producers.reserve(lscb_active_producers().producers.size()); - for (auto const &bp: lscb_active_producers().producers) { + for (const auto& bp: lscb_active_producers().producers) { lscb_producers.emplace_back(bp.block_signing_key); } auto schedule_threshold = lscb_producers.size() * 2 / 3 + 1; @@ -935,7 +949,7 @@ namespace eosio { vector view_change_producers; view_change_producers.reserve(view_changes.size()); - for (auto &vc: view_changes) { + for (auto& vc : view_changes) { auto pmm = pbft_message_metadata(vc, chain_id); view_changes_metadata.emplace_back(pmm); if (is_valid_view_change(vc, pmm.sender_key)) { @@ -961,16 +975,16 @@ namespace eosio { auto highest_pcc = vector{}; auto highest_scp = pbft_stable_checkpoint(); - for (auto const &vc: nv.view_changed_cert.view_changes) { + for (const auto& vc: nv.view_changed_cert.view_changes) { if (vc.prepared_cert.block_info.block_num() > highest_ppc.block_info.block_num() && is_valid_prepared_certificate(vc.prepared_cert)) { highest_ppc = vc.prepared_cert; } - for (auto const &cc: vc.committed_certs) { + for (const auto& cc: vc.committed_certs) { if (is_valid_committed_certificate(cc)) { auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), - [&](const pbft_committed_certificate &ext) { + [&](const pbft_committed_certificate& ext) { return ext.block_info.block_id == cc.block_info.block_id; }); if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); @@ -1001,15 +1015,15 @@ namespace eosio { ("hpcc", highest_scp)("pc", nv.stable_checkpoint)); } - bool pbft_database::should_stop_view_change(const pbft_view_change &vc) { + bool pbft_database::should_stop_view_change(const pbft_view_change& vc) { auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto vc_lscb = vc.stable_checkpoint.block_info.block_num(); return vc_lscb > 0 && lscb_num > vc_lscb; } - vector> pbft_database::fetch_fork_from(vector &block_infos) { + vector pbft_database::fetch_fork_from(fork_info_type& block_infos) { - vector> result; + vector result; if (block_infos.empty()) { return result; } @@ -1019,7 +1033,7 @@ namespace eosio { } sort(block_infos.begin(), block_infos.end(), - [](const block_info_type &a, const block_info_type &b) -> bool { return a.block_num() > b.block_num(); }); + [](const block_info_type& a, const block_info_type& b) -> bool { return a.block_num() > b.block_num(); }); while (!block_infos.empty()) { auto fork = fetch_first_fork_from(block_infos); @@ -1030,8 +1044,8 @@ namespace eosio { return result; } - vector pbft_database::fetch_first_fork_from(vector &bi) { - vector result; + fork_info_type pbft_database::fetch_first_fork_from(fork_info_type& bi) { + fork_info_type result; if (bi.empty()) { return result; } @@ -1071,39 +1085,39 @@ namespace eosio { return result; } - bool pbft_database::is_valid_longest_fork(const block_info_type &bi, vector block_infos, unsigned long threshold, unsigned long non_fork_bp_count) { + bool pbft_database::is_valid_longest_fork( + const block_info_type& bi, + fork_info_type& block_infos, + unsigned long threshold, + unsigned long non_fork_bp_count) { auto forks = fetch_fork_from(block_infos); - vector longest_fork; - for (auto const &f : forks) { + fork_info_type longest_fork; + for (const auto& f : forks) { if (f.size() > longest_fork.size()) { longest_fork = f; } } - if (longest_fork.size() + non_fork_bp_count < threshold) return false; - - if (longest_fork.empty()) return true; - auto calculated_block_info = longest_fork.back(); - - return bi.block_id == calculated_block_info.block_id; + return longest_fork.empty() + || (longest_fork.size() + non_fork_bp_count >= threshold && bi.block_id == longest_fork.back().block_id); } - pbft_stable_checkpoint pbft_database::fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr &b) { + pbft_stable_checkpoint pbft_database::fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr& b) { + + pbft_stable_checkpoint psc; try { if (b) { - auto &extn = b->block_extensions; + auto& extn = b->block_extensions; for (auto it = extn.begin(); it != extn.end();) { if (it->first == static_cast(block_extension_type::pbft_stable_checkpoint)) { auto scp_ds = it->second; fc::datastream ds(scp_ds.data(), scp_ds.size()); + fc::raw::unpack(ds, psc); - pbft_stable_checkpoint scp; - fc::raw::unpack(ds, scp); - - if (is_valid_stable_checkpoint(scp)) { - return scp; + if (is_valid_stable_checkpoint(psc)) { + break; } else { it = extn.erase(it); } @@ -1114,32 +1128,34 @@ namespace eosio { } } catch(...) { elog("no stable checkpoints found in the block extension"); + psc = pbft_stable_checkpoint(); } - return pbft_stable_checkpoint(); + return psc; } - pbft_stable_checkpoint pbft_database::get_stable_checkpoint_by_id(const block_id_type &block_id, bool incl_blk_extn ) { - auto const &by_block = checkpoint_index.get(); + pbft_stable_checkpoint pbft_database::get_stable_checkpoint_by_id(const block_id_type& block_id, bool incl_blk_extn ) { + pbft_stable_checkpoint psc; + const auto& by_block = checkpoint_index.get(); auto itr = by_block.find(block_id); if (itr == by_block.end()) { if (incl_blk_extn) { auto blk = ctrl.fetch_block_by_id(block_id); - return fetch_stable_checkpoint_from_blk_extn(blk); + psc = fetch_stable_checkpoint_from_blk_extn(blk); } - return pbft_stable_checkpoint(); + return psc; } auto cpp = *itr; if (cpp->is_stable) { - pbft_stable_checkpoint psc; psc.block_info={cpp->block_id}; psc.checkpoints.reserve(cpp->checkpoints.size()); - for (auto & checkpoint : cpp->checkpoints) { + for (auto& checkpoint : cpp->checkpoints) { psc.checkpoints.emplace_back(checkpoint.second) ; } - return psc; - } else return pbft_stable_checkpoint(); + + } + return psc; } block_info_type pbft_database::cal_pending_stable_checkpoint() const { @@ -1147,7 +1163,7 @@ namespace eosio { auto pending_scb_num = ctrl.last_stable_checkpoint_block_num(); auto pending_scb_info = block_info_type{ctrl.last_stable_checkpoint_block_id()}; - auto const &by_blk_num = checkpoint_index.get(); + const auto& by_blk_num = checkpoint_index.get(); auto itr = by_blk_num.lower_bound(pending_scb_num); if (itr == by_blk_num.end()) return pending_scb_info; @@ -1161,7 +1177,7 @@ namespace eosio { producer_schedule_type new_schedule; if (pending_scb_num == 0) { - auto const &ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; + const auto& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; if (ucb == 0) { current_schedule = ctrl.initial_schedule(); new_schedule = ctrl.initial_schedule(); @@ -1193,82 +1209,69 @@ namespace eosio { } vector pbft_database::generate_and_add_pbft_checkpoint() { - auto checkpoint = [&](const block_num_type &in) { + auto checkpoint = [&](const block_num_type& in) { auto const& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; if (!ctrl.is_pbft_enabled()) return false; if (in <= ucb) return false; auto watermarks = get_updated_watermarks(); return in == ucb + 1 // checkpoint on first pbft block; - || in % pbft_checkpoint_granularity == 1 // checkpoint on every 100 block; + || in % get_checkpoint_interval() == 1 // checkpoint on every 100 block; || std::find(watermarks.begin(), watermarks.end(), in) != watermarks.end(); // checkpoint on bp schedule change; }; - auto new_pc = vector{}; + vector new_pc{}; + auto my_sps = ctrl.my_signature_providers(); - auto const &by_commit_and_num_index = pbft_state_index.get(); + const auto& by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end() || !(*itr)->is_committed) return new_pc; pbft_state_ptr psp = (*itr); - - flat_map pending_checkpoint_block_num; // block_height and retry_flag auto lscb_num = ctrl.last_stable_checkpoint_block_num(); + + vector pending_checkpoint_block_num; + pending_checkpoint_block_num.reserve(psp->block_num - lscb_num); for (auto i = psp->block_num; i > lscb_num && i > 1; --i) { if (checkpoint(i)) { - auto &by_block = checkpoint_index.get(); - - if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(i)) { - auto c_itr = by_block.find(bs->id); - if (c_itr == by_block.end()) { - pending_checkpoint_block_num[i] = false; - } else { - auto checkpoints = (*c_itr)->checkpoints; - for (auto const &my_sp : ctrl.my_signature_providers()) { - if (checkpoints.find(my_sp.first) != checkpoints.end() && !(*c_itr)->is_stable) { - pending_checkpoint_block_num[i] = true; //retry sending at this time. - } - } - if (pending_checkpoint_block_num.find(i) == pending_checkpoint_block_num.end()) { - pending_checkpoint_block_num[i] = false; - } - } - } + pending_checkpoint_block_num.emplace_back(i); } } - auto &by_block = checkpoint_index.get(); + auto& by_block = checkpoint_index.get(); if (!pending_checkpoint_block_num.empty()) { std::sort(pending_checkpoint_block_num.begin(), pending_checkpoint_block_num.end()); - for (auto& bnum_and_retry: pending_checkpoint_block_num) { - if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(bnum_and_retry.first)) { - for (auto const &my_sp : ctrl.my_signature_providers()) { + for (auto bnum: pending_checkpoint_block_num) { + if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(bnum)) { + for (const auto& sp : my_sps) { pbft_checkpoint cp; - cp.block_info={bs->id}; - cp.sender_signature = my_sp.second(cp.digest(chain_id)); - if (!bnum_and_retry.second && is_valid_checkpoint(cp, my_sp.first)) { //first time sending this checkpoint - add_pbft_checkpoint(cp, my_sp.first); + cp.block_info = {bs->id}; + cp.sender_signature = sp.second(cp.digest(chain_id)); + if (is_valid_checkpoint(cp, sp.first)) { + add_pbft_checkpoint(cp, sp.first); + new_pc.emplace_back(cp); } - new_pc.emplace_back(cp); } } } } else if (lscb_num > 0) { //retry sending my lscb - for (auto const &my_sp : ctrl.my_signature_providers()) { + for (const auto& sp : my_sps) { pbft_checkpoint cp; cp.block_info={ctrl.last_stable_checkpoint_block_id()}; - cp.sender_signature = my_sp.second(cp.digest(chain_id)); - new_pc.emplace_back(cp); + cp.sender_signature = sp.second(cp.digest(chain_id)); + if (is_valid_checkpoint(cp, sp.first)) { + new_pc.emplace_back(cp); + } } } return new_pc; } - void pbft_database::add_pbft_checkpoint(pbft_checkpoint &cp, const public_key_type &pk) { + void pbft_database::add_pbft_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk) { auto cp_block_state = ctrl.fetch_block_state_by_id(cp.block_info.block_id); if (!cp_block_state) return; - auto &by_block = checkpoint_index.get(); + auto& by_block = checkpoint_index.get(); auto itr = by_block.find(cp.block_info.block_id); if (itr == by_block.end()) { flat_map checkpoints; @@ -1284,9 +1287,11 @@ namespace eosio { auto csp = (*itr); auto checkpoints = csp->checkpoints; if (checkpoints.find(pk) == checkpoints.end()) { - by_block.modify(itr, [&](const pbft_checkpoint_state_ptr &pcp) { + by_block.modify(itr, [&](const pbft_checkpoint_state_ptr& pcp) { csp->checkpoints[pk] = cp; }); + } else { + return; } } @@ -1296,13 +1301,13 @@ namespace eosio { if (csp->checkpoints.size() >= threshold && !csp->is_stable) { auto cp_count = 0; - for (auto const &bp: active_bps) { - for (auto const &c: csp->checkpoints) { + for (const auto& bp: active_bps) { + for (const auto& c: csp->checkpoints) { if (bp.block_signing_key == c.first) cp_count += 1; } } if (cp_count >= threshold) { - by_block.modify(itr, [&](const pbft_checkpoint_state_ptr &pcp) { csp->is_stable = true; }); + by_block.modify(itr, [&](const pbft_checkpoint_state_ptr& pcp) { csp->is_stable = true; }); auto id = csp->block_id; auto blk = ctrl.fetch_block_by_id(id); @@ -1315,7 +1320,7 @@ namespace eosio { fc::raw::pack( ds, scp ); blk->block_extensions.emplace_back(); - auto &extension = blk->block_extensions.back(); + auto& extension = blk->block_extensions.back(); extension.first = static_cast(block_extension_type::pbft_stable_checkpoint ); extension.second.resize(scp_size); std::copy(buffer->begin(),buffer->end(), extension.second.data()); @@ -1324,13 +1329,6 @@ namespace eosio { } } - void pbft_database::send_pbft_checkpoint() { - auto cps_to_send = generate_and_add_pbft_checkpoint(); - for (auto const &cp: cps_to_send) { - emit(pbft_outgoing_checkpoint, std::make_shared(cp)); - } - } - void pbft_database::checkpoint_local() { auto pending_scb_info = cal_pending_stable_checkpoint(); auto lscb_num = ctrl.last_stable_checkpoint_block_num(); @@ -1339,35 +1337,36 @@ namespace eosio { if (pending_num > lscb_num) { ctrl.set_pbft_latest_checkpoint(pending_id); if (ctrl.last_irreversible_block_num() < pending_num) ctrl.pbft_commit_local(pending_id); - auto &by_block_id_index = pbft_state_index.get(); + auto& by_block_id_index = pbft_state_index.get(); auto pitr = by_block_id_index.find(pending_id); if (pitr != by_block_id_index.end()) { prune(*pitr); } } - auto &bni = checkpoint_index.get(); + auto& bni = checkpoint_index.get(); auto oldest = bni.begin(); - if ( oldest != bni.end() + while ( oldest != bni.end() && (*oldest)->is_stable && (*oldest)->block_num < lscb_num - oldest_stable_checkpoint ) { prune(*oldest); + oldest = bni.begin(); } } - bool pbft_database::is_valid_checkpoint(const pbft_checkpoint &cp, const public_key_type &pk) { + bool pbft_database::is_valid_checkpoint(const pbft_checkpoint& cp, const public_key_type& pk) { if (cp.block_info.block_num() > ctrl.head_block_num() || cp.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) return false; if (auto bs = ctrl.fetch_block_state_by_id(cp.block_info.block_id)) { auto active_bps = bs->active_schedule.producers; - for (auto const &bp: active_bps) { + for (const auto& bp: active_bps) { if (bp.block_signing_key == pk) return true; } } return false; } - bool pbft_database::is_valid_stable_checkpoint(const pbft_stable_checkpoint &scp, bool add_to_pbft_db) { + bool pbft_database::is_valid_stable_checkpoint(const pbft_stable_checkpoint& scp, bool add_to_pbft_db) { if (scp.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) // the stable checkpoint is way behind lib, no way getting the block state, // it will not be applied nor saved, thus considered safe. @@ -1377,7 +1376,7 @@ namespace eosio { auto checkpoints_metadata = vector>{}; checkpoints_metadata.reserve(checkpoints.size()); - for (auto &cp : checkpoints) { + for (auto& cp : checkpoints) { auto pmm = pbft_message_metadata(cp, chain_id); checkpoints_metadata.emplace_back(pmm); if (cp.block_info != scp.block_info || !is_valid_checkpoint(cp, pmm.sender_key)) return false; @@ -1390,8 +1389,8 @@ namespace eosio { if (auto bs = ctrl.fetch_block_state_by_number(scp.block_info.block_num())) { auto as = bs->active_schedule; auto cp_count = 0; - for (auto const &bp: as.producers) { - for (auto const &cpm: checkpoints_metadata) { + for (const auto& bp: as.producers) { + for (const auto& cpm: checkpoints_metadata) { if (bp.block_signing_key == cpm.sender_key) cp_count += 1; } } @@ -1404,24 +1403,24 @@ namespace eosio { bool pbft_database::should_send_pbft_msg() { auto schedules = get_updated_fork_schedules(); - for (auto const &bp: schedules) { - for (auto const &sp: ctrl.my_signature_providers()) { + for (const auto& bp: schedules) { + for (const auto& sp: ctrl.my_signature_providers()) { if (bp.first == sp.first) return true; } } return false; } - bool pbft_database::should_recv_pbft_msg(const public_key_type &pub_key) { + bool pbft_database::should_recv_pbft_msg(const public_key_type& pub_key) { auto schedules = get_updated_fork_schedules(); - for (auto const &bp: schedules) { + for (const auto& bp: schedules) { if (bp.first == pub_key) return true; } return false; } - public_key_type pbft_database::get_new_view_primary_key(const pbft_view_type target_view) { + public_key_type pbft_database::get_new_view_primary_key(pbft_view_type target_view) { auto active_bps = lscb_active_producers().producers; if (active_bps.empty()) return public_key_type(); @@ -1430,19 +1429,24 @@ namespace eosio { } producer_schedule_type pbft_database::lscb_active_producers() const { + + auto ps = ctrl.initial_schedule(); auto num = ctrl.last_stable_checkpoint_block_num(); if (num == 0) { - auto const &ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; - if (ucb == 0) return ctrl.initial_schedule(); + const auto& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; + if (ucb == 0) return ps; num = ucb; } if (auto bs = ctrl.fetch_block_state_by_number(num)) { - if (bs->pending_schedule.producers.empty()) return bs->active_schedule; - return bs->pending_schedule; + if (bs->pending_schedule.producers.empty()) { + ps = bs->active_schedule; + } else { + ps = bs->pending_schedule; + } } - return ctrl.initial_schedule(); + return ps; } block_num_type pbft_database::get_current_pbft_watermark() { @@ -1460,7 +1464,7 @@ namespace eosio { void pbft_database::update_fork_schedules() { - auto vector_minus = [&](vector &v1, vector &v2) + auto vector_minus = [&](vector& v1, vector& v2) { vector diff; std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), @@ -1479,7 +1483,7 @@ namespace eosio { for (auto i: added) { if (auto bs = ctrl.fetch_block_state_by_number(i)) { auto as = bs->active_schedule.producers; - for (auto &bp: as) { + for (const auto& bp: as) { auto key = bp.block_signing_key; if (fork_schedules.find(key) == fork_schedules.end()) { fork_schedules[key] = i; @@ -1503,7 +1507,7 @@ namespace eosio { auto lscb_bps = lscb_active_producers().producers; auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - for (auto &bp: lscb_bps) { + for (const auto& bp: lscb_bps) { if (fork_schedules.find(bp.block_signing_key) == fork_schedules.end() || fork_schedules[bp.block_signing_key] < lscb_num) { fork_schedules[bp.block_signing_key] = lscb_num; @@ -1521,14 +1525,22 @@ namespace eosio { return fork_schedules; } - bool pbft_database::is_less_than_high_watermark(const block_num_type &bnum) { + uint16_t pbft_database::get_view_change_timeout() const { + return ctrl.get_pbft_properties().configuration.view_change_timeout; + } + + uint16_t pbft_database::get_checkpoint_interval() const { + return ctrl.get_pbft_properties().configuration.pbft_checkpoint_granularity; + } + + bool pbft_database::is_less_than_high_watermark(block_num_type bnum) { auto current_watermark = get_current_pbft_watermark(); return current_watermark == 0 || bnum <= current_watermark; } pbft_state_ptr pbft_database::get_pbft_state_by_id(const block_id_type& id) const { - auto &by_block_id_index = pbft_state_index.get(); + auto& by_block_id_index = pbft_state_index.get(); auto itr = by_block_id_index.find(id); if (itr != by_block_id_index.end()) return (*itr); @@ -1536,9 +1548,9 @@ namespace eosio { return pbft_state_ptr(); } - vector pbft_database::get_checkpoints_by_num(const block_num_type& num) const { + vector pbft_database::get_checkpoints_by_num(block_num_type num) const { auto results = vector{}; - auto &by_num_index = checkpoint_index.get(); + auto& by_num_index = checkpoint_index.get(); auto pitr = by_num_index.lower_bound( num ); while(pitr != by_num_index.end() && (*pitr)->block_num == num ) { @@ -1549,8 +1561,8 @@ namespace eosio { return results; } - pbft_view_change_state_ptr pbft_database::get_view_changes_by_target_view(const pbft_view_type& tv) const { - auto &by_view_index = view_state_index.get(); + pbft_view_change_state_ptr pbft_database::get_view_changes_by_target_view(pbft_view_type tv) const { + auto& by_view_index = view_state_index.get(); auto itr = by_view_index.find(tv); if (itr != by_view_index.end()) return (*itr); @@ -1578,10 +1590,10 @@ namespace eosio { EOS_ASSERT(result.second, pbft_exception, "unable to insert pbft checkpoint index, duplicate state detected"); } - void pbft_database::prune(const pbft_state_ptr &h) { + void pbft_database::prune(const pbft_state_ptr& h) { auto num = h->block_num; - auto &by_bn = pbft_state_index.get(); + auto& by_bn = pbft_state_index.get(); auto bni = by_bn.begin(); while (bni != by_bn.end() && (*bni)->block_num < num) { prune(*bni); @@ -1594,10 +1606,10 @@ namespace eosio { } } - void pbft_database::prune(const pbft_checkpoint_state_ptr &h) { + void pbft_database::prune(const pbft_checkpoint_state_ptr& h) { auto num = h->block_num; - auto &by_bn = checkpoint_index.get(); + auto& by_bn = checkpoint_index.get(); auto bni = by_bn.begin(); while (bni != by_bn.end() && (*bni)->block_num < num) { prune(*bni); @@ -1609,22 +1621,5 @@ namespace eosio { checkpoint_index.erase(itr); } } - - template - void pbft_database::emit(const Signal &s, Arg &&a) { - try { - s(std::forward(a)); - } catch (boost::interprocess::bad_alloc &e) { - wlog("bad alloc"); - throw e; - } catch (controller_emit_signal_exception &e) { - wlog("${details}", ("details", e.to_detail_string())); - throw e; - } catch (fc::exception &e) { - wlog("${details}", ("details", e.to_detail_string())); - } catch (...) { - wlog("signal handler threw exception"); - } - } } } \ No newline at end of file diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index a7993d40a27..6131f00f701 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -210,6 +210,17 @@ class privileged_api : public context_aware_api { }); } + void set_pbft_parameters_packed( array_ptr packed_pbft_parameters, size_t datalen) { + datastream ds( packed_pbft_parameters, datalen ); + chain::chain_config3 cfg; + fc::raw::unpack(ds, cfg); + cfg.validate(); + context.db.modify( context.control.get_pbft_properties(), + [&]( auto& gpp ) { + gpp.configuration = cfg; + }); + } + // *bos begin* void set_name_list_packed(int64_t list, int64_t action, array_ptr packed_name_list, size_t datalen) { diff --git a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp index 81935707abe..9a3212a56fd 100644 --- a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp +++ b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp @@ -80,6 +80,9 @@ namespace eosio { namespace chain { namespace plugin_interface { using checkpoint_channel = channel_decl; } + + using committed_transition_channel = channel_decl; + using prepared_transition_channel = channel_decl; } } } } diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 581bcb80443..c720b348e10 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -740,7 +740,7 @@ void chain_plugin::plugin_initialize(const variables_map& options) { ilog("include pbft controller..."); my->pbft_ctrl.emplace(*my->chain); - // set up method providers + // set up method providers my->get_block_by_number_provider = app().get_method().register_provider( [this]( uint32_t block_num ) -> signed_block_ptr { return my->chain->fetch_block_by_number( block_num ); @@ -825,27 +825,27 @@ void chain_plugin::plugin_initialize(const variables_map& options) { my->on_pbft_incoming_checkpoint(cp); }); - my->pbft_outgoing_prepare_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_prepare.connect( + my->pbft_outgoing_prepare_connection = my->pbft_ctrl->state_machine.pbft_outgoing_prepare.connect( [this]( const pbft_prepare_ptr& prepare ) { my->pbft_outgoing_prepare_channel.publish( prepare ); }); - my->pbft_outgoing_commit_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_commit.connect( + my->pbft_outgoing_commit_connection = my->pbft_ctrl->state_machine.pbft_outgoing_commit.connect( [this]( const pbft_commit_ptr& commit ) { my->pbft_outgoing_commit_channel.publish( commit ); }); - my->pbft_outgoing_view_change_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_view_change.connect( + my->pbft_outgoing_view_change_connection = my->pbft_ctrl->state_machine.pbft_outgoing_view_change.connect( [this]( const pbft_view_change_ptr& view_change ) { my->pbft_outgoing_view_change_channel.publish( view_change ); }); - my->pbft_outgoing_new_view_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_new_view.connect( + my->pbft_outgoing_new_view_connection = my->pbft_ctrl->state_machine.pbft_outgoing_new_view.connect( [this]( const pbft_new_view_ptr& new_view ) { my->pbft_outgoing_new_view_channel.publish( new_view ); }); - my->pbft_outgoing_checkpoint_connection = my->pbft_ctrl->pbft_db.pbft_outgoing_checkpoint.connect( + my->pbft_outgoing_checkpoint_connection = my->pbft_ctrl->state_machine.pbft_outgoing_checkpoint.connect( [this]( const pbft_checkpoint_ptr& checkpoint ) { my->pbft_outgoing_checkpoint_channel.publish( checkpoint ); }); @@ -1209,8 +1209,8 @@ read_only::get_info_results read_only::get_info(const read_only::get_info_params db.fork_db_head_block_id(), db.fork_db_head_block_time(), db.fork_db_head_block_producer(), - pbft_ctrl.state_machine->get_current_view(), - pbft_ctrl.state_machine->get_target_view(), + pbft_ctrl.state_machine.get_current_view(), + pbft_ctrl.state_machine.get_target_view(), db.last_stable_checkpoint_block_num(), rm.get_virtual_block_cpu_limit(), rm.get_virtual_block_net_limit(), diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 529bd3ed900..31fdeec6dd1 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -153,13 +153,11 @@ namespace eosio { unique_ptr transaction_check; unique_ptr keepalive_timer; unique_ptr pbft_message_cache_timer; - unique_ptr connection_monitor_timer; boost::asio::steady_timer::duration connector_period; boost::asio::steady_timer::duration txn_exp_period; boost::asio::steady_timer::duration resp_expected_period; boost::asio::steady_timer::duration keepalive_interval{std::chrono::seconds{32}}; boost::asio::steady_timer::duration pbft_message_cache_tick_interval{std::chrono::seconds{10}}; - boost::asio::steady_timer::duration connection_monitor_tick_interval{std::chrono::seconds{2}}; int max_cleanup_time_ms = 0; const std::chrono::system_clock::duration peer_authentication_interval{std::chrono::seconds{1}}; ///< Peer clock may be no more than 1 second skewed from our clock, including network latency. @@ -246,16 +244,14 @@ namespace eosio { void handle_message( connection_ptr c, const response_p2p_message &msg); //pbft messages - bool maybe_add_to_pbft_cache(const string &key); + bool maybe_add_to_pbft_cache(const string& key); void clean_expired_pbft_messages(); template - bool is_pbft_msg_outdated(M const & msg); + bool is_pbft_msg_outdated(const M& msg); template - bool is_pbft_msg_valid(M const & msg); + bool is_pbft_msg_valid(const M& msg); - void bcast_pbft_msg(const net_message &msg, int ttl); - - void forward_pbft_msg(const connection_ptr& c, const net_message &msg, int ttl); + void bcast_pbft_msg(const net_message& msg, int ttl, const connection_ptr& c = nullptr); void pbft_outgoing_prepare(const pbft_prepare_ptr& prepare); void pbft_outgoing_commit(const pbft_commit_ptr& commit); @@ -263,14 +259,14 @@ namespace eosio { void pbft_outgoing_new_view(const pbft_new_view_ptr& new_view); void pbft_outgoing_checkpoint(const pbft_checkpoint_ptr& checkpoint); - void handle_message( const connection_ptr& c, const pbft_prepare &msg); - void handle_message( const connection_ptr& c, const pbft_commit &msg); - void handle_message( const connection_ptr& c, const pbft_view_change &msg); - void handle_message( const connection_ptr& c, const pbft_new_view &msg); - void handle_message( const connection_ptr& c, const pbft_checkpoint &msg); - void handle_message( const connection_ptr& c, const pbft_stable_checkpoint &msg); - void handle_message( const connection_ptr& c, const checkpoint_request_message &msg); - void handle_message( const connection_ptr& c, const compressed_pbft_message &msg); + void handle_message( const connection_ptr& c, const pbft_prepare& msg); + void handle_message( const connection_ptr& c, const pbft_commit& msg); + void handle_message( const connection_ptr& c, const pbft_view_change& msg); + void handle_message( const connection_ptr& c, const pbft_new_view& msg); + void handle_message( const connection_ptr& c, const pbft_checkpoint& msg); + void handle_message( const connection_ptr& c, const pbft_stable_checkpoint& msg); + void handle_message( const connection_ptr& c, const checkpoint_request_message& msg); + void handle_message( const connection_ptr& c, const compressed_pbft_message& msg); void start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection); void start_txn_timer(); @@ -281,7 +277,6 @@ namespace eosio { void connection_monitor(std::weak_ptr from_connection); void pbft_message_cache_ticker(); - void connection_monitor_ticker(); /** \name Peer Timestamps * Time message handling * @{ @@ -590,7 +585,6 @@ namespace eosio { std::shared_ptr> message; fc::time_point_sec deadline; }; - const int OUT_QUEUE_SIZE_LIMIT_FROM_WRITE_QUEUE = 100; const int OUT_QUEUE_SIZE_LIMIT = 200; deque pbft_queue; @@ -703,7 +697,7 @@ namespace eosio { std::function callback, bool to_sync_queue = false); void do_queue_write(); - void fill_out_buffer_with_pbft_queue(std::vector &bufs); + void fill_out_buffer_with_pbft_queue(std::vector& bufs); void send_p2p_request(bool discoverable); void send_p2p_response(bool discoverable,string p2p_peer_list); @@ -814,7 +808,6 @@ namespace eosio { void recv_handshake(const connection_ptr& c, const handshake_message& msg); void recv_notice(const connection_ptr& c, const notice_message& msg); bool is_syncing(); - void set_in_sync(); void sync_stable_checkpoints(const connection_ptr& c, uint32_t target); }; @@ -1152,16 +1145,15 @@ namespace eosio { }); } - void connection::fill_out_buffer_with_pbft_queue(std::vector &bufs){ + void connection::fill_out_buffer_with_pbft_queue(std::vector& bufs){ //delete timeout pbft message auto now = time_point::now(); - int drop_pbft_count = 0; - while (pbft_queue.size()>0) { - if (pbft_queue.front().deadline <= now) { - pbft_queue.pop_front(); - ++drop_pbft_count; + auto itr = pbft_queue.begin(); + while (itr != pbft_queue.end()) { + if (itr->deadline <= now) { + itr = pbft_queue.erase(itr); } else { - break; + ++itr; } } @@ -1399,7 +1391,7 @@ namespace eosio { return false; } return true; - } + } bool connection::add_peer_block(const peer_block_state& entry) { auto bptr = blk_state.get().find(entry.id); @@ -1486,10 +1478,6 @@ namespace eosio { return state != in_sync; } - void sync_manager::set_in_sync() { - set_state(in_sync); - } - void sync_manager::request_next_chunk( const connection_ptr& conn ) { uint32_t head_block = chain_plug->chain().fork_db_head_block_num(); @@ -1609,16 +1597,22 @@ namespace eosio { void sync_manager::sync_stable_checkpoints(const connection_ptr& c, uint32_t target) { controller& cc = chain_plug->chain(); uint32_t lscb_num = cc.last_stable_checkpoint_block_num(); - if (last_req_scp_num < lscb_num || last_req_scp_num == 0 || last_req_scp_num >= target) last_req_scp_num = lscb_num; + auto head_num = cc.head_block_num(); + if (last_req_scp_num < lscb_num + || last_req_scp_num == 0 + || last_req_scp_num > target) last_req_scp_num = lscb_num; + + auto pbft_checkpoint_granularity = chain_plug->pbft_ctrl().pbft_db.get_checkpoint_interval(); auto end = target; auto max_target_scp_num = last_req_scp_num + pbft_checkpoint_granularity * 10; - if (target > max_target_scp_num) end = max_target_scp_num; + if (target > max_target_scp_num) end = std::min(max_target_scp_num, head_num); + if (end - last_req_scp_num < pbft_checkpoint_granularity) return; checkpoint_request_message crm = {last_req_scp_num+1,end}; c->enqueue( net_message(crm)); fc_dlog(logger, "request sync stable checkpoints from ${s} to ${e}", - ("s", last_req_scp_num+1)("e", max_target_scp_num)); - last_req_scp_num = max_target_scp_num; + ("s", last_req_scp_num+1)("e", end)); + last_req_scp_num = end; } void sync_manager::reassign_fetch(const connection_ptr& c, go_away_reason reason) { @@ -2837,18 +2831,18 @@ namespace eosio { fc_dlog(logger, "received checkpoint request message ${m}, from ${p}", ("m", msg)("p", c->peer_name())); - if ( msg.end_block - msg.start_block > pbft_checkpoint_granularity * 100) { + if ( msg.end_block - msg.start_block > chain_plug->pbft_ctrl().pbft_db.get_checkpoint_interval() * 100) { fc_dlog(logger, "request range too large"); return; } vector scp_stack; - controller &cc = my_impl->chain_plug->chain(); - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + controller& cc = my_impl->chain_plug->chain(); + pbft_controller& pcc = my_impl->chain_plug->pbft_ctrl(); auto end_block = std::min(msg.end_block, cc.last_stable_checkpoint_block_num()); - for (auto i = end_block; i >= msg.start_block && i>0; --i) { + for (auto i = end_block; i >= msg.start_block && i > 0; --i) { try { auto bid = cc.get_block_id_for_num(i); auto scp = pcc.pbft_db.get_stable_checkpoint_by_id(bid); @@ -3008,21 +3002,11 @@ namespace eosio { && !sync_master->is_syncing(); } - void net_plugin_impl::bcast_pbft_msg(const net_message &msg, int ttl) { - if (sync_master->is_syncing()) return; + void net_plugin_impl::bcast_pbft_msg(const net_message &msg, int ttl, const connection_ptr& c) { +// if (sync_master->is_syncing()) return; auto deadline = time_point_sec(time_point::now()) + ttl; - for (auto &conn: connections) { - if (conn->pbft_ready()) { - conn->enqueue_pbft(encode_pbft_message(msg), deadline); - } - } - } - - void net_plugin_impl::forward_pbft_msg(const connection_ptr& c, const net_message &msg, int ttl) { - auto deadline = time_point_sec(time_point::now()) + ttl; - for (auto &conn: connections) { if (conn != c && conn->pbft_ready()) { conn->enqueue_pbft(encode_pbft_message(msg), deadline); @@ -3031,51 +3015,42 @@ namespace eosio { } void net_plugin_impl::pbft_outgoing_prepare(const pbft_prepare_ptr& msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); - if (!added) return; - - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - - bcast_pbft_msg(*msg, pbft_message_TTL); - fc_dlog( logger, "sent prepare at height: ${n}, view: ${v} ", ("n", msg->block_info.block_num())("v", msg->view)); + if (maybe_add_to_pbft_cache(std::string(msg->sender_signature))) { + bcast_pbft_msg(*msg, pbft_message_TTL); + fc_dlog(logger, "sent prepare at height: ${n}, view: ${v} ", + ("n", msg->block_info.block_num())("v", msg->view)); + } } void net_plugin_impl::pbft_outgoing_commit(const pbft_commit_ptr& msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); - if (!added) return; - - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - - bcast_pbft_msg(*msg, pbft_message_TTL); - fc_dlog( logger, "sent commit at height: ${n}, view: ${v} ", ("n", msg->block_info.block_num())("v", msg->view)); + if (maybe_add_to_pbft_cache(std::string(msg->sender_signature))) { + bcast_pbft_msg(*msg, pbft_message_TTL); + fc_dlog(logger, "sent commit at height: ${n}, view: ${v} ", + ("n", msg->block_info.block_num())("v", msg->view)); + } } void net_plugin_impl::pbft_outgoing_view_change(const pbft_view_change_ptr& msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); - if (!added) return; - - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - - bcast_pbft_msg(*msg, pbft_message_TTL); - fc_dlog( logger, "sent view change {cv: ${cv}, tv: ${tv}}", ("cv", msg->current_view)("tv", msg->target_view)); + if (maybe_add_to_pbft_cache(std::string(msg->sender_signature))) { + bcast_pbft_msg(*msg, pbft_message_TTL); + fc_dlog(logger, "sent view change {cv: ${cv}, tv: ${tv}}", + ("cv", msg->current_view)("tv", msg->target_view)); + } } void net_plugin_impl::pbft_outgoing_new_view(const pbft_new_view_ptr& msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); - if (!added) return; + if (maybe_add_to_pbft_cache(std::string(msg->sender_signature))) { + bcast_pbft_msg(*msg, 60 * pbft_message_TTL); + fc_dlog( logger, "sent new view at view: ${v} ", ("v", msg->new_view)); + } - bcast_pbft_msg(*msg, INT_MAX); - fc_dlog( logger, "sent new view at view: ${v} ", ("v", msg->new_view)); } void net_plugin_impl::pbft_outgoing_checkpoint(const pbft_checkpoint_ptr& msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg->sender_signature)); - if (!added) return; - - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - - bcast_pbft_msg(*msg, pbft_message_TTL); - fc_dlog( logger, "sent checkpoint at height: ${n} ", ("n", msg->block_info.block_num())); + if (maybe_add_to_pbft_cache(std::string(msg->sender_signature))) { + bcast_pbft_msg(*msg, pbft_message_TTL); + fc_dlog(logger, "sent checkpoint at height: ${n} ", ("n", msg->block_info.block_num())); + } } bool net_plugin_impl::maybe_add_to_pbft_cache(const string &key){ @@ -3103,99 +3078,89 @@ namespace eosio { } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_prepare &msg) { + if (is_pbft_msg_valid(msg) && maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { + auto pmm = pbft_message_metadata(msg, chain_id); - if (!is_pbft_msg_valid(msg)) return; - - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; - - auto pmm = pbft_message_metadata(std::move(msg), chain_id); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + if (!pcc.pbft_db.is_valid_prepare(pmm.msg, pmm.sender_key)) return; + bcast_pbft_msg(pmm.msg, pbft_message_TTL, c); + fc_dlog(logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", + ("n", pmm.msg.block_info.block_num())("v", pmm.msg.view)("k", pmm.sender_key)); - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_prepare(pmm.msg, pmm.sender_key)) return; - - forward_pbft_msg(c, pmm.msg, pbft_message_TTL); - fc_dlog( logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", pmm.msg.block_info.block_num())("v", pmm.msg.view)("k", pmm.sender_key)); + pbft_incoming_prepare_channel.publish(std::make_shared>(std::move(pmm))); + } - pbft_incoming_prepare_channel.publish(std::make_shared>(std::move(pmm))); } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_commit &msg) { + if (is_pbft_msg_valid(msg) && maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { + auto pmm = pbft_message_metadata(msg, chain_id); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + if (!pcc.pbft_db.is_valid_commit(pmm.msg, pmm.sender_key)) return; - if (!is_pbft_msg_valid(msg)) return; - - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; - - auto pmm = pbft_message_metadata(std::move(msg), chain_id); - - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_commit(pmm.msg, pmm.sender_key)) return; - - forward_pbft_msg(c, pmm.msg, pbft_message_TTL); - fc_dlog( logger, "received commit at height: ${n}, view: ${v}, from ${k}, ", ("n", pmm.msg.block_info.block_num())("v", pmm.msg.view)("k", pmm.sender_key)); + bcast_pbft_msg(pmm.msg, pbft_message_TTL, c); + fc_dlog(logger, "received commit at height: ${n}, view: ${v}, from ${k}, ", + ("n", pmm.msg.block_info.block_num())("v", pmm.msg.view)("k", pmm.sender_key)); - pbft_incoming_commit_channel.publish(std::make_shared>(std::move(pmm))); + pbft_incoming_commit_channel.publish(std::make_shared>(std::move(pmm))); + } } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_view_change &msg) { + if (is_pbft_msg_valid(msg) && maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { + auto pmm = pbft_message_metadata(msg, chain_id); - if (!is_pbft_msg_valid(msg)) return; - - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + controller &ctrl = my_impl->chain_plug->chain(); + if (!pcc.pbft_db.is_valid_view_change(pmm.msg, pmm.sender_key)) return; - auto pmm = pbft_message_metadata( std::move(msg), chain_id); - - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - controller &ctrl = my_impl->chain_plug->chain(); - if (!pcc.pbft_db.is_valid_view_change(pmm.msg, pmm.sender_key)) return; - - auto missing_blocks = set{}; - for (auto const &b: pmm.msg.prepared_cert.pre_prepares) { - if (!ctrl.fetch_block_by_id(b)) missing_blocks.emplace(b); - } + auto missing_blocks = set{}; + for (auto const &b: pmm.msg.prepared_cert.pre_prepares) { + if (!ctrl.fetch_block_by_id(b)) missing_blocks.emplace(b); + } - if (!missing_blocks.empty()) { - fc_dlog( logger, "requesting ${num} missing blocks from view change", ("num", missing_blocks.size())); - request_message req; - for (auto const &b: missing_blocks) { - req.req_blocks.ids.push_back(b); + if (!missing_blocks.empty()) { + fc_dlog(logger, "requesting ${num} missing blocks from view change", ("num", missing_blocks.size())); + request_message req; + for (auto const &b: missing_blocks) { + req.req_blocks.ids.push_back(b); + } + req.req_trx.mode = normal; + req.req_blocks.mode = normal; + c->enqueue(req); } - req.req_trx.mode = normal; - req.req_blocks.mode = normal; - c->enqueue(req); - } - forward_pbft_msg(c, pmm.msg, pbft_message_TTL); - fc_dlog( logger, "received view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", pmm.msg.current_view)("tv", pmm.msg.target_view)("v", pmm.sender_key)); + bcast_pbft_msg(pmm.msg, pbft_message_TTL, c); + fc_dlog(logger, "received view change {cv: ${cv}, tv: ${tv}} from ${v}", + ("cv", pmm.msg.current_view)("tv", pmm.msg.target_view)("v", pmm.sender_key)); - pbft_incoming_view_change_channel.publish(std::make_shared>(std::move(pmm))); + pbft_incoming_view_change_channel.publish(std::make_shared>(std::move(pmm))); + } } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_new_view &msg) { - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; + if (maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (time_point_sec(time_point::now()) > time_point_sec(msg.common.timestamp) + 60 * pbft_message_TTL - || msg.new_view <= pcc.state_machine->get_current_view()) { - //skip new view messages that are too old or whose target views are lower than mine. - return; - } + if (time_point_sec(time_point::now()) > time_point_sec(msg.common.timestamp) + 60 * pbft_message_TTL + || msg.new_view <= pcc.state_machine.get_current_view()) { + //skip new view messages that are too old or whose target views are lower than mine. + return; + } - auto pmm = pbft_message_metadata(std::move(msg), chain_id); + auto pmm = pbft_message_metadata(msg, chain_id); - if (pmm.sender_key != pcc.pbft_db.get_new_view_primary_key(pmm.msg.new_view)) return; + if (pmm.sender_key != pcc.pbft_db.get_new_view_primary_key(pmm.msg.new_view)) return; - forward_pbft_msg(c, pmm.msg, INT_MAX); - fc_dlog( logger, "received new view: ${n}, from ${v}", ("n", pmm.msg)("v", pmm.sender_key)); + bcast_pbft_msg(pmm.msg, 60 * pbft_message_TTL, c); + fc_dlog(logger, "received new view: ${n}, from ${v}", ("n", pmm.msg)("v", pmm.sender_key)); - pbft_incoming_new_view_channel.publish(std::make_shared>(std::move(pmm))); + pbft_incoming_new_view_channel.publish(std::make_shared>(std::move(pmm))); + } } void net_plugin_impl::handle_message( const connection_ptr& c, const compressed_pbft_message &msg) { @@ -3215,21 +3180,18 @@ namespace eosio { } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_checkpoint &msg) { + if (is_pbft_msg_valid(msg) && maybe_add_to_pbft_cache(std::string(msg.sender_signature))) { + auto pmm = pbft_message_metadata(msg, chain_id); - if (!is_pbft_msg_valid(msg)) return; + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + if (!pcc.pbft_db.is_valid_checkpoint(pmm.msg, pmm.sender_key)) return; - auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); - if (!added) return; + bcast_pbft_msg(pmm.msg, pbft_message_TTL, c); + fc_dlog(logger, "received checkpoint at ${n}, from ${v}", + ("n", pmm.msg.block_info.block_num())("v", pmm.sender_key)); - auto pmm = pbft_message_metadata(std::move(msg), chain_id); - - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_checkpoint(pmm.msg, pmm.sender_key)) return; - - forward_pbft_msg(c, pmm.msg, pbft_message_TTL); - fc_dlog( logger, "received checkpoint at ${n}, from ${v}", ("n", pmm.msg.block_info.block_num())("v", pmm.sender_key)); - - pbft_incoming_checkpoint_channel.publish(std::make_shared>(std::move(pmm))); + pbft_incoming_checkpoint_channel.publish(std::make_shared>(std::move(pmm))); + } } void net_plugin_impl::handle_message( const connection_ptr& c, const pbft_stable_checkpoint &msg) { @@ -3237,7 +3199,8 @@ namespace eosio { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_stable_checkpoint(msg, true)) return; - fc_ilog(logger, "received stable checkpoint at ${n}, from ${v}", ("n", msg.block_info.block_num())("v", c->peer_name())); + fc_ilog(logger, "received stable checkpoint at ${n}, from ${v}", + ("n", msg.block_info.block_num())("v", c->peer_name())); } void net_plugin_impl::start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection) { @@ -3266,87 +3229,17 @@ namespace eosio { }); } - void net_plugin_impl::pbft_message_cache_ticker() { - pbft_message_cache_timer->expires_from_now (pbft_message_cache_tick_interval); - pbft_message_cache_timer->async_wait ([this](boost::system::error_code ec) { - - if ( !ec ) { - clean_expired_pbft_messages(); - } else { - wlog ("pbft message cache ticker error: ${m}", ("m", ec.message())); - pbft_message_cache_ticker(); - } - - }); - } + void net_plugin_impl::pbft_message_cache_ticker() { + pbft_message_cache_timer->expires_from_now (pbft_message_cache_tick_interval); + pbft_message_cache_timer->async_wait ([this](boost::system::error_code ec) { - void net_plugin_impl::connection_monitor_ticker() { - connection_monitor_timer->expires_from_now (connection_monitor_tick_interval); - connection_monitor_timer->async_wait ([this](boost::system::error_code ec) { - connection_monitor_ticker (); - if (ec) { - wlog ("connection monitor ticker error: ${m}", ("m", ec.message())); - } - int total=0; - int current=0; - for(auto &conn: connections){ - if(conn->current()){ - ++current; - } - ++total; - auto is_open = conn->socket && conn->socket->is_open(); -// auto paddr = conn->peer_addr; -// paddr.insert(0, 20 - paddr.length(), ' '); - std::ostringstream ss; - - auto so = is_open?"1":"0"; - auto con = conn->connecting ?"1":"0"; - auto syn = conn->syncing ?"1":"0"; - auto cur = conn->current() ?"1":"0"; - ss << so << con << syn << cur ; - auto status = ss.str(); - - ss.str(""); - ss.clear(); - - ss << std::setfill(' ') << std::setw(22) << conn->peer_addr; - auto paddr = ss.str(); - - ss.str(""); - ss.clear(); - - ss << std::setfill(' ') << std::setw(6) << conn->buffer_queue.write_queue_size(); - auto write_queue = ss.str(); - - ss.str(""); - ss.clear(); - - ss << std::setfill(' ') << std::setw(6) << conn->buffer_queue.out_queue_size(); - auto out_queue = ss.str(); - - ss.str(""); - ss.clear(); - - ss << std::setfill(' ') << std::setw(6) << conn->pbft_queue.size(); - auto pbft_queue = ss.str(); - - auto conn_str = conn->peer_addr; - if(conn_str.empty()) { - try { - conn_str = boost::lexical_cast(conn->socket->remote_endpoint()); - } catch (...) { - - } - } - - dlog("connection: ${conn} \tstatus(socket|connecting|syncing|current): ${status}\t|\twrite_queue: ${write}\t|\tout_queue: ${out}\t|\tpbft_queue: ${pbft}", ("status",status)("conn",conn_str)("write",write_queue)("out",out_queue)("pbft",pbft_queue)); - } - dlog("connections stats: current : ${current}\t total : ${total} ",("current",current)("total",total)); - dlog("================================================================================================"); - auto local_trx_pool_size = local_txns.size(); - fc_dlog(logger, "local trx pool size: ${local_trx_pool_size}",("local_trx_pool_size",local_trx_pool_size)); - fc_dlog(logger, "================================================================================================"); - }); + if ( !ec ) { + clean_expired_pbft_messages(); + } else { + wlog ("pbft message cache ticker error: ${m}", ("m", ec.message())); + pbft_message_cache_ticker(); + } + }); } void net_plugin_impl::ticker() { @@ -3745,9 +3638,7 @@ namespace eosio { my->keepalive_timer.reset( new boost::asio::steady_timer( app().get_io_service())); my->ticker(); my->pbft_message_cache_timer.reset( new boost::asio::steady_timer( app().get_io_service())); - my->connection_monitor_timer.reset( new boost::asio::steady_timer( app().get_io_service())); my->pbft_message_cache_ticker(); -// my->connection_monitor_ticker(); } FC_LOG_AND_RETHROW() } diff --git a/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp b/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp index 69f67ea6cf8..726e4d43591 100644 --- a/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp +++ b/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp @@ -26,15 +26,15 @@ class pbft_plugin : public appbase::plugin { pbft_state get_pbft_record( const block_id_type& bid )const; - vector get_pbft_checkpoints_record(const block_num_type &bnum)const; - pbft_view_change_state get_view_change_record(const pbft_view_type& view)const; + vector get_pbft_checkpoints_record(block_num_type bnum)const; + pbft_view_change_state get_view_change_record(pbft_view_type view)const; vector get_watermarks()const; flat_map get_fork_schedules()const; const char* get_pbft_status()const; block_id_type get_pbft_prepared_id()const; block_id_type get_pbft_my_prepare_id()const; - void set_pbft_current_view(const pbft_view_type &view); + void set_pbft_current_view(pbft_view_type view); private: diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index 0dcc60a5d11..7d27f1607bd 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -3,32 +3,49 @@ #include #include #include +#include namespace eosio { static appbase::abstract_plugin &_pbft_plugin = app().register_plugin(); using namespace std; using namespace eosio::chain; + using namespace eosio::chain::plugin_interface; + using boost::signals2::scoped_connection; + class pbft_plugin_impl { public: + pbft_plugin_impl() + :transit_to_committed_channel(app().get_channel()) + ,transit_to_prepared_channel(app().get_channel()) + {} + unique_ptr prepare_timer; unique_ptr commit_timer; unique_ptr view_change_timer; unique_ptr checkpoint_timer; - boost::asio::steady_timer::duration prepare_timeout{std::chrono::milliseconds{1000}}; - boost::asio::steady_timer::duration commit_timeout{std::chrono::milliseconds{1000}}; + boost::asio::steady_timer::duration prepare_timeout{std::chrono::milliseconds{750}}; + boost::asio::steady_timer::duration commit_timeout{std::chrono::milliseconds{750}}; boost::asio::steady_timer::duration view_change_check_interval{std::chrono::seconds{5}}; - boost::asio::steady_timer::duration checkpoint_timeout{std::chrono::seconds{50}}; + boost::asio::steady_timer::duration checkpoint_timeout{std::chrono::seconds{25}}; void prepare_timer_tick(); - void commit_timer_tick(); - void view_change_timer_tick(); - void checkpoint_timer_tick(); + fc::optional pbft_transit_to_committed_connection; + pbft::committed_transition_channel::channel_type::handle transit_to_committed_subscription; + pbft::committed_transition_channel::channel_type& transit_to_committed_channel; + + fc::optional pbft_transit_to_prepared_connection; + pbft::prepared_transition_channel::channel_type::handle transit_to_prepared_subscription; + pbft::prepared_transition_channel::channel_type& transit_to_prepared_channel; + + void on_committed_transition(); + void on_prepared_transition(); + private: bool upgraded = false; bool is_replaying(); @@ -36,109 +53,48 @@ namespace eosio { bool pbft_ready(); }; - pbft_plugin::pbft_plugin() : my(new pbft_plugin_impl()) {} - - pbft_plugin::~pbft_plugin() = default; - - void pbft_plugin::set_program_options(options_description &, options_description &cfg) { + void pbft_plugin_impl::on_committed_transition() { + prepare_timer_tick(); } - void pbft_plugin::plugin_initialize(const variables_map &options) { - ilog("Initialize pbft plugin"); - my->prepare_timer = std::make_unique(app().get_io_service()); - my->commit_timer = std::make_unique(app().get_io_service()); - my->view_change_timer = std::make_unique(app().get_io_service()); - my->checkpoint_timer = std::make_unique(app().get_io_service()); - } - - void pbft_plugin::plugin_startup() { - my->prepare_timer_tick(); - my->commit_timer_tick(); - my->view_change_timer_tick(); - my->checkpoint_timer_tick(); - } - - void pbft_plugin::plugin_shutdown() {} - - pbft_state pbft_plugin::get_pbft_record( const block_id_type& bid ) const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - auto record = pbft_ctrl.pbft_db.get_pbft_state_by_id(bid); - if (record) return *record; - return pbft_state(); - } - - vector pbft_plugin::get_pbft_checkpoints_record(const block_num_type &bnum) const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - auto records = pbft_ctrl.pbft_db.get_checkpoints_by_num(bnum); - if (!records.empty()) return records; - return vector(); - } - pbft_view_change_state pbft_plugin::get_view_change_record(const pbft_view_type& view) const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - auto record = pbft_ctrl.pbft_db.get_view_changes_by_target_view(view); - if (record) return *record; - return pbft_view_change_state(); - } - - vector pbft_plugin::get_watermarks() const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - return pbft_ctrl.pbft_db.get_pbft_watermarks(); - } - - flat_map pbft_plugin::get_fork_schedules() const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - return pbft_ctrl.pbft_db.get_pbft_fork_schedules(); - } - - const char* pbft_plugin::get_pbft_status() const { - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - return pbft_ctrl.state_machine->get_current()->get_name(); - } - - block_id_type pbft_plugin::get_pbft_prepared_id() const { - auto& ctrl = app().get_plugin().chain(); - return ctrl.get_pbft_prepared(); - } - - block_id_type pbft_plugin::get_pbft_my_prepare_id() const { - auto& ctrl = app().get_plugin().chain(); - return ctrl.get_pbft_my_prepare(); - } - - void pbft_plugin::set_pbft_current_view(const pbft_view_type& view) { - //this is used to boost the recovery from a disaster, do not set this unless you have to do so. - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - pbft_ctrl.state_machine->manually_set_current_view(view); + void pbft_plugin_impl::on_prepared_transition() { + commit_timer_tick(); } void pbft_plugin_impl::prepare_timer_tick() { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + prepare_timer->expires_from_now(prepare_timeout); prepare_timer->async_wait([&](boost::system::error_code ec) { - prepare_timer_tick(); - if (ec) { + if ( ec == boost::asio::error::operation_aborted ) { + return; + } else if (ec) { wlog ("pbft plugin prepare timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { + chain::pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_prepare(); } + prepare_timer_tick(); }); } void pbft_plugin_impl::commit_timer_tick() { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + commit_timer->expires_from_now(commit_timeout); commit_timer->async_wait([&](boost::system::error_code ec) { - commit_timer_tick(); - if (ec) { + if ( ec == boost::asio::error::operation_aborted ) { + return; + } else if (ec) { wlog ("pbft plugin commit timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { + chain::pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_commit(); } + commit_timer_tick(); }); } void pbft_plugin_impl::view_change_timer_tick() { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + try { view_change_timer->cancel(); } catch (boost::system::system_error &e) { @@ -150,27 +106,31 @@ namespace eosio { if (ec) { wlog ("pbft plugin view change timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { + chain::pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_view_change(); } }); } void pbft_plugin_impl::checkpoint_timer_tick() { - chain::pbft_controller &pbft_ctrl = app().get_plugin().pbft_ctrl(); + checkpoint_timer->expires_from_now(checkpoint_timeout); checkpoint_timer->async_wait([&](boost::system::error_code ec) { - checkpoint_timer_tick(); - if (ec) { + if ( ec == boost::asio::error::operation_aborted ) { + return; + } if (ec) { wlog ("pbft plugin checkpoint timer tick error: ${m}", ("m", ec.message())); } else if (pbft_ready()) { + chain::pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); pbft_ctrl.maybe_pbft_checkpoint(); - chain::controller &ctrl = app().get_plugin().chain(); - if ( ctrl.head_block_num() - ctrl.last_stable_checkpoint_block_num() / pbft_checkpoint_granularity > 1) { - //perhaps we need to sync stable checkpoints from other peers - app().get_plugin().maybe_sync_stable_checkpoints(); - } + chain::controller& ctrl = app().get_plugin().chain(); + if ( ctrl.head_block_num() - ctrl.last_stable_checkpoint_block_num() / pbft_ctrl.pbft_db.get_checkpoint_interval() > 1) { + //perhaps we need to sync stable checkpoints from other peers + app().get_plugin().maybe_sync_stable_checkpoints(); + } } + checkpoint_timer_tick(); }); } @@ -204,4 +164,87 @@ namespace eosio { return enabled && !is_syncing() && !is_replaying(); } + + pbft_plugin::pbft_plugin() : my(new pbft_plugin_impl()) {} + + pbft_plugin::~pbft_plugin() = default; + + void pbft_plugin::set_program_options(options_description &, options_description &cfg) { + } + + void pbft_plugin::plugin_initialize(const variables_map &options) { + ilog("Initialize pbft plugin"); + my->prepare_timer = std::make_unique(app().get_io_service()); + my->commit_timer = std::make_unique(app().get_io_service()); + my->view_change_timer = std::make_unique(app().get_io_service()); + my->checkpoint_timer = std::make_unique(app().get_io_service()); + } + + void pbft_plugin::plugin_startup() { + my->prepare_timer_tick(); + my->commit_timer_tick(); + my->view_change_timer_tick(); + my->checkpoint_timer_tick(); + + my->pbft_transit_to_prepared_connection = app().get_plugin().pbft_ctrl().state_machine.pbft_transit_to_prepared.connect( [this]( bool prepared ) { + my->on_prepared_transition(); + }); + + my->pbft_transit_to_committed_connection = app().get_plugin().pbft_ctrl().state_machine.pbft_transit_to_committed.connect( [this]( bool committed ) { + my->on_committed_transition(); + }); + } + + void pbft_plugin::plugin_shutdown() {} + + pbft_state pbft_plugin::get_pbft_record( const block_id_type& bid ) const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto record = pbft_ctrl.pbft_db.get_pbft_state_by_id(bid); + if (record) return *record; + return pbft_state(); + } + + vector pbft_plugin::get_pbft_checkpoints_record(block_num_type bnum) const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto records = pbft_ctrl.pbft_db.get_checkpoints_by_num(bnum); + if (!records.empty()) return records; + return vector(); + } + pbft_view_change_state pbft_plugin::get_view_change_record(pbft_view_type view) const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto record = pbft_ctrl.pbft_db.get_view_changes_by_target_view(view); + if (record) return *record; + return pbft_view_change_state(); + } + + vector pbft_plugin::get_watermarks() const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + return pbft_ctrl.pbft_db.get_pbft_watermarks(); + } + + flat_map pbft_plugin::get_fork_schedules() const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + return pbft_ctrl.pbft_db.get_pbft_fork_schedules(); + } + + const char* pbft_plugin::get_pbft_status() const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + return pbft_ctrl.state_machine.get_current()->get_name(); + } + + block_id_type pbft_plugin::get_pbft_prepared_id() const { + auto& ctrl = app().get_plugin().chain(); + return ctrl.get_pbft_prepared(); + } + + block_id_type pbft_plugin::get_pbft_my_prepare_id() const { + auto& ctrl = app().get_plugin().chain(); + return ctrl.get_pbft_my_prepare(); + } + + void pbft_plugin::set_pbft_current_view(pbft_view_type view) { + //this is used to boost the recovery from a disaster, do not set this unless you have to do so. + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + pbft_ctrl.state_machine.manually_set_current_view(view); + } } diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index f2d75c5a6e8..ff47933e765 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -209,13 +209,13 @@ BOOST_AUTO_TEST_CASE(view_change_validation) { BOOST_CHECK_EQUAL(ctrl.head_block_num(), 102); - for(int i = 0; i< pbft_ctrl.view_change_timeout; i++){ + for(int i = 0; i< pbft_ctrl.pbft_db.get_view_change_timeout(); i++){ pbft_ctrl.maybe_pbft_view_change(); } - pbft_ctrl.state_machine->do_send_view_change(); + pbft_ctrl.state_machine.do_send_view_change(); auto new_view = pbft_ctrl.pbft_db.get_proposed_new_view_num(); auto vcc = pbft_ctrl.pbft_db.generate_view_changed_certificate(new_view); - auto nv_msg = pbft_ctrl.pbft_db.send_pbft_new_view(vcc, new_view); + auto nv_msg = pbft_ctrl.pbft_db.generate_pbft_new_view(vcc, new_view); bool nv_flag; try { @@ -302,19 +302,19 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.last_irreversible_block_num(), 101); //generate new view with short fork prepare certificate - pbft_new_view_generator.state_machine->set_prepares_cache(pbft_prepare()); + pbft_new_view_generator.state_machine.set_prepare_cache(pbft_prepare()); BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_send_pbft_msg(), true); ctrl_new_view_generator.reset_pbft_my_prepare(); pbft_new_view_generator.maybe_pbft_prepare(); BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_prepared(), true); BOOST_CHECK_EQUAL(ctrl_new_view_generator.head_block_num(), 136); - for(int i = 0; ido_send_view_change(); + pbft_new_view_generator.state_machine.do_send_view_change(); auto new_view = pbft_new_view_generator.pbft_db.get_proposed_new_view_num(); auto vcc = pbft_new_view_generator.pbft_db.generate_view_changed_certificate(new_view); - auto nv_msg = pbft_new_view_generator.pbft_db.send_pbft_new_view( + auto nv_msg = pbft_new_view_generator.pbft_db.generate_pbft_new_view( vcc, new_view); @@ -393,7 +393,7 @@ BOOST_AUTO_TEST_CASE(new_view_with_committed_cert_call_two_times_maybe_switch_fo c1.produce_blocks(6); new_view_generator.produce_blocks(10); - c1_pbft_controller.state_machine->set_prepares_cache(pbft_prepare()); + c1_pbft_controller.state_machine.set_prepare_cache(pbft_prepare()); c1_ctrl.reset_pbft_my_prepare(); c1_pbft_controller.maybe_pbft_prepare(); c1.produce_block(); @@ -410,7 +410,7 @@ BOOST_AUTO_TEST_CASE(new_view_with_committed_cert_call_two_times_maybe_switch_fo //generate new view with long fork commit certificate - pbft_new_view_generator.state_machine->set_prepares_cache(pbft_prepare()); + pbft_new_view_generator.state_machine.set_prepare_cache(pbft_prepare()); BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_send_pbft_msg(), true); ctrl_new_view_generator.reset_pbft_my_prepare(); pbft_new_view_generator.maybe_pbft_prepare(); @@ -424,24 +424,22 @@ BOOST_AUTO_TEST_CASE(new_view_with_committed_cert_call_two_times_maybe_switch_fo new_view_generator.produce_block(); BOOST_CHECK_EQUAL(ctrl_new_view_generator.last_irreversible_block_num(), 137); - for(int i = 0; ido_send_view_change(); + pbft_new_view_generator.state_machine.do_send_view_change(); auto new_view = pbft_new_view_generator.pbft_db.get_proposed_new_view_num(); auto vcc = pbft_new_view_generator.pbft_db.generate_view_changed_certificate(new_view); - auto nv_msg = pbft_new_view_generator.pbft_db.send_pbft_new_view(vcc, new_view); + auto nv_msg = pbft_new_view_generator.pbft_db.generate_pbft_new_view(vcc, new_view); //can switch fork after apply prepare certificate in new view auto pmm = pbft_message_metadata(nv_msg, c1_pbft_controller.pbft_db.get_chain_id()); - /// boscore issue https://github.com/boscore/bos/issues/114. - /// It will never throw exception block_validate_exception, "next block must be in the future" in the version 20e08dba c1_pbft_controller.on_pbft_new_view(std::make_shared>(pmm)); c1_pbft_controller.maybe_pbft_commit(); c1.produce_blocks(2); BOOST_CHECK_EQUAL(c1_ctrl.last_irreversible_block_num(), 137); - // make sure commited block same with new view generator lib block + // make sure committed block same with new view generator lib block BOOST_CHECK_EQUAL(c1_ctrl.fetch_block_by_number(137)->id(), ctrl_new_view_generator.fetch_block_by_number(137)->id()); } @@ -542,28 +540,33 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { push_blocks(c2, c1); /// make c1 lib 98 c1_pbft_controller.maybe_pbft_prepare(); - pbft_prepare c2_prepare_ = c2_pbft_controller.state_machine->get_prepares_cache(); + pbft_prepare c2_prepare_ = c2_pbft_controller.state_machine.get_prepare_cache(); BOOST_CHECK_EQUAL(c2_prepare_.block_info.block_num(), 98); - c1_pbft_controller.state_machine->on_prepare(std::make_shared>(c2_prepare_, c2_pbft_controller.pbft_db.get_chain_id())); + c1_pbft_controller.state_machine.on_prepare(std::make_shared>(c2_prepare_, c2_pbft_controller.pbft_db.get_chain_id())); c1_pbft_controller.maybe_pbft_commit(); - pbft_commit c2_commit_ = c2_pbft_controller.state_machine->get_commits_cache(); - c1_pbft_controller.state_machine->on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); + pbft_commit c2_commit_ = c2_pbft_controller.state_machine.get_commit_cache(); + c1_pbft_controller.state_machine.on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); + auto c1_my_prepare_block = c1_ctrl.get_pbft_my_prepare(); c1.produce_block(); c1_pbft_controller.maybe_pbft_commit(); BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 98); +// c1_ctrl.set_pbft_my_prepare(c1_ctrl.get_block_id_for_num(99)); c2_pbft_controller.maybe_pbft_commit(); /// make c3_final lib 98 c3_final_pbft_controller.maybe_pbft_prepare(); - pbft_prepare c1_prepare_ = c1_pbft_controller.state_machine->get_prepares_cache(); - BOOST_CHECK_EQUAL(c1_prepare_.block_info.block_num(), 99); - c3_final_pbft_controller.state_machine->on_prepare(std::make_shared>(c1_prepare_, c1_pbft_controller.pbft_db.get_chain_id())); + pbft_prepare c1_prepare_ = c1_pbft_controller.state_machine.get_prepare_cache(); + + auto forks = c1_ctrl.fork_db().fetch_branch_from(c1_prepare_.block_info.block_id, c1_my_prepare_block); + BOOST_CHECK_EQUAL(forks.first.size() >= 1 && forks.second.size() == 1, true); + c3_final.produce_block(); + c3_final_pbft_controller.state_machine.on_prepare(std::make_shared>(c1_prepare_, c1_pbft_controller.pbft_db.get_chain_id())); c3_final_pbft_controller.maybe_pbft_commit(); - pbft_commit c1_commit_ = c1_pbft_controller.state_machine->get_commits_cache(); - c3_final_pbft_controller.state_machine->on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); + pbft_commit c1_commit_ = c1_pbft_controller.state_machine.get_commit_cache(); + c3_final_pbft_controller.state_machine.on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); c3_final.produce_block(); c3_final_pbft_controller.maybe_pbft_commit(); BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 98); @@ -572,36 +575,36 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { push_blocks(c2, c2_prime); pbft_prepare c1_prepare; - c1_prepare_ = c1_pbft_controller.state_machine->get_prepares_cache(); + c1_prepare_ = c1_pbft_controller.state_machine.get_prepare_cache(); c1_prepare = c1_prepare_; /// for set pbft commit cache to 99 c2.produce_block(); c2_pbft_controller.maybe_pbft_prepare(); - c2_prepare_ = c2_pbft_controller.state_machine->get_prepares_cache(); + c2_prepare_ = c2_pbft_controller.state_machine.get_prepare_cache(); BOOST_CHECK_EQUAL(c2_prepare_.block_info.block_num(), 99); c2_pbft_controller.maybe_pbft_commit(); c2.produce_block(); c2_pbft_controller.maybe_pbft_commit(); - c2_commit_ = c2_pbft_controller.state_machine->get_commits_cache(); + c2_commit_ = c2_pbft_controller.state_machine.get_commit_cache(); BOOST_CHECK_EQUAL(c2_commit_.block_info.block_num(), 99); BOOST_CHECK_EQUAL(c2.control->last_irreversible_block_num(), 99); push_blocks(c2, c1); c1_pbft_controller.maybe_pbft_prepare(); - c2_prepare_ = c2_pbft_controller.state_machine->get_prepares_cache(); - c1_pbft_controller.state_machine->on_prepare(std::make_shared>(c2_prepare_, c2_pbft_controller.pbft_db.get_chain_id())); + c2_prepare_ = c2_pbft_controller.state_machine.get_prepare_cache(); + c1_pbft_controller.state_machine.on_prepare(std::make_shared>(c2_prepare_, c2_pbft_controller.pbft_db.get_chain_id())); c1_pbft_controller.maybe_pbft_commit(); - c2_commit_ = c2_pbft_controller.state_machine->get_commits_cache(); - c1_pbft_controller.state_machine->on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); + c2_commit_ = c2_pbft_controller.state_machine.get_commit_cache(); + c1_pbft_controller.state_machine.on_commit(std::make_shared>(c2_commit_, c2_pbft_controller.pbft_db.get_chain_id())); c1.produce_block(); c1_pbft_controller.maybe_pbft_commit(); - c1_prepare_ = c1_pbft_controller.state_machine->get_prepares_cache(); - c1_commit_ = c1_pbft_controller.state_machine->get_commits_cache(); - BOOST_CHECK_EQUAL(c1_commit_.block_info.block_num(), 99); + c1_prepare_ = c1_pbft_controller.state_machine.get_prepare_cache(); + c1_commit_ = c1_pbft_controller.state_machine.get_commit_cache(); + BOOST_CHECK_EQUAL(c1_commit_.block_info.block_num(), 100); BOOST_CHECK_EQUAL(c1.control->last_irreversible_block_num(), 99); c3_final_pbft_controller.maybe_pbft_prepare(); @@ -609,25 +612,26 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { c3_final.produce_block(); c3_final.produce_block(); - BOOST_CHECK_EQUAL(c1_prepare.block_info.block_num(), 99); - /// set c3 my preprare at 100 - c3_final_ctrl.set_pbft_my_prepare(c3_final_ctrl.get_block_id_for_num(100)); - c3_final_pbft_controller.state_machine->on_prepare(std::make_shared>(c1_prepare, c1_pbft_controller.pbft_db.get_chain_id())); + BOOST_CHECK_EQUAL(c1_prepare.block_info.block_num(), 100); + /// set c3 my prepare at 101 + c3_final_ctrl.set_pbft_my_prepare(c3_final_ctrl.get_block_id_for_num(101)); + c3_final_pbft_controller.state_machine.on_prepare(std::make_shared>(c1_prepare, c1_pbft_controller.pbft_db.get_chain_id())); - pbft_prepare c3_final_prepare = c3_final_pbft_controller.state_machine->get_prepares_cache(); - // check c3 prepare at 99 - BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 99); - curr_state = c3_final_pbft_controller.state_machine->get_current()->get_name(); + pbft_prepare c3_final_prepare = c3_final_pbft_controller.state_machine.get_prepare_cache(); + // check c3 prepare at 101 + BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 101); + curr_state = c3_final_pbft_controller.state_machine.get_current()->get_name(); BOOST_CHECK_EQUAL(curr_state, "{==== PREPARED ====}"); c3_final_pbft_controller.maybe_pbft_commit(); + c2_prime.produce_block(); c2_prime.create_accounts({N(tester1)}); - c2_prime.produce_blocks(5); + c2_prime.produce_blocks(6); //push fork to c3_final - for(int i = 100; i <= 104; i++) { + for(int i = 101; i <= 106; i++) { auto fb = c2_prime.control->fetch_block_by_number(i); c3_final.push_block(fb); } @@ -640,23 +644,23 @@ BOOST_AUTO_TEST_CASE(switch_fork_reserve_prepare) { BOOST_CHECK_EQUAL(tmp_c2_prime_prepared_fork->pbft_my_prepare, true); BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 98); - BOOST_CHECK_EQUAL(c3_final.control->head_block_num(), 104); + BOOST_CHECK_EQUAL(c3_final.control->head_block_num(), 106); c3_final_pbft_controller.maybe_pbft_commit(); c3_final.produce_block(); - pbft_commit c3_final_commit = c3_final_pbft_controller.state_machine->get_commits_cache(); + pbft_commit c3_final_commit = c3_final_pbft_controller.state_machine.get_commit_cache(); /// on commit will prepare next block immediately will trigger reserve prepare - c3_final_pbft_controller.state_machine->on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); + c3_final_pbft_controller.state_machine.on_commit(std::make_shared>(c1_commit_, c1_pbft_controller.pbft_db.get_chain_id())); // for sync c3_final.produce_block(); c3_final_pbft_controller.maybe_pbft_commit(); - curr_state = c3_final_pbft_controller.state_machine->get_current()->get_name(); + curr_state = c3_final_pbft_controller.state_machine.get_current()->get_name(); BOOST_CHECK_EQUAL(curr_state, "{==== COMMITTED ====}"); - BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 99); + BOOST_CHECK_EQUAL(c3_final.control->last_irreversible_block_num(), 100); c3_final_pbft_controller.maybe_pbft_prepare(); - c3_final_prepare = c3_final_pbft_controller.state_machine->get_prepares_cache(); - BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 100); + c3_final_prepare = c3_final_pbft_controller.state_machine.get_prepare_cache(); + BOOST_CHECK_EQUAL(c3_final_prepare.block_info.block_num(), 101); } From 08ec703be2f4fe2960bf1d5d03bcd2f416202725 Mon Sep 17 00:00:00 2001 From: thaipandada Date: Wed, 21 Aug 2019 09:49:45 +0800 Subject: [PATCH 19/37] update version info --- CMakeLists.txt | 2 +- Docker/README.md | 4 ++-- README.md | 2 +- README_CN.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 696bd5361f0..2276554450b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,7 @@ set( CXX_STANDARD_REQUIRED ON) set(VERSION_MAJOR 3) set(VERSION_MINOR 0) -set(VERSION_PATCH 1) +set(VERSION_PATCH 2) if(VERSION_SUFFIX) set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}") diff --git a/Docker/README.md b/Docker/README.md index 57d456fe78e..c06694deffb 100644 --- a/Docker/README.md +++ b/Docker/README.md @@ -20,10 +20,10 @@ cd bos/Docker docker build . -t boscore/bos -s BOS ``` -The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v3.0.1 tag, you could do the following: +The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v3.0.2 tag, you could do the following: ```bash -docker build -t boscore/bos:v3.0.1 --build-arg branch=v3.0.1 . +docker build -t boscore/bos:v3.0.2 --build-arg branch=v3.0.2 . ``` diff --git a/README.md b/README.md index 711835c591f..334f7cad8e0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # BOSCore - Born for DApps. Born for Usability. -## BOSCore Version: v3.0.1 +## BOSCore Version: v3.0.2 ### Basic EOSIO Version: v1.6.6 (support REX) # Background diff --git a/README_CN.md b/README_CN.md index ade0d3715a1..f7b893a12f7 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,6 +1,6 @@ # BOSCore - 更可用的链,为DApp而生。 -## BOSCore Version: v3.0.1 +## BOSCore Version: v3.0.2 ### Basic EOSIO Version: v1.6.6 (support REX) # 背景 From 2680d27f882d13770a85a8ef5ede2197be04f5cc Mon Sep 17 00:00:00 2001 From: thaipandada Date: Wed, 21 Aug 2019 13:38:32 +0800 Subject: [PATCH 20/37] fix issues 111 --- Docker/Dockerfile | 11 ++++++----- eosio_build.sh | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Docker/Dockerfile b/Docker/Dockerfile index 81b09c4171a..416cb2af00f 100644 --- a/Docker/Dockerfile +++ b/Docker/Dockerfile @@ -3,15 +3,16 @@ ARG branch=master ARG symbol=SYS ENV OPENSSL_ROOT_DIR /usr/include/openssl +ENV INSTALL_PREFIX=/usr/local/eosio +RUN mkdir -p "${INSTALL_PREFIX}" RUN git clone -b $branch https://github.com/boscore/bos.git --recursive \ && cd bos && echo "$branch:$(git rev-parse HEAD)" > /etc/eosio-version \ - && cmake -H. -B"/tmp/build" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \ - -DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX=/tmp/build -DBUILD_MONGO_DB_PLUGIN=true -DCORE_SYMBOL_NAME=$symbol \ - -DOPENSSL_ROOT_DIR="${OPENSSL_ROOT_DIR}" \ - && cmake --build /tmp/build --target install - + && cmake -H. -B"${INSTALL_PREFIX}" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \ + -DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}" -DBUILD_MONGO_DB_PLUGIN=true -DCORE_SYMBOL_NAME=$symbol \ + -DOPENSSL_ROOT_DIR="${OPENSSL_ROOT_DIR}" -DCMAKE_CXX_STANDARD_LIBRARIES="-lpthread" \ + && cmake --build "${INSTALL_PREFIX}" --target install FROM ubuntu:18.04 diff --git a/eosio_build.sh b/eosio_build.sh index b600e0905ea..eba45661cdd 100755 --- a/eosio_build.sh +++ b/eosio_build.sh @@ -272,6 +272,7 @@ -DCMAKE_C_COMPILER="${C_COMPILER}" -DWASM_ROOT="${WASM_ROOT}" -DCORE_SYMBOL_NAME="${CORE_SYMBOL_NAME}" \ -DOPENSSL_ROOT_DIR="${OPENSSL_ROOT_DIR}" -DBUILD_MONGO_DB_PLUGIN=true \ -DENABLE_COVERAGE_TESTING="${ENABLE_COVERAGE_TESTING}" -DBUILD_DOXYGEN="${DOXYGEN}" \ + -DCMAKE_CXX_STANDARD_LIBRARIES="-lpthread" \ -DCMAKE_INSTALL_PREFIX="/usr/local/eosio" ${LOCAL_CMAKE_FLAGS} "${SOURCE_DIR}" then printf "\\n\\t>>>>>>>>>>>>>>>>>>>> CMAKE building BOSCore has exited with the above error.\\n\\n" From 22bbfa062496239ffcaa48a5fcca49b6e9b20d25 Mon Sep 17 00:00:00 2001 From: thaipandada Date: Fri, 23 Aug 2019 14:02:09 +0800 Subject: [PATCH 21/37] adjust the dockerfile --- Docker/Dockerfile | 15 +++++---------- Docker/nodeosd.sh | 6 ------ 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/Docker/Dockerfile b/Docker/Dockerfile index 416cb2af00f..3ccc4bd0e62 100644 --- a/Docker/Dockerfile +++ b/Docker/Dockerfile @@ -3,28 +3,23 @@ ARG branch=master ARG symbol=SYS ENV OPENSSL_ROOT_DIR /usr/include/openssl -ENV INSTALL_PREFIX=/usr/local/eosio - -RUN mkdir -p "${INSTALL_PREFIX}" RUN git clone -b $branch https://github.com/boscore/bos.git --recursive \ && cd bos && echo "$branch:$(git rev-parse HEAD)" > /etc/eosio-version \ - && cmake -H. -B"${INSTALL_PREFIX}" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \ - -DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}" -DBUILD_MONGO_DB_PLUGIN=true -DCORE_SYMBOL_NAME=$symbol \ - -DOPENSSL_ROOT_DIR="${OPENSSL_ROOT_DIR}" -DCMAKE_CXX_STANDARD_LIBRARIES="-lpthread" \ - && cmake --build "${INSTALL_PREFIX}" --target install - + && cmake -H. -B"/tmp/build" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \ + -DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX=/tmp/build -DBUILD_MONGO_DB_PLUGIN=true -DCORE_SYMBOL_NAME=$symbol \ + -DOPENSSL_ROOT_DIR="${OPENSSL_ROOT_DIR}" -DCMAKE_CXX_STANDARD_LIBRARIES="-lpthread" \ + && cmake --build /tmp/build --target install FROM ubuntu:18.04 RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install openssl ca-certificates && rm -rf /var/lib/apt/lists/* COPY --from=builder /usr/local/lib/* /usr/local/lib/ COPY --from=builder /tmp/build/bin /opt/eosio/bin -COPY --from=builder /tmp/build/contracts /contracts COPY --from=builder /bos/Docker/config.ini / COPY --from=builder /etc/eosio-version /etc COPY --from=builder /bos/Docker/nodeosd.sh /opt/eosio/bin/nodeosd.sh ENV EOSIO_ROOT=/opt/eosio RUN chmod +x /opt/eosio/bin/nodeosd.sh ENV LD_LIBRARY_PATH /usr/local/lib -ENV PATH /opt/eosio/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +ENV PATH /opt/eosio/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \ No newline at end of file diff --git a/Docker/nodeosd.sh b/Docker/nodeosd.sh index 870548d6b6b..86f676dd159 100755 --- a/Docker/nodeosd.sh +++ b/Docker/nodeosd.sh @@ -11,12 +11,6 @@ if [ -f '/opt/eosio/bin/data-dir/config.ini' ]; then cp /config.ini /opt/eosio/bin/data-dir fi -if [ -d '/opt/eosio/bin/data-dir/contracts' ]; then - echo - else - cp -r /contracts /opt/eosio/bin/data-dir -fi - while :; do case $1 in --config-dir=?*) From b097d3ea46d5f090540cb84c0eaf320433635bec Mon Sep 17 00:00:00 2001 From: oldcold Date: Tue, 27 Aug 2019 02:06:36 +0800 Subject: [PATCH 22/37] avoid sending last prepare. --- libraries/chain/pbft.cpp | 4 +++- libraries/chain/pbft_database.cpp | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 8ac97cb1c49..69be56b67d2 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -301,7 +301,9 @@ namespace eosio { set_view_change_timer(0); set_current(std::make_shared(*this, pbft_db)); - emit(pbft_transit_to_committed, true); + if (!get_prepare_cache().empty()) { + emit(pbft_transit_to_committed, true); + } } void psm_machine::transit_to_prepared_state() { diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 5bf4a743bd1..84c7a70bcca 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -223,7 +223,8 @@ namespace eosio { if (high_watermark_block_num <= lib) return prepares_to_be_cached; - if (auto hwbs = ctrl.fork_db().get_block_in_current_chain_by_num(high_watermark_block_num)) { + auto hwbs = ctrl.fork_db().get_block_in_current_chain_by_num(high_watermark_block_num); + if ( hwbs && hwbs->id != my_prepare) { auto sent = false; for (const auto& sp : my_sps) { pbft_prepare new_p; From 5e2cecc69462832c3664f3ebf4e2daf050d2f98c Mon Sep 17 00:00:00 2001 From: oldcold Date: Tue, 17 Sep 2019 17:22:13 +0800 Subject: [PATCH 23/37] fix pbft cert generation and validation --- libraries/chain/pbft_database.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 84c7a70bcca..fcd517dbbb4 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -650,12 +650,14 @@ namespace eosio { for (const auto& pre: prepares) { if (prepare_count.find(pre.first.first) == prepare_count.end()) prepare_count[pre.first.first] = 0; - prepare_msg[pre.first.first].emplace_back(pre.second); } for (const auto& bp: as) { for (const auto& pp: prepares) { - if (bp.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; + prepare_msg[pp.first.first].emplace_back(pp.second); + } } } @@ -737,12 +739,14 @@ namespace eosio { for (const auto& com: commits) { if (commit_count.find(com.first.first) == commit_count.end()) commit_count[com.first.first] = 0; - commit_msg[com.first.first].emplace_back(com.second); } for (const auto& bp: as) { for (const auto& cc: commits) { - if (bp.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; + commit_msg[cc.first.first].emplace_back(cc.second); + } } } @@ -773,11 +777,15 @@ namespace eosio { auto pvs = *itr; + auto lscb_bps = lscb_active_producers().producers; + if (pvs->is_view_changed) { pvcc.target_view=pvs->view; pvcc.view_changes.reserve(pvs->view_changes.size()); - for(auto& view_change : pvs->view_changes) { - pvcc.view_changes.emplace_back( view_change.second ); + for (auto& bp : lscb_bps) { + for(auto& view_change : pvs->view_changes) { + if (bp.block_signing_key == view_change.first) pvcc.view_changes.emplace_back(view_change.second); + } } } return pvcc; @@ -798,8 +806,7 @@ namespace eosio { for (auto& p : prepares) { auto pmm = pbft_message_metadata(p, chain_id); prepares_metadata.emplace_back(pmm); - if (!is_valid_prepare(p, pmm.sender_key)) return false; - if (add_to_pbft_db) add_pbft_prepare(p, pmm.sender_key); + if ( add_to_pbft_db && is_valid_prepare(p, pmm.sender_key) ) add_pbft_prepare(p, pmm.sender_key); } auto cert_id = certificate.block_info.block_id; @@ -861,8 +868,7 @@ namespace eosio { for (auto& c : commits) { auto pmm = pbft_message_metadata(c, chain_id); commits_metadata.emplace_back(pmm); - if (!is_valid_commit(c, pmm.sender_key)) return false; - if (add_to_pbft_db) add_pbft_commit(c, pmm.sender_key); + if (add_to_pbft_db && is_valid_commit(c, pmm.sender_key)) add_pbft_commit(c, pmm.sender_key); } auto cert_id = certificate.block_info.block_id; From 4304c51d6f7f0636a63fe46169bd5c0a0fc99583 Mon Sep 17 00:00:00 2001 From: oldcold Date: Tue, 10 Sep 2019 18:03:14 +0800 Subject: [PATCH 24/37] attempt to fix bad prepared cert --- libraries/chain/pbft_database.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index fcd517dbbb4..35ebee45628 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -1100,14 +1100,24 @@ namespace eosio { auto forks = fetch_fork_from(block_infos); fork_info_type longest_fork; + longest_fork.reserve(threshold); for (const auto& f : forks) { if (f.size() > longest_fork.size()) { longest_fork = f; } } - return longest_fork.empty() - || (longest_fork.size() + non_fork_bp_count >= threshold && bi.block_id == longest_fork.back().block_id); + if (longest_fork.empty()) { + return true; + } else if (longest_fork.size() + non_fork_bp_count < threshold) { + return false; + } else { + while (non_fork_bp_count) { + longest_fork.emplace_back(block_info_type{}); + --non_fork_bp_count; + } + return longest_fork[2/3*threshold].block_id == bi.block_id; + } } pbft_stable_checkpoint pbft_database::fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr& b) { From 3144c18d603f532e759e3cb480dbed1d088fb387 Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 18 Sep 2019 11:18:56 +0800 Subject: [PATCH 25/37] fix longest fork threshold --- libraries/chain/pbft_database.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 35ebee45628..17f21a7aee7 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -1109,14 +1109,14 @@ namespace eosio { if (longest_fork.empty()) { return true; - } else if (longest_fork.size() + non_fork_bp_count < threshold) { + } else if (longest_fork.size() + non_fork_bp_count < threshold || threshold == 0) { return false; } else { while (non_fork_bp_count) { longest_fork.emplace_back(block_info_type{}); --non_fork_bp_count; } - return longest_fork[2/3*threshold].block_id == bi.block_id; + return longest_fork[threshold-1].block_id == bi.block_id; } } From 3971da577ca2b62f43fa64a7f9cc25da7c77caa9 Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 18 Sep 2019 15:19:40 +0800 Subject: [PATCH 26/37] redo cert validation --- .../include/eosio/chain/pbft_database.hpp | 4 - libraries/chain/pbft_database.cpp | 285 ++++++++++-------- 2 files changed, 163 insertions(+), 126 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 6b4bb2cd7a9..d14d381017a 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -503,16 +503,12 @@ namespace eosio { bool is_less_than_high_watermark(block_num_type bnum); bool is_valid_prepared_certificate(const pbft_prepared_certificate& certificate, bool add_to_pbft_db = false); bool is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db = false); - bool is_valid_longest_fork(const block_info_type& bi, fork_info_type& block_infos, unsigned long threshold, unsigned long non_fork_bp_count); 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(fork_info_type& block_infos); - fork_info_type fetch_first_fork_from(fork_info_type& bi); - void set(const pbft_state_ptr& s); void set(const pbft_checkpoint_state_ptr& s); void prune(const pbft_state_ptr& h); diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 17f21a7aee7..de91e792713 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -818,41 +818,105 @@ namespace eosio { auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; flat_map prepare_count; + flat_map>> prepare_msg; for (const auto& pm: prepares_metadata) { - if (prepare_count.find(pm.msg.view) == prepare_count.end()) prepare_count[pm.msg.view] = 0; + if (prepare_count.find(pm.msg.view) == prepare_count.end()) { + prepare_count[pm.msg.view] = 0; + prepare_msg[pm.msg.view].reserve(bp_threshold); + } } for (const auto& bp: producer_schedule.producers) { for (const auto& pm: prepares_metadata) { - if (bp.block_signing_key == pm.sender_key) prepare_count[pm.msg.view] += 1; + if (bp.block_signing_key == pm.sender_key) { + prepare_count[pm.msg.view] += 1; + prepare_msg[pm.msg.view].emplace_back(pm); + } } } auto should_prepared = false; - + auto valid_prepares = vector>{}; + valid_prepares.reserve(bp_threshold); for (const auto& e: prepare_count) { if (e.second >= bp_threshold) { should_prepared = true; + valid_prepares = prepare_msg[e.first]; } } if (!should_prepared) return false; - //validate prepare - auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - auto non_fork_bp_count = 0; - fork_info_type prepare_infos; - prepare_infos.reserve(certificate.prepares.size()); - for (const auto& p : certificate.prepares) { - //only search in fork db - if (p.block_info.block_num() <= lscb_num) { - ++non_fork_bp_count; - } else { - prepare_infos.emplace_back(p.block_info); + auto local_index = pbft_state_multi_index_type{}; + for (auto &p: valid_prepares) { + auto& by_block_id_index = local_index.get(); + + auto current = ctrl.fetch_block_state_by_id(p.msg.block_info.block_id); + + while ((current) && (current->block_num > ctrl.last_stable_checkpoint_block_num())) { + auto curr_itr = by_block_id_index.find(current->id); + + if (curr_itr == by_block_id_index.end()) { + try { + flat_map, pbft_prepare> local_prepares; + local_prepares[std::make_pair(p.msg.view, p.sender_key)] = p.msg; + pbft_state curr_ps; + curr_ps.block_id = current->id; + curr_ps.block_num = current->block_num; + curr_ps.prepares = local_prepares; + auto curr_psp = std::make_shared(move(curr_ps)); + local_index.insert(curr_psp); + } catch (...) { + elog("prepare insert failure: ${p}", ("p", p.msg)); + } + } else { + auto local_prepares = (*curr_itr)->prepares; + if (local_prepares.find(std::make_pair(p.msg.view, p.sender_key)) == local_prepares.end()) { + by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr &psp) { + psp->prepares[std::make_pair(p.msg.view, p.sender_key)] = p.msg; + }); + } + } + curr_itr = by_block_id_index.find(current->id); + if (curr_itr != by_block_id_index.end()) { + + auto cpsp = *curr_itr; + auto local_prepares = cpsp->prepares; + auto as = current->active_schedule.producers; + auto threshold = as.size() * 2 / 3 + 1; + if (local_prepares.size() >= threshold && !cpsp->is_prepared && + is_less_than_high_watermark(cpsp->block_num)) { + flat_map local_prepare_count; + for (const auto &pre: local_prepares) { + if (local_prepare_count.find(pre.second.view) == local_prepare_count.end()) + local_prepare_count[pre.second.view] = 0; + } + + for (const auto &bp: as) { + for (const auto &pp: local_prepares) { + if (bp.block_signing_key == pp.first.second) local_prepare_count[pp.first.first] += 1; + } + } + for (const auto &e: local_prepare_count) { + if (e.second >= threshold) { + by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr& p) { p->is_prepared = true; }); + } + } + } + current = ctrl.fetch_block_state_by_id(current->prev()); + } } } - return is_valid_longest_fork(certificate.block_info, prepare_infos, bp_threshold, non_fork_bp_count); + + const auto& by_prepare_and_num_index = local_index.get(); + auto itr = by_prepare_and_num_index.begin(); + if (itr == by_prepare_and_num_index.end()) return false; + + pbft_state_ptr psp = *itr; + + return psp->is_prepared + && psp->block_id == certificate.block_info.block_id; } bool pbft_database::is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db) { @@ -880,41 +944,110 @@ namespace eosio { auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; flat_map commit_count; + flat_map>> commit_msg; for (const auto& cm: commits_metadata) { - if (commit_count.find(cm.msg.view) == commit_count.end()) commit_count[cm.msg.view] = 0; + if (commit_count.find(cm.msg.view) == commit_count.end()) { + commit_count[cm.msg.view] = 0; + commit_msg[cm.msg.view].reserve(bp_threshold); + } } for (const auto& bp: producer_schedule.producers) { for (const auto& cm: commits_metadata) { - if (bp.block_signing_key == cm.sender_key) commit_count[cm.msg.view] += 1; + if (bp.block_signing_key == cm.sender_key) { + commit_count[cm.msg.view] += 1; + commit_msg[cm.msg.view].emplace_back(cm); + } } } auto should_committed = false; - + auto valid_commits = vector>{}; + valid_commits.reserve(bp_threshold); for (const auto& e: commit_count) { if (e.second >= bp_threshold) { should_committed = true; + valid_commits = commit_msg[e.first]; } } if (!should_committed) return false; - //validate commit - auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - auto non_fork_bp_count = 0; - fork_info_type commit_infos; - commit_infos.reserve(certificate.commits.size()); - for (const auto& c : certificate.commits) { - //only search in fork db - if (c.block_info.block_num() <= lscb_num) { - ++non_fork_bp_count; - } else { - commit_infos.emplace_back(c.block_info); + auto local_index = pbft_state_multi_index_type{}; + for (auto &c: valid_commits) { + auto& by_block_id_index = local_index.get(); + + auto current = ctrl.fetch_block_state_by_id(c.msg.block_info.block_id); + + while ((current) && (current->block_num > ctrl.last_stable_checkpoint_block_num())) { + + auto curr_itr = by_block_id_index.find(current->id); + + if (curr_itr == by_block_id_index.end()) { + try { + flat_map, pbft_commit> local_commits; + local_commits[std::make_pair(c.msg.view, c.sender_key)] = c.msg; + pbft_state curr_ps; + curr_ps.block_id = current->id; + curr_ps.block_num = current->block_num; + curr_ps.commits = local_commits; + auto curr_psp = std::make_shared(move(curr_ps)); + local_index.insert(curr_psp); + } catch (...) { + elog("commit insertion failure: ${c}", ("c", c.msg)); + } + } else { + auto local_commits = (*curr_itr)->commits; + if (local_commits.find(std::make_pair(c.msg.view, c.sender_key)) == local_commits.end()) { + by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr &psp) { + psp->commits[std::make_pair(c.msg.view, c.sender_key)] = c.msg; + std::sort(psp->commits.begin(), psp->commits.end(), less<>()); + }); + } + } + + curr_itr = by_block_id_index.find(current->id); + if (curr_itr != by_block_id_index.end()) { + + auto cpsp = *curr_itr; + + auto as = current->active_schedule.producers; + auto threshold = as.size() * 2 / 3 + 1; + auto local_commits = cpsp->commits; + if (local_commits.size() >= threshold && !cpsp->is_committed && + is_less_than_high_watermark(cpsp->block_num)) { + flat_map local_commit_count; + for (const auto &com: local_commits) { + if (local_commit_count.find(com.second.view) == local_commit_count.end()) + local_commit_count[com.second.view] = 0; + } + + for (const auto &bp: as) { + for (const auto &pc: local_commits) { + if (bp.block_signing_key == pc.first.second) local_commit_count[pc.first.first] += 1; + } + } + + for (const auto &e: local_commit_count) { + if (e.second >= threshold) { + by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr& p) { p->is_committed = true; }); + } + } + } + current = ctrl.fetch_block_state_by_id(current->prev()); + } } + } - return is_valid_longest_fork(certificate.block_info, commit_infos, bp_threshold, non_fork_bp_count); + const auto& by_commit_and_num_index = local_index.get(); + auto itr = by_commit_and_num_index.begin(); + if (itr == by_commit_and_num_index.end()) return false; + + pbft_state_ptr psp = *itr; + + return psp->is_committed + && psp->block_id == certificate.block_info.block_id; } bool pbft_database::is_valid_view_change(const pbft_view_change& vc, const public_key_type& pk) { @@ -1028,98 +1161,6 @@ namespace eosio { return vc_lscb > 0 && lscb_num > vc_lscb; } - vector pbft_database::fetch_fork_from(fork_info_type& block_infos) { - - vector result; - if (block_infos.empty()) { - return result; - } - if (block_infos.size() == 1) { - result.emplace_back(initializer_list{block_infos.front()}); - return result; - } - - sort(block_infos.begin(), block_infos.end(), - [](const block_info_type& a, const block_info_type& b) -> bool { return a.block_num() > b.block_num(); }); - - while (!block_infos.empty()) { - auto fork = fetch_first_fork_from(block_infos); - if (!fork.empty()) { - result.emplace_back(fork); - } - } - return result; - } - - fork_info_type pbft_database::fetch_first_fork_from(fork_info_type& bi) { - fork_info_type result; - if (bi.empty()) { - return result; - } - if (bi.size() == 1) { - result.emplace_back(bi.front()); - bi.clear(); - return result; - } - //bi should be sorted desc - auto high = bi.front().block_num(); - auto low = bi.back().block_num(); - - auto id = bi.front().block_id; - auto num = bi.front().block_num(); - while (num <= high && num >= low && !bi.empty()) { - auto bs = ctrl.fetch_block_state_by_id(id); - - for (auto it = bi.begin(); it != bi.end();) { - if (it->block_id == id) { - if (bs) { - //add to result only if b exist - result.emplace_back((*it)); - } - it = bi.erase(it); - } else { - it++; - } - } - if (bs) { - id = bs->prev(); - num--; - } else { - break; - } - } - - return result; - } - - bool pbft_database::is_valid_longest_fork( - const block_info_type& bi, - fork_info_type& block_infos, - unsigned long threshold, - unsigned long non_fork_bp_count) { - - auto forks = fetch_fork_from(block_infos); - fork_info_type longest_fork; - longest_fork.reserve(threshold); - for (const auto& f : forks) { - if (f.size() > longest_fork.size()) { - longest_fork = f; - } - } - - if (longest_fork.empty()) { - return true; - } else if (longest_fork.size() + non_fork_bp_count < threshold || threshold == 0) { - return false; - } else { - while (non_fork_bp_count) { - longest_fork.emplace_back(block_info_type{}); - --non_fork_bp_count; - } - return longest_fork[threshold-1].block_id == bi.block_id; - } - } - pbft_stable_checkpoint pbft_database::fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr& b) { pbft_stable_checkpoint psc; From 2ce70d774b83b0f0ebd76ed03f82a3a500ca4623 Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 18 Sep 2019 18:48:16 +0800 Subject: [PATCH 27/37] refactor validation, add comments --- .../include/eosio/chain/pbft_database.hpp | 36 +++- libraries/chain/pbft_database.cpp | 159 +++++------------- 2 files changed, 76 insertions(+), 119 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index d14d381017a..3bc63bc3737 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -332,9 +332,19 @@ namespace eosio { bool is_stable = false; }; + using producer_and_block_info = std::pair; + + struct validation_state { + block_id_type block_id; + block_num_type block_num = 0; + vector producers; + bool enough = false; + }; + using pbft_state_ptr = std::shared_ptr; using pbft_view_change_state_ptr = std::shared_ptr; using pbft_checkpoint_state_ptr = std::shared_ptr; + using validation_state_ptr = std::shared_ptr; struct by_block_id; struct by_num; @@ -414,6 +424,28 @@ namespace eosio { > > pbft_checkpoint_state_multi_index_type; + struct by_block_id; + struct by_status_and_num; + typedef multi_index_container< + validation_state_ptr, + indexed_by< + hashed_unique < + tag, + member, + std::hash + >, + ordered_non_unique< + tag, + composite_key< + validation_state, + member, + member + >, + composite_key_compare< greater<>, greater<> > + > + > + > local_state_multi_index_type; + class pbft_database { public: explicit pbft_database(controller& ctrl); @@ -503,6 +535,7 @@ namespace eosio { bool is_less_than_high_watermark(block_num_type bnum); bool is_valid_prepared_certificate(const pbft_prepared_certificate& certificate, bool add_to_pbft_db = false); bool is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db = false); + bool is_valid_longest_fork(const vector& producers, const block_info_type& cert_info); producer_schedule_type lscb_active_producers() const; vector& get_updated_watermarks(); @@ -538,4 +571,5 @@ FC_REFLECT(eosio::chain::pbft_stable_checkpoint, (block_info)(checkpoints)) FC_REFLECT(eosio::chain::pbft_state, (block_id)(block_num)(prepares)(is_prepared)(commits)(is_committed)) FC_REFLECT(eosio::chain::pbft_view_change_state, (view)(view_changes)(is_view_changed)) -FC_REFLECT(eosio::chain::pbft_checkpoint_state, (block_id)(block_num)(checkpoints)(is_stable)) \ No newline at end of file +FC_REFLECT(eosio::chain::pbft_checkpoint_state, (block_id)(block_num)(checkpoints)(is_stable)) +FC_REFLECT(eosio::chain::validation_state, (block_id)(block_num)(producers)(enough)) \ No newline at end of file diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index de91e792713..e30d3f7e060 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -818,7 +818,7 @@ namespace eosio { auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; flat_map prepare_count; - flat_map>> prepare_msg; + flat_map> prepare_msg; for (const auto& pm: prepares_metadata) { if (prepare_count.find(pm.msg.view) == prepare_count.end()) { @@ -831,13 +831,13 @@ namespace eosio { for (const auto& pm: prepares_metadata) { if (bp.block_signing_key == pm.sender_key) { prepare_count[pm.msg.view] += 1; - prepare_msg[pm.msg.view].emplace_back(pm); + prepare_msg[pm.msg.view].emplace_back(std::make_pair(pm.sender_key, pm.msg.block_info)); } } } auto should_prepared = false; - auto valid_prepares = vector>{}; + auto valid_prepares = vector{}; valid_prepares.reserve(bp_threshold); for (const auto& e: prepare_count) { if (e.second >= bp_threshold) { @@ -846,77 +846,7 @@ namespace eosio { } } - if (!should_prepared) return false; - - auto local_index = pbft_state_multi_index_type{}; - for (auto &p: valid_prepares) { - auto& by_block_id_index = local_index.get(); - - auto current = ctrl.fetch_block_state_by_id(p.msg.block_info.block_id); - - while ((current) && (current->block_num > ctrl.last_stable_checkpoint_block_num())) { - auto curr_itr = by_block_id_index.find(current->id); - - if (curr_itr == by_block_id_index.end()) { - try { - flat_map, pbft_prepare> local_prepares; - local_prepares[std::make_pair(p.msg.view, p.sender_key)] = p.msg; - pbft_state curr_ps; - curr_ps.block_id = current->id; - curr_ps.block_num = current->block_num; - curr_ps.prepares = local_prepares; - auto curr_psp = std::make_shared(move(curr_ps)); - local_index.insert(curr_psp); - } catch (...) { - elog("prepare insert failure: ${p}", ("p", p.msg)); - } - } else { - auto local_prepares = (*curr_itr)->prepares; - if (local_prepares.find(std::make_pair(p.msg.view, p.sender_key)) == local_prepares.end()) { - by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr &psp) { - psp->prepares[std::make_pair(p.msg.view, p.sender_key)] = p.msg; - }); - } - } - curr_itr = by_block_id_index.find(current->id); - if (curr_itr != by_block_id_index.end()) { - - auto cpsp = *curr_itr; - auto local_prepares = cpsp->prepares; - auto as = current->active_schedule.producers; - auto threshold = as.size() * 2 / 3 + 1; - if (local_prepares.size() >= threshold && !cpsp->is_prepared && - is_less_than_high_watermark(cpsp->block_num)) { - flat_map local_prepare_count; - for (const auto &pre: local_prepares) { - if (local_prepare_count.find(pre.second.view) == local_prepare_count.end()) - local_prepare_count[pre.second.view] = 0; - } - - for (const auto &bp: as) { - for (const auto &pp: local_prepares) { - if (bp.block_signing_key == pp.first.second) local_prepare_count[pp.first.first] += 1; - } - } - for (const auto &e: local_prepare_count) { - if (e.second >= threshold) { - by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr& p) { p->is_prepared = true; }); - } - } - } - current = ctrl.fetch_block_state_by_id(current->prev()); - } - } - } - - const auto& by_prepare_and_num_index = local_index.get(); - auto itr = by_prepare_and_num_index.begin(); - if (itr == by_prepare_and_num_index.end()) return false; - - pbft_state_ptr psp = *itr; - - return psp->is_prepared - && psp->block_id == certificate.block_info.block_id; + return should_prepared && is_valid_longest_fork(valid_prepares, certificate.block_info); } bool pbft_database::is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db) { @@ -944,7 +874,7 @@ namespace eosio { auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; flat_map commit_count; - flat_map>> commit_msg; + flat_map> commit_msg; for (const auto& cm: commits_metadata) { if (commit_count.find(cm.msg.view) == commit_count.end()) { @@ -957,13 +887,13 @@ namespace eosio { for (const auto& cm: commits_metadata) { if (bp.block_signing_key == cm.sender_key) { commit_count[cm.msg.view] += 1; - commit_msg[cm.msg.view].emplace_back(cm); + commit_msg[cm.msg.view].emplace_back(std::make_pair(cm.sender_key, cm.msg.block_info)); } } } auto should_committed = false; - auto valid_commits = vector>{}; + auto valid_commits = vector{}; valid_commits.reserve(bp_threshold); for (const auto& e: commit_count) { if (e.second >= bp_threshold) { @@ -972,37 +902,39 @@ namespace eosio { } } - if (!should_committed) return false; + return should_committed && is_valid_longest_fork(valid_commits, certificate.block_info); + } - auto local_index = pbft_state_multi_index_type{}; - for (auto &c: valid_commits) { - auto& by_block_id_index = local_index.get(); + bool pbft_database::is_valid_longest_fork(const vector& block_infos, const block_info_type& cert_info) { - auto current = ctrl.fetch_block_state_by_id(c.msg.block_info.block_id); + //add all valid block_infos in to a temp multi_index, this implementation which might contains heavier computation + auto local_index = local_state_multi_index_type(); + for (auto &e: block_infos) { - while ((current) && (current->block_num > ctrl.last_stable_checkpoint_block_num())) { + auto& by_block_id_index = local_index.get(); + auto current = ctrl.fetch_block_state_by_id(e.second.block_id); + + while ( current ) { auto curr_itr = by_block_id_index.find(current->id); if (curr_itr == by_block_id_index.end()) { try { - flat_map, pbft_commit> local_commits; - local_commits[std::make_pair(c.msg.view, c.sender_key)] = c.msg; - pbft_state curr_ps; + vector bis; + bis.reserve(block_infos.size()); + bis.emplace_back(e.first); + validation_state curr_ps; curr_ps.block_id = current->id; curr_ps.block_num = current->block_num; - curr_ps.commits = local_commits; - auto curr_psp = std::make_shared(move(curr_ps)); + curr_ps.producers = bis; + auto curr_psp = std::make_shared(move(curr_ps)); local_index.insert(curr_psp); - } catch (...) { - elog("commit insertion failure: ${c}", ("c", c.msg)); - } + } catch (...) {} } else { - auto local_commits = (*curr_itr)->commits; - if (local_commits.find(std::make_pair(c.msg.view, c.sender_key)) == local_commits.end()) { - by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr &psp) { - psp->commits[std::make_pair(c.msg.view, c.sender_key)] = c.msg; - std::sort(psp->commits.begin(), psp->commits.end(), less<>()); + auto keys = (*curr_itr)->producers; + if (std::find(keys.begin(), keys.end(),e.first) == keys.end()) { + by_block_id_index.modify(curr_itr, [&](const validation_state_ptr &lsp) { + lsp->producers.emplace_back(e.first); }); } } @@ -1014,40 +946,31 @@ namespace eosio { auto as = current->active_schedule.producers; auto threshold = as.size() * 2 / 3 + 1; - auto local_commits = cpsp->commits; - if (local_commits.size() >= threshold && !cpsp->is_committed && - is_less_than_high_watermark(cpsp->block_num)) { - flat_map local_commit_count; - for (const auto &com: local_commits) { - if (local_commit_count.find(com.second.view) == local_commit_count.end()) - local_commit_count[com.second.view] = 0; - } + auto keys = cpsp->producers; + if (keys.size() >= threshold && !cpsp->enough ) { + uint32_t count = 0; for (const auto &bp: as) { - for (const auto &pc: local_commits) { - if (bp.block_signing_key == pc.first.second) local_commit_count[pc.first.first] += 1; + for (const auto &k: keys) { + if (bp.block_signing_key == k) count += 1; } } - for (const auto &e: local_commit_count) { - if (e.second >= threshold) { - by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr& p) { p->is_committed = true; }); - } + if (count >= threshold) { + by_block_id_index.modify(curr_itr, [&](const validation_state_ptr& p) { p->enough = true; }); } } - current = ctrl.fetch_block_state_by_id(current->prev()); } + current = ctrl.fetch_block_state_by_id(current->prev()); } - } - const auto& by_commit_and_num_index = local_index.get(); - auto itr = by_commit_and_num_index.begin(); - if (itr == by_commit_and_num_index.end()) return false; + const auto& by_status_and_num_index = local_index.get(); + auto itr = by_status_and_num_index.begin(); + if (itr == by_status_and_num_index.end()) return false; - pbft_state_ptr psp = *itr; + auto psp = *itr; - return psp->is_committed - && psp->block_id == certificate.block_info.block_id; + return psp->enough && psp->block_id == cert_info.block_id; } bool pbft_database::is_valid_view_change(const pbft_view_change& vc, const public_key_type& pk) { From b1ea9fd9875444aa98428f61fe32a16677807862 Mon Sep 17 00:00:00 2001 From: oldcold Date: Fri, 20 Sep 2019 11:45:59 +0800 Subject: [PATCH 28/37] clean up longest fork validation --- libraries/chain/pbft_database.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index e30d3f7e060..9e8466f4433 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -907,11 +907,11 @@ namespace eosio { bool pbft_database::is_valid_longest_fork(const vector& block_infos, const block_info_type& cert_info) { - //add all valid block_infos in to a temp multi_index, this implementation which might contains heavier computation + //add all valid block_infos in to a temp multi_index, this implementation might contains heavier computation auto local_index = local_state_multi_index_type(); + auto& by_block_id_index = local_index.get(); for (auto &e: block_infos) { - auto& by_block_id_index = local_index.get(); auto current = ctrl.fetch_block_state_by_id(e.second.block_id); while ( current ) { @@ -920,21 +920,21 @@ namespace eosio { if (curr_itr == by_block_id_index.end()) { try { - vector bis; - bis.reserve(block_infos.size()); - bis.emplace_back(e.first); + vector keys; + keys.reserve(block_infos.size()); + keys.emplace_back(e.first); validation_state curr_ps; curr_ps.block_id = current->id; curr_ps.block_num = current->block_num; - curr_ps.producers = bis; + curr_ps.producers = keys; auto curr_psp = std::make_shared(move(curr_ps)); local_index.insert(curr_psp); } catch (...) {} } else { auto keys = (*curr_itr)->producers; if (std::find(keys.begin(), keys.end(),e.first) == keys.end()) { - by_block_id_index.modify(curr_itr, [&](const validation_state_ptr &lsp) { - lsp->producers.emplace_back(e.first); + by_block_id_index.modify(curr_itr, [&](const validation_state_ptr &vsp) { + vsp->producers.emplace_back(e.first); }); } } @@ -968,7 +968,7 @@ namespace eosio { auto itr = by_status_and_num_index.begin(); if (itr == by_status_and_num_index.end()) return false; - auto psp = *itr; + validation_state_ptr psp = *itr; return psp->enough && psp->block_id == cert_info.block_id; } From 783ceb75653f67c0cb8313fd3cfb0f93578766ac Mon Sep 17 00:00:00 2001 From: oldcold Date: Fri, 20 Sep 2019 18:46:36 +0800 Subject: [PATCH 29/37] add watermark check --- libraries/chain/pbft_database.cpp | 75 ++++++++++++++++--------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 9e8466f4433..e48c3195a9e 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -910,54 +910,57 @@ namespace eosio { //add all valid block_infos in to a temp multi_index, this implementation might contains heavier computation auto local_index = local_state_multi_index_type(); auto& by_block_id_index = local_index.get(); + auto watermark = get_current_pbft_watermark(); for (auto &e: block_infos) { auto current = ctrl.fetch_block_state_by_id(e.second.block_id); while ( current ) { - - auto curr_itr = by_block_id_index.find(current->id); - - if (curr_itr == by_block_id_index.end()) { - try { - vector keys; - keys.reserve(block_infos.size()); - keys.emplace_back(e.first); - validation_state curr_ps; - curr_ps.block_id = current->id; - curr_ps.block_num = current->block_num; - curr_ps.producers = keys; - auto curr_psp = std::make_shared(move(curr_ps)); - local_index.insert(curr_psp); - } catch (...) {} - } else { - auto keys = (*curr_itr)->producers; - if (std::find(keys.begin(), keys.end(),e.first) == keys.end()) { - by_block_id_index.modify(curr_itr, [&](const validation_state_ptr &vsp) { - vsp->producers.emplace_back(e.first); - }); + if (watermark == 0 || current->block_num <= watermark) { + auto curr_itr = by_block_id_index.find(current->id); + + if (curr_itr == by_block_id_index.end()) { + try { + vector keys; + keys.reserve(block_infos.size()); + keys.emplace_back(e.first); + validation_state curr_ps; + curr_ps.block_id = current->id; + curr_ps.block_num = current->block_num; + curr_ps.producers = keys; + auto curr_psp = std::make_shared(move(curr_ps)); + local_index.insert(curr_psp); + } catch (...) {} + } else { + auto keys = (*curr_itr)->producers; + if (std::find(keys.begin(), keys.end(), e.first) == keys.end()) { + by_block_id_index.modify(curr_itr, [&](const validation_state_ptr &vsp) { + vsp->producers.emplace_back(e.first); + }); + } } - } - curr_itr = by_block_id_index.find(current->id); - if (curr_itr != by_block_id_index.end()) { + curr_itr = by_block_id_index.find(current->id); + if (curr_itr != by_block_id_index.end()) { - auto cpsp = *curr_itr; + auto cpsp = *curr_itr; - auto as = current->active_schedule.producers; - auto threshold = as.size() * 2 / 3 + 1; - auto keys = cpsp->producers; - if (keys.size() >= threshold && !cpsp->enough ) { - uint32_t count = 0; + auto as = current->active_schedule.producers; + auto threshold = as.size() * 2 / 3 + 1; + auto keys = cpsp->producers; + if (keys.size() >= threshold && !cpsp->enough) { + uint32_t count = 0; - for (const auto &bp: as) { - for (const auto &k: keys) { - if (bp.block_signing_key == k) count += 1; + for (const auto &bp: as) { + for (const auto &k: keys) { + if (bp.block_signing_key == k) count += 1; + } } - } - if (count >= threshold) { - by_block_id_index.modify(curr_itr, [&](const validation_state_ptr& p) { p->enough = true; }); + if (count >= threshold) { + by_block_id_index.modify(curr_itr, + [&](const validation_state_ptr &p) { p->enough = true; }); + } } } } From 144b4a9f0f6a91791aeb92f5912cac6449835383 Mon Sep 17 00:00:00 2001 From: oldcold Date: Sun, 22 Sep 2019 16:30:51 +0800 Subject: [PATCH 30/37] Fix pbft certifications (#127) * fix pbft cert generation and validation * attempt to fix bad prepared cert * fix longest fork threshold * redo cert validation * refactor validation, add comments * clean up longest fork validation * add watermark check --- .../include/eosio/chain/pbft_database.hpp | 40 ++- libraries/chain/pbft_database.cpp | 237 ++++++++---------- 2 files changed, 145 insertions(+), 132 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 6b4bb2cd7a9..3bc63bc3737 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -332,9 +332,19 @@ namespace eosio { bool is_stable = false; }; + using producer_and_block_info = std::pair; + + struct validation_state { + block_id_type block_id; + block_num_type block_num = 0; + vector producers; + bool enough = false; + }; + using pbft_state_ptr = std::shared_ptr; using pbft_view_change_state_ptr = std::shared_ptr; using pbft_checkpoint_state_ptr = std::shared_ptr; + using validation_state_ptr = std::shared_ptr; struct by_block_id; struct by_num; @@ -414,6 +424,28 @@ namespace eosio { > > pbft_checkpoint_state_multi_index_type; + struct by_block_id; + struct by_status_and_num; + typedef multi_index_container< + validation_state_ptr, + indexed_by< + hashed_unique < + tag, + member, + std::hash + >, + ordered_non_unique< + tag, + composite_key< + validation_state, + member, + member + >, + composite_key_compare< greater<>, greater<> > + > + > + > local_state_multi_index_type; + class pbft_database { public: explicit pbft_database(controller& ctrl); @@ -503,16 +535,13 @@ namespace eosio { bool is_less_than_high_watermark(block_num_type bnum); bool is_valid_prepared_certificate(const pbft_prepared_certificate& certificate, bool add_to_pbft_db = false); bool is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db = false); - bool is_valid_longest_fork(const block_info_type& bi, fork_info_type& block_infos, unsigned long threshold, unsigned long non_fork_bp_count); + bool is_valid_longest_fork(const vector& producers, const block_info_type& cert_info); 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(fork_info_type& block_infos); - fork_info_type fetch_first_fork_from(fork_info_type& bi); - void set(const pbft_state_ptr& s); void set(const pbft_checkpoint_state_ptr& s); void prune(const pbft_state_ptr& h); @@ -542,4 +571,5 @@ FC_REFLECT(eosio::chain::pbft_stable_checkpoint, (block_info)(checkpoints)) FC_REFLECT(eosio::chain::pbft_state, (block_id)(block_num)(prepares)(is_prepared)(commits)(is_committed)) FC_REFLECT(eosio::chain::pbft_view_change_state, (view)(view_changes)(is_view_changed)) -FC_REFLECT(eosio::chain::pbft_checkpoint_state, (block_id)(block_num)(checkpoints)(is_stable)) \ No newline at end of file +FC_REFLECT(eosio::chain::pbft_checkpoint_state, (block_id)(block_num)(checkpoints)(is_stable)) +FC_REFLECT(eosio::chain::validation_state, (block_id)(block_num)(producers)(enough)) \ No newline at end of file diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 84c7a70bcca..e48c3195a9e 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -650,12 +650,14 @@ namespace eosio { for (const auto& pre: prepares) { if (prepare_count.find(pre.first.first) == prepare_count.end()) prepare_count[pre.first.first] = 0; - prepare_msg[pre.first.first].emplace_back(pre.second); } for (const auto& bp: as) { for (const auto& pp: prepares) { - if (bp.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; + prepare_msg[pp.first.first].emplace_back(pp.second); + } } } @@ -737,12 +739,14 @@ namespace eosio { for (const auto& com: commits) { if (commit_count.find(com.first.first) == commit_count.end()) commit_count[com.first.first] = 0; - commit_msg[com.first.first].emplace_back(com.second); } for (const auto& bp: as) { for (const auto& cc: commits) { - if (bp.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; + commit_msg[cc.first.first].emplace_back(cc.second); + } } } @@ -773,11 +777,15 @@ namespace eosio { auto pvs = *itr; + auto lscb_bps = lscb_active_producers().producers; + if (pvs->is_view_changed) { pvcc.target_view=pvs->view; pvcc.view_changes.reserve(pvs->view_changes.size()); - for(auto& view_change : pvs->view_changes) { - pvcc.view_changes.emplace_back( view_change.second ); + for (auto& bp : lscb_bps) { + for(auto& view_change : pvs->view_changes) { + if (bp.block_signing_key == view_change.first) pvcc.view_changes.emplace_back(view_change.second); + } } } return pvcc; @@ -798,8 +806,7 @@ namespace eosio { for (auto& p : prepares) { auto pmm = pbft_message_metadata(p, chain_id); prepares_metadata.emplace_back(pmm); - if (!is_valid_prepare(p, pmm.sender_key)) return false; - if (add_to_pbft_db) add_pbft_prepare(p, pmm.sender_key); + if ( add_to_pbft_db && is_valid_prepare(p, pmm.sender_key) ) add_pbft_prepare(p, pmm.sender_key); } auto cert_id = certificate.block_info.block_id; @@ -811,41 +818,35 @@ namespace eosio { auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; flat_map prepare_count; + flat_map> prepare_msg; for (const auto& pm: prepares_metadata) { - if (prepare_count.find(pm.msg.view) == prepare_count.end()) prepare_count[pm.msg.view] = 0; + if (prepare_count.find(pm.msg.view) == prepare_count.end()) { + prepare_count[pm.msg.view] = 0; + prepare_msg[pm.msg.view].reserve(bp_threshold); + } } for (const auto& bp: producer_schedule.producers) { for (const auto& pm: prepares_metadata) { - if (bp.block_signing_key == pm.sender_key) prepare_count[pm.msg.view] += 1; + if (bp.block_signing_key == pm.sender_key) { + prepare_count[pm.msg.view] += 1; + prepare_msg[pm.msg.view].emplace_back(std::make_pair(pm.sender_key, pm.msg.block_info)); + } } } auto should_prepared = false; - + auto valid_prepares = vector{}; + valid_prepares.reserve(bp_threshold); for (const auto& e: prepare_count) { if (e.second >= bp_threshold) { should_prepared = true; + valid_prepares = prepare_msg[e.first]; } } - if (!should_prepared) return false; - - //validate prepare - auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - auto non_fork_bp_count = 0; - fork_info_type prepare_infos; - prepare_infos.reserve(certificate.prepares.size()); - for (const auto& p : certificate.prepares) { - //only search in fork db - if (p.block_info.block_num() <= lscb_num) { - ++non_fork_bp_count; - } else { - prepare_infos.emplace_back(p.block_info); - } - } - return is_valid_longest_fork(certificate.block_info, prepare_infos, bp_threshold, non_fork_bp_count); + return should_prepared && is_valid_longest_fork(valid_prepares, certificate.block_info); } bool pbft_database::is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db) { @@ -861,8 +862,7 @@ namespace eosio { for (auto& c : commits) { auto pmm = pbft_message_metadata(c, chain_id); commits_metadata.emplace_back(pmm); - if (!is_valid_commit(c, pmm.sender_key)) return false; - if (add_to_pbft_db) add_pbft_commit(c, pmm.sender_key); + if (add_to_pbft_db && is_valid_commit(c, pmm.sender_key)) add_pbft_commit(c, pmm.sender_key); } auto cert_id = certificate.block_info.block_id; @@ -874,41 +874,106 @@ namespace eosio { auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; flat_map commit_count; + flat_map> commit_msg; for (const auto& cm: commits_metadata) { - if (commit_count.find(cm.msg.view) == commit_count.end()) commit_count[cm.msg.view] = 0; + if (commit_count.find(cm.msg.view) == commit_count.end()) { + commit_count[cm.msg.view] = 0; + commit_msg[cm.msg.view].reserve(bp_threshold); + } } for (const auto& bp: producer_schedule.producers) { for (const auto& cm: commits_metadata) { - if (bp.block_signing_key == cm.sender_key) commit_count[cm.msg.view] += 1; + if (bp.block_signing_key == cm.sender_key) { + commit_count[cm.msg.view] += 1; + commit_msg[cm.msg.view].emplace_back(std::make_pair(cm.sender_key, cm.msg.block_info)); + } } } auto should_committed = false; - + auto valid_commits = vector{}; + valid_commits.reserve(bp_threshold); for (const auto& e: commit_count) { if (e.second >= bp_threshold) { should_committed = true; + valid_commits = commit_msg[e.first]; } } - if (!should_committed) return false; + return should_committed && is_valid_longest_fork(valid_commits, certificate.block_info); + } - //validate commit - auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - auto non_fork_bp_count = 0; - fork_info_type commit_infos; - commit_infos.reserve(certificate.commits.size()); - for (const auto& c : certificate.commits) { - //only search in fork db - if (c.block_info.block_num() <= lscb_num) { - ++non_fork_bp_count; - } else { - commit_infos.emplace_back(c.block_info); + bool pbft_database::is_valid_longest_fork(const vector& block_infos, const block_info_type& cert_info) { + + //add all valid block_infos in to a temp multi_index, this implementation might contains heavier computation + auto local_index = local_state_multi_index_type(); + auto& by_block_id_index = local_index.get(); + auto watermark = get_current_pbft_watermark(); + for (auto &e: block_infos) { + + auto current = ctrl.fetch_block_state_by_id(e.second.block_id); + + while ( current ) { + if (watermark == 0 || current->block_num <= watermark) { + auto curr_itr = by_block_id_index.find(current->id); + + if (curr_itr == by_block_id_index.end()) { + try { + vector keys; + keys.reserve(block_infos.size()); + keys.emplace_back(e.first); + validation_state curr_ps; + curr_ps.block_id = current->id; + curr_ps.block_num = current->block_num; + curr_ps.producers = keys; + auto curr_psp = std::make_shared(move(curr_ps)); + local_index.insert(curr_psp); + } catch (...) {} + } else { + auto keys = (*curr_itr)->producers; + if (std::find(keys.begin(), keys.end(), e.first) == keys.end()) { + by_block_id_index.modify(curr_itr, [&](const validation_state_ptr &vsp) { + vsp->producers.emplace_back(e.first); + }); + } + } + + curr_itr = by_block_id_index.find(current->id); + if (curr_itr != by_block_id_index.end()) { + + auto cpsp = *curr_itr; + + auto as = current->active_schedule.producers; + auto threshold = as.size() * 2 / 3 + 1; + auto keys = cpsp->producers; + if (keys.size() >= threshold && !cpsp->enough) { + uint32_t count = 0; + + for (const auto &bp: as) { + for (const auto &k: keys) { + if (bp.block_signing_key == k) count += 1; + } + } + + if (count >= threshold) { + by_block_id_index.modify(curr_itr, + [&](const validation_state_ptr &p) { p->enough = true; }); + } + } + } + } + current = ctrl.fetch_block_state_by_id(current->prev()); } } - return is_valid_longest_fork(certificate.block_info, commit_infos, bp_threshold, non_fork_bp_count); + const auto& by_status_and_num_index = local_index.get(); + auto itr = by_status_and_num_index.begin(); + if (itr == by_status_and_num_index.end()) return false; + + validation_state_ptr psp = *itr; + + return psp->enough && psp->block_id == cert_info.block_id; } bool pbft_database::is_valid_view_change(const pbft_view_change& vc, const public_key_type& pk) { @@ -1022,88 +1087,6 @@ namespace eosio { return vc_lscb > 0 && lscb_num > vc_lscb; } - vector pbft_database::fetch_fork_from(fork_info_type& block_infos) { - - vector result; - if (block_infos.empty()) { - return result; - } - if (block_infos.size() == 1) { - result.emplace_back(initializer_list{block_infos.front()}); - return result; - } - - sort(block_infos.begin(), block_infos.end(), - [](const block_info_type& a, const block_info_type& b) -> bool { return a.block_num() > b.block_num(); }); - - while (!block_infos.empty()) { - auto fork = fetch_first_fork_from(block_infos); - if (!fork.empty()) { - result.emplace_back(fork); - } - } - return result; - } - - fork_info_type pbft_database::fetch_first_fork_from(fork_info_type& bi) { - fork_info_type result; - if (bi.empty()) { - return result; - } - if (bi.size() == 1) { - result.emplace_back(bi.front()); - bi.clear(); - return result; - } - //bi should be sorted desc - auto high = bi.front().block_num(); - auto low = bi.back().block_num(); - - auto id = bi.front().block_id; - auto num = bi.front().block_num(); - while (num <= high && num >= low && !bi.empty()) { - auto bs = ctrl.fetch_block_state_by_id(id); - - for (auto it = bi.begin(); it != bi.end();) { - if (it->block_id == id) { - if (bs) { - //add to result only if b exist - result.emplace_back((*it)); - } - it = bi.erase(it); - } else { - it++; - } - } - if (bs) { - id = bs->prev(); - num--; - } else { - break; - } - } - - return result; - } - - bool pbft_database::is_valid_longest_fork( - const block_info_type& bi, - fork_info_type& block_infos, - unsigned long threshold, - unsigned long non_fork_bp_count) { - - auto forks = fetch_fork_from(block_infos); - fork_info_type longest_fork; - for (const auto& f : forks) { - if (f.size() > longest_fork.size()) { - longest_fork = f; - } - } - - return longest_fork.empty() - || (longest_fork.size() + non_fork_bp_count >= threshold && bi.block_id == longest_fork.back().block_id); - } - pbft_stable_checkpoint pbft_database::fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr& b) { pbft_stable_checkpoint psc; From 9a0957691c51d8f6805cde544db1499a3fb53bfe Mon Sep 17 00:00:00 2001 From: thaipandada Date: Sun, 22 Sep 2019 17:25:05 +0800 Subject: [PATCH 31/37] prepare 3.0.3-rc1 --- CMakeLists.txt | 2 +- Docker/README.md | 4 ++-- README.md | 2 +- README_CN.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2276554450b..2039df3546f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,7 @@ set( CXX_STANDARD_REQUIRED ON) set(VERSION_MAJOR 3) set(VERSION_MINOR 0) -set(VERSION_PATCH 2) +set(VERSION_PATCH 3) if(VERSION_SUFFIX) set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}") diff --git a/Docker/README.md b/Docker/README.md index c06694deffb..d5927cd13e1 100644 --- a/Docker/README.md +++ b/Docker/README.md @@ -20,10 +20,10 @@ cd bos/Docker docker build . -t boscore/bos -s BOS ``` -The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v3.0.2 tag, you could do the following: +The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v3.0.3-rc1 tag, you could do the following: ```bash -docker build -t boscore/bos:v3.0.2 --build-arg branch=v3.0.2 . +docker build -t boscore/bos:v3.0.3-rc1 --build-arg branch=v3.0.3-rc1 . ``` diff --git a/README.md b/README.md index 334f7cad8e0..d0ef2cc4ce8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # BOSCore - Born for DApps. Born for Usability. -## BOSCore Version: v3.0.2 +## BOSCore Version: v3.0.3-rc1 ### Basic EOSIO Version: v1.6.6 (support REX) # Background diff --git a/README_CN.md b/README_CN.md index f7b893a12f7..8f637894f3a 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,6 +1,6 @@ # BOSCore - 更可用的链,为DApp而生。 -## BOSCore Version: v3.0.2 +## BOSCore Version: v3.0.3-rc1 ### Basic EOSIO Version: v1.6.6 (support REX) # 背景 From fbee0348c05872cb943b1e56dfa410280cd3b7c2 Mon Sep 17 00:00:00 2001 From: oldcold Date: Mon, 23 Sep 2019 19:45:19 +0800 Subject: [PATCH 32/37] further fix on commit certs generation and validation --- libraries/chain/pbft_database.cpp | 82 ++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 13 deletions(-) diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index e48c3195a9e..3f1c947bbf4 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -597,21 +597,41 @@ namespace eosio { auto highest_pcc = vector{}; auto highest_sc = pbft_stable_checkpoint(); + vector ccb; + auto watermarks = get_updated_watermarks(); + for (auto& watermark : watermarks) { + //collecting committed cert on every water mark. + if (watermark > ctrl.last_stable_checkpoint_block_num()) { + ccb.emplace_back(watermark); + } + } + + block_num_type highest_lib = 0; + pbft_committed_certificate highest_lib_pcc; for (const auto& vc: vcc.view_changes) { if (vc.prepared_cert.block_info.block_num() > highest_ppc.block_info.block_num()) { highest_ppc = vc.prepared_cert; } for (const auto& cc: vc.committed_certs) { + if (cc.block_info.block_num() > highest_lib) { + highest_lib_pcc = 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); + [&](const pbft_committed_certificate& ext) { + return ext.block_info.block_id == cc.block_info.block_id; + }); + if (p_itr == highest_pcc.end() //unique block num + && std::find(watermarks.begin(), watermarks.end(), cc.block_info.block_num()) != watermarks.end()) { // and it is a watermark + highest_pcc.emplace_back(cc); + } } if (vc.stable_checkpoint.block_info.block_num() > highest_sc.block_info.block_num()) { highest_sc = vc.stable_checkpoint; } } + highest_pcc.emplace_back(highest_lib_pcc); nv.new_view = new_view; nv.prepared_cert = highest_ppc; @@ -796,8 +816,8 @@ namespace eosio { 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; + // a certificate under lib is also treated as null. + if (certificate.block_info.block_num() <= ctrl.last_irreversible_block_num()) return true; auto prepares = certificate.prepares; auto prepares_metadata = vector>{}; @@ -910,13 +930,24 @@ namespace eosio { //add all valid block_infos in to a temp multi_index, this implementation might contains heavier computation auto local_index = local_state_multi_index_type(); auto& by_block_id_index = local_index.get(); - auto watermark = get_current_pbft_watermark(); + + vector ccb; + auto past_watermarks = get_updated_watermarks(); + for (auto& w : past_watermarks) { + //adding committed cert on every water mark. + if (w < ctrl.last_irreversible_block_num()) { + ccb.emplace_back(w); + } + } + + auto next_watermark = get_current_pbft_watermark(); + for (auto &e: block_infos) { auto current = ctrl.fetch_block_state_by_id(e.second.block_id); while ( current ) { - if (watermark == 0 || current->block_num <= watermark) { + if (next_watermark == 0 || current->block_num <= next_watermark) { auto curr_itr = by_block_id_index.find(current->id); if (curr_itr == by_block_id_index.end()) { @@ -959,7 +990,7 @@ namespace eosio { if (count >= threshold) { by_block_id_index.modify(curr_itr, - [&](const validation_state_ptr &p) { p->enough = true; }); + [&](const validation_state_ptr &p) { p->enough = true; }); } } } @@ -967,13 +998,20 @@ namespace eosio { current = ctrl.fetch_block_state_by_id(current->prev()); } } - const auto& by_status_and_num_index = local_index.get(); - auto itr = by_status_and_num_index.begin(); - if (itr == by_status_and_num_index.end()) return false; - validation_state_ptr psp = *itr; + if (std::find(ccb.begin(), ccb.end(), cert_info.block_num()) != ccb.end()) { + auto itr = by_block_id_index.find(cert_info.block_id); + if (itr == by_block_id_index.end()) return false; + return (*itr)->enough; + + } else { + const auto &by_status_and_num_index = local_index.get(); + auto itr = by_status_and_num_index.begin(); + if (itr == by_status_and_num_index.end()) return false; - return psp->enough && psp->block_id == cert_info.block_id; + validation_state_ptr psp = *itr; + return psp->enough && psp->block_id == cert_info.block_id; + } } bool pbft_database::is_valid_view_change(const pbft_view_change& vc, const public_key_type& pk) { @@ -1041,6 +1079,17 @@ namespace eosio { auto highest_pcc = vector{}; auto highest_scp = pbft_stable_checkpoint(); + vector ccb; + auto watermarks = get_updated_watermarks(); + for (auto& watermark : watermarks) { + //collecting committed cert on every water mark. + if (watermark > ctrl.last_stable_checkpoint_block_num()) { + ccb.emplace_back(watermark); + } + } + + block_num_type highest_lib = 0; + pbft_committed_certificate highest_lib_pcc; for (const auto& vc: nv.view_changed_cert.view_changes) { if (vc.prepared_cert.block_info.block_num() > highest_ppc.block_info.block_num() && is_valid_prepared_certificate(vc.prepared_cert)) { @@ -1049,11 +1098,17 @@ namespace eosio { for (const auto& cc: vc.committed_certs) { if (is_valid_committed_certificate(cc)) { + if (cc.block_info.block_num() > highest_lib) { + highest_lib_pcc = 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); + if (p_itr == highest_pcc.end() //unique block num + && std::find(watermarks.begin(), watermarks.end(), cc.block_info.block_num()) != watermarks.end()) { // and it is a watermark + highest_pcc.emplace_back(cc); + } } } @@ -1062,6 +1117,7 @@ namespace eosio { highest_scp = vc.stable_checkpoint; } } + highest_pcc.emplace_back(highest_lib_pcc); EOS_ASSERT(highest_ppc.block_info == nv.prepared_cert.block_info, pbft_exception, "prepared certificate does not match, should be ${hppc} but ${pc} given", From 2e097505fa56580a1c1acc3fbec9517a5e43e9f2 Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 25 Sep 2019 12:10:12 +0800 Subject: [PATCH 33/37] fix finding max committed certs block num --- libraries/chain/pbft_database.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 395c1acc21d..4321eaae991 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -616,6 +616,7 @@ namespace eosio { for (const auto& cc: vc.committed_certs) { if (cc.block_info.block_num() > highest_lib) { highest_lib_pcc = cc; + highest_lib = cc.block_info.block_num(); } auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), [&](const pbft_committed_certificate& ext) { @@ -1101,6 +1102,7 @@ namespace eosio { if (is_valid_committed_certificate(cc)) { if (cc.block_info.block_num() > highest_lib) { highest_lib_pcc = cc; + highest_lib = cc.block_info.block_num(); } auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), [&](const pbft_committed_certificate& ext) { From e73c33311eb357163957fff8a71feb7e906c4963 Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 25 Sep 2019 21:20:01 +0800 Subject: [PATCH 34/37] highest committed cert block id should be strictly equal to the one from evidences --- libraries/chain/pbft_database.cpp | 71 ++++++------------------------- 1 file changed, 14 insertions(+), 57 deletions(-) diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 4321eaae991..c8ebab42447 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -597,42 +597,21 @@ namespace eosio { auto highest_pcc = vector{}; auto highest_sc = pbft_stable_checkpoint(); - vector ccb; - auto watermarks = get_updated_watermarks(); - for (auto& watermark : watermarks) { - //collecting committed cert on every water mark. - if (watermark > ctrl.last_stable_checkpoint_block_num()) { - ccb.emplace_back(watermark); - } - } - - block_num_type highest_lib = 0; - pbft_committed_certificate highest_lib_pcc; for (const auto& vc: vcc.view_changes) { if (vc.prepared_cert.block_info.block_num() > highest_ppc.block_info.block_num()) { highest_ppc = vc.prepared_cert; } for (const auto& cc: vc.committed_certs) { - if (cc.block_info.block_num() > highest_lib) { - highest_lib_pcc = cc; - highest_lib = cc.block_info.block_num(); - } 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() //unique block num - && std::find(watermarks.begin(), watermarks.end(), cc.block_info.block_num()) != watermarks.end()) { // and it is a watermark - highest_pcc.emplace_back(cc); - } + [&](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()) { highest_sc = vc.stable_checkpoint; } } - highest_pcc.emplace_back(highest_lib_pcc); nv.new_view = new_view; nv.prepared_cert = highest_ppc; @@ -867,10 +846,10 @@ namespace eosio { } } - return should_prepared && is_valid_longest_fork(valid_prepares, certificate.block_info); + return should_prepared && is_valid_longest_fork(valid_prepares, certificate.block_info, true); } - bool pbft_database::is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db) { + bool pbft_database::is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db, bool at_the_top) { // 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. @@ -923,24 +902,15 @@ namespace eosio { } } - return should_committed && is_valid_longest_fork(valid_commits, certificate.block_info); + return should_committed && is_valid_longest_fork(valid_commits, certificate.block_info, at_the_top); } - bool pbft_database::is_valid_longest_fork(const vector& block_infos, const block_info_type& cert_info) { + bool pbft_database::is_valid_longest_fork(const vector& block_infos, const block_info_type& cert_info, bool at_the_top ) { //add all valid block_infos in to a temp multi_index, this implementation might contains heavier computation auto local_index = local_state_multi_index_type(); auto& by_block_id_index = local_index.get(); - vector ccb; - auto past_watermarks = get_updated_watermarks(); - for (auto& w : past_watermarks) { - //adding committed cert on every water mark. - if (w < ctrl.last_irreversible_block_num()) { - ccb.emplace_back(w); - } - } - auto next_watermark = get_current_pbft_watermark(); for (auto &e: block_infos) { @@ -1001,7 +971,7 @@ namespace eosio { } } - if (std::find(ccb.begin(), ccb.end(), cert_info.block_num()) != ccb.end()) { + if (!at_the_top) { auto itr = by_block_id_index.find(cert_info.block_id); if (itr == by_block_id_index.end()) return false; return (*itr)->enough; @@ -1081,17 +1051,6 @@ namespace eosio { auto highest_pcc = vector{}; auto highest_scp = pbft_stable_checkpoint(); - vector ccb; - auto watermarks = get_updated_watermarks(); - for (auto& watermark : watermarks) { - //collecting committed cert on every water mark. - if (watermark > ctrl.last_stable_checkpoint_block_num()) { - ccb.emplace_back(watermark); - } - } - - block_num_type highest_lib = 0; - pbft_committed_certificate highest_lib_pcc; for (const auto& vc: nv.view_changed_cert.view_changes) { if (vc.prepared_cert.block_info.block_num() > highest_ppc.block_info.block_num() && is_valid_prepared_certificate(vc.prepared_cert)) { @@ -1100,18 +1059,11 @@ namespace eosio { for (const auto& cc: vc.committed_certs) { if (is_valid_committed_certificate(cc)) { - if (cc.block_info.block_num() > highest_lib) { - highest_lib_pcc = cc; - highest_lib = cc.block_info.block_num(); - } 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() //unique block num - && std::find(watermarks.begin(), watermarks.end(), cc.block_info.block_num()) != watermarks.end()) { // and it is a watermark - highest_pcc.emplace_back(cc); - } + if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); } } @@ -1120,7 +1072,6 @@ namespace eosio { highest_scp = vc.stable_checkpoint; } } - highest_pcc.emplace_back(highest_lib_pcc); EOS_ASSERT(highest_ppc.block_info == nv.prepared_cert.block_info, pbft_exception, "prepared certificate does not match, should be ${hppc} but ${pc} given", @@ -1135,6 +1086,12 @@ namespace eosio { ("hpcc", highest_pcc[i])("cc", committed_certs[i])); } + if (!committed_certs.empty()) { + EOS_ASSERT(is_valid_committed_certificate(committed_certs.back(), false, true), pbft_exception, + "highest committed certificate is invalid, ${cc}", + ("cc", committed_certs.back())); + } + 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)); From 6c8470dc2c66d4c23c635d12d742ad3181a39419 Mon Sep 17 00:00:00 2001 From: thaipandada Date: Wed, 25 Sep 2019 21:40:24 +0800 Subject: [PATCH 35/37] merge EOSIO ##7979 --- libraries/chain/include/eosio/chain/wasm_eosio_injection.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/chain/include/eosio/chain/wasm_eosio_injection.hpp b/libraries/chain/include/eosio/chain/wasm_eosio_injection.hpp index a67ca9ef696..d7a64f809d0 100644 --- a/libraries/chain/include/eosio/chain/wasm_eosio_injection.hpp +++ b/libraries/chain/include/eosio/chain/wasm_eosio_injection.hpp @@ -761,6 +761,7 @@ namespace eosio { namespace chain { namespace wasm_injections { struct post_op_injectors : wasm_ops::op_types { using loop_t = wasm_ops::loop ; using call_t = wasm_ops::call ; + using grow_memory_t = wasm_ops::grow_memory ; }; template From 91ba180e319d57f573d3abc3a1746ecc67bf8ee6 Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 25 Sep 2019 22:09:05 +0800 Subject: [PATCH 36/37] add missing file --- libraries/chain/include/eosio/chain/pbft_database.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 3bc63bc3737..fd38f9e9330 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -534,8 +534,8 @@ namespace eosio { block_info_type cal_pending_stable_checkpoint() const; bool is_less_than_high_watermark(block_num_type bnum); bool is_valid_prepared_certificate(const pbft_prepared_certificate& certificate, bool add_to_pbft_db = false); - bool is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db = false); - bool is_valid_longest_fork(const vector& producers, const block_info_type& cert_info); + bool is_valid_committed_certificate(const pbft_committed_certificate& certificate, bool add_to_pbft_db = false, bool at_the_top = false); + bool is_valid_longest_fork(const vector& producers, const block_info_type& cert_info, bool at_the_top = false); producer_schedule_type lscb_active_producers() const; vector& get_updated_watermarks(); From 4dd90055176068d4c815747d9aed022d477e3f19 Mon Sep 17 00:00:00 2001 From: thaipandada Date: Thu, 3 Oct 2019 20:50:58 +0800 Subject: [PATCH 37/37] PBFT validation fixes --- Docker/README.md | 4 ++-- README.md | 2 +- README_CN.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Docker/README.md b/Docker/README.md index d5927cd13e1..087105fed7b 100644 --- a/Docker/README.md +++ b/Docker/README.md @@ -20,10 +20,10 @@ cd bos/Docker docker build . -t boscore/bos -s BOS ``` -The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v3.0.3-rc1 tag, you could do the following: +The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v3.0.3 tag, you could do the following: ```bash -docker build -t boscore/bos:v3.0.3-rc1 --build-arg branch=v3.0.3-rc1 . +docker build -t boscore/bos:v3.0.3 --build-arg branch=v3.0.3 . ``` diff --git a/README.md b/README.md index d0ef2cc4ce8..cab40f08390 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # BOSCore - Born for DApps. Born for Usability. -## BOSCore Version: v3.0.3-rc1 +## BOSCore Version: v3.0.3 ### Basic EOSIO Version: v1.6.6 (support REX) # Background diff --git a/README_CN.md b/README_CN.md index 8f637894f3a..5603854c913 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,6 +1,6 @@ # BOSCore - 更可用的链,为DApp而生。 -## BOSCore Version: v3.0.3-rc1 +## BOSCore Version: v3.0.3 ### Basic EOSIO Version: v1.6.6 (support REX) # 背景