Skip to content

Commit b1c7c78

Browse files
committed
net_mn: test regular connection refresh after selecting peer as quorum member
1 parent 76eec64 commit b1c7c78

File tree

4 files changed

+67
-13
lines changed

4 files changed

+67
-13
lines changed

src/rpc/misc.cpp

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -760,19 +760,21 @@ const char* SINGLE_CONN = "single_conn";
760760
const char* QUORUM_MEMBERS_CONN = "quorum_members_conn";
761761
const char* IQR_MEMBERS_CONN = "iqr_members_conn";
762762
const char* PROBE_CONN = "probe_conn";
763+
const char* CLEAR_CONN = "clear_conn";
763764

764765
/* What essentially does is add a pending MN connection
765766
* Can be in the following forms:
766767
* 1) Direct single DMN connection.
767768
* 2) Quorum members connection (set of DMNs to connect).
768769
* 3) Quorum relay members connections (set of DMNs to connect and relay intra-quorum messages).
769770
* 4) Probe DMN connection.
771+
* 5) Clear tier two net connections cache
770772
**/
771773
UniValue mnconnect(const JSONRPCRequest& request)
772774
{
773-
if (request.fHelp || request.params.size() < 2 || request.params.size() > 4) {
775+
if (request.fHelp || request.params.size() > 4) {
774776
throw std::runtime_error(
775-
"mnconnect \"op_type\" \"[pro_tx_hash, pro_tx_hash,..]\" (llmq_type \"quorum_hash\")\n"
777+
"mnconnect \"op_type\" (\"[pro_tx_hash, pro_tx_hash,..]\" llmq_type \"quorum_hash\")\n"
776778
"\nAdd manual quorum members connections for internal testing purposes of the tier two p2p network layer\n"
777779
);
778780
}
@@ -781,7 +783,19 @@ UniValue mnconnect(const JSONRPCRequest& request)
781783
if (!chainparams.IsRegTestNet())
782784
throw std::runtime_error("mnconnect for regression testing (-regtest mode) only");
783785

784-
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR});
786+
// Connection type
787+
RPCTypeCheck(request.params, {UniValue::VSTR});
788+
const std::string& op_type = request.params[0].get_str();
789+
790+
// DMNs pro_tx list
791+
std::set<uint256> set_dmn_protxhash;
792+
if (request.params.size() > 1) {
793+
RPCTypeCheckArgument(request.params[1], UniValue::VARR);
794+
const auto& array{request.params[1].get_array()};
795+
for (unsigned int i = 0; i < array.size(); i++) {
796+
set_dmn_protxhash.emplace(uint256S(array[i].get_str()));
797+
}
798+
}
785799

786800
Consensus::LLMQType llmq_type = Consensus::LLMQ_NONE;
787801
if (request.params.size() > 2) {
@@ -795,15 +809,6 @@ UniValue mnconnect(const JSONRPCRequest& request)
795809
quorum_hash = uint256S(request.params[3].get_str());
796810
}
797811

798-
// First obtain the connection type
799-
const std::string& op_type = request.params[0].get_str();
800-
// Check provided mn_list
801-
const auto& array{request.params[1].get_array()};
802-
std::set<uint256> set_dmn_protxhash;
803-
for (unsigned int i = 0; i < array.size(); i++) {
804-
set_dmn_protxhash.emplace(uint256S(array[i].get_str()));
805-
}
806-
807812
const auto& mn_connan = g_connman->GetTierTwoConnMan();
808813
if (op_type == SINGLE_CONN) {
809814
for (const auto& protxhash : set_dmn_protxhash) {
@@ -821,6 +826,9 @@ UniValue mnconnect(const JSONRPCRequest& request)
821826
} else if (op_type == PROBE_CONN) {
822827
mn_connan->addPendingProbeConnections(set_dmn_protxhash);
823828
return true;
829+
} else if (op_type == CLEAR_CONN) {
830+
mn_connan->clear();
831+
return true;
824832
}
825833
return false;
826834
}

src/tiertwo/net_masternodes.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,15 @@ void TierTwoConnMan::addPendingProbeConnections(const std::set<uint256>& proTxHa
123123
masternodePendingProbes.insert(proTxHashes.begin(), proTxHashes.end());
124124
}
125125

