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));