From f6222541151cba44a785dd323899b55c18b9e0da Mon Sep 17 00:00:00 2001 From: oldcold Date: Tue, 30 Apr 2019 21:55:33 +0800 Subject: [PATCH 1/9] bug fix: sort vectors before intersection. --- libraries/chain/pbft_database.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 6d6f7b4e575..b11afe061bb 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -786,6 +786,9 @@ namespace eosio { } vector intersection; + + std::sort(lib_producers.begin(),lib_producers.end()); + std::sort(view_change_producers.begin(),view_change_producers.end()); std::set_intersection(lib_producers.begin(),lib_producers.end(), view_change_producers.begin(),view_change_producers.end(), back_inserter(intersection)); From 707e8c91dae88d448730b6aa874b3146ed4aceda Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 1 May 2019 11:05:53 +0800 Subject: [PATCH 2/9] force attempt to switch forks upon set_pbft_lib. --- libraries/chain/controller.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 93c5b0c63fb..a1ca3f5bb0a 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1664,10 +1664,10 @@ struct controller_impl { if ((!pending || pending->_block_status != controller::block_status::incomplete) && pending_pbft_lib ) { fork_db.set_bft_irreversible(*pending_pbft_lib); pending_pbft_lib.reset(); + } - if (read_mode != db_read_mode::IRREVERSIBLE) { - maybe_switch_forks(controller::block_status::complete); - } + if (read_mode != db_read_mode::IRREVERSIBLE) { + maybe_switch_forks(controller::block_status::complete); } } From 822201b1200ed2a8265ed1229f6fdd7a14eeffac Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 1 May 2019 21:03:08 +0800 Subject: [PATCH 3/9] attempt to switch forks after mark fork db. --- libraries/chain/controller.cpp | 23 +++++++++++++------ .../chain/include/eosio/chain/controller.hpp | 7 +++--- .../include/eosio/chain/pbft_database.hpp | 3 ++- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index a1ca3f5bb0a..91eacfe5390 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1664,10 +1664,10 @@ struct controller_impl { if ((!pending || pending->_block_status != controller::block_status::incomplete) && pending_pbft_lib ) { fork_db.set_bft_irreversible(*pending_pbft_lib); pending_pbft_lib.reset(); - } - if (read_mode != db_read_mode::IRREVERSIBLE) { - maybe_switch_forks(controller::block_status::complete); + if (read_mode != db_read_mode::IRREVERSIBLE) { + maybe_switch_forks(controller::block_status::complete); + } } } @@ -1698,7 +1698,7 @@ struct controller_impl { void maybe_switch_forks( controller::block_status s ) { auto new_head = fork_db.head(); - if( new_head->header.previous == head->id ) { + if( new_head->header.previous == head->id && !pending) { try { apply_block( new_head->block, s ); fork_db.mark_in_current_chain( new_head, true ); @@ -2520,21 +2520,23 @@ chain_id_type controller::get_chain_id()const { return my->chain_id; } -void controller::set_pbft_prepared(const block_id_type& id) const { +void controller::set_pbft_prepared(const block_id_type& id) { my->pbft_prepared.reset(); auto bs = fetch_block_state_by_id(id); if (bs) { my->pbft_prepared = bs; my->fork_db.mark_pbft_prepared_fork(bs); + maybe_switch_forks(); } } -void controller::set_pbft_my_prepare(const block_id_type& id) const { +void controller::set_pbft_my_prepare(const block_id_type& id) { my->my_prepare.reset(); auto bs = fetch_block_state_by_id(id); if (bs) { my->my_prepare = bs; my->fork_db.mark_pbft_my_prepare_fork(bs); + maybe_switch_forks(); } } @@ -2543,8 +2545,9 @@ block_id_type controller::get_pbft_my_prepare() const { return block_id_type{}; } -void controller::reset_pbft_my_prepare() const { +void controller::reset_pbft_my_prepare() { my->fork_db.remove_pbft_my_prepare_fork(); + maybe_switch_forks(); if (my->my_prepare) my->my_prepare.reset(); } @@ -2711,6 +2714,12 @@ bool controller::under_upgrade() const { return my->is_upgrading(); } +void controller::maybe_switch_forks() { + if (my->read_mode != db_read_mode::IRREVERSIBLE) { + my->maybe_switch_forks(controller::block_status::complete); + } +} + // this will be used in unit_test only, should not be called anywhere else. void controller::set_upo(uint32_t target_block_num) { try { diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 392a052819d..d2172f683ab 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -289,10 +289,11 @@ namespace eosio { namespace chain { producer_schedule_type initial_schedule()const; bool is_replaying()const; - void set_pbft_prepared(const block_id_type& id)const; - void set_pbft_my_prepare(const block_id_type& id)const; + void set_pbft_prepared(const block_id_type& id); + void set_pbft_my_prepare(const block_id_type& id); block_id_type get_pbft_my_prepare()const; - void reset_pbft_my_prepare()const; + void reset_pbft_my_prepare(); + void maybe_switch_forks(); signal pre_accepted_block; signal accepted_block_header; diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 01c36132a6b..33e0a54f558 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -597,8 +597,9 @@ namespace eosio { bool should_stop_view_change(const pbft_view_change &vc); block_num_type get_current_pbft_watermark(); - controller &ctrl; + private: + 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; From 41c8d6f19609362b3fb880a1dbd60776af0f9a35 Mon Sep 17 00:00:00 2001 From: oldcold Date: Thu, 2 May 2019 23:44:16 +0800 Subject: [PATCH 4/9] add committed cert info view change & new view; --- libraries/chain/controller.cpp | 6 +- libraries/chain/include/eosio/chain/pbft.hpp | 5 + .../include/eosio/chain/pbft_database.hpp | 60 ++++- libraries/chain/pbft.cpp | 22 ++ libraries/chain/pbft_database.cpp | 252 ++++++++++++++++-- plugins/net_plugin/net_plugin.cpp | 4 +- 6 files changed, 316 insertions(+), 33 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 91eacfe5390..a1847a0b12b 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -351,6 +351,9 @@ struct controller_impl { void init(std::function shutdown, const snapshot_reader_ptr& snapshot) { + //do upgrade migration if necessary; + migrate_upgrade(); + bool report_integrity_hash = !!snapshot; if (snapshot) { EOS_ASSERT( !head, fork_database_exception, "" ); @@ -381,9 +384,6 @@ struct controller_impl { } } - //do upgrade migration if necessary; - migrate_upgrade(); - if( shutdown() ) return; const auto& ubi = reversible_blocks.get_index(); diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index bbca6a494ae..4d62f6c7507 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -14,6 +14,7 @@ namespace eosio { vector commits_cache; vector view_changes_cache; vector prepared_certificate; + vector> committed_certificate; vector view_changed_certificate; }; @@ -73,6 +74,10 @@ namespace eosio { void set_prepared_certificate(const vector &prepared_certificate); + const vector> &get_committed_certificate() const; + + void set_committed_certificate(const vector> &pbft_committed_certificate_vector); + const vector &get_view_changed_certificate() const; void set_view_changed_certificate(const vector &view_changed_certificate); diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 33e0a54f558..4e021700577 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -243,11 +243,51 @@ namespace eosio { } }; + struct pbft_committed_certificate { + block_id_type block_id; + block_num_type block_num = 0; + vector commits; + + public_key_type public_key; + signature_type producer_signature; + + bool operator==(const pbft_committed_certificate &rhs) const { + return block_num == rhs.block_num + && block_id == rhs.block_id + && commits == rhs.commits + && public_key == rhs.public_key; + } + + bool operator!=(const pbft_committed_certificate &rhs) const { + return !(*this == rhs); + } + + digest_type digest() const { + digest_type::encoder enc; + fc::raw::pack(enc, block_id); + fc::raw::pack(enc, block_num); + fc::raw::pack(enc, commits); + fc::raw::pack(enc, public_key); + return enc.result(); + } + + bool is_signature_valid() const { + try { + auto pk = crypto::public_key(producer_signature, digest(), true); + return public_key == pk; + } catch (fc::exception & /*e*/) { + return false; + } + } + }; + + struct pbft_view_change { string uuid; uint32_t current_view; uint32_t target_view; pbft_prepared_certificate prepared; + vector committed; pbft_stable_checkpoint stable_checkpoint; public_key_type public_key; chain_id_type chain_id = chain_id_type(""); @@ -258,6 +298,7 @@ namespace eosio { return current_view == rhs.current_view && target_view == rhs.target_view && prepared == rhs.prepared + && committed == rhs.committed && stable_checkpoint == rhs.stable_checkpoint && public_key == rhs.public_key && chain_id == rhs.chain_id @@ -277,6 +318,7 @@ namespace eosio { fc::raw::pack(enc, current_view); fc::raw::pack(enc, target_view); fc::raw::pack(enc, prepared); + fc::raw::pack(enc, committed); fc::raw::pack(enc, stable_checkpoint); fc::raw::pack(enc, public_key); fc::raw::pack(enc, chain_id); @@ -333,6 +375,7 @@ namespace eosio { string uuid; uint32_t view; pbft_prepared_certificate prepared; + vector committed; pbft_stable_checkpoint stable_checkpoint; pbft_view_changed_certificate view_changed; public_key_type public_key; @@ -343,6 +386,7 @@ namespace eosio { bool operator==(const pbft_new_view &rhs) const { return view == rhs.view && prepared == rhs.prepared + && committed == rhs.committed && stable_checkpoint == rhs.stable_checkpoint && view_changed == rhs.view_changed && public_key == rhs.public_key @@ -362,6 +406,7 @@ namespace eosio { digest_type::encoder enc; fc::raw::pack(enc, view); fc::raw::pack(enc, prepared); + fc::raw::pack(enc, committed); fc::raw::pack(enc, stable_checkpoint); fc::raw::pack(enc, view_changed); fc::raw::pack(enc, public_key); @@ -532,6 +577,7 @@ namespace eosio { vector send_and_add_pbft_view_change( const vector &vcv = vector{}, const vector &ppc = vector{}, + const vector> &pcc = vector>{}, uint32_t current_view = 0, uint32_t new_view = 1); @@ -557,6 +603,8 @@ namespace eosio { vector generate_prepared_certificate(); + vector> generate_committed_certificate(); + vector generate_view_changed_certificate(uint32_t target_view); pbft_stable_checkpoint get_stable_checkpoint_by_id(const block_id_type &block_id); @@ -596,6 +644,8 @@ namespace eosio { bool should_stop_view_change(const pbft_view_change &vc); + pbft_state_ptr get_pbft_state_by_id(const block_id_type& id)const; + block_num_type get_current_pbft_watermark(); private: @@ -610,13 +660,15 @@ namespace eosio { bool is_valid_prepared_certificate(const pbft_prepared_certificate &certificate); + bool is_valid_committed_certificate(const pbft_committed_certificate &certificate); + public_key_type get_new_view_primary_key(uint32_t target_view); vector> fetch_fork_from(vector block_infos); vector fetch_first_fork_from(vector &bi); - producer_schedule_type lib_active_producers() const; + producer_schedule_type lscb_active_producers() const; template void emit(const Signal &s, Arg &&a); @@ -638,12 +690,12 @@ FC_REFLECT(eosio::chain::pbft_prepare, FC_REFLECT(eosio::chain::pbft_commit, (uuid)(view)(block_num)(block_id)(public_key)(chain_id)(producer_signature)(timestamp)) FC_REFLECT(eosio::chain::pbft_view_change, - (uuid)(current_view)(target_view)(prepared)(stable_checkpoint)(public_key)(chain_id)(producer_signature)( - timestamp)) + (uuid)(current_view)(target_view)(prepared)(committed)(stable_checkpoint)(public_key)(chain_id)(producer_signature)(timestamp)) FC_REFLECT(eosio::chain::pbft_new_view, - (uuid)(view)(prepared)(stable_checkpoint)(view_changed)(public_key)(chain_id)(producer_signature)(timestamp)) + (uuid)(view)(prepared)(committed)(stable_checkpoint)(view_changed)(public_key)(chain_id)(producer_signature)(timestamp)) FC_REFLECT(eosio::chain::pbft_state, (block_id)(block_num)(prepares)(should_prepared)(commits)(should_committed)) FC_REFLECT(eosio::chain::pbft_prepared_certificate, (block_id)(block_num)(prepares)(public_key)(producer_signature)) +FC_REFLECT(eosio::chain::pbft_committed_certificate, (block_id)(block_num)(commits)(public_key)(producer_signature)) FC_REFLECT(eosio::chain::pbft_view_changed_certificate, (view)(view_changes)(public_key)(producer_signature)) FC_REFLECT(eosio::chain::pbft_checkpoint, (uuid)(block_num)(block_id)(public_key)(chain_id)(producer_signature)(timestamp)) diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 08c52087fd4..5e013ed1c24 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -509,6 +509,18 @@ namespace eosio { } } + if (!new_view.committed.empty()) { + for (auto cp :new_view.committed) { + for (auto c: cp.commits) { + try { + pbft_db.add_pbft_commit(c); + } catch (...) { + wlog( "commit insertion failure: ${cp}", ("cp", cp)); + } + } + } + } + if (!new_view.prepared.prepares.empty()) { for (auto p: new_view.prepared.prepares) { try { @@ -531,6 +543,7 @@ namespace eosio { if (this->get_target_view_retries() == 0) { this->set_view_changes_cache(vector{}); this->set_prepared_certificate(pbft_db.generate_prepared_certificate()); + this->set_committed_certificate(pbft_db.generate_committed_certificate()); } EOS_ASSERT((this->get_target_view() > this->get_current_view()), pbft_exception, @@ -547,6 +560,7 @@ namespace eosio { auto view_changes = pbft_db.send_and_add_pbft_view_change( this->get_view_changes_cache(), this->get_prepared_certificate(), + this->get_committed_certificate(), this->get_current_view(), this->get_target_view()); @@ -595,6 +609,14 @@ namespace eosio { this->cache.prepared_certificate = prepared_certificate; } + const vector> &psm_machine::get_committed_certificate() const { + return this->cache.committed_certificate; + } + + void psm_machine::set_committed_certificate(const vector> &pbft_committed_certificate_vector) { + this->cache.committed_certificate = pbft_committed_certificate_vector; + } + const vector &psm_machine::get_view_changed_certificate() const { return this->cache.view_changed_certificate; } diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index b11afe061bb..a0cf032b012 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -427,7 +427,7 @@ namespace eosio { void pbft_database::add_pbft_view_change(pbft_view_change &vc) { if (!is_valid_view_change(vc)) return; - auto active_bps = lib_active_producers().producers; + auto active_bps = lscb_active_producers().producers; auto &by_view_index = view_state_index.get(); auto itr = by_view_index.find(vc.target_view); @@ -472,7 +472,7 @@ namespace eosio { if (itr == by_view_index.end()) return nv; while (itr != by_view_index.end()) { - auto active_bps = lib_active_producers().producers; + auto active_bps = lscb_active_producers().producers; auto vc_count = 0; auto pvs = (*itr); @@ -494,6 +494,7 @@ namespace eosio { vector pbft_database::send_and_add_pbft_view_change( const vector &vcv, const vector &ppc, + const vector> &pcc, uint32_t current_view, uint32_t new_view) { if (!vcv.empty()) { @@ -517,9 +518,18 @@ namespace eosio { auto my_ppc = pbft_prepared_certificate{}; if (ppc_ptr != ppc.end()) my_ppc = *ppc_ptr; + + auto my_pcc = vector{}; + for (auto const &c: pcc) { + for (auto const &e: c) { + if (my_pcc.empty() && e.public_key == my_sp.first) { + my_pcc = c; + } + } + } auto my_lsc = get_stable_checkpoint_by_id(ctrl.last_stable_checkpoint_block_id()); auto uuid = boost::uuids::to_string(uuid_generator()); - auto vc = pbft_view_change{uuid, current_view, new_view, my_ppc, my_lsc, my_sp.first, chain_id()}; + auto vc = pbft_view_change{uuid, current_view, new_view, my_ppc, my_pcc, my_lsc, my_sp.first, chain_id()}; vc.producer_signature = my_sp.second(vc.digest()); emit(pbft_outgoing_view_change, vc); add_pbft_view_change(vc); @@ -553,7 +563,7 @@ namespace eosio { } void pbft_database::prune_pbft_index() { - pbft_state_index.clear(); +// pbft_state_index.clear(); view_state_index.clear(); ctrl.reset_pbft_my_prepare(); } @@ -575,6 +585,7 @@ namespace eosio { if (vcc_ptr == vcc.end()) return pbft_new_view{}; auto highest_ppc = pbft_prepared_certificate{}; + auto highest_pcc = vector{}; auto highest_sc = pbft_stable_checkpoint{}; for (const auto &vc: vcc_ptr->view_changes) { @@ -582,6 +593,14 @@ namespace eosio { highest_ppc = vc.prepared; } + for (auto const &cc: vc.committed) { + if (is_valid_committed_certificate(cc)) { + auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), + [&](const pbft_committed_certificate &ext) { return ext.block_id == cc.block_id; }); + if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); + } + } + if (vc.stable_checkpoint.block_num > highest_sc.block_num && is_valid_stable_checkpoint(vc.stable_checkpoint)) { highest_sc = vc.stable_checkpoint; @@ -590,7 +609,7 @@ namespace eosio { auto uuid = boost::uuids::to_string(uuid_generator()); - auto nv = pbft_new_view{uuid, current_view, highest_ppc, highest_sc, *vcc_ptr, sp_itr->first, chain_id()}; + auto nv = pbft_new_view{uuid, current_view, highest_ppc, highest_pcc, highest_sc, *vcc_ptr, sp_itr->first, chain_id()}; nv.producer_signature = sp_itr->second(nv.digest()); emit(pbft_outgoing_new_view, nv); @@ -643,6 +662,80 @@ namespace eosio { } else return vector{}; } + vector> pbft_database::generate_committed_certificate() { + auto pcc = vector>{}; + pcc.resize(ctrl.my_signature_providers().size()); + auto vc = vector{}; + 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 vector>{}; + pbft_state_ptr psp = *itr; + auto committed_block_num = psp->block_num; + + if (prepare_watermarks.empty() || committed_block_num < prepare_watermarks[0]) { + if (psp->should_committed && (committed_block_num > (ctrl.last_stable_checkpoint_block_num()))) { + for (auto const &my_sp : ctrl.my_signature_providers()) { + auto pc = pbft_committed_certificate{psp->block_id, psp->block_num, psp->commits, my_sp.first}; + pc.producer_signature = my_sp.second(pc.digest()); + for (auto &c: pcc) { + c.emplace_back(pc); + } + } + return pcc; + } else return vector>{}; + } + + const auto &by_id_index = pbft_state_index.get(); + + for (auto i = 0; i < prepare_watermarks.size() && prepare_watermarks[i] <= committed_block_num; ++i) { + auto cbs = ctrl.fetch_block_state_by_number(prepare_watermarks[i]); + if (cbs) { + auto it = by_id_index.find(cbs->id); + if (it == by_id_index.end() || !(*it)->should_committed) return vector>{}; + auto as = cbs->active_schedule.producers; + + auto commits = (*it)->commits; + auto valid_commits = vector{}; + + flat_map commit_count; + flat_map> commit_msg; + + for (const auto &com: commits) { + if (commit_count.find(com.view) == commit_count.end()) commit_count[com.view] = 0; + commit_msg[com.view].emplace_back(com); + } + + for (auto const &sp: as) { + for (auto const &cc: commits) { + if (sp.block_signing_key == cc.public_key) commit_count[cc.view] += 1; + } + } + + for (auto const &e: commit_count) { + if (e.second >= as.size() * 2 / 3 + 1) { + valid_commits = commit_msg[e.first]; + } + } + + if (valid_commits.empty()) return vector>{}; + + for (auto &c: valid_commits) { + vc.emplace_back(c); + } + + for (auto const &my_sp : ctrl.my_signature_providers()) { + auto pc = pbft_committed_certificate{cbs->id, cbs->block_num, vc, my_sp.first}; + pc.producer_signature = my_sp.second(pc.digest()); + for (auto &c: pcc) { + c.emplace_back(pc); + } + } + } else return vector>{}; + } + return pcc; + } + vector pbft_database::generate_view_changed_certificate(uint32_t target_view) { auto vcc = vector{}; @@ -662,7 +755,7 @@ namespace eosio { } else return vector{}; } - bool pbft_database::is_valid_prepared_certificate(const eosio::chain::pbft_prepared_certificate &certificate) { + bool pbft_database::is_valid_prepared_certificate(const pbft_prepared_certificate &certificate) { // an empty certificate is valid since it acts as a null digest in pbft. if (certificate == pbft_prepared_certificate{}) return true; // a certificate under lscb (no longer in fork_db) is also treated as null. @@ -677,7 +770,7 @@ namespace eosio { auto cert_id = certificate.block_id; auto cert_bs = ctrl.fetch_block_state_by_id(cert_id); - auto producer_schedule = lib_active_producers(); + auto producer_schedule = lscb_active_producers(); if (certificate.block_num > 0 && cert_bs) { producer_schedule = cert_bs->active_schedule; } @@ -744,6 +837,88 @@ namespace eosio { } } + bool pbft_database::is_valid_committed_certificate(const pbft_committed_certificate &certificate) { + // an empty certificate is valid since it acts as a null digest in pbft. + if (certificate == pbft_committed_certificate{}) return true; + // a certificate under lscb (no longer in fork_db) is also treated as null. + if (certificate.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; + + auto valid = true; + valid = valid && certificate.is_signature_valid(); + for (auto const &c : certificate.commits) { + valid = valid && is_valid_commit(c); + if (!valid) return false; + } + + auto cert_id = certificate.block_id; + auto cert_bs = ctrl.fetch_block_state_by_id(cert_id); + auto producer_schedule = lscb_active_producers(); + if (certificate.block_num > 0 && cert_bs) { + producer_schedule = cert_bs->active_schedule; + } + auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; + + auto commits = certificate.commits; + flat_map commit_count; + + for (const auto &pre: commits) { + if (commit_count.find(pre.view) == commit_count.end()) commit_count[pre.view] = 0; + } + + for (auto const &sp: producer_schedule.producers) { + for (auto const &pp: commits) { + if (sp.block_signing_key == pp.public_key) commit_count[pp.view] += 1; + } + } + + auto should_committed = false; + + for (auto const &e: commit_count) { + if (e.second >= bp_threshold) { + should_committed = true; + } + } + + if (!should_committed) return false; + + { + //validate commit + auto lscb = ctrl.last_stable_checkpoint_block_num(); + auto non_fork_bp_count = 0; + vector commit_infos(certificate.commits.size()); + for (auto const &p : certificate.commits) { + //only search in fork db + if (p.block_num <= lscb) { + ++non_fork_bp_count; + } else { + commit_infos.emplace_back(block_info{p.block_id, p.block_num}); + } + } + + auto commit_forks = fetch_fork_from(commit_infos); + vector longest_fork; + for (auto const &f : commit_forks) { + if (f.size() > longest_fork.size()) { + longest_fork = f; + } + } + if (longest_fork.size() + non_fork_bp_count < bp_threshold) return false; + + if (longest_fork.empty()) return true; + + auto calculated_block_info = longest_fork.back(); + + auto current_bs = ctrl.fetch_block_state_by_id(calculated_block_info.block_id); + while (current_bs) { + if (certificate.block_id == current_bs->id && certificate.block_num == current_bs->block_num) { + return true; + } + current_bs = ctrl.fetch_block_state_by_id(current_bs->prev()); + } + return false; + } + } + bool pbft_database::is_valid_view_change(const pbft_view_change &vc) { if (vc.chain_id != chain_id()) return false; @@ -771,7 +946,7 @@ namespace eosio { EOS_ASSERT(nv.view_changed.view == nv.view, pbft_exception, "target view not match"); vector lib_producers; - for (const auto& pk: lib_active_producers().producers) { + for (const auto& pk: lscb_active_producers().producers) { lib_producers.emplace_back(pk.block_signing_key); } auto schedule_threshold = lib_producers.size() * 2 / 3 + 1; @@ -798,6 +973,7 @@ namespace eosio { EOS_ASSERT(should_new_view(nv.view), pbft_exception, "should not enter new view: ${nv}", ("nv", nv.view)); auto highest_ppc = pbft_prepared_certificate{}; + auto highest_pcc = vector{}; auto highest_scp = pbft_stable_checkpoint{}; for (const auto &vc: nv.view_changed.view_changes) { @@ -806,6 +982,14 @@ namespace eosio { highest_ppc = vc.prepared; } + for (auto const &cc: vc.committed) { + if (is_valid_committed_certificate(cc)) { + auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), + [&](const pbft_committed_certificate &ext) { return ext.block_id == cc.block_id; }); + if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); + } + } + if (vc.stable_checkpoint.block_num > highest_scp.block_num && is_valid_stable_checkpoint(vc.stable_checkpoint)) { highest_scp = vc.stable_checkpoint; @@ -816,6 +1000,8 @@ namespace eosio { "prepared certificate not match, should be ${hpcc} but ${pc} given", ("hpcc",highest_ppc)("pc", nv.prepared)); + EOS_ASSERT(highest_pcc == nv.committed, pbft_exception, "committed certificate not match"); + EOS_ASSERT(highest_scp == nv.stable_checkpoint, pbft_exception, "stable checkpoint not match, should be ${hscp} but ${scp} given", ("hpcc",highest_scp)("pc", nv.stable_checkpoint)); @@ -963,11 +1149,16 @@ namespace eosio { if (lscb_num == 0) { const auto& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; - if (ucb == 0) return lscb_info; - auto bs = ctrl.fetch_block_state_by_number(ucb); - if (!bs) return lscb_info; - current_schedule = bs->active_schedule; - new_schedule = bs->pending_schedule; +// if (ucb == 0) return lscb_info; + if (ucb == 0) { + current_schedule = ctrl.initial_schedule(); + new_schedule = ctrl.initial_schedule(); + } else { + auto bs = ctrl.fetch_block_state_by_number(ucb); + if (!bs) return lscb_info; + current_schedule = bs->active_schedule; + new_schedule = bs->pending_schedule; + } } else if (lscb) { current_schedule = lscb->active_schedule; new_schedule = lscb->pending_schedule; @@ -1001,7 +1192,7 @@ namespace eosio { auto checkpoint = [&](const block_num_type &in) { const auto& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; - if (ucb == 0) return false; + if (!ctrl.is_upgraded()) return false; return in >= ucb && (in % 100 == 1 || std::find(prepare_watermarks.begin(), prepare_watermarks.end(), in) != prepare_watermarks.end()); }; @@ -1203,7 +1394,7 @@ namespace eosio { //use last_stable_checkpoint producer schedule auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - auto as = lib_active_producers(); + auto as = lscb_active_producers(); auto my_sp = ctrl.my_signature_providers(); for (auto i = lscb_num; i <= ctrl.head_block_num(); ++i) { @@ -1221,7 +1412,7 @@ namespace eosio { bool pbft_database::should_recv_pbft_msg(const public_key_type &pub_key) { auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - auto as = lib_active_producers(); + auto as = lscb_active_producers(); auto my_sp = ctrl.my_signature_providers(); for (auto i = lscb_num; i <= ctrl.head_block_num(); ++i) { @@ -1236,21 +1427,21 @@ namespace eosio { public_key_type pbft_database::get_new_view_primary_key(const uint32_t target_view) { - auto active_bps = lib_active_producers().producers; + auto active_bps = lscb_active_producers().producers; if (active_bps.empty()) return public_key_type{}; return active_bps[target_view % active_bps.size()].block_signing_key; } - producer_schedule_type pbft_database::lib_active_producers() const { - auto lib_num = ctrl.last_irreversible_block_num(); - if (lib_num == 0) return ctrl.initial_schedule(); + producer_schedule_type pbft_database::lscb_active_producers() const { + auto lscb_num = ctrl.last_stable_checkpoint_block_num(); + if (lscb_num == 0) return ctrl.initial_schedule(); - auto lib_state = ctrl.fetch_block_state_by_number(lib_num); - if (!lib_state) return ctrl.initial_schedule(); + auto lscb_state = ctrl.fetch_block_state_by_number(lscb_num); + if (!lscb_state) return ctrl.initial_schedule(); - if (lib_state->pending_schedule.producers.empty()) return lib_state->active_schedule; - return lib_state->pending_schedule; + if (lscb_state->pending_schedule.producers.empty()) return lscb_state->active_schedule; + return lscb_state->pending_schedule; } chain_id_type pbft_database::chain_id() { @@ -1294,6 +1485,19 @@ namespace eosio { if (cw > lib) return cw; else return 0; } + 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 itr = by_block_id_index.find(id); + + if (itr != by_block_id_index.end()) { + return (*itr); + } + + return pbft_state_ptr{}; + } + void pbft_database::set(pbft_state_ptr s) { auto result = pbft_state_index.insert(s); diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 7321c5de820..a450177c41a 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -3098,7 +3098,7 @@ namespace eosio { if (!pcc.pbft_db.is_valid_new_view(msg)) return; forward_pbft_msg(c, msg); - fc_dlog( logger, "received new view: ${n}, from ${v}", ("n", msg)("v", msg.public_key)); + fc_ilog( logger, "received new view: ${n}, from ${v}", ("n", msg)("v", msg.public_key)); pbft_incoming_new_view_channel.publish(msg); } @@ -3114,7 +3114,7 @@ namespace eosio { if (!pcc.pbft_db.is_valid_checkpoint(msg)) return; forward_pbft_msg(c, msg); - fc_dlog( logger, "received checkpoint at ${n}, from ${v}", ("n", msg.block_num)("v", msg.public_key)); + fc_ilog( logger, "received checkpoint at ${n}, from ${v}", ("n", msg.block_num)("v", msg.public_key)); pbft_incoming_checkpoint_channel.publish(msg); } From 24f5c46235fc1892032ae578a56a466ed8c0ec18 Mon Sep 17 00:00:00 2001 From: deadlock Date: Fri, 3 May 2019 01:24:18 +0800 Subject: [PATCH 5/9] add pbft test case --- unittests/pbft_tests.cpp | 298 ++++++++++++++++++++++++++++++++++----- 1 file changed, 262 insertions(+), 36 deletions(-) diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index 50d8e573fe4..8f725f27488 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -17,37 +17,71 @@ using namespace eosio::testing; BOOST_AUTO_TEST_SUITE(pbft_tests) +std::map make_signature_provider(){ + std::map msp; - BOOST_AUTO_TEST_CASE(can_init) { - tester tester; - controller &ctrl = *tester.control.get(); - pbft_controller pbft_ctrl{ctrl}; + auto priv_eosio = tester::get_private_key( N(eosio), "active" ); + auto pub_eosio = tester::get_public_key( N(eosio), "active"); + auto sp_eosio = [priv_eosio]( const eosio::chain::digest_type& digest ) { + return priv_eosio.sign(digest); + }; + msp[pub_eosio]=sp_eosio; - tester.produce_block(); - auto p = pbft_ctrl.pbft_db.should_prepared(); - BOOST_CHECK(!p); - } + 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[pub_alice]=sp_alice; - BOOST_AUTO_TEST_CASE(can_advance_lib_in_old_version) { - tester tester; - controller &ctrl = *tester.control.get(); - pbft_controller pbft_ctrl{ctrl}; - - auto privkey = tester::get_private_key( N(eosio), "active" ); - auto pubkey = tester::get_public_key( N(eosio), "active"); - auto sp = [privkey]( const eosio::chain::digest_type& digest ) { - return privkey.sign(digest); - }; - std::map msp; - msp[pubkey]=sp; - ctrl.set_my_signature_providers(msp); - - tester.produce_block();//produce block num 2 - BOOST_REQUIRE_EQUAL(ctrl.last_irreversible_block_num(), 0); - BOOST_REQUIRE_EQUAL(ctrl.head_block_num(), 2); - tester.produce_block(); - BOOST_REQUIRE_EQUAL(ctrl.last_irreversible_block_num(), 2); - BOOST_REQUIRE_EQUAL(ctrl.head_block_num(), 3); + 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[pub_bob]=sp_bob; + + auto priv_carol = tester::get_private_key( N(carol), "active" ); + auto pub_carol = tester::get_public_key( N(carol), "active"); + auto sp_carol = [priv_carol]( const eosio::chain::digest_type& digest ) { + return priv_carol.sign(digest); + }; + msp[pub_carol]=sp_carol; + + auto priv_deny = tester::get_private_key( N(deny), "active" ); + auto pub_deny = tester::get_public_key( N(deny), "active"); + auto sp_deny = [priv_deny]( const eosio::chain::digest_type& digest ) { + return priv_deny.sign(digest); + }; + msp[pub_deny]=sp_deny; + + return msp; +} + +BOOST_AUTO_TEST_CASE(can_init) { + tester tester; + controller &ctrl = *tester.control.get(); + pbft_controller pbft_ctrl{ctrl}; + + tester.produce_block(); + auto p = pbft_ctrl.pbft_db.should_prepared(); + BOOST_CHECK(!p); +} + +BOOST_AUTO_TEST_CASE(can_advance_lib_in_old_version) { + tester tester; + controller &ctrl = *tester.control.get(); + pbft_controller pbft_ctrl{ctrl}; + + auto msp = make_signature_provider(); + ctrl.set_my_signature_providers(msp); + + tester.produce_block();//produce block num 2 + BOOST_REQUIRE_EQUAL(ctrl.last_irreversible_block_num(), 0); + BOOST_REQUIRE_EQUAL(ctrl.head_block_num(), 2); + tester.produce_block(); + BOOST_REQUIRE_EQUAL(ctrl.last_irreversible_block_num(), 2); + BOOST_REQUIRE_EQUAL(ctrl.head_block_num(), 3); } BOOST_AUTO_TEST_CASE(can_advance_lib_after_upgrade) { @@ -60,14 +94,7 @@ BOOST_AUTO_TEST_CASE(can_advance_lib_after_upgrade) { const auto upo_upgrade_target_block_num = upo.upgrade_target_block_num; BOOST_CHECK_EQUAL(upo_upgrade_target_block_num, 150); - - auto privkey = tester::get_private_key( N(eosio), "active" ); - auto pubkey = tester::get_public_key( N(eosio), "active"); - auto sp = [privkey]( const eosio::chain::digest_type& digest ) { - return privkey.sign(digest); - }; - std::map msp; - msp[pubkey]=sp; + auto msp = make_signature_provider(); ctrl.set_my_signature_providers(msp); auto is_upgraded = ctrl.is_upgraded(); @@ -100,4 +127,203 @@ 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(); + pbft_controller pbft_ctrl{ctrl}; + + ctrl.set_upo(109); + + const auto& upo = ctrl.db().get(); + const auto upo_upgrade_target_block_num = upo.upgrade_target_block_num; + BOOST_CHECK_EQUAL(upo_upgrade_target_block_num, 109); + + auto msp = make_signature_provider(); + ctrl.set_my_signature_providers(msp); + + auto is_upgraded = ctrl.is_upgraded(); + + BOOST_CHECK_EQUAL(is_upgraded, false); + + tester.produce_block();//produce block num 2 + tester.create_accounts( {N(alice),N(bob),N(carol),N(deny)} ); + tester.set_producers({N(alice),N(bob),N(carol),N(deny)}); + tester.produce_blocks(3);//produce block num 3,4,5 + BOOST_CHECK_EQUAL(ctrl.active_producers().producers.front().producer_name, N(alice)); + BOOST_CHECK_EQUAL(ctrl.head_block_producer(),N(eosio)); + tester.produce_blocks(7);//produce to block 12 + BOOST_CHECK_EQUAL(ctrl.head_block_producer(),N(alice)); + + BOOST_CHECK_EQUAL(ctrl.last_irreversible_block_num(), 4); + BOOST_CHECK_EQUAL(ctrl.head_block_num(), 12); + tester.produce_blocks(156 - 12); + BOOST_CHECK_EQUAL(ctrl.last_irreversible_block_num(), 108); + BOOST_CHECK_EQUAL(ctrl.head_block_num(), 156); + + is_upgraded = ctrl.is_upgraded(); + BOOST_CHECK_EQUAL(is_upgraded, false); + tester.produce_blocks(12); + is_upgraded = ctrl.is_upgraded(); + BOOST_CHECK_EQUAL(is_upgraded, true); + BOOST_CHECK_EQUAL(ctrl.last_irreversible_block_num(), 120); + BOOST_CHECK_EQUAL(ctrl.head_block_num(), 168); + BOOST_CHECK_EQUAL(ctrl.pending_pbft_lib(), false); + + pbft_ctrl.maybe_pbft_prepare(); + pbft_ctrl.maybe_pbft_commit(); + + BOOST_CHECK_EQUAL(ctrl.pending_pbft_lib(), true); + tester.produce_block(); //set lib using pending pbft lib + + BOOST_CHECK_EQUAL(ctrl.last_irreversible_block_num(), 168); + BOOST_CHECK_EQUAL(ctrl.head_block_num(), 169); +} + +void push_blocks( tester& from, tester& to ) { + while( to.control->fork_db_head_block_num() < from.control->fork_db_head_block_num() ) { + auto fb = from.control->fetch_block_by_number( to.control->fork_db_head_block_num()+1 ); + to.push_block( fb ); +// if(fb->block_num()>60) { +// BOOST_CHECK_EQUAL(from.control.get()->fetch_block_state_by_id(fb->id())->id, +// to.control.get()->fetch_block_state_by_id(fb->id())->id); +// } + } +} + +BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_on_short_fork) { + tester base_fork, short_prepared_fork, long_non_prepared_fork, new_view_generator; + controller &ctrl_base_fork = *base_fork.control.get(); + pbft_controller pbft_ctrl{ctrl_base_fork}; + controller &ctrl_short_prepared_fork = *short_prepared_fork.control.get(); + pbft_controller pbft_short_prepared_fork{ctrl_short_prepared_fork}; + controller &ctrl_long_non_prepared_fork = *long_non_prepared_fork.control.get(); + pbft_controller pbft_long_non_prepared_fork{ctrl_long_non_prepared_fork}; + 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(); + ctrl_base_fork.set_my_signature_providers(msp); + ctrl_short_prepared_fork.set_my_signature_providers(msp); + ctrl_long_non_prepared_fork.set_my_signature_providers(msp); + ctrl_new_view_generator.set_my_signature_providers(msp); + + ctrl_base_fork.set_upo(48); + ctrl_short_prepared_fork.set_upo(48); + ctrl_long_non_prepared_fork.set_upo(48); + ctrl_new_view_generator.set_upo(48); + + base_fork.create_accounts( {N(alice),N(bob),N(carol),N(deny)} ); + base_fork.set_producers({N(alice),N(bob),N(carol),N(deny)}); + base_fork.produce_blocks(95); + + long_non_prepared_fork.create_accounts( {N(alice),N(bob),N(carol),N(deny)} ); + long_non_prepared_fork.set_producers({N(alice),N(bob),N(carol),N(deny)}); + long_non_prepared_fork.produce_blocks(95); + + short_prepared_fork.create_accounts( {N(alice),N(bob),N(carol),N(deny)} ); + short_prepared_fork.set_producers({N(alice),N(bob),N(carol),N(deny)}); + short_prepared_fork.produce_blocks(95); + + 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(95); + + auto is_upgraded = ctrl_base_fork.is_upgraded(); + BOOST_CHECK_EQUAL(ctrl_base_fork.active_producers().producers.front().producer_name, N(alice)); + BOOST_CHECK_EQUAL(is_upgraded, true); + BOOST_CHECK_EQUAL(ctrl_base_fork.last_irreversible_block_num(), 48); + BOOST_CHECK_EQUAL(ctrl_base_fork.head_block_num(), 96); + + pbft_ctrl.maybe_pbft_prepare(); + pbft_ctrl.maybe_pbft_commit(); + base_fork.produce_blocks(4); + + pbft_long_non_prepared_fork.maybe_pbft_prepare(); + pbft_long_non_prepared_fork.maybe_pbft_commit(); + long_non_prepared_fork.produce_blocks(4); + + pbft_short_prepared_fork.maybe_pbft_prepare(); + pbft_short_prepared_fork.maybe_pbft_commit(); + short_prepared_fork.produce_blocks(4); + + + pbft_new_view_generator.maybe_pbft_prepare(); + pbft_new_view_generator.maybe_pbft_commit(); + new_view_generator.produce_blocks(4); + + BOOST_CHECK_EQUAL(ctrl_base_fork.last_irreversible_block_num(), 96); + BOOST_CHECK_EQUAL(ctrl_base_fork.head_block_num(), 100); + +// push_blocks(base_fork, long_non_prepared_fork); +// push_blocks(base_fork, short_prepared_fork); +// push_blocks(base_fork, new_view_generator); + +// pbft_short_prepared_fork.maybe_pbft_prepare(); +// pbft_short_prepared_fork.maybe_pbft_commit(); +// pbft_long_non_prepared_fork.maybe_pbft_prepare(); +// pbft_long_non_prepared_fork.maybe_pbft_commit(); +// pbft_new_view_generator.maybe_pbft_prepare(); +// pbft_new_view_generator.maybe_pbft_commit(); + + BOOST_CHECK_EQUAL(ctrl_base_fork.is_upgraded(), true); + BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.is_upgraded(), true); + BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.is_upgraded(), true); + BOOST_CHECK_EQUAL(ctrl_new_view_generator.is_upgraded(), true); + BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.head_block_num(), 100); + BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.head_block_num(), 100); + BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.fetch_block_by_number(100)->id(), ctrl_short_prepared_fork.fetch_block_by_number(100)->id()); + + + + short_prepared_fork.create_accounts({N(shortname)}); + long_non_prepared_fork.create_accounts({N(longname)}); + short_prepared_fork.produce_blocks(36); + push_blocks(short_prepared_fork, new_view_generator); + long_non_prepared_fork.produce_blocks(72); + + + + BOOST_CHECK_EQUAL(ctrl_new_view_generator.head_block_num(), 136); + BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.head_block_num(), 136); + BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.head_block_num(), 172); + BOOST_CHECK_EQUAL(ctrl_new_view_generator.last_irreversible_block_num(), 96); + BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.last_irreversible_block_num(), 96); + BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.last_irreversible_block_num(), 96); + + //generate new view with short fork prepare certificate + pbft_new_view_generator.state_machine.set_current(new psm_committed_state); + pbft_new_view_generator.state_machine.set_prepares_cache({}); + BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_send_pbft_msg(), true); + pbft_new_view_generator.maybe_pbft_prepare(); + BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_prepared(), true); + BOOST_CHECK_EQUAL(ctrl_new_view_generator.head_block_num(), 136); + for(int i = 0; i Date: Fri, 3 May 2019 16:13:27 +0800 Subject: [PATCH 6/9] add test case switch_fork_when_accept_new_view_with_prepare_certificate_on_short_fork --- libraries/chain/controller.cpp | 6 ++ libraries/chain/fork_database.cpp | 32 +++++++ .../chain/include/eosio/chain/controller.hpp | 1 + .../include/eosio/chain/fork_database.hpp | 2 + libraries/chain/pbft_database.cpp | 4 +- unittests/pbft_tests.cpp | 92 ++++++++----------- 6 files changed, 79 insertions(+), 58 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index a1847a0b12b..b56063dad91 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -2551,6 +2551,12 @@ void controller::reset_pbft_my_prepare() { if (my->my_prepare) my->my_prepare.reset(); } +void controller::reset_pbft_prepared() { + my->fork_db.remove_pbft_prepared_fork(); + maybe_switch_forks(); + if (my->pbft_prepared) my->pbft_prepared.reset(); +} + db_read_mode controller::get_read_mode()const { return my->read_mode; } diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index 5509ff631b2..d7a69671d25 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -442,6 +442,38 @@ namespace eosio { namespace chain { my->head = *my->index.get().begin(); } + void fork_database::remove_pbft_prepared_fork() { + auto oldest = *my->index.get().begin(); + + auto& by_id_idx = my->index.get(); + auto itr = by_id_idx.find( oldest->id ); + by_id_idx.modify( itr, [&]( auto& bsp ) { bsp->pbft_prepared = false; }); + + auto update = [&]( const vector& in ) { + vector updated; + + for( const auto& i : in ) { + auto& pidx = my->index.get(); + auto pitr = pidx.lower_bound( i ); + auto epitr = pidx.upper_bound( i ); + while( pitr != epitr ) { + pidx.modify( pitr, [&]( auto& bsp ) { + bsp->pbft_prepared = false; + updated.push_back( bsp->id ); + }); + ++pitr; + } + } + return updated; + }; + + vector queue{ oldest->id }; + while(!queue.empty()) { + queue = update( queue ); + } + my->head = *my->index.get().begin(); + } + block_state_ptr fork_database::get_block_in_current_chain_by_num( uint32_t n )const { const auto& numidx = my->index.get(); auto nitr = numidx.lower_bound( n ); diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index d2172f683ab..a6ca7e12bc0 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -293,6 +293,7 @@ namespace eosio { namespace chain { void set_pbft_my_prepare(const block_id_type& id); block_id_type get_pbft_my_prepare()const; void reset_pbft_my_prepare(); + void reset_pbft_prepared(); void maybe_switch_forks(); signal pre_accepted_block; diff --git a/libraries/chain/include/eosio/chain/fork_database.hpp b/libraries/chain/include/eosio/chain/fork_database.hpp index 10eb41a6852..55e40580eb2 100644 --- a/libraries/chain/include/eosio/chain/fork_database.hpp +++ b/libraries/chain/include/eosio/chain/fork_database.hpp @@ -80,6 +80,8 @@ namespace eosio { namespace chain { void remove_pbft_my_prepare_fork(); + void remove_pbft_prepared_fork(); + private: unique_ptr my; }; diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index a0cf032b012..c759a05651f 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -803,7 +803,7 @@ namespace eosio { //validate prepare auto lscb = ctrl.last_stable_checkpoint_block_num(); auto non_fork_bp_count = 0; - vector prepare_infos(certificate.prepares.size()); + vector prepare_infos; for (auto const &p : certificate.prepares) { //only search in fork db if (p.block_num <= lscb) { @@ -885,7 +885,7 @@ namespace eosio { //validate commit auto lscb = ctrl.last_stable_checkpoint_block_num(); auto non_fork_bp_count = 0; - vector commit_infos(certificate.commits.size()); + vector commit_infos; for (auto const &p : certificate.commits) { //only search in fork db if (p.block_num <= lscb) { diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index 8f725f27488..3abf5285cee 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -192,9 +192,7 @@ void push_blocks( tester& from, tester& to ) { } BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_on_short_fork) { - tester base_fork, short_prepared_fork, long_non_prepared_fork, new_view_generator; - controller &ctrl_base_fork = *base_fork.control.get(); - pbft_controller pbft_ctrl{ctrl_base_fork}; + tester short_prepared_fork, long_non_prepared_fork, new_view_generator; controller &ctrl_short_prepared_fork = *short_prepared_fork.control.get(); pbft_controller pbft_short_prepared_fork{ctrl_short_prepared_fork}; controller &ctrl_long_non_prepared_fork = *long_non_prepared_fork.control.get(); @@ -203,75 +201,48 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o pbft_controller pbft_new_view_generator{ctrl_new_view_generator}; auto msp = make_signature_provider(); - ctrl_base_fork.set_my_signature_providers(msp); ctrl_short_prepared_fork.set_my_signature_providers(msp); ctrl_long_non_prepared_fork.set_my_signature_providers(msp); ctrl_new_view_generator.set_my_signature_providers(msp); - ctrl_base_fork.set_upo(48); ctrl_short_prepared_fork.set_upo(48); ctrl_long_non_prepared_fork.set_upo(48); ctrl_new_view_generator.set_upo(48); - base_fork.create_accounts( {N(alice),N(bob),N(carol),N(deny)} ); - base_fork.set_producers({N(alice),N(bob),N(carol),N(deny)}); - base_fork.produce_blocks(95); - long_non_prepared_fork.create_accounts( {N(alice),N(bob),N(carol),N(deny)} ); long_non_prepared_fork.set_producers({N(alice),N(bob),N(carol),N(deny)}); - long_non_prepared_fork.produce_blocks(95); + long_non_prepared_fork.produce_blocks(100); short_prepared_fork.create_accounts( {N(alice),N(bob),N(carol),N(deny)} ); short_prepared_fork.set_producers({N(alice),N(bob),N(carol),N(deny)}); - short_prepared_fork.produce_blocks(95); + short_prepared_fork.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(95); - - auto is_upgraded = ctrl_base_fork.is_upgraded(); - BOOST_CHECK_EQUAL(ctrl_base_fork.active_producers().producers.front().producer_name, N(alice)); - BOOST_CHECK_EQUAL(is_upgraded, true); - BOOST_CHECK_EQUAL(ctrl_base_fork.last_irreversible_block_num(), 48); - BOOST_CHECK_EQUAL(ctrl_base_fork.head_block_num(), 96); - - pbft_ctrl.maybe_pbft_prepare(); - pbft_ctrl.maybe_pbft_commit(); - base_fork.produce_blocks(4); + new_view_generator.produce_blocks(100); pbft_long_non_prepared_fork.maybe_pbft_prepare(); pbft_long_non_prepared_fork.maybe_pbft_commit(); - long_non_prepared_fork.produce_blocks(4); + long_non_prepared_fork.produce_blocks(1); + pbft_long_non_prepared_fork.maybe_pbft_commit(); + long_non_prepared_fork.produce_blocks(25); pbft_short_prepared_fork.maybe_pbft_prepare(); pbft_short_prepared_fork.maybe_pbft_commit(); - short_prepared_fork.produce_blocks(4); + short_prepared_fork.produce_blocks(1); + pbft_short_prepared_fork.maybe_pbft_commit(); + short_prepared_fork.produce_blocks(25); pbft_new_view_generator.maybe_pbft_prepare(); pbft_new_view_generator.maybe_pbft_commit(); - new_view_generator.produce_blocks(4); + new_view_generator.produce_blocks(1); - BOOST_CHECK_EQUAL(ctrl_base_fork.last_irreversible_block_num(), 96); - BOOST_CHECK_EQUAL(ctrl_base_fork.head_block_num(), 100); - -// push_blocks(base_fork, long_non_prepared_fork); -// push_blocks(base_fork, short_prepared_fork); -// push_blocks(base_fork, new_view_generator); - -// pbft_short_prepared_fork.maybe_pbft_prepare(); -// pbft_short_prepared_fork.maybe_pbft_commit(); -// pbft_long_non_prepared_fork.maybe_pbft_prepare(); -// pbft_long_non_prepared_fork.maybe_pbft_commit(); -// pbft_new_view_generator.maybe_pbft_prepare(); -// pbft_new_view_generator.maybe_pbft_commit(); - - BOOST_CHECK_EQUAL(ctrl_base_fork.is_upgraded(), true); BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.is_upgraded(), true); BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.is_upgraded(), true); BOOST_CHECK_EQUAL(ctrl_new_view_generator.is_upgraded(), true); - BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.head_block_num(), 100); - BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.head_block_num(), 100); + BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.head_block_num(), 127); + BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.head_block_num(), 127); BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.fetch_block_by_number(100)->id(), ctrl_short_prepared_fork.fetch_block_by_number(100)->id()); @@ -283,21 +254,23 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o long_non_prepared_fork.produce_blocks(72); + pbft_new_view_generator.maybe_pbft_commit(); + new_view_generator.produce_blocks(3); + push_blocks(new_view_generator, short_prepared_fork); - BOOST_CHECK_EQUAL(ctrl_new_view_generator.head_block_num(), 136); - BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.head_block_num(), 136); - BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.head_block_num(), 172); - BOOST_CHECK_EQUAL(ctrl_new_view_generator.last_irreversible_block_num(), 96); - BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.last_irreversible_block_num(), 96); - BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.last_irreversible_block_num(), 96); + BOOST_CHECK_EQUAL(ctrl_new_view_generator.head_block_num(), 166); + BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.head_block_num(), 166); + BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.head_block_num(), 199); + BOOST_CHECK_EQUAL(ctrl_new_view_generator.last_irreversible_block_num(), 101); + BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.last_irreversible_block_num(), 101); + 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_current(new psm_committed_state); pbft_new_view_generator.state_machine.set_prepares_cache({}); BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_send_pbft_msg(), true); pbft_new_view_generator.maybe_pbft_prepare(); BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_prepared(), true); - BOOST_CHECK_EQUAL(ctrl_new_view_generator.head_block_num(), 136); + BOOST_CHECK_EQUAL(ctrl_new_view_generator.head_block_num(), 166); for(int i = 0; i Date: Fri, 3 May 2019 18:07:36 +0800 Subject: [PATCH 7/9] bug fix: pbft switch fork to short lib --- libraries/chain/controller.cpp | 25 ++++++++++------- libraries/chain/fork_database.cpp | 1 + libraries/chain/pbft_database.cpp | 10 +++---- unittests/pbft_tests.cpp | 45 ++++++++++++++++--------------- 4 files changed, 46 insertions(+), 35 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index b56063dad91..cfa7ebb3f01 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -903,13 +903,12 @@ struct controller_impl { void commit_block( bool add_to_fork_db ) { auto reset_pending_on_exit = fc::make_scoped_exit([this]{ pending.reset(); - set_pbft_lib(); - set_pbft_lscb(); + }); try { - set_pbft_lib(); - set_pbft_lscb(); + + if (add_to_fork_db) { pending->_pending_block_state->validated = true; @@ -1337,6 +1336,9 @@ struct controller_impl { { EOS_ASSERT( !pending, block_validate_exception, "pending block already exists" ); + set_pbft_lib(); + set_pbft_lscb(); + auto guard_pending = fc::make_scoped_exit([this](){ pending.reset(); }); @@ -1661,11 +1663,13 @@ struct controller_impl { void set_pbft_lib() { - if ((!pending || pending->_block_status != controller::block_status::incomplete) && pending_pbft_lib ) { + if (!is_new_version()) return; + + if ( pending_pbft_lib ) { fork_db.set_bft_irreversible(*pending_pbft_lib); pending_pbft_lib.reset(); - if (read_mode != db_read_mode::IRREVERSIBLE) { + if (!pending && read_mode != db_read_mode::IRREVERSIBLE) { maybe_switch_forks(controller::block_status::complete); } } @@ -1677,7 +1681,10 @@ struct controller_impl { } void set_pbft_lscb() { - if ((!pending || pending->_block_status != controller::block_status::incomplete) && pending_pbft_checkpoint ) { + + if (!is_new_version()) return; + + if ( pending_pbft_checkpoint ) { auto checkpoint_block_state = fork_db.get_block(*pending_pbft_checkpoint); if (checkpoint_block_state) { @@ -1698,7 +1705,7 @@ struct controller_impl { void maybe_switch_forks( controller::block_status s ) { auto new_head = fork_db.head(); - if( new_head->header.previous == head->id && !pending) { + if( new_head->header.previous == head->id ) { try { apply_block( new_head->block, s ); fork_db.mark_in_current_chain( new_head, true ); @@ -2721,7 +2728,7 @@ bool controller::under_upgrade() const { } void controller::maybe_switch_forks() { - if (my->read_mode != db_read_mode::IRREVERSIBLE) { + if (!pending_block_state() && my->read_mode != db_read_mode::IRREVERSIBLE) { my->maybe_switch_forks(controller::block_status::complete); } } diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index d7a69671d25..21cfd79dbc2 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -547,6 +547,7 @@ namespace eosio { namespace chain { while( queue.size() ) { queue = update( queue ); } + my->head = *my->index.get().begin(); } void fork_database::set_latest_checkpoint( block_id_type id) { diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index c759a05651f..d53a7ae3369 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -945,11 +945,11 @@ namespace eosio { EOS_ASSERT(nv.view_changed.view == nv.view, pbft_exception, "target view not match"); - vector lib_producers; + vector lscb_producers; for (const auto& pk: lscb_active_producers().producers) { - lib_producers.emplace_back(pk.block_signing_key); + lscb_producers.emplace_back(pk.block_signing_key); } - auto schedule_threshold = lib_producers.size() * 2 / 3 + 1; + auto schedule_threshold = lscb_producers.size() * 2 / 3 + 1; vector view_change_producers; @@ -962,9 +962,9 @@ namespace eosio { vector intersection; - std::sort(lib_producers.begin(),lib_producers.end()); + std::sort(lscb_producers.begin(),lscb_producers.end()); std::sort(view_change_producers.begin(),view_change_producers.end()); - std::set_intersection(lib_producers.begin(),lib_producers.end(), + std::set_intersection(lscb_producers.begin(),lscb_producers.end(), view_change_producers.begin(),view_change_producers.end(), back_inserter(intersection)); diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index 3abf5285cee..71110c9cc2a 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -184,10 +184,6 @@ void push_blocks( tester& from, tester& to ) { while( to.control->fork_db_head_block_num() < from.control->fork_db_head_block_num() ) { auto fb = from.control->fetch_block_by_number( to.control->fork_db_head_block_num()+1 ); to.push_block( fb ); -// if(fb->block_num()>60) { -// BOOST_CHECK_EQUAL(from.control.get()->fetch_block_state_by_id(fb->id())->id, -// to.control.get()->fetch_block_state_by_id(fb->id())->id); -// } } } @@ -249,18 +245,18 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o short_prepared_fork.create_accounts({N(shortname)}); long_non_prepared_fork.create_accounts({N(longname)}); - short_prepared_fork.produce_blocks(36); + short_prepared_fork.produce_blocks(6); push_blocks(short_prepared_fork, new_view_generator); - long_non_prepared_fork.produce_blocks(72); + long_non_prepared_fork.produce_blocks(10); pbft_new_view_generator.maybe_pbft_commit(); new_view_generator.produce_blocks(3); push_blocks(new_view_generator, short_prepared_fork); - BOOST_CHECK_EQUAL(ctrl_new_view_generator.head_block_num(), 166); - BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.head_block_num(), 166); - BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.head_block_num(), 199); + BOOST_CHECK_EQUAL(ctrl_new_view_generator.head_block_num(), 136); + BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.head_block_num(), 136); + BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.head_block_num(), 137); BOOST_CHECK_EQUAL(ctrl_new_view_generator.last_irreversible_block_num(), 101); BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.last_irreversible_block_num(), 101); BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.last_irreversible_block_num(), 101); @@ -270,7 +266,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_send_pbft_msg(), true); pbft_new_view_generator.maybe_pbft_prepare(); BOOST_CHECK_EQUAL(pbft_new_view_generator.pbft_db.should_prepared(), true); - BOOST_CHECK_EQUAL(ctrl_new_view_generator.head_block_num(), 166); + BOOST_CHECK_EQUAL(ctrl_new_view_generator.head_block_num(), 136); for(int i = 0; i Date: Fri, 3 May 2019 23:21:51 +0800 Subject: [PATCH 8/9] sort committed cert before apply; move upgrade status into controller impl; reformat code. --- libraries/chain/controller.cpp | 94 ++++---- .../chain/include/eosio/chain/controller.hpp | 4 +- libraries/chain/include/eosio/chain/pbft.hpp | 2 +- .../include/eosio/chain/pbft_database.hpp | 10 + libraries/chain/pbft.cpp | 8 +- libraries/chain/pbft_database.cpp | 215 ++++++++---------- libraries/chain/wasm_interface.cpp | 6 +- plugins/net_plugin/net_plugin.cpp | 2 +- plugins/pbft_plugin/pbft_plugin.cpp | 6 +- plugins/producer_plugin/producer_plugin.cpp | 6 +- unittests/pbft_tests.cpp | 16 +- 11 files changed, 175 insertions(+), 194 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index cfa7ebb3f01..7eb92ab4b12 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -123,6 +123,8 @@ struct controller_impl { chainbase::database reversible_blocks; ///< a special database to persist blocks that have successfully been applied but are still reversible block_log blog; optional pending; + bool pbft_enabled = false; + bool pbft_upgrading = false; optional pending_pbft_lib; optional pending_pbft_checkpoint; vector proposed_schedule_blocks; @@ -881,22 +883,6 @@ struct controller_impl { } } - bool is_new_version() { - auto ucb = upgrade_complete_block(); - //new version starts from the next block of ucb, this is to avoid inconsistency after pre calculation inside schedule loop. - if (ucb) return head->block_num > *ucb; - return false; - } - - bool is_upgrading() { - auto utb = upgrade_target_block(); - auto ucb = upgrade_complete_block(); - auto is_upgrading = false; - if (utb) is_upgrading = head->block_num >= *utb; - if (ucb) is_upgrading = is_upgrading && head->block_num <= *ucb; - return is_upgrading; - } - /** * @post regardless of the success of commit block there is no active pending block */ @@ -908,13 +894,10 @@ struct controller_impl { try { - if (add_to_fork_db) { pending->_pending_block_state->validated = true; - auto new_version = is_new_version(); - - auto new_bsp = fork_db.add(pending->_pending_block_state, true, new_version); + auto new_bsp = fork_db.add(pending->_pending_block_state, true, pbft_enabled); emit(self.accepted_block_header, pending->_pending_block_state); head = fork_db.head(); @@ -1352,31 +1335,41 @@ struct controller_impl { pending.emplace(maybe_session()); } - auto utb = upgrade_target_block(); - auto ucb = upgrade_complete_block(); - if (utb && !ucb) { - if (head->dpos_irreversible_blocknum >= *utb) { - const auto& upo = db.get(); + auto utb = optional{}; + auto& upo = db.get(); + if (upo.upgrade_target_block_num > 0) utb = upo.upgrade_target_block_num; + + auto ucb = optional{}; + if (upo.upgrade_complete_block_num > 0) ucb = upo.upgrade_complete_block_num; + + + if (utb && !ucb && head->dpos_irreversible_blocknum >= *utb) { db.modify( upo, [&]( auto& up ) { up.upgrade_complete_block_num = head->block_num; }); - wlog("system is going to be new version after the block ${b}", ("b", head->block_num)); - } + if (!replaying) wlog("pbft will be working after the block ${b}", ("b", head->block_num)); } - auto new_version = is_new_version(); - auto upgrading = is_upgrading(); + if ( !pbft_enabled && utb && head->block_num >= *utb) { + if (!pbft_upgrading) pbft_upgrading = true; + + // new version starts from the next block of ucb, this is to avoid inconsistency after pre calculation inside schedule loop. + if (ucb && head->block_num > *ucb) { + if (pbft_upgrading) pbft_upgrading = false; + pbft_enabled = true; + } + } pending->_block_status = s; pending->_producer_block_id = producer_block_id; pending->_signer = signer; - pending->_pending_block_state = std::make_shared( *head, when, new_version); // promotes pending schedule (if any) to active + pending->_pending_block_state = std::make_shared( *head, when, pbft_enabled); // promotes pending schedule (if any) to active pending->_pending_block_state->in_current_chain = true; - pending->_pending_block_state->set_confirmed(confirm_block_count, new_version); + pending->_pending_block_state->set_confirmed(confirm_block_count, pbft_enabled); - auto was_pending_promoted = pending->_pending_block_state->maybe_promote_pending(new_version); + auto was_pending_promoted = pending->_pending_block_state->maybe_promote_pending(pbft_enabled); //modify state in speculative block only if we are speculative reads mode (other wise we need clean state for head or irreversible reads) if ( read_mode == db_read_mode::SPECULATIVE || pending->_block_status != controller::block_status::incomplete ) { @@ -1386,7 +1379,7 @@ struct controller_impl { auto lib_num = std::max(pending->_pending_block_state->dpos_irreversible_blocknum, pending->_pending_block_state->bft_irreversible_blocknum); auto lscb_num = pending->_pending_block_state->pbft_stable_checkpoint_blocknum; - if (new_version && gpo.proposed_schedule_block_num) { + if (pbft_enabled && gpo.proposed_schedule_block_num) { proposed_schedule_blocks.emplace_back(*gpo.proposed_schedule_block_num); for ( auto itr = proposed_schedule_blocks.begin(); itr != proposed_schedule_blocks.end();) { if ((*itr) < lscb_num) { @@ -1403,7 +1396,7 @@ struct controller_impl { && pending->_pending_block_state->pending_schedule.producers.size() == 0 // ... and there is room for a new pending schedule ... && !was_pending_promoted; // ... and not just because it was promoted to active at the start of this block, then: - if (new_version) { + if (pbft_enabled) { should_promote_pending_schedule = should_promote_pending_schedule && pending->_pending_block_state->block_num > *gpo.proposed_schedule_block_num; } else { @@ -1411,11 +1404,11 @@ struct controller_impl { && ( *gpo.proposed_schedule_block_num <= pending->_pending_block_state->dpos_irreversible_blocknum ); } - if ( upgrading && !replaying) wlog("system is upgrading, no producer schedule promotion will happen until fully upgraded."); + if ( pbft_upgrading && !replaying) wlog("system is upgrading, no producer schedule promotion will happen until fully upgraded."); if ( should_promote_pending_schedule ) { - if (!upgrading) { + if (!pbft_upgrading) { // Promote proposed schedule to pending schedule. if (!replaying) { ilog("promoting proposed schedule (set in block ${proposed_num}) to pending; current block: ${n} lib: ${lib} schedule: ${schedule} ", @@ -1425,7 +1418,7 @@ struct controller_impl { } pending->_pending_block_state->set_new_producers(gpo.proposed_schedule); - if (new_version) { + if (pbft_enabled) { promoted_schedule_blocks.emplace_back(pending->_pending_block_state->block_num); for ( auto itr = promoted_schedule_blocks.begin(); itr != promoted_schedule_blocks.end();) { if ((*itr) < lscb_num) { @@ -1578,11 +1571,11 @@ struct controller_impl { auto prev = fork_db.get_block( b->previous ); EOS_ASSERT( prev, unlinkable_block_exception, "unlinkable block ${id}", ("id", id)("previous", b->previous) ); - auto new_version = is_new_version(); + auto pbft = pbft_enabled; - return async_thread_pool( thread_pool, [b, prev, new_version]() { + return async_thread_pool( thread_pool, [b, prev, pbft]() { const bool skip_validate_signee = false; - return std::make_shared( *prev, move( b ), skip_validate_signee, new_version); + return std::make_shared( *prev, move( b ), skip_validate_signee, pbft); } ); } @@ -1597,8 +1590,7 @@ struct controller_impl { auto& b = new_header_state->block; emit( self.pre_accepted_block, b ); - auto new_version = is_new_version(); - fork_db.add( new_header_state, false, new_version); + fork_db.add( new_header_state, false, pbft_enabled); if (conf.trusted_producers.count(b->producer)) { trusted_producer_light_validation = true; @@ -1628,9 +1620,7 @@ struct controller_impl { emit( self.pre_accepted_block, b ); const bool skip_validate_signee = !conf.force_all_checks; - auto new_version = is_new_version(); - - auto new_header_state = fork_db.add( b, skip_validate_signee, new_version); + auto new_header_state = fork_db.add( b, skip_validate_signee, pbft_enabled); emit( self.accepted_block_header, new_header_state ); @@ -1663,7 +1653,7 @@ struct controller_impl { void set_pbft_lib() { - if (!is_new_version()) return; + if (!pbft_enabled) return; if ( pending_pbft_lib ) { fork_db.set_bft_irreversible(*pending_pbft_lib); @@ -1682,7 +1672,7 @@ struct controller_impl { void set_pbft_lscb() { - if (!is_new_version()) return; + if (!pbft_enabled) return; if ( pending_pbft_checkpoint ) { @@ -2138,7 +2128,7 @@ chainbase::database& controller::mutable_db()const { return my->db; } const fork_database& controller::fork_db()const { return my->fork_db; } -std::map controller::my_signature_providers()const{ +std::map controller:: my_signature_providers()const{ return my->conf.my_signature_providers; } @@ -2719,12 +2709,12 @@ const upgrade_property_object& controller::get_upgrade_properties()const { return my->db.get(); } -bool controller::is_upgraded() const { - return my->is_new_version(); +bool controller::is_pbft_enabled() const { + return my->pbft_enabled; } -bool controller::under_upgrade() const { - return my->is_upgrading(); +bool controller::under_maintenance() const { + return my->pbft_upgrading; } void controller::maybe_switch_forks() { diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index a6ca7e12bc0..9bc79f70eee 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -306,8 +306,8 @@ namespace eosio { namespace chain { signal bad_alloc; const upgrade_property_object& get_upgrade_properties()const; - bool is_upgraded()const; - bool under_upgrade()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/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index 4d62f6c7507..ca8130a2381 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -68,7 +68,7 @@ namespace eosio { const uint32_t &get_current_view() const; - void set_current_view(const uint32_t ¤t_view); + void set_current_view(const uint32_t &cv); const vector &get_prepared_certificate() const; diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 4e021700577..e680e57d934 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -262,6 +262,10 @@ namespace eosio { return !(*this == rhs); } + bool operator<(const pbft_committed_certificate &rhs) const { + return block_num < rhs.block_num; + } + digest_type digest() const { digest_type::encoder enc; fc::raw::pack(enc, block_id); @@ -668,6 +672,12 @@ namespace eosio { vector fetch_first_fork_from(vector &bi); + bool is_valid_longest_fork( + const block_info &bi, + vector block_infos, + unsigned long threshold, + unsigned long non_fork_bp_count); + producer_schedule_type lscb_active_producers() const; template diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 5e013ed1c24..3d8b0ac2ff5 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -510,7 +510,9 @@ namespace eosio { } if (!new_view.committed.empty()) { - for (auto cp :new_view.committed) { + auto committed_certs = new_view.committed; + std::sort(committed_certs.begin(), committed_certs.end()); + for (auto cp :committed_certs) { for (auto c: cp.commits) { try { pbft_db.add_pbft_commit(c); @@ -597,8 +599,8 @@ namespace eosio { return this->current_view; } - void psm_machine::set_current_view(const uint32_t ¤t_view) { - this->current_view = current_view; + void psm_machine::set_current_view(const uint32_t &cv) { + this->current_view = cv; } const vector &psm_machine::get_prepared_certificate() const { diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index d53a7ae3369..dea1e58da90 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -665,73 +665,71 @@ namespace eosio { vector> pbft_database::generate_committed_certificate() { auto pcc = vector>{}; pcc.resize(ctrl.my_signature_providers().size()); - auto vc = vector{}; 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 vector>{}; pbft_state_ptr psp = *itr; - auto committed_block_num = psp->block_num; + if (itr == by_commit_and_num_index.end() || !psp->should_committed) return vector>{}; - if (prepare_watermarks.empty() || committed_block_num < prepare_watermarks[0]) { - if (psp->should_committed && (committed_block_num > (ctrl.last_stable_checkpoint_block_num()))) { - for (auto const &my_sp : ctrl.my_signature_providers()) { - auto pc = pbft_committed_certificate{psp->block_id, psp->block_num, psp->commits, my_sp.first}; - pc.producer_signature = my_sp.second(pc.digest()); - for (auto &c: pcc) { - c.emplace_back(pc); - } - } - return pcc; - } else return vector>{}; + auto highest_committed_block_num = psp->block_num; + + vector ccb; + + //adding my highest committed cert. + if ( highest_committed_block_num > ctrl.last_stable_checkpoint_block_num() ) { + ccb.emplace_back(highest_committed_block_num); } - const auto &by_id_index = pbft_state_index.get(); + for (auto i = 0; i < prepare_watermarks.size() && prepare_watermarks[i] < highest_committed_block_num; ++i) { + //adding committed cert on every water mark. + ccb.emplace_back(prepare_watermarks[i]); + } - for (auto i = 0; i < prepare_watermarks.size() && prepare_watermarks[i] <= committed_block_num; ++i) { - auto cbs = ctrl.fetch_block_state_by_number(prepare_watermarks[i]); - if (cbs) { - auto it = by_id_index.find(cbs->id); - if (it == by_id_index.end() || !(*it)->should_committed) return vector>{}; - auto as = cbs->active_schedule.producers; + const auto &by_id_index = pbft_state_index.get(); - auto commits = (*it)->commits; - auto valid_commits = vector{}; + for (const auto &committed_block_num: ccb) { + auto cbs = ctrl.fetch_block_state_by_number(committed_block_num); + if (!cbs) return vector>{}; - flat_map commit_count; - flat_map> commit_msg; + auto it = by_id_index.find(cbs->id); + if (it == by_id_index.end() || !(*it)->should_committed) { + return vector>{}; + } - for (const auto &com: commits) { - if (commit_count.find(com.view) == commit_count.end()) commit_count[com.view] = 0; - commit_msg[com.view].emplace_back(com); - } + auto as = cbs->active_schedule.producers; - for (auto const &sp: as) { - for (auto const &cc: commits) { - if (sp.block_signing_key == cc.public_key) commit_count[cc.view] += 1; - } - } + auto commits = (*it)->commits; + auto valid_commits = vector{}; - for (auto const &e: commit_count) { - if (e.second >= as.size() * 2 / 3 + 1) { - valid_commits = commit_msg[e.first]; - } - } + flat_map commit_count; + flat_map> commit_msg; - if (valid_commits.empty()) return vector>{}; + for (const auto &com: commits) { + if (commit_count.find(com.view) == commit_count.end()) commit_count[com.view] = 0; + commit_msg[com.view].emplace_back(com); + } - for (auto &c: valid_commits) { - vc.emplace_back(c); + for (auto const &sp: as) { + for (auto const &cc: commits) { + if (sp.block_signing_key == cc.public_key) commit_count[cc.view] += 1; } + } - for (auto const &my_sp : ctrl.my_signature_providers()) { - auto pc = pbft_committed_certificate{cbs->id, cbs->block_num, vc, my_sp.first}; - pc.producer_signature = my_sp.second(pc.digest()); - for (auto &c: pcc) { - c.emplace_back(pc); - } + for (auto const &e: commit_count) { + if (e.second >= as.size() * 2 / 3 + 1) { + valid_commits = commit_msg[e.first]; } - } else return vector>{}; + } + + if (valid_commits.empty()) return vector>{}; + + auto j = 0; + for (auto const &my_sp : ctrl.my_signature_providers()) { + auto cc = pbft_committed_certificate{cbs->id, cbs->block_num, valid_commits, my_sp.first}; + cc.producer_signature = my_sp.second(cc.digest()); + pcc[j].emplace_back(cc); + ++j; + } } return pcc; } @@ -799,42 +797,20 @@ namespace eosio { if (!should_prepared) return false; - { - //validate prepare - auto lscb = ctrl.last_stable_checkpoint_block_num(); - auto non_fork_bp_count = 0; - vector prepare_infos; - for (auto const &p : certificate.prepares) { - //only search in fork db - if (p.block_num <= lscb) { - ++non_fork_bp_count; - } else { - prepare_infos.emplace_back(block_info{p.block_id, p.block_num}); - } - } - - auto prepare_forks = fetch_fork_from(prepare_infos); - vector longest_fork; - for (auto const &f : prepare_forks) { - if (f.size() > longest_fork.size()) { - longest_fork = f; - } - } - if (longest_fork.size() + non_fork_bp_count < bp_threshold) return false; - - if (longest_fork.empty()) return true; - - auto calculated_block_info = longest_fork.back(); - - auto current_bs = ctrl.fetch_block_state_by_id(calculated_block_info.block_id); - while (current_bs) { - if (certificate.block_id == current_bs->id && certificate.block_num == current_bs->block_num) { - return true; - } - current_bs = ctrl.fetch_block_state_by_id(current_bs->prev()); + //validate prepare + auto lscb = ctrl.last_stable_checkpoint_block_num(); + auto non_fork_bp_count = 0; + vector prepare_infos; + for (auto const &p : certificate.prepares) { + //only search in fork db + if (p.block_num <= lscb) { + ++non_fork_bp_count; + } else { + prepare_infos.emplace_back(block_info{p.block_id, p.block_num}); } - return false; } + auto cert_info = block_info{certificate.block_id, certificate.block_num}; + return is_valid_longest_fork(cert_info, prepare_infos, bp_threshold, non_fork_bp_count); } bool pbft_database::is_valid_committed_certificate(const pbft_committed_certificate &certificate) { @@ -881,42 +857,20 @@ namespace eosio { if (!should_committed) return false; - { - //validate commit - auto lscb = ctrl.last_stable_checkpoint_block_num(); - auto non_fork_bp_count = 0; - vector commit_infos; - for (auto const &p : certificate.commits) { - //only search in fork db - if (p.block_num <= lscb) { - ++non_fork_bp_count; - } else { - commit_infos.emplace_back(block_info{p.block_id, p.block_num}); - } - } - - auto commit_forks = fetch_fork_from(commit_infos); - vector longest_fork; - for (auto const &f : commit_forks) { - if (f.size() > longest_fork.size()) { - longest_fork = f; - } - } - if (longest_fork.size() + non_fork_bp_count < bp_threshold) return false; - - if (longest_fork.empty()) return true; - - auto calculated_block_info = longest_fork.back(); - - auto current_bs = ctrl.fetch_block_state_by_id(calculated_block_info.block_id); - while (current_bs) { - if (certificate.block_id == current_bs->id && certificate.block_num == current_bs->block_num) { - return true; - } - current_bs = ctrl.fetch_block_state_by_id(current_bs->prev()); + //validate commit + auto lscb = ctrl.last_stable_checkpoint_block_num(); + auto non_fork_bp_count = 0; + vector commit_infos; + for (auto const &p : certificate.commits) { + //only search in fork db + if (p.block_num <= lscb) { + ++non_fork_bp_count; + } else { + commit_infos.emplace_back(block_info{p.block_id, p.block_num}); } - return false; } + auto cert_info = block_info{certificate.block_id, certificate.block_num}; + return is_valid_longest_fork(cert_info, commit_infos, bp_threshold, non_fork_bp_count); } bool pbft_database::is_valid_view_change(const pbft_view_change &vc) { @@ -1080,6 +1034,31 @@ namespace eosio { return result; } + bool pbft_database::is_valid_longest_fork(const block_info &bi, vector 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) { + 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(); + + auto current_bs = ctrl.fetch_block_state_by_id(calculated_block_info.block_id); + while (current_bs) { + if (bi.block_id == current_bs->id && bi.block_num == current_bs->block_num) { + return true; + } + current_bs = ctrl.fetch_block_state_by_id(current_bs->prev()); + } + return false; + } + pbft_stable_checkpoint pbft_database::fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr &b) { try { if (b) { @@ -1192,7 +1171,7 @@ namespace eosio { auto checkpoint = [&](const block_num_type &in) { const auto& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; - if (!ctrl.is_upgraded()) return false; + if (!ctrl.is_pbft_enabled()) return false; return in >= ucb && (in % 100 == 1 || std::find(prepare_watermarks.begin(), prepare_watermarks.end(), in) != prepare_watermarks.end()); }; diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index bc0a764ed10..a7993d40a27 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -198,11 +198,11 @@ class privileged_api : public context_aware_api { uint32_t target_num; fc::raw::unpack(ds, target_num); - EOS_ASSERT( context.control.head_block_num() < target_num - 100, wasm_execution_error, "upgrade target block is too close"); + EOS_ASSERT( context.control.head_block_num() < target_num - 100, wasm_execution_error, "target block invalid"); - EOS_ASSERT( !context.control.is_upgraded(), wasm_execution_error, "the system has already upgraded to the new version"); + EOS_ASSERT( !context.control.is_pbft_enabled(), wasm_execution_error, "pbft is already enabled"); - EOS_ASSERT( !context.control.under_upgrade(), wasm_execution_error, "the system is currently under upgrade"); + EOS_ASSERT( !context.control.under_maintenance(), wasm_execution_error, "the system is under maintenance"); context.db.modify( context.control.get_upgrade_properties(), [&]( auto& uprops ) { diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index a450177c41a..2dcafa4feda 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -1668,7 +1668,7 @@ namespace eosio { uint32_t head = cc.fork_db_head_block_num(); block_id_type head_id = cc.fork_db_head_block_id(); - auto upgraded = cc.is_upgraded(); + auto upgraded = cc.is_pbft_enabled(); if (peer_lib > lscb_num && upgraded) { //there might be a better way to sync checkpoints, yet we do not want to modify the existing handshake msg. fc_dlog(logger, "request sync checkpoints"); diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index 3b1762ba744..63bb1415b2c 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -133,9 +133,9 @@ namespace eosio { // only trigger pbft related logic if I am in sync and replayed. auto& chain = app().get_plugin().chain(); - auto new_version = chain.is_upgraded(); + auto enabled = chain.is_pbft_enabled(); - if (new_version && !upgraded) { + if (enabled && !upgraded) { wlog( "\n" "******** BATCH-PBFT ENABLED ********\n" "* *\n" @@ -149,6 +149,6 @@ namespace eosio { upgraded = true; } - return (new_version && (!is_syncing() && !is_replaying())); + return enabled && !is_syncing() && !is_replaying(); } } diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 61f6ac15f12..b41e159a6db 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -225,7 +225,7 @@ class producer_plugin_impl : public std::enable_shared_from_thisid; - auto new_version = chain.is_upgraded(); + auto new_version = chain.is_pbft_enabled(); auto new_bs = bsp->generate_next(new_block_header.timestamp, new_version); @@ -344,7 +344,7 @@ class producer_plugin_impl : public std::enable_shared_from_thistimestamp < fc::minutes(5) || (block->block_num() % 1000 == 0) ) { - if (chain.is_upgraded()) { + if (chain.is_pbft_enabled()) { ilog("Received block ${id}... #${n} @ ${t} signed by ${p} [trxs: ${count}, lib: ${lib}, lscb: ${lscb}, latency: ${latency} ms]", ("p", block->producer)("id", fc::variant(block->id()).as_string().substr(8, 16)) ("n", block_header::num_from_id(block->id()))("t", block->timestamp) @@ -1104,7 +1104,7 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { _pending_block_mode = pending_block_mode::speculating; } - auto new_version = chain.is_upgraded(); + auto new_version = chain.is_pbft_enabled(); if (_pending_block_mode == pending_block_mode::producing && !new_version) { // determine if our watermark excludes us from producing at this point diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index 71110c9cc2a..e2bf7918272 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -97,7 +97,7 @@ BOOST_AUTO_TEST_CASE(can_advance_lib_after_upgrade) { auto msp = make_signature_provider(); ctrl.set_my_signature_providers(msp); - auto is_upgraded = ctrl.is_upgraded(); + auto is_upgraded = ctrl.is_pbft_enabled(); BOOST_CHECK_EQUAL(is_upgraded, false); @@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(can_advance_lib_after_upgrade) { BOOST_CHECK_EQUAL(ctrl.last_irreversible_block_num(), 151); BOOST_CHECK_EQUAL(ctrl.head_block_num(), 152); - is_upgraded = ctrl.is_upgraded(); + is_upgraded = ctrl.is_pbft_enabled(); BOOST_CHECK_EQUAL(is_upgraded, true); tester.produce_blocks(10); @@ -142,7 +142,7 @@ BOOST_AUTO_TEST_CASE(can_advance_lib_after_upgrade_with_four_producers) { auto msp = make_signature_provider(); ctrl.set_my_signature_providers(msp); - auto is_upgraded = ctrl.is_upgraded(); + auto is_upgraded = ctrl.is_pbft_enabled(); BOOST_CHECK_EQUAL(is_upgraded, false); @@ -161,10 +161,10 @@ BOOST_AUTO_TEST_CASE(can_advance_lib_after_upgrade_with_four_producers) { BOOST_CHECK_EQUAL(ctrl.last_irreversible_block_num(), 108); BOOST_CHECK_EQUAL(ctrl.head_block_num(), 156); - is_upgraded = ctrl.is_upgraded(); + is_upgraded = ctrl.is_pbft_enabled(); BOOST_CHECK_EQUAL(is_upgraded, false); tester.produce_blocks(12); - is_upgraded = ctrl.is_upgraded(); + is_upgraded = ctrl.is_pbft_enabled(); BOOST_CHECK_EQUAL(is_upgraded, true); BOOST_CHECK_EQUAL(ctrl.last_irreversible_block_num(), 120); BOOST_CHECK_EQUAL(ctrl.head_block_num(), 168); @@ -234,9 +234,9 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o pbft_new_view_generator.maybe_pbft_commit(); new_view_generator.produce_blocks(1); - BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.is_upgraded(), true); - BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.is_upgraded(), true); - BOOST_CHECK_EQUAL(ctrl_new_view_generator.is_upgraded(), true); + BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.is_pbft_enabled(), true); + BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.is_pbft_enabled(), true); + BOOST_CHECK_EQUAL(ctrl_new_view_generator.is_pbft_enabled(), true); BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.head_block_num(), 127); BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.head_block_num(), 127); BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.fetch_block_by_number(100)->id(), ctrl_short_prepared_fork.fetch_block_by_number(100)->id()); From ad8ee81ac9f95281deb8fb4a3275ff300a550859 Mon Sep 17 00:00:00 2001 From: deadlock Date: Fri, 3 May 2019 23:47:43 +0800 Subject: [PATCH 9/9] bugfix:fix snapshot integrity test --- libraries/chain/controller.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 7eb92ab4b12..55f3a939acd 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -353,8 +353,6 @@ struct controller_impl { void init(std::function shutdown, const snapshot_reader_ptr& snapshot) { - //do upgrade migration if necessary; - migrate_upgrade(); bool report_integrity_hash = !!snapshot; if (snapshot) { @@ -363,6 +361,9 @@ struct controller_impl { read_from_snapshot( snapshot ); + //do upgrade migration if necessary; + migrate_upgrade(); //compatiable for snapshot integrity test + auto end = blog.read_head(); if( !end ) { blog.reset( conf.genesis, signed_block_ptr(), head->block_num + 1 ); @@ -373,6 +374,8 @@ struct controller_impl { "Block log is provided with snapshot but does not contain the head block from the snapshot" ); } } else { + //do upgrade migration if necessary; + migrate_upgrade(); //compatiable for snapshot integrity test if( !head ) { initialize_fork_db(); // set head to genesis state }