126+
void TierTwoConnMan::clear()
127+
{
128+
LOCK(cs_vPendingMasternodes);
129+
masternodeQuorumNodes.clear();
130+
masternodeQuorumRelayMembers.clear();
131+
vPendingMasternodes.clear();
132+
masternodePendingProbes.clear();
133+
}
134+
126135
void TierTwoConnMan::start(CScheduler& scheduler, const TierTwoConnMan::Options& options)
127136
{
128137
// Must be started after connman

src/tiertwo/net_masternodes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ class TierTwoConnMan
5858
// Set the local DMN so the node does not try to connect to himself
5959
void setLocalDMN(const uint256& pro_tx_hash) { WITH_LOCK(cs_vPendingMasternodes, local_dmn_pro_tx_hash = pro_tx_hash;); }
6060

61+
// Clear connections cache
62+
void clear();
63+
6164
// Manages the MN connections
6265
void ThreadOpenMasternodeConnections();
6366
void start(CScheduler& scheduler, const TierTwoConnMan::Options& options);

test/functional/p2p_quorum_connect.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
assert_equal,
1515
assert_true,
1616
bytes_to_hex_str,
17+
connect_nodes,
1718
connect_nodes_clique,
1819
hash256,
1920
hex_str_to_bytes,
@@ -128,7 +129,17 @@ def check_peers_info(self, peers_info, quorum_members, is_iqr_conn, inbound=Fals
128129

129130
def has_mn_auth_connection(self, node, expected_proreg_tx_hash):
130131
peer_info = node.getpeerinfo()
131-
return (len(peer_info) == 1) and (peer_info[0]["verif_mn_proreg_tx_hash"] == expected_proreg_tx_hash)
132+
return (len(peer_info) == 1) and "verif_mn_proreg_tx_hash" in peer_info[0]\
133+
and (peer_info[0]["verif_mn_proreg_tx_hash"] == expected_proreg_tx_hash)
134+
135+
def has_single_regular_connection(self, node):
136+
peer_info = node.getpeerinfo()
137+
return len(peer_info) == 1 and "verif_mn_proreg_tx_hash" not in peer_info[0]
138+
139+
def clean_conns_and_disconnect(self, node):
140+
node.mnconnect("clear_conn")
141+
self.disconnect_peers(node)
142+
wait_until(lambda: len(node.getpeerinfo()) == 0, timeout=30)
132143

133144
def run_test(self):
134145
self.disable_mocktime()
@@ -224,6 +235,29 @@ def run_test(self):
224235
assert_equal(len(self.miner.getpeerinfo()), 0)
225236
self.log.info("Regular node disconnected auth connection successfully")
226237

238+
##############################################################################
239+
# 6) Now test regular connection refresh after selecting peer as quorum member
240+
##############################################################################
241+
self.log.info("6) Now test regular connection refresh after selecting peer as quorum member..")
242+
# Cleaning internal data first
243+
mn5_node = self.nodes[mn5.idx]
244+
self.clean_conns_and_disconnect(mn5_node)
245+
self.clean_conns_and_disconnect(mn6_node)
246+
247+
# Create the regular connection
248+
connect_nodes(mn5_node, mn6.idx)
249+
wait_until(lambda: len(mn5_node.getpeerinfo()) == 1, timeout=30)
250+
assert_true(self.has_single_regular_connection(mn5_node))
251+
assert_true(self.has_single_regular_connection(mn6_node))
252+
253+
# Now refresh it to be a quorum member connection
254+
quorum_hash = mn5_node.getbestblockhash()
255+
assert mn5_node.mnconnect("quorum_members_conn", [mn6.proTx], 1, quorum_hash)
256+
assert mn5_node.mnconnect("iqr_members_conn", [mn6.proTx], 1, quorum_hash)
257+
assert mn6_node.mnconnect("iqr_members_conn", [mn5.proTx], 1, quorum_hash)
258+
259+
wait_until(lambda: self.has_mn_auth_connection(mn5_node, mn6.proTx), timeout=60)
260+
self.log.info("Connection refreshed!")
227261

228262
if __name__ == '__main__':
229263
DMNConnectionTest().main()

0 commit comments

Comments
 (0)