fix(net): Do not punish nodes when Quorum data are missing. (#5272)

## Issue being fixed or feature implemented
Currently, we store internally the nodes that already requested
`QGETDATA` for the same Quorum.
If data for the same Quorum is requested twice from the same `proRegTx`,
then the requester is P2P misbehaved.

## What was done?
Some data like `VerificationVector` and `EncryptedContributions` are not
instantly available.
This PR does not misbehave nodes for requesting data that weren't
available when asked.

## How Has This Been Tested?


## Breaking Changes


## Checklist:
- [x] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have added or updated relevant unit/integration/functional/e2e
tests
- [ ] I have made corresponding changes to the documentation

**For repository code-owners and collaborators only**
- [x] I have assigned this pull request to a milestone
This commit is contained in:
Odysseas Gabrielides 2023-03-30 18:05:15 +03:00 committed by GitHub
parent 08aa10c8cb
commit f4b91c08a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -631,13 +631,29 @@ void CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, C
CQuorumDataRequest request; CQuorumDataRequest request;
vRecv >> request; vRecv >> request;
auto sendQDATA = [&](CQuorumDataRequest::Errors nError = CQuorumDataRequest::Errors::UNDEFINED, auto sendQDATA = [&](CQuorumDataRequest::Errors nError,
bool request_limit_exceeded,
const CDataStream& body = CDataStream(SER_NETWORK, PROTOCOL_VERSION)) { const CDataStream& body = CDataStream(SER_NETWORK, PROTOCOL_VERSION)) {
switch (nError) {
case (CQuorumDataRequest::Errors::NONE):
case (CQuorumDataRequest::Errors::QUORUM_TYPE_INVALID):
case (CQuorumDataRequest::Errors::QUORUM_BLOCK_NOT_FOUND):
case (CQuorumDataRequest::Errors::QUORUM_NOT_FOUND):
case (CQuorumDataRequest::Errors::MASTERNODE_IS_NO_MEMBER):
case (CQuorumDataRequest::Errors::UNDEFINED):
if (request_limit_exceeded) errorHandler("Request limit exceeded", 25);
break;
case (CQuorumDataRequest::Errors::QUORUM_VERIFICATION_VECTOR_MISSING):
case (CQuorumDataRequest::Errors::ENCRYPTED_CONTRIBUTIONS_MISSING):
// Do not punish limit exceed if we don't have the requested data
break;
}
request.SetError(nError); request.SetError(nError);
CDataStream ssResponse(SER_NETWORK, pfrom.GetSendVersion(), request, body); CDataStream ssResponse(SER_NETWORK, pfrom.GetSendVersion(), request, body);
connman.PushMessage(&pfrom, CNetMsgMaker(pfrom.GetSendVersion()).Make(NetMsgType::QDATA, ssResponse)); connman.PushMessage(&pfrom, CNetMsgMaker(pfrom.GetSendVersion()).Make(NetMsgType::QDATA, ssResponse));
}; };
bool request_limit_exceeded(false);
{ {
LOCK2(cs_main, cs_data_requests); LOCK2(cs_main, cs_data_requests);
CQuorumDataRequestKey key; CQuorumDataRequestKey key;
@ -651,24 +667,24 @@ void CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, C
} else if (it->second.IsExpired()) { } else if (it->second.IsExpired()) {
it->second = request; it->second = request;
} else { } else {
errorHandler("Request limit exceeded", 25); request_limit_exceeded = true;
} }
} }
if (!GetLLMQParams(request.GetLLMQType()).has_value()) { if (!GetLLMQParams(request.GetLLMQType()).has_value()) {
sendQDATA(CQuorumDataRequest::Errors::QUORUM_TYPE_INVALID); sendQDATA(CQuorumDataRequest::Errors::QUORUM_TYPE_INVALID, request_limit_exceeded);
return; return;
} }
const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return LookupBlockIndex(request.GetQuorumHash())); const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return LookupBlockIndex(request.GetQuorumHash()));
if (pQuorumBaseBlockIndex == nullptr) { if (pQuorumBaseBlockIndex == nullptr) {
sendQDATA(CQuorumDataRequest::Errors::QUORUM_BLOCK_NOT_FOUND); sendQDATA(CQuorumDataRequest::Errors::QUORUM_BLOCK_NOT_FOUND, request_limit_exceeded);
return; return;
} }
const CQuorumCPtr pQuorum = GetQuorum(request.GetLLMQType(), pQuorumBaseBlockIndex); const CQuorumCPtr pQuorum = GetQuorum(request.GetLLMQType(), pQuorumBaseBlockIndex);
if (pQuorum == nullptr) { if (pQuorum == nullptr) {
sendQDATA(CQuorumDataRequest::Errors::QUORUM_NOT_FOUND); sendQDATA(CQuorumDataRequest::Errors::QUORUM_NOT_FOUND, request_limit_exceeded);
return; return;
} }
@ -677,7 +693,7 @@ void CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, C
// Check if request wants QUORUM_VERIFICATION_VECTOR data // Check if request wants QUORUM_VERIFICATION_VECTOR data
if (request.GetDataMask() & CQuorumDataRequest::QUORUM_VERIFICATION_VECTOR) { if (request.GetDataMask() & CQuorumDataRequest::QUORUM_VERIFICATION_VECTOR) {
if (!pQuorum->HasVerificationVector()) { if (!pQuorum->HasVerificationVector()) {
sendQDATA(CQuorumDataRequest::Errors::QUORUM_VERIFICATION_VECTOR_MISSING); sendQDATA(CQuorumDataRequest::Errors::QUORUM_VERIFICATION_VECTOR_MISSING, request_limit_exceeded);
return; return;
} }
@ -689,20 +705,20 @@ void CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, C
int memberIdx = pQuorum->GetMemberIndex(request.GetProTxHash()); int memberIdx = pQuorum->GetMemberIndex(request.GetProTxHash());
if (memberIdx == -1) { if (memberIdx == -1) {
sendQDATA(CQuorumDataRequest::Errors::MASTERNODE_IS_NO_MEMBER); sendQDATA(CQuorumDataRequest::Errors::MASTERNODE_IS_NO_MEMBER, request_limit_exceeded);
return; return;
} }
std::vector<CBLSIESEncryptedObject<CBLSSecretKey>> vecEncrypted; std::vector<CBLSIESEncryptedObject<CBLSSecretKey>> vecEncrypted;
if (!dkgManager.GetEncryptedContributions(request.GetLLMQType(), pQuorumBaseBlockIndex, pQuorum->qc->validMembers, request.GetProTxHash(), vecEncrypted)) { if (!dkgManager.GetEncryptedContributions(request.GetLLMQType(), pQuorumBaseBlockIndex, pQuorum->qc->validMembers, request.GetProTxHash(), vecEncrypted)) {
sendQDATA(CQuorumDataRequest::Errors::ENCRYPTED_CONTRIBUTIONS_MISSING); sendQDATA(CQuorumDataRequest::Errors::ENCRYPTED_CONTRIBUTIONS_MISSING, request_limit_exceeded);
return; return;
} }
ssResponseData << vecEncrypted; ssResponseData << vecEncrypted;
} }
sendQDATA(CQuorumDataRequest::Errors::NONE, ssResponseData); sendQDATA(CQuorumDataRequest::Errors::NONE, request_limit_exceeded, ssResponseData);
return; return;
} }