Merge branch '1.8.3-dev' into 1.8-maint

This commit is contained in:
langerhans 2015-07-02 19:54:14 +02:00
commit 66eb58e86c
24 changed files with 823 additions and 795 deletions

24
RELEASE_NOTES_1.8.3.md Normal file
View file

@ -0,0 +1,24 @@
# Dogecoin Core 1.8.3
Dogecoin Core 1.8.3 is a security release. It fixes issues in regards to an upcoming announcement of possible DoS vulnerabilities.
See [the announcement on the bitcoin-dev mailing list](https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-June/009135.html) for reference.
It is strongly recommended to upgrade your installation in case you run a node open to inbound connections from the internet.
If your installation is not open to incoming connections this update is not mandatory, but we still recommend keeping your client up to date.
## Dogecoin Core Release Notes
* Pull in patches from usptream to mitigate the risk of a DoS attack.
* Update the DNS seeds for more reliable bootstrapping of the initial peer discovery.
* Update the list of fixed nodes, in case all other means of peer discovery fail.
## Credits
Listed in strictly alphabetical order, using name listed in Github. This
includes those whose contributions to Bitcoin Core have been merged
into this Dogecoin Core release:
* P. Kaufmann
* Max K.
* Ross Nicoll
* Wladimir J. van der Laan
* Pieter Wuille

View file

@ -2,10 +2,10 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 1)
define(_CLIENT_VERSION_MINOR, 8)
define(_CLIENT_VERSION_REVISION, 2)
define(_CLIENT_VERSION_REVISION, 3)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2014)
define(_COPYRIGHT_YEAR, 2015)
AC_INIT([Dogecoin Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[info@dogecoin.com],[dogecoin])
AC_CONFIG_AUX_DIR([src/build-aux])
AC_CONFIG_MACRO_DIR([src/m4])

View file

@ -10,7 +10,7 @@ touch "$DATADIR/regtest/debug.log"
tail -q -n 1 -F "$DATADIR/regtest/debug.log" | grep -m 1 -q "Done loading" &
WAITER=$!
PORT=`expr $BASHPID + 10000`
"@abs_top_builddir@/src/bitcoind@EXEEXT@" -connect=0.0.0.0 -datadir="$DATADIR" -rpcuser=user -rpcpassword=pass -listen -keypool=3 -debug -debug=net -logtimestamps -port=$PORT -regtest -rpcport=`expr $PORT + 1` &
"@abs_top_builddir@/src/bitcoind@EXEEXT@" -connect=0.0.0.0 -datadir="$DATADIR" -rpcuser=user -rpcpassword=pass -listen -keypool=3 -debug -debug=net -logtimestamps -port=$PORT -whitelist=127.0.0.1 -regtest -rpcport=`expr $PORT + 1` &
BITCOIND=$!
#Install a watchdog.

View file

@ -9,34 +9,27 @@
using namespace std;
int CAddrInfo::GetTriedBucket(const std::vector<unsigned char> &nKey) const
int CAddrInfo::GetTriedBucket(const uint256& nKey) const
{
CDataStream ss1(SER_GETHASH, 0);
std::vector<unsigned char> vchKey = GetKey();
ss1 << nKey << vchKey;
uint64_t hash1 = Hash(ss1.begin(), ss1.end()).GetLow64();
CDataStream ss2(SER_GETHASH, 0);
std::vector<unsigned char> vchGroupKey = GetGroup();
ss2 << nKey << vchGroupKey << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP);
uint64_t hash2 = Hash(ss2.begin(), ss2.end()).GetLow64();
uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetHash().GetLow64();
uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup() << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetHash().GetLow64();
return hash2 % ADDRMAN_TRIED_BUCKET_COUNT;
}
int CAddrInfo::GetNewBucket(const std::vector<unsigned char> &nKey, const CNetAddr& src) const
int CAddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src) const
{
CDataStream ss1(SER_GETHASH, 0);
std::vector<unsigned char> vchGroupKey = GetGroup();
std::vector<unsigned char> vchSourceGroupKey = src.GetGroup();
ss1 << nKey << vchGroupKey << vchSourceGroupKey;
uint64_t hash1 = Hash(ss1.begin(), ss1.end()).GetLow64();
CDataStream ss2(SER_GETHASH, 0);
ss2 << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP);
uint64_t hash2 = Hash(ss2.begin(), ss2.end()).GetLow64();
uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup() << vchSourceGroupKey).GetHash().GetLow64();
uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetHash().GetLow64();
return hash2 % ADDRMAN_NEW_BUCKET_COUNT;
}
int CAddrInfo::GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const
{
uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? 'N' : 'K') << nBucket << GetKey()).GetHash().GetLow64();
return hash1 % ADDRMAN_BUCKET_SIZE;
}
bool CAddrInfo::IsTerrible(int64_t nNow) const
{
if (nLastTry && nLastTry >= nNow-60) // never remove things tried the last minute
@ -67,8 +60,6 @@ double CAddrInfo::GetChance(int64_t nNow) const
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)
fChance *= 0.01;
@ -125,93 +116,44 @@ void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2)
vRandom[nRndPos2] = nId1;
}
int CAddrMan::SelectTried(int nKBucket)
void CAddrMan::Delete(int nId)
{
std::vector<int> &vTried = vvTried[nKBucket];
assert(mapInfo.count(nId) != 0);
CAddrInfo& info = mapInfo[nId];
assert(!info.fInTried);
assert(info.nRefCount == 0);
// 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++)
{
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;
}
}
return nOldestPos;
SwapRandom(info.nRandomPos, vRandom.size() - 1);
vRandom.pop_back();
mapAddr.erase(info);
mapInfo.erase(nId);
nNew--;
}
int CAddrMan::ShrinkNew(int nUBucket)
void CAddrMan::ClearNew(int nUBucket, int nUBucketPos)
{
assert(nUBucket >= 0 && (unsigned int)nUBucket < vvNew.size());
std::set<int> &vNew = vvNew[nUBucket];
// first look for deletable items
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);
vRandom.pop_back();
mapAddr.erase(info);
mapInfo.erase(*it);
nNew--;
}
vNew.erase(it);
return 0;
// if there is an entry in the specified bucket, delete it.
if (vvNew[nUBucket][nUBucketPos] != -1) {
int nIdDelete = vvNew[nUBucket][nUBucketPos];
CAddrInfo& infoDelete = mapInfo[nIdDelete];
assert(infoDelete.nRefCount > 0);
infoDelete.nRefCount--;
vvNew[nUBucket][nUBucketPos] = -1;
if (infoDelete.nRefCount == 0) {
Delete(nIdDelete);
}
}
// otherwise, select four randomly, and pick the oldest of those to replace
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])
{
assert(nOldest == -1 || mapInfo.count(*it) == 1);
if (nOldest == -1 || mapInfo[*it].nTime < mapInfo[nOldest].nTime)
nOldest = *it;
}
nI++;
}
assert(mapInfo.count(nOldest) == 1);
CAddrInfo &info = mapInfo[nOldest];
if (--info.nRefCount == 0)
{
SwapRandom(info.nRandomPos, vRandom.size()-1);
vRandom.pop_back();
mapAddr.erase(info);
mapInfo.erase(nOldest);
nNew--;
}
vNew.erase(nOldest);
return 1;
}
void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin)
void CAddrMan::MakeTried(CAddrInfo& info, int nId)
{
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++)
{
if ((*it).erase(nId))
for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
int pos = info.GetBucketPosition(nKey, true, bucket);
if (vvNew[bucket][pos] == nId) {
vvNew[bucket][pos] = -1;
info.nRefCount--;
}
}
nNew--;
@ -219,46 +161,36 @@ 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];
int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
// first check whether there is place to just add it
if (vTried.size() < ADDRMAN_TRIED_BUCKET_SIZE)
{
vTried.push_back(nId);
nTried++;
info.fInTried = true;
return;
// first make space to add it (the existing tried entry there is moved to new, deleting whatever is there).
if (vvTried[nKBucket][nKBucketPos] != -1) {
// find an item to evict
int nIdEvict = vvTried[nKBucket][nKBucketPos];
assert(mapInfo.count(nIdEvict) == 1);
CAddrInfo& infoOld = mapInfo[nIdEvict];
// Remove the to-be-evicted item from the tried set.
infoOld.fInTried = false;
vvTried[nKBucket][nKBucketPos] = -1;
nTried--;
// find which new bucket it belongs to
int nUBucket = infoOld.GetNewBucket(nKey);
int nUBucketPos = infoOld.GetBucketPosition(nKey, true, nUBucket);
ClearNew(nUBucket, nUBucketPos);
assert(vvNew[nUBucket][nUBucketPos] == -1);
// Enter it into the new set again.
infoOld.nRefCount = 1;
vvNew[nUBucket][nUBucketPos] = nIdEvict;
nNew++;
}
assert(vvTried[nKBucket][nKBucketPos] == -1);
// otherwise, find an item to evict
int nPos = SelectTried(nKBucket);
// 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];
// remove the to-be-replaced tried entry from the tried set
CAddrInfo& infoOld = mapInfo[vTried[nPos]];
infoOld.fInTried = false;
infoOld.nRefCount = 1;
// 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 so, move it back there
vNew.insert(vTried[nPos]);
} else {
// otherwise, move it to the new bucket nId came from (there is certainly place there)
vvNew[nOrigin].insert(vTried[nPos]);
}
nNew++;
vTried[nPos] = nId;
// we just overwrote an entry in vTried; no need to update nTried
vvTried[nKBucket][nKBucketPos] = nId;
nTried++;
info.fInTried = true;
return;
}
void CAddrMan::Good_(const CService &addr, int64_t nTime)
@ -279,22 +211,21 @@ void CAddrMan::Good_(const CService &addr, int64_t nTime)
// update info
info.nLastSuccess = nTime;
info.nLastTry = nTime;
info.nTime = nTime;
info.nAttempts = 0;
// nTime is not updated here, to avoid leaking information about
// currently-connected peers.
// if it is already in the tried set, don't do anything else
if (info.fInTried)
return;
// find a bucket it is in now
int nRnd = GetRandInt(vvNew.size());
int nRnd = GetRandInt(ADDRMAN_NEW_BUCKET_COUNT);
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 < ADDRMAN_NEW_BUCKET_COUNT; n++) {
int nB = (n + nRnd) % ADDRMAN_NEW_BUCKET_COUNT;
int nBpos = info.GetBucketPosition(nKey, true, nB);
if (vvNew[nB][nBpos] == nId) {
nUBucket = nB;
break;
}
@ -307,7 +238,7 @@ void CAddrMan::Good_(const CService &addr, int64_t nTime)
LogPrint("addrman", "Moving %s to tried\n", addr.ToString());
// move nId to the tried tables
MakeTried(info, nId, nUBucket);
MakeTried(info, nId);
}
bool CAddrMan::Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty)
@ -356,13 +287,25 @@ 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))
{
pinfo->nRefCount++;
if (vNew.size() == ADDRMAN_NEW_BUCKET_SIZE)
ShrinkNew(nUBucket);
vvNew[nUBucket].insert(nId);
int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket);
if (vvNew[nUBucket][nUBucketPos] != nId) {
bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;
if (!fInsert) {
CAddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];
if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) {
// Overwrite the existing new table entry.
fInsert = true;
}
}
if (fInsert) {
ClearNew(nUBucket, nUBucketPos);
pinfo->nRefCount++;
vvNew[nUBucket][nUBucketPos] = nId;
} else {
if (pinfo->nRefCount == 0) {
Delete(nId);
}
}
}
return fNew;
}
@ -386,44 +329,39 @@ void CAddrMan::Attempt_(const CService &addr, int64_t nTime)
info.nAttempts++;
}
CAddress CAddrMan::Select_(int nUnkBias)
CAddress CAddrMan::Select_()
{
if (size() == 0)
return CAddress();
double nCorTried = sqrt(nTried) * (100.0 - nUnkBias);
double nCorNew = sqrt(nNew) * nUnkBias;
if ((nCorTried + nCorNew)*GetRandInt(1<<30)/(1<<30) < nCorTried)
{
// Use a 50% chance for choosing between tried and new table entries.
if (nTried > 0 && (nNew == 0 || GetRandInt(2) == 0)) {
// use a tried node
double fChanceFactor = 1.0;
while(1)
{
int nKBucket = GetRandInt(vvTried.size());
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))
while (1) {
int nKBucket = GetRandInt(ADDRMAN_TRIED_BUCKET_COUNT);
int nKBucketPos = GetRandInt(ADDRMAN_BUCKET_SIZE);
if (vvTried[nKBucket][nKBucketPos] == -1)
continue;
int nId = vvTried[nKBucket][nKBucketPos];
assert(mapInfo.count(nId) == 1);
CAddrInfo& info = mapInfo[nId];
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)
{
int nUBucket = GetRandInt(vvNew.size());
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))
while (1) {
int nUBucket = GetRandInt(ADDRMAN_NEW_BUCKET_COUNT);
int nUBucketPos = GetRandInt(ADDRMAN_BUCKET_SIZE);
if (vvNew[nUBucket][nUBucketPos] == -1)
continue;
int nId = vvNew[nUBucket][nUBucketPos];
assert(mapInfo.count(nId) == 1);
CAddrInfo& info = mapInfo[nId];
if (GetRandInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30))
return info;
fChanceFactor *= 1.2;
}
@ -462,29 +400,37 @@ int CAddrMan::Check_()
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;
setTried.erase(*it);
for (int n = 0; n < ADDRMAN_TRIED_BUCKET_COUNT; n++) {
for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
if (vvTried[n][i] != -1) {
if (!setTried.count(vvTried[n][i]))
return -11;
if (mapInfo[vvTried[n][i]].GetTriedBucket(nKey) != n)
return -17;
if (mapInfo[vvTried[n][i]].GetBucketPosition(nKey, false, n) != i)
return -18;
setTried.erase(vvTried[n][i]);
}
}
}
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);
for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
if (vvNew[n][i] != -1) {
if (!mapNew.count(vvNew[n][i]))
return -12;
if (mapInfo[vvNew[n][i]].GetBucketPosition(nKey, true, n) != i)
return -19;
if (--mapNew[vvNew[n][i]] == 0)
mapNew.erase(vvNew[n][i]);
}
}
}
if (setTried.size()) return -13;
if (mapNew.size()) return -15;
if (nKey.IsNull())
return -16;
return 0;
}

