@@ -39,6 +39,11 @@ CChainLocksHandler::~CChainLocksHandler()
3939void CChainLocksHandler::Start ()
4040{
4141 quorumSigningManager->RegisterRecoveredSigsListener (this );
42+ scheduler->scheduleEvery ([&]() {
43+ // regularely retry signing the current chaintip
44+ TrySignChainTip ();
45+ },
46+ 5000 );
4247}
4348
4449void CChainLocksHandler::Stop ()
@@ -180,55 +185,86 @@ void CChainLocksHandler::AcceptedBlockHeader(const CBlockIndex* pindexNew)
180185
181186void CChainLocksHandler::UpdatedBlockTip (const CBlockIndex* pindexNew, const CBlockIndex* pindexFork)
182187{
188+ // don't call TrySignChainTip directly but instead let the scheduler call it. This way we ensure that cs_main is
189+ // never locked and TrySignChainTip is not called twice in parallel
190+ LOCK (cs);
191+ if (tryLockChainTipScheduled) {
192+ return ;
193+ }
194+ tryLockChainTipScheduled = true ;
195+ scheduler->scheduleFromNow ([&]() {
196+ TrySignChainTip ();
197+ LOCK (cs);
198+ tryLockChainTipScheduled = false ;
199+ },
200+ 0 );
201+ }
202+
203+ void CChainLocksHandler::TrySignChainTip ()
204+ {
205+ Cleanup ();
206+
207+ const CBlockIndex* pindex;
208+ {
209+ LOCK (cs_main);
210+ pindex = chainActive.Tip ();
211+ }
212+
183213 if (!fMasterNode ) {
184214 return ;
185215 }
186- if (!pindexNew ->pprev ) {
216+ if (!pindex ->pprev ) {
187217 return ;
188218 }
189219 if (!sporkManager.IsSporkActive (SPORK_23_CHAINLOCKS_ENFORCEMENT)) {
190220 return ;
191221 }
192222
193- Cleanup ();
194-
195223 // DIP8 defines a process called "Signing attempts" which should run before the CLSIG is finalized
196224 // To simplify the initial implementation, we skip this process and directly try to create a CLSIG
197225 // This will fail when multiple blocks compete, but we accept this for the initial implementation.
198226 // Later, we'll add the multiple attempts process.
199227
200- uint256 requestId = ::SerializeHash (std::make_pair (CLSIG_REQUESTID_PREFIX, pindexNew->nHeight ));
201- uint256 msgHash = pindexNew->GetBlockHash ();
202-
203228 {
204229 LOCK (cs);
205230
206- if (bestChainLockBlockIndex == pindexNew ) {
231+ if (bestChainLockBlockIndex == pindex ) {
207232 // we first got the CLSIG, then the header, and then the block was connected.
208233 // In this case there is no need to continue here.
209234 return ;
210235 }
211236
212- if (InternalHasConflictingChainLock (pindexNew->nHeight , pindexNew->GetBlockHash ())) {
237+ if (pindex->nHeight == lastSignedHeight) {
238+ // already signed this one
239+ return ;
240+ }
241+
242+ if (bestChainLock.nHeight >= pindex->nHeight ) {
243+ // already got the same CLSIG or a better one
244+ return ;
245+ }
246+
247+ if (InternalHasConflictingChainLock (pindex->nHeight , pindex->GetBlockHash ())) {
213248 if (!inEnforceBestChainLock) {
214249 // we accepted this block when there was no lock yet, but now a conflicting lock appeared. Invalidate it.
215250 LogPrintf (" CChainLocksHandler::%s -- conflicting lock after block was accepted, invalidating now\n " ,
216251 __func__);
217- ScheduleInvalidateBlock (pindexNew );
252+ ScheduleInvalidateBlock (pindex );
218253 }
219254 return ;
220255 }
256+ }
221257
222- if (bestChainLock.nHeight >= pindexNew->nHeight ) {
223- // already got the same CLSIG or a better one
224- return ;
225- }
258+ uint256 requestId = ::SerializeHash (std::make_pair (CLSIG_REQUESTID_PREFIX, pindex->nHeight ));
259+ uint256 msgHash = pindex->GetBlockHash ();
226260
227- if (pindexNew->nHeight == lastSignedHeight) {
228- // already signed this one
261+ {
262+ LOCK (cs);
263+ if (bestChainLock.nHeight >= pindex->nHeight ) {
264+ // might have happened while we didn't hold cs
229265 return ;
230266 }
231- lastSignedHeight = pindexNew ->nHeight ;
267+ lastSignedHeight = pindex ->nHeight ;
232268 lastSignedRequestId = requestId;
233269 lastSignedMsgHash = msgHash;
234270 }
0 commit comments