Changeset View
Changeset View
Standalone View
Standalone View
src/seeder/bitcoin.cpp
#include <seeder/bitcoin.h> | #include <seeder/bitcoin.h> | ||||
#include <hash.h> | #include <hash.h> | ||||
#include <netbase.h> | #include <netbase.h> | ||||
#include <seeder/db.h> | #include <seeder/db.h> | ||||
#include <serialize.h> | #include <serialize.h> | ||||
#include <streams.h> | |||||
#include <uint256.h> | #include <uint256.h> | ||||
#include <algorithm> | #include <algorithm> | ||||
// Weither we are on testnet or mainnet. | // Weither we are on testnet or mainnet. | ||||
bool fTestNet; | bool fTestNet; | ||||
// The network magic to use. | // The network magic to use. | ||||
CMessageHeader::MessageMagic netMagic = {{0xe3, 0xe1, 0xf3, 0xe8}}; | CMessageHeader::MessageMagic netMagic = {{0xe3, 0xe1, 0xf3, 0xe8}}; | ||||
#define BITCOIN_SEED_NONCE 0x0539a019ca550825ULL | #define BITCOIN_SEED_NONCE 0x0539a019ca550825ULL | ||||
static const uint32_t allones(-1); | static const uint32_t allones(-1); | ||||
class CSeederNode { | void CSeederNode::BeginMessage(const char *pszCommand) { | ||||
SOCKET sock; | |||||
CDataStream vSend; | |||||
CDataStream vRecv; | |||||
uint32_t nHeaderStart; | |||||
uint32_t nMessageStart; | |||||
int nVersion; | |||||
std::string strSubVer; | |||||
int nStartingHeight; | |||||
std::vector<CAddress> *vAddr; | |||||
int ban; | |||||
int64_t doneAfter; | |||||
CAddress you; | |||||
int GetTimeout() { return you.IsTor() ? 120 : 30; } | |||||
void BeginMessage(const char *pszCommand) { | |||||
if (nHeaderStart != allones) { | if (nHeaderStart != allones) { | ||||
AbortMessage(); | AbortMessage(); | ||||
} | } | ||||
nHeaderStart = vSend.size(); | nHeaderStart = vSend.size(); | ||||
vSend << CMessageHeader(netMagic, pszCommand, 0); | vSend << CMessageHeader(netMagic, pszCommand, 0); | ||||
nMessageStart = vSend.size(); | nMessageStart = vSend.size(); | ||||
// fprintf(stdout, "%s: SEND %s\n", ToString(you).c_str(), pszCommand); | // fprintf(stdout, "%s: SEND %s\n", ToString(you).c_str(), pszCommand); | ||||
} | } | ||||
void AbortMessage() { | void CSeederNode::AbortMessage() { | ||||
if (nHeaderStart == allones) { | if (nHeaderStart == allones) { | ||||
return; | return; | ||||
} | } | ||||
vSend.resize(nHeaderStart); | vSend.resize(nHeaderStart); | ||||
nHeaderStart = allones; | nHeaderStart = allones; | ||||
nMessageStart = allones; | nMessageStart = allones; | ||||
} | } | ||||
void EndMessage() { | void CSeederNode::EndMessage() { | ||||
if (nHeaderStart == allones) { | if (nHeaderStart == allones) { | ||||
return; | return; | ||||
} | } | ||||
uint32_t nSize = vSend.size() - nMessageStart; | uint32_t nSize = vSend.size() - nMessageStart; | ||||
memcpy((char *)&vSend[nHeaderStart] + | memcpy((char *)&vSend[nHeaderStart] + | ||||
offsetof(CMessageHeader, nMessageSize), | offsetof(CMessageHeader, nMessageSize), | ||||
&nSize, sizeof(nSize)); | &nSize, sizeof(nSize)); | ||||
if (vSend.GetVersion() >= 209) { | if (vSend.GetVersion() >= 209) { | ||||
uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end()); | uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end()); | ||||
unsigned int nChecksum = 0; | unsigned int nChecksum = 0; | ||||
memcpy(&nChecksum, &hash, sizeof(nChecksum)); | memcpy(&nChecksum, &hash, sizeof(nChecksum)); | ||||
assert(nMessageStart - nHeaderStart >= | assert(nMessageStart - nHeaderStart >= | ||||
offsetof(CMessageHeader, pchChecksum) + sizeof(nChecksum)); | offsetof(CMessageHeader, pchChecksum) + sizeof(nChecksum)); | ||||
memcpy((char *)&vSend[nHeaderStart] + | memcpy((char *)&vSend[nHeaderStart] + | ||||
offsetof(CMessageHeader, pchChecksum), | offsetof(CMessageHeader, pchChecksum), | ||||
&nChecksum, sizeof(nChecksum)); | &nChecksum, sizeof(nChecksum)); | ||||
} | } | ||||
nHeaderStart = allones; | nHeaderStart = allones; | ||||
nMessageStart = allones; | nMessageStart = allones; | ||||
} | } | ||||
void Send() { | void CSeederNode::Send() { | ||||
if (sock == INVALID_SOCKET) { | if (sock == INVALID_SOCKET) { | ||||
return; | return; | ||||
} | } | ||||
if (vSend.empty()) { | if (vSend.empty()) { | ||||
return; | return; | ||||
} | } | ||||
int nBytes = send(sock, &vSend[0], vSend.size(), 0); | int nBytes = send(sock, &vSend[0], vSend.size(), 0); | ||||
if (nBytes > 0) { | if (nBytes > 0) { | ||||
vSend.erase(vSend.begin(), vSend.begin() + nBytes); | vSend.erase(vSend.begin(), vSend.begin() + nBytes); | ||||
} else { | } else { | ||||
close(sock); | close(sock); | ||||
sock = INVALID_SOCKET; | sock = INVALID_SOCKET; | ||||
} | } | ||||
} | } | ||||
void PushVersion() { | void CSeederNode::PushVersion() { | ||||
int64_t nTime = time(nullptr); | int64_t nTime = time(nullptr); | ||||
uint64_t nLocalNonce = BITCOIN_SEED_NONCE; | uint64_t nLocalNonce = BITCOIN_SEED_NONCE; | ||||
int64_t nLocalServices = 0; | int64_t nLocalServices = 0; | ||||
CService myService; | CService myService; | ||||
CAddress me(myService, ServiceFlags(NODE_NETWORK | NODE_BITCOIN_CASH)); | CAddress me(myService, ServiceFlags(NODE_NETWORK | NODE_BITCOIN_CASH)); | ||||
BeginMessage("version"); | BeginMessage("version"); | ||||
int nBestHeight = GetRequireHeight(); | int nBestHeight = GetRequireHeight(); | ||||
std::string ver = "/bitcoin-cash-seeder:0.15/"; | std::string ver = "/bitcoin-cash-seeder:0.15/"; | ||||
vSend << PROTOCOL_VERSION << nLocalServices << nTime << you << me | vSend << PROTOCOL_VERSION << nLocalServices << nTime << you << me | ||||
<< nLocalNonce << ver << nBestHeight; | << nLocalNonce << ver << nBestHeight; | ||||
EndMessage(); | EndMessage(); | ||||
} | } | ||||
void GotVersion() { | void CSeederNode::GotVersion() { | ||||
// fprintf(stdout, "\n%s: version %i\n", ToString(you).c_str(), | // fprintf(stdout, "\n%s: version %i\n", ToString(you).c_str(), | ||||
// nVersion); | // nVersion); | ||||
if (vAddr) { | if (vAddr) { | ||||
BeginMessage("getaddr"); | BeginMessage("getaddr"); | ||||
EndMessage(); | EndMessage(); | ||||
doneAfter = time(nullptr) + GetTimeout(); | doneAfter = time(nullptr) + GetTimeout(); | ||||
} else { | } else { | ||||
doneAfter = time(nullptr) + 1; | doneAfter = time(nullptr) + 1; | ||||
} | } | ||||
} | } | ||||
bool ProcessMessage(std::string strCommand, CDataStream &recv) { | bool CSeederNode::ProcessMessage(std::string strCommand, CDataStream &recv) { | ||||
// fprintf(stdout, "%s: RECV %s\n", ToString(you).c_str(), | // fprintf(stdout, "%s: RECV %s\n", ToString(you).c_str(), | ||||
// strCommand.c_str()); | // strCommand.c_str()); | ||||
if (strCommand == "version") { | if (strCommand == "version") { | ||||
int64_t nTime; | int64_t nTime; | ||||
CAddress addrMe; | CAddress addrMe; | ||||
CAddress addrFrom; | CAddress addrFrom; | ||||
uint64_t nNonce = 1; | uint64_t nNonce = 1; | ||||
uint64_t nServiceInt; | uint64_t nServiceInt; | ||||
recv >> nVersion >> nServiceInt >> nTime >> addrMe; | recv >> nVersion >> nServiceInt >> nTime >> addrMe; | ||||
you.nServices = ServiceFlags(nServiceInt); | you.nServices = ServiceFlags(nServiceInt); | ||||
if (nVersion == 10300) nVersion = 300; | if (nVersion == 10300) nVersion = 300; | ||||
if (nVersion >= 106 && !recv.empty()) recv >> addrFrom >> nNonce; | if (nVersion >= 106 && !recv.empty()) recv >> addrFrom >> nNonce; | ||||
if (nVersion >= 106 && !recv.empty()) recv >> strSubVer; | if (nVersion >= 106 && !recv.empty()) recv >> strSubVer; | ||||
if (nVersion >= 209 && !recv.empty()) recv >> nStartingHeight; | if (nVersion >= 209 && !recv.empty()) recv >> nStartingHeight; | ||||
if (nVersion >= 209) { | if (nVersion >= 209) { | ||||
BeginMessage("verack"); | BeginMessage("verack"); | ||||
EndMessage(); | EndMessage(); | ||||
} | } | ||||
vSend.SetVersion(std::min(nVersion, PROTOCOL_VERSION)); | vSend.SetVersion(std::min(nVersion, PROTOCOL_VERSION)); | ||||
if (nVersion < 209) { | if (nVersion < 209) { | ||||
vRecv.SetVersion(std::min(nVersion, PROTOCOL_VERSION)); | vRecv.SetVersion(std::min(nVersion, PROTOCOL_VERSION)); | ||||
GotVersion(); | GotVersion(); | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
if (strCommand == "verack") { | if (strCommand == "verack") { | ||||
vRecv.SetVersion(std::min(nVersion, PROTOCOL_VERSION)); | vRecv.SetVersion(std::min(nVersion, PROTOCOL_VERSION)); | ||||
GotVersion(); | GotVersion(); | ||||
return false; | return false; | ||||
} | } | ||||
if (strCommand == "addr" && vAddr) { | if (strCommand == "addr" && vAddr) { | ||||
std::vector<CAddress> vAddrNew; | std::vector<CAddress> vAddrNew; | ||||
recv >> vAddrNew; | recv >> vAddrNew; | ||||
// fprintf(stdout, "%s: got %i addresses\n", ToString(you).c_str(), | // fprintf(stdout, "%s: got %i addresses\n", ToString(you).c_str(), | ||||
// (int)vAddrNew.size()); | // (int)vAddrNew.size()); | ||||
int64_t now = time(nullptr); | int64_t now = time(nullptr); | ||||
std::vector<CAddress>::iterator it = vAddrNew.begin(); | std::vector<CAddress>::iterator it = vAddrNew.begin(); | ||||
if (vAddrNew.size() > 1) { | if (vAddrNew.size() > 1) { | ||||
if (doneAfter == 0 || doneAfter > now + 1) doneAfter = now + 1; | if (doneAfter == 0 || doneAfter > now + 1) doneAfter = now + 1; | ||||
} | } | ||||
while (it != vAddrNew.end()) { | while (it != vAddrNew.end()) { | ||||
CAddress &addr = *it; | CAddress &addr = *it; | ||||
// fprintf(stdout, "%s: got address %s\n", | // fprintf(stdout, "%s: got address %s\n", | ||||
// ToString(you).c_str(), | // ToString(you).c_str(), | ||||
// addr.ToString().c_str(), (int)(vAddr->size())); | // addr.ToString().c_str(), (int)(vAddr->size())); | ||||
it++; | it++; | ||||
if (addr.nTime <= 100000000 || addr.nTime > now + 600) { | if (addr.nTime <= 100000000 || addr.nTime > now + 600) { | ||||
addr.nTime = now - 5 * 86400; | addr.nTime = now - 5 * 86400; | ||||
} | } | ||||
if (addr.nTime > now - 604800) { | if (addr.nTime > now - 604800) { | ||||
vAddr->push_back(addr); | vAddr->push_back(addr); | ||||
} | } | ||||
// fprintf(stdout, "%s: added address %s (#%i)\n", | // fprintf(stdout, "%s: added address %s (#%i)\n", | ||||
// ToString(you).c_str(), | // ToString(you).c_str(), | ||||
// addr.ToString().c_str(), (int)(vAddr->size())); | // addr.ToString().c_str(), (int)(vAddr->size())); | ||||
if (vAddr->size() > 1000) { | if (vAddr->size() > 1000) { | ||||
doneAfter = 1; | doneAfter = 1; | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
bool ProcessMessages() { | bool CSeederNode::ProcessMessages() { | ||||
if (vRecv.empty()) { | if (vRecv.empty()) { | ||||
return false; | return false; | ||||
} | } | ||||
do { | do { | ||||
CDataStream::iterator pstart = std::search( | CDataStream::iterator pstart = std::search( | ||||
vRecv.begin(), vRecv.end(), BEGIN(netMagic), END(netMagic)); | vRecv.begin(), vRecv.end(), BEGIN(netMagic), END(netMagic)); | ||||
uint32_t nHeaderSize = GetSerializeSize( | uint32_t nHeaderSize = GetSerializeSize( | ||||
CMessageHeader(netMagic), vRecv.GetType(), vRecv.GetVersion()); | CMessageHeader(netMagic), vRecv.GetType(), vRecv.GetVersion()); | ||||
if (vRecv.end() - pstart < nHeaderSize) { | if (vRecv.end() - pstart < nHeaderSize) { | ||||
if (vRecv.size() > nHeaderSize) { | if (vRecv.size() > nHeaderSize) { | ||||
vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize); | vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize); | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
vRecv.erase(vRecv.begin(), pstart); | vRecv.erase(vRecv.begin(), pstart); | ||||
std::vector<char> vHeaderSave(vRecv.begin(), | std::vector<char> vHeaderSave(vRecv.begin(), | ||||
vRecv.begin() + nHeaderSize); | vRecv.begin() + nHeaderSize); | ||||
CMessageHeader hdr(netMagic); | CMessageHeader hdr(netMagic); | ||||
vRecv >> hdr; | vRecv >> hdr; | ||||
if (!hdr.IsValidWithoutConfig(netMagic)) { | if (!hdr.IsValidWithoutConfig(netMagic)) { | ||||
// fprintf(stdout, "%s: BAD (invalid header)\n", | // fprintf(stdout, "%s: BAD (invalid header)\n", | ||||
// ToString(you).c_str()); | // ToString(you).c_str()); | ||||
ban = 100000; | ban = 100000; | ||||
return true; | return true; | ||||
} | } | ||||
std::string strCommand = hdr.GetCommand(); | std::string strCommand = hdr.GetCommand(); | ||||
unsigned int nMessageSize = hdr.nMessageSize; | unsigned int nMessageSize = hdr.nMessageSize; | ||||
if (nMessageSize > MAX_SIZE) { | if (nMessageSize > MAX_SIZE) { | ||||
// fprintf(stdout, "%s: BAD (message too large)\n", | // fprintf(stdout, "%s: BAD (message too large)\n", | ||||
// ToString(you).c_str()); | // ToString(you).c_str()); | ||||
ban = 100000; | ban = 100000; | ||||
return true; | return true; | ||||
} | } | ||||
if (nMessageSize > vRecv.size()) { | if (nMessageSize > vRecv.size()) { | ||||
vRecv.insert(vRecv.begin(), vHeaderSave.begin(), | vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end()); | ||||
vHeaderSave.end()); | |||||
break; | break; | ||||
} | } | ||||
if (vRecv.GetVersion() >= 209) { | if (vRecv.GetVersion() >= 209) { | ||||
uint256 hash = | uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize); | ||||
Hash(vRecv.begin(), vRecv.begin() + nMessageSize); | |||||
if (memcmp(hash.begin(), hdr.pchChecksum, | if (memcmp(hash.begin(), hdr.pchChecksum, | ||||
CMessageHeader::CHECKSUM_SIZE) != 0) { | CMessageHeader::CHECKSUM_SIZE) != 0) { | ||||
continue; | continue; | ||||
} | } | ||||
} | } | ||||
CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, | CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, | ||||
vRecv.GetType(), vRecv.GetVersion()); | vRecv.GetType(), vRecv.GetVersion()); | ||||
vRecv.ignore(nMessageSize); | vRecv.ignore(nMessageSize); | ||||
if (ProcessMessage(strCommand, vMsg)) { | if (ProcessMessage(strCommand, vMsg)) { | ||||
return true; | return true; | ||||
} | } | ||||
// fprintf(stdout, "%s: done processing %s\n", | // fprintf(stdout, "%s: done processing %s\n", | ||||
// ToString(you).c_str(), | // ToString(you).c_str(), | ||||
// strCommand.c_str()); | // strCommand.c_str()); | ||||
} while (1); | } while (1); | ||||
return false; | return false; | ||||
} | } | ||||
public: | CSeederNode::CSeederNode(const CService &ip, std::vector<CAddress> *vAddrIn) | ||||
CSeederNode(const CService &ip, std::vector<CAddress> *vAddrIn) | |||||
: sock(INVALID_SOCKET), vSend(SER_NETWORK, 0), vRecv(SER_NETWORK, 0), | : sock(INVALID_SOCKET), vSend(SER_NETWORK, 0), vRecv(SER_NETWORK, 0), | ||||
nHeaderStart(-1), nMessageStart(-1), nVersion(0), vAddr(vAddrIn), | nHeaderStart(-1), nMessageStart(-1), nVersion(0), vAddr(vAddrIn), ban(0), | ||||
ban(0), doneAfter(0), | doneAfter(0), you(ip, ServiceFlags(NODE_NETWORK | NODE_BITCOIN_CASH)) { | ||||
you(ip, ServiceFlags(NODE_NETWORK | NODE_BITCOIN_CASH)) { | |||||
if (time(nullptr) > 1329696000) { | if (time(nullptr) > 1329696000) { | ||||
vSend.SetVersion(209); | vSend.SetVersion(209); | ||||
vRecv.SetVersion(209); | vRecv.SetVersion(209); | ||||
} | } | ||||
} | } | ||||
bool Run() { | bool CSeederNode::Run() { | ||||
// FIXME: This logic is duplicated with CConnman::ConnectNode for no | // FIXME: This logic is duplicated with CConnman::ConnectNode for no | ||||
// good reason. | // good reason. | ||||
bool connected = false; | bool connected = false; | ||||
proxyType proxy; | proxyType proxy; | ||||
if (you.IsValid()) { | if (you.IsValid()) { | ||||
bool proxyConnectionFailed = false; | bool proxyConnectionFailed = false; | ||||
if (GetProxy(you.GetNetwork(), proxy)) { | if (GetProxy(you.GetNetwork(), proxy)) { | ||||
sock = CreateSocket(proxy.proxy); | sock = CreateSocket(proxy.proxy); | ||||
if (sock == INVALID_SOCKET) { | if (sock == INVALID_SOCKET) { | ||||
return false; | return false; | ||||
} | } | ||||
connected = ConnectThroughProxy( | connected = ConnectThroughProxy( | ||||
proxy, you.ToStringIP(), you.GetPort(), sock, | proxy, you.ToStringIP(), you.GetPort(), sock, nConnectTimeout, | ||||
nConnectTimeout, &proxyConnectionFailed); | &proxyConnectionFailed); | ||||
} else { | } else { | ||||
// no proxy needed (none set for target network) | // no proxy needed (none set for target network) | ||||
sock = CreateSocket(you); | sock = CreateSocket(you); | ||||
if (sock == INVALID_SOCKET) { | if (sock == INVALID_SOCKET) { | ||||
return false; | return false; | ||||
} | } | ||||
// no proxy needed (none set for target network) | // no proxy needed (none set for target network) | ||||
connected = | connected = ConnectSocketDirectly(you, sock, nConnectTimeout, true); | ||||
ConnectSocketDirectly(you, sock, nConnectTimeout, true); | |||||
} | } | ||||
} | } | ||||
if (!connected) { | if (!connected) { | ||||
// fprintf(stdout, "Cannot connect to %s\n", ToString(you).c_str()); | // fprintf(stdout, "Cannot connect to %s\n", ToString(you).c_str()); | ||||
CloseSocket(sock); | CloseSocket(sock); | ||||
return false; | return false; | ||||
} | } | ||||
PushVersion(); | PushVersion(); | ||||
Send(); | Send(); | ||||
bool res = true; | bool res = true; | ||||
int64_t now; | int64_t now; | ||||
while (now = time(nullptr), ban == 0 && | while (now = time(nullptr), ban == 0 && | ||||
(doneAfter == 0 || doneAfter > now) && | (doneAfter == 0 || doneAfter > now) && | ||||
sock != INVALID_SOCKET) { | sock != INVALID_SOCKET) { | ||||
char pchBuf[0x10000]; | char pchBuf[0x10000]; | ||||
fd_set set; | fd_set set; | ||||
FD_ZERO(&set); | FD_ZERO(&set); | ||||
FD_SET(sock, &set); | FD_SET(sock, &set); | ||||
struct timeval wa; | struct timeval wa; | ||||
if (doneAfter) { | if (doneAfter) { | ||||
wa.tv_sec = doneAfter - now; | wa.tv_sec = doneAfter - now; | ||||
wa.tv_usec = 0; | wa.tv_usec = 0; | ||||
} else { | } else { | ||||
wa.tv_sec = GetTimeout(); | wa.tv_sec = GetTimeout(); | ||||
wa.tv_usec = 0; | wa.tv_usec = 0; | ||||
} | } | ||||
int ret = select(sock + 1, &set, nullptr, &set, &wa); | int ret = select(sock + 1, &set, nullptr, &set, &wa); | ||||
if (ret != 1) { | if (ret != 1) { | ||||
if (!doneAfter) res = false; | if (!doneAfter) res = false; | ||||
break; | break; | ||||
} | } | ||||
int nBytes = recv(sock, pchBuf, sizeof(pchBuf), 0); | int nBytes = recv(sock, pchBuf, sizeof(pchBuf), 0); | ||||
int nPos = vRecv.size(); | int nPos = vRecv.size(); | ||||
if (nBytes > 0) { | if (nBytes > 0) { | ||||
vRecv.resize(nPos + nBytes); | vRecv.resize(nPos + nBytes); | ||||
memcpy(&vRecv[nPos], pchBuf, nBytes); | memcpy(&vRecv[nPos], pchBuf, nBytes); | ||||
} else if (nBytes == 0) { | } else if (nBytes == 0) { | ||||
// fprintf(stdout, "%s: BAD (connection closed prematurely)\n", | // fprintf(stdout, "%s: BAD (connection closed prematurely)\n", | ||||
// ToString(you).c_str()); | // ToString(you).c_str()); | ||||
res = false; | res = false; | ||||
break; | break; | ||||
} else { | } else { | ||||
// fprintf(stdout, "%s: BAD (connection error)\n", | // fprintf(stdout, "%s: BAD (connection error)\n", | ||||
// ToString(you).c_str()); | // ToString(you).c_str()); | ||||
res = false; | res = false; | ||||
break; | break; | ||||
} | } | ||||
ProcessMessages(); | ProcessMessages(); | ||||
Send(); | Send(); | ||||
} | } | ||||
if (sock == INVALID_SOCKET) res = false; | if (sock == INVALID_SOCKET) res = false; | ||||
close(sock); | close(sock); | ||||
sock = INVALID_SOCKET; | sock = INVALID_SOCKET; | ||||
return (ban == 0) && res; | return (ban == 0) && res; | ||||
} | } | ||||
int GetBan() { return ban; } | |||||
int GetClientVersion() { return nVersion; } | |||||
std::string GetClientSubVersion() { return strSubVer; } | |||||
int GetStartingHeight() { return nStartingHeight; } | |||||
}; | |||||
bool TestNode(const CService &cip, int &ban, int &clientV, | bool TestNode(const CService &cip, int &ban, int &clientV, | ||||
std::string &clientSV, int &blocks, | std::string &clientSV, int &blocks, | ||||
std::vector<CAddress> *vAddr) { | std::vector<CAddress> *vAddr) { | ||||
try { | try { | ||||
CSeederNode node(cip, vAddr); | CSeederNode node(cip, vAddr); | ||||
bool ret = node.Run(); | bool ret = node.Run(); | ||||
if (!ret) { | if (!ret) { | ||||
ban = node.GetBan(); | ban = node.GetBan(); | ||||
Show All 14 Lines |