Move ChainLock signing into TrySignChainTip and call it periodically

Later commits will introduce checks for "safe TXs" which might abort the
signing on first try, but succeed a few seconds later, so we periodically
retry to sign the tip.
This commit is contained in:
Alexander Block 2019-02-28 15:02:20 +01:00
parent bd7edc8ae9
commit 0a5e8eb862
3 changed files with 45 additions and 17 deletions

View File

@ -35,12 +35,16 @@ CChainLocksHandler::~CChainLocksHandler()
{ {
} }
void CChainLocksHandler::RegisterAsRecoveredSigsListener() void CChainLocksHandler::Start()
{ {
quorumSigningManager->RegisterRecoveredSigsListener(this); quorumSigningManager->RegisterRecoveredSigsListener(this);
scheduler->scheduleEvery([&]() {
// regularely retry signing the current chaintip as it might have failed before due to missing ixlocks
TrySignChainTip();
}, 5000);
} }
void CChainLocksHandler::UnregisterAsRecoveredSigsListener() void CChainLocksHandler::Stop()
{ {
quorumSigningManager->UnregisterRecoveredSigsListener(this); quorumSigningManager->UnregisterRecoveredSigsListener(this);
} }
@ -184,30 +188,52 @@ void CChainLocksHandler::AcceptedBlockHeader(const CBlockIndex* pindexNew)
void CChainLocksHandler::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork) void CChainLocksHandler::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork)
{ {
// don't call TrySignChainTip directly but instead let the scheduler call it. This way we ensure that cs_main is
// never locked and TrySignChainTip is not called twice in parallel
LOCK(cs);
if (tryLockChainTipScheduled) {
return;
}
tryLockChainTipScheduled = true;
scheduler->scheduleFromNow([&]() {
TrySignChainTip();
LOCK(cs);
tryLockChainTipScheduled = false;
}, 0);
}
void CChainLocksHandler::TrySignChainTip()
{
Cleanup();
const CBlockIndex* pindex;
{
LOCK(cs_main);
pindex = chainActive.Tip();
}
if (!fMasternodeMode) { if (!fMasternodeMode) {
return; return;
} }
if (!pindexNew->pprev) { if (!pindex->pprev) {
return; return;
} }
if (!sporkManager.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED)) { if (!sporkManager.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED)) {
return; return;
} }
Cleanup();
// DIP8 defines a process called "Signing attempts" which should run before the CLSIG is finalized // DIP8 defines a process called "Signing attempts" which should run before the CLSIG is finalized
// To simplify the initial implementation, we skip this process and directly try to create a CLSIG // To simplify the initial implementation, we skip this process and directly try to create a CLSIG
// This will fail when multiple blocks compete, but we accept this for the initial implementation. // This will fail when multiple blocks compete, but we accept this for the initial implementation.
// Later, we'll add the multiple attempts process. // Later, we'll add the multiple attempts process.
uint256 requestId = ::SerializeHash(std::make_pair(CLSIG_REQUESTID_PREFIX, pindexNew->nHeight)); uint256 requestId = ::SerializeHash(std::make_pair(CLSIG_REQUESTID_PREFIX, pindex->nHeight));
uint256 msgHash = pindexNew->GetBlockHash(); uint256 msgHash = pindex->GetBlockHash();
{ {
LOCK(cs); LOCK(cs);
if (bestChainLockBlockIndex == pindexNew) { if (bestChainLockBlockIndex == pindex) {
// we first got the CLSIG, then the header, and then the block was connected. // we first got the CLSIG, then the header, and then the block was connected.
// In this case there is no need to continue here. // In this case there is no need to continue here.
// However, NotifyChainLock might not have been called yet, so call it now if needed // However, NotifyChainLock might not have been called yet, so call it now if needed
@ -218,26 +244,26 @@ void CChainLocksHandler::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBl
return; return;
} }
if (InternalHasConflictingChainLock(pindexNew->nHeight, pindexNew->GetBlockHash())) { if (InternalHasConflictingChainLock(pindex->nHeight, pindex->GetBlockHash())) {
if (!inEnforceBestChainLock) { if (!inEnforceBestChainLock) {
// we accepted this block when there was no lock yet, but now a conflicting lock appeared. Invalidate it. // we accepted this block when there was no lock yet, but now a conflicting lock appeared. Invalidate it.
LogPrintf("CChainLocksHandler::%s -- conflicting lock after block was accepted, invalidating now\n", LogPrintf("CChainLocksHandler::%s -- conflicting lock after block was accepted, invalidating now\n",
__func__); __func__);
ScheduleInvalidateBlock(pindexNew); ScheduleInvalidateBlock(pindex);
} }
return; return;
} }
if (bestChainLock.nHeight >= pindexNew->nHeight) { if (bestChainLock.nHeight >= pindex->nHeight) {
// already got the same CLSIG or a better one // already got the same CLSIG or a better one
return; return;
} }
if (pindexNew->nHeight == lastSignedHeight) { if (pindex->nHeight == lastSignedHeight) {
// already signed this one // already signed this one
return; return;
} }
lastSignedHeight = pindexNew->nHeight; lastSignedHeight = pindex->nHeight;
lastSignedRequestId = requestId; lastSignedRequestId = requestId;
lastSignedMsgHash = msgHash; lastSignedMsgHash = msgHash;
} }

