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() void Run()
{ {
ThreadCounter count(*this); ThreadCounter count(*this);
while (running) { while (true) {
std::unique_ptr<WorkItem> i; std::unique_ptr<WorkItem> i;
{ {
std::unique_lock<std::mutex> lock(cs); std::unique_lock<std::mutex> lock(cs);

View File

@ -65,7 +65,7 @@ CCriticalSection cs_main;
BlockMap mapBlockIndex; BlockMap mapBlockIndex;
CChain chainActive; CChain chainActive;
CBlockIndex *pindexBestHeader = NULL; 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; CWaitableCriticalSection csBestBlock;
CConditionVariable cvBlockChange; CConditionVariable cvBlockChange;
int nScriptCheckThreads = 0; int nScriptCheckThreads = 0;
@ -362,7 +362,7 @@ int64_t GetBlockTimeout(int64_t nTime, int nValidatedQueuedBefore, const Consens
void InitializeNode(NodeId nodeid, const CNode *pnode) { void InitializeNode(NodeId nodeid, const CNode *pnode) {
LOCK(cs_main); LOCK(cs_main);
CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second; CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second;
state.name = pnode->addrName; state.name = pnode->GetAddrName();
state.address = pnode->addr; state.address = pnode->addr;
} }
@ -5594,10 +5594,16 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
pfrom->PushMessage("block", block); pfrom->PushMessage("block", block);
else // MSG_FILTERED_BLOCK) else // MSG_FILTERED_BLOCK)
{ {
LOCK(pfrom->cs_filter); bool send = false;
if (pfrom->pfilter) 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); pfrom->PushMessage("merkleblock", merkleBlock);
// CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see // 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 // 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 addrMe;
CAddress addrFrom; CAddress addrFrom;
uint64_t nNonce = 1; 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) if (pfrom->nVersion < MIN_PEER_PROTO_VERSION)
{ {
// disconnect from peers older than this 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()) if (!vRecv.empty())
vRecv >> addrFrom >> nNonce; vRecv >> addrFrom >> nNonce;
if (!vRecv.empty()) { if (!vRecv.empty()) {
vRecv >> LIMITED_STRING(pfrom->strSubVer, MAX_SUBVERSION_LENGTH); vRecv >> LIMITED_STRING(strSubVer, MAX_SUBVERSION_LENGTH);
pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer, SAFE_CHARS_SUBVERSION); 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()) if (!vRecv.empty())
vRecv >> pfrom->fRelayTxes; // set to true after we get the first filter* message vRecv >> pfrom->fRelayTxes; // set to true after we get the first filter* message
else else
@ -5763,7 +5776,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
return true; return true;
} }
pfrom->addrLocal = addrMe; pfrom->SetAddrLocal(addrMe);
if (pfrom->fInbound && addrMe.IsRoutable()) if (pfrom->fInbound && addrMe.IsRoutable())
{ {
SeenLocal(addrMe); SeenLocal(addrMe);
@ -5773,6 +5786,11 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
if (pfrom->fInbound) if (pfrom->fInbound)
pfrom->PushVersion(); pfrom->PushVersion();
{
LOCK(pfrom->cs_SubVer);
pfrom->strSubVer = strSubVer;
pfrom->cleanSubVer = cleanSubVer;
}
pfrom->fClient = !(pfrom->nServices & NODE_NETWORK); pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);
// Potentially mark this peer as a preferred download peer. // 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()); LogPrintf("ProcessMessages: advertizing address %s\n", addr.ToString());
pfrom->PushAddress(addr, insecure_rand); pfrom->PushAddress(addr, insecure_rand);
} else if (IsPeerAddrLocalGood(pfrom)) { } else if (IsPeerAddrLocalGood(pfrom)) {
addr.SetIP(pfrom->addrLocal); addr.SetIP(addrMe);
LogPrintf("ProcessMessages: advertizing address %s\n", addr.ToString()); LogPrintf("ProcessMessages: advertizing address %s\n", addr.ToString());
pfrom->PushAddress(addr, insecure_rand); pfrom->PushAddress(addr, insecure_rand);
} }
@ -5832,7 +5850,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
remoteAddr = ", peeraddr=" + pfrom->addr.ToString(); remoteAddr = ", peeraddr=" + pfrom->addr.ToString();
LogPrintf("receive version message: %s: version %d, blocks=%d, us=%s, peer=%d%s\n", 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, pfrom->nStartingHeight, addrMe.ToString(), pfrom->id,
remoteAddr); remoteAddr);
@ -6476,7 +6494,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
if (pingUsecTime > 0) { if (pingUsecTime > 0) {
// Successful ping time measurement, replace previous // Successful ping time measurement, replace previous
pfrom->nPingUsecTime = pingUsecTime; pfrom->nPingUsecTime = pingUsecTime;
pfrom->nMinPingUsecTime = std::min(pfrom->nMinPingUsecTime, pingUsecTime); pfrom->nMinPingUsecTime = std::min(pfrom->nMinPingUsecTime.load(), pingUsecTime);
} else { } else {
// This should never happen // This should never happen
sProblem = "Timing mishap"; sProblem = "Timing mishap";
@ -6578,8 +6596,8 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
delete pfrom->pfilter; delete pfrom->pfilter;
pfrom->pfilter = new CBloomFilter(filter); pfrom->pfilter = new CBloomFilter(filter);
pfrom->pfilter->UpdateEmptyFull(); 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, // 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 // and thus, the maximum size any matched object can have) in a filteradd message
if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) bool bad = false;
{ if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) {
LOCK(cs_main); bad = true;
Misbehaving(pfrom->GetId(), 100);
} else { } else {
LOCK(pfrom->cs_filter); LOCK(pfrom->cs_filter);
if (pfrom->pfilter) if (pfrom->pfilter) {
pfrom->pfilter->insert(vData); pfrom->pfilter->insert(vData);
else } else {
{ bad = true;
LOCK(cs_main);
Misbehaving(pfrom->GetId(), 100);
} }
} }
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? // Is our peer's addrLocal potentially useful as an external IP source?
bool IsPeerAddrLocalGood(CNode *pnode) bool IsPeerAddrLocalGood(CNode *pnode)
{ {
return fDiscover && pnode->addr.IsRoutable() && pnode->addrLocal.IsRoutable() && CService addrLocal = pnode->GetAddrLocal();
!IsLimited(pnode->addrLocal.GetNetwork()); return fDiscover && pnode->addr.IsRoutable() && addrLocal.IsRoutable() &&
!IsLimited(addrLocal.GetNetwork());
} }
// pushes our own address to a peer // pushes our own address to a peer
@ -208,7 +209,7 @@ void AdvertizeLocal(CNode *pnode)
if (IsPeerAddrLocalGood(pnode) && (!addrLocal.IsRoutable() || if (IsPeerAddrLocalGood(pnode) && (!addrLocal.IsRoutable() ||
GetRand((GetnScore(addrLocal) > LOCAL_MANUAL) ? 8:2) == 0)) GetRand((GetnScore(addrLocal) > LOCAL_MANUAL) ? 8:2) == 0))
{ {
addrLocal.SetIP(pnode->addrLocal); addrLocal.SetIP(pnode->GetAddrLocal());
} }
if (addrLocal.IsRoutable()) if (addrLocal.IsRoutable())
{ {
@ -350,9 +351,11 @@ CNode* FindNode(const CSubNet& subNet)
CNode* FindNode(const std::string& addrName) CNode* FindNode(const std::string& addrName)
{ {
LOCK(cs_vNodes); LOCK(cs_vNodes);
for (CNode* pnode : vNodes) for (CNode* pnode : vNodes) {
if (pnode->addrName == addrName) if (pnode->GetAddrName() == addrName) {
return (pnode); return (pnode);
}
}
return NULL; return NULL;
} }
@ -372,6 +375,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
return NULL; return NULL;
// Look for an existing connection // Look for an existing connection
LOCK(cs_vNodes);
CNode* pnode = FindNode((CService)addrConnect); CNode* pnode = FindNode((CService)addrConnect);
if (pnode) if (pnode)
{ {
@ -408,8 +412,6 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
vNodes.push_back(pnode); vNodes.push_back(pnode);
} }
pnode->nTimeConnected = GetTime();
return pnode; return pnode;
} else if (!proxyConnectionFailed) { } else if (!proxyConnectionFailed) {
// If connecting to the node failed, and failure is not caused by a problem connecting to // 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() void CNode::CloseSocketDisconnect()
{ {
fDisconnect = true; fDisconnect = true;
if (hSocket != INVALID_SOCKET)
{ {
LogPrint("net", "disconnecting peer=%d\n", id); LOCK(cs_hSocket);
CloseSocket(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 // 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); 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) void CNode::copyStats(CNodeStats &stats)
{ {
stats.nodeid = this->GetId(); stats.nodeid = this->GetId();
stats.nServices = nServices; stats.nServices = nServices;
stats.fRelayTxes = fRelayTxes; {
LOCK(cs_filter);
stats.fRelayTxes = fRelayTxes;
}
stats.nLastSend = nLastSend; stats.nLastSend = nLastSend;
stats.nLastRecv = nLastRecv; stats.nLastRecv = nLastRecv;
stats.nTimeConnected = nTimeConnected; stats.nTimeConnected = nTimeConnected;
stats.nTimeOffset = nTimeOffset; stats.nTimeOffset = nTimeOffset;
stats.addrName = addrName; stats.addrName = GetAddrName();
stats.nVersion = nVersion; stats.nVersion = nVersion;
stats.cleanSubVer = cleanSubVer; {
LOCK(cs_SubVer);
stats.cleanSubVer = cleanSubVer;
}
stats.fInbound = fInbound; stats.fInbound = fInbound;
stats.nStartingHeight = nStartingHeight; stats.nStartingHeight = nStartingHeight;
stats.nSendBytes = nSendBytes; {
stats.nRecvBytes = nRecvBytes; LOCK(cs_vSend);
stats.nSendBytes = nSendBytes;
}
{
LOCK(cs_vRecv);
stats.nRecvBytes = nRecvBytes;
}
stats.fWhitelisted = fWhitelisted; stats.fWhitelisted = fWhitelisted;
// It is common for nodes with good ping times to suddenly become lagged, // 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); stats.dPingWait = (((double)nPingUsecWait) / 1e6);
// Leave string empty if addrLocal invalid (not filled in yet) // 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) // requires LOCK(cs_vRecvMsg)
@ -780,10 +824,19 @@ void SocketSendData(CNode *pnode)
while (it != pnode->vSendMsg.end()) { while (it != pnode->vSendMsg.end()) {
const CSerializeData &data = *it; const CSerializeData &data = *it;
assert(data.size() > pnode->nSendOffset); 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) { if (nBytes > 0) {
pnode->nLastSend = GetTime(); pnode->nLastSend = GetTime();
pnode->nSendBytes += nBytes; {
LOCK(pnode->cs_vSend);
pnode->nSendBytes += nBytes;
}
pnode->nSendOffset += nBytes; pnode->nSendOffset += nBytes;
pnode->RecordBytesSent(nBytes); pnode->RecordBytesSent(nBytes);
if (pnode->nSendOffset == data.size()) { if (pnode->nSendOffset == data.size()) {
@ -1142,12 +1195,6 @@ void ThreadSocketHandler()
LOCK(cs_vNodes); LOCK(cs_vNodes);
for (CNode* pnode : 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: // Implement the following logic:
// * If there is data to send, select() for sending data. As this only // * If there is data to send, select() for sending data. As this only
// happens when optimistic write failed, we choose to first drain the // happens when optimistic write failed, we choose to first drain the
@ -1163,19 +1210,35 @@ void ThreadSocketHandler()
// * We send some data. // * We send some data.
// * We wait for data to be received (and disconnect after timeout). // * We wait for data to be received (and disconnect after timeout).
// * We process a message in the buffer (message handler thread). // * We process a message in the buffer (message handler thread).
bool select_send;
{ {
TRY_LOCK(pnode->cs_vSend, lockSend); TRY_LOCK(pnode->cs_vSend, lockSend);
if (lockSend && !pnode->vSendMsg.empty()) { select_send = lockSend && !pnode->vSendMsg.empty();
FD_SET(pnode->hSocket, &fdsetSend);
continue;
}
} }
bool select_recv;
{ {
TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
if (lockRecv && ( select_recv = lockRecv && (
pnode->vRecvMsg.empty() || !pnode->vRecvMsg.front().complete() || pnode->vRecvMsg.empty() || !pnode->vRecvMsg.front().complete() ||
pnode->GetTotalRecvSize() <= ReceiveFloodSize())) pnode->GetTotalRecvSize() <= ReceiveFloodSize());
FD_SET(pnode->hSocket, &fdsetRecv); }
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 // Receive
// //
if (pnode->hSocket == INVALID_SOCKET) bool recvSet = false;
continue; bool sendSet = false;
if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError)) 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); TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
if (lockRecv) if (lockRecv)
@ -1238,13 +1310,22 @@ void ThreadSocketHandler()
{ {
// typical socket buffer is 8K-64K // typical socket buffer is 8K-64K
char pchBuf[0x10000]; 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 (nBytes > 0)
{ {
if (!pnode->ReceiveMsgBytes(pchBuf, nBytes)) if (!pnode->ReceiveMsgBytes(pchBuf, nBytes))
pnode->CloseSocketDisconnect(); pnode->CloseSocketDisconnect();
pnode->nLastRecv = GetTime(); pnode->nLastRecv = GetTime();
pnode->nRecvBytes += nBytes; {
LOCK(pnode->cs_vRecv);
pnode->nRecvBytes += nBytes;
}
pnode->RecordBytesRecv(nBytes); pnode->RecordBytesRecv(nBytes);
} }
else if (nBytes == 0) else if (nBytes == 0)
@ -1272,9 +1353,7 @@ void ThreadSocketHandler()
// //
// Send // Send
// //
if (pnode->hSocket == INVALID_SOCKET) if (sendSet)
continue;
if (FD_ISSET(pnode->hSocket, &fdsetSend))
{ {
TRY_LOCK(pnode->cs_vSend, lockSend); TRY_LOCK(pnode->cs_vSend, lockSend);
if (lockSend) if (lockSend)
@ -1931,9 +2010,11 @@ public:
~CNetCleanup() ~CNetCleanup()
{ {
// Close sockets // Close sockets
for (CNode* pnode : vNodes) for (CNode* pnode : vNodes) {
LOCK(pnode->cs_hSocket);
if (pnode->hSocket != INVALID_SOCKET) if (pnode->hSocket != INVALID_SOCKET)
CloseSocket(pnode->hSocket); CloseSocket(pnode->hSocket);
}
for (ListenSocket& hListenSocket : vhListenSocket) for (ListenSocket& hListenSocket : vhListenSocket)
if (hListenSocket.socket != INVALID_SOCKET) if (hListenSocket.socket != INVALID_SOCKET)
if (!CloseSocket(hListenSocket.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) : CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) :
ssSend(SER_NETWORK, INIT_PROTO_VERSION), ssSend(SER_NETWORK, INIT_PROTO_VERSION),
nTimeConnected(GetTime()),
addr(addrIn), addr(addrIn),
nKeyedNetGroup(CalculateKeyedNetGroup(addrIn)), nKeyedNetGroup(CalculateKeyedNetGroup(addrIn)),
addrKnown(5000, 0.001), addrKnown(5000, 0.001),
@ -2170,7 +2252,6 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
nLastRecv = 0; nLastRecv = 0;
nSendBytes = 0; nSendBytes = 0;
nRecvBytes = 0; nRecvBytes = 0;
nTimeConnected = GetTime();
nTimeOffset = 0; nTimeOffset = 0;
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
nVersion = 0; nVersion = 0;

View File

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

View File

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

View File

@ -50,8 +50,9 @@ void MilliSleep(int64_t n)
std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime) 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 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; std::stringstream ss;
ss.imbue(loc); ss.imbue(loc);
ss << boost::posix_time::from_time_t(nTime); ss << boost::posix_time::from_time_t(nTime);

View File

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

View File

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

View File

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

View File

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