View file

@ -8,6 +8,7 @@
#include "netbase.h"
#include "protocol.h"
#include "sync.h"
#include "uint256.h"
#include "util.h"
#include <map>
@ -75,17 +76,20 @@ public:
}
// Calculate in which "tried" bucket this entry belongs
int GetTriedBucket(const std::vector<unsigned char> &nKey) const;
int GetTriedBucket(const uint256 &nKey) const;
// Calculate in which "new" bucket this entry belongs, given a certain source
int GetNewBucket(const std::vector<unsigned char> &nKey, const CNetAddr& src) const;
int GetNewBucket(const uint256 &nKey, const CNetAddr& src) const;
// Calculate in which "new" bucket this entry belongs, using its default source
int GetNewBucket(const std::vector<unsigned char> &nKey) const
int GetNewBucket(const uint256 &nKey) const
{
return GetNewBucket(nKey, source);
}
//! Calculate in which position of a bucket to store this entry.
int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const;
// Determine whether the statistics about this entry are bad enough so that it can just be deleted
bool IsTerrible(int64_t nNow = GetAdjustedTime()) const;
@ -94,55 +98,49 @@ public:
};
// Stochastic address manager
//
// Design goals:
// * Only keep a limited number of addresses around, so that addr.dat and memory requirements do not grow without bound.
// * Keep the address tables in-memory, and asynchronously dump the entire to able in addr.dat.
// * Make sure no (localized) attacker can fill the entire table with his nodes/addresses.
//
// To that end:
// * Addresses are organized into buckets.
// * Address that have not yet been tried go into 256 "new" buckets.
// * Based on the address range (/16 for IPv4) of source of the information, 32 buckets are selected at random
// * The actual bucket is chosen from one of these, based on the range the address itself is located.
// * One single address can occur in up to 4 different buckets, to increase selection chances for addresses that
// are seen frequently. The chance for increasing this multiplicity decreases exponentially.
// * When adding a new address to a full bucket, a randomly chosen entry (with a bias favoring less recently seen
// ones) is removed from it first.
// * Addresses of nodes that are known to be accessible go into 64 "tried" buckets.
// * Each address range selects at random 4 of these buckets.
// * The actual bucket is chosen from one of these, based on the full address.
// * When adding a new good address to a full bucket, a randomly chosen entry (with a bias favoring less recently
// tried ones) is evicted from it, back to the "new" buckets.
// * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not
// be observable by adversaries.
// * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN will introduce frequent (and expensive)
// consistency checks for the entire data structure.
/** Stochastic address manager
*
* Design goals:
* * Keep the address tables in-memory, and asynchronously dump the entire to able in peers.dat.
* * Make sure no (localized) attacker can fill the entire table with his nodes/addresses.
*
* To that end:
* * Addresses are organized into buckets.
* * Address that have not yet been tried go into 1024 "new" buckets.
* * Based on the address range (/16 for IPv4) of source of the information, 64 buckets are selected at random
* * The actual bucket is chosen from one of these, based on the range the address itself is located.
* * One single address can occur in up to 8 different buckets, to increase selection chances for addresses that
* are seen frequently. The chance for increasing this multiplicity decreases exponentially.
* * When adding a new address to a full bucket, a randomly chosen entry (with a bias favoring less recently seen
* ones) is removed from it first.
* * Addresses of nodes that are known to be accessible go into 256 "tried" buckets.
* * Each address range selects at random 8 of these buckets.
* * The actual bucket is chosen from one of these, based on the full address.
* * When adding a new good address to a full bucket, a randomly chosen entry (with a bias favoring less recently
* tried ones) is evicted from it, back to the "new" buckets.
* * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not
* be observable by adversaries.
* * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN will introduce frequent (and expensive)
* consistency checks for the entire data structure.
*/
// total number of buckets for tried addresses
#define ADDRMAN_TRIED_BUCKET_COUNT 64
// maximum allowed number of entries in buckets for tried addresses
#define ADDRMAN_TRIED_BUCKET_SIZE 64
#define ADDRMAN_TRIED_BUCKET_COUNT 256
// total number of buckets for new addresses
#define ADDRMAN_NEW_BUCKET_COUNT 256
#define ADDRMAN_NEW_BUCKET_COUNT 1024
// maximum allowed number of entries in buckets for new addresses
#define ADDRMAN_NEW_BUCKET_SIZE 64
// maximum allowed number of entries in buckets for new and tried addresses
#define ADDRMAN_BUCKET_SIZE 64
// over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread
#define ADDRMAN_TRIED_BUCKETS_PER_GROUP 4
#define ADDRMAN_TRIED_BUCKETS_PER_GROUP 8
// over how many buckets entries with new addresses originating from a single group are spread
#define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP 32
#define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP 64
// in how many buckets for entries with new addresses a single address may occur
#define ADDRMAN_NEW_BUCKETS_PER_ADDRESS 4
// how many entries in a bucket with tried addresses are inspected, when selecting one to replace
#define ADDRMAN_TRIED_ENTRIES_INSPECT_ON_EVICT 4
#define ADDRMAN_NEW_BUCKETS_PER_ADDRESS 8
// how old addresses can maximally be
#define ADDRMAN_HORIZON_DAYS 30
@ -170,7 +168,7 @@ private:
mutable CCriticalSection cs;
// secret key to randomize bucket select with
std::vector<unsigned char> nKey;
uint256 nKey;
// last used nId
int nIdCount;
@ -188,13 +186,13 @@ private:
int nTried;
// list of "tried" buckets
std::vector<std::vector<int> > vvTried;
int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE];
// number of (unique) "new" entries
int nNew;
// list of "new" buckets
std::vector<std::set<int> > vvNew;
int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE];
protected:
@ -208,17 +206,14 @@ protected:
// Swap two elements in vRandom.
void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2);
// Return position in given bucket to replace.
int SelectTried(int nKBucket);
// Remove an element from a "new" bucket.
// This is the only place where actual deletes occur.
// They are never deleted while in the "tried" table, only possibly evicted back to the "new" table.
int ShrinkNew(int nUBucket);
// Move an entry from the "new" table(s) to the "tried" table
// @pre vvUnkown[nOrigin].count(nId) != 0
void MakeTried(CAddrInfo& info, int nId, int nOrigin);
void MakeTried(CAddrInfo& info, int nId);
// Delete an entry. It must not be in tried, and have refcount 0.
void Delete(int nId);
// Clear a position in a "new" table. This is the only place where entries are actually deleted.
void ClearNew(int nUBucket, int nUBucketPos);
// Mark an entry "good", possibly moving it from "new" to "tried".
void Good_(const CService &addr, int64_t nTime);
@ -230,8 +225,7 @@ protected:
void Attempt_(const CService &addr, int64_t nTime);
// Select an address to connect to.
// nUnkBias determines how much to favor new addresses over tried ones (min=0, max=100)
CAddress Select_(int nUnkBias);
CAddress Select_();
#ifdef DEBUG_ADDRMAN
// Perform consistency check. Returns an error code or zero.
@ -245,153 +239,220 @@ protected:
void Connected_(const CService &addr, int64_t nTime);
public:
/**
* serialized format:
* * version byte (currently 1)
* * 0x20 + nKey (serialized as if it were a vector, for backward compatibility)
* * nNew
* * nTried
* * number of "new" buckets XOR 2**30
* * all nNew addrinfos in vvNew
* * all nTried addrinfos in vvTried
* * for each bucket:
* * number of elements
* * for each element: index
*
* 2**30 is xorred with the number of buckets to make addrman deserializer v0 detect it
* as incompatible. This is necessary because it did not check the version number on
* deserialization.
*
* Notice that vvTried, mapAddr and vVector are never encoded explicitly;
* they are instead reconstructed from the other information.
*
* vvNew is serialized, but only used if ADDRMAN_UNKOWN_BUCKET_COUNT didn't change,
* otherwise it is reconstructed as well.
*
* This format is more complex, but significantly smaller (at most 1.5 MiB), and supports
* changes to the ADDRMAN_ parameters without breaking the on-disk structure.
*
* We don't use ADD_SERIALIZE_METHODS since the serialization and deserialization code has
* very little in common.
*/
template<typename Stream>
void Serialize(Stream &s, int nType, int nVersionDummy) const
{
LOCK(cs);
IMPLEMENT_SERIALIZE
(({
// serialized format:
// * version byte (currently 0)
// * nKey
// * nNew
// * nTried
// * number of "new" buckets
// * all nNew addrinfos in vvNew
// * all nTried addrinfos in vvTried
// * for each bucket:
// * number of elements
// * for each element: index
//
// Notice that vvTried, mapAddr and vVector are never encoded explicitly;
// they are instead reconstructed from the other information.
//
// vvNew is serialized, but only used if ADDRMAN_UNKOWN_BUCKET_COUNT didn't change,
// otherwise it is reconstructed as well.
//
// This format is more complex, but significantly smaller (at most 1.5 MiB), and supports
// changes to the ADDRMAN_ parameters without breaking the on-disk structure.
{
LOCK(cs);
unsigned char nVersion = 0;
READWRITE(nVersion);
READWRITE(nKey);
READWRITE(nNew);
READWRITE(nTried);
unsigned char nVersion = 1;
s << nVersion;
s << ((unsigned char)32);
s << nKey;
s << nNew;
s << nTried;
CAddrMan *am = const_cast<CAddrMan*>(this);
if (fWrite)
{
int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT;
READWRITE(nUBuckets);
std::map<int, int> mapUnkIds;
int nIds = 0;
for (std::map<int, CAddrInfo>::iterator it = am->mapInfo.begin(); it != am->mapInfo.end(); it++)
{
if (nIds == nNew) break; // this means nNew was wrong, oh ow
mapUnkIds[(*it).first] = nIds;
CAddrInfo &info = (*it).second;
if (info.nRefCount)
{
READWRITE(info);
nIds++;
}
int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
s << nUBuckets;
std::map<int, int> mapUnkIds;
int nIds = 0;
for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {
mapUnkIds[(*it).first] = nIds;
const CAddrInfo &info = (*it).second;
if (info.nRefCount) {
assert(nIds != nNew); // this means nNew was wrong, oh ow
s << info;
nIds++;
}
}
nIds = 0;
for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {
const CAddrInfo &info = (*it).second;
if (info.fInTried) {
assert(nIds != nTried); // this means nTried was wrong, oh ow
s << info;
nIds++;
}
}
for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
int nSize = 0;
for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
if (vvNew[bucket][i] != -1)
nSize++;
}
s << nSize;
for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
if (vvNew[bucket][i] != -1) {
int nIndex = mapUnkIds[vvNew[bucket][i]];
s << nIndex;
}
nIds = 0;
for (std::map<int, CAddrInfo>::iterator it = am->mapInfo.begin(); it != am->mapInfo.end(); it++)
{
if (nIds == nTried) break; // this means nTried was wrong, oh ow
CAddrInfo &info = (*it).second;
if (info.fInTried)
{
READWRITE(info);
nIds++;
}
}
for (std::vector<std::set<int> >::iterator it = am->vvNew.begin(); it != am->vvNew.end(); it++)
{
const std::set<int> &vNew = (*it);
int nSize = vNew.size();
READWRITE(nSize);
for (std::set<int>::iterator it2 = vNew.begin(); it2 != vNew.end(); it2++)
{
int nIndex = mapUnkIds[*it2];
READWRITE(nIndex);
}
}
}
}
template<typename Stream>
void Unserialize(Stream& s, int nType, int nVersionDummy)
{
LOCK(cs);
Clear();
unsigned char nVersion;
s >> nVersion;
unsigned char nKeySize;
s >> nKeySize;
if (nKeySize != 32) throw std::ios_base::failure("Incorrect keysize in addrman deserialization");
s >> nKey;
s >> nNew;
s >> nTried;
int nUBuckets = 0;
s >> nUBuckets;
if (nVersion != 0) {
nUBuckets ^= (1 << 30);
}
// Deserialize entries from the new table.
for (int n = 0; n < nNew; n++) {
CAddrInfo &info = mapInfo[n];
s >> info;
mapAddr[info] = n;
info.nRandomPos = vRandom.size();
vRandom.push_back(n);
if (nVersion != 1 || nUBuckets != ADDRMAN_NEW_BUCKET_COUNT) {
// In case the new table data cannot be used (nVersion unknown, or bucket count wrong),
// immediately try to give them a reference based on their primary source address.
int nUBucket = info.GetNewBucket(nKey);
int nUBucketPos = info.GetBucketPosition(nKey, true, nUBucket);
if (vvNew[nUBucket][nUBucketPos] == -1) {
vvNew[nUBucket][nUBucketPos] = n;
info.nRefCount++;
}
}
}
nIdCount = nNew;
// Deserialize entries from the tried table.
int nLost = 0;
for (int n = 0; n < nTried; n++) {
CAddrInfo info;
s >> info;
int nKBucket = info.GetTriedBucket(nKey);
int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
if (vvTried[nKBucket][nKBucketPos] == -1) {
info.nRandomPos = vRandom.size();
info.fInTried = true;
vRandom.push_back(nIdCount);
mapInfo[nIdCount] = info;
mapAddr[info] = nIdCount;
vvTried[nKBucket][nKBucketPos] = nIdCount;
nIdCount++;
} else {
int nUBuckets = 0;
READWRITE(nUBuckets);
am->nIdCount = 0;
am->mapInfo.clear();
am->mapAddr.clear();
am->vRandom.clear();
am->vvTried = std::vector<std::vector<int> >(ADDRMAN_TRIED_BUCKET_COUNT, std::vector<int>(0));
am->vvNew = std::vector<std::set<int> >(ADDRMAN_NEW_BUCKET_COUNT, std::set<int>());
for (int n = 0; n < am->nNew; n++)
{
CAddrInfo &info = am->mapInfo[n];
READWRITE(info);
am->mapAddr[info] = n;
info.nRandomPos = vRandom.size();
am->vRandom.push_back(n);
if (nUBuckets != ADDRMAN_NEW_BUCKET_COUNT)
{
am->vvNew[info.GetNewBucket(am->nKey)].insert(n);
nLost++;
}
}
nTried -= nLost;
// Deserialize positions in the new table (if possible).
for (int bucket = 0; bucket < nUBuckets; bucket++) {
int nSize = 0;
s >> nSize;
for (int n = 0; n < nSize; n++) {
int nIndex = 0;
s >> nIndex;
if (nIndex >= 0 && nIndex < nNew) {
CAddrInfo &info = mapInfo[nIndex];
int nUBucketPos = info.GetBucketPosition(nKey, true, bucket);
if (nVersion == 1 && nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && vvNew[bucket][nUBucketPos] == -1 && info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS) {
info.nRefCount++;
}
}
am->nIdCount = am->nNew;
int nLost = 0;
for (int n = 0; n < am->nTried; n++)
{
CAddrInfo info;
READWRITE(info);
std::vector<int> &vTried = am->vvTried[info.GetTriedBucket(am->nKey)];
if (vTried.size() < ADDRMAN_TRIED_BUCKET_SIZE)
{
info.nRandomPos = vRandom.size();
info.fInTried = true;
am->vRandom.push_back(am->nIdCount);
am->mapInfo[am->nIdCount] = info;
am->mapAddr[info] = am->nIdCount;
vTried.push_back(am->nIdCount);
am->nIdCount++;
} else {
nLost++;
}
}
am->nTried -= nLost;
for (int b = 0; b < nUBuckets; b++)
{
std::set<int> &vNew = am->vvNew[b];
int nSize = 0;
READWRITE(nSize);
for (int n = 0; n < nSize; n++)
{
int nIndex = 0;
READWRITE(nIndex);
CAddrInfo &info = am->mapInfo[nIndex];
if (nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
{
info.nRefCount++;
vNew.insert(nIndex);
}
vvNew[bucket][nUBucketPos] = nIndex;
}
}
}
}
});)
CAddrMan() : vRandom(0), vvTried(ADDRMAN_TRIED_BUCKET_COUNT, std::vector<int>(0)), vvNew(ADDRMAN_NEW_BUCKET_COUNT, std::set<int>())
// Prune new entries with refcount 0 (as a result of collisions).
int nLostUnk = 0;
for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); ) {
if (it->second.fInTried == false && it->second.nRefCount == 0) {
std::map<int, CAddrInfo>::const_iterator itCopy = it++;
Delete(itCopy->first);
nLostUnk++;
} else {
it++;
}
}
if (nLost + nLostUnk > 0) {
LogPrint("addrman", "addrman lost %i new and %i tried addresses due to collisions\n", nLostUnk, nLost);
}
Check();
}
unsigned int GetSerializeSize(int nType, int nVersion) const
{
nKey.resize(32);
RAND_bytes(&nKey[0], 32);
return (CSizeComputer(nType, nVersion) << *this).size();
}
nIdCount = 0;
nTried = 0;
nNew = 0;
void Clear()
{
std::vector<int>().swap(vRandom);
RAND_bytes((unsigned char *)&nKey, 32);
for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
vvNew[bucket][entry] = -1;
}
}
for (size_t bucket = 0; bucket < ADDRMAN_TRIED_BUCKET_COUNT; bucket++) {
for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
vvTried[bucket][entry] = -1;
}
}
nIdCount = 0;
nTried = 0;
nNew = 0;
}
CAddrMan()
{
Clear();
}
~CAddrMan()
{
nKey = uint256(0);
}
// Return the number of (unique) addresses in all tables.
int size()
int size()
{
return vRandom.size();
}
@ -462,15 +523,16 @@ public:
}
}
// Choose an address to connect to.
// nUnkBias determines how much "new" entries are favored over "tried" ones (0-100).
CAddress Select(int nUnkBias = 50)
/**
* Choose an address to connect to.
*/
CAddress Select()
{
CAddress addrRet;
{
LOCK(cs);
Check();
addrRet = Select_(nUnkBias);
addrRet = Select_();
Check();
}
return addrRet;

View file

@ -22,81 +22,62 @@ using namespace boost::assign;
unsigned int pnSeed[] =
{
0xdc7fa218, 0xb4b68d18, 0xd286166c, 0xb0bbb052, 0x5d9fe2bc, 0x0256c0ad, 0x4297d23e, 0x2cf5226c,
0xa80dfb94, 0xf1a134d0, 0x4215042e, 0x7c51486d, 0x3a51486d, 0xd5c63832, 0xde5b7e02, 0xdb176018,
0x332745ad, 0x7172c7c6, 0xfb90b742, 0x134dd9a2, 0x25e238ae, 0xc332ed40, 0x24a0a4c6, 0xcd5e0905,
0xcaca87dc, 0xe28ac836, 0xc79c2942, 0x672baa6b, 0xa2012363, 0xf848f160, 0x34747b6d, 0xe6f7f1c0,
0xbbc51955, 0x4e106d5b, 0x69e47046, 0x4ca0d54a, 0x6d0a65c6, 0x441d9c32, 0x436d5d81, 0xbdfffbce,
0x1cd2f2a2, 0x112daa6b, 0x30b85f47, 0x02100ab9, 0x2e044bad, 0x2071ff45, 0x5f98b54b, 0x55a40905,
0x651aaa6b, 0xe99ef2c5, 0x17c35ad0, 0x8db55d41, 0x587921cb, 0x3865ea2e, 0xba0d63c0, 0x8eb88b52,
0x7a80a7c7, 0x4d5c5747, 0x3fd4f3a2, 0xf825be43, 0x161eaa6b, 0x43eda52e, 0x03b422b0, 0x5c0e63c0,
0x6dfc47d4, 0x1a017ebc, 0xfb65c7c6, 0x535809b0, 0x8b58f181, 0x2454ed5e, 0x68220254, 0x7aaca143,
0x91c10a55, 0x8bd74ece, 0xd67ef118, 0x0a15aa46, 0xa0c1b1ad, 0x4052d74a, 0xede8494b, 0xd5c49452,
0x8fc97e18, 0x78c01c54, 0x2fbcf1c0, 0x335a046c, 0x3dc8834b, 0x6c550025, 0x278ab5d1, 0xc4422e4e,
0x45e2073a, 0xa83fbd41, 0x738d1581, 0x9a3c0cc3, 0xf48d5436, 0x5ba835c6, 0xc63aaa6b, 0xd33328bc,
0x9f703ab0, 0xee45ba36, 0x78417244, 0xf9e6e460, 0x288eb06c, 0x22a3e417, 0xdade69c6, 0x8b7bc447,
0x7975c244, 0x51ef4cb7, 0x48ecffad, 0x32bf0918, 0xa98baa51, 0xedf5fa60, 0xe0aca658, 0x68fca0d9,
0xe762c7c6, 0x1d2bc24e, 0x612d454b, 0x759fd295, 0xc218ef17, 0xb5c0b162, 0x5aaed56c, 0x1b52dc62,
0x416c2d05, 0x42fbbfc3, 0xdc63134c, 0xc1b9e2bc, 0x0bd7f74d, 0x5eb9e2bc, 0xaf05a843, 0xafdf2e32,
0x7d35bdd5, 0x8feeaa6b, 0x3e9e7d18, 0x47d1079d, 0x4d1d6a57, 0xc6cbffad, 0x0e80a7c7, 0x8dd0e8d8,
0x334a066b, 0x31fae3bc, 0x0669e53a, 0x632c784c, 0x30381cb9, 0xaea5d118, 0xb7ee9ade, 0x4c37175e,
0x9885f3a2, 0xbde5f6d8, 0xae62f3a2, 0xe276692e, 0xba5d1218, 0x511d5618, 0x7e81d78f, 0x14eb4c90,
0x44e5c780, 0xe2708abc, 0xe261d3c6, 0x7aca584a, 0x8c037786, 0x7e3baa6b, 0xb912d8a2, 0x170763c0,
0xbed1d23e, 0xdce46ccf, 0x5cdb1748, 0xc215f5ac, 0x99f7cabc, 0x4d658248, 0x3798bacd, 0x2dbb8932,
0xe93faa6b, 0x639f534b, 0x43f6754c, 0x0440bd44, 0x4919aa6b, 0x30644aad, 0xc96e9c4e, 0x421daa6b,
0x90760248, 0x096a1bc6, 0xba4b40ad, 0x3574fa5b, 0x20fe0732, 0x41535143, 0xdf843944, 0x103b8dd1,
0xde76a032, 0xf405e447, 0xcc86bb25, 0xb3b22e6c, 0x12c35ad0, 0xa330aa6b, 0x14e69544, 0x177becd1,
0xf32e484b, 0x15b1ce6d, 0x0d2c7662, 0x862d6441, 0xa2c39805, 0xc7eeaa6b, 0xf38f494c, 0x16d5b947,
0x9fb8e2bc, 0xe13e175e, 0x656c39ad, 0x7a384946, 0x10460905, 0x9cf870d1, 0xb375c60e, 0x481cba6a,
0x87ed6cd8, 0x2d7b67ae, 0x01540f48, 0x84028fc6, 0xdd85c144, 0x8f53ee54, 0x1a9e4fad, 0x84acc548,
0x52d51248, 0xac47ab43, 0xf16ab743, 0x65ab6f18, 0xa8f73060, 0x56c84832, 0x9c6a604a, 0x8ef1ffad,
0x4676a043, 0x6568c23e, 0x416ed459, 0xb586ec62, 0x122e98c2, 0x81a65618, 0x17db048e, 0x690f3b25,
0xb58c4e32, 0x8e69e297, 0xd4dcaf42, 0x5158ac43, 0x0f9da082, 0x6cbaee60, 0x9e115b82, 0x55dffe96,
0xa899f660, 0x846a0905, 0xf53a9252, 0xb283a4b8, 0x6db66b18, 0x867316b2, 0xdfad5753, 0x59995dd0,
0x5e1caa6b, 0x08b3f160, 0x056a1bc6, 0x9c5403ae, 0x738cae43, 0x77fd211b, 0xd8e3a951, 0x150aad43,
0x558809b0, 0xf04f454a, 0x09daf150, 0x3a433d63, 0xa4daf1c0, 0x4d551ac7, 0xd0edec69, 0xbe36f118,
0x5b76b818, 0x8d919bd8, 0xbc92ea52, 0xe8096ec3, 0x1895e2bc, 0xfd053360, 0x701c42ad, 0x9a8e9bd8,
0xac06aa6b, 0xc9851a56, 0x54f65e46, 0xb39e306c, 0x880763c0, 0x361f1fb0, 0x95a5b04c, 0x897319ad,
0xc1b9be46, 0xe6d89d9d, 0xa75cd443, 0xb7361147, 0x630b8b25, 0x5a2e4ea6, 0x203bbb4b, 0x5b4b6c18,
0x9dbbac43, 0x6d0663c0, 0x1f115536, 0x61d80718, 0xf4fde097, 0xfb50e162, 0x954a6276, 0x0006ee47,
0x30b26eae, 0xf5737358, 0xf9a5fdce, 0xf2c75d18, 0xfda64b25, 0xd565d1a2, 0xf055a743, 0x10aaa545,
0xa70c63c0, 0xa15a4450, 0xdbcb13ad, 0xdc705246, 0x02f7e9c7, 0xe57e6763, 0x65604ead, 0x07df1955,
0x882faa6b, 0xb4286b18, 0x539747c0, 0xc9b6a1c0, 0xb76e7f46, 0xf3418432, 0xd5bbb153, 0xb840d3a2,
0x6c0717d9, 0xb14109b0, 0x94076181, 0xf40aa953, 0x08de89c3, 0x06bdaa4d, 0x27efae32, 0x5ba4fe45,
0x1e7410cc, 0x57e847d4, 0xe5425177, 0xb50b714c, 0x06513532, 0xfde617c6, 0xe05c3532, 0x0af30852,
0xa2a33a60, 0x2cc7f3a2, 0x5777cf57, 0x313477d5, 0x311544c1, 0x49f4aa6b, 0xef01ef17, 0x07db33d4,
0x0a60c947, 0xe4174e4d, 0x34058a12, 0x411e3ab8, 0xfc4a9532, 0x5bcaf082, 0x55c21955, 0x489a32b6,
0xf1f7154c, 0x60fa9f6e, 0x4dc4ec57, 0x5fe7a743, 0x1309e552, 0x03e12c42, 0x07f4175e, 0xcb56aa43,
0x9d411787, 0xc1686041, 0xeec21955, 0xe97cf3a2, 0x11cc6044, 0xce9b2b47, 0x32bb53d4, 0xc7153b25,
0x7c24188d, 0x1640c947, 0x1606b941, 0x671d864b, 0xb4430118, 0x3c6641ad, 0xf99000c0, 0x57a745ad,
0xf098880e, 0x7cd14298, 0xb53316b2, 0x5b0749ae, 0x80c734c6, 0x5bb26318, 0xf5734761, 0xb5a0f1c0,
0x643f3cae, 0xd034324a, 0xd5ef81ae, 0xa383e447, 0x8c820298, 0xeba139ae, 0x1e73c80e, 0x0c3fe743,
0x8ac65918, 0x03104081, 0xa486bb25, 0x24165343, 0x15c67118, 0x6204f948, 0x4e3d5bc6, 0x3ef9f382,
0xe3e7524a, 0x9f10634c, 0xfba8794c, 0x0c2d306c, 0xb99df762, 0x3e1a4d47, 0x3f6c3951, 0xd373354d,
0xca206c4a, 0x6f454aad, 0x02f5af43, 0x0f35831f, 0x31bcd4ad, 0xfa34da48, 0x3a598cae, 0x26ef7f4c,
0xa104b648, 0x9cf2134c, 0xc5c2336c, 0x448f9c5b, 0x55b8f1c0, 0x115917ad, 0x33216f4b, 0x5c67692e,
0xd436c658, 0x7c22da36, 0x0ce9e217, 0xa62a3160, 0xb08803ae, 0xf918c162, 0x0e9c096c, 0xf250119c,
0x0d987f47, 0x40254832, 0x610df245, 0xa55cf3a2, 0xd4886e4a, 0xc172aa43, 0x1af4c04e, 0xbe2d47ae,
0x58a0cf45, 0xa414dc48, 0xdde3f3a2, 0x26562843, 0x9aea0455, 0xb1b63c44, 0xcef89963, 0x12005d4d,
0x21c21754, 0x18eef160, 0x4903a1cf, 0x9b023818, 0x4685336c, 0xc9f31556, 0xe6dd0a18, 0x099630ad,
0x10dabd32, 0xcaaf708c, 0xc53ebb25, 0x42657a90, 0x74e3614c, 0x365c4048, 0x7cf9f3a2, 0x7f2addb0,
0xe6bf09b0, 0x1165fa5b, 0xcef84e43, 0x895be7cf, 0xb2116c4a, 0xa423108a, 0xa3bec236, 0x196db14c,
0xe05f6f4f, 0x07ee0118, 0xdcb8f8ce, 0xbd5e7918, 0x2159ab4d, 0x8ae54170, 0x527b0905, 0x7c8d3d44,
0x0d552705, 0xe5b21cad, 0x1b8ae64e, 0xc79cab55, 0x4e88e2bc, 0x444c1581, 0x86147c4c, 0xb4222648,
0x4136daad, 0x437ea22e, 0x2b92694c, 0x154baa6b, 0x0555795b, 0x9b484232, 0x6944f181, 0x036a6259,
0x1808ff60, 0xb0403148, 0x7b5e1b59, 0xdd30fb62, 0x4583266c, 0xb289c96d, 0x35e4aa6b, 0x50a23532,
0x3f1263c0, 0x763aae6c, 0xa729c144, 0x5ee5c64c, 0x02bf35d0, 0x367f3ac6, 0xfe547940, 0x2e1ea353,
0xe798ee48, 0x6c058495, 0x755dd5cb, 0x2ca6ef63, 0x7a0574bc, 0x9ac81c2e, 0xa5b33e44, 0x4fe69953,
0xf9556d62, 0x086a1bc6, 0xac28126c, 0x4fa7e6ad, 0xd4293d3e, 0x4e4f764b, 0x718849ad, 0x8139ff18,
0x4c6118b9, 0x65444c90, 0x371eeda9, 0xe2b4c0ad, 0xcd01f5da, 0x7671c344, 0x3021f518, 0x26369c4b,
0xd7f6f360, 0xdb55336c, 0xccdc7d18, 0x51d732c6, 0x335b5b4c, 0x094c2d05, 0x0dd546a6, 0x83d33118,
0x33dcff6d, 0xfd40b64c, 0x86e93f18, 0x87e2c780, 0xf0e1c1b2, 0xc67be347, 0x1df9d243, 0x6a646dae,
0xb0833b47, 0x8f457e4c, 0x0dbbe2bc, 0x4ac048c6, 0x7cc2194c, 0x1c84bb25, 0xb66b8218, 0xe3ee027b,
0x5cd4048e, 0xadcb0b18, 0xdc036e18, 0xb62e7999, 0xdee95243, 0x1ccdc344, 0x91cde560, 0xc8e0f460,
0xbea0f1c0, 0x35747b6d, 0x9686bb25, 0x28ce3c47, 0xaf0e5e48, 0x87f58f4b, 0x124dd9a2, 0xa21463c0,
0xa8f94952, 0xf71fd586, 0xe6fa056c, 0x92b86bb8, 0x707d6981, 0x22870732, 0x116fef62, 0xe0fd3ead,
0x78c2814e, 0x95d882c3, 0xdb3cba32, 0xe8b0e2bc, 0xb9c69b18, 0xe29ed783, 0x26c01118, 0xcbcd8451,
0xf1d02e18, 0x1b55aead, 0xb5549bc0, 0x47baa232, 0xbcf8f1c0, 0xae29dbb2, 0x0b881cd2, 0x75c8bb25,
0x14851955, 0xc7113b25, 0xa6db048e, 0x77606505, 0x4f163b25, 0x567c692e, 0x25e02a64, 0x10143b25,
0x93123b25, 0xa463f8a2, 0xef218abc, 0x25133b25, 0xe189bb25, 0xc0f83eb2, 0x6ab7c936, 0xa3624c90,
0x6af8c4d9, 0x38c55b80, 0xb21f09b0, 0x33e7a5bc, 0xf558fb94, 0x6a5c4c90, 0x20d0048e, 0x14d1048e,
0xcabd2e4e, 0x26bfd35f, 0x065e8abc, 0xccce1c2e, 0x2a55ec6d, 0xcd01f5da, 0x0bef32c6, 0x991d5fc0,
0x6f4d4550, 0x0f35831f, 0xc7183b25, 0x8c7b0905, 0x7a9cbb25, 0x7eafa951, 0x86579bc0, 0xa15a4450,
0xe5425177, 0x876e8ad5, 0xf6946257, 0x40c5ffad, 0x2e209d53, 0x6262e773, 0x42ef4c90, 0x9fc351c5,
0x45ac795b, 0x6ac66d4f, 0x0a588abc, 0x9d411787, 0x8f9bbb25, 0xc4288368, 0xf745535b, 0x9c7086cf,
0xc4422e4e, 0xc2533532, 0x84945250, 0x8b5d715e, 0x0f331c73, 0x228a9bd8, 0x4f3f0849, 0x17f4bbd5,
0xc0e64a4a, 0xc53ebb25, 0x8dfab7ad, 0x36097e40, 0x2a27966b, 0x307d8abc, 0x1a32c405, 0xcf8d3c41,
0x809f8705, 0x21f232c6, 0x64693660, 0x83b763c0, 0xc613ec68, 0xaf517462, 0x8f61e497, 0xae7b0451,
0xafd61955, 0x2b85d772, 0xde0cf062, 0xee4ec780, 0xef6aa56f, 0x09b85d61, 0xac44f6cc, 0xc0b73505,
0x0dedb944, 0x554d6f4c, 0x627dfe42, 0x48ca34ae, 0x272371d4, 0xf252a5bc, 0x8740f718, 0x262371d4,
0x3ce82760, 0xe17c8845, 0x7c17332a, 0x4f5abb25, 0x07eccf57, 0x183f6018, 0xcb4b5f5c, 0xc34a0d47,
0x60a4c780, 0xe9c2784c, 0xbccac24d, 0xc143f03c, 0x0260ba7c, 0x4a81ae58, 0xe131b843, 0x1dae7fd5,
0x75d041ad, 0x390c7ed0, 0xaeac6d62, 0x8de20e4c, 0x915ee097, 0x1a3e1049, 0x8aca6f18, 0xd4470444,
0x4856b3ad, 0x387e211b, 0xd191feb6, 0xe3bd0d41, 0x130009b0, 0xdf18be43, 0xdf143b25, 0x1e93e66d,
0x41cfa262, 0x859baa51, 0x3618aa6b, 0x74c5f1c0, 0x3c14226c, 0x5c3cd070, 0xbc671b4f, 0x3f5871d5,
0x37011e02, 0xfe53186c, 0xd39bd176, 0x3822b718, 0xe27d3060, 0xabee32c6, 0xc697c818, 0xd22cde50,
0xc4cc6c3a, 0xd24ccd43, 0xd450bb25, 0x4101ee43, 0x20f232c6, 0xb7997845, 0xd4e3c162, 0x2fbe7670,
0x41a5ee52, 0x800a201b, 0x4699ccda, 0xfcabb552, 0xde53ad32, 0x61668c18, 0xca9ec24e, 0x8b1eac49,
0xb990b142, 0xf1e1784d, 0x30d04147, 0x785a995b, 0x12d14acc, 0x39d43680, 0x65e70844, 0x54783b18,
0x232a3a63, 0x4e0a194f, 0x2b813b18, 0x2ac0bc49, 0x6af1ae51, 0x3256d062, 0x13d72bd9, 0xa5496444,
0xbc944c47, 0x7d35bdd5, 0x109f2446, 0x16ef2e25, 0xe2f2784b, 0xee5ddaac, 0xc7889718, 0xaf49be6d,
0xc914a443, 0x1d2bc24e, 0x82199d5d, 0x689c226c, 0x04441b46, 0x1feca832, 0x94208c55, 0x6756a149,
0x09dee8d8, 0x1435e9a9, 0x82859f32, 0xadf0a662, 0x2f2bb856, 0x756bcd5a, 0x6b6be917, 0x1c40604a,
0xeec4b749, 0x4d44a6b8, 0x162d1cb0, 0x22f232c6, 0x5f2012ad, 0x35612053, 0x02b35e47, 0x2d5c3f44,
0x6904ef17, 0xef8a0b4c, 0xe6908932, 0x0df86c76, 0x3669343c, 0xdd8ba87c, 0x35841386, 0xb406e044,
0x14a6946d, 0x6a448e3f, 0x2341295e, 0xb2837325, 0x82cf0c05, 0xa64d4141, 0xeb24c672, 0x4282ffda,
0xccf2336c, 0x64813fbc, 0x9c81d259, 0xfbe6ed60, 0xc24a1c6c, 0x470ddc48, 0xd4dcaf42, 0x4c373fb2,
0xbb9589d9, 0x7e431bc6, 0x3d24be43, 0xf417af44, 0x83f05243, 0xbe022363, 0x10b71d5d, 0xaf4b88d5,
0xc3b66644, 0x31d30b71, 0xa056aa6b, 0x48db0364, 0x9780f5ac, 0x763aa0ad, 0x8ebcfe40, 0x241847ad,
0xacdbf562, 0xfd09f743, 0x4f211c60, 0x0d963468, 0x80db149a, 0x18e8b944, 0xbcc27746, 0x8f6ce95f,
0xde2cee2e, 0x45a71457, 0xde894ead, 0x024cd348, 0x2e0e74ce, 0x23300cac, 0x90527f62, 0x1d66e56d,
0x83eddb8d, 0x0850f555, 0xe9a4e797, 0x0ef1ab56, 0x140ed98e, 0x2d3f944d, 0x0b6d18bc, 0xab33ca49,
0xaed3b962, 0xc8a0f155, 0xb3eb9c32, 0xfc06424b, 0x927af8ac, 0xdf0119bc, 0xf7ba2452, 0x26590c05,
0x0ec0cb6d, 0x337b252d, 0xe7b04a97, 0x5cc4a505, 0x9e81884a, 0xd052534b, 0xf7aa7761, 0x6666b527,
0x49a4fd62, 0x3f715247, 0x902baa46, 0x7645812e, 0xbf771240, 0xe58e2451, 0xbb95fca2, 0x35204718,
0x759138ae, 0x84300edf, 0x67140d47, 0x2c34465f, 0x260d0f18, 0xfd985c32, 0x3ba94cb2, 0x8067b545,
0x062ac825, 0xdee9de59, 0x6254bf32, 0x9b6d2b44, 0xbebd7670, 0x3c55b46c, 0x5e8e5561, 0xa6d9a656,
0x631fe149, 0x102f0378, 0xf4ede844, 0x34b94b3e, 0x73cdd55a, 0xd114c850, 0x7b6c5343, 0x6a3dde47,
0x385da2b8, 0xf5f8c3d2, 0xe44c0654, 0xa4cb42bb, 0xf53fd176, 0xa424a14b, 0x79b38856, 0xdb717b5d,
0x97f0b8bf, 0x031c4627, 0x9731d35a, 0x7bd81e4c, 0x43a850bc, 0xa336ff71, 0xbabd0b59, 0x9767bc73,
0x1c131d4c, 0x06a47744, 0x1f5dbe5e, 0xf76f18bc, 0x560ab918, 0xd7cb0202, 0x569b326c, 0x52024c72,
0x47525a5f, 0xd36d475f, 0x2e7d5dcc, 0x60330202, 0xd13c026c, 0x1660d7b0, 0x1a042f4e, 0xe644005e,
0x5c53ba41, 0xc5adf651, 0x84e15d62, 0xcb76364d, 0x78ec8573, 0x5f6a06ae, 0xac8d3347, 0xd8758fd5,
0x91c5351f, 0xdd6d67b1, 0x6027e53c, 0x308bba6d, 0x15448945, 0x612d454b, 0x3a10a143, 0x9b38cf56,
0x3c44c556, 0xffb8784c, 0x5409b04b, 0xab2f7661, 0xa286534b, 0x0476c944, 0xd9cf4a52, 0x9cfa276c,
0xaf07936b, 0xfcd02e32, 0x2361db8d, 0xc62c878d, 0x560ae740, 0xb21d0818, 0x7a2c4605, 0x8cc6a73b,
0x5757be56, 0x50f1e218, 0x13b9194f, 0x48eb17ad, 0x4279112e, 0xf92a3fbc, 0x8ecc0202, 0xe93237ae,
0x9bcfc80e, 0x4d72a343, 0xb97eed8d, 0x6732b55e, 0x14fdab43, 0x05e502d4, 0x88bd436d, 0xf4985a86,
0xa12f8156, 0x2a91052e, 0xa651d98e, 0x2f750947, 0x61fd5455, 0x8bbcb66e, 0xd7383a60, 0xd9d3945c,
0x52e5ac2e, 0x5f7a49be, 0x59036a44, 0x4b7b1978, 0x3a88ca4e, 0x910953b2, 0xc744996d, 0x0b6277c7,
0x02a1a6b8, 0x0234d9ad, 0x0e7b8f45, 0x48738653, 0x3a1a5447, 0x0fdc4950, 0x672d5847, 0x04e44448,
0x7750945c, 0x602f3260, 0xf5b42201, 0x5c05922e, 0x203c5332, 0x1f7c484b, 0x1b2d8caf, 0xbc99e797,
0xe695ed62, 0x11b38375, 0x55b84bb2, 0xfce349be, 0x7181456a, 0x4f51f643, 0x66bb7e52, 0x5d235db2,
0xb8c52ab2, 0x111b90d9, 0xa80eb118
};
class CMainParams : public CChainParams {
@ -143,9 +124,9 @@ public:
assert(genesis.hashMerkleRoot == uint256("0x5b2a3f53f605d62c53e62932dac6925e3d74afa5a4b459745c36d42d0ed26a69"));
vSeeds.push_back(CDNSSeedData("dogecoin.com", "seed.dogecoin.com"));
vSeeds.push_back(CDNSSeedData("mophides.com", "seed.mophides.com"));
vSeeds.push_back(CDNSSeedData("dglibrary.org", "seed.dglibrary.org"));
vSeeds.push_back(CDNSSeedData("dogechain.info", "seed.dogechain.info"));
vSeeds.push_back(CDNSSeedData("multidoge.org", "seed.multidoge.org"));
vSeeds.push_back(CDNSSeedData("multidoge.org", "seed2.multidoge.org"));
vSeeds.push_back(CDNSSeedData("doger.dogecoin.com", "seed.doger.dogecoin.com"));
// Workaround for Boost not being quite compatible with C++11;
std::vector<unsigned char> pka = list_of(30);

View file

@ -11,7 +11,7 @@
// These need to be macros, as version.cpp's and dogecoin-qt.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR 1
#define CLIENT_VERSION_MINOR 8
#define CLIENT_VERSION_REVISION 2
#define CLIENT_VERSION_REVISION 3
#define CLIENT_VERSION_BUILD 0
// Set to true for release, false for prerelease or test build

View file

@ -59,19 +59,4 @@ typedef u_int SOCKET;
#define SOCKET_ERROR -1
#endif
inline int myclosesocket(SOCKET& hSocket)
{
if (hSocket == INVALID_SOCKET)
return WSAENOTSOCK;
#ifdef WIN32
int ret = closesocket(hSocket);
#else
int ret = close(hSocket);
#endif
hSocket = INVALID_SOCKET;
return ret;
}
#define closesocket(s) myclosesocket(s)
#endif

View file

@ -62,7 +62,8 @@ CWallet* pwalletMain;
enum BindFlags {
BF_NONE = 0,
BF_EXPLICIT = (1U << 0),
BF_REPORT_ERROR = (1U << 1)
BF_REPORT_ERROR = (1U << 1),
BF_WHITELIST = (1U << 2),
};
@ -183,7 +184,7 @@ bool static Bind(const CService &addr, unsigned int flags) {
if (!(flags & BF_EXPLICIT) && IsLimited(addr))
return false;
std::string strError;
if (!BindListenPort(addr, strError)) {
if (!BindListenPort(addr, strError, flags & BF_WHITELIST)) {
if (flags & BF_REPORT_ERROR)
return InitError(strError);
return false;
@ -236,9 +237,8 @@ std::string HelpMessage(HelpMessageMode hmm)
strUsage += " -onion=<ip:port> " + _("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: -proxy)") + "\n";
strUsage += " -onlynet=<net> " + _("Only connect to nodes in network <net> (IPv4, IPv6 or Tor)") + "\n";
strUsage += " -port=<port> " + _("Listen for connections on <port> (default: 22556 or testnet: 44556)") + "\n";
strUsage += " -proxy=<ip:port> " + _("Connect through SOCKS proxy") + "\n";
strUsage += " -proxy=<ip:port> " + _("Connect through SOCKS5 proxy") + "\n";
strUsage += " -seednode=<ip> " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n";
strUsage += " -socks=<n> " + _("Select SOCKS version for -proxy (4 or 5, default: 5)") + "\n";
strUsage += " -timeout=<n> " + _("Specify connection timeout in milliseconds (default: 5000)") + "\n";
#ifdef USE_UPNP
#if USE_UPNP
@ -247,6 +247,8 @@ std::string HelpMessage(HelpMessageMode hmm)
strUsage += " -upnp " + _("Use UPnP to map the listening port (default: 0)") + "\n";
#endif
#endif
strUsage += " -whitebind=<addr> " + _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6") + "\n";
strUsage += " -whitelist=<netmask> " + _("Whitelist peers connecting from the given netmask or ip. Can be specified multiple times.") + "\n";
#ifdef ENABLE_WALLET
strUsage += "\n" + _("Wallet options:") + "\n";
@ -479,11 +481,11 @@ bool AppInit2(boost::thread_group& threadGroup)
nLocalServices |= NODE_BLOOM;
}
if (mapArgs.count("-bind")) {
if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) {
// when specifying an explicit binding address, you want to listen on it
// even when -connect or -proxy is specified
if (SoftSetBoolArg("-listen", true))
LogPrintf("AppInit2 : parameter interaction: -bind set -> setting -listen=1\n");
LogPrintf("AppInit2 : parameter interaction: -bind or -whitebind set -> setting -listen=1\n");
}
if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) {
@ -527,7 +529,7 @@ bool AppInit2(boost::thread_group& threadGroup)
}
// Make sure enough file descriptors are available
int nBind = std::max((int)mapArgs.count("-bind"), 1);
int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1);
nMaxConnections = GetArg("-maxconnections", 125);
nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS);
@ -549,6 +551,12 @@ bool AppInit2(boost::thread_group& threadGroup)
// Check for -debugnet (deprecated)
if (GetBoolArg("-debugnet", false))
InitWarning(_("Warning: Deprecated argument -debugnet ignored, use -debug=net"));
// Check for -socks - as this is a privacy risk to continue, exit here
if (mapArgs.count("-socks"))
return InitError(_("Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported."));
// Check for -tor - as this is a privacy risk to continue, exit here
if (GetBoolArg("-tor", false))
return InitError(_("Error: Unsupported argument -tor found, use -onion."));
fBenchmark = GetBoolArg("-benchmark", false);
mempool.setSanityCheck(GetBoolArg("-checkmempool", RegTest()));
@ -732,10 +740,6 @@ bool AppInit2(boost::thread_group& threadGroup)
RegisterNodeSignals(GetNodeSignals());
int nSocksVersion = GetArg("-socks", 5);
if (nSocksVersion != 4 && nSocksVersion != 5)
return InitError(strprintf(_("Unknown -socks proxy version requested: %i"), nSocksVersion));
if (mapArgs.count("-onlynet")) {
std::set<enum Network> nets;
BOOST_FOREACH(std::string snet, mapMultiArgs["-onlynet"]) {
@ -751,6 +755,15 @@ bool AppInit2(boost::thread_group& threadGroup)
}
}
if (mapArgs.count("-whitelist")) {
BOOST_FOREACH(const std::string& net, mapMultiArgs["-whitelist"]) {
CSubNet subnet(net);
if (!subnet.IsValid())
return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net));
CNode::AddWhitelistedRange(subnet);
}
}
CService addrProxy;
bool fProxy = false;
if (mapArgs.count("-proxy")) {
@ -759,12 +772,10 @@ bool AppInit2(boost::thread_group& threadGroup)
return InitError(strprintf(_("Invalid -proxy address: '%s'"), mapArgs["-proxy"]));
if (!IsLimited(NET_IPV4))
SetProxy(NET_IPV4, addrProxy, nSocksVersion);
if (nSocksVersion > 4) {
if (!IsLimited(NET_IPV6))
SetProxy(NET_IPV6, addrProxy, nSocksVersion);
SetNameProxy(addrProxy, nSocksVersion);
}
SetProxy(NET_IPV4, addrProxy);
if (!IsLimited(NET_IPV6))
SetProxy(NET_IPV6, addrProxy);
SetNameProxy(addrProxy);
fProxy = true;
}
@ -782,24 +793,32 @@ bool AppInit2(boost::thread_group& threadGroup)
addrOnion = mapArgs.count("-onion")?CService(mapArgs["-onion"], 9050):CService(mapArgs["-tor"], 9050);
if (!addrOnion.IsValid())
return InitError(strprintf(_("Invalid -onion address: '%s'"), mapArgs.count("-onion")?mapArgs["-onion"]:mapArgs["-tor"]));
SetProxy(NET_TOR, addrOnion, 5);
SetProxy(NET_TOR, addrOnion);
SetReachable(NET_TOR);
}
// see Step 2: parameter interactions for more information about these
fNoListen = !GetBoolArg("-listen", true);
fListen = GetBoolArg("-listen", true);
fDiscover = GetBoolArg("-discover", true);
fNameLookup = GetBoolArg("-dns", true);
bool fBound = false;
if (!fNoListen) {
if (mapArgs.count("-bind")) {
if (fListen) {
if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) {
BOOST_FOREACH(std::string strBind, mapMultiArgs["-bind"]) {
CService addrBind;
if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))
return InitError(strprintf(_("Cannot resolve -bind address: '%s'"), strBind));
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
}
BOOST_FOREACH(std::string strBind, mapMultiArgs["-whitebind"]) {
CService addrBind;
if (!Lookup(strBind.c_str(), addrBind, 0, false))
return InitError(strprintf(_("Cannot resolve -whitebind address: '%s'"), strBind));
if (addrBind.GetPort() == 0)
return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind));
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
}
}
else {
struct in_addr inaddr_any;

View file

@ -207,9 +207,13 @@ struct CBlockReject {
// processing of incoming data is done after the ProcessMessage call returns,
// and we're no longer holding the node's locks.
struct CNodeState {
//! The peer's address
CService address;
//! Whether we have a fully established connection.
bool fCurrentlyConnected;
// Accumulated misbehaviour score for this peer.
int nMisbehavior;
// Whether this peer should be disconnected and banned.
// Whether this peer should be disconnected and banned (unless whitelisted).
bool fShouldBan;
// String name of this peer (debugging/logging purposes).
std::string name;
@ -223,6 +227,7 @@ struct CNodeState {
int64_t nLastBlockProcess;
CNodeState() {
fCurrentlyConnected = false;
nMisbehavior = 0;
fShouldBan = false;
nBlocksToDownload = 0;
@ -253,12 +258,16 @@ void InitializeNode(NodeId nodeid, const CNode *pnode) {
LOCK(cs_main);
CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second;
state.name = pnode->addrName;
state.address = pnode->addr;
}
void FinalizeNode(NodeId nodeid) {
LOCK(cs_main);
CNodeState *state = State(nodeid);
if (state->nMisbehavior == 0 && state->fCurrentlyConnected) {
AddressCurrentlyConnected(state->address);
}
BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight)
mapBlocksInFlight.erase(entry.hash);
BOOST_FOREACH(const uint256& hash, state->vBlocksToDownload)
@ -1571,7 +1580,8 @@ void Misbehaving(NodeId pnode, int howmuch)
return;
state->nMisbehavior += howmuch;
if (state->nMisbehavior >= GetArg("-banscore", 100))
int banscore = GetArg("-banscore", 100);
if (state->nMisbehavior >= banscore && state->nMisbehavior - howmuch < banscore)
{
LogPrintf("Misbehaving: %s (%d -> %d) BAN THRESHOLD EXCEEDED\n", state->name, state->nMisbehavior-howmuch, state->nMisbehavior);
state->fShouldBan = true;
@ -3737,7 +3747,7 @@ void static ProcessGetData(CNode* pfrom)
}
}
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived)
{
RandAddSeedPerfmon();
LogPrint("net", "received: %s (%" PRIszu" bytes)\n", strCommand, vRecv.size());
@ -3822,7 +3832,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (!pfrom->fInbound)
{
// Advertise our address
if (!fNoListen && !IsInitialBlockDownload())
if (fListen && !IsInitialBlockDownload())
{
CAddress addr = GetLocalAddress(&pfrom->addr);
if (addr.IsRoutable())
@ -3870,6 +3880,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
else if (strCommand == "verack")
{
pfrom->SetRecvVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
// Mark this node as currently connected, so we update its timestamp later.
if (pfrom->fNetworkNode) {
LOCK(cs_main);
State(pfrom->GetId())->fCurrentlyConnected = true;
}
}
@ -4163,6 +4179,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTx);
if (nEvicted > 0)
LogPrint("mempool", "mapOrphan overflow, removed %u tx\n", nEvicted);
} else if (pfrom->fWhitelisted) {
// Always relay transactions received from whitelisted peers, even
// if they are already in the mempool (allowing the node to function
// as a gateway for nodes hidden behind it).
RelayTransaction(tx, tx.GetHash());
}
int nDoS = 0;
if (state.IsInvalid(nDoS))
@ -4257,7 +4278,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
else if (strCommand == "pong")
{
int64_t pingUsecEnd = GetTimeMicros();
int64_t pingUsecEnd = nTimeReceived;
uint64_t nonce = 0;
size_t nAvail = vRecv.in_avail();
bool bPingFinished = false;
@ -4426,11 +4447,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
// Update the last seen time for this node's address
if (pfrom->fNetworkNode)
if (strCommand == "version" || strCommand == "addr" || strCommand == "inv" || strCommand == "getdata" || strCommand == "ping")
AddressCurrentlyConnected(pfrom->addr);
return true;
}
@ -4513,7 +4529,7 @@ bool ProcessMessages(CNode* pfrom)
bool fRet = false;
try
{
fRet = ProcessMessage(pfrom, strCommand, vRecv);
fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime);
boost::this_thread::interruption_point();
}
catch (std::ios_base::failure& e)
@ -4572,8 +4588,8 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// RPC ping request by user
pingSend = true;
}
if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSendMsg.empty()) {
// Ping automatically sent as a keepalive
if (pto->nPingNonceSent == 0 && pto->nPingUsecStart + PING_INTERVAL * 1000000 < GetTimeMicros()) {
// Ping automatically sent as a latency probe & keepalive.
pingSend = true;
}
if (pingSend) {
@ -4581,15 +4597,14 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
while (nonce == 0) {
RAND_bytes((unsigned char*)&nonce, sizeof(nonce));
}
pto->nPingNonceSent = nonce;
pto->fPingQueued = false;
pto->nPingUsecStart = GetTimeMicros();
if (pto->nVersion > BIP0031_VERSION) {
// Take timestamp as close as possible before transmitting ping
pto->nPingUsecStart = GetTimeMicros();
pto->nPingNonceSent = nonce;
pto->PushMessage("ping", nonce);
} else {
// Peer is too old to support ping command with nonce, pong will never arrive, disable timing
pto->nPingUsecStart = 0;
// Peer is too old to support ping command with nonce, pong will never arrive.
pto->nPingNonceSent = 0;
pto->PushMessage("ping");
}
}
@ -4611,7 +4626,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
pnode->setAddrKnown.clear();
// Rebroadcast our address
if (!fNoListen)
if (fListen)
{
CAddress addr = GetLocalAddress(&pnode->addr);
if (addr.IsRoutable())
@ -4650,11 +4665,14 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
CNodeState &state = *State(pto->GetId());
if (state.fShouldBan) {
if (pto->addr.IsLocal())
LogPrintf("Warning: not banning local node %s!\n", pto->addr.ToString());
if (pto->fWhitelisted)
LogPrintf("Warning: not punishing whitelisted peer %s!\n", pto->addr.ToString());
else {
pto->fDisconnect = true;
CNode::Ban(pto->addr);
if (pto->addr.IsLocal())
LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString());
else
CNode::Ban(pto->addr);
}
state.fShouldBan = false;
}

View file

@ -36,9 +36,31 @@
#define MSG_NOSIGNAL 0
#endif
// Fix for ancient MinGW versions, that don't have defined these in ws2tcpip.h.
// Todo: Can be removed when our pull-tester is upgraded to a modern MinGW version.
#ifdef WIN32
#ifndef PROTECTION_LEVEL_UNRESTRICTED
#define PROTECTION_LEVEL_UNRESTRICTED 10
#endif
#ifndef IPV6_PROTECTION_LEVEL
#define IPV6_PROTECTION_LEVEL 23
#endif
#endif
using namespace std;
using namespace boost;
namespace {
const int MAX_OUTBOUND_CONNECTIONS = 8;
struct ListenSocket {
SOCKET socket;
bool whitelisted;
ListenSocket(SOCKET socket, bool whitelisted) : socket(socket), whitelisted(whitelisted) {}
};
}
bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
@ -46,6 +68,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
// Global state variables
//
bool fDiscover = true;
bool fListen = true;
uint64_t nLocalServices = NODE_NETWORK;
CCriticalSection cs_mapLocalHost;
map<CNetAddr, LocalServiceInfo> mapLocalHost;
@ -54,7 +77,7 @@ static bool vfLimited[NET_MAX] = {};
static CNode* pnodeLocalHost = NULL;
static CNode* pnodeSync = NULL;
uint64_t nLocalHostNonce = 0;
static std::vector<SOCKET> vhListenSocket;
static std::vector<ListenSocket> vhListenSocket;
CAddrMan addrman;
int nMaxConnections = 125;
int nMaxOutboundConnections = 8;
@ -98,7 +121,7 @@ unsigned short GetListenPort()
// find 'best' local address for a particular peer
bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
{
if (fNoListen)
if (!fListen)
return false;
int nBestScore = -1;
@ -313,7 +336,7 @@ bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const cha
{
if (!RecvLine(hSocket, strLine))
{
closesocket(hSocket);
CloseSocket(hSocket);
return false;
}
if (pszKeyword == NULL)
@ -324,7 +347,7 @@ bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const cha
break;
}
}
closesocket(hSocket);
CloseSocket(hSocket);
if (strLine.find("<") != string::npos)
strLine = strLine.substr(0, strLine.find("<"));
strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r"));
@ -338,7 +361,7 @@ bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const cha
return true;
}
}
closesocket(hSocket);
CloseSocket(hSocket);
return error("GetMyExternalIP() : connection closed");
}
@ -499,8 +522,7 @@ void CNode::CloseSocketDisconnect()
if (hSocket != INVALID_SOCKET)
{
LogPrint("net", "disconnecting node %s\n", addrName);
closesocket(hSocket);
hSocket = INVALID_SOCKET;
CloseSocket(hSocket);
}
// in case this fails, we'll empty the recv buffer when the CNode is deleted
@ -513,11 +535,6 @@ void CNode::CloseSocketDisconnect()
pnodeSync = NULL;
}
void CNode::Cleanup()
{
}
void CNode::PushVersion()
{
int nBestHeight = g_signals.GetHeight().get_value_or(0);
@ -570,6 +587,24 @@ bool CNode::Ban(const CNetAddr &addr) {
return true;
}
std::vector<CSubNet> CNode::vWhitelistedRange;
CCriticalSection CNode::cs_vWhitelistedRange;
bool CNode::IsWhitelistedRange(const CNetAddr &addr) {
LOCK(cs_vWhitelistedRange);
BOOST_FOREACH(const CSubNet& subnet, vWhitelistedRange) {
if (subnet.Match(addr))
return true;
}
return false;
}
void CNode::AddWhitelistedRange(const CSubNet &subnet) {
LOCK(cs_vWhitelistedRange);
vWhitelistedRange.push_back(subnet);
}
#undef X
#define X(name) stats.name = name
void CNode::copyStats(CNodeStats &stats)
@ -586,6 +621,7 @@ void CNode::copyStats(CNodeStats &stats)
X(nStartingHeight);
X(nSendBytes);
X(nRecvBytes);
X(fWhitelisted);
stats.fSyncNode = (this == pnodeSync);
// It is common for nodes with good ping times to suddenly become lagged,
@ -630,8 +666,16 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes)
if (handled < 0)
return false;
if (msg.in_data && msg.hdr.nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH) {
LogPrint("net", "Oversized message from peer=%i, disconnecting", GetId());
return false;
}
pch += handled;
nBytes -= handled;
if (msg.complete())
msg.nTime = GetTimeMicros();
}
return true;
@ -759,7 +803,6 @@ void ThreadSocketHandler()
// close socket and cleanup
pnode->CloseSocketDisconnect();
pnode->Cleanup();
// hold in disconnected pool until all refs are released
if (pnode->fNetworkNode || pnode->fInbound)
@ -803,7 +846,6 @@ void ThreadSocketHandler()
uiInterface.NotifyNumConnectionsChanged(nPrevNodeCount);
}
//
// Find which sockets have data to receive
//
@ -820,11 +862,12 @@ void ThreadSocketHandler()
SOCKET hSocketMax = 0;
bool have_fds = false;
BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) {
FD_SET(hListenSocket, &fdsetRecv);
hSocketMax = max(hSocketMax, hListenSocket);
BOOST_FOREACH(const ListenSocket& hListenSocket, vhListenSocket) {
FD_SET(hListenSocket.socket, &fdsetRecv);
hSocketMax = max(hSocketMax, hListenSocket.socket);
have_fds = true;
}
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
@ -885,58 +928,61 @@ void ThreadSocketHandler()
MilliSleep(timeout.tv_usec/1000);
}
//
// Accept new connections
//
BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
BOOST_FOREACH(const ListenSocket& hListenSocket, vhListenSocket)
{
struct sockaddr_storage sockaddr;
socklen_t len = sizeof(sockaddr);
SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
CAddress addr;
int nInbound = 0;
if (hListenSocket.socket != INVALID_SOCKET && FD_ISSET(hListenSocket.socket, &fdsetRecv))
{
struct sockaddr_storage sockaddr;
socklen_t len = sizeof(sockaddr);
SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len);
CAddress addr;
int nInbound = 0;
if (hSocket != INVALID_SOCKET)
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
LogPrintf("Warning: Unknown socket family\n");
if (hSocket != INVALID_SOCKET)
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
LogPrintf("Warning: Unknown socket family\n");
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode->fInbound)
nInbound++;
}
if (hSocket == INVALID_SOCKET)
{
int nErr = WSAGetLastError();
if (nErr != WSAEWOULDBLOCK)
LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr));
}
else if (nInbound >= nMaxConnections - nMaxOutboundConnections)
{
closesocket(hSocket);
}
else if (CNode::IsBanned(addr))
{
LogPrintf("connection from %s dropped (banned)\n", addr.ToString());
closesocket(hSocket);
}
else
{
LogPrint("net", "accepted connection %s\n", addr.ToString());
CNode* pnode = new CNode(hSocket, addr, "", true);
pnode->AddRef();
bool whitelisted = hListenSocket.whitelisted || CNode::IsWhitelistedRange(addr);
{
LOCK(cs_vNodes);
vNodes.push_back(pnode);
BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode->fInbound)
nInbound++;
}
if (hSocket == INVALID_SOCKET)
{
int nErr = WSAGetLastError();
if (nErr != WSAEWOULDBLOCK)
LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr));
}
else if (nInbound >= nMaxConnections - MAX_OUTBOUND_CONNECTIONS)
{
CloseSocket(hSocket);
}
else if (CNode::IsBanned(addr) && !whitelisted)
{
LogPrintf("connection from %s dropped (banned)\n", addr.ToString());
CloseSocket(hSocket);
}
else
{
LogPrint("net", "accepted connection %s\n", addr.ToString());
CNode* pnode = new CNode(hSocket, addr, "", true);
pnode->AddRef();
pnode->fWhitelisted = whitelisted;
{
LOCK(cs_vNodes);
vNodes.push_back(pnode);
}
}
}
}
//
// Service each socket
//
@ -1010,23 +1056,27 @@ void ThreadSocketHandler()
//
// Inactivity checking
//
if (pnode->vSendMsg.empty())
pnode->nLastSendEmpty = GetTime();
if (GetTime() - pnode->nTimeConnected > 60)
int64_t nTime = GetTime();
if (nTime - pnode->nTimeConnected > 60)
{
if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
{
LogPrint("net", "socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0);
pnode->fDisconnect = true;
}
else if (GetTime() - pnode->nLastSend > 90*60 && GetTime() - pnode->nLastSendEmpty > 90*60)
else if (nTime - pnode->nLastSend > TIMEOUT_INTERVAL)
{
LogPrintf("socket not sending\n");
LogPrintf("socket sending timeout: %is\n", nTime - pnode->nLastSend);
pnode->fDisconnect = true;
}
else if (GetTime() - pnode->nLastRecv > 90*60)
else if (nTime - pnode->nLastRecv > (pnode->nVersion > BIP0031_VERSION ? TIMEOUT_INTERVAL : 90*60))
{
LogPrintf("socket inactivity timeout\n");
LogPrintf("socket receive timeout: %is\n", nTime - pnode->nLastRecv);
pnode->fDisconnect = true;
}
else if (pnode->nPingNonceSent && pnode->nPingUsecStart + TIMEOUT_INTERVAL * 1000000 < GetTimeMicros())
{
LogPrintf("ping timeout: %fs\n", 0.000001 * (GetTimeMicros() - pnode->nPingUsecStart));
pnode->fDisconnect = true;
}
}
@ -1310,8 +1360,7 @@ void ThreadOpenConnections()
int nTries = 0;
while (true)
{
// use an nUnkBias between 10 (no outgoing connections) and 90 (8 outgoing connections)
CAddress addr = addrman.Select(10 + min(nOutbound,8)*10);
CAddress addr = addrman.Select();
// if we selected an invalid address, restart
if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))
@ -1557,7 +1606,7 @@ void ThreadMessageHandler()
bool BindListenPort(const CService &addrBind, string& strError)
bool BindListenPort(const CService &addrBind, string& strError, bool fWhitelisted)
{
strError = "";
int nOne = 1;
@ -1580,18 +1629,16 @@ bool BindListenPort(const CService &addrBind, string& strError)
return false;
}
#ifndef WIN32
#ifdef SO_NOSIGPIPE
// Different way of disabling SIGPIPE on BSD
setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
#endif
#ifndef WIN32
// Allow binding if the port is still in TIME_WAIT state after
// the program was closed and restarted. Not an issue on windows.
// the program was closed and restarted. Not an issue on windows!
setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
#endif
#ifdef WIN32
// Set to non-blocking, incoming connections will also inherit this
if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
@ -1615,10 +1662,8 @@ bool BindListenPort(const CService &addrBind, string& strError)
#endif
#endif
#ifdef WIN32
int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */;
int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */;
// this call is allowed to fail
setsockopt(hListenSocket, IPPROTO_IPV6, nParameterId, (const char*)&nProtLevel, sizeof(int));
int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED;
setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int));
#endif
}
@ -1630,6 +1675,7 @@ bool BindListenPort(const CService &addrBind, string& strError)
else
strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString(), NetworkErrorString(nErr));
LogPrintf("%s\n", strError);
CloseSocket(hListenSocket);
return false;
}
LogPrintf("Bound to %s\n", addrBind.ToString());
@ -1639,12 +1685,13 @@ bool BindListenPort(const CService &addrBind, string& strError)
{
strError = strprintf(_("Error: Listening for incoming connections failed (listen returned error %s)"), NetworkErrorString(WSAGetLastError()));
LogPrintf("%s\n", strError);
CloseSocket(hListenSocket);
return false;
}
vhListenSocket.push_back(hListenSocket);
vhListenSocket.push_back(ListenSocket(hListenSocket, fWhitelisted));
if (addrBind.IsRoutable() && fDiscover)
if (addrBind.IsRoutable() && fDiscover && !fWhitelisted)
AddLocal(addrBind, LOCAL_BIND);
return true;
@ -1771,11 +1818,11 @@ public:
// Close sockets
BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode->hSocket != INVALID_SOCKET)
closesocket(pnode->hSocket);
BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
if (hListenSocket != INVALID_SOCKET)
if (closesocket(hListenSocket) == SOCKET_ERROR)
LogPrintf("closesocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError()));
CloseSocket(pnode->hSocket);
BOOST_FOREACH(ListenSocket& hListenSocket, vhListenSocket)
if (hListenSocket.socket != INVALID_SOCKET)
if (!CloseSocket(hListenSocket.socket))
LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError()));
// clean up some globals (to help leak detection)
BOOST_FOREACH(CNode *pnode, vNodes)
@ -1784,6 +1831,7 @@ public:
delete pnode;
vNodes.clear();
vNodesDisconnected.clear();
vhListenSocket.clear();
delete semOutbound;
semOutbound = NULL;
delete pnodeLocalHost;

