@@ -68,6 +68,12 @@ bool TierTwoConnMan::isMasternodeQuorumNode(const CNode* pnode)
6868 return false ;
6969}
7070
71+ void TierTwoConnMan::addPendingProbeConnections (const std::set<uint256>& proTxHashes)
72+ {
73+ LOCK (cs_vPendingMasternodes);
74+ masternodePendingProbes.insert (proTxHashes.begin (), proTxHashes.end ());
75+ }
76+
7177void TierTwoConnMan::start (CScheduler& scheduler)
7278{
7379 // Must be started after connman
@@ -94,10 +100,10 @@ void TierTwoConnMan::interrupt()
94100 interruptNet ();
95101}
96102
97- void TierTwoConnMan::openConnection (const CAddress& addrConnect)
103+ void TierTwoConnMan::openConnection (const CAddress& addrConnect, bool isProbe )
98104{
99105 if (interruptNet) return ;
100- connman->OpenNetworkConnection (addrConnect, false , nullptr , nullptr , false , false , false , true );
106+ connman->OpenNetworkConnection (addrConnect, false , nullptr , nullptr , false , false , false , true , isProbe );
101107}
102108
103109class PeerData {
@@ -109,6 +115,13 @@ class PeerData {
109115 bool operator ==(const CService& s) const { return service == s; }
110116};
111117
118+ struct MnService {
119+ public:
120+ uint256 verif_proreg_tx_hash{UINT256_ZERO};
121+ bool is_inbound{false };
122+ bool operator ==(const uint256& hash) const { return verif_proreg_tx_hash == hash; }
123+ };
124+
112125void TierTwoConnMan::ThreadOpenMasternodeConnections ()
113126{
114127 const auto & chainParams = Params ();
@@ -131,11 +144,11 @@ void TierTwoConnMan::ThreadOpenMasternodeConnections()
131144 // Gather all connected peers first, so we don't
132145 // try to connect to an already connected peer
133146 std::vector<PeerData> connectedNodes;
134- std::set<uint256 > connectedProRegTxHashes;
147+ std::vector<MnService > connectedProRegTxHashes;
135148 connman->ForEachNode ([&](const CNode* pnode) {
136149 connectedNodes.emplace_back (PeerData{pnode->addr , pnode->fDisconnect , pnode->m_masternode_connection });
137150 if (!pnode->verifiedProRegTxHash .IsNull ()) {
138- connectedProRegTxHashes.emplace ( pnode->verifiedProRegTxHash );
151+ connectedProRegTxHashes.emplace_back (MnService{ pnode->verifiedProRegTxHash , pnode-> fInbound } );
139152 }
140153 });
141154
@@ -144,13 +157,14 @@ void TierTwoConnMan::ThreadOpenMasternodeConnections()
144157 // Current list
145158 auto mnList = deterministicMNManager->GetListAtChainTip ();
146159 int64_t currentTime = GetAdjustedTime ();
160+ bool isProbe = false ;
147161 {
148162 LOCK (cs_vPendingMasternodes);
149163 std::vector<CDeterministicMNCPtr> pending;
150164 for (const auto & group: masternodeQuorumNodes) {
151165 for (const auto & proRegTxHash: group.second ) {
152166 // Skip if already have this member connected
153- if (connectedProRegTxHashes.count ( proRegTxHash)) continue ;
167+ if (std::count ( connectedProRegTxHashes.begin (), connectedProRegTxHashes. end (), proRegTxHash) > 0 ) continue ;
154168
155169 // Check if DMN exists in tip list
156170 const auto & dmn = mnList.GetValidMN (proRegTxHash);
@@ -171,13 +185,52 @@ void TierTwoConnMan::ThreadOpenMasternodeConnections()
171185 pending.emplace_back (dmn);
172186 }
173187 }
174- // todo: add proving system.
175188 // Select a random node to connect
176189 if (!pending.empty ()) {
177190 dmnToConnect = pending[GetRandInt ((int )pending.size ())];
178191 LogPrint (BCLog::NET_MN, " TierTwoConnMan::%s -- opening quorum connection to %s, service=%s\n " ,
179192 __func__, dmnToConnect->proTxHash .ToString (), dmnToConnect->pdmnState ->addr .ToString ());
180193 }
194+
195+ // If no node was selected, let's try to probe nodes connection
196+ if (!dmnToConnect) {
197+ for (auto it = masternodePendingProbes.begin (); it != masternodePendingProbes.end (); ) {
198+ auto dmn = mnList.GetMN (*it);
199+ if (!dmn) {
200+ it = masternodePendingProbes.erase (it);
201+ continue ;
202+ }
203+
204+ // Discard already connected outbound MNs
205+ auto mnService = std::find (connectedProRegTxHashes.begin (), connectedProRegTxHashes.end (), dmn->proTxHash );
206+ bool connectedAndOutbound = mnService != std::end (connectedProRegTxHashes) && !mnService->is_inbound ;
207+ if (connectedAndOutbound) {
208+ // we already have an outbound connection to this MN so there is no eed to probe it again
209+ g_mmetaman.GetMetaInfo (dmn->proTxHash )->SetLastOutboundSuccess (currentTime);
210+ it = masternodePendingProbes.erase (it);
211+ continue ;
212+ }
213+
214+ ++it;
215+
216+ int64_t lastAttempt = g_mmetaman.GetMetaInfo (dmn->proTxHash )->GetLastOutboundAttempt ();
217+ // back off trying connecting to an address if we already tried recently
218+ if (currentTime - lastAttempt < chainParams.LLMQConnectionRetryTimeout ()) {
219+ continue ;
220+ }
221+ pending.emplace_back (dmn);
222+ }
223+
224+ // Select a random node to connect
225+ if (!pending.empty ()) {
226+ dmnToConnect = pending[GetRandInt ((int )pending.size ())];
227+ masternodePendingProbes.erase (dmnToConnect->proTxHash );
228+ isProbe = true ;
229+
230+ LogPrint (BCLog::NET_MN, " CConnman::%s -- probing masternode %s, service=%s\n " ,
231+ __func__, dmnToConnect->proTxHash .ToString (), dmnToConnect->pdmnState ->addr .ToString ());
232+ }
233+ }
181234 }
182235
183236 // No DMN to connect
@@ -190,7 +243,7 @@ void TierTwoConnMan::ThreadOpenMasternodeConnections()
190243 triedConnect = true ;
191244
192245 // Now connect
193- openConnection (CAddress (dmnToConnect->pdmnState ->addr , NODE_NETWORK));
246+ openConnection (CAddress (dmnToConnect->pdmnState ->addr , NODE_NETWORK), isProbe );
194247 // should be in the list now if connection was opened
195248 bool connected = connman->ForNode (dmnToConnect->pdmnState ->addr , CConnman::AllNodes, [&](CNode* pnode) {
196249 if (pnode->fDisconnect ) {
0 commit comments