@@ -214,6 +214,13 @@ OverlayManagerImpl::PeersList::acceptAuthenticatedPeer(Peer::pointer peer)
214214 ZoneScoped;
215215 releaseAssert (threadIsMain ());
216216
217+ if (peer->isMutualQsetPeer ())
218+ {
219+ // Mutual direct-qset peers are operator-bounded by QUORUM_SET and must
220+ // not consume ordinary inbound/outbound authenticated capacity.
221+ return moveToAuthenticated (peer);
222+ }
223+
217224 CLOG_TRACE (Overlay, " Trying to promote peer to authenticated {}" ,
218225 peer->toString ());
219226 if (mOverlayManager .isPreferred (peer.get ()))
@@ -679,6 +686,70 @@ OverlayManagerImpl::connectTo(std::vector<PeerBareAddress> const& peers,
679686 return count;
680687}
681688
689+ void
690+ OverlayManagerImpl::connectToQsetPeers (int & availablePendingSlots)
691+ {
692+ ZoneScoped;
693+ releaseAssert (availablePendingSlots >= 0 );
694+ if (availablePendingSlots == 0 )
695+ {
696+ return ;
697+ }
698+
699+ auto missing = mDirectQsetPeers ;
700+ missing.erase (mApp .getConfig ().NODE_SEED .getPublicKey ());
701+ for (auto const & peer : getAuthenticatedPeers ())
702+ {
703+ missing.erase (peer.first );
704+ }
705+ for (auto it = missing.begin (); it != missing.end ();)
706+ {
707+ auto info = mQuorumPeerState .getInfo (*it);
708+ if (info && info->remoteRole == RemoteQsetRole::None)
709+ {
710+ it = missing.erase (it);
711+ }
712+ else
713+ {
714+ ++it;
715+ }
716+ }
717+
718+ if (missing.empty ())
719+ {
720+ return ;
721+ }
722+
723+ constexpr auto QSET_PROBE_BATCH_SIZE = 4 ;
724+ std::vector<PeerBareAddress> candidates;
725+ auto appendCandidates = [&](PeerType peerType) {
726+ auto peers = getPeersToConnectTo (QSET_PROBE_BATCH_SIZE , peerType);
727+ candidates.insert (std::end (candidates), std::begin (peers),
728+ std::end (peers));
729+ };
730+ appendCandidates (PeerType::INBOUND );
731+ appendCandidates (PeerType::OUTBOUND );
732+
733+ std::set<PeerBareAddress> tried;
734+ for (auto const & address : candidates)
735+ {
736+ if (availablePendingSlots == 0 )
737+ {
738+ return ;
739+ }
740+ if (mProbedNonQset .find (address) != std::end (mProbedNonQset ) ||
741+ getConnectedPeer (address) || !tried.insert (address).second )
742+ {
743+ continue ;
744+ }
745+
746+ if (connectToImpl (address, false ))
747+ {
748+ --availablePendingSlots;
749+ }
750+ }
751+ }
752+
682753void
683754OverlayManagerImpl::updateTimerAndMaybeDropRandomPeer (bool shouldDrop)
684755{
@@ -867,6 +938,8 @@ OverlayManagerImpl::tick()
867938 availablePendingSlots -= pendingUsedByOutbound;
868939 }
869940
941+ connectToQsetPeers (availablePendingSlots);
942+
870943 // Finally, attempt to promote some inbound connections to outbound
871944 if (availablePendingSlots > 0 )
872945 {
@@ -900,10 +973,16 @@ OverlayManagerImpl::availableOutboundAuthenticatedSlots() const
900973 ? OverlayManager::MIN_INBOUND_FACTOR
901974 : mApp .getConfig ().TARGET_PEER_CONNECTIONS ;
902975
903- if (mOutboundPeers .mAuthenticated .size () < adjustedTarget)
976+ auto mutualQsetCount = std::count_if (
977+ std::begin (mOutboundPeers .mAuthenticated ),
978+ std::end (mOutboundPeers .mAuthenticated ),
979+ [](auto const & peer) { return peer.second ->isMutualQsetPeer (); });
980+ auto ordinaryOutboundCount =
981+ mOutboundPeers .mAuthenticated .size () - mutualQsetCount;
982+
983+ if (ordinaryOutboundCount < adjustedTarget)
904984 {
905- return static_cast <int >(adjustedTarget -
906- mOutboundPeers .mAuthenticated .size ());
985+ return static_cast <int >(adjustedTarget - ordinaryOutboundCount);
907986 }
908987 else
909988 {
@@ -1191,6 +1270,14 @@ OverlayManagerImpl::isDirectQsetPeer(NodeID const& nodeID) const
11911270 return mDirectQsetPeers .count (nodeID) != 0 ;
11921271}
11931272
1273+ void
1274+ OverlayManagerImpl::recordProbedNonQsetAddress (PeerBareAddress const & address)
1275+ {
1276+ releaseAssert (threadIsMain ());
1277+ releaseAssert (!address.isEmpty ());
1278+ mProbedNonQset .insert (address);
1279+ }
1280+
11941281static xdr::opaque_array<32 > const TX_BATCH_HASH = [] {
11951282 xdr::opaque_array<32 > bytes{};
11961283 for (auto & b : bytes)
0 commit comments