View File

@ -49,6 +49,7 @@ class CChainLocksHandler : public CRecoveredSigsListener
private: private:
CScheduler* scheduler; CScheduler* scheduler;
CCriticalSection cs; CCriticalSection cs;
bool tryLockChainTipScheduled{false};
std::atomic<bool> inEnforceBestChainLock{false}; std::atomic<bool> inEnforceBestChainLock{false};
uint256 bestChainLockHash; uint256 bestChainLockHash;
@ -74,8 +75,8 @@ public:
CChainLocksHandler(CScheduler* _scheduler); CChainLocksHandler(CScheduler* _scheduler);
~CChainLocksHandler(); ~CChainLocksHandler();
void RegisterAsRecoveredSigsListener(); void Start();
void UnregisterAsRecoveredSigsListener(); void Stop();
bool AlreadyHave(const CInv& inv); bool AlreadyHave(const CInv& inv);
bool GetChainLockByHash(const uint256& hash, CChainLockSig& ret); bool GetChainLockByHash(const uint256& hash, CChainLockSig& ret);
@ -86,6 +87,7 @@ public:
void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork); void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork);
void NewPoWValidBlock(const CBlockIndex* pindex, const std::shared_ptr<const CBlock>& block); void NewPoWValidBlock(const CBlockIndex* pindex, const std::shared_ptr<const CBlock>& block);
void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock); void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock);
void TrySignChainTip();
void EnforceBestChainLock(); void EnforceBestChainLock();
virtual void HandleNewRecoveredSig(const CRecoveredSig& recoveredSig); virtual void HandleNewRecoveredSig(const CRecoveredSig& recoveredSig);

View File

@ -66,7 +66,7 @@ void StartLLMQSystem()
quorumSigSharesManager->StartWorkerThread(); quorumSigSharesManager->StartWorkerThread();
} }
if (chainLocksHandler) { if (chainLocksHandler) {
chainLocksHandler->RegisterAsRecoveredSigsListener(); chainLocksHandler->Start();
} }
if (quorumInstantSendManager) { if (quorumInstantSendManager) {
quorumInstantSendManager->RegisterAsRecoveredSigsListener(); quorumInstantSendManager->RegisterAsRecoveredSigsListener();
@ -79,7 +79,7 @@ void StopLLMQSystem()
quorumInstantSendManager->UnregisterAsRecoveredSigsListener(); quorumInstantSendManager->UnregisterAsRecoveredSigsListener();
} }
if (chainLocksHandler) { if (chainLocksHandler) {
chainLocksHandler->UnregisterAsRecoveredSigsListener(); chainLocksHandler->Stop();
} }
if (quorumSigSharesManager) { if (quorumSigSharesManager) {
quorumSigSharesManager->StopWorkerThread(); quorumSigSharesManager->StopWorkerThread();