Try to avoid being marked as a bad quorum member when we sleep for too long in SleepBeforePhase (#3245)

* Do not sleep at the last block of the phase, it's not safe

* Refactor it a bit to make it clearer what's going on here

* Stop sleeping if blocks came faster than we expected
This commit is contained in:
UdjinM6 2019-12-31 13:01:01 +03:00
parent db6ea1de8e
commit c42b200973
2 changed files with 32 additions and 9 deletions

View File

@ -115,6 +115,7 @@ void CDKGSessionHandler::UpdatedBlockTip(const CBlockIndex* pindexNew)
int quorumStageInt = pindexNew->nHeight % params.dkgInterval;
const CBlockIndex* pindexQuorum = pindexNew->GetAncestor(pindexNew->nHeight - quorumStageInt);
currentHeight = pindexNew->nHeight;
quorumHeight = pindexQuorum->nHeight;
quorumHash = pindexQuorum->GetBlockHash();
@ -236,22 +237,43 @@ void CDKGSessionHandler::SleepBeforePhase(QuorumPhase curPhase,
return;
}
// expected time for a full phase
double phaseTime = params.dkgPhaseBlocks * Params().GetConsensus().nPowTargetSpacing * 1000;
// expected time per member
phaseTime = phaseTime / params.size;
// Two blocks can come very close to each other, this happens pretty regularly. We don't want to be
// left behind and marked as a bad member. This means that we should not count the last block of the
// phase as a safe one to keep sleeping, that's why we calculate the phase sleep time as a time of
// the full phase minus one block here.
double phaseSleepTime = (params.dkgPhaseBlocks - 1) * Params().GetConsensus().nPowTargetSpacing * 1000;
// Expected phase sleep time per member
double phaseSleepTimePerMember = phaseSleepTime / params.size;
// Don't expect perfect block times and thus reduce the phase time to be on the secure side (caller chooses factor)
phaseTime *= randomSleepFactor;
double adjustedPhaseSleepTimePerMember = phaseSleepTimePerMember * randomSleepFactor;
int64_t sleepTime = (int64_t)(phaseTime * curSession->GetMyMemberIndex());
int64_t sleepTime = (int64_t)(adjustedPhaseSleepTimePerMember * curSession->GetMyMemberIndex());
int64_t endTime = GetTimeMillis() + sleepTime;
int heightTmp{-1};
int heightStart{-1};
{
LOCK(cs);
heightTmp = heightStart = currentHeight;
}
while (GetTimeMillis() < endTime) {
if (stopRequested || ShutdownRequested()) {
throw AbortPhaseException();
}
auto p = GetPhaseAndQuorumHash();
if (p.first != curPhase || p.second != expectedQuorumHash) {
throw AbortPhaseException();
{
LOCK(cs);
if (currentHeight > heightTmp) {
// New block(s) just came in
int64_t expectedBlockTime = (currentHeight - heightStart) * Params().GetConsensus().nPowTargetSpacing * 1000;
if (expectedBlockTime > sleepTime) {
// Blocks came faster than we expected, jump into the phase func asap
break;
}
heightTmp = currentHeight;
}
if (phase != curPhase || quorumHash != expectedQuorumHash) {
// Smth went wrong and/or we missed quite a few blocks and it's just too late now
throw AbortPhaseException();
}
}
if (!runWhileWaiting()) {
MilliSleep(100);

View File

@ -107,6 +107,7 @@ private:
CDKGSessionManager& dkgManager;
QuorumPhase phase{QuorumPhase_Idle};
int currentHeight{-1};
int quorumHeight{-1};
uint256 quorumHash;
std::shared_ptr<CDKGSession> curSession;