Auto merge of #5009 - LarryRuane:upstream-locking-0.14, r=str4d

Bitcoin 0.14 locking PRs

These are locking changes from upstream (bitcoin core) release 0.14, oldest to newest (when merged to the master branch).

Each commit also includes a reference both to the PR and the upstream commit.

- bitcoin/bitcoin#8472
- bitcoin/bitcoin#8606
  - Excludes a lock move because we don't have bitcoin/bitcoin#7840 which this move was partially-reverting.
- bitcoin/bitcoin#9230
  - Only first commit (we don't have `LogTimestampStr` anymore).
- bitcoin/bitcoin#9243
  - Only the sixth commit, excluding `IsArgSet` locking (we haven't pulled that function in yet).
- bitcoin/bitcoin#9626
  - The cherry-picked commit does not match the upstream at all, but the resulting lock is useful.
- bitcoin/bitcoin#9679
- bitcoin/bitcoin#9227
- bitcoin/bitcoin#9698
  - Excludes change to `CConnman::PushMessage` in second commit (which we don't have yet).
- bitcoin/bitcoin#9708
- bitcoin/bitcoin#9771
This commit is contained in:
Homu 2021-04-02 01:03:27 +00:00
commit 80e66e7daa
13 changed files with 284 additions and 147 deletions

View File

@ -119,7 +119,7 @@ public:
void Run()
{
ThreadCounter count(*this);
while (running) {
while (true) {
std::unique_ptr<WorkItem> i;
{
std::unique_lock<std::mutex> lock(cs);

View File

@ -65,7 +65,7 @@ CCriticalSection cs_main;
BlockMap mapBlockIndex;
CChain chainActive;
CBlockIndex *pindexBestHeader = NULL;
static int64_t nTimeBestReceived = 0;
static std::atomic<int64_t> nTimeBestReceived(0); // Used only to inform the wallet of when we last received a block
CWaitableCriticalSection csBestBlock;
CConditionVariable cvBlockChange;
int nScriptCheckThreads = 0;
@ -362,7 +362,7 @@ int64_t GetBlockTimeout(int64_t nTime, int nValidatedQueuedBefore, const Consens
void InitializeNode(NodeId nodeid, const CNode *pnode) {
LOCK(cs_main);
CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second;
state.name = pnode->addrName;
state.name = pnode->GetAddrName();
state.address = pnode->addr;
}
@ -5594,10 +5594,16 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
pfrom->PushMessage("block", block);
else // MSG_FILTERED_BLOCK)
{
LOCK(pfrom->cs_filter);
if (pfrom->pfilter)
bool send = false;
CMerkleBlock merkleBlock;
{
CMerkleBlock merkleBlock(block, *pfrom->pfilter);
LOCK(pfrom->cs_filter);
if (pfrom->pfilter) {
send = true;
merkleBlock = CMerkleBlock(block, *pfrom->pfilter);
}
}
if (send) {
pfrom->PushMessage("merkleblock", merkleBlock);
// CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see
// This avoids hurting performance by pointlessly requiring a round-trip
@ -5712,7 +5718,11 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
CAddress addrMe;
CAddress addrFrom;
uint64_t nNonce = 1;
vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;
std::string strSubVer;
std::string cleanSubVer;
uint64_t nServices;
vRecv >> pfrom->nVersion >> nServices >> nTime >> addrMe;
pfrom->nServices = nServices;
if (pfrom->nVersion < MIN_PEER_PROTO_VERSION)
{
// disconnect from peers older than this proto version
@ -5745,11 +5755,14 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
if (!vRecv.empty())
vRecv >> addrFrom >> nNonce;
if (!vRecv.empty()) {
vRecv >> LIMITED_STRING(pfrom->strSubVer, MAX_SUBVERSION_LENGTH);
pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer, SAFE_CHARS_SUBVERSION);
vRecv >> LIMITED_STRING(strSubVer, MAX_SUBVERSION_LENGTH);
cleanSubVer = SanitizeString(strSubVer, SAFE_CHARS_SUBVERSION);
}
if (!vRecv.empty()) {
int nStartingHeight;
vRecv >> nStartingHeight;
pfrom->nStartingHeight = nStartingHeight;
}
if (!vRecv.empty())
vRecv >> pfrom->nStartingHeight;
if (!vRecv.empty())
vRecv >> pfrom->fRelayTxes; // set to true after we get the first filter* message
else
@ -5763,7 +5776,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
return true;
}
pfrom->addrLocal = addrMe;
pfrom->SetAddrLocal(addrMe);
if (pfrom->fInbound && addrMe.IsRoutable())
{
SeenLocal(addrMe);
@ -5773,6 +5786,11 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
if (pfrom->fInbound)
pfrom->PushVersion();
{
LOCK(pfrom->cs_SubVer);
pfrom->strSubVer = strSubVer;
pfrom->cleanSubVer = cleanSubVer;
}
pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);
// Potentially mark this peer as a preferred download peer.
@ -5797,7 +5815,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
LogPrintf("ProcessMessages: advertizing address %s\n", addr.ToString());
pfrom->PushAddress(addr, insecure_rand);
} else if (IsPeerAddrLocalGood(pfrom)) {
addr.SetIP(pfrom->addrLocal);
addr.SetIP(addrMe);
LogPrintf("ProcessMessages: advertizing address %s\n", addr.ToString());
pfrom->PushAddress(addr, insecure_rand);
}
@ -5832,7 +5850,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
remoteAddr = ", peeraddr=" + pfrom->addr.ToString();
LogPrintf("receive version message: %s: version %d, blocks=%d, us=%s, peer=%d%s\n",
pfrom->cleanSubVer, pfrom->nVersion,
cleanSubVer, pfrom->nVersion,
pfrom->nStartingHeight, addrMe.ToString(), pfrom->id,
remoteAddr);
@ -6476,7 +6494,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
if (pingUsecTime > 0) {
// Successful ping time measurement, replace previous
pfrom->nPingUsecTime = pingUsecTime;
pfrom->nMinPingUsecTime = std::min(pfrom->nMinPingUsecTime, pingUsecTime);
pfrom->nMinPingUsecTime = std::min(pfrom->nMinPingUsecTime.load(), pingUsecTime);
} else {
// This should never happen
sProblem = "Timing mishap";
@ -6578,8 +6596,8 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
delete pfrom->pfilter;
pfrom->pfilter = new CBloomFilter(filter);
pfrom->pfilter->UpdateEmptyFull();
pfrom->fRelayTxes = true;
}
pfrom->fRelayTxes = true;
}
@ -6590,20 +6608,21 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
// Nodes must NEVER send a data item > 520 bytes (the max size for a script data object,
// and thus, the maximum size any matched object can have) in a filteradd message
if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE)
{
LOCK(cs_main);
Misbehaving(pfrom->GetId(), 100);
bool bad = false;
if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) {
bad = true;
} else {
LOCK(pfrom->cs_filter);
if (pfrom->pfilter)
if (pfrom->pfilter) {
pfrom->pfilter->insert(vData);
else
{
LOCK(cs_main);
Misbehaving(pfrom->GetId(), 100);
} else {
bad = true;
}
}
if (bad) {
LOCK(cs_main);
Misbehaving(pfrom->GetId(), 100);
}
}

View File

@ -192,8 +192,9 @@ int GetnScore(const CService& addr)
// Is our peer's addrLocal potentially useful as an external IP source?
bool IsPeerAddrLocalGood(CNode *pnode)
{
return fDiscover && pnode->addr.IsRoutable() && pnode->addrLocal.IsRoutable() &&
!IsLimited(pnode->addrLocal.GetNetwork());
CService addrLocal = pnode->GetAddrLocal();
return fDiscover && pnode->addr.IsRoutable() && addrLocal.IsRoutable() &&
!IsLimited(addrLocal.GetNetwork());
}
// pushes our own address to a peer
@ -208,7 +209,7 @@ void AdvertizeLocal(CNode *pnode)
if (IsPeerAddrLocalGood(pnode) && (!addrLocal.IsRoutable() ||
GetRand((GetnScore(addrLocal) > LOCAL_MANUAL) ? 8:2) == 0))
{
addrLocal.SetIP(pnode->addrLocal);
addrLocal.SetIP(pnode->GetAddrLocal());
}
if (addrLocal.IsRoutable())
{
@ -350,9 +351,11 @@ CNode* FindNode(const CSubNet& subNet)
CNode* FindNode(const std::string& addrName)
{
LOCK(cs_vNodes);
for (CNode* pnode : vNodes)
if (pnode->addrName == addrName)
for (CNode* pnode : vNodes) {
if (pnode->GetAddrName() == addrName) {
return (pnode);
}
}
return NULL;
}
@ -372,6 +375,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
return NULL;
// Look for an existing connection
LOCK(cs_vNodes);
CNode* pnode = FindNode((CService)addrConnect);
if (pnode)
{
@ -408,8 +412,6 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
vNodes.push_back(pnode);
}
pnode->nTimeConnected = GetTime();
return pnode;
} else if (!proxyConnectionFailed) {
// If connecting to the node failed, and failure is not caused by a problem connecting to
@ -443,10 +445,12 @@ static void DumpBanlist()
void CNode::CloseSocketDisconnect()
{
fDisconnect = true;
if (hSocket != INVALID_SOCKET)
{
LogPrint("net", "disconnecting peer=%d\n", id);
CloseSocket(hSocket);
LOCK(cs_hSocket);
if (hSocket != INVALID_SOCKET) {
LogPrint("net", "disconnecting peer=%d\n", id);
CloseSocket(hSocket);
}
}
// in case this fails, we'll empty the recv buffer when the CNode is deleted
@ -636,22 +640,61 @@ void CNode::AddWhitelistedRange(const CSubNet &subnet) {
vWhitelistedRange.push_back(subnet);
}
std::string CNode::GetAddrName() const {
LOCK(cs_addrName);
return addrName;
}
void CNode::MaybeSetAddrName(const std::string& addrNameIn) {
LOCK(cs_addrName);
if (addrName.empty()) {
addrName = addrNameIn;
}
}
CService CNode::GetAddrLocal() const {
LOCK(cs_addrLocal);
return addrLocal;
}
void CNode::SetAddrLocal(const CService& addrLocalIn) {
LOCK(cs_addrLocal);
if (addrLocal.IsValid()) {
error("Addr local already set for node: %i. Refusing to change from %s to %s", id, addrLocal.ToString(), addrLocalIn.ToString());
} else {
addrLocal = addrLocalIn;
}
}
void CNode::copyStats(CNodeStats &stats)
{
stats.nodeid = this->GetId();
stats.nServices = nServices;
stats.fRelayTxes = fRelayTxes;
{
LOCK(cs_filter);
stats.fRelayTxes = fRelayTxes;
}
stats.nLastSend = nLastSend;
stats.nLastRecv = nLastRecv;
stats.nTimeConnected = nTimeConnected;
stats.nTimeOffset = nTimeOffset;
stats.addrName = addrName;
stats.addrName = GetAddrName();
stats.nVersion = nVersion;
stats.cleanSubVer = cleanSubVer;
{
LOCK(cs_SubVer);
stats.cleanSubVer = cleanSubVer;
}
stats.fInbound = fInbound;
stats.nStartingHeight = nStartingHeight;
stats.nSendBytes = nSendBytes;
stats.nRecvBytes = nRecvBytes;
{
LOCK(cs_vSend);
stats.nSendBytes = nSendBytes;
}
{
LOCK(cs_vRecv);
stats.nRecvBytes = nRecvBytes;
}
stats.fWhitelisted = fWhitelisted;
// It is common for nodes with good ping times to suddenly become lagged,
@ -670,7 +713,8 @@ void CNode::copyStats(CNodeStats &stats)
stats.dPingWait = (((double)nPingUsecWait) / 1e6);
// Leave string empty if addrLocal invalid (not filled in yet)
stats.addrLocal = addrLocal.IsValid() ? addrLocal.ToString() : "";
CService addrLocalUnlocked = GetAddrLocal();
stats.addrLocal = addrLocalUnlocked.IsValid() ? addrLocalUnlocked.ToString() : "";
}
// requires LOCK(cs_vRecvMsg)
@ -780,10 +824,19 @@ void SocketSendData(CNode *pnode)
while (it != pnode->vSendMsg.end()) {
const CSerializeData &data = *it;
assert(data.size() > pnode->nSendOffset);
int nBytes = send(pnode->hSocket, &data[pnode->nSendOffset], data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
int nBytes = 0;
{
LOCK(pnode->cs_hSocket);
if (pnode->hSocket == INVALID_SOCKET)
break;
nBytes = send(pnode->hSocket, &data[pnode->nSendOffset], data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
}
if (nBytes > 0) {
pnode->nLastSend = GetTime();
pnode->nSendBytes += nBytes;
{
LOCK(pnode->cs_vSend);
pnode->nSendBytes += nBytes;
}
pnode->nSendOffset += nBytes;
pnode->RecordBytesSent(nBytes);
if (pnode->nSendOffset == data.size()) {
@ -1142,12 +1195,6 @@ void ThreadSocketHandler()
LOCK(cs_vNodes);
for (CNode* pnode : vNodes)
{
if (pnode->hSocket == INVALID_SOCKET)
continue;
FD_SET(pnode->hSocket, &fdsetError);
hSocketMax = max(hSocketMax, pnode->hSocket);
have_fds = true;
// Implement the following logic:
// * If there is data to send, select() for sending data. As this only
// happens when optimistic write failed, we choose to first drain the
@ -1163,19 +1210,35 @@ void ThreadSocketHandler()
// * We send some data.
// * We wait for data to be received (and disconnect after timeout).
// * We process a message in the buffer (message handler thread).
bool select_send;
{
TRY_LOCK(pnode->cs_vSend, lockSend);
if (lockSend && !pnode->vSendMsg.empty()) {
FD_SET(pnode->hSocket, &fdsetSend);
continue;
}
select_send = lockSend && !pnode->vSendMsg.empty();
}
bool select_recv;
{
TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
if (lockRecv && (
select_recv = lockRecv && (
pnode->vRecvMsg.empty() || !pnode->vRecvMsg.front().complete() ||
pnode->GetTotalRecvSize() <= ReceiveFloodSize()))
FD_SET(pnode->hSocket, &fdsetRecv);
pnode->GetTotalRecvSize() <= ReceiveFloodSize());
}
LOCK(pnode->cs_hSocket);
if (pnode->hSocket == INVALID_SOCKET)
continue;
FD_SET(pnode->hSocket, &fdsetError);
hSocketMax = max(hSocketMax, pnode->hSocket);
have_fds = true;
if (select_send) {
FD_SET(pnode->hSocket, &fdsetSend);
continue;
}
if (select_recv) {
FD_SET(pnode->hSocket, &fdsetRecv);
}
}
}
@ -1228,9 +1291,18 @@ void ThreadSocketHandler()
//
// Receive
//
if (pnode->hSocket == INVALID_SOCKET)
continue;
if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
bool recvSet = false;
bool sendSet = false;
bool errorSet = false;
{
LOCK(pnode->cs_hSocket);
if (pnode->hSocket == INVALID_SOCKET)
continue;
recvSet = FD_ISSET(pnode->hSocket, &fdsetRecv);
sendSet = FD_ISSET(pnode->hSocket, &fdsetSend);
errorSet = FD_ISSET(pnode->hSocket, &fdsetError);
}
if (recvSet || errorSet)
{
TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
if (lockRecv)
@ -1238,13 +1310,22 @@ void ThreadSocketHandler()
{
// typical socket buffer is 8K-64K
char pchBuf[0x10000];
int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
int nBytes = 0;
{
LOCK(pnode->cs_hSocket);
if (pnode->hSocket == INVALID_SOCKET)
continue;
nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
}
if (nBytes > 0)
{
if (!pnode->ReceiveMsgBytes(pchBuf, nBytes))
pnode->CloseSocketDisconnect();
pnode->nLastRecv = GetTime();
pnode->nRecvBytes += nBytes;
{
LOCK(pnode->cs_vRecv);
pnode->nRecvBytes += nBytes;
}
pnode->RecordBytesRecv(nBytes);
}
else if (nBytes == 0)
@ -1272,9 +1353,7 @@ void ThreadSocketHandler()
//
// Send
//
if (pnode->hSocket == INVALID_SOCKET)
continue;
if (FD_ISSET(pnode->hSocket, &fdsetSend))
if (sendSet)
{
TRY_LOCK(pnode->cs_vSend, lockSend);
if (lockSend)
@ -1931,9 +2010,11 @@ public:
~CNetCleanup()
{
// Close sockets
for (CNode* pnode : vNodes)
for (CNode* pnode : vNodes) {
LOCK(pnode->cs_hSocket);
if (pnode->hSocket != INVALID_SOCKET)
CloseSocket(pnode->hSocket);
}
for (ListenSocket& hListenSocket : vhListenSocket)
if (hListenSocket.socket != INVALID_SOCKET)
if (!CloseSocket(hListenSocket.socket))
@ -2158,6 +2239,7 @@ unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", DEFAULT_MAX
CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) :
ssSend(SER_NETWORK, INIT_PROTO_VERSION),
nTimeConnected(GetTime()),
addr(addrIn),
nKeyedNetGroup(CalculateKeyedNetGroup(addrIn)),
addrKnown(5000, 0.001),
@ -2170,7 +2252,6 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
nLastRecv = 0;
nSendBytes = 0;
nRecvBytes = 0;
nTimeConnected = GetTime();
nTimeOffset = 0;
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
nVersion = 0;

View File

@ -256,7 +256,7 @@ class CNode
{
public:
// socket
uint64_t nServices;
std::atomic<uint64_t> nServices;
SOCKET hSocket;
CDataStream ssSend;
std::string strSendCommand; // Current command being assembled in ssSend
@ -265,6 +265,8 @@ public:
uint64_t nSendBytes;
std::deque<CSerializeData> vSendMsg;
CCriticalSection cs_vSend;
CCriticalSection cs_hSocket;
CCriticalSection cs_vRecv;
std::deque<CInv> vRecvGetData;
std::deque<CNetMessage> vRecvMsg;
@ -272,19 +274,18 @@ public:
uint64_t nRecvBytes;
int nRecvVersion;
int64_t nLastSend;
int64_t nLastRecv;
int64_t nTimeConnected;
int64_t nTimeOffset;
std::atomic<int64_t> nLastSend;
std::atomic<int64_t> nLastRecv;
const int64_t nTimeConnected;
std::atomic<int64_t> nTimeOffset;
const CAddress addr;
std::string addrName;
CService addrLocal;
int nVersion;
// strSubVer is whatever byte array we read from the wire. However, this field is intended
// to be printed out, displayed to humans in various forms and so on. So we sanitize it and
// store the sanitized version in cleanSubVer. The original should be used when dealing with
// the network or wire types and the cleaned string used when displayed or logged.
std::string strSubVer, cleanSubVer;
CCriticalSection cs_SubVer; // used for both cleanSubVer and strSubVer
bool fWhitelisted; // This peer can bypass DoS banning.
bool fOneShot;
bool fClient;
@ -301,8 +302,8 @@ public:
CSemaphoreGrant grantOutbound;
CCriticalSection cs_filter;
CBloomFilter* pfilter;
int nRefCount;
NodeId id;
std::atomic<int> nRefCount;
const uint64_t nKeyedNetGroup;
@ -328,7 +329,7 @@ protected:
public:
uint256 hashContinue;
int nStartingHeight;
std::atomic<int> nStartingHeight;
// flood relay
std::vector<CAddress> vAddrToSend;
@ -345,15 +346,15 @@ public:
// Ping time measurement:
// The pong reply we're expecting, or 0 if no pong expected.
uint64_t nPingNonceSent;
std::atomic<uint64_t> nPingNonceSent;
// Time (in usec) the last ping was sent, or 0 if no ping was ever sent.
int64_t nPingUsecStart;
std::atomic<int64_t> nPingUsecStart;
// Last measured round-trip time.
int64_t nPingUsecTime;
std::atomic<int64_t> nPingUsecTime;
// Best measured round-trip time.
int64_t nMinPingUsecTime;
std::atomic<int64_t> nMinPingUsecTime;
// Whether a ping is requested.
bool fPingQueued;
std::atomic<bool> fPingQueued;
CNode(SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false);
~CNode();
@ -376,6 +377,12 @@ private:
static uint64_t CalculateKeyedNetGroup(const CAddress& ad);
mutable CCriticalSection cs_addrName;
std::string addrName;
CService addrLocal;
mutable CCriticalSection cs_addrLocal;
public:
// Regenerate the span for this CNode. This re-queries the log filter to see
@ -412,6 +419,10 @@ public:
msg.SetVersion(nVersionIn);
}
CService GetAddrLocal() const;
//! May not be called more than once
void SetAddrLocal(const CService& addrLocalIn);
CNode* AddRef()
{
nRefCount++;
@ -700,6 +711,9 @@ public:
//!response the time in seconds left in the current max outbound cycle
// in case of no limit, it will always respond with 0
static uint64_t GetMaxOutboundTimeLeftInCycle();
std::string GetAddrName() const;
//! Sets the addrName only if it was not previously set
void MaybeSetAddrName(const std::string& addrNameIn);
};

View File

@ -68,9 +68,8 @@ static void CopyNodeStats(std::vector<CNodeStats>& vstats)
LOCK(cs_vNodes);
vstats.reserve(vNodes.size());
for (CNode* pnode : vNodes) {
CNodeStats stats;
pnode->copyStats(stats);
vstats.push_back(stats);
vstats.emplace_back();
pnode->copyStats(vstats.back());
}
}

View File

@ -171,7 +171,10 @@ public:
typedef CMutexLock<CCriticalSection> CCriticalBlock;
#define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__)
#define PASTE(x, y) x ## y
#define PASTE2(x, y) PASTE(x, y)
#define LOCK(cs) CCriticalBlock PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
#define LOCK2(cs1, cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__), criticalblock2(cs2, #cs2, __FILE__, __LINE__)
#define TRY_LOCK(cs, name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true)

View File

@ -87,6 +87,7 @@ using namespace std;
const char * const BITCOIN_CONF_FILENAME = "zcash.conf";
const char * const BITCOIN_PID_FILENAME = "zcashd.pid";
CCriticalSection cs_args;
map<string, string> mapArgs;
map<string, vector<string> > mapMultiArgs;
bool fDebug = false;
@ -113,6 +114,7 @@ static void InterpretNegativeSetting(std::string& strKey, std::string& strValue)
void ParseParameters(int argc, const char* const argv[])
{
LOCK(cs_args);
mapArgs.clear();
mapMultiArgs.clear();
@ -148,6 +150,7 @@ void ParseParameters(int argc, const char* const argv[])
std::string GetArg(const std::string& strArg, const std::string& strDefault)
{
LOCK(cs_args);
if (mapArgs.count(strArg))
return mapArgs[strArg];
return strDefault;
@ -155,6 +158,7 @@ std::string GetArg(const std::string& strArg, const std::string& strDefault)
int64_t GetArg(const std::string& strArg, int64_t nDefault)
{
LOCK(cs_args);
if (mapArgs.count(strArg))
return atoi64(mapArgs[strArg]);
return nDefault;
@ -162,6 +166,7 @@ int64_t GetArg(const std::string& strArg, int64_t nDefault)
bool GetBoolArg(const std::string& strArg, bool fDefault)
{
LOCK(cs_args);
if (mapArgs.count(strArg))
return InterpretBool(mapArgs[strArg]);
return fDefault;
@ -169,6 +174,7 @@ bool GetBoolArg(const std::string& strArg, bool fDefault)
bool SoftSetArg(const std::string& strArg, const std::string& strValue)
{
LOCK(cs_args);
if (mapArgs.count(strArg))
return false;
mapArgs[strArg] = strValue;
@ -286,7 +292,7 @@ static fs::path ZC_GetDefaultBaseParamsDir()
const fs::path &ZC_GetParamsDir()
{
LOCK(csPathCached); // Reuse the same lock as upstream.
LOCK2(cs_args, csPathCached);
fs::path &path = zc_paramsPathCached;
@ -313,6 +319,7 @@ const fs::path &ZC_GetParamsDir()
const fs::path GetExportDir()
{
fs::path path;
LOCK(cs_args);
if (mapArgs.count("-exportdir")) {
path = fs::system_complete(mapArgs["-exportdir"]);
if (fs::exists(path) && !fs::is_directory(path)) {
@ -328,8 +335,7 @@ const fs::path GetExportDir()
const fs::path &GetDataDir(bool fNetSpecific)
{
LOCK(csPathCached);
LOCK2(cs_args, csPathCached);
fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached;
@ -357,6 +363,7 @@ const fs::path &GetDataDir(bool fNetSpecific)
void ClearDatadirCache()
{
LOCK(csPathCached);
pathCached = fs::path();
pathCachedNetSpecific = fs::path();
}
@ -402,23 +409,26 @@ void ReadConfigFile(const std::string& confPath,
};
set<string> unique_options;
for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
{
string strKey = string("-") + it->string_key;
string strValue = it->value[0];
if (find(allowed_duplicates.begin(), allowed_duplicates.end(), it->string_key) == allowed_duplicates.end())
LOCK(cs_args);
for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
{
if (!unique_options.insert(strKey).second) {
throw std::runtime_error(strprintf("Option '%s' is duplicated, which is not allowed.", strKey));
}
}
string strKey = string("-") + it->string_key;
string strValue = it->value[0];
InterpretNegativeSetting(strKey, strValue);
// Don't overwrite existing settings so command line settings override zcash.conf
if (mapSettingsRet.count(strKey) == 0)
mapSettingsRet[strKey] = strValue;
mapMultiSettingsRet[strKey].push_back(strValue);
if (find(allowed_duplicates.begin(), allowed_duplicates.end(), it->string_key) == allowed_duplicates.end())
{
if (!unique_options.insert(strKey).second) {
throw std::runtime_error(strprintf("Option '%s' is duplicated, which is not allowed.", strKey));
}
}
InterpretNegativeSetting(strKey, strValue);
// Don't overwrite existing settings so command line settings override zcash.conf
if (mapSettingsRet.count(strKey) == 0)
mapSettingsRet[strKey] = strValue;
mapMultiSettingsRet[strKey].push_back(strValue);
}
}
// If datadir is changed in .conf file:
ClearDatadirCache();

View File

@ -50,8 +50,9 @@ void MilliSleep(int64_t n)
std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime)
{
static std::locale classic(std::locale::classic());
// std::locale takes ownership of the pointer
std::locale loc(std::locale::classic(), new boost::posix_time::time_facet(pszFormat));
std::locale loc(classic, new boost::posix_time::time_facet(pszFormat));
std::stringstream ss;
ss.imbue(loc);
ss << boost::posix_time::from_time_t(nTime);

View File

@ -24,9 +24,6 @@
using namespace std;
unsigned int nWalletDBUpdated;
//
// CDB
//

View File

@ -24,8 +24,6 @@
static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100;
static const bool DEFAULT_WALLET_PRIVDB = true;
extern unsigned int nWalletDBUpdated;
class CDBEnv
{
private:

View File

@ -4835,7 +4835,7 @@ bool CWallet::InitLoadWallet(bool clearWitnessCaches)
walletInstance->ScanForWalletTransactions(pindexRescan, true);
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
walletInstance->SetBestChain(chainActive.GetLocator());
nWalletDBUpdated++;
CWalletDB::IncrementUpdateCounter();
// Restore wallet transaction metadata after -zapwallettxes=1
if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2")

View File

@ -20,18 +20,21 @@
#include <boost/scoped_ptr.hpp>
#include <boost/thread.hpp>
#include <atomic>
using namespace std;
static uint64_t nAccountingEntryNumber = 0;
static std::atomic<unsigned int> nWalletDBUpdateCounter;
//
// CWalletDB
//
bool CWalletDB::WriteName(const string& strAddress, const string& strName)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Write(make_pair(string("name"), strAddress), strName);
}
@ -39,37 +42,37 @@ bool CWalletDB::EraseName(const string& strAddress)
{
// This should only be used for sending addresses, never for receiving addresses,
// receiving addresses must always have an address book entry if they're not change return.
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Erase(make_pair(string("name"), strAddress));
}
bool CWalletDB::WritePurpose(const string& strAddress, const string& strPurpose)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Write(make_pair(string("purpose"), strAddress), strPurpose);
}
bool CWalletDB::ErasePurpose(const string& strPurpose)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Erase(make_pair(string("purpose"), strPurpose));
}
bool CWalletDB::WriteTx(uint256 hash, const CWalletTx& wtx)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Write(std::make_pair(std::string("tx"), hash), wtx);
}
bool CWalletDB::EraseTx(uint256 hash)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Erase(std::make_pair(std::string("tx"), hash));
}
bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
keyMeta, false))
@ -89,7 +92,7 @@ bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
const CKeyMetadata &keyMeta)
{
const bool fEraseUnencryptedKey = true;
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
keyMeta))
@ -111,7 +114,7 @@ bool CWalletDB::WriteCryptedZKey(const libzcash::SproutPaymentAddress & addr,
const CKeyMetadata &keyMeta)
{
const bool fEraseUnencryptedKey = true;
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
if (!Write(std::make_pair(std::string("zkeymeta"), addr), keyMeta))
return false;
@ -131,7 +134,7 @@ bool CWalletDB::WriteCryptedSaplingZKey(
const CKeyMetadata &keyMeta)
{
const bool fEraseUnencryptedKey = true;
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
auto ivk = extfvk.fvk.in_viewing_key();
if (!Write(std::make_pair(std::string("sapzkeymeta"), ivk), keyMeta))
@ -149,13 +152,13 @@ bool CWalletDB::WriteCryptedSaplingZKey(
bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
}
bool CWalletDB::WriteZKey(const libzcash::SproutPaymentAddress& addr, const libzcash::SproutSpendingKey& key, const CKeyMetadata &keyMeta)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
if (!Write(std::make_pair(std::string("zkeymeta"), addr), keyMeta))
return false;
@ -167,7 +170,7 @@ bool CWalletDB::WriteSaplingZKey(const libzcash::SaplingIncomingViewingKey &ivk,
const libzcash::SaplingExtendedSpendingKey &key,
const CKeyMetadata &keyMeta)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
if (!Write(std::make_pair(std::string("sapzkeymeta"), ivk), keyMeta))
return false;
@ -179,58 +182,58 @@ bool CWalletDB::WriteSaplingPaymentAddress(
const libzcash::SaplingPaymentAddress &addr,
const libzcash::SaplingIncomingViewingKey &ivk)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Write(std::make_pair(std::string("sapzaddr"), addr), ivk, false);
}
bool CWalletDB::WriteSproutViewingKey(const libzcash::SproutViewingKey &vk)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Write(std::make_pair(std::string("vkey"), vk), '1');
}
bool CWalletDB::EraseSproutViewingKey(const libzcash::SproutViewingKey &vk)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Erase(std::make_pair(std::string("vkey"), vk));
}
bool CWalletDB::WriteSaplingExtendedFullViewingKey(
const libzcash::SaplingExtendedFullViewingKey &extfvk)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Write(std::make_pair(std::string("sapextfvk"), extfvk), '1');
}
bool CWalletDB::EraseSaplingExtendedFullViewingKey(
const libzcash::SaplingExtendedFullViewingKey &extfvk)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Erase(std::make_pair(std::string("sapextfvk"), extfvk));
}
bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Write(std::make_pair(std::string("cscript"), hash), *(const CScriptBase*)(&redeemScript), false);
}
bool CWalletDB::WriteWatchOnly(const CScript &dest)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Write(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)), '1');
}
bool CWalletDB::EraseWatchOnly(const CScript &dest)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Erase(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)));
}
bool CWalletDB::WriteBestBlock(const CBlockLocator& locator)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Write(std::string("bestblock"), locator);
}
@ -241,19 +244,19 @@ bool CWalletDB::ReadBestBlock(CBlockLocator& locator)
bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Write(std::string("orderposnext"), nOrderPosNext);
}
bool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Write(std::string("defaultkey"), vchPubKey);
}
bool CWalletDB::WriteWitnessCacheSize(int64_t nWitnessCacheSize)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Write(std::string("witnesscachesize"), nWitnessCacheSize);
}
@ -264,13 +267,13 @@ bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)
bool CWalletDB::WritePool(int64_t nPool, const CKeyPool& keypool)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Write(std::make_pair(std::string("pool"), nPool), keypool);
}
bool CWalletDB::ErasePool(int64_t nPool)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Erase(std::make_pair(std::string("pool"), nPool));
}
@ -904,8 +907,8 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
bool fNoncriticalErrors = false;
DBErrors result = DB_LOAD_OK;
LOCK(pwallet->cs_wallet);
try {
LOCK(pwallet->cs_wallet);
int nMinVersion = 0;
if (Read((string)"minversion", nMinVersion))
{
@ -1105,20 +1108,20 @@ void ThreadFlushWalletDB(const string& strFile)
if (!GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET))
return;
unsigned int nLastSeen = nWalletDBUpdated;
unsigned int nLastFlushed = nWalletDBUpdated;
unsigned int nLastSeen = CWalletDB::GetUpdateCounter();
unsigned int nLastFlushed = CWalletDB::GetUpdateCounter();
int64_t nLastWalletUpdate = GetTime();
while (true)
{
MilliSleep(500);
if (nLastSeen != nWalletDBUpdated)
if (nLastSeen != CWalletDB::GetUpdateCounter())
{
nLastSeen = nWalletDBUpdated;
nLastSeen = CWalletDB::GetUpdateCounter();
nLastWalletUpdate = GetTime();
}
if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2)
if (nLastFlushed != CWalletDB::GetUpdateCounter() && GetTime() - nLastWalletUpdate >= 2)
{
TRY_LOCK(bitdb.cs_db,lockDb);
if (lockDb)
@ -1139,7 +1142,7 @@ void ThreadFlushWalletDB(const string& strFile)
if (mi != bitdb.mapFileUseCount.end())
{
LogPrint("db", "Flushing %s\n", strFile);
nLastFlushed = nWalletDBUpdated;
nLastFlushed = CWalletDB::GetUpdateCounter();
int64_t nStart = GetTimeMillis();
// Flush wallet file so it's self contained
@ -1282,31 +1285,41 @@ bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename)
bool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Write(std::make_pair(std::string("destdata"), std::make_pair(address, key)), value);
}
bool CWalletDB::EraseDestData(const std::string &address, const std::string &key)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Erase(std::make_pair(std::string("destdata"), std::make_pair(address, key)));
}
bool CWalletDB::WriteHDSeed(const HDSeed& seed)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Write(std::make_pair(std::string("hdseed"), seed.Fingerprint()), seed.RawSeed());
}
bool CWalletDB::WriteCryptedHDSeed(const uint256& seedFp, const std::vector<unsigned char>& vchCryptedSecret)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Write(std::make_pair(std::string("chdseed"), seedFp), vchCryptedSecret);
}
bool CWalletDB::WriteHDChain(const CHDChain& chain)
{
nWalletDBUpdated++;
nWalletDBUpdateCounter++;
return Write(std::string("hdchain"), chain);
}
void CWalletDB::IncrementUpdateCounter()
{
nWalletDBUpdateCounter++;
}
unsigned int CWalletDB::GetUpdateCounter()
{
return nWalletDBUpdateCounter;
}

View File

@ -203,6 +203,8 @@ public:
bool WriteSaplingExtendedFullViewingKey(const libzcash::SaplingExtendedFullViewingKey &extfvk);
bool EraseSaplingExtendedFullViewingKey(const libzcash::SaplingExtendedFullViewingKey &extfvk);
static void IncrementUpdateCounter();
static unsigned int GetUpdateCounter();
private:
CWalletDB(const CWalletDB&);
void operator=(const CWalletDB&);