|
16 | 16 | #include <validation.h> |
17 | 17 | #include <validationinterface.h> |
18 | 18 |
|
| 19 | +#include <vector> |
| 20 | + |
19 | 21 | #include <instantsend/instantsend.h> |
20 | 22 | #include <llmq/quorums.h> |
21 | 23 | #include <masternode/sync.h> |
@@ -71,6 +73,7 @@ void CChainLocksHandler::Start(const llmq::CInstantSendManager& isman) |
71 | 73 | [&]() { |
72 | 74 | auto signer = m_signer.load(std::memory_order_acquire); |
73 | 75 | CheckActiveState(); |
| 76 | + ProcessPendingCoinbaseChainLocks(); |
74 | 77 | EnforceBestChainLock(); |
75 | 78 | Cleanup(); |
76 | 79 | // regularly retry signing the current chaintip as it might have failed before due to missing islocks |
@@ -490,4 +493,72 @@ void CChainLocksHandler::Cleanup() |
490 | 493 | } |
491 | 494 | } |
492 | 495 | } |
| 496 | + |
| 497 | +void CChainLocksHandler::QueueCoinbaseChainLock(const chainlock::ChainLockSig& clsig) |
| 498 | +{ |
| 499 | + AssertLockNotHeld(cs); |
| 500 | + LOCK(cs); |
| 501 | + |
| 502 | + if (!IsEnabled()) { |
| 503 | + return; |
| 504 | + } |
| 505 | + |
| 506 | + // Only queue if it's potentially newer than what we have |
| 507 | + if (!bestChainLock.IsNull() && clsig.getHeight() <= bestChainLock.getHeight()) { |
| 508 | + return; |
| 509 | + } |
| 510 | + |
| 511 | + // Check if we've already seen this chainlock |
| 512 | + const uint256 hash = ::SerializeHash(clsig); |
| 513 | + if (seenChainLocks.count(hash) != 0) { |
| 514 | + return; |
| 515 | + } |
| 516 | + |
| 517 | + pendingCoinbaseChainLocks.push_back(clsig); |
| 518 | +} |
| 519 | + |
| 520 | +void CChainLocksHandler::ProcessPendingCoinbaseChainLocks() |
| 521 | +{ |
| 522 | + AssertLockNotHeld(cs); |
| 523 | + AssertLockNotHeld(cs_main); |
| 524 | + |
| 525 | + if (!IsEnabled()) { |
| 526 | + return; |
| 527 | + } |
| 528 | + |
| 529 | + std::vector<chainlock::ChainLockSig> toProcess; |
| 530 | + { |
| 531 | + LOCK(cs); |
| 532 | + if (pendingCoinbaseChainLocks.empty()) { |
| 533 | + return; |
| 534 | + } |
| 535 | + |
| 536 | + // Move all pending chainlocks to a local vector for processing |
| 537 | + toProcess.reserve(pendingCoinbaseChainLocks.size()); |
| 538 | + while (!pendingCoinbaseChainLocks.empty()) { |
| 539 | + toProcess.push_back(pendingCoinbaseChainLocks.front()); |
| 540 | + pendingCoinbaseChainLocks.pop_front(); |
| 541 | + } |
| 542 | + } |
| 543 | + |
| 544 | + // Process each chainlock outside the lock |
| 545 | + for (const auto& clsig : toProcess) { |
| 546 | + const uint256 hash = ::SerializeHash(clsig); |
| 547 | + |
| 548 | + // Check again if we still want to process this (might have been processed via network) |
| 549 | + { |
| 550 | + LOCK(cs); |
| 551 | + if (seenChainLocks.count(hash) != 0) { |
| 552 | + continue; |
| 553 | + } |
| 554 | + if (!bestChainLock.IsNull() && clsig.getHeight() <= bestChainLock.getHeight()) { |
| 555 | + continue; |
| 556 | + } |
| 557 | + } |
| 558 | + |
| 559 | + // Process as if it came from a coinbase (from = -1 means internal) |
| 560 | + // Ignore return value as we're processing internally from coinbase |
| 561 | + (void)ProcessNewChainLock(-1, clsig, hash); |
| 562 | + } |
| 563 | +} |
493 | 564 | } // namespace llmq |
0 commit comments