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 pasta
parent 38c1ee7509
commit bcb65a217d
No known key found for this signature in database
GPG Key ID: 52527BEDABE87984

View File

@ -630,13 +630,29 @@ void CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, C
CQuorumDataRequest 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)) {
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);
CDataStream ssResponse(SER_NETWORK, pfrom.GetSendVersion(), request, body);
connman.PushMessage(&pfrom, CNetMsgMaker(pfrom.GetSendVersion()).Make(NetMsgType::QDATA, ssResponse));
};
bool request_limit_exceeded(false);
{
LOCK2(cs_main, cs_data_requests);
CQuorumDataRequestKey key;
@ -650,24 +666,24 @@ void CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, C
} else if (it->second.IsExpired()) {
it->second = request;
} else {
errorHandler("Request limit exceeded", 25);
request_limit_exceeded = true;
}
}
if (!GetLLMQParams(request.GetLLMQType()).has_value()) {
sendQDATA(CQuorumDataRequest::Errors::QUORUM_TYPE_INVALID);
sendQDATA(CQuorumDataRequest::Errors::QUORUM_TYPE_INVALID, request_limit_exceeded);
return;
}
const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return LookupBlockIndex(request.GetQuorumHash()));
if (pQuorumBaseBlockIndex == nullptr) {
sendQDATA(CQuorumDataRequest::Errors::QUORUM_BLOCK_NOT_FOUND);
sendQDATA(CQuorumDataRequest::Errors::QUORUM_BLOCK_NOT_FOUND, request_limit_exceeded);
return;
}
const CQuorumCPtr pQuorum = GetQuorum(request.GetLLMQType(), pQuorumBaseBlockIndex);
if (pQuorum == nullptr) {
sendQDATA(CQuorumDataRequest::Errors::QUORUM_NOT_FOUND);
sendQDATA(CQuorumDataRequest::Errors::QUORUM_NOT_FOUND, request_limit_exceeded);
return;
}
@ -676,7 +692,7 @@ void CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, C
// Check if request wants QUORUM_VERIFICATION_VECTOR data
if (request.GetDataMask() & CQuorumDataRequest::QUORUM_VERIFICATION_VECTOR) {
if (!pQuorum->HasVerificationVector()) {
sendQDATA(CQuorumDataRequest::Errors::QUORUM_VERIFICATION_VECTOR_MISSING);
sendQDATA(CQuorumDataRequest::Errors::QUORUM_VERIFICATION_VECTOR_MISSING, request_limit_exceeded);
return;
}
@ -688,20 +704,20 @@ void CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, C
int memberIdx = pQuorum->GetMemberIndex(request.GetProTxHash());
if (memberIdx == -1) {
sendQDATA(CQuorumDataRequest::Errors::MASTERNODE_IS_NO_MEMBER);
sendQDATA(CQuorumDataRequest::Errors::MASTERNODE_IS_NO_MEMBER, request_limit_exceeded);
return;
}
std::vector<CBLSIESEncryptedObject<CBLSSecretKey>> 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;
}
ssResponseData << vecEncrypted;
}
sendQDATA(CQuorumDataRequest::Errors::NONE, ssResponseData);
sendQDATA(CQuorumDataRequest::Errors::NONE, request_limit_exceeded, ssResponseData);
return;
}