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);
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);
}
@ -184,30 +188,52 @@ void CChainLocksHandler::AcceptedBlockHeader(const CBlockIndex* pindexNew)
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) {
return;
}
if (!pindexNew->pprev) {
if (!pindex->pprev) {
return;
}
if (!sporkManager.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED)) {
return;
}
Cleanup();
// 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
// This will fail when multiple blocks compete, but we accept this for the initial implementation.
// Later, we'll add the multiple attempts process.
uint256 requestId = ::SerializeHash(std::make_pair(CLSIG_REQUESTID_PREFIX, pindexNew->nHeight));
uint256 msgHash = pindexNew->GetBlockHash();
uint256 requestId = ::SerializeHash(std::make_pair(CLSIG_REQUESTID_PREFIX, pindex->nHeight));
uint256 msgHash = pindex->GetBlockHash();
{
LOCK(cs);
if (bestChainLockBlockIndex == pindexNew) {
if (bestChainLockBlockIndex == pindex) {
// we first got the CLSIG, then the header, and then the block was connected.
// In this case there is no need to continue here.
// 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;
}
if (InternalHasConflictingChainLock(pindexNew->nHeight, pindexNew->GetBlockHash())) {
if (InternalHasConflictingChainLock(pindex->nHeight, pindex->GetBlockHash())) {
if (!inEnforceBestChainLock) {
// 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",
__func__);
ScheduleInvalidateBlock(pindexNew);
ScheduleInvalidateBlock(pindex);
}
return;
}
if (bestChainLock.nHeight >= pindexNew->nHeight) {
if (bestChainLock.nHeight >= pindex->nHeight) {
// already got the same CLSIG or a better one
return;
}
if (pindexNew->nHeight == lastSignedHeight) {
if (pindex->nHeight == lastSignedHeight) {
// already signed this one
return;
}
lastSignedHeight = pindexNew->nHeight;
lastSignedHeight = pindex->nHeight;
lastSignedRequestId = requestId;
lastSignedMsgHash = msgHash;
}

View File

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

View File

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