Skip to content

Commit

Permalink
Move ChainLock signing into TrySignChainTip and call it periodically
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
codablock committed Mar 7, 2019
1 parent bd7edc8 commit 0a5e8eb
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 17 deletions.
52 changes: 39 additions & 13 deletions src/llmq/quorums_chainlocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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
Expand All @@ -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;
}
Expand Down
6 changes: 4 additions & 2 deletions src/llmq/quorums_chainlocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class CChainLocksHandler : public CRecoveredSigsListener
private:
CScheduler* scheduler;
CCriticalSection cs;
bool tryLockChainTipScheduled{false};
std::atomic<bool> inEnforceBestChainLock{false};

uint256 bestChainLockHash;
Expand All @@ -74,8 +75,8 @@ class CChainLocksHandler : public CRecoveredSigsListener
CChainLocksHandler(CScheduler* _scheduler);
~CChainLocksHandler();

void RegisterAsRecoveredSigsListener();
void UnregisterAsRecoveredSigsListener();
void Start();
void Stop();

bool AlreadyHave(const CInv& inv);
bool GetChainLockByHash(const uint256& hash, CChainLockSig& ret);
Expand All @@ -86,6 +87,7 @@ class CChainLocksHandler : public CRecoveredSigsListener
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);

Expand Down
4 changes: 2 additions & 2 deletions src/llmq/quorums_init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ void StartLLMQSystem()
quorumSigSharesManager->StartWorkerThread();
}
if (chainLocksHandler) {
chainLocksHandler->RegisterAsRecoveredSigsListener();
chainLocksHandler->Start();
}
if (quorumInstantSendManager) {
quorumInstantSendManager->RegisterAsRecoveredSigsListener();
Expand All @@ -79,7 +79,7 @@ void StopLLMQSystem()
quorumInstantSendManager->UnregisterAsRecoveredSigsListener();
}
if (chainLocksHandler) {
chainLocksHandler->UnregisterAsRecoveredSigsListener();
chainLocksHandler->Stop();
}
if (quorumSigSharesManager) {
quorumSigSharesManager->StopWorkerThread();
Expand Down

0 comments on commit 0a5e8eb

Please sign in to comment.