diff --git a/src/avalanche/peermanager.cpp b/src/avalanche/peermanager.cpp --- a/src/avalanche/peermanager.cpp +++ b/src/avalanche/peermanager.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -980,22 +981,34 @@ // previous block or lacking node connected. // The previous block time is capped to now for the unlikely event the // previous block time is in the future. + std::chrono::seconds registrationDelay = + std::chrono::duration_cast( + IsLeeKuanYewEnabled(chainman.GetConsensus(), pprev) + ? 4 * Peer::DANGLING_TIMEOUT + : 2 * Peer::DANGLING_TIMEOUT); + std::chrono::seconds maxRegistrationDelay = + std::chrono::duration_cast( + IsLeeKuanYewEnabled(chainman.GetConsensus(), pprev) + ? 6 * Peer::DANGLING_TIMEOUT + : 4 * Peer::DANGLING_TIMEOUT); + std::chrono::seconds minRegistrationDelay = + std::chrono::duration_cast( + 2 * Peer::DANGLING_TIMEOUT); + + const int64_t targetRegistrationTime = + std::min(pprev->GetBlockTime(), GetTime()) - registrationDelay.count(); const int64_t maxRegistrationTime = std::min(pprev->GetBlockTime(), GetTime()) - - std::chrono::duration_cast(2 * - Peer::DANGLING_TIMEOUT) - .count(); - - const int64_t recentRegistrationTime = + minRegistrationDelay.count(); + const int64_t minRegistrationTime = std::min(pprev->GetBlockTime(), GetTime()) - - std::chrono::duration_cast(4 * - Peer::DANGLING_TIMEOUT) - .count(); + maxRegistrationDelay.count(); const BlockHash prevblockhash = pprev->GetBlockHash(); - winners.clear(); - while (winners.size() < peers.size()) { + std::vector selectedProofs; + ProofRef firstCompliantProof = ProofRef(); + while (selectedProofs.size() < peers.size()) { double bestRewardRank = std::numeric_limits::max(); ProofRef selectedProof = ProofRef(); int64_t selectedProofRegistrationTime{0}; @@ -1012,8 +1025,10 @@ continue; } - if (std::find(winners.begin(), winners.end(), - peer.proof->getPayoutScript()) != winners.end()) { + if (std::find_if(selectedProofs.begin(), selectedProofs.end(), + [&peer](const ProofRef &proof) { + return peer.getProofId() == proof->getId(); + }) != selectedProofs.end()) { continue; } @@ -1070,15 +1085,41 @@ break; } - winners.push_back(selectedProof->getPayoutScript()); + if (!firstCompliantProof && + selectedProofRegistrationTime < targetRegistrationTime) { + firstCompliantProof = selectedProof; + } + + selectedProofs.push_back(selectedProof); - if (selectedProofRegistrationTime < recentRegistrationTime && + if (selectedProofRegistrationTime < minRegistrationTime && !isFlaky(selectedProof->getId())) { break; } } - return winners.size() > 0; + winners.clear(); + + if (!firstCompliantProof) { + return false; + } + + winners.reserve(selectedProofs.size()); + + // Find the winner + for (const ProofRef &proof : selectedProofs) { + if (proof->getId() == firstCompliantProof->getId()) { + winners.push_back(proof->getPayoutScript()); + } + } + // Add the others (if any) after the winner + for (const ProofRef &proof : selectedProofs) { + if (proof->getId() != firstCompliantProof->getId()) { + winners.push_back(proof->getPayoutScript()); + } + } + + return true; } bool PeerManager::isFlaky(const ProofId &proofid) const { diff --git a/src/avalanche/test/peermanager_tests.cpp b/src/avalanche/test/peermanager_tests.cpp --- a/src/avalanche/test/peermanager_tests.cpp +++ b/src/avalanche/test/peermanager_tests.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include