Skip to content

Commit

Permalink
Fix deadlock condition in listtokenssinceblock command - Add semaphor…
Browse files Browse the repository at this point in the history
…e to SyncWithValidationInterfaceQueue to avoid deadlock - Add LOCK to LookupBlockIndex to avoid deadlock
  • Loading branch information
wagerr-builder committed Jan 29, 2024
1 parent 5b2a3e4 commit 8b8bd76
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 6 deletions.
9 changes: 7 additions & 2 deletions src/tokens/rpctokenwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -578,9 +578,10 @@ extern UniValue listtokenssinceblock(const JSONRPCRequest& request)

// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();

pwallet->BlockUntilSyncedToCurrentChain();
LOCK(pwallet->cs_wallet);
EnsureWalletIsUnlocked(pwallet);

unsigned int curparam = 0;

Expand All @@ -604,7 +605,11 @@ extern UniValue listtokenssinceblock(const JSONRPCRequest& request)
uint256 blockId;

blockId.SetHex(request.params[curparam].get_str());
pindex = LookupBlockIndex(blockId);

{ // Start of scope for cs_main lock
LOCK(cs_main);
pindex = LookupBlockIndex(blockId);
} // End of scope for cs_main lock, lock is automatically released here
}

curparam++;
Expand Down
18 changes: 14 additions & 4 deletions src/validationinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@

#include <boost/signals2/signal.hpp>

#include <condition_variable>
#include <mutex>

std::mutex mtx;
std::condition_variable cv;
bool is_drained = false;

struct ValidationInterfaceConnections {
boost::signals2::scoped_connection UpdatedBlockTip;
boost::signals2::scoped_connection SynchronousUpdatedBlockTip;
Expand Down Expand Up @@ -163,11 +170,14 @@ void CallFunctionInValidationInterfaceQueue(std::function<void ()> func) {
void SyncWithValidationInterfaceQueue() {
AssertLockNotHeld(cs_main);
// Block until the validation queue drains
std::promise<void> promise;
CallFunctionInValidationInterfaceQueue([&promise] {
promise.set_value();
std::unique_lock<std::mutex> lock(mtx);
CallFunctionInValidationInterfaceQueue([&] {
std::lock_guard<std::mutex> lock(mtx);
is_drained = true;
cv.notify_one();
});
promise.get_future().wait();
cv.wait(lock, []{ return is_drained; });
is_drained = false;
}

void CMainSignals::MempoolEntryRemoved(CTransactionRef ptx, MemPoolRemovalReason reason) {
Expand Down

0 comments on commit 8b8bd76

Please sign in to comment.