From 034760720d36ebee06bee206748d9079d3161de6 Mon Sep 17 00:00:00 2001 From: SergiySW <sergiysw@gmail.com> Date: Mon, 26 Nov 2018 23:20:41 +0300 Subject: [PATCH 1/6] Replay votes in response to a confirm_req for an active block Port of https://github.com/nanocurrency/raiblocks/pull/1382/ --- rai/core_test/node.cpp | 45 ++++++++++++++++++++++++++++++++++++++++++ rai/node/node.cpp | 38 ++++++++++++++++++++++++++++++----- rai/node/node.hpp | 1 + rai/node/voting.cpp | 10 ++++++++++ 4 files changed, 89 insertions(+), 5 deletions(-) diff --git a/rai/core_test/node.cpp b/rai/core_test/node.cpp index 2b093785b7..a3f1bb75b0 100644 --- a/rai/core_test/node.cpp +++ b/rai/core_test/node.cpp @@ -1915,3 +1915,48 @@ TEST (node, block_processor_reject_state) node.block_processor.flush (); ASSERT_TRUE (node.ledger.block_exists (send2->hash ())); } + +TEST (node, confirm_req_active) +{ + rai::system system (24000, 2); + rai::keypair key1; + system.wallet (0)->insert_adhoc (key1.prv); + rai::genesis genesis; + auto amount (rai::genesis_amount / 100); + std::shared_ptr<rai::block> send1 (std::make_shared<rai::send_block> (genesis.hash (), key1.pub, rai::genesis_amount - amount, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ()))); + system.nodes[0]->process_active (send1); + system.deadline_set (5s); + while (!system.nodes[0]->block (send1->hash ())) + { + ASSERT_NO_ERROR (system.poll ()); + } + // Force a receive to assign the stake + system.wallet (0)->receive_async (send1, key1.pub, amount, [](std::shared_ptr<rai::block>) {}); + while (!system.nodes[1]->active.active (*send1)) + { + ASSERT_NO_ERROR (system.poll ()); + } + while (system.nodes[1]->stats.count (rai::stat::type::message, rai::stat::detail::confirm_ack, rai::stat::dir::in) == 0) + { + ASSERT_NO_ERROR (system.poll ()); + } + for (size_t i = 0; i < 20; ++i) + { + system.nodes[1]->network.broadcast_confirm_req (send1); + } + while (system.nodes[0]->stats.count (rai::stat::type::message, rai::stat::detail::confirm_req, rai::stat::dir::in) < 20) + { + ASSERT_NO_ERROR (system.poll ()); + } + while (system.nodes[1]->stats.count (rai::stat::type::message, rai::stat::detail::confirm_ack, rai::stat::dir::in) < 20) + { + ASSERT_NO_ERROR (system.poll ()); + } + { + auto transaction (system.nodes[0]->store.tx_begin_read ()); + std::lock_guard<std::mutex> guard (boost::polymorphic_downcast<rai::mdb_store *> (system.nodes[0]->store_impl.get ())->cache_mutex); + auto vote (system.nodes[0]->store.vote_current (transaction, key1.pub)); + ASSERT_NE (vote, nullptr); + ASSERT_LT (vote->sequence, 20); + } +} diff --git a/rai/node/node.cpp b/rai/node/node.cpp index cd5ab93c69..c43d045a46 100644 --- a/rai/node/node.cpp +++ b/rai/node/node.cpp @@ -540,12 +540,39 @@ class network_message_visitor : public rai::message_visitor // Don't load nodes with disabled voting if (node.config.enable_voting) { - auto transaction (node.store.tx_begin_read ()); - auto successor (node.ledger.successor (transaction, message_a.block->root ())); - if (successor != nullptr) + std::lock_guard<std::mutex> active_lock (node.active.mutex); + auto active_it (node.active.roots.get<0> ().find (message_a.block->root ())); + if (active_it != node.active.roots.get<0> ().end ()) { - auto same_block (successor->hash () == message_a.block->hash ()); - confirm_block (transaction, node, sender, std::move (successor), !same_block); + // Replay votes in response to a confirm_req for an active block + for (auto & it : active_it->election->our_last_votes) + { + rai::confirm_ack confirm (it.second); + std::shared_ptr<std::vector<uint8_t>> vote_bytes (new std::vector<uint8_t>); + { + rai::vectorstream stream (*vote_bytes); + confirm.serialize (stream); + } + node.network.confirm_send (confirm, vote_bytes, sender); + } + rai::publish publish (active_it->election->status.winner); + std::shared_ptr<std::vector<uint8_t>> publish_bytes (new std::vector<uint8_t>); + { + rai::vectorstream stream (*publish_bytes); + publish.serialize (stream); + } + node.network.republish (publish.block->hash (), publish_bytes, sender); + } + else + { + // Generating new vote + auto transaction (node.store.tx_begin_read ()); + auto successor (node.ledger.successor (transaction, message_a.block->root ())); + if (successor != nullptr) + { + auto same_block (successor->hash () == message_a.block->hash ()); + confirm_block (transaction, node, sender, std::move (successor), !same_block); + } } } } @@ -2717,6 +2744,7 @@ void rai::election::compute_rep_votes (rai::transaction const & transaction_a) { node.wallets.foreach_representative (transaction_a, [this, &transaction_a](rai::public_key const & pub_a, rai::raw_key const & prv_a) { auto vote (this->node.store.vote_generate (transaction_a, pub_a, prv_a, status.winner)); + this->our_last_votes[pub_a] = vote; this->node.vote_processor.vote (vote, this->node.network.endpoint ()); }); } diff --git a/rai/node/node.hpp b/rai/node/node.hpp index bf73af717f..6205855afb 100644 --- a/rai/node/node.hpp +++ b/rai/node/node.hpp @@ -65,6 +65,7 @@ class election : public std::enable_shared_from_this<rai::election> void stop (); rai::node & node; std::unordered_map<rai::account, rai::vote_info> last_votes; + std::unordered_map<rai::account, std::shared_ptr<rai::vote>> our_last_votes; std::unordered_map<rai::block_hash, std::shared_ptr<rai::block>> blocks; rai::block_hash root; rai::election_status status; diff --git a/rai/node/voting.cpp b/rai/node/voting.cpp index 63b3f31e6e..7441d7c090 100644 --- a/rai/node/voting.cpp +++ b/rai/node/voting.cpp @@ -49,6 +49,16 @@ void rai::vote_generator::send (std::unique_lock<std::mutex> & lock_a) auto transaction (node.store.tx_begin_read ()); node.wallets.foreach_representative (transaction, [this, &hashes_l, &transaction](rai::public_key const & pub_a, rai::raw_key const & prv_a) { auto vote (this->node.store.vote_generate (transaction, pub_a, prv_a, hashes_l)); + std::unique_lock<std::mutex> lock (node.active.mutex); + for (auto & hash : hashes_l) + { + auto existing (this->node.active.successors.find (hash)); + if (existing != this->node.active.successors.end ()) + { + existing->second->our_last_votes[pub_a] = vote;; + } + } + lock.unlock (); this->node.vote_processor.vote (vote, this->node.network.endpoint ()); }); } From 99706182a0fd6f632ae821abb4c955a4140dd45e Mon Sep 17 00:00:00 2001 From: SergiySW <sergiysw@gmail.com> Date: Tue, 27 Nov 2018 03:16:29 +0300 Subject: [PATCH 2/6] Improve confirm_req active_transactions mutex lock --- rai/node/node.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rai/node/node.cpp b/rai/node/node.cpp index c43d045a46..83b546f67e 100644 --- a/rai/node/node.cpp +++ b/rai/node/node.cpp @@ -540,7 +540,7 @@ class network_message_visitor : public rai::message_visitor // Don't load nodes with disabled voting if (node.config.enable_voting) { - std::lock_guard<std::mutex> active_lock (node.active.mutex); + std::unique_lock<std::mutex> active_lock (node.active.mutex); auto active_it (node.active.roots.get<0> ().find (message_a.block->root ())); if (active_it != node.active.roots.get<0> ().end ()) { @@ -556,6 +556,7 @@ class network_message_visitor : public rai::message_visitor node.network.confirm_send (confirm, vote_bytes, sender); } rai::publish publish (active_it->election->status.winner); + active_lock.unlock (); std::shared_ptr<std::vector<uint8_t>> publish_bytes (new std::vector<uint8_t>); { rai::vectorstream stream (*publish_bytes); @@ -565,6 +566,7 @@ class network_message_visitor : public rai::message_visitor } else { + active_lock.unlock (); // Generating new vote auto transaction (node.store.tx_begin_read ()); auto successor (node.ledger.successor (transaction, message_a.block->root ())); From a42a577ec128380196fb260bab8f4b1635c6880a Mon Sep 17 00:00:00 2001 From: SergiySW <sergiysw@gmail.com> Date: Tue, 27 Nov 2018 03:33:07 +0300 Subject: [PATCH 3/6] Typo --- rai/node/voting.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rai/node/voting.cpp b/rai/node/voting.cpp index 7441d7c090..97badb7e04 100644 --- a/rai/node/voting.cpp +++ b/rai/node/voting.cpp @@ -55,7 +55,7 @@ void rai::vote_generator::send (std::unique_lock<std::mutex> & lock_a) auto existing (this->node.active.successors.find (hash)); if (existing != this->node.active.successors.end ()) { - existing->second->our_last_votes[pub_a] = vote;; + existing->second->our_last_votes[pub_a] = vote; } } lock.unlock (); From 2cf9fa9697852536356d9a9c3c9c418b3c36366c Mon Sep 17 00:00:00 2001 From: SergiySW <sergiysw@gmail.com> Date: Tue, 27 Nov 2018 21:22:21 +0300 Subject: [PATCH 4/6] Regenerate votes for long unconfirmed blocks Useful for tests & largest representatives --- rai/node/node.cpp | 6 ++++++ rai/node/node.hpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/rai/node/node.cpp b/rai/node/node.cpp index 83b546f67e..c89fe3da74 100644 --- a/rai/node/node.cpp +++ b/rai/node/node.cpp @@ -3047,6 +3047,12 @@ void rai::active_transactions::announce_votes (std::unique_lock<std::mutex> & lo } } } + /* Regenerate votes for long unconfirmed blocks + Useful for tests & large representatives */ + if (node.config.enable_voting && election_l->our_last_votes.empty ()) + { + node.block_processor.generator.add (election_l->status.winner->hash ()); + } } } if (i->election->announcements < announcement_long || i->election->announcements % announcement_long == 1) diff --git a/rai/node/node.hpp b/rai/node/node.hpp index 6205855afb..db065f6dd8 100644 --- a/rai/node/node.hpp +++ b/rai/node/node.hpp @@ -385,6 +385,7 @@ class block_processor bool have_blocks (); void process_blocks (); rai::process_return process_receive_one (rai::transaction const &, std::shared_ptr<rai::block>, std::chrono::steady_clock::time_point = std::chrono::steady_clock::now (), bool = false); + rai::vote_generator generator; private: void queue_unchecked (rai::transaction const &, rai::block_hash const &); @@ -399,7 +400,6 @@ class block_processor std::deque<std::shared_ptr<rai::block>> forced; std::condition_variable condition; rai::node & node; - rai::vote_generator generator; std::mutex mutex; }; class node : public std::enable_shared_from_this<rai::node> From b1d05d0ce83e6aa2950f8ecfa1a3c266cfcde2a0 Mon Sep 17 00:00:00 2001 From: SergiySW <sergiysw@gmail.com> Date: Wed, 28 Nov 2018 15:46:32 +0300 Subject: [PATCH 5/6] Add recursive_mutex to foreach_representative To prevent node.unlock_search assert --- rai/core_test/node.cpp | 5 ++++- rai/node/wallet.cpp | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/rai/core_test/node.cpp b/rai/core_test/node.cpp index a3f1bb75b0..0ff29df1ea 100644 --- a/rai/core_test/node.cpp +++ b/rai/core_test/node.cpp @@ -363,7 +363,10 @@ TEST (node, unlock_search) ASSERT_NO_ERROR (system.poll ()); } system.wallet (0)->insert_adhoc (key2.prv); - system.wallet (0)->store.password.value_set (rai::keypair ().prv); + { + std::lock_guard<std::recursive_mutex> lock (system.wallet (0)->store.mutex); + system.wallet (0)->store.password.value_set (rai::keypair ().prv); + } auto node (system.nodes[0]); { auto transaction (system.wallet (0)->wallets.tx_begin (true)); diff --git a/rai/node/wallet.cpp b/rai/node/wallet.cpp index 8336798a5c..01f042f398 100644 --- a/rai/node/wallet.cpp +++ b/rai/node/wallet.cpp @@ -1385,6 +1385,7 @@ void rai::wallets::foreach_representative (rai::transaction const & transaction_ for (auto i (items.begin ()), n (items.end ()); i != n; ++i) { auto & wallet (*i->second); + std::lock_guard<std::recursive_mutex> lock (wallet.store.mutex); for (auto j (wallet.store.begin (transaction_a)), m (wallet.store.end ()); j != m; ++j) { rai::account account (j->first); From bc37550236febdf5b315a32ff68f3804f6b44813 Mon Sep 17 00:00:00 2001 From: SergiySW <sergiysw@gmail.com> Date: Wed, 28 Nov 2018 20:05:26 +0300 Subject: [PATCH 6/6] Fix build warning --- rai/node/voting.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rai/node/voting.cpp b/rai/node/voting.cpp index 97badb7e04..a42bda2247 100644 --- a/rai/node/voting.cpp +++ b/rai/node/voting.cpp @@ -49,7 +49,7 @@ void rai::vote_generator::send (std::unique_lock<std::mutex> & lock_a) auto transaction (node.store.tx_begin_read ()); node.wallets.foreach_representative (transaction, [this, &hashes_l, &transaction](rai::public_key const & pub_a, rai::raw_key const & prv_a) { auto vote (this->node.store.vote_generate (transaction, pub_a, prv_a, hashes_l)); - std::unique_lock<std::mutex> lock (node.active.mutex); + std::unique_lock<std::mutex> lock (this->node.active.mutex); for (auto & hash : hashes_l) { auto existing (this->node.active.successors.find (hash));