View file

@ -28,6 +28,7 @@
#include <boost/signals2/signal.hpp>
#include <openssl/rand.h>
class CAddrMan;
class CBlockIndex;
class CNode;
@ -36,8 +37,14 @@ namespace boost {
class thread_group;
}
/** Time between pings automatically sent out for latency probing and keepalive (in seconds). */
static const int PING_INTERVAL = 2 * 60;
/** Time after which to disconnect, after waiting for a ping response (or inactivity). */
static const int TIMEOUT_INTERVAL = 20 * 60;
/** The maximum number of entries in an 'inv' protocol message */
static const unsigned int MAX_INV_SZ = 50000;
/** Maximum length of incoming protocol messages (no message over 2 MiB is currently acceptable). */
static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 2 * 1024 * 1024;
/** The maximum number of entries in mapAskFor */
static const size_t MAPASKFOR_MAX_SZ = MAX_INV_SZ;
@ -53,7 +60,7 @@ CNode* FindNode(const CService& ip);
CNode* ConnectNode(CAddress addrConnect, const char *strDest = NULL);
void MapPort(bool fUseUPnP);
unsigned short GetListenPort();
bool BindListenPort(const CService &bindAddr, std::string& strError=REF(std::string()));
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
void StartNode(boost::thread_group& threadGroup);
bool StopNode();
void SocketSendData(CNode *pnode);
@ -100,6 +107,7 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
extern bool fDiscover;
extern bool fListen;
extern uint64_t nLocalServices;
extern uint64_t nLocalHostNonce;
extern CAddrMan addrman;
@ -143,6 +151,7 @@ public:
uint64_t nSendBytes;
uint64_t nRecvBytes;
bool fSyncNode;
bool fWhitelisted;
double dPingTime;
double dPingWait;
std::string addrLocal;
@ -162,11 +171,14 @@ public:
CDataStream vRecv; // received message data
unsigned int nDataPos;
int64_t nTime; // time (in microseconds) of message receipt.
CNetMessage(int nTypeIn, int nVersionIn) : hdrbuf(nTypeIn, nVersionIn), vRecv(nTypeIn, nVersionIn) {
hdrbuf.resize(24);
in_data = false;
nHdrPos = 0;
nDataPos = 0;
nTime = 0;
}
bool complete() const
@ -212,7 +224,6 @@ public:
int64_t nLastSend;
int64_t nLastRecv;
int64_t nLastSendEmpty;
int64_t nTimeConnected;
CAddress addr;
std::string addrName;
@ -223,6 +234,7 @@ public:
// store the sanitized version in cleanSubVer. The original should be used when dealing with
// the network or wire types and the cleaned string used when displayed or logged.
std::string strSubVer, cleanSubVer;
bool fWhitelisted; // This peer can bypass DoS banning.
bool fOneShot;
bool fClient;
bool fInbound;
@ -246,6 +258,11 @@ protected:
static std::map<CNetAddr, int64_t> setBanned;
static CCriticalSection cs_setBanned;
// Whitelisted ranges. Any node connecting from these is automatically
// whitelisted (as well as those connecting to whitelisted binds).
static std::vector<CSubNet> vWhitelistedRange;
static CCriticalSection cs_vWhitelistedRange;
// Basic fuzz-testing
void Fuzz(int nChance); // modifies ssSend
@ -268,10 +285,14 @@ public:
CCriticalSection cs_inventory;
std::multimap<int64_t, CInv> mapAskFor;
// Ping time measurement
// Ping time measurement:
// The pong reply we're expecting, or 0 if no pong expected.
uint64_t nPingNonceSent;
// Time (in usec) the last ping was sent, or 0 if no ping was ever sent.
int64_t nPingUsecStart;
// Last measured round-trip time.
int64_t nPingUsecTime;
// Whether a ping is requested.
bool fPingQueued;
CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), setAddrKnown(5000)
@ -283,12 +304,12 @@ public:
nLastRecv = 0;
nSendBytes = 0;
nRecvBytes = 0;
nLastSendEmpty = GetTime();
nTimeConnected = GetTime();
addr = addrIn;
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
nVersion = 0;
strSubVer = "";
fWhitelisted = false;
fOneShot = false;
fClient = false; // set by version message
fInbound = fInboundIn;
@ -328,8 +349,7 @@ public:
{
if (hSocket != INVALID_SOCKET)
{
closesocket(hSocket);
hSocket = INVALID_SOCKET;
CloseSocket(hSocket);
}
if (pfilter)
delete pfilter;
@ -682,8 +702,6 @@ public:
void Subscribe(unsigned int nChannel, unsigned int nHops=0);
void CancelSubscribe(unsigned int nChannel);
void CloseSocketDisconnect();
void Cleanup();
// Denial-of-service detection/prevention
// The idea is to detect peers that are behaving
@ -704,6 +722,9 @@ public:
static bool Ban(const CNetAddr &ip);
void copyStats(CNodeStats &stats);
static bool IsWhitelistedRange(const CNetAddr &ip);
static void AddWhitelistedRange(const CSubNet &subnet);
// Network stats
static void RecordBytesRecv(uint64_t bytes);
static void RecordBytesSent(uint64_t bytes);

View file

@ -25,7 +25,7 @@ using namespace std;
// Settings
static proxyType proxyInfo[NET_MAX];
static proxyType nameproxyInfo;
static CService nameProxy;
static CCriticalSection cs_proxyInfos;
int nConnectTimeout = 5000;
bool fNameLookup = false;
@ -161,56 +161,12 @@ bool LookupNumeric(const char *pszName, CService& addr, int portDefault)
return Lookup(pszName, addr, portDefault, false);
}
bool static Socks4(const CService &addrDest, SOCKET& hSocket)
{
LogPrintf("SOCKS4 connecting %s\n", addrDest.ToString());
if (!addrDest.IsIPv4())
{
closesocket(hSocket);
return error("Proxy destination is not IPv4");
}
char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
if (!addrDest.GetSockAddr((struct sockaddr*)&addr, &len) || addr.sin_family != AF_INET)
{
closesocket(hSocket);
return error("Cannot get proxy destination address");
}
memcpy(pszSocks4IP + 2, &addr.sin_port, 2);
memcpy(pszSocks4IP + 4, &addr.sin_addr, 4);
char* pszSocks4 = pszSocks4IP;
int nSize = sizeof(pszSocks4IP);
int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL);
if (ret != nSize)
{
closesocket(hSocket);
return error("Error sending to proxy");
}
char pchRet[8];
if (recv(hSocket, pchRet, 8, 0) != 8)
{
closesocket(hSocket);
return error("Error reading proxy response");
}
if (pchRet[1] != 0x5a)
{
closesocket(hSocket);
if (pchRet[1] != 0x5b)
LogPrintf("ERROR: Proxy returned error %d\n", pchRet[1]);
return false;
}
LogPrintf("SOCKS4 connected %s\n", addrDest.ToString());
return true;
}
bool static Socks5(string strDest, int port, SOCKET& hSocket)
{
LogPrintf("SOCKS5 connecting %s\n", strDest);
if (strDest.size() > 255)
{
closesocket(hSocket);
CloseSocket(hSocket);
return error("Hostname too long");
}
char pszSocks5Init[] = "\5\1\0";
@ -219,18 +175,18 @@ bool static Socks5(string strDest, int port, SOCKET& hSocket)
ssize_t ret = send(hSocket, pszSocks5Init, nSize, MSG_NOSIGNAL);
if (ret != nSize)
{
closesocket(hSocket);
CloseSocket(hSocket);
return error("Error sending to proxy");
}
char pchRet1[2];
if (recv(hSocket, pchRet1, 2, 0) != 2)
{
closesocket(hSocket);
CloseSocket(hSocket);
return error("Error reading proxy response");
}
if (pchRet1[0] != 0x05 || pchRet1[1] != 0x00)
{
closesocket(hSocket);
CloseSocket(hSocket);
return error("Proxy failed to initialize");
}
string strSocks5("\5\1");
@ -242,23 +198,23 @@ bool static Socks5(string strDest, int port, SOCKET& hSocket)
ret = send(hSocket, strSocks5.c_str(), strSocks5.size(), MSG_NOSIGNAL);
if (ret != (ssize_t)strSocks5.size())
{
closesocket(hSocket);
CloseSocket(hSocket);
return error("Error sending to proxy");
}
char pchRet2[4];
if (recv(hSocket, pchRet2, 4, 0) != 4)
{
closesocket(hSocket);
CloseSocket(hSocket);
return error("Error reading proxy response");
}
if (pchRet2[0] != 0x05)
{
closesocket(hSocket);
CloseSocket(hSocket);
return error("Proxy failed to accept request");
}
if (pchRet2[1] != 0x00)
{
closesocket(hSocket);
CloseSocket(hSocket);
switch (pchRet2[1])
{
case 0x01: return error("Proxy error: general failure");
@ -274,7 +230,7 @@ bool static Socks5(string strDest, int port, SOCKET& hSocket)
}
if (pchRet2[2] != 0x00)
{
closesocket(hSocket);
CloseSocket(hSocket);
return error("Error: malformed proxy response");
}
char pchRet3[256];
@ -286,23 +242,23 @@ bool static Socks5(string strDest, int port, SOCKET& hSocket)
{
ret = recv(hSocket, pchRet3, 1, 0) != 1;
if (ret) {
closesocket(hSocket);
CloseSocket(hSocket);
return error("Error reading from proxy");
}
int nRecv = pchRet3[0];
ret = recv(hSocket, pchRet3, nRecv, 0) != nRecv;
break;
}
default: closesocket(hSocket); return error("Error: malformed proxy response");
default: CloseSocket(hSocket); return error("Error: malformed proxy response");
}
if (ret)
{
closesocket(hSocket);
CloseSocket(hSocket);
return error("Error reading from proxy");
}
if (recv(hSocket, pchRet3, 2, 0) != 2)
{
closesocket(hSocket);
CloseSocket(hSocket);
return error("Error reading from proxy");
}
LogPrintf("SOCKS5 connected %s\n", strDest);
@ -336,7 +292,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == -1)
#endif
{
closesocket(hSocket);
CloseSocket(hSocket);
return false;
}
@ -356,13 +312,13 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
if (nRet == 0)
{
LogPrint("net", "connection to %s timeout\n", addrConnect.ToString());
closesocket(hSocket);
CloseSocket(hSocket);
return false;
}
if (nRet == SOCKET_ERROR)
{
LogPrintf("select() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
closesocket(hSocket);
CloseSocket(hSocket);
return false;
}
socklen_t nRetSize = sizeof(nRet);
@ -373,13 +329,13 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
#endif
{
LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
closesocket(hSocket);
CloseSocket(hSocket);
return false;
}
if (nRet != 0)
{
LogPrintf("connect() to %s failed after select(): %s\n", addrConnect.ToString(), NetworkErrorString(nRet));
closesocket(hSocket);
CloseSocket(hSocket);
return false;
}
}
@ -390,7 +346,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
#endif
{
LogPrintf("connect() to %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
closesocket(hSocket);
CloseSocket(hSocket);
return false;
}
}
@ -406,7 +362,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
if (fcntl(hSocket, F_SETFL, fFlags & ~O_NONBLOCK) == SOCKET_ERROR)
#endif
{
closesocket(hSocket);
CloseSocket(hSocket);
return false;
}
@ -414,53 +370,49 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
return true;
}
bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion) {
bool SetProxy(enum Network net, CService addrProxy) {
assert(net >= 0 && net < NET_MAX);
if (nSocksVersion != 0 && nSocksVersion != 4 && nSocksVersion != 5)
return false;
if (nSocksVersion != 0 && !addrProxy.IsValid())
if (!addrProxy.IsValid())
return false;
LOCK(cs_proxyInfos);
proxyInfo[net] = std::make_pair(addrProxy, nSocksVersion);
proxyInfo[net] = addrProxy;
return true;
}
bool GetProxy(enum Network net, proxyType &proxyInfoOut) {
assert(net >= 0 && net < NET_MAX);
LOCK(cs_proxyInfos);
if (!proxyInfo[net].second)
if (!proxyInfo[net].IsValid())
return false;
proxyInfoOut = proxyInfo[net];
return true;
}
bool SetNameProxy(CService addrProxy, int nSocksVersion) {
if (nSocksVersion != 0 && nSocksVersion != 5)
return false;
if (nSocksVersion != 0 && !addrProxy.IsValid())
bool SetNameProxy(CService addrProxy) {
if (!addrProxy.IsValid())
return false;
LOCK(cs_proxyInfos);
nameproxyInfo = std::make_pair(addrProxy, nSocksVersion);
nameProxy = addrProxy;
return true;
}
bool GetNameProxy(proxyType &nameproxyInfoOut) {
bool GetNameProxy(CService &nameProxyOut) {
LOCK(cs_proxyInfos);
if (!nameproxyInfo.second)
if(!nameProxy.IsValid())
return false;
nameproxyInfoOut = nameproxyInfo;
nameProxyOut = nameProxy;
return true;
}
bool HaveNameProxy() {
LOCK(cs_proxyInfos);
return nameproxyInfo.second != 0;
return nameProxy.IsValid();
}
bool IsProxy(const CNetAddr &addr) {
LOCK(cs_proxyInfos);
for (int i = 0; i < NET_MAX; i++) {
if (proxyInfo[i].second && (addr == (CNetAddr)proxyInfo[i].first))
if (addr == (CNetAddr)proxyInfo[i])
return true;
}
return false;
@ -469,31 +421,18 @@ bool IsProxy(const CNetAddr &addr) {
bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
{
proxyType proxy;
// no proxy needed
// no proxy needed (none set for target network)
if (!GetProxy(addrDest.GetNetwork(), proxy))
return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout);
SOCKET hSocket = INVALID_SOCKET;
// first connect to proxy server
if (!ConnectSocketDirectly(proxy.first, hSocket, nTimeout))
if (!ConnectSocketDirectly(proxy, hSocket, nTimeout))
return false;
// do socks negotiation
switch (proxy.second) {
case 4:
if (!Socks4(addrDest, hSocket))
return false;
break;
case 5:
if (!Socks5(addrDest.ToStringIP(), addrDest.GetPort(), hSocket))
return false;
break;
default:
closesocket(hSocket);
if (!Socks5(addrDest.ToStringIP(), addrDest.GetPort(), hSocket))
return false;
}
hSocketRet = hSocket;
return true;
@ -507,30 +446,25 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest
SOCKET hSocket = INVALID_SOCKET;
proxyType nameproxy;
GetNameProxy(nameproxy);
CService nameProxy;
GetNameProxy(nameProxy);
CService addrResolved(CNetAddr(strDest, fNameLookup && !nameproxy.second), port);
CService addrResolved(CNetAddr(strDest, fNameLookup && !HaveNameProxy()), port);
if (addrResolved.IsValid()) {
addr = addrResolved;
return ConnectSocket(addr, hSocketRet, nTimeout);
}
addr = CService("0.0.0.0:0");
if (!nameproxy.second)
return false;
if (!ConnectSocketDirectly(nameproxy.first, hSocket, nTimeout))
return false;
switch(nameproxy.second) {
default:
case 4:
closesocket(hSocket);
return false;
case 5:
if (!Socks5(strDest, port, hSocket))
return false;
break;
}
addr = CService("0.0.0.0:0");
if (!HaveNameProxy())
return false;
// first connect to name proxy server
if (!ConnectSocketDirectly(nameProxy, hSocket, nTimeout))
return false;
// do socks negotiation
if (!Socks5(strDest, (unsigned short)port, hSocket))
return false;
hSocketRet = hSocket;
return true;
@ -1270,3 +1204,16 @@ std::string NetworkErrorString(int err)
return strprintf("%s (%d)", s, err);
}
#endif
bool CloseSocket(SOCKET& hSocket)
{
if (hSocket == INVALID_SOCKET)
return false;
#ifdef WIN32
int ret = closesocket(hSocket);
#else
int ret = close(hSocket);
#endif
hSocket = INVALID_SOCKET;
return ret != SOCKET_ERROR;
}

View file

@ -163,14 +163,14 @@ class CService : public CNetAddr
)
};
typedef std::pair<CService, int> proxyType;
typedef CService proxyType;
enum Network ParseNetwork(std::string net);
void SplitHostPort(std::string in, int &portOut, std::string &hostOut);
bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion = 5);
bool SetProxy(enum Network net, CService addrProxy);
bool GetProxy(enum Network net, proxyType &proxyInfoOut);
bool IsProxy(const CNetAddr &addr);
bool SetNameProxy(CService addrProxy, int nSocksVersion = 5);
bool SetNameProxy(CService addrProxy);
bool HaveNameProxy();
bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0, bool fAllowLookup = true);
bool LookupHostNumeric(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0);
@ -181,5 +181,7 @@ bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout = nCon
bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault = 0, int nTimeout = nConnectTimeout);
/** Return readable error string for a network error code */
std::string NetworkErrorString(int err);
/** Close socket and set hSocket to INVALID_SOCKET */
bool CloseSocket(SOCKET& hSocket);
#endif

View file

@ -318,26 +318,6 @@
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="socksVersionLabel">
<property name="text">
<string>SOCKS &amp;Version:</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="buddy">
<cstring>socksVersion</cstring>
</property>
</widget>
</item>
<item>
<widget class="QValueComboBox" name="socksVersion">
<property name="toolTip">
<string>SOCKS version of the proxy (e.g. 5)</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_1_Network">
<property name="orientation">

View file

@ -49,15 +49,8 @@ OptionsDialog::OptionsDialog(QWidget *parent) :
ui->proxyPort->setEnabled(false);
ui->proxyPort->setValidator(new QIntValidator(1, 65535, this));
/** SOCKS version is only selectable for default proxy and is always 5 for IPv6 and Tor */
ui->socksVersion->setEnabled(false);
ui->socksVersion->addItem("5", 5);
ui->socksVersion->addItem("4", 4);
ui->socksVersion->setCurrentIndex(0);
connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyIp, SLOT(setEnabled(bool)));
connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyPort, SLOT(setEnabled(bool)));
connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->socksVersion, SLOT(setEnabled(bool)));
ui->proxyIp->installEventFilter(this);
@ -175,7 +168,6 @@ void OptionsDialog::setMapper()
mapper->addMapping(ui->connectSocks, OptionsModel::ProxyUse);
mapper->addMapping(ui->proxyIp, OptionsModel::ProxyIP);
mapper->addMapping(ui->proxyPort, OptionsModel::ProxyPort);
mapper->addMapping(ui->socksVersion, OptionsModel::ProxySocksVersion);
/* Window */
#ifndef Q_OS_MAC

