Merge pull request #4933
20e01b1
Apply clang-format on some infrequently-updated files (Pieter Wuille)
This commit is contained in:
commit
934b153a2c
30 changed files with 845 additions and 742 deletions
225
src/addrman.cpp
225
src/addrman.cpp
|
@ -9,7 +9,7 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
int CAddrInfo::GetTriedBucket(const std::vector<unsigned char> &nKey) const
|
||||
int CAddrInfo::GetTriedBucket(const std::vector<unsigned char>& nKey) const
|
||||
{
|
||||
CDataStream ss1(SER_GETHASH, 0);
|
||||
std::vector<unsigned char> vchKey = GetKey();
|
||||
|
@ -23,7 +23,7 @@ int CAddrInfo::GetTriedBucket(const std::vector<unsigned char> &nKey) const
|
|||
return hash2 % ADDRMAN_TRIED_BUCKET_COUNT;
|
||||
}
|
||||
|
||||
int CAddrInfo::GetNewBucket(const std::vector<unsigned char> &nKey, const CNetAddr& src) const
|
||||
int CAddrInfo::GetNewBucket(const std::vector<unsigned char>& nKey, const CNetAddr& src) const
|
||||
{
|
||||
CDataStream ss1(SER_GETHASH, 0);
|
||||
std::vector<unsigned char> vchGroupKey = GetGroup();
|
||||
|
@ -39,19 +39,19 @@ int CAddrInfo::GetNewBucket(const std::vector<unsigned char> &nKey, const CNetAd
|
|||
|
||||
bool CAddrInfo::IsTerrible(int64_t nNow) const
|
||||
{
|
||||
if (nLastTry && nLastTry >= nNow-60) // never remove things tried the last minute
|
||||
if (nLastTry && nLastTry >= nNow - 60) // never remove things tried the last minute
|
||||
return false;
|
||||
|
||||
if (nTime > nNow + 10*60) // came in a flying DeLorean
|
||||
if (nTime > nNow + 10 * 60) // came in a flying DeLorean
|
||||
return true;
|
||||
|
||||
if (nTime==0 || nNow-nTime > ADDRMAN_HORIZON_DAYS*24*60*60) // not seen in recent history
|
||||
if (nTime == 0 || nNow - nTime > ADDRMAN_HORIZON_DAYS * 24 * 60 * 60) // not seen in recent history
|
||||
return true;
|
||||
|
||||
if (nLastSuccess==0 && nAttempts>=ADDRMAN_RETRIES) // tried N times and never a success
|
||||
if (nLastSuccess == 0 && nAttempts >= ADDRMAN_RETRIES) // tried N times and never a success
|
||||
return true;
|
||||
|
||||
if (nNow-nLastSuccess > ADDRMAN_MIN_FAIL_DAYS*24*60*60 && nAttempts>=ADDRMAN_MAX_FAILURES) // N successive failures in the last week
|
||||
if (nNow - nLastSuccess > ADDRMAN_MIN_FAIL_DAYS * 24 * 60 * 60 && nAttempts >= ADDRMAN_MAX_FAILURES) // N successive failures in the last week
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -64,23 +64,25 @@ double CAddrInfo::GetChance(int64_t nNow) const
|
|||
int64_t nSinceLastSeen = nNow - nTime;
|
||||
int64_t nSinceLastTry = nNow - nLastTry;
|
||||
|
||||
if (nSinceLastSeen < 0) nSinceLastSeen = 0;
|
||||
if (nSinceLastTry < 0) nSinceLastTry = 0;
|
||||
if (nSinceLastSeen < 0)
|
||||
nSinceLastSeen = 0;
|
||||
if (nSinceLastTry < 0)
|
||||
nSinceLastTry = 0;
|
||||
|
||||
fChance *= 600.0 / (600.0 + nSinceLastSeen);
|
||||
|
||||
// deprioritize very recent attempts away
|
||||
if (nSinceLastTry < 60*10)
|
||||
if (nSinceLastTry < 60 * 10)
|
||||
fChance *= 0.01;
|
||||
|
||||
// deprioritize 50% after each failed attempt
|
||||
for (int n=0; n<nAttempts; n++)
|
||||
for (int n = 0; n < nAttempts; n++)
|
||||
fChance /= 1.5;
|
||||
|
||||
return fChance;
|
||||
}
|
||||
|
||||
CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int *pnId)
|
||||
CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId)
|
||||
{
|
||||
std::map<CNetAddr, int>::iterator it = mapAddr.find(addr);
|
||||
if (it == mapAddr.end())
|
||||
|
@ -93,7 +95,7 @@ CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int *pnId)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
CAddrInfo* CAddrMan::Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId)
|
||||
CAddrInfo* CAddrMan::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId)
|
||||
{
|
||||
int nId = nIdCount++;
|
||||
mapInfo[nId] = CAddrInfo(addr, addrSource);
|
||||
|
@ -127,22 +129,21 @@ void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2)
|
|||
|
||||
int CAddrMan::SelectTried(int nKBucket)
|
||||
{
|
||||
std::vector<int> &vTried = vvTried[nKBucket];
|
||||
std::vector<int>& vTried = vvTried[nKBucket];
|
||||
|
||||
// random shuffle the first few elements (using the entire list)
|
||||
// find the least recently tried among them
|
||||
int64_t nOldest = -1;
|
||||
int nOldestPos = -1;
|
||||
for (unsigned int i = 0; i < ADDRMAN_TRIED_ENTRIES_INSPECT_ON_EVICT && i < vTried.size(); i++)
|
||||
{
|
||||
for (unsigned int i = 0; i < ADDRMAN_TRIED_ENTRIES_INSPECT_ON_EVICT && i < vTried.size(); i++) {
|
||||
int nPos = GetRandInt(vTried.size() - i) + i;
|
||||
int nTemp = vTried[nPos];
|
||||
vTried[nPos] = vTried[i];
|
||||
vTried[i] = nTemp;
|
||||
assert(nOldest == -1 || mapInfo.count(nTemp) == 1);
|
||||
if (nOldest == -1 || mapInfo[nTemp].nLastSuccess < mapInfo[nOldest].nLastSuccess) {
|
||||
nOldest = nTemp;
|
||||
nOldestPos = nPos;
|
||||
nOldest = nTemp;
|
||||
nOldestPos = nPos;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,18 +153,15 @@ int CAddrMan::SelectTried(int nKBucket)
|
|||
int CAddrMan::ShrinkNew(int nUBucket)
|
||||
{
|
||||
assert(nUBucket >= 0 && (unsigned int)nUBucket < vvNew.size());
|
||||
std::set<int> &vNew = vvNew[nUBucket];
|
||||
std::set<int>& vNew = vvNew[nUBucket];
|
||||
|
||||
// first look for deletable items
|
||||
for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++)
|
||||
{
|
||||
for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++) {
|
||||
assert(mapInfo.count(*it));
|
||||
CAddrInfo &info = mapInfo[*it];
|
||||
if (info.IsTerrible())
|
||||
{
|
||||
if (--info.nRefCount == 0)
|
||||
{
|
||||
SwapRandom(info.nRandomPos, vRandom.size()-1);
|
||||
CAddrInfo& info = mapInfo[*it];
|
||||
if (info.IsTerrible()) {
|
||||
if (--info.nRefCount == 0) {
|
||||
SwapRandom(info.nRandomPos, vRandom.size() - 1);
|
||||
vRandom.pop_back();
|
||||
mapAddr.erase(info);
|
||||
mapInfo.erase(*it);
|
||||
|
@ -178,10 +176,8 @@ int CAddrMan::ShrinkNew(int nUBucket)
|
|||
int n[4] = {GetRandInt(vNew.size()), GetRandInt(vNew.size()), GetRandInt(vNew.size()), GetRandInt(vNew.size())};
|
||||
int nI = 0;
|
||||
int nOldest = -1;
|
||||
for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++)
|
||||
{
|
||||
if (nI == n[0] || nI == n[1] || nI == n[2] || nI == n[3])
|
||||
{
|
||||
for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++) {
|
||||
if (nI == n[0] || nI == n[1] || nI == n[2] || nI == n[3]) {
|
||||
assert(nOldest == -1 || mapInfo.count(*it) == 1);
|
||||
if (nOldest == -1 || mapInfo[*it].nTime < mapInfo[nOldest].nTime)
|
||||
nOldest = *it;
|
||||
|
@ -189,10 +185,9 @@ int CAddrMan::ShrinkNew(int nUBucket)
|
|||
nI++;
|
||||
}
|
||||
assert(mapInfo.count(nOldest) == 1);
|
||||
CAddrInfo &info = mapInfo[nOldest];
|
||||
if (--info.nRefCount == 0)
|
||||
{
|
||||
SwapRandom(info.nRandomPos, vRandom.size()-1);
|
||||
CAddrInfo& info = mapInfo[nOldest];
|
||||
if (--info.nRefCount == 0) {
|
||||
SwapRandom(info.nRandomPos, vRandom.size() - 1);
|
||||
vRandom.pop_back();
|
||||
mapAddr.erase(info);
|
||||
mapInfo.erase(nOldest);
|
||||
|
@ -208,8 +203,7 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin)
|
|||
assert(vvNew[nOrigin].count(nId) == 1);
|
||||
|
||||
// remove the entry from all new buckets
|
||||
for (std::vector<std::set<int> >::iterator it = vvNew.begin(); it != vvNew.end(); it++)
|
||||
{
|
||||
for (std::vector<std::set<int> >::iterator it = vvNew.begin(); it != vvNew.end(); it++) {
|
||||
if ((*it).erase(nId))
|
||||
info.nRefCount--;
|
||||
}
|
||||
|
@ -219,11 +213,10 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin)
|
|||
|
||||
// what tried bucket to move the entry to
|
||||
int nKBucket = info.GetTriedBucket(nKey);
|
||||
std::vector<int> &vTried = vvTried[nKBucket];
|
||||
std::vector<int>& vTried = vvTried[nKBucket];
|
||||
|
||||
// first check whether there is place to just add it
|
||||
if (vTried.size() < ADDRMAN_TRIED_BUCKET_SIZE)
|
||||
{
|
||||
if (vTried.size() < ADDRMAN_TRIED_BUCKET_SIZE) {
|
||||
vTried.push_back(nId);
|
||||
nTried++;
|
||||
info.fInTried = true;
|
||||
|
@ -236,7 +229,7 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin)
|
|||
// find which new bucket it belongs to
|
||||
assert(mapInfo.count(vTried[nPos]) == 1);
|
||||
int nUBucket = mapInfo[vTried[nPos]].GetNewBucket(nKey);
|
||||
std::set<int> &vNew = vvNew[nUBucket];
|
||||
std::set<int>& vNew = vvNew[nUBucket];
|
||||
|
||||
// remove the to-be-replaced tried entry from the tried set
|
||||
CAddrInfo& infoOld = mapInfo[vTried[nPos]];
|
||||
|
@ -245,8 +238,7 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin)
|
|||
// do not update nTried, as we are going to move something else there immediately
|
||||
|
||||
// check whether there is place in that one,
|
||||
if (vNew.size() < ADDRMAN_NEW_BUCKET_SIZE)
|
||||
{
|
||||
if (vNew.size() < ADDRMAN_NEW_BUCKET_SIZE) {
|
||||
// if so, move it back there
|
||||
vNew.insert(vTried[nPos]);
|
||||
} else {
|
||||
|
@ -261,16 +253,16 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin)
|
|||
return;
|
||||
}
|
||||
|
||||
void CAddrMan::Good_(const CService &addr, int64_t nTime)
|
||||
void CAddrMan::Good_(const CService& addr, int64_t nTime)
|
||||
{
|
||||
int nId;
|
||||
CAddrInfo *pinfo = Find(addr, &nId);
|
||||
CAddrInfo* pinfo = Find(addr, &nId);
|
||||
|
||||
// if not found, bail out
|
||||
if (!pinfo)
|
||||
return;
|
||||
|
||||
CAddrInfo &info = *pinfo;
|
||||
CAddrInfo& info = *pinfo;
|
||||
|
||||
// check whether we are talking about the exact same CService (including same port)
|
||||
if (info != addr)
|
||||
|
@ -289,12 +281,10 @@ void CAddrMan::Good_(const CService &addr, int64_t nTime)
|
|||
// find a bucket it is in now
|
||||
int nRnd = GetRandInt(vvNew.size());
|
||||
int nUBucket = -1;
|
||||
for (unsigned int n = 0; n < vvNew.size(); n++)
|
||||
{
|
||||
int nB = (n+nRnd) % vvNew.size();
|
||||
std::set<int> &vNew = vvNew[nB];
|
||||
if (vNew.count(nId))
|
||||
{
|
||||
for (unsigned int n = 0; n < vvNew.size(); n++) {
|
||||
int nB = (n + nRnd) % vvNew.size();
|
||||
std::set<int>& vNew = vvNew[nB];
|
||||
if (vNew.count(nId)) {
|
||||
nUBucket = nB;
|
||||
break;
|
||||
}
|
||||
|
@ -302,7 +292,8 @@ void CAddrMan::Good_(const CService &addr, int64_t nTime)
|
|||
|
||||
// if no bucket is found, something bad happened;
|
||||
// TODO: maybe re-add the node, but for now, just bail out
|
||||
if (nUBucket == -1) return;
|
||||
if (nUBucket == -1)
|
||||
return;
|
||||
|
||||
LogPrint("addrman", "Moving %s to tried\n", addr.ToString());
|
||||
|
||||
|
@ -310,17 +301,16 @@ void CAddrMan::Good_(const CService &addr, int64_t nTime)
|
|||
MakeTried(info, nId, nUBucket);
|
||||
}
|
||||
|
||||
bool CAddrMan::Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty)
|
||||
bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty)
|
||||
{
|
||||
if (!addr.IsRoutable())
|
||||
return false;
|
||||
|
||||
bool fNew = false;
|
||||
int nId;
|
||||
CAddrInfo *pinfo = Find(addr, &nId);
|
||||
CAddrInfo* pinfo = Find(addr, &nId);
|
||||
|
||||
if (pinfo)
|
||||
{
|
||||
if (pinfo) {
|
||||
// periodically update nTime
|
||||
bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
|
||||
int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
|
||||
|
@ -344,7 +334,7 @@ bool CAddrMan::Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimeP
|
|||
|
||||
// stochastic test: previous nRefCount == N: 2^N times harder to increase it
|
||||
int nFactor = 1;
|
||||
for (int n=0; n<pinfo->nRefCount; n++)
|
||||
for (int n = 0; n < pinfo->nRefCount; n++)
|
||||
nFactor *= 2;
|
||||
if (nFactor > 1 && (GetRandInt(nFactor) != 0))
|
||||
return false;
|
||||
|
@ -356,9 +346,8 @@ bool CAddrMan::Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimeP
|
|||
}
|
||||
|
||||
int nUBucket = pinfo->GetNewBucket(nKey, source);
|
||||
std::set<int> &vNew = vvNew[nUBucket];
|
||||
if (!vNew.count(nId))
|
||||
{
|
||||
std::set<int>& vNew = vvNew[nUBucket];
|
||||
if (!vNew.count(nId)) {
|
||||
pinfo->nRefCount++;
|
||||
if (vNew.size() == ADDRMAN_NEW_BUCKET_SIZE)
|
||||
ShrinkNew(nUBucket);
|
||||
|
@ -367,15 +356,15 @@ bool CAddrMan::Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimeP
|
|||
return fNew;
|
||||
}
|
||||
|
||||
void CAddrMan::Attempt_(const CService &addr, int64_t nTime)
|
||||
void CAddrMan::Attempt_(const CService& addr, int64_t nTime)
|
||||
{
|
||||
CAddrInfo *pinfo = Find(addr);
|
||||
CAddrInfo* pinfo = Find(addr);
|
||||
|
||||
// if not found, bail out
|
||||
if (!pinfo)
|
||||
return;
|
||||
|
||||
CAddrInfo &info = *pinfo;
|
||||
CAddrInfo& info = *pinfo;
|
||||
|
||||
// check whether we are talking about the exact same CService (including same port)
|
||||
if (info != addr)
|
||||
|
@ -393,37 +382,36 @@ CAddress CAddrMan::Select_(int nUnkBias)
|
|||
|
||||
double nCorTried = sqrt(nTried) * (100.0 - nUnkBias);
|
||||
double nCorNew = sqrt(nNew) * nUnkBias;
|
||||
if ((nCorTried + nCorNew)*GetRandInt(1<<30)/(1<<30) < nCorTried)
|
||||
{
|
||||
if ((nCorTried + nCorNew) * GetRandInt(1 << 30) / (1 << 30) < nCorTried) {
|
||||
// use a tried node
|
||||
double fChanceFactor = 1.0;
|
||||
while(1)
|
||||
{
|
||||
while (1) {
|
||||
int nKBucket = GetRandInt(vvTried.size());
|
||||
std::vector<int> &vTried = vvTried[nKBucket];
|
||||
if (vTried.size() == 0) continue;
|
||||
std::vector<int>& vTried = vvTried[nKBucket];
|
||||
if (vTried.size() == 0)
|
||||
continue;
|
||||
int nPos = GetRandInt(vTried.size());
|
||||
assert(mapInfo.count(vTried[nPos]) == 1);
|
||||
CAddrInfo &info = mapInfo[vTried[nPos]];
|
||||
if (GetRandInt(1<<30) < fChanceFactor*info.GetChance()*(1<<30))
|
||||
CAddrInfo& info = mapInfo[vTried[nPos]];
|
||||
if (GetRandInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30))
|
||||
return info;
|
||||
fChanceFactor *= 1.2;
|
||||
}
|
||||
} else {
|
||||
// use a new node
|
||||
double fChanceFactor = 1.0;
|
||||
while(1)
|
||||
{
|
||||
while (1) {
|
||||
int nUBucket = GetRandInt(vvNew.size());
|
||||
std::set<int> &vNew = vvNew[nUBucket];
|
||||
if (vNew.size() == 0) continue;
|
||||
std::set<int>& vNew = vvNew[nUBucket];
|
||||
if (vNew.size() == 0)
|
||||
continue;
|
||||
int nPos = GetRandInt(vNew.size());
|
||||
std::set<int>::iterator it = vNew.begin();
|
||||
while (nPos--)
|
||||
it++;
|
||||
assert(mapInfo.count(*it) == 1);
|
||||
CAddrInfo &info = mapInfo[*it];
|
||||
if (GetRandInt(1<<30) < fChanceFactor*info.GetChance()*(1<<30))
|
||||
CAddrInfo& info = mapInfo[*it];
|
||||
if (GetRandInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30))
|
||||
return info;
|
||||
fChanceFactor *= 1.2;
|
||||
}
|
||||
|
@ -436,69 +424,76 @@ int CAddrMan::Check_()
|
|||
std::set<int> setTried;
|
||||
std::map<int, int> mapNew;
|
||||
|
||||
if (vRandom.size() != nTried + nNew) return -7;
|
||||
if (vRandom.size() != nTried + nNew)
|
||||
return -7;
|
||||
|
||||
for (std::map<int, CAddrInfo>::iterator it = mapInfo.begin(); it != mapInfo.end(); it++)
|
||||
{
|
||||
for (std::map<int, CAddrInfo>::iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {
|
||||
int n = (*it).first;
|
||||
CAddrInfo &info = (*it).second;
|
||||
if (info.fInTried)
|
||||
{
|
||||
|
||||
if (!info.nLastSuccess) return -1;
|
||||
if (info.nRefCount) return -2;
|
||||
CAddrInfo& info = (*it).second;
|
||||
if (info.fInTried) {
|
||||
if (!info.nLastSuccess)
|
||||
return -1;
|
||||
if (info.nRefCount)
|
||||
return -2;
|
||||
setTried.insert(n);
|
||||
} else {
|
||||
if (info.nRefCount < 0 || info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS) return -3;
|
||||
if (!info.nRefCount) return -4;
|
||||
if (info.nRefCount < 0 || info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
|
||||
return -3;
|
||||
if (!info.nRefCount)
|
||||
return -4;
|
||||
mapNew[n] = info.nRefCount;
|
||||
}
|
||||
if (mapAddr[info] != n) return -5;
|
||||
if (info.nRandomPos<0 || info.nRandomPos>=vRandom.size() || vRandom[info.nRandomPos] != n) return -14;
|
||||
if (info.nLastTry < 0) return -6;
|
||||
if (info.nLastSuccess < 0) return -8;
|
||||
if (mapAddr[info] != n)
|
||||
return -5;
|
||||
if (info.nRandomPos < 0 || info.nRandomPos >= vRandom.size() || vRandom[info.nRandomPos] != n)
|
||||
return -14;
|
||||
if (info.nLastTry < 0)
|
||||
return -6;
|
||||
if (info.nLastSuccess < 0)
|
||||
return -8;
|
||||
}
|
||||
|
||||
if (setTried.size() != nTried) return -9;
|
||||
if (mapNew.size() != nNew) return -10;
|
||||
if (setTried.size() != nTried)
|
||||
return -9;
|
||||
if (mapNew.size() != nNew)
|
||||
return -10;
|
||||
|
||||
for (int n=0; n<vvTried.size(); n++)
|
||||
{
|
||||
std::vector<int> &vTried = vvTried[n];
|
||||
for (std::vector<int>::iterator it = vTried.begin(); it != vTried.end(); it++)
|
||||
{
|
||||
if (!setTried.count(*it)) return -11;
|
||||
for (int n = 0; n < vvTried.size(); n++) {
|
||||
std::vector<int>& vTried = vvTried[n];
|
||||
for (std::vector<int>::iterator it = vTried.begin(); it != vTried.end(); it++) {
|
||||
if (!setTried.count(*it))
|
||||
return -11;
|
||||
setTried.erase(*it);
|
||||
}
|
||||
}
|
||||
|
||||
for (int n=0; n<vvNew.size(); n++)
|
||||
{
|
||||
std::set<int> &vNew = vvNew[n];
|
||||
for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++)
|
||||
{
|
||||
if (!mapNew.count(*it)) return -12;
|
||||
for (int n = 0; n < vvNew.size(); n++) {
|
||||
std::set<int>& vNew = vvNew[n];
|
||||
for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++) {
|
||||
if (!mapNew.count(*it))
|
||||
return -12;
|
||||
if (--mapNew[*it] == 0)
|
||||
mapNew.erase(*it);
|
||||
}
|
||||
}
|
||||
|
||||
if (setTried.size()) return -13;
|
||||
if (mapNew.size()) return -15;
|
||||
if (setTried.size())
|
||||
return -13;
|
||||
if (mapNew.size())
|
||||
return -15;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void CAddrMan::GetAddr_(std::vector<CAddress> &vAddr)
|
||||
void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr)
|
||||
{
|
||||
unsigned int nNodes = ADDRMAN_GETADDR_MAX_PCT * vRandom.size() / 100;
|
||||
if (nNodes > ADDRMAN_GETADDR_MAX)
|
||||
nNodes = ADDRMAN_GETADDR_MAX;
|
||||
|
||||
// gather a list of random nodes, skipping those of low quality
|
||||
for (unsigned int n = 0; n < vRandom.size(); n++)
|
||||
{
|
||||
for (unsigned int n = 0; n < vRandom.size(); n++) {
|
||||
if (vAddr.size() >= nNodes)
|
||||
break;
|
||||
|
||||
|
@ -512,15 +507,15 @@ void CAddrMan::GetAddr_(std::vector<CAddress> &vAddr)
|
|||
}
|
||||
}
|
||||
|
||||
void CAddrMan::Connected_(const CService &addr, int64_t nTime)
|
||||
void CAddrMan::Connected_(const CService& addr, int64_t nTime)
|
||||
{
|
||||
CAddrInfo *pinfo = Find(addr);
|
||||
CAddrInfo* pinfo = Find(addr);
|
||||
|
||||
// if not found, bail out
|
||||
if (!pinfo)
|
||||
return;
|
||||
|
||||
CAddrInfo &info = *pinfo;
|
||||
CAddrInfo& info = *pinfo;
|
||||
|
||||
// check whether we are talking about the exact same CService (including same port)
|
||||
if (info != addr)
|
||||
|
|
|
@ -37,13 +37,13 @@ static inline size_t GetSystemPageSize()
|
|||
page_size = sSysInfo.dwPageSize;
|
||||
#elif defined(PAGESIZE) // defined in limits.h
|
||||
page_size = PAGESIZE;
|
||||
#else // assume some POSIX OS
|
||||
#else // assume some POSIX OS
|
||||
page_size = sysconf(_SC_PAGESIZE);
|
||||
#endif
|
||||
return page_size;
|
||||
}
|
||||
|
||||
bool MemoryPageLocker::Lock(const void *addr, size_t len)
|
||||
bool MemoryPageLocker::Lock(const void* addr, size_t len)
|
||||
{
|
||||
#ifdef WIN32
|
||||
return VirtualLock(const_cast<void*>(addr), len) != 0;
|
||||
|
@ -52,7 +52,7 @@ bool MemoryPageLocker::Lock(const void *addr, size_t len)
|
|||
#endif
|
||||
}
|
||||
|
||||
bool MemoryPageLocker::Unlock(const void *addr, size_t len)
|
||||
bool MemoryPageLocker::Unlock(const void* addr, size_t len)
|
||||
{
|
||||
#ifdef WIN32
|
||||
return VirtualUnlock(const_cast<void*>(addr), len) != 0;
|
||||
|
@ -64,4 +64,3 @@ bool MemoryPageLocker::Unlock(const void *addr, size_t len)
|
|||
LockedPageManager::LockedPageManager() : LockedPageManagerBase<MemoryPageLocker>(GetSystemPageSize())
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -26,14 +26,14 @@
|
|||
* small objects that span up to a few pages, mostly smaller than a page. To support large allocations,
|
||||
* something like an interval tree would be the preferred data structure.
|
||||
*/
|
||||
template <class Locker> class LockedPageManagerBase
|
||||
template <class Locker>
|
||||
class LockedPageManagerBase
|
||||
{
|
||||
public:
|
||||
LockedPageManagerBase(size_t page_size):
|
||||
page_size(page_size)
|
||||
LockedPageManagerBase(size_t page_size) : page_size(page_size)
|
||||
{
|
||||
// Determine bitmask for extracting page from address
|
||||
assert(!(page_size & (page_size-1))); // size must be power of two
|
||||
assert(!(page_size & (page_size - 1))); // size must be power of two
|
||||
page_mask = ~(page_size - 1);
|
||||
}
|
||||
|
||||
|
@ -44,22 +44,21 @@ public:
|
|||
|
||||
|
||||
// For all pages in affected range, increase lock count
|
||||
void LockRange(void *p, size_t size)
|
||||
void LockRange(void* p, size_t size)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
if(!size) return;
|
||||
if (!size)
|
||||
return;
|
||||
const size_t base_addr = reinterpret_cast<size_t>(p);
|
||||
const size_t start_page = base_addr & page_mask;
|
||||
const size_t end_page = (base_addr + size - 1) & page_mask;
|
||||
for(size_t page = start_page; page <= end_page; page += page_size)
|
||||
{
|
||||
for (size_t page = start_page; page <= end_page; page += page_size) {
|
||||
Histogram::iterator it = histogram.find(page);
|
||||
if(it == histogram.end()) // Newly locked page
|
||||
if (it == histogram.end()) // Newly locked page
|
||||
{
|
||||
locker.Lock(reinterpret_cast<void*>(page), page_size);
|
||||
histogram.insert(std::make_pair(page, 1));
|
||||
}
|
||||
else // Page was already locked; increase counter
|
||||
} else // Page was already locked; increase counter
|
||||
{
|
||||
it->second += 1;
|
||||
}
|
||||
|
@ -67,20 +66,20 @@ public:
|
|||
}
|
||||
|
||||
// For all pages in affected range, decrease lock count
|
||||
void UnlockRange(void *p, size_t size)
|
||||
void UnlockRange(void* p, size_t size)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
if(!size) return;
|
||||
if (!size)
|
||||
return;
|
||||
const size_t base_addr = reinterpret_cast<size_t>(p);
|
||||
const size_t start_page = base_addr & page_mask;
|
||||
const size_t end_page = (base_addr + size - 1) & page_mask;
|
||||
for(size_t page = start_page; page <= end_page; page += page_size)
|
||||
{
|
||||
for (size_t page = start_page; page <= end_page; page += page_size) {
|
||||
Histogram::iterator it = histogram.find(page);
|
||||
assert(it != histogram.end()); // Cannot unlock an area that was not locked
|
||||
// Decrease counter for page, when it is zero, the page will be unlocked
|
||||
it->second -= 1;
|
||||
if(it->second == 0) // Nothing on the page anymore that keeps it locked
|
||||
if (it->second == 0) // Nothing on the page anymore that keeps it locked
|
||||
{
|
||||
// Unlock page and remove the count from histogram
|
||||
locker.Unlock(reinterpret_cast<void*>(page), page_size);
|
||||
|
@ -101,7 +100,7 @@ private:
|
|||
boost::mutex mutex;
|
||||
size_t page_size, page_mask;
|
||||
// map of page base address to lock count
|
||||
typedef std::map<size_t,int> Histogram;
|
||||
typedef std::map<size_t, int> Histogram;
|
||||
Histogram histogram;
|
||||
};
|
||||
|
||||
|
@ -116,11 +115,11 @@ public:
|
|||
/** Lock memory pages.
|
||||
* addr and len must be a multiple of the system page size
|
||||
*/
|
||||
bool Lock(const void *addr, size_t len);
|
||||
bool Lock(const void* addr, size_t len);
|
||||
/** Unlock memory pages.
|
||||
* addr and len must be a multiple of the system page size
|
||||
*/
|
||||
bool Unlock(const void *addr, size_t len);
|
||||
bool Unlock(const void* addr, size_t len);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -134,10 +133,10 @@ public:
|
|||
* secure_allocator are created. So instead of having LockedPageManager also be
|
||||
* static-initialized, it is created on demand.
|
||||
*/
|
||||
class LockedPageManager: public LockedPageManagerBase<MemoryPageLocker>
|
||||
class LockedPageManager : public LockedPageManagerBase<MemoryPageLocker>
|
||||
{
|
||||
public:
|
||||
static LockedPageManager& Instance()
|
||||
static LockedPageManager& Instance()
|
||||
{
|
||||
boost::call_once(LockedPageManager::CreateInstance, LockedPageManager::init_flag);
|
||||
return *LockedPageManager::_instance;
|
||||
|
@ -165,11 +164,15 @@ private:
|
|||
// Functions for directly locking/unlocking memory objects.
|
||||
// Intended for non-dynamically allocated structures.
|
||||
//
|
||||
template<typename T> void LockObject(const T &t) {
|
||||
template <typename T>
|
||||
void LockObject(const T& t)
|
||||
{
|
||||
LockedPageManager::Instance().LockRange((void*)(&t), sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T> void UnlockObject(const T &t) {
|
||||
template <typename T>
|
||||
void UnlockObject(const T& t)
|
||||
{
|
||||
OPENSSL_cleanse((void*)(&t), sizeof(T));
|
||||
LockedPageManager::Instance().UnlockRange((void*)(&t), sizeof(T));
|
||||
}
|
||||
|
@ -178,13 +181,12 @@ template<typename T> void UnlockObject(const T &t) {
|
|||
// Allocator that locks its contents from being paged
|
||||
// out of memory and clears its contents before deletion.
|
||||
//
|
||||
template<typename T>
|
||||
struct secure_allocator : public std::allocator<T>
|
||||
{
|
||||
template <typename T>
|
||||
struct secure_allocator : public std::allocator<T> {
|
||||
// MSVC8 default copy constructor is broken
|
||||
typedef std::allocator<T> base;
|
||||
typedef typename base::size_type size_type;
|
||||
typedef typename base::difference_type difference_type;
|
||||
typedef typename base::difference_type difference_type;
|
||||
typedef typename base::pointer pointer;
|
||||
typedef typename base::const_pointer const_pointer;
|
||||
typedef typename base::reference reference;
|
||||
|
@ -193,14 +195,18 @@ struct secure_allocator : public std::allocator<T>
|
|||
secure_allocator() throw() {}
|
||||
secure_allocator(const secure_allocator& a) throw() : base(a) {}
|
||||
template <typename U>
|
||||
secure_allocator(const secure_allocator<U>& a) throw() : base(a) {}
|
||||
~secure_allocator() throw() {}
|
||||
template<typename _Other> struct rebind
|
||||
{ typedef secure_allocator<_Other> other; };
|
||||
|
||||
T* allocate(std::size_t n, const void *hint = 0)
|
||||
secure_allocator(const secure_allocator<U>& a) throw() : base(a)
|
||||
{
|
||||
T *p;
|
||||
}
|
||||
~secure_allocator() throw() {}
|
||||
template <typename _Other>
|
||||
struct rebind {
|
||||
typedef secure_allocator<_Other> other;
|
||||
};
|
||||
|
||||
T* allocate(std::size_t n, const void* hint = 0)
|
||||
{
|
||||
T* p;
|
||||
p = std::allocator<T>::allocate(n, hint);
|
||||
if (p != NULL)
|
||||
LockedPageManager::Instance().LockRange(p, sizeof(T) * n);
|
||||
|
@ -209,8 +215,7 @@ struct secure_allocator : public std::allocator<T>
|
|||
|
||||
void deallocate(T* p, std::size_t n)
|
||||
{
|
||||
if (p != NULL)
|
||||
{
|
||||
if (p != NULL) {
|
||||
OPENSSL_cleanse(p, sizeof(T) * n);
|
||||
LockedPageManager::Instance().UnlockRange(p, sizeof(T) * n);
|
||||
}
|
||||
|
@ -222,13 +227,12 @@ struct secure_allocator : public std::allocator<T>
|
|||
//
|
||||
// Allocator that clears its contents before deletion.
|
||||
//
|
||||
template<typename T>
|
||||
struct zero_after_free_allocator : public std::allocator<T>
|
||||
{
|
||||
template <typename T>
|
||||
struct zero_after_free_allocator : public std::allocator<T> {
|
||||
// MSVC8 default copy constructor is broken
|
||||
typedef std::allocator<T> base;
|
||||
typedef typename base::size_type size_type;
|
||||
typedef typename base::difference_type difference_type;
|
||||
typedef typename base::difference_type difference_type;
|
||||
typedef typename base::pointer pointer;
|
||||
typedef typename base::const_pointer const_pointer;
|
||||
typedef typename base::reference reference;
|
||||
|
@ -237,10 +241,14 @@ struct zero_after_free_allocator : public std::allocator<T>
|
|||
zero_after_free_allocator() throw() {}
|
||||
zero_after_free_allocator(const zero_after_free_allocator& a) throw() : base(a) {}
|
||||
template <typename U>
|
||||
zero_after_free_allocator(const zero_after_free_allocator<U>& a) throw() : base(a) {}
|
||||
zero_after_free_allocator(const zero_after_free_allocator<U>& a) throw() : base(a)
|
||||
{
|
||||
}
|
||||
~zero_after_free_allocator() throw() {}
|
||||
template<typename _Other> struct rebind
|
||||
{ typedef zero_after_free_allocator<_Other> other; };
|
||||
template <typename _Other>
|
||||
struct rebind {
|
||||
typedef zero_after_free_allocator<_Other> other;
|
||||
};
|
||||
|
||||
void deallocate(T* p, std::size_t n)
|
||||
{
|
||||
|
|
129
src/base58.cpp
129
src/base58.cpp
|
@ -18,7 +18,8 @@
|
|||
/* All alphanumeric characters except for "0", "I", "O", and "l" */
|
||||
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
|
||||
bool DecodeBase58(const char *psz, std::vector<unsigned char>& vch) {
|
||||
bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)
|
||||
{
|
||||
// Skip leading spaces.
|
||||
while (*psz && isspace(*psz))
|
||||
psz++;
|
||||
|
@ -33,7 +34,7 @@ bool DecodeBase58(const char *psz, std::vector<unsigned char>& vch) {
|
|||
// Process the characters.
|
||||
while (*psz && !isspace(*psz)) {
|
||||
// Decode base58 character
|
||||
const char *ch = strchr(pszBase58, *psz);
|
||||
const char* ch = strchr(pszBase58, *psz);
|
||||
if (ch == NULL)
|
||||
return false;
|
||||
// Apply "b256 = b256 * 58 + ch".
|
||||
|
@ -59,11 +60,12 @@ bool DecodeBase58(const char *psz, std::vector<unsigned char>& vch) {
|
|||
vch.reserve(zeroes + (b256.end() - it));
|
||||
vch.assign(zeroes, 0x00);
|
||||
while (it != b256.end())
|
||||
vch.push_back(*(it++));
|
||||
vch.push_back(*(it++));
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) {
|
||||
std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
|
||||
{
|
||||
// Skip & count leading zeroes.
|
||||
int zeroes = 0;
|
||||
while (pbegin != pend && *pbegin == 0) {
|
||||
|
@ -97,15 +99,18 @@ std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
|
|||
return str;
|
||||
}
|
||||
|
||||
std::string EncodeBase58(const std::vector<unsigned char>& vch) {
|
||||
std::string EncodeBase58(const std::vector<unsigned char>& vch)
|
||||
{
|
||||
return EncodeBase58(&vch[0], &vch[0] + vch.size());
|
||||
}
|
||||
|
||||
bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet) {
|
||||
bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
|
||||
{
|
||||
return DecodeBase58(str.c_str(), vchRet);
|
||||
}
|
||||
|
||||
std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn) {
|
||||
std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)
|
||||
{
|
||||
// add 4-byte hash check to the end
|
||||
std::vector<unsigned char> vch(vchIn);
|
||||
uint256 hash = Hash(vch.begin(), vch.end());
|
||||
|
@ -113,45 +118,49 @@ std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn) {
|
|||
return EncodeBase58(vch);
|
||||
}
|
||||
|
||||
bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet) {
|
||||
bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)
|
||||
{
|
||||
if (!DecodeBase58(psz, vchRet) ||
|
||||
(vchRet.size() < 4))
|
||||
{
|
||||
(vchRet.size() < 4)) {
|
||||
vchRet.clear();
|
||||
return false;
|
||||
}
|
||||
// re-calculate the checksum, insure it matches the included 4-byte checksum
|
||||
uint256 hash = Hash(vchRet.begin(), vchRet.end()-4);
|
||||
if (memcmp(&hash, &vchRet.end()[-4], 4) != 0)
|
||||
{
|
||||
uint256 hash = Hash(vchRet.begin(), vchRet.end() - 4);
|
||||
if (memcmp(&hash, &vchRet.end()[-4], 4) != 0) {
|
||||
vchRet.clear();
|
||||
return false;
|
||||
}
|
||||
vchRet.resize(vchRet.size()-4);
|
||||
vchRet.resize(vchRet.size() - 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet) {
|
||||
bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet)
|
||||
{
|
||||
return DecodeBase58Check(str.c_str(), vchRet);
|
||||
}
|
||||
|
||||
CBase58Data::CBase58Data() {
|
||||
CBase58Data::CBase58Data()
|
||||
{
|
||||
vchVersion.clear();
|
||||
vchData.clear();
|
||||
}
|
||||
|
||||
void CBase58Data::SetData(const std::vector<unsigned char> &vchVersionIn, const void* pdata, size_t nSize) {
|
||||
void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const void* pdata, size_t nSize)
|
||||
{
|
||||
vchVersion = vchVersionIn;
|
||||
vchData.resize(nSize);
|
||||
if (!vchData.empty())
|
||||
memcpy(&vchData[0], pdata, nSize);
|
||||
}
|
||||
|
||||
void CBase58Data::SetData(const std::vector<unsigned char> &vchVersionIn, const unsigned char *pbegin, const unsigned char *pend) {
|
||||
void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const unsigned char* pbegin, const unsigned char* pend)
|
||||
{
|
||||
SetData(vchVersionIn, (void*)pbegin, pend - pbegin);
|
||||
}
|
||||
|
||||
bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes) {
|
||||
bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes)
|
||||
{
|
||||
std::vector<unsigned char> vchTemp;
|
||||
bool rc58 = DecodeBase58Check(psz, vchTemp);
|
||||
if ((!rc58) || (vchTemp.size() < nVersionBytes)) {
|
||||
|
@ -167,65 +176,80 @@ bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CBase58Data::SetString(const std::string& str) {
|
||||
bool CBase58Data::SetString(const std::string& str)
|
||||
{
|
||||
return SetString(str.c_str());
|
||||
}
|
||||
|
||||
std::string CBase58Data::ToString() const {
|
||||
std::string CBase58Data::ToString() const
|
||||
{
|
||||
std::vector<unsigned char> vch = vchVersion;
|
||||
vch.insert(vch.end(), vchData.begin(), vchData.end());
|
||||
return EncodeBase58Check(vch);
|
||||
}
|
||||
|
||||
int CBase58Data::CompareTo(const CBase58Data& b58) const {
|
||||
if (vchVersion < b58.vchVersion) return -1;
|
||||
if (vchVersion > b58.vchVersion) return 1;
|
||||
if (vchData < b58.vchData) return -1;
|
||||
if (vchData > b58.vchData) return 1;
|
||||
int CBase58Data::CompareTo(const CBase58Data& b58) const
|
||||
{
|
||||
if (vchVersion < b58.vchVersion)
|
||||
return -1;
|
||||
if (vchVersion > b58.vchVersion)
|
||||
return 1;
|
||||
if (vchData < b58.vchData)
|
||||
return -1;
|
||||
if (vchData > b58.vchData)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace {
|
||||
namespace
|
||||
{
|
||||
class CBitcoinAddressVisitor : public boost::static_visitor<bool>
|
||||
{
|
||||
private:
|
||||
CBitcoinAddress* addr;
|
||||
|
||||
class CBitcoinAddressVisitor : public boost::static_visitor<bool> {
|
||||
private:
|
||||
CBitcoinAddress *addr;
|
||||
public:
|
||||
CBitcoinAddressVisitor(CBitcoinAddress *addrIn) : addr(addrIn) { }
|
||||
public:
|
||||
CBitcoinAddressVisitor(CBitcoinAddress* addrIn) : addr(addrIn) {}
|
||||
|
||||
bool operator()(const CKeyID &id) const { return addr->Set(id); }
|
||||
bool operator()(const CScriptID &id) const { return addr->Set(id); }
|
||||
bool operator()(const CNoDestination &no) const { return false; }
|
||||
};
|
||||
bool operator()(const CKeyID& id) const { return addr->Set(id); }
|
||||
bool operator()(const CScriptID& id) const { return addr->Set(id); }
|
||||
bool operator()(const CNoDestination& no) const { return false; }
|
||||
};
|
||||
|
||||
} // anon namespace
|
||||
|
||||
bool CBitcoinAddress::Set(const CKeyID &id) {
|
||||
bool CBitcoinAddress::Set(const CKeyID& id)
|
||||
{
|
||||
SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBitcoinAddress::Set(const CScriptID &id) {
|
||||
bool CBitcoinAddress::Set(const CScriptID& id)
|
||||
{
|
||||
SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBitcoinAddress::Set(const CTxDestination &dest) {
|
||||
bool CBitcoinAddress::Set(const CTxDestination& dest)
|
||||
{
|
||||
return boost::apply_visitor(CBitcoinAddressVisitor(this), dest);
|
||||
}
|
||||
|
||||
bool CBitcoinAddress::IsValid() const {
|
||||
bool CBitcoinAddress::IsValid() const
|
||||
{
|
||||
return IsValid(Params());
|
||||
}
|
||||
|
||||
bool CBitcoinAddress::IsValid(const CChainParams ¶ms) const {
|
||||
bool CBitcoinAddress::IsValid(const CChainParams& params) const
|
||||
{
|
||||
bool fCorrectSize = vchData.size() == 20;
|
||||
bool fKnownVersion = vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS) ||
|
||||
vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
|
||||
return fCorrectSize && fKnownVersion;
|
||||
}
|
||||
|
||||
CTxDestination CBitcoinAddress::Get() const {
|
||||
CTxDestination CBitcoinAddress::Get() const
|
||||
{
|
||||
if (!IsValid())
|
||||
return CNoDestination();
|
||||
uint160 id;
|
||||
|
@ -238,7 +262,8 @@ CTxDestination CBitcoinAddress::Get() const {
|
|||
return CNoDestination();
|
||||
}
|
||||
|
||||
bool CBitcoinAddress::GetKeyID(CKeyID &keyID) const {
|
||||
bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const
|
||||
{
|
||||
if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
|
||||
return false;
|
||||
uint160 id;
|
||||
|
@ -247,33 +272,39 @@ bool CBitcoinAddress::GetKeyID(CKeyID &keyID) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CBitcoinAddress::IsScript() const {
|
||||
bool CBitcoinAddress::IsScript() const
|
||||
{
|
||||
return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
|
||||
}
|
||||
|
||||
void CBitcoinSecret::SetKey(const CKey& vchSecret) {
|
||||
void CBitcoinSecret::SetKey(const CKey& vchSecret)
|
||||
{
|
||||
assert(vchSecret.IsValid());
|
||||
SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size());
|
||||
if (vchSecret.IsCompressed())
|
||||
vchData.push_back(1);
|
||||
}
|
||||
|
||||
CKey CBitcoinSecret::GetKey() {
|
||||
CKey CBitcoinSecret::GetKey()
|
||||
{
|
||||
CKey ret;
|
||||
ret.Set(&vchData[0], &vchData[32], vchData.size() > 32 && vchData[32] == 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CBitcoinSecret::IsValid() const {
|
||||
bool CBitcoinSecret::IsValid() const
|
||||
{
|
||||
bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1);
|
||||
bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY);
|
||||
return fExpectedFormat && fCorrectVersion;
|
||||
}
|
||||
|
||||
bool CBitcoinSecret::SetString(const char* pszSecret) {
|
||||
bool CBitcoinSecret::SetString(const char* pszSecret)
|
||||
{
|
||||
return CBase58Data::SetString(pszSecret) && IsValid();
|
||||
}
|
||||
|
||||
bool CBitcoinSecret::SetString(const std::string& strSecret) {
|
||||
bool CBitcoinSecret::SetString(const std::string& strSecret)
|
||||
{
|
||||
return SetString(strSecret.c_str());
|
||||
}
|
||||
|
|
|
@ -17,9 +17,11 @@ using namespace boost::assign;
|
|||
// Main network
|
||||
//
|
||||
|
||||
class CBaseMainParams : public CBaseChainParams {
|
||||
class CBaseMainParams : public CBaseChainParams
|
||||
{
|
||||
public:
|
||||
CBaseMainParams() {
|
||||
CBaseMainParams()
|
||||
{
|
||||
networkID = CBaseChainParams::MAIN;
|
||||
nRPCPort = 8332;
|
||||
}
|
||||
|
@ -29,9 +31,11 @@ static CBaseMainParams mainParams;
|
|||
//
|
||||
// Testnet (v3)
|
||||
//
|
||||
class CBaseTestNetParams : public CBaseMainParams {
|
||||
class CBaseTestNetParams : public CBaseMainParams
|
||||
{
|
||||
public:
|
||||
CBaseTestNetParams() {
|
||||
CBaseTestNetParams()
|
||||
{
|
||||
networkID = CBaseChainParams::TESTNET;
|
||||
nRPCPort = 18332;
|
||||
strDataDir = "testnet3";
|
||||
|
@ -42,40 +46,45 @@ static CBaseTestNetParams testNetParams;
|
|||
//
|
||||
// Regression test
|
||||
//
|
||||
class CBaseRegTestParams : public CBaseTestNetParams {
|
||||
class CBaseRegTestParams : public CBaseTestNetParams
|
||||
{
|
||||
public:
|
||||
CBaseRegTestParams() {
|
||||
CBaseRegTestParams()
|
||||
{
|
||||
networkID = CBaseChainParams::REGTEST;
|
||||
strDataDir = "regtest";
|
||||
}
|
||||
};
|
||||
static CBaseRegTestParams regTestParams;
|
||||
|
||||
static CBaseChainParams *pCurrentBaseParams = 0;
|
||||
static CBaseChainParams* pCurrentBaseParams = 0;
|
||||
|
||||
const CBaseChainParams &BaseParams() {
|
||||
const CBaseChainParams& BaseParams()
|
||||
{
|
||||
assert(pCurrentBaseParams);
|
||||
return *pCurrentBaseParams;
|
||||
}
|
||||
|
||||
void SelectBaseParams(CBaseChainParams::Network network) {
|
||||
void SelectBaseParams(CBaseChainParams::Network network)
|
||||
{
|
||||
switch (network) {
|
||||
case CBaseChainParams::MAIN:
|
||||
pCurrentBaseParams = &mainParams;
|
||||
break;
|
||||
case CBaseChainParams::TESTNET:
|
||||
pCurrentBaseParams = &testNetParams;
|
||||
break;
|
||||
case CBaseChainParams::REGTEST:
|
||||
pCurrentBaseParams = ®TestParams;
|
||||
break;
|
||||
default:
|
||||
assert(false && "Unimplemented network");
|
||||
return;
|
||||
case CBaseChainParams::MAIN:
|
||||
pCurrentBaseParams = &mainParams;
|
||||
break;
|
||||
case CBaseChainParams::TESTNET:
|
||||
pCurrentBaseParams = &testNetParams;
|
||||
break;
|
||||
case CBaseChainParams::REGTEST:
|
||||
pCurrentBaseParams = ®TestParams;
|
||||
break;
|
||||
default:
|
||||
assert(false && "Unimplemented network");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool SelectBaseParamsFromCommandLine() {
|
||||
bool SelectBaseParamsFromCommandLine()
|
||||
{
|
||||
bool fRegTest = GetBoolArg("-regtest", false);
|
||||
bool fTestNet = GetBoolArg("-testnet", false);
|
||||
|
||||
|
@ -93,6 +102,7 @@ bool SelectBaseParamsFromCommandLine() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool AreBaseParamsConfigured() {
|
||||
bool AreBaseParamsConfigured()
|
||||
{
|
||||
return pCurrentBaseParams != NULL;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ public:
|
|||
const std::string& DataDir() const { return strDataDir; }
|
||||
int RPCPort() const { return nRPCPort; }
|
||||
Network NetworkID() const { return networkID; }
|
||||
|
||||
protected:
|
||||
CBaseChainParams() {}
|
||||
|
||||
|
@ -38,7 +39,7 @@ protected:
|
|||
* Return the currently selected parameters. This won't change after app startup
|
||||
* outside of the unit tests.
|
||||
*/
|
||||
const CBaseChainParams &BaseParams();
|
||||
const CBaseChainParams& BaseParams();
|
||||
|
||||
/** Sets the params returned by Params() to those for the given network. */
|
||||
void SelectBaseParams(CBaseChainParams::Network network);
|
||||
|
|
|
@ -13,20 +13,20 @@ class uint256;
|
|||
/** Block-chain checkpoints are compiled-in sanity checks.
|
||||
* They are updated every release or three.
|
||||
*/
|
||||
namespace Checkpoints {
|
||||
namespace Checkpoints
|
||||
{
|
||||
// Returns true if block passes checkpoint checks
|
||||
bool CheckBlock(int nHeight, const uint256& hash);
|
||||
|
||||
// Returns true if block passes checkpoint checks
|
||||
bool CheckBlock(int nHeight, const uint256& hash);
|
||||
// Return conservative estimate of total number of blocks, 0 if unknown
|
||||
int GetTotalBlocksEstimate();
|
||||
|
||||
// Return conservative estimate of total number of blocks, 0 if unknown
|
||||
int GetTotalBlocksEstimate();
|
||||
// Returns last CBlockIndex* in mapBlockIndex that is a checkpoint
|
||||
CBlockIndex* GetLastCheckpoint();
|
||||
|
||||
// Returns last CBlockIndex* in mapBlockIndex that is a checkpoint
|
||||
CBlockIndex* GetLastCheckpoint();
|
||||
double GuessVerificationProgress(CBlockIndex* pindex, bool fSigchecks = true);
|
||||
|
||||
double GuessVerificationProgress(CBlockIndex *pindex, bool fSigchecks = true);
|
||||
|
||||
extern bool fEnabled;
|
||||
extern bool fEnabled;
|
||||
|
||||
} //namespace Checkpoints
|
||||
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
template<typename T> class CCheckQueueControl;
|
||||
template <typename T>
|
||||
class CCheckQueueControl;
|
||||
|
||||
/** Queue for verifications that have to be performed.
|
||||
* The verifications are represented by a type T, which must provide an
|
||||
|
@ -24,7 +25,9 @@ template<typename T> class CCheckQueueControl;
|
|||
* the master is done adding work, it temporarily joins the worker pool
|
||||
* as an N'th worker, until all jobs are done.
|
||||
*/
|
||||
template<typename T> class CCheckQueue {
|
||||
template <typename T>
|
||||
class CCheckQueue
|
||||
{
|
||||
private:
|
||||
// Mutex to protect the inner state
|
||||
boost::mutex mutex;
|
||||
|
@ -60,8 +63,9 @@ private:
|
|||
unsigned int nBatchSize;
|
||||
|
||||
// Internal function that does bulk of the verification work.
|
||||
bool Loop(bool fMaster = false) {
|
||||
boost::condition_variable &cond = fMaster ? condMaster : condWorker;
|
||||
bool Loop(bool fMaster = false)
|
||||
{
|
||||
boost::condition_variable& cond = fMaster ? condMaster : condWorker;
|
||||
std::vector<T> vChecks;
|
||||
vChecks.reserve(nBatchSize);
|
||||
unsigned int nNow = 0;
|
||||
|
@ -103,41 +107,43 @@ private:
|
|||
nNow = std::max(1U, std::min(nBatchSize, (unsigned int)queue.size() / (nTotal + nIdle + 1)));
|
||||
vChecks.resize(nNow);
|
||||
for (unsigned int i = 0; i < nNow; i++) {
|
||||
// We want the lock on the mutex to be as short as possible, so swap jobs from the global
|
||||
// queue to the local batch vector instead of copying.
|
||||
vChecks[i].swap(queue.back());
|
||||
queue.pop_back();
|
||||
// We want the lock on the mutex to be as short as possible, so swap jobs from the global
|
||||
// queue to the local batch vector instead of copying.
|
||||
vChecks[i].swap(queue.back());
|
||||
queue.pop_back();
|
||||
}
|
||||
// Check whether we need to do work at all
|
||||
fOk = fAllOk;
|
||||
}
|
||||
// execute work
|
||||
BOOST_FOREACH(T &check, vChecks)
|
||||
BOOST_FOREACH (T& check, vChecks)
|
||||
if (fOk)
|
||||
fOk = check();
|
||||
vChecks.clear();
|
||||
} while(true);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
public:
|
||||
// Create a new check queue
|
||||
CCheckQueue(unsigned int nBatchSizeIn) :
|
||||
nIdle(0), nTotal(0), fAllOk(true), nTodo(0), fQuit(false), nBatchSize(nBatchSizeIn) {}
|
||||
CCheckQueue(unsigned int nBatchSizeIn) : nIdle(0), nTotal(0), fAllOk(true), nTodo(0), fQuit(false), nBatchSize(nBatchSizeIn) {}
|
||||
|
||||
// Worker thread
|
||||
void Thread() {
|
||||
void Thread()
|
||||
{
|
||||
Loop();
|
||||
}
|
||||
|
||||
// Wait until execution finishes, and return whether all evaluations where succesful.
|
||||
bool Wait() {
|
||||
bool Wait()
|
||||
{
|
||||
return Loop(true);
|
||||
}
|
||||
|
||||
// Add a batch of checks to the queue
|
||||
void Add(std::vector<T> &vChecks) {
|
||||
void Add(std::vector<T>& vChecks)
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(mutex);
|
||||
BOOST_FOREACH(T &check, vChecks) {
|
||||
BOOST_FOREACH (T& check, vChecks) {
|
||||
queue.push_back(T());
|
||||
check.swap(queue.back());
|
||||
}
|
||||
|
@ -148,7 +154,8 @@ public:
|
|||
condWorker.notify_all();
|
||||
}
|
||||
|
||||
~CCheckQueue() {
|
||||
~CCheckQueue()
|
||||
{
|
||||
}
|
||||
|
||||
friend class CCheckQueueControl<T>;
|
||||
|
@ -157,13 +164,16 @@ public:
|
|||
/** RAII-style controller object for a CCheckQueue that guarantees the passed
|
||||
* queue is finished before continuing.
|
||||
*/
|
||||
template<typename T> class CCheckQueueControl {
|
||||
template <typename T>
|
||||
class CCheckQueueControl
|
||||
{
|
||||
private:
|
||||
CCheckQueue<T> *pqueue;
|
||||
CCheckQueue<T>* pqueue;
|
||||
bool fDone;
|
||||
|
||||
public:
|
||||
CCheckQueueControl(CCheckQueue<T> *pqueueIn) : pqueue(pqueueIn), fDone(false) {
|
||||
CCheckQueueControl(CCheckQueue<T>* pqueueIn) : pqueue(pqueueIn), fDone(false)
|
||||
{
|
||||
// passed queue is supposed to be unused, or NULL
|
||||
if (pqueue != NULL) {
|
||||
assert(pqueue->nTotal == pqueue->nIdle);
|
||||
|
@ -172,7 +182,8 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
bool Wait() {
|
||||
bool Wait()
|
||||
{
|
||||
if (pqueue == NULL)
|
||||
return true;
|
||||
bool fRet = pqueue->Wait();
|
||||
|
@ -180,12 +191,14 @@ public:
|
|||
return fRet;
|
||||
}
|
||||
|
||||
void Add(std::vector<T> &vChecks) {
|
||||
void Add(std::vector<T>& vChecks)
|
||||
{
|
||||
if (pqueue != NULL)
|
||||
pqueue->Add(vChecks);
|
||||
}
|
||||
|
||||
~CCheckQueueControl() {
|
||||
~CCheckQueueControl()
|
||||
{
|
||||
if (!fDone)
|
||||
Wait();
|
||||
}
|
||||
|
|
|
@ -13,13 +13,13 @@
|
|||
//
|
||||
|
||||
// These need to be macros, as version.cpp's and bitcoin*-res.rc's voodoo requires it
|
||||
#define CLIENT_VERSION_MAJOR 0
|
||||
#define CLIENT_VERSION_MINOR 9
|
||||
#define CLIENT_VERSION_REVISION 99
|
||||
#define CLIENT_VERSION_BUILD 0
|
||||
#define CLIENT_VERSION_MAJOR 0
|
||||
#define CLIENT_VERSION_MINOR 9
|
||||
#define CLIENT_VERSION_REVISION 99
|
||||
#define CLIENT_VERSION_BUILD 0
|
||||
|
||||
// Set to true for release, false for prerelease or test build
|
||||
#define CLIENT_VERSION_IS_RELEASE false
|
||||
#define CLIENT_VERSION_IS_RELEASE false
|
||||
|
||||
// Copyright year (2009-this)
|
||||
// Todo: update this when changing our copyright comments in the source
|
||||
|
@ -33,6 +33,6 @@
|
|||
#define DO_STRINGIZE(X) #X
|
||||
|
||||
// Copyright string used in Windows .rc files
|
||||
#define COPYRIGHT_STR "2009-" STRINGIZE(COPYRIGHT_YEAR) " The Bitcoin Core Developers"
|
||||
#define COPYRIGHT_STR "2009-" STRINGIZE(COPYRIGHT_YEAR) " The Bitcoin Core Developers"
|
||||
|
||||
#endif // CLIENTVERSION_H
|
||||
|
|
|
@ -57,7 +57,6 @@ public:
|
|||
|
||||
private:
|
||||
std::set<COutPoint> setSelected;
|
||||
|
||||
};
|
||||
|
||||
#endif // COINCONTROL_H
|
||||
|
|
144
src/db.cpp
144
src/db.cpp
|
@ -30,7 +30,6 @@ using namespace boost;
|
|||
unsigned int nWalletDBUpdated;
|
||||
|
||||
|
||||
|
||||
//
|
||||
// CDB
|
||||
//
|
||||
|
@ -94,15 +93,15 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn)
|
|||
dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1);
|
||||
dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1);
|
||||
int ret = dbenv.open(path.string().c_str(),
|
||||
DB_CREATE |
|
||||
DB_INIT_LOCK |
|
||||
DB_INIT_LOG |
|
||||
DB_INIT_MPOOL |
|
||||
DB_INIT_TXN |
|
||||
DB_THREAD |
|
||||
DB_RECOVER |
|
||||
nEnvFlags,
|
||||
S_IRUSR | S_IWUSR);
|
||||
DB_CREATE |
|
||||
DB_INIT_LOCK |
|
||||
DB_INIT_LOG |
|
||||
DB_INIT_MPOOL |
|
||||
DB_INIT_TXN |
|
||||
DB_THREAD |
|
||||
DB_RECOVER |
|
||||
nEnvFlags,
|
||||
S_IRUSR | S_IWUSR);
|
||||
if (ret != 0)
|
||||
return error("CDBEnv::Open : Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret));
|
||||
|
||||
|
@ -121,21 +120,21 @@ void CDBEnv::MakeMock()
|
|||
LogPrint("db", "CDBEnv::MakeMock\n");
|
||||
|
||||
dbenv.set_cachesize(1, 0, 1);
|
||||
dbenv.set_lg_bsize(10485760*4);
|
||||
dbenv.set_lg_bsize(10485760 * 4);
|
||||
dbenv.set_lg_max(10485760);
|
||||
dbenv.set_lk_max_locks(10000);
|
||||
dbenv.set_lk_max_objects(10000);
|
||||
dbenv.set_flags(DB_AUTO_COMMIT, 1);
|
||||
dbenv.log_set_config(DB_LOG_IN_MEMORY, 1);
|
||||
int ret = dbenv.open(NULL,
|
||||
DB_CREATE |
|
||||
DB_INIT_LOCK |
|
||||
DB_INIT_LOG |
|
||||
DB_INIT_MPOOL |
|
||||
DB_INIT_TXN |
|
||||
DB_THREAD |
|
||||
DB_PRIVATE,
|
||||
S_IRUSR | S_IWUSR);
|
||||
DB_CREATE |
|
||||
DB_INIT_LOCK |
|
||||
DB_INIT_LOG |
|
||||
DB_INIT_MPOOL |
|
||||
DB_INIT_TXN |
|
||||
DB_THREAD |
|
||||
DB_PRIVATE,
|
||||
S_IRUSR | S_IWUSR);
|
||||
if (ret > 0)
|
||||
throw runtime_error(strprintf("CDBEnv::MakeMock : Error %d opening database environment.", ret));
|
||||
|
||||
|
@ -160,30 +159,27 @@ CDBEnv::VerifyResult CDBEnv::Verify(std::string strFile, bool (*recoverFunc)(CDB
|
|||
return (fRecovered ? RECOVER_OK : RECOVER_FAIL);
|
||||
}
|
||||
|
||||
bool CDBEnv::Salvage(std::string strFile, bool fAggressive,
|
||||
std::vector<CDBEnv::KeyValPair >& vResult)
|
||||
bool CDBEnv::Salvage(std::string strFile, bool fAggressive, std::vector<CDBEnv::KeyValPair>& vResult)
|
||||
{
|
||||
LOCK(cs_db);
|
||||
assert(mapFileUseCount.count(strFile) == 0);
|
||||
|
||||
u_int32_t flags = DB_SALVAGE;
|
||||
if (fAggressive) flags |= DB_AGGRESSIVE;
|
||||
if (fAggressive)
|
||||
flags |= DB_AGGRESSIVE;
|
||||
|
||||
stringstream strDump;
|
||||
|
||||
Db db(&dbenv, 0);
|
||||
int result = db.verify(strFile.c_str(), NULL, &strDump, flags);
|
||||
if (result == DB_VERIFY_BAD)
|
||||
{
|
||||
if (result == DB_VERIFY_BAD) {
|
||||
LogPrintf("CDBEnv::Salvage : Database salvage found errors, all data may not be recoverable.\n");
|
||||
if (!fAggressive)
|
||||
{
|
||||
if (!fAggressive) {
|
||||
LogPrintf("CDBEnv::Salvage : Rerun with aggressive mode to ignore errors and continue.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (result != 0 && result != DB_VERIFY_BAD)
|
||||
{
|
||||
if (result != 0 && result != DB_VERIFY_BAD) {
|
||||
LogPrintf("CDBEnv::Salvage : Database salvage failed with result %d.\n", result);
|
||||
return false;
|
||||
}
|
||||
|
@ -201,13 +197,11 @@ bool CDBEnv::Salvage(std::string strFile, bool fAggressive,
|
|||
getline(strDump, strLine); // Skip past header
|
||||
|
||||
std::string keyHex, valueHex;
|
||||
while (!strDump.eof() && keyHex != "DATA=END")
|
||||
{
|
||||
while (!strDump.eof() && keyHex != "DATA=END") {
|
||||
getline(strDump, keyHex);
|
||||
if (keyHex != "DATA_END")
|
||||
{
|
||||
if (keyHex != "DATA_END") {
|
||||
getline(strDump, valueHex);
|
||||
vResult.push_back(make_pair(ParseHex(keyHex),ParseHex(valueHex)));
|
||||
vResult.push_back(make_pair(ParseHex(keyHex), ParseHex(valueHex)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,8 +218,7 @@ void CDBEnv::CheckpointLSN(const std::string& strFile)
|
|||
}
|
||||
|
||||
|
||||
CDB::CDB(const std::string& strFilename, const char* pszMode) :
|
||||
pdb(NULL), activeTxn(NULL)
|
||||
CDB::CDB(const std::string& strFilename, const char* pszMode) : pdb(NULL), activeTxn(NULL)
|
||||
{
|
||||
int ret;
|
||||
fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w'));
|
||||
|
@ -245,28 +238,25 @@ CDB::CDB(const std::string& strFilename, const char* pszMode) :
|
|||
strFile = strFilename;
|
||||
++bitdb.mapFileUseCount[strFile];
|
||||
pdb = bitdb.mapDb[strFile];
|
||||
if (pdb == NULL)
|
||||
{
|
||||
if (pdb == NULL) {
|
||||
pdb = new Db(&bitdb.dbenv, 0);
|
||||
|
||||
bool fMockDb = bitdb.IsMock();
|
||||
if (fMockDb)
|
||||
{
|
||||
DbMpoolFile*mpf = pdb->get_mpf();
|
||||
if (fMockDb) {
|
||||
DbMpoolFile* mpf = pdb->get_mpf();
|
||||
ret = mpf->set_flags(DB_MPOOL_NOFILE, 1);
|
||||
if (ret != 0)
|
||||
throw runtime_error(strprintf("CDB : Failed to configure for no temp file backing for database %s", strFile));
|
||||
}
|
||||
|
||||
ret = pdb->open(NULL, // Txn pointer
|
||||
fMockDb ? NULL : strFile.c_str(), // Filename
|
||||
ret = pdb->open(NULL, // Txn pointer
|
||||
fMockDb ? NULL : strFile.c_str(), // Filename
|
||||
fMockDb ? strFile.c_str() : "main", // Logical db name
|
||||
DB_BTREE, // Database type
|
||||
nFlags, // Flags
|
||||
DB_BTREE, // Database type
|
||||
nFlags, // Flags
|
||||
0);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
if (ret != 0) {
|
||||
delete pdb;
|
||||
pdb = NULL;
|
||||
--bitdb.mapFileUseCount[strFile];
|
||||
|
@ -274,8 +264,7 @@ CDB::CDB(const std::string& strFilename, const char* pszMode) :
|
|||
throw runtime_error(strprintf("CDB : Error %d, can't open database %s", ret, strFile));
|
||||
}
|
||||
|
||||
if (fCreate && !Exists(string("version")))
|
||||
{
|
||||
if (fCreate && !Exists(string("version"))) {
|
||||
bool fTmp = fReadOnly;
|
||||
fReadOnly = false;
|
||||
WriteVersion(CLIENT_VERSION);
|
||||
|
@ -297,7 +286,7 @@ void CDB::Flush()
|
|||
if (fReadOnly)
|
||||
nMinutes = 1;
|
||||
|
||||
bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0);
|
||||
bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100) * 1024 : 0, nMinutes, 0);
|
||||
}
|
||||
|
||||
void CDB::Close()
|
||||
|
@ -321,8 +310,7 @@ void CDBEnv::CloseDb(const string& strFile)
|
|||
{
|
||||
{
|
||||
LOCK(cs_db);
|
||||
if (mapDb[strFile] != NULL)
|
||||
{
|
||||
if (mapDb[strFile] != NULL) {
|
||||
// Close the database handle
|
||||
Db* pdb = mapDb[strFile];
|
||||
pdb->close(0);
|
||||
|
@ -343,12 +331,10 @@ bool CDBEnv::RemoveDb(const string& strFile)
|
|||
|
||||
bool CDB::Rewrite(const string& strFile, const char* pszSkip)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
while (true) {
|
||||
{
|
||||
LOCK(bitdb.cs_db);
|
||||
if (!bitdb.mapFileUseCount.count(strFile) || bitdb.mapFileUseCount[strFile] == 0)
|
||||
{
|
||||
if (!bitdb.mapFileUseCount.count(strFile) || bitdb.mapFileUseCount[strFile] == 0) {
|
||||
// Flush log data to the dat file
|
||||
bitdb.CloseDb(strFile);
|
||||
bitdb.CheckpointLSN(strFile);
|
||||
|
@ -361,32 +347,27 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip)
|
|||
CDB db(strFile.c_str(), "r");
|
||||
Db* pdbCopy = new Db(&bitdb.dbenv, 0);
|
||||
|
||||
int ret = pdbCopy->open(NULL, // Txn pointer
|
||||
strFileRes.c_str(), // Filename
|
||||
"main", // Logical db name
|
||||
DB_BTREE, // Database type
|
||||
DB_CREATE, // Flags
|
||||
int ret = pdbCopy->open(NULL, // Txn pointer
|
||||
strFileRes.c_str(), // Filename
|
||||
"main", // Logical db name
|
||||
DB_BTREE, // Database type
|
||||
DB_CREATE, // Flags
|
||||
0);
|
||||
if (ret > 0)
|
||||
{
|
||||
if (ret > 0) {
|
||||
LogPrintf("CDB::Rewrite : Can't create database file %s\n", strFileRes);
|
||||
fSuccess = false;
|
||||
}
|
||||
|
||||
Dbc* pcursor = db.GetCursor();
|
||||
if (pcursor)
|
||||
while (fSuccess)
|
||||
{
|
||||
while (fSuccess) {
|
||||
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
||||
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
|
||||
int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT);
|
||||
if (ret == DB_NOTFOUND)
|
||||
{
|
||||
if (ret == DB_NOTFOUND) {
|
||||
pcursor->close();
|
||||
break;
|
||||
}
|
||||
else if (ret != 0)
|
||||
{
|
||||
} else if (ret != 0) {
|
||||
pcursor->close();
|
||||
fSuccess = false;
|
||||
break;
|
||||
|
@ -394,8 +375,7 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip)
|
|||
if (pszSkip &&
|
||||
strncmp(&ssKey[0], pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0)
|
||||
continue;
|
||||
if (strncmp(&ssKey[0], "\x07version", 8) == 0)
|
||||
{
|
||||
if (strncmp(&ssKey[0], "\x07version", 8) == 0) {
|
||||
// Update version:
|
||||
ssValue.clear();
|
||||
ssValue << CLIENT_VERSION;
|
||||
|
@ -406,8 +386,7 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip)
|
|||
if (ret2 > 0)
|
||||
fSuccess = false;
|
||||
}
|
||||
if (fSuccess)
|
||||
{
|
||||
if (fSuccess) {
|
||||
db.Close();
|
||||
bitdb.CloseDb(strFile);
|
||||
if (pdbCopy->close(0))
|
||||
|
@ -415,8 +394,7 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip)
|
|||
delete pdbCopy;
|
||||
}
|
||||
}
|
||||
if (fSuccess)
|
||||
{
|
||||
if (fSuccess) {
|
||||
Db dbA(&bitdb.dbenv, 0);
|
||||
if (dbA.remove(strFile.c_str(), NULL, 0))
|
||||
fSuccess = false;
|
||||
|
@ -445,13 +423,11 @@ void CDBEnv::Flush(bool fShutdown)
|
|||
{
|
||||
LOCK(cs_db);
|
||||
map<string, int>::iterator mi = mapFileUseCount.begin();
|
||||
while (mi != mapFileUseCount.end())
|
||||
{
|
||||
while (mi != mapFileUseCount.end()) {
|
||||
string strFile = (*mi).first;
|
||||
int nRefCount = (*mi).second;
|
||||
LogPrint("db", "CDBEnv::Flush : Flushing %s (refcount = %d)...\n", strFile, nRefCount);
|
||||
if (nRefCount == 0)
|
||||
{
|
||||
if (nRefCount == 0) {
|
||||
// Move log data to the dat file
|
||||
CloseDb(strFile);
|
||||
LogPrint("db", "CDBEnv::Flush : %s checkpoint\n", strFile);
|
||||
|
@ -461,16 +437,13 @@ void CDBEnv::Flush(bool fShutdown)
|
|||
dbenv.lsn_reset(strFile.c_str(), 0);
|
||||
LogPrint("db", "CDBEnv::Flush : %s closed\n", strFile);
|
||||
mapFileUseCount.erase(mi++);
|
||||
}
|
||||
else
|
||||
} else
|
||||
mi++;
|
||||
}
|
||||
LogPrint("db", "CDBEnv::Flush : Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", GetTimeMillis() - nStart);
|
||||
if (fShutdown)
|
||||
{
|
||||
if (fShutdown) {
|
||||
char** listp;
|
||||
if (mapFileUseCount.empty())
|
||||
{
|
||||
if (mapFileUseCount.empty()) {
|
||||
dbenv.log_archive(&listp, DB_ARCH_REMOVE);
|
||||
Close();
|
||||
if (!fMockDb)
|
||||
|
@ -479,4 +452,3 @@ void CDBEnv::Flush(bool fShutdown)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
33
src/db.h
33
src/db.h
|
@ -54,7 +54,9 @@ public:
|
|||
* This must be called BEFORE strFile is opened.
|
||||
* Returns true if strFile is OK.
|
||||
*/
|
||||
enum VerifyResult { VERIFY_OK, RECOVER_OK, RECOVER_FAIL };
|
||||
enum VerifyResult { VERIFY_OK,
|
||||
RECOVER_OK,
|
||||
RECOVER_FAIL };
|
||||
VerifyResult Verify(std::string strFile, bool (*recoverFunc)(CDBEnv& dbenv, std::string strFile));
|
||||
/*
|
||||
* Salvage data from a file that Verify says is bad.
|
||||
|
@ -66,7 +68,7 @@ public:
|
|||
typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;
|
||||
bool Salvage(std::string strFile, bool fAggressive, std::vector<KeyValPair>& vResult);
|
||||
|
||||
bool Open(const boost::filesystem::path &path);
|
||||
bool Open(const boost::filesystem::path& path);
|
||||
void Close();
|
||||
void Flush(bool fShutdown);
|
||||
void CheckpointLSN(const std::string& strFile);
|
||||
|
@ -74,7 +76,7 @@ public:
|
|||
void CloseDb(const std::string& strFile);
|
||||
bool RemoveDb(const std::string& strFile);
|
||||
|
||||
DbTxn *TxnBegin(int flags=DB_TXN_WRITE_NOSYNC)
|
||||
DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC)
|
||||
{
|
||||
DbTxn* ptxn = NULL;
|
||||
int ret = dbenv.txn_begin(NULL, &ptxn, flags);
|
||||
|
@ -93,10 +95,10 @@ class CDB
|
|||
protected:
|
||||
Db* pdb;
|
||||
std::string strFile;
|
||||
DbTxn *activeTxn;
|
||||
DbTxn* activeTxn;
|
||||
bool fReadOnly;
|
||||
|
||||
explicit CDB(const std::string& strFilename, const char* pszMode="r+");
|
||||
explicit CDB(const std::string& strFilename, const char* pszMode = "r+");
|
||||
~CDB() { Close(); }
|
||||
|
||||
public:
|
||||
|
@ -108,7 +110,7 @@ private:
|
|||
void operator=(const CDB&);
|
||||
|
||||
protected:
|
||||
template<typename K, typename T>
|
||||
template <typename K, typename T>
|
||||
bool Read(const K& key, T& value)
|
||||
{
|
||||
if (!pdb)
|
||||
|
@ -132,8 +134,7 @@ protected:
|
|||
try {
|
||||
CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
|
||||
ssValue >> value;
|
||||
}
|
||||
catch (const std::exception &) {
|
||||
} catch (const std::exception&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -143,8 +144,8 @@ protected:
|
|||
return (ret == 0);
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
bool Write(const K& key, const T& value, bool fOverwrite=true)
|
||||
template <typename K, typename T>
|
||||
bool Write(const K& key, const T& value, bool fOverwrite = true)
|
||||
{
|
||||
if (!pdb)
|
||||
return false;
|
||||
|
@ -172,7 +173,7 @@ protected:
|
|||
return (ret == 0);
|
||||
}
|
||||
|
||||
template<typename K>
|
||||
template <typename K>
|
||||
bool Erase(const K& key)
|
||||
{
|
||||
if (!pdb)
|
||||
|
@ -194,7 +195,7 @@ protected:
|
|||
return (ret == 0 || ret == DB_NOTFOUND);
|
||||
}
|
||||
|
||||
template<typename K>
|
||||
template <typename K>
|
||||
bool Exists(const K& key)
|
||||
{
|
||||
if (!pdb)
|
||||
|
@ -225,18 +226,16 @@ protected:
|
|||
return pcursor;
|
||||
}
|
||||
|
||||
int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags=DB_NEXT)
|
||||
int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags = DB_NEXT)
|
||||
{
|
||||
// Read at cursor
|
||||
Dbt datKey;
|
||||
if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
|
||||
{
|
||||
if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) {
|
||||
datKey.set_data(&ssKey[0]);
|
||||
datKey.set_size(ssKey.size());
|
||||
}
|
||||
Dbt datValue;
|
||||
if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
|
||||
{
|
||||
if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) {
|
||||
datValue.set_data(&ssValue[0]);
|
||||
datValue.set_size(ssValue.size());
|
||||
}
|
||||
|
|
32
src/hash.cpp
32
src/hash.cpp
|
@ -1,6 +1,6 @@
|
|||
#include "hash.h"
|
||||
|
||||
inline uint32_t ROTL32 ( uint32_t x, int8_t r )
|
||||
inline uint32_t ROTL32(uint32_t x, int8_t r)
|
||||
{
|
||||
return (x << r) | (x >> (32 - r));
|
||||
}
|
||||
|
@ -16,33 +16,37 @@ unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char
|
|||
|
||||
//----------
|
||||
// body
|
||||
const uint32_t * blocks = (const uint32_t *)(&vDataToHash[0] + nblocks*4);
|
||||
const uint32_t* blocks = (const uint32_t*)(&vDataToHash[0] + nblocks * 4);
|
||||
|
||||
for(int i = -nblocks; i; i++)
|
||||
{
|
||||
for (int i = -nblocks; i; i++) {
|
||||
uint32_t k1 = blocks[i];
|
||||
|
||||
k1 *= c1;
|
||||
k1 = ROTL32(k1,15);
|
||||
k1 = ROTL32(k1, 15);
|
||||
k1 *= c2;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = ROTL32(h1,13);
|
||||
h1 = h1*5+0xe6546b64;
|
||||
h1 = ROTL32(h1, 13);
|
||||
h1 = h1 * 5 + 0xe6546b64;
|
||||
}
|
||||
|
||||
//----------
|
||||
// tail
|
||||
const uint8_t * tail = (const uint8_t*)(&vDataToHash[0] + nblocks*4);
|
||||
const uint8_t* tail = (const uint8_t*)(&vDataToHash[0] + nblocks * 4);
|
||||
|
||||
uint32_t k1 = 0;
|
||||
|
||||
switch(vDataToHash.size() & 3)
|
||||
{
|
||||
case 3: k1 ^= tail[2] << 16;
|
||||
case 2: k1 ^= tail[1] << 8;
|
||||
case 1: k1 ^= tail[0];
|
||||
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
|
||||
switch (vDataToHash.size() & 3) {
|
||||
case 3:
|
||||
k1 ^= tail[2] << 16;
|
||||
case 2:
|
||||
k1 ^= tail[1] << 8;
|
||||
case 1:
|
||||
k1 ^= tail[0];
|
||||
k1 *= c1;
|
||||
k1 = ROTL32(k1, 15);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
};
|
||||
|
||||
//----------
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
|
||||
class CWallet;
|
||||
|
||||
namespace boost {
|
||||
class thread_group;
|
||||
namespace boost
|
||||
{
|
||||
class thread_group;
|
||||
} // namespace boost
|
||||
|
||||
extern CWallet* pwalletMain;
|
||||
|
@ -22,8 +23,7 @@ void Shutdown();
|
|||
bool AppInit2(boost::thread_group& threadGroup);
|
||||
|
||||
/* The help message mode determines what help message to show */
|
||||
enum HelpMessageMode
|
||||
{
|
||||
enum HelpMessageMode {
|
||||
HMM_BITCOIND,
|
||||
HMM_BITCOIN_QT
|
||||
};
|
||||
|
|
131
src/key.h
131
src/key.h
|
@ -26,27 +26,29 @@
|
|||
class CKeyID : public uint160
|
||||
{
|
||||
public:
|
||||
CKeyID() : uint160(0) { }
|
||||
CKeyID(const uint160 &in) : uint160(in) { }
|
||||
CKeyID() : uint160(0) {}
|
||||
CKeyID(const uint160& in) : uint160(in) {}
|
||||
};
|
||||
|
||||
/** A reference to a CScript: the Hash160 of its serialization (see script.h) */
|
||||
class CScriptID : public uint160
|
||||
{
|
||||
public:
|
||||
CScriptID() : uint160(0) { }
|
||||
CScriptID(const uint160 &in) : uint160(in) { }
|
||||
CScriptID() : uint160(0) {}
|
||||
CScriptID(const uint160& in) : uint160(in) {}
|
||||
};
|
||||
|
||||
/** An encapsulated public key. */
|
||||
class CPubKey {
|
||||
class CPubKey
|
||||
{
|
||||
private:
|
||||
// Just store the serialized data.
|
||||
// Its length can very cheaply be computed from the first byte.
|
||||
unsigned char vch[65];
|
||||
|
||||
// Compute the length of a pubkey with a given first byte.
|
||||
unsigned int static GetLen(unsigned char chHeader) {
|
||||
unsigned int static GetLen(unsigned char chHeader)
|
||||
{
|
||||
if (chHeader == 2 || chHeader == 3)
|
||||
return 33;
|
||||
if (chHeader == 4 || chHeader == 6 || chHeader == 7)
|
||||
|
@ -55,66 +57,79 @@ private:
|
|||
}
|
||||
|
||||
// Set this key data to be invalid
|
||||
void Invalidate() {
|
||||
void Invalidate()
|
||||
{
|
||||
vch[0] = 0xFF;
|
||||
}
|
||||
|
||||
public:
|
||||
// Construct an invalid public key.
|
||||
CPubKey() {
|
||||
CPubKey()
|
||||
{
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
// Initialize a public key using begin/end iterators to byte data.
|
||||
template<typename T>
|
||||
void Set(const T pbegin, const T pend) {
|
||||
template <typename T>
|
||||
void Set(const T pbegin, const T pend)
|
||||
{
|
||||
int len = pend == pbegin ? 0 : GetLen(pbegin[0]);
|
||||
if (len && len == (pend-pbegin))
|
||||
if (len && len == (pend - pbegin))
|
||||
memcpy(vch, (unsigned char*)&pbegin[0], len);
|
||||
else
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
// Construct a public key using begin/end iterators to byte data.
|
||||
template<typename T>
|
||||
CPubKey(const T pbegin, const T pend) {
|
||||
template <typename T>
|
||||
CPubKey(const T pbegin, const T pend)
|
||||
{
|
||||
Set(pbegin, pend);
|
||||
}
|
||||
|
||||
// Construct a public key from a byte vector.
|
||||
CPubKey(const std::vector<unsigned char> &vch) {
|
||||
CPubKey(const std::vector<unsigned char>& vch)
|
||||
{
|
||||
Set(vch.begin(), vch.end());
|
||||
}
|
||||
|
||||
// Simple read-only vector-like interface to the pubkey data.
|
||||
unsigned int size() const { return GetLen(vch[0]); }
|
||||
const unsigned char *begin() const { return vch; }
|
||||
const unsigned char *end() const { return vch+size(); }
|
||||
const unsigned char &operator[](unsigned int pos) const { return vch[pos]; }
|
||||
const unsigned char* begin() const { return vch; }
|
||||
const unsigned char* end() const { return vch + size(); }
|
||||
const unsigned char& operator[](unsigned int pos) const { return vch[pos]; }
|
||||
|
||||
// Comparator implementation.
|
||||
friend bool operator==(const CPubKey &a, const CPubKey &b) {
|
||||
friend bool operator==(const CPubKey& a, const CPubKey& b)
|
||||
{
|
||||
return a.vch[0] == b.vch[0] &&
|
||||
memcmp(a.vch, b.vch, a.size()) == 0;
|
||||
}
|
||||
friend bool operator!=(const CPubKey &a, const CPubKey &b) {
|
||||
friend bool operator!=(const CPubKey& a, const CPubKey& b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
friend bool operator<(const CPubKey &a, const CPubKey &b) {
|
||||
friend bool operator<(const CPubKey& a, const CPubKey& b)
|
||||
{
|
||||
return a.vch[0] < b.vch[0] ||
|
||||
(a.vch[0] == b.vch[0] && memcmp(a.vch, b.vch, a.size()) < 0);
|
||||
}
|
||||
|
||||
// Implement serialization, as if this was a byte vector.
|
||||
unsigned int GetSerializeSize(int nType, int nVersion) const {
|
||||
unsigned int GetSerializeSize(int nType, int nVersion) const
|
||||
{
|
||||
return size() + 1;
|
||||
}
|
||||
template<typename Stream> void Serialize(Stream &s, int nType, int nVersion) const {
|
||||
template <typename Stream>
|
||||
void Serialize(Stream& s, int nType, int nVersion) const
|
||||
{
|
||||
unsigned int len = size();
|
||||
::WriteCompactSize(s, len);
|
||||
s.write((char*)vch, len);
|
||||
}
|
||||
template<typename Stream> void Unserialize(Stream &s, int nType, int nVersion) {
|
||||
template <typename Stream>
|
||||
void Unserialize(Stream& s, int nType, int nVersion)
|
||||
{
|
||||
unsigned int len = ::ReadCompactSize(s);
|
||||
if (len <= 65) {
|
||||
s.read((char*)vch, len);
|
||||
|
@ -128,19 +143,22 @@ public:
|
|||
}
|
||||
|
||||
// Get the KeyID of this public key (hash of its serialization)
|
||||
CKeyID GetID() const {
|
||||
return CKeyID(Hash160(vch, vch+size()));
|
||||
CKeyID GetID() const
|
||||
{
|
||||
return CKeyID(Hash160(vch, vch + size()));
|
||||
}
|
||||
|
||||
// Get the 256-bit hash of this public key.
|
||||
uint256 GetHash() const {
|
||||
return Hash(vch, vch+size());
|
||||
uint256 GetHash() const
|
||||
{
|
||||
return Hash(vch, vch + size());
|
||||
}
|
||||
|
||||
// Check syntactic correctness.
|
||||
//
|
||||
// Note that this is consensus critical as CheckSig() calls it!
|
||||
bool IsValid() const {
|
||||
bool IsValid() const
|
||||
{
|
||||
return size() > 0;
|
||||
}
|
||||
|
||||
|
@ -148,16 +166,17 @@ public:
|
|||
bool IsFullyValid() const;
|
||||
|
||||
// Check whether this is a compressed public key.
|
||||
bool IsCompressed() const {
|
||||
bool IsCompressed() const
|
||||
{
|
||||
return size() == 33;
|
||||
}
|
||||
|
||||
// Verify a DER signature (~72 bytes).
|
||||
// If this public key is not fully valid, the return value will be false.
|
||||
bool Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const;
|
||||
bool Verify(const uint256& hash, const std::vector<unsigned char>& vchSig) const;
|
||||
|
||||
// Recover a public key from a compact signature.
|
||||
bool RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig);
|
||||
bool RecoverCompact(const uint256& hash, const std::vector<unsigned char>& vchSig);
|
||||
|
||||
// Turn this public key into an uncompressed public key.
|
||||
bool Decompress();
|
||||
|
@ -172,7 +191,8 @@ public:
|
|||
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
|
||||
|
||||
/** An encapsulated private key. */
|
||||
class CKey {
|
||||
class CKey
|
||||
{
|
||||
private:
|
||||
// Whether this private key is valid. We check for correctness when modifying the key
|
||||
// data, so fValid should always correspond to the actual state.
|
||||
|
@ -185,33 +205,38 @@ private:
|
|||
unsigned char vch[32];
|
||||
|
||||
// Check whether the 32-byte array pointed to be vch is valid keydata.
|
||||
bool static Check(const unsigned char *vch);
|
||||
public:
|
||||
bool static Check(const unsigned char* vch);
|
||||
|
||||
public:
|
||||
// Construct an invalid private key.
|
||||
CKey() : fValid(false), fCompressed(false) {
|
||||
CKey() : fValid(false), fCompressed(false)
|
||||
{
|
||||
LockObject(vch);
|
||||
}
|
||||
|
||||
// Copy constructor. This is necessary because of memlocking.
|
||||
CKey(const CKey &secret) : fValid(secret.fValid), fCompressed(secret.fCompressed) {
|
||||
CKey(const CKey& secret) : fValid(secret.fValid), fCompressed(secret.fCompressed)
|
||||
{
|
||||
LockObject(vch);
|
||||
memcpy(vch, secret.vch, sizeof(vch));
|
||||
}
|
||||
|
||||
// Destructor (again necessary because of memlocking).
|
||||
~CKey() {
|
||||
~CKey()
|
||||
{
|
||||
UnlockObject(vch);
|
||||
}
|
||||
|
||||
friend bool operator==(const CKey &a, const CKey &b) {
|
||||
friend bool operator==(const CKey& a, const CKey& b)
|
||||
{
|
||||
return a.fCompressed == b.fCompressed && a.size() == b.size() &&
|
||||
memcmp(&a.vch[0], &b.vch[0], a.size()) == 0;
|
||||
}
|
||||
|
||||
// Initialize using begin and end iterators to byte data.
|
||||
template<typename T>
|
||||
void Set(const T pbegin, const T pend, bool fCompressedIn) {
|
||||
template <typename T>
|
||||
void Set(const T pbegin, const T pend, bool fCompressedIn)
|
||||
{
|
||||
if (pend - pbegin != 32) {
|
||||
fValid = false;
|
||||
return;
|
||||
|
@ -227,8 +252,8 @@ public:
|
|||
|
||||
// Simple read-only vector-like interface.
|
||||
unsigned int size() const { return (fValid ? 32 : 0); }
|
||||
const unsigned char *begin() const { return vch; }
|
||||
const unsigned char *end() const { return vch + size(); }
|
||||
const unsigned char* begin() const { return vch; }
|
||||
const unsigned char* end() const { return vch + size(); }
|
||||
|
||||
// Check whether this private key is valid.
|
||||
bool IsValid() const { return fValid; }
|
||||
|
@ -237,7 +262,7 @@ public:
|
|||
bool IsCompressed() const { return fCompressed; }
|
||||
|
||||
// Initialize from a CPrivKey (serialized OpenSSL private key data).
|
||||
bool SetPrivKey(const CPrivKey &vchPrivKey, bool fCompressed);
|
||||
bool SetPrivKey(const CPrivKey& vchPrivKey, bool fCompressed);
|
||||
|
||||
// Generate a new private key using a cryptographic PRNG.
|
||||
void MakeNewKey(bool fCompressed);
|
||||
|
@ -251,23 +276,23 @@ public:
|
|||
CPubKey GetPubKey() const;
|
||||
|
||||
// Create a DER-serialized signature.
|
||||
bool Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) const;
|
||||
bool Sign(const uint256& hash, std::vector<unsigned char>& vchSig) const;
|
||||
|
||||
// Create a compact signature (65 bytes), which allows reconstructing the used public key.
|
||||
// The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
|
||||
// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
|
||||
// 0x1D = second key with even y, 0x1E = second key with odd y,
|
||||
// add 0x04 for compressed keys.
|
||||
bool SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) const;
|
||||
bool SignCompact(const uint256& hash, std::vector<unsigned char>& vchSig) const;
|
||||
|
||||
// Derive BIP32 child key.
|
||||
bool Derive(CKey& keyChild, unsigned char ccChild[32], unsigned int nChild, const unsigned char cc[32]) const;
|
||||
|
||||
// Load private key and check that public key matches.
|
||||
bool Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck);
|
||||
bool Load(CPrivKey& privkey, CPubKey& vchPubKey, bool fSkipCheck);
|
||||
|
||||
// Check whether an element of a signature (r or s) is valid.
|
||||
static bool CheckSignatureElement(const unsigned char *vch, int len, bool half);
|
||||
static bool CheckSignatureElement(const unsigned char* vch, int len, bool half);
|
||||
};
|
||||
|
||||
struct CExtPubKey {
|
||||
|
@ -277,14 +302,15 @@ struct CExtPubKey {
|
|||
unsigned char vchChainCode[32];
|
||||
CPubKey pubkey;
|
||||
|
||||
friend bool operator==(const CExtPubKey &a, const CExtPubKey &b) {
|
||||
friend bool operator==(const CExtPubKey& a, const CExtPubKey& b)
|
||||
{
|
||||
return a.nDepth == b.nDepth && memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], 4) == 0 && a.nChild == b.nChild &&
|
||||
memcmp(&a.vchChainCode[0], &b.vchChainCode[0], 32) == 0 && a.pubkey == b.pubkey;
|
||||
}
|
||||
|
||||
void Encode(unsigned char code[74]) const;
|
||||
void Decode(const unsigned char code[74]);
|
||||
bool Derive(CExtPubKey &out, unsigned int nChild) const;
|
||||
bool Derive(CExtPubKey& out, unsigned int nChild) const;
|
||||
};
|
||||
|
||||
struct CExtKey {
|
||||
|
@ -294,16 +320,17 @@ struct CExtKey {
|
|||
unsigned char vchChainCode[32];
|
||||
CKey key;
|
||||
|
||||
friend bool operator==(const CExtKey &a, const CExtKey &b) {
|
||||
friend bool operator==(const CExtKey& a, const CExtKey& b)
|
||||
{
|
||||
return a.nDepth == b.nDepth && memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], 4) == 0 && a.nChild == b.nChild &&
|
||||
memcmp(&a.vchChainCode[0], &b.vchChainCode[0], 32) == 0 && a.key == b.key;
|
||||
}
|
||||
|
||||
void Encode(unsigned char code[74]) const;
|
||||
void Decode(const unsigned char code[74]);
|
||||
bool Derive(CExtKey &out, unsigned int nChild) const;
|
||||
bool Derive(CExtKey& out, unsigned int nChild) const;
|
||||
CExtPubKey Neuter() const;
|
||||
void SetMaster(const unsigned char *seed, unsigned int nSeedLen);
|
||||
void SetMaster(const unsigned char* seed, unsigned int nSeedLen);
|
||||
};
|
||||
|
||||
/** Check that required EC support is available at runtime */
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
#include <leveldb/filter_policy.h>
|
||||
#include <memenv.h>
|
||||
|
||||
void HandleError(const leveldb::Status &status) throw(leveldb_error) {
|
||||
void HandleError(const leveldb::Status& status) throw(leveldb_error)
|
||||
{
|
||||
if (status.ok())
|
||||
return;
|
||||
LogPrintf("%s\n", status.ToString());
|
||||
|
@ -25,7 +26,8 @@ void HandleError(const leveldb::Status &status) throw(leveldb_error) {
|
|||
throw leveldb_error("Unknown database error");
|
||||
}
|
||||
|
||||
static leveldb::Options GetOptions(size_t nCacheSize) {
|
||||
static leveldb::Options GetOptions(size_t nCacheSize)
|
||||
{
|
||||
leveldb::Options options;
|
||||
options.block_cache = leveldb::NewLRUCache(nCacheSize / 2);
|
||||
options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously
|
||||
|
@ -40,7 +42,8 @@ static leveldb::Options GetOptions(size_t nCacheSize) {
|
|||
return options;
|
||||
}
|
||||
|
||||
CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path &path, size_t nCacheSize, bool fMemory, bool fWipe) {
|
||||
CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe)
|
||||
{
|
||||
penv = NULL;
|
||||
readoptions.verify_checksums = true;
|
||||
iteroptions.verify_checksums = true;
|
||||
|
@ -64,7 +67,8 @@ CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path &path, size_t nCa
|
|||
LogPrintf("Opened LevelDB successfully\n");
|
||||
}
|
||||
|
||||
CLevelDBWrapper::~CLevelDBWrapper() {
|
||||
CLevelDBWrapper::~CLevelDBWrapper()
|
||||
{
|
||||
delete pdb;
|
||||
pdb = NULL;
|
||||
delete options.filter_policy;
|
||||
|
@ -75,7 +79,8 @@ CLevelDBWrapper::~CLevelDBWrapper() {
|
|||
options.env = NULL;
|
||||
}
|
||||
|
||||
bool CLevelDBWrapper::WriteBatch(CLevelDBBatch &batch, bool fSync) throw(leveldb_error) {
|
||||
bool CLevelDBWrapper::WriteBatch(CLevelDBBatch& batch, bool fSync) throw(leveldb_error)
|
||||
{
|
||||
leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch);
|
||||
HandleError(status);
|
||||
return true;
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
class leveldb_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
leveldb_error(const std::string &msg) : std::runtime_error(msg) {}
|
||||
leveldb_error(const std::string& msg) : std::runtime_error(msg) {}
|
||||
};
|
||||
|
||||
void HandleError(const leveldb::Status &status) throw(leveldb_error);
|
||||
void HandleError(const leveldb::Status& status) throw(leveldb_error);
|
||||
|
||||
// Batch of changes queued to be written to a CLevelDBWrapper
|
||||
class CLevelDBBatch
|
||||
|
@ -31,7 +31,9 @@ private:
|
|||
leveldb::WriteBatch batch;
|
||||
|
||||
public:
|
||||
template<typename K, typename V> void Write(const K& key, const V& value) {
|
||||
template <typename K, typename V>
|
||||
void Write(const K& key, const V& value)
|
||||
{
|
||||
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
||||
ssKey.reserve(ssKey.GetSerializeSize(key));
|
||||
ssKey << key;
|
||||
|
@ -45,7 +47,9 @@ public:
|
|||
batch.Put(slKey, slValue);
|
||||
}
|
||||
|
||||
template<typename K> void Erase(const K& key) {
|
||||
template <typename K>
|
||||
void Erase(const K& key)
|
||||
{
|
||||
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
||||
ssKey.reserve(ssKey.GetSerializeSize(key));
|
||||
ssKey << key;
|
||||
|
@ -59,7 +63,7 @@ class CLevelDBWrapper
|
|||
{
|
||||
private:
|
||||
// custom environment this database is using (may be NULL in case of default environment)
|
||||
leveldb::Env *penv;
|
||||
leveldb::Env* penv;
|
||||
|
||||
// database options used
|
||||
leveldb::Options options;
|
||||
|
@ -77,13 +81,15 @@ private:
|
|||
leveldb::WriteOptions syncoptions;
|
||||
|
||||
// the database itself
|
||||
leveldb::DB *pdb;
|
||||
leveldb::DB* pdb;
|
||||
|
||||
public:
|
||||
CLevelDBWrapper(const boost::filesystem::path &path, size_t nCacheSize, bool fMemory = false, bool fWipe = false);
|
||||
CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false);
|
||||
~CLevelDBWrapper();
|
||||
|
||||
template<typename K, typename V> bool Read(const K& key, V& value) const throw(leveldb_error) {
|
||||
template <typename K, typename V>
|
||||
bool Read(const K& key, V& value) const throw(leveldb_error)
|
||||
{
|
||||
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
||||
ssKey.reserve(ssKey.GetSerializeSize(key));
|
||||
ssKey << key;
|
||||
|
@ -100,19 +106,23 @@ public:
|
|||
try {
|
||||
CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION);
|
||||
ssValue >> value;
|
||||
} catch(const std::exception &) {
|
||||
} catch (const std::exception&) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename K, typename V> bool Write(const K& key, const V& value, bool fSync = false) throw(leveldb_error) {
|
||||
template <typename K, typename V>
|
||||
bool Write(const K& key, const V& value, bool fSync = false) throw(leveldb_error)
|
||||
{
|
||||
CLevelDBBatch batch;
|
||||
batch.Write(key, value);
|
||||
return WriteBatch(batch, fSync);
|
||||
}
|
||||
|
||||
template<typename K> bool Exists(const K& key) const throw(leveldb_error) {
|
||||
template <typename K>
|
||||
bool Exists(const K& key) const throw(leveldb_error)
|
||||
{
|
||||
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
||||
ssKey.reserve(ssKey.GetSerializeSize(key));
|
||||
ssKey << key;
|
||||
|
@ -129,26 +139,31 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
template<typename K> bool Erase(const K& key, bool fSync = false) throw(leveldb_error) {
|
||||
template <typename K>
|
||||
bool Erase(const K& key, bool fSync = false) throw(leveldb_error)
|
||||
{
|
||||
CLevelDBBatch batch;
|
||||
batch.Erase(key);
|
||||
return WriteBatch(batch, fSync);
|
||||
}
|
||||
|
||||
bool WriteBatch(CLevelDBBatch &batch, bool fSync = false) throw(leveldb_error);
|
||||
bool WriteBatch(CLevelDBBatch& batch, bool fSync = false) throw(leveldb_error);
|
||||
|
||||
// not available for LevelDB; provide for compatibility with BDB
|
||||
bool Flush() {
|
||||
bool Flush()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sync() throw(leveldb_error) {
|
||||
bool Sync() throw(leveldb_error)
|
||||
{
|
||||
CLevelDBBatch batch;
|
||||
return WriteBatch(batch, true);
|
||||
}
|
||||
|
||||
// not exactly clean encapsulation, but it's easiest for now
|
||||
leveldb::Iterator *NewIterator() {
|
||||
leveldb::Iterator* NewIterator()
|
||||
{
|
||||
return pdb->NewIterator(iteroptions);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
#include <map>
|
||||
|
||||
/** STL-like map container that only keeps the N elements with the highest value. */
|
||||
template <typename K, typename V> class limitedmap
|
||||
template <typename K, typename V>
|
||||
class limitedmap
|
||||
{
|
||||
public:
|
||||
typedef K key_type;
|
||||
|
@ -36,10 +37,8 @@ public:
|
|||
void insert(const value_type& x)
|
||||
{
|
||||
std::pair<iterator, bool> ret = map.insert(x);
|
||||
if (ret.second)
|
||||
{
|
||||
if (nMaxSize && map.size() == nMaxSize)
|
||||
{
|
||||
if (ret.second) {
|
||||
if (nMaxSize && map.size() == nMaxSize) {
|
||||
map.erase(rmap.begin()->second);
|
||||
rmap.erase(rmap.begin());
|
||||
}
|
||||
|
@ -54,8 +53,7 @@ public:
|
|||
return;
|
||||
std::pair<rmap_iterator, rmap_iterator> itPair = rmap.equal_range(itTarget->second);
|
||||
for (rmap_iterator it = itPair.first; it != itPair.second; ++it)
|
||||
if (it->second == itTarget)
|
||||
{
|
||||
if (it->second == itTarget) {
|
||||
rmap.erase(it);
|
||||
map.erase(itTarget);
|
||||
return;
|
||||
|
@ -72,8 +70,7 @@ public:
|
|||
return;
|
||||
std::pair<rmap_iterator, rmap_iterator> itPair = rmap.equal_range(itTarget->second);
|
||||
for (rmap_iterator it = itPair.first; it != itPair.second; ++it)
|
||||
if (it->second == itTarget)
|
||||
{
|
||||
if (it->second == itTarget) {
|
||||
rmap.erase(it);
|
||||
itTarget->second = v;
|
||||
rmap.insert(make_pair(v, itTarget));
|
||||
|
@ -88,8 +85,7 @@ public:
|
|||
size_type max_size(size_type s)
|
||||
{
|
||||
if (s)
|
||||
while (map.size() > s)
|
||||
{
|
||||
while (map.size() > s) {
|
||||
map.erase(rmap.begin()->second);
|
||||
rmap.erase(rmap.begin());
|
||||
}
|
||||
|
|
18
src/mruset.h
18
src/mruset.h
|
@ -10,7 +10,8 @@
|
|||
#include <utility>
|
||||
|
||||
/** STL-like set container that only keeps the most recent N elements. */
|
||||
template <typename T> class mruset
|
||||
template <typename T>
|
||||
class mruset
|
||||
{
|
||||
public:
|
||||
typedef T key_type;
|
||||
|
@ -32,17 +33,19 @@ public:
|
|||
bool empty() const { return set.empty(); }
|
||||
iterator find(const key_type& k) const { return set.find(k); }
|
||||
size_type count(const key_type& k) const { return set.count(k); }
|
||||
void clear() { set.clear(); queue.clear(); }
|
||||
void clear()
|
||||
{
|
||||
set.clear();
|
||||
queue.clear();
|
||||
}
|
||||
bool inline friend operator==(const mruset<T>& a, const mruset<T>& b) { return a.set == b.set; }
|
||||
bool inline friend operator==(const mruset<T>& a, const std::set<T>& b) { return a.set == b; }
|
||||
bool inline friend operator<(const mruset<T>& a, const mruset<T>& b) { return a.set < b.set; }
|
||||
std::pair<iterator, bool> insert(const key_type& x)
|
||||
{
|
||||
std::pair<iterator, bool> ret = set.insert(x);
|
||||
if (ret.second)
|
||||
{
|
||||
if (nMaxSize && queue.size() == nMaxSize)
|
||||
{
|
||||
if (ret.second) {
|
||||
if (nMaxSize && queue.size() == nMaxSize) {
|
||||
set.erase(queue.front());
|
||||
queue.pop_front();
|
||||
}
|
||||
|
@ -54,8 +57,7 @@ public:
|
|||
size_type max_size(size_type s)
|
||||
{
|
||||
if (s)
|
||||
while (queue.size() > s)
|
||||
{
|
||||
while (queue.size() > s) {
|
||||
set.erase(queue.front());
|
||||
queue.pop_front();
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ static bool noui_ThreadSafeMessageBox(const std::string& message, const std::str
|
|||
return false;
|
||||
}
|
||||
|
||||
static void noui_InitMessage(const std::string &message)
|
||||
static void noui_InitMessage(const std::string& message)
|
||||
{
|
||||
LogPrintf("init message: %s\n", message);
|
||||
}
|
||||
|
|
143
src/protocol.h
143
src/protocol.h
|
@ -4,7 +4,7 @@
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This header can only be compiled as C++.
|
||||
#error This header can only be compiled as C++.
|
||||
#endif
|
||||
|
||||
#ifndef __INCLUDED_PROTOCOL_H__
|
||||
|
@ -28,43 +28,43 @@
|
|||
*/
|
||||
class CMessageHeader
|
||||
{
|
||||
public:
|
||||
CMessageHeader();
|
||||
CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn);
|
||||
public:
|
||||
CMessageHeader();
|
||||
CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn);
|
||||
|
||||
std::string GetCommand() const;
|
||||
bool IsValid() const;
|
||||
std::string GetCommand() const;
|
||||
bool IsValid() const;
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
READWRITE(FLATDATA(pchMessageStart));
|
||||
READWRITE(FLATDATA(pchCommand));
|
||||
READWRITE(nMessageSize);
|
||||
READWRITE(nChecksum);
|
||||
}
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
|
||||
{
|
||||
READWRITE(FLATDATA(pchMessageStart));
|
||||
READWRITE(FLATDATA(pchCommand));
|
||||
READWRITE(nMessageSize);
|
||||
READWRITE(nChecksum);
|
||||
}
|
||||
|
||||
// TODO: make private (improves encapsulation)
|
||||
public:
|
||||
enum {
|
||||
COMMAND_SIZE=12,
|
||||
MESSAGE_SIZE_SIZE=sizeof(int),
|
||||
CHECKSUM_SIZE=sizeof(int),
|
||||
public:
|
||||
enum {
|
||||
COMMAND_SIZE = 12,
|
||||
MESSAGE_SIZE_SIZE = sizeof(int),
|
||||
CHECKSUM_SIZE = sizeof(int),
|
||||
|
||||
MESSAGE_SIZE_OFFSET=MESSAGE_START_SIZE+COMMAND_SIZE,
|
||||
CHECKSUM_OFFSET=MESSAGE_SIZE_OFFSET+MESSAGE_SIZE_SIZE,
|
||||
HEADER_SIZE=MESSAGE_START_SIZE+COMMAND_SIZE+MESSAGE_SIZE_SIZE+CHECKSUM_SIZE
|
||||
};
|
||||
char pchMessageStart[MESSAGE_START_SIZE];
|
||||
char pchCommand[COMMAND_SIZE];
|
||||
unsigned int nMessageSize;
|
||||
unsigned int nChecksum;
|
||||
MESSAGE_SIZE_OFFSET = MESSAGE_START_SIZE + COMMAND_SIZE,
|
||||
CHECKSUM_OFFSET = MESSAGE_SIZE_OFFSET + MESSAGE_SIZE_SIZE,
|
||||
HEADER_SIZE = MESSAGE_START_SIZE + COMMAND_SIZE + MESSAGE_SIZE_SIZE + CHECKSUM_SIZE
|
||||
};
|
||||
char pchMessageStart[MESSAGE_START_SIZE];
|
||||
char pchCommand[COMMAND_SIZE];
|
||||
unsigned int nMessageSize;
|
||||
unsigned int nChecksum;
|
||||
};
|
||||
|
||||
/** nServices flags */
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
NODE_NETWORK = (1 << 0),
|
||||
|
||||
// Bits 24-31 are reserved for temporary experiments. Just pick a bit that
|
||||
|
@ -79,68 +79,69 @@ enum
|
|||
/** A CService with information about it as peer */
|
||||
class CAddress : public CService
|
||||
{
|
||||
public:
|
||||
CAddress();
|
||||
explicit CAddress(CService ipIn, uint64_t nServicesIn=NODE_NETWORK);
|
||||
public:
|
||||
CAddress();
|
||||
explicit CAddress(CService ipIn, uint64_t nServicesIn = NODE_NETWORK);
|
||||
|
||||
void Init();
|
||||
void Init();
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
if (ser_action.ForRead())
|
||||
Init();
|
||||
if (nType & SER_DISK)
|
||||
READWRITE(nVersion);
|
||||
if ((nType & SER_DISK) ||
|
||||
(nVersion >= CADDR_TIME_VERSION && !(nType & SER_GETHASH)))
|
||||
READWRITE(nTime);
|
||||
READWRITE(nServices);
|
||||
READWRITE(*(CService*)this);
|
||||
}
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
|
||||
{
|
||||
if (ser_action.ForRead())
|
||||
Init();
|
||||
if (nType & SER_DISK)
|
||||
READWRITE(nVersion);
|
||||
if ((nType & SER_DISK) ||
|
||||
(nVersion >= CADDR_TIME_VERSION && !(nType & SER_GETHASH)))
|
||||
READWRITE(nTime);
|
||||
READWRITE(nServices);
|
||||
READWRITE(*(CService*)this);
|
||||
}
|
||||
|
||||
// TODO: make private (improves encapsulation)
|
||||
public:
|
||||
uint64_t nServices;
|
||||
public:
|
||||
uint64_t nServices;
|
||||
|
||||
// disk and network only
|
||||
unsigned int nTime;
|
||||
// disk and network only
|
||||
unsigned int nTime;
|
||||
|
||||
// memory only
|
||||
int64_t nLastTry;
|
||||
// memory only
|
||||
int64_t nLastTry;
|
||||
};
|
||||
|
||||
/** inv message data */
|
||||
class CInv
|
||||
{
|
||||
public:
|
||||
CInv();
|
||||
CInv(int typeIn, const uint256& hashIn);
|
||||
CInv(const std::string& strType, const uint256& hashIn);
|
||||
public:
|
||||
CInv();
|
||||
CInv(int typeIn, const uint256& hashIn);
|
||||
CInv(const std::string& strType, const uint256& hashIn);
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
READWRITE(type);
|
||||
READWRITE(hash);
|
||||
}
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
|
||||
{
|
||||
READWRITE(type);
|
||||
READWRITE(hash);
|
||||
}
|
||||
|
||||
friend bool operator<(const CInv& a, const CInv& b);
|
||||
friend bool operator<(const CInv& a, const CInv& b);
|
||||
|
||||
bool IsKnownType() const;
|
||||
const char* GetCommand() const;
|
||||
std::string ToString() const;
|
||||
bool IsKnownType() const;
|
||||
const char* GetCommand() const;
|
||||
std::string ToString() const;
|
||||
|
||||
// TODO: make private (improves encapsulation)
|
||||
public:
|
||||
int type;
|
||||
uint256 hash;
|
||||
public:
|
||||
int type;
|
||||
uint256 hash;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
MSG_TX = 1,
|
||||
MSG_BLOCK,
|
||||
// Nodes may always request a MSG_FILTERED_BLOCK in a getdata, however,
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
#ifdef WIN32
|
||||
#include "compat.h" // for Windows API
|
||||
#endif
|
||||
#include "serialize.h" // for begin_ptr(vec)
|
||||
#include "util.h" // for LogPrint()
|
||||
#include "serialize.h" // for begin_ptr(vec)
|
||||
#include "util.h" // for LogPrint()
|
||||
#include "utilstrencodings.h" // for GetTime()
|
||||
|
||||
#include <limits>
|
||||
|
@ -56,28 +56,25 @@ void RandAddSeedPerfmon()
|
|||
#ifdef WIN32
|
||||
// Don't need this on Linux, OpenSSL automatically uses /dev/urandom
|
||||
// Seed with the entire set of perfmon data
|
||||
std::vector <unsigned char> vData(250000,0);
|
||||
std::vector<unsigned char> vData(250000, 0);
|
||||
long ret = 0;
|
||||
unsigned long nSize = 0;
|
||||
const size_t nMaxSize = 10000000; // Bail out at more than 10MB of performance data
|
||||
while (true)
|
||||
{
|
||||
while (true) {
|
||||
nSize = vData.size();
|
||||
ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, begin_ptr(vData), &nSize);
|
||||
if (ret != ERROR_MORE_DATA || vData.size() >= nMaxSize)
|
||||
break;
|
||||
vData.resize(std::max((vData.size()*3)/2, nMaxSize)); // Grow size of buffer exponentially
|
||||
vData.resize(std::max((vData.size() * 3) / 2, nMaxSize)); // Grow size of buffer exponentially
|
||||
}
|
||||
RegCloseKey(HKEY_PERFORMANCE_DATA);
|
||||
if (ret == ERROR_SUCCESS)
|
||||
{
|
||||
RAND_add(begin_ptr(vData), nSize, nSize/100.0);
|
||||
if (ret == ERROR_SUCCESS) {
|
||||
RAND_add(begin_ptr(vData), nSize, nSize / 100.0);
|
||||
OPENSSL_cleanse(begin_ptr(vData), nSize);
|
||||
LogPrint("rand", "%s: %lu bytes\n", __func__, nSize);
|
||||
} else {
|
||||
static bool warned = false; // Warn only once
|
||||
if (!warned)
|
||||
{
|
||||
if (!warned) {
|
||||
LogPrintf("%s: Warning: RegQueryValueExA(HKEY_PERFORMANCE_DATA) failed with code %i\n", __func__, ret);
|
||||
warned = true;
|
||||
}
|
||||
|
@ -85,7 +82,7 @@ void RandAddSeedPerfmon()
|
|||
#endif
|
||||
}
|
||||
|
||||
bool GetRandBytes(unsigned char *buf, int num)
|
||||
bool GetRandBytes(unsigned char* buf, int num)
|
||||
{
|
||||
if (RAND_bytes(buf, num) != 1) {
|
||||
LogPrintf("%s: OpenSSL RAND_bytes() failed with error: %s\n", __func__, ERR_error_string(ERR_get_error(), NULL));
|
||||
|
@ -126,18 +123,17 @@ uint32_t insecure_rand_Rw = 11;
|
|||
void seed_insecure_rand(bool fDeterministic)
|
||||
{
|
||||
// The seed values have some unlikely fixed points which we avoid.
|
||||
if(fDeterministic)
|
||||
{
|
||||
if (fDeterministic) {
|
||||
insecure_rand_Rz = insecure_rand_Rw = 11;
|
||||
} else {
|
||||
uint32_t tmp;
|
||||
do {
|
||||
GetRandBytes((unsigned char*)&tmp, 4);
|
||||
} while(tmp == 0 || tmp == 0x9068ffffU);
|
||||
} while (tmp == 0 || tmp == 0x9068ffffU);
|
||||
insecure_rand_Rz = tmp;
|
||||
do {
|
||||
GetRandBytes((unsigned char*)&tmp, 4);
|
||||
} while(tmp == 0 || tmp == 0x464fffffU);
|
||||
} while (tmp == 0 || tmp == 0x464fffffU);
|
||||
insecure_rand_Rw = tmp;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ void RandAddSeedPerfmon();
|
|||
/**
|
||||
* Functions to gather random data via the OpenSSL PRNG
|
||||
*/
|
||||
bool GetRandBytes(unsigned char *buf, int num);
|
||||
bool GetRandBytes(unsigned char* buf, int num);
|
||||
uint64_t GetRand(uint64_t nMax);
|
||||
int GetRandInt(int nMax);
|
||||
uint256 GetRandHash();
|
||||
|
|
|
@ -10,6 +10,6 @@
|
|||
#include "json/json_spirit_utils.h"
|
||||
#include "json/json_spirit_writer_template.h"
|
||||
|
||||
json_spirit::Array RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams);
|
||||
json_spirit::Array RPCConvertValues(const std::string& strMethod, const std::vector<std::string>& strParams);
|
||||
|
||||
#endif // _BITCOINRPC_CLIENT_H_
|
||||
|
|
48
src/sync.cpp
48
src/sync.cpp
|
@ -32,8 +32,7 @@ void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
|
|||
// Complain if any thread tries to lock in a different order.
|
||||
//
|
||||
|
||||
struct CLockLocation
|
||||
{
|
||||
struct CLockLocation {
|
||||
CLockLocation(const char* pszName, const char* pszFile, int nLine)
|
||||
{
|
||||
mutexName = pszName;
|
||||
|
@ -43,7 +42,7 @@ struct CLockLocation
|
|||
|
||||
std::string ToString() const
|
||||
{
|
||||
return mutexName+" "+sourceFile+":"+itostr(sourceLine);
|
||||
return mutexName + " " + sourceFile + ":" + itostr(sourceLine);
|
||||
}
|
||||
|
||||
std::string MutexName() const { return mutexName; }
|
||||
|
@ -54,7 +53,7 @@ private:
|
|||
int sourceLine;
|
||||
};
|
||||
|
||||
typedef std::vector< std::pair<void*, CLockLocation> > LockStack;
|
||||
typedef std::vector<std::pair<void*, CLockLocation> > LockStack;
|
||||
|
||||
static boost::mutex dd_mutex;
|
||||
static std::map<std::pair<void*, void*>, LockStack> lockorders;
|
||||
|
@ -65,17 +64,19 @@ static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch,
|
|||
{
|
||||
LogPrintf("POTENTIAL DEADLOCK DETECTED\n");
|
||||
LogPrintf("Previous lock order was:\n");
|
||||
BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s2)
|
||||
{
|
||||
if (i.first == mismatch.first) LogPrintf(" (1)");
|
||||
if (i.first == mismatch.second) LogPrintf(" (2)");
|
||||
BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s2) {
|
||||
if (i.first == mismatch.first)
|
||||
LogPrintf(" (1)");
|
||||
if (i.first == mismatch.second)
|
||||
LogPrintf(" (2)");
|
||||
LogPrintf(" %s\n", i.second.ToString());
|
||||
}
|
||||
LogPrintf("Current lock order is:\n");
|
||||
BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s1)
|
||||
{
|
||||
if (i.first == mismatch.first) LogPrintf(" (1)");
|
||||
if (i.first == mismatch.second) LogPrintf(" (2)");
|
||||
BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s1) {
|
||||
if (i.first == mismatch.first)
|
||||
LogPrintf(" (1)");
|
||||
if (i.first == mismatch.second)
|
||||
LogPrintf(" (2)");
|
||||
LogPrintf(" %s\n", i.second.ToString());
|
||||
}
|
||||
}
|
||||
|
@ -91,8 +92,9 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
|
|||
(*lockstack).push_back(std::make_pair(c, locklocation));
|
||||
|
||||
if (!fTry) {
|
||||
BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, (*lockstack)) {
|
||||
if (i.first == c) break;
|
||||
BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, (*lockstack)) {
|
||||
if (i.first == c)
|
||||
break;
|
||||
|
||||
std::pair<void*, void*> p1 = std::make_pair(i.first, c);
|
||||
if (lockorders.count(p1))
|
||||
|
@ -100,8 +102,7 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
|
|||
lockorders[p1] = (*lockstack);
|
||||
|
||||
std::pair<void*, void*> p2 = std::make_pair(c, i.first);
|
||||
if (lockorders.count(p2))
|
||||
{
|
||||
if (lockorders.count(p2)) {
|
||||
potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]);
|
||||
break;
|
||||
}
|
||||
|
@ -112,8 +113,7 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
|
|||
|
||||
static void pop_lock()
|
||||
{
|
||||
if (fDebug)
|
||||
{
|
||||
if (fDebug) {
|
||||
const CLockLocation& locklocation = (*lockstack).rbegin()->second;
|
||||
LogPrint("lock", "Unlocked: %s\n", locklocation.ToString());
|
||||
}
|
||||
|
@ -135,17 +135,17 @@ void LeaveCritical()
|
|||
std::string LocksHeld()
|
||||
{
|
||||
std::string result;
|
||||
BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)&i, *lockstack)
|
||||
BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, *lockstack)
|
||||
result += i.second.ToString() + std::string("\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
void AssertLockHeldInternal(const char *pszName, const char* pszFile, int nLine, void *cs)
|
||||
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
|
||||
{
|
||||
BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)&i, *lockstack)
|
||||
if (i.first == cs) return;
|
||||
fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s",
|
||||
pszName, pszFile, nLine, LocksHeld().c_str());
|
||||
BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, *lockstack)
|
||||
if (i.first == cs)
|
||||
return;
|
||||
fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
|
||||
abort();
|
||||
}
|
||||
|
||||
|
|
70
src/sync.h
70
src/sync.h
|
@ -48,7 +48,6 @@ LEAVE_CRITICAL_SECTION(mutex); // no RAII
|
|||
*/
|
||||
|
||||
|
||||
|
||||
///////////////////////////////
|
||||
// //
|
||||
// THE ACTUAL IMPLEMENTATION //
|
||||
|
@ -63,17 +62,17 @@ class LOCKABLE AnnotatedMixin : public PARENT
|
|||
public:
|
||||
void lock() EXCLUSIVE_LOCK_FUNCTION()
|
||||
{
|
||||
PARENT::lock();
|
||||
PARENT::lock();
|
||||
}
|
||||
|
||||
void unlock() UNLOCK_FUNCTION()
|
||||
{
|
||||
PARENT::unlock();
|
||||
PARENT::unlock();
|
||||
}
|
||||
|
||||
bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
|
||||
{
|
||||
return PARENT::try_lock();
|
||||
return PARENT::try_lock();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -91,11 +90,13 @@ typedef boost::condition_variable CConditionVariable;
|
|||
void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
|
||||
void LeaveCritical();
|
||||
std::string LocksHeld();
|
||||
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void *cs);
|
||||
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
|
||||
#else
|
||||
void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
|
||||
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 AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
|
||||
#endif
|
||||
#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
|
||||
|
||||
|
@ -104,7 +105,7 @@ void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
|
|||
#endif
|
||||
|
||||
/** Wrapper around boost::unique_lock<Mutex> */
|
||||
template<typename Mutex>
|
||||
template <typename Mutex>
|
||||
class CMutexLock
|
||||
{
|
||||
private:
|
||||
|
@ -114,11 +115,10 @@ private:
|
|||
{
|
||||
EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()));
|
||||
#ifdef DEBUG_LOCKCONTENTION
|
||||
if (!lock.try_lock())
|
||||
{
|
||||
if (!lock.try_lock()) {
|
||||
PrintLockContention(pszName, pszFile, nLine);
|
||||
#endif
|
||||
lock.lock();
|
||||
lock.lock();
|
||||
#ifdef DEBUG_LOCKCONTENTION
|
||||
}
|
||||
#endif
|
||||
|
@ -157,19 +157,19 @@ public:
|
|||
typedef CMutexLock<CCriticalSection> CCriticalBlock;
|
||||
|
||||
#define LOCK(cs) CCriticalBlock criticalblock(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)
|
||||
#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 ENTER_CRITICAL_SECTION(cs) \
|
||||
{ \
|
||||
#define ENTER_CRITICAL_SECTION(cs) \
|
||||
{ \
|
||||
EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \
|
||||
(cs).lock(); \
|
||||
(cs).lock(); \
|
||||
}
|
||||
|
||||
#define LEAVE_CRITICAL_SECTION(cs) \
|
||||
{ \
|
||||
(cs).unlock(); \
|
||||
LeaveCritical(); \
|
||||
{ \
|
||||
(cs).unlock(); \
|
||||
LeaveCritical(); \
|
||||
}
|
||||
|
||||
class CSemaphore
|
||||
|
@ -182,7 +182,8 @@ private:
|
|||
public:
|
||||
CSemaphore(int init) : value(init) {}
|
||||
|
||||
void wait() {
|
||||
void wait()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(mutex);
|
||||
while (value < 1) {
|
||||
condition.wait(lock);
|
||||
|
@ -190,7 +191,8 @@ public:
|
|||
value--;
|
||||
}
|
||||
|
||||
bool try_wait() {
|
||||
bool try_wait()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(mutex);
|
||||
if (value < 1)
|
||||
return false;
|
||||
|
@ -198,7 +200,8 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
void post() {
|
||||
void post()
|
||||
{
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(mutex);
|
||||
value++;
|
||||
|
@ -211,31 +214,35 @@ public:
|
|||
class CSemaphoreGrant
|
||||
{
|
||||
private:
|
||||
CSemaphore *sem;
|
||||
CSemaphore* sem;
|
||||
bool fHaveGrant;
|
||||
|
||||
public:
|
||||
void Acquire() {
|
||||
void Acquire()
|
||||
{
|
||||
if (fHaveGrant)
|
||||
return;
|
||||
sem->wait();
|
||||
fHaveGrant = true;
|
||||
}
|
||||
|
||||
void Release() {
|
||||
void Release()
|
||||
{
|
||||
if (!fHaveGrant)
|
||||
return;
|
||||
sem->post();
|
||||
fHaveGrant = false;
|
||||
}
|
||||
|
||||
bool TryAcquire() {
|
||||
bool TryAcquire()
|
||||
{
|
||||
if (!fHaveGrant && sem->try_wait())
|
||||
fHaveGrant = true;
|
||||
return fHaveGrant;
|
||||
}
|
||||
|
||||
void MoveTo(CSemaphoreGrant &grant) {
|
||||
void MoveTo(CSemaphoreGrant& grant)
|
||||
{
|
||||
grant.Release();
|
||||
grant.sem = sem;
|
||||
grant.fHaveGrant = fHaveGrant;
|
||||
|
@ -245,18 +252,21 @@ public:
|
|||
|
||||
CSemaphoreGrant() : sem(NULL), fHaveGrant(false) {}
|
||||
|
||||
CSemaphoreGrant(CSemaphore &sema, bool fTry = false) : sem(&sema), fHaveGrant(false) {
|
||||
CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
|
||||
{
|
||||
if (fTry)
|
||||
TryAcquire();
|
||||
else
|
||||
Acquire();
|
||||
}
|
||||
|
||||
~CSemaphoreGrant() {
|
||||
~CSemaphoreGrant()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
operator bool() {
|
||||
operator bool()
|
||||
{
|
||||
return fHaveGrant;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -13,24 +13,24 @@
|
|||
// See http://clang.llvm.org/docs/LanguageExtensions.html#threadsafety
|
||||
// for documentation. The clang compiler can do advanced static analysis
|
||||
// of locking when given the -Wthread-safety option.
|
||||
#define LOCKABLE __attribute__ ((lockable))
|
||||
#define SCOPED_LOCKABLE __attribute__ ((scoped_lockable))
|
||||
#define GUARDED_BY(x) __attribute__ ((guarded_by(x)))
|
||||
#define GUARDED_VAR __attribute__ ((guarded_var))
|
||||
#define PT_GUARDED_BY(x) __attribute__ ((pt_guarded_by(x)))
|
||||
#define PT_GUARDED_VAR __attribute__ ((pt_guarded_var))
|
||||
#define ACQUIRED_AFTER(...) __attribute__ ((acquired_after(__VA_ARGS__)))
|
||||
#define ACQUIRED_BEFORE(...) __attribute__ ((acquired_before(__VA_ARGS__)))
|
||||
#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__ ((exclusive_lock_function(__VA_ARGS__)))
|
||||
#define SHARED_LOCK_FUNCTION(...) __attribute__ ((shared_lock_function(__VA_ARGS__)))
|
||||
#define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__ ((exclusive_trylock_function(__VA_ARGS__)))
|
||||
#define SHARED_TRYLOCK_FUNCTION(...) __attribute__ ((shared_trylock_function(__VA_ARGS__)))
|
||||
#define UNLOCK_FUNCTION(...) __attribute__ ((unlock_function(__VA_ARGS__)))
|
||||
#define LOCK_RETURNED(x) __attribute__ ((lock_returned(x)))
|
||||
#define LOCKS_EXCLUDED(...) __attribute__ ((locks_excluded(__VA_ARGS__)))
|
||||
#define EXCLUSIVE_LOCKS_REQUIRED(...) __attribute__ ((exclusive_locks_required(__VA_ARGS__)))
|
||||
#define SHARED_LOCKS_REQUIRED(...) __attribute__ ((shared_locks_required(__VA_ARGS__)))
|
||||
#define NO_THREAD_SAFETY_ANALYSIS __attribute__ ((no_thread_safety_analysis))
|
||||
#define LOCKABLE __attribute__((lockable))
|
||||
#define SCOPED_LOCKABLE __attribute__((scoped_lockable))
|
||||
#define GUARDED_BY(x) __attribute__((guarded_by(x)))
|
||||
#define GUARDED_VAR __attribute__((guarded_var))
|
||||
#define PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x)))
|
||||
#define PT_GUARDED_VAR __attribute__((pt_guarded_var))
|
||||
#define ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__)))
|
||||
#define ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__)))
|
||||
#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__((exclusive_lock_function(__VA_ARGS__)))
|
||||
#define SHARED_LOCK_FUNCTION(...) __attribute__((shared_lock_function(__VA_ARGS__)))
|
||||
#define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__((exclusive_trylock_function(__VA_ARGS__)))
|
||||
#define SHARED_TRYLOCK_FUNCTION(...) __attribute__((shared_trylock_function(__VA_ARGS__)))
|
||||
#define UNLOCK_FUNCTION(...) __attribute__((unlock_function(__VA_ARGS__)))
|
||||
#define LOCK_RETURNED(x) __attribute__((lock_returned(x)))
|
||||
#define LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__)))
|
||||
#define EXCLUSIVE_LOCKS_REQUIRED(...) __attribute__((exclusive_locks_required(__VA_ARGS__)))
|
||||
#define SHARED_LOCKS_REQUIRED(...) __attribute__((shared_locks_required(__VA_ARGS__)))
|
||||
#define NO_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis))
|
||||
#else
|
||||
#define LOCKABLE
|
||||
#define SCOPED_LOCKABLE
|
||||
|
@ -50,6 +50,6 @@
|
|||
#define EXCLUSIVE_LOCKS_REQUIRED(...)
|
||||
#define SHARED_LOCKS_REQUIRED(...)
|
||||
#define NO_THREAD_SAFETY_ANALYSIS
|
||||
#endif // __GNUC__
|
||||
#endif // __GNUC__
|
||||
|
||||
#endif // BITCOIN_THREADSAFETY_H
|
||||
#endif // BITCOIN_THREADSAFETY_H
|
||||
|
|
|
@ -15,15 +15,16 @@ class CNetAddr;
|
|||
/** Median filter over a stream of values.
|
||||
* Returns the median of the last N numbers
|
||||
*/
|
||||
template <typename T> class CMedianFilter
|
||||
template <typename T>
|
||||
class CMedianFilter
|
||||
{
|
||||
private:
|
||||
std::vector<T> vValues;
|
||||
std::vector<T> vSorted;
|
||||
unsigned int nSize;
|
||||
|
||||
public:
|
||||
CMedianFilter(unsigned int size, T initial_value):
|
||||
nSize(size)
|
||||
CMedianFilter(unsigned int size, T initial_value) : nSize(size)
|
||||
{
|
||||
vValues.reserve(size);
|
||||
vValues.push_back(initial_value);
|
||||
|
@ -32,8 +33,7 @@ public:
|
|||
|
||||
void input(T value)
|
||||
{
|
||||
if(vValues.size() == nSize)
|
||||
{
|
||||
if (vValues.size() == nSize) {
|
||||
vValues.erase(vValues.begin());
|
||||
}
|
||||
vValues.push_back(value);
|
||||
|
@ -46,14 +46,13 @@ public:
|
|||
T median() const
|
||||
{
|
||||
int size = vSorted.size();
|
||||
assert(size>0);
|
||||
if(size & 1) // Odd number of elements
|
||||
assert(size > 0);
|
||||
if (size & 1) // Odd number of elements
|
||||
{
|
||||
return vSorted[size/2];
|
||||
}
|
||||
else // Even number of elements
|
||||
return vSorted[size / 2];
|
||||
} else // Even number of elements
|
||||
{
|
||||
return (vSorted[size/2-1] + vSorted[size/2]) / 2;
|
||||
return (vSorted[size / 2 - 1] + vSorted[size / 2]) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,7 +61,7 @@ public:
|
|||
return vValues.size();
|
||||
}
|
||||
|
||||
std::vector<T> sorted () const
|
||||
std::vector<T> sorted() const
|
||||
{
|
||||
return vSorted;
|
||||
}
|
||||
|
|
133
src/uint256.cpp
133
src/uint256.cpp
|
@ -10,13 +10,13 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
template<unsigned int BITS>
|
||||
template <unsigned int BITS>
|
||||
base_uint<BITS>::base_uint(const std::string& str)
|
||||
{
|
||||
SetHex(str);
|
||||
}
|
||||
|
||||
template<unsigned int BITS>
|
||||
template <unsigned int BITS>
|
||||
base_uint<BITS>::base_uint(const std::vector<unsigned char>& vch)
|
||||
{
|
||||
if (vch.size() != sizeof(pn))
|
||||
|
@ -24,7 +24,7 @@ base_uint<BITS>::base_uint(const std::vector<unsigned char>& vch)
|
|||
memcpy(pn, &vch[0], sizeof(pn));
|
||||
}
|
||||
|
||||
template<unsigned int BITS>
|
||||
template <unsigned int BITS>
|
||||
base_uint<BITS>& base_uint<BITS>::operator<<=(unsigned int shift)
|
||||
{
|
||||
base_uint<BITS> a(*this);
|
||||
|
@ -33,15 +33,15 @@ base_uint<BITS>& base_uint<BITS>::operator<<=(unsigned int shift)
|
|||
int k = shift / 32;
|
||||
shift = shift % 32;
|
||||
for (int i = 0; i < WIDTH; i++) {
|
||||
if (i+k+1 < WIDTH && shift != 0)
|
||||
pn[i+k+1] |= (a.pn[i] >> (32-shift));
|
||||
if (i+k < WIDTH)
|
||||
pn[i+k] |= (a.pn[i] << shift);
|
||||
if (i + k + 1 < WIDTH && shift != 0)
|
||||
pn[i + k + 1] |= (a.pn[i] >> (32 - shift));
|
||||
if (i + k < WIDTH)
|
||||
pn[i + k] |= (a.pn[i] << shift);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<unsigned int BITS>
|
||||
template <unsigned int BITS>
|
||||
base_uint<BITS>& base_uint<BITS>::operator>>=(unsigned int shift)
|
||||
{
|
||||
base_uint<BITS> a(*this);
|
||||
|
@ -50,15 +50,15 @@ base_uint<BITS>& base_uint<BITS>::operator>>=(unsigned int shift)
|
|||
int k = shift / 32;
|
||||
shift = shift % 32;
|
||||
for (int i = 0; i < WIDTH; i++) {
|
||||
if (i-k-1 >= 0 && shift != 0)
|
||||
pn[i-k-1] |= (a.pn[i] << (32-shift));
|
||||
if (i-k >= 0)
|
||||
pn[i-k] |= (a.pn[i] >> shift);
|
||||
if (i - k - 1 >= 0 && shift != 0)
|
||||
pn[i - k - 1] |= (a.pn[i] << (32 - shift));
|
||||
if (i - k >= 0)
|
||||
pn[i - k] |= (a.pn[i] >> shift);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<unsigned int BITS>
|
||||
template <unsigned int BITS>
|
||||
base_uint<BITS>& base_uint<BITS>::operator*=(uint32_t b32)
|
||||
{
|
||||
uint64_t carry = 0;
|
||||
|
@ -70,7 +70,7 @@ base_uint<BITS>& base_uint<BITS>::operator*=(uint32_t b32)
|
|||
return *this;
|
||||
}
|
||||
|
||||
template<unsigned int BITS>
|
||||
template <unsigned int BITS>
|
||||
base_uint<BITS>& base_uint<BITS>::operator*=(const base_uint& b)
|
||||
{
|
||||
base_uint<BITS> a = *this;
|
||||
|
@ -86,12 +86,12 @@ base_uint<BITS>& base_uint<BITS>::operator*=(const base_uint& b)
|
|||
return *this;
|
||||
}
|
||||
|
||||
template<unsigned int BITS>
|
||||
template <unsigned int BITS>
|
||||
base_uint<BITS>& base_uint<BITS>::operator/=(const base_uint& b)
|
||||
{
|
||||
base_uint<BITS> div = b; // make a copy, so we can shift.
|
||||
base_uint<BITS> div = b; // make a copy, so we can shift.
|
||||
base_uint<BITS> num = *this; // make a copy, so we can subtract.
|
||||
*this = 0; // the quotient.
|
||||
*this = 0; // the quotient.
|
||||
int num_bits = num.bits();
|
||||
int div_bits = div.bits();
|
||||
if (div_bits == 0)
|
||||
|
@ -112,9 +112,10 @@ base_uint<BITS>& base_uint<BITS>::operator/=(const base_uint& b)
|
|||
return *this;
|
||||
}
|
||||
|
||||
template<unsigned int BITS>
|
||||
int base_uint<BITS>::CompareTo(const base_uint<BITS>& b) const {
|
||||
for (int i = WIDTH-1; i >= 0; i--) {
|
||||
template <unsigned int BITS>
|
||||
int base_uint<BITS>::CompareTo(const base_uint<BITS>& b) const
|
||||
{
|
||||
for (int i = WIDTH - 1; i >= 0; i--) {
|
||||
if (pn[i] < b.pn[i])
|
||||
return -1;
|
||||
if (pn[i] > b.pn[i])
|
||||
|
@ -123,9 +124,10 @@ int base_uint<BITS>::CompareTo(const base_uint<BITS>& b) const {
|
|||
return 0;
|
||||
}
|
||||
|
||||
template<unsigned int BITS>
|
||||
bool base_uint<BITS>::EqualTo(uint64_t b) const {
|
||||
for (int i = WIDTH-1; i >= 2; i--) {
|
||||
template <unsigned int BITS>
|
||||
bool base_uint<BITS>::EqualTo(uint64_t b) const
|
||||
{
|
||||
for (int i = WIDTH - 1; i >= 2; i--) {
|
||||
if (pn[i])
|
||||
return false;
|
||||
}
|
||||
|
@ -136,7 +138,7 @@ bool base_uint<BITS>::EqualTo(uint64_t b) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
template<unsigned int BITS>
|
||||
template <unsigned int BITS>
|
||||
double base_uint<BITS>::getdouble() const
|
||||
{
|
||||
double ret = 0.0;
|
||||
|
@ -148,19 +150,19 @@ double base_uint<BITS>::getdouble() const
|
|||
return ret;
|
||||
}
|
||||
|
||||
template<unsigned int BITS>
|
||||
template <unsigned int BITS>
|
||||
std::string base_uint<BITS>::GetHex() const
|
||||
{
|
||||
char psz[sizeof(pn)*2 + 1];
|
||||
char psz[sizeof(pn) * 2 + 1];
|
||||
for (unsigned int i = 0; i < sizeof(pn); i++)
|
||||
sprintf(psz + i*2, "%02x", ((unsigned char*)pn)[sizeof(pn) - i - 1]);
|
||||
return std::string(psz, psz + sizeof(pn)*2);
|
||||
sprintf(psz + i * 2, "%02x", ((unsigned char*)pn)[sizeof(pn) - i - 1]);
|
||||
return std::string(psz, psz + sizeof(pn) * 2);
|
||||
}
|
||||
|
||||
template<unsigned int BITS>
|
||||
template <unsigned int BITS>
|
||||
void base_uint<BITS>::SetHex(const char* psz)
|
||||
{
|
||||
memset(pn,0,sizeof(pn));
|
||||
memset(pn, 0, sizeof(pn));
|
||||
|
||||
// skip leading spaces
|
||||
while (isspace(*psz))
|
||||
|
@ -186,28 +188,28 @@ void base_uint<BITS>::SetHex(const char* psz)
|
|||
}
|
||||
}
|
||||
|
||||
template<unsigned int BITS>
|
||||
template <unsigned int BITS>
|
||||
void base_uint<BITS>::SetHex(const std::string& str)
|
||||
{
|
||||
SetHex(str.c_str());
|
||||
}
|
||||
|
||||
template<unsigned int BITS>
|
||||
template <unsigned int BITS>
|
||||
std::string base_uint<BITS>::ToString() const
|
||||
{
|
||||
return (GetHex());
|
||||
}
|
||||
|
||||
template<unsigned int BITS>
|
||||
template <unsigned int BITS>
|
||||
unsigned int base_uint<BITS>::bits() const
|
||||
{
|
||||
for (int pos = WIDTH-1; pos >= 0; pos--) {
|
||||
for (int pos = WIDTH - 1; pos >= 0; pos--) {
|
||||
if (pn[pos]) {
|
||||
for (int bits = 31; bits > 0; bits--) {
|
||||
if (pn[pos] & 1<<bits)
|
||||
return 32*pos + bits + 1;
|
||||
if (pn[pos] & 1 << bits)
|
||||
return 32 * pos + bits + 1;
|
||||
}
|
||||
return 32*pos + 1;
|
||||
return 32 * pos + 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -249,16 +251,16 @@ template unsigned int base_uint<256>::bits() const;
|
|||
|
||||
// This implementation directly uses shifts instead of going
|
||||
// through an intermediate MPI representation.
|
||||
uint256& uint256::SetCompact(uint32_t nCompact, bool *pfNegative, bool *pfOverflow)
|
||||
uint256& uint256::SetCompact(uint32_t nCompact, bool* pfNegative, bool* pfOverflow)
|
||||
{
|
||||
int nSize = nCompact >> 24;
|
||||
uint32_t nWord = nCompact & 0x007fffff;
|
||||
if (nSize <= 3) {
|
||||
nWord >>= 8*(3-nSize);
|
||||
nWord >>= 8 * (3 - nSize);
|
||||
*this = nWord;
|
||||
} else {
|
||||
*this = nWord;
|
||||
*this <<= 8*(nSize-3);
|
||||
*this <<= 8 * (nSize - 3);
|
||||
}
|
||||
if (pfNegative)
|
||||
*pfNegative = nWord != 0 && (nCompact & 0x00800000) != 0;
|
||||
|
@ -274,9 +276,9 @@ uint32_t uint256::GetCompact(bool fNegative) const
|
|||
int nSize = (bits() + 7) / 8;
|
||||
uint32_t nCompact = 0;
|
||||
if (nSize <= 3) {
|
||||
nCompact = GetLow64() << 8*(3-nSize);
|
||||
nCompact = GetLow64() << 8 * (3 - nSize);
|
||||
} else {
|
||||
uint256 bn = *this >> 8*(nSize-3);
|
||||
uint256 bn = *this >> 8 * (nSize - 3);
|
||||
nCompact = bn.GetLow64();
|
||||
}
|
||||
// The 0x00800000 bit denotes the sign.
|
||||
|
@ -295,27 +297,46 @@ uint32_t uint256::GetCompact(bool fNegative) const
|
|||
static void inline HashMix(uint32_t& a, uint32_t& b, uint32_t& c)
|
||||
{
|
||||
// Taken from lookup3, by Bob Jenkins.
|
||||
a -= c; a ^= ((c << 4) | (c >> 28)); c += b;
|
||||
b -= a; b ^= ((a << 6) | (a >> 26)); a += c;
|
||||
c -= b; c ^= ((b << 8) | (b >> 24)); b += a;
|
||||
a -= c; a ^= ((c << 16) | (c >> 16)); c += b;
|
||||
b -= a; b ^= ((a << 19) | (a >> 13)); a += c;
|
||||
c -= b; c ^= ((b << 4) | (b >> 28)); b += a;
|
||||
a -= c;
|
||||
a ^= ((c << 4) | (c >> 28));
|
||||
c += b;
|
||||
b -= a;
|
||||
b ^= ((a << 6) | (a >> 26));
|
||||
a += c;
|
||||
c -= b;
|
||||
c ^= ((b << 8) | (b >> 24));
|
||||
b += a;
|
||||
a -= c;
|
||||
a ^= ((c << 16) | (c >> 16));
|
||||
c += b;
|
||||
b -= a;
|
||||
b ^= ((a << 19) | (a >> 13));
|
||||
a += c;
|
||||
c -= b;
|
||||
c ^= ((b << 4) | (b >> 28));
|
||||
b += a;
|
||||
}
|
||||
|
||||
static void inline HashFinal(uint32_t& a, uint32_t& b, uint32_t& c)
|
||||
{
|
||||
// Taken from lookup3, by Bob Jenkins.
|
||||
c ^= b; c -= ((b << 14) | (b >> 18));
|
||||
a ^= c; a -= ((c << 11) | (c >> 21));
|
||||
b ^= a; b -= ((a << 25) | (a >> 7));
|
||||
c ^= b; c -= ((b << 16) | (b >> 16));
|
||||
a ^= c; a -= ((c << 4) | (c >> 28));
|
||||
b ^= a; b -= ((a << 14) | (a >> 18));
|
||||
c ^= b; c -= ((b << 24) | (b >> 8));
|
||||
c ^= b;
|
||||
c -= ((b << 14) | (b >> 18));
|
||||
a ^= c;
|
||||
a -= ((c << 11) | (c >> 21));
|
||||
b ^= a;
|
||||
b -= ((a << 25) | (a >> 7));
|
||||
c ^= b;
|
||||
c -= ((b << 16) | (b >> 16));
|
||||
a ^= c;
|
||||
a -= ((c << 4) | (c >> 28));
|
||||
b ^= a;
|
||||
b -= ((a << 14) | (a >> 18));
|
||||
c ^= b;
|
||||
c -= ((b << 24) | (b >> 8));
|
||||
}
|
||||
|
||||
uint64_t uint256::GetHash(const uint256 &salt) const
|
||||
uint64_t uint256::GetHash(const uint256& salt) const
|
||||
{
|
||||
uint32_t a, b, c;
|
||||
a = b = c = 0xdeadbeef + (WIDTH << 2);
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
const std::string CLIENT_NAME("Satoshi");
|
||||
|
||||
// Client version number
|
||||
#define CLIENT_VERSION_SUFFIX ""
|
||||
#define CLIENT_VERSION_SUFFIX ""
|
||||
|
||||
|
||||
// The following part of the code determines the CLIENT_BUILD variable.
|
||||
|
@ -35,40 +35,40 @@ const std::string CLIENT_NAME("Satoshi");
|
|||
|
||||
// First, include build.h if requested
|
||||
#ifdef HAVE_BUILD_INFO
|
||||
# include "build.h"
|
||||
#include "build.h"
|
||||
#endif
|
||||
|
||||
// git will put "#define GIT_ARCHIVE 1" on the next line inside archives. $Format:%n#define GIT_ARCHIVE 1$
|
||||
#ifdef GIT_ARCHIVE
|
||||
# define GIT_COMMIT_ID "$Format:%h$"
|
||||
# define GIT_COMMIT_DATE "$Format:%cD$"
|
||||
#define GIT_COMMIT_ID "$Format:%h$"
|
||||
#define GIT_COMMIT_DATE "$Format:%cD$"
|
||||
#endif
|
||||
|
||||
#define BUILD_DESC_WITH_SUFFIX(maj,min,rev,build,suffix) \
|
||||
#define BUILD_DESC_WITH_SUFFIX(maj, min, rev, build, suffix) \
|
||||
"v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-" DO_STRINGIZE(suffix)
|
||||
|
||||
#define BUILD_DESC_FROM_COMMIT(maj,min,rev,build,commit) \
|
||||
#define BUILD_DESC_FROM_COMMIT(maj, min, rev, build, commit) \
|
||||
"v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-g" commit
|
||||
|
||||
#define BUILD_DESC_FROM_UNKNOWN(maj,min,rev,build) \
|
||||
#define BUILD_DESC_FROM_UNKNOWN(maj, min, rev, build) \
|
||||
"v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-unk"
|
||||
|
||||
#ifndef BUILD_DESC
|
||||
# ifdef BUILD_SUFFIX
|
||||
# define BUILD_DESC BUILD_DESC_WITH_SUFFIX(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD, BUILD_SUFFIX)
|
||||
# elif defined(GIT_COMMIT_ID)
|
||||
# define BUILD_DESC BUILD_DESC_FROM_COMMIT(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD, GIT_COMMIT_ID)
|
||||
# else
|
||||
# define BUILD_DESC BUILD_DESC_FROM_UNKNOWN(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD)
|
||||
# endif
|
||||
#ifdef BUILD_SUFFIX
|
||||
#define BUILD_DESC BUILD_DESC_WITH_SUFFIX(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD, BUILD_SUFFIX)
|
||||
#elif defined(GIT_COMMIT_ID)
|
||||
#define BUILD_DESC BUILD_DESC_FROM_COMMIT(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD, GIT_COMMIT_ID)
|
||||
#else
|
||||
#define BUILD_DESC BUILD_DESC_FROM_UNKNOWN(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef BUILD_DATE
|
||||
# ifdef GIT_COMMIT_DATE
|
||||
# define BUILD_DATE GIT_COMMIT_DATE
|
||||
# else
|
||||
# define BUILD_DATE __DATE__ ", " __TIME__
|
||||
# endif
|
||||
#ifdef GIT_COMMIT_DATE
|
||||
#define BUILD_DATE GIT_COMMIT_DATE
|
||||
#else
|
||||
#define BUILD_DATE __DATE__ ", " __TIME__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX);
|
||||
|
@ -76,10 +76,10 @@ const std::string CLIENT_DATE(BUILD_DATE);
|
|||
|
||||
static std::string FormatVersion(int nVersion)
|
||||
{
|
||||
if (nVersion%100 == 0)
|
||||
return strprintf("%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100);
|
||||
if (nVersion % 100 == 0)
|
||||
return strprintf("%d.%d.%d", nVersion / 1000000, (nVersion / 10000) % 100, (nVersion / 100) % 100);
|
||||
else
|
||||
return strprintf("%d.%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100, nVersion%100);
|
||||
return strprintf("%d.%d.%d.%d", nVersion / 1000000, (nVersion / 10000) % 100, (nVersion / 100) % 100, nVersion % 100);
|
||||
}
|
||||
|
||||
std::string FormatFullVersion()
|
||||
|
|
Loading…
Reference in a new issue