From a28493e29af72c2eec479a4d821b7dabb56737e6 Mon Sep 17 00:00:00 2001 From: oldcold Date: Tue, 14 May 2019 18:56:10 +0800 Subject: [PATCH 01/22] fix potential crash when calculating integrity hash --- libraries/chain/controller.cpp | 97 +++++++++++++++------------------- 1 file changed, 43 insertions(+), 54 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index c6f611de03c..bf187a5a14d 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -557,20 +557,19 @@ struct controller_impl { section.add_row(batch_pbft_snapshot_migration{}, db); }); - if (pbft_enabled) { - snapshot->write_section([this]( auto §ion ) { - section.add_row(batch_pbft_enabled{}, db); - }); - snapshot->write_section([this](auto §ion) { - auto bid = fork_db.get_block_in_current_chain_by_num(fork_db.head()->pbft_stable_checkpoint_blocknum)->id; - EOS_ASSERT(bid != block_id_type{}, snapshot_exception, "cannot find lscb block"); - auto bss = fork_db.fetch_branch_from(fork_db.head()->id, bid).first; - section.template add_row(bss, db); - }); + auto lscb = fork_db.get_block_in_current_chain_by_num(fork_db.head()->pbft_stable_checkpoint_blocknum); + if (pbft_enabled && lscb) { + snapshot->write_section([this]( auto §ion ) { + section.add_row(batch_pbft_enabled{}, db); + }); + snapshot->write_section([this, &lscb](auto §ion) { + auto bss = fork_db.fetch_branch_from(fork_db.head()->id, lscb->id).first; + section.add_row(bss, db); + }); } else { - snapshot->write_section([this]( auto §ion ){ - section.template add_row(*fork_db.head(), db); - }); + snapshot->write_section([this]( auto §ion ) { + section.template add_row(*fork_db.head(), db); + }); } controller_index_set::walk_indices([this, &snapshot]( auto utils ){ @@ -602,53 +601,43 @@ struct controller_impl { }); bool migrated = snapshot->has_section(); - if (migrated) { - auto upgraded = snapshot->has_section(); - if (upgraded) { - snapshot->read_section([this](auto §ion) { - branch_type bss; - section.template read_row(bss, db); - EOS_ASSERT(!bss.empty(), snapshot_exception, "no last stable checkpoint block in the snapshot"); - - wlog("${n} reversible blocks found in the snapshot", ("n", bss.size())); - - for (auto i = bss.rbegin(); i != bss.rend(); ++i ) { - if (i == bss.rbegin()) { - fork_db.set(*i); - snapshot_head_block = (*i)->block_num; - } else { - fork_db.add((*i), true, true); - } - fork_db.set_validity((*i), true); - fork_db.mark_in_current_chain((*i), true); + auto upgraded = snapshot->has_section(); + if (migrated && upgraded) { + + snapshot->read_section([this](auto §ion) { + branch_type bss; + section.read_row(bss, db); + if (bss.empty()) elog( "no last stable checkpoint block found in the snapshot, perhaps corrupted"); + + wlog("${n} fork_db blocks found in the snapshot", ("n", bss.size())); + + for (auto i = bss.rbegin(); i != bss.rend(); ++i ) { + if (i == bss.rbegin()) { + fork_db.set(*i); + snapshot_head_block = (*i)->block_num; + } else { + fork_db.add((*i), true, true); + } + fork_db.set_validity((*i), true); + fork_db.mark_in_current_chain((*i), true); } head = fork_db.head(); - }); - } else { - snapshot->read_section([this](auto §ion) { - block_header_state head_header_state; - section.read_row(head_header_state, db); - - auto head_state = std::make_shared(head_header_state); - fork_db.set(head_state); - fork_db.set_validity(head_state, true); - fork_db.mark_in_current_chain(head_state, true); - head = head_state; - snapshot_head_block = head->block_num; - }); - } + }); } else { - snapshot->read_section([this](snapshot_reader::section_reader §ion) { + snapshot->read_section([this, &migrated](snapshot_reader::section_reader §ion) { block_header_state head_header_state; - section.read_pbft_migrate_row(head_header_state, db); - + if (migrated) { + section.read_row(head_header_state, db); + } else { + section.read_pbft_migrate_row(head_header_state, db); + } auto head_state = std::make_shared(head_header_state); fork_db.set(head_state); fork_db.set_validity(head_state, true); fork_db.mark_in_current_chain(head_state, true); head = head_state; snapshot_head_block = head->block_num; - }); + }); } @@ -661,14 +650,14 @@ struct controller_impl { } if(snapshot->has_section()){ - snapshot->read_section([this]( auto& section ) { + snapshot->read_section([this]( auto& section ) { bool more = !section.empty(); while(more) { - decltype(utils)::create(db, [this, §ion, &more]( auto &row ) { + decltype(utils)::create(db, [this, §ion, &more]( auto &row ) { more = section.read_row(row, db); - }); + }); } - }); + }); } }); From 8dad3186718b0be44a1ff49d991ca24c51ade1c1 Mon Sep 17 00:00:00 2001 From: oldcold Date: Tue, 14 May 2019 21:57:06 +0800 Subject: [PATCH 02/22] fix snapshot's container reading in different os. --- libraries/chain/controller.cpp | 43 +++++++++++++++++----------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index bf187a5a14d..e26e1e44112 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -544,6 +544,7 @@ struct controller_impl { }); } + struct lscb_branch{}; void add_to_snapshot( const snapshot_writer_ptr& snapshot ) const { snapshot->write_section([this]( auto §ion ){ section.add_row(chain_snapshot_header(), db); @@ -562,9 +563,10 @@ struct controller_impl { snapshot->write_section([this]( auto §ion ) { section.add_row(batch_pbft_enabled{}, db); }); - snapshot->write_section([this, &lscb](auto §ion) { + + snapshot->write_section([this, &lscb](auto §ion) { auto bss = fork_db.fetch_branch_from(fork_db.head()->id, lscb->id).first; - section.add_row(bss, db); + section.template add_row(bss, db); }); } else { snapshot->write_section([this]( auto §ion ) { @@ -603,25 +605,24 @@ struct controller_impl { bool migrated = snapshot->has_section(); auto upgraded = snapshot->has_section(); if (migrated && upgraded) { - - snapshot->read_section([this](auto §ion) { - branch_type bss; - section.read_row(bss, db); - if (bss.empty()) elog( "no last stable checkpoint block found in the snapshot, perhaps corrupted"); - - wlog("${n} fork_db blocks found in the snapshot", ("n", bss.size())); - - for (auto i = bss.rbegin(); i != bss.rend(); ++i ) { - if (i == bss.rbegin()) { - fork_db.set(*i); - snapshot_head_block = (*i)->block_num; - } else { - fork_db.add((*i), true, true); - } - fork_db.set_validity((*i), true); - fork_db.mark_in_current_chain((*i), true); - } - head = fork_db.head(); + snapshot->read_section([this](auto §ion) { + branch_type bss; + section.template read_row(bss, db); + if (bss.empty()) elog( "no last stable checkpoint block found in the snapshot, perhaps corrupted"); + + wlog("${n} fork_db blocks found in the snapshot", ("n", bss.size())); + + for (auto i = bss.rbegin(); i != bss.rend(); ++i ) { + if (i == bss.rbegin()) { + fork_db.set(*i); + snapshot_head_block = (*i)->block_num; + } else { + fork_db.add((*i), true, true); + } + fork_db.set_validity((*i), true); + fork_db.mark_in_current_chain((*i), true); + } + head = fork_db.head(); }); } else { snapshot->read_section([this, &migrated](snapshot_reader::section_reader §ion) { From 37beebe0be10a1a5bea1c264eaf744b46d446eb8 Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 15 May 2019 12:26:42 +0800 Subject: [PATCH 03/22] reformat snapshot sections; reformat getting block state in pbft_db. --- libraries/chain/controller.cpp | 37 +----- .../include/eosio/chain/chain_snapshot.hpp | 13 +- libraries/chain/pbft_database.cpp | 119 +++++++++--------- 3 files changed, 73 insertions(+), 96 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index e26e1e44112..9fb60881f85 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -544,7 +544,6 @@ struct controller_impl { }); } - struct lscb_branch{}; void add_to_snapshot( const snapshot_writer_ptr& snapshot ) const { snapshot->write_section([this]( auto §ion ){ section.add_row(chain_snapshot_header(), db); @@ -554,17 +553,13 @@ struct controller_impl { section.add_row(conf.genesis, db); }); - snapshot->write_section([this]( auto §ion ){ - section.add_row(batch_pbft_snapshot_migration{}, db); - }); + snapshot->write_section([]( auto §ion ){}); auto lscb = fork_db.get_block_in_current_chain_by_num(fork_db.head()->pbft_stable_checkpoint_blocknum); if (pbft_enabled && lscb) { - snapshot->write_section([this]( auto §ion ) { - section.add_row(batch_pbft_enabled{}, db); - }); + snapshot->write_section([]( auto §ion ) {}); - snapshot->write_section([this, &lscb](auto §ion) { + snapshot->write_section([this, &lscb](auto §ion) { auto bss = fork_db.fetch_branch_from(fork_db.head()->id, lscb->id).first; section.template add_row(bss, db); }); @@ -602,15 +597,15 @@ struct controller_impl { header.validate(); }); - bool migrated = snapshot->has_section(); + bool migrated = snapshot->has_section(); auto upgraded = snapshot->has_section(); if (migrated && upgraded) { - snapshot->read_section([this](auto §ion) { + snapshot->read_section([this](auto §ion) { branch_type bss; section.template read_row(bss, db); if (bss.empty()) elog( "no last stable checkpoint block found in the snapshot, perhaps corrupted"); - wlog("${n} fork_db blocks found in the snapshot", ("n", bss.size())); + ilog("${n} fork_db blocks found in the snapshot", ("n", bss.size())); for (auto i = bss.rbegin(); i != bss.rend(); ++i ) { if (i == bss.rbegin()) { @@ -921,26 +916,6 @@ struct controller_impl { } // "bos end" - optional upgrade_target_block() { - - const auto& upo = db.get(); - if (upo.upgrade_target_block_num > 0) { - return upo.upgrade_target_block_num; - } else { - return optional{}; - } - } - - optional upgrade_complete_block() { - - const auto& upo = db.get(); - if (upo.upgrade_complete_block_num > 0) { - return upo.upgrade_complete_block_num; - } else { - return optional{}; - } - } - /** * @post regardless of the success of commit block there is no active pending block */ diff --git a/libraries/chain/include/eosio/chain/chain_snapshot.hpp b/libraries/chain/include/eosio/chain/chain_snapshot.hpp index 43801333d2f..58ea0d45725 100644 --- a/libraries/chain/include/eosio/chain/chain_snapshot.hpp +++ b/libraries/chain/include/eosio/chain/chain_snapshot.hpp @@ -29,16 +29,11 @@ struct chain_snapshot_header { } }; -struct batch_pbft_snapshot_migration{ - bool migrated = true; -}; +struct batch_pbft_snapshot_migrated{}; -struct batch_pbft_enabled { - bool enabled = true; -}; +struct batch_pbft_enabled{}; +struct batch_pbft_lscb_branch{}; } } -FC_REFLECT(eosio::chain::chain_snapshot_header,(version)) -FC_REFLECT(eosio::chain::batch_pbft_snapshot_migration,(migrated)) -FC_REFLECT(eosio::chain::batch_pbft_enabled,(enabled)) \ No newline at end of file +FC_REFLECT(eosio::chain::chain_snapshot_header,(version)) \ No newline at end of file diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 5440aec0db2..4d487651dfe 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -212,24 +212,26 @@ namespace eosio { auto current_watermark = get_current_pbft_watermark(); auto lib = ctrl.last_irreversible_block_num(); - uint32_t high_water_mark_block_num = head_block_num; + uint32_t high_watermark_block_num = head_block_num; if ( current_watermark > 0 ) { - high_water_mark_block_num = std::min(head_block_num, current_watermark); + high_watermark_block_num = std::min(head_block_num, current_watermark); } - if (high_water_mark_block_num <= lib) return vector{}; + if (high_watermark_block_num <= lib) return vector{}; - block_id_type high_water_mark_block_id = ctrl.get_block_id_for_num(high_water_mark_block_num); - for (auto const &sp : ctrl.my_signature_providers()) { - auto uuid = boost::uuids::to_string(uuid_generator()); - auto p = pbft_prepare{uuid, current_view, high_water_mark_block_num, high_water_mark_block_id, - sp.first, chain_id()}; - p.producer_signature = sp.second(p.digest()); - add_pbft_prepare(p); - emit(pbft_outgoing_prepare, p); - new_pv.emplace_back(p); - ctrl.set_pbft_my_prepare(high_water_mark_block_id); + if (auto hwbs = ctrl.fork_db().get_block_in_current_chain_by_num(high_watermark_block_num)) { + + for (auto const &sp : ctrl.my_signature_providers()) { + auto uuid = boost::uuids::to_string(uuid_generator()); + auto p = pbft_prepare{uuid, current_view, high_watermark_block_num, hwbs->id, sp.first, + chain_id()}; + p.producer_signature = sp.second(p.digest()); + add_pbft_prepare(p); + emit(pbft_outgoing_prepare, p); + new_pv.emplace_back(p); + ctrl.set_pbft_my_prepare(hwbs->id); + } } return new_pv; } @@ -338,13 +340,14 @@ namespace eosio { } else { const auto &by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); - if (itr == by_prepare_and_num_index.end()) { - return vector{}; - } - vector new_cv; + if (itr == by_prepare_and_num_index.end()) return vector{}; + + pbft_state_ptr psp = *itr; auto bs = ctrl.fork_db().get_block(psp->block_id); + if (!bs) return vector{}; + vector new_cv; if (psp->should_prepared && (psp->block_num > ctrl.last_irreversible_block_num())) { for (auto const &sp : ctrl.my_signature_providers()) { @@ -1174,8 +1177,10 @@ namespace eosio { auto checkpoint = [&](const block_num_type &in) { const auto& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; if (!ctrl.is_pbft_enabled()) return false; - return in >= ucb - && (in == ucb + 1 || in % 100 == 1 || std::find(prepare_watermarks.begin(), prepare_watermarks.end(), in) != prepare_watermarks.end()); + if (in <= ucb) return false; + return in == ucb + 1 // checkpoint on first pbft block; + || in % 100 == 1 // checkpoint on every 100 block; + || std::find(prepare_watermarks.begin(), prepare_watermarks.end(), in) != prepare_watermarks.end(); // checkpoint on bp schedule change; }; for (auto i = psp->block_num; @@ -1183,19 +1188,22 @@ namespace eosio { if (checkpoint(i)) { my_latest_checkpoint = max(i, my_latest_checkpoint); auto &by_block = checkpoint_index.get(); - auto c_itr = by_block.find(ctrl.get_block_id_for_num(i)); - if (c_itr == by_block.end()) { - pending_checkpoint_block_num.emplace_back(i); - } else { - auto checkpoints = (*c_itr)->checkpoints; - bool contains_mine = false; - for (auto const &my_sp : ctrl.my_signature_providers()) { - auto p_itr = find_if(checkpoints.begin(), checkpoints.end(), - [&](const pbft_checkpoint &ext) { return ext.public_key == my_sp.first; }); - if (p_itr != checkpoints.end()) contains_mine = true; - } - if (!contains_mine) { + + if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(i)) { + auto c_itr = by_block.find(bs->id); + if (c_itr == by_block.end()) { pending_checkpoint_block_num.emplace_back(i); + } else { + auto checkpoints = (*c_itr)->checkpoints; + bool contains_mine = false; + for (auto const &my_sp : ctrl.my_signature_providers()) { + auto p_itr = find_if(checkpoints.begin(), checkpoints.end(), + [&](const pbft_checkpoint &ext) { return ext.public_key == my_sp.first; }); + if (p_itr != checkpoints.end()) contains_mine = true; + } + if (!contains_mine) { + pending_checkpoint_block_num.emplace_back(i); + } } } } @@ -1204,36 +1212,37 @@ namespace eosio { if (!pending_checkpoint_block_num.empty()) { std::sort(pending_checkpoint_block_num.begin(), pending_checkpoint_block_num.end()); for (auto h: pending_checkpoint_block_num) { - for (auto const &my_sp : ctrl.my_signature_providers()) { - auto uuid = boost::uuids::to_string(uuid_generator()); - auto cp = pbft_checkpoint{uuid, h, ctrl.get_block_id_for_num(h), - my_sp.first, .chain_id=chain_id()}; - cp.producer_signature = my_sp.second(cp.digest()); - add_pbft_checkpoint(cp); - new_pc.emplace_back(cp); + if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(h)) { + for (auto const &my_sp : ctrl.my_signature_providers()) { + auto uuid = boost::uuids::to_string(uuid_generator()); + auto cp = pbft_checkpoint{uuid, h, bs->id, my_sp.first, .chain_id=chain_id()}; + cp.producer_signature = my_sp.second(cp.digest()); + add_pbft_checkpoint(cp); + new_pc.emplace_back(cp); + } } } } else if (my_latest_checkpoint > 1) { - auto lscb_id = ctrl.get_block_id_for_num(my_latest_checkpoint); - auto &by_block = checkpoint_index.get(); - auto h_itr = by_block.find(lscb_id); - if (h_itr != by_block.end()) { - auto checkpoints = (*h_itr)->checkpoints; - for (auto const &my_sp : ctrl.my_signature_providers()) { - for (auto const &cp: checkpoints) { - if (my_sp.first == cp.public_key) { - auto retry_cp = cp; - auto uuid = boost::uuids::to_string(uuid_generator()); - retry_cp.uuid = uuid; - retry_cp.timestamp = time_point::now(); - retry_cp.producer_signature = my_sp.second(retry_cp.digest()); - new_pc.emplace_back(retry_cp); + if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(my_latest_checkpoint)) { + auto &by_block = checkpoint_index.get(); + auto h_itr = by_block.find(bs->id); + if (h_itr != by_block.end()) { + auto checkpoints = (*h_itr)->checkpoints; + for (auto const &my_sp : ctrl.my_signature_providers()) { + for (auto const &cp: checkpoints) { + if (my_sp.first == cp.public_key) { + auto retry_cp = cp; + auto uuid = boost::uuids::to_string(uuid_generator()); + retry_cp.uuid = uuid; + retry_cp.timestamp = time_point::now(); + retry_cp.producer_signature = my_sp.second(retry_cp.digest()); + new_pc.emplace_back(retry_cp); + } } } } } } - return new_pc; } @@ -1262,9 +1271,7 @@ namespace eosio { auto csp = (*itr); auto checkpoints = csp->checkpoints; auto p_itr = find_if(checkpoints.begin(), checkpoints.end(), - [&](const pbft_checkpoint &existed) { - return existed.public_key == cp.public_key; - }); + [&](const pbft_checkpoint &existed) { return existed.public_key == cp.public_key; }); if (p_itr == checkpoints.end()) { by_block.modify(itr, [&](const pbft_checkpoint_state_ptr &pcp) { csp->checkpoints.emplace_back(cp); From 1cc5e17a219c43db086013aa9fe13c51c3c4aea0 Mon Sep 17 00:00:00 2001 From: oldcold Date: Fri, 17 May 2019 22:38:09 +0800 Subject: [PATCH 04/22] re-struct pbft message; compress pbft new view --- libraries/chain/controller.cpp | 2 - libraries/chain/include/eosio/chain/pbft.hpp | 23 +- .../include/eosio/chain/pbft_database.hpp | 435 ++++++------------ libraries/chain/pbft.cpp | 124 +++-- libraries/chain/pbft_database.cpp | 222 ++++----- .../include/eosio/net_plugin/protocol.hpp | 10 +- plugins/net_plugin/net_plugin.cpp | 114 +++-- 7 files changed, 394 insertions(+), 536 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 9fb60881f85..1d5b0ee231f 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -2343,7 +2343,6 @@ block_id_type controller::last_stable_checkpoint_block_id() const { return block_id_type{}; } - vector controller::proposed_schedule_block_nums() const { return my->proposed_schedule_blocks; } @@ -2681,7 +2680,6 @@ producer_schedule_type controller::initial_schedule() const { return producer_schedule_type{ 0, {{eosio::chain::config::system_account_name, my->conf.genesis.initial_key}} }; } - bool controller::is_known_unexpired_transaction( const transaction_id_type& id) const { return db().find(id); } diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index dd275943451..2beb900d68d 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -13,9 +13,9 @@ namespace eosio { vector prepares_cache; vector commits_cache; vector view_changes_cache; - vector prepared_certificate; - vector> committed_certificate; - vector view_changed_certificate; + pbft_prepared_certificate prepared_certificate; + vector committed_certificate; + pbft_view_changed_certificate view_changed_certificate; }; class psm_machine { @@ -51,6 +51,9 @@ namespace eosio { template void transit_to_view_change_state(T const & s); + template + bool maybe_new_view(T const & s); + template void transit_to_new_view(const pbft_new_view &new_view, T const &s); @@ -70,17 +73,17 @@ namespace eosio { void set_current_view(const uint32_t &cv); - const vector &get_prepared_certificate() const; + const pbft_prepared_certificate &get_prepared_certificate() const; - void set_prepared_certificate(const vector &pcert); + void set_prepared_certificate(const pbft_prepared_certificate &pcert); - const vector> &get_committed_certificate() const; + const vector &get_committed_certificate() const; - void set_committed_certificate(const vector> &ccert); + void set_committed_certificate(const vector &ccert); - const vector &get_view_changed_certificate() const; + const pbft_view_changed_certificate &get_view_changed_certificate() const; - void set_view_changed_certificate(const vector &vc_cert); + void set_view_changed_certificate(const pbft_view_changed_certificate &vc_cert); const uint32_t &get_target_view_retries() const; @@ -208,7 +211,7 @@ namespace eosio { class pbft_controller { public: - pbft_controller(controller& ctrl); + explicit pbft_controller(controller& ctrl); ~pbft_controller(); pbft_database pbft_db; diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index e680e57d934..fbb725f525e 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -26,88 +26,80 @@ namespace eosio { block_num_type block_num = 0; }; - struct pbft_prepare { - string uuid; - uint32_t view; - block_num_type block_num = 0; - block_id_type block_id; + struct pbft_message { + string uuid; public_key_type public_key; - chain_id_type chain_id = chain_id_type(""); - signature_type producer_signature; - time_point timestamp = time_point::now(); + chain_id_type chain_id = chain_id_type(""); + signature_type producer_signature; + time_point timestamp = time_point::now(); + virtual digest_type digest() const { + digest_type::encoder enc; + fc::raw::pack(enc, public_key); + fc::raw::pack(enc, chain_id); + return enc.result(); + } - bool operator==(const pbft_prepare &rhs) const { - return view == rhs.view - && block_num == rhs.block_num - && block_id == rhs.block_id - && public_key == rhs.public_key - && chain_id == rhs.chain_id - && timestamp == rhs.timestamp; + virtual 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; + } } - bool operator!=(const pbft_prepare &rhs) const { - return !(*this == rhs); + virtual ~pbft_message() = default; + }; + + struct pbft_prepare final: public pbft_message { + explicit pbft_prepare() = default; + uint32_t view = 0; + block_num_type block_num = 0; + block_id_type block_id; + + bool operator==(const pbft_prepare &rhs) const { + return digest() == rhs.digest(); } bool operator<(const pbft_prepare &rhs) const { if (block_num < rhs.block_num) { return true; - } else return block_num == rhs.block_num && view < rhs.view; + } else { + return block_num == rhs.block_num && view < rhs.view; + } } - digest_type digest() const { + digest_type digest() const override { digest_type::encoder enc; fc::raw::pack(enc, view); fc::raw::pack(enc, block_num); fc::raw::pack(enc, block_id); fc::raw::pack(enc, public_key); fc::raw::pack(enc, chain_id); - fc::raw::pack(enc, timestamp); 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_commit { - string uuid; - uint32_t view; - block_num_type block_num = 0; - block_id_type block_id; - public_key_type public_key; - chain_id_type chain_id = chain_id_type(""); - signature_type producer_signature; - time_point timestamp = time_point::now(); - + struct pbft_commit final: public pbft_message { + explicit pbft_commit() = default; + uint32_t view = 0; + block_num_type block_num = 0; + block_id_type block_id; bool operator==(const pbft_commit &rhs) const { - return view == rhs.view - && block_num == rhs.block_num - && block_id == rhs.block_id - && public_key == rhs.public_key - && chain_id == rhs.chain_id - && timestamp == rhs.timestamp; - } - - bool operator!=(const pbft_commit &rhs) const { - return !(*this == rhs); + return digest() == rhs.digest(); } bool operator<(const pbft_commit &rhs) const { if (block_num < rhs.block_num) { return true; - } else return block_num == rhs.block_num && view < rhs.view; + } else { + return block_num == rhs.block_num && view < rhs.view; + } } - digest_type digest() const { + digest_type digest() const override { digest_type::encoder enc; fc::raw::pack(enc, view); fc::raw::pack(enc, block_num); @@ -117,33 +109,16 @@ namespace eosio { fc::raw::pack(enc, timestamp); 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_checkpoint { - string uuid; - block_num_type block_num = 0; - block_id_type block_id; - public_key_type public_key; - chain_id_type chain_id = chain_id_type(""); - signature_type producer_signature; - time_point timestamp = time_point::now(); + struct pbft_checkpoint final: public pbft_message { + explicit pbft_checkpoint() = default; - bool operator==(const pbft_checkpoint &rhs) const { - return block_num == rhs.block_num - && block_id == rhs.block_id - && public_key == rhs.public_key - && chain_id == rhs.chain_id - && timestamp == rhs.timestamp; + block_num_type block_num = 0; + block_id_type block_id; + bool operator==(const pbft_checkpoint &rhs) const { + return digest() == rhs.digest(); } bool operator!=(const pbft_checkpoint &rhs) const { @@ -154,7 +129,7 @@ namespace eosio { return block_num < rhs.block_num; } - digest_type digest() const { + digest_type digest() const override { digest_type::encoder enc; fc::raw::pack(enc, block_num); fc::raw::pack(enc, block_id); @@ -163,35 +138,15 @@ namespace eosio { fc::raw::pack(enc, timestamp); 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_stable_checkpoint { - block_num_type block_num = 0; - block_id_type block_id; - vector checkpoints; - chain_id_type chain_id = chain_id_type(""); - - bool operator==(const pbft_stable_checkpoint &rhs) const { - return block_id == rhs.block_id - && block_num == rhs.block_num - && checkpoints == rhs.checkpoints - && chain_id == rhs.chain_id; - } - - bool operator!=(const pbft_stable_checkpoint &rhs) const { - return !(*this == rhs); - } + struct pbft_certificate { + block_num_type block_num = 0; + block_id_type block_id; + vector messages; + chain_id_type chain_id = chain_id_type(""); - bool operator<(const pbft_stable_checkpoint &rhs) const { + bool operator<(const pbft_certificate &rhs) const { return block_num < rhs.block_num; } @@ -199,125 +154,65 @@ namespace eosio { digest_type::encoder enc; fc::raw::pack(enc, block_num); fc::raw::pack(enc, block_id); - fc::raw::pack(enc, checkpoints); + fc::raw::pack(enc, messages); fc::raw::pack(enc, chain_id); return enc.result(); } }; - struct pbft_prepared_certificate { - block_id_type block_id; - block_num_type block_num = 0; - vector prepares; + struct pbft_stable_checkpoint final: public pbft_certificate { + explicit pbft_stable_checkpoint() = default; - public_key_type public_key; - signature_type producer_signature; + vector messages; - bool operator==(const pbft_prepared_certificate &rhs) const { - return block_num == rhs.block_num - && block_id == rhs.block_id - && prepares == rhs.prepares - && public_key == rhs.public_key; + bool operator==(const pbft_stable_checkpoint &rhs) const { + return digest() == rhs.digest(); } - bool operator!=(const pbft_prepared_certificate &rhs) const { + bool operator!=(const pbft_stable_checkpoint &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, prepares); - 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_committed_certificate { - block_id_type block_id; - block_num_type block_num = 0; - vector commits; - - public_key_type public_key; - signature_type producer_signature; + struct pbft_prepared_certificate final: public pbft_certificate { + explicit pbft_prepared_certificate() = default; - 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; - } + vector messages; - bool operator!=(const pbft_committed_certificate &rhs) const { - return !(*this == rhs); + bool operator==(const pbft_prepared_certificate &rhs) const { + return digest() == rhs.digest(); } + }; - bool operator<(const pbft_committed_certificate &rhs) const { - return block_num < rhs.block_num; - } + struct pbft_committed_certificate final: public pbft_certificate { + explicit pbft_committed_certificate() = default; - 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(); - } + vector messages; - 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; - } + bool operator==(const pbft_committed_certificate &rhs) const { + return digest() == rhs.digest(); } }; - 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(""); - signature_type producer_signature; - time_point timestamp = time_point::now(); + struct pbft_view_change final: public pbft_message { + explicit pbft_view_change() = default; - bool operator==(const pbft_view_change &rhs) const { - 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 - && timestamp == rhs.timestamp; - } + uint32_t current_view = 0; + uint32_t target_view = 1; + pbft_prepared_certificate prepared; + vector committed; + pbft_stable_checkpoint stable_checkpoint; - bool operator!=(const pbft_view_change &rhs) const { - return !(*this == rhs); + bool operator==(const pbft_view_change &rhs) const { + return digest() == rhs.digest(); } bool operator<(const pbft_view_change &rhs) const { return target_view < rhs.target_view; } - digest_type digest() const { + digest_type digest() const override { digest_type::encoder enc; fc::raw::pack(enc, current_view); fc::raw::pack(enc, target_view); @@ -326,87 +221,46 @@ namespace eosio { fc::raw::pack(enc, stable_checkpoint); fc::raw::pack(enc, public_key); fc::raw::pack(enc, chain_id); - fc::raw::pack(enc, timestamp); 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_changed_certificate { - uint32_t view; - vector view_changes; + explicit pbft_view_changed_certificate() = default; - public_key_type public_key; - signature_type producer_signature; + vector messages; + uint32_t view = 0; bool operator==(const pbft_view_changed_certificate &rhs) const { - return view == rhs.view - && view_changes == rhs.view_changes - && public_key == rhs.public_key; - } - - bool operator!=(const pbft_view_changed_certificate &rhs) const { - return !(*this == rhs); + return digest() == rhs.digest(); } digest_type digest() const { digest_type::encoder enc; fc::raw::pack(enc, view); - fc::raw::pack(enc, view_changes); - fc::raw::pack(enc, public_key); + fc::raw::pack(enc, messages); 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_new_view { - 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; - chain_id_type chain_id = chain_id_type(""); - signature_type producer_signature; - time_point timestamp = time_point::now(); + struct pbft_new_view final: public pbft_message { + explicit pbft_new_view() = default; - 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 - && chain_id == rhs.chain_id - && timestamp == rhs.timestamp; - } + uint32_t view = 0; + pbft_prepared_certificate prepared; + vector committed; + pbft_stable_checkpoint stable_checkpoint; + pbft_view_changed_certificate view_changed; - bool operator!=(const pbft_new_view &rhs) const { - return !(*this == rhs); + bool operator==(const pbft_new_view &rhs) const { + return digest() == rhs.digest(); } bool operator<(const pbft_new_view &rhs) const { return view < rhs.view; } - digest_type digest() const { + digest_type digest() const override { digest_type::encoder enc; fc::raw::pack(enc, view); fc::raw::pack(enc, prepared); @@ -415,44 +269,34 @@ namespace eosio { fc::raw::pack(enc, view_changed); fc::raw::pack(enc, public_key); fc::raw::pack(enc, chain_id); - fc::raw::pack(enc, timestamp); 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_state { - block_id_type block_id; - block_num_type block_num = 0; - vector prepares; - bool should_prepared = false; - vector commits; - bool should_committed = false; + block_id_type block_id; + block_num_type block_num = 0; + vector prepares; + bool should_prepared = false; + vector commits; + bool should_committed = false; }; - struct pbft_view_state { - uint32_t view; - vector view_changes; - bool should_view_changed = false; + struct pbft_view_change_state { + uint32_t view; + vector view_changes; + bool should_view_changed = false; }; struct pbft_checkpoint_state { - block_id_type block_id; - block_num_type block_num = 0; + block_id_type block_id; + block_num_type block_num = 0; vector checkpoints; - bool is_stable = false; + bool is_stable = false; }; using pbft_state_ptr = std::shared_ptr; - using pbft_view_state_ptr = std::shared_ptr; + using pbft_view_change_state_ptr = std::shared_ptr; using pbft_checkpoint_state_ptr = std::shared_ptr; struct by_block_id; @@ -500,19 +344,19 @@ namespace eosio { struct by_view; struct by_count_and_view; typedef multi_index_container< - pbft_view_state_ptr, + pbft_view_change_state_ptr, indexed_by< hashed_unique< tag, - member, + member, std::hash >, ordered_non_unique< tag, composite_key< - pbft_view_state, - member, - member + pbft_view_change_state, + member, + member >, composite_key_compare, greater<>> > @@ -580,13 +424,13 @@ namespace eosio { vector send_and_add_pbft_view_change( const vector &vcv = vector{}, - const vector &ppc = vector{}, - const vector> &pcc = vector>{}, + const pbft_prepared_certificate &ppc = pbft_prepared_certificate{}, + const vector &pcc = vector{}, uint32_t current_view = 0, uint32_t new_view = 1); pbft_new_view send_pbft_new_view( - const vector &vcc = vector{}, + const pbft_view_changed_certificate &vcc = pbft_view_changed_certificate{}, uint32_t current_view = 1); vector generate_and_add_pbft_checkpoint(); @@ -603,13 +447,11 @@ namespace eosio { uint32_t get_committed_view(); - chain_id_type chain_id(); - - vector generate_prepared_certificate(); + pbft_prepared_certificate generate_prepared_certificate(); - vector> generate_committed_certificate(); + vector generate_committed_certificate(); - vector generate_view_changed_certificate(uint32_t target_view); + pbft_view_changed_certificate generate_view_changed_certificate(uint32_t target_view); pbft_stable_checkpoint get_stable_checkpoint_by_id(const block_id_type &block_id); @@ -657,6 +499,7 @@ namespace eosio { pbft_state_multi_index_type pbft_state_index; pbft_view_state_multi_index_type view_state_index; pbft_checkpoint_state_multi_index_type checkpoint_index; + chain_id_type chain_id = chain_id_type(""); fc::path pbft_db_dir; fc::path checkpoints_dir; boost::uuids::random_generator uuid_generator; @@ -668,7 +511,7 @@ namespace eosio { public_key_type get_new_view_primary_key(uint32_t target_view); - vector> fetch_fork_from(vector block_infos); + vector> fetch_fork_from(vector &block_infos); vector fetch_first_fork_from(vector &bi); @@ -695,19 +538,17 @@ namespace eosio { } /// namespace eosio::chain FC_REFLECT(eosio::chain::block_info, (block_id)(block_num)) -FC_REFLECT(eosio::chain::pbft_prepare, - (uuid)(view)(block_num)(block_id)(public_key)(chain_id)(producer_signature)(timestamp)) -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)(committed)(stable_checkpoint)(public_key)(chain_id)(producer_signature)(timestamp)) -FC_REFLECT(eosio::chain::pbft_new_view, - (uuid)(view)(prepared)(committed)(stable_checkpoint)(view_changed)(public_key)(chain_id)(producer_signature)(timestamp)) +FC_REFLECT(eosio::chain::pbft_message, (uuid)(public_key)(chain_id)(producer_signature)(timestamp)) +FC_REFLECT_DERIVED(eosio::chain::pbft_prepare, (eosio::chain::pbft_message), (view)(block_num)(block_id)) +FC_REFLECT_DERIVED(eosio::chain::pbft_commit, (eosio::chain::pbft_message), (view)(block_num)(block_id)) +FC_REFLECT_DERIVED(eosio::chain::pbft_view_change, (eosio::chain::pbft_message), (current_view)(target_view)(prepared)(committed)(stable_checkpoint)) +FC_REFLECT_DERIVED(eosio::chain::pbft_new_view, (eosio::chain::pbft_message), (view)(prepared)(committed)(stable_checkpoint)(view_changed)) +FC_REFLECT_DERIVED(eosio::chain::pbft_checkpoint, (eosio::chain::pbft_message), (block_num)(block_id)) +FC_REFLECT(eosio::chain::pbft_certificate, (block_num)(block_id)(messages)) +FC_REFLECT_DERIVED(eosio::chain::pbft_prepared_certificate, (eosio::chain::pbft_certificate), ) +FC_REFLECT_DERIVED(eosio::chain::pbft_committed_certificate,(eosio::chain::pbft_certificate), ) +FC_REFLECT(eosio::chain::pbft_view_changed_certificate, (view)(messages)) +FC_REFLECT_DERIVED(eosio::chain::pbft_stable_checkpoint, (eosio::chain::pbft_certificate), ) 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)) -FC_REFLECT(eosio::chain::pbft_stable_checkpoint, (block_num)(block_id)(checkpoints)(chain_id)) +FC_REFLECT(eosio::chain::pbft_view_change_state, (view)(view_changes)(should_view_changed)) FC_REFLECT(eosio::chain::pbft_checkpoint_state, (block_id)(block_num)(checkpoints)(is_stable)) \ No newline at end of file diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 2236de50f5a..76c7b161179 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -103,8 +103,9 @@ namespace eosio { this->set_commits_cache(vector{}); this->set_view_changes_cache(vector{}); - this->set_prepared_certificate(vector{}); - this->set_view_changed_certificate(vector{}); + this->set_prepared_certificate(pbft_prepared_certificate{}); + this->set_committed_certificate(vector{}); + this->set_view_changed_certificate(pbft_view_changed_certificate{}); this->view_change_timer = 0; this->target_view_retries = 0; @@ -236,9 +237,9 @@ namespace eosio { } } - void psm_prepared_state::manually_set_view(psm_machine *m, const uint32_t ¤t_view) { - m->set_current_view(current_view); - m->set_target_view(current_view+1); + void psm_prepared_state::manually_set_view(psm_machine *m, const uint32_t &view) { + m->set_current_view(view); + m->set_target_view(view+1); m->transit_to_view_change_state(this); } @@ -317,9 +318,9 @@ namespace eosio { } } - void psm_committed_state::manually_set_view(psm_machine *m, const uint32_t ¤t_view) { - m->set_current_view(current_view); - m->set_target_view(current_view+1); + void psm_committed_state::manually_set_view(psm_machine *m, const uint32_t &view) { + m->set_current_view(view); + m->set_target_view(view+1); m->transit_to_view_change_state(this); } @@ -355,28 +356,7 @@ namespace eosio { pbft_db.add_pbft_view_change(e); - //if view_change >= 2f+1, calculate next primary, send new view if is primary - auto nv = m->get_target_view(); - if (pbft_db.should_new_view(nv) && pbft_db.is_new_primary(nv)) { - - m->set_view_changed_certificate(pbft_db.generate_view_changed_certificate(nv)); - - auto new_view = pbft_db.get_proposed_new_view_num(); - if (new_view != nv) return; - - auto nv_msg = pbft_db.send_pbft_new_view( - m->get_view_changed_certificate(), - new_view); - - if (nv_msg == pbft_new_view{}) return; - - try { - m->transit_to_new_view(nv_msg, this); - } catch(const fc::exception& ex) { - wlog("bad new view, ${s} ", ("s",ex.to_string())); - } - return; - } + m->maybe_new_view(this); } void psm_view_change_state::send_view_change(psm_machine *m, pbft_database &pbft_db) { @@ -390,28 +370,7 @@ namespace eosio { m->send_pbft_view_change(); - //if view_change >= 2f+1, calculate next primary, send new view if is primary - auto nv = m->get_target_view(); - if (pbft_db.should_new_view(nv) && pbft_db.is_new_primary(nv)) { - - m->set_view_changed_certificate(pbft_db.generate_view_changed_certificate(nv)); - - auto new_view = pbft_db.get_proposed_new_view_num(); - if (new_view != nv) return; - - auto nv_msg = pbft_db.send_pbft_new_view( - m->get_view_changed_certificate(), - new_view); - - if (nv_msg == pbft_new_view{}) return; - - try { - m->transit_to_new_view(nv_msg, this); - } catch(const fc::exception& ex) { - wlog("bad new view, ${s} ", ("s",ex.to_string())); - } - return; - } + m->maybe_new_view(this); } @@ -426,9 +385,9 @@ namespace eosio { } } - void psm_view_change_state::manually_set_view(psm_machine *m, const uint32_t ¤t_view) { - m->set_current_view(current_view); - m->set_target_view(current_view+1); + void psm_view_change_state::manually_set_view(psm_machine *m, const uint32_t &view) { + m->set_current_view(view); + m->set_target_view(view+1); m->transit_to_view_change_state(this); } @@ -473,11 +432,41 @@ namespace eosio { this->set_target_view_retries(0); this->set_current(new psm_view_change_state); - if (pbft_db.should_send_pbft_msg()) this->send_pbft_view_change(); - + if (pbft_db.should_send_pbft_msg()) { + this->send_pbft_view_change(); + auto nv = this->maybe_new_view(s); + if (nv) return; + } delete s; } + template + bool psm_machine::maybe_new_view(T const &s) { + //if view_change >= 2f+1, calculate next primary, send new view if is primary + auto nv = this->get_target_view(); + if (pbft_db.should_new_view(nv) && pbft_db.is_new_primary(nv)) { + + this->set_view_changed_certificate(pbft_db.generate_view_changed_certificate(nv)); + + auto new_view = pbft_db.get_proposed_new_view_num(); + if (new_view != nv) return false; + + auto nv_msg = pbft_db.send_pbft_new_view( + this->get_view_changed_certificate(), + new_view); + + if (nv_msg == pbft_new_view{}) return false; + + try { + this->transit_to_new_view(nv_msg, s); + return true; + } catch(const fc::exception& ex) { + wlog("bad new view, ${s} ", ("s",ex.to_string())); + } + } + return false; + } + template void psm_machine::transit_to_new_view(const pbft_new_view &new_view, T const &s) { @@ -500,7 +489,7 @@ namespace eosio { this->pbft_db.prune_pbft_index(); if (!(new_view.stable_checkpoint == pbft_stable_checkpoint{})) { - for (auto cp :new_view.stable_checkpoint.checkpoints) { + for (auto cp :new_view.stable_checkpoint.messages) { try { pbft_db.add_pbft_checkpoint(cp); } catch (...) { @@ -513,7 +502,7 @@ namespace eosio { auto committed_certs = new_view.committed; std::sort(committed_certs.begin(), committed_certs.end()); for (auto cp :committed_certs) { - for (auto c: cp.commits) { + for (auto c: cp.messages) { try { pbft_db.add_pbft_commit(c); } catch (...) { @@ -523,8 +512,8 @@ namespace eosio { } } - if (!new_view.prepared.prepares.empty()) { - for (auto p: new_view.prepared.prepares) { + if (!new_view.prepared.messages.empty()) { + for (auto p: new_view.prepared.messages) { try { pbft_db.add_pbft_prepare(p); } catch (...) { @@ -603,28 +592,27 @@ namespace eosio { this->current_view = cv; } - const vector &psm_machine::get_prepared_certificate() const { + const pbft_prepared_certificate &psm_machine::get_prepared_certificate() const { return this->cache.prepared_certificate; } - void psm_machine::set_prepared_certificate(const vector &pcert) { + void psm_machine::set_prepared_certificate(const pbft_prepared_certificate &pcert) { this->cache.prepared_certificate = pcert; } - const vector> &psm_machine::get_committed_certificate() const { + const vector &psm_machine::get_committed_certificate() const { return this->cache.committed_certificate; } - void psm_machine::set_committed_certificate(const vector> &ccert) { + void psm_machine::set_committed_certificate(const vector &ccert) { this->cache.committed_certificate = ccert; } - const vector &psm_machine::get_view_changed_certificate() const { + const pbft_view_changed_certificate &psm_machine::get_view_changed_certificate() const { return this->cache.view_changed_certificate; } - void psm_machine::set_view_changed_certificate( - const vector &vc_cert) { + void psm_machine::set_view_changed_certificate(const pbft_view_changed_certificate &vc_cert) { this->cache.view_changed_certificate = vc_cert; } diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 4d487651dfe..ae503b16f9a 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -13,6 +13,7 @@ namespace eosio { prepare_watermarks = vector{}; pbft_db_dir = ctrl.state_dir(); checkpoints_dir = ctrl.blocks_dir(); + chain_id = ctrl.get_chain_id(); if (!fc::is_directory(pbft_db_dir)) fc::create_directories(pbft_db_dir); @@ -129,7 +130,7 @@ namespace eosio { auto curr_psp = make_shared(curr_ps); pbft_state_index.insert(curr_psp); } catch (...) { - wlog( "prepare insert failure: ${p}", ("p", p)); + elog( "prepare insert failure: ${p}", ("p", p)); } } else { auto prepares = (*curr_itr)->prepares; @@ -201,7 +202,8 @@ namespace eosio { for (auto const &sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); auto my_prepare_num = ctrl.fetch_block_state_by_id(my_prepare)->block_num; - auto p = pbft_prepare{uuid, current_view, my_prepare_num, my_prepare, sp.first, chain_id()}; + auto p = pbft_prepare{}; + p.uuid=uuid; p.view=current_view; p.block_num=my_prepare_num; p.block_id=my_prepare; p.public_key=sp.first; p.chain_id=chain_id; p.producer_signature = sp.second(p.digest()); emit(pbft_outgoing_prepare, p); new_pv.emplace_back(p); @@ -224,8 +226,8 @@ namespace eosio { for (auto const &sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); - auto p = pbft_prepare{uuid, current_view, high_watermark_block_num, hwbs->id, sp.first, - chain_id()}; + auto p = pbft_prepare{}; + p.uuid=uuid; p.view=current_view; p.block_num=high_watermark_block_num; p.block_id=hwbs->id; p.public_key=sp.first; p.chain_id=chain_id; p.producer_signature = sp.second(p.digest()); add_pbft_prepare(p); emit(pbft_outgoing_prepare, p); @@ -256,7 +258,7 @@ namespace eosio { } bool pbft_database::is_valid_prepare(const pbft_prepare &p) { - if (p.chain_id != chain_id()) return false; + if (p.chain_id != chain_id) return false; // a prepare msg under lscb (which is no longer in fork_db), can be treated as null, thus true. if (p.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; if (!p.is_signature_valid()) return false; @@ -280,7 +282,7 @@ namespace eosio { auto curr_psp = make_shared(curr_ps); pbft_state_index.insert(curr_psp); } catch (...) { - wlog("commit insertion failure: ${c}", ("c", c)); + elog("commit insertion failure: ${c}", ("c", c)); } } else { auto commits = (*curr_itr)->commits; @@ -352,7 +354,8 @@ namespace eosio { for (auto const &sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); - auto c = pbft_commit{uuid, current_view, psp->block_num, psp->block_id, sp.first, chain_id()}; + auto c = pbft_commit{}; + c.uuid=uuid; c.view=current_view; c.block_num=psp->block_num; c.block_id=psp->block_id; c.public_key=sp.first; c.chain_id=chain_id; c.producer_signature = sp.second(c.digest()); add_pbft_commit(c); emit(pbft_outgoing_commit, c); @@ -408,7 +411,7 @@ namespace eosio { } bool pbft_database::is_valid_commit(const pbft_commit &c) { - if (c.chain_id != chain_id()) return false; + if (c.chain_id != chain_id) return false; if (c.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; if (!c.is_signature_valid()) return false; return should_recv_pbft_msg(c.public_key); @@ -435,8 +438,8 @@ namespace eosio { auto &by_view_index = view_state_index.get(); auto itr = by_view_index.find(vc.target_view); if (itr == by_view_index.end()) { - auto vs = pbft_view_state{vc.target_view, .view_changes={vc}}; - auto vsp = make_shared(vs); + auto vs = pbft_view_change_state{vc.target_view, .view_changes={vc}}; + auto vsp = make_shared(vs); view_state_index.insert(vsp); } else { auto pvs = (*itr); @@ -446,7 +449,7 @@ namespace eosio { return existed.public_key == vc.public_key; }); if (p_itr == view_changes.end()) { - by_view_index.modify(itr, [&](const pbft_view_state_ptr &pvsp) { + by_view_index.modify(itr, [&](const pbft_view_change_state_ptr &pvsp) { pvsp->view_changes.emplace_back(vc); }); } @@ -463,7 +466,7 @@ namespace eosio { } } if (vc_count >= active_bps.size() * 2 / 3 + 1) { - by_view_index.modify(itr, [&](const pbft_view_state_ptr &pvsp) { pvsp->should_view_changed = true; }); + by_view_index.modify(itr, [&](const pbft_view_change_state_ptr &pvsp) { pvsp->should_view_changed = true; }); } } } @@ -496,8 +499,8 @@ namespace eosio { vector pbft_database::send_and_add_pbft_view_change( const vector &vcv, - const vector &ppc, - const vector> &pcc, + const pbft_prepared_certificate &ppc, + const vector &pcc, uint32_t current_view, uint32_t new_view) { if (!vcv.empty()) { @@ -514,25 +517,11 @@ namespace eosio { vector new_vcv; for (auto const &my_sp : ctrl.my_signature_providers()) { - auto ppc_ptr = find_if(ppc.begin(), ppc.end(), - [&](const pbft_prepared_certificate &v) { - return v.public_key == my_sp.first; - }); - - 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_pcc, my_lsc, my_sp.first, chain_id()}; + auto vc = pbft_view_change{}; + vc.uuid=uuid; vc.current_view=current_view; vc.target_view=new_view; vc.prepared=ppc; vc.committed=pcc; vc.stable_checkpoint=my_lsc; vc.public_key=my_sp.first; vc.chain_id=chain_id; vc.producer_signature = my_sp.second(vc.digest()); emit(pbft_outgoing_view_change, vc); add_pbft_view_change(vc); @@ -566,13 +555,12 @@ namespace eosio { } void pbft_database::prune_pbft_index() { -// pbft_state_index.clear(); view_state_index.clear(); ctrl.reset_pbft_my_prepare(); } pbft_new_view pbft_database::send_pbft_new_view( - const vector &vcc, + const pbft_view_changed_certificate &vcc, uint32_t current_view) { auto primary_key = get_new_view_primary_key(current_view); @@ -582,16 +570,13 @@ namespace eosio { auto my_sps = ctrl.my_signature_providers(); auto sp_itr = my_sps.find(primary_key); - auto vcc_ptr = find_if(vcc.begin(), vcc.end(), - [&](const pbft_view_changed_certificate &v) { return v.public_key == primary_key; }); - - if (vcc_ptr == vcc.end()) return pbft_new_view{}; + if (vcc == pbft_view_changed_certificate{}) 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) { + for (const auto &vc: vcc.messages) { if (vc.prepared.block_num > highest_ppc.block_num && is_valid_prepared_certificate(vc.prepared)) { highest_ppc = vc.prepared; } @@ -612,69 +597,66 @@ namespace eosio { auto uuid = boost::uuids::to_string(uuid_generator()); - auto nv = pbft_new_view{uuid, current_view, highest_ppc, highest_pcc, highest_sc, *vcc_ptr, sp_itr->first, chain_id()}; + auto nv = pbft_new_view{}; + nv.uuid=uuid; nv.view=current_view; nv.prepared=highest_ppc; nv.committed=highest_pcc; nv.stable_checkpoint=highest_sc, nv.view_changed=vcc, nv.public_key=sp_itr->first; nv.chain_id=chain_id; nv.producer_signature = sp_itr->second(nv.digest()); emit(pbft_outgoing_new_view, nv); return nv; } - vector pbft_database::generate_prepared_certificate() { - auto ppc = vector{}; + pbft_prepared_certificate pbft_database::generate_prepared_certificate() { + const auto &by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); - if (itr == by_prepare_and_num_index.end()) return vector{}; + if (itr == by_prepare_and_num_index.end()) return pbft_prepared_certificate{}; pbft_state_ptr psp = *itr; auto prepared_block_state = ctrl.fetch_block_state_by_id(psp->block_id); - if (!prepared_block_state) return vector{}; + if (!prepared_block_state) return pbft_prepared_certificate{}; auto as = prepared_block_state->active_schedule.producers; if (psp->should_prepared && (psp->block_num > (ctrl.last_irreversible_block_num()))) { - for (auto const &my_sp : ctrl.my_signature_providers()) { - auto prepares = psp->prepares; - auto valid_prepares = vector{}; + auto prepares = psp->prepares; + auto valid_prepares = vector{}; - flat_map prepare_count; - flat_map> prepare_msg; + flat_map prepare_count; + flat_map> prepare_msg; - for (const auto &pre: prepares) { - if (prepare_count.find(pre.view) == prepare_count.end()) prepare_count[pre.view] = 0; - prepare_msg[pre.view].emplace_back(pre); - } + for (const auto &pre: prepares) { + if (prepare_count.find(pre.view) == prepare_count.end()) prepare_count[pre.view] = 0; + prepare_msg[pre.view].emplace_back(pre); + } - for (auto const &sp: as) { - for (auto const &pp: prepares) { - if (sp.block_signing_key == pp.public_key) prepare_count[pp.view] += 1; - } + for (auto const &sp: as) { + for (auto const &pp: prepares) { + if (sp.block_signing_key == pp.public_key) prepare_count[pp.view] += 1; } + } - for (auto const &e: prepare_count) { - if (e.second >= as.size() * 2 / 3 + 1) { - valid_prepares = prepare_msg[e.first]; - } + for (auto const &e: prepare_count) { + if (e.second >= as.size() * 2 / 3 + 1) { + valid_prepares = prepare_msg[e.first]; } + } - if (valid_prepares.empty()) return vector{}; + if (valid_prepares.empty()) return pbft_prepared_certificate{}; - auto pc = pbft_prepared_certificate{psp->block_id, psp->block_num, valid_prepares, my_sp.first}; - pc.producer_signature = my_sp.second(pc.digest()); - ppc.emplace_back(pc); - } - return ppc; - } else return vector{}; + auto pc = pbft_prepared_certificate{}; + pc.block_id=psp->block_id; pc.block_num=psp->block_num; pc.messages=valid_prepares; + return pc; + } else return pbft_prepared_certificate{}; } - vector> pbft_database::generate_committed_certificate() { - auto pcc = vector>{}; - pcc.resize(ctrl.my_signature_providers().size()); + vector pbft_database::generate_committed_certificate() { + 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>{}; + if (itr == by_commit_and_num_index.end()) return vector{}; pbft_state_ptr psp = *itr; - if (!psp->should_committed) return vector>{}; + if (!psp->should_committed) return vector{}; auto highest_committed_block_num = psp->block_num; @@ -692,13 +674,14 @@ namespace eosio { const auto &by_id_index = pbft_state_index.get(); + auto pcc = vector{}; for (const auto &committed_block_num: ccb) { auto cbs = ctrl.fetch_block_state_by_number(committed_block_num); - if (!cbs) return vector>{}; + if (!cbs) return vector{}; auto it = by_id_index.find(cbs->id); if (it == by_id_index.end() || !(*it)->should_committed) { - return vector>{}; + return vector{}; } auto as = cbs->active_schedule.producers; @@ -726,36 +709,30 @@ namespace eosio { } } - if (valid_commits.empty()) return vector>{}; + if (valid_commits.empty()) return vector{}; + + auto cc = pbft_committed_certificate{}; + cc.block_id=cbs->id; cc.block_num=cbs->block_num; cc.messages=valid_commits; + pcc.emplace_back(cc); + - 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; } - vector pbft_database::generate_view_changed_certificate(uint32_t target_view) { - auto vcc = vector{}; + pbft_view_changed_certificate pbft_database::generate_view_changed_certificate(uint32_t target_view) { auto &by_view_index = view_state_index.get(); auto itr = by_view_index.find(target_view); - if (itr == by_view_index.end()) return vcc; + if (itr == by_view_index.end()) return pbft_view_changed_certificate{}; auto pvs = *itr; if (pvs->should_view_changed) { - for (auto const &my_sp : ctrl.my_signature_providers()) { - auto pc = pbft_view_changed_certificate{pvs->view, pvs->view_changes, my_sp.first}; - pc.producer_signature = my_sp.second(pc.digest()); - vcc.emplace_back(pc); - } - return vcc; - } else return vector{}; + auto pvcc = pbft_view_changed_certificate{}; + pvcc.view=pvs->view; pvcc.messages=pvs->view_changes; + return pvcc; + } else return pbft_view_changed_certificate{}; } bool pbft_database::is_valid_prepared_certificate(const pbft_prepared_certificate &certificate) { @@ -765,8 +742,7 @@ namespace eosio { if (certificate.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; auto valid = true; - valid = valid && certificate.is_signature_valid(); - for (auto const &p : certificate.prepares) { + for (auto const &p : certificate.messages) { valid = valid && is_valid_prepare(p); if (!valid) return false; } @@ -779,7 +755,7 @@ namespace eosio { } auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; - auto prepares = certificate.prepares; + auto prepares = certificate.messages; flat_map prepare_count; for (const auto &pre: prepares) { @@ -806,7 +782,7 @@ namespace eosio { auto lscb = ctrl.last_stable_checkpoint_block_num(); auto non_fork_bp_count = 0; vector prepare_infos; - for (auto const &p : certificate.prepares) { + for (auto const &p : certificate.messages) { //only search in fork db if (p.block_num <= lscb) { ++non_fork_bp_count; @@ -825,8 +801,7 @@ namespace eosio { 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) { + for (auto const &c : certificate.messages) { valid = valid && is_valid_commit(c); if (!valid) return false; } @@ -839,7 +814,7 @@ namespace eosio { } auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; - auto commits = certificate.commits; + auto commits = certificate.messages; flat_map commit_count; for (const auto &pre: commits) { @@ -866,7 +841,7 @@ namespace eosio { auto lscb = ctrl.last_stable_checkpoint_block_num(); auto non_fork_bp_count = 0; vector commit_infos; - for (auto const &p : certificate.commits) { + for (auto const &p : certificate.messages) { //only search in fork db if (p.block_num <= lscb) { ++non_fork_bp_count; @@ -879,7 +854,7 @@ namespace eosio { } bool pbft_database::is_valid_view_change(const pbft_view_change &vc) { - if (vc.chain_id != chain_id()) return false; + if (vc.chain_id != chain_id) return false; return vc.is_signature_valid() && should_recv_pbft_msg(vc.public_key); @@ -890,7 +865,7 @@ namespace eosio { bool pbft_database::is_valid_new_view(const pbft_new_view &nv) { //all signatures should be valid - EOS_ASSERT(nv.chain_id == chain_id(), pbft_exception, "wrong chain."); + EOS_ASSERT(nv.chain_id == chain_id, pbft_exception, "wrong chain."); EOS_ASSERT(is_valid_prepared_certificate(nv.prepared), pbft_exception, "bad prepared certificate: ${pc}", ("pc", nv.prepared)); @@ -898,8 +873,6 @@ namespace eosio { EOS_ASSERT(is_valid_stable_checkpoint(nv.stable_checkpoint), pbft_exception, "bad stable checkpoint: ${scp}", ("scp", nv.stable_checkpoint)); - EOS_ASSERT(nv.view_changed.is_signature_valid(), pbft_exception, "bad view changed signature"); - EOS_ASSERT(nv.is_signature_valid(), pbft_exception, "bad new view signature"); EOS_ASSERT(nv.view_changed.view == nv.view, pbft_exception, "target view not match"); @@ -912,7 +885,7 @@ namespace eosio { vector view_change_producers; - for (auto vc: nv.view_changed.view_changes) { + for (auto vc: nv.view_changed.messages) { if (is_valid_view_change(vc)) { add_pbft_view_change(vc); view_change_producers.emplace_back(vc.public_key); @@ -935,7 +908,7 @@ namespace eosio { auto highest_pcc = vector{}; auto highest_scp = pbft_stable_checkpoint{}; - for (const auto &vc: nv.view_changed.view_changes) { + for (const auto &vc: nv.view_changed.messages) { if (vc.prepared.block_num > highest_ppc.block_num && is_valid_prepared_certificate(vc.prepared)) { highest_ppc = vc.prepared; @@ -974,23 +947,22 @@ namespace eosio { && lscb_num > vc.stable_checkpoint.block_num; } - vector> pbft_database::fetch_fork_from(const vector block_infos) { - auto bi = block_infos; + vector> pbft_database::fetch_fork_from(vector &block_infos) { vector> result; - if (bi.empty()) { + if (block_infos.empty()) { return result; } - if (bi.size() == 1) { - result.emplace_back(initializer_list{bi.front()}); + if (block_infos.size() == 1) { + result.emplace_back(initializer_list{block_infos.front()}); return result; } - sort(bi.begin(), bi.end(), + sort(block_infos.begin(), block_infos.end(), [](const block_info &a, const block_info &b) -> bool { return a.block_num > b.block_num; }); - while (!bi.empty()) { - auto fork = fetch_first_fork_from(bi); + while (!block_infos.empty()) { + auto fork = fetch_first_fork_from(block_infos); if (!fork.empty()) { result.emplace_back(fork); } @@ -1088,7 +1060,7 @@ namespace eosio { } } } catch(...) { - wlog("no stable checkpoints found in the block extension"); + elog("no stable checkpoints found in the block extension"); } return pbft_stable_checkpoint{}; } @@ -1105,7 +1077,8 @@ namespace eosio { if (cpp->is_stable) { if (ctrl.my_signature_providers().empty()) return pbft_stable_checkpoint{}; - auto psc = pbft_stable_checkpoint{cpp->block_num, cpp->block_id, cpp->checkpoints, chain_id()}; + auto psc = pbft_stable_checkpoint{}; + psc.block_num=cpp->block_num; psc.block_id=cpp->block_id; psc.messages=cpp->checkpoints; psc.chain_id=chain_id; return psc; } else return pbft_stable_checkpoint{}; } @@ -1133,7 +1106,6 @@ namespace eosio { if (lscb_num == 0) { const auto& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; -// if (ucb == 0) return lscb_info; if (ucb == 0) { current_schedule = ctrl.initial_schedule(); new_schedule = ctrl.initial_schedule(); @@ -1211,11 +1183,12 @@ namespace eosio { if (!pending_checkpoint_block_num.empty()) { std::sort(pending_checkpoint_block_num.begin(), pending_checkpoint_block_num.end()); - for (auto h: pending_checkpoint_block_num) { - if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(h)) { + for (auto bnum: pending_checkpoint_block_num) { + if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(bnum)) { for (auto const &my_sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); - auto cp = pbft_checkpoint{uuid, h, bs->id, my_sp.first, .chain_id=chain_id()}; + auto cp = pbft_checkpoint{}; + cp.uuid=uuid; cp.block_num=bnum; cp.block_id=bs->id; cp.public_key=my_sp.first; cp.chain_id=chain_id; cp.producer_signature = my_sp.second(cp.digest()); add_pbft_checkpoint(cp); new_pc.emplace_back(cp); @@ -1354,7 +1327,7 @@ namespace eosio { return true; auto valid = true; - for (const auto &c: scp.checkpoints) { + for (const auto &c: scp.messages) { valid = valid && is_valid_checkpoint(c) && c.block_id == scp.block_id && c.block_num == scp.block_num; @@ -1366,7 +1339,7 @@ namespace eosio { auto as = bs->active_schedule; auto cp_count = 0; for (auto const &sp: as.producers) { - for (auto const &v: scp.checkpoints) { + for (auto const &v: scp.messages) { if (sp.block_signing_key == v.public_key) cp_count += 1; } } @@ -1401,7 +1374,6 @@ namespace eosio { auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto as = lscb_active_producers(); - auto my_sp = ctrl.my_signature_providers(); for (auto i = lscb_num; i <= ctrl.head_block_num(); ++i) { for (auto const &bp: as.producers) { @@ -1437,10 +1409,6 @@ namespace eosio { return bs->pending_schedule; } - chain_id_type pbft_database::chain_id() { - return ctrl.get_chain_id(); - } - block_num_type pbft_database::get_current_pbft_watermark() { auto unique_merge = [&](vector &v1, vector &v2) { diff --git a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp index 65b81583364..61a2a033d59 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp @@ -146,6 +146,11 @@ struct request_p2p_message{ bool discoverable; string p2p_peer_list; }; + + struct compressed_pbft_new_view { + std::shared_ptr > content; + }; + using net_message = static_variant; + checkpoint_request_message, + compressed_pbft_new_view>; + } // namespace eosio FC_REFLECT( eosio::select_ids, (mode)(pending)(ids) ) @@ -184,6 +191,7 @@ FC_REFLECT( eosio::sync_request_message, (start_block)(end_block) ) FC_REFLECT( eosio::request_p2p_message, (discoverable) ) FC_REFLECT( eosio::response_p2p_message, (discoverable)(p2p_peer_list) ) FC_REFLECT( eosio::checkpoint_request_message, (start_block)(end_block) ) +FC_REFLECT( eosio::compressed_pbft_new_view, (content)) /** diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 2dcafa4feda..2a42b8f3179 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -28,6 +28,10 @@ #include +#include +#include +#include + using namespace eosio::chain::plugin_interface::compat; namespace fc { @@ -109,6 +113,8 @@ namespace eosio { }; class net_plugin_impl { private: + std::vector compress_pbft(const std::shared_ptr>& m)const; + std::vector decompress_pbft(const std::shared_ptr>& m)const; std::shared_ptr> encode_pbft_message(const net_message &msg)const; public: net_plugin_impl(); @@ -264,6 +270,7 @@ namespace eosio { 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_new_view &msg); void start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection); void start_txn_timer(); @@ -677,6 +684,7 @@ namespace eosio { bool trigger_send, go_away_reason close_after_send, bool to_sync_queue = false); void enqueue_pbft( const std::shared_ptr>& m, const time_point_sec deadline); + bool pbft_read_to_send(); void cancel_sync(go_away_reason); @@ -1380,35 +1388,6 @@ namespace eosio { sync_wait(); } -// bool connection::process_next_message(net_plugin_impl& impl, uint32_t message_length) { -// vector tmp_data; -// tmp_data.resize(message_length); -// -// try { -// auto ds = pending_message_buffer.create_datastream(); -// auto read_index = pending_message_buffer.read_index(); -// pending_message_buffer.peek(tmp_data.data(),message_length,read_index); -// -// net_message msg; -// fc::raw::unpack(ds, msg); -// msg_handler m(impl, shared_from_this() ); -// if( msg.contains() ) { -// m( std::move( msg.get() ) ); -// } else if( msg.contains() ) { -// m( std::move( msg.get() ) ); -// } else { -// msg.visit( m ); -// } -// } catch( const fc::exception& e ) { -// wlog("error message length: ${l}", ("l", message_length)); -// wlog("error raw bytes ${s}", ("s", tmp_data)); -// edump((e.to_detail_string() )); -// impl.close( shared_from_this() ); -// return false; -// } -// return true; -// } - bool connection::process_next_message(net_plugin_impl& impl, uint32_t message_length) { try { auto ds = pending_message_buffer.create_datastream(); @@ -2066,6 +2045,51 @@ namespace eosio { } //------------------------------------------------------------------------ + + namespace bio = boost::iostreams; + template + struct read_limiter { + using char_type = char; + using category = bio::multichar_output_filter_tag; + + template + size_t write(Sink &sink, const char* s, size_t count) + { + EOS_ASSERT(_total + count <= Limit, tx_decompression_error, "Exceeded maximum decompressed transaction size"); + _total += count; + return bio::write(sink, s, count); + } + size_t _total = 0; + }; + + std::vector net_plugin_impl::compress_pbft(const std::shared_ptr>& m) const { + std::vector out; + bio::filtering_ostream comp; + comp.push(bio::zlib_compressor(bio::zlib::best_compression)); + comp.push(bio::back_inserter(out)); + bio::write(comp, m->data(), m->size()); + bio::close(comp); + return out; + } + + std::vector net_plugin_impl::decompress_pbft(const std::shared_ptr>& m) const { + try { + std::vector out; + bio::filtering_ostream decomp; + decomp.push(bio::zlib_decompressor()); + decomp.push(read_limiter<1*1024*1024>()); // limit to 10 megs decompressed for zip bomb protections + decomp.push(bio::back_inserter(out)); + bio::write(decomp, m->data(), m->size()); + bio::close(decomp); + return out; + } catch( fc::exception& er ) { + throw; + } catch( ... ) { + fc::unhandled_exception er( FC_LOG_MESSAGE( warn, "internal decompression error"), std::current_exception() ); + throw er; + } + } + std::shared_ptr> net_plugin_impl::encode_pbft_message(const net_message &msg) const { uint32_t payload_size = fc::raw::pack_size( msg ); @@ -2078,8 +2102,25 @@ namespace eosio { fc::datastream ds( send_buffer->data(), buffer_size); ds.write( header, header_size ); fc::raw::pack( ds, msg ); + auto out_buffer = send_buffer; + + if (msg.contains()) { + payload_size = fc::raw::pack_size( msg ); + + header = reinterpret_cast(&payload_size); + header_size = sizeof(payload_size); + buffer_size = header_size + payload_size; + + auto compressed_buffer = std::make_shared>(buffer_size); + fc::datastream ds( compressed_buffer->data(), buffer_size); + ds.write( header, header_size ); - return send_buffer; + auto compressed_msg = std::make_shared>(compress_pbft(send_buffer)); + auto cpnv = compressed_pbft_new_view{compressed_msg}; + fc::raw::pack( ds, &cpnv ); + out_buffer = compressed_buffer; + } + return out_buffer; } void net_plugin_impl::connect(const connection_ptr& c) { @@ -3103,6 +3144,17 @@ namespace eosio { pbft_incoming_new_view_channel.publish(msg); } + void net_plugin_impl::handle_message( connection_ptr c, const compressed_pbft_new_view &msg) { + + auto decompressed_new_view = decompress_pbft(msg.content); + + pbft_new_view nv; + fc::datastream ds(decompressed_new_view.data(), decompressed_new_view.size()); + fc::raw::unpack(ds, nv); + + handle_message(c, nv); + } + void net_plugin_impl::handle_message( connection_ptr c, const pbft_checkpoint &msg) { if (!is_pbft_msg_valid(msg)) return; @@ -3126,7 +3178,7 @@ namespace eosio { if (pcc.pbft_db.is_valid_stable_checkpoint(msg)) { fc_ilog(logger, "received stable checkpoint at ${n}, from ${v}", ("n", msg.block_num)("v", c->peer_name())); - for (auto cp: msg.checkpoints) { + for (auto cp: msg.messages) { pbft_incoming_checkpoint_channel.publish(cp); } } From 902177ada809f5a695d9fda453461bbbbfcbb709 Mon Sep 17 00:00:00 2001 From: oldcold Date: Sat, 18 May 2019 15:48:29 +0800 Subject: [PATCH 05/22] add new view primary check; add debug info during prepare (commit) insertion. --- .../include/eosio/chain/pbft_database.hpp | 4 +-- libraries/chain/pbft.cpp | 3 ++ libraries/chain/pbft_database.cpp | 33 ++++++++++++++++--- plugins/net_plugin/net_plugin.cpp | 2 +- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index e680e57d934..e8a6705d606 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -621,6 +621,8 @@ namespace eosio { bool should_recv_pbft_msg(const public_key_type &pub_key); + public_key_type get_new_view_primary_key(uint32_t target_view); + void send_pbft_checkpoint(); bool is_valid_checkpoint(const pbft_checkpoint &cp); @@ -666,8 +668,6 @@ namespace eosio { 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); diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 2236de50f5a..7be7b43eb57 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -104,6 +104,7 @@ namespace eosio { this->set_view_changes_cache(vector{}); this->set_prepared_certificate(vector{}); + this->set_committed_certificate(vector>{}); this->set_view_changed_certificate(vector{}); this->view_change_timer = 0; @@ -184,6 +185,7 @@ namespace eosio { if (pending_commit_local && !pbft_db.pending_pbft_lib()) { pbft_db.send_pbft_checkpoint(); + dlog("pending pbft lib has been applied, transit to committed state now.."); m->transit_to_committed_state(this, false); } } @@ -203,6 +205,7 @@ namespace eosio { if (pending_commit_local && !pbft_db.pending_pbft_lib()) { pbft_db.send_pbft_checkpoint(); + dlog("pending pbft lib has been applied, transit to committed state now.."); m->transit_to_committed_state(this, false); } } diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 4d487651dfe..f7133a66b93 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -142,10 +142,15 @@ namespace eosio { psp->prepares.emplace_back(p); std::sort(psp->prepares.begin(), psp->prepares.end(), less<>()); }); + } else { + dlog( "prepare already exists: ${p}", ("p", p)); } } curr_itr = by_block_id_index.find(current->id); - if (curr_itr == by_block_id_index.end()) return; + if (curr_itr == by_block_id_index.end()) { + dlog( "block id ${id} cannot be found", ("id", current->id)); + return; + } auto prepares = (*curr_itr)->prepares; auto as = current->active_schedule.producers; @@ -164,6 +169,7 @@ namespace eosio { if (e.second >= as.size() * 2 / 3 + 1) { by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr &psp) { psp->should_prepared = true; }); + dlog( "block id ${id} is now prepared at view ${v}", ("id", current->id)("v", e.first)); } } } @@ -293,11 +299,16 @@ namespace eosio { psp->commits.emplace_back(c); std::sort(psp->commits.begin(), psp->commits.end(), less<>()); }); + } else { + dlog( "commit already exists: ${c}", ("c", c)); } } curr_itr = by_block_id_index.find(current->id); - if (curr_itr == by_block_id_index.end()) return; + if (curr_itr == by_block_id_index.end()) { + dlog( "block id ${id} cannot be found", ("id", current->id)); + return; + } auto commits = (*curr_itr)->commits; @@ -319,6 +330,7 @@ namespace eosio { if (e.second >= current->active_schedule.producers.size() * 2 / 3 + 1) { by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr &psp) { psp->should_committed = true; }); + dlog( "block id ${id} is now committed at view ${v}", ("id", current->id)("v", e.first)); } } } @@ -417,11 +429,15 @@ namespace eosio { void pbft_database::commit_local() { 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; + if (itr == by_commit_and_num_index.end()) { + dlog( "no block to be committed local"); + return; + } pbft_state_ptr psp = *itr; ctrl.pbft_commit_local(psp->block_id); + dlog( "block id ${id} is committed local", ("id", psp->block_id)); } bool pbft_database::pending_pbft_lib() { @@ -892,15 +908,23 @@ namespace eosio { EOS_ASSERT(nv.chain_id == chain_id(), pbft_exception, "wrong chain."); + EOS_ASSERT(nv.is_signature_valid(), pbft_exception, "bad new view signature"); + + EOS_ASSERT(nv.public_key == get_new_view_primary_key(nv.view), pbft_exception, "new view is not signed with expected key"); + EOS_ASSERT(is_valid_prepared_certificate(nv.prepared), pbft_exception, "bad prepared certificate: ${pc}", ("pc", nv.prepared)); EOS_ASSERT(is_valid_stable_checkpoint(nv.stable_checkpoint), pbft_exception, "bad stable checkpoint: ${scp}", ("scp", nv.stable_checkpoint)); + for (auto const &c: nv.committed) { + EOS_ASSERT(is_valid_committed_certificate(c), pbft_exception, + "bad committed certificate: ${cc}", ("cc", c)); + } + EOS_ASSERT(nv.view_changed.is_signature_valid(), pbft_exception, "bad view changed signature"); - EOS_ASSERT(nv.is_signature_valid(), pbft_exception, "bad new view signature"); EOS_ASSERT(nv.view_changed.view == nv.view, pbft_exception, "target view not match"); @@ -1401,7 +1425,6 @@ namespace eosio { auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto as = lscb_active_producers(); - auto my_sp = ctrl.my_signature_providers(); for (auto i = lscb_num; i <= ctrl.head_block_num(); ++i) { for (auto const &bp: as.producers) { diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 2dcafa4feda..d4a5489eab4 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -3095,7 +3095,7 @@ namespace eosio { if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!pcc.pbft_db.is_valid_new_view(msg)) return; + if (!(msg.public_key == pcc.pbft_db.get_new_view_primary_key(msg.view) && msg.is_signature_valid())) return; forward_pbft_msg(c, msg); fc_ilog( logger, "received new view: ${n}, from ${v}", ("n", msg)("v", msg.public_key)); From cf75956dd658ae9f53202b989f83a5d19771b51a Mon Sep 17 00:00:00 2001 From: oldcold Date: Tue, 21 May 2019 18:12:00 +0800 Subject: [PATCH 06/22] optimise cal in `should_recv_pbft_msg` and `should_send_pbft_msg`; do not send stable checkpoints higher than my lscb --- .../include/eosio/chain/pbft_database.hpp | 2 ++ libraries/chain/pbft_database.cpp | 31 ++++++++++++++++--- plugins/net_plugin/net_plugin.cpp | 7 +++-- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index e8a6705d606..3d02d104e4e 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -689,6 +689,8 @@ namespace eosio { void prune(const pbft_state_ptr &h); + void prune_checkpoints(const pbft_checkpoint_state_ptr &h); + }; } diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index f7133a66b93..47d22f5d014 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -1345,7 +1345,14 @@ namespace eosio { prune(*pitr); } } - +// auto &bni = checkpoint_index.get(); +// auto oldest = bni.begin(); +// if (oldest != bni.end() && lscb_num - (*oldest)->block_num > 10000) { +// auto it = bni.lower_bound(lscb_num - 10000); +// if (it != bni.end() && (*it)->is_stable) { +// prune_checkpoints(*it); +// } +// } } void pbft_database::send_pbft_checkpoint() { @@ -1404,12 +1411,11 @@ namespace eosio { bool pbft_database::should_send_pbft_msg() { //use last_stable_checkpoint producer schedule - auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto as = lscb_active_producers(); auto my_sp = ctrl.my_signature_providers(); - for (auto i = lscb_num; i <= ctrl.head_block_num(); ++i) { + for (auto i: prepare_watermarks) { for (auto const &bp: as.producers) { for (auto const &my: my_sp) { if (bp.block_signing_key == my.first) return true; @@ -1422,11 +1428,10 @@ 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 = lscb_active_producers(); - for (auto i = lscb_num; i <= ctrl.head_block_num(); ++i) { + for (auto i: prepare_watermarks) { for (auto const &bp: as.producers) { if (bp.block_signing_key == pub_key) return true; } @@ -1542,6 +1547,22 @@ namespace eosio { } } + void pbft_database::prune_checkpoints(const pbft_checkpoint_state_ptr &h) { + auto num = h->block_num; + + auto &by_bn = checkpoint_index.get(); + auto bni = by_bn.begin(); + while (bni != by_bn.end() && (*bni)->block_num < num) { + prune_checkpoints(*bni); + bni = by_bn.begin(); + } + + auto itr = checkpoint_index.find(h->block_id); + if (itr != checkpoint_index.end()) { + checkpoint_index.erase(itr); + } + } + template void pbft_database::emit(const Signal &s, Arg &&a) { try { diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index d4a5489eab4..ad00c2e268f 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -938,7 +938,6 @@ namespace eosio { void connection::blk_send_branch() { controller& cc = my_impl->chain_plug->chain(); - pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); uint32_t head_num = cc.fork_db_head_block_num(); notice_message note; note.known_blocks.mode = normal; @@ -2798,7 +2797,9 @@ namespace eosio { controller &cc = my_impl->chain_plug->chain(); pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - for (auto i = msg.end_block; i >= msg.start_block && i>0; --i) { + 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 != pbft_stable_checkpoint{}) { @@ -3104,7 +3105,7 @@ namespace eosio { } void net_plugin_impl::handle_message( connection_ptr c, const pbft_checkpoint &msg) { - + fc_ilog( logger, "received checkpoint at ${n}, from ${v}", ("n", msg.block_num)("v", msg.public_key)); if (!is_pbft_msg_valid(msg)) return; auto added = maybe_add_pbft_cache(msg.uuid); From 3c45326edf8b08243822312559a7e41ba05e0f69 Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 22 May 2019 22:03:14 +0800 Subject: [PATCH 07/22] generate pbft watermark from forkdb. --- libraries/chain/controller.cpp | 30 +---- libraries/chain/fork_database.cpp | 39 +++++- .../chain/include/eosio/chain/block_state.hpp | 3 +- .../chain/include/eosio/chain/controller.hpp | 3 +- .../include/eosio/chain/fork_database.hpp | 4 + .../include/eosio/chain/pbft_database.hpp | 3 + libraries/chain/pbft_database.cpp | 121 ++++++++---------- 7 files changed, 101 insertions(+), 102 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 9fb60881f85..cfb137f6038 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -127,8 +127,6 @@ struct controller_impl { bool pbft_upgrading = false; optional pending_pbft_lib; optional pending_pbft_checkpoint; - vector proposed_schedule_blocks; - vector promoted_schedule_blocks; block_state_ptr pbft_prepared; block_state_ptr my_prepare; block_state_ptr head; @@ -1390,14 +1388,8 @@ struct controller_impl { auto lscb_num = pending->_pending_block_state->pbft_stable_checkpoint_blocknum; 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) { - itr = proposed_schedule_blocks.erase(itr); - } else { - ++itr; - } - } + auto bs = fork_db.get_block_in_current_chain_by_num(*gpo.proposed_schedule_block_num); + if (bs) fork_db.mark_as_pbft_watermark(bs); } bool should_promote_pending_schedule = false; @@ -1429,14 +1421,7 @@ struct controller_impl { pending->_pending_block_state->set_new_producers(gpo.proposed_schedule); 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) { - itr = promoted_schedule_blocks.erase(itr); - } else { - ++itr; - } - } + pending->_pending_block_state->pbft_watermark = true; } } db.modify( gpo, [&]( auto& gp ) { @@ -2343,13 +2328,8 @@ block_id_type controller::last_stable_checkpoint_block_id() const { return block_id_type{}; } - -vector controller::proposed_schedule_block_nums() const { - return my->proposed_schedule_blocks; -} - -vector controller::promoted_schedule_block_nums() const { - return my->promoted_schedule_blocks; +vector controller::get_watermarks() const { + return my->fork_db.get_watermarks_in_forkdb(); } bool controller::is_replaying() const { diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index d6624b54f04..0a3ad4c098c 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -17,6 +17,7 @@ namespace eosio { namespace chain { struct by_block_id; struct by_block_num; struct by_lib_block_num; + struct by_watermark; struct by_prev; typedef multi_index_container< block_state_ptr, @@ -32,13 +33,20 @@ namespace eosio { namespace chain { >, ordered_non_unique< tag, composite_key< block_state, - member, - member, - member, - member, - member + member, + member, + member, + member, + member >, composite_key_compare< std::greater, std::greater, std::greater, std::greater, std::greater > + >, + ordered_non_unique< tag, + composite_key< block_state, + member, + member + >, + composite_key_compare< std::greater<>, std::greater > > > > fork_multi_index_type; @@ -202,7 +210,6 @@ namespace eosio { namespace chain { auto prior = my->index.find( n->block->previous ); - //TODO: to be optimised. if (prior != my->index.end()) { if ((*prior)->pbft_prepared) mark_pbft_prepared_fork(*prior); if ((*prior)->pbft_my_prepare) mark_pbft_my_prepare_fork(*prior); @@ -601,5 +608,23 @@ namespace eosio { namespace chain { } } + vector fork_database::get_watermarks_in_forkdb() { + vector watermarks; + auto& pidx = my->index.get(); + auto pitr = pidx.begin(); + while (pitr != pidx.end() && (*pitr)->pbft_watermark) { + watermarks.emplace_back((*pitr)->block_num); + } + return watermarks; + } + + void fork_database::mark_as_pbft_watermark( const block_state_ptr& h) { + auto& by_id_idx = my->index.get(); + auto itr = by_id_idx.find( h->id ); + EOS_ASSERT( itr != by_id_idx.end(), fork_db_block_not_found, "could not find block in fork database" ); + by_id_idx.modify( itr, [&]( auto& bsp ) { bsp->pbft_watermark = true; }); + } + + - } } /// eosio::chain + } } /// eosio::chain diff --git a/libraries/chain/include/eosio/chain/block_state.hpp b/libraries/chain/include/eosio/chain/block_state.hpp index 3745beaaeaf..c81efff2717 100644 --- a/libraries/chain/include/eosio/chain/block_state.hpp +++ b/libraries/chain/include/eosio/chain/block_state.hpp @@ -23,6 +23,7 @@ namespace eosio { namespace chain { bool in_current_chain = false; bool pbft_prepared = false; bool pbft_my_prepare = false; + bool pbft_watermark = false; /// this data is redundant with the data stored in block, but facilitates /// recapturing transactions when we pop a block @@ -33,4 +34,4 @@ namespace eosio { namespace chain { } } /// namespace eosio::chain -FC_REFLECT_DERIVED( eosio::chain::block_state, (eosio::chain::block_header_state), (block)(validated)(in_current_chain)(pbft_prepared)(pbft_my_prepare) ) +FC_REFLECT_DERIVED( eosio::chain::block_state, (eosio::chain::block_header_state), (block)(validated)(in_current_chain)(pbft_prepared)(pbft_my_prepare)(pbft_watermark) ) diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 9bc79f70eee..36c15c56ca3 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -168,8 +168,7 @@ namespace eosio { namespace chain { bool pending_pbft_lib(); - vector proposed_schedule_block_nums()const; - vector promoted_schedule_block_nums()const; + vector get_watermarks() const; void set_pbft_latest_checkpoint( const block_id_type& id ); uint32_t last_stable_checkpoint_block_num()const; diff --git a/libraries/chain/include/eosio/chain/fork_database.hpp b/libraries/chain/include/eosio/chain/fork_database.hpp index 55e40580eb2..2e8ff899853 100644 --- a/libraries/chain/include/eosio/chain/fork_database.hpp +++ b/libraries/chain/include/eosio/chain/fork_database.hpp @@ -82,6 +82,10 @@ namespace eosio { namespace chain { void remove_pbft_prepared_fork(); + vector get_watermarks_in_forkdb(); + + void mark_as_pbft_watermark( const block_state_ptr& h); + private: unique_ptr my; }; diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 3d02d104e4e..77b4cf99ad8 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -654,6 +654,8 @@ namespace eosio { block_num_type get_current_pbft_watermark(); + void update_fork_schedules(); + private: controller &ctrl; pbft_state_multi_index_type pbft_state_index; @@ -663,6 +665,7 @@ namespace eosio { fc::path checkpoints_dir; boost::uuids::random_generator uuid_generator; vector prepare_watermarks; + flat_map fork_schedules; bool is_valid_prepared_certificate(const pbft_prepared_certificate &certificate); diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 47d22f5d014..76d8f203ebd 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -35,15 +35,6 @@ namespace eosio { set(std::make_shared(move(s))); } - unsigned_int watermarks_size; - fc::raw::unpack(ds, watermarks_size); - for (uint32_t i = 0, n = watermarks_size.value; i < n; ++i) { - block_num_type h; - fc::raw::unpack(ds, h); - prepare_watermarks.emplace_back(h); - } - sort(prepare_watermarks.begin(), prepare_watermarks.end()); - } else { pbft_state_index = pbft_state_multi_index_type{}; } @@ -72,7 +63,6 @@ namespace eosio { void pbft_database::close() { - fc::path checkpoints_db = checkpoints_dir / config::checkpoints_filename; std::ofstream c_out(checkpoints_db.generic_string().c_str(), std::ios::out | std::ios::binary | std::ofstream::trunc); @@ -94,24 +84,14 @@ namespace eosio { fc::raw::pack(out, *s); } - - uint32_t watermarks_size = prepare_watermarks.size(); - fc::raw::pack(out, unsigned_int{watermarks_size}); - - for (const auto &n: prepare_watermarks) { - fc::raw::pack(out, n); - } - pbft_state_index.clear(); checkpoint_index.clear(); - prepare_watermarks.clear(); } pbft_database::~pbft_database() { close(); } - void pbft_database::add_pbft_prepare(pbft_prepare &p) { if (!is_valid_prepare(p)) return; @@ -701,6 +681,7 @@ namespace eosio { ccb.emplace_back(highest_committed_block_num); } + update_fork_schedules(); 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]); @@ -1157,7 +1138,6 @@ namespace eosio { if (lscb_num == 0) { const auto& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; -// if (ucb == 0) return lscb_info; if (ucb == 0) { current_schedule = ctrl.initial_schedule(); new_schedule = ctrl.initial_schedule(); @@ -1209,6 +1189,7 @@ namespace eosio { for (auto i = psp->block_num; i > std::max(ctrl.last_stable_checkpoint_block_num(), static_cast(1)); --i) { + update_fork_schedules(); if (checkpoint(i)) { my_latest_checkpoint = max(i, my_latest_checkpoint); auto &by_block = checkpoint_index.get(); @@ -1410,33 +1391,21 @@ namespace eosio { bool pbft_database::should_send_pbft_msg() { - //use last_stable_checkpoint producer schedule - - auto as = lscb_active_producers(); auto my_sp = ctrl.my_signature_providers(); - - for (auto i: prepare_watermarks) { - for (auto const &bp: as.producers) { - for (auto const &my: my_sp) { - if (bp.block_signing_key == my.first) return true; - } + update_fork_schedules(); + for (auto const &bp: fork_schedules) { + for (auto const &my: my_sp) { + if (bp.first == my.first) return true; } - auto bs = ctrl.fetch_block_state_by_number(i); - if (bs && bs->active_schedule != as) as = bs->active_schedule; } return false; } bool pbft_database::should_recv_pbft_msg(const public_key_type &pub_key) { - auto as = lscb_active_producers(); - - for (auto i: prepare_watermarks) { - for (auto const &bp: as.producers) { - if (bp.block_signing_key == pub_key) return true; - } - auto bs = ctrl.fetch_block_state_by_number(i); - if (bs && bs->active_schedule != as) as = bs->active_schedule; + update_fork_schedules(); + for (auto const &bp: fork_schedules) { + if (bp.first == pub_key) return true; } return false; } @@ -1470,34 +1439,8 @@ namespace eosio { } block_num_type pbft_database::get_current_pbft_watermark() { - auto unique_merge = [&](vector &v1, vector &v2) - { - std::sort(v1.begin(), v1.end()); - v1.reserve(v1.size() + v2.size()); - v1.insert(v1.end(), v2.begin(), v2.end()); - - sort( v1.begin(), v1.end() ); - v1.erase( unique( v1.begin(), v1.end() ), v1.end() ); - }; - + update_fork_schedules(); auto lib = ctrl.last_irreversible_block_num(); - auto lscb = ctrl.last_stable_checkpoint_block_num(); - - auto proposed_schedule_blocks = ctrl.proposed_schedule_block_nums(); - auto promoted_schedule_blocks = ctrl.promoted_schedule_block_nums(); - unique_merge(prepare_watermarks, proposed_schedule_blocks); - unique_merge(prepare_watermarks, promoted_schedule_blocks); - - - for ( auto itr = prepare_watermarks.begin(); itr != prepare_watermarks.end();) { - if ((*itr) <= lscb) { - itr = prepare_watermarks.erase(itr); - } else { - ++itr; - } - } - std::sort(prepare_watermarks.begin(), prepare_watermarks.end()); - if (prepare_watermarks.empty()) return 0; @@ -1506,6 +1449,50 @@ namespace eosio { if (cw > lib) return cw; else return 0; } + void pbft_database::update_fork_schedules() { + + auto vector_diff = [&](vector &v1, vector &v2) + { + vector diff; + std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), + std::inserter(diff, diff.begin())); + return diff; + }; + + auto watermarks = ctrl.get_watermarks(); + + if (watermarks != prepare_watermarks) { + auto prev = prepare_watermarks; + prepare_watermarks = watermarks; + std::sort(prepare_watermarks.begin(), prepare_watermarks.end()); + auto added = vector_diff(prepare_watermarks, prev); + auto removed = vector_diff(prev, prepare_watermarks); + for (auto i: added) { + if (auto bs = ctrl.fetch_block_state_by_number(i)) { + auto as = bs->active_schedule.producers; + for (auto &bp: as) { + auto key = bp.block_signing_key; + if (fork_schedules.find(key) == fork_schedules.end()) { + fork_schedules[key] = i; + } else if ( i > fork_schedules[key]) { + fork_schedules[key] = i; + } + } + } + } + if (!removed.empty()) { + auto pruned_num = *max_element(removed.begin(), removed.end()); + for (auto itr = fork_schedules.begin(); itr != fork_schedules.end();) { + if ((*itr).second <= pruned_num) { + itr = fork_schedules.erase(itr); + } else { + ++itr; + } + } + } + } + } + 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(); From 303c12d6af7995bd3e8d9360a799dc3530c76272 Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 22 May 2019 22:03:14 +0800 Subject: [PATCH 08/22] generate pbft watermark from forkdb. --- libraries/chain/controller.cpp | 35 ++--- libraries/chain/fork_database.cpp | 40 +++++- .../chain/include/eosio/chain/block_state.hpp | 3 +- .../chain/include/eosio/chain/controller.hpp | 3 +- .../include/eosio/chain/fork_database.hpp | 4 + .../include/eosio/chain/pbft_database.hpp | 3 + libraries/chain/pbft_database.cpp | 130 +++++++++--------- 7 files changed, 114 insertions(+), 104 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 9fb60881f85..06f379644d5 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -127,8 +127,6 @@ struct controller_impl { bool pbft_upgrading = false; optional pending_pbft_lib; optional pending_pbft_checkpoint; - vector proposed_schedule_blocks; - vector promoted_schedule_blocks; block_state_ptr pbft_prepared; block_state_ptr my_prepare; block_state_ptr head; @@ -944,6 +942,10 @@ struct controller_impl { }); } + if (pbft_enabled && pending->_pending_block_state->pbft_watermark) { + if (auto bs = fork_db.get_block(pending->_pending_block_state->id)) fork_db.mark_as_pbft_watermark(bs); + } + emit( self.accepted_block, pending->_pending_block_state ); } catch (...) { // dont bother resetting pending, instead abort the block @@ -1387,17 +1389,10 @@ struct controller_impl { const auto& gpo = db.get(); 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 (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) { - itr = proposed_schedule_blocks.erase(itr); - } else { - ++itr; - } - } + auto bs = fork_db.get_block_in_current_chain_by_num(*gpo.proposed_schedule_block_num); + if (bs) fork_db.mark_as_pbft_watermark(bs); } bool should_promote_pending_schedule = false; @@ -1429,14 +1424,7 @@ struct controller_impl { pending->_pending_block_state->set_new_producers(gpo.proposed_schedule); 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) { - itr = promoted_schedule_blocks.erase(itr); - } else { - ++itr; - } - } + pending->_pending_block_state->pbft_watermark = true; } } db.modify( gpo, [&]( auto& gp ) { @@ -2343,13 +2331,8 @@ block_id_type controller::last_stable_checkpoint_block_id() const { return block_id_type{}; } - -vector controller::proposed_schedule_block_nums() const { - return my->proposed_schedule_blocks; -} - -vector controller::promoted_schedule_block_nums() const { - return my->promoted_schedule_blocks; +vector controller::get_watermarks() const { + return my->fork_db.get_watermarks_in_forkdb(); } bool controller::is_replaying() const { diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index d6624b54f04..24defd10740 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -17,6 +17,7 @@ namespace eosio { namespace chain { struct by_block_id; struct by_block_num; struct by_lib_block_num; + struct by_watermark; struct by_prev; typedef multi_index_container< block_state_ptr, @@ -32,13 +33,20 @@ namespace eosio { namespace chain { >, ordered_non_unique< tag, composite_key< block_state, - member, - member, - member, - member, - member + member, + member, + member, + member, + member >, composite_key_compare< std::greater, std::greater, std::greater, std::greater, std::greater > + >, + ordered_non_unique< tag, + composite_key< block_state, + member, + member + >, + composite_key_compare< std::greater<>, std::less<> > > > > fork_multi_index_type; @@ -202,7 +210,6 @@ namespace eosio { namespace chain { auto prior = my->index.find( n->block->previous ); - //TODO: to be optimised. if (prior != my->index.end()) { if ((*prior)->pbft_prepared) mark_pbft_prepared_fork(*prior); if ((*prior)->pbft_my_prepare) mark_pbft_my_prepare_fork(*prior); @@ -601,5 +608,24 @@ namespace eosio { namespace chain { } } + vector fork_database::get_watermarks_in_forkdb() { + vector watermarks; + auto& pidx = my->index.get(); + auto pitr = pidx.begin(); + while (pitr != pidx.end() && (*pitr)->pbft_watermark) { + watermarks.emplace_back((*pitr)->block_num); + ++pitr; + } + return watermarks; + } + + void fork_database::mark_as_pbft_watermark( const block_state_ptr& h) { + auto& by_id_idx = my->index.get(); + auto itr = by_id_idx.find( h->id ); + EOS_ASSERT( itr != by_id_idx.end(), fork_db_block_not_found, "could not find block in fork database" ); + by_id_idx.modify( itr, [&]( auto& bsp ) { bsp->pbft_watermark = true; }); + } + + - } } /// eosio::chain + } } /// eosio::chain diff --git a/libraries/chain/include/eosio/chain/block_state.hpp b/libraries/chain/include/eosio/chain/block_state.hpp index 3745beaaeaf..c81efff2717 100644 --- a/libraries/chain/include/eosio/chain/block_state.hpp +++ b/libraries/chain/include/eosio/chain/block_state.hpp @@ -23,6 +23,7 @@ namespace eosio { namespace chain { bool in_current_chain = false; bool pbft_prepared = false; bool pbft_my_prepare = false; + bool pbft_watermark = false; /// this data is redundant with the data stored in block, but facilitates /// recapturing transactions when we pop a block @@ -33,4 +34,4 @@ namespace eosio { namespace chain { } } /// namespace eosio::chain -FC_REFLECT_DERIVED( eosio::chain::block_state, (eosio::chain::block_header_state), (block)(validated)(in_current_chain)(pbft_prepared)(pbft_my_prepare) ) +FC_REFLECT_DERIVED( eosio::chain::block_state, (eosio::chain::block_header_state), (block)(validated)(in_current_chain)(pbft_prepared)(pbft_my_prepare)(pbft_watermark) ) diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 9bc79f70eee..36c15c56ca3 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -168,8 +168,7 @@ namespace eosio { namespace chain { bool pending_pbft_lib(); - vector proposed_schedule_block_nums()const; - vector promoted_schedule_block_nums()const; + vector get_watermarks() const; void set_pbft_latest_checkpoint( const block_id_type& id ); uint32_t last_stable_checkpoint_block_num()const; diff --git a/libraries/chain/include/eosio/chain/fork_database.hpp b/libraries/chain/include/eosio/chain/fork_database.hpp index 55e40580eb2..2e8ff899853 100644 --- a/libraries/chain/include/eosio/chain/fork_database.hpp +++ b/libraries/chain/include/eosio/chain/fork_database.hpp @@ -82,6 +82,10 @@ namespace eosio { namespace chain { void remove_pbft_prepared_fork(); + vector get_watermarks_in_forkdb(); + + void mark_as_pbft_watermark( const block_state_ptr& h); + private: unique_ptr my; }; diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 3d02d104e4e..77b4cf99ad8 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -654,6 +654,8 @@ namespace eosio { block_num_type get_current_pbft_watermark(); + void update_fork_schedules(); + private: controller &ctrl; pbft_state_multi_index_type pbft_state_index; @@ -663,6 +665,7 @@ namespace eosio { fc::path checkpoints_dir; boost::uuids::random_generator uuid_generator; vector prepare_watermarks; + flat_map fork_schedules; bool is_valid_prepared_certificate(const pbft_prepared_certificate &certificate); diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 47d22f5d014..d59a5b2c67d 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -35,15 +35,6 @@ namespace eosio { set(std::make_shared(move(s))); } - unsigned_int watermarks_size; - fc::raw::unpack(ds, watermarks_size); - for (uint32_t i = 0, n = watermarks_size.value; i < n; ++i) { - block_num_type h; - fc::raw::unpack(ds, h); - prepare_watermarks.emplace_back(h); - } - sort(prepare_watermarks.begin(), prepare_watermarks.end()); - } else { pbft_state_index = pbft_state_multi_index_type{}; } @@ -72,7 +63,6 @@ namespace eosio { void pbft_database::close() { - fc::path checkpoints_db = checkpoints_dir / config::checkpoints_filename; std::ofstream c_out(checkpoints_db.generic_string().c_str(), std::ios::out | std::ios::binary | std::ofstream::trunc); @@ -94,24 +84,14 @@ namespace eosio { fc::raw::pack(out, *s); } - - uint32_t watermarks_size = prepare_watermarks.size(); - fc::raw::pack(out, unsigned_int{watermarks_size}); - - for (const auto &n: prepare_watermarks) { - fc::raw::pack(out, n); - } - pbft_state_index.clear(); checkpoint_index.clear(); - prepare_watermarks.clear(); } pbft_database::~pbft_database() { close(); } - void pbft_database::add_pbft_prepare(pbft_prepare &p) { if (!is_valid_prepare(p)) return; @@ -701,6 +681,7 @@ namespace eosio { ccb.emplace_back(highest_committed_block_num); } + update_fork_schedules(); 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]); @@ -1157,7 +1138,6 @@ namespace eosio { if (lscb_num == 0) { const auto& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; -// if (ucb == 0) return lscb_info; if (ucb == 0) { current_schedule = ctrl.initial_schedule(); new_schedule = ctrl.initial_schedule(); @@ -1207,8 +1187,8 @@ namespace eosio { || std::find(prepare_watermarks.begin(), prepare_watermarks.end(), in) != prepare_watermarks.end(); // checkpoint on bp schedule change; }; - for (auto i = psp->block_num; - i > std::max(ctrl.last_stable_checkpoint_block_num(), static_cast(1)); --i) { + update_fork_schedules(); + for (auto i = psp->block_num; i > ctrl.last_stable_checkpoint_block_num() && i > 1; --i) { if (checkpoint(i)) { my_latest_checkpoint = max(i, my_latest_checkpoint); auto &by_block = checkpoint_index.get(); @@ -1410,33 +1390,21 @@ namespace eosio { bool pbft_database::should_send_pbft_msg() { - //use last_stable_checkpoint producer schedule - - auto as = lscb_active_producers(); auto my_sp = ctrl.my_signature_providers(); - - for (auto i: prepare_watermarks) { - for (auto const &bp: as.producers) { - for (auto const &my: my_sp) { - if (bp.block_signing_key == my.first) return true; - } + update_fork_schedules(); + for (auto const &bp: fork_schedules) { + for (auto const &my: my_sp) { + if (bp.first == my.first) return true; } - auto bs = ctrl.fetch_block_state_by_number(i); - if (bs && bs->active_schedule != as) as = bs->active_schedule; } return false; } bool pbft_database::should_recv_pbft_msg(const public_key_type &pub_key) { - auto as = lscb_active_producers(); - - for (auto i: prepare_watermarks) { - for (auto const &bp: as.producers) { - if (bp.block_signing_key == pub_key) return true; - } - auto bs = ctrl.fetch_block_state_by_number(i); - if (bs && bs->active_schedule != as) as = bs->active_schedule; + update_fork_schedules(); + for (auto const &bp: fork_schedules) { + if (bp.first == pub_key) return true; } return false; } @@ -1470,40 +1438,66 @@ namespace eosio { } block_num_type pbft_database::get_current_pbft_watermark() { - auto unique_merge = [&](vector &v1, vector &v2) - { - std::sort(v1.begin(), v1.end()); - v1.reserve(v1.size() + v2.size()); - v1.insert(v1.end(), v2.begin(), v2.end()); - - sort( v1.begin(), v1.end() ); - v1.erase( unique( v1.begin(), v1.end() ), v1.end() ); - }; - + update_fork_schedules(); auto lib = ctrl.last_irreversible_block_num(); - auto lscb = ctrl.last_stable_checkpoint_block_num(); - auto proposed_schedule_blocks = ctrl.proposed_schedule_block_nums(); - auto promoted_schedule_blocks = ctrl.promoted_schedule_block_nums(); - unique_merge(prepare_watermarks, proposed_schedule_blocks); - unique_merge(prepare_watermarks, promoted_schedule_blocks); + if (prepare_watermarks.empty()) return 0; + auto cw = *std::upper_bound(prepare_watermarks.begin(), prepare_watermarks.end(), lib); - for ( auto itr = prepare_watermarks.begin(); itr != prepare_watermarks.end();) { - if ((*itr) <= lscb) { - itr = prepare_watermarks.erase(itr); - } else { - ++itr; - } - } - std::sort(prepare_watermarks.begin(), prepare_watermarks.end()); + if (cw > lib) return cw; else return 0; + } + void pbft_database::update_fork_schedules() { - if (prepare_watermarks.empty()) return 0; + auto vector_minus = [&](vector &v1, vector &v2) + { + vector diff; + std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), + std::inserter(diff, diff.begin())); + return diff; + }; - auto cw = *std::upper_bound(prepare_watermarks.begin(), prepare_watermarks.end(), lib); + auto watermarks = ctrl.get_watermarks(); + + if (watermarks != prepare_watermarks) { + auto prev = prepare_watermarks; + prepare_watermarks = watermarks; + std::sort(prepare_watermarks.begin(), prepare_watermarks.end()); + auto added = vector_minus(prepare_watermarks, prev); + auto removed = vector_minus(prev, prepare_watermarks); + for (auto i: added) { + if (auto bs = ctrl.fetch_block_state_by_number(i)) { + auto as = bs->active_schedule.producers; + for (auto &bp: as) { + auto key = bp.block_signing_key; + if (fork_schedules.find(key) == fork_schedules.end()) { + fork_schedules[key] = i; + } else if ( i > fork_schedules[key]) { + fork_schedules[key] = i; + } + } + } + } + if (!removed.empty()) { + auto pruned_num = *max_element(removed.begin(), removed.end()); + for (auto itr = fork_schedules.begin(); itr != fork_schedules.end();) { + if ((*itr).second <= pruned_num) { + itr = fork_schedules.erase(itr); + } else { + ++itr; + } + } + } + } - if (cw > lib) return cw; else return 0; + if (fork_schedules.empty()) { + auto lscb_bps = lscb_active_producers().producers; + auto lscb_num = ctrl.last_stable_checkpoint_block_num(); + for (auto &bp: lscb_bps) { + fork_schedules[bp.block_signing_key] = lscb_num; + } + } } pbft_state_ptr pbft_database::get_pbft_state_by_id(const block_id_type& id) const { From f475fa6158537c8b17f8c1ea7b301fe296a1cec0 Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 29 May 2019 17:55:39 +0800 Subject: [PATCH 09/22] add pbft_api_plugin --- libraries/chain/controller.cpp | 6 + .../chain/include/eosio/chain/controller.hpp | 1 + libraries/chain/include/eosio/chain/pbft.hpp | 11 +- .../include/eosio/chain/pbft_database.hpp | 59 ++++---- libraries/chain/pbft.cpp | 6 +- libraries/chain/pbft_database.cpp | 130 +++++++++++------- plugins/CMakeLists.txt | 1 + plugins/net_plugin/net_plugin.cpp | 3 +- plugins/pbft_api_plugin/CMakeLists.txt | 7 + .../eosio/pbft_api_plugin/pbft_api_plugin.hpp | 35 +++++ plugins/pbft_api_plugin/pbft_api_plugin.cpp | 90 ++++++++++++ .../include/eosio/pbft_plugin/pbft_plugin.hpp | 18 ++- plugins/pbft_plugin/pbft_plugin.cpp | 55 +++++++- .../producer_api_plugin.cpp | 2 - .../eosio/producer_plugin/producer_plugin.hpp | 2 - plugins/producer_plugin/producer_plugin.cpp | 6 - programs/nodeos/CMakeLists.txt | 1 + 17 files changed, 339 insertions(+), 94 deletions(-) create mode 100644 plugins/pbft_api_plugin/CMakeLists.txt create mode 100644 plugins/pbft_api_plugin/include/eosio/pbft_api_plugin/pbft_api_plugin.hpp create mode 100644 plugins/pbft_api_plugin/pbft_api_plugin.cpp diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 06f379644d5..41a39099b5e 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -2533,6 +2533,12 @@ void controller::set_pbft_my_prepare(const block_id_type& id) { } } +block_id_type controller::get_pbft_prepared() const { + if (my->pbft_prepared) return my->pbft_prepared->id; + return block_id_type{}; +} + + block_id_type controller::get_pbft_my_prepare() const { if (my->my_prepare) return my->my_prepare->id; return block_id_type{}; diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 36c15c56ca3..7a90125da6e 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -290,6 +290,7 @@ namespace eosio { namespace chain { void set_pbft_prepared(const block_id_type& id); void set_pbft_my_prepare(const block_id_type& id); + block_id_type get_pbft_prepared()const; block_id_type get_pbft_my_prepare()const; void reset_pbft_my_prepare(); void reset_pbft_prepared(); diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index dd275943451..cdd393ad887 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -29,6 +29,10 @@ namespace eosio { current = s; } + psm_state* get_current() { + return this->current; + } + void on_prepare(pbft_prepare &e); void send_prepare(); @@ -130,6 +134,8 @@ namespace eosio { virtual void manually_set_view(psm_machine *m, const uint32_t &view) = 0; + virtual const char* get_name() = 0; + }; class psm_prepared_state final: public psm_state { @@ -156,6 +162,7 @@ namespace eosio { bool pending_commit_local; + const char* get_name() override { return "prepared"; } }; class psm_committed_state final: public psm_state { @@ -179,7 +186,7 @@ namespace eosio { void manually_set_view(psm_machine *m, const uint32_t &view) override; - bool pending_commit_local; + const char* get_name() override { return "committed"; } }; class psm_view_change_state final: public psm_state { @@ -199,6 +206,8 @@ namespace eosio { void on_new_view(psm_machine *m, pbft_new_view &e, pbft_database &pbft_db) override; void manually_set_view(psm_machine *m, const uint32_t &view) override; + + const char* get_name() override { return "view change"; } }; struct pbft_config { diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 77b4cf99ad8..51518f019f8 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -20,6 +20,7 @@ namespace eosio { using namespace std; using boost::uuids::uuid; + using pbft_view_type = uint32_t; struct block_info { block_id_type block_id; @@ -28,7 +29,7 @@ namespace eosio { struct pbft_prepare { string uuid; - uint32_t view; + pbft_view_type view; block_num_type block_num = 0; block_id_type block_id; public_key_type public_key; @@ -79,7 +80,7 @@ namespace eosio { struct pbft_commit { string uuid; - uint32_t view; + pbft_view_type view; block_num_type block_num = 0; block_id_type block_id; public_key_type public_key; @@ -143,7 +144,6 @@ namespace eosio { && public_key == rhs.public_key && chain_id == rhs.chain_id && timestamp == rhs.timestamp; - } bool operator!=(const pbft_checkpoint &rhs) const { @@ -288,8 +288,8 @@ namespace eosio { struct pbft_view_change { string uuid; - uint32_t current_view; - uint32_t target_view; + pbft_view_type current_view; + pbft_view_type target_view; pbft_prepared_certificate prepared; vector committed; pbft_stable_checkpoint stable_checkpoint; @@ -341,7 +341,7 @@ namespace eosio { }; struct pbft_view_changed_certificate { - uint32_t view; + pbft_view_type view; vector view_changes; public_key_type public_key; @@ -377,7 +377,7 @@ namespace eosio { struct pbft_new_view { string uuid; - uint32_t view; + pbft_view_type view; pbft_prepared_certificate prepared; vector committed; pbft_stable_checkpoint stable_checkpoint; @@ -439,7 +439,7 @@ namespace eosio { }; struct pbft_view_state { - uint32_t view; + pbft_view_type view; vector view_changes; bool should_view_changed = false; }; @@ -504,15 +504,15 @@ namespace eosio { indexed_by< hashed_unique< tag, - member, - std::hash + member, + std::hash >, ordered_non_unique< tag, composite_key< pbft_view_state, member, - member + member >, composite_key_compare, greater<>> > @@ -554,13 +554,13 @@ namespace eosio { bool should_committed(); - uint32_t should_view_change(); + pbft_view_type should_view_change(); - bool should_new_view(uint32_t target_view); + bool should_new_view(pbft_view_type target_view); - bool is_new_primary(uint32_t target_view); + bool is_new_primary(pbft_view_type target_view); - uint32_t get_proposed_new_view_num(); + pbft_view_type get_proposed_new_view_num(); void add_pbft_prepare(pbft_prepare &p); @@ -572,22 +572,22 @@ namespace eosio { vector send_and_add_pbft_prepare( const vector &pv = vector{}, - uint32_t current_view = 0); + pbft_view_type current_view = 0); vector send_and_add_pbft_commit( const vector &cv = vector{}, - uint32_t current_view = 0); + pbft_view_type current_view = 0); 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); + pbft_view_type current_view = 0, + pbft_view_type new_view = 1); pbft_new_view send_pbft_new_view( const vector &vcc = vector{}, - uint32_t current_view = 1); + pbft_view_type current_view = 1); vector generate_and_add_pbft_checkpoint(); @@ -601,7 +601,7 @@ namespace eosio { void prune_pbft_index(); - uint32_t get_committed_view(); + pbft_view_type get_committed_view(); chain_id_type chain_id(); @@ -609,7 +609,7 @@ namespace eosio { vector> generate_committed_certificate(); - vector generate_view_changed_certificate(uint32_t target_view); + vector generate_view_changed_certificate(pbft_view_type target_view); pbft_stable_checkpoint get_stable_checkpoint_by_id(const block_id_type &block_id); @@ -621,10 +621,12 @@ namespace eosio { bool should_recv_pbft_msg(const public_key_type &pub_key); - public_key_type get_new_view_primary_key(uint32_t target_view); + public_key_type get_new_view_primary_key(pbft_view_type target_view); void send_pbft_checkpoint(); + void checkpoint_local(); + bool is_valid_checkpoint(const pbft_checkpoint &cp); bool is_valid_stable_checkpoint(const pbft_stable_checkpoint &scp); @@ -652,6 +654,14 @@ namespace eosio { pbft_state_ptr get_pbft_state_by_id(const block_id_type& id)const; + vector get_checkpoints_by_num(const block_num_type& num)const; + + pbft_view_state_ptr get_view_changes_by_target_view(const pbft_view_type& tv)const; + + vector get_pbft_watermarks()const; + + flat_map get_pbft_fork_schedules()const; + block_num_type get_current_pbft_watermark(); void update_fork_schedules(); @@ -715,4 +725,5 @@ FC_REFLECT(eosio::chain::pbft_view_changed_certificate, (view)(view_changes)(pub FC_REFLECT(eosio::chain::pbft_checkpoint, (uuid)(block_num)(block_id)(public_key)(chain_id)(producer_signature)(timestamp)) FC_REFLECT(eosio::chain::pbft_stable_checkpoint, (block_num)(block_id)(checkpoints)(chain_id)) -FC_REFLECT(eosio::chain::pbft_checkpoint_state, (block_id)(block_num)(checkpoints)(is_stable)) \ No newline at end of file +FC_REFLECT(eosio::chain::pbft_checkpoint_state, (block_id)(block_num)(checkpoints)(is_stable)) +FC_REFLECT(eosio::chain::pbft_view_state, (view)(view_changes)(should_view_changed)) \ No newline at end of file diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 7be7b43eb57..cd35d5720dc 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -85,10 +85,12 @@ namespace eosio { void pbft_controller::send_pbft_checkpoint() { if (!pbft_db.should_send_pbft_msg()) return; pbft_db.send_pbft_checkpoint(); + pbft_db.checkpoint_local(); } void pbft_controller::on_pbft_checkpoint(pbft_checkpoint &cp) { pbft_db.add_pbft_checkpoint(cp); + pbft_db.checkpoint_local(); } psm_state::psm_state() = default; @@ -245,9 +247,7 @@ namespace eosio { m->transit_to_view_change_state(this); } - psm_committed_state::psm_committed_state() { - pending_commit_local = false; - } + psm_committed_state::psm_committed_state() = default; psm_committed_state::~psm_committed_state() = default; diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index d59a5b2c67d..ceeca762eb9 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -24,7 +24,7 @@ namespace eosio { fc::datastream ds(content.data(), content.size()); // keep these unused variables. - uint32_t current_view; + pbft_view_type current_view; fc::raw::unpack(ds, current_view); unsigned_int size; @@ -134,7 +134,7 @@ namespace eosio { auto prepares = (*curr_itr)->prepares; auto as = current->active_schedule.producers; - flat_map prepare_count; + flat_map prepare_count; for (const auto &pre: prepares) { if (prepare_count.find(pre.view) == prepare_count.end()) prepare_count[pre.view] = 0; } @@ -158,7 +158,7 @@ namespace eosio { } - vector pbft_database::send_and_add_pbft_prepare(const vector &pv, uint32_t current_view) { + vector pbft_database::send_and_add_pbft_prepare(const vector &pv, pbft_view_type current_view) { auto head_block_num = ctrl.head_block_num(); if (head_block_num <= 1) return vector{}; @@ -293,7 +293,7 @@ namespace eosio { auto commits = (*curr_itr)->commits; auto as = current->active_schedule; - flat_map commit_count; + flat_map commit_count; for (const auto &com: commits) { if (commit_count.find(com.view) == commit_count.end()) commit_count[com.view] = 0; } @@ -318,7 +318,7 @@ namespace eosio { } } - vector pbft_database::send_and_add_pbft_commit(const vector &cv, uint32_t current_view) { + vector pbft_database::send_and_add_pbft_commit(const vector &cv, pbft_view_type current_view) { if (!cv.empty()) { for (auto c : cv) { //change uuid, sign again, update cache, then emit @@ -368,8 +368,8 @@ namespace eosio { return (psp->should_committed && (psp->block_num > ctrl.last_irreversible_block_num())); } - uint32_t pbft_database::get_committed_view() { - uint32_t new_view = 0; + pbft_view_type pbft_database::get_committed_view() { + pbft_view_type new_view = 0; if (!should_committed()) return new_view; const auto &by_commit_and_num_index = pbft_state_index.get(); @@ -382,7 +382,7 @@ namespace eosio { auto commits = (*itr)->commits; - flat_map commit_count; + flat_map commit_count; for (const auto &com: commits) { if (commit_count.find(com.view) == commit_count.end()) { commit_count[com.view] = 1; @@ -464,8 +464,8 @@ namespace eosio { } } - uint32_t pbft_database::should_view_change() { - uint32_t nv = 0; + pbft_view_type pbft_database::should_view_change() { + pbft_view_type nv = 0; auto &by_view_index = view_state_index.get(); auto itr = by_view_index.begin(); if (itr == by_view_index.end()) return nv; @@ -494,8 +494,8 @@ namespace eosio { const vector &vcv, const vector &ppc, const vector> &pcc, - uint32_t current_view, - uint32_t new_view) { + pbft_view_type current_view, + pbft_view_type new_view) { if (!vcv.empty()) { for (auto vc : vcv) { //change uuid, sign again, update cache, then emit @@ -538,21 +538,21 @@ namespace eosio { } } - bool pbft_database::should_new_view(const uint32_t target_view) { + bool pbft_database::should_new_view(const pbft_view_type target_view) { auto &by_view_index = view_state_index.get(); auto itr = by_view_index.find(target_view); if (itr == by_view_index.end()) return false; return (*itr)->should_view_changed; } - uint32_t pbft_database::get_proposed_new_view_num() { + pbft_view_type pbft_database::get_proposed_new_view_num() { auto &by_count_and_view_index = view_state_index.get(); auto itr = by_count_and_view_index.begin(); if (itr == by_count_and_view_index.end() || !(*itr)->should_view_changed) return 0; return (*itr)->view; } - bool pbft_database::is_new_primary(const uint32_t target_view) { + bool pbft_database::is_new_primary(const pbft_view_type target_view) { auto primary_key = get_new_view_primary_key(target_view); if (primary_key == public_key_type{}) return false; @@ -562,14 +562,13 @@ namespace eosio { } void pbft_database::prune_pbft_index() { -// pbft_state_index.clear(); view_state_index.clear(); ctrl.reset_pbft_my_prepare(); } pbft_new_view pbft_database::send_pbft_new_view( const vector &vcc, - uint32_t current_view) { + pbft_view_type current_view) { auto primary_key = get_new_view_primary_key(current_view); if (!is_new_primary(current_view)) return pbft_new_view{}; @@ -631,8 +630,8 @@ namespace eosio { auto prepares = psp->prepares; auto valid_prepares = vector{}; - flat_map prepare_count; - flat_map> prepare_msg; + flat_map prepare_count; + flat_map> prepare_msg; for (const auto &pre: prepares) { if (prepare_count.find(pre.view) == prepare_count.end()) prepare_count[pre.view] = 0; @@ -703,8 +702,8 @@ namespace eosio { auto commits = (*it)->commits; auto valid_commits = vector{}; - flat_map commit_count; - flat_map> commit_msg; + 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; @@ -736,7 +735,7 @@ namespace eosio { return pcc; } - vector pbft_database::generate_view_changed_certificate(uint32_t target_view) { + vector pbft_database::generate_view_changed_certificate(pbft_view_type target_view) { auto vcc = vector{}; auto &by_view_index = view_state_index.get(); @@ -777,7 +776,7 @@ namespace eosio { auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; auto prepares = certificate.prepares; - flat_map prepare_count; + flat_map prepare_count; for (const auto &pre: prepares) { if (prepare_count.find(pre.view) == prepare_count.end()) prepare_count[pre.view] = 0; @@ -837,7 +836,7 @@ namespace eosio { auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; auto commits = certificate.commits; - flat_map commit_count; + flat_map commit_count; for (const auto &pre: commits) { if (commit_count.find(pre.view) == commit_count.end()) commit_count[pre.view] = 0; @@ -1254,8 +1253,6 @@ namespace eosio { if (!is_valid_checkpoint(cp)) return; - auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - auto cp_block_state = ctrl.fetch_block_state_by_id(cp.block_id); if (!cp_block_state) return; auto active_bps = cp_block_state->active_schedule.producers; @@ -1312,8 +1309,18 @@ 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); + } + } + void pbft_database::checkpoint_local() { auto lscb_info = cal_pending_stable_checkpoint(); + auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto pending_num = lscb_info.block_num; auto pending_id = lscb_info.block_id; if (pending_num > lscb_num) { @@ -1325,21 +1332,14 @@ namespace eosio { prune(*pitr); } } -// auto &bni = checkpoint_index.get(); -// auto oldest = bni.begin(); -// if (oldest != bni.end() && lscb_num - (*oldest)->block_num > 10000) { -// auto it = bni.lower_bound(lscb_num - 10000); -// if (it != bni.end() && (*it)->is_stable) { -// prune_checkpoints(*it); -// } -// } - } - - 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); - } + // auto &bni = checkpoint_index.get(); + // auto oldest = bni.begin(); + // if (oldest != bni.end() && lscb_num - (*oldest)->block_num > 10000) { + // auto it = bni.lower_bound(lscb_num - 10000); + // if (it != bni.end() && (*it)->is_stable) { + // prune_checkpoints(*it); + // } + // } } bool pbft_database::is_valid_checkpoint(const pbft_checkpoint &cp) { @@ -1409,7 +1409,7 @@ namespace eosio { return false; } - public_key_type pbft_database::get_new_view_primary_key(const uint32_t target_view) { + public_key_type pbft_database::get_new_view_primary_key(const pbft_view_type target_view) { auto active_bps = lscb_active_producers().producers; if (active_bps.empty()) return public_key_type{}; @@ -1491,28 +1491,58 @@ namespace eosio { } } - if (fork_schedules.empty()) { - auto lscb_bps = lscb_active_producers().producers; - auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - for (auto &bp: lscb_bps) { + auto lscb_bps = lscb_active_producers().producers; + auto lscb_num = ctrl.last_stable_checkpoint_block_num(); + for (auto &bp: lscb_bps) { + if (fork_schedules.find(bp.block_signing_key) == fork_schedules.end() + || fork_schedules[bp.block_signing_key] < lscb_num) { fork_schedules[bp.block_signing_key] = lscb_num; } } + } 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); - } + if (itr != by_block_id_index.end()) return (*itr); return pbft_state_ptr{}; } + vector pbft_database::get_checkpoints_by_num(const block_num_type& num) const { + auto results = vector{}; + auto &by_num_index = checkpoint_index.get(); + + auto pitr = by_num_index.lower_bound( num ); + auto epitr = by_num_index.upper_bound( num ); + while( pitr != epitr ) { + if (pitr != by_num_index.end() && (*pitr)) results.emplace_back(*(*pitr)); + ++pitr; + } + + return results; + } + + pbft_view_state_ptr pbft_database::get_view_changes_by_target_view(const pbft_view_type& tv) const { + auto &by_view_index = view_state_index.get(); + auto itr = by_view_index.find(tv); + + if (itr != by_view_index.end()) return (*itr); + + return pbft_view_state_ptr{}; + } + + vector pbft_database::get_pbft_watermarks() const { + return prepare_watermarks; + } + + flat_map pbft_database::get_pbft_fork_schedules() const { + return fork_schedules; + } + void pbft_database::set(pbft_state_ptr s) { auto result = pbft_state_index.insert(s); diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index d81bd231a45..8eb52950702 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -10,6 +10,7 @@ add_subdirectory(producer_api_plugin) add_subdirectory(history_plugin) add_subdirectory(history_api_plugin) add_subdirectory(pbft_plugin) +add_subdirectory(pbft_api_plugin) add_subdirectory(state_history_plugin) add_subdirectory(wallet_plugin) diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index ad00c2e268f..3fe87cc36bd 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -3015,6 +3015,7 @@ namespace eosio { if (!pcc.pbft_db.is_valid_checkpoint(msg)) return; bcast_pbft_msg(msg); + fc_ilog( logger, "sent checkpoint at height: ${n}, from ${k}, ", ("n", msg.block_num)("k", msg.public_key)); } bool net_plugin_impl::maybe_add_pbft_cache(const string &uuid){ @@ -3105,7 +3106,7 @@ namespace eosio { } void net_plugin_impl::handle_message( connection_ptr c, const pbft_checkpoint &msg) { - fc_ilog( logger, "received checkpoint at ${n}, from ${v}", ("n", msg.block_num)("v", msg.public_key)); + if (!is_pbft_msg_valid(msg)) return; auto added = maybe_add_pbft_cache(msg.uuid); diff --git a/plugins/pbft_api_plugin/CMakeLists.txt b/plugins/pbft_api_plugin/CMakeLists.txt new file mode 100644 index 00000000000..cda4ea2a0e8 --- /dev/null +++ b/plugins/pbft_api_plugin/CMakeLists.txt @@ -0,0 +1,7 @@ +file(GLOB HEADERS "include/eosio/pbft_api_plugin/*.hpp") +add_library( pbft_api_plugin + pbft_api_plugin.cpp + ${HEADERS} ) + +target_link_libraries( pbft_api_plugin pbft_plugin http_plugin appbase ) +target_include_directories( pbft_api_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/plugins/pbft_api_plugin/include/eosio/pbft_api_plugin/pbft_api_plugin.hpp b/plugins/pbft_api_plugin/include/eosio/pbft_api_plugin/pbft_api_plugin.hpp new file mode 100644 index 00000000000..f90e1cd2bb3 --- /dev/null +++ b/plugins/pbft_api_plugin/include/eosio/pbft_api_plugin/pbft_api_plugin.hpp @@ -0,0 +1,35 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#pragma once + +#include +#include + +#include + +namespace eosio { + +using namespace appbase; + +class pbft_api_plugin : public plugin { + public: + APPBASE_PLUGIN_REQUIRES( (pbft_plugin)(http_plugin)) + + pbft_api_plugin() = default; + pbft_api_plugin(const pbft_api_plugin&) = delete; + pbft_api_plugin(pbft_api_plugin&&) = delete; + pbft_api_plugin& operator=(const pbft_api_plugin&) = delete; + pbft_api_plugin& operator=(pbft_api_plugin&&) = delete; + virtual ~pbft_api_plugin() override = default; + + virtual void set_program_options(options_description& cli, options_description& cfg) override {} + void plugin_initialize(const variables_map& vm); + void plugin_startup(); + void plugin_shutdown() {} + + private: +}; + +} diff --git a/plugins/pbft_api_plugin/pbft_api_plugin.cpp b/plugins/pbft_api_plugin/pbft_api_plugin.cpp new file mode 100644 index 00000000000..37d3176d4bb --- /dev/null +++ b/plugins/pbft_api_plugin/pbft_api_plugin.cpp @@ -0,0 +1,90 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#include +#include + +#include +#include + +#include + +namespace eosio { namespace detail { + struct pbft_api_plugin_response { + std::string result; + }; +}} + +FC_REFLECT(eosio::detail::pbft_api_plugin_response, (result)); + +namespace eosio { + +static appbase::abstract_plugin& _pbft_api_plugin = app().register_plugin(); + +using namespace eosio; + +#define CALL(api_name, api_handle, call_name, INVOKE, http_response_code) \ +{std::string("/v1/" #api_name "/" #call_name), \ + [&api_handle](string, string body, url_response_callback cb) mutable { \ + try { \ + if (body.empty()) body = "{}"; \ + INVOKE \ + cb(http_response_code, fc::json::to_string(result)); \ + } catch (...) { \ + http_plugin::handle_exception(#api_name, #call_name, body, cb); \ + } \ + }} +#define INVOKE_R(api_handle, call_name) \ + auto result = api_handle.call_name(); + +#define INVOKE_R_P(api_handle, call_name, in_param) \ + auto result = api_handle.call_name(fc::json::from_string(body).as()); + +#define INVOKE_W_P(api_handle, call_name, in_param) \ + api_handle.call_name(fc::json::from_string(body).as()); \ + eosio::detail::pbft_api_plugin_response result{"ok"}; + +void pbft_api_plugin::plugin_startup() { + ilog("starting pbft_api_plugin"); + // lifetime of plugin is lifetime of application + auto& pbft = app().get_plugin(); + + app().get_plugin().add_api({ + CALL(pbft, pbft, get_watermarks, INVOKE_R(pbft, get_watermarks), 200), + CALL(pbft, pbft, get_fork_schedules, INVOKE_R(pbft, get_fork_schedules), 200), + CALL(pbft, pbft, get_pbft_record, INVOKE_R_P(pbft, get_pbft_record, block_id_type), 200), + CALL(pbft, pbft, get_pbft_checkpoints_record, INVOKE_R_P(pbft, get_pbft_checkpoints_record, block_num_type), 200), + CALL(pbft, pbft, get_view_change_record, INVOKE_R_P(pbft, get_view_change_record, pbft_view_type), 200), + CALL(pbft, pbft, get_pbft_status, INVOKE_R(pbft, get_pbft_status), 200), + CALL(pbft, pbft, get_pbft_status, INVOKE_R(pbft, get_pbft_status), 200), + CALL(pbft, pbft, get_pbft_status, INVOKE_R(pbft, get_pbft_status), 200), + CALL(pbft, pbft, set_pbft_current_view, INVOKE_W_P(pbft, set_pbft_current_view, pbft_view_type), 201), + }); +} + +void pbft_api_plugin::plugin_initialize(const variables_map& options) { + try { + const auto& _http_plugin = app().get_plugin(); + if( !_http_plugin.is_on_loopback()) { + wlog( "\n" + "**********SECURITY WARNING**********\n" + "* *\n" + "* -- PBFT API -- *\n" + "* - EXPOSED to the LOCAL NETWORK - *\n" + "* - USE ONLY ON SECURE NETWORKS! - *\n" + "* *\n" + "************************************\n" ); + + } + } FC_LOG_AND_RETHROW() +} + +#undef INVOKE_R +#undef INVOKE_R_P +#undef INVOKE_W_P + + +#undef CALL + +} diff --git a/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp b/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp index d94c74785e3..5619ba8494c 100644 --- a/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp +++ b/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp @@ -4,6 +4,9 @@ */ #pragma once #include +#include +#include +#include namespace eosio { @@ -13,7 +16,7 @@ class pbft_plugin : public appbase::plugin { public: pbft_plugin(); virtual ~pbft_plugin(); - + APPBASE_PLUGIN_REQUIRES() virtual void set_program_options(options_description&, options_description& cfg) override; @@ -21,6 +24,19 @@ class pbft_plugin : public appbase::plugin { void plugin_startup(); void plugin_shutdown(); + + pbft_state get_pbft_record( const block_id_type& bid )const; + vector get_pbft_checkpoints_record(const block_num_type &bnum)const; + pbft_view_state get_view_change_record(const pbft_view_type& view)const; + vector get_watermarks()const; + flat_map get_fork_schedules()const; + const char* get_pbft_status()const; + block_id_type get_pbft_prepared_block_id()const; + block_id_type get_pbft_my_prepare_id()const; + + void set_pbft_current_view(pbft_view_type view); + + private: std::unique_ptr my; }; diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index 63bb1415b2c..aca3c11b992 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -2,9 +2,6 @@ #include #include -#include -#include -#include #include namespace eosio { @@ -61,7 +58,57 @@ namespace eosio { my->checkpoint_timer_tick(); } - void pbft_plugin::plugin_shutdown() { + void pbft_plugin::plugin_shutdown() {} + + pbft_state pbft_plugin::get_pbft_record( const block_id_type& bid ) const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto record = pbft_ctrl.pbft_db.get_pbft_state_by_id(bid); + if (record) return *record; + return pbft_state(); + } + + vector pbft_plugin::get_pbft_checkpoints_record(const block_num_type &bnum) const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto records = pbft_ctrl.pbft_db.get_checkpoints_by_num(bnum); + if (!records.empty()) return records; + return vector(); + } + pbft_view_state pbft_plugin::get_view_change_record(const pbft_view_type& view) const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + auto record = pbft_ctrl.pbft_db.get_view_changes_by_target_view(view); + if (record) return *record; + return pbft_view_state(); + } + + vector pbft_plugin::get_watermarks() const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + return pbft_ctrl.pbft_db.get_pbft_watermarks(); + } + + flat_map pbft_plugin::get_fork_schedules() const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + return pbft_ctrl.pbft_db.get_pbft_fork_schedules(); + } + + const char* pbft_plugin::get_pbft_status() const { + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + return pbft_ctrl.state_machine.get_current()->get_name(); + } + + block_id_type pbft_plugin::get_pbft_prepared_block_id() const { + auto& ctrl = app().get_plugin().chain(); + return ctrl.get_pbft_prepared(); + } + + block_id_type pbft_plugin::get_pbft_my_prepare_id() const { + auto& ctrl = app().get_plugin().chain(); + return ctrl.get_pbft_my_prepare(); + } + + void pbft_plugin::set_pbft_current_view(const pbft_view_type view) { + //this is used to boost the recovery from a disaster, do not set this unless you have to do so. + pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); + pbft_ctrl.state_machine.manually_set_current_view(view); } void pbft_plugin_impl::prepare_timer_tick() { diff --git a/plugins/producer_api_plugin/producer_api_plugin.cpp b/plugins/producer_api_plugin/producer_api_plugin.cpp index 62f4664ed82..7fcde1ac98c 100644 --- a/plugins/producer_api_plugin/producer_api_plugin.cpp +++ b/plugins/producer_api_plugin/producer_api_plugin.cpp @@ -90,8 +90,6 @@ void producer_api_plugin::plugin_startup() { INVOKE_R_V(producer, get_integrity_hash), 201), CALL(producer, producer, create_snapshot, INVOKE_R_V(producer, create_snapshot), 201), - CALL(producer, producer, set_pbft_current_view, - INVOKE_V_R(producer, set_pbft_current_view, uint32_t), 201), }); } diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp index f6d10eb277b..c43f0e0f38b 100644 --- a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp +++ b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp @@ -82,8 +82,6 @@ class producer_plugin : public appbase::plugin { integrity_hash_information get_integrity_hash() const; snapshot_information create_snapshot() const; - void set_pbft_current_view(const uint32_t view); - signal confirmed_block; private: std::shared_ptr my; diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index e614e84d398..c39ba284342 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -979,12 +979,6 @@ producer_plugin::snapshot_information producer_plugin::create_snapshot() const { return {head_id, snapshot_path}; } -void producer_plugin::set_pbft_current_view(const uint32_t view) { - //this is used to recover from a disaster, do not set this unless you have to do so. - pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - pbft_ctrl.state_machine.manually_set_current_view(view); -} - optional producer_plugin_impl::calculate_next_block_time(const account_name& producer_name, const block_timestamp_type& current_block_time) const { chain::controller& chain = chain_plug->chain(); const auto& hbs = chain.head_block_state(); diff --git a/programs/nodeos/CMakeLists.txt b/programs/nodeos/CMakeLists.txt index 9399302f246..4714803f680 100644 --- a/programs/nodeos/CMakeLists.txt +++ b/programs/nodeos/CMakeLists.txt @@ -64,6 +64,7 @@ target_link_libraries( ${NODE_EXECUTABLE_NAME} PRIVATE -Wl,${whole_archive_flag} producer_api_plugin -Wl,${no_whole_archive_flag} PRIVATE -Wl,${whole_archive_flag} test_control_plugin -Wl,${no_whole_archive_flag} PRIVATE -Wl,${whole_archive_flag} test_control_api_plugin -Wl,${no_whole_archive_flag} + PRIVATE -Wl,${whole_archive_flag} pbft_api_plugin -Wl,${no_whole_archive_flag} PRIVATE -Wl,${build_id_flag} PRIVATE chain_plugin http_plugin producer_plugin http_client_plugin pbft_plugin PRIVATE eosio_chain fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) From 8a1c39cd6dc21c7f070f04deab3c856c15fac4a9 Mon Sep 17 00:00:00 2001 From: oldcold Date: Thu, 30 May 2019 17:32:42 +0800 Subject: [PATCH 10/22] increase pbft message deadline --- plugins/net_plugin/net_plugin.cpp | 46 +++++---------------- plugins/pbft_api_plugin/pbft_api_plugin.cpp | 2 - 2 files changed, 11 insertions(+), 37 deletions(-) diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 3fe87cc36bd..fa0f03c87a2 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -175,7 +175,7 @@ namespace eosio { std::unordered_map pbft_message_cache{}; const int pbft_message_cache_TTL = 600; - const int pbft_message_TTL = 10; + const int pbft_message_TTL = 60; channels::transaction_ack::channel_type::handle incoming_transaction_ack_subscription; eosio::chain::plugin_interface::pbft::outgoing::prepare_channel::channel_type::handle pbft_outgoing_prepare_subscription; @@ -1155,7 +1155,7 @@ namespace eosio { break; } } - + if (drop_pbft_count) wlog("dropped ${n} outdated pbft messages", ("n",drop_pbft_count)); //drop timeout messages in mem, init send buffer only when actual send happens //copied from a previous version of connection::enqueue connection_wptr weak_this = shared_from_this(); @@ -1287,8 +1287,7 @@ namespace eosio { to_sync_queue); } - void connection::enqueue_pbft(const std::shared_ptr>& m, - const time_point_sec deadline = time_point_sec(static_cast(600))) + void connection::enqueue_pbft(const std::shared_ptr>& m, const time_point_sec deadline) { pbft_queue.push_back(queued_pbft_message{m, deadline }); if (buffer_queue.is_out_queue_empty()) { @@ -1379,35 +1378,6 @@ namespace eosio { sync_wait(); } -// bool connection::process_next_message(net_plugin_impl& impl, uint32_t message_length) { -// vector tmp_data; -// tmp_data.resize(message_length); -// -// try { -// auto ds = pending_message_buffer.create_datastream(); -// auto read_index = pending_message_buffer.read_index(); -// pending_message_buffer.peek(tmp_data.data(),message_length,read_index); -// -// net_message msg; -// fc::raw::unpack(ds, msg); -// msg_handler m(impl, shared_from_this() ); -// if( msg.contains() ) { -// m( std::move( msg.get() ) ); -// } else if( msg.contains() ) { -// m( std::move( msg.get() ) ); -// } else { -// msg.visit( m ); -// } -// } catch( const fc::exception& e ) { -// wlog("error message length: ${l}", ("l", message_length)); -// wlog("error raw bytes ${s}", ("s", tmp_data)); -// edump((e.to_detail_string() )); -// impl.close( shared_from_this() ); -// return false; -// } -// return true; -// } - bool connection::process_next_message(net_plugin_impl& impl, uint32_t message_length) { try { auto ds = pending_message_buffer.create_datastream(); @@ -2932,13 +2902,19 @@ namespace eosio { template bool net_plugin_impl::is_pbft_msg_outdated(M const & msg) { - return (time_point_sec(time_point::now()) > time_point_sec(msg.timestamp) + pbft_message_TTL); + if (time_point_sec(time_point::now()) > time_point_sec(msg.timestamp) + pbft_message_TTL) { + wlog("received a outdated pbft message ${m}", ("m", msg)); + return true; + } + return false; } template bool net_plugin_impl::is_pbft_msg_valid(M const & msg) { // Do some basic validations of an incoming pbft msg, bad msgs should be quickly discarded without affecting state. - return (chain_id == msg.chain_id && !is_pbft_msg_outdated(msg) && !sync_master->is_syncing()); + return chain_id == msg.chain_id + && !is_pbft_msg_outdated(msg) + && !sync_master->is_syncing(); } void net_plugin_impl::bcast_pbft_msg(const net_message &msg) { diff --git a/plugins/pbft_api_plugin/pbft_api_plugin.cpp b/plugins/pbft_api_plugin/pbft_api_plugin.cpp index 37d3176d4bb..76d9605d873 100644 --- a/plugins/pbft_api_plugin/pbft_api_plugin.cpp +++ b/plugins/pbft_api_plugin/pbft_api_plugin.cpp @@ -57,8 +57,6 @@ void pbft_api_plugin::plugin_startup() { CALL(pbft, pbft, get_pbft_checkpoints_record, INVOKE_R_P(pbft, get_pbft_checkpoints_record, block_num_type), 200), CALL(pbft, pbft, get_view_change_record, INVOKE_R_P(pbft, get_view_change_record, pbft_view_type), 200), CALL(pbft, pbft, get_pbft_status, INVOKE_R(pbft, get_pbft_status), 200), - CALL(pbft, pbft, get_pbft_status, INVOKE_R(pbft, get_pbft_status), 200), - CALL(pbft, pbft, get_pbft_status, INVOKE_R(pbft, get_pbft_status), 200), CALL(pbft, pbft, set_pbft_current_view, INVOKE_W_P(pbft, set_pbft_current_view, pbft_view_type), 201), }); } From 56110e076aa864a9b02b16f674e96152248d1969 Mon Sep 17 00:00:00 2001 From: oldcold Date: Thu, 30 May 2019 20:01:31 +0800 Subject: [PATCH 11/22] increase new view message deadline; add prepared & my_prepare in pbft_api_plugin --- libraries/chain/pbft_database.cpp | 11 ++---- plugins/net_plugin/net_plugin.cpp | 36 +++++++++---------- plugins/pbft_api_plugin/pbft_api_plugin.cpp | 2 ++ .../include/eosio/pbft_plugin/pbft_plugin.hpp | 2 +- plugins/pbft_plugin/pbft_plugin.cpp | 2 +- 5 files changed, 24 insertions(+), 29 deletions(-) diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index ceeca762eb9..468ee4c579a 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -122,8 +122,6 @@ namespace eosio { psp->prepares.emplace_back(p); std::sort(psp->prepares.begin(), psp->prepares.end(), less<>()); }); - } else { - dlog( "prepare already exists: ${p}", ("p", p)); } } curr_itr = by_block_id_index.find(current->id); @@ -148,8 +146,7 @@ namespace eosio { for (auto const &e: prepare_count) { if (e.second >= as.size() * 2 / 3 + 1) { by_block_id_index.modify(curr_itr, - [&](const pbft_state_ptr &psp) { psp->should_prepared = true; }); - dlog( "block id ${id} is now prepared at view ${v}", ("id", current->id)("v", e.first)); + [&](const pbft_state_ptr &psp) { psp->should_prepared = true; }); } } } @@ -279,8 +276,6 @@ namespace eosio { psp->commits.emplace_back(c); std::sort(psp->commits.begin(), psp->commits.end(), less<>()); }); - } else { - dlog( "commit already exists: ${c}", ("c", c)); } } @@ -309,8 +304,7 @@ namespace eosio { for (auto const &e: commit_count) { if (e.second >= current->active_schedule.producers.size() * 2 / 3 + 1) { by_block_id_index.modify(curr_itr, - [&](const pbft_state_ptr &psp) { psp->should_committed = true; }); - dlog( "block id ${id} is now committed at view ${v}", ("id", current->id)("v", e.first)); + [&](const pbft_state_ptr &psp) { psp->should_committed = true; }); } } } @@ -417,7 +411,6 @@ namespace eosio { pbft_state_ptr psp = *itr; ctrl.pbft_commit_local(psp->block_id); - dlog( "block id ${id} is committed local", ("id", psp->block_id)); } bool pbft_database::pending_pbft_lib() { diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index fa0f03c87a2..0e6ca0efb78 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -247,9 +247,9 @@ namespace eosio { template bool is_pbft_msg_valid(M const & msg); - void bcast_pbft_msg(const net_message &msg); + void bcast_pbft_msg(const net_message &msg, int ttl); - void forward_pbft_msg(connection_ptr c, const net_message &msg); + 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); @@ -2912,15 +2912,15 @@ namespace eosio { template bool net_plugin_impl::is_pbft_msg_valid(M const & msg) { // Do some basic validations of an incoming pbft msg, bad msgs should be quickly discarded without affecting state. - return chain_id == msg.chain_id + return chain_id == msg.chain_id && !is_pbft_msg_outdated(msg) && !sync_master->is_syncing(); } - void net_plugin_impl::bcast_pbft_msg(const net_message &msg) { + void net_plugin_impl::bcast_pbft_msg(const net_message &msg, int ttl) { if (sync_master->is_syncing()) return; - auto deadline = time_point_sec(time_point::now()) + pbft_message_TTL; + auto deadline = time_point_sec(time_point::now()) + ttl; for (auto &conn: connections) { if (conn->pbft_ready()) { @@ -2929,8 +2929,8 @@ namespace eosio { } } - void net_plugin_impl::forward_pbft_msg(connection_ptr c, const net_message &msg) { - auto deadline = time_point_sec(time_point::now()) + pbft_message_TTL; + void net_plugin_impl::forward_pbft_msg(connection_ptr c, const net_message &msg, int ttl) { + auto deadline = time_point_sec(time_point::now()) + ttl; for (auto &conn: connections) { if (conn != c && conn->pbft_ready()) { @@ -2946,7 +2946,7 @@ namespace eosio { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_prepare(msg)) return; - bcast_pbft_msg(msg); + bcast_pbft_msg(msg, pbft_message_TTL); fc_ilog( logger, "sent prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_num)("v", msg.view)("k", msg.public_key)); } @@ -2957,7 +2957,7 @@ namespace eosio { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_commit(msg)) return; - bcast_pbft_msg(msg); + bcast_pbft_msg(msg, pbft_message_TTL); fc_ilog( logger, "sent commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_num)("v", msg.view)("k", msg.public_key)); } @@ -2968,7 +2968,7 @@ namespace eosio { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_view_change(msg)) return; - bcast_pbft_msg(msg); + bcast_pbft_msg(msg, pbft_message_TTL); fc_ilog( logger, "sent view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", msg.current_view)("tv", msg.target_view)("v", msg.public_key)); } @@ -2979,7 +2979,7 @@ namespace eosio { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_new_view(msg)) return; - bcast_pbft_msg(msg); + bcast_pbft_msg(msg, INT_MAX); fc_ilog( logger, "sent new view at view: ${v}, from ${k}, ", ("v", msg.view)("k", msg.public_key)); } @@ -2990,7 +2990,7 @@ namespace eosio { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_checkpoint(msg)) return; - bcast_pbft_msg(msg); + bcast_pbft_msg(msg, pbft_message_TTL); fc_ilog( logger, "sent checkpoint at height: ${n}, from ${k}, ", ("n", msg.block_num)("k", msg.public_key)); } @@ -3026,7 +3026,7 @@ namespace eosio { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_prepare(msg)) return; - forward_pbft_msg(c, msg); + forward_pbft_msg(c, msg, pbft_message_TTL); fc_ilog( logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_num)("v", msg.view)("k", msg.public_key)); pbft_incoming_prepare_channel.publish(msg); @@ -3043,7 +3043,7 @@ namespace eosio { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_commit(msg)) return; - forward_pbft_msg(c, msg); + forward_pbft_msg(c, msg, pbft_message_TTL); fc_ilog( logger, "received commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_num)("v", msg.view)("k", msg.public_key)); pbft_incoming_commit_channel.publish(msg); @@ -3059,7 +3059,7 @@ namespace eosio { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_view_change(msg)) return; - forward_pbft_msg(c, msg); + forward_pbft_msg(c, msg, pbft_message_TTL); fc_ilog( logger, "received view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", msg.current_view)("tv", msg.target_view)("v", msg.public_key)); pbft_incoming_view_change_channel.publish(msg); @@ -3067,7 +3067,7 @@ namespace eosio { void net_plugin_impl::handle_message( connection_ptr c, const pbft_new_view &msg) { - if (!is_pbft_msg_valid(msg)) return; + if (chain_id != msg.chain_id) return; auto added = maybe_add_pbft_cache(msg.uuid); if (!added) return; @@ -3075,7 +3075,7 @@ namespace eosio { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!(msg.public_key == pcc.pbft_db.get_new_view_primary_key(msg.view) && msg.is_signature_valid())) return; - forward_pbft_msg(c, msg); + forward_pbft_msg(c, msg, INT_MAX); fc_ilog( logger, "received new view: ${n}, from ${v}", ("n", msg)("v", msg.public_key)); pbft_incoming_new_view_channel.publish(msg); @@ -3091,7 +3091,7 @@ namespace eosio { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_checkpoint(msg)) return; - forward_pbft_msg(c, msg); + forward_pbft_msg(c, msg, pbft_message_TTL); fc_ilog( logger, "received checkpoint at ${n}, from ${v}", ("n", msg.block_num)("v", msg.public_key)); pbft_incoming_checkpoint_channel.publish(msg); diff --git a/plugins/pbft_api_plugin/pbft_api_plugin.cpp b/plugins/pbft_api_plugin/pbft_api_plugin.cpp index 76d9605d873..33fcd7b8654 100644 --- a/plugins/pbft_api_plugin/pbft_api_plugin.cpp +++ b/plugins/pbft_api_plugin/pbft_api_plugin.cpp @@ -57,6 +57,8 @@ void pbft_api_plugin::plugin_startup() { CALL(pbft, pbft, get_pbft_checkpoints_record, INVOKE_R_P(pbft, get_pbft_checkpoints_record, block_num_type), 200), CALL(pbft, pbft, get_view_change_record, INVOKE_R_P(pbft, get_view_change_record, pbft_view_type), 200), CALL(pbft, pbft, get_pbft_status, INVOKE_R(pbft, get_pbft_status), 200), + CALL(pbft, pbft, get_pbft_prepared_id, INVOKE_R(pbft, get_pbft_prepared_id), 200), + CALL(pbft, pbft, get_pbft_my_prepare_id, INVOKE_R(pbft, get_pbft_my_prepare_id), 200), CALL(pbft, pbft, set_pbft_current_view, INVOKE_W_P(pbft, set_pbft_current_view, pbft_view_type), 201), }); } diff --git a/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp b/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp index 5619ba8494c..b28702c00c0 100644 --- a/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp +++ b/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp @@ -31,7 +31,7 @@ class pbft_plugin : public appbase::plugin { vector get_watermarks()const; flat_map get_fork_schedules()const; const char* get_pbft_status()const; - block_id_type get_pbft_prepared_block_id()const; + block_id_type get_pbft_prepared_id()const; block_id_type get_pbft_my_prepare_id()const; void set_pbft_current_view(pbft_view_type view); diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index aca3c11b992..b3554ddfe70 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -95,7 +95,7 @@ namespace eosio { return pbft_ctrl.state_machine.get_current()->get_name(); } - block_id_type pbft_plugin::get_pbft_prepared_block_id() const { + block_id_type pbft_plugin::get_pbft_prepared_id() const { auto& ctrl = app().get_plugin().chain(); return ctrl.get_pbft_prepared(); } From 7b241d5775f1c43aa121c6715f5e7c42bd1f6357 Mon Sep 17 00:00:00 2001 From: oldcold Date: Fri, 17 May 2019 22:38:09 +0800 Subject: [PATCH 12/22] re-struct pbft message; compress pbft new view --- libraries/chain/include/eosio/chain/pbft.hpp | 23 +- .../include/eosio/chain/pbft_database.hpp | 434 ++++++------------ libraries/chain/pbft.cpp | 119 +++-- libraries/chain/pbft_database.cpp | 218 ++++----- .../include/eosio/net_plugin/protocol.hpp | 10 +- plugins/net_plugin/net_plugin.cpp | 85 +++- 6 files changed, 392 insertions(+), 497 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index cdd393ad887..885b3c4a201 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -13,9 +13,9 @@ namespace eosio { vector prepares_cache; vector commits_cache; vector view_changes_cache; - vector prepared_certificate; - vector> committed_certificate; - vector view_changed_certificate; + pbft_prepared_certificate prepared_certificate; + vector committed_certificate; + pbft_view_changed_certificate view_changed_certificate; }; class psm_machine { @@ -55,6 +55,9 @@ namespace eosio { template void transit_to_view_change_state(T const & s); + template + bool maybe_new_view(T const & s); + template void transit_to_new_view(const pbft_new_view &new_view, T const &s); @@ -74,17 +77,17 @@ namespace eosio { void set_current_view(const uint32_t &cv); - const vector &get_prepared_certificate() const; + const pbft_prepared_certificate &get_prepared_certificate() const; - void set_prepared_certificate(const vector &pcert); + void set_prepared_certificate(const pbft_prepared_certificate &pcert); - const vector> &get_committed_certificate() const; + const vector &get_committed_certificate() const; - void set_committed_certificate(const vector> &ccert); + void set_committed_certificate(const vector &ccert); - const vector &get_view_changed_certificate() const; + const pbft_view_changed_certificate &get_view_changed_certificate() const; - void set_view_changed_certificate(const vector &vc_cert); + void set_view_changed_certificate(const pbft_view_changed_certificate &vc_cert); const uint32_t &get_target_view_retries() const; @@ -217,7 +220,7 @@ namespace eosio { class pbft_controller { public: - pbft_controller(controller& ctrl); + explicit pbft_controller(controller& ctrl); ~pbft_controller(); pbft_database pbft_db; diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 51518f019f8..14f0c27620a 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -27,88 +27,80 @@ namespace eosio { block_num_type block_num = 0; }; - struct pbft_prepare { - string uuid; - pbft_view_type view; - block_num_type block_num = 0; - block_id_type block_id; + struct pbft_message { + string uuid; public_key_type public_key; - chain_id_type chain_id = chain_id_type(""); - signature_type producer_signature; - time_point timestamp = time_point::now(); + chain_id_type chain_id = chain_id_type(""); + signature_type producer_signature; + time_point timestamp = time_point::now(); + virtual digest_type digest() const { + digest_type::encoder enc; + fc::raw::pack(enc, public_key); + fc::raw::pack(enc, chain_id); + return enc.result(); + } - bool operator==(const pbft_prepare &rhs) const { - return view == rhs.view - && block_num == rhs.block_num - && block_id == rhs.block_id - && public_key == rhs.public_key - && chain_id == rhs.chain_id - && timestamp == rhs.timestamp; + virtual 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; + } } - bool operator!=(const pbft_prepare &rhs) const { - return !(*this == rhs); + virtual ~pbft_message() = default; + }; + + struct pbft_prepare final: public pbft_message { + explicit pbft_prepare() = default; + uint32_t view = 0; + block_num_type block_num = 0; + block_id_type block_id; + + bool operator==(const pbft_prepare &rhs) const { + return digest() == rhs.digest(); } bool operator<(const pbft_prepare &rhs) const { if (block_num < rhs.block_num) { return true; - } else return block_num == rhs.block_num && view < rhs.view; + } else { + return block_num == rhs.block_num && view < rhs.view; + } } - digest_type digest() const { + digest_type digest() const override { digest_type::encoder enc; fc::raw::pack(enc, view); fc::raw::pack(enc, block_num); fc::raw::pack(enc, block_id); fc::raw::pack(enc, public_key); fc::raw::pack(enc, chain_id); - fc::raw::pack(enc, timestamp); 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_commit { - string uuid; - pbft_view_type view; - block_num_type block_num = 0; - block_id_type block_id; - public_key_type public_key; - chain_id_type chain_id = chain_id_type(""); - signature_type producer_signature; - time_point timestamp = time_point::now(); - + struct pbft_commit final: public pbft_message { + explicit pbft_commit() = default; + pbft_view_type view = 0; + block_num_type block_num = 0; + block_id_type block_id; bool operator==(const pbft_commit &rhs) const { - return view == rhs.view - && block_num == rhs.block_num - && block_id == rhs.block_id - && public_key == rhs.public_key - && chain_id == rhs.chain_id - && timestamp == rhs.timestamp; - } - - bool operator!=(const pbft_commit &rhs) const { - return !(*this == rhs); + return digest() == rhs.digest(); } bool operator<(const pbft_commit &rhs) const { if (block_num < rhs.block_num) { return true; - } else return block_num == rhs.block_num && view < rhs.view; + } else { + return block_num == rhs.block_num && view < rhs.view; + } } - digest_type digest() const { + digest_type digest() const override { digest_type::encoder enc; fc::raw::pack(enc, view); fc::raw::pack(enc, block_num); @@ -118,32 +110,16 @@ namespace eosio { fc::raw::pack(enc, timestamp); 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_checkpoint { - string uuid; - block_num_type block_num = 0; - block_id_type block_id; - public_key_type public_key; - chain_id_type chain_id = chain_id_type(""); - signature_type producer_signature; - time_point timestamp = time_point::now(); + struct pbft_checkpoint final: public pbft_message { + explicit pbft_checkpoint() = default; + + block_num_type block_num = 0; + block_id_type block_id; bool operator==(const pbft_checkpoint &rhs) const { - return block_num == rhs.block_num - && block_id == rhs.block_id - && public_key == rhs.public_key - && chain_id == rhs.chain_id - && timestamp == rhs.timestamp; + return digest() == rhs.digest(); } bool operator!=(const pbft_checkpoint &rhs) const { @@ -154,7 +130,7 @@ namespace eosio { return block_num < rhs.block_num; } - digest_type digest() const { + digest_type digest() const override { digest_type::encoder enc; fc::raw::pack(enc, block_num); fc::raw::pack(enc, block_id); @@ -163,35 +139,15 @@ namespace eosio { fc::raw::pack(enc, timestamp); 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_stable_checkpoint { - block_num_type block_num = 0; - block_id_type block_id; - vector checkpoints; - chain_id_type chain_id = chain_id_type(""); + struct pbft_certificate { + block_num_type block_num = 0; + block_id_type block_id; + vector messages; + chain_id_type chain_id = chain_id_type(""); - bool operator==(const pbft_stable_checkpoint &rhs) const { - return block_id == rhs.block_id - && block_num == rhs.block_num - && checkpoints == rhs.checkpoints - && chain_id == rhs.chain_id; - } - - bool operator!=(const pbft_stable_checkpoint &rhs) const { - return !(*this == rhs); - } - - bool operator<(const pbft_stable_checkpoint &rhs) const { + bool operator<(const pbft_certificate &rhs) const { return block_num < rhs.block_num; } @@ -199,125 +155,65 @@ namespace eosio { digest_type::encoder enc; fc::raw::pack(enc, block_num); fc::raw::pack(enc, block_id); - fc::raw::pack(enc, checkpoints); + fc::raw::pack(enc, messages); fc::raw::pack(enc, chain_id); return enc.result(); } }; - struct pbft_prepared_certificate { - block_id_type block_id; - block_num_type block_num = 0; - vector prepares; + struct pbft_stable_checkpoint final: public pbft_certificate { + explicit pbft_stable_checkpoint() = default; - public_key_type public_key; - signature_type producer_signature; + vector messages; - bool operator==(const pbft_prepared_certificate &rhs) const { - return block_num == rhs.block_num - && block_id == rhs.block_id - && prepares == rhs.prepares - && public_key == rhs.public_key; + bool operator==(const pbft_stable_checkpoint &rhs) const { + return digest() == rhs.digest(); } - bool operator!=(const pbft_prepared_certificate &rhs) const { + bool operator!=(const pbft_stable_checkpoint &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, prepares); - 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_committed_certificate { - block_id_type block_id; - block_num_type block_num = 0; - vector commits; + struct pbft_prepared_certificate final: public pbft_certificate { + explicit pbft_prepared_certificate() = default; - public_key_type public_key; - signature_type producer_signature; + vector messages; - 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_prepared_certificate &rhs) const { + return digest() == rhs.digest(); } + }; - bool operator!=(const pbft_committed_certificate &rhs) const { - return !(*this == rhs); - } + struct pbft_committed_certificate final: public pbft_certificate { + explicit pbft_committed_certificate() = default; - bool operator<(const pbft_committed_certificate &rhs) const { - return block_num < rhs.block_num; - } + vector messages; - 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; - } + bool operator==(const pbft_committed_certificate &rhs) const { + return digest() == rhs.digest(); } }; - struct pbft_view_change { - string uuid; - pbft_view_type current_view; - pbft_view_type 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(""); - signature_type producer_signature; - time_point timestamp = time_point::now(); + struct pbft_view_change final: public pbft_message { + explicit pbft_view_change() = default; - bool operator==(const pbft_view_change &rhs) const { - 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 - && timestamp == rhs.timestamp; - } + uint32_t current_view = 0; + uint32_t target_view = 1; + pbft_prepared_certificate prepared; + vector committed; + pbft_stable_checkpoint stable_checkpoint; - bool operator!=(const pbft_view_change &rhs) const { - return !(*this == rhs); + bool operator==(const pbft_view_change &rhs) const { + return digest() == rhs.digest(); } bool operator<(const pbft_view_change &rhs) const { return target_view < rhs.target_view; } - digest_type digest() const { + digest_type digest() const override { digest_type::encoder enc; fc::raw::pack(enc, current_view); fc::raw::pack(enc, target_view); @@ -326,87 +222,46 @@ namespace eosio { fc::raw::pack(enc, stable_checkpoint); fc::raw::pack(enc, public_key); fc::raw::pack(enc, chain_id); - fc::raw::pack(enc, timestamp); 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_changed_certificate { - pbft_view_type view; - vector view_changes; + explicit pbft_view_changed_certificate() = default; - public_key_type public_key; - signature_type producer_signature; + vector messages; + uint32_t view = 0; bool operator==(const pbft_view_changed_certificate &rhs) const { - return view == rhs.view - && view_changes == rhs.view_changes - && public_key == rhs.public_key; - } - - bool operator!=(const pbft_view_changed_certificate &rhs) const { - return !(*this == rhs); + return digest() == rhs.digest(); } digest_type digest() const { digest_type::encoder enc; fc::raw::pack(enc, view); - fc::raw::pack(enc, view_changes); - fc::raw::pack(enc, public_key); + fc::raw::pack(enc, messages); 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_new_view { - string uuid; - pbft_view_type view; - pbft_prepared_certificate prepared; - vector committed; - pbft_stable_checkpoint stable_checkpoint; - pbft_view_changed_certificate view_changed; - public_key_type public_key; - chain_id_type chain_id = chain_id_type(""); - signature_type producer_signature; - time_point timestamp = time_point::now(); + struct pbft_new_view final: public pbft_message { + explicit pbft_new_view() = default; - 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 - && chain_id == rhs.chain_id - && timestamp == rhs.timestamp; - } + pbft_view_type view = 0; + pbft_prepared_certificate prepared; + vector committed; + pbft_stable_checkpoint stable_checkpoint; + pbft_view_changed_certificate view_changed; - bool operator!=(const pbft_new_view &rhs) const { - return !(*this == rhs); + bool operator==(const pbft_new_view &rhs) const { + return digest() == rhs.digest(); } bool operator<(const pbft_new_view &rhs) const { return view < rhs.view; } - digest_type digest() const { + digest_type digest() const override { digest_type::encoder enc; fc::raw::pack(enc, view); fc::raw::pack(enc, prepared); @@ -415,44 +270,34 @@ namespace eosio { fc::raw::pack(enc, view_changed); fc::raw::pack(enc, public_key); fc::raw::pack(enc, chain_id); - fc::raw::pack(enc, timestamp); 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_state { - block_id_type block_id; - block_num_type block_num = 0; - vector prepares; - bool should_prepared = false; - vector commits; - bool should_committed = false; + block_id_type block_id; + block_num_type block_num = 0; + vector prepares; + bool should_prepared = false; + vector commits; + bool should_committed = false; }; - struct pbft_view_state { - pbft_view_type view; - vector view_changes; - bool should_view_changed = false; + struct pbft_view_change_state { + pbft_view_type view; + vector view_changes; + bool should_view_changed = false; }; struct pbft_checkpoint_state { - block_id_type block_id; - block_num_type block_num = 0; + block_id_type block_id; + block_num_type block_num = 0; vector checkpoints; - bool is_stable = false; + bool is_stable = false; }; using pbft_state_ptr = std::shared_ptr; - using pbft_view_state_ptr = std::shared_ptr; + using pbft_view_change_state_ptr = std::shared_ptr; using pbft_checkpoint_state_ptr = std::shared_ptr; struct by_block_id; @@ -500,19 +345,19 @@ namespace eosio { struct by_view; struct by_count_and_view; typedef multi_index_container< - pbft_view_state_ptr, + pbft_view_change_state_ptr, indexed_by< hashed_unique< tag, - member, + member, std::hash >, ordered_non_unique< tag, composite_key< - pbft_view_state, - member, - member + pbft_view_change_state, + member, + member >, composite_key_compare, greater<>> > @@ -580,13 +425,13 @@ namespace eosio { vector send_and_add_pbft_view_change( const vector &vcv = vector{}, - const vector &ppc = vector{}, - const vector> &pcc = vector>{}, + const pbft_prepared_certificate &ppc = pbft_prepared_certificate{}, + const vector &pcc = vector{}, pbft_view_type current_view = 0, pbft_view_type new_view = 1); pbft_new_view send_pbft_new_view( - const vector &vcc = vector{}, + const pbft_view_changed_certificate &vcc = pbft_view_changed_certificate{}, pbft_view_type current_view = 1); vector generate_and_add_pbft_checkpoint(); @@ -603,13 +448,11 @@ namespace eosio { pbft_view_type get_committed_view(); - chain_id_type chain_id(); - - vector generate_prepared_certificate(); + pbft_prepared_certificate generate_prepared_certificate(); - vector> generate_committed_certificate(); + vector generate_committed_certificate(); - vector generate_view_changed_certificate(pbft_view_type target_view); + pbft_view_changed_certificate generate_view_changed_certificate(pbft_view_type target_view); pbft_stable_checkpoint get_stable_checkpoint_by_id(const block_id_type &block_id); @@ -671,6 +514,7 @@ namespace eosio { pbft_state_multi_index_type pbft_state_index; pbft_view_state_multi_index_type view_state_index; pbft_checkpoint_state_multi_index_type checkpoint_index; + chain_id_type chain_id = chain_id_type(""); fc::path pbft_db_dir; fc::path checkpoints_dir; boost::uuids::random_generator uuid_generator; @@ -681,7 +525,7 @@ namespace eosio { bool is_valid_committed_certificate(const pbft_committed_certificate &certificate); - vector> fetch_fork_from(vector block_infos); + vector> fetch_fork_from(vector &block_infos); vector fetch_first_fork_from(vector &bi); @@ -710,20 +554,18 @@ namespace eosio { } /// namespace eosio::chain FC_REFLECT(eosio::chain::block_info, (block_id)(block_num)) -FC_REFLECT(eosio::chain::pbft_prepare, - (uuid)(view)(block_num)(block_id)(public_key)(chain_id)(producer_signature)(timestamp)) -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)(committed)(stable_checkpoint)(public_key)(chain_id)(producer_signature)(timestamp)) -FC_REFLECT(eosio::chain::pbft_new_view, - (uuid)(view)(prepared)(committed)(stable_checkpoint)(view_changed)(public_key)(chain_id)(producer_signature)(timestamp)) +FC_REFLECT(eosio::chain::pbft_message, (uuid)(public_key)(chain_id)(producer_signature)(timestamp)) +FC_REFLECT_DERIVED(eosio::chain::pbft_prepare, (eosio::chain::pbft_message), (view)(block_num)(block_id)) +FC_REFLECT_DERIVED(eosio::chain::pbft_commit, (eosio::chain::pbft_message), (view)(block_num)(block_id)) +FC_REFLECT_DERIVED(eosio::chain::pbft_view_change, (eosio::chain::pbft_message), (current_view)(target_view)(prepared)(committed)(stable_checkpoint)) +FC_REFLECT_DERIVED(eosio::chain::pbft_new_view, (eosio::chain::pbft_message), (view)(prepared)(committed)(stable_checkpoint)(view_changed)) +FC_REFLECT_DERIVED(eosio::chain::pbft_checkpoint, (eosio::chain::pbft_message), (block_num)(block_id)) +FC_REFLECT(eosio::chain::pbft_certificate, (block_num)(block_id)(messages)) +FC_REFLECT_DERIVED(eosio::chain::pbft_prepared_certificate, (eosio::chain::pbft_certificate), ) +FC_REFLECT_DERIVED(eosio::chain::pbft_committed_certificate,(eosio::chain::pbft_certificate), ) +FC_REFLECT(eosio::chain::pbft_view_changed_certificate, (view)(messages)) +FC_REFLECT_DERIVED(eosio::chain::pbft_stable_checkpoint, (eosio::chain::pbft_certificate), ) 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)) -FC_REFLECT(eosio::chain::pbft_stable_checkpoint, (block_num)(block_id)(checkpoints)(chain_id)) +FC_REFLECT(eosio::chain::pbft_view_change_state, (view)(view_changes)(should_view_changed)) FC_REFLECT(eosio::chain::pbft_checkpoint_state, (block_id)(block_num)(checkpoints)(is_stable)) FC_REFLECT(eosio::chain::pbft_view_state, (view)(view_changes)(should_view_changed)) \ No newline at end of file diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index cd35d5720dc..bdf0f718b4b 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -241,9 +241,9 @@ namespace eosio { } } - void psm_prepared_state::manually_set_view(psm_machine *m, const uint32_t ¤t_view) { - m->set_current_view(current_view); - m->set_target_view(current_view+1); + void psm_prepared_state::manually_set_view(psm_machine *m, const uint32_t &view) { + m->set_current_view(view); + m->set_target_view(view+1); m->transit_to_view_change_state(this); } @@ -320,9 +320,9 @@ namespace eosio { } } - void psm_committed_state::manually_set_view(psm_machine *m, const uint32_t ¤t_view) { - m->set_current_view(current_view); - m->set_target_view(current_view+1); + void psm_committed_state::manually_set_view(psm_machine *m, const uint32_t &view) { + m->set_current_view(view); + m->set_target_view(view+1); m->transit_to_view_change_state(this); } @@ -358,28 +358,7 @@ namespace eosio { pbft_db.add_pbft_view_change(e); - //if view_change >= 2f+1, calculate next primary, send new view if is primary - auto nv = m->get_target_view(); - if (pbft_db.should_new_view(nv) && pbft_db.is_new_primary(nv)) { - - m->set_view_changed_certificate(pbft_db.generate_view_changed_certificate(nv)); - - auto new_view = pbft_db.get_proposed_new_view_num(); - if (new_view != nv) return; - - auto nv_msg = pbft_db.send_pbft_new_view( - m->get_view_changed_certificate(), - new_view); - - if (nv_msg == pbft_new_view{}) return; - - try { - m->transit_to_new_view(nv_msg, this); - } catch(const fc::exception& ex) { - wlog("bad new view, ${s} ", ("s",ex.to_string())); - } - return; - } + m->maybe_new_view(this); } void psm_view_change_state::send_view_change(psm_machine *m, pbft_database &pbft_db) { @@ -393,28 +372,7 @@ namespace eosio { m->send_pbft_view_change(); - //if view_change >= 2f+1, calculate next primary, send new view if is primary - auto nv = m->get_target_view(); - if (pbft_db.should_new_view(nv) && pbft_db.is_new_primary(nv)) { - - m->set_view_changed_certificate(pbft_db.generate_view_changed_certificate(nv)); - - auto new_view = pbft_db.get_proposed_new_view_num(); - if (new_view != nv) return; - - auto nv_msg = pbft_db.send_pbft_new_view( - m->get_view_changed_certificate(), - new_view); - - if (nv_msg == pbft_new_view{}) return; - - try { - m->transit_to_new_view(nv_msg, this); - } catch(const fc::exception& ex) { - wlog("bad new view, ${s} ", ("s",ex.to_string())); - } - return; - } + m->maybe_new_view(this); } @@ -429,9 +387,9 @@ namespace eosio { } } - void psm_view_change_state::manually_set_view(psm_machine *m, const uint32_t ¤t_view) { - m->set_current_view(current_view); - m->set_target_view(current_view+1); + void psm_view_change_state::manually_set_view(psm_machine *m, const uint32_t &view) { + m->set_current_view(view); + m->set_target_view(view+1); m->transit_to_view_change_state(this); } @@ -476,11 +434,41 @@ namespace eosio { this->set_target_view_retries(0); this->set_current(new psm_view_change_state); - if (pbft_db.should_send_pbft_msg()) this->send_pbft_view_change(); - + if (pbft_db.should_send_pbft_msg()) { + this->send_pbft_view_change(); + auto nv = this->maybe_new_view(s); + if (nv) return; + } delete s; } + template + bool psm_machine::maybe_new_view(T const &s) { + //if view_change >= 2f+1, calculate next primary, send new view if is primary + auto nv = this->get_target_view(); + if (pbft_db.should_new_view(nv) && pbft_db.is_new_primary(nv)) { + + this->set_view_changed_certificate(pbft_db.generate_view_changed_certificate(nv)); + + auto new_view = pbft_db.get_proposed_new_view_num(); + if (new_view != nv) return false; + + auto nv_msg = pbft_db.send_pbft_new_view( + this->get_view_changed_certificate(), + new_view); + + if (nv_msg == pbft_new_view{}) return false; + + try { + this->transit_to_new_view(nv_msg, s); + return true; + } catch(const fc::exception& ex) { + wlog("bad new view, ${s} ", ("s",ex.to_string())); + } + } + return false; + } + template void psm_machine::transit_to_new_view(const pbft_new_view &new_view, T const &s) { @@ -503,7 +491,7 @@ namespace eosio { this->pbft_db.prune_pbft_index(); if (!(new_view.stable_checkpoint == pbft_stable_checkpoint{})) { - for (auto cp :new_view.stable_checkpoint.checkpoints) { + for (auto cp :new_view.stable_checkpoint.messages) { try { pbft_db.add_pbft_checkpoint(cp); } catch (...) { @@ -516,7 +504,7 @@ namespace eosio { auto committed_certs = new_view.committed; std::sort(committed_certs.begin(), committed_certs.end()); for (auto cp :committed_certs) { - for (auto c: cp.commits) { + for (auto c: cp.messages) { try { pbft_db.add_pbft_commit(c); } catch (...) { @@ -526,8 +514,8 @@ namespace eosio { } } - if (!new_view.prepared.prepares.empty()) { - for (auto p: new_view.prepared.prepares) { + if (!new_view.prepared.messages.empty()) { + for (auto p: new_view.prepared.messages) { try { pbft_db.add_pbft_prepare(p); } catch (...) { @@ -606,28 +594,27 @@ namespace eosio { this->current_view = cv; } - const vector &psm_machine::get_prepared_certificate() const { + const pbft_prepared_certificate &psm_machine::get_prepared_certificate() const { return this->cache.prepared_certificate; } - void psm_machine::set_prepared_certificate(const vector &pcert) { + void psm_machine::set_prepared_certificate(const pbft_prepared_certificate &pcert) { this->cache.prepared_certificate = pcert; } - const vector> &psm_machine::get_committed_certificate() const { + const vector &psm_machine::get_committed_certificate() const { return this->cache.committed_certificate; } - void psm_machine::set_committed_certificate(const vector> &ccert) { + void psm_machine::set_committed_certificate(const vector &ccert) { this->cache.committed_certificate = ccert; } - const vector &psm_machine::get_view_changed_certificate() const { + const pbft_view_changed_certificate &psm_machine::get_view_changed_certificate() const { return this->cache.view_changed_certificate; } - void psm_machine::set_view_changed_certificate( - const vector &vc_cert) { + void psm_machine::set_view_changed_certificate(const pbft_view_changed_certificate &vc_cert) { this->cache.view_changed_certificate = vc_cert; } diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 468ee4c579a..b65b9c10ac0 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -13,6 +13,7 @@ namespace eosio { prepare_watermarks = vector{}; pbft_db_dir = ctrl.state_dir(); checkpoints_dir = ctrl.blocks_dir(); + chain_id = ctrl.get_chain_id(); if (!fc::is_directory(pbft_db_dir)) fc::create_directories(pbft_db_dir); @@ -109,7 +110,7 @@ namespace eosio { auto curr_psp = make_shared(curr_ps); pbft_state_index.insert(curr_psp); } catch (...) { - wlog( "prepare insert failure: ${p}", ("p", p)); + elog( "prepare insert failure: ${p}", ("p", p)); } } else { auto prepares = (*curr_itr)->prepares; @@ -184,7 +185,8 @@ namespace eosio { for (auto const &sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); auto my_prepare_num = ctrl.fetch_block_state_by_id(my_prepare)->block_num; - auto p = pbft_prepare{uuid, current_view, my_prepare_num, my_prepare, sp.first, chain_id()}; + auto p = pbft_prepare{}; + p.uuid=uuid; p.view=current_view; p.block_num=my_prepare_num; p.block_id=my_prepare; p.public_key=sp.first; p.chain_id=chain_id; p.producer_signature = sp.second(p.digest()); emit(pbft_outgoing_prepare, p); new_pv.emplace_back(p); @@ -207,8 +209,8 @@ namespace eosio { for (auto const &sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); - auto p = pbft_prepare{uuid, current_view, high_watermark_block_num, hwbs->id, sp.first, - chain_id()}; + auto p = pbft_prepare{}; + p.uuid=uuid; p.view=current_view; p.block_num=high_watermark_block_num; p.block_id=hwbs->id; p.public_key=sp.first; p.chain_id=chain_id; p.producer_signature = sp.second(p.digest()); add_pbft_prepare(p); emit(pbft_outgoing_prepare, p); @@ -239,7 +241,7 @@ namespace eosio { } bool pbft_database::is_valid_prepare(const pbft_prepare &p) { - if (p.chain_id != chain_id()) return false; + if (p.chain_id != chain_id) return false; // a prepare msg under lscb (which is no longer in fork_db), can be treated as null, thus true. if (p.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; if (!p.is_signature_valid()) return false; @@ -263,7 +265,7 @@ namespace eosio { auto curr_psp = make_shared(curr_ps); pbft_state_index.insert(curr_psp); } catch (...) { - wlog("commit insertion failure: ${c}", ("c", c)); + elog("commit insertion failure: ${c}", ("c", c)); } } else { auto commits = (*curr_itr)->commits; @@ -338,7 +340,8 @@ namespace eosio { for (auto const &sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); - auto c = pbft_commit{uuid, current_view, psp->block_num, psp->block_id, sp.first, chain_id()}; + auto c = pbft_commit{}; + c.uuid=uuid; c.view=current_view; c.block_num=psp->block_num; c.block_id=psp->block_id; c.public_key=sp.first; c.chain_id=chain_id; c.producer_signature = sp.second(c.digest()); add_pbft_commit(c); emit(pbft_outgoing_commit, c); @@ -394,7 +397,7 @@ namespace eosio { } bool pbft_database::is_valid_commit(const pbft_commit &c) { - if (c.chain_id != chain_id()) return false; + if (c.chain_id != chain_id) return false; if (c.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; if (!c.is_signature_valid()) return false; return should_recv_pbft_msg(c.public_key); @@ -424,8 +427,8 @@ namespace eosio { auto &by_view_index = view_state_index.get(); auto itr = by_view_index.find(vc.target_view); if (itr == by_view_index.end()) { - auto vs = pbft_view_state{vc.target_view, .view_changes={vc}}; - auto vsp = make_shared(vs); + auto vs = pbft_view_change_state{vc.target_view, .view_changes={vc}}; + auto vsp = make_shared(vs); view_state_index.insert(vsp); } else { auto pvs = (*itr); @@ -435,7 +438,7 @@ namespace eosio { return existed.public_key == vc.public_key; }); if (p_itr == view_changes.end()) { - by_view_index.modify(itr, [&](const pbft_view_state_ptr &pvsp) { + by_view_index.modify(itr, [&](const pbft_view_change_state_ptr &pvsp) { pvsp->view_changes.emplace_back(vc); }); } @@ -452,7 +455,7 @@ namespace eosio { } } if (vc_count >= active_bps.size() * 2 / 3 + 1) { - by_view_index.modify(itr, [&](const pbft_view_state_ptr &pvsp) { pvsp->should_view_changed = true; }); + by_view_index.modify(itr, [&](const pbft_view_change_state_ptr &pvsp) { pvsp->should_view_changed = true; }); } } } @@ -485,8 +488,8 @@ namespace eosio { vector pbft_database::send_and_add_pbft_view_change( const vector &vcv, - const vector &ppc, - const vector> &pcc, + const pbft_prepared_certificate &ppc, + const vector &pcc, pbft_view_type current_view, pbft_view_type new_view) { if (!vcv.empty()) { @@ -503,25 +506,11 @@ namespace eosio { vector new_vcv; for (auto const &my_sp : ctrl.my_signature_providers()) { - auto ppc_ptr = find_if(ppc.begin(), ppc.end(), - [&](const pbft_prepared_certificate &v) { - return v.public_key == my_sp.first; - }); - - 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_pcc, my_lsc, my_sp.first, chain_id()}; + auto vc = pbft_view_change{}; + vc.uuid=uuid; vc.current_view=current_view; vc.target_view=new_view; vc.prepared=ppc; vc.committed=pcc; vc.stable_checkpoint=my_lsc; vc.public_key=my_sp.first; vc.chain_id=chain_id; vc.producer_signature = my_sp.second(vc.digest()); emit(pbft_outgoing_view_change, vc); add_pbft_view_change(vc); @@ -560,7 +549,7 @@ namespace eosio { } pbft_new_view pbft_database::send_pbft_new_view( - const vector &vcc, + const pbft_view_changed_certificate &vcc, pbft_view_type current_view) { auto primary_key = get_new_view_primary_key(current_view); @@ -570,16 +559,13 @@ namespace eosio { auto my_sps = ctrl.my_signature_providers(); auto sp_itr = my_sps.find(primary_key); - auto vcc_ptr = find_if(vcc.begin(), vcc.end(), - [&](const pbft_view_changed_certificate &v) { return v.public_key == primary_key; }); - - if (vcc_ptr == vcc.end()) return pbft_new_view{}; + if (vcc == pbft_view_changed_certificate{}) 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) { + for (const auto &vc: vcc.messages) { if (vc.prepared.block_num > highest_ppc.block_num && is_valid_prepared_certificate(vc.prepared)) { highest_ppc = vc.prepared; } @@ -600,69 +586,66 @@ namespace eosio { auto uuid = boost::uuids::to_string(uuid_generator()); - auto nv = pbft_new_view{uuid, current_view, highest_ppc, highest_pcc, highest_sc, *vcc_ptr, sp_itr->first, chain_id()}; + auto nv = pbft_new_view{}; + nv.uuid=uuid; nv.view=current_view; nv.prepared=highest_ppc; nv.committed=highest_pcc; nv.stable_checkpoint=highest_sc, nv.view_changed=vcc, nv.public_key=sp_itr->first; nv.chain_id=chain_id; nv.producer_signature = sp_itr->second(nv.digest()); emit(pbft_outgoing_new_view, nv); return nv; } - vector pbft_database::generate_prepared_certificate() { - auto ppc = vector{}; + pbft_prepared_certificate pbft_database::generate_prepared_certificate() { + const auto &by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); - if (itr == by_prepare_and_num_index.end()) return vector{}; + if (itr == by_prepare_and_num_index.end()) return pbft_prepared_certificate{}; pbft_state_ptr psp = *itr; auto prepared_block_state = ctrl.fetch_block_state_by_id(psp->block_id); - if (!prepared_block_state) return vector{}; + if (!prepared_block_state) return pbft_prepared_certificate{}; auto as = prepared_block_state->active_schedule.producers; if (psp->should_prepared && (psp->block_num > (ctrl.last_irreversible_block_num()))) { - for (auto const &my_sp : ctrl.my_signature_providers()) { - auto prepares = psp->prepares; - auto valid_prepares = vector{}; + auto prepares = psp->prepares; + auto valid_prepares = vector{}; - flat_map prepare_count; - flat_map> prepare_msg; + flat_map prepare_count; + flat_map> prepare_msg; - for (const auto &pre: prepares) { - if (prepare_count.find(pre.view) == prepare_count.end()) prepare_count[pre.view] = 0; - prepare_msg[pre.view].emplace_back(pre); - } + for (const auto &pre: prepares) { + if (prepare_count.find(pre.view) == prepare_count.end()) prepare_count[pre.view] = 0; + prepare_msg[pre.view].emplace_back(pre); + } - for (auto const &sp: as) { - for (auto const &pp: prepares) { - if (sp.block_signing_key == pp.public_key) prepare_count[pp.view] += 1; - } + for (auto const &sp: as) { + for (auto const &pp: prepares) { + if (sp.block_signing_key == pp.public_key) prepare_count[pp.view] += 1; } + } - for (auto const &e: prepare_count) { - if (e.second >= as.size() * 2 / 3 + 1) { - valid_prepares = prepare_msg[e.first]; - } + for (auto const &e: prepare_count) { + if (e.second >= as.size() * 2 / 3 + 1) { + valid_prepares = prepare_msg[e.first]; } + } - if (valid_prepares.empty()) return vector{}; + if (valid_prepares.empty()) return pbft_prepared_certificate{}; - auto pc = pbft_prepared_certificate{psp->block_id, psp->block_num, valid_prepares, my_sp.first}; - pc.producer_signature = my_sp.second(pc.digest()); - ppc.emplace_back(pc); - } - return ppc; - } else return vector{}; + auto pc = pbft_prepared_certificate{}; + pc.block_id=psp->block_id; pc.block_num=psp->block_num; pc.messages=valid_prepares; + return pc; + } else return pbft_prepared_certificate{}; } - vector> pbft_database::generate_committed_certificate() { - auto pcc = vector>{}; - pcc.resize(ctrl.my_signature_providers().size()); + vector pbft_database::generate_committed_certificate() { + 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>{}; + if (itr == by_commit_and_num_index.end()) return vector{}; pbft_state_ptr psp = *itr; - if (!psp->should_committed) return vector>{}; + if (!psp->should_committed) return vector{}; auto highest_committed_block_num = psp->block_num; @@ -681,13 +664,14 @@ namespace eosio { const auto &by_id_index = pbft_state_index.get(); + auto pcc = vector{}; for (const auto &committed_block_num: ccb) { auto cbs = ctrl.fetch_block_state_by_number(committed_block_num); - if (!cbs) return vector>{}; + if (!cbs) return vector{}; auto it = by_id_index.find(cbs->id); if (it == by_id_index.end() || !(*it)->should_committed) { - return vector>{}; + return vector{}; } auto as = cbs->active_schedule.producers; @@ -715,36 +699,30 @@ namespace eosio { } } - if (valid_commits.empty()) return vector>{}; + if (valid_commits.empty()) return vector{}; + + auto cc = pbft_committed_certificate{}; + cc.block_id=cbs->id; cc.block_num=cbs->block_num; cc.messages=valid_commits; + pcc.emplace_back(cc); + - 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; } - vector pbft_database::generate_view_changed_certificate(pbft_view_type target_view) { - auto vcc = vector{}; + pbft_view_changed_certificate pbft_database::generate_view_changed_certificate(pbft_view_type target_view) { auto &by_view_index = view_state_index.get(); auto itr = by_view_index.find(target_view); - if (itr == by_view_index.end()) return vcc; + if (itr == by_view_index.end()) return pbft_view_changed_certificate{}; auto pvs = *itr; if (pvs->should_view_changed) { - for (auto const &my_sp : ctrl.my_signature_providers()) { - auto pc = pbft_view_changed_certificate{pvs->view, pvs->view_changes, my_sp.first}; - pc.producer_signature = my_sp.second(pc.digest()); - vcc.emplace_back(pc); - } - return vcc; - } else return vector{}; + auto pvcc = pbft_view_changed_certificate{}; + pvcc.view=pvs->view; pvcc.messages=pvs->view_changes; + return pvcc; + } else return pbft_view_changed_certificate{}; } bool pbft_database::is_valid_prepared_certificate(const pbft_prepared_certificate &certificate) { @@ -754,8 +732,7 @@ namespace eosio { if (certificate.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; auto valid = true; - valid = valid && certificate.is_signature_valid(); - for (auto const &p : certificate.prepares) { + for (auto const &p : certificate.messages) { valid = valid && is_valid_prepare(p); if (!valid) return false; } @@ -768,7 +745,7 @@ namespace eosio { } auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; - auto prepares = certificate.prepares; + auto prepares = certificate.messages; flat_map prepare_count; for (const auto &pre: prepares) { @@ -795,7 +772,7 @@ namespace eosio { auto lscb = ctrl.last_stable_checkpoint_block_num(); auto non_fork_bp_count = 0; vector prepare_infos; - for (auto const &p : certificate.prepares) { + for (auto const &p : certificate.messages) { //only search in fork db if (p.block_num <= lscb) { ++non_fork_bp_count; @@ -814,8 +791,7 @@ namespace eosio { 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) { + for (auto const &c : certificate.messages) { valid = valid && is_valid_commit(c); if (!valid) return false; } @@ -828,7 +804,7 @@ namespace eosio { } auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; - auto commits = certificate.commits; + auto commits = certificate.messages; flat_map commit_count; for (const auto &pre: commits) { @@ -855,7 +831,7 @@ namespace eosio { auto lscb = ctrl.last_stable_checkpoint_block_num(); auto non_fork_bp_count = 0; vector commit_infos; - for (auto const &p : certificate.commits) { + for (auto const &p : certificate.messages) { //only search in fork db if (p.block_num <= lscb) { ++non_fork_bp_count; @@ -868,7 +844,7 @@ namespace eosio { } bool pbft_database::is_valid_view_change(const pbft_view_change &vc) { - if (vc.chain_id != chain_id()) return false; + if (vc.chain_id != chain_id) return false; return vc.is_signature_valid() && should_recv_pbft_msg(vc.public_key); @@ -879,7 +855,7 @@ namespace eosio { bool pbft_database::is_valid_new_view(const pbft_new_view &nv) { //all signatures should be valid - EOS_ASSERT(nv.chain_id == chain_id(), pbft_exception, "wrong chain."); + EOS_ASSERT(nv.chain_id == chain_id, pbft_exception, "wrong chain."); EOS_ASSERT(nv.is_signature_valid(), pbft_exception, "bad new view signature"); @@ -898,6 +874,7 @@ namespace eosio { EOS_ASSERT(nv.view_changed.is_signature_valid(), pbft_exception, "bad view changed signature"); + EOS_ASSERT(nv.is_signature_valid(), pbft_exception, "bad new view signature"); EOS_ASSERT(nv.view_changed.view == nv.view, pbft_exception, "target view not match"); @@ -909,7 +886,7 @@ namespace eosio { vector view_change_producers; - for (auto vc: nv.view_changed.view_changes) { + for (auto vc: nv.view_changed.messages) { if (is_valid_view_change(vc)) { add_pbft_view_change(vc); view_change_producers.emplace_back(vc.public_key); @@ -932,7 +909,7 @@ namespace eosio { auto highest_pcc = vector{}; auto highest_scp = pbft_stable_checkpoint{}; - for (const auto &vc: nv.view_changed.view_changes) { + for (const auto &vc: nv.view_changed.messages) { if (vc.prepared.block_num > highest_ppc.block_num && is_valid_prepared_certificate(vc.prepared)) { highest_ppc = vc.prepared; @@ -971,23 +948,22 @@ namespace eosio { && lscb_num > vc.stable_checkpoint.block_num; } - vector> pbft_database::fetch_fork_from(const vector block_infos) { - auto bi = block_infos; + vector> pbft_database::fetch_fork_from(vector &block_infos) { vector> result; - if (bi.empty()) { + if (block_infos.empty()) { return result; } - if (bi.size() == 1) { - result.emplace_back(initializer_list{bi.front()}); + if (block_infos.size() == 1) { + result.emplace_back(initializer_list{block_infos.front()}); return result; } - sort(bi.begin(), bi.end(), + sort(block_infos.begin(), block_infos.end(), [](const block_info &a, const block_info &b) -> bool { return a.block_num > b.block_num; }); - while (!bi.empty()) { - auto fork = fetch_first_fork_from(bi); + while (!block_infos.empty()) { + auto fork = fetch_first_fork_from(block_infos); if (!fork.empty()) { result.emplace_back(fork); } @@ -1085,7 +1061,7 @@ namespace eosio { } } } catch(...) { - wlog("no stable checkpoints found in the block extension"); + elog("no stable checkpoints found in the block extension"); } return pbft_stable_checkpoint{}; } @@ -1102,7 +1078,8 @@ namespace eosio { if (cpp->is_stable) { if (ctrl.my_signature_providers().empty()) return pbft_stable_checkpoint{}; - auto psc = pbft_stable_checkpoint{cpp->block_num, cpp->block_id, cpp->checkpoints, chain_id()}; + auto psc = pbft_stable_checkpoint{}; + psc.block_num=cpp->block_num; psc.block_id=cpp->block_id; psc.messages=cpp->checkpoints; psc.chain_id=chain_id; return psc; } else return pbft_stable_checkpoint{}; } @@ -1207,11 +1184,12 @@ namespace eosio { if (!pending_checkpoint_block_num.empty()) { std::sort(pending_checkpoint_block_num.begin(), pending_checkpoint_block_num.end()); - for (auto h: pending_checkpoint_block_num) { - if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(h)) { + for (auto bnum: pending_checkpoint_block_num) { + if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(bnum)) { for (auto const &my_sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); - auto cp = pbft_checkpoint{uuid, h, bs->id, my_sp.first, .chain_id=chain_id()}; + auto cp = pbft_checkpoint{}; + cp.uuid=uuid; cp.block_num=bnum; cp.block_id=bs->id; cp.public_key=my_sp.first; cp.chain_id=chain_id; cp.producer_signature = my_sp.second(cp.digest()); add_pbft_checkpoint(cp); new_pc.emplace_back(cp); @@ -1358,7 +1336,7 @@ namespace eosio { return true; auto valid = true; - for (const auto &c: scp.checkpoints) { + for (const auto &c: scp.messages) { valid = valid && is_valid_checkpoint(c) && c.block_id == scp.block_id && c.block_num == scp.block_num; @@ -1370,7 +1348,7 @@ namespace eosio { auto as = bs->active_schedule; auto cp_count = 0; for (auto const &sp: as.producers) { - for (auto const &v: scp.checkpoints) { + for (auto const &v: scp.messages) { if (sp.block_signing_key == v.public_key) cp_count += 1; } } @@ -1426,10 +1404,6 @@ namespace eosio { return bs->pending_schedule; } - chain_id_type pbft_database::chain_id() { - return ctrl.get_chain_id(); - } - block_num_type pbft_database::get_current_pbft_watermark() { update_fork_schedules(); auto lib = ctrl.last_irreversible_block_num(); diff --git a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp index 65b81583364..61a2a033d59 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp @@ -146,6 +146,11 @@ struct request_p2p_message{ bool discoverable; string p2p_peer_list; }; + + struct compressed_pbft_new_view { + std::shared_ptr > content; + }; + using net_message = static_variant; + checkpoint_request_message, + compressed_pbft_new_view>; + } // namespace eosio FC_REFLECT( eosio::select_ids, (mode)(pending)(ids) ) @@ -184,6 +191,7 @@ FC_REFLECT( eosio::sync_request_message, (start_block)(end_block) ) FC_REFLECT( eosio::request_p2p_message, (discoverable) ) FC_REFLECT( eosio::response_p2p_message, (discoverable)(p2p_peer_list) ) FC_REFLECT( eosio::checkpoint_request_message, (start_block)(end_block) ) +FC_REFLECT( eosio::compressed_pbft_new_view, (content)) /** diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 0e6ca0efb78..cfc48ca5445 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -28,6 +28,10 @@ #include +#include +#include +#include + using namespace eosio::chain::plugin_interface::compat; namespace fc { @@ -109,6 +113,8 @@ namespace eosio { }; class net_plugin_impl { private: + std::vector compress_pbft(const std::shared_ptr>& m)const; + std::vector decompress_pbft(const std::shared_ptr>& m)const; std::shared_ptr> encode_pbft_message(const net_message &msg)const; public: net_plugin_impl(); @@ -264,6 +270,7 @@ namespace eosio { 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_new_view &msg); void start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection); void start_txn_timer(); @@ -677,6 +684,7 @@ namespace eosio { bool trigger_send, go_away_reason close_after_send, bool to_sync_queue = false); void enqueue_pbft( const std::shared_ptr>& m, const time_point_sec deadline); + bool pbft_read_to_send(); void cancel_sync(go_away_reason); @@ -2035,6 +2043,51 @@ namespace eosio { } //------------------------------------------------------------------------ + + namespace bio = boost::iostreams; + template + struct read_limiter { + using char_type = char; + using category = bio::multichar_output_filter_tag; + + template + size_t write(Sink &sink, const char* s, size_t count) + { + EOS_ASSERT(_total + count <= Limit, tx_decompression_error, "Exceeded maximum decompressed transaction size"); + _total += count; + return bio::write(sink, s, count); + } + size_t _total = 0; + }; + + std::vector net_plugin_impl::compress_pbft(const std::shared_ptr>& m) const { + std::vector out; + bio::filtering_ostream comp; + comp.push(bio::zlib_compressor(bio::zlib::best_compression)); + comp.push(bio::back_inserter(out)); + bio::write(comp, m->data(), m->size()); + bio::close(comp); + return out; + } + + std::vector net_plugin_impl::decompress_pbft(const std::shared_ptr>& m) const { + try { + std::vector out; + bio::filtering_ostream decomp; + decomp.push(bio::zlib_decompressor()); + decomp.push(read_limiter<1*1024*1024>()); // limit to 10 megs decompressed for zip bomb protections + decomp.push(bio::back_inserter(out)); + bio::write(decomp, m->data(), m->size()); + bio::close(decomp); + return out; + } catch( fc::exception& er ) { + throw; + } catch( ... ) { + fc::unhandled_exception er( FC_LOG_MESSAGE( warn, "internal decompression error"), std::current_exception() ); + throw er; + } + } + std::shared_ptr> net_plugin_impl::encode_pbft_message(const net_message &msg) const { uint32_t payload_size = fc::raw::pack_size( msg ); @@ -2047,8 +2100,25 @@ namespace eosio { fc::datastream ds( send_buffer->data(), buffer_size); ds.write( header, header_size ); fc::raw::pack( ds, msg ); + auto out_buffer = send_buffer; + + if (msg.contains()) { + payload_size = fc::raw::pack_size( msg ); - return send_buffer; + header = reinterpret_cast(&payload_size); + header_size = sizeof(payload_size); + buffer_size = header_size + payload_size; + + auto compressed_buffer = std::make_shared>(buffer_size); + fc::datastream ds( compressed_buffer->data(), buffer_size); + ds.write( header, header_size ); + + auto compressed_msg = std::make_shared>(compress_pbft(send_buffer)); + auto cpnv = compressed_pbft_new_view{compressed_msg}; + fc::raw::pack( ds, &cpnv ); + out_buffer = compressed_buffer; + } + return out_buffer; } void net_plugin_impl::connect(const connection_ptr& c) { @@ -3081,6 +3151,17 @@ namespace eosio { pbft_incoming_new_view_channel.publish(msg); } + void net_plugin_impl::handle_message( connection_ptr c, const compressed_pbft_new_view &msg) { + + auto decompressed_new_view = decompress_pbft(msg.content); + + pbft_new_view nv; + fc::datastream ds(decompressed_new_view.data(), decompressed_new_view.size()); + fc::raw::unpack(ds, nv); + + handle_message(c, nv); + } + void net_plugin_impl::handle_message( connection_ptr c, const pbft_checkpoint &msg) { if (!is_pbft_msg_valid(msg)) return; @@ -3104,7 +3185,7 @@ namespace eosio { if (pcc.pbft_db.is_valid_stable_checkpoint(msg)) { fc_ilog(logger, "received stable checkpoint at ${n}, from ${v}", ("n", msg.block_num)("v", c->peer_name())); - for (auto cp: msg.checkpoints) { + for (auto cp: msg.messages) { pbft_incoming_checkpoint_channel.publish(cp); } } From 3b7068b6d3897e75bd7f4a057e8145f7114fb2e5 Mon Sep 17 00:00:00 2001 From: oldcold Date: Fri, 31 May 2019 18:26:33 +0800 Subject: [PATCH 13/22] fix bug in new view decompression. --- .../include/eosio/chain/pbft_database.hpp | 117 +++++++------- libraries/chain/pbft.cpp | 8 +- libraries/chain/pbft_database.cpp | 143 ++++++++---------- .../include/eosio/net_plugin/protocol.hpp | 6 +- plugins/net_plugin/net_plugin.cpp | 84 +++++----- .../include/eosio/pbft_plugin/pbft_plugin.hpp | 6 +- plugins/pbft_plugin/pbft_plugin.cpp | 4 +- 7 files changed, 182 insertions(+), 186 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 14f0c27620a..18d3c4b4b02 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -25,6 +25,14 @@ namespace eosio { struct block_info { block_id_type block_id; block_num_type block_num = 0; + + bool operator==(const block_info &rhs) const { + return block_id == rhs.block_id && block_num == rhs.block_num; + } + + bool operator!=(const block_info &rhs) const { + return !(*this == rhs); + } }; struct pbft_message { @@ -36,8 +44,10 @@ namespace eosio { virtual digest_type digest() const { digest_type::encoder enc; + fc::raw::pack(enc, uuid); fc::raw::pack(enc, public_key); fc::raw::pack(enc, chain_id); + fc::raw::pack(enc, timestamp); return enc.result(); } @@ -55,56 +65,57 @@ namespace eosio { struct pbft_prepare final: public pbft_message { explicit pbft_prepare() = default; - uint32_t view = 0; - block_num_type block_num = 0; - block_id_type block_id; + + pbft_view_type view = 0; + block_info block; bool operator==(const pbft_prepare &rhs) const { return digest() == rhs.digest(); } bool operator<(const pbft_prepare &rhs) const { - if (block_num < rhs.block_num) { + if (block.block_num < rhs.block.block_num) { return true; } else { - return block_num == rhs.block_num && view < rhs.view; + return block.block_num == rhs.block.block_num && view < rhs.view; } } digest_type digest() const override { digest_type::encoder enc; + fc::raw::pack(enc, uuid); fc::raw::pack(enc, view); - fc::raw::pack(enc, block_num); - fc::raw::pack(enc, block_id); + fc::raw::pack(enc, block); fc::raw::pack(enc, public_key); fc::raw::pack(enc, chain_id); + fc::raw::pack(enc, timestamp); return enc.result(); } }; struct pbft_commit final: public pbft_message { explicit pbft_commit() = default; - pbft_view_type view = 0; - block_num_type block_num = 0; - block_id_type block_id; + + pbft_view_type view = 0; + block_info block; bool operator==(const pbft_commit &rhs) const { return digest() == rhs.digest(); } bool operator<(const pbft_commit &rhs) const { - if (block_num < rhs.block_num) { + if (block.block_num < rhs.block.block_num) { return true; } else { - return block_num == rhs.block_num && view < rhs.view; + return block.block_num == rhs.block.block_num && view < rhs.view; } } digest_type digest() const override { digest_type::encoder enc; + fc::raw::pack(enc, uuid); fc::raw::pack(enc, view); - fc::raw::pack(enc, block_num); - fc::raw::pack(enc, block_id); + fc::raw::pack(enc, block); fc::raw::pack(enc, public_key); fc::raw::pack(enc, chain_id); fc::raw::pack(enc, timestamp); @@ -115,8 +126,7 @@ namespace eosio { struct pbft_checkpoint final: public pbft_message { explicit pbft_checkpoint() = default; - block_num_type block_num = 0; - block_id_type block_id; + block_info block; bool operator==(const pbft_checkpoint &rhs) const { return digest() == rhs.digest(); @@ -127,13 +137,13 @@ namespace eosio { } bool operator<(const pbft_checkpoint &rhs) const { - return block_num < rhs.block_num; + return block.block_num < rhs.block.block_num; } digest_type digest() const override { digest_type::encoder enc; - fc::raw::pack(enc, block_num); - fc::raw::pack(enc, block_id); + fc::raw::pack(enc, uuid); + fc::raw::pack(enc, block); fc::raw::pack(enc, public_key); fc::raw::pack(enc, chain_id); fc::raw::pack(enc, timestamp); @@ -142,19 +152,17 @@ namespace eosio { }; struct pbft_certificate { - block_num_type block_num = 0; - block_id_type block_id; + block_info block; vector messages; chain_id_type chain_id = chain_id_type(""); bool operator<(const pbft_certificate &rhs) const { - return block_num < rhs.block_num; + return block.block_num < rhs.block.block_num; } digest_type digest() const { digest_type::encoder enc; - fc::raw::pack(enc, block_num); - fc::raw::pack(enc, block_id); + fc::raw::pack(enc, block); fc::raw::pack(enc, messages); fc::raw::pack(enc, chain_id); return enc.result(); @@ -199,8 +207,8 @@ namespace eosio { struct pbft_view_change final: public pbft_message { explicit pbft_view_change() = default; - uint32_t current_view = 0; - uint32_t target_view = 1; + pbft_view_type current_view = 0; + pbft_view_type target_view = 1; pbft_prepared_certificate prepared; vector committed; pbft_stable_checkpoint stable_checkpoint; @@ -215,12 +223,14 @@ namespace eosio { digest_type digest() const override { digest_type::encoder enc; + fc::raw::pack(enc, uuid); 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, timestamp); fc::raw::pack(enc, chain_id); return enc.result(); } @@ -247,7 +257,7 @@ namespace eosio { struct pbft_new_view final: public pbft_message { explicit pbft_new_view() = default; - pbft_view_type view = 0; + pbft_view_type view = 0; pbft_prepared_certificate prepared; vector committed; pbft_stable_checkpoint stable_checkpoint; @@ -263,12 +273,14 @@ namespace eosio { digest_type digest() const override { digest_type::encoder enc; + fc::raw::pack(enc, uuid); 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); + fc::raw::pack(enc, timestamp); fc::raw::pack(enc, chain_id); return enc.result(); } @@ -284,7 +296,7 @@ namespace eosio { }; struct pbft_view_change_state { - pbft_view_type view; + pbft_view_type view; vector view_changes; bool should_view_changed = false; }; @@ -474,21 +486,6 @@ namespace eosio { bool is_valid_stable_checkpoint(const pbft_stable_checkpoint &scp); - 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; - bool is_valid_view_change(const pbft_view_change &vc); bool is_valid_new_view(const pbft_new_view &nv); @@ -499,7 +496,7 @@ namespace eosio { vector get_checkpoints_by_num(const block_num_type& num)const; - pbft_view_state_ptr get_view_changes_by_target_view(const pbft_view_type& tv)const; + pbft_view_change_state_ptr get_view_changes_by_target_view(const pbft_view_type& tv)const; vector get_pbft_watermarks()const; @@ -509,6 +506,21 @@ namespace eosio { void update_fork_schedules(); + 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; + private: controller &ctrl; pbft_state_multi_index_type pbft_state_index; @@ -555,17 +567,16 @@ namespace eosio { FC_REFLECT(eosio::chain::block_info, (block_id)(block_num)) FC_REFLECT(eosio::chain::pbft_message, (uuid)(public_key)(chain_id)(producer_signature)(timestamp)) -FC_REFLECT_DERIVED(eosio::chain::pbft_prepare, (eosio::chain::pbft_message), (view)(block_num)(block_id)) -FC_REFLECT_DERIVED(eosio::chain::pbft_commit, (eosio::chain::pbft_message), (view)(block_num)(block_id)) +FC_REFLECT_DERIVED(eosio::chain::pbft_prepare, (eosio::chain::pbft_message), (view)(block)) +FC_REFLECT_DERIVED(eosio::chain::pbft_commit, (eosio::chain::pbft_message), (view)(block)) FC_REFLECT_DERIVED(eosio::chain::pbft_view_change, (eosio::chain::pbft_message), (current_view)(target_view)(prepared)(committed)(stable_checkpoint)) FC_REFLECT_DERIVED(eosio::chain::pbft_new_view, (eosio::chain::pbft_message), (view)(prepared)(committed)(stable_checkpoint)(view_changed)) -FC_REFLECT_DERIVED(eosio::chain::pbft_checkpoint, (eosio::chain::pbft_message), (block_num)(block_id)) -FC_REFLECT(eosio::chain::pbft_certificate, (block_num)(block_id)(messages)) -FC_REFLECT_DERIVED(eosio::chain::pbft_prepared_certificate, (eosio::chain::pbft_certificate), ) -FC_REFLECT_DERIVED(eosio::chain::pbft_committed_certificate,(eosio::chain::pbft_certificate), ) +FC_REFLECT_DERIVED(eosio::chain::pbft_checkpoint, (eosio::chain::pbft_message), (block)) +FC_REFLECT(eosio::chain::pbft_certificate, (block)(messages)) +FC_REFLECT_DERIVED(eosio::chain::pbft_prepared_certificate, (eosio::chain::pbft_certificate), (messages)) +FC_REFLECT_DERIVED(eosio::chain::pbft_committed_certificate,(eosio::chain::pbft_certificate), (messages)) FC_REFLECT(eosio::chain::pbft_view_changed_certificate, (view)(messages)) -FC_REFLECT_DERIVED(eosio::chain::pbft_stable_checkpoint, (eosio::chain::pbft_certificate), ) +FC_REFLECT_DERIVED(eosio::chain::pbft_stable_checkpoint, (eosio::chain::pbft_certificate), (messages)) FC_REFLECT(eosio::chain::pbft_state, (block_id)(block_num)(prepares)(should_prepared)(commits)(should_committed)) FC_REFLECT(eosio::chain::pbft_view_change_state, (view)(view_changes)(should_view_changed)) -FC_REFLECT(eosio::chain::pbft_checkpoint_state, (block_id)(block_num)(checkpoints)(is_stable)) -FC_REFLECT(eosio::chain::pbft_view_state, (view)(view_changes)(should_view_changed)) \ No newline at end of file +FC_REFLECT(eosio::chain::pbft_checkpoint_state, (block_id)(block_num)(checkpoints)(is_stable)) \ No newline at end of file diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index bdf0f718b4b..e5ed158f04a 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -105,9 +105,9 @@ namespace eosio { this->set_commits_cache(vector{}); this->set_view_changes_cache(vector{}); - this->set_prepared_certificate(vector{}); - this->set_committed_certificate(vector>{}); - this->set_view_changed_certificate(vector{}); + this->set_prepared_certificate(pbft_prepared_certificate{}); + this->set_committed_certificate(vector{}); + this->set_view_changed_certificate(pbft_view_changed_certificate{}); this->view_change_timer = 0; this->target_view_retries = 0; @@ -187,7 +187,6 @@ namespace eosio { if (pending_commit_local && !pbft_db.pending_pbft_lib()) { pbft_db.send_pbft_checkpoint(); - dlog("pending pbft lib has been applied, transit to committed state now.."); m->transit_to_committed_state(this, false); } } @@ -207,7 +206,6 @@ namespace eosio { if (pending_commit_local && !pbft_db.pending_pbft_lib()) { pbft_db.send_pbft_checkpoint(); - dlog("pending pbft lib has been applied, transit to committed state now.."); m->transit_to_committed_state(this, false); } } diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index b65b9c10ac0..5e9a2a8c5ab 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -99,7 +99,7 @@ namespace eosio { auto &by_block_id_index = pbft_state_index.get(); - auto current = ctrl.fetch_block_state_by_id(p.block_id); + auto current = ctrl.fetch_block_state_by_id(p.block.block_id); while ((current) && (current->block_num > ctrl.last_irreversible_block_num())) { auto curr_itr = by_block_id_index.find(current->id); @@ -126,10 +126,7 @@ namespace eosio { } } curr_itr = by_block_id_index.find(current->id); - if (curr_itr == by_block_id_index.end()) { - dlog( "block id ${id} cannot be found", ("id", current->id)); - return; - } + if (curr_itr == by_block_id_index.end()) return; auto prepares = (*curr_itr)->prepares; auto as = current->active_schedule.producers; @@ -185,8 +182,8 @@ namespace eosio { for (auto const &sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); auto my_prepare_num = ctrl.fetch_block_state_by_id(my_prepare)->block_num; - auto p = pbft_prepare{}; - p.uuid=uuid; p.view=current_view; p.block_num=my_prepare_num; p.block_id=my_prepare; p.public_key=sp.first; p.chain_id=chain_id; + pbft_prepare p; + p.uuid=uuid; p.view=current_view; p.block={my_prepare, my_prepare_num}; p.public_key=sp.first; p.chain_id=chain_id; p.producer_signature = sp.second(p.digest()); emit(pbft_outgoing_prepare, p); new_pv.emplace_back(p); @@ -209,14 +206,14 @@ namespace eosio { for (auto const &sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); - auto p = pbft_prepare{}; - p.uuid=uuid; p.view=current_view; p.block_num=high_watermark_block_num; p.block_id=hwbs->id; p.public_key=sp.first; p.chain_id=chain_id; + pbft_prepare p; + p.uuid=uuid; p.view=current_view; p.block={hwbs->id, high_watermark_block_num}; p.public_key=sp.first; p.chain_id=chain_id; p.producer_signature = sp.second(p.digest()); add_pbft_prepare(p); emit(pbft_outgoing_prepare, p); new_pv.emplace_back(p); - ctrl.set_pbft_my_prepare(hwbs->id); } + ctrl.set_pbft_my_prepare(hwbs->id); } return new_pv; } @@ -243,7 +240,7 @@ namespace eosio { bool pbft_database::is_valid_prepare(const pbft_prepare &p) { if (p.chain_id != chain_id) return false; // a prepare msg under lscb (which is no longer in fork_db), can be treated as null, thus true. - if (p.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; + if (p.block.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; if (!p.is_signature_valid()) return false; return should_recv_pbft_msg(p.public_key); } @@ -253,7 +250,7 @@ namespace eosio { if (!is_valid_commit(c)) return; auto &by_block_id_index = pbft_state_index.get(); - auto current = ctrl.fetch_block_state_by_id(c.block_id); + auto current = ctrl.fetch_block_state_by_id(c.block.block_id); while ((current) && (current->block_num > ctrl.last_irreversible_block_num())) { @@ -282,10 +279,7 @@ namespace eosio { } curr_itr = by_block_id_index.find(current->id); - if (curr_itr == by_block_id_index.end()) { - dlog( "block id ${id} cannot be found", ("id", current->id)); - return; - } + if (curr_itr == by_block_id_index.end()) return; auto commits = (*curr_itr)->commits; @@ -330,7 +324,6 @@ namespace eosio { auto itr = by_prepare_and_num_index.begin(); if (itr == by_prepare_and_num_index.end()) return vector{}; - pbft_state_ptr psp = *itr; auto bs = ctrl.fork_db().get_block(psp->block_id); if (!bs) return vector{}; @@ -340,8 +333,8 @@ namespace eosio { for (auto const &sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); - auto c = pbft_commit{}; - c.uuid=uuid; c.view=current_view; c.block_num=psp->block_num; c.block_id=psp->block_id; c.public_key=sp.first; c.chain_id=chain_id; + pbft_commit c; + c.uuid=uuid; c.view=current_view; c.block={psp->block_id, psp->block_num}; c.public_key=sp.first; c.chain_id=chain_id; c.producer_signature = sp.second(c.digest()); add_pbft_commit(c); emit(pbft_outgoing_commit, c); @@ -398,7 +391,7 @@ namespace eosio { bool pbft_database::is_valid_commit(const pbft_commit &c) { if (c.chain_id != chain_id) return false; - if (c.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; + if (c.block.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; if (!c.is_signature_valid()) return false; return should_recv_pbft_msg(c.public_key); } @@ -406,10 +399,7 @@ namespace eosio { void pbft_database::commit_local() { 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()) { - dlog( "no block to be committed local"); - return; - } + if (itr == by_commit_and_num_index.end()) return; pbft_state_ptr psp = *itr; @@ -509,7 +499,7 @@ namespace eosio { 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{}; + pbft_view_change vc; vc.uuid=uuid; vc.current_view=current_view; vc.target_view=new_view; vc.prepared=ppc; vc.committed=pcc; vc.stable_checkpoint=my_lsc; vc.public_key=my_sp.first; vc.chain_id=chain_id; vc.producer_signature = my_sp.second(vc.digest()); emit(pbft_outgoing_view_change, vc); @@ -566,19 +556,19 @@ namespace eosio { auto highest_sc = pbft_stable_checkpoint{}; for (const auto &vc: vcc.messages) { - if (vc.prepared.block_num > highest_ppc.block_num && is_valid_prepared_certificate(vc.prepared)) { + if (vc.prepared.block.block_num > highest_ppc.block.block_num && is_valid_prepared_certificate(vc.prepared)) { 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; }); + [&](const pbft_committed_certificate &ext) { return ext.block.block_id == cc.block.block_id; }); if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); } } - if (vc.stable_checkpoint.block_num > highest_sc.block_num && + if (vc.stable_checkpoint.block.block_num > highest_sc.block.block_num && is_valid_stable_checkpoint(vc.stable_checkpoint)) { highest_sc = vc.stable_checkpoint; } @@ -586,7 +576,7 @@ namespace eosio { auto uuid = boost::uuids::to_string(uuid_generator()); - auto nv = pbft_new_view{}; + pbft_new_view nv; nv.uuid=uuid; nv.view=current_view; nv.prepared=highest_ppc; nv.committed=highest_pcc; nv.stable_checkpoint=highest_sc, nv.view_changed=vcc, nv.public_key=sp_itr->first; nv.chain_id=chain_id; nv.producer_signature = sp_itr->second(nv.digest()); @@ -632,7 +622,7 @@ namespace eosio { if (valid_prepares.empty()) return pbft_prepared_certificate{}; auto pc = pbft_prepared_certificate{}; - pc.block_id=psp->block_id; pc.block_num=psp->block_num; pc.messages=valid_prepares; + pc.block.block_id=psp->block_id; pc.block.block_num=psp->block_num; pc.messages=valid_prepares; return pc; } else return pbft_prepared_certificate{}; } @@ -702,7 +692,7 @@ namespace eosio { if (valid_commits.empty()) return vector{}; auto cc = pbft_committed_certificate{}; - cc.block_id=cbs->id; cc.block_num=cbs->block_num; cc.messages=valid_commits; + cc.block.block_id=cbs->id; cc.block.block_num=cbs->block_num; cc.messages=valid_commits; pcc.emplace_back(cc); @@ -729,7 +719,7 @@ namespace eosio { // 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. - if (certificate.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; + if (certificate.block.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; auto valid = true; for (auto const &p : certificate.messages) { @@ -737,10 +727,10 @@ namespace eosio { if (!valid) return false; } - auto cert_id = certificate.block_id; + auto cert_id = certificate.block.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) { + if (certificate.block.block_num > 0 && cert_bs) { producer_schedule = cert_bs->active_schedule; } auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; @@ -774,21 +764,20 @@ namespace eosio { vector prepare_infos; for (auto const &p : certificate.messages) { //only search in fork db - if (p.block_num <= lscb) { + if (p.block.block_num <= lscb) { ++non_fork_bp_count; } else { - prepare_infos.emplace_back(block_info{p.block_id, p.block_num}); + prepare_infos.emplace_back(p.block); } } - 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); + return is_valid_longest_fork(certificate.block, prepare_infos, bp_threshold, non_fork_bp_count); } 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; + if (certificate.block.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; auto valid = true; for (auto const &c : certificate.messages) { @@ -796,10 +785,10 @@ namespace eosio { if (!valid) return false; } - auto cert_id = certificate.block_id; + auto cert_id = certificate.block.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) { + if (certificate.block.block_num > 0 && cert_bs) { producer_schedule = cert_bs->active_schedule; } auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; @@ -833,14 +822,13 @@ namespace eosio { vector commit_infos; for (auto const &p : certificate.messages) { //only search in fork db - if (p.block_num <= lscb) { + if (p.block.block_num <= lscb) { ++non_fork_bp_count; } else { - commit_infos.emplace_back(block_info{p.block_id, p.block_num}); + commit_infos.emplace_back(p.block); } } - 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); + return is_valid_longest_fork(certificate.block, commit_infos, bp_threshold, non_fork_bp_count); } bool pbft_database::is_valid_view_change(const pbft_view_change &vc) { @@ -868,12 +856,9 @@ namespace eosio { "bad stable checkpoint: ${scp}", ("scp", nv.stable_checkpoint)); for (auto const &c: nv.committed) { - EOS_ASSERT(is_valid_committed_certificate(c), pbft_exception, - "bad committed certificate: ${cc}", ("cc", c)); + EOS_ASSERT(is_valid_committed_certificate(c), pbft_exception, "bad committed certificate: ${cc}", ("cc", c)); } - EOS_ASSERT(nv.view_changed.is_signature_valid(), pbft_exception, "bad view changed signature"); - EOS_ASSERT(nv.is_signature_valid(), pbft_exception, "bad new view signature"); EOS_ASSERT(nv.view_changed.view == nv.view, pbft_exception, "target view not match"); @@ -910,7 +895,7 @@ namespace eosio { auto highest_scp = pbft_stable_checkpoint{}; for (const auto &vc: nv.view_changed.messages) { - if (vc.prepared.block_num > highest_ppc.block_num + if (vc.prepared.block.block_num > highest_ppc.block.block_num && is_valid_prepared_certificate(vc.prepared)) { highest_ppc = vc.prepared; } @@ -918,12 +903,12 @@ namespace eosio { 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; }); + [&](const pbft_committed_certificate &ext) { return ext.block.block_id == cc.block.block_id; }); if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); } } - if (vc.stable_checkpoint.block_num > highest_scp.block_num + if (vc.stable_checkpoint.block.block_num > highest_scp.block.block_num && is_valid_stable_checkpoint(vc.stable_checkpoint)) { highest_scp = vc.stable_checkpoint; } @@ -944,8 +929,8 @@ namespace eosio { bool pbft_database::should_stop_view_change(const pbft_view_change &vc) { auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - return lscb_num > vc.prepared.block_num - && lscb_num > vc.stable_checkpoint.block_num; + return lscb_num > vc.prepared.block.block_num + && lscb_num > vc.stable_checkpoint.block.block_num; } vector> pbft_database::fetch_fork_from(vector &block_infos) { @@ -1078,8 +1063,8 @@ namespace eosio { if (cpp->is_stable) { if (ctrl.my_signature_providers().empty()) return pbft_stable_checkpoint{}; - auto psc = pbft_stable_checkpoint{}; - psc.block_num=cpp->block_num; psc.block_id=cpp->block_id; psc.messages=cpp->checkpoints; psc.chain_id=chain_id; + pbft_stable_checkpoint psc; + psc.block={cpp->block_id, cpp->block_num}; psc.messages=cpp->checkpoints; psc.chain_id=chain_id; return psc; } else return pbft_stable_checkpoint{}; } @@ -1188,8 +1173,8 @@ namespace eosio { if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(bnum)) { for (auto const &my_sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); - auto cp = pbft_checkpoint{}; - cp.uuid=uuid; cp.block_num=bnum; cp.block_id=bs->id; cp.public_key=my_sp.first; cp.chain_id=chain_id; + pbft_checkpoint cp; + cp.uuid=uuid; cp.block={bs->id, bnum}; cp.public_key=my_sp.first; cp.chain_id=chain_id; cp.producer_signature = my_sp.second(cp.digest()); add_pbft_checkpoint(cp); new_pc.emplace_back(cp); @@ -1224,7 +1209,7 @@ namespace eosio { if (!is_valid_checkpoint(cp)) return; - auto cp_block_state = ctrl.fetch_block_state_by_id(cp.block_id); + auto cp_block_state = ctrl.fetch_block_state_by_id(cp.block.block_id); if (!cp_block_state) return; auto active_bps = cp_block_state->active_schedule.producers; auto checkpoint_count = count_if(active_bps.begin(), active_bps.end(), [&](const producer_key &p) { @@ -1233,12 +1218,12 @@ namespace eosio { if (checkpoint_count == 0) return; auto &by_block = checkpoint_index.get(); - auto itr = by_block.find(cp.block_id); + auto itr = by_block.find(cp.block.block_id); if (itr == by_block.end()) { - auto cs = pbft_checkpoint_state{cp.block_id, cp.block_num, .checkpoints={cp}}; + auto cs = pbft_checkpoint_state{cp.block.block_id, cp.block.block_num, .checkpoints={cp}}; auto csp = make_shared(cs); checkpoint_index.insert(csp); - itr = by_block.find(cp.block_id); + itr = by_block.find(cp.block.block_id); } else { auto csp = (*itr); auto checkpoints = csp->checkpoints; @@ -1303,23 +1288,23 @@ namespace eosio { prune(*pitr); } } - // auto &bni = checkpoint_index.get(); - // auto oldest = bni.begin(); - // if (oldest != bni.end() && lscb_num - (*oldest)->block_num > 10000) { - // auto it = bni.lower_bound(lscb_num - 10000); - // if (it != bni.end() && (*it)->is_stable) { - // prune_checkpoints(*it); - // } - // } + auto &bni = checkpoint_index.get(); + auto oldest = bni.begin(); + if (oldest != bni.end() && lscb_num - (*oldest)->block_num > 10000) { + auto it = bni.lower_bound(lscb_num - 10000); + if (it != bni.end() && (*it)->is_stable) { + prune_checkpoints(*it); + } + } } bool pbft_database::is_valid_checkpoint(const pbft_checkpoint &cp) { - if (cp.block_num > ctrl.head_block_num() - || cp.block_num <= ctrl.last_stable_checkpoint_block_num() + if (cp.block.block_num > ctrl.head_block_num() + || cp.block.block_num <= ctrl.last_stable_checkpoint_block_num() || !cp.is_signature_valid()) return false; - auto bs = ctrl.fetch_block_state_by_id(cp.block_id); + auto bs = ctrl.fetch_block_state_by_id(cp.block.block_id); if (bs) { auto active_bps = bs->active_schedule.producers; for (const auto &bp: active_bps) { @@ -1330,20 +1315,18 @@ namespace eosio { } bool pbft_database::is_valid_stable_checkpoint(const pbft_stable_checkpoint &scp) { - if (scp.block_num <= ctrl.last_stable_checkpoint_block_num()) + if (scp.block.block_num <= ctrl.last_stable_checkpoint_block_num()) // the stable checkpoint is way behind lib, no way getting the block state, // it will not be applied nor saved, thus considered safe. return true; auto valid = true; for (const auto &c: scp.messages) { - valid = valid && is_valid_checkpoint(c) - && c.block_id == scp.block_id - && c.block_num == scp.block_num; + valid = valid && is_valid_checkpoint(c) && c.block == scp.block; if (!valid) return false; } - auto bs = ctrl.fetch_block_state_by_number(scp.block_num); + auto bs = ctrl.fetch_block_state_by_number(scp.block.block_num); if (bs) { auto as = bs->active_schedule; auto cp_count = 0; @@ -1493,13 +1476,13 @@ namespace eosio { return results; } - pbft_view_state_ptr pbft_database::get_view_changes_by_target_view(const pbft_view_type& tv) const { + pbft_view_change_state_ptr pbft_database::get_view_changes_by_target_view(const pbft_view_type& tv) const { auto &by_view_index = view_state_index.get(); auto itr = by_view_index.find(tv); if (itr != by_view_index.end()) return (*itr); - return pbft_view_state_ptr{}; + return pbft_view_change_state_ptr{}; } vector pbft_database::get_pbft_watermarks() const { diff --git a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp index 61a2a033d59..fdb39c847de 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp @@ -147,7 +147,7 @@ struct request_p2p_message{ string p2p_peer_list; }; - struct compressed_pbft_new_view { + struct compressed_pbft_message { std::shared_ptr > content; }; @@ -169,7 +169,7 @@ struct request_p2p_message{ pbft_checkpoint, pbft_stable_checkpoint, checkpoint_request_message, - compressed_pbft_new_view>; + compressed_pbft_message>; } // namespace eosio @@ -191,7 +191,7 @@ FC_REFLECT( eosio::sync_request_message, (start_block)(end_block) ) FC_REFLECT( eosio::request_p2p_message, (discoverable) ) FC_REFLECT( eosio::response_p2p_message, (discoverable)(p2p_peer_list) ) FC_REFLECT( eosio::checkpoint_request_message, (start_block)(end_block) ) -FC_REFLECT( eosio::compressed_pbft_new_view, (content)) +FC_REFLECT( eosio::compressed_pbft_message, (content)) /** diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index cfc48ca5445..434956c9561 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -115,7 +115,7 @@ namespace eosio { private: std::vector compress_pbft(const std::shared_ptr>& m)const; std::vector decompress_pbft(const std::shared_ptr>& m)const; - std::shared_ptr> encode_pbft_message(const net_message &msg)const; + std::shared_ptr> encode_pbft_message(const net_message &msg, bool compress = false)const; public: net_plugin_impl(); @@ -246,8 +246,8 @@ namespace eosio { void handle_message( connection_ptr c, const response_p2p_message &msg); //pbft messages - bool maybe_add_pbft_cache(const string &uuid); - void clean_expired_pbft_cache(); + bool maybe_add_to_pbft_cache(const string &uuid); + void clean_expired_pbft_messages(); template bool is_pbft_msg_outdated(M const & msg); template @@ -270,7 +270,7 @@ namespace eosio { 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_new_view &msg); + void handle_message( 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(); @@ -2088,7 +2088,7 @@ namespace eosio { } } - std::shared_ptr> net_plugin_impl::encode_pbft_message(const net_message &msg) const { + std::shared_ptr> net_plugin_impl::encode_pbft_message(const net_message &msg, bool compress) const { uint32_t payload_size = fc::raw::pack_size( msg ); @@ -2102,8 +2102,10 @@ namespace eosio { fc::raw::pack( ds, msg ); auto out_buffer = send_buffer; - if (msg.contains()) { - payload_size = fc::raw::pack_size( msg ); + if (compress) { + auto compressed_msg = std::make_shared>(compress_pbft(send_buffer)); + auto cpnv = compressed_pbft_message{compressed_msg}; + payload_size = fc::raw::pack_size( cpnv ); header = reinterpret_cast(&payload_size); header_size = sizeof(payload_size); @@ -2112,9 +2114,6 @@ namespace eosio { auto compressed_buffer = std::make_shared>(buffer_size); fc::datastream ds( compressed_buffer->data(), buffer_size); ds.write( header, header_size ); - - auto compressed_msg = std::make_shared>(compress_pbft(send_buffer)); - auto cpnv = compressed_pbft_new_view{compressed_msg}; fc::raw::pack( ds, &cpnv ); out_buffer = compressed_buffer; } @@ -3010,61 +3009,61 @@ namespace eosio { } void net_plugin_impl::pbft_outgoing_prepare(const pbft_prepare &msg) { - auto added = maybe_add_pbft_cache(msg.uuid); + auto added = maybe_add_to_pbft_cache(msg.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_prepare(msg)) return; bcast_pbft_msg(msg, pbft_message_TTL); - fc_ilog( logger, "sent prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_num)("v", msg.view)("k", msg.public_key)); + fc_dlog( logger, "sent prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block.block_num)("v", msg.view)("k", msg.public_key)); } void net_plugin_impl::pbft_outgoing_commit(const pbft_commit &msg) { - auto added = maybe_add_pbft_cache(msg.uuid); + auto added = maybe_add_to_pbft_cache(msg.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_commit(msg)) return; bcast_pbft_msg(msg, pbft_message_TTL); - fc_ilog( logger, "sent commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_num)("v", msg.view)("k", msg.public_key)); + fc_dlog( logger, "sent commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block.block_num)("v", msg.view)("k", msg.public_key)); } void net_plugin_impl::pbft_outgoing_view_change(const pbft_view_change &msg) { - auto added = maybe_add_pbft_cache(msg.uuid); + auto added = maybe_add_to_pbft_cache(msg.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_view_change(msg)) return; bcast_pbft_msg(msg, pbft_message_TTL); - fc_ilog( logger, "sent view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", msg.current_view)("tv", msg.target_view)("v", msg.public_key)); + fc_dlog( logger, "sent view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", msg.current_view)("tv", msg.target_view)("v", msg.public_key)); } void net_plugin_impl::pbft_outgoing_new_view(const pbft_new_view &msg) { - auto added = maybe_add_pbft_cache(msg.uuid); + auto added = maybe_add_to_pbft_cache(msg.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_new_view(msg)) return; bcast_pbft_msg(msg, INT_MAX); - fc_ilog( logger, "sent new view at view: ${v}, from ${k}, ", ("v", msg.view)("k", msg.public_key)); + fc_dlog( logger, "sent new view at view: ${v}, from ${k}, ", ("v", msg.view)("k", msg.public_key)); } void net_plugin_impl::pbft_outgoing_checkpoint(const pbft_checkpoint &msg) { - auto added = maybe_add_pbft_cache(msg.uuid); + auto added = maybe_add_to_pbft_cache(msg.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_checkpoint(msg)) return; bcast_pbft_msg(msg, pbft_message_TTL); - fc_ilog( logger, "sent checkpoint at height: ${n}, from ${k}, ", ("n", msg.block_num)("k", msg.public_key)); + fc_dlog( logger, "sent checkpoint at height: ${n}, from ${k}, ", ("n", msg.block.block_num)("k", msg.public_key)); } - bool net_plugin_impl::maybe_add_pbft_cache(const string &uuid){ + bool net_plugin_impl::maybe_add_to_pbft_cache(const string &uuid){ auto itr = pbft_message_cache.find(uuid); if (itr == pbft_message_cache.end()) { //add to cache @@ -3074,7 +3073,7 @@ namespace eosio { return false; } - void net_plugin_impl::clean_expired_pbft_cache(){ + void net_plugin_impl::clean_expired_pbft_messages(){ auto itr = pbft_message_cache.begin(); auto now = time_point::now(); @@ -3090,14 +3089,14 @@ namespace eosio { if (!is_pbft_msg_valid(msg)) return; - auto added = maybe_add_pbft_cache(msg.uuid); + auto added = maybe_add_to_pbft_cache(msg.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_prepare(msg)) return; forward_pbft_msg(c, msg, pbft_message_TTL); - fc_ilog( logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_num)("v", msg.view)("k", msg.public_key)); + fc_dlog( logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block.block_num)("v", msg.view)("k", msg.public_key)); pbft_incoming_prepare_channel.publish(msg); @@ -3107,14 +3106,14 @@ namespace eosio { if (!is_pbft_msg_valid(msg)) return; - auto added = maybe_add_pbft_cache(msg.uuid); + auto added = maybe_add_to_pbft_cache(msg.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_commit(msg)) return; forward_pbft_msg(c, msg, pbft_message_TTL); - fc_ilog( logger, "received commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_num)("v", msg.view)("k", msg.public_key)); + fc_dlog( logger, "received commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block.block_num)("v", msg.view)("k", msg.public_key)); pbft_incoming_commit_channel.publish(msg); } @@ -3123,14 +3122,14 @@ namespace eosio { if (!is_pbft_msg_valid(msg)) return; - auto added = maybe_add_pbft_cache(msg.uuid); + auto added = maybe_add_to_pbft_cache(msg.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_view_change(msg)) return; forward_pbft_msg(c, msg, pbft_message_TTL); - fc_ilog( logger, "received view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", msg.current_view)("tv", msg.target_view)("v", msg.public_key)); + fc_dlog( logger, "received view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", msg.current_view)("tv", msg.target_view)("v", msg.public_key)); pbft_incoming_view_change_channel.publish(msg); } @@ -3139,41 +3138,46 @@ namespace eosio { if (chain_id != msg.chain_id) return; - auto added = maybe_add_pbft_cache(msg.uuid); + auto added = maybe_add_to_pbft_cache(msg.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!(msg.public_key == pcc.pbft_db.get_new_view_primary_key(msg.view) && msg.is_signature_valid())) return; forward_pbft_msg(c, msg, INT_MAX); - fc_ilog( logger, "received new view: ${n}, from ${v}", ("n", msg)("v", msg.public_key)); + fc_dlog( logger, "received new view: ${n}, from ${v}", ("n", msg)("v", msg.public_key)); pbft_incoming_new_view_channel.publish(msg); } - void net_plugin_impl::handle_message( connection_ptr c, const compressed_pbft_new_view &msg) { + void net_plugin_impl::handle_message( connection_ptr c, const compressed_pbft_message &msg) { - auto decompressed_new_view = decompress_pbft(msg.content); + auto decompressed_msg = decompress_pbft(msg.content); - pbft_new_view nv; - fc::datastream ds(decompressed_new_view.data(), decompressed_new_view.size()); - fc::raw::unpack(ds, nv); + net_message message; + fc::datastream ds(decompressed_msg.data(), decompressed_msg.size()); + fc::raw::unpack(ds, message); - handle_message(c, nv); + try { + msg_handler m(*this, c); + message.visit( m ); + } catch( const fc::exception& e ) { + edump((e.to_detail_string() )); + } } void net_plugin_impl::handle_message( connection_ptr c, const pbft_checkpoint &msg) { if (!is_pbft_msg_valid(msg)) return; - auto added = maybe_add_pbft_cache(msg.uuid); + auto added = maybe_add_to_pbft_cache(msg.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_checkpoint(msg)) return; forward_pbft_msg(c, msg, pbft_message_TTL); - fc_ilog( logger, "received checkpoint at ${n}, from ${v}", ("n", msg.block_num)("v", msg.public_key)); + fc_dlog( logger, "received checkpoint at ${n}, from ${v}", ("n", msg.block.block_num)("v", msg.public_key)); pbft_incoming_checkpoint_channel.publish(msg); } @@ -3184,7 +3188,7 @@ namespace eosio { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (pcc.pbft_db.is_valid_stable_checkpoint(msg)) { - fc_ilog(logger, "received stable checkpoint at ${n}, from ${v}", ("n", msg.block_num)("v", c->peer_name())); + fc_ilog(logger, "received stable checkpoint at ${n}, from ${v}", ("n", msg.block.block_num)("v", c->peer_name())); for (auto cp: msg.messages) { pbft_incoming_checkpoint_channel.publish(cp); } @@ -3224,7 +3228,7 @@ namespace eosio { if (ec) { wlog ("pbft message cache ticker error: ${m}", ("m", ec.message())); } - clean_expired_pbft_cache(); + clean_expired_pbft_messages(); }); } diff --git a/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp b/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp index b28702c00c0..7208d198366 100644 --- a/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp +++ b/plugins/pbft_plugin/include/eosio/pbft_plugin/pbft_plugin.hpp @@ -22,19 +22,19 @@ class pbft_plugin : public appbase::plugin { void plugin_initialize(const variables_map& options); void plugin_startup(); - void plugin_shutdown(); + static void plugin_shutdown(); pbft_state get_pbft_record( const block_id_type& bid )const; vector get_pbft_checkpoints_record(const block_num_type &bnum)const; - pbft_view_state get_view_change_record(const pbft_view_type& view)const; + pbft_view_change_state get_view_change_record(const pbft_view_type& view)const; vector get_watermarks()const; flat_map get_fork_schedules()const; const char* get_pbft_status()const; block_id_type get_pbft_prepared_id()const; block_id_type get_pbft_my_prepare_id()const; - void set_pbft_current_view(pbft_view_type view); + static void set_pbft_current_view(pbft_view_type view); private: diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index b3554ddfe70..d320d31526a 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -73,11 +73,11 @@ namespace eosio { if (!records.empty()) return records; return vector(); } - pbft_view_state pbft_plugin::get_view_change_record(const pbft_view_type& view) const { + pbft_view_change_state pbft_plugin::get_view_change_record(const pbft_view_type& view) const { pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); auto record = pbft_ctrl.pbft_db.get_view_changes_by_target_view(view); if (record) return *record; - return pbft_view_state(); + return pbft_view_change_state(); } vector pbft_plugin::get_watermarks() const { From fd444d25fc0b5667fa8d09561576ae56ad2c03ea Mon Sep 17 00:00:00 2001 From: oldcold Date: Mon, 3 Jun 2019 00:59:08 +0800 Subject: [PATCH 14/22] optimise scp sync; move upo creation into `update_pbft_status`; --- libraries/chain/controller.cpp | 56 +++++++++++++------------------ plugins/net_plugin/net_plugin.cpp | 35 +++++++++++++------ 2 files changed, 49 insertions(+), 42 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 41a39099b5e..75b6c0fad79 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -360,7 +360,7 @@ struct controller_impl { read_from_snapshot( snapshot ); //do upgrade migration if necessary; - migrate_upgrade(); //compatiable for snapshot integrity test + update_pbft_status(); //compatiable for snapshot integrity test auto end = blog.read_head(); if( !end ) { @@ -375,7 +375,7 @@ struct controller_impl { } } else { //do upgrade migration if necessary; - migrate_upgrade(); //compatiable for snapshot integrity test + update_pbft_status(); //compatiable for snapshot integrity test if( !head ) { initialize_fork_db(); // set head to genesis state } @@ -426,43 +426,35 @@ struct controller_impl { //*bos end* } - void migrate_upgrade() { - //generate upo. - try { - db.get(); - if (pbft_enabled) wlog("pbft enabled"); - } catch( const boost::exception& e) { - wlog("no upo found, generating..."); - db.create([](auto&){}); - } - update_pbft_status(); - } - void update_pbft_status() { - 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; + try { + 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; - }); - if (!replaying) wlog("pbft will be working after the block ${b}", ("b", head->block_num)); - } + if (utb && !ucb && head->dpos_irreversible_blocknum >= *utb) { + db.modify( upo, [&]( auto& up ) { + up.upgrade_complete_block_num = head->block_num; + }); + if (!replaying) wlog("pbft will be working after the block ${b}", ("b", head->block_num)); + } - if ( !pbft_enabled && utb && head->block_num >= *utb) { - if (!pbft_upgrading) pbft_upgrading = true; + 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) { + // 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; - } - } + } + } + } catch( const boost::exception& e) { + wlog("no upo found, generating..."); + db.create([](auto&){}); + } } ~controller_impl() { diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 0e6ca0efb78..7deb80cd407 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -389,6 +389,8 @@ namespace eosio { constexpr uint16_t net_version = proto_explicit_sync; + constexpr uint16_t pbft_checkpoint_granularity = 100; + struct transaction_state { transaction_id_type id; uint32_t block_num = 0; ///< the block number the transaction was included in @@ -684,7 +686,6 @@ namespace eosio { bool enqueue_sync_block(); void request_sync_blocks(uint32_t start, uint32_t end); - void request_sync_checkpoints(uint32_t start, uint32_t end); void cancel_wait(); void sync_wait(); void fetch_wait(); @@ -783,6 +784,7 @@ namespace eosio { uint32_t sync_last_requested_num; uint32_t sync_next_expected_num; uint32_t sync_req_span; + uint32_t last_req_scp_num; connection_ptr source; stages state; @@ -807,6 +809,7 @@ namespace eosio { void recv_notice(const connection_ptr& c, const notice_message& msg); bool is_syncing(); void set_in_sync(); + void sync_stable_checkpoints(const connection_ptr& c, uint32_t target); }; class dispatch_manager { @@ -1371,13 +1374,6 @@ namespace eosio { sync_wait(); } - void connection::request_sync_checkpoints(uint32_t start, uint32_t end) { - fc_dlog(logger, "request sync checkpoints"); - checkpoint_request_message crm = {start,end}; - enqueue( net_message(crm)); - sync_wait(); - } - bool connection::process_next_message(net_plugin_impl& impl, uint32_t message_length) { try { auto ds = pending_message_buffer.create_datastream(); @@ -1604,6 +1600,22 @@ namespace eosio { request_next_chunk(c); } + void sync_manager::sync_stable_checkpoints(const connection_ptr& c, uint32_t target) { + controller& cc = chain_plug->chain(); + uint32_t lscb_num = cc.last_stable_checkpoint_block_num(); + if (last_req_scp_num < lscb_num || last_req_scp_num == 0) last_req_scp_num = lscb_num; + auto end = target; + auto max_target_scp_num = last_req_scp_num + pbft_checkpoint_granularity * 10; + if (target > max_target_scp_num) end = max_target_scp_num; + + checkpoint_request_message crm = {last_req_scp_num+1,end}; + c->enqueue( net_message(crm)); + fc_dlog(logger, "request sync stable checkpoints from ${s} to ${e}", + ("s", last_req_scp_num+1)("e", max_target_scp_num)); + last_req_scp_num = max_target_scp_num; + c->sync_wait(); + } + void sync_manager::reassign_fetch(const connection_ptr& c, go_away_reason reason) { fc_ilog(logger, "reassign_fetch, our last req is ${cc}, next expected is ${ne} peer ${p}", ( "cc",sync_last_requested_num)("ne",sync_next_expected_num)("p",c->peer_name())); @@ -1638,10 +1650,13 @@ namespace eosio { uint32_t head = cc.fork_db_head_block_num(); block_id_type head_id = cc.fork_db_head_block_id(); auto upgraded = cc.is_pbft_enabled(); - if (peer_lib > lscb_num && upgraded) { + if (upgraded + && peer_lib > lscb_num + && head - lscb_num >= pbft_checkpoint_granularity * 2) + { //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"); - c->request_sync_checkpoints(lscb_num, peer_lib); + sync_stable_checkpoints(c, peer_lib); } if (head_id == msg.head_id) { From a63265fe5b016f6164d3a19480d9cf1a72795ba2 Mon Sep 17 00:00:00 2001 From: oldcold Date: Mon, 3 Jun 2019 19:22:35 +0800 Subject: [PATCH 15/22] fix bug in loading old version snapshots. --- libraries/chain/include/eosio/chain/snapshot.hpp | 1 + libraries/chain/pbft_database.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/chain/include/eosio/chain/snapshot.hpp b/libraries/chain/include/eosio/chain/snapshot.hpp index 52b986510bd..b1a3a44892f 100644 --- a/libraries/chain/include/eosio/chain/snapshot.hpp +++ b/libraries/chain/include/eosio/chain/snapshot.hpp @@ -239,6 +239,7 @@ namespace eosio { namespace chain { fc::raw::unpack(tmp_ds, data); auto original_data_length = tmp_ds.tellp() - 4; in.seekg(original_data_length); + data.pbft_stable_checkpoint_blocknum = 0; }else{ fc::raw::unpack(in, data); } diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 468ee4c579a..78357ecdc29 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -1436,9 +1436,11 @@ namespace eosio { if (prepare_watermarks.empty()) return 0; - auto cw = *std::upper_bound(prepare_watermarks.begin(), prepare_watermarks.end(), lib); + auto cw = std::upper_bound(prepare_watermarks.begin(), prepare_watermarks.end(), lib); - if (cw > lib) return cw; else return 0; + if (cw == prepare_watermarks.end() || *cw <= lib) return 0; + + return *cw; } void pbft_database::update_fork_schedules() { From 45ad108f563ca54394d7f645a5745f279f45b33e Mon Sep 17 00:00:00 2001 From: oldcold Date: Tue, 4 Jun 2019 20:07:29 +0800 Subject: [PATCH 16/22] add message_type in pbft messages; refactor code. --- libraries/chain/include/eosio/chain/pbft.hpp | 110 ++--- .../include/eosio/chain/pbft_database.hpp | 450 ++++++++++-------- libraries/chain/pbft.cpp | 327 ++++++------- libraries/chain/pbft_database.cpp | 261 +++++----- plugins/chain_plugin/chain_plugin.cpp | 4 +- plugins/net_plugin/net_plugin.cpp | 54 +-- plugins/pbft_plugin/pbft_plugin.cpp | 4 +- unittests/pbft_tests.cpp | 34 ++ 8 files changed, 664 insertions(+), 580 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index 885b3c4a201..cb397b61a9a 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -1,3 +1,5 @@ +#include + #pragma once #include @@ -18,19 +20,21 @@ namespace eosio { pbft_view_changed_certificate view_changed_certificate; }; - class psm_machine { - class psm_state *current; + class psm_state; + using psm_state_ptr = std::shared_ptr; + + class psm_machine : public std::enable_shared_from_this { public: explicit psm_machine(pbft_database& pbft_db); ~psm_machine(); - void set_current(psm_state *s) { - current = s; + void set_current(psm_state_ptr s) { + current = std::move(s); } - psm_state* get_current() { - return this->current; + psm_state_ptr get_current() { + return current; } void on_prepare(pbft_prepare &e); @@ -44,22 +48,17 @@ namespace eosio { void on_new_view(pbft_new_view &e); - template - void transit_to_committed_state(T const & s, bool to_new_view); + void transit_to_committed_state(psm_state_ptr s, bool to_new_view); - template - void transit_to_prepared_state(T const & s); + void transit_to_prepared_state(psm_state_ptr s); void send_pbft_view_change(); - template - void transit_to_view_change_state(T const & s); + void transit_to_view_change_state(psm_state_ptr s); - template - bool maybe_new_view(T const & s); + bool maybe_new_view(psm_state_ptr s); - template - void transit_to_new_view(const pbft_new_view &new_view, T const &s); + void transit_to_new_view(const pbft_new_view &new_view, psm_state_ptr s); const vector &get_prepares_cache() const; @@ -111,34 +110,35 @@ namespace eosio { uint32_t view_change_timer; private: + psm_state_ptr current; pbft_database &pbft_db; - }; - class psm_state { + using psm_machine_ptr = std::shared_ptr; + + class psm_state : public std::enable_shared_from_this { public: psm_state(); ~psm_state(); - virtual void on_prepare(psm_machine *m, pbft_prepare &e, pbft_database &pbft_db) = 0; + virtual void on_prepare(psm_machine_ptr m, pbft_prepare &e, pbft_database &pbft_db) = 0; - virtual void send_prepare(psm_machine *m, pbft_database &pbft_db) = 0; + virtual void send_prepare(psm_machine_ptr m, pbft_database &pbft_db) = 0; - virtual void on_commit(psm_machine *m, pbft_commit &e, pbft_database &pbft_db) = 0; + virtual void on_commit(psm_machine_ptr m, pbft_commit &e, pbft_database &pbft_db) = 0; - virtual void send_commit(psm_machine *m, pbft_database &pbft_db) = 0; + virtual void send_commit(psm_machine_ptr m, pbft_database &pbft_db) = 0; - virtual void on_view_change(psm_machine *m, pbft_view_change &e, pbft_database &pbft_db) = 0; + virtual void on_view_change(psm_machine_ptr m, pbft_view_change &e, pbft_database &pbft_db) = 0; - virtual void send_view_change(psm_machine *m, pbft_database &pbft_db) = 0; + virtual void send_view_change(psm_machine_ptr m, pbft_database &pbft_db) = 0; - virtual void on_new_view(psm_machine *m, pbft_new_view &e, pbft_database &pbft_db) = 0; - - virtual void manually_set_view(psm_machine *m, const uint32_t &view) = 0; + virtual void on_new_view(psm_machine_ptr m, pbft_new_view &e, pbft_database &pbft_db) = 0; virtual const char* get_name() = 0; + std::shared_ptr get_self() { return shared_from_this(); }; }; class psm_prepared_state final: public psm_state { @@ -147,25 +147,23 @@ namespace eosio { psm_prepared_state(); ~psm_prepared_state(); - void on_prepare(psm_machine *m, pbft_prepare &e, pbft_database &pbft_db) override; - - void send_prepare(psm_machine *m, pbft_database &pbft_db) override; + void on_prepare(psm_machine_ptr m, pbft_prepare &e, pbft_database &pbft_db) override; - void on_commit(psm_machine *m, pbft_commit &e, pbft_database &pbft_db) override; + void send_prepare(psm_machine_ptr m, pbft_database &pbft_db) override; - void send_commit(psm_machine *m, pbft_database &pbft_db) override; + void on_commit(psm_machine_ptr m, pbft_commit &e, pbft_database &pbft_db) override; - void on_view_change(psm_machine *m, pbft_view_change &e, pbft_database &pbft_db) override; + void send_commit(psm_machine_ptr m, pbft_database &pbft_db) override; - void send_view_change(psm_machine *m, pbft_database &pbft_db) override; + void on_view_change(psm_machine_ptr m, pbft_view_change &e, pbft_database &pbft_db) override; - void on_new_view(psm_machine *m, pbft_new_view &e, pbft_database &pbft_db) override; + void send_view_change(psm_machine_ptr m, pbft_database &pbft_db) override; - void manually_set_view(psm_machine *m, const uint32_t &view) override; + void on_new_view(psm_machine_ptr m, pbft_new_view &e, pbft_database &pbft_db) override; bool pending_commit_local; - const char* get_name() override { return "prepared"; } + const char* get_name() override { return "{==== PREPARED ====}"; } }; class psm_committed_state final: public psm_state { @@ -173,44 +171,40 @@ namespace eosio { psm_committed_state(); ~psm_committed_state(); - void on_prepare(psm_machine *m, pbft_prepare &e, pbft_database &pbft_db) override; + void on_prepare(psm_machine_ptr m, pbft_prepare &e, pbft_database &pbft_db) override; - void send_prepare(psm_machine *m, pbft_database &pbft_db) override; + void send_prepare(psm_machine_ptr m, pbft_database &pbft_db) override; - void on_commit(psm_machine *m, pbft_commit &e, pbft_database &pbft_db) override; + void on_commit(psm_machine_ptr m, pbft_commit &e, pbft_database &pbft_db) override; - void send_commit(psm_machine *m, pbft_database &pbft_db) override; + void send_commit(psm_machine_ptr m, pbft_database &pbft_db) override; - void on_view_change(psm_machine *m, pbft_view_change &e, pbft_database &pbft_db) override; + void on_view_change(psm_machine_ptr m, pbft_view_change &e, pbft_database &pbft_db) override; - void send_view_change(psm_machine *m, pbft_database &pbft_db) override; + void send_view_change(psm_machine_ptr m, pbft_database &pbft_db) override; - void on_new_view(psm_machine *m, pbft_new_view &e, pbft_database &pbft_db) override; + void on_new_view(psm_machine_ptr m, pbft_new_view &e, pbft_database &pbft_db) override; - void manually_set_view(psm_machine *m, const uint32_t &view) override; - - const char* get_name() override { return "committed"; } + const char* get_name() override { return "{==== COMMITTED ====}"; } }; class psm_view_change_state final: public psm_state { public: - void on_prepare(psm_machine *m, pbft_prepare &e, pbft_database &pbft_db) override; - - void send_prepare(psm_machine *m, pbft_database &pbft_db) override; + void on_prepare(psm_machine_ptr m, pbft_prepare &e, pbft_database &pbft_db) override; - void on_commit(psm_machine *m, pbft_commit &e, pbft_database &pbft_db) override; + void send_prepare(psm_machine_ptr m, pbft_database &pbft_db) override; - void send_commit(psm_machine *m, pbft_database &pbft_db) override; + void on_commit(psm_machine_ptr m, pbft_commit &e, pbft_database &pbft_db) override; - void on_view_change(psm_machine *m, pbft_view_change &e, pbft_database &pbft_db) override; + void send_commit(psm_machine_ptr m, pbft_database &pbft_db) override; - void send_view_change(psm_machine *m, pbft_database &pbft_db) override; + void on_view_change(psm_machine_ptr m, pbft_view_change &e, pbft_database &pbft_db) override; - void on_new_view(psm_machine *m, pbft_new_view &e, pbft_database &pbft_db) override; + void send_view_change(psm_machine_ptr m, pbft_database &pbft_db) override; - void manually_set_view(psm_machine *m, const uint32_t &view) override; + void on_new_view(psm_machine_ptr m, pbft_new_view &e, pbft_database &pbft_db) override; - const char* get_name() override { return "view change"; } + const char* get_name() override { return "{==== VIEW CHANGE ====}"; } }; struct pbft_config { @@ -224,7 +218,7 @@ namespace eosio { ~pbft_controller(); pbft_database pbft_db; - psm_machine state_machine; + std::shared_ptr state_machine; pbft_config config; void maybe_pbft_prepare(); diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 18d3c4b4b02..fcbd8fcaba8 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -22,114 +22,140 @@ namespace eosio { using pbft_view_type = uint32_t; - struct block_info { + enum class pbft_message_type : uint16_t { + prepare, + commit, + checkpoint, + view_change, + new_view + }; + + struct block_info_type { block_id_type block_id; block_num_type block_num = 0; - bool operator==(const block_info &rhs) const { + bool operator==(const block_info_type &rhs) const { return block_id == rhs.block_id && block_num == rhs.block_num; } - bool operator!=(const block_info &rhs) const { + bool operator!=(const block_info_type &rhs) const { return !(*this == rhs); } }; - struct pbft_message { - string uuid; + struct pbft_message_header { + explicit pbft_message_header(const pbft_message_type t) {type = t;} + + pbft_message_type type; + string uuid; public_key_type public_key; - chain_id_type chain_id = chain_id_type(""); - signature_type producer_signature; - time_point timestamp = time_point::now(); + chain_id_type chain_id = chain_id_type(""); + time_point timestamp = time_point::now(); - virtual digest_type digest() const { - digest_type::encoder enc; - fc::raw::pack(enc, uuid); - fc::raw::pack(enc, public_key); - fc::raw::pack(enc, chain_id); - fc::raw::pack(enc, timestamp); - return enc.result(); - } - virtual 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; - } + bool operator==(const pbft_message_header &rhs) const { + return type == rhs.type + && chain_id == rhs.chain_id + && public_key == rhs.public_key; } - virtual ~pbft_message() = default; + ~pbft_message_header() = default; }; - struct pbft_prepare final: public pbft_message { + struct pbft_prepare { explicit pbft_prepare() = default; - pbft_view_type view = 0; - block_info block; + pbft_message_header msg_header = pbft_message_header(pbft_message_type::prepare); + pbft_view_type view = 0; + block_info_type block_info; + signature_type producer_signature; bool operator==(const pbft_prepare &rhs) const { - return digest() == rhs.digest(); + return msg_header == rhs.msg_header + && view == rhs.view + && block_info == rhs.block_info; } bool operator<(const pbft_prepare &rhs) const { - if (block.block_num < rhs.block.block_num) { + if (block_info.block_num < rhs.block_info.block_num) { return true; + } else if (block_info.block_num == rhs.block_info.block_num) { + return view < rhs.view; } else { - return block.block_num == rhs.block.block_num && view < rhs.view; + return false; } } - digest_type digest() const override { + digest_type digest() const { digest_type::encoder enc; - fc::raw::pack(enc, uuid); + fc::raw::pack(enc, msg_header); fc::raw::pack(enc, view); - fc::raw::pack(enc, block); - fc::raw::pack(enc, public_key); - fc::raw::pack(enc, chain_id); - fc::raw::pack(enc, timestamp); + fc::raw::pack(enc, block_info); return enc.result(); } + + bool is_signature_valid() const { + try { + auto pk = crypto::public_key(producer_signature, digest(), true); + return msg_header.public_key == pk; + } catch (fc::exception & /*e*/) { + return false; + } + } }; - struct pbft_commit final: public pbft_message { + struct pbft_commit { explicit pbft_commit() = default; - pbft_view_type view = 0; - block_info block; + pbft_message_header msg_header = pbft_message_header(pbft_message_type::commit); + pbft_view_type view = 0; + block_info_type block_info; + signature_type producer_signature; bool operator==(const pbft_commit &rhs) const { - return digest() == rhs.digest(); + return msg_header == rhs.msg_header + && view == rhs.view + && block_info == rhs.block_info; } bool operator<(const pbft_commit &rhs) const { - if (block.block_num < rhs.block.block_num) { + if (block_info.block_num < rhs.block_info.block_num) { return true; + } else if (block_info.block_num == rhs.block_info.block_num) { + return view < rhs.view; } else { - return block.block_num == rhs.block.block_num && view < rhs.view; + return false; } } - digest_type digest() const override { + digest_type digest() const { digest_type::encoder enc; - fc::raw::pack(enc, uuid); + fc::raw::pack(enc, msg_header); fc::raw::pack(enc, view); - fc::raw::pack(enc, block); - fc::raw::pack(enc, public_key); - fc::raw::pack(enc, chain_id); - fc::raw::pack(enc, timestamp); + fc::raw::pack(enc, block_info); return enc.result(); } + + bool is_signature_valid() const { + try { + auto pk = crypto::public_key(producer_signature, digest(), true); + return msg_header.public_key == pk; + } catch (fc::exception & /*e*/) { + return false; + } + } }; - struct pbft_checkpoint final: public pbft_message { + struct pbft_checkpoint { explicit pbft_checkpoint() = default; - block_info block; + pbft_message_header msg_header = pbft_message_header(pbft_message_type::checkpoint); + block_info_type block_info; + signature_type producer_signature; bool operator==(const pbft_checkpoint &rhs) const { - return digest() == rhs.digest(); + return msg_header == rhs.msg_header + && block_info == rhs.block_info; } bool operator!=(const pbft_checkpoint &rhs) const { @@ -137,175 +163,222 @@ namespace eosio { } bool operator<(const pbft_checkpoint &rhs) const { - return block.block_num < rhs.block.block_num; + return block_info.block_num < rhs.block_info.block_num; } - digest_type digest() const override { + digest_type digest() const { digest_type::encoder enc; - fc::raw::pack(enc, uuid); - fc::raw::pack(enc, block); - fc::raw::pack(enc, public_key); - fc::raw::pack(enc, chain_id); - fc::raw::pack(enc, timestamp); + fc::raw::pack(enc, msg_header); + fc::raw::pack(enc, block_info); return enc.result(); } - }; - - struct pbft_certificate { - block_info block; - vector messages; - chain_id_type chain_id = chain_id_type(""); - - bool operator<(const pbft_certificate &rhs) const { - return block.block_num < rhs.block.block_num; - } - digest_type digest() const { - digest_type::encoder enc; - fc::raw::pack(enc, block); - fc::raw::pack(enc, messages); - fc::raw::pack(enc, chain_id); - return enc.result(); + bool is_signature_valid() const { + try { + auto pk = crypto::public_key(producer_signature, digest(), true); + return msg_header.public_key == pk; + } catch (fc::exception & /*e*/) { + return false; + } } }; - struct pbft_stable_checkpoint final: public pbft_certificate { + struct pbft_stable_checkpoint { explicit pbft_stable_checkpoint() = default; - vector messages; + block_info_type block_info; + vector checkpoints; + //TODO: should contains chain id? bool operator==(const pbft_stable_checkpoint &rhs) const { - return digest() == rhs.digest(); + return block_info == rhs.block_info + && checkpoints == rhs.checkpoints; + } + + bool operator<(const pbft_stable_checkpoint &rhs) const { + return block_info.block_num < rhs.block_info.block_num; } bool operator!=(const pbft_stable_checkpoint &rhs) const { return !(*this == rhs); } + + bool empty() const { + return (*this == pbft_stable_checkpoint()); + } }; - struct pbft_prepared_certificate final: public pbft_certificate { + struct pbft_prepared_certificate { explicit pbft_prepared_certificate() = default; - vector messages; + block_info_type block_info; + vector prepares; bool operator==(const pbft_prepared_certificate &rhs) const { - return digest() == rhs.digest(); + return block_info == rhs.block_info; + //TODO: should compare messages? + } + + bool operator<(const pbft_prepared_certificate &rhs) const { + return block_info.block_num < rhs.block_info.block_num; + } + + bool empty() const { + return (*this == pbft_prepared_certificate()); } }; - struct pbft_committed_certificate final: public pbft_certificate { + struct pbft_committed_certificate { explicit pbft_committed_certificate() = default; - vector messages; + block_info_type block_info; + vector commits; bool operator==(const pbft_committed_certificate &rhs) const { - return digest() == rhs.digest(); + return block_info == rhs.block_info; + } + + bool operator<(const pbft_committed_certificate &rhs) const { + return block_info.block_num < rhs.block_info.block_num; + } + + bool empty() const { + return *this == pbft_committed_certificate(); } }; - struct pbft_view_change final: public pbft_message { + struct pbft_view_change { explicit pbft_view_change() = default; - pbft_view_type current_view = 0; - pbft_view_type target_view = 1; - pbft_prepared_certificate prepared; - vector committed; - pbft_stable_checkpoint stable_checkpoint; + pbft_message_header msg_header = pbft_message_header(pbft_message_type::view_change); + pbft_view_type current_view = 0; + pbft_view_type target_view = 1; + pbft_prepared_certificate prepared_cert; + vector committed_cert; + pbft_stable_checkpoint stable_checkpoint; + signature_type producer_signature; bool operator==(const pbft_view_change &rhs) const { - return digest() == rhs.digest(); + return msg_header == rhs.msg_header + && current_view == rhs.current_view + && target_view == rhs.target_view + && prepared_cert == rhs.prepared_cert + && committed_cert == rhs.committed_cert + && stable_checkpoint == rhs.stable_checkpoint; } bool operator<(const pbft_view_change &rhs) const { return target_view < rhs.target_view; } - digest_type digest() const override { + digest_type digest() const { digest_type::encoder enc; - fc::raw::pack(enc, uuid); + fc::raw::pack(enc, msg_header); 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, prepared_cert); + fc::raw::pack(enc, committed_cert); fc::raw::pack(enc, stable_checkpoint); - fc::raw::pack(enc, public_key); - fc::raw::pack(enc, timestamp); - fc::raw::pack(enc, chain_id); return enc.result(); } + + bool is_signature_valid() const { + try { + auto pk = crypto::public_key(producer_signature, digest(), true); + return msg_header.public_key == pk; + } catch (fc::exception & /*e*/) { + return false; + } + } }; struct pbft_view_changed_certificate { explicit pbft_view_changed_certificate() = default; - vector messages; - uint32_t view = 0; + uint32_t target_view = 0; + vector view_changes; bool operator==(const pbft_view_changed_certificate &rhs) const { - return digest() == rhs.digest(); + return target_view == rhs.target_view + && view_changes == rhs.view_changes; + //TODO: should include chain id? } - digest_type digest() const { - digest_type::encoder enc; - fc::raw::pack(enc, view); - fc::raw::pack(enc, messages); - return enc.result(); + bool empty() const { + return *this == pbft_view_changed_certificate(); } }; - struct pbft_new_view final: public pbft_message { + struct pbft_new_view { explicit pbft_new_view() = default; - pbft_view_type view = 0; - pbft_prepared_certificate prepared; - vector committed; - pbft_stable_checkpoint stable_checkpoint; - pbft_view_changed_certificate view_changed; + pbft_message_header msg_header = pbft_message_header(pbft_message_type::new_view); + pbft_view_type new_view = 0; + pbft_prepared_certificate prepared_cert; + vector committed_cert; + pbft_stable_checkpoint stable_checkpoint; + pbft_view_changed_certificate view_changed_cert; + signature_type producer_signature; bool operator==(const pbft_new_view &rhs) const { - return digest() == rhs.digest(); + return msg_header == rhs.msg_header + && new_view == rhs.new_view + && prepared_cert == rhs.prepared_cert + && committed_cert == rhs.committed_cert + && stable_checkpoint == rhs.stable_checkpoint + && view_changed_cert == rhs.view_changed_cert; } bool operator<(const pbft_new_view &rhs) const { - return view < rhs.view; + return new_view < rhs.new_view; } - digest_type digest() const override { + digest_type digest() const { digest_type::encoder enc; - fc::raw::pack(enc, uuid); - fc::raw::pack(enc, view); - fc::raw::pack(enc, prepared); - fc::raw::pack(enc, committed); + fc::raw::pack(enc, msg_header); + fc::raw::pack(enc, new_view); + fc::raw::pack(enc, prepared_cert); + fc::raw::pack(enc, committed_cert); fc::raw::pack(enc, stable_checkpoint); - fc::raw::pack(enc, view_changed); - fc::raw::pack(enc, public_key); - fc::raw::pack(enc, timestamp); - fc::raw::pack(enc, chain_id); + fc::raw::pack(enc, view_changed_cert); return enc.result(); } + + bool is_signature_valid() const { + try { + auto pk = crypto::public_key(producer_signature, digest(), true); + return msg_header.public_key == pk; + } catch (fc::exception & /*e*/) { + return false; + } + } + + bool empty() const { + return *this == pbft_new_view(); + } }; struct pbft_state { - block_id_type block_id; - block_num_type block_num = 0; - vector prepares; - bool should_prepared = false; - vector commits; - bool should_committed = false; + block_id_type block_id; + block_num_type block_num = 0; + vector prepares; + bool should_prepared = false; + vector commits; + bool should_committed = false; }; struct pbft_view_change_state { - pbft_view_type view; - vector view_changes; - bool should_view_changed = false; + pbft_view_type view; + vector view_changes; + bool should_view_changed = false; }; struct pbft_checkpoint_state { - block_id_type block_id; - block_num_type block_num = 0; + block_id_type block_id; + block_num_type block_num = 0; vector checkpoints; - bool is_stable = false; + bool is_stable = false; }; using pbft_state_ptr = std::shared_ptr; @@ -319,18 +392,15 @@ namespace eosio { typedef multi_index_container< pbft_state_ptr, indexed_by< - hashed_unique< + hashed_unique < tag, member, std::hash >, ordered_non_unique< tag, - composite_key< - pbft_state, - member - >, - composite_key_compare> + member, + less<> >, ordered_non_unique< tag, @@ -339,7 +409,7 @@ namespace eosio { member, member >, - composite_key_compare, greater<>> + composite_key_compare< greater<>, greater<> > >, ordered_non_unique< tag, @@ -348,21 +418,20 @@ namespace eosio { member, member >, - composite_key_compare, greater<>> + composite_key_compare< greater<>, greater<> > > > - > - pbft_state_multi_index_type; + > pbft_state_multi_index_type; struct by_view; struct by_count_and_view; typedef multi_index_container< pbft_view_change_state_ptr, indexed_by< - hashed_unique< + ordered_unique< tag, member, - std::hash + greater<> >, ordered_non_unique< tag, @@ -374,8 +443,7 @@ namespace eosio { composite_key_compare, greater<>> > > - > - pbft_view_state_multi_index_type; + > pbft_view_state_multi_index_type; struct by_block_id; struct by_num; @@ -389,15 +457,11 @@ namespace eosio { >, ordered_non_unique< tag, - composite_key< - pbft_checkpoint_state, - member - >, - composite_key_compare> + member, + less<> > > - > - pbft_checkpoint_state_multi_index_type; + > pbft_checkpoint_state_multi_index_type; class pbft_database { public: @@ -470,7 +534,7 @@ namespace eosio { pbft_stable_checkpoint fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr &b); - block_info cal_pending_stable_checkpoint() const; + block_info_type cal_pending_stable_checkpoint() const; bool should_send_pbft_msg(); @@ -492,15 +556,15 @@ 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; + pbft_state_ptr get_pbft_state_by_id(const block_id_type &id) const; - vector get_checkpoints_by_num(const block_num_type& num)const; + vector get_checkpoints_by_num(const block_num_type &num) const; - pbft_view_change_state_ptr get_view_changes_by_target_view(const pbft_view_type& tv)const; + pbft_view_change_state_ptr get_view_changes_by_target_view(const pbft_view_type &tv) const; - vector get_pbft_watermarks()const; + vector get_pbft_watermarks() const; - flat_map get_pbft_fork_schedules()const; + flat_map get_pbft_fork_schedules() const; block_num_type get_current_pbft_watermark(); @@ -522,28 +586,30 @@ namespace eosio { signal pbft_incoming_checkpoint; 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; - chain_id_type chain_id = chain_id_type(""); - fc::path pbft_db_dir; - fc::path checkpoints_dir; - boost::uuids::random_generator uuid_generator; - vector prepare_watermarks; - flat_map fork_schedules; + 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; + chain_id_type chain_id = ctrl.get_chain_id(); + fc::path pbft_db_dir; + fc::path checkpoints_dir; + boost::uuids::random_generator uuid_generator; + vector prepare_watermarks; + flat_map fork_schedules; + + bool is_valid_pbft_message_header(const pbft_message_header &msg_header); bool is_valid_prepared_certificate(const pbft_prepared_certificate &certificate); bool is_valid_committed_certificate(const pbft_committed_certificate &certificate); - vector> fetch_fork_from(vector &block_infos); + vector> fetch_fork_from(vector &block_infos); - vector fetch_first_fork_from(vector &bi); + vector fetch_first_fork_from(vector &bi); bool is_valid_longest_fork( - const block_info &bi, - vector block_infos, + const block_info_type &bi, + vector block_infos, unsigned long threshold, unsigned long non_fork_bp_count); @@ -552,31 +618,33 @@ namespace eosio { template void emit(const Signal &s, Arg &&a); - void set(pbft_state_ptr s); + void set(const pbft_state_ptr& s); - void set(pbft_checkpoint_state_ptr s); + void set(const pbft_checkpoint_state_ptr& s); void prune(const pbft_state_ptr &h); void prune_checkpoints(const pbft_checkpoint_state_ptr &h); - }; - } } /// namespace eosio::chain -FC_REFLECT(eosio::chain::block_info, (block_id)(block_num)) -FC_REFLECT(eosio::chain::pbft_message, (uuid)(public_key)(chain_id)(producer_signature)(timestamp)) -FC_REFLECT_DERIVED(eosio::chain::pbft_prepare, (eosio::chain::pbft_message), (view)(block)) -FC_REFLECT_DERIVED(eosio::chain::pbft_commit, (eosio::chain::pbft_message), (view)(block)) -FC_REFLECT_DERIVED(eosio::chain::pbft_view_change, (eosio::chain::pbft_message), (current_view)(target_view)(prepared)(committed)(stable_checkpoint)) -FC_REFLECT_DERIVED(eosio::chain::pbft_new_view, (eosio::chain::pbft_message), (view)(prepared)(committed)(stable_checkpoint)(view_changed)) -FC_REFLECT_DERIVED(eosio::chain::pbft_checkpoint, (eosio::chain::pbft_message), (block)) -FC_REFLECT(eosio::chain::pbft_certificate, (block)(messages)) -FC_REFLECT_DERIVED(eosio::chain::pbft_prepared_certificate, (eosio::chain::pbft_certificate), (messages)) -FC_REFLECT_DERIVED(eosio::chain::pbft_committed_certificate,(eosio::chain::pbft_certificate), (messages)) -FC_REFLECT(eosio::chain::pbft_view_changed_certificate, (view)(messages)) -FC_REFLECT_DERIVED(eosio::chain::pbft_stable_checkpoint, (eosio::chain::pbft_certificate), (messages)) +FC_REFLECT(eosio::chain::block_info_type, (block_id)(block_num)) +FC_REFLECT_ENUM(eosio::chain::pbft_message_type, (prepare)(commit)(checkpoint)(view_change)(new_view)) + +FC_REFLECT(eosio::chain::pbft_message_header, (type)(uuid)(public_key)(chain_id)(timestamp)) +FC_REFLECT(eosio::chain::pbft_prepare, (msg_header)(view)(block_info)(producer_signature)) +FC_REFLECT(eosio::chain::pbft_commit, (msg_header)(view)(block_info)(producer_signature)) +FC_REFLECT(eosio::chain::pbft_checkpoint,(msg_header)(block_info)(producer_signature)) +FC_REFLECT(eosio::chain::pbft_view_change, (msg_header)(current_view)(target_view)(prepared_cert)(committed_cert)(stable_checkpoint)(producer_signature)) +FC_REFLECT(eosio::chain::pbft_new_view, (msg_header)(new_view)(prepared_cert)(committed_cert)(stable_checkpoint)(view_changed_cert)(producer_signature)) + + +FC_REFLECT(eosio::chain::pbft_prepared_certificate, (block_info)(prepares)) +FC_REFLECT(eosio::chain::pbft_committed_certificate,(block_info)(commits)) +FC_REFLECT(eosio::chain::pbft_view_changed_certificate, (target_view)(view_changes)) +FC_REFLECT(eosio::chain::pbft_stable_checkpoint, (block_info)(checkpoints)) + FC_REFLECT(eosio::chain::pbft_state, (block_id)(block_num)(prepares)(should_prepared)(commits)(should_committed)) FC_REFLECT(eosio::chain::pbft_view_change_state, (view)(view_changes)(should_view_changed)) FC_REFLECT(eosio::chain::pbft_checkpoint_state, (block_id)(block_num)(checkpoints)(is_stable)) \ No newline at end of file diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index e5ed158f04a..122f594d2a0 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -5,7 +5,9 @@ namespace eosio { namespace chain { - pbft_controller::pbft_controller(controller &ctrl) : pbft_db(ctrl), state_machine(pbft_db) { + pbft_controller::pbft_controller(controller &ctrl) : + pbft_db(ctrl), + state_machine(new psm_machine(pbft_db)) { config.view_change_timeout = 6; config.bp_candidate = true; datadir = ctrl.state_dir(); @@ -21,9 +23,9 @@ namespace eosio { fc::datastream ds(content.data(), content.size()); uint32_t current_view; fc::raw::unpack(ds, current_view); - state_machine.set_current_view(current_view); + state_machine->set_current_view(current_view); - state_machine.set_target_view(state_machine.get_current_view() + 1); + state_machine->set_target_view(state_machine->get_current_view() + 1); ilog("current view: ${cv}", ("cv", current_view)); } @@ -35,51 +37,51 @@ namespace eosio { std::ofstream out(pbft_db_dat.generic_string().c_str(), std::ios::out | std::ios::binary | std::ofstream::trunc); - uint32_t current_view = state_machine.get_current_view(); + uint32_t current_view = state_machine->get_current_view(); fc::raw::pack(out, current_view); } void pbft_controller::maybe_pbft_prepare() { if (!pbft_db.should_send_pbft_msg()) return; - state_machine.send_prepare(); + state_machine->send_prepare(); } void pbft_controller::maybe_pbft_commit() { if (!pbft_db.should_send_pbft_msg()) return; - state_machine.send_commit(); + state_machine->send_commit(); } void pbft_controller::maybe_pbft_view_change() { if (!pbft_db.should_send_pbft_msg()) return; - if (state_machine.get_view_change_timer() <= config.view_change_timeout) { - if (!state_machine.get_view_changes_cache().empty()) { - pbft_db.send_and_add_pbft_view_change(state_machine.get_view_changes_cache()); + if (state_machine->get_view_change_timer() <= config.view_change_timeout) { + if (!state_machine->get_view_changes_cache().empty()) { + pbft_db.send_and_add_pbft_view_change(state_machine->get_view_changes_cache()); } - state_machine.set_view_change_timer(state_machine.get_view_change_timer() + 1); + state_machine->set_view_change_timer(state_machine->get_view_change_timer() + 1); } else { - state_machine.set_view_change_timer(0); - state_machine.send_view_change(); + state_machine->set_view_change_timer(0); + state_machine->send_view_change(); } } void pbft_controller::on_pbft_prepare(pbft_prepare &p) { if (!config.bp_candidate) return; - state_machine.on_prepare(p); + state_machine->on_prepare(p); } void pbft_controller::on_pbft_commit(pbft_commit &c) { if (!config.bp_candidate) return; - state_machine.on_commit(c); + state_machine->on_commit(c); } void pbft_controller::on_pbft_view_change(pbft_view_change &vc) { if (!config.bp_candidate) return; - state_machine.on_view_change(vc); + state_machine->on_view_change(vc); } void pbft_controller::on_pbft_new_view(pbft_new_view &nv) { if (!config.bp_candidate) return; - state_machine.on_new_view(nv); + state_machine->on_new_view(nv); } void pbft_controller::send_pbft_checkpoint() { @@ -99,54 +101,56 @@ namespace eosio { psm_machine::psm_machine(pbft_database &pbft_db) : pbft_db(pbft_db) { - this->set_current(new psm_committed_state); + set_current(std::make_shared()); - this->set_prepares_cache(vector{}); - this->set_commits_cache(vector{}); - this->set_view_changes_cache(vector{}); + set_prepares_cache(vector{}); + set_commits_cache(vector{}); + set_view_changes_cache(vector{}); - this->set_prepared_certificate(pbft_prepared_certificate{}); - this->set_committed_certificate(vector{}); - this->set_view_changed_certificate(pbft_view_changed_certificate{}); + set_prepared_certificate(pbft_prepared_certificate{}); + set_committed_certificate(vector{}); + set_view_changed_certificate(pbft_view_changed_certificate{}); - this->view_change_timer = 0; - this->target_view_retries = 0; - this->current_view = 0; - this->target_view = this->current_view + 1; + view_change_timer = 0; + target_view_retries = 0; + current_view = 0; + target_view = current_view + 1; } psm_machine::~psm_machine() = default; void psm_machine::on_prepare(pbft_prepare &e) { - current->on_prepare(this, e, pbft_db); + current->on_prepare(shared_from_this(), e, pbft_db); } void psm_machine::send_prepare() { - current->send_prepare(this, pbft_db); + current->send_prepare(shared_from_this(), pbft_db); } void psm_machine::on_commit(pbft_commit &e) { - current->on_commit(this, e, pbft_db); + current->on_commit(shared_from_this(), e, pbft_db); } void psm_machine::send_commit() { - current->send_commit(this, pbft_db); + current->send_commit(shared_from_this(), pbft_db); } void psm_machine::on_view_change(pbft_view_change &e) { - current->on_view_change(this, e, pbft_db); + current->on_view_change(shared_from_this(), e, pbft_db); } void psm_machine::send_view_change() { - current->send_view_change(this, pbft_db); + current->send_view_change(shared_from_this(), pbft_db); } void psm_machine::on_new_view(pbft_new_view &e) { - current->on_new_view(this, e, pbft_db); + current->on_new_view(shared_from_this(), e, pbft_db); } void psm_machine::manually_set_current_view(const uint32_t &cv) { - current->manually_set_view(this, cv); + set_current_view(cv); + set_target_view(cv + 1); + transit_to_view_change_state(get_current()); } /** @@ -159,18 +163,18 @@ namespace eosio { psm_prepared_state::~psm_prepared_state() = default; - void psm_prepared_state::on_prepare(psm_machine *m, pbft_prepare &e, pbft_database &pbft_db) { + void psm_prepared_state::on_prepare(psm_machine_ptr m, pbft_prepare &e, pbft_database &pbft_db) { //ignore } - void psm_prepared_state::send_prepare(psm_machine *m, pbft_database &pbft_db) { + void psm_prepared_state::send_prepare(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 *m, pbft_commit &e, pbft_database &pbft_db) { + void psm_prepared_state::on_commit(psm_machine_ptr m, pbft_commit &e, pbft_database &pbft_db) { if (e.view < m->get_current_view()) return; @@ -187,12 +191,12 @@ namespace eosio { if (pending_commit_local && !pbft_db.pending_pbft_lib()) { pbft_db.send_pbft_checkpoint(); - m->transit_to_committed_state(this, false); + m->transit_to_committed_state(shared_from_this(), false); } } - void psm_prepared_state::send_commit(psm_machine *m, pbft_database &pbft_db) { + void psm_prepared_state::send_commit(psm_machine_ptr m, pbft_database &pbft_db) { auto commits = pbft_db.send_and_add_pbft_commit(m->get_commits_cache(), m->get_current_view()); if (!commits.empty()) { @@ -206,11 +210,11 @@ namespace eosio { if (pending_commit_local && !pbft_db.pending_pbft_lib()) { pbft_db.send_pbft_checkpoint(); - m->transit_to_committed_state(this, false); + m->transit_to_committed_state(shared_from_this(), false); } } - void psm_prepared_state::on_view_change(psm_machine *m, pbft_view_change &e, pbft_database &pbft_db) { + void psm_prepared_state::on_view_change(psm_machine_ptr m, pbft_view_change &e, pbft_database &pbft_db) { if (e.target_view <= m->get_current_view()) return; @@ -220,31 +224,25 @@ namespace eosio { auto target_view = pbft_db.should_view_change(); if (target_view > 0 && target_view > m->get_current_view()) { m->set_target_view(target_view); - m->transit_to_view_change_state(this); + m->transit_to_view_change_state(shared_from_this()); } } - void psm_prepared_state::send_view_change(psm_machine *m, pbft_database &pbft_db) { - m->transit_to_view_change_state(this); + void psm_prepared_state::send_view_change(psm_machine_ptr m, pbft_database &pbft_db) { + m->transit_to_view_change_state(shared_from_this()); } - void psm_prepared_state::on_new_view(psm_machine *m, pbft_new_view &e, pbft_database &pbft_db) { + void psm_prepared_state::on_new_view(psm_machine_ptr m, pbft_new_view &e, pbft_database &pbft_db) { - if (e.view <= m->get_current_view()) return; + if (e.new_view <= m->get_current_view()) return; try { - m->transit_to_new_view(e, this); + m->transit_to_new_view(e, shared_from_this()); } catch(const fc::exception& ex) { wlog("bad new view, ${s} ", ("s",ex.to_string())); } } - void psm_prepared_state::manually_set_view(psm_machine *m, const uint32_t &view) { - m->set_current_view(view); - m->set_target_view(view+1); - m->transit_to_view_change_state(this); - } - psm_committed_state::psm_committed_state() = default; psm_committed_state::~psm_committed_state() = default; @@ -252,7 +250,7 @@ namespace eosio { /** * psm_committed_state */ - void psm_committed_state::on_prepare(psm_machine *m, pbft_prepare &e, pbft_database &pbft_db) { + void psm_committed_state::on_prepare(psm_machine_ptr m, pbft_prepare &e, pbft_database &pbft_db) { //validate if (e.view < m->get_current_view()) return; @@ -260,10 +258,10 @@ namespace eosio { pbft_db.add_pbft_prepare(e); //if prepare >= 2f+1, transit to prepared - if (pbft_db.should_prepared()) m->transit_to_prepared_state(this); + if (pbft_db.should_prepared()) m->transit_to_prepared_state(shared_from_this()); } - void psm_committed_state::send_prepare(psm_machine *m, pbft_database &pbft_db) { + void psm_committed_state::send_prepare(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()); @@ -272,24 +270,24 @@ namespace eosio { } //if prepare >= 2f+1, transit to prepared - if (pbft_db.should_prepared()) m->transit_to_prepared_state(this); + if (pbft_db.should_prepared()) m->transit_to_prepared_state(shared_from_this()); } - void psm_committed_state::on_commit(psm_machine *m, pbft_commit &e, pbft_database &pbft_db) { + void psm_committed_state::on_commit(psm_machine_ptr m, pbft_commit &e, pbft_database &pbft_db) { if (e.view < m->get_current_view()) return; pbft_db.add_pbft_commit(e); } - void psm_committed_state::send_commit(psm_machine *m, pbft_database &pbft_db) { + void psm_committed_state::send_commit(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 *m, pbft_view_change &e, pbft_database &pbft_db) { + void psm_committed_state::on_view_change(psm_machine_ptr m, pbft_view_change &e, pbft_database &pbft_db) { if (e.target_view <= m->get_current_view()) return; @@ -299,56 +297,50 @@ namespace eosio { auto new_view = pbft_db.should_view_change(); if (new_view > 0 && new_view > m->get_current_view()) { m->set_target_view(new_view); - m->transit_to_view_change_state(this); + m->transit_to_view_change_state(shared_from_this()); } } - void psm_committed_state::send_view_change(psm_machine *m, pbft_database &pbft_db) { - m->transit_to_view_change_state(this); + void psm_committed_state::send_view_change(psm_machine_ptr m, pbft_database &pbft_db) { + m->transit_to_view_change_state(shared_from_this()); } - void psm_committed_state::on_new_view(psm_machine *m, pbft_new_view &e, pbft_database &pbft_db) { + void psm_committed_state::on_new_view(psm_machine_ptr m, pbft_new_view &e, pbft_database &pbft_db) { - if (e.view <= m->get_current_view()) return; + if (e.new_view <= m->get_current_view()) return; try { - m->transit_to_new_view(e, this); + m->transit_to_new_view(e, shared_from_this()); } catch(const fc::exception& ex) { wlog("bad new view, ${s} ", ("s",ex.to_string())); } } - void psm_committed_state::manually_set_view(psm_machine *m, const uint32_t &view) { - m->set_current_view(view); - m->set_target_view(view+1); - m->transit_to_view_change_state(this); - } - /** * psm_view_change_state */ - void psm_view_change_state::on_prepare(psm_machine *m, pbft_prepare &e, pbft_database &pbft_db) { + void psm_view_change_state::on_prepare(psm_machine_ptr m, pbft_prepare &e, pbft_database &pbft_db) { //ignore; } - void psm_view_change_state::send_prepare(psm_machine *m, pbft_database &pbft_db) { + void psm_view_change_state::send_prepare(psm_machine_ptr m, pbft_database &pbft_db) { //ignore; } - void psm_view_change_state::on_commit(psm_machine *m, pbft_commit &e, pbft_database &pbft_db) { + void psm_view_change_state::on_commit(psm_machine_ptr m, pbft_commit &e, pbft_database &pbft_db) { //ignore; } - void psm_view_change_state::send_commit(psm_machine *m, pbft_database &pbft_db) { + void psm_view_change_state::send_commit(psm_machine_ptr m, pbft_database &pbft_db) { //ignore; } - void psm_view_change_state::on_view_change(psm_machine *m, pbft_view_change &e, pbft_database &pbft_db) { + void psm_view_change_state::on_view_change(psm_machine_ptr m, pbft_view_change &e, pbft_database &pbft_db) { //skip from view change state if my lib is higher than my view change state height. auto vc = m->get_view_changes_cache(); if (!vc.empty() && pbft_db.should_stop_view_change(vc.front())) { - m->transit_to_committed_state(this, false); + m->transit_to_committed_state(shared_from_this(), false); return; } @@ -356,109 +348,99 @@ namespace eosio { pbft_db.add_pbft_view_change(e); - m->maybe_new_view(this); + m->maybe_new_view(shared_from_this()); } - void psm_view_change_state::send_view_change(psm_machine *m, pbft_database &pbft_db) { + void psm_view_change_state::send_view_change(psm_machine_ptr m, pbft_database &pbft_db) { //skip from view change state if my lib is higher than my view change state height. auto vc = m->get_view_changes_cache(); if (!vc.empty() && pbft_db.should_stop_view_change(vc.front())) { - m->transit_to_committed_state(this, false); + m->transit_to_committed_state(shared_from_this(), false); return; } m->send_pbft_view_change(); - m->maybe_new_view(this); + m->maybe_new_view(shared_from_this()); } - void psm_view_change_state::on_new_view(psm_machine *m, pbft_new_view &e, pbft_database &pbft_db) { + void psm_view_change_state::on_new_view(psm_machine_ptr m, pbft_new_view &e, pbft_database &pbft_db) { - if (e.view <= m->get_current_view()) return; + if (e.new_view <= m->get_current_view()) return; try { - m->transit_to_new_view(e, this); + m->transit_to_new_view(e, shared_from_this()); } catch(const fc::exception& ex) { wlog("bad new view, ${s} ", ("s",ex.to_string())); } } - void psm_view_change_state::manually_set_view(psm_machine *m, const uint32_t &view) { - m->set_current_view(view); - m->set_target_view(view+1); - m->transit_to_view_change_state(this); - } - - template - void psm_machine::transit_to_committed_state(T const & s, bool to_new_view) { + void psm_machine::transit_to_committed_state(psm_state_ptr s, bool to_new_view) { if (!to_new_view) { auto nv = pbft_db.get_committed_view(); - if (nv > this->get_current_view()) this->set_current_view(nv); - this->set_target_view(this->get_current_view() + 1); + if (nv > get_current_view()) set_current_view(nv); + set_target_view(get_current_view() + 1); } - auto prepares = this->pbft_db.send_and_add_pbft_prepare(vector{}, this->get_current_view()); + auto prepares = pbft_db.send_and_add_pbft_prepare(vector{}, get_current_view()); set_prepares_cache(prepares); - this->set_view_changes_cache(vector{}); - this->set_view_change_timer(0); + set_view_changes_cache(vector{}); + set_view_change_timer(0); - this->set_current(new psm_committed_state); - delete s; + set_current(std::make_shared()); + s.reset(); } - template - void psm_machine::transit_to_prepared_state(T const & s) { + void psm_machine::transit_to_prepared_state(psm_state_ptr s) { - auto commits = this->pbft_db.send_and_add_pbft_commit(vector{}, this->get_current_view()); + auto commits = pbft_db.send_and_add_pbft_commit(vector{}, get_current_view()); set_commits_cache(commits); - this->set_view_changes_cache(vector{}); + set_view_changes_cache(vector{}); - this->set_current(new psm_prepared_state); - delete s; + set_current(std::make_shared()); + s.reset(); } - template - void psm_machine::transit_to_view_change_state(T const &s) { + void psm_machine::transit_to_view_change_state(psm_state_ptr s) { - this->set_commits_cache(vector{}); - this->set_prepares_cache(vector{}); + set_commits_cache(vector{}); + set_prepares_cache(vector{}); - this->set_view_change_timer(0); - this->set_target_view_retries(0); + set_view_change_timer(0); + set_target_view_retries(0); - this->set_current(new psm_view_change_state); + set_current(std::make_shared()); if (pbft_db.should_send_pbft_msg()) { - this->send_pbft_view_change(); - auto nv = this->maybe_new_view(s); + send_pbft_view_change(); + auto nv = maybe_new_view(s); if (nv) return; } - delete s; + s.reset(); } - template - bool psm_machine::maybe_new_view(T const &s) { + bool psm_machine::maybe_new_view(psm_state_ptr s) { //if view_change >= 2f+1, calculate next primary, send new view if is primary - auto nv = this->get_target_view(); + auto nv = get_target_view(); if (pbft_db.should_new_view(nv) && pbft_db.is_new_primary(nv)) { - this->set_view_changed_certificate(pbft_db.generate_view_changed_certificate(nv)); + set_view_changed_certificate(pbft_db.generate_view_changed_certificate(nv)); auto new_view = pbft_db.get_proposed_new_view_num(); if (new_view != nv) return false; auto nv_msg = pbft_db.send_pbft_new_view( - this->get_view_changed_certificate(), + get_view_changed_certificate(), new_view); if (nv_msg == pbft_new_view{}) return false; try { - this->transit_to_new_view(nv_msg, s); + transit_to_new_view(nv_msg, s); return true; } catch(const fc::exception& ex) { wlog("bad new view, ${s} ", ("s",ex.to_string())); @@ -467,8 +449,7 @@ namespace eosio { return false; } - template - void psm_machine::transit_to_new_view(const pbft_new_view &new_view, T const &s) { + void psm_machine::transit_to_new_view(const pbft_new_view &new_view, psm_state_ptr s) { auto valid_nv = false; try { @@ -478,18 +459,18 @@ namespace eosio { } EOS_ASSERT(valid_nv, pbft_exception, "new view is not valid, waiting for next round.."); - this->set_current_view(new_view.view); - this->set_target_view(new_view.view + 1); + set_current_view(new_view.new_view); + set_target_view(new_view.new_view + 1); - this->set_prepares_cache(vector{}); + set_prepares_cache(vector{}); - this->set_view_change_timer(0); - this->set_target_view_retries(0); + set_view_change_timer(0); + set_target_view_retries(0); - this->pbft_db.prune_pbft_index(); + pbft_db.prune_pbft_index(); if (!(new_view.stable_checkpoint == pbft_stable_checkpoint{})) { - for (auto cp :new_view.stable_checkpoint.messages) { + for (auto cp :new_view.stable_checkpoint.checkpoints) { try { pbft_db.add_pbft_checkpoint(cp); } catch (...) { @@ -498,11 +479,11 @@ namespace eosio { } } - if (!new_view.committed.empty()) { - auto committed_certs = new_view.committed; + if (!new_view.committed_cert.empty()) { + auto committed_certs = new_view.committed_cert; std::sort(committed_certs.begin(), committed_certs.end()); for (auto cp :committed_certs) { - for (auto c: cp.messages) { + for (auto c: cp.commits) { try { pbft_db.add_pbft_commit(c); } catch (...) { @@ -512,8 +493,8 @@ namespace eosio { } } - if (!new_view.prepared.messages.empty()) { - for (auto p: new_view.prepared.messages) { + if (!new_view.prepared_cert.prepares.empty()) { + for (auto p: new_view.prepared_cert.prepares) { try { pbft_db.add_pbft_prepare(p); } catch (...) { @@ -531,113 +512,113 @@ namespace eosio { void psm_machine::send_pbft_view_change() { - 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()); + if (get_target_view_retries() == 0) { + set_view_changes_cache(vector{}); + set_prepared_certificate(pbft_db.generate_prepared_certificate()); + set_committed_certificate(pbft_db.generate_committed_certificate()); } - EOS_ASSERT((this->get_target_view() > this->get_current_view()), pbft_exception, + EOS_ASSERT((get_target_view() > get_current_view()), pbft_exception, "target view should be always greater than current view"); - if (this->get_target_view_retries() < pow(2, this->get_target_view() - this->get_current_view() - 1)) { - this->set_target_view_retries(this->get_target_view_retries() + 1); + if (get_target_view_retries() < pow(2,get_target_view() - get_current_view() - 1)) { + set_target_view_retries(get_target_view_retries() + 1); } else { - this->set_target_view_retries(0); - this->set_target_view(this->get_target_view() + 1); - this->set_view_changes_cache(vector{}); + set_target_view_retries(0); + set_target_view(get_target_view() + 1); + set_view_changes_cache(vector{}); } 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()); + get_view_changes_cache(), + get_prepared_certificate(), + get_committed_certificate(), + get_current_view(), + get_target_view()); if (!view_changes.empty()) { - this->set_view_changes_cache(view_changes); + set_view_changes_cache(view_changes); } } const vector &psm_machine::get_prepares_cache() const { - return this->cache.prepares_cache; + return cache.prepares_cache; } void psm_machine::set_prepares_cache(const vector &pcache) { - this->cache.prepares_cache = pcache; + cache.prepares_cache = pcache; } const vector &psm_machine::get_commits_cache() const { - return this->cache.commits_cache; + return cache.commits_cache; } void psm_machine::set_commits_cache(const vector &ccache) { - this->cache.commits_cache = ccache; + cache.commits_cache = ccache; } const vector &psm_machine::get_view_changes_cache() const { - return this->cache.view_changes_cache; + return cache.view_changes_cache; } void psm_machine::set_view_changes_cache(const vector &vc_cache) { - this->cache.view_changes_cache = vc_cache; + cache.view_changes_cache = vc_cache; } const uint32_t &psm_machine::get_current_view() const { - return this->current_view; + return current_view; } void psm_machine::set_current_view(const uint32_t &cv) { - this->current_view = cv; + current_view = cv; } const pbft_prepared_certificate &psm_machine::get_prepared_certificate() const { - return this->cache.prepared_certificate; + return cache.prepared_certificate; } void psm_machine::set_prepared_certificate(const pbft_prepared_certificate &pcert) { - this->cache.prepared_certificate = pcert; + cache.prepared_certificate = pcert; } const vector &psm_machine::get_committed_certificate() const { - return this->cache.committed_certificate; + return cache.committed_certificate; } void psm_machine::set_committed_certificate(const vector &ccert) { - this->cache.committed_certificate = ccert; + cache.committed_certificate = ccert; } const pbft_view_changed_certificate &psm_machine::get_view_changed_certificate() const { - return this->cache.view_changed_certificate; + return cache.view_changed_certificate; } void psm_machine::set_view_changed_certificate(const pbft_view_changed_certificate &vc_cert) { - this->cache.view_changed_certificate = vc_cert; + cache.view_changed_certificate = vc_cert; } const uint32_t &psm_machine::get_target_view_retries() const { - return this->target_view_retries; + return target_view_retries; } void psm_machine::set_target_view_retries(const uint32_t &tv_reties) { - this->target_view_retries = tv_reties; + target_view_retries = tv_reties; } const uint32_t &psm_machine::get_target_view() const { - return this->target_view; + return target_view; } void psm_machine::set_target_view(const uint32_t &tv) { - this->target_view = tv; + target_view = tv; } const uint32_t &psm_machine::get_view_change_timer() const { - return this->view_change_timer; + return view_change_timer; } void psm_machine::set_view_change_timer(const uint32_t &vc_timer) { - this->view_change_timer = vc_timer; + view_change_timer = vc_timer; } } } \ No newline at end of file diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 5e9a2a8c5ab..7e6092b3a68 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -99,7 +99,7 @@ namespace eosio { auto &by_block_id_index = pbft_state_index.get(); - auto current = ctrl.fetch_block_state_by_id(p.block.block_id); + auto current = ctrl.fetch_block_state_by_id(p.block_info.block_id); while ((current) && (current->block_num > ctrl.last_irreversible_block_num())) { auto curr_itr = by_block_id_index.find(current->id); @@ -116,7 +116,8 @@ namespace eosio { auto prepares = (*curr_itr)->prepares; auto p_itr = find_if(prepares.begin(), prepares.end(), [&](const pbft_prepare &prep) { - return prep.public_key == p.public_key && prep.view == p.view; + return prep.msg_header.public_key == p.msg_header.public_key + && prep.view == p.view; }); if (p_itr == prepares.end()) { by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr &psp) { @@ -138,7 +139,7 @@ namespace eosio { if (!(*curr_itr)->should_prepared) { for (auto const &sp: as) { for (auto const &pp: prepares) { - if (sp.block_signing_key == pp.public_key) prepare_count[pp.view] += 1; + if (sp.block_signing_key == pp.msg_header.public_key) prepare_count[pp.view] += 1; } } for (auto const &e: prepare_count) { @@ -172,9 +173,9 @@ namespace eosio { for (auto p : pv) { //change uuid, sign again, update cache, then emit auto uuid = boost::uuids::to_string(uuid_generator()); - p.uuid = uuid; - p.timestamp = time_point::now(); - p.producer_signature = ctrl.my_signature_providers()[p.public_key](p.digest()); + p.msg_header.uuid = uuid; + p.msg_header.timestamp = time_point::now(); + p.producer_signature = ctrl.my_signature_providers()[p.msg_header.public_key](p.digest()); emit(pbft_outgoing_prepare, p); } return vector{}; @@ -183,7 +184,7 @@ namespace eosio { auto uuid = boost::uuids::to_string(uuid_generator()); auto my_prepare_num = ctrl.fetch_block_state_by_id(my_prepare)->block_num; pbft_prepare p; - p.uuid=uuid; p.view=current_view; p.block={my_prepare, my_prepare_num}; p.public_key=sp.first; p.chain_id=chain_id; + p.msg_header.uuid=uuid; p.view=current_view; p.block_info={my_prepare, my_prepare_num}; p.msg_header.public_key=sp.first; p.msg_header.chain_id=chain_id; p.producer_signature = sp.second(p.digest()); emit(pbft_outgoing_prepare, p); new_pv.emplace_back(p); @@ -207,7 +208,7 @@ namespace eosio { for (auto const &sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); pbft_prepare p; - p.uuid=uuid; p.view=current_view; p.block={hwbs->id, high_watermark_block_num}; p.public_key=sp.first; p.chain_id=chain_id; + p.msg_header.uuid=uuid; p.view=current_view; p.block_info={hwbs->id, high_watermark_block_num}; p.msg_header.public_key=sp.first; p.msg_header.chain_id=chain_id; p.producer_signature = sp.second(p.digest()); add_pbft_prepare(p); emit(pbft_outgoing_prepare, p); @@ -238,11 +239,11 @@ namespace eosio { } bool pbft_database::is_valid_prepare(const pbft_prepare &p) { - if (p.chain_id != chain_id) return false; + if (!is_valid_pbft_message_header(p.msg_header)) return false; // a prepare msg under lscb (which is no longer in fork_db), can be treated as null, thus true. - if (p.block.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; + if (p.block_info.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; if (!p.is_signature_valid()) return false; - return should_recv_pbft_msg(p.public_key); + return should_recv_pbft_msg(p.msg_header.public_key); } void pbft_database::add_pbft_commit(pbft_commit &c) { @@ -250,7 +251,7 @@ namespace eosio { if (!is_valid_commit(c)) return; auto &by_block_id_index = pbft_state_index.get(); - auto current = ctrl.fetch_block_state_by_id(c.block.block_id); + auto current = ctrl.fetch_block_state_by_id(c.block_info.block_id); while ((current) && (current->block_num > ctrl.last_irreversible_block_num())) { @@ -268,7 +269,8 @@ namespace eosio { auto commits = (*curr_itr)->commits; auto p_itr = find_if(commits.begin(), commits.end(), [&](const pbft_commit &comm) { - return comm.public_key == c.public_key && comm.view == c.view; + return comm.msg_header.public_key == c.msg_header.public_key + && comm.view == c.view; }); if (p_itr == commits.end()) { by_block_id_index.modify(curr_itr, [&](const pbft_state_ptr &psp) { @@ -293,7 +295,7 @@ namespace eosio { for (auto const &sp: as.producers) { for (auto const &pc: commits) { - if (sp.block_signing_key == pc.public_key) commit_count[pc.view] += 1; + if (sp.block_signing_key == pc.msg_header.public_key) commit_count[pc.view] += 1; } } @@ -313,9 +315,9 @@ namespace eosio { for (auto c : cv) { //change uuid, sign again, update cache, then emit auto uuid = boost::uuids::to_string(uuid_generator()); - c.uuid = uuid; - c.timestamp = time_point::now(); - c.producer_signature = ctrl.my_signature_providers()[c.public_key](c.digest()); + c.msg_header.uuid = uuid; + c.msg_header.timestamp = time_point::now(); + c.producer_signature = ctrl.my_signature_providers()[c.msg_header.public_key](c.digest()); emit(pbft_outgoing_commit, c); } return vector{}; @@ -334,7 +336,7 @@ namespace eosio { for (auto const &sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); pbft_commit c; - c.uuid=uuid; c.view=current_view; c.block={psp->block_id, psp->block_num}; c.public_key=sp.first; c.chain_id=chain_id; + c.msg_header.uuid=uuid; c.view=current_view; c.block_info={psp->block_id, psp->block_num}; c.msg_header.public_key=sp.first; c.msg_header.chain_id=chain_id; c.producer_signature = sp.second(c.digest()); add_pbft_commit(c); emit(pbft_outgoing_commit, c); @@ -390,10 +392,10 @@ namespace eosio { } bool pbft_database::is_valid_commit(const pbft_commit &c) { - if (c.chain_id != chain_id) return false; - if (c.block.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; + if (!is_valid_pbft_message_header(c.msg_header)) return false; + if (c.block_info.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; if (!c.is_signature_valid()) return false; - return should_recv_pbft_msg(c.public_key); + return should_recv_pbft_msg(c.msg_header.public_key); } void pbft_database::commit_local() { @@ -425,7 +427,7 @@ namespace eosio { auto view_changes = pvs->view_changes; auto p_itr = find_if(view_changes.begin(), view_changes.end(), [&](const pbft_view_change &existed) { - return existed.public_key == vc.public_key; + return existed.msg_header.public_key == vc.msg_header.public_key; }); if (p_itr == view_changes.end()) { by_view_index.modify(itr, [&](const pbft_view_change_state_ptr &pvsp) { @@ -441,7 +443,7 @@ namespace eosio { if (!(*itr)->should_view_changed) { for (auto const &sp: active_bps) { for (auto const &v: (*itr)->view_changes) { - if (sp.block_signing_key == v.public_key) vc_count += 1; + if (sp.block_signing_key == v.msg_header.public_key) vc_count += 1; } } if (vc_count >= active_bps.size() * 2 / 3 + 1) { @@ -463,7 +465,7 @@ namespace eosio { for (auto const &bp: active_bps) { for (auto const &pp: pvs->view_changes) { - if (bp.block_signing_key == pp.public_key) vc_count += 1; + if (bp.block_signing_key == pp.msg_header.public_key) vc_count += 1; } } //if contains self or view_change >= f+1, transit to view_change and send view change @@ -486,9 +488,9 @@ namespace eosio { for (auto vc : vcv) { //change uuid, sign again, update cache, then emit auto uuid = boost::uuids::to_string(uuid_generator()); - vc.uuid = uuid; - vc.timestamp = time_point::now(); - vc.producer_signature = ctrl.my_signature_providers()[vc.public_key](vc.digest()); + vc.msg_header.uuid = uuid; + vc.msg_header.timestamp = time_point::now(); + vc.producer_signature = ctrl.my_signature_providers()[vc.msg_header.public_key](vc.digest()); emit(pbft_outgoing_view_change, vc); } return vector{}; @@ -500,7 +502,7 @@ namespace eosio { auto my_lsc = get_stable_checkpoint_by_id(ctrl.last_stable_checkpoint_block_id()); auto uuid = boost::uuids::to_string(uuid_generator()); pbft_view_change vc; - vc.uuid=uuid; vc.current_view=current_view; vc.target_view=new_view; vc.prepared=ppc; vc.committed=pcc; vc.stable_checkpoint=my_lsc; vc.public_key=my_sp.first; vc.chain_id=chain_id; + vc.msg_header.uuid=uuid; vc.current_view=current_view; vc.target_view=new_view; vc.prepared_cert=ppc; vc.committed_cert=pcc; vc.stable_checkpoint=my_lsc; vc.msg_header.public_key=my_sp.first; vc.msg_header.chain_id=chain_id; vc.producer_signature = my_sp.second(vc.digest()); emit(pbft_outgoing_view_change, vc); add_pbft_view_change(vc); @@ -543,32 +545,30 @@ namespace eosio { pbft_view_type current_view) { auto primary_key = get_new_view_primary_key(current_view); - if (!is_new_primary(current_view)) return pbft_new_view{}; + if (!is_new_primary(current_view) || vcc.empty()) return pbft_new_view{}; //`sp_itr` is not possible to be the end iterator, since it's already been checked in `is_new_primary`. auto my_sps = ctrl.my_signature_providers(); auto sp_itr = my_sps.find(primary_key); - if (vcc == pbft_view_changed_certificate{}) return pbft_new_view{}; - - auto highest_ppc = pbft_prepared_certificate{}; + auto highest_ppc = pbft_prepared_certificate(); auto highest_pcc = vector{}; - auto highest_sc = pbft_stable_checkpoint{}; + auto highest_sc = pbft_stable_checkpoint(); - for (const auto &vc: vcc.messages) { - if (vc.prepared.block.block_num > highest_ppc.block.block_num && is_valid_prepared_certificate(vc.prepared)) { - highest_ppc = vc.prepared; + for (const auto &vc: vcc.view_changes) { + if (vc.prepared_cert.block_info.block_num > highest_ppc.block_info.block_num && is_valid_prepared_certificate(vc.prepared_cert)) { + highest_ppc = vc.prepared_cert; } - for (auto const &cc: vc.committed) { + for (auto const &cc: vc.committed_cert) { if (is_valid_committed_certificate(cc)) { auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), - [&](const pbft_committed_certificate &ext) { return ext.block.block_id == cc.block.block_id; }); + [&](const pbft_committed_certificate &ext) { return ext.block_info.block_id == cc.block_info.block_id; }); if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); } } - if (vc.stable_checkpoint.block.block_num > highest_sc.block.block_num && + if (vc.stable_checkpoint.block_info.block_num > highest_sc.block_info.block_num && is_valid_stable_checkpoint(vc.stable_checkpoint)) { highest_sc = vc.stable_checkpoint; } @@ -577,7 +577,7 @@ namespace eosio { auto uuid = boost::uuids::to_string(uuid_generator()); pbft_new_view nv; - nv.uuid=uuid; nv.view=current_view; nv.prepared=highest_ppc; nv.committed=highest_pcc; nv.stable_checkpoint=highest_sc, nv.view_changed=vcc, nv.public_key=sp_itr->first; nv.chain_id=chain_id; + nv.msg_header.uuid=uuid; nv.new_view=current_view; nv.prepared_cert=highest_ppc; nv.committed_cert=highest_pcc; nv.stable_checkpoint=highest_sc, nv.view_changed_cert=vcc, nv.msg_header.public_key=sp_itr->first; nv.msg_header.chain_id=chain_id; nv.producer_signature = sp_itr->second(nv.digest()); emit(pbft_outgoing_new_view, nv); @@ -609,7 +609,7 @@ namespace eosio { for (auto const &sp: as) { for (auto const &pp: prepares) { - if (sp.block_signing_key == pp.public_key) prepare_count[pp.view] += 1; + if (sp.block_signing_key == pp.msg_header.public_key) prepare_count[pp.view] += 1; } } @@ -622,7 +622,7 @@ namespace eosio { if (valid_prepares.empty()) return pbft_prepared_certificate{}; auto pc = pbft_prepared_certificate{}; - pc.block.block_id=psp->block_id; pc.block.block_num=psp->block_num; pc.messages=valid_prepares; + pc.block_info.block_id=psp->block_id; pc.block_info.block_num=psp->block_num; pc.prepares=valid_prepares; return pc; } else return pbft_prepared_certificate{}; } @@ -679,7 +679,7 @@ namespace eosio { for (auto const &sp: as) { for (auto const &cc: commits) { - if (sp.block_signing_key == cc.public_key) commit_count[cc.view] += 1; + if (sp.block_signing_key == cc.msg_header.public_key) commit_count[cc.view] += 1; } } @@ -692,7 +692,7 @@ namespace eosio { if (valid_commits.empty()) return vector{}; auto cc = pbft_committed_certificate{}; - cc.block.block_id=cbs->id; cc.block.block_num=cbs->block_num; cc.messages=valid_commits; + cc.block_info.block_id=cbs->id; cc.block_info.block_num=cbs->block_num; cc.commits=valid_commits; pcc.emplace_back(cc); @@ -710,32 +710,34 @@ namespace eosio { if (pvs->should_view_changed) { auto pvcc = pbft_view_changed_certificate{}; - pvcc.view=pvs->view; pvcc.messages=pvs->view_changes; + pvcc.target_view=pvs->view; pvcc.view_changes=pvs->view_changes; return pvcc; } else return pbft_view_changed_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; + if (certificate.empty()) return true; // a certificate under lscb (no longer in fork_db) is also treated as null. - if (certificate.block.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; + if (certificate.block_info.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; auto valid = true; - for (auto const &p : certificate.messages) { + for (auto const &p : certificate.prepares) { valid = valid && is_valid_prepare(p); if (!valid) return false; } - auto cert_id = certificate.block.block_id; + 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(); - if (certificate.block.block_num > 0 && cert_bs) { + if (certificate.block_info.block_num > 0 && cert_bs) { producer_schedule = cert_bs->active_schedule; } auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; - auto prepares = certificate.messages; + auto prepares = certificate.prepares; flat_map prepare_count; for (const auto &pre: prepares) { @@ -744,7 +746,7 @@ namespace eosio { for (auto const &sp: producer_schedule.producers) { for (auto const &pp: prepares) { - if (sp.block_signing_key == pp.public_key) prepare_count[pp.view] += 1; + if (sp.block_signing_key == pp.msg_header.public_key) prepare_count[pp.view] += 1; } } @@ -761,39 +763,39 @@ namespace eosio { //validate prepare auto lscb = ctrl.last_stable_checkpoint_block_num(); auto non_fork_bp_count = 0; - vector prepare_infos; - for (auto const &p : certificate.messages) { + vector prepare_infos; + for (auto const &p : certificate.prepares) { //only search in fork db - if (p.block.block_num <= lscb) { + if (p.block_info.block_num <= lscb) { ++non_fork_bp_count; } else { - prepare_infos.emplace_back(p.block); + prepare_infos.emplace_back(p.block_info); } } - return is_valid_longest_fork(certificate.block, prepare_infos, bp_threshold, non_fork_bp_count); + return is_valid_longest_fork(certificate.block_info, prepare_infos, bp_threshold, non_fork_bp_count); } bool pbft_database::is_valid_committed_certificate(const pbft_committed_certificate &certificate) { // an empty certificate is valid since it acts as a null digest in pbft. - if (certificate == pbft_committed_certificate{}) return true; + if (certificate.empty()) return true; // a certificate under lscb (no longer in fork_db) is also treated as null. - if (certificate.block.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; + if (certificate.block_info.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; auto valid = true; - for (auto const &c : certificate.messages) { + for (auto const &c : certificate.commits) { valid = valid && is_valid_commit(c); if (!valid) return false; } - auto cert_id = certificate.block.block_id; + 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(); - if (certificate.block.block_num > 0 && cert_bs) { + if (certificate.block_info.block_num > 0 && cert_bs) { producer_schedule = cert_bs->active_schedule; } auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; - auto commits = certificate.messages; + auto commits = certificate.commits; flat_map commit_count; for (const auto &pre: commits) { @@ -802,7 +804,7 @@ namespace eosio { 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; + if (sp.block_signing_key == pp.msg_header.public_key) commit_count[pp.view] += 1; } } @@ -819,23 +821,23 @@ namespace eosio { //validate commit auto lscb = ctrl.last_stable_checkpoint_block_num(); auto non_fork_bp_count = 0; - vector commit_infos; - for (auto const &p : certificate.messages) { + vector commit_infos; + for (auto const &p : certificate.commits) { //only search in fork db - if (p.block.block_num <= lscb) { + if (p.block_info.block_num <= lscb) { ++non_fork_bp_count; } else { - commit_infos.emplace_back(p.block); + commit_infos.emplace_back(p.block_info); } } - return is_valid_longest_fork(certificate.block, commit_infos, bp_threshold, non_fork_bp_count); + return is_valid_longest_fork(certificate.block_info, commit_infos, bp_threshold, non_fork_bp_count); } bool pbft_database::is_valid_view_change(const pbft_view_change &vc) { - if (vc.chain_id != chain_id) return false; + if (vc.msg_header.chain_id != chain_id) return false; return vc.is_signature_valid() - && should_recv_pbft_msg(vc.public_key); + && should_recv_pbft_msg(vc.msg_header.public_key); // No need to check prepared cert and stable checkpoint, until generate or validate a new view msg } @@ -843,25 +845,25 @@ namespace eosio { bool pbft_database::is_valid_new_view(const pbft_new_view &nv) { //all signatures should be valid - EOS_ASSERT(nv.chain_id == chain_id, pbft_exception, "wrong chain."); + EOS_ASSERT(nv.msg_header.chain_id == chain_id, pbft_exception, "wrong chain."); EOS_ASSERT(nv.is_signature_valid(), pbft_exception, "bad new view signature"); - EOS_ASSERT(nv.public_key == get_new_view_primary_key(nv.view), pbft_exception, "new view is not signed with expected key"); + EOS_ASSERT(nv.msg_header.public_key == get_new_view_primary_key(nv.new_view), pbft_exception, "new view is not signed with expected key"); - EOS_ASSERT(is_valid_prepared_certificate(nv.prepared), pbft_exception, - "bad prepared certificate: ${pc}", ("pc", nv.prepared)); + EOS_ASSERT(is_valid_prepared_certificate(nv.prepared_cert), pbft_exception, + "bad prepared certificate: ${pc}", ("pc", nv.prepared_cert)); EOS_ASSERT(is_valid_stable_checkpoint(nv.stable_checkpoint), pbft_exception, "bad stable checkpoint: ${scp}", ("scp", nv.stable_checkpoint)); - for (auto const &c: nv.committed) { + for (auto const &c: nv.committed_cert) { EOS_ASSERT(is_valid_committed_certificate(c), pbft_exception, "bad committed certificate: ${cc}", ("cc", c)); } EOS_ASSERT(nv.is_signature_valid(), pbft_exception, "bad new view signature"); - EOS_ASSERT(nv.view_changed.view == nv.view, pbft_exception, "target view not match"); + EOS_ASSERT(nv.view_changed_cert.target_view == nv.new_view, pbft_exception, "target view not match"); vector lscb_producers; for (const auto& pk: lscb_active_producers().producers) { @@ -871,10 +873,10 @@ namespace eosio { vector view_change_producers; - for (auto vc: nv.view_changed.messages) { + for (auto vc: nv.view_changed_cert.view_changes) { if (is_valid_view_change(vc)) { add_pbft_view_change(vc); - view_change_producers.emplace_back(vc.public_key); + view_change_producers.emplace_back(vc.msg_header.public_key); } } @@ -888,37 +890,37 @@ namespace eosio { EOS_ASSERT(intersection.size() >= schedule_threshold, pbft_exception, "view changes count not enough"); - EOS_ASSERT(should_new_view(nv.view), pbft_exception, "should not enter new view: ${nv}", ("nv", nv.view)); + EOS_ASSERT(should_new_view(nv.new_view), pbft_exception, "should not enter new view: ${nv}", ("nv", nv.new_view)); auto highest_ppc = pbft_prepared_certificate{}; auto highest_pcc = vector{}; auto highest_scp = pbft_stable_checkpoint{}; - for (const auto &vc: nv.view_changed.messages) { - if (vc.prepared.block.block_num > highest_ppc.block.block_num - && is_valid_prepared_certificate(vc.prepared)) { - highest_ppc = vc.prepared; + for (const auto &vc: nv.view_changed_cert.view_changes) { + if (vc.prepared_cert.block_info.block_num > highest_ppc.block_info.block_num + && is_valid_prepared_certificate(vc.prepared_cert)) { + highest_ppc = vc.prepared_cert; } - for (auto const &cc: vc.committed) { + for (auto const &cc: vc.committed_cert) { if (is_valid_committed_certificate(cc)) { auto p_itr = find_if(highest_pcc.begin(), highest_pcc.end(), - [&](const pbft_committed_certificate &ext) { return ext.block.block_id == cc.block.block_id; }); + [&](const pbft_committed_certificate &ext) { return ext.block_info.block_id == cc.block_info.block_id; }); if (p_itr == highest_pcc.end()) highest_pcc.emplace_back(cc); } } - if (vc.stable_checkpoint.block.block_num > highest_scp.block.block_num + if (vc.stable_checkpoint.block_info.block_num > highest_scp.block_info.block_num && is_valid_stable_checkpoint(vc.stable_checkpoint)) { highest_scp = vc.stable_checkpoint; } } - EOS_ASSERT(highest_ppc == nv.prepared, pbft_exception, + EOS_ASSERT(highest_ppc == nv.prepared_cert, pbft_exception, "prepared certificate not match, should be ${hpcc} but ${pc} given", - ("hpcc",highest_ppc)("pc", nv.prepared)); + ("hpcc",highest_ppc)("pc", nv.prepared_cert)); - EOS_ASSERT(highest_pcc == nv.committed, pbft_exception, "committed certificate not match"); + EOS_ASSERT(highest_pcc == nv.committed_cert, 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", @@ -929,23 +931,23 @@ namespace eosio { bool pbft_database::should_stop_view_change(const pbft_view_change &vc) { auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - return lscb_num > vc.prepared.block.block_num - && lscb_num > vc.stable_checkpoint.block.block_num; + return lscb_num > vc.prepared_cert.block_info.block_num + && lscb_num > vc.stable_checkpoint.block_info.block_num; } - vector> pbft_database::fetch_fork_from(vector &block_infos) { + vector> pbft_database::fetch_fork_from(vector &block_infos) { - vector> result; + vector> result; if (block_infos.empty()) { return result; } if (block_infos.size() == 1) { - result.emplace_back(initializer_list{block_infos.front()}); + result.emplace_back(initializer_list{block_infos.front()}); return result; } sort(block_infos.begin(), block_infos.end(), - [](const block_info &a, const block_info &b) -> bool { return a.block_num > b.block_num; }); + [](const block_info_type &a, const block_info_type &b) -> bool { return a.block_num > b.block_num; }); while (!block_infos.empty()) { auto fork = fetch_first_fork_from(block_infos); @@ -956,8 +958,8 @@ namespace eosio { return result; } - vector pbft_database::fetch_first_fork_from(vector &bi) { - vector result; + vector pbft_database::fetch_first_fork_from(vector &bi) { + vector result; if (bi.empty()) { return result; } @@ -997,10 +999,10 @@ 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) { + bool pbft_database::is_valid_longest_fork(const block_info_type &bi, vector block_infos, unsigned long threshold, unsigned long non_fork_bp_count) { auto forks = fetch_fork_from(block_infos); - vector longest_fork; + vector longest_fork; for (auto const &f : forks) { if (f.size() > longest_fork.size()) { longest_fork = f; @@ -1064,17 +1066,17 @@ namespace eosio { if (cpp->is_stable) { if (ctrl.my_signature_providers().empty()) return pbft_stable_checkpoint{}; pbft_stable_checkpoint psc; - psc.block={cpp->block_id, cpp->block_num}; psc.messages=cpp->checkpoints; psc.chain_id=chain_id; + psc.block_info={cpp->block_id, cpp->block_num}; psc.checkpoints=cpp->checkpoints;; return psc; } else return pbft_stable_checkpoint{}; } - block_info pbft_database::cal_pending_stable_checkpoint() const { + block_info_type pbft_database::cal_pending_stable_checkpoint() const { //TODO: maybe use watermarks instead? auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto lscb_id = ctrl.last_stable_checkpoint_block_id(); - auto lscb_info = block_info{lscb_id, lscb_num}; + auto lscb_info = block_info_type{lscb_id, lscb_num}; const auto &by_blk_num = checkpoint_index.get(); auto itr = by_blk_num.lower_bound(lscb_num); @@ -1156,7 +1158,7 @@ namespace eosio { bool contains_mine = false; for (auto const &my_sp : ctrl.my_signature_providers()) { auto p_itr = find_if(checkpoints.begin(), checkpoints.end(), - [&](const pbft_checkpoint &ext) { return ext.public_key == my_sp.first; }); + [&](const pbft_checkpoint &ext) { return ext.msg_header.public_key == my_sp.first; }); if (p_itr != checkpoints.end()) contains_mine = true; } if (!contains_mine) { @@ -1174,7 +1176,7 @@ namespace eosio { for (auto const &my_sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); pbft_checkpoint cp; - cp.uuid=uuid; cp.block={bs->id, bnum}; cp.public_key=my_sp.first; cp.chain_id=chain_id; + cp.msg_header.uuid=uuid; cp.block_info={bs->id, bnum}; cp.msg_header.public_key=my_sp.first; cp.msg_header.chain_id=chain_id; cp.producer_signature = my_sp.second(cp.digest()); add_pbft_checkpoint(cp); new_pc.emplace_back(cp); @@ -1189,11 +1191,11 @@ namespace eosio { auto checkpoints = (*h_itr)->checkpoints; for (auto const &my_sp : ctrl.my_signature_providers()) { for (auto const &cp: checkpoints) { - if (my_sp.first == cp.public_key) { + if (my_sp.first == cp.msg_header.public_key) { auto retry_cp = cp; auto uuid = boost::uuids::to_string(uuid_generator()); - retry_cp.uuid = uuid; - retry_cp.timestamp = time_point::now(); + retry_cp.msg_header.uuid = uuid; + retry_cp.msg_header.timestamp = time_point::now(); retry_cp.producer_signature = my_sp.second(retry_cp.digest()); new_pc.emplace_back(retry_cp); } @@ -1209,26 +1211,26 @@ namespace eosio { if (!is_valid_checkpoint(cp)) return; - auto cp_block_state = ctrl.fetch_block_state_by_id(cp.block.block_id); + auto cp_block_state = ctrl.fetch_block_state_by_id(cp.block_info.block_id); if (!cp_block_state) return; auto active_bps = cp_block_state->active_schedule.producers; auto checkpoint_count = count_if(active_bps.begin(), active_bps.end(), [&](const producer_key &p) { - return p.block_signing_key == cp.public_key; + return p.block_signing_key == cp.msg_header.public_key; }); if (checkpoint_count == 0) return; auto &by_block = checkpoint_index.get(); - auto itr = by_block.find(cp.block.block_id); + auto itr = by_block.find(cp.block_info.block_id); if (itr == by_block.end()) { - auto cs = pbft_checkpoint_state{cp.block.block_id, cp.block.block_num, .checkpoints={cp}}; + auto cs = pbft_checkpoint_state{cp.block_info.block_id, cp.block_info.block_num, .checkpoints={cp}}; auto csp = make_shared(cs); checkpoint_index.insert(csp); - itr = by_block.find(cp.block.block_id); + itr = by_block.find(cp.block_info.block_id); } else { auto csp = (*itr); auto checkpoints = csp->checkpoints; auto p_itr = find_if(checkpoints.begin(), checkpoints.end(), - [&](const pbft_checkpoint &existed) { return existed.public_key == cp.public_key; }); + [&](const pbft_checkpoint &existed) { return existed.msg_header.public_key == cp.msg_header.public_key; }); if (p_itr == checkpoints.end()) { by_block.modify(itr, [&](const pbft_checkpoint_state_ptr &pcp) { csp->checkpoints.emplace_back(cp); @@ -1241,7 +1243,7 @@ namespace eosio { if (!csp->is_stable) { for (auto const &sp: active_bps) { for (auto const &pp: csp->checkpoints) { - if (sp.block_signing_key == pp.public_key) cp_count += 1; + if (sp.block_signing_key == pp.msg_header.public_key) cp_count += 1; } } if (cp_count >= active_bps.size() * 2 / 3 + 1) { @@ -1299,40 +1301,41 @@ namespace eosio { } bool pbft_database::is_valid_checkpoint(const pbft_checkpoint &cp) { + if (!(is_valid_pbft_message_header(cp.msg_header) && cp.is_signature_valid())) return false; - if (cp.block.block_num > ctrl.head_block_num() - || cp.block.block_num <= ctrl.last_stable_checkpoint_block_num() + if (cp.block_info.block_num > ctrl.head_block_num() + || cp.block_info.block_num <= ctrl.last_stable_checkpoint_block_num() || !cp.is_signature_valid()) return false; - auto bs = ctrl.fetch_block_state_by_id(cp.block.block_id); + auto bs = ctrl.fetch_block_state_by_id(cp.block_info.block_id); if (bs) { auto active_bps = bs->active_schedule.producers; for (const auto &bp: active_bps) { - if (bp.block_signing_key == cp.public_key) return true; + if (bp.block_signing_key == cp.msg_header.public_key) return true; } } return false; } bool pbft_database::is_valid_stable_checkpoint(const pbft_stable_checkpoint &scp) { - if (scp.block.block_num <= ctrl.last_stable_checkpoint_block_num()) + if (scp.block_info.block_num <= ctrl.last_stable_checkpoint_block_num()) // the stable checkpoint is way behind lib, no way getting the block state, // it will not be applied nor saved, thus considered safe. return true; auto valid = true; - for (const auto &c: scp.messages) { - valid = valid && is_valid_checkpoint(c) && c.block == scp.block; + for (const auto &c: scp.checkpoints) { + valid = valid && is_valid_checkpoint(c) && c.block_info == scp.block_info; if (!valid) return false; } - auto bs = ctrl.fetch_block_state_by_number(scp.block.block_num); + auto bs = ctrl.fetch_block_state_by_number(scp.block_info.block_num); if (bs) { auto as = bs->active_schedule; auto cp_count = 0; for (auto const &sp: as.producers) { - for (auto const &v: scp.messages) { - if (sp.block_signing_key == v.public_key) cp_count += 1; + for (auto const &v: scp.checkpoints) { + if (sp.block_signing_key == v.msg_header.public_key) cp_count += 1; } } valid = valid && cp_count >= as.producers.size() * 2 / 3 + 1; @@ -1342,6 +1345,10 @@ namespace eosio { return valid; } + bool pbft_database::is_valid_pbft_message_header(const pbft_message_header &msg_header) { + return msg_header.chain_id == chain_id; + } + bool pbft_database::should_send_pbft_msg() { auto my_sp = ctrl.my_signature_providers(); @@ -1493,13 +1500,13 @@ namespace eosio { return fork_schedules; } - void pbft_database::set(pbft_state_ptr s) { + void pbft_database::set(const pbft_state_ptr& s) { auto result = pbft_state_index.insert(s); EOS_ASSERT(result.second, pbft_exception, "unable to insert pbft state, duplicate state detected"); } - void pbft_database::set(pbft_checkpoint_state_ptr s) { + void pbft_database::set(const pbft_checkpoint_state_ptr& s) { auto result = checkpoint_index.insert(s); EOS_ASSERT(result.second, pbft_exception, "unable to insert pbft checkpoint index, duplicate state detected"); diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 965acc44a35..1caabd56acd 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -1209,8 +1209,8 @@ read_only::get_info_results read_only::get_info(const read_only::get_info_params db.fork_db_head_block_id(), db.fork_db_head_block_time(), db.fork_db_head_block_producer(), - pbft_ctrl.state_machine.get_current_view(), - pbft_ctrl.state_machine.get_target_view(), + pbft_ctrl.state_machine->get_current_view(), + pbft_ctrl.state_machine->get_target_view(), db.last_stable_checkpoint_block_num(), rm.get_virtual_block_cpu_limit(), rm.get_virtual_block_net_limit(), diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 3f7a85c2224..c3ba5c98a30 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -2971,13 +2971,13 @@ namespace eosio { template bool net_plugin_impl::is_pbft_msg_outdated(M const & msg) { - return (time_point_sec(time_point::now()) > time_point_sec(msg.timestamp) + pbft_message_TTL); + return (time_point_sec(time_point::now()) > time_point_sec(msg.msg_header.timestamp) + pbft_message_TTL); } template bool net_plugin_impl::is_pbft_msg_valid(M const & msg) { // Do some basic validations of an incoming pbft msg, bad msgs should be quickly discarded without affecting state. - return chain_id == msg.chain_id + return chain_id == msg.msg_header.chain_id && !is_pbft_msg_outdated(msg) && !sync_master->is_syncing(); } @@ -3005,58 +3005,58 @@ namespace eosio { } void net_plugin_impl::pbft_outgoing_prepare(const pbft_prepare &msg) { - auto added = maybe_add_to_pbft_cache(msg.uuid); + auto added = maybe_add_to_pbft_cache(msg.msg_header.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_prepare(msg)) return; bcast_pbft_msg(msg, pbft_message_TTL); - fc_dlog( logger, "sent prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block.block_num)("v", msg.view)("k", msg.public_key)); + fc_dlog( logger, "sent prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num)("v", msg.view)("k", msg.msg_header.public_key)); } void net_plugin_impl::pbft_outgoing_commit(const pbft_commit &msg) { - auto added = maybe_add_to_pbft_cache(msg.uuid); + auto added = maybe_add_to_pbft_cache(msg.msg_header.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_commit(msg)) return; bcast_pbft_msg(msg, pbft_message_TTL); - fc_dlog( logger, "sent commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block.block_num)("v", msg.view)("k", msg.public_key)); + fc_dlog( logger, "sent commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num)("v", msg.view)("k", msg.msg_header.public_key)); } void net_plugin_impl::pbft_outgoing_view_change(const pbft_view_change &msg) { - auto added = maybe_add_to_pbft_cache(msg.uuid); + auto added = maybe_add_to_pbft_cache(msg.msg_header.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_view_change(msg)) return; bcast_pbft_msg(msg, pbft_message_TTL); - fc_dlog( logger, "sent view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", msg.current_view)("tv", msg.target_view)("v", msg.public_key)); + fc_dlog( logger, "sent view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", msg.current_view)("tv", msg.target_view)("v", msg.msg_header.public_key)); } void net_plugin_impl::pbft_outgoing_new_view(const pbft_new_view &msg) { - auto added = maybe_add_to_pbft_cache(msg.uuid); + auto added = maybe_add_to_pbft_cache(msg.msg_header.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_new_view(msg)) return; bcast_pbft_msg(msg, INT_MAX); - fc_dlog( logger, "sent new view at view: ${v}, from ${k}, ", ("v", msg.view)("k", msg.public_key)); + fc_dlog( logger, "sent new view at view: ${v}, from ${k}, ", ("v", msg.new_view)("k", msg.msg_header.public_key)); } void net_plugin_impl::pbft_outgoing_checkpoint(const pbft_checkpoint &msg) { - auto added = maybe_add_to_pbft_cache(msg.uuid); + auto added = maybe_add_to_pbft_cache(msg.msg_header.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_checkpoint(msg)) return; bcast_pbft_msg(msg, pbft_message_TTL); - fc_dlog( logger, "sent checkpoint at height: ${n}, from ${k}, ", ("n", msg.block.block_num)("k", msg.public_key)); + fc_dlog( logger, "sent checkpoint at height: ${n}, from ${k}, ", ("n", msg.block_info.block_num)("k", msg.msg_header.public_key)); } bool net_plugin_impl::maybe_add_to_pbft_cache(const string &uuid){ @@ -3085,14 +3085,14 @@ namespace eosio { if (!is_pbft_msg_valid(msg)) return; - auto added = maybe_add_to_pbft_cache(msg.uuid); + auto added = maybe_add_to_pbft_cache(msg.msg_header.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_prepare(msg)) return; forward_pbft_msg(c, msg, pbft_message_TTL); - fc_dlog( logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block.block_num)("v", msg.view)("k", msg.public_key)); + fc_dlog( logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num)("v", msg.view)("k", msg.msg_header.public_key)); pbft_incoming_prepare_channel.publish(msg); @@ -3102,14 +3102,14 @@ namespace eosio { if (!is_pbft_msg_valid(msg)) return; - auto added = maybe_add_to_pbft_cache(msg.uuid); + auto added = maybe_add_to_pbft_cache(msg.msg_header.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_commit(msg)) return; forward_pbft_msg(c, msg, pbft_message_TTL); - fc_dlog( logger, "received commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block.block_num)("v", msg.view)("k", msg.public_key)); + fc_dlog( logger, "received commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num)("v", msg.view)("k", msg.msg_header.public_key)); pbft_incoming_commit_channel.publish(msg); } @@ -3118,30 +3118,30 @@ namespace eosio { if (!is_pbft_msg_valid(msg)) return; - auto added = maybe_add_to_pbft_cache(msg.uuid); + auto added = maybe_add_to_pbft_cache(msg.msg_header.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_view_change(msg)) return; forward_pbft_msg(c, msg, pbft_message_TTL); - fc_dlog( logger, "received view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", msg.current_view)("tv", msg.target_view)("v", msg.public_key)); + fc_dlog( logger, "received view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", msg.current_view)("tv", msg.target_view)("v", msg.msg_header.public_key)); pbft_incoming_view_change_channel.publish(msg); } void net_plugin_impl::handle_message( connection_ptr c, const pbft_new_view &msg) { - if (chain_id != msg.chain_id) return; + if (chain_id != msg.msg_header.chain_id) return; - auto added = maybe_add_to_pbft_cache(msg.uuid); + auto added = maybe_add_to_pbft_cache(msg.msg_header.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!(msg.public_key == pcc.pbft_db.get_new_view_primary_key(msg.view) && msg.is_signature_valid())) return; + if (!(msg.msg_header.public_key == pcc.pbft_db.get_new_view_primary_key(msg.new_view) && msg.is_signature_valid())) return; forward_pbft_msg(c, msg, INT_MAX); - fc_dlog( logger, "received new view: ${n}, from ${v}", ("n", msg)("v", msg.public_key)); + fc_dlog( logger, "received new view: ${n}, from ${v}", ("n", msg)("v", msg.msg_header.public_key)); pbft_incoming_new_view_channel.publish(msg); } @@ -3166,26 +3166,26 @@ namespace eosio { if (!is_pbft_msg_valid(msg)) return; - auto added = maybe_add_to_pbft_cache(msg.uuid); + auto added = maybe_add_to_pbft_cache(msg.msg_header.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_checkpoint(msg)) return; forward_pbft_msg(c, msg, pbft_message_TTL); - fc_dlog( logger, "received checkpoint at ${n}, from ${v}", ("n", msg.block.block_num)("v", msg.public_key)); + fc_dlog( logger, "received checkpoint at ${n}, from ${v}", ("n", msg.block_info.block_num)("v", msg.msg_header.public_key)); pbft_incoming_checkpoint_channel.publish(msg); } void net_plugin_impl::handle_message( connection_ptr c, const pbft_stable_checkpoint &msg) { - if (chain_id != msg.chain_id) return; + //TODO: if (chain_id != msg.msg_header.chain_id) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (pcc.pbft_db.is_valid_stable_checkpoint(msg)) { - fc_ilog(logger, "received stable checkpoint at ${n}, from ${v}", ("n", msg.block.block_num)("v", c->peer_name())); - for (auto cp: msg.messages) { + fc_ilog(logger, "received stable checkpoint at ${n}, from ${v}", ("n", msg.block_info.block_num)("v", c->peer_name())); + for (auto cp: msg.checkpoints) { pbft_incoming_checkpoint_channel.publish(cp); } } diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index d320d31526a..188afe2c6dd 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -92,7 +92,7 @@ namespace eosio { const char* pbft_plugin::get_pbft_status() const { pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - return pbft_ctrl.state_machine.get_current()->get_name(); + return pbft_ctrl.state_machine->get_current()->get_name(); } block_id_type pbft_plugin::get_pbft_prepared_id() const { @@ -108,7 +108,7 @@ namespace eosio { void pbft_plugin::set_pbft_current_view(const pbft_view_type view) { //this is used to boost the recovery from a disaster, do not set this unless you have to do so. pbft_controller& pbft_ctrl = app().get_plugin().pbft_ctrl(); - pbft_ctrl.state_machine.manually_set_current_view(view); + pbft_ctrl.state_machine->manually_set_current_view(view); } void pbft_plugin_impl::prepare_timer_tick() { diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index e2bf7918272..de7fa10d0e7 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -187,6 +187,40 @@ void push_blocks( tester& from, tester& to ) { } } +BOOST_AUTO_TEST_CASE(view_change_validation) { + tester tester; + controller &ctrl = *tester.control; + pbft_controller pbft_ctrl{ctrl}; + + auto msp = make_signature_provider(); + ctrl.set_my_signature_providers(msp); + + ctrl.set_upo(48); + + 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(100); + + pbft_ctrl.maybe_pbft_prepare(); + pbft_ctrl.maybe_pbft_commit(); + tester.produce_blocks(1); + + BOOST_CHECK_EQUAL(ctrl.is_pbft_enabled(), true); + BOOST_CHECK_EQUAL(ctrl.head_block_num(), 101); + + + for(int i = 0; i< pbft_ctrl.config.view_change_timeout; i++){ + pbft_ctrl.maybe_pbft_view_change(); + } + pbft_ctrl.state_machine.send_pbft_view_change(); + auto new_view = pbft_ctrl.pbft_db.get_proposed_new_view_num(); + auto vcc = pbft_ctrl.pbft_db.generate_view_changed_certificate(new_view); + auto nv_msg = pbft_ctrl.pbft_db.send_pbft_new_view(vcc, new_view); + + nv_msg.msg_header.public_key = tester::get_public_key( N(bob), "active"); + BOOST_CHECK_EQUAL(pbft_ctrl.pbft_db.is_valid_new_view(nv_msg), false); +} + 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(); From 7c9404e1a0be6869511e665511d00f0855be4750 Mon Sep 17 00:00:00 2001 From: oldcold Date: Thu, 6 Jun 2019 16:10:52 +0800 Subject: [PATCH 17/22] remove pbft controller config; fix net layer bugs. --- libraries/chain/include/eosio/chain/pbft.hpp | 17 +- .../include/eosio/chain/pbft_database.hpp | 215 ++++++++---------- libraries/chain/pbft.cpp | 13 +- libraries/chain/pbft_database.cpp | 128 ++++++----- .../include/eosio/net_plugin/protocol.hpp | 2 +- plugins/net_plugin/net_plugin.cpp | 66 +++--- plugins/pbft_plugin/pbft_plugin.cpp | 4 +- unittests/pbft_tests.cpp | 14 +- 8 files changed, 216 insertions(+), 243 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index cb397b61a9a..8b0b5338ff8 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -207,19 +207,14 @@ namespace eosio { const char* get_name() override { return "{==== VIEW CHANGE ====}"; } }; - struct pbft_config { - uint32_t view_change_timeout = 6; - bool bp_candidate = false; - }; - class pbft_controller { public: explicit pbft_controller(controller& ctrl); ~pbft_controller(); + const uint16_t view_change_timeout = 6; - pbft_database pbft_db; - std::shared_ptr state_machine; - pbft_config config; + pbft_database pbft_db; + std::shared_ptr state_machine; void maybe_pbft_prepare(); void maybe_pbft_commit(); @@ -233,11 +228,9 @@ namespace eosio { void on_pbft_checkpoint(pbft_checkpoint &cp); private: - fc::path datadir; - - + fc::path datadir; }; } } /// namespace eosio::chain -FC_REFLECT(eosio::chain::pbft_controller, (pbft_db)(state_machine)(config)) \ No newline at end of file +FC_REFLECT(eosio::chain::pbft_controller, (pbft_db)(state_machine)) \ No newline at end of file diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index fcbd8fcaba8..186e3e801e3 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -31,8 +31,8 @@ namespace eosio { }; struct block_info_type { - block_id_type block_id; - block_num_type block_num = 0; + block_id_type block_id; + block_num_type block_num = 0; bool operator==(const block_info_type &rhs) const { return block_id == rhs.block_id && block_num == rhs.block_num; @@ -43,35 +43,40 @@ namespace eosio { } }; - struct pbft_message_header { - explicit pbft_message_header(const pbft_message_type t) {type = t;} + struct pbft_message_common { + pbft_message_type type; + explicit pbft_message_common(pbft_message_type t): type{t} {}; - pbft_message_type type; - string uuid; - public_key_type public_key; - chain_id_type chain_id = chain_id_type(""); - time_point timestamp = time_point::now(); + string uuid; + public_key_type sender; + chain_id_type chain_id = chain_id_type(""); + time_point timestamp = time_point::now(); - - bool operator==(const pbft_message_header &rhs) const { + bool operator==(const pbft_message_common &rhs) const { return type == rhs.type && chain_id == rhs.chain_id - && public_key == rhs.public_key; + && sender == rhs.sender; } - ~pbft_message_header() = default; + bool empty() const { + return uuid == string() + && sender == public_key_type() + && chain_id == chain_id_type(""); + } + + ~pbft_message_common() = default; }; struct pbft_prepare { explicit pbft_prepare() = default; - pbft_message_header msg_header = pbft_message_header(pbft_message_type::prepare); - pbft_view_type view = 0; - block_info_type block_info; - signature_type producer_signature; + pbft_message_common common = pbft_message_common(pbft_message_type::prepare); + pbft_view_type view = 0; + block_info_type block_info; + signature_type sender_signature; bool operator==(const pbft_prepare &rhs) const { - return msg_header == rhs.msg_header + return common == rhs.common && view == rhs.view && block_info == rhs.block_info; } @@ -88,7 +93,7 @@ namespace eosio { digest_type digest() const { digest_type::encoder enc; - fc::raw::pack(enc, msg_header); + fc::raw::pack(enc, common); fc::raw::pack(enc, view); fc::raw::pack(enc, block_info); return enc.result(); @@ -96,8 +101,8 @@ namespace eosio { bool is_signature_valid() const { try { - auto pk = crypto::public_key(producer_signature, digest(), true); - return msg_header.public_key == pk; + auto pk = crypto::public_key(sender_signature, digest(), true); + return common.sender == pk; } catch (fc::exception & /*e*/) { return false; } @@ -107,13 +112,13 @@ namespace eosio { struct pbft_commit { explicit pbft_commit() = default; - pbft_message_header msg_header = pbft_message_header(pbft_message_type::commit); - pbft_view_type view = 0; - block_info_type block_info; - signature_type producer_signature; + pbft_message_common common = pbft_message_common(pbft_message_type::commit); + pbft_view_type view = 0; + block_info_type block_info; + signature_type sender_signature; bool operator==(const pbft_commit &rhs) const { - return msg_header == rhs.msg_header + return common == rhs.common && view == rhs.view && block_info == rhs.block_info; } @@ -130,7 +135,7 @@ namespace eosio { digest_type digest() const { digest_type::encoder enc; - fc::raw::pack(enc, msg_header); + fc::raw::pack(enc, common); fc::raw::pack(enc, view); fc::raw::pack(enc, block_info); return enc.result(); @@ -138,8 +143,8 @@ namespace eosio { bool is_signature_valid() const { try { - auto pk = crypto::public_key(producer_signature, digest(), true); - return msg_header.public_key == pk; + auto pk = crypto::public_key(sender_signature, digest(), true); + return common.sender == pk; } catch (fc::exception & /*e*/) { return false; } @@ -149,12 +154,12 @@ namespace eosio { struct pbft_checkpoint { explicit pbft_checkpoint() = default; - pbft_message_header msg_header = pbft_message_header(pbft_message_type::checkpoint); - block_info_type block_info; - signature_type producer_signature; + pbft_message_common common = pbft_message_common(pbft_message_type::checkpoint); + block_info_type block_info; + signature_type sender_signature; bool operator==(const pbft_checkpoint &rhs) const { - return msg_header == rhs.msg_header + return common == rhs.common && block_info == rhs.block_info; } @@ -168,15 +173,15 @@ namespace eosio { digest_type digest() const { digest_type::encoder enc; - fc::raw::pack(enc, msg_header); + fc::raw::pack(enc, common); fc::raw::pack(enc, block_info); return enc.result(); } bool is_signature_valid() const { try { - auto pk = crypto::public_key(producer_signature, digest(), true); - return msg_header.public_key == pk; + auto pk = crypto::public_key(sender_signature, digest(), true); + return common.sender == pk; } catch (fc::exception & /*e*/) { return false; } @@ -186,87 +191,61 @@ namespace eosio { struct pbft_stable_checkpoint { explicit pbft_stable_checkpoint() = default; - block_info_type block_info; + block_info_type block_info; vector checkpoints; - //TODO: should contains chain id? - - bool operator==(const pbft_stable_checkpoint &rhs) const { - return block_info == rhs.block_info - && checkpoints == rhs.checkpoints; - } bool operator<(const pbft_stable_checkpoint &rhs) const { return block_info.block_num < rhs.block_info.block_num; } - bool operator!=(const pbft_stable_checkpoint &rhs) const { - return !(*this == rhs); - } - bool empty() const { - return (*this == pbft_stable_checkpoint()); + return block_info == block_info_type() + && checkpoints.empty(); } }; struct pbft_prepared_certificate { explicit pbft_prepared_certificate() = default; - block_info_type block_info; + block_info_type block_info; vector prepares; - bool operator==(const pbft_prepared_certificate &rhs) const { - return block_info == rhs.block_info; - //TODO: should compare messages? - } - bool operator<(const pbft_prepared_certificate &rhs) const { return block_info.block_num < rhs.block_info.block_num; } bool empty() const { - return (*this == pbft_prepared_certificate()); + return block_info == block_info_type() + && prepares.empty(); } }; struct pbft_committed_certificate { explicit pbft_committed_certificate() = default; - block_info_type block_info; + block_info_type block_info; vector commits; - bool operator==(const pbft_committed_certificate &rhs) const { - return block_info == rhs.block_info; - } - bool operator<(const pbft_committed_certificate &rhs) const { return block_info.block_num < rhs.block_info.block_num; } bool empty() const { - return *this == pbft_committed_certificate(); + return block_info == block_info_type() + && commits.empty(); } }; - struct pbft_view_change { explicit pbft_view_change() = default; - pbft_message_header msg_header = pbft_message_header(pbft_message_type::view_change); - pbft_view_type current_view = 0; - pbft_view_type target_view = 1; - pbft_prepared_certificate prepared_cert; - vector committed_cert; - pbft_stable_checkpoint stable_checkpoint; - signature_type producer_signature; - - bool operator==(const pbft_view_change &rhs) const { - return msg_header == rhs.msg_header - && current_view == rhs.current_view - && target_view == rhs.target_view - && prepared_cert == rhs.prepared_cert - && committed_cert == rhs.committed_cert - && stable_checkpoint == rhs.stable_checkpoint; - } + pbft_message_common common = pbft_message_common(pbft_message_type::view_change); + pbft_view_type current_view = 0; + pbft_view_type target_view = 1; + pbft_prepared_certificate prepared_cert; + vector committed_cert; + pbft_stable_checkpoint stable_checkpoint; + signature_type sender_signature; bool operator<(const pbft_view_change &rhs) const { return target_view < rhs.target_view; @@ -274,7 +253,7 @@ namespace eosio { digest_type digest() const { digest_type::encoder enc; - fc::raw::pack(enc, msg_header); + fc::raw::pack(enc, common); fc::raw::pack(enc, current_view); fc::raw::pack(enc, target_view); fc::raw::pack(enc, prepared_cert); @@ -285,50 +264,46 @@ namespace eosio { bool is_signature_valid() const { try { - auto pk = crypto::public_key(producer_signature, digest(), true); - return msg_header.public_key == pk; + auto pk = crypto::public_key(sender_signature, digest(), true); + return common.sender == pk; } catch (fc::exception & /*e*/) { return false; } } + + bool empty() const { + return common.empty() + && current_view == 0 + && target_view == 0 + && prepared_cert.empty() + && committed_cert.empty() + && stable_checkpoint.empty() + && sender_signature == signature_type(); + } }; struct pbft_view_changed_certificate { explicit pbft_view_changed_certificate() = default; - uint32_t target_view = 0; - vector view_changes; - - bool operator==(const pbft_view_changed_certificate &rhs) const { - return target_view == rhs.target_view - && view_changes == rhs.view_changes; - //TODO: should include chain id? - } + pbft_view_type target_view = 0; + vector view_changes; bool empty() const { - return *this == pbft_view_changed_certificate(); + return target_view == 0 + && view_changes.empty(); } }; struct pbft_new_view { explicit pbft_new_view() = default; - pbft_message_header msg_header = pbft_message_header(pbft_message_type::new_view); - pbft_view_type new_view = 0; - pbft_prepared_certificate prepared_cert; - vector committed_cert; - pbft_stable_checkpoint stable_checkpoint; - pbft_view_changed_certificate view_changed_cert; - signature_type producer_signature; - - bool operator==(const pbft_new_view &rhs) const { - return msg_header == rhs.msg_header - && new_view == rhs.new_view - && prepared_cert == rhs.prepared_cert - && committed_cert == rhs.committed_cert - && stable_checkpoint == rhs.stable_checkpoint - && view_changed_cert == rhs.view_changed_cert; - } + pbft_message_common common = pbft_message_common(pbft_message_type::new_view); + pbft_view_type new_view = 0; + pbft_prepared_certificate prepared_cert; + vector committed_cert; + pbft_stable_checkpoint stable_checkpoint; + pbft_view_changed_certificate view_changed_cert; + signature_type sender_signature; bool operator<(const pbft_new_view &rhs) const { return new_view < rhs.new_view; @@ -336,7 +311,7 @@ namespace eosio { digest_type digest() const { digest_type::encoder enc; - fc::raw::pack(enc, msg_header); + fc::raw::pack(enc, common); fc::raw::pack(enc, new_view); fc::raw::pack(enc, prepared_cert); fc::raw::pack(enc, committed_cert); @@ -347,15 +322,21 @@ namespace eosio { bool is_signature_valid() const { try { - auto pk = crypto::public_key(producer_signature, digest(), true); - return msg_header.public_key == pk; + auto pk = crypto::public_key(sender_signature, digest(), true); + return common.sender == pk; } catch (fc::exception & /*e*/) { return false; } } bool empty() const { - return *this == pbft_new_view(); + return common.empty() + && new_view == 0 + && prepared_cert.empty() + && committed_cert.empty() + && stable_checkpoint.empty() + && view_changed_cert.empty() + && sender_signature == signature_type(); } }; @@ -597,7 +578,7 @@ namespace eosio { vector prepare_watermarks; flat_map fork_schedules; - bool is_valid_pbft_message_header(const pbft_message_header &msg_header); + bool is_valid_pbft_message_header(const pbft_message_common &common); bool is_valid_prepared_certificate(const pbft_prepared_certificate &certificate); @@ -632,12 +613,12 @@ namespace eosio { FC_REFLECT(eosio::chain::block_info_type, (block_id)(block_num)) FC_REFLECT_ENUM(eosio::chain::pbft_message_type, (prepare)(commit)(checkpoint)(view_change)(new_view)) -FC_REFLECT(eosio::chain::pbft_message_header, (type)(uuid)(public_key)(chain_id)(timestamp)) -FC_REFLECT(eosio::chain::pbft_prepare, (msg_header)(view)(block_info)(producer_signature)) -FC_REFLECT(eosio::chain::pbft_commit, (msg_header)(view)(block_info)(producer_signature)) -FC_REFLECT(eosio::chain::pbft_checkpoint,(msg_header)(block_info)(producer_signature)) -FC_REFLECT(eosio::chain::pbft_view_change, (msg_header)(current_view)(target_view)(prepared_cert)(committed_cert)(stable_checkpoint)(producer_signature)) -FC_REFLECT(eosio::chain::pbft_new_view, (msg_header)(new_view)(prepared_cert)(committed_cert)(stable_checkpoint)(view_changed_cert)(producer_signature)) +FC_REFLECT(eosio::chain::pbft_message_common, (type)(uuid)(sender)(chain_id)(timestamp)) +FC_REFLECT(eosio::chain::pbft_prepare, (common)(view)(block_info)(sender_signature)) +FC_REFLECT(eosio::chain::pbft_commit, (common)(view)(block_info)(sender_signature)) +FC_REFLECT(eosio::chain::pbft_checkpoint,(common)(block_info)(sender_signature)) +FC_REFLECT(eosio::chain::pbft_view_change, (common)(current_view)(target_view)(prepared_cert)(committed_cert)(stable_checkpoint)(sender_signature)) +FC_REFLECT(eosio::chain::pbft_new_view, (common)(new_view)(prepared_cert)(committed_cert)(stable_checkpoint)(view_changed_cert)(sender_signature)) FC_REFLECT(eosio::chain::pbft_prepared_certificate, (block_info)(prepares)) diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 122f594d2a0..1e9e81cf371 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -8,8 +8,6 @@ namespace eosio { pbft_controller::pbft_controller(controller &ctrl) : pbft_db(ctrl), state_machine(new psm_machine(pbft_db)) { - config.view_change_timeout = 6; - config.bp_candidate = true; datadir = ctrl.state_dir(); if (!fc::is_directory(datadir)) @@ -24,7 +22,6 @@ namespace eosio { uint32_t current_view; fc::raw::unpack(ds, current_view); state_machine->set_current_view(current_view); - state_machine->set_target_view(state_machine->get_current_view() + 1); ilog("current view: ${cv}", ("cv", current_view)); } @@ -53,7 +50,7 @@ namespace eosio { void pbft_controller::maybe_pbft_view_change() { if (!pbft_db.should_send_pbft_msg()) return; - if (state_machine->get_view_change_timer() <= config.view_change_timeout) { + if (state_machine->get_view_change_timer() <= view_change_timeout) { if (!state_machine->get_view_changes_cache().empty()) { pbft_db.send_and_add_pbft_view_change(state_machine->get_view_changes_cache()); } @@ -65,22 +62,18 @@ namespace eosio { } void pbft_controller::on_pbft_prepare(pbft_prepare &p) { - if (!config.bp_candidate) return; state_machine->on_prepare(p); } void pbft_controller::on_pbft_commit(pbft_commit &c) { - if (!config.bp_candidate) return; state_machine->on_commit(c); } void pbft_controller::on_pbft_view_change(pbft_view_change &vc) { - if (!config.bp_candidate) return; state_machine->on_view_change(vc); } void pbft_controller::on_pbft_new_view(pbft_new_view &nv) { - if (!config.bp_candidate) return; state_machine->on_new_view(nv); } @@ -437,7 +430,7 @@ namespace eosio { get_view_changed_certificate(), new_view); - if (nv_msg == pbft_new_view{}) return false; + if (nv_msg.empty()) return false; try { transit_to_new_view(nv_msg, s); @@ -469,7 +462,7 @@ namespace eosio { pbft_db.prune_pbft_index(); - if (!(new_view.stable_checkpoint == pbft_stable_checkpoint{})) { + if (!(new_view.stable_checkpoint.empty())) { for (auto cp :new_view.stable_checkpoint.checkpoints) { try { pbft_db.add_pbft_checkpoint(cp); diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index a419ad3e0dd..e0779c37127 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -116,7 +116,7 @@ namespace eosio { auto prepares = (*curr_itr)->prepares; auto p_itr = find_if(prepares.begin(), prepares.end(), [&](const pbft_prepare &prep) { - return prep.msg_header.public_key == p.msg_header.public_key + return prep.common.sender == p.common.sender && prep.view == p.view; }); if (p_itr == prepares.end()) { @@ -139,7 +139,7 @@ namespace eosio { if (!(*curr_itr)->should_prepared) { for (auto const &sp: as) { for (auto const &pp: prepares) { - if (sp.block_signing_key == pp.msg_header.public_key) prepare_count[pp.view] += 1; + if (sp.block_signing_key == pp.common.sender) prepare_count[pp.view] += 1; } } for (auto const &e: prepare_count) { @@ -173,9 +173,9 @@ namespace eosio { for (auto p : pv) { //change uuid, sign again, update cache, then emit auto uuid = boost::uuids::to_string(uuid_generator()); - p.msg_header.uuid = uuid; - p.msg_header.timestamp = time_point::now(); - p.producer_signature = ctrl.my_signature_providers()[p.msg_header.public_key](p.digest()); + p.common.uuid = uuid; + p.common.timestamp = time_point::now(); + p.sender_signature = ctrl.my_signature_providers()[p.common.sender](p.digest()); emit(pbft_outgoing_prepare, p); } return vector{}; @@ -184,8 +184,8 @@ namespace eosio { auto uuid = boost::uuids::to_string(uuid_generator()); auto my_prepare_num = ctrl.fetch_block_state_by_id(my_prepare)->block_num; pbft_prepare p; - p.msg_header.uuid=uuid; p.view=current_view; p.block_info={my_prepare, my_prepare_num}; p.msg_header.public_key=sp.first; p.msg_header.chain_id=chain_id; - p.producer_signature = sp.second(p.digest()); + p.common.uuid=uuid; p.view=current_view; p.block_info={my_prepare, my_prepare_num}; p.common.sender=sp.first; p.common.chain_id=chain_id; + p.sender_signature = sp.second(p.digest()); emit(pbft_outgoing_prepare, p); new_pv.emplace_back(p); } @@ -208,8 +208,8 @@ namespace eosio { for (auto const &sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); pbft_prepare p; - p.msg_header.uuid=uuid; p.view=current_view; p.block_info={hwbs->id, high_watermark_block_num}; p.msg_header.public_key=sp.first; p.msg_header.chain_id=chain_id; - p.producer_signature = sp.second(p.digest()); + p.common.uuid=uuid; p.view=current_view; p.block_info={hwbs->id, high_watermark_block_num}; p.common.sender=sp.first; p.common.chain_id=chain_id; + p.sender_signature = sp.second(p.digest()); add_pbft_prepare(p); emit(pbft_outgoing_prepare, p); new_pv.emplace_back(p); @@ -239,11 +239,11 @@ namespace eosio { } bool pbft_database::is_valid_prepare(const pbft_prepare &p) { - if (!is_valid_pbft_message_header(p.msg_header)) return false; + if (!is_valid_pbft_message_header(p.common)) return false; // a prepare msg under lscb (which is no longer in fork_db), can be treated as null, thus true. if (p.block_info.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; if (!p.is_signature_valid()) return false; - return should_recv_pbft_msg(p.msg_header.public_key); + return should_recv_pbft_msg(p.common.sender); } void pbft_database::add_pbft_commit(pbft_commit &c) { @@ -269,7 +269,7 @@ namespace eosio { auto commits = (*curr_itr)->commits; auto p_itr = find_if(commits.begin(), commits.end(), [&](const pbft_commit &comm) { - return comm.msg_header.public_key == c.msg_header.public_key + return comm.common.sender == c.common.sender && comm.view == c.view; }); if (p_itr == commits.end()) { @@ -295,7 +295,7 @@ namespace eosio { for (auto const &sp: as.producers) { for (auto const &pc: commits) { - if (sp.block_signing_key == pc.msg_header.public_key) commit_count[pc.view] += 1; + if (sp.block_signing_key == pc.common.sender) commit_count[pc.view] += 1; } } @@ -315,9 +315,9 @@ namespace eosio { for (auto c : cv) { //change uuid, sign again, update cache, then emit auto uuid = boost::uuids::to_string(uuid_generator()); - c.msg_header.uuid = uuid; - c.msg_header.timestamp = time_point::now(); - c.producer_signature = ctrl.my_signature_providers()[c.msg_header.public_key](c.digest()); + c.common.uuid = uuid; + c.common.timestamp = time_point::now(); + c.sender_signature = ctrl.my_signature_providers()[c.common.sender](c.digest()); emit(pbft_outgoing_commit, c); } return vector{}; @@ -336,8 +336,8 @@ namespace eosio { for (auto const &sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); pbft_commit c; - c.msg_header.uuid=uuid; c.view=current_view; c.block_info={psp->block_id, psp->block_num}; c.msg_header.public_key=sp.first; c.msg_header.chain_id=chain_id; - c.producer_signature = sp.second(c.digest()); + c.common.uuid=uuid; c.view=current_view; c.block_info={psp->block_id, psp->block_num}; c.common.sender=sp.first; c.common.chain_id=chain_id; + c.sender_signature = sp.second(c.digest()); add_pbft_commit(c); emit(pbft_outgoing_commit, c); new_cv.emplace_back(c); @@ -392,10 +392,10 @@ namespace eosio { } bool pbft_database::is_valid_commit(const pbft_commit &c) { - if (!is_valid_pbft_message_header(c.msg_header)) return false; + if (!is_valid_pbft_message_header(c.common)) return false; if (c.block_info.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; if (!c.is_signature_valid()) return false; - return should_recv_pbft_msg(c.msg_header.public_key); + return should_recv_pbft_msg(c.common.sender); } void pbft_database::commit_local() { @@ -427,7 +427,7 @@ namespace eosio { auto view_changes = pvs->view_changes; auto p_itr = find_if(view_changes.begin(), view_changes.end(), [&](const pbft_view_change &existed) { - return existed.msg_header.public_key == vc.msg_header.public_key; + return existed.common.sender == vc.common.sender; }); if (p_itr == view_changes.end()) { by_view_index.modify(itr, [&](const pbft_view_change_state_ptr &pvsp) { @@ -443,7 +443,7 @@ namespace eosio { if (!(*itr)->should_view_changed) { for (auto const &sp: active_bps) { for (auto const &v: (*itr)->view_changes) { - if (sp.block_signing_key == v.msg_header.public_key) vc_count += 1; + if (sp.block_signing_key == v.common.sender) vc_count += 1; } } if (vc_count >= active_bps.size() * 2 / 3 + 1) { @@ -465,7 +465,7 @@ namespace eosio { for (auto const &bp: active_bps) { for (auto const &pp: pvs->view_changes) { - if (bp.block_signing_key == pp.msg_header.public_key) vc_count += 1; + if (bp.block_signing_key == pp.common.sender) vc_count += 1; } } //if contains self or view_change >= f+1, transit to view_change and send view change @@ -488,9 +488,9 @@ namespace eosio { for (auto vc : vcv) { //change uuid, sign again, update cache, then emit auto uuid = boost::uuids::to_string(uuid_generator()); - vc.msg_header.uuid = uuid; - vc.msg_header.timestamp = time_point::now(); - vc.producer_signature = ctrl.my_signature_providers()[vc.msg_header.public_key](vc.digest()); + vc.common.uuid = uuid; + vc.common.timestamp = time_point::now(); + vc.sender_signature = ctrl.my_signature_providers()[vc.common.sender](vc.digest()); emit(pbft_outgoing_view_change, vc); } return vector{}; @@ -502,8 +502,8 @@ namespace eosio { auto my_lsc = get_stable_checkpoint_by_id(ctrl.last_stable_checkpoint_block_id()); auto uuid = boost::uuids::to_string(uuid_generator()); pbft_view_change vc; - vc.msg_header.uuid=uuid; vc.current_view=current_view; vc.target_view=new_view; vc.prepared_cert=ppc; vc.committed_cert=pcc; vc.stable_checkpoint=my_lsc; vc.msg_header.public_key=my_sp.first; vc.msg_header.chain_id=chain_id; - vc.producer_signature = my_sp.second(vc.digest()); + vc.common.uuid=uuid; vc.current_view=current_view; vc.target_view=new_view; vc.prepared_cert=ppc; vc.committed_cert=pcc; vc.stable_checkpoint=my_lsc; vc.common.sender=my_sp.first; vc.common.chain_id=chain_id; + vc.sender_signature = my_sp.second(vc.digest()); emit(pbft_outgoing_view_change, vc); add_pbft_view_change(vc); new_vcv.emplace_back(vc); @@ -577,9 +577,9 @@ namespace eosio { auto uuid = boost::uuids::to_string(uuid_generator()); pbft_new_view nv; - nv.msg_header.uuid=uuid; nv.new_view=current_view; nv.prepared_cert=highest_ppc; nv.committed_cert=highest_pcc; nv.stable_checkpoint=highest_sc, nv.view_changed_cert=vcc, nv.msg_header.public_key=sp_itr->first; nv.msg_header.chain_id=chain_id; + nv.common.uuid=uuid; nv.new_view=current_view; nv.prepared_cert=highest_ppc; nv.committed_cert=highest_pcc; nv.stable_checkpoint=highest_sc, nv.view_changed_cert=vcc, nv.common.sender=sp_itr->first; nv.common.chain_id=chain_id; - nv.producer_signature = sp_itr->second(nv.digest()); + nv.sender_signature = sp_itr->second(nv.digest()); emit(pbft_outgoing_new_view, nv); return nv; } @@ -609,7 +609,7 @@ namespace eosio { for (auto const &sp: as) { for (auto const &pp: prepares) { - if (sp.block_signing_key == pp.msg_header.public_key) prepare_count[pp.view] += 1; + if (sp.block_signing_key == pp.common.sender) prepare_count[pp.view] += 1; } } @@ -679,7 +679,7 @@ namespace eosio { for (auto const &sp: as) { for (auto const &cc: commits) { - if (sp.block_signing_key == cc.msg_header.public_key) commit_count[cc.view] += 1; + if (sp.block_signing_key == cc.common.sender) commit_count[cc.view] += 1; } } @@ -746,7 +746,7 @@ namespace eosio { for (auto const &sp: producer_schedule.producers) { for (auto const &pp: prepares) { - if (sp.block_signing_key == pp.msg_header.public_key) prepare_count[pp.view] += 1; + if (sp.block_signing_key == pp.common.sender) prepare_count[pp.view] += 1; } } @@ -804,7 +804,7 @@ namespace eosio { for (auto const &sp: producer_schedule.producers) { for (auto const &pp: commits) { - if (sp.block_signing_key == pp.msg_header.public_key) commit_count[pp.view] += 1; + if (sp.block_signing_key == pp.common.sender) commit_count[pp.view] += 1; } } @@ -834,10 +834,10 @@ namespace eosio { } bool pbft_database::is_valid_view_change(const pbft_view_change &vc) { - if (vc.msg_header.chain_id != chain_id) return false; + if (vc.common.chain_id != chain_id) return false; return vc.is_signature_valid() - && should_recv_pbft_msg(vc.msg_header.public_key); + && should_recv_pbft_msg(vc.common.sender); // No need to check prepared cert and stable checkpoint, until generate or validate a new view msg } @@ -845,11 +845,11 @@ namespace eosio { bool pbft_database::is_valid_new_view(const pbft_new_view &nv) { //all signatures should be valid - EOS_ASSERT(nv.msg_header.chain_id == chain_id, pbft_exception, "wrong chain."); + EOS_ASSERT(nv.common.chain_id == chain_id, pbft_exception, "wrong chain."); EOS_ASSERT(nv.is_signature_valid(), pbft_exception, "bad new view signature"); - EOS_ASSERT(nv.msg_header.public_key == get_new_view_primary_key(nv.new_view), pbft_exception, "new view is not signed with expected key"); + EOS_ASSERT(nv.common.sender == get_new_view_primary_key(nv.new_view), pbft_exception, "new view is not signed with expected key"); EOS_ASSERT(is_valid_prepared_certificate(nv.prepared_cert), pbft_exception, "bad prepared certificate: ${pc}", ("pc", nv.prepared_cert)); @@ -876,7 +876,7 @@ namespace eosio { for (auto vc: nv.view_changed_cert.view_changes) { if (is_valid_view_change(vc)) { add_pbft_view_change(vc); - view_change_producers.emplace_back(vc.msg_header.public_key); + view_change_producers.emplace_back(vc.common.sender); } } @@ -916,14 +916,22 @@ namespace eosio { } } - EOS_ASSERT(highest_ppc == nv.prepared_cert, pbft_exception, - "prepared certificate not match, should be ${hpcc} but ${pc} given", - ("hpcc",highest_ppc)("pc", nv.prepared_cert)); + EOS_ASSERT(highest_ppc.block_info == nv.prepared_cert.block_info, pbft_exception, + "prepared certificate does not match, should be ${hppc} but ${pc} given", + ("hppc",highest_ppc)("pc", nv.prepared_cert)); - EOS_ASSERT(highest_pcc == nv.committed_cert, pbft_exception, "committed certificate not match"); + std::sort(highest_pcc.begin(), highest_pcc.end()); + auto committed_certs = nv.committed_cert; + std::sort(committed_certs.begin(), committed_certs.end()); + EOS_ASSERT(highest_pcc.size() == committed_certs.size(), pbft_exception, "wrong committed certificates size"); + for (auto i = 0; i < committed_certs.size(); ++i) { + EOS_ASSERT(highest_pcc[i].block_info == committed_certs[i].block_info, pbft_exception, + "committed certificate does not match, should be ${hpcc} but ${cc} given", + ("hpcc",highest_pcc[i])("cc", committed_certs[i])); + } - EOS_ASSERT(highest_scp == nv.stable_checkpoint, pbft_exception, - "stable checkpoint not match, should be ${hscp} but ${scp} given", + EOS_ASSERT(highest_scp.block_info == nv.stable_checkpoint.block_info, pbft_exception, + "stable checkpoint does not match, should be ${hscp} but ${scp} given", ("hpcc",highest_scp)("pc", nv.stable_checkpoint)); return true; @@ -1158,7 +1166,7 @@ namespace eosio { bool contains_mine = false; for (auto const &my_sp : ctrl.my_signature_providers()) { auto p_itr = find_if(checkpoints.begin(), checkpoints.end(), - [&](const pbft_checkpoint &ext) { return ext.msg_header.public_key == my_sp.first; }); + [&](const pbft_checkpoint &ext) { return ext.common.sender == my_sp.first; }); if (p_itr != checkpoints.end()) contains_mine = true; } if (!contains_mine) { @@ -1176,8 +1184,8 @@ namespace eosio { for (auto const &my_sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); pbft_checkpoint cp; - cp.msg_header.uuid=uuid; cp.block_info={bs->id, bnum}; cp.msg_header.public_key=my_sp.first; cp.msg_header.chain_id=chain_id; - cp.producer_signature = my_sp.second(cp.digest()); + cp.common.uuid=uuid; cp.block_info={bs->id, bnum}; cp.common.sender=my_sp.first; cp.common.chain_id=chain_id; + cp.sender_signature = my_sp.second(cp.digest()); add_pbft_checkpoint(cp); new_pc.emplace_back(cp); } @@ -1191,12 +1199,12 @@ namespace eosio { auto checkpoints = (*h_itr)->checkpoints; for (auto const &my_sp : ctrl.my_signature_providers()) { for (auto const &cp: checkpoints) { - if (my_sp.first == cp.msg_header.public_key) { + if (my_sp.first == cp.common.sender) { auto retry_cp = cp; auto uuid = boost::uuids::to_string(uuid_generator()); - retry_cp.msg_header.uuid = uuid; - retry_cp.msg_header.timestamp = time_point::now(); - retry_cp.producer_signature = my_sp.second(retry_cp.digest()); + retry_cp.common.uuid = uuid; + retry_cp.common.timestamp = time_point::now(); + retry_cp.sender_signature = my_sp.second(retry_cp.digest()); new_pc.emplace_back(retry_cp); } } @@ -1215,7 +1223,7 @@ namespace eosio { if (!cp_block_state) return; auto active_bps = cp_block_state->active_schedule.producers; auto checkpoint_count = count_if(active_bps.begin(), active_bps.end(), [&](const producer_key &p) { - return p.block_signing_key == cp.msg_header.public_key; + return p.block_signing_key == cp.common.sender; }); if (checkpoint_count == 0) return; @@ -1230,7 +1238,7 @@ namespace eosio { auto csp = (*itr); auto checkpoints = csp->checkpoints; auto p_itr = find_if(checkpoints.begin(), checkpoints.end(), - [&](const pbft_checkpoint &existed) { return existed.msg_header.public_key == cp.msg_header.public_key; }); + [&](const pbft_checkpoint &existed) { return existed.common.sender == cp.common.sender; }); if (p_itr == checkpoints.end()) { by_block.modify(itr, [&](const pbft_checkpoint_state_ptr &pcp) { csp->checkpoints.emplace_back(cp); @@ -1243,7 +1251,7 @@ namespace eosio { if (!csp->is_stable) { for (auto const &sp: active_bps) { for (auto const &pp: csp->checkpoints) { - if (sp.block_signing_key == pp.msg_header.public_key) cp_count += 1; + if (sp.block_signing_key == pp.common.sender) cp_count += 1; } } if (cp_count >= active_bps.size() * 2 / 3 + 1) { @@ -1301,7 +1309,7 @@ namespace eosio { } bool pbft_database::is_valid_checkpoint(const pbft_checkpoint &cp) { - if (!(is_valid_pbft_message_header(cp.msg_header) && cp.is_signature_valid())) return false; + if (!(is_valid_pbft_message_header(cp.common) && cp.is_signature_valid())) return false; if (cp.block_info.block_num > ctrl.head_block_num() || cp.block_info.block_num <= ctrl.last_stable_checkpoint_block_num() @@ -1311,7 +1319,7 @@ namespace eosio { if (bs) { auto active_bps = bs->active_schedule.producers; for (const auto &bp: active_bps) { - if (bp.block_signing_key == cp.msg_header.public_key) return true; + if (bp.block_signing_key == cp.common.sender) return true; } } return false; @@ -1335,7 +1343,7 @@ namespace eosio { auto cp_count = 0; for (auto const &sp: as.producers) { for (auto const &v: scp.checkpoints) { - if (sp.block_signing_key == v.msg_header.public_key) cp_count += 1; + if (sp.block_signing_key == v.common.sender) cp_count += 1; } } valid = valid && cp_count >= as.producers.size() * 2 / 3 + 1; @@ -1345,8 +1353,8 @@ namespace eosio { return valid; } - bool pbft_database::is_valid_pbft_message_header(const pbft_message_header &msg_header) { - return msg_header.chain_id == chain_id; + bool pbft_database::is_valid_pbft_message_header(const pbft_message_common &common) { + return common.chain_id == chain_id; } bool pbft_database::should_send_pbft_msg() { diff --git a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp index fdb39c847de..73a2e9caa04 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp @@ -148,7 +148,7 @@ struct request_p2p_message{ }; struct compressed_pbft_message { - std::shared_ptr > content; + std::vector content; }; using net_message = static_variant compress_pbft(const std::shared_ptr>& m)const; - std::vector decompress_pbft(const std::shared_ptr>& m)const; + std::vector decompress_pbft(const std::vector& m)const; std::shared_ptr> encode_pbft_message(const net_message &msg, bool compress = false)const; public: net_plugin_impl(); @@ -1611,7 +1611,7 @@ namespace eosio { void sync_manager::sync_stable_checkpoints(const connection_ptr& c, uint32_t target) { controller& cc = chain_plug->chain(); uint32_t lscb_num = cc.last_stable_checkpoint_block_num(); - if (last_req_scp_num < lscb_num || last_req_scp_num == 0) last_req_scp_num = lscb_num; + if (last_req_scp_num < lscb_num || last_req_scp_num == 0 || last_req_scp_num >= target) last_req_scp_num = lscb_num; auto end = target; auto max_target_scp_num = last_req_scp_num + pbft_checkpoint_granularity * 10; if (target > max_target_scp_num) end = max_target_scp_num; @@ -1660,7 +1660,7 @@ namespace eosio { auto upgraded = cc.is_pbft_enabled(); if (upgraded && peer_lib > lscb_num - && head - lscb_num >= pbft_checkpoint_granularity * 2) + && (head - lscb_num) / pbft_checkpoint_granularity > 1) { //there might be a better way to sync checkpoints, yet we do not want to modify the existing handshake msg. fc_dlog(logger, "request sync checkpoints"); @@ -2085,14 +2085,14 @@ namespace eosio { return out; } - std::vector net_plugin_impl::decompress_pbft(const std::shared_ptr>& m) const { + std::vector net_plugin_impl::decompress_pbft(const std::vector& m) const { try { std::vector out; bio::filtering_ostream decomp; decomp.push(bio::zlib_decompressor()); decomp.push(read_limiter<1*1024*1024>()); // limit to 10 megs decompressed for zip bomb protections decomp.push(bio::back_inserter(out)); - bio::write(decomp, m->data(), m->size()); + bio::write(decomp, m.data(), m.size()); bio::close(decomp); return out; } catch( fc::exception& er ) { @@ -2118,8 +2118,7 @@ namespace eosio { auto out_buffer = send_buffer; if (compress) { - auto compressed_msg = std::make_shared>(compress_pbft(send_buffer)); - auto cpnv = compressed_pbft_message{compressed_msg}; + auto cpnv = compressed_pbft_message{ compress_pbft(send_buffer) }; payload_size = fc::raw::pack_size( cpnv ); header = reinterpret_cast(&payload_size); @@ -2856,7 +2855,7 @@ namespace eosio { 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 != pbft_stable_checkpoint{}) { + if (!scp.empty()) { scp_stack.push_back(scp); } } @@ -2940,7 +2939,7 @@ namespace eosio { auto &pcc = chain_plug->pbft_ctrl(); auto scp = pcc.pbft_db.fetch_stable_checkpoint_from_blk_extn(blk); - if (scp != pbft_stable_checkpoint{}) { + if (!scp.empty()) { handle_message(c, scp); } } catch( const unlinkable_block_exception &ex) { @@ -2986,13 +2985,13 @@ namespace eosio { template bool net_plugin_impl::is_pbft_msg_outdated(M const & msg) { - return (time_point_sec(time_point::now()) > time_point_sec(msg.msg_header.timestamp) + pbft_message_TTL); + return (time_point_sec(time_point::now()) > time_point_sec(msg.common.timestamp) + pbft_message_TTL); } template bool net_plugin_impl::is_pbft_msg_valid(M const & msg) { // Do some basic validations of an incoming pbft msg, bad msgs should be quickly discarded without affecting state. - return chain_id == msg.msg_header.chain_id + return chain_id == msg.common.chain_id && !is_pbft_msg_outdated(msg) && !sync_master->is_syncing(); } @@ -3020,58 +3019,58 @@ namespace eosio { } void net_plugin_impl::pbft_outgoing_prepare(const pbft_prepare &msg) { - auto added = maybe_add_to_pbft_cache(msg.msg_header.uuid); + auto added = maybe_add_to_pbft_cache(msg.common.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_prepare(msg)) return; bcast_pbft_msg(msg, pbft_message_TTL); - fc_dlog( logger, "sent prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num)("v", msg.view)("k", msg.msg_header.public_key)); + fc_dlog( logger, "sent prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num)("v", msg.view)("k", msg.common.sender)); } void net_plugin_impl::pbft_outgoing_commit(const pbft_commit &msg) { - auto added = maybe_add_to_pbft_cache(msg.msg_header.uuid); + auto added = maybe_add_to_pbft_cache(msg.common.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_commit(msg)) return; bcast_pbft_msg(msg, pbft_message_TTL); - fc_dlog( logger, "sent commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num)("v", msg.view)("k", msg.msg_header.public_key)); + fc_dlog( logger, "sent commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num)("v", msg.view)("k", msg.common.sender)); } void net_plugin_impl::pbft_outgoing_view_change(const pbft_view_change &msg) { - auto added = maybe_add_to_pbft_cache(msg.msg_header.uuid); + auto added = maybe_add_to_pbft_cache(msg.common.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_view_change(msg)) return; bcast_pbft_msg(msg, pbft_message_TTL); - fc_dlog( logger, "sent view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", msg.current_view)("tv", msg.target_view)("v", msg.msg_header.public_key)); + fc_dlog( logger, "sent view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", msg.current_view)("tv", msg.target_view)("v", msg.common.sender)); } void net_plugin_impl::pbft_outgoing_new_view(const pbft_new_view &msg) { - auto added = maybe_add_to_pbft_cache(msg.msg_header.uuid); + auto added = maybe_add_to_pbft_cache(msg.common.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_new_view(msg)) return; bcast_pbft_msg(msg, INT_MAX); - fc_dlog( logger, "sent new view at view: ${v}, from ${k}, ", ("v", msg.new_view)("k", msg.msg_header.public_key)); + fc_dlog( logger, "sent new view at view: ${v}, from ${k}, ", ("v", msg.new_view)("k", msg.common.sender)); } void net_plugin_impl::pbft_outgoing_checkpoint(const pbft_checkpoint &msg) { - auto added = maybe_add_to_pbft_cache(msg.msg_header.uuid); + auto added = maybe_add_to_pbft_cache(msg.common.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_checkpoint(msg)) return; bcast_pbft_msg(msg, pbft_message_TTL); - fc_dlog( logger, "sent checkpoint at height: ${n}, from ${k}, ", ("n", msg.block_info.block_num)("k", msg.msg_header.public_key)); + fc_dlog( logger, "sent checkpoint at height: ${n}, from ${k}, ", ("n", msg.block_info.block_num)("k", msg.common.sender)); } bool net_plugin_impl::maybe_add_to_pbft_cache(const string &uuid){ @@ -3100,14 +3099,14 @@ namespace eosio { if (!is_pbft_msg_valid(msg)) return; - auto added = maybe_add_to_pbft_cache(msg.msg_header.uuid); + auto added = maybe_add_to_pbft_cache(msg.common.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_prepare(msg)) return; forward_pbft_msg(c, msg, pbft_message_TTL); - fc_dlog( logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num)("v", msg.view)("k", msg.msg_header.public_key)); + fc_dlog( logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num)("v", msg.view)("k", msg.common.sender)); pbft_incoming_prepare_channel.publish(msg); @@ -3117,14 +3116,14 @@ namespace eosio { if (!is_pbft_msg_valid(msg)) return; - auto added = maybe_add_to_pbft_cache(msg.msg_header.uuid); + auto added = maybe_add_to_pbft_cache(msg.common.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_commit(msg)) return; forward_pbft_msg(c, msg, pbft_message_TTL); - fc_dlog( logger, "received commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num)("v", msg.view)("k", msg.msg_header.public_key)); + fc_dlog( logger, "received commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num)("v", msg.view)("k", msg.common.sender)); pbft_incoming_commit_channel.publish(msg); } @@ -3133,30 +3132,30 @@ namespace eosio { if (!is_pbft_msg_valid(msg)) return; - auto added = maybe_add_to_pbft_cache(msg.msg_header.uuid); + auto added = maybe_add_to_pbft_cache(msg.common.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_view_change(msg)) return; forward_pbft_msg(c, msg, pbft_message_TTL); - fc_dlog( logger, "received view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", msg.current_view)("tv", msg.target_view)("v", msg.msg_header.public_key)); + fc_dlog( logger, "received view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", msg.current_view)("tv", msg.target_view)("v", msg.common.sender)); pbft_incoming_view_change_channel.publish(msg); } void net_plugin_impl::handle_message( connection_ptr c, const pbft_new_view &msg) { - if (chain_id != msg.msg_header.chain_id) return; + if (chain_id != msg.common.chain_id) return; - auto added = maybe_add_to_pbft_cache(msg.msg_header.uuid); + auto added = maybe_add_to_pbft_cache(msg.common.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); - if (!(msg.msg_header.public_key == pcc.pbft_db.get_new_view_primary_key(msg.new_view) && msg.is_signature_valid())) return; + if (!(msg.common.sender == pcc.pbft_db.get_new_view_primary_key(msg.new_view) && msg.is_signature_valid())) return; forward_pbft_msg(c, msg, INT_MAX); - fc_dlog( logger, "received new view: ${n}, from ${v}", ("n", msg)("v", msg.msg_header.public_key)); + fc_dlog( logger, "received new view: ${n}, from ${v}", ("n", msg)("v", msg.common.sender)); pbft_incoming_new_view_channel.publish(msg); } @@ -3181,20 +3180,19 @@ namespace eosio { if (!is_pbft_msg_valid(msg)) return; - auto added = maybe_add_to_pbft_cache(msg.msg_header.uuid); + auto added = maybe_add_to_pbft_cache(msg.common.uuid); if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (!pcc.pbft_db.is_valid_checkpoint(msg)) return; forward_pbft_msg(c, msg, pbft_message_TTL); - fc_dlog( logger, "received checkpoint at ${n}, from ${v}", ("n", msg.block_info.block_num)("v", msg.msg_header.public_key)); + fc_dlog( logger, "received checkpoint at ${n}, from ${v}", ("n", msg.block_info.block_num)("v", msg.common.sender)); pbft_incoming_checkpoint_channel.publish(msg); } void net_plugin_impl::handle_message( connection_ptr c, const pbft_stable_checkpoint &msg) { - //TODO: if (chain_id != msg.msg_header.chain_id) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); diff --git a/plugins/pbft_plugin/pbft_plugin.cpp b/plugins/pbft_plugin/pbft_plugin.cpp index 188afe2c6dd..10f2a1af06c 100644 --- a/plugins/pbft_plugin/pbft_plugin.cpp +++ b/plugins/pbft_plugin/pbft_plugin.cpp @@ -18,7 +18,7 @@ namespace eosio { boost::asio::steady_timer::duration prepare_timeout{std::chrono::milliseconds{1000}}; boost::asio::steady_timer::duration commit_timeout{std::chrono::milliseconds{1000}}; - boost::asio::steady_timer::duration view_change_timeout{std::chrono::seconds{5}}; + boost::asio::steady_timer::duration view_change_check_interval{std::chrono::seconds{5}}; boost::asio::steady_timer::duration checkpoint_timeout{std::chrono::seconds{50}}; void prepare_timer_tick(); @@ -144,7 +144,7 @@ namespace eosio { } catch (boost::system::system_error &e) { elog("view change timer cancel error: ${e}", ("e", e.what())); } - view_change_timer->expires_from_now(view_change_timeout); + view_change_timer->expires_from_now(view_change_check_interval); view_change_timer->async_wait([&](boost::system::error_code ec) { view_change_timer_tick(); if (ec) { diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index de7fa10d0e7..af00cb8cefa 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -209,15 +209,15 @@ BOOST_AUTO_TEST_CASE(view_change_validation) { BOOST_CHECK_EQUAL(ctrl.head_block_num(), 101); - for(int i = 0; i< pbft_ctrl.config.view_change_timeout; i++){ + for(int i = 0; i< pbft_ctrl.view_change_timeout; i++){ pbft_ctrl.maybe_pbft_view_change(); } - pbft_ctrl.state_machine.send_pbft_view_change(); + pbft_ctrl.state_machine->send_pbft_view_change(); auto new_view = pbft_ctrl.pbft_db.get_proposed_new_view_num(); auto vcc = pbft_ctrl.pbft_db.generate_view_changed_certificate(new_view); auto nv_msg = pbft_ctrl.pbft_db.send_pbft_new_view(vcc, new_view); - nv_msg.msg_header.public_key = tester::get_public_key( N(bob), "active"); + nv_msg.common.sender = tester::get_public_key( N(bob), "active"); BOOST_CHECK_EQUAL(pbft_ctrl.pbft_db.is_valid_new_view(nv_msg), false); } @@ -296,15 +296,15 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o BOOST_CHECK_EQUAL(ctrl_long_non_prepared_fork.last_irreversible_block_num(), 101); //generate new view with short fork prepare certificate - pbft_new_view_generator.state_machine.set_prepares_cache({}); + pbft_new_view_generator.state_machine->set_prepares_cache({}); 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; isend_pbft_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( @@ -324,7 +324,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.head_block_num(), 137); //can switch fork after apply prepare certificate in new view - pbft_short_prepared_fork.state_machine.on_new_view(nv_msg); + pbft_short_prepared_fork.state_machine->on_new_view(nv_msg); BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.head_block_num(), 136); BOOST_CHECK_EQUAL(ctrl_short_prepared_fork.last_irreversible_block_num(), 101); From 74bde5c757a83768f7c5d6fed6e882bf1db05ba9 Mon Sep 17 00:00:00 2001 From: oldcold Date: Thu, 6 Jun 2019 23:26:28 +0800 Subject: [PATCH 18/22] bug fix: view change certs generation; --- libraries/chain/block_header_state.cpp | 26 +++++------ libraries/chain/block_state.cpp | 8 ++-- libraries/chain/fork_database.cpp | 12 ++--- .../eosio/chain/block_header_state.hpp | 8 ++-- .../chain/include/eosio/chain/block_state.hpp | 4 +- .../include/eosio/chain/fork_database.hpp | 4 +- .../include/eosio/chain/pbft_database.hpp | 4 +- libraries/chain/pbft.cpp | 16 +++---- libraries/chain/pbft_database.cpp | 46 ++++++++++--------- plugins/net_plugin/net_plugin.cpp | 1 - plugins/producer_plugin/producer_plugin.cpp | 12 ++--- 11 files changed, 73 insertions(+), 68 deletions(-) diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index 96838c2fc25..690b10a947e 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -33,7 +33,7 @@ namespace eosio { namespace chain { * contain a transaction mroot, action mroot, or new_producers as those components * are derived from chain state. */ - block_header_state block_header_state::generate_next( block_timestamp_type when, bool new_version )const { + block_header_state block_header_state::generate_next( block_timestamp_type when, bool pbft_enabled )const { block_header_state result; if( when != block_timestamp_type() ) { @@ -65,7 +65,7 @@ namespace eosio { namespace chain { result.pbft_stable_checkpoint_blocknum = pbft_stable_checkpoint_blocknum; - if (new_version) { + if (pbft_enabled) { result.dpos_irreversible_blocknum = dpos_irreversible_blocknum; } else { result.producer_to_last_implied_irb[prokey.producer_name] = result.dpos_proposed_irreversible_blocknum; @@ -81,7 +81,7 @@ namespace eosio { namespace chain { auto num_active_producers = active_schedule.producers.size(); uint32_t required_confs = (uint32_t)(num_active_producers * 2 / 3) + 1; - if (!new_version) { + if (!pbft_enabled) { if (confirm_count.size() < config::maximum_tracked_dpos_confirmations) { result.confirm_count.reserve(confirm_count.size() + 1); result.confirm_count = confirm_count; @@ -97,10 +97,10 @@ namespace eosio { namespace chain { return result; } /// generate_next - bool block_header_state::maybe_promote_pending( bool new_version ) { + bool block_header_state::maybe_promote_pending( bool pbft_enabled ) { bool should_promote_pending = pending_schedule.producers.size(); - if ( !new_version ) { + if ( !pbft_enabled ) { should_promote_pending = should_promote_pending && dpos_irreversible_blocknum >= pending_schedule_lib_num; } @@ -115,7 +115,7 @@ namespace eosio { namespace chain { new_producer_to_last_produced[pro.producer_name] = existing->second; } else { //TODO: max of bft and dpos lib - if (new_version) { + if (pbft_enabled) { new_producer_to_last_produced[pro.producer_name] = bft_irreversible_blocknum; } else { new_producer_to_last_produced[pro.producer_name] = dpos_irreversible_blocknum; @@ -131,7 +131,7 @@ namespace eosio { namespace chain { new_producer_to_last_implied_irb[pro.producer_name] = existing->second; } else { //TODO: max of bft and dpos lib - if (new_version) { + if (pbft_enabled) { new_producer_to_last_implied_irb[pro.producer_name] = bft_irreversible_blocknum; } else { new_producer_to_last_implied_irb[pro.producer_name] = dpos_irreversible_blocknum; @@ -168,13 +168,13 @@ namespace eosio { namespace chain { * * If the header specifies new_producers then apply them accordingly. */ - block_header_state block_header_state::next( const signed_block_header& h, bool skip_validate_signee, bool new_version )const { + block_header_state block_header_state::next( const signed_block_header& h, bool skip_validate_signee, bool pbft_enabled )const { EOS_ASSERT( h.timestamp != block_timestamp_type(), block_validate_exception, "", ("h",h) ); //EOS_ASSERT( h.header_extensions.size() == 0, block_validate_exception, "no supported extensions" ); EOS_ASSERT( h.timestamp > header.timestamp, block_validate_exception, "block must be later in time" ); EOS_ASSERT( h.previous == id, unlinkable_block_exception, "block must link to current state" ); - auto result = generate_next( h.timestamp, new_version); + auto result = generate_next( h.timestamp, pbft_enabled); EOS_ASSERT( result.header.producer == h.producer, wrong_producer, "wrong producer specified" ); EOS_ASSERT( result.header.schedule_version == h.schedule_version, producer_schedule_exception, "schedule_version in signed block is corrupted" ); @@ -189,10 +189,10 @@ namespace eosio { namespace chain { /// must result in header state changes - result.set_confirmed(h.confirmed, new_version); + result.set_confirmed(h.confirmed, pbft_enabled); - auto was_pending_promoted = result.maybe_promote_pending(new_version); + auto was_pending_promoted = result.maybe_promote_pending(pbft_enabled); if( h.new_producers ) { EOS_ASSERT( !was_pending_promoted, producer_schedule_exception, "cannot set pending producer schedule in the same block in which pending was promoted to active" ); @@ -214,7 +214,7 @@ namespace eosio { namespace chain { return result; } /// next - void block_header_state::set_confirmed( uint16_t num_prev_blocks, bool new_version ) { + void block_header_state::set_confirmed( uint16_t num_prev_blocks, bool pbft_enabled ) { /* idump((num_prev_blocks)(confirm_count.size())); @@ -222,7 +222,7 @@ namespace eosio { namespace chain { std::cerr << "confirm_count["<() ) { static_cast(*block) = header; } - block_state::block_state( const block_header_state& prev, signed_block_ptr b, bool skip_validate_signee, bool new_version ) - :block_header_state( prev.next( *b, skip_validate_signee, new_version)), block( move(b) ) + block_state::block_state( const block_header_state& prev, signed_block_ptr b, bool skip_validate_signee, bool pbft_enabled ) + :block_header_state( prev.next( *b, skip_validate_signee, pbft_enabled)), block( move(b) ) { } diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index 24defd10740..35406f7ea91 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -195,7 +195,7 @@ namespace eosio { namespace chain { } } - block_state_ptr fork_database::add( const block_state_ptr& n, bool skip_validate_previous, bool new_version ) { + block_state_ptr fork_database::add( const block_state_ptr& n, bool skip_validate_previous, bool pbft_enabled ) { EOS_ASSERT( n, fork_database_exception, "attempt to add null block state" ); EOS_ASSERT( my->head, fork_db_block_not_found, "no head block set" ); @@ -224,7 +224,7 @@ namespace eosio { namespace chain { auto should_prune_oldest = oldest->block_num < lib; - if (new_version) { + if (pbft_enabled) { should_prune_oldest = should_prune_oldest && oldest->block_num < checkpoint; } @@ -235,7 +235,7 @@ namespace eosio { namespace chain { return n; } - block_state_ptr fork_database::add( signed_block_ptr b, bool skip_validate_signee, bool new_version ) { + block_state_ptr fork_database::add( signed_block_ptr b, bool skip_validate_signee, bool pbft_enabled ) { EOS_ASSERT( b, fork_database_exception, "attempt to add null block" ); EOS_ASSERT( my->head, fork_db_block_not_found, "no head block set" ); const auto& by_id_idx = my->index.get(); @@ -245,9 +245,9 @@ namespace eosio { namespace chain { auto prior = by_id_idx.find( b->previous ); EOS_ASSERT( prior != by_id_idx.end(), unlinkable_block_exception, "unlinkable block", ("id", string(b->id()))("previous", string(b->previous)) ); - auto result = std::make_shared( **prior, move(b), skip_validate_signee, new_version); + auto result = std::make_shared( **prior, move(b), skip_validate_signee, pbft_enabled); EOS_ASSERT( result, fork_database_exception , "fail to add new block state" ); - return add(result, true, new_version); + return add(result, true, pbft_enabled); } const block_state_ptr& fork_database::head()const { return my->head; } @@ -612,7 +612,7 @@ namespace eosio { namespace chain { vector watermarks; auto& pidx = my->index.get(); auto pitr = pidx.begin(); - while (pitr != pidx.end() && (*pitr)->pbft_watermark) { + while (pitr != pidx.end() && (*pitr)->pbft_watermark && (*pitr)->in_current_chain) { watermarks.emplace_back((*pitr)->block_num); ++pitr; } diff --git a/libraries/chain/include/eosio/chain/block_header_state.hpp b/libraries/chain/include/eosio/chain/block_header_state.hpp index a443532013a..56d234cf10b 100644 --- a/libraries/chain/include/eosio/chain/block_header_state.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state.hpp @@ -29,13 +29,13 @@ struct block_header_state { vector confirmations; uint32_t pbft_stable_checkpoint_blocknum = 0; - block_header_state next( const signed_block_header& h, bool trust = false, bool new_version = false)const; - block_header_state generate_next( block_timestamp_type when, bool new_version = false )const; + block_header_state next( const signed_block_header& h, bool trust = false, bool pbft_enabled = false )const; + block_header_state generate_next( block_timestamp_type when, bool pbft_enabled = false )const; void set_new_producers( producer_schedule_type next_pending ); - void set_confirmed( uint16_t num_prev_blocks, bool new_version = false ); + void set_confirmed( uint16_t num_prev_blocks, bool pbft_enabled = false ); void add_confirmation( const header_confirmation& c ); - bool maybe_promote_pending( bool new_version = false); + bool maybe_promote_pending( bool pbft_enabled = false ); bool has_pending_producers()const { return pending_schedule.producers.size(); } diff --git a/libraries/chain/include/eosio/chain/block_state.hpp b/libraries/chain/include/eosio/chain/block_state.hpp index c81efff2717..ef42af36bab 100644 --- a/libraries/chain/include/eosio/chain/block_state.hpp +++ b/libraries/chain/include/eosio/chain/block_state.hpp @@ -13,8 +13,8 @@ namespace eosio { namespace chain { struct block_state : public block_header_state { explicit block_state( const block_header_state& cur ):block_header_state(cur){} - block_state( const block_header_state& prev, signed_block_ptr b, bool skip_validate_signee, bool new_version ); - block_state( const block_header_state& prev, block_timestamp_type when, bool new_version ); + block_state( const block_header_state& prev, signed_block_ptr b, bool skip_validate_signee, bool pbft_enabled ); + block_state( const block_header_state& prev, block_timestamp_type when, bool pbft_enabled ); block_state() = default; /// weak_ptr prev_block_state.... diff --git a/libraries/chain/include/eosio/chain/fork_database.hpp b/libraries/chain/include/eosio/chain/fork_database.hpp index 2e8ff899853..823c65c5b92 100644 --- a/libraries/chain/include/eosio/chain/fork_database.hpp +++ b/libraries/chain/include/eosio/chain/fork_database.hpp @@ -40,8 +40,8 @@ namespace eosio { namespace chain { * block_state and will return a pointer to the new block state or * throw on error. */ - block_state_ptr add( signed_block_ptr b, bool skip_validate_signee, bool new_version ); - block_state_ptr add( const block_state_ptr& next_block, bool skip_validate_previous, bool new_version ); + block_state_ptr add( signed_block_ptr b, bool skip_validate_signee, bool pbft_enabled ); + block_state_ptr add( const block_state_ptr& next_block, bool skip_validate_previous, bool pbft_enabled ); void remove( const block_id_type& id ); void add( const header_confirmation& c ); diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 186e3e801e3..1b1d3b52131 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -578,7 +578,7 @@ namespace eosio { vector prepare_watermarks; flat_map fork_schedules; - bool is_valid_pbft_message_header(const pbft_message_common &common); + bool is_valid_pbft_message(const pbft_message_common &common); bool is_valid_prepared_certificate(const pbft_prepared_certificate &certificate); @@ -596,6 +596,8 @@ namespace eosio { producer_schedule_type lscb_active_producers() const; + vector& get_updated_watermarks(); + template void emit(const Signal &s, Arg &&a); diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 1e9e81cf371..17a5d3ee3e9 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -505,6 +505,14 @@ namespace eosio { void psm_machine::send_pbft_view_change() { + if (get_target_view_retries() < pow(2,get_target_view() - get_current_view() - 1)) { + set_target_view_retries(get_target_view_retries() + 1); + } else { + set_target_view_retries(0); + set_target_view(get_target_view() + 1); + set_view_changes_cache(vector{}); + } + if (get_target_view_retries() == 0) { set_view_changes_cache(vector{}); set_prepared_certificate(pbft_db.generate_prepared_certificate()); @@ -514,14 +522,6 @@ namespace eosio { EOS_ASSERT((get_target_view() > get_current_view()), pbft_exception, "target view should be always greater than current view"); - if (get_target_view_retries() < pow(2,get_target_view() - get_current_view() - 1)) { - set_target_view_retries(get_target_view_retries() + 1); - } else { - set_target_view_retries(0); - set_target_view(get_target_view() + 1); - set_view_changes_cache(vector{}); - } - auto view_changes = pbft_db.send_and_add_pbft_view_change( get_view_changes_cache(), get_prepared_certificate(), diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index e0779c37127..3e997248c87 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -24,9 +24,8 @@ namespace eosio { fc::datastream ds(content.data(), content.size()); - // keep these unused variables. - pbft_view_type current_view; - fc::raw::unpack(ds, current_view); + //skip current_view in pbftdb.dat. + ds.seekp(ds.tellp() + 4); unsigned_int size; fc::raw::unpack(ds, size); @@ -35,7 +34,6 @@ namespace eosio { fc::raw::unpack(ds, s); set(std::make_shared(move(s))); } - } else { pbft_state_index = pbft_state_multi_index_type{}; } @@ -239,7 +237,7 @@ namespace eosio { } bool pbft_database::is_valid_prepare(const pbft_prepare &p) { - if (!is_valid_pbft_message_header(p.common)) return false; + if (!is_valid_pbft_message(p.common)) return false; // a prepare msg under lscb (which is no longer in fork_db), can be treated as null, thus true. if (p.block_info.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; if (!p.is_signature_valid()) return false; @@ -392,7 +390,7 @@ namespace eosio { } bool pbft_database::is_valid_commit(const pbft_commit &c) { - if (!is_valid_pbft_message_header(c.common)) return false; + if (!is_valid_pbft_message(c.common)) return false; if (c.block_info.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; if (!c.is_signature_valid()) return false; return should_recv_pbft_msg(c.common.sender); @@ -622,7 +620,7 @@ namespace eosio { if (valid_prepares.empty()) return pbft_prepared_certificate{}; auto pc = pbft_prepared_certificate{}; - pc.block_info.block_id=psp->block_id; pc.block_info.block_num=psp->block_num; pc.prepares=valid_prepares; + pc.block_info={psp->block_id, psp->block_num}; pc.prepares=valid_prepares; return pc; } else return pbft_prepared_certificate{}; } @@ -642,14 +640,17 @@ namespace eosio { vector ccb; //adding my highest committed cert. - if ( highest_committed_block_num > ctrl.last_stable_checkpoint_block_num() ) { + auto lscb_num = ctrl.last_stable_checkpoint_block_num(); + if ( highest_committed_block_num > lscb_num ) { ccb.emplace_back(highest_committed_block_num); } - update_fork_schedules(); - for (auto i = 0; i < prepare_watermarks.size() && prepare_watermarks[i] < highest_committed_block_num; ++i) { + auto watermarks = get_updated_watermarks(); + for (auto i = 0; i < watermarks.size(); ++i) { //adding committed cert on every water mark. - ccb.emplace_back(prepare_watermarks[i]); + if (watermarks[i] < highest_committed_block_num && watermarks[i] > lscb_num) { + ccb.emplace_back(watermarks[i]); + } } const auto &by_id_index = pbft_state_index.get(); @@ -692,10 +693,8 @@ namespace eosio { if (valid_commits.empty()) return vector{}; auto cc = pbft_committed_certificate{}; - cc.block_info.block_id=cbs->id; cc.block_info.block_num=cbs->block_num; cc.commits=valid_commits; + cc.block_info={cbs->id, cbs->block_num}; cc.commits=valid_commits; pcc.emplace_back(cc); - - } return pcc; } @@ -1146,9 +1145,10 @@ namespace eosio { const auto& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; if (!ctrl.is_pbft_enabled()) return false; if (in <= ucb) return false; + auto watermarks = get_updated_watermarks(); return in == ucb + 1 // checkpoint on first pbft block; || in % 100 == 1 // checkpoint on every 100 block; - || std::find(prepare_watermarks.begin(), prepare_watermarks.end(), in) != prepare_watermarks.end(); // checkpoint on bp schedule change; + || std::find(watermarks.begin(), watermarks.end(), in) != watermarks.end(); // checkpoint on bp schedule change; }; update_fork_schedules(); @@ -1309,7 +1309,7 @@ namespace eosio { } bool pbft_database::is_valid_checkpoint(const pbft_checkpoint &cp) { - if (!(is_valid_pbft_message_header(cp.common) && cp.is_signature_valid())) return false; + if (!(is_valid_pbft_message(cp.common) && cp.is_signature_valid())) return false; if (cp.block_info.block_num > ctrl.head_block_num() || cp.block_info.block_num <= ctrl.last_stable_checkpoint_block_num() @@ -1353,7 +1353,7 @@ namespace eosio { return valid; } - bool pbft_database::is_valid_pbft_message_header(const pbft_message_common &common) { + bool pbft_database::is_valid_pbft_message(const pbft_message_common &common) { return common.chain_id == chain_id; } @@ -1403,14 +1403,14 @@ namespace eosio { } block_num_type pbft_database::get_current_pbft_watermark() { - update_fork_schedules(); auto lib = ctrl.last_irreversible_block_num(); - if (prepare_watermarks.empty()) return 0; + auto watermarks = get_updated_watermarks(); + if (watermarks.empty()) return 0; - auto cw = std::upper_bound(prepare_watermarks.begin(), prepare_watermarks.end(), lib); + auto cw = std::upper_bound(watermarks.begin(), watermarks.end(), lib); - if (cw == prepare_watermarks.end() || *cw <= lib) return 0; + if (cw == watermarks.end() || *cw <= lib) return 0; return *cw; } @@ -1466,7 +1466,11 @@ namespace eosio { fork_schedules[bp.block_signing_key] = lscb_num; } } + } + vector& pbft_database::get_updated_watermarks() { + update_fork_schedules(); + return prepare_watermarks; } pbft_state_ptr pbft_database::get_pbft_state_by_id(const block_id_type& id) const { diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 90526bce227..f570a43914e 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -1621,7 +1621,6 @@ namespace eosio { fc_dlog(logger, "request sync stable checkpoints from ${s} to ${e}", ("s", last_req_scp_num+1)("e", max_target_scp_num)); last_req_scp_num = max_target_scp_num; - c->sync_wait(); } void sync_manager::reassign_fetch(const connection_ptr& c, go_away_reason reason) { diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index c39ba284342..a43ff3fdd76 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -225,12 +225,12 @@ class producer_plugin_impl : public std::enable_shared_from_thisid; - auto new_version = chain.is_pbft_enabled(); + auto pbft_enabled = chain.is_pbft_enabled(); - auto new_bs = bsp->generate_next(new_block_header.timestamp, new_version); + auto new_bs = bsp->generate_next(new_block_header.timestamp, pbft_enabled); // for newly installed producers we can set their watermarks to the block they became active - if (new_bs.maybe_promote_pending(new_version) && bsp->active_schedule.version != new_bs.active_schedule.version) { + if (new_bs.maybe_promote_pending(pbft_enabled) && bsp->active_schedule.version != new_bs.active_schedule.version) { flat_set new_producers; new_producers.reserve(new_bs.active_schedule.producers.size()); for( const auto& p: new_bs.active_schedule.producers) { @@ -1098,9 +1098,9 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { _pending_block_mode = pending_block_mode::speculating; } - auto new_version = chain.is_pbft_enabled(); + auto pbft_enabled = chain.is_pbft_enabled(); - if (_pending_block_mode == pending_block_mode::producing && !new_version) { + if (_pending_block_mode == pending_block_mode::producing && !pbft_enabled) { // determine if our watermark excludes us from producing at this point if (currrent_watermark_itr != _producer_watermarks.end()) { if (currrent_watermark_itr->second >= hbs->block_num + 1) { @@ -1122,7 +1122,7 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { try { uint16_t blocks_to_confirm = 0; - if (_pending_block_mode == pending_block_mode::producing && !new_version) { + if (_pending_block_mode == pending_block_mode::producing && !pbft_enabled) { // determine how many blocks this producer can confirm // 1) if it is not a producer from this node, assume no confirmations (we will discard this block anyway) // 2) if it is a producer on this node that has never produced, the conservative approach is to assume no From 2ffcf15b54bd9977e4d8a54a11d22b147020f144 Mon Sep 17 00:00:00 2001 From: oldcold Date: Fri, 7 Jun 2019 17:06:43 +0800 Subject: [PATCH 19/22] retry sending all pending checkpoints; --- libraries/chain/fork_database.cpp | 6 +- .../include/eosio/chain/pbft_database.hpp | 2 + libraries/chain/pbft_database.cpp | 66 +++++++------------ 3 files changed, 28 insertions(+), 46 deletions(-) diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index 35406f7ea91..425c212a8cd 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -135,8 +135,6 @@ namespace eosio { namespace chain { my->head = get_block( head_id ); } - - fc::remove( fork_db_dat ); } } @@ -612,8 +610,8 @@ namespace eosio { namespace chain { vector watermarks; auto& pidx = my->index.get(); auto pitr = pidx.begin(); - while (pitr != pidx.end() && (*pitr)->pbft_watermark && (*pitr)->in_current_chain) { - watermarks.emplace_back((*pitr)->block_num); + while (pitr != pidx.end() && (*pitr)->pbft_watermark) { + watermarks.emplace_back((*pitr)->block_num); //should consider only current_chain? ++pitr; } return watermarks; diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 1b1d3b52131..664c60531a4 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -598,6 +598,8 @@ namespace eosio { vector& get_updated_watermarks(); + flat_map& get_updated_fork_schedules(); + template void emit(const Signal &s, Arg &&a); diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 3e997248c87..3bbb47d6f18 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -646,10 +646,10 @@ namespace eosio { } auto watermarks = get_updated_watermarks(); - for (auto i = 0; i < watermarks.size(); ++i) { + for (auto& watermark : watermarks) { //adding committed cert on every water mark. - if (watermarks[i] < highest_committed_block_num && watermarks[i] > lscb_num) { - ccb.emplace_back(watermarks[i]); + if (watermark < highest_committed_block_num && watermark > lscb_num) { + ccb.emplace_back(watermark); } } @@ -1080,7 +1080,6 @@ namespace eosio { block_info_type pbft_database::cal_pending_stable_checkpoint() const { - //TODO: maybe use watermarks instead? auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto lscb_id = ctrl.last_stable_checkpoint_block_id(); auto lscb_info = block_info_type{lscb_id, lscb_num}; @@ -1137,9 +1136,7 @@ namespace eosio { pbft_state_ptr psp = (*itr); - vector pending_checkpoint_block_num; - - block_num_type my_latest_checkpoint = 0; + flat_map pending_checkpoint_block_num; // block_height and retry_flag auto checkpoint = [&](const block_num_type &in) { const auto& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; @@ -1151,63 +1148,43 @@ namespace eosio { || std::find(watermarks.begin(), watermarks.end(), in) != watermarks.end(); // checkpoint on bp schedule change; }; - update_fork_schedules(); for (auto i = psp->block_num; i > ctrl.last_stable_checkpoint_block_num() && i > 1; --i) { if (checkpoint(i)) { - my_latest_checkpoint = max(i, my_latest_checkpoint); auto &by_block = checkpoint_index.get(); if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(i)) { auto c_itr = by_block.find(bs->id); if (c_itr == by_block.end()) { - pending_checkpoint_block_num.emplace_back(i); + pending_checkpoint_block_num[i] = false; } else { auto checkpoints = (*c_itr)->checkpoints; - bool contains_mine = false; for (auto const &my_sp : ctrl.my_signature_providers()) { auto p_itr = find_if(checkpoints.begin(), checkpoints.end(), [&](const pbft_checkpoint &ext) { return ext.common.sender == my_sp.first; }); - if (p_itr != checkpoints.end()) contains_mine = true; + if (p_itr != checkpoints.end()) pending_checkpoint_block_num[i] = true; //retry sending at this time. } - if (!contains_mine) { - pending_checkpoint_block_num.emplace_back(i); + if (pending_checkpoint_block_num.find(i) == pending_checkpoint_block_num.end()) { + pending_checkpoint_block_num[i] = false; } } } } } + auto &by_block = checkpoint_index.get(); if (!pending_checkpoint_block_num.empty()) { std::sort(pending_checkpoint_block_num.begin(), pending_checkpoint_block_num.end()); - for (auto bnum: pending_checkpoint_block_num) { - if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(bnum)) { + for (auto& bnum_and_retry: pending_checkpoint_block_num) { + if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(bnum_and_retry.first)) { for (auto const &my_sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); pbft_checkpoint cp; - cp.common.uuid=uuid; cp.block_info={bs->id, bnum}; cp.common.sender=my_sp.first; cp.common.chain_id=chain_id; + cp.common.uuid=uuid; cp.block_info={bs->id, bs->block_num}; cp.common.sender=my_sp.first; cp.common.chain_id=chain_id; cp.sender_signature = my_sp.second(cp.digest()); - add_pbft_checkpoint(cp); - new_pc.emplace_back(cp); - } - } - } - } else if (my_latest_checkpoint > 1) { - if (auto bs = ctrl.fork_db().get_block_in_current_chain_by_num(my_latest_checkpoint)) { - auto &by_block = checkpoint_index.get(); - auto h_itr = by_block.find(bs->id); - if (h_itr != by_block.end()) { - auto checkpoints = (*h_itr)->checkpoints; - for (auto const &my_sp : ctrl.my_signature_providers()) { - for (auto const &cp: checkpoints) { - if (my_sp.first == cp.common.sender) { - auto retry_cp = cp; - auto uuid = boost::uuids::to_string(uuid_generator()); - retry_cp.common.uuid = uuid; - retry_cp.common.timestamp = time_point::now(); - retry_cp.sender_signature = my_sp.second(retry_cp.digest()); - new_pc.emplace_back(retry_cp); - } + if (!bnum_and_retry.second) { //first time sending this checkpoint + add_pbft_checkpoint(cp); } + new_pc.emplace_back(cp); } } } @@ -1360,8 +1337,8 @@ namespace eosio { bool pbft_database::should_send_pbft_msg() { auto my_sp = ctrl.my_signature_providers(); - update_fork_schedules(); - for (auto const &bp: fork_schedules) { + auto schedules = get_updated_fork_schedules(); + for (auto const &bp: schedules) { for (auto const &my: my_sp) { if (bp.first == my.first) return true; } @@ -1371,8 +1348,8 @@ namespace eosio { bool pbft_database::should_recv_pbft_msg(const public_key_type &pub_key) { - update_fork_schedules(); - for (auto const &bp: fork_schedules) { + auto schedules = get_updated_fork_schedules(); + for (auto const &bp: schedules) { if (bp.first == pub_key) return true; } return false; @@ -1473,6 +1450,11 @@ namespace eosio { return prepare_watermarks; } + flat_map& pbft_database::get_updated_fork_schedules() { + update_fork_schedules(); + return fork_schedules; + } + 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(); From 299f82f9e2d729a10b6cfc6c8ee44c5bb24d374d Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 9 Jun 2019 03:05:12 +0800 Subject: [PATCH 20/22] check all prepares (commits) fall on the same fork during generating prepared cert (committed cert) --- libraries/chain/pbft_database.cpp | 100 +++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 30 deletions(-) diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 3bbb47d6f18..44fa5afef65 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -159,14 +159,15 @@ namespace eosio { auto my_prepare = ctrl.get_pbft_my_prepare(); auto reserve_prepare = [&](const block_id_type &in) { - if (in == block_id_type{} || !ctrl.fetch_block_state_by_id(in)) return false; + if (in == block_id_type() || !ctrl.fetch_block_state_by_id(in)) return false; auto lib = ctrl.last_irreversible_block_id(); - if (lib == block_id_type{}) return true; + if (lib == block_id_type()) return true; auto forks = ctrl.fork_db().fetch_branch_from(in, lib); return !forks.first.empty() && forks.second.empty(); }; vector new_pv; + new_pv.reserve(ctrl.my_signature_providers().size()); if (!pv.empty()) { for (auto p : pv) { //change uuid, sign again, update cache, then emit @@ -329,6 +330,7 @@ namespace eosio { if (!bs) return vector{}; vector new_cv; + new_cv.reserve(ctrl.my_signature_providers().size()); if (psp->should_prepared && (psp->block_num > ctrl.last_irreversible_block_num())) { for (auto const &sp : ctrl.my_signature_providers()) { @@ -494,7 +496,7 @@ namespace eosio { return vector{}; } else { vector new_vcv; - + new_vcv.reserve(ctrl.my_signature_providers().size()); for (auto const &my_sp : ctrl.my_signature_providers()) { auto my_lsc = get_stable_checkpoint_by_id(ctrl.last_stable_checkpoint_block_id()); @@ -527,7 +529,7 @@ namespace eosio { bool pbft_database::is_new_primary(const pbft_view_type target_view) { auto primary_key = get_new_view_primary_key(target_view); - if (primary_key == public_key_type{}) return false; + if (primary_key == public_key_type()) return false; auto sps = ctrl.my_signature_providers(); auto sp_itr = sps.find(primary_key); return sp_itr != sps.end(); @@ -543,7 +545,7 @@ namespace eosio { pbft_view_type current_view) { auto primary_key = get_new_view_primary_key(current_view); - if (!is_new_primary(current_view) || vcc.empty()) return pbft_new_view{}; + if (!is_new_primary(current_view) || vcc.empty()) return pbft_new_view(); //`sp_itr` is not possible to be the end iterator, since it's already been checked in `is_new_primary`. auto my_sps = ctrl.my_signature_providers(); @@ -586,11 +588,11 @@ namespace eosio { const auto &by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); - if (itr == by_prepare_and_num_index.end()) return pbft_prepared_certificate{}; + if (itr == by_prepare_and_num_index.end()) return pbft_prepared_certificate(); pbft_state_ptr psp = *itr; auto prepared_block_state = ctrl.fetch_block_state_by_id(psp->block_id); - if (!prepared_block_state) return pbft_prepared_certificate{}; + if (!prepared_block_state) return pbft_prepared_certificate(); auto as = prepared_block_state->active_schedule.producers; if (psp->should_prepared && (psp->block_num > (ctrl.last_irreversible_block_num()))) { @@ -611,18 +613,35 @@ namespace eosio { } } + auto bp_threshold = as.size() * 2 / 3 + 1; for (auto const &e: prepare_count) { - if (e.second >= as.size() * 2 / 3 + 1) { + if (e.second >= bp_threshold) { valid_prepares = prepare_msg[e.first]; } } - if (valid_prepares.empty()) return pbft_prepared_certificate{}; + if (valid_prepares.empty()) return pbft_prepared_certificate(); + + vector prepare_infos; + prepare_infos.reserve(valid_prepares.size()); + for (auto const &p : valid_prepares) { + prepare_infos.emplace_back(p.block_info); + } + auto forks = fetch_fork_from(prepare_infos); - auto pc = pbft_prepared_certificate{}; + vector longest_fork; + for (auto const &f : forks) { + if (f.size() > longest_fork.size()) { + longest_fork = f; + } + } + + if (longest_fork.size() < bp_threshold) return pbft_prepared_certificate(); + + pbft_prepared_certificate pc; pc.block_info={psp->block_id, psp->block_num}; pc.prepares=valid_prepares; return pc; - } else return pbft_prepared_certificate{}; + } else return pbft_prepared_certificate(); } vector pbft_database::generate_committed_certificate() { @@ -656,6 +675,7 @@ namespace eosio { const auto &by_id_index = pbft_state_index.get(); auto pcc = vector{}; + pcc.reserve(ccb.size()); for (const auto &committed_block_num: ccb) { auto cbs = ctrl.fetch_block_state_by_number(committed_block_num); if (!cbs) return vector{}; @@ -684,15 +704,32 @@ namespace eosio { } } + auto bp_threshold = as.size() * 2 / 3 + 1; for (auto const &e: commit_count) { - if (e.second >= as.size() * 2 / 3 + 1) { + if (e.second >= bp_threshold) { valid_commits = commit_msg[e.first]; } } if (valid_commits.empty()) return vector{}; - auto cc = pbft_committed_certificate{}; + vector commit_infos; + commit_infos.reserve(valid_commits.size()); + for (auto const &p : valid_commits) { + commit_infos.emplace_back(p.block_info); + } + auto forks = fetch_fork_from(commit_infos); + + vector longest_fork; + for (auto const &f : forks) { + if (f.size() > longest_fork.size()) { + longest_fork = f; + } + } + + if (longest_fork.size() < bp_threshold) return vector{}; + + pbft_committed_certificate cc; cc.block_info={cbs->id, cbs->block_num}; cc.commits=valid_commits; pcc.emplace_back(cc); } @@ -703,15 +740,15 @@ namespace eosio { auto &by_view_index = view_state_index.get(); auto itr = by_view_index.find(target_view); - if (itr == by_view_index.end()) return pbft_view_changed_certificate{}; + if (itr == by_view_index.end()) return pbft_view_changed_certificate(); auto pvs = *itr; if (pvs->should_view_changed) { - auto pvcc = pbft_view_changed_certificate{}; + auto pvcc = pbft_view_changed_certificate(); pvcc.target_view=pvs->view; pvcc.view_changes=pvs->view_changes; return pvcc; - } else return pbft_view_changed_certificate{}; + } else return pbft_view_changed_certificate(); } @@ -763,6 +800,7 @@ namespace eosio { auto lscb = ctrl.last_stable_checkpoint_block_num(); auto non_fork_bp_count = 0; vector prepare_infos; + prepare_infos.reserve(certificate.prepares.size()); for (auto const &p : certificate.prepares) { //only search in fork db if (p.block_info.block_num <= lscb) { @@ -821,12 +859,13 @@ namespace eosio { auto lscb = ctrl.last_stable_checkpoint_block_num(); auto non_fork_bp_count = 0; vector commit_infos; - for (auto const &p : certificate.commits) { + commit_infos.reserve(certificate.commits.size()); + for (auto const &c : certificate.commits) { //only search in fork db - if (p.block_info.block_num <= lscb) { + if (c.block_info.block_num <= lscb) { ++non_fork_bp_count; } else { - commit_infos.emplace_back(p.block_info); + commit_infos.emplace_back(c.block_info); } } return is_valid_longest_fork(certificate.block_info, commit_infos, bp_threshold, non_fork_bp_count); @@ -865,13 +904,14 @@ namespace eosio { EOS_ASSERT(nv.view_changed_cert.target_view == nv.new_view, pbft_exception, "target view not match"); vector lscb_producers; + lscb_producers.reserve(lscb_active_producers().producers.size()); for (const auto& pk: lscb_active_producers().producers) { lscb_producers.emplace_back(pk.block_signing_key); } auto schedule_threshold = lscb_producers.size() * 2 / 3 + 1; vector view_change_producers; - + view_change_producers.reserve(nv.view_changed_cert.view_changes.size()); for (auto vc: nv.view_changed_cert.view_changes) { if (is_valid_view_change(vc)) { add_pbft_view_change(vc); @@ -891,9 +931,9 @@ namespace eosio { EOS_ASSERT(should_new_view(nv.new_view), pbft_exception, "should not enter new view: ${nv}", ("nv", nv.new_view)); - auto highest_ppc = pbft_prepared_certificate{}; + auto highest_ppc = pbft_prepared_certificate(); auto highest_pcc = vector{}; - auto highest_scp = pbft_stable_checkpoint{}; + auto highest_scp = pbft_stable_checkpoint(); for (const auto &vc: nv.view_changed_cert.view_changes) { if (vc.prepared_cert.block_info.block_num > highest_ppc.block_info.block_num @@ -1023,7 +1063,7 @@ namespace eosio { 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) { + if (bi == block_info_type{current_bs->id, current_bs->block_num}) { return true; } current_bs = ctrl.fetch_block_state_by_id(current_bs->prev()); @@ -1057,7 +1097,7 @@ namespace eosio { } catch(...) { elog("no stable checkpoints found in the block extension"); } - return pbft_stable_checkpoint{}; + return pbft_stable_checkpoint(); } pbft_stable_checkpoint pbft_database::get_stable_checkpoint_by_id(const block_id_type &block_id) { @@ -1071,11 +1111,11 @@ namespace eosio { auto cpp = *itr; if (cpp->is_stable) { - if (ctrl.my_signature_providers().empty()) return pbft_stable_checkpoint{}; + if (ctrl.my_signature_providers().empty()) return pbft_stable_checkpoint(); pbft_stable_checkpoint psc; psc.block_info={cpp->block_id, cpp->block_num}; psc.checkpoints=cpp->checkpoints;; return psc; - } else return pbft_stable_checkpoint{}; + } else return pbft_stable_checkpoint(); } block_info_type pbft_database::cal_pending_stable_checkpoint() const { @@ -1129,7 +1169,7 @@ namespace eosio { vector pbft_database::generate_and_add_pbft_checkpoint() { auto new_pc = vector{}; - + new_pc.reserve(ctrl.my_signature_providers().size()); const auto &by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end() || !(*itr)->should_committed) return new_pc; @@ -1358,7 +1398,7 @@ namespace eosio { public_key_type pbft_database::get_new_view_primary_key(const pbft_view_type target_view) { auto active_bps = lscb_active_producers().producers; - if (active_bps.empty()) return public_key_type{}; + if (active_bps.empty()) return public_key_type(); return active_bps[target_view % active_bps.size()].block_signing_key; } @@ -1462,7 +1502,7 @@ namespace eosio { if (itr != by_block_id_index.end()) return (*itr); - return pbft_state_ptr{}; + return pbft_state_ptr(); } vector pbft_database::get_checkpoints_by_num(const block_num_type& num) const { @@ -1485,7 +1525,7 @@ namespace eosio { if (itr != by_view_index.end()) return (*itr); - return pbft_view_change_state_ptr{}; + return pbft_view_change_state_ptr(); } vector pbft_database::get_pbft_watermarks() const { From 01775eadf077da74bca45aa987d07da3c2145518 Mon Sep 17 00:00:00 2001 From: oldcold Date: Tue, 11 Jun 2019 21:18:50 +0800 Subject: [PATCH 21/22] add pre_prepares in prepared_cert, requesting missing blocks upon view change. --- libraries/chain/include/eosio/chain/pbft.hpp | 18 +- .../include/eosio/chain/pbft_database.hpp | 69 +++-- libraries/chain/pbft.cpp | 30 +- libraries/chain/pbft_database.cpp | 288 +++++++++--------- plugins/net_plugin/net_plugin.cpp | 43 ++- 5 files changed, 232 insertions(+), 216 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index 8b0b5338ff8..193acc86f0e 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -60,15 +60,15 @@ namespace eosio { void transit_to_new_view(const pbft_new_view &new_view, psm_state_ptr s); - const vector &get_prepares_cache() const; + const vector& get_prepares_cache() const; void set_prepares_cache(const vector &pcache); - const vector &get_commits_cache() const; + const vector& get_commits_cache() const; void set_commits_cache(const vector &ccache); - const vector &get_view_changes_cache() const; + const vector& get_view_changes_cache() const; void set_view_changes_cache(const vector &vc_cache); @@ -76,27 +76,27 @@ namespace eosio { void set_current_view(const uint32_t &cv); - const pbft_prepared_certificate &get_prepared_certificate() const; + const pbft_prepared_certificate& get_prepared_certificate() const; void set_prepared_certificate(const pbft_prepared_certificate &pcert); - const vector &get_committed_certificate() const; + const vector& get_committed_certificate() const; void set_committed_certificate(const vector &ccert); - const pbft_view_changed_certificate &get_view_changed_certificate() const; + const pbft_view_changed_certificate& get_view_changed_certificate() const; void set_view_changed_certificate(const pbft_view_changed_certificate &vc_cert); - const uint32_t &get_target_view_retries() const; + const uint32_t& get_target_view_retries() const; void set_target_view_retries(const uint32_t &tv_reties); - const uint32_t &get_target_view() const; + const uint32_t& get_target_view() const; void set_target_view(const uint32_t &tv); - const uint32_t &get_view_change_timer() const; + const uint32_t& get_view_change_timer() const; void set_view_change_timer(const uint32_t &vc_timer); diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index 664c60531a4..a92f25dc9f5 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace eosio { namespace chain { @@ -32,10 +33,13 @@ namespace eosio { struct block_info_type { block_id_type block_id; - block_num_type block_num = 0; + + block_num_type block_num() const { + return fc::endian_reverse_u32(block_id._hash[0]); + } bool operator==(const block_info_type &rhs) const { - return block_id == rhs.block_id && block_num == rhs.block_num; + return block_id == rhs.block_id; } bool operator!=(const block_info_type &rhs) const { @@ -59,7 +63,7 @@ namespace eosio { } bool empty() const { - return uuid == string() + return uuid.empty() && sender == public_key_type() && chain_id == chain_id_type(""); } @@ -82,9 +86,9 @@ namespace eosio { } bool operator<(const pbft_prepare &rhs) const { - if (block_info.block_num < rhs.block_info.block_num) { + if (block_info.block_num() < rhs.block_info.block_num()) { return true; - } else if (block_info.block_num == rhs.block_info.block_num) { + } else if (block_info.block_num() == rhs.block_info.block_num()) { return view < rhs.view; } else { return false; @@ -124,9 +128,9 @@ namespace eosio { } bool operator<(const pbft_commit &rhs) const { - if (block_info.block_num < rhs.block_info.block_num) { + if (block_info.block_num() < rhs.block_info.block_num()) { return true; - } else if (block_info.block_num == rhs.block_info.block_num) { + } else if (block_info.block_num() == rhs.block_info.block_num()) { return view < rhs.view; } else { return false; @@ -168,7 +172,7 @@ namespace eosio { } bool operator<(const pbft_checkpoint &rhs) const { - return block_info.block_num < rhs.block_info.block_num; + return block_info.block_num() < rhs.block_info.block_num(); } digest_type digest() const { @@ -195,7 +199,7 @@ namespace eosio { vector checkpoints; bool operator<(const pbft_stable_checkpoint &rhs) const { - return block_info.block_num < rhs.block_info.block_num; + return block_info.block_num() < rhs.block_info.block_num(); } bool empty() const { @@ -208,10 +212,11 @@ namespace eosio { explicit pbft_prepared_certificate() = default; block_info_type block_info; + set pre_prepares; vector prepares; bool operator<(const pbft_prepared_certificate &rhs) const { - return block_info.block_num < rhs.block_info.block_num; + return block_info.block_num() < rhs.block_info.block_num(); } bool empty() const { @@ -227,7 +232,7 @@ namespace eosio { vector commits; bool operator<(const pbft_committed_certificate &rhs) const { - return block_info.block_num < rhs.block_info.block_num; + return block_info.block_num() < rhs.block_info.block_num(); } bool empty() const { @@ -344,15 +349,15 @@ namespace eosio { block_id_type block_id; block_num_type block_num = 0; vector prepares; - bool should_prepared = false; + bool is_prepared = false; vector commits; - bool should_committed = false; + bool is_committed = false; }; struct pbft_view_change_state { pbft_view_type view; vector view_changes; - bool should_view_changed = false; + bool is_view_changed = false; }; struct pbft_checkpoint_state { @@ -387,7 +392,7 @@ namespace eosio { tag, composite_key< pbft_state, - member, + member, member >, composite_key_compare< greater<>, greater<> > @@ -396,7 +401,7 @@ namespace eosio { tag, composite_key< pbft_state, - member, + member, member >, composite_key_compare< greater<>, greater<> > @@ -418,7 +423,7 @@ namespace eosio { tag, composite_key< pbft_view_change_state, - member, + member, member >, composite_key_compare, greater<>> @@ -466,8 +471,12 @@ namespace eosio { void add_pbft_prepare(pbft_prepare &p); + void mark_as_prepared(const block_id_type &bid); + void add_pbft_commit(pbft_commit &c); + void mark_as_committed(const block_id_type &bid); + void add_pbft_view_change(pbft_view_change &vc); void add_pbft_checkpoint(pbft_checkpoint &cp); @@ -567,16 +576,16 @@ namespace eosio { signal pbft_incoming_checkpoint; 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; - chain_id_type chain_id = ctrl.get_chain_id(); - fc::path pbft_db_dir; - fc::path checkpoints_dir; - boost::uuids::random_generator uuid_generator; - vector prepare_watermarks; - flat_map fork_schedules; + 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; + chain_id_type chain_id = ctrl.get_chain_id(); + fc::path pbft_db_dir; + fc::path checkpoints_dir; + boost::uuids::random_generator uuid_generator; + vector prepare_watermarks; + flat_map fork_schedules; bool is_valid_pbft_message(const pbft_message_common &common); @@ -614,7 +623,7 @@ namespace eosio { } } /// namespace eosio::chain -FC_REFLECT(eosio::chain::block_info_type, (block_id)(block_num)) +FC_REFLECT(eosio::chain::block_info_type, (block_id)) FC_REFLECT_ENUM(eosio::chain::pbft_message_type, (prepare)(commit)(checkpoint)(view_change)(new_view)) FC_REFLECT(eosio::chain::pbft_message_common, (type)(uuid)(sender)(chain_id)(timestamp)) @@ -630,6 +639,6 @@ FC_REFLECT(eosio::chain::pbft_committed_certificate,(block_info)(commits)) FC_REFLECT(eosio::chain::pbft_view_changed_certificate, (target_view)(view_changes)) FC_REFLECT(eosio::chain::pbft_stable_checkpoint, (block_info)(checkpoints)) -FC_REFLECT(eosio::chain::pbft_state, (block_id)(block_num)(prepares)(should_prepared)(commits)(should_committed)) -FC_REFLECT(eosio::chain::pbft_view_change_state, (view)(view_changes)(should_view_changed)) +FC_REFLECT(eosio::chain::pbft_state, (block_id)(block_num)(prepares)(is_prepared)(commits)(is_committed)) +FC_REFLECT(eosio::chain::pbft_view_change_state, (view)(view_changes)(is_view_changed)) FC_REFLECT(eosio::chain::pbft_checkpoint_state, (block_id)(block_num)(checkpoints)(is_stable)) \ No newline at end of file diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 17a5d3ee3e9..02b1ad4530f 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -444,7 +444,7 @@ namespace eosio { void psm_machine::transit_to_new_view(const pbft_new_view &new_view, psm_state_ptr s) { - auto valid_nv = false; + bool valid_nv; try { valid_nv = pbft_db.is_valid_new_view(new_view); } catch (const fc::exception& ex) { @@ -475,14 +475,15 @@ namespace eosio { if (!new_view.committed_cert.empty()) { auto committed_certs = new_view.committed_cert; std::sort(committed_certs.begin(), committed_certs.end()); - for (auto cp :committed_certs) { - for (auto c: cp.commits) { + for (auto cc :committed_certs) { + for (auto c: cc.commits) { try { pbft_db.add_pbft_commit(c); } catch (...) { - wlog( "commit insertion failure: ${cp}", ("cp", cp)); + wlog( "commit insertion failure: ${c}", ("c", c)); } } + pbft_db.mark_as_committed(cc.block_info.block_id); } } @@ -494,6 +495,7 @@ namespace eosio { wlog("prepare insertion failure: ${p}", ("p", p)); } } + pbft_db.mark_as_prepared(new_view.prepared_cert.block_info.block_id); if (pbft_db.should_prepared()) { transit_to_prepared_state(s); return; @@ -534,7 +536,7 @@ namespace eosio { } } - const vector &psm_machine::get_prepares_cache() const { + const vector& psm_machine::get_prepares_cache() const { return cache.prepares_cache; } @@ -542,7 +544,7 @@ namespace eosio { cache.prepares_cache = pcache; } - const vector &psm_machine::get_commits_cache() const { + const vector& psm_machine::get_commits_cache() const { return cache.commits_cache; } @@ -550,7 +552,7 @@ namespace eosio { cache.commits_cache = ccache; } - const vector &psm_machine::get_view_changes_cache() const { + const vector& psm_machine::get_view_changes_cache() const { return cache.view_changes_cache; } @@ -558,7 +560,7 @@ namespace eosio { cache.view_changes_cache = vc_cache; } - const uint32_t &psm_machine::get_current_view() const { + const uint32_t& psm_machine::get_current_view() const { return current_view; } @@ -566,7 +568,7 @@ namespace eosio { current_view = cv; } - const pbft_prepared_certificate &psm_machine::get_prepared_certificate() const { + const pbft_prepared_certificate& psm_machine::get_prepared_certificate() const { return cache.prepared_certificate; } @@ -574,7 +576,7 @@ namespace eosio { cache.prepared_certificate = pcert; } - const vector &psm_machine::get_committed_certificate() const { + const vector& psm_machine::get_committed_certificate() const { return cache.committed_certificate; } @@ -582,7 +584,7 @@ namespace eosio { cache.committed_certificate = ccert; } - const pbft_view_changed_certificate &psm_machine::get_view_changed_certificate() const { + const pbft_view_changed_certificate& psm_machine::get_view_changed_certificate() const { return cache.view_changed_certificate; } @@ -590,7 +592,7 @@ namespace eosio { cache.view_changed_certificate = vc_cert; } - const uint32_t &psm_machine::get_target_view_retries() const { + const uint32_t& psm_machine::get_target_view_retries() const { return target_view_retries; } @@ -598,7 +600,7 @@ namespace eosio { target_view_retries = tv_reties; } - const uint32_t &psm_machine::get_target_view() const { + const uint32_t& psm_machine::get_target_view() const { return target_view; } @@ -606,7 +608,7 @@ namespace eosio { target_view = tv; } - const uint32_t &psm_machine::get_view_change_timer() const { + const uint32_t& psm_machine::get_view_change_timer() const { return view_change_timer; } diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 44fa5afef65..7f6219dfc97 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -69,7 +69,7 @@ namespace eosio { uint32_t num_records_in_checkpoint_db = checkpoint_index.size(); fc::raw::pack(c_out, unsigned_int{num_records_in_checkpoint_db}); - for (const auto &s: checkpoint_index) { + for (auto const &s: checkpoint_index) { fc::raw::pack(c_out, *s); } @@ -79,7 +79,7 @@ namespace eosio { uint32_t num_records_in_db = pbft_state_index.size(); fc::raw::pack(out, unsigned_int{num_records_in_db}); - for (const auto &s : pbft_state_index) { + for (auto const &s : pbft_state_index) { fc::raw::pack(out, *s); } @@ -127,23 +127,25 @@ namespace eosio { curr_itr = by_block_id_index.find(current->id); if (curr_itr == by_block_id_index.end()) return; - auto prepares = (*curr_itr)->prepares; + auto cpsp = *curr_itr; + auto prepares = cpsp->prepares; auto as = current->active_schedule.producers; - flat_map prepare_count; - for (const auto &pre: prepares) { - if (prepare_count.find(pre.view) == prepare_count.end()) prepare_count[pre.view] = 0; - } + auto threshold = as.size()* 2 / 3 + 1; + if (prepares.size() >= threshold && !cpsp->is_prepared) { + flat_map prepare_count; + for (auto const &pre: prepares) { + if (prepare_count.find(pre.view) == prepare_count.end()) prepare_count[pre.view] = 0; + } + - if (!(*curr_itr)->should_prepared) { for (auto const &sp: as) { for (auto const &pp: prepares) { if (sp.block_signing_key == pp.common.sender) prepare_count[pp.view] += 1; } } for (auto const &e: prepare_count) { - if (e.second >= as.size() * 2 / 3 + 1) { - by_block_id_index.modify(curr_itr, - [&](const pbft_state_ptr &psp) { psp->should_prepared = true; }); + if (e.second >= threshold) { + mark_as_prepared(cpsp->block_id); } } } @@ -151,6 +153,12 @@ namespace eosio { } } + void pbft_database::mark_as_prepared(const block_id_type &bid) { + auto &by_block_id_index = pbft_state_index.get(); + auto itr = by_block_id_index.find(bid); + if (itr == by_block_id_index.end()) return; + by_block_id_index.modify(itr, [&](const pbft_state_ptr &p) { p->is_prepared = true; }); + } vector pbft_database::send_and_add_pbft_prepare(const vector &pv, pbft_view_type current_view) { @@ -181,9 +189,8 @@ namespace eosio { } else if (reserve_prepare(my_prepare)) { for (auto const &sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); - auto my_prepare_num = ctrl.fetch_block_state_by_id(my_prepare)->block_num; pbft_prepare p; - p.common.uuid=uuid; p.view=current_view; p.block_info={my_prepare, my_prepare_num}; p.common.sender=sp.first; p.common.chain_id=chain_id; + p.common.uuid=uuid; p.view=current_view; p.block_info={my_prepare}; p.common.sender=sp.first; p.common.chain_id=chain_id; p.sender_signature = sp.second(p.digest()); emit(pbft_outgoing_prepare, p); new_pv.emplace_back(p); @@ -207,7 +214,7 @@ namespace eosio { for (auto const &sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); pbft_prepare p; - p.common.uuid=uuid; p.view=current_view; p.block_info={hwbs->id, high_watermark_block_num}; p.common.sender=sp.first; p.common.chain_id=chain_id; + p.common.uuid=uuid; p.view=current_view; p.block_info={hwbs->id}; p.common.sender=sp.first; p.common.chain_id=chain_id; p.sender_signature = sp.second(p.digest()); add_pbft_prepare(p); emit(pbft_outgoing_prepare, p); @@ -221,7 +228,7 @@ namespace eosio { bool pbft_database::should_prepared() { - const auto &by_prepare_and_num_index = pbft_state_index.get(); + auto const &by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); if (itr == by_prepare_and_num_index.end()) return false; @@ -230,7 +237,7 @@ namespace eosio { if (psp->block_num > current_watermark && current_watermark > 0) return false; - if (psp->should_prepared && (psp->block_num > ctrl.last_irreversible_block_num())) { + if (psp->is_prepared && (psp->block_num > ctrl.last_irreversible_block_num())) { ctrl.set_pbft_prepared((*itr)->block_id); return true; } @@ -240,7 +247,7 @@ namespace eosio { bool pbft_database::is_valid_prepare(const pbft_prepare &p) { if (!is_valid_pbft_message(p.common)) return false; // a prepare msg under lscb (which is no longer in fork_db), can be treated as null, thus true. - if (p.block_info.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; + if (p.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) return true; if (!p.is_signature_valid()) return false; return should_recv_pbft_msg(p.common.sender); } @@ -282,26 +289,28 @@ namespace eosio { curr_itr = by_block_id_index.find(current->id); if (curr_itr == by_block_id_index.end()) return; - auto commits = (*curr_itr)->commits; - auto as = current->active_schedule; - flat_map commit_count; - for (const auto &com: commits) { - if (commit_count.find(com.view) == commit_count.end()) commit_count[com.view] = 0; - } + auto cpsp = *curr_itr; + + auto as = current->active_schedule.producers; + auto threshold = as.size()* 2 / 3 + 1; + auto commits = cpsp->commits; + if (commits.size() >= threshold && !cpsp->is_committed) { + flat_map commit_count; + for (auto const &com: commits) { + if (commit_count.find(com.view) == commit_count.end()) commit_count[com.view] = 0; + } - if (!(*curr_itr)->should_committed) { - for (auto const &sp: as.producers) { + for (auto const &sp: as) { for (auto const &pc: commits) { if (sp.block_signing_key == pc.common.sender) commit_count[pc.view] += 1; } } for (auto const &e: commit_count) { - if (e.second >= current->active_schedule.producers.size() * 2 / 3 + 1) { - by_block_id_index.modify(curr_itr, - [&](const pbft_state_ptr &psp) { psp->should_committed = true; }); + if (e.second >= threshold) { + mark_as_committed(cpsp->block_id); } } } @@ -321,7 +330,7 @@ namespace eosio { } return vector{}; } else { - const auto &by_prepare_and_num_index = pbft_state_index.get(); + auto const &by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); if (itr == by_prepare_and_num_index.end()) return vector{}; @@ -331,12 +340,12 @@ namespace eosio { vector new_cv; new_cv.reserve(ctrl.my_signature_providers().size()); - if (psp->should_prepared && (psp->block_num > ctrl.last_irreversible_block_num())) { + if (psp->is_prepared && (psp->block_num > ctrl.last_irreversible_block_num())) { for (auto const &sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); pbft_commit c; - c.common.uuid=uuid; c.view=current_view; c.block_info={psp->block_id, psp->block_num}; c.common.sender=sp.first; c.common.chain_id=chain_id; + c.common.uuid=uuid; c.view=current_view; c.block_info={psp->block_id}; c.common.sender=sp.first; c.common.chain_id=chain_id; c.sender_signature = sp.second(c.digest()); add_pbft_commit(c); emit(pbft_outgoing_commit, c); @@ -347,8 +356,15 @@ namespace eosio { } } + void pbft_database::mark_as_committed(const block_id_type &bid) { + auto &by_block_id_index = pbft_state_index.get(); + auto itr = by_block_id_index.find(bid); + if (itr == by_block_id_index.end()) return; + by_block_id_index.modify(itr, [&](const pbft_state_ptr &p) { p->is_committed = true; }); + } + bool pbft_database::should_committed() { - const auto &by_commit_and_num_index = pbft_state_index.get(); + auto const &by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end()) return false; pbft_state_ptr psp = *itr; @@ -357,14 +373,14 @@ namespace eosio { if (psp->block_num > current_watermark && current_watermark > 0) return false; - return (psp->should_committed && (psp->block_num > ctrl.last_irreversible_block_num())); + return (psp->is_committed && (psp->block_num > ctrl.last_irreversible_block_num())); } pbft_view_type pbft_database::get_committed_view() { pbft_view_type new_view = 0; if (!should_committed()) return new_view; - const auto &by_commit_and_num_index = pbft_state_index.get(); + auto const &by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); pbft_state_ptr psp = *itr; @@ -375,7 +391,7 @@ namespace eosio { auto commits = (*itr)->commits; flat_map commit_count; - for (const auto &com: commits) { + for (auto const &com: commits) { if (commit_count.find(com.view) == commit_count.end()) { commit_count[com.view] = 1; } else { @@ -393,13 +409,13 @@ namespace eosio { bool pbft_database::is_valid_commit(const pbft_commit &c) { if (!is_valid_pbft_message(c.common)) return false; - if (c.block_info.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; + if (c.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) return true; if (!c.is_signature_valid()) return false; return should_recv_pbft_msg(c.common.sender); } void pbft_database::commit_local() { - const auto &by_commit_and_num_index = pbft_state_index.get(); + auto const &by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end()) return; @@ -439,15 +455,18 @@ namespace eosio { itr = by_view_index.find(vc.target_view); if (itr == by_view_index.end()) return; - auto vc_count = 0; - if (!(*itr)->should_view_changed) { + auto vsp = *itr; + auto threshold = active_bps.size() * 2 / 3 + 1; + if (vsp->view_changes.size() >= threshold && !vsp->is_view_changed) { + auto vc_count = 0; + for (auto const &sp: active_bps) { for (auto const &v: (*itr)->view_changes) { if (sp.block_signing_key == v.common.sender) vc_count += 1; } } - if (vc_count >= active_bps.size() * 2 / 3 + 1) { - by_view_index.modify(itr, [&](const pbft_view_change_state_ptr &pvsp) { pvsp->should_view_changed = true; }); + if (vc_count >= threshold) { + by_view_index.modify(itr, [&](const pbft_view_change_state_ptr &pvsp) { pvsp->is_view_changed = true; }); } } } @@ -516,13 +535,13 @@ namespace eosio { auto &by_view_index = view_state_index.get(); auto itr = by_view_index.find(target_view); if (itr == by_view_index.end()) return false; - return (*itr)->should_view_changed; + return (*itr)->is_view_changed; } pbft_view_type pbft_database::get_proposed_new_view_num() { auto &by_count_and_view_index = view_state_index.get(); auto itr = by_count_and_view_index.begin(); - if (itr == by_count_and_view_index.end() || !(*itr)->should_view_changed) return 0; + if (itr == by_count_and_view_index.end() || !(*itr)->is_view_changed) return 0; return (*itr)->view; } @@ -555,8 +574,9 @@ namespace eosio { auto highest_pcc = vector{}; auto highest_sc = pbft_stable_checkpoint(); - for (const auto &vc: vcc.view_changes) { - if (vc.prepared_cert.block_info.block_num > highest_ppc.block_info.block_num && is_valid_prepared_certificate(vc.prepared_cert)) { + for (auto const &vc: vcc.view_changes) { + if (vc.prepared_cert.block_info.block_num() > highest_ppc.block_info.block_num() + && is_valid_prepared_certificate(vc.prepared_cert)) { highest_ppc = vc.prepared_cert; } @@ -568,7 +588,7 @@ namespace eosio { } } - if (vc.stable_checkpoint.block_info.block_num > highest_sc.block_info.block_num && + if (vc.stable_checkpoint.block_info.block_num() > highest_sc.block_info.block_num() && is_valid_stable_checkpoint(vc.stable_checkpoint)) { highest_sc = vc.stable_checkpoint; } @@ -586,7 +606,7 @@ namespace eosio { pbft_prepared_certificate pbft_database::generate_prepared_certificate() { - const auto &by_prepare_and_num_index = pbft_state_index.get(); + auto const &by_prepare_and_num_index = pbft_state_index.get(); auto itr = by_prepare_and_num_index.begin(); if (itr == by_prepare_and_num_index.end()) return pbft_prepared_certificate(); pbft_state_ptr psp = *itr; @@ -595,14 +615,14 @@ namespace eosio { if (!prepared_block_state) return pbft_prepared_certificate(); auto as = prepared_block_state->active_schedule.producers; - if (psp->should_prepared && (psp->block_num > (ctrl.last_irreversible_block_num()))) { + if (psp->is_prepared && (psp->block_num > (ctrl.last_irreversible_block_num()))) { auto prepares = psp->prepares; auto valid_prepares = vector{}; flat_map prepare_count; flat_map> prepare_msg; - for (const auto &pre: prepares) { + for (auto const &pre: prepares) { if (prepare_count.find(pre.view) == prepare_count.end()) prepare_count[pre.view] = 0; prepare_msg[pre.view].emplace_back(pre); } @@ -622,37 +642,28 @@ namespace eosio { if (valid_prepares.empty()) return pbft_prepared_certificate(); - vector prepare_infos; - prepare_infos.reserve(valid_prepares.size()); - for (auto const &p : valid_prepares) { - prepare_infos.emplace_back(p.block_info); - } - auto forks = fetch_fork_from(prepare_infos); - - vector longest_fork; - for (auto const &f : forks) { - if (f.size() > longest_fork.size()) { - longest_fork = f; + pbft_prepared_certificate pc; + pc.block_info={psp->block_id}; pc.prepares=valid_prepares; pc.pre_prepares.emplace(psp->block_id); + for (auto const &p: valid_prepares) { + auto bid = p.block_info.block_id; + while (bid != psp->block_id) { + pc.pre_prepares.emplace(bid); + bid = ctrl.fetch_block_state_by_id(bid)->prev(); } } - - if (longest_fork.size() < bp_threshold) return pbft_prepared_certificate(); - - pbft_prepared_certificate pc; - pc.block_info={psp->block_id, psp->block_num}; pc.prepares=valid_prepares; return pc; } else return pbft_prepared_certificate(); } vector pbft_database::generate_committed_certificate() { - const auto &by_commit_and_num_index = pbft_state_index.get(); + auto const &by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); if (itr == by_commit_and_num_index.end()) return vector{}; pbft_state_ptr psp = *itr; - if (!psp->should_committed) return vector{}; + if (!psp->is_committed) return vector{}; auto highest_committed_block_num = psp->block_num; @@ -672,16 +683,16 @@ namespace eosio { } } - const auto &by_id_index = pbft_state_index.get(); + auto const &by_id_index = pbft_state_index.get(); auto pcc = vector{}; pcc.reserve(ccb.size()); - for (const auto &committed_block_num: ccb) { + for (auto const &committed_block_num: ccb) { auto cbs = ctrl.fetch_block_state_by_number(committed_block_num); if (!cbs) return vector{}; auto it = by_id_index.find(cbs->id); - if (it == by_id_index.end() || !(*it)->should_committed) { + if (it == by_id_index.end() || !(*it)->is_committed) { return vector{}; } @@ -693,7 +704,7 @@ namespace eosio { flat_map commit_count; flat_map> commit_msg; - for (const auto &com: commits) { + for (auto const &com: commits) { if (commit_count.find(com.view) == commit_count.end()) commit_count[com.view] = 0; commit_msg[com.view].emplace_back(com); } @@ -713,24 +724,8 @@ namespace eosio { if (valid_commits.empty()) return vector{}; - vector commit_infos; - commit_infos.reserve(valid_commits.size()); - for (auto const &p : valid_commits) { - commit_infos.emplace_back(p.block_info); - } - auto forks = fetch_fork_from(commit_infos); - - vector longest_fork; - for (auto const &f : forks) { - if (f.size() > longest_fork.size()) { - longest_fork = f; - } - } - - if (longest_fork.size() < bp_threshold) return vector{}; - pbft_committed_certificate cc; - cc.block_info={cbs->id, cbs->block_num}; cc.commits=valid_commits; + cc.block_info={cbs->id}; cc.commits=valid_commits; pcc.emplace_back(cc); } return pcc; @@ -744,7 +739,7 @@ namespace eosio { auto pvs = *itr; - if (pvs->should_view_changed) { + if (pvs->is_view_changed) { auto pvcc = pbft_view_changed_certificate(); pvcc.target_view=pvs->view; pvcc.view_changes=pvs->view_changes; return pvcc; @@ -757,7 +752,7 @@ namespace eosio { // an empty certificate is valid since it acts as a null digest in pbft. if (certificate.empty()) return true; // a certificate under lscb (no longer in fork_db) is also treated as null. - if (certificate.block_info.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; + if (certificate.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) return true; auto valid = true; for (auto const &p : certificate.prepares) { @@ -768,7 +763,7 @@ namespace eosio { 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(); - if (certificate.block_info.block_num > 0 && cert_bs) { + if (certificate.block_info.block_num() > 0 && cert_bs) { producer_schedule = cert_bs->active_schedule; } auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; @@ -776,7 +771,7 @@ namespace eosio { auto prepares = certificate.prepares; flat_map prepare_count; - for (const auto &pre: prepares) { + for (auto const &pre: prepares) { if (prepare_count.find(pre.view) == prepare_count.end()) prepare_count[pre.view] = 0; } @@ -803,7 +798,7 @@ namespace eosio { prepare_infos.reserve(certificate.prepares.size()); for (auto const &p : certificate.prepares) { //only search in fork db - if (p.block_info.block_num <= lscb) { + if (p.block_info.block_num() <= lscb) { ++non_fork_bp_count; } else { prepare_infos.emplace_back(p.block_info); @@ -816,7 +811,7 @@ namespace eosio { // an empty certificate is valid since it acts as a null digest in pbft. if (certificate.empty()) return true; // a certificate under lscb (no longer in fork_db) is also treated as null. - if (certificate.block_info.block_num <= ctrl.last_stable_checkpoint_block_num()) return true; + if (certificate.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) return true; auto valid = true; for (auto const &c : certificate.commits) { @@ -827,7 +822,7 @@ namespace eosio { 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(); - if (certificate.block_info.block_num > 0 && cert_bs) { + if (certificate.block_info.block_num() > 0 && cert_bs) { producer_schedule = cert_bs->active_schedule; } auto bp_threshold = producer_schedule.producers.size() * 2 / 3 + 1; @@ -835,7 +830,7 @@ namespace eosio { auto commits = certificate.commits; flat_map commit_count; - for (const auto &pre: commits) { + for (auto const &pre: commits) { if (commit_count.find(pre.view) == commit_count.end()) commit_count[pre.view] = 0; } @@ -862,7 +857,7 @@ namespace eosio { commit_infos.reserve(certificate.commits.size()); for (auto const &c : certificate.commits) { //only search in fork db - if (c.block_info.block_num <= lscb) { + if (c.block_info.block_num() <= lscb) { ++non_fork_bp_count; } else { commit_infos.emplace_back(c.block_info); @@ -905,7 +900,7 @@ namespace eosio { vector lscb_producers; lscb_producers.reserve(lscb_active_producers().producers.size()); - for (const auto& pk: lscb_active_producers().producers) { + for (auto const& pk: lscb_active_producers().producers) { lscb_producers.emplace_back(pk.block_signing_key); } auto schedule_threshold = lscb_producers.size() * 2 / 3 + 1; @@ -935,8 +930,8 @@ namespace eosio { auto highest_pcc = vector{}; auto highest_scp = pbft_stable_checkpoint(); - for (const auto &vc: nv.view_changed_cert.view_changes) { - if (vc.prepared_cert.block_info.block_num > highest_ppc.block_info.block_num + for (auto const &vc: nv.view_changed_cert.view_changes) { + if (vc.prepared_cert.block_info.block_num() > highest_ppc.block_info.block_num() && is_valid_prepared_certificate(vc.prepared_cert)) { highest_ppc = vc.prepared_cert; } @@ -949,7 +944,7 @@ namespace eosio { } } - if (vc.stable_checkpoint.block_info.block_num > highest_scp.block_info.block_num + if (vc.stable_checkpoint.block_info.block_num() > highest_scp.block_info.block_num() && is_valid_stable_checkpoint(vc.stable_checkpoint)) { highest_scp = vc.stable_checkpoint; } @@ -978,8 +973,8 @@ namespace eosio { bool pbft_database::should_stop_view_change(const pbft_view_change &vc) { auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - return lscb_num > vc.prepared_cert.block_info.block_num - && lscb_num > vc.stable_checkpoint.block_info.block_num; + return lscb_num > vc.prepared_cert.block_info.block_num() + && lscb_num > vc.stable_checkpoint.block_info.block_num(); } vector> pbft_database::fetch_fork_from(vector &block_infos) { @@ -994,7 +989,7 @@ namespace eosio { } sort(block_infos.begin(), block_infos.end(), - [](const block_info_type &a, const block_info_type &b) -> bool { return a.block_num > b.block_num; }); + [](const block_info_type &a, const block_info_type &b) -> bool { return a.block_num() > b.block_num(); }); while (!block_infos.empty()) { auto fork = fetch_first_fork_from(block_infos); @@ -1016,11 +1011,11 @@ namespace eosio { return result; } //bi should be sorted desc - auto high = bi.front().block_num; - auto low = bi.back().block_num; + auto high = bi.front().block_num(); + auto low = bi.back().block_num(); auto id = bi.front().block_id; - auto num = bi.front().block_num; + auto num = bi.front().block_num(); while (num <= high && num >= low && !bi.empty()) { auto bs = ctrl.fetch_block_state_by_id(id); @@ -1061,14 +1056,7 @@ namespace eosio { 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_info_type{current_bs->id, current_bs->block_num}) { - return true; - } - current_bs = ctrl.fetch_block_state_by_id(current_bs->prev()); - } - return false; + return bi.block_id == calculated_block_info.block_id; } pbft_stable_checkpoint pbft_database::fetch_stable_checkpoint_from_blk_extn(const signed_block_ptr &b) { @@ -1101,7 +1089,7 @@ namespace eosio { } pbft_stable_checkpoint pbft_database::get_stable_checkpoint_by_id(const block_id_type &block_id) { - const auto &by_block = checkpoint_index.get(); + auto const &by_block = checkpoint_index.get(); auto itr = by_block.find(block_id); if (itr == by_block.end()) { auto blk = ctrl.fetch_block_by_id(block_id); @@ -1113,7 +1101,7 @@ namespace eosio { if (cpp->is_stable) { if (ctrl.my_signature_providers().empty()) return pbft_stable_checkpoint(); pbft_stable_checkpoint psc; - psc.block_info={cpp->block_id, cpp->block_num}; psc.checkpoints=cpp->checkpoints;; + psc.block_info={cpp->block_id}; psc.checkpoints=cpp->checkpoints; return psc; } else return pbft_stable_checkpoint(); } @@ -1122,9 +1110,9 @@ namespace eosio { auto lscb_num = ctrl.last_stable_checkpoint_block_num(); auto lscb_id = ctrl.last_stable_checkpoint_block_id(); - auto lscb_info = block_info_type{lscb_id, lscb_num}; + auto lscb_info = block_info_type{lscb_id}; - const auto &by_blk_num = checkpoint_index.get(); + auto const &by_blk_num = checkpoint_index.get(); auto itr = by_blk_num.lower_bound(lscb_num); if (itr == by_blk_num.end()) return lscb_info; @@ -1139,7 +1127,7 @@ namespace eosio { producer_schedule_type new_schedule; if (lscb_num == 0) { - const auto& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; + auto const& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; if (ucb == 0) { current_schedule = ctrl.initial_schedule(); new_schedule = ctrl.initial_schedule(); @@ -1158,8 +1146,7 @@ namespace eosio { if ((*itr)->is_stable && (head_checkpoint_schedule == current_schedule || head_checkpoint_schedule == new_schedule)) { - lscb_info.block_id = (*itr)->block_id; - lscb_info.block_num = (*itr)->block_num; + lscb_info = block_info_type{(*itr)->block_id}; } } ++itr; @@ -1168,26 +1155,25 @@ namespace eosio { } vector pbft_database::generate_and_add_pbft_checkpoint() { - auto new_pc = vector{}; - new_pc.reserve(ctrl.my_signature_providers().size()); - const auto &by_commit_and_num_index = pbft_state_index.get(); - auto itr = by_commit_and_num_index.begin(); - if (itr == by_commit_and_num_index.end() || !(*itr)->should_committed) return new_pc; - - pbft_state_ptr psp = (*itr); - - flat_map pending_checkpoint_block_num; // block_height and retry_flag - auto checkpoint = [&](const block_num_type &in) { - const auto& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; + auto const& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; if (!ctrl.is_pbft_enabled()) return false; if (in <= ucb) return false; auto watermarks = get_updated_watermarks(); return in == ucb + 1 // checkpoint on first pbft block; - || in % 100 == 1 // checkpoint on every 100 block; - || std::find(watermarks.begin(), watermarks.end(), in) != watermarks.end(); // checkpoint on bp schedule change; + || in % 100 == 1 // checkpoint on every 100 block; + || std::find(watermarks.begin(), watermarks.end(), in) != watermarks.end(); // checkpoint on bp schedule change; }; + auto new_pc = vector{}; + new_pc.reserve(ctrl.my_signature_providers().size()); + auto const &by_commit_and_num_index = pbft_state_index.get(); + auto itr = by_commit_and_num_index.begin(); + if (itr == by_commit_and_num_index.end() || !(*itr)->is_committed) return new_pc; + + pbft_state_ptr psp = (*itr); + + flat_map pending_checkpoint_block_num; // block_height and retry_flag for (auto i = psp->block_num; i > ctrl.last_stable_checkpoint_block_num() && i > 1; --i) { if (checkpoint(i)) { auto &by_block = checkpoint_index.get(); @@ -1201,7 +1187,7 @@ namespace eosio { for (auto const &my_sp : ctrl.my_signature_providers()) { auto p_itr = find_if(checkpoints.begin(), checkpoints.end(), [&](const pbft_checkpoint &ext) { return ext.common.sender == my_sp.first; }); - if (p_itr != checkpoints.end()) pending_checkpoint_block_num[i] = true; //retry sending at this time. + if (p_itr != checkpoints.end() && !(*c_itr)->is_stable) pending_checkpoint_block_num[i] = true; //retry sending at this time. } if (pending_checkpoint_block_num.find(i) == pending_checkpoint_block_num.end()) { pending_checkpoint_block_num[i] = false; @@ -1219,7 +1205,7 @@ namespace eosio { for (auto const &my_sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); pbft_checkpoint cp; - cp.common.uuid=uuid; cp.block_info={bs->id, bs->block_num}; cp.common.sender=my_sp.first; cp.common.chain_id=chain_id; + cp.common.uuid=uuid; cp.block_info={bs->id}; cp.common.sender=my_sp.first; cp.common.chain_id=chain_id; cp.sender_signature = my_sp.second(cp.digest()); if (!bnum_and_retry.second) { //first time sending this checkpoint add_pbft_checkpoint(cp); @@ -1247,7 +1233,7 @@ namespace eosio { auto &by_block = checkpoint_index.get(); auto itr = by_block.find(cp.block_info.block_id); if (itr == by_block.end()) { - auto cs = pbft_checkpoint_state{cp.block_info.block_id, cp.block_info.block_num, .checkpoints={cp}}; + auto cs = pbft_checkpoint_state{cp.block_info.block_id, cp.block_info.block_num(), .checkpoints={cp}}; auto csp = make_shared(cs); checkpoint_index.insert(csp); itr = by_block.find(cp.block_info.block_id); @@ -1264,14 +1250,16 @@ namespace eosio { } auto csp = (*itr); - auto cp_count = 0; - if (!csp->is_stable) { + auto threshold = active_bps.size() * 2 / 3 + 1; + if (csp->checkpoints.size() >= threshold && !csp->is_stable) { + auto cp_count = 0; + for (auto const &sp: active_bps) { for (auto const &pp: csp->checkpoints) { if (sp.block_signing_key == pp.common.sender) cp_count += 1; } } - if (cp_count >= active_bps.size() * 2 / 3 + 1) { + if (cp_count >= threshold) { by_block.modify(itr, [&](const pbft_checkpoint_state_ptr &pcp) { csp->is_stable = true; }); auto id = csp->block_id; auto blk = ctrl.fetch_block_by_id(id); @@ -1304,12 +1292,12 @@ namespace eosio { void pbft_database::checkpoint_local() { auto lscb_info = cal_pending_stable_checkpoint(); auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - auto pending_num = lscb_info.block_num; + auto pending_num = lscb_info.block_num(); auto pending_id = lscb_info.block_id; if (pending_num > lscb_num) { ctrl.set_pbft_latest_checkpoint(pending_id); if (ctrl.last_irreversible_block_num() < pending_num) ctrl.pbft_commit_local(pending_id); - const auto &by_block_id_index = pbft_state_index.get(); + auto const &by_block_id_index = pbft_state_index.get(); auto pitr = by_block_id_index.find(pending_id); if (pitr != by_block_id_index.end()) { prune(*pitr); @@ -1328,14 +1316,14 @@ namespace eosio { bool pbft_database::is_valid_checkpoint(const pbft_checkpoint &cp) { if (!(is_valid_pbft_message(cp.common) && cp.is_signature_valid())) return false; - if (cp.block_info.block_num > ctrl.head_block_num() - || cp.block_info.block_num <= ctrl.last_stable_checkpoint_block_num() + if (cp.block_info.block_num() > ctrl.head_block_num() + || cp.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num() || !cp.is_signature_valid()) return false; auto bs = ctrl.fetch_block_state_by_id(cp.block_info.block_id); if (bs) { auto active_bps = bs->active_schedule.producers; - for (const auto &bp: active_bps) { + for (auto const &bp: active_bps) { if (bp.block_signing_key == cp.common.sender) return true; } } @@ -1343,18 +1331,18 @@ namespace eosio { } bool pbft_database::is_valid_stable_checkpoint(const pbft_stable_checkpoint &scp) { - if (scp.block_info.block_num <= ctrl.last_stable_checkpoint_block_num()) + if (scp.block_info.block_num() <= ctrl.last_stable_checkpoint_block_num()) // the stable checkpoint is way behind lib, no way getting the block state, // it will not be applied nor saved, thus considered safe. return true; auto valid = true; - for (const auto &c: scp.checkpoints) { + for (auto const &c: scp.checkpoints) { valid = valid && is_valid_checkpoint(c) && c.block_info == scp.block_info; if (!valid) return false; } - auto bs = ctrl.fetch_block_state_by_number(scp.block_info.block_num); + auto bs = ctrl.fetch_block_state_by_number(scp.block_info.block_num()); if (bs) { auto as = bs->active_schedule; auto cp_count = 0; @@ -1407,7 +1395,7 @@ namespace eosio { auto num = ctrl.last_stable_checkpoint_block_num(); if (num == 0) { - const auto &ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; + auto const &ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; if (ucb == 0) return ctrl.initial_schedule(); num = ucb; } diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index f570a43914e..f9d03274d47 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -2783,11 +2783,11 @@ namespace eosio { } void net_plugin_impl::handle_message(const connection_ptr& c, const request_message& msg) { - if( msg.req_blocks.ids.size() > 1 ) { - elog( "Invalid request_message, req_blocks.ids.size ${s}", ("s", msg.req_blocks.ids.size()) ); - close(c); - return; - } +// if( msg.req_blocks.ids.size() > 1 ) { +// elog( "Invalid request_message, req_blocks.ids.size ${s}", ("s", msg.req_blocks.ids.size()) ); +// close(c); +// return; +// } // we should enable requesting multiple blocks switch (msg.req_blocks.mode) { case catch_up : @@ -2797,7 +2797,9 @@ namespace eosio { case normal : peer_ilog(c, "received request_message:normal"); if( !msg.req_blocks.ids.empty() ) { - c->blk_send(msg.req_blocks.ids.back()); + for (auto const &bid: msg.req_blocks.ids) { + c->blk_send(bid); + } } break; default:; @@ -3025,7 +3027,7 @@ namespace eosio { if (!pcc.pbft_db.is_valid_prepare(msg)) return; bcast_pbft_msg(msg, pbft_message_TTL); - fc_dlog( logger, "sent prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num)("v", msg.view)("k", msg.common.sender)); + fc_dlog( logger, "sent prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num())("v", msg.view)("k", msg.common.sender)); } void net_plugin_impl::pbft_outgoing_commit(const pbft_commit &msg) { @@ -3036,7 +3038,7 @@ namespace eosio { if (!pcc.pbft_db.is_valid_commit(msg)) return; bcast_pbft_msg(msg, pbft_message_TTL); - fc_dlog( logger, "sent commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num)("v", msg.view)("k", msg.common.sender)); + fc_dlog( logger, "sent commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num())("v", msg.view)("k", msg.common.sender)); } void net_plugin_impl::pbft_outgoing_view_change(const pbft_view_change &msg) { @@ -3069,7 +3071,7 @@ namespace eosio { if (!pcc.pbft_db.is_valid_checkpoint(msg)) return; bcast_pbft_msg(msg, pbft_message_TTL); - fc_dlog( logger, "sent checkpoint at height: ${n}, from ${k}, ", ("n", msg.block_info.block_num)("k", msg.common.sender)); + fc_dlog( logger, "sent checkpoint at height: ${n}, from ${k}, ", ("n", msg.block_info.block_num())("k", msg.common.sender)); } bool net_plugin_impl::maybe_add_to_pbft_cache(const string &uuid){ @@ -3105,7 +3107,7 @@ namespace eosio { if (!pcc.pbft_db.is_valid_prepare(msg)) return; forward_pbft_msg(c, msg, pbft_message_TTL); - fc_dlog( logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num)("v", msg.view)("k", msg.common.sender)); + fc_dlog( logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num())("v", msg.view)("k", msg.common.sender)); pbft_incoming_prepare_channel.publish(msg); @@ -3122,7 +3124,7 @@ namespace eosio { if (!pcc.pbft_db.is_valid_commit(msg)) return; forward_pbft_msg(c, msg, pbft_message_TTL); - fc_dlog( logger, "received commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num)("v", msg.view)("k", msg.common.sender)); + fc_dlog( logger, "received commit at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num())("v", msg.view)("k", msg.common.sender)); pbft_incoming_commit_channel.publish(msg); } @@ -3135,7 +3137,22 @@ namespace eosio { if (!added) return; pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); + controller &ctrl = my_impl->chain_plug->chain(); if (!pcc.pbft_db.is_valid_view_change(msg)) return; + auto missing_blocks = set{}; + for (auto const &b: msg.prepared_cert.pre_prepares) { + if (!ctrl.fetch_block_by_id(b)) missing_blocks.emplace(b); + } + + if (!missing_blocks.empty()) { + request_message req; + for (auto const &b: missing_blocks) { + req.req_blocks.ids.push_back(b); + } + req.req_trx.mode = normal; + req.req_blocks.mode = normal; + c->enqueue(req); + } forward_pbft_msg(c, msg, pbft_message_TTL); fc_dlog( logger, "received view change {cv: ${cv}, tv: ${tv}} from ${v}", ("cv", msg.current_view)("tv", msg.target_view)("v", msg.common.sender)); @@ -3186,7 +3203,7 @@ namespace eosio { if (!pcc.pbft_db.is_valid_checkpoint(msg)) return; forward_pbft_msg(c, msg, pbft_message_TTL); - fc_dlog( logger, "received checkpoint at ${n}, from ${v}", ("n", msg.block_info.block_num)("v", msg.common.sender)); + fc_dlog( logger, "received checkpoint at ${n}, from ${v}", ("n", msg.block_info.block_num())("v", msg.common.sender)); pbft_incoming_checkpoint_channel.publish(msg); } @@ -3196,7 +3213,7 @@ namespace eosio { pbft_controller &pcc = my_impl->chain_plug->pbft_ctrl(); if (pcc.pbft_db.is_valid_stable_checkpoint(msg)) { - fc_ilog(logger, "received stable checkpoint at ${n}, from ${v}", ("n", msg.block_info.block_num)("v", c->peer_name())); + fc_ilog(logger, "received stable checkpoint at ${n}, from ${v}", ("n", msg.block_info.block_num())("v", c->peer_name())); for (auto cp: msg.checkpoints) { pbft_incoming_checkpoint_channel.publish(cp); } From a3d05a032ce79c818dc61ce65e3366bc9a2925ee Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 12 Jun 2019 18:04:30 +0800 Subject: [PATCH 22/22] bug fix: reset view change state cache properly. --- libraries/chain/include/eosio/chain/pbft.hpp | 2 +- .../include/eosio/chain/pbft_database.hpp | 2 +- libraries/chain/pbft.cpp | 23 ++++++++++--------- libraries/chain/pbft_database.cpp | 11 ++++++--- plugins/net_plugin/net_plugin.cpp | 1 - unittests/pbft_tests.cpp | 4 ++-- 6 files changed, 24 insertions(+), 19 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index 193acc86f0e..cba705a2c50 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -52,7 +52,7 @@ namespace eosio { void transit_to_prepared_state(psm_state_ptr s); - void send_pbft_view_change(); + void do_send_view_change(); void transit_to_view_change_state(psm_state_ptr s); diff --git a/libraries/chain/include/eosio/chain/pbft_database.hpp b/libraries/chain/include/eosio/chain/pbft_database.hpp index a92f25dc9f5..1bff8528ae1 100644 --- a/libraries/chain/include/eosio/chain/pbft_database.hpp +++ b/libraries/chain/include/eosio/chain/pbft_database.hpp @@ -634,7 +634,7 @@ FC_REFLECT(eosio::chain::pbft_view_change, (common)(current_view)(target_view)(p FC_REFLECT(eosio::chain::pbft_new_view, (common)(new_view)(prepared_cert)(committed_cert)(stable_checkpoint)(view_changed_cert)(sender_signature)) -FC_REFLECT(eosio::chain::pbft_prepared_certificate, (block_info)(prepares)) +FC_REFLECT(eosio::chain::pbft_prepared_certificate, (block_info)(pre_prepares)(prepares)) FC_REFLECT(eosio::chain::pbft_committed_certificate,(block_info)(commits)) FC_REFLECT(eosio::chain::pbft_view_changed_certificate, (target_view)(view_changes)) FC_REFLECT(eosio::chain::pbft_stable_checkpoint, (block_info)(checkpoints)) diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 02b1ad4530f..dc8e87f8198 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -353,7 +353,7 @@ namespace eosio { return; } - m->send_pbft_view_change(); + m->do_send_view_change(); m->maybe_new_view(shared_from_this()); } @@ -409,7 +409,7 @@ namespace eosio { set_current(std::make_shared()); if (pbft_db.should_send_pbft_msg()) { - send_pbft_view_change(); + do_send_view_change(); auto nv = maybe_new_view(s); if (nv) return; } @@ -475,7 +475,7 @@ namespace eosio { if (!new_view.committed_cert.empty()) { auto committed_certs = new_view.committed_cert; std::sort(committed_certs.begin(), committed_certs.end()); - for (auto cc :committed_certs) { + for (auto const &cc :committed_certs) { for (auto c: cc.commits) { try { pbft_db.add_pbft_commit(c); @@ -505,20 +505,21 @@ namespace eosio { transit_to_committed_state(s, true); } - void psm_machine::send_pbft_view_change() { + void psm_machine::do_send_view_change() { + + auto reset_view_change_state = [&]() { + set_view_changes_cache(vector{}); + set_prepared_certificate(pbft_db.generate_prepared_certificate()); + set_committed_certificate(pbft_db.generate_committed_certificate()); + }; if (get_target_view_retries() < pow(2,get_target_view() - get_current_view() - 1)) { + if (get_target_view_retries() == 0) reset_view_change_state(); set_target_view_retries(get_target_view_retries() + 1); } else { set_target_view_retries(0); set_target_view(get_target_view() + 1); - set_view_changes_cache(vector{}); - } - - if (get_target_view_retries() == 0) { - set_view_changes_cache(vector{}); - set_prepared_certificate(pbft_db.generate_prepared_certificate()); - set_committed_certificate(pbft_db.generate_committed_certificate()); + reset_view_change_state(); } EOS_ASSERT((get_target_view() > get_current_view()), pbft_exception, diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 7f6219dfc97..338c7fbd441 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -153,10 +153,15 @@ namespace eosio { } } - void pbft_database::mark_as_prepared(const block_id_type &bid) { + void pbft_database::mark_as_prepared(const block_id_type &bid) { auto &by_block_id_index = pbft_state_index.get(); auto itr = by_block_id_index.find(bid); - if (itr == by_block_id_index.end()) return; + if (itr == by_block_id_index.end()) { + auto ps = pbft_state{bid, block_info_type{bid}.block_num(), .is_prepared = true}; + auto psp = make_shared(ps); + pbft_state_index.insert(psp); + return; + } by_block_id_index.modify(itr, [&](const pbft_state_ptr &p) { p->is_prepared = true; }); } @@ -615,7 +620,7 @@ namespace eosio { if (!prepared_block_state) return pbft_prepared_certificate(); auto as = prepared_block_state->active_schedule.producers; - if (psp->is_prepared && (psp->block_num > (ctrl.last_irreversible_block_num()))) { + if (psp->is_prepared && psp->block_num > ctrl.last_irreversible_block_num()) { auto prepares = psp->prepares; auto valid_prepares = vector{}; diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index f9d03274d47..cdc243a8fef 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -3110,7 +3110,6 @@ namespace eosio { fc_dlog( logger, "received prepare at height: ${n}, view: ${v}, from ${k}, ", ("n", msg.block_info.block_num())("v", msg.view)("k", msg.common.sender)); pbft_incoming_prepare_channel.publish(msg); - } void net_plugin_impl::handle_message( connection_ptr c, const pbft_commit &msg) { diff --git a/unittests/pbft_tests.cpp b/unittests/pbft_tests.cpp index af00cb8cefa..2b68d3c80df 100644 --- a/unittests/pbft_tests.cpp +++ b/unittests/pbft_tests.cpp @@ -212,7 +212,7 @@ BOOST_AUTO_TEST_CASE(view_change_validation) { for(int i = 0; i< pbft_ctrl.view_change_timeout; i++){ pbft_ctrl.maybe_pbft_view_change(); } - pbft_ctrl.state_machine->send_pbft_view_change(); + pbft_ctrl.state_machine->do_send_view_change(); auto new_view = pbft_ctrl.pbft_db.get_proposed_new_view_num(); auto vcc = pbft_ctrl.pbft_db.generate_view_changed_certificate(new_view); auto nv_msg = pbft_ctrl.pbft_db.send_pbft_new_view(vcc, new_view); @@ -304,7 +304,7 @@ BOOST_AUTO_TEST_CASE(switch_fork_when_accept_new_view_with_prepare_certificate_o for(int i = 0; isend_pbft_view_change(); + pbft_new_view_generator.state_machine->do_send_view_change(); auto new_view = pbft_new_view_generator.pbft_db.get_proposed_new_view_num(); auto vcc = pbft_new_view_generator.pbft_db.generate_view_changed_certificate(new_view); auto nv_msg = pbft_new_view_generator.pbft_db.send_pbft_new_view(