View file

@ -123,11 +123,6 @@ void OptionsModel::Init()
// Only try to set -proxy, if user has enabled fUseProxy
if (settings.value("fUseProxy").toBool() && !SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString()))
addOverriddenOption("-proxy");
if (!settings.contains("nSocksVersion"))
settings.setValue("nSocksVersion", 5);
// Only try to set -socks, if user has enabled fUseProxy
if (settings.value("fUseProxy").toBool() && !SoftSetArg("-socks", settings.value("nSocksVersion").toString().toStdString()))
addOverriddenOption("-socks");
// Display
if (!settings.contains("language"))
@ -189,8 +184,6 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts);
return strlIpPort.at(1);
}
case ProxySocksVersion:
return settings.value("nSocksVersion", 5);
#ifdef ENABLE_WALLET
case Fee:
@ -282,13 +275,6 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
}
}
break;
case ProxySocksVersion: {
if (settings.value("nSocksVersion") != value) {
settings.setValue("nSocksVersion", value.toInt());
setRestartRequired(true);
}
}
break;
#ifdef ENABLE_WALLET
case Fee: // core option - can be changed on-the-fly
// Todo: Add is valid check and warn via message, if not
@ -357,20 +343,16 @@ bool OptionsModel::getProxySettings(QNetworkProxy& proxy) const
// GUI settings can be overridden with -proxy.
proxyType curProxy;
if (GetProxy(NET_IPV4, curProxy)) {
if (curProxy.second == 5) {
proxy.setType(QNetworkProxy::Socks5Proxy);
proxy.setHostName(QString::fromStdString(curProxy.first.ToStringIP()));
proxy.setPort(curProxy.first.GetPort());
proxy.setType(QNetworkProxy::Socks5Proxy);
proxy.setHostName(QString::fromStdString(curProxy.ToStringIP()));
proxy.setPort(curProxy.GetPort());
return true;
}
else
return false;
return true;
}
else
proxy.setType(QNetworkProxy::NoProxy);
return true;
return false;
}
void OptionsModel::setRestartRequired(bool fRequired)

