diff --git a/src/net.cpp b/src/net.cpp index e1c86e23962cc..a49132c8dfc77 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -3486,8 +3486,7 @@ void CConnman::ThreadOpenMasternodeConnections(CDeterministicMNManager& dmnman, didConnect = false; - if (!fNetworkActive || !mn_sync.IsBlockchainSynced()) - continue; + if (!fNetworkActive || !m_masternode_thread_active || !mn_sync.IsBlockchainSynced()) continue; std::set connectedNodes; std::map connectedProRegTxHashes; diff --git a/src/net.h b/src/net.h index 33c6c8908cf19..ab17ca77587d9 100644 --- a/src/net.h +++ b/src/net.h @@ -1223,6 +1223,8 @@ friend class CNode; bool GetNetworkActive() const { return fNetworkActive; }; bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; }; void SetNetworkActive(bool active, CMasternodeSync* const mn_sync); + bool GetMasternodeThreadActive() const { return m_masternode_thread_active; }; + void SetMasternodeThreadActive(bool active) { m_masternode_thread_active = active; }; SocketEventsMode GetSocketEventsMode() const { return socketEventsMode; } enum class MasternodeConn { @@ -1721,6 +1723,7 @@ friend class CNode; std::vector vhListenSocket; std::atomic fNetworkActive{true}; + std::atomic m_masternode_thread_active{true}; bool fAddressesInitialized{false}; AddrMan& addrman; const NetGroupManager& m_netgroupman; diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 8af1bcf4410cf..fd4d3a08d49f5 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -175,6 +175,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "prioritisetransaction", 1, "fee_delta" }, { "setban", 2, "bantime" }, { "setban", 3, "absolute" }, + { "setmnthreadactive", 0, "state" }, { "setnetworkactive", 0, "state" }, { "setcoinjoinrounds", 0, "rounds" }, { "setcoinjoinamount", 0, "amount" }, diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index b4c962fd876f1..a5ae324644c0d 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -1019,6 +1019,32 @@ static RPCHelpMan addpeeraddress() }; } +static RPCHelpMan setmnthreadactive() +{ + return RPCHelpMan{"setmnthreadactive", + "\nDisable/enable automatic masternode connections thread activity.\n", + { + {"state", RPCArg::Type::BOOL, RPCArg::Optional::NO, "true to enable the thread, false to disable"}, + }, + RPCResult{RPCResult::Type::BOOL, "", "The value that was passed in"}, + RPCExamples{""}, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ + + if (Params().NetworkIDString() != CBaseChainParams::REGTEST) { + throw std::runtime_error("setmnthreadactive is for regression testing (-regtest mode) only."); + } + + const NodeContext& node = EnsureAnyNodeContext(request.context); + CConnman& connman = EnsureConnman(node); + + connman.SetMasternodeThreadActive(request.params[0].get_bool()); + + return connman.GetMasternodeThreadActive(); +}, + }; +} + void RegisterNetRPCCommands(CRPCTable &t) { // clang-format off @@ -1042,6 +1068,7 @@ static const CRPCCommand commands[] = { "hidden", &addconnection, }, { "hidden", &addpeeraddress, }, + { "hidden", &setmnthreadactive }, }; // clang-format on for (const auto& c : commands) { diff --git a/src/test/fuzz/rpc.cpp b/src/test/fuzz/rpc.cpp index 79062ef49d2c1..7a2e052649ffc 100644 --- a/src/test/fuzz/rpc.cpp +++ b/src/test/fuzz/rpc.cpp @@ -150,6 +150,7 @@ const std::vector RPC_COMMANDS_SAFE_FOR_FUZZING{ "reconsiderblock", "scantxoutset", "sendrawtransaction", + "setmnthreadactive", "setmocktime", "setnetworkactive", "signmessagewithprivkey", diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index ccbc4596672ef..d30ff52bca5a8 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -1083,6 +1083,8 @@ def __init__(self, proTxHash, ownerAddr, votingAddr, rewards_address, operator_r self.collateral_vout = collateral_vout self.addr = addr self.evo = evo + self.node = None + self.nodeIdx = None class DashTestFramework(BitcoinTestFramework): @@ -1097,6 +1099,15 @@ def run_test(self): """Tests must override this method to define test logic""" raise NotImplementedError + def connect_nodes(self, a, b): + for mn2 in self.mninfo: + if mn2.node is not None: + mn2.node.setmnthreadactive(False) + super().connect_nodes(a, b) + for mn2 in self.mninfo: + if mn2.node is not None: + mn2.node.setmnthreadactive(True) + def set_dash_test_params(self, num_nodes, masterodes_count, extra_args=None, fast_dip3_enforcement=False, evo_count=0): self.mn_count = masterodes_count self.evo_count = evo_count @@ -1435,17 +1446,12 @@ def do_connect(idx): job.result() jobs.clear() - # connect nodes in parallel - for idx in range(0, self.mn_count): - jobs.append(executor.submit(do_connect, idx)) - - # wait for all nodes to connect - for job in jobs: - job.result() - jobs.clear() - executor.shutdown() + # connect nodes + for idx in range(0, self.mn_count): + do_connect(idx) + def start_masternode(self, mninfo, extra_args=None): args = ['-masternodeblsprivkey=%s' % mninfo.keyOperator] + self.extra_args[mninfo.nodeIdx] if extra_args is not None: