diff --git a/src/llmq/quorums_instantsend.cpp b/src/llmq/quorums_instantsend.cpp index 09f34eefd0d921..6c4f480df6d16b 100644 --- a/src/llmq/quorums_instantsend.cpp +++ b/src/llmq/quorums_instantsend.cpp @@ -733,6 +733,8 @@ void CInstantSendManager::ProcessInstantSendLock(NodeId from, const uint256& has } db.WriteNewInstantSendLock(hash, islock); + + pendingRetryTxs.emplace(islock.txid); } CInv inv(MSG_ISLOCK, hash); @@ -745,8 +747,6 @@ void CInstantSendManager::ProcessInstantSendLock(NodeId from, const uint256& has } RemoveMempoolConflictsForLock(hash, islock); - RetryLockTxs(islock.txid); - UpdateWalletTransaction(islock.txid, tx); } @@ -802,7 +802,8 @@ void CInstantSendManager::SyncTransaction(const CTransaction& tx, const CBlockIn bool chainlocked = pindex && chainLocksHandler->HasChainLock(pindex->nHeight, pindex->GetBlockHash()); if (!islockHash.IsNull() || chainlocked) { - RetryLockTxs(tx.GetHash()); + LOCK(cs); + pendingRetryTxs.emplace(tx.GetHash()); } else { ProcessTx(tx, Params().GetConsensus()); } @@ -849,14 +850,14 @@ void CInstantSendManager::HandleFullyConfirmedBlock(const CBlockIndex* pindex) inputRequestIds.erase(inputRequestId); } } + + // Retry all not yet locked mempool TXs and TX which where mined after the fully confirmed block + pendingRetryAllTxs = true; } for (auto& p : removeISLocks) { UpdateWalletTransaction(p.second->txid, nullptr); } - - // Retry all not yet locked mempool TXs and TX which where mined after the fully confirmed block - RetryLockTxs(uint256()); } void CInstantSendManager::RemoveMempoolConflictsForLock(const uint256& hash, const CInstantSendLock& islock) @@ -883,10 +884,23 @@ void CInstantSendManager::RemoveMempoolConflictsForLock(const uint256& hash, con } } -void CInstantSendManager::RetryLockTxs(const uint256& lockedParentTx) +bool CInstantSendManager::ProcessPendingRetryLockTxs() { + bool retryAllTxs; + decltype(pendingRetryTxs) parentTxs; + { + LOCK(cs); + retryAllTxs = pendingRetryAllTxs; + parentTxs = std::move(pendingRetryTxs); + pendingRetryAllTxs = false; + } + + if (!retryAllTxs && parentTxs.empty()) { + return false; + } + if (!IsNewInstantSendEnabled()) { - return; + return false; } // Let's retry all unlocked TXs from mempool and and recently connected blocks @@ -896,16 +910,18 @@ void CInstantSendManager::RetryLockTxs(const uint256& lockedParentTx) { LOCK(mempool.cs); - if (lockedParentTx.IsNull()) { + if (retryAllTxs) { txs.reserve(mempool.mapTx.size()); for (auto it = mempool.mapTx.begin(); it != mempool.mapTx.end(); ++it) { txs.emplace(it->GetTx().GetHash(), it->GetSharedTx()); } } else { - auto it = mempool.mapNextTx.lower_bound(COutPoint(lockedParentTx, 0)); - while (it != mempool.mapNextTx.end() && it->first->hash == lockedParentTx) { - txs.emplace(it->second->GetHash(), mempool.get(it->second->GetHash())); - ++it; + for (const auto& parentTx : parentTxs) { + auto it = mempool.mapNextTx.lower_bound(COutPoint(parentTx, 0)); + while (it != mempool.mapNextTx.end() && it->first->hash == parentTx) { + txs.emplace(it->second->GetHash(), mempool.get(it->second->GetHash())); + ++it; + } } } } @@ -935,12 +951,12 @@ void CInstantSendManager::RetryLockTxs(const uint256& lockedParentTx) } for (const auto& tx : block.vtx) { - if (lockedParentTx.IsNull()) { + if (retryAllTxs) { txs.emplace(tx->GetHash(), tx); } else { bool isChild = false; for (auto& in : tx->vin) { - if (in.prevout.hash == lockedParentTx) { + if (parentTxs.count(in.prevout.hash)) { isChild = true; break; } @@ -955,6 +971,7 @@ void CInstantSendManager::RetryLockTxs(const uint256& lockedParentTx) depth++; } + bool didWork = false; for (auto& p : txs) { auto& tx = p.second; { @@ -983,7 +1000,10 @@ void CInstantSendManager::RetryLockTxs(const uint256& lockedParentTx) } ProcessTx(*tx, Params().GetConsensus()); + didWork = true; } + + return didWork; } bool CInstantSendManager::AlreadyHave(const CInv& inv) diff --git a/src/llmq/quorums_instantsend.h b/src/llmq/quorums_instantsend.h index 5d6b0cc0300894..8ca6d6c06c39b4 100644 --- a/src/llmq/quorums_instantsend.h +++ b/src/llmq/quorums_instantsend.h @@ -90,6 +90,10 @@ class CInstantSendManager : public CRecoveredSigsListener // Incoming and not verified yet std::unordered_map> pendingInstantSendLocks; + // a set of recently IS locked TXs for which we can retry locking of children + std::unordered_set pendingRetryTxs; + bool pendingRetryAllTxs{false}; + public: CInstantSendManager(CDBWrapper& _llmqDb); ~CInstantSendManager(); @@ -125,7 +129,7 @@ class CInstantSendManager : public CRecoveredSigsListener void HandleFullyConfirmedBlock(const CBlockIndex* pindex); void RemoveMempoolConflictsForLock(const uint256& hash, const CInstantSendLock& islock); - void RetryLockTxs(const uint256& lockedParentTx); + bool ProcessPendingRetryLockTxs(); bool AlreadyHave(const CInv& inv); bool GetInstantSendLockByHash(const uint256& hash, CInstantSendLock& ret); diff --git a/src/llmq/quorums_signing_shares.cpp b/src/llmq/quorums_signing_shares.cpp index ba44eeb2a9ef97..7b72db2a7d63b5 100644 --- a/src/llmq/quorums_signing_shares.cpp +++ b/src/llmq/quorums_signing_shares.cpp @@ -1361,6 +1361,7 @@ void CSigSharesManager::WorkThreadMain() // a dedicated place for coordination of these calls didWork |= quorumSigningManager->ProcessPendingRecoveredSigs(*g_connman); didWork |= quorumInstantSendManager->ProcessPendingInstantSendLocks(); + didWork |= quorumInstantSendManager->ProcessPendingRetryLockTxs(); didWork |= ProcessPendingSigShares(*g_connman); didWork |= SignPendingSigShares();