View file

@ -345,20 +345,14 @@ void PaymentServer::initNetManager()
QNetworkProxy proxy;
// Query active proxy (fails if no SOCKS5 proxy)
// Query active SOCKS5 proxy
if (optionsModel->getProxySettings(proxy)) {
if (proxy.type() == QNetworkProxy::Socks5Proxy) {
netManager->setProxy(proxy);
netManager->setProxy(proxy);
qDebug() << "PaymentServer::initNetManager : Using SOCKS5 proxy" << proxy.hostName() << ":" << proxy.port();
}
else
qDebug() << "PaymentServer::initNetManager : No active proxy server found.";
qDebug() << "PaymentServer::initNetManager : Using SOCKS5 proxy" << proxy.hostName() << ":" << proxy.port();
}
else
emit message(tr("Net manager warning"),
tr("Your active proxy doesn't support SOCKS5, which is required for payment requests via proxy."),
CClientUIInterface::MSG_WARNING);
qDebug() << "PaymentServer::initNetManager : No active proxy server found.";
connect(netManager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(netRequestFinished(QNetworkReply*)));

View file

@ -71,7 +71,7 @@ Value getinfo(const Array& params, bool fHelp)
obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("timeoffset", GetTimeOffset()));
obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.ToStringIPPort() : string())));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("testnet", TestNet()));
#ifdef ENABLE_WALLET

