Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bitcoin 0.16 locking PRs #5017

Merged
merged 17 commits into from
Apr 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions src/addrman.h
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ class CAddrMan

void Clear()
{
LOCK(cs);
std::vector<int>().swap(vRandom);
nKey = GetRandHash();
for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
Expand Down
70 changes: 34 additions & 36 deletions src/httpserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <event2/http.h>
#include <event2/thread.h>
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include <event2/util.h>
#include <event2/keyvalq_struct.h>

Expand Down Expand Up @@ -72,34 +73,13 @@ class WorkQueue
std::deque<std::unique_ptr<WorkItem>> queue;
bool running;
size_t maxDepth;
int numThreads;

/** RAII object to keep track of number of running worker threads */
class ThreadCounter
{
public:
WorkQueue &wq;
ThreadCounter(WorkQueue &w): wq(w)
{
std::lock_guard<std::mutex> lock(wq.cs);
wq.numThreads += 1;
}
~ThreadCounter()
{
std::lock_guard<std::mutex> lock(wq.cs);
wq.numThreads -= 1;
wq.cond.notify_all();
}
};

public:
WorkQueue(size_t maxDepth) : running(true),
maxDepth(maxDepth),
numThreads(0)
maxDepth(maxDepth)
{
}
/** Precondition: worker threads have all stopped
* (call WaitExit)
/** Precondition: worker threads have all stopped (they have been joined).
*/
~WorkQueue()
{
Expand All @@ -118,7 +98,6 @@ class WorkQueue
/** Thread function */
void Run()
{
ThreadCounter count(*this);
while (true) {
std::unique_ptr<WorkItem> i;
{
Expand All @@ -140,13 +119,6 @@ class WorkQueue
running = false;
cond.notify_all();
}
/** Wait for worker threads to exit */
void WaitExit()
{
std::unique_lock<std::mutex> lock(cs);
while (numThreads > 0)
cond.wait(lock);
}

/** Return current depth of queue */
size_t Depth()
Expand Down Expand Up @@ -246,6 +218,16 @@ static std::string RequestMethodString(HTTPRequest::RequestMethod m)
/** HTTP request callback */
static void http_request_cb(struct evhttp_request* req, void* arg)
{
// Disable reading to work around a libevent bug, fixed in 2.2.0.
if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) {
evhttp_connection* conn = evhttp_request_get_connection(req);
if (conn) {
bufferevent* bev = evhttp_connection_get_bufferevent(conn);
if (bev) {
bufferevent_disable(bev, EV_READ);
}
}
}
std::unique_ptr<HTTPRequest> hreq(new HTTPRequest(req));

LogPrint("http", "Received a %s request for %s from %s\n",
Expand Down Expand Up @@ -442,6 +424,7 @@ bool InitHTTPServer()

std::thread threadHTTP;
std::future<bool> threadResult;
static std::vector<std::thread> g_thread_http_workers;

bool StartHTTPServer()
{
Expand All @@ -453,8 +436,7 @@ bool StartHTTPServer()
threadHTTP = std::thread(std::move(task), eventBase, eventHTTP);

for (int i = 0; i < rpcThreads; i++) {
std::thread rpc_worker(HTTPWorkQueueRun, workQueue);
rpc_worker.detach();
g_thread_http_workers.emplace_back(HTTPWorkQueueRun, workQueue);
}
return true;
}
Expand All @@ -479,7 +461,10 @@ void StopHTTPServer()
LogPrint("http", "Stopping HTTP server\n");
if (workQueue) {
LogPrint("http", "Waiting for HTTP worker threads to exit\n");
workQueue->WaitExit();
for (auto& thread: g_thread_http_workers) {
thread.join();
}
g_thread_http_workers.clear();
delete workQueue;
}
if (eventBase) {
Expand Down Expand Up @@ -604,8 +589,21 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
struct evbuffer* evb = evhttp_request_get_output_buffer(req);
assert(evb);
evbuffer_add(evb, strReply.data(), strReply.size());
HTTPEvent* ev = new HTTPEvent(eventBase, true,
std::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL));
auto req_copy = req;
HTTPEvent* ev = new HTTPEvent(eventBase, true, [req_copy, nStatus]{
evhttp_send_reply(req_copy, nStatus, nullptr, nullptr);
// Re-enable reading from the socket. This is the second part of the libevent
// workaround above.
if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) {
evhttp_connection* conn = evhttp_request_get_connection(req_copy);
if (conn) {
bufferevent* bev = evhttp_connection_get_bufferevent(conn);
if (bev) {
bufferevent_enable(bev, EV_READ | EV_WRITE);
}
}
}
});
ev->trigger(0);
replySent = true;
req = 0; // transferred back to main thread
Expand Down
18 changes: 7 additions & 11 deletions src/keystore.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class CKeyStore
//! Check whether a key corresponding to a given address is present in the store.
virtual bool HaveKey(const CKeyID &address) const =0;
virtual bool GetKey(const CKeyID &address, CKey& keyOut) const =0;
virtual void GetKeys(std::set<CKeyID> &setAddress) const =0;
virtual std::set<CKeyID> GetKeys() const =0;
virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const =0;

//! Support for BIP 0013 : see https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki
Expand Down Expand Up @@ -148,18 +148,14 @@ class CBasicKeyStore : public CKeyStore
}
return result;
}
void GetKeys(std::set<CKeyID> &setAddress) const
std::set<CKeyID> GetKeys() const
{
setAddress.clear();
{
LOCK(cs_KeyStore);
KeyMap::const_iterator mi = mapKeys.begin();
while (mi != mapKeys.end())
{
setAddress.insert((*mi).first);
mi++;
}
std::set<CKeyID> set_address;
LOCK(cs_KeyStore);
for (const auto& mi : mapKeys) {
set_address.insert(mi.first);
}
return set_address;
}
bool GetKey(const CKeyID &address, CKey &keyOut) const
{
Expand Down
14 changes: 3 additions & 11 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1483,8 +1483,10 @@ bool AcceptToMemoryPool(
bool* pfMissingInputs, bool fRejectAbsurdFee)
{
AssertLockHeld(cs_main);
if (pfMissingInputs)
LOCK(pool.cs); // mempool "read lock" (held through pool.addUnchecked())
if (pfMissingInputs) {
*pfMissingInputs = false;
}

int nextBlockHeight = chainActive.Height() + 1;

Expand Down Expand Up @@ -1536,8 +1538,6 @@ bool AcceptToMemoryPool(
return false;

// Check for conflicts with in-memory transactions
{
LOCK(pool.cs); // protect pool.mapNextTx
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
COutPoint outpoint = tx.vin[i].prevout;
Expand All @@ -1559,15 +1559,12 @@ bool AcceptToMemoryPool(
return false;
}
}
}

{
CCoinsView dummy;
CCoinsViewCache view(&dummy);

CAmount nValueIn = 0;
{
LOCK(pool.cs);
CCoinsViewMemPool viewMemPool(pcoinsTip, pool);
view.SetBackend(viewMemPool);

Expand Down Expand Up @@ -1609,9 +1606,7 @@ bool AcceptToMemoryPool(

nValueIn = view.GetValueIn(tx);

// we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool
view.SetBackend(dummy);
}

// Check for non-standard pay-to-script-hash in inputs
if (chainparams.RequireStandard() && !AreInputsStandard(tx, view, consensusBranchId))
Expand Down Expand Up @@ -1723,9 +1718,6 @@ bool AcceptToMemoryPool(
}

{
// We lock to prevent other threads from accessing the mempool between adding and evicting
LOCK(pool.cs);

// Store transaction in memory
pool.addUnchecked(hash, entry, !IsInitialBlockDownload(chainparams.GetConsensus()));

Expand Down
13 changes: 10 additions & 3 deletions src/rest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,11 @@ static bool rest_headers(HTTPRequest* req,
}
case RF_JSON: {
UniValue jsonHeaders(UniValue::VARR);
for (const CBlockIndex *pindex : headers) {
jsonHeaders.push_back(blockheaderToJSON(pindex));
{
LOCK(cs_main);
for (const CBlockIndex *pindex : headers) {
jsonHeaders.push_back(blockheaderToJSON(pindex));
}
}
string strJSON = jsonHeaders.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
Expand Down Expand Up @@ -238,7 +241,11 @@ static bool rest_block(HTTPRequest* req,
}

case RF_JSON: {
UniValue objBlock = blockToJSON(block, pblockindex, showTxDetails);
UniValue objBlock;
{
LOCK(cs_main);
objBlock = blockToJSON(block, pblockindex, showTxDetails);
}
string strJSON = objBlock.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
req->WriteReply(HTTP_OK, strJSON);
Expand Down
2 changes: 2 additions & 0 deletions src/rpc/blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ static UniValue ValuePoolDesc(

UniValue blockheaderToJSON(const CBlockIndex* blockindex)
{
AssertLockHeld(cs_main);
UniValue result(UniValue::VOBJ);
result.pushKV("hash", blockindex->GetBlockHash().GetHex());
int confirmations = -1;
Expand Down Expand Up @@ -220,6 +221,7 @@ UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex)

UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false)
{
AssertLockHeld(cs_main);
UniValue result(UniValue::VOBJ);
result.pushKV("hash", block.GetHash().GetHex());
int confirmations = -1;
Expand Down
10 changes: 10 additions & 0 deletions src/sync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,16 @@ void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine,
abort();
}

void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
{
for (const std::pair<void*, CLockLocation>& i : *lockstack) {
if (i.first == cs) {
fprintf(stderr, "Assertion failed: lock %s held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
abort();
}
}
}

void DeleteLock(void* cs)
{
if (!lockdata.available) {
Expand Down
3 changes: 3 additions & 0 deletions src/sync.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,17 @@ void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs
void LeaveCritical();
std::string LocksHeld();
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
void DeleteLock(void* cs);
#else
void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
void static inline LeaveCritical() {}
void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
void static inline AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
void static inline DeleteLock(void* cs) {}
#endif
#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
#define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs)

/**
* Wrapped boost mutex: supports recursive locking, but no waiting
Expand Down
23 changes: 11 additions & 12 deletions src/wallet/crypter.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,22 @@

class uint256;

#include <atomic>

const unsigned int WALLET_CRYPTO_KEY_SIZE = 32;
const unsigned int WALLET_CRYPTO_SALT_SIZE = 8;
const unsigned int WALLET_CRYPTO_IV_SIZE = 16;

/**
* Private key encryption is done based on a CMasterKey,
* which holds a salt and random encryption key.
*
*
* CMasterKeys are encrypted using AES-256-CBC using a key
* derived using derivation method nDerivationMethod
* (0 == EVP_sha512()) and derivation iterations nDeriveIterations.
* vchOtherDerivationParameters is provided for alternative algorithms
* which may require more parameters (such as scrypt).
*
*
* Wallet Private Keys are then encrypted using AES-256-CBC
* with the double-sha256 of the public key as the IV, and the
* master key's key as the encryption key (see keystore.[ch]).
Expand Down Expand Up @@ -138,7 +140,7 @@ class CCryptoKeyStore : public CBasicKeyStore

//! if fUseCrypto is true, mapKeys, mapSproutSpendingKeys, and mapSaplingSpendingKeys must be empty
//! if fUseCrypto is false, vMasterKey must be empty
bool fUseCrypto;
std::atomic<bool> fUseCrypto;

//! keeps track of whether Unlock has run a thorough check before
bool fDecryptionThoroughlyChecked;
Expand Down Expand Up @@ -186,21 +188,18 @@ class CCryptoKeyStore : public CBasicKeyStore
}
bool GetKey(const CKeyID &address, CKey& keyOut) const;
bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
void GetKeys(std::set<CKeyID> &setAddress) const
std::set<CKeyID> GetKeys() const
{
LOCK(cs_KeyStore);
if (!fUseCrypto)
{
CBasicKeyStore::GetKeys(setAddress);
return;
return CBasicKeyStore::GetKeys();
}
setAddress.clear();
CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
while (mi != mapCryptedKeys.end())
{
setAddress.insert((*mi).first);
mi++;
std::set<CKeyID> set_address;
for (const auto& mi : mapCryptedKeys) {
set_address.insert(mi.first);
}
return set_address;
}
virtual bool AddCryptedSproutSpendingKey(
const libzcash::SproutPaymentAddress &address,
Expand Down