Merge pull request #4936 from PastaPastaPasta/v18.x-rc10

[V18.x] backport: rc10 backports
This commit is contained in:
UdjinM6 2022-07-26 02:48:10 +03:00 committed by GitHub
commit 1fa81c6a04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 85 additions and 27 deletions

View File

@ -2,7 +2,7 @@ AC_PREREQ([2.69])
define(_CLIENT_VERSION_MAJOR, 18) define(_CLIENT_VERSION_MAJOR, 18)
define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_MINOR, 0)
define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_RC, 9) define(_CLIENT_VERSION_RC, 10)
define(_CLIENT_VERSION_IS_RELEASE, false) define(_CLIENT_VERSION_IS_RELEASE, false)
define(_COPYRIGHT_YEAR, 2022) define(_COPYRIGHT_YEAR, 2022)
define(_COPYRIGHT_HOLDERS,[The %s developers]) define(_COPYRIGHT_HOLDERS,[The %s developers])

View File

@ -32,7 +32,10 @@ static const std::string DB_QUORUM_QUORUM_VVEC = "q_Qqvvec";
CQuorumManager* quorumManager; CQuorumManager* quorumManager;
CCriticalSection cs_data_requests; CCriticalSection cs_data_requests;
static std::unordered_map<std::pair<uint256, bool>, CQuorumDataRequest, StaticSaltedHasher> mapQuorumDataRequests GUARDED_BY(cs_data_requests); //key = <ProTx, bool, quorumHash, llmqType>
//TODO: Document purpose of bool
using key_t = std::tuple<uint256, bool, uint256, uint8_t>;
static std::unordered_map<key_t, CQuorumDataRequest, StaticSaltedHasher> mapQuorumDataRequests GUARDED_BY(cs_data_requests);
static uint256 MakeQuorumKey(const CQuorum& q) static uint256 MakeQuorumKey(const CQuorum& q)
{ {
@ -195,8 +198,7 @@ void CQuorumManager::TriggerQuorumDataRecoveryThreads(const CBlockIndex* pIndex)
LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Process block %s\n", __func__, pIndex->GetBlockHash().ToString()); LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Process block %s\n", __func__, pIndex->GetBlockHash().ToString());
for (auto& params : Params().GetConsensus().llmqs) { for (auto& params : Params().GetConsensus().llmqs) {
// Process signingActiveQuorumCount + 1 quorums for all available llmqTypes const auto vecQuorums = ScanQuorums(params.type, pIndex, params.keepOldConnections);
const auto vecQuorums = ScanQuorums(params.type, pIndex, params.signingActiveQuorumCount + 1);
// First check if we are member of any quorum of this type // First check if we are member of any quorum of this type
auto proTxHash = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash); auto proTxHash = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash);
@ -434,7 +436,8 @@ bool CQuorumManager::RequestQuorumData(CNode* pFrom, Consensus::LLMQType llmqTyp
} }
LOCK(cs_data_requests); LOCK(cs_data_requests);
auto key = std::make_pair(pFrom->GetVerifiedProRegTxHash(), true); auto quorumHash = pQuorumBaseBlockIndex->GetBlockHash();
auto key = std::make_tuple(pFrom->GetVerifiedProRegTxHash(), true, quorumHash, (uint8_t)llmqType);
auto it = mapQuorumDataRequests.emplace(key, CQuorumDataRequest(llmqType, pQuorumBaseBlockIndex->GetBlockHash(), nDataMask, proTxHash)); auto it = mapQuorumDataRequests.emplace(key, CQuorumDataRequest(llmqType, pQuorumBaseBlockIndex->GetBlockHash(), nDataMask, proTxHash));
if (!it.second && !it.first->second.IsExpired()) { if (!it.second && !it.first->second.IsExpired()) {
LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Already requested\n", __func__); LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Already requested\n", __func__);
@ -585,11 +588,13 @@ void CQuorumManager::ProcessMessage(CNode* pFrom, const std::string& msg_type, C
{ {
LOCK2(cs_main, cs_data_requests); LOCK2(cs_main, cs_data_requests);
auto key = std::make_pair(pFrom->GetVerifiedProRegTxHash(), false); auto quorumHash = request.GetQuorumHash();
auto llmqType = (uint8_t) request.GetLLMQType();
auto key = std::make_tuple(pFrom->GetVerifiedProRegTxHash(), false, quorumHash, llmqType);
auto it = mapQuorumDataRequests.find(key); auto it = mapQuorumDataRequests.find(key);
if (it == mapQuorumDataRequests.end()) { if (it == mapQuorumDataRequests.end()) {
it = mapQuorumDataRequests.emplace(key, request).first; it = mapQuorumDataRequests.emplace(key, request).first;
} else if(it->second.IsExpired()) { } else if (it->second.IsExpired()) {
it->second = request; it->second = request;
} else { } else {
errorHandler("Request limit exceeded", 25); errorHandler("Request limit exceeded", 25);
@ -658,7 +663,10 @@ void CQuorumManager::ProcessMessage(CNode* pFrom, const std::string& msg_type, C
{ {
LOCK2(cs_main, cs_data_requests); LOCK2(cs_main, cs_data_requests);
auto it = mapQuorumDataRequests.find(std::make_pair(pFrom->GetVerifiedProRegTxHash(), true)); auto quorumHash = request.GetQuorumHash();
auto llmqType = (uint8_t) request.GetLLMQType();
auto key = std::make_tuple(pFrom->GetVerifiedProRegTxHash(), true, quorumHash, llmqType);
auto it = mapQuorumDataRequests.find(key);
if (it == mapQuorumDataRequests.end()) { if (it == mapQuorumDataRequests.end()) {
errorHandler("Not requested"); errorHandler("Not requested");
return; return;
@ -830,7 +838,10 @@ void CQuorumManager::StartQuorumDataRecoveryThread(const CQuorumCPtr pQuorum, co
pCurrentMemberHash = &vecMemberHashes[(nMyStartOffset + nTries++) % vecMemberHashes.size()]; pCurrentMemberHash = &vecMemberHashes[(nMyStartOffset + nTries++) % vecMemberHashes.size()];
{ {
LOCK(cs_data_requests); LOCK(cs_data_requests);
auto it = mapQuorumDataRequests.find(std::make_pair(*pCurrentMemberHash, true)); auto quorumHash = pQuorum->qc->quorumHash;
auto llmqType = (uint8_t)pQuorum->qc->quorumIndex;
auto key = std::make_tuple(*pCurrentMemberHash, true, quorumHash, (uint8_t)llmqType);
auto it = mapQuorumDataRequests.find(key);
if (it != mapQuorumDataRequests.end() && !it->second.IsExpired()) { if (it != mapQuorumDataRequests.end() && !it->second.IsExpired()) {
printLog("Already asked"); printLog("Already asked");
continue; continue;
@ -855,7 +866,10 @@ void CQuorumManager::StartQuorumDataRecoveryThread(const CQuorumCPtr pQuorum, co
printLog("Requested"); printLog("Requested");
} else { } else {
LOCK(cs_data_requests); LOCK(cs_data_requests);
auto it = mapQuorumDataRequests.find(std::make_pair(verifiedProRegTxHash, true)); auto quorumHash = pQuorum->qc->quorumHash;
auto llmqType = (uint8_t)pQuorum->qc->quorumIndex;
auto key = std::make_tuple(*pCurrentMemberHash, true, quorumHash, (uint8_t)llmqType);
auto it = mapQuorumDataRequests.find(key);
if (it == mapQuorumDataRequests.end()) { if (it == mapQuorumDataRequests.end()) {
printLog("Failed"); printLog("Failed");
pNode->fDisconnect = true; pNode->fDisconnect = true;

View File

@ -798,7 +798,7 @@ bool CLLMQUtils::IsQuorumActive(Consensus::LLMQType llmqType, const uint256& quo
// sig shares and recovered sigs are only accepted from recent/active quorums // sig shares and recovered sigs are only accepted from recent/active quorums
// we allow one more active quorum as specified in consensus, as otherwise there is a small window where things could // we allow one more active quorum as specified in consensus, as otherwise there is a small window where things could
// fail while we are on the brink of a new quorum // fail while we are on the brink of a new quorum
auto quorums = quorumManager->ScanQuorums(llmqType, GetLLMQParams(llmqType).signingActiveQuorumCount + 1); auto quorums = quorumManager->ScanQuorums(llmqType, GetLLMQParams(llmqType).keepOldConnections);
return ranges::any_of(quorums, [&quorumHash](const auto& q){ return q->qc->quorumHash == quorumHash; }); return ranges::any_of(quorums, [&quorumHash](const auto& q){ return q->qc->quorumHash == quorumHash; });
} }
@ -942,7 +942,7 @@ void CLLMQUtils::InitQuorumsCache(CacheType& cache)
{ {
for (auto& llmq : Params().GetConsensus().llmqs) { for (auto& llmq : Params().GetConsensus().llmqs) {
cache.emplace(std::piecewise_construct, std::forward_as_tuple(llmq.type), cache.emplace(std::piecewise_construct, std::forward_as_tuple(llmq.type),
std::forward_as_tuple(llmq.signingActiveQuorumCount + 1)); std::forward_as_tuple(llmq.keepOldConnections));
} }
} }
template void CLLMQUtils::InitQuorumsCache<std::map<Consensus::LLMQType, unordered_lru_cache<uint256, bool, StaticSaltedHasher>>>(std::map<Consensus::LLMQType, unordered_lru_cache<uint256, bool, StaticSaltedHasher>>& cache); template void CLLMQUtils::InitQuorumsCache<std::map<Consensus::LLMQType, unordered_lru_cache<uint256, bool, StaticSaltedHasher>>>(std::map<Consensus::LLMQType, unordered_lru_cache<uint256, bool, StaticSaltedHasher>>& cache);

View File

@ -61,6 +61,9 @@ void CMasternodeUtils::ProcessMasternodeConnections(CConnman& connman)
} else if (GetSystemTimeInSeconds() - pnode->nTimeConnected < 5) { } else if (GetSystemTimeInSeconds() - pnode->nTimeConnected < 5) {
// non-verified, give it some time to verify itself // non-verified, give it some time to verify itself
return; return;
} else if (pnode->qwatch) {
// keep watching nodes
return;
} }
// we're not disconnecting masternode probes for at least a few seconds // we're not disconnecting masternode probes for at least a few seconds
if (pnode->m_masternode_probe_connection && GetSystemTimeInSeconds() - pnode->nTimeConnected < 5) return; if (pnode->m_masternode_probe_connection && GetSystemTimeInSeconds() - pnode->nTimeConnected < 5) return;

View File

@ -2379,6 +2379,7 @@ void CConnman::ThreadOpenMasternodeConnections()
return; return;
int64_t nANow = GetAdjustedTime(); int64_t nANow = GetAdjustedTime();
constexpr const auto &_func_ = __func__;
// NOTE: Process only one pending masternode at a time // NOTE: Process only one pending masternode at a time
@ -2405,6 +2406,22 @@ void CConnman::ThreadOpenMasternodeConnections()
continue; continue;
} }
const auto& addr2 = dmn->pdmnState->addr; const auto& addr2 = dmn->pdmnState->addr;
if (connectedNodes.count(addr2) && !connectedProRegTxHashes.count(proRegTxHash)) {
// we probably connected to it before it became a masternode
// or maybe we are still waiting for mnauth
(void)ForNode(addr2, [&](CNode* pnode) {
if (pnode->nTimeFirstMessageReceived != 0 && GetSystemTimeInSeconds() - pnode->nTimeFirstMessageReceived > 5) {
// clearly not expecting mnauth to take that long even if it wasn't the first message
// we received (as it should normally), disconnect
LogPrint(BCLog::NET_NETCONN, "CConnman::%s -- dropping non-mnauth connection to %s, service=%s\n", _func_, proRegTxHash.ToString(), addr2.ToString(false));
pnode->fDisconnect = true;
return true;
}
return false;
});
// either way - it's not ready, skip it for now
continue;
}
if (!connectedNodes.count(addr2) && !IsMasternodeOrDisconnectRequested(addr2) && !connectedProRegTxHashes.count(proRegTxHash)) { if (!connectedNodes.count(addr2) && !IsMasternodeOrDisconnectRequested(addr2) && !connectedProRegTxHashes.count(proRegTxHash)) {
int64_t lastAttempt = mmetaman.GetMetaInfo(dmn->proTxHash)->GetLastOutboundAttempt(); int64_t lastAttempt = mmetaman.GetMetaInfo(dmn->proTxHash)->GetLastOutboundAttempt();
// back off trying connecting to an address if we already tried recently // back off trying connecting to an address if we already tried recently
@ -3366,6 +3383,8 @@ size_t CConnman::GetNodeCount(NumConnections flags)
} }
if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT)) { if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT)) {
nNum++; nNum++;
} else if (flags == CONNECTIONS_VERIFIED) {
nNum++;
} }
} }

View File

@ -2716,7 +2716,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStrea
// Tell our peer that he should send us CoinJoin queue messages // Tell our peer that he should send us CoinJoin queue messages
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDDSQUEUE, true)); connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDDSQUEUE, true));
if (llmq::CLLMQUtils::IsWatchQuorumsEnabled() && !pfrom->m_masternode_connection) { if (llmq::CLLMQUtils::IsWatchQuorumsEnabled() && connman->IsMasternodeQuorumNode(pfrom)) {
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::QWATCH)); connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::QWATCH));
} }
@ -2748,7 +2748,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStrea
if (pfrom->nTimeFirstMessageReceived == 0) { if (pfrom->nTimeFirstMessageReceived == 0) {
// First message after VERSION/VERACK // First message after VERSION/VERACK
pfrom->nTimeFirstMessageReceived = GetTimeMicros(); pfrom->nTimeFirstMessageReceived = GetSystemTimeInSeconds();
pfrom->fFirstMessageIsMNAUTH = msg_type == NetMsgType::MNAUTH; pfrom->fFirstMessageIsMNAUTH = msg_type == NetMsgType::MNAUTH;
// Note: do not break the flow here // Note: do not break the flow here

View File

@ -13,6 +13,20 @@
template<typename T> struct SaltedHasherImpl; template<typename T> struct SaltedHasherImpl;
template<typename N, typename M, typename K, typename Q>
struct SaltedHasherImpl<std::tuple<N, M, K, Q>>
{
static std::size_t CalcHash(const std::tuple<N, M, K, Q>& v, uint64_t k0, uint64_t k1)
{
CSipHasher c(k0, k1);
c.Write((unsigned char*)&std::get<0>(v), sizeof(M));
c.Write((unsigned char*)&std::get<1>(v), sizeof(N));
c.Write((unsigned char*)&std::get<2>(v), sizeof(K));
c.Write((unsigned char*)&std::get<3>(v), sizeof(Q));
return c.Finalize();
}
};
template<typename N> template<typename N>
struct SaltedHasherImpl<std::pair<uint256, N>> struct SaltedHasherImpl<std::pair<uint256, N>>
{ {

View File

@ -7,7 +7,7 @@
Tests correspond to code in rpc/net.cpp. Tests correspond to code in rpc/net.cpp.
""" """
from test_framework.test_framework import BitcoinTestFramework from test_framework.test_framework import DashTestFramework
from test_framework.util import ( from test_framework.util import (
assert_equal, assert_equal,
assert_greater_than_or_equal, assert_greater_than_or_equal,
@ -47,15 +47,9 @@ def assert_net_servicesnames(servicesflag, servicenames):
assert "HEADERS_COMPRESSED" in servicenames assert "HEADERS_COMPRESSED" in servicenames
class NetTest(BitcoinTestFramework): class NetTest(DashTestFramework):
def set_test_params(self): def set_test_params(self):
self.setup_clean_chain = True self.set_dash_test_params(3, 1, fast_dip3_enforcement=True)
self.num_nodes = 2
def setup_network(self):
self.disable_mocktime()
self.setup_nodes()
connect_nodes(self.nodes[0], 1)
def run_test(self): def run_test(self):
# Wait for one ping/pong to finish so that we can be sure that there is no chatter between nodes for some time # Wait for one ping/pong to finish so that we can be sure that there is no chatter between nodes for some time
@ -76,7 +70,9 @@ class NetTest(BitcoinTestFramework):
def _test_connection_count(self): def _test_connection_count(self):
# connect_nodes connects each node to the other # connect_nodes connects each node to the other
assert_equal(self.nodes[0].getconnectioncount(), 2) # and node0 was also connected to node2 (a masternode)
# during network setup
assert_equal(self.nodes[0].getconnectioncount(), 3)
def _test_getnettotals(self): def _test_getnettotals(self):
# getnettotals totalbytesrecv and totalbytessent should be # getnettotals totalbytesrecv and totalbytessent should be
@ -87,7 +83,7 @@ class NetTest(BitcoinTestFramework):
net_totals_before = self.nodes[0].getnettotals() net_totals_before = self.nodes[0].getnettotals()
peer_info = self.nodes[0].getpeerinfo() peer_info = self.nodes[0].getpeerinfo()
net_totals_after = self.nodes[0].getnettotals() net_totals_after = self.nodes[0].getnettotals()
assert_equal(len(peer_info), 2) assert_equal(len(peer_info), 3)
peers_recv = sum([peer['bytesrecv'] for peer in peer_info]) peers_recv = sum([peer['bytesrecv'] for peer in peer_info])
peers_sent = sum([peer['bytessent'] for peer in peer_info]) peers_sent = sum([peer['bytessent'] for peer in peer_info])
@ -110,7 +106,7 @@ class NetTest(BitcoinTestFramework):
def _test_getnetworkinfo(self): def _test_getnetworkinfo(self):
assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True) assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True)
assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2) assert_equal(self.nodes[0].getnetworkinfo()['connections'], 3)
self.nodes[0].setnetworkactive(state=False) self.nodes[0].setnetworkactive(state=False)
assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], False) assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], False)
@ -131,6 +127,17 @@ class NetTest(BitcoinTestFramework):
for info in network_info: for info in network_info:
assert_net_servicesnames(int(info["localservices"], 16), info["localservicesnames"]) assert_net_servicesnames(int(info["localservices"], 16), info["localservicesnames"])
self.log.info('Test extended connections info')
connect_nodes(self.nodes[1], 2)
self.nodes[1].ping()
wait_until(lambda: all(['pingtime' in n for n in self.nodes[1].getpeerinfo()]))
assert_equal(self.nodes[1].getnetworkinfo()['connections'], 3)
assert_equal(self.nodes[1].getnetworkinfo()['inboundconnections'], 1)
assert_equal(self.nodes[1].getnetworkinfo()['outboundconnections'], 2)
assert_equal(self.nodes[1].getnetworkinfo()['mnconnections'], 1)
assert_equal(self.nodes[1].getnetworkinfo()['inboundmnconnections'], 0)
assert_equal(self.nodes[1].getnetworkinfo()['outboundmnconnections'], 1)
def _test_getaddednodeinfo(self): def _test_getaddednodeinfo(self):
assert_equal(self.nodes[0].getaddednodeinfo(), []) assert_equal(self.nodes[0].getaddednodeinfo(), [])
# add a node (node2) to node0 # add a node (node2) to node0
@ -180,7 +187,8 @@ class NetTest(BitcoinTestFramework):
node_addresses = self.nodes[0].getnodeaddresses(REQUEST_COUNT) node_addresses = self.nodes[0].getnodeaddresses(REQUEST_COUNT)
assert_equal(len(node_addresses), REQUEST_COUNT) assert_equal(len(node_addresses), REQUEST_COUNT)
for a in node_addresses: for a in node_addresses:
assert_greater_than(a["time"], 1527811200) # 1st June 2018 # see penalty calculations for ADDRs with nTime <= 100000000 in net_processing.cpp
assert_equal(a["time"], self.mocktime - 5 * 24 * 60 * 60 - 2 * 60 * 60)
assert_equal(a["services"], NODE_NETWORK) assert_equal(a["services"], NODE_NETWORK)
assert a["address"] in imported_addrs assert a["address"] in imported_addrs
assert_equal(a["port"], 8333) assert_equal(a["port"], 8333)