View file

@ -134,8 +134,8 @@ Value getpeerinfo(const Array& params, bool fHelp)
if (fStateStats) {
obj.push_back(Pair("banscore", statestats.nMisbehavior));
}
if (stats.fSyncNode)
obj.push_back(Pair("syncnode", true));
obj.push_back(Pair("syncnode", stats.fSyncNode));
obj.push_back(Pair("whitelisted", stats.fWhitelisted));
ret.push_back(obj);
}
@ -368,7 +368,7 @@ Value getnetworkinfo(const Array& params, bool fHelp)
obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
obj.push_back(Pair("timeoffset", GetTimeOffset()));
obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.ToStringIPPort() : string())));
obj.push_back(Pair("relayfee", ValueFromAmount(CTransaction::nMinRelayTxFee)));
Array localAddresses;
{

View file

@ -831,6 +831,35 @@ struct ser_streamplaceholder
typedef std::vector<char, zero_after_free_allocator<char> > CSerializeData;
class CSizeComputer
{
protected:
size_t nSize;
public:
int nType;
int nVersion;
CSizeComputer(int nTypeIn, int nVersionIn) : nSize(0), nType(nTypeIn), nVersion(nVersionIn) {}
CSizeComputer& write(const char *psz, int nSize)
{
this->nSize += nSize;
return *this;
}
template<typename T>
CSizeComputer& operator<<(const T& obj)
{
::Serialize(*this, obj, nType, nVersion);
return (*this);
}
size_t size() const {
return nSize;
}
};
/** Double ended buffer combining vector and stream-like interfaces.
*
* >> and << read and write unformatted data using the above serialization templates.

View file

@ -97,7 +97,6 @@ bool fDaemon = false;
bool fServer = false;
string strMiscWarning;
bool fBloomFilters = true;
bool fNoListen = false;
bool fLogTimestamps = false;
volatile bool fReopenDebugLog = false;
CClientUIInterface uiInterface;

View file

@ -115,7 +115,6 @@ extern bool fPrintToDebugLog;
extern bool fServer;
extern std::string strMiscWarning;
extern bool fBloomFilters;
extern bool fNoListen;
extern bool fLogTimestamps;
extern volatile bool fReopenDebugLog;