diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ec500711..696bd5361 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 0) +set(VERSION_PATCH 1) 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 02eabc07b..57d456fe7 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.0 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.1 tag, you could do the following: ```bash -docker build -t boscore/bos:v3.0.0 --build-arg branch=v3.0.0 . +docker build -t boscore/bos:v3.0.1 --build-arg branch=v3.0.1 . ``` diff --git a/README.md b/README.md index db7f7e0f8..711835c59 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # BOSCore - Born for DApps. Born for Usability. -## BOSCore Version: v3.0.0 +## BOSCore Version: v3.0.1 ### Basic EOSIO Version: v1.6.6 (support REX) # Background @@ -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 718c2ace4..ade0d3715 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,6 +1,6 @@ # BOSCore - 更可用的链,为DApp而生。 -## BOSCore Version: v3.0.0 +## BOSCore Version: v3.0.1 ### Basic EOSIO Version: v1.6.6 (support REX) # 背景 @@ -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) diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index ba78d3ab1..2bebe05cc 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(const 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(const 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 7fd03ebb3..b72f9645b 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 8789abce3..ccc5598dc 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -69,19 +69,19 @@ 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(const pbft_metadata_ptr &nv) { + void pbft_controller::on_pbft_new_view(const pbft_metadata_ptr& nv) { state_machine->on_new_view(nv); } @@ -113,31 +113,31 @@ 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(const pbft_metadata_ptr &e) { + void psm_machine::on_new_view(const pbft_metadata_ptr& e) { if (e->msg.new_view <= get_current_view()) return; try { @@ -167,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; @@ -201,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()) { @@ -220,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; @@ -235,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()); } @@ -246,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; @@ -258,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()); @@ -270,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; @@ -278,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; @@ -300,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()); } @@ -309,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(); @@ -342,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(); @@ -356,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(); @@ -366,26 +366,26 @@ 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); 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); + //TODO: reset commit timer; 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()); @@ -399,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) { @@ -419,13 +418,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; @@ -464,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 7bcaf19fa..3e2a71fd8 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -180,7 +180,10 @@ namespace eosio { auto lib = ctrl.last_irreversible_block_id(); if (lib == block_id_type()) return true; auto forks = ctrl.fork_db().fetch_branch_from(in, lib); - return !forks.first.empty() && forks.second.empty(); + + //`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; }; @@ -190,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)) { @@ -198,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; @@ -222,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; @@ -327,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 { @@ -348,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; } @@ -512,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 { @@ -528,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; } @@ -602,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, std::make_shared(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() { @@ -840,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(); @@ -1320,7 +1327,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 a168ea549..81935707a 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 ce0eab28d..581bcb804 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 3b1a38f13..529bd3ed9 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, 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(); @@ -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; @@ -2362,7 +2362,8 @@ namespace eosio { } if( !conn->read_delay_timer ) return; conn->read_delay_timer->expires_from_now( def_read_delay_for_full_write_queue ); - conn->read_delay_timer->async_wait([this, weak_conn]( boost::system::error_code ) { + conn->read_delay_timer->async_wait([this, weak_conn]( boost::system::error_code ec ) { + if ( ec == boost::asio::error::operation_aborted ) return; auto conn = weak_conn.lock(); if( !conn ) return; start_read_message( conn ); @@ -2830,11 +2831,17 @@ 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; - fc_dlog(logger, "received checkpoint request message ${m}", ("m", msg)); + 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) { + 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(); @@ -2842,10 +2849,14 @@ namespace eosio { 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) { - auto bid = cc.get_block_id_for_num(i); - auto scp = pcc.pbft_db.get_stable_checkpoint_by_id(bid); - if (!scp.empty()) { - scp_stack.push_back(scp); + try { + auto bid = cc.get_block_id_for_num(i); + auto scp = pcc.pbft_db.get_stable_checkpoint_by_id(bid); + if (!scp.empty()) { + scp_stack.push_back(scp); + } + } catch (...) { + break; } } @@ -3009,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) { @@ -3019,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){ @@ -3080,6 +3089,8 @@ namespace eosio { } void net_plugin_impl::clean_expired_pbft_messages(){ + pbft_message_cache_ticker(); + auto itr = pbft_message_cache.begin(); auto now = time_point::now(); @@ -3091,57 +3102,59 @@ 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, 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; - 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(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, const pbft_commit &msg) { + 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(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_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, 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; - 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(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); } @@ -3156,29 +3169,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, const pbft_new_view &msg) { auto added = maybe_add_to_pbft_cache(std::string(msg.sender_signature)); if (!added) return; - auto pmm = pbft_message_metadata(msg, chain_id); + pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - 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(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); - 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, const compressed_pbft_message &msg) { auto decompressed_msg = decompress_pbft(msg.content); @@ -3194,25 +3214,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, 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; - 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_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, const pbft_stable_checkpoint &msg) { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); @@ -3249,11 +3269,14 @@ 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) { - pbft_message_cache_ticker (); - if (ec) { + + if ( !ec ) { + clean_expired_pbft_messages(); + } else { wlog ("pbft message cache ticker error: ${m}", ("m", ec.message())); + pbft_message_cache_ticker(); } - clean_expired_pbft_messages(); + }); } diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index 266a043bf..f2d75c5a6 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); @@ -347,6 +349,445 @@ 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)); +} + +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_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(); + 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_ctrl.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_ctrl.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 final + c3_final.produce_block(); + c3_final.create_accounts( {N(alice), N(bob)} ); + c3_final.produce_block(); + + // make and get signature provider for c3 final + std::map msp_c3_final; + msp_c3_final[pub_bob]=sp_bob; + + c3_final_ctrl.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 + c1_pbft_controller.maybe_pbft_prepare(); + pbft_prepare c2_prepare_ = c2_pbft_controller.state_machine->get_prepares_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.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); + + pbft_prepare c1_prepare; + c1_prepare_ = c1_pbft_controller.state_machine->get_prepares_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(); + 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); + + c3_final_pbft_controller.maybe_pbft_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())); + + 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_final + 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); + + 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(); + /// 